diff --git a/.travis.yml b/.travis.yml index 6bb94decea..703ff4cf34 100644 --- a/.travis.yml +++ b/.travis.yml @@ -53,7 +53,7 @@ before_install: fi; before_script: - - git submodule update --init asmjit 3rdparty/ffmpeg 3rdparty/pugixml 3rdparty/GSL 3rdparty/libpng Vulkan/glslang Vulkan/Vulkan-LoaderAndValidationLayers + - git submodule update --init asmjit 3rdparty/ffmpeg 3rdparty/pugixml 3rdparty/GSL 3rdparty/libpng Vulkan/glslang Vulkan/Vulkan-LoaderAndValidationLayers Utilities/yaml-cpp - mkdir build - cd build - if [ "$TRAVIS_OS_NAME" = "linux" ]; then cmake ..; else cmake .. -DLLVM_DIR=/usr/local/opt/llvm36/lib/llvm-3.6/share/llvm/cmake; fi diff --git a/README.md b/README.md index 3d8efc9641..e6bdefceda 100644 --- a/README.md +++ b/README.md @@ -37,9 +37,11 @@ __Mac OSX__ ### Building -To initialize the repository don't forget to execute `git submodule update --init` to pull the wxWidgets source. +To initialize the repository don't forget to execute `git submodule update --init` to pull the submodules. * __Windows__: -Open the *.SLN* file, and press *Build* > *Clean Solution*, then *Build Solution*. *Rebuild* may not work correctly. +1) Open the *.SLN* file. +2) Build the projects in *__BUILD_BEFORE* folder: right-click on every project > *Build*. +3) Press *BUILD* > *Build Solution* or *Rebuild Solution*. * __Linux & Mac OSX__: If you want to build with LLVM, then LLVM 3.6.2 is required. `cd rpcs3 && cmake CMakeLists.txt && make && cd ../` then run with `cd bin && ./rpcs3`. diff --git a/Utilities/Atomic.h b/Utilities/Atomic.h index 49948c2744..b7591b556a 100644 --- a/Utilities/Atomic.h +++ b/Utilities/Atomic.h @@ -1,696 +1,979 @@ #pragma once -#if defined(__GNUG__) +#include "types.h" -template inline std::enable_if_t sync_val_compare_and_swap(volatile T* dest, T2 comp, T2 exch) +// Helper class, provides access to compiler-specific atomic intrinsics +template +struct atomic_storage { - return __sync_val_compare_and_swap(dest, comp, exch); -} + static_assert(sizeof(T) <= 16 && sizeof(T) == alignof(T), "atomic_storage<> error: invalid type"); -template inline std::enable_if_t sync_bool_compare_and_swap(volatile T* dest, T2 comp, T2 exch) -{ - return __sync_bool_compare_and_swap(dest, comp, exch); -} + /* First part: Non-MSVC intrinsics */ -template inline std::enable_if_t sync_lock_test_and_set(volatile T* dest, T2 value) -{ - return __sync_lock_test_and_set(dest, value); -} - -template inline std::enable_if_t sync_fetch_and_add(volatile T* dest, T2 value) -{ - return __sync_fetch_and_add(dest, value); -} - -template inline std::enable_if_t sync_fetch_and_sub(volatile T* dest, T2 value) -{ - return __sync_fetch_and_sub(dest, value); -} - -template inline std::enable_if_t sync_fetch_and_or(volatile T* dest, T2 value) -{ - return __sync_fetch_and_or(dest, value); -} - -template inline std::enable_if_t sync_fetch_and_and(volatile T* dest, T2 value) -{ - return __sync_fetch_and_and(dest, value); -} - -template inline std::enable_if_t sync_fetch_and_xor(volatile T* dest, T2 value) -{ - return __sync_fetch_and_xor(dest, value); -} - -#elif defined(_MSC_VER) - -// atomic compare and swap functions - -inline u8 sync_val_compare_and_swap(volatile u8* dest, u8 comp, u8 exch) -{ - return _InterlockedCompareExchange8((volatile char*)dest, exch, comp); -} - -inline u16 sync_val_compare_and_swap(volatile u16* dest, u16 comp, u16 exch) -{ - return _InterlockedCompareExchange16((volatile short*)dest, exch, comp); -} - -inline u32 sync_val_compare_and_swap(volatile u32* dest, u32 comp, u32 exch) -{ - return _InterlockedCompareExchange((volatile long*)dest, exch, comp); -} - -inline u64 sync_val_compare_and_swap(volatile u64* dest, u64 comp, u64 exch) -{ - return _InterlockedCompareExchange64((volatile long long*)dest, exch, comp); -} - -inline u128 sync_val_compare_and_swap(volatile u128* dest, u128 comp, u128 exch) -{ - _InterlockedCompareExchange128((volatile long long*)dest, exch.hi, exch.lo, (long long*)&comp); - return comp; -} - -inline bool sync_bool_compare_and_swap(volatile u8* dest, u8 comp, u8 exch) -{ - return (u8)_InterlockedCompareExchange8((volatile char*)dest, exch, comp) == comp; -} - -inline bool sync_bool_compare_and_swap(volatile u16* dest, u16 comp, u16 exch) -{ - return (u16)_InterlockedCompareExchange16((volatile short*)dest, exch, comp) == comp; -} - -inline bool sync_bool_compare_and_swap(volatile u32* dest, u32 comp, u32 exch) -{ - return (u32)_InterlockedCompareExchange((volatile long*)dest, exch, comp) == comp; -} - -inline bool sync_bool_compare_and_swap(volatile u64* dest, u64 comp, u64 exch) -{ - return (u64)_InterlockedCompareExchange64((volatile long long*)dest, exch, comp) == comp; -} - -inline bool sync_bool_compare_and_swap(volatile u128* dest, u128 comp, u128 exch) -{ - return _InterlockedCompareExchange128((volatile long long*)dest, exch.hi, exch.lo, (long long*)&comp) != 0; -} - -// atomic exchange functions - -inline u8 sync_lock_test_and_set(volatile u8* dest, u8 value) -{ - return _InterlockedExchange8((volatile char*)dest, value); -} - -inline u16 sync_lock_test_and_set(volatile u16* dest, u16 value) -{ - return _InterlockedExchange16((volatile short*)dest, value); -} - -inline u32 sync_lock_test_and_set(volatile u32* dest, u32 value) -{ - return _InterlockedExchange((volatile long*)dest, value); -} - -inline u64 sync_lock_test_and_set(volatile u64* dest, u64 value) -{ - return _InterlockedExchange64((volatile long long*)dest, value); -} - -inline u128 sync_lock_test_and_set(volatile u128* dest, u128 value) -{ - while (true) - { - u128 old; - old.lo = dest->lo; - old.hi = dest->hi; - - if (sync_bool_compare_and_swap(dest, old, value)) return old; - } -} - -// atomic add functions - -inline u8 sync_fetch_and_add(volatile u8* dest, u8 value) -{ - return _InterlockedExchangeAdd8((volatile char*)dest, value); -} - -inline u16 sync_fetch_and_add(volatile u16* dest, u16 value) -{ - return _InterlockedExchangeAdd16((volatile short*)dest, value); -} - -inline u32 sync_fetch_and_add(volatile u32* dest, u32 value) -{ - return _InterlockedExchangeAdd((volatile long*)dest, value); -} - -inline u64 sync_fetch_and_add(volatile u64* dest, u64 value) -{ - return _InterlockedExchangeAdd64((volatile long long*)dest, value); -} - -inline u128 sync_fetch_and_add(volatile u128* dest, u128 value) -{ - while (true) - { - u128 old; - old.lo = dest->lo; - old.hi = dest->hi; - - if (sync_bool_compare_and_swap(dest, old, old + value)) return old; - } -} - -// atomic sub functions - -inline u8 sync_fetch_and_sub(volatile u8* dest, u8 value) -{ - return _InterlockedExchangeAdd8((volatile char*)dest, -(char)value); -} - -inline u16 sync_fetch_and_sub(volatile u16* dest, u16 value) -{ - return _InterlockedExchangeAdd16((volatile short*)dest, -(short)value); -} - -inline u32 sync_fetch_and_sub(volatile u32* dest, u32 value) -{ - return _InterlockedExchangeAdd((volatile long*)dest, -(long)value); -} - -inline u64 sync_fetch_and_sub(volatile u64* dest, u64 value) -{ - return _InterlockedExchangeAdd64((volatile long long*)dest, -(long long)value); -} - -inline u128 sync_fetch_and_sub(volatile u128* dest, u128 value) -{ - while (true) - { - u128 old; - old.lo = dest->lo; - old.hi = dest->hi; - - if (sync_bool_compare_and_swap(dest, old, old - value)) return old; - } -} - -// atomic `bitwise or` functions - -inline u8 sync_fetch_and_or(volatile u8* dest, u8 value) -{ - return _InterlockedOr8((volatile char*)dest, value); -} - -inline u16 sync_fetch_and_or(volatile u16* dest, u16 value) -{ - return _InterlockedOr16((volatile short*)dest, value); -} - -inline u32 sync_fetch_and_or(volatile u32* dest, u32 value) -{ - return _InterlockedOr((volatile long*)dest, value); -} - -inline u64 sync_fetch_and_or(volatile u64* dest, u64 value) -{ - return _InterlockedOr64((volatile long long*)dest, value); -} - -inline u128 sync_fetch_and_or(volatile u128* dest, u128 value) -{ - while (true) - { - u128 old; - old.lo = dest->lo; - old.hi = dest->hi; - - if (sync_bool_compare_and_swap(dest, old, old | value)) return old; - } -} - -// atomic `bitwise and` functions - -inline u8 sync_fetch_and_and(volatile u8* dest, u8 value) -{ - return _InterlockedAnd8((volatile char*)dest, value); -} - -inline u16 sync_fetch_and_and(volatile u16* dest, u16 value) -{ - return _InterlockedAnd16((volatile short*)dest, value); -} - -inline u32 sync_fetch_and_and(volatile u32* dest, u32 value) -{ - return _InterlockedAnd((volatile long*)dest, value); -} - -inline u64 sync_fetch_and_and(volatile u64* dest, u64 value) -{ - return _InterlockedAnd64((volatile long long*)dest, value); -} - -inline u128 sync_fetch_and_and(volatile u128* dest, u128 value) -{ - while (true) - { - u128 old; - old.lo = dest->lo; - old.hi = dest->hi; - - if (sync_bool_compare_and_swap(dest, old, old & value)) return old; - } -} - -// atomic `bitwise xor` functions - -inline u8 sync_fetch_and_xor(volatile u8* dest, u8 value) -{ - return _InterlockedXor8((volatile char*)dest, value); -} - -inline u16 sync_fetch_and_xor(volatile u16* dest, u16 value) -{ - return _InterlockedXor16((volatile short*)dest, value); -} - -inline u32 sync_fetch_and_xor(volatile u32* dest, u32 value) -{ - return _InterlockedXor((volatile long*)dest, value); -} - -inline u64 sync_fetch_and_xor(volatile u64* dest, u64 value) -{ - return _InterlockedXor64((volatile long long*)dest, value); -} - -inline u128 sync_fetch_and_xor(volatile u128* dest, u128 value) -{ - while (true) - { - u128 old; - old.lo = dest->lo; - old.hi = dest->hi; - - if (sync_bool_compare_and_swap(dest, old, old ^ value)) return old; - } -} - -#endif /* _MSC_VER */ - -template struct atomic_storage -{ - static_assert(!Size, "Invalid atomic type"); -}; - -template struct atomic_storage -{ - using type = u8; -}; - -template struct atomic_storage -{ - using type = u16; -}; - -template struct atomic_storage -{ - using type = u32; -}; - -template struct atomic_storage -{ - using type = u64; -}; - -template struct atomic_storage -{ - using type = u128; -}; - -template using atomic_storage_t = typename atomic_storage::type; - -// atomic result wrapper; implements special behaviour for void result type -template struct atomic_op_result_t -{ - RT result; - - template atomic_op_result_t(T func, VT& var, Args&&... args) - : result(std::move(func(var, std::forward(args)...))) +#ifndef _MSC_VER + static inline bool compare_exchange(T& dest, T& comp, T exch) { + return __atomic_compare_exchange(&dest, &comp, &exch, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); } - RT move() + static inline T load(const T& dest) { - return std::move(result); + T result; + __atomic_load(&dest, &result, __ATOMIC_SEQ_CST); + return result; + } + + static inline void store(T& dest, T value) + { + __atomic_store(&dest, &value, __ATOMIC_SEQ_CST); + } + + static inline T exchange(T& dest, T value) + { + T result; + __atomic_exchange(&dest, &value, &result, __ATOMIC_SEQ_CST); + return result; + } + + static inline T fetch_add(T& dest, T value) + { + return __atomic_fetch_add(&dest, value, __ATOMIC_SEQ_CST); + } + + static inline T add_fetch(T& dest, T value) + { + return __atomic_add_fetch(&dest, value, __ATOMIC_SEQ_CST); + } + + static inline T fetch_sub(T& dest, T value) + { + return __atomic_fetch_sub(&dest, value, __ATOMIC_SEQ_CST); + } + + static inline T sub_fetch(T& dest, T value) + { + return __atomic_sub_fetch(&dest, value, __ATOMIC_SEQ_CST); + } + + static inline T fetch_and(T& dest, T value) + { + return __atomic_fetch_and(&dest, value, __ATOMIC_SEQ_CST); + } + + static inline T and_fetch(T& dest, T value) + { + return __atomic_and_fetch(&dest, value, __ATOMIC_SEQ_CST); + } + + static inline T fetch_xor(T& dest, T value) + { + return __atomic_fetch_xor(&dest, value, __ATOMIC_SEQ_CST); + } + + static inline T xor_fetch(T& dest, T value) + { + return __atomic_xor_fetch(&dest, value, __ATOMIC_SEQ_CST); + } + + static inline T fetch_or(T& dest, T value) + { + return __atomic_fetch_or(&dest, value, __ATOMIC_SEQ_CST); + } + + static inline T or_fetch(T& dest, T value) + { + return __atomic_or_fetch(&dest, value, __ATOMIC_SEQ_CST); + } +#endif + + /* Second part: MSVC-specific */ + +#ifdef _MSC_VER + static inline T add_fetch(T& dest, T value) + { + return atomic_storage::fetch_add(dest, value) + value; + } + + static inline T fetch_sub(T& dest, T value) + { + return atomic_storage::fetch_add(dest, 0 - value); + } + + static inline T sub_fetch(T& dest, T value) + { + return atomic_storage::fetch_add(dest, 0 - value) - value; + } + + static inline T and_fetch(T& dest, T value) + { + return atomic_storage::fetch_and(dest, value) & value; + } + + static inline T or_fetch(T& dest, T value) + { + return atomic_storage::fetch_or(dest, value) | value; + } + + static inline T xor_fetch(T& dest, T value) + { + return atomic_storage::fetch_xor(dest, value) ^ value; + } +#endif + + /* Third part: fallbacks, may be hidden by subsequent atomic_storage<> specializations */ + + static inline T fetch_inc(T& dest) + { + return atomic_storage::fetch_add(dest, 1); + } + + static inline T inc_fetch(T& dest) + { + return atomic_storage::add_fetch(dest, 1); + } + + static inline T fetch_dec(T& dest) + { + return atomic_storage::fetch_sub(dest, 1); + } + + static inline T dec_fetch(T& dest) + { + return atomic_storage::sub_fetch(dest, 1); + } + + static inline bool bts(T& dest, uint bit) + { + const T mask = static_cast(1) << bit; + return (atomic_storage::fetch_or(dest, mask) & mask) != 0; + } + + static inline bool btr(T& dest, uint bit) + { + const T mask = static_cast(1) << bit; + return (atomic_storage::fetch_and(dest, ~mask) & mask) != 0; + } + + static inline bool btc(T& dest, uint bit) + { + const T mask = static_cast(1) << bit; + return (atomic_storage::fetch_xor(dest, mask) & mask) != 0; } }; -// void specialization: result is the initial value of the first arg -template struct atomic_op_result_t -{ - VT result; +/* The rest: ugly MSVC intrinsics + possibly __asm__ implementations (TODO) */ - template atomic_op_result_t(T func, VT& var, Args&&... args) - : result(var) +template +struct atomic_storage : atomic_storage +{ +#ifdef _MSC_VER + static inline bool compare_exchange(T& dest, T& comp, T exch) { - func(var, std::forward(args)...); + char v = *(char*)∁ + char r = _InterlockedCompareExchange8((volatile char*)&dest, (char&)exch, v); + comp = (T&)r; + return r == v; } - VT move() + static inline T load(const T& dest) { - return std::move(result); + char value = *(const volatile char*)&dest; + _ReadWriteBarrier(); + return (T&)value; + } + + static inline void store(T& dest, T value) + { + _InterlockedExchange8((volatile char*)&dest, (char&)value); + } + + static inline T exchange(T& dest, T value) + { + char r = _InterlockedExchange8((volatile char*)&dest, (char&)value); + return (T&)r; + } + + static inline T fetch_add(T& dest, T value) + { + char r = _InterlockedExchangeAdd8((volatile char*)&dest, (char&)value); + return (T&)r; + } + + static inline T fetch_and(T& dest, T value) + { + char r = _InterlockedAnd8((volatile char*)&dest, (char&)value); + return (T&)r; + } + + static inline T fetch_or(T& dest, T value) + { + char r = _InterlockedOr8((volatile char*)&dest, (char&)value); + return (T&)r; + } + + static inline T fetch_xor(T& dest, T value) + { + char r = _InterlockedXor8((volatile char*)&dest, (char&)value); + return (T&)r; + } +#endif +}; + +template +struct atomic_storage : atomic_storage +{ +#ifdef _MSC_VER + static inline bool compare_exchange(T& dest, T& comp, T exch) + { + short v = *(short*)∁ + short r = _InterlockedCompareExchange16((volatile short*)&dest, (short&)exch, v); + comp = (T&)r; + return r == v; + } + + static inline T load(const T& dest) + { + short value = *(const volatile short*)&dest; + _ReadWriteBarrier(); + return (T&)value; + } + + static inline void store(T& dest, T value) + { + _InterlockedExchange16((volatile short*)&dest, (short&)value); + } + + static inline T exchange(T& dest, T value) + { + short r = _InterlockedExchange16((volatile short*)&dest, (short&)value); + return (T&)r; + } + + static inline T fetch_add(T& dest, T value) + { + short r = _InterlockedExchangeAdd16((volatile short*)&dest, (short&)value); + return (T&)r; + } + + static inline T fetch_and(T& dest, T value) + { + short r = _InterlockedAnd16((volatile short*)&dest, (short&)value); + return (T&)r; + } + + static inline T fetch_or(T& dest, T value) + { + short r = _InterlockedOr16((volatile short*)&dest, (short&)value); + return (T&)r; + } + + static inline T fetch_xor(T& dest, T value) + { + short r = _InterlockedXor16((volatile short*)&dest, (short&)value); + return (T&)r; + } + + static inline T inc_fetch(T& dest) + { + short r = _InterlockedIncrement16((volatile short*)&dest); + return (T&)r; + } + + static inline T dec_fetch(T& dest) + { + short r = _InterlockedDecrement16((volatile short*)&dest); + return (T&)r; + } +#endif +}; + +template +struct atomic_storage : atomic_storage +{ +#ifdef _MSC_VER + static inline bool compare_exchange(T& dest, T& comp, T exch) + { + long v = *(long*)∁ + long r = _InterlockedCompareExchange((volatile long*)&dest, (long&)exch, v); + comp = (T&)r; + return r == v; + } + + static inline T load(const T& dest) + { + long value = *(const volatile long*)&dest; + _ReadWriteBarrier(); + return (T&)value; + } + + static inline void store(T& dest, T value) + { + _InterlockedExchange((volatile long*)&dest, (long&)value); + } + + static inline T exchange(T& dest, T value) + { + long r = _InterlockedExchange((volatile long*)&dest, (long&)value); + return (T&)r; + } + + static inline T fetch_add(T& dest, T value) + { + long r = _InterlockedExchangeAdd((volatile long*)&dest, (long&)value); + return (T&)r; + } + + static inline T fetch_and(T& dest, T value) + { + long r = _InterlockedAnd((volatile long*)&dest, (long&)value); + return (T&)r; + } + + static inline T fetch_or(T& dest, T value) + { + long r = _InterlockedOr((volatile long*)&dest, (long&)value); + return (T&)r; + } + + static inline T fetch_xor(T& dest, T value) + { + long r = _InterlockedXor((volatile long*)&dest, (long&)value); + return (T&)r; + } + + static inline T inc_fetch(T& dest) + { + long r = _InterlockedIncrement((volatile long*)&dest); + return (T&)r; + } + + static inline T dec_fetch(T& dest) + { + long r = _InterlockedDecrement((volatile long*)&dest); + return (T&)r; + } + + static inline bool bts(T& dest, uint bit) + { + return _interlockedbittestandset((volatile long*)&dest, bit) != 0; + } + + static inline bool btr(T& dest, uint bit) + { + return _interlockedbittestandreset((volatile long*)&dest, bit) != 0; + } +#endif +}; + +template +struct atomic_storage : atomic_storage +{ +#ifdef _MSC_VER + static inline bool compare_exchange(T& dest, T& comp, T exch) + { + llong v = *(llong*)∁ + llong r = _InterlockedCompareExchange64((volatile llong*)&dest, (llong&)exch, v); + comp = (T&)r; + return r == v; + } + + static inline T load(const T& dest) + { + llong value = *(const volatile llong*)&dest; + _ReadWriteBarrier(); + return (T&)value; + } + + static inline void store(T& dest, T value) + { + _InterlockedExchange64((volatile llong*)&dest, (llong&)value); + } + + static inline T exchange(T& dest, T value) + { + llong r = _InterlockedExchange64((volatile llong*)&dest, (llong&)value); + return (T&)r; + } + + static inline T fetch_add(T& dest, T value) + { + llong r = _InterlockedExchangeAdd64((volatile llong*)&dest, (llong&)value); + return (T&)r; + } + + static inline T fetch_and(T& dest, T value) + { + llong r = _InterlockedAnd64((volatile llong*)&dest, (llong&)value); + return (T&)r; + } + + static inline T fetch_or(T& dest, T value) + { + llong r = _InterlockedOr64((volatile llong*)&dest, (llong&)value); + return (T&)r; + } + + static inline T fetch_xor(T& dest, T value) + { + llong r = _InterlockedXor64((volatile llong*)&dest, (llong&)value); + return (T&)r; + } + + static inline T inc_fetch(T& dest) + { + llong r = _InterlockedIncrement64((volatile llong*)&dest); + return (T&)r; + } + + static inline T dec_fetch(T& dest) + { + llong r = _InterlockedDecrement64((volatile llong*)&dest); + return (T&)r; + } + + static inline bool bts(T& dest, uint bit) + { + return _interlockedbittestandset64((volatile llong*)&dest, bit) != 0; + } + + static inline bool btr(T& dest, uint bit) + { + return _interlockedbittestandreset64((volatile llong*)&dest, bit) != 0; + } +#endif +}; + +template +struct atomic_storage : atomic_storage +{ +#ifdef _MSC_VER + static inline bool compare_exchange(T& dest, T& comp, T exch) + { + llong* _exch = (llong*)&exch; + return _InterlockedCompareExchange128((volatile llong*)&dest, _exch[1], _exch[0], (llong*)&comp) != 0; + } + + static inline T load(const T& dest) + { + llong result[2]; + _InterlockedCompareExchange128((volatile llong*)&dest, 0, 0, result); + return *(T*)+result; + } + + static inline void store(T& dest, T value) + { + llong lo = *(llong*)&value; + llong hi = *((llong*)&value + 1); + llong cmp[2]{ *(volatile llong*)&dest, *((volatile llong*)&dest + 1) }; + while (!_InterlockedCompareExchange128((volatile llong*)&dest, hi, lo, cmp)); + } + + static inline T exchange(T& dest, T value) + { + llong lo = *(llong*)&value; + llong hi = *((llong*)&value + 1); + llong cmp[2]{ *(volatile llong*)&dest, *((volatile llong*)&dest + 1) }; + while (!_InterlockedCompareExchange128((volatile llong*)&dest, hi, lo, cmp)); + return *(T*)+cmp; + } +#endif +}; + +template +struct atomic_add +{ + auto operator()(T1& lhs, const T2& rhs) const + { + return lhs += rhs; } }; -// member function specialization -template struct atomic_op_result_t +template +struct atomic_add::value && std::is_convertible::value>> { - RT result; + static constexpr auto fetch_op = &atomic_storage::fetch_add; + static constexpr auto op_fetch = &atomic_storage::add_fetch; + static constexpr auto atomic_op = &atomic_storage::add_fetch; +}; - template atomic_op_result_t(RT(CT::*func)(FArgs...), VT& var, Args&&... args) - : result(std::move((var.*func)(std::forward(args)...))) +template +struct atomic_sub +{ + auto operator()(T1& lhs, const T2& rhs) const { - } - - RT move() - { - return std::move(result); + return lhs -= rhs; } }; -// member function void specialization -template struct atomic_op_result_t +template +struct atomic_sub::value && std::is_convertible::value>> { - VT result; + static constexpr auto fetch_op = &atomic_storage::fetch_sub; + static constexpr auto op_fetch = &atomic_storage::sub_fetch; + static constexpr auto atomic_op = &atomic_storage::sub_fetch; +}; - template atomic_op_result_t(void(CT::*func)(FArgs...), VT& var, Args&&... args) - : result(var) +template +struct atomic_pre_inc +{ + auto operator()(T& v) const { - (var.*func)(std::forward(args)...); + return ++v; + } +}; + +template +struct atomic_pre_inc::value>> +{ + static constexpr auto atomic_op = &atomic_storage::inc_fetch; +}; + +template +struct atomic_post_inc +{ + auto operator()(T& v) const + { + return v++; + } +}; + +template +struct atomic_post_inc::value>> +{ + static constexpr auto atomic_op = &atomic_storage::fetch_inc; +}; + +template +struct atomic_pre_dec +{ + auto operator()(T& v) const + { + return --v; + } +}; + +template +struct atomic_pre_dec::value>> +{ + static constexpr auto atomic_op = &atomic_storage::dec_fetch; +}; + +template +struct atomic_post_dec +{ + auto operator()(T& v) const + { + return v--; + } +}; + +template +struct atomic_post_dec::value>> +{ + static constexpr auto atomic_op = &atomic_storage::fetch_dec; +}; + +template +struct atomic_and +{ + auto operator()(T1& lhs, const T2& rhs) const + { + return lhs &= rhs; + } +}; + +template +struct atomic_and::value && std::is_convertible::value>> +{ + static constexpr auto fetch_op = &atomic_storage::fetch_and; + static constexpr auto op_fetch = &atomic_storage::and_fetch; + static constexpr auto atomic_op = &atomic_storage::and_fetch; +}; + +template +struct atomic_or +{ + auto operator()(T1& lhs, const T2& rhs) const + { + return lhs |= rhs; + } +}; + +template +struct atomic_or::value && std::is_convertible::value>> +{ + static constexpr auto fetch_op = &atomic_storage::fetch_or; + static constexpr auto op_fetch = &atomic_storage::or_fetch; + static constexpr auto atomic_op = &atomic_storage::or_fetch; +}; + +template +struct atomic_xor +{ + auto operator()(T1& lhs, const T2& rhs) const + { + return lhs ^= rhs; + } +}; + +template +struct atomic_xor::value && std::is_convertible::value>> +{ + static constexpr auto fetch_op = &atomic_storage::fetch_xor; + static constexpr auto op_fetch = &atomic_storage::xor_fetch; + static constexpr auto atomic_op = &atomic_storage::xor_fetch; +}; + +template +struct atomic_test_and_set +{ + bool operator()(T1& lhs, const T2& rhs) const + { + return lhs.test_and_set(rhs); + } +}; + +template +struct atomic_test_and_set::value && std::is_convertible::value>> +{ + static inline bool op(T1& lhs, const T2& rhs) + { + return (atomic_storage::fetch_or(lhs, rhs) & rhs) != 0; } - VT move() + static constexpr auto fetch_op = &op; + static constexpr auto op_fetch = &op; + static constexpr auto atomic_op = &op; +}; + +template +struct atomic_test_and_reset +{ + bool operator()(T1& lhs, const T2& rhs) const { - return std::move(result); + return lhs.test_and_reset(rhs); } }; +template +struct atomic_test_and_reset::value && std::is_convertible::value>> +{ + static inline bool op(T1& lhs, const T2& rhs) + { + return (atomic_storage::fetch_and(lhs, ~rhs) & rhs) != 0; + } + + static constexpr auto fetch_op = &op; + static constexpr auto op_fetch = &op; + static constexpr auto atomic_op = &op; +}; + +template +struct atomic_test_and_complement +{ + bool operator()(T1& lhs, const T2& rhs) const + { + return lhs.test_and_complement(rhs); + } +}; + +template +struct atomic_test_and_complement::value && std::is_convertible::value>> +{ + static inline bool op(T1& lhs, const T2& rhs) + { + return (atomic_storage::fetch_xor(lhs, rhs) & rhs) != 0; + } + + static constexpr auto fetch_op = &op; + static constexpr auto op_fetch = &op; + static constexpr auto atomic_op = &op; +}; + // Atomic type with lock-free and standard layout guarantees (and appropriate limitations) -template class atomic_t +template +class atomic_t { - using type = std::remove_cv_t; - using stype = atomic_storage_t; - using storage = atomic_storage; + using type = typename std::remove_cv::type; - static_assert(alignof(type) <= alignof(stype), "atomic_t<> error: unexpected alignment"); + static_assert(alignof(type) == sizeof(type), "atomic_t<> error: unexpected alignment, use alignas() if necessary"); - stype m_data; - - template static inline void write_relaxed(volatile T2& data, const T2& value) - { - data = value; - } - - static inline void write_relaxed(volatile u128& data, const u128& value) - { - sync_lock_test_and_set(&data, value); - } - - template static inline T2 read_relaxed(const volatile T2& data) - { - return data; - } - - static inline u128 read_relaxed(const volatile u128& value) - { - return sync_val_compare_and_swap(const_cast(&value), u128{0}, u128{0}); - } + type m_data; public: - static inline const stype to_subtype(const type& value) - { - return reinterpret_cast(value); - } - - static inline const type from_subtype(const stype value) - { - return reinterpret_cast(value); - } - atomic_t() = default; atomic_t(const atomic_t&) = delete; - atomic_t(type value) - : m_data(to_subtype(value)) - { - } - atomic_t& operator =(const atomic_t&) = delete; - atomic_t& operator =(type value) - { - return write_relaxed(m_data, to_subtype(value)), *this; - } + // Define simple type + using simple_type = simple_t; - operator type() const volatile + explicit constexpr atomic_t(const type& value) + : m_data(value) { - return from_subtype(read_relaxed(m_data)); - } - - // Unsafe direct access - stype* raw_data() - { - return reinterpret_cast(&m_data); } // Unsafe direct access type& raw() { - return reinterpret_cast(m_data); + return m_data; } // Atomically compare data with cmp, replace with exch if equal, return previous data value anyway - type compare_and_swap(const type& cmp, const type& exch) volatile + simple_type compare_and_swap(const type& cmp, const type& exch) { - return from_subtype(sync_val_compare_and_swap(&m_data, to_subtype(cmp), to_subtype(exch))); + type old = cmp; + atomic_storage::compare_exchange(m_data, old, exch); + return old; } // Atomically compare data with cmp, replace with exch if equal, return true if data was replaced - bool compare_and_swap_test(const type& cmp, const type& exch) volatile + bool compare_and_swap_test(const type& cmp, const type& exch) { - return sync_bool_compare_and_swap(&m_data, to_subtype(cmp), to_subtype(exch)); + type old = cmp; + return atomic_storage::compare_exchange(m_data, old, exch); } - // Atomically replace data with exch, return previous data value - type exchange(const type& exch) volatile + // Atomic operation; returns old value, discards function result value + template> + type fetch_op(F&& func, const Args&... args) { - return from_subtype(sync_lock_test_and_set(&m_data, to_subtype(exch))); - } + type _new, old = atomic_storage::load(m_data); - // Atomically read data, possibly without memory barrier (not for 128 bit) - type load() const volatile - { - return from_subtype(read_relaxed(m_data)); - } - - // Atomically write data, possibly without memory barrier (not for 128 bit) - void store(const type& value) volatile - { - write_relaxed(m_data, to_subtype(value)); - } - - // Perform an atomic operation on data (func is either pointer to member function or callable object with a T& first arg); - // Returns the result of the callable object call or previous (old) value of the atomic variable if the return type is void - template> auto atomic_op(F func, Args&&... args) volatile -> decltype(atomic_op_result_t::result) - { while (true) { - // Read the old value from memory - const stype old = read_relaxed(m_data); + func(_new = old, args...); - // Copy the old value - stype _new = old; - - // Call atomic op for the local copy of the old value and save the return value of the function - atomic_op_result_t result(func, reinterpret_cast(_new), args...); - - // Atomically compare value with `old`, replace with `_new` and return on success - if (sync_bool_compare_and_swap(&m_data, old, _new)) return result.move(); + if (atomic_storage::compare_exchange(m_data, old, _new)) return old; } } - // Atomic bitwise OR, returns previous data - type _or(const type& right) volatile + // Helper overload for calling optimized implementation + template> + type fetch_op(F&&, const Args&... args) { - return from_subtype(sync_fetch_and_or(&m_data, to_subtype(right))); + return F::fetch_op(m_data, args...); } - // Atomic bitwise AND, returns previous data - type _and(const type& right) volatile + // Atomic operation; returns new value, discards function result value + template> + type op_fetch(F&& func, const Args&... args) { - return from_subtype(sync_fetch_and_and(&m_data, to_subtype(right))); + type _new, old = atomic_storage::load(m_data); + + while (true) + { + func(_new = old, args...); + + if (atomic_storage::compare_exchange(m_data, old, _new)) return _new; + } } - // Atomic bitwise AND NOT (inverts right argument), returns previous data - type _and_not(const type& right) volatile + // Helper overload for calling optimized implementation + template> + type op_fetch(F&&, const Args&... args) { - return from_subtype(sync_fetch_and_and(&m_data, ~to_subtype(right))); + return F::op_fetch(m_data, args...); } - // Atomic bitwise XOR, returns previous data - type _xor(const type& right) volatile + // Atomic operation; returns function result value + template, typename = std::enable_if_t::value>> + RT atomic_op(F&& func, const Args&... args) { - return from_subtype(sync_fetch_and_xor(&m_data, to_subtype(right))); + type _new, old = atomic_storage::load(m_data); + + while (true) + { + RT&& result = func(_new = old, args...); + + if (atomic_storage::compare_exchange(m_data, old, _new)) return std::move(result); + } } - type operator |=(const type& right) volatile + // Overload for void return type + template, typename = std::enable_if_t::value>> + void atomic_op(F&& func, const Args&... args) { - return from_subtype(sync_fetch_and_or(&m_data, to_subtype(right)) | to_subtype(right)); + type _new, old = atomic_storage::load(m_data); + + while (true) + { + func(_new = old, args...); + + if (atomic_storage::compare_exchange(m_data, old, _new)) return; + } } - type operator &=(const type& right) volatile + // Helper overload for calling optimized implementation + template> + auto atomic_op(F&&, const Args&... args) { - return from_subtype(sync_fetch_and_and(&m_data, to_subtype(right)) & to_subtype(right)); + return F::atomic_op(m_data, args...); } - type operator ^=(const type& right) volatile + // Atomically read data + type load() const { - return from_subtype(sync_fetch_and_xor(&m_data, to_subtype(right)) ^ to_subtype(right)); + return atomic_storage::load(m_data); + } + + // Atomically read data + operator simple_type() const + { + return atomic_storage::load(m_data); + } + + // Atomically write data + void store(const type& rhs) + { + atomic_storage::store(m_data, rhs); + } + + type operator =(const type& rhs) + { + atomic_storage::store(m_data, rhs); + return rhs; + } + + // Atomically replace data with value, return previous data value + type exchange(const type& rhs) + { + return atomic_storage::exchange(m_data, rhs); + } + + template + type fetch_add(const T2& rhs) + { + return fetch_op(atomic_add{}, rhs); + } + + template + type add_fetch(const T2& rhs) + { + return op_fetch(atomic_add{}, rhs); + } + + template + auto operator +=(const T2& rhs) + { + return atomic_op(atomic_add{}, rhs); + } + + template + type fetch_sub(const T2& rhs) + { + return fetch_op(atomic_sub{}, rhs); + } + + template + type sub_fetch(const T2& rhs) + { + return op_fetch(atomic_sub{}, rhs); + } + + template + auto operator -=(const T2& rhs) + { + return atomic_op(atomic_sub{}, rhs); + } + + template + type fetch_and(const T2& rhs) + { + return fetch_op(atomic_and{}, rhs); + } + + template + type and_fetch(const T2& rhs) + { + return op_fetch(atomic_and{}, rhs); + } + + template + auto operator &=(const T2& rhs) + { + return atomic_op(atomic_and{}, rhs); + } + + template + type fetch_or(const T2& rhs) + { + return fetch_op(atomic_or{}, rhs); + } + + template + type or_fetch(const T2& rhs) + { + return op_fetch(atomic_or{}, rhs); + } + + template + auto operator |=(const T2& rhs) + { + return atomic_op(atomic_or{}, rhs); + } + + template + type fetch_xor(const T2& rhs) + { + return fetch_op(atomic_xor{}, rhs); + } + + template + type xor_fetch(const T2& rhs) + { + return op_fetch(atomic_xor{}, rhs); + } + + template + auto operator ^=(const T2& rhs) + { + return atomic_op(atomic_xor{}, rhs); + } + + auto operator ++() + { + return atomic_op(atomic_pre_inc{}); + } + + auto operator --() + { + return atomic_op(atomic_pre_dec{}); + } + + auto operator ++(int) + { + return atomic_op(atomic_post_inc{}); + } + + auto operator --(int) + { + return atomic_op(atomic_post_dec{}); + } + + template + auto test(const T2& rhs) const + { + return load().test(rhs); + } + + template + auto test_and_set(const T2& rhs) + { + return atomic_op(atomic_test_and_set{}, rhs); + } + + template + auto test_and_reset(const T2& rhs) + { + return atomic_op(atomic_test_and_reset{}, rhs); + } + + template + auto test_and_complement(const T2& rhs) + { + return atomic_op(atomic_test_and_complement{}, rhs); } }; - -template inline std::enable_if_t operator ++(atomic_t& left) -{ - return left.from_subtype(sync_fetch_and_add(left.raw_data(), 1) + 1); -} - -template inline std::enable_if_t operator --(atomic_t& left) -{ - return left.from_subtype(sync_fetch_and_sub(left.raw_data(), 1) - 1); -} - -template inline std::enable_if_t operator ++(atomic_t& left, int) -{ - return left.from_subtype(sync_fetch_and_add(left.raw_data(), 1)); -} - -template inline std::enable_if_t operator --(atomic_t& left, int) -{ - return left.from_subtype(sync_fetch_and_sub(left.raw_data(), 1)); -} - -template inline std::enable_if_t::value, T> operator +=(atomic_t& left, const T2& right) -{ - return left.from_subtype(sync_fetch_and_add(left.raw_data(), right) + right); -} - -template inline std::enable_if_t::value, T> operator -=(atomic_t& left, const T2& right) -{ - return left.from_subtype(sync_fetch_and_sub(left.raw_data(), right) - right); -} - -template inline std::enable_if_t> operator ++(atomic_t>& left) -{ - return left.from_subtype(sync_fetch_and_add(left.raw_data(), 1) + 1); -} - -template inline std::enable_if_t> operator --(atomic_t>& left) -{ - return left.from_subtype(sync_fetch_and_sub(left.raw_data(), 1) - 1); -} - -template inline std::enable_if_t> operator ++(atomic_t>& left, int) -{ - return left.from_subtype(sync_fetch_and_add(left.raw_data(), 1)); -} - -template inline std::enable_if_t> operator --(atomic_t>& left, int) -{ - return left.from_subtype(sync_fetch_and_sub(left.raw_data(), 1)); -} - -template inline std::enable_if_t::value, nse_t> operator +=(atomic_t>& left, const T2& right) -{ - return left.from_subtype(sync_fetch_and_add(left.raw_data(), right) + right); -} - -template inline std::enable_if_t::value, nse_t> operator -=(atomic_t>& left, const T2& right) -{ - return left.from_subtype(sync_fetch_and_sub(left.raw_data(), right) - right); -} - -template inline std::enable_if_t> operator ++(atomic_t>& left) -{ - return left.atomic_op([](se_t& value) -> se_t - { - return ++value; - }); -} - -template inline std::enable_if_t> operator --(atomic_t>& left) -{ - return left.atomic_op([](se_t& value) -> se_t - { - return --value; - }); -} - -template inline std::enable_if_t> operator ++(atomic_t>& left, int) -{ - return left.atomic_op([](se_t& value) -> se_t - { - return value++; - }); -} - -template inline std::enable_if_t> operator --(atomic_t>& left, int) -{ - return left.atomic_op([](se_t& value) -> se_t - { - return value--; - }); -} - -template inline std::enable_if_t::value, se_t> operator +=(atomic_t>& left, const T2& right) -{ - return left.atomic_op([&](se_t& value) -> se_t - { - return value += right; - }); -} - -template inline std::enable_if_t::value, se_t> operator -=(atomic_t>& left, const T2& right) -{ - return left.atomic_op([&](se_t& value) -> se_t - { - return value -= right; - }); -} - -// Atomic BE Type (for PS3 virtual memory) -template using atomic_be_t = atomic_t>; - -// Atomic LE Type (for PSV virtual memory) -template using atomic_le_t = atomic_t>; - -// Algorithm for std::atomic; similar to atomic_t::atomic_op() -template> auto atomic_op(std::atomic& var, F func, Args&&... args) -> decltype(atomic_op_result_t::result) -{ - auto old = var.load(); - - while (true) - { - auto _new = old; - - atomic_op_result_t result(func, _new, args...); - - if (var.compare_exchange_strong(old, _new)) return result.move(); - } -} diff --git a/Utilities/AutoPause.cpp b/Utilities/AutoPause.cpp index 35608d3300..5fc5125975 100644 --- a/Utilities/AutoPause.cpp +++ b/Utilities/AutoPause.cpp @@ -1,57 +1,29 @@ #include "stdafx.h" -#include "AutoPause.h" -#include "Utilities/Log.h" -#include "Utilities/File.h" +#include "Config.h" #include "Emu/System.h" -#include "Emu/state.h" +#include "AutoPause.h" -using namespace Debug; +cfg::bool_entry g_cfg_debug_autopause_syscall(cfg::root.misc, "Auto Pause at System Call"); +cfg::bool_entry g_cfg_debug_autopause_func_call(cfg::root.misc, "Auto Pause at Function Call"); -std::unique_ptr g_autopause; - -AutoPause& AutoPause::getInstance(void) +debug::autopause& debug::autopause::get_instance() { - if (!g_autopause) + // Use magic static + static autopause instance; + return instance; +} + +// Load Auto Pause Configuration from file "pause.bin" +void debug::autopause::reload(void) +{ + auto& instance = get_instance(); + + instance.m_pause_function.clear(); + instance.m_pause_syscall.clear(); + + // TODO: better format, possibly a config entry + if (fs::file list{ fs::get_config_dir() + "pause.bin" }) { - g_autopause.reset(new AutoPause); - } - - return *g_autopause; -} - -//Still use binary format. Default Setting should be "disable all auto pause". -AutoPause::AutoPause(void) -{ - m_pause_function.reserve(16); - m_pause_syscall.reserve(16); - initialized = false; - //Reload(false, false); - Reload(); -} - -//Notice: I would not allow to write the binary to file in this command. -AutoPause::~AutoPause(void) -{ - initialized = false; - m_pause_function.clear(); - m_pause_syscall.clear(); - m_pause_function_enable = false; - m_pause_syscall_enable = false; -} - -//Load Auto Pause Configuration from file "pause.bin" -//This would be able to create in a GUI window. -void AutoPause::Reload(void) -{ - if (fs::is_file(fs::get_config_dir() + "pause.bin")) - { - m_pause_function.clear(); - m_pause_function.reserve(16); - m_pause_syscall.clear(); - m_pause_syscall.reserve(16); - - fs::file list(fs::get_config_dir() + "pause.bin"); - //System calls ID and Function calls ID are all u32 iirc. u32 num; size_t fmax = list.size(); size_t fcur = 0; @@ -64,60 +36,38 @@ void AutoPause::Reload(void) if (num < 1024) { - //Less than 1024 - be regarded as a system call. - //emplace_back may not cause reductant move/copy operation. - m_pause_syscall.emplace_back(num); - LOG_WARNING(HLE, "Auto Pause: Find System Call ID 0x%x", num); + instance.m_pause_syscall.emplace(num); + LOG_WARNING(HLE, "Set autopause at syscall %lld", num); } else { - m_pause_function.emplace_back(num); - LOG_WARNING(HLE, "Auto Pause: Find Function Call ID 0x%x", num); + instance.m_pause_function.emplace(num); + LOG_WARNING(HLE, "Set autopause at function 0x%08x", num); } } } - - m_pause_syscall_enable = rpcs3::config.misc.debug.auto_pause_syscall.value(); - m_pause_function_enable = rpcs3::config.misc.debug.auto_pause_func_call.value(); - initialized = true; } -void AutoPause::TryPause(u32 code) +bool debug::autopause::pause_syscall(u64 code) { - if (code < 1024) + if (g_cfg_debug_autopause_syscall && get_instance().m_pause_syscall.count(code) != 0) { - //Would first check Enable setting. Then the list length. - if ((!m_pause_syscall_enable) - || (m_pause_syscall.size() <= 0)) - { - return; - } - - for (u32 i = 0; i < m_pause_syscall.size(); ++i) - { - if (code == m_pause_syscall[i]) - { - Emu.Pause(); - LOG_ERROR(HLE, "Auto Pause Triggered: System call 0x%x", code); // Used Error - } - } + Emu.Pause(); + LOG_SUCCESS(HLE, "Autopause triggered at syscall %lld", code); + return true; } - else - { - //Well similiar.. Seperate the list caused by possible setting difference. - if ((!m_pause_function_enable) - || (m_pause_function.size() <= 0)) - { - return; - } - for (u32 i = 0; i < m_pause_function.size(); ++i) - { - if (code == m_pause_function[i]) - { - Emu.Pause(); - LOG_ERROR(HLE, "Auto Pause Triggered: Function call 0x%x", code); // Used Error - } - } - } + return false; +} + +bool debug::autopause::pause_function(u32 code) +{ + if (g_cfg_debug_autopause_func_call && get_instance().m_pause_function.count(code) != 0) + { + Emu.Pause(); + LOG_SUCCESS(HLE, "Autopause triggered at function 0x%08x", code); + return true; + } + + return false; } diff --git a/Utilities/AutoPause.h b/Utilities/AutoPause.h index cf871b46cb..13a2f0c133 100644 --- a/Utilities/AutoPause.h +++ b/Utilities/AutoPause.h @@ -1,24 +1,20 @@ #pragma once -//Regarded as a Debugger Enchantment -namespace Debug { - //To store the pause function/call id, and let those pause there. - //Would be with a GUI to configure those. - struct AutoPause +// Regarded as a Debugger Enchantment +namespace debug +{ + // To store the pause function/call id, and let those pause there. + // Would be with a GUI to configure those. + class autopause { - std::vector m_pause_syscall; - std::vector m_pause_function; - bool initialized; - bool m_pause_syscall_enable; - bool m_pause_function_enable; + std::unordered_set m_pause_syscall; + std::unordered_set m_pause_function; - AutoPause(); - ~AutoPause(); + static autopause& get_instance(); public: - static AutoPause& getInstance(void); - void Reload(void); - - void TryPause(u32 code); + static void reload(); + static bool pause_syscall(u64 code); + static bool pause_function(u32 code); }; -} \ No newline at end of file +} diff --git a/Utilities/BEType.h b/Utilities/BEType.h index 80c8256a2f..d5b51b99c7 100644 --- a/Utilities/BEType.h +++ b/Utilities/BEType.h @@ -1,16 +1,14 @@ #pragma once -#ifdef _MSC_VER -#include -#else -#include -#endif +#include "types.h" +#include "Platform.h" -#define IS_LE_MACHINE // only draft - -union v128 +union alignas(16) v128 { - template class masked_array_t // array type accessed as (index ^ M) + char _bytes[16]; + + template + struct masked_array_t // array type accessed as (index ^ M) { T m_data[N]; @@ -24,24 +22,11 @@ union v128 { 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 +#if IS_LE_MACHINE == 1 template using normal_array_t = masked_array_t; template using reversed_array_t = masked_array_t; -#else - template using normal_array_t = masked_array_t; - template using reversed_array_t = masked_array_t; #endif normal_array_t _u64; @@ -73,7 +58,7 @@ union v128 __m128i vi; __m128d vd; - class bit_array_128 + struct bit_array_128 { u64 m_data[2]; @@ -125,36 +110,18 @@ union v128 // Index 0 returns the MSB and index 127 returns the LSB bit_element operator [](u32 index) { -#ifdef IS_LE_MACHINE +#if IS_LE_MACHINE == 1 return bit_element(m_data[1 - (index >> 6)], 0x8000000000000000ull >> (index & 0x3F)); -#else - return bit_element(m_data[index >> 6], 0x8000000000000000ull >> (index & 0x3F)); #endif } // Index 0 returns the MSB and index 127 returns the LSB bool operator [](u32 index) const { -#ifdef IS_LE_MACHINE +#if IS_LE_MACHINE == 1 return (m_data[1 - (index >> 6)] & (0x8000000000000000ull >> (index & 0x3F))) != 0; -#else - return (m_data[index >> 6] & (0x8000000000000000ull >> (index & 0x3F))) != 0; #endif } - - bit_element at(u32 index) - { - 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(__FUNCTION__); - - return operator[](index); - } } _bit; @@ -320,16 +287,6 @@ union v128 return _u64[0] != right._u64[0] || _u64[1] != right._u64[1]; } - bool is_any_1() const // check if any bit is 1 - { - return _u64[0] || _u64[1]; - } - - bool is_any_0() const // check if any bit is 0 - { - return ~_u64[0] || ~_u64[1]; - } - // result = (~left) & (right) static inline v128 andnot(const v128& left, const v128& right) { @@ -345,15 +302,8 @@ union v128 std::string to_hex() const; std::string to_xyzw() const; - - static inline v128 byteswap(const v128 val) - { - return fromV(_mm_shuffle_epi8(val.vi, _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15))); - } }; -CHECK_SIZE_ALIGN(v128, 16, 16); - inline v128 operator |(const v128& left, const v128& right) { return v128::fromV(_mm_or_si128(left.vi, right.vi)); @@ -374,21 +324,21 @@ inline v128 operator ~(const v128& other) return v128::from64(~other._u64[0], ~other._u64[1]); } -template struct se_storage +#define IS_INTEGER(t) (std::is_integral::value || std::is_enum::value) +#define IS_BINARY_COMPARABLE(t1, t2) (IS_INTEGER(t1) && IS_INTEGER(t2) && sizeof(t1) == sizeof(t2)) + +template +struct se_storage { static_assert(!Size, "Bad se_storage<> type"); }; -template struct se_storage +template +struct se_storage { using type = u16; - [[deprecated]] static constexpr u16 _swap(u16 src) // for reference - { - return (src >> 8) | (src << 8); - } - - static inline u16 swap(u16 src) + static constexpr u16 swap(u16 src) { #if defined(__GNUG__) return __builtin_bswap16(src); @@ -409,16 +359,12 @@ template struct se_storage } }; -template struct se_storage +template +struct se_storage { using type = u32; - [[deprecated]] static constexpr u32 _swap(u32 src) // for reference - { - return (src >> 24) | (src << 24) | ((src >> 8) & 0x0000ff00) | ((src << 8) & 0x00ff0000); - } - - static inline u32 swap(u32 src) + static constexpr u32 swap(u32 src) { #if defined(__GNUG__) return __builtin_bswap32(src); @@ -439,22 +385,12 @@ template struct se_storage } }; -template struct se_storage +template +struct se_storage { using type = u64; - [[deprecated]] static constexpr u64 _swap(u64 src) // for reference - { - return (src >> 56) | (src << 56) | - ((src >> 40) & 0x000000000000ff00) | - ((src >> 24) & 0x0000000000ff0000) | - ((src >> 8) & 0x00000000ff000000) | - ((src << 8) & 0x000000ff00000000) | - ((src << 24) & 0x0000ff0000000000) | - ((src << 40) & 0x00ff000000000000); - } - - static inline u64 swap(u64 src) + static constexpr u64 swap(u64 src) { #if defined(__GNUG__) return __builtin_bswap64(src); @@ -475,25 +411,32 @@ template struct se_storage } }; -template struct se_storage +template +struct se_storage { using type = v128; + static inline v128 swap(const v128& src) + { + return v128::fromV(_mm_shuffle_epi8(src.vi, _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15))); + } + static inline v128 to(const T& src) { - return v128::byteswap(reinterpret_cast(src)); + return swap(reinterpret_cast(src)); } static inline T from(const v128& src) { - const v128 result = v128::byteswap(src); + const v128 result = swap(src); return reinterpret_cast(result); } }; template using se_storage_t = typename se_storage::type; -template struct se_convert +template +struct se_convert { using type_from = std::remove_cv_t; using type_to = std::remove_cv_t; @@ -515,10 +458,12 @@ template struct se_convert static struct se_raw_tag_t {} constexpr se_raw{}; -template class se_t; +template +class se_t; -// se_t with switched endianness -template class se_t +// Switched endianness +template +class se_t { using type = typename std::remove_cv::type; using stype = se_storage_t; @@ -526,14 +471,13 @@ template class se_t stype m_data; - static_assert(!std::is_union::value && !std::is_class::value || std::is_same::value || std::is_same::value, "se_t<> error: invalid type (struct or union)"); static_assert(!std::is_pointer::value, "se_t<> error: invalid type (pointer)"); static_assert(!std::is_reference::value, "se_t<> error: invalid type (reference)"); static_assert(!std::is_array::value, "se_t<> error: invalid type (array)"); - //static_assert(!std::is_enum::value, "se_t<> error: invalid type (enumeration), use integral type instead"); - static_assert(alignof(type) == alignof(stype), "se_t<> error: unexpected alignment"); + static_assert(sizeof(type) == alignof(type), "se_t<> error: unexpected alignment"); - template struct bool_converter + template + struct bool_converter { static inline bool to_bool(const se_t& value) { @@ -541,7 +485,8 @@ template class se_t } }; - template struct bool_converter::value>> + template + struct bool_converter::value>> { static inline bool to_bool(const se_t& value) { @@ -559,7 +504,7 @@ public: { } - // construct directly from raw data (don't use) + // Construct directly from raw data (don't use) constexpr se_t(const stype& raw_value, const se_raw_tag_t&) : m_data(raw_value) { @@ -570,7 +515,7 @@ public: return storage::from(m_data); } - // access underlying raw data (don't use) + // Access underlying raw data (don't use) constexpr const stype& raw_data() const noexcept { return m_data; @@ -583,78 +528,96 @@ public: return m_data = storage::to(value), *this; } + using simple_type = simple_t; + operator type() const { return storage::from(m_data); } - // optimization + // Optimization explicit operator bool() const { return bool_converter::to_bool(*this); } - // optimization - template std::enable_if_t operator &=(const se_t& right) + // Optimization + template + std::enable_if_t operator &=(const se_t& right) { return m_data &= right.raw_data(), *this; } - // optimization - template std::enable_if_t::value, se_t&> operator &=(CT right) + // Optimization + template + std::enable_if_t::value && std::is_convertible::value, se_t&> operator &=(CT right) { return m_data &= storage::to(right), *this; } - // optimization - template std::enable_if_t operator |=(const se_t& right) + // Optimization + template + std::enable_if_t operator |=(const se_t& right) { return m_data |= right.raw_data(), *this; } - // optimization - template std::enable_if_t::value, se_t&> operator |=(CT right) + // Optimization + template + std::enable_if_t::value && std::is_convertible::value, se_t&> operator |=(CT right) { return m_data |= storage::to(right), *this; } - // optimization - template std::enable_if_t operator ^=(const se_t& right) + // Optimization + template + std::enable_if_t operator ^=(const se_t& right) { return m_data ^= right.raw_data(), *this; } - // optimization - template std::enable_if_t::value, se_t&> operator ^=(CT right) + // Optimization + template + std::enable_if_t::value && std::is_convertible::value, se_t&> operator ^=(CT right) { return m_data ^= storage::to(right), *this; } }; -// se_t with native endianness -template class se_t +// Native endianness +template +class se_t { using type = typename std::remove_cv::type; - type m_data; - - static_assert(!std::is_union::value && !std::is_class::value || std::is_same::value || std::is_same::value, "se_t<> error: invalid type (struct or union)"); static_assert(!std::is_pointer::value, "se_t<> error: invalid type (pointer)"); static_assert(!std::is_reference::value, "se_t<> error: invalid type (reference)"); static_assert(!std::is_array::value, "se_t<> error: invalid type (array)"); - //static_assert(!std::is_enum::value, "se_t<> error: invalid type (enumeration), use integral type instead"); + static_assert(sizeof(type) == alignof(type), "se_t<> error: unexpected alignment"); + + type m_data; public: se_t() = default; - se_t(const se_t&) = default; - constexpr se_t(type value) : m_data(value) { } - type value() const + // Construct directly from raw data (don't use) + constexpr se_t(const type& raw_value, const se_raw_tag_t&) + : m_data(raw_value) + { + } + + constexpr type value() const + { + return m_data; + } + + // Access underlying raw data (don't use) + constexpr const type& raw_data() const noexcept { return m_data; } @@ -666,22 +629,27 @@ public: return m_data = value, *this; } - operator type() const + using simple_type = simple_t; + + constexpr operator type() const { return m_data; } - template std::enable_if_t::value, se_t&> operator &=(const CT& right) + template + std::enable_if_t::value && std::is_convertible::value, se_t&> operator &=(const CT& right) { return m_data &= right, *this; } - template std::enable_if_t::value, se_t&> operator |=(const CT& right) + template + std::enable_if_t::value && std::is_convertible::value, se_t&> operator |=(const CT& right) { return m_data |= right, *this; } - template std::enable_if_t::value, se_t&> operator ^=(const CT& right) + template + std::enable_if_t::value && std::is_convertible::value, se_t&> operator ^=(const CT& right) { return m_data ^= right, *this; } @@ -690,49 +658,57 @@ public: // se_t with native endianness (alias) template using nse_t = se_t; -template inline se_t& operator +=(se_t& left, const T1& right) +template +inline se_t& operator +=(se_t& left, const T1& right) { auto value = left.value(); return left = (value += right); } -template inline se_t& operator -=(se_t& left, const T1& right) +template +inline se_t& operator -=(se_t& left, const T1& right) { auto value = left.value(); return left = (value -= right); } -template inline se_t& operator *=(se_t& left, const T1& right) +template +inline se_t& operator *=(se_t& left, const T1& right) { auto value = left.value(); return left = (value *= right); } -template inline se_t& operator /=(se_t& left, const T1& right) +template +inline se_t& operator /=(se_t& left, const T1& right) { auto value = left.value(); return left = (value /= right); } -template inline se_t& operator %=(se_t& left, const T1& right) +template +inline se_t& operator %=(se_t& left, const T1& right) { auto value = left.value(); return left = (value %= right); } -template inline se_t& operator <<=(se_t& left, const T1& right) +template +inline se_t& operator <<=(se_t& left, const T1& right) { auto value = left.value(); return left = (value <<= right); } -template inline se_t& operator >>=(se_t& left, const T1& right) +template +inline se_t& operator >>=(se_t& left, const T1& right) { auto value = left.value(); return left = (value >>= right); } -template inline se_t operator ++(se_t& left, int) +template +inline se_t operator ++(se_t& left, int) { auto value = left.value(); auto result = value++; @@ -740,7 +716,8 @@ template inline se_t operator ++(se_t& left, return result; } -template inline se_t operator --(se_t& left, int) +template +inline se_t operator --(se_t& left, int) { auto value = left.value(); auto result = value--; @@ -748,193 +725,205 @@ template inline se_t operator --(se_t& left, return result; } -template inline se_t& operator ++(se_t& right) +template +inline se_t& operator ++(se_t& right) { auto value = right.value(); return right = ++value; } -template inline se_t& operator --(se_t& right) +template +inline se_t& operator --(se_t& right) { auto value = right.value(); return right = --value; } -// optimization -template inline std::enable_if_t operator ==(const se_t& left, const se_t& right) +// Optimization +template +inline std::enable_if_t operator ==(const se_t& left, const se_t& right) { return left.raw_data() == right.raw_data(); } -// optimization -template inline std::enable_if_t= sizeof(T2), bool> operator ==(const se_t& left, T2 right) +// Optimization +template +inline std::enable_if_t::value && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2), bool> operator ==(const se_t& left, T2 right) { return left.raw_data() == se_storage::to(right); } -// optimization -template inline std::enable_if_t operator ==(T1 left, const se_t& right) +// Optimization +template +inline std::enable_if_t::value && sizeof(T1) <= sizeof(T2), bool> operator ==(T1 left, const se_t& right) { return se_storage::to(left) == right.raw_data(); } -// optimization -template inline std::enable_if_t operator !=(const se_t& left, const se_t& right) +// Optimization +template +inline std::enable_if_t operator !=(const se_t& left, const se_t& right) { return left.raw_data() != right.raw_data(); } -// optimization -template inline std::enable_if_t= sizeof(T2), bool> operator !=(const se_t& left, T2 right) +// Optimization +template +inline std::enable_if_t::value && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2), bool> operator !=(const se_t& left, T2 right) { return left.raw_data() != se_storage::to(right); } -// optimization -template inline std::enable_if_t operator !=(T1 left, const se_t& right) +// Optimization +template +inline std::enable_if_t::value && sizeof(T1) <= sizeof(T2), bool> operator !=(T1 left, const se_t& right) { return se_storage::to(left) != right.raw_data(); } -// optimization -template inline std::enable_if_t= 4, se_t> operator &(const se_t& left, const se_t& right) +// Optimization +template +inline std::enable_if_t= 4, se_t> operator &(const se_t& left, const se_t& right) { return{ left.raw_data() & right.raw_data(), se_raw }; } -// optimization -template inline std::enable_if_t= sizeof(T2) && sizeof(T1) >= 4, se_t> operator &(const se_t& left, T2 right) +// Optimization +template +inline std::enable_if_t::value && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2) && sizeof(T1) >= 4, se_t> operator &(const se_t& left, T2 right) { return{ left.raw_data() & se_storage::to(right), se_raw }; } -// optimization -template inline std::enable_if_t= 4, se_t> operator &(T1 left, const se_t& right) +// Optimization +template +inline std::enable_if_t::value && sizeof(T1) <= sizeof(T2) && sizeof(T2) >= 4, se_t> operator &(T1 left, const se_t& right) { return{ se_storage::to(left) & right.raw_data(), se_raw }; } -// optimization -template inline std::enable_if_t= 4, se_t> operator |(const se_t& left, const se_t& right) +// Optimization +template +inline std::enable_if_t= 4, se_t> operator |(const se_t& left, const se_t& right) { return{ left.raw_data() | right.raw_data(), se_raw }; } -// optimization -template inline std::enable_if_t= sizeof(T2) && sizeof(T1) >= 4, se_t> operator |(const se_t& left, T2 right) +// Optimization +template +inline std::enable_if_t::value && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2) && sizeof(T1) >= 4, se_t> operator |(const se_t& left, T2 right) { return{ left.raw_data() | se_storage::to(right), se_raw }; } -// optimization -template inline std::enable_if_t= 4, se_t> operator |(T1 left, const se_t& right) +// Optimization +template +inline std::enable_if_t::value && sizeof(T1) <= sizeof(T2) && sizeof(T2) >= 4, se_t> operator |(T1 left, const se_t& right) { return{ se_storage::to(left) | right.raw_data(), se_raw }; } -// optimization -template inline std::enable_if_t= 4, se_t> operator ^(const se_t& left, const se_t& right) +// Optimization +template +inline std::enable_if_t= 4, se_t> operator ^(const se_t& left, const se_t& right) { return{ left.raw_data() ^ right.raw_data(), se_raw }; } -// optimization -template inline std::enable_if_t= sizeof(T2) && sizeof(T1) >= 4, se_t> operator ^(const se_t& left, T2 right) +// Optimization +template +inline std::enable_if_t::value && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2) && sizeof(T1) >= 4, se_t> operator ^(const se_t& left, T2 right) { return{ left.raw_data() ^ se_storage::to(right), se_raw }; } -// optimization -template inline std::enable_if_t= 4, se_t> operator ^(T1 left, const se_t& right) +// Optimization +template +inline std::enable_if_t::value && sizeof(T1) <= sizeof(T2) && sizeof(T2) >= 4, se_t> operator ^(T1 left, const se_t& right) { return{ se_storage::to(left) ^ right.raw_data(), se_raw }; } -// optimization -template inline std::enable_if_t= 4, se_t> operator ~(const se_t& right) +// Optimization +template +inline std::enable_if_t::value && sizeof(T) >= 4, se_t> operator ~(const se_t& right) { return{ ~right.raw_data(), se_raw }; } -#ifdef IS_LE_MACHINE +#if IS_LE_MACHINE == 1 template using be_t = se_t; template using le_t = se_t; -#else -template using be_t = se_t; -template using le_t = se_t; #endif - -template struct to_se +// Type converter: converts native endianness arithmetic/enum types to appropriate se_t<> type +template +struct to_se { + // Convert arithmetic and enum types using type = typename std::conditional::value || std::is_enum::value, se_t, T>::type; }; -template struct to_se::value>> // move const qualifier -{ - using type = const typename to_se::type; -}; - -template struct to_se::value && !std::is_const::value>> // move volatile qualifier -{ - using type = volatile typename to_se::type; -}; - -template struct to_se -{ - using type = typename to_se::type[]; -}; - -template struct to_se -{ - using type = typename to_se::type[N]; -}; - -template struct to_se { using type = se_t; }; template struct to_se { using type = se_t; }; template struct to_se { using type = bool; }; template struct to_se { using type = char; }; template struct to_se { using type = u8; }; template struct to_se { using type = s8; }; -#ifdef IS_LE_MACHINE +template +struct to_se::value>> +{ + // Move const qualifier + using type = const typename to_se::type; +}; + +template +struct to_se::value && !std::is_const::value>> +{ + // Move volatile qualifier + using type = volatile typename to_se::type; +}; + +template +struct to_se +{ + // Move array qualifier + using type = typename to_se::type[]; +}; + +template +struct to_se +{ + // Move array qualifier + using type = typename to_se::type[N]; +}; + +// BE/LE aliases for to_se<> +#if IS_LE_MACHINE == 1 template using to_be_t = typename to_se::type; template using to_le_t = typename to_se::type; -#else -template using to_be_t = typename to_se::type; -template using to_le_t = typename to_se::type; #endif +// BE/LE aliases for atomic_t +#if IS_LE_MACHINE == 1 +template using atomic_be_t = atomic_t>; +template using atomic_le_t = atomic_t>; +#endif -template struct to_ne +namespace fmt { - using type = T; -}; + // Formatting for BE/LE data + template + struct unveil, void> + { + using result_type = typename unveil::result_type; -template struct to_ne> -{ - using type = typename std::remove_cv::type; -}; + static inline result_type get_value(const se_t& arg) + { + return unveil::get_value(arg); + } + }; +} -template struct to_ne::value>> // move const qualifier -{ - using type = const typename to_ne::type; -}; - -template struct to_ne::value && !std::is_const::value>> // move volatile qualifier -{ - using type = volatile typename to_ne::type; -}; - -template struct to_ne -{ - using type = typename to_ne::type[]; -}; - -template struct to_ne -{ - using type = typename to_ne::type[N]; -}; - -// restore native endianness for T: returns T for be_t or le_t, T otherwise -template using to_ne_t = typename to_ne::type; +#undef IS_BINARY_COMPARABLE +#undef IS_INTEGER diff --git a/Utilities/BitField.h b/Utilities/BitField.h index 7c7ad0704f..ef03e0ab8a 100644 --- a/Utilities/BitField.h +++ b/Utilities/BitField.h @@ -1,73 +1,106 @@ #pragma once -// BitField access helper class (N bits from I position), intended to be put in union -template class bf_t +#include "types.h" + +template +struct bf_base { - // 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"); + using type = T; + using vtype = simple_t; - // Underlying data type - using type = typename std::remove_cv::type; + // Datatype bitsize + static constexpr uint bitmax = sizeof(T) * CHAR_BIT; static_assert(N - 1 < bitmax, "bf_base<> error: N out of bounds"); + + // Field bitsize + static constexpr uint bitsize = N; - // Underlying value type (native endianness) - using vtype = typename to_ne::type; + // Value mask + static constexpr vtype vmask = static_cast(~std::make_unsigned_t{} >> (bitmax - bitsize)); - // Mask of size N - constexpr static vtype s_mask = (static_cast(1) << N) - 1; - - // Underlying data member +protected: type m_data; +}; - // Conversion operator helper (uses SFINAE) - template struct converter {}; +// Bitfield accessor (N bits from I position, 0 is LSB) +template +struct bf_t : bf_base +{ + using type = typename bf_t::type; + using vtype = typename bf_t::vtype; - template struct converter::value>> + // Field offset + static constexpr uint bitpos = I; static_assert(bitpos + N <= bf_t::bitmax, "bf_t<> error: I out of bounds"); + + // Get bitmask of size N, at I pos + static constexpr vtype data_mask() + { + return bf_t::vmask << bitpos; + } + + // Bitfield extraction helper + template + struct extract_impl + { + static_assert(!sizeof(T2), "bf_t<> error: Invalid type"); + }; + + template + struct extract_impl::value>> { // Load unsigned value - static inline T2 convert(const type& data) + static constexpr T2 extract(const T& data) { - return (data >> I) & s_mask; + return (data >> bitpos) & bf_t::vmask; } }; - template struct converter::value>> + template + struct extract_impl::value>> { // Load signed value (sign-extended) - static inline T2 convert(const type& data) + static constexpr T2 extract(const T& data) { - return data << (sizeof(T) * 8 - I - N) >> (sizeof(T) * 8 - N); + return data << (bf_t::bitmax - bitpos - N) >> (bf_t::bitmax - N); } }; -public: - // Assignment operator (store bitfield value) - bf_t& operator =(vtype value) + // Bitfield extraction + static constexpr vtype extract(const T& data) { - m_data = (m_data & ~(s_mask << I)) | (value & s_mask) << I; - return *this; + return extract_impl::extract(data); } - // Conversion operator (load bitfield value) - operator vtype() const + // Bitfield insertion + static constexpr vtype insert(vtype value) { - return converter::convert(m_data); + return (value & bf_t::vmask) << bitpos; } - // Get raw data with mask applied - type unshifted() const + // Load bitfield value + constexpr operator vtype() const { - return (m_data & (s_mask << I)); + return extract(this->m_data); } - // Optimized bool conversion - explicit operator bool() const + // Load raw data with mask applied + constexpr T unshifted() const + { + return this->m_data & data_mask(); + } + + // Optimized bool conversion (must be removed if inappropriate) + explicit constexpr operator bool() const { return unshifted() != 0; } - // Postfix increment operator + // Store bitfield value + bf_t& operator =(vtype value) + { + this->m_data = (this->m_data & ~data_mask()) | insert(value); + return *this; + } + vtype operator ++(int) { vtype result = *this; @@ -75,13 +108,11 @@ public: return result; } - // Prefix increment operator bf_t& operator ++() { return *this = *this + 1; } - // Postfix decrement operator vtype operator --(int) { vtype result = *this; @@ -89,52 +120,125 @@ public: 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; + this->m_data &= (right & bf_t::vmask) << bitpos; return *this; } - // Bitwise OR assignment operator bf_t& operator |=(vtype right) { - m_data |= (right & s_mask) << I; + this->m_data |= (right & bf_t::vmask) << bitpos; return *this; } - // Bitwise XOR assignment operator bf_t& operator ^=(vtype right) { - m_data ^= (right & s_mask) << I; + this->m_data ^= (right & bf_t::vmask) << bitpos; return *this; } }; -template using bf_be_t = bf_t, I, N>; +// Field pack (concatenated from left to right) +template +struct cf_t : bf_base::bitsize> +{ + using type = typename cf_t::type; + using vtype = typename cf_t::vtype; -template using bf_le_t = bf_t, I, N>; + // Get disjunction of all "data" masks of concatenated values + static constexpr vtype data_mask() + { + return F::data_mask() | cf_t::data_mask(); + } + + // Extract all bitfields and concatenate + static constexpr vtype extract(const type& data) + { + return F::extract(data) << cf_t::bitsize | cf_t::extract(data); + } + + // Split bitfields and insert them + static constexpr vtype insert(vtype value) + { + return F::insert(value >> cf_t::bitsize) | cf_t::insert(value); + } + + // Load value + constexpr operator vtype() const + { + return extract(this->m_data); + } + + // Store value + cf_t& operator =(vtype value) + { + this->m_data = (this->m_data & ~data_mask()) | insert(value); + return *this; + } +}; + +// Empty field pack (recursion terminator) +template<> +struct cf_t +{ + static constexpr uint bitsize = 0; + + static constexpr uint data_mask() + { + return 0; + } + + template + static constexpr auto extract(const T& data) -> decltype(+T()) + { + return 0; + } + + template + static constexpr T insert(T value) + { + return 0; + } +}; + +// Fixed field (provides constant values in field pack) +template +struct ff_t : bf_base +{ + using type = typename ff_t::type; + using vtype = typename ff_t::vtype; + + // Return constant value + static constexpr vtype extract(const type& data) + { + static_assert((V & ff_t::vmask) == V, "ff_t<> error: V out of bounds"); + return V; + } + + // Get value + operator vtype() const + { + return V; + } +}; diff --git a/Utilities/Config.cpp b/Utilities/Config.cpp new file mode 100644 index 0000000000..e7368683c3 --- /dev/null +++ b/Utilities/Config.cpp @@ -0,0 +1,203 @@ +#include "stdafx.h" +#include "Config.h" + +#include "yaml-cpp/yaml.h" + +namespace cfg +{ + _log::channel cfg("CFG", _log::level::notice); + + entry_base::entry_base(type _type) + : m_type(_type) + { + if (_type != type::node) + { + throw std::logic_error("Invalid root node"); + } + } + + entry_base::entry_base(type _type, node& owner, const std::string& name) + : m_type(_type) + { + if (!owner.m_nodes.emplace(name, this).second) + { + throw std::logic_error("Node already exists"); + } + } + + entry_base& entry_base::operator[](const std::string& name) const + { + if (m_type == type::node) + { + return *static_cast(*this).m_nodes.at(name); + } + + throw std::logic_error("Invalid node type"); + } + + entry_base& entry_base::operator[](const char* name) const + { + if (m_type == type::node) + { + return *static_cast(*this).m_nodes.at(name); + } + + throw std::logic_error("Invalid node type"); + } + + // Emit YAML + static void encode(YAML::Emitter& out, const class entry_base& rhs); + + // Incrementally load config entries from YAML::Node. + // The config value is preserved if the corresponding YAML node doesn't exist. + static void decode(const YAML::Node& data, class entry_base& rhs); +} + +bool cfg::try_to_int64(s64* out, const std::string& value, s64 min, s64 max) +{ + // TODO: this could be rewritten without exceptions (but it should be as safe as possible and provide logs) + s64 result; + std::size_t pos; + + try + { + result = std::stoll(value, &pos, 0 /* Auto-detect numeric base */); + } + catch (const std::exception& e) + { + if (out) cfg.error("cfg::try_to_int('%s'): exception: %s", value, e.what()); + return false; + } + + if (pos != value.size()) + { + if (out) cfg.error("cfg::try_to_int('%s'): unexpected characters (pos=%zu)", value, pos); + return false; + } + + if (result < min || result > max) + { + if (out) cfg.error("cfg::try_to_int('%s'): out of bounds (%lld..%lld)", value, min, max); + return false; + } + + if (out) *out = result; + return true; +} + +void cfg::encode(YAML::Emitter& out, const cfg::entry_base& rhs) +{ + switch (rhs.get_type()) + { + case type::node: + { + out << YAML::BeginMap; + for (const auto& np : static_cast(rhs).get_nodes()) + { + out << YAML::Key << np.first; + out << YAML::Value; encode(out, *np.second); + } + + out << YAML::EndMap; + return; + } + case type::set: + { + out << YAML::BeginSeq; + for (const auto& str : static_cast(rhs).get_set()) + { + out << str; + } + + out << YAML::EndSeq; + return; + } + } + + out << rhs.to_string(); +} + +void cfg::decode(const YAML::Node& data, cfg::entry_base& rhs) +{ + switch (rhs.get_type()) + { + case type::node: + { + if (data.IsScalar() || data.IsSequence()) + { + return; // ??? + } + + for (const auto& pair : data) + { + if (!pair.first.IsScalar()) continue; + + // Find the key among existing nodes + const auto name = pair.first.Scalar(); + const auto found = static_cast(rhs).get_nodes().find(name); + + if (found != static_cast(rhs).get_nodes().cend()) + { + decode(pair.second, *found->second); + } + else + { + // ??? + } + } + + break; + } + case type::set: + { + std::vector values; + + if (YAML::convert::decode(data, values)) + { + rhs.from_list(std::move(values)); + } + + break; + } + default: + { + std::string value; + + if (YAML::convert::decode(data, value)) + { + rhs.from_string(value); + } + + break; // ??? + } + } +} + +std::string cfg::node::to_string() const +{ + YAML::Emitter out; + cfg::encode(out, *this); + + return{ out.c_str(), out.size() }; +} + +bool cfg::node::from_string(const std::string& value) +{ + cfg::decode(YAML::Load(value), *this); + return true; +} + +void cfg::node::from_default() +{ + for (auto& node : m_nodes) + { + node.second->from_default(); + } +} + +cfg::root_node& cfg::get_root() +{ + // Magic static + static root_node root; + return root; +} diff --git a/Utilities/Config.h b/Utilities/Config.h new file mode 100644 index 0000000000..203e959a30 --- /dev/null +++ b/Utilities/Config.h @@ -0,0 +1,523 @@ +#pragma once + +#include "Utilities/Atomic.h" +#include +#include + +namespace cfg +{ + // Convert string to signed integer + bool try_to_int64(s64* out, const std::string& value, s64 min, s64 max); + + // Config tree entry type. + enum class type : uint + { + node = 0, // cfg::node type + boolean, // cfg::bool_entry type + fixed_map, // cfg::map_entry type + enumeration, // cfg::enum_entry type + integer, // cfg::int_entry type + string, // cfg::string_entry type + set, // cfg::set_entry type + }; + + // Config tree entry abstract base class + class entry_base + { + const type m_type; + + protected: + // Ownerless entry constructor + entry_base(type _type); + + // Owned entry constructor + entry_base(type _type, class node& owner, const std::string& name); + + public: + // Disallow copy/move constructors and assignments + entry_base(const entry_base&) = delete; + + // Get type + type get_type() const { return m_type; } + + // Access child node (must exist) + entry_base& operator [](const std::string& name) const; entry_base& operator [](const char* name) const; + + // Reset defaults + virtual void from_default() = 0; + + // Convert to string (optional) + virtual std::string to_string() const + { + return{}; + } + + // Try to convert from string (optional) + virtual bool from_string(const std::string&) + { + throw std::logic_error("from_string() not specified"); + } + + // Get string list (optional) + virtual std::vector to_list() const + { + return{}; + } + + // Set multiple values. Implementation-specific, optional. + virtual bool from_list(std::vector&&) + { + throw std::logic_error("from_list() not specified"); + } + }; + + // Config tree node which contains another nodes + class node : public entry_base + { + std::map m_nodes; + + friend class entry_base; + + public: + // Root node constructor + node() + : entry_base(type::node) + { + } + + // Registered node constructor + node(node& owner, const std::string& name) + : entry_base(type::node, owner, name) + { + } + + // Get child nodes + const std::map& get_nodes() const + { + return m_nodes; + } + + // Serialize node + std::string to_string() const override; + + // Deserialize node + bool from_string(const std::string& value) override; + + // Set default values + void from_default() override; + }; + + struct bool_entry final : public entry_base + { + atomic_t value; + + const bool def; + + bool_entry(node& owner, const std::string& name, bool def = false) + : entry_base(type::boolean, owner, name) + , value(def) + , def(def) + { + } + + explicit operator bool() const + { + return value.load(); + } + + bool_entry& operator =(bool value) + { + value = value; + return *this; + } + + void from_default() override + { + value = def; + } + + std::string to_string() const override + { + return value.load() ? "true" : "false"; + } + + bool from_string(const std::string& value) override + { + if (value == "false") + this->value = false; + else if (value == "true") + this->value = true; + else + return false; + + return true; + } + }; + + // Value node with fixed set of possible values, each maps to a value of type T. + template + struct map_entry final : public entry_base + { + using init_type = std::initializer_list>; + using map_type = std::unordered_map; + using list_type = std::vector; + using value_type = typename map_type::value_type; + + static map_type make_map(init_type init) + { + map_type map(init.size()); + + for (const auto& v : init) + { + // Ensure elements are unique + ASSERT(map.emplace(v.first, v.second).second); + } + + return map; + } + + static list_type make_list(init_type init) + { + list_type list; list.reserve(init.size()); + + for (const auto& v : init) + { + list.emplace_back(v.first); + } + + return list; + } + + public: + const map_type map; + const list_type list; // Element list sorted in original order + const value_type& def; // Pointer to the default value + + private: + atomic_t m_value; + + public: + map_entry(node& owner, const std::string& name, const std::string& def, init_type init) + : entry_base(type::fixed_map, owner, name) + , map(make_map(init)) + , list(make_list(init)) + , def(*map.find(def)) + , m_value(&this->def) + { + } + + map_entry(node& owner, const std::string& name, std::size_t def_index, init_type init) + : map_entry(owner, name, def_index < init.size() ? (init.begin() + def_index)->first : throw std::logic_error("Invalid default value index"), init) + { + } + + map_entry(node& owner, const std::string& name, init_type init) + : map_entry(owner, name, 0, init) + { + } + + const T& get() const + { + return m_value.load()->second; + } + + void from_default() override + { + m_value = &def; + } + + std::string to_string() const override + { + return m_value.load()->first; + } + + bool from_string(const std::string& value) override + { + const auto found = map.find(value); + + if (found == map.end()) + { + return false; + } + else + { + m_value = &*found; + return true; + } + } + + std::vector to_list() const override + { + return list; + } + }; + + // Value node with fixed set of possible values, each maps to an enum value of type T. + template + class enum_entry final : public entry_base + { + // Value or reference + std::conditional_t&, atomic_t> m_value; + + public: + const T def; + + enum_entry(node& owner, const std::string& name, std::conditional_t&, T> value) + : entry_base(type::enumeration, owner, name) + , m_value(value) + , def(value) + { + } + + operator T() const + { + return m_value.load(); + } + + enum_entry& operator =(T value) + { + m_value = value; + return *this; + } + + void from_default() override + { + m_value = def; + } + + std::string to_string() const override + { + for (const auto& pair : bijective::map) + { + if (pair.first == m_value) + { + return pair.second; + } + } + + return{}; // TODO: ??? + } + + bool from_string(const std::string& value) override + { + for (const auto& pair : bijective::map) + { + if (pair.second == value) + { + m_value = pair.first; + return true; + } + } + + return false; + } + + std::vector to_list() const override + { + std::vector result; + + for (const auto& pair : bijective::map) + { + result.emplace_back(pair.second); + } + + return result; + } + }; + + // Signed 32/64-bit integer entry with custom Min/Max range. + template + class int_entry final : public entry_base + { + static_assert(Min < Max, "Invalid cfg::int_entry range"); + + // Prefer 32 bit type if possible + using int_type = std::conditional_t= INT32_MIN && Max <= INT32_MAX, s32, s64>; + + atomic_t m_value; + + public: + const int_type def; + + int_entry(node& owner, const std::string& name, int_type def = std::min(Max, std::max(Min, 0))) + : entry_base(type::integer, owner, name) + , m_value(def) + , def(def) + { + } + + operator int_type() const + { + return m_value.load(); + } + + int_entry& operator =(int_type value) + { + if (value < Min || value > Max) + { + throw fmt::exception("Value out of the valid range: %lld" HERE, s64{ value }); + } + + m_value = value; + return *this; + } + + void from_default() override + { + m_value = def; + } + + std::string to_string() const override + { + return std::to_string(m_value.load()); + } + + bool from_string(const std::string& value) override + { + s64 result; + if (try_to_int64(&result, value, Min, Max)) + { + m_value = static_cast(result); + return true; + } + + return false; + } + }; + + // Alias for 32 bit int + using int32_entry = int_entry; + + // Alias for 64 bit int + using int64_entry = int_entry; + + // Simple string entry with mutex + class string_entry final : public entry_base + { + mutable std::mutex m_mutex; + std::string m_value; + + public: + const std::string def; + + string_entry(node& owner, const std::string& name, const std::string& def = {}) + : entry_base(type::string, owner, name) + , m_value(def) + , def(def) + { + } + + operator std::string() const + { + std::lock_guard lock(m_mutex); + return m_value; + } + + std::string get() const + { + return *this; + } + + string_entry& operator =(const std::string& value) + { + std::lock_guard lock(m_mutex); + m_value = value; + return *this; + } + + std::size_t size() const + { + std::lock_guard lock(m_mutex); + return m_value.size(); + } + + void from_default() override + { + *this = def; + } + + std::string to_string() const override + { + std::lock_guard lock(m_mutex); + return m_value; + } + + bool from_string(const std::string& value) override + { + *this = value; + return true; + } + }; + + // Simple set entry with mutex (TODO: template for various types) + class set_entry final : public entry_base + { + mutable std::mutex m_mutex; + + std::set m_set; + + public: + // Default value is empty list in current implementation + set_entry(node& owner, const std::string& name) + : entry_base(type::set, owner, name) + { + } + + std::set get_set() const + { + std::lock_guard lock(m_mutex); + + return m_set; + } + + void set_set(std::set&& set) + { + std::lock_guard lock(m_mutex); + m_set = std::move(set); + } + + void from_default() override + { + std::lock_guard lock(m_mutex); + m_set = {}; + } + + std::vector to_list() const override + { + std::lock_guard lock(m_mutex); + + return{ m_set.begin(), m_set.end() }; + } + + bool from_list(std::vector&& list) override + { + std::lock_guard lock(m_mutex); + m_set = { std::make_move_iterator(list.begin()), std::make_move_iterator(list.end()) }; + + return true; + } + }; + + // Root type with some predefined nodes. Don't change it, this is not mandatory for adding nodes. + struct root_node : node + { + node core { *this, "Core" }; + node vfs { *this, "VFS" }; + node log { *this, "Log" }; + node video { *this, "Video" }; + node audio { *this, "Audio" }; + node io { *this, "Input/Output" }; + node sys { *this, "System" }; + node net { *this, "Net" }; + node misc { *this, "Miscellaneous" }; + }; + + // Get global configuration root instance + extern root_node& get_root(); + + // Global configuration root instance (cached reference) + static root_node& root = get_root(); +} + +// Registered log channel +#define LOG_CHANNEL(name) _log::channel name(#name, _log::level::notice); namespace _log { cfg::enum_entry<_log::level, true> name(cfg::root.log, #name, ::name.enabled); } diff --git a/Utilities/File.cpp b/Utilities/File.cpp index 9d3d4571e3..7581ccbde4 100644 --- a/Utilities/File.cpp +++ b/Utilities/File.cpp @@ -1,5 +1,8 @@ -#include "stdafx.h" #include "File.h" +#include "StrFmt.h" +#include "Macro.h" +#include "SharedMutex.h" +#include #ifdef _WIN32 @@ -12,13 +15,13 @@ static std::unique_ptr to_wchar(const std::string& source) { const auto buf_size = source.size() + 1; // size + null terminator - const int size = source.size() < INT_MAX ? static_cast(buf_size) : throw EXCEPTION("Invalid source length (0x%llx)", source.size()); + const int size = source.size() < INT_MAX ? static_cast(buf_size) : throw fmt::exception("to_wchar(): invalid source length (0x%llx)", source.size()); std::unique_ptr buffer(new wchar_t[buf_size]); // allocate buffer assuming that length is the max possible size if (!MultiByteToWideChar(CP_UTF8, 0, source.c_str(), size, buffer.get(), size)) { - throw EXCEPTION("MultiByteToWideChar() failed (0x%x).", GetLastError()); + throw fmt::exception("to_wchar(): MultiByteToWideChar() failed: error %u.", GetLastError()); } return buffer; @@ -28,7 +31,7 @@ static void to_utf8(std::string& result, const wchar_t* source) { const auto length = std::wcslen(source); - const int buf_size = length <= INT_MAX / 3 ? static_cast(length) * 3 + 1 : throw EXCEPTION("Invalid source length (0x%llx)", length); + const int buf_size = length <= INT_MAX / 3 ? static_cast(length) * 3 + 1 : throw fmt::exception("to_utf8(): invalid source length (0x%llx)", length); result.resize(buf_size); // set max possible length for utf-8 + null terminator @@ -38,7 +41,7 @@ static void to_utf8(std::string& result, const wchar_t* source) } else { - throw EXCEPTION("WideCharToMultiByte() failed (0x%x).", GetLastError()); + throw fmt::exception("to_utf8(): WideCharToMultiByte() failed: error %u.", GetLastError()); } } @@ -85,6 +88,68 @@ static time_t to_time(const FILETIME& ft) #endif +namespace fs +{ + class device_manager final + { + mutable shared_mutex m_mutex; + + std::unordered_map> m_map; + + public: + std::shared_ptr get_device(const std::string& name); + std::shared_ptr set_device(const std::string& name, const std::shared_ptr&); + }; + + static device_manager& get_device_manager() + { + // Use magic static + static device_manager instance; + return instance; + } +} + +safe_buffers std::shared_ptr fs::device_manager::get_device(const std::string& name) +{ + reader_lock lock(m_mutex); + + const auto found = m_map.find(name); + + if (found == m_map.end()) + { + return nullptr; + } + + return found->second; +} + +safe_buffers std::shared_ptr fs::device_manager::set_device(const std::string& name, const std::shared_ptr& device) +{ + std::lock_guard lock(m_mutex); + + return m_map[name] = device; +} + +safe_buffers std::shared_ptr fs::get_virtual_device(const std::string& path) +{ + // Every virtual device path must have "//" at the beginning + if (path.size() > 2 && reinterpret_cast(path.front()) == '//') + { + return get_device_manager().get_device(path.substr(0, path.find_first_of('/', 2))); + } + + return nullptr; +} + +safe_buffers std::shared_ptr fs::set_virtual_device(const std::string& name, const std::shared_ptr& device) +{ + Expects(name.size() > 2); + Expects(name[0] == '/'); + Expects(name[1] == '/'); + + return get_device_manager().set_device(name, device); +} + std::string fs::get_parent_dir(const std::string& path) { // Search upper bound (set to the last character, npos for empty string) @@ -112,32 +177,37 @@ std::string fs::get_parent_dir(const std::string& path) static const auto test_get_parent_dir = []() -> bool { // Success: - CHECK_ASSERTION(fs::get_parent_dir("/x/y///") == "/x"); - CHECK_ASSERTION(fs::get_parent_dir("/x/y/") == "/x"); - CHECK_ASSERTION(fs::get_parent_dir("/x/y") == "/x"); - CHECK_ASSERTION(fs::get_parent_dir("x:/y") == "x:"); - CHECK_ASSERTION(fs::get_parent_dir("//x/y") == "//x"); + ASSERT(fs::get_parent_dir("/x/y///") == "/x"); + ASSERT(fs::get_parent_dir("/x/y/") == "/x"); + ASSERT(fs::get_parent_dir("/x/y") == "/x"); + ASSERT(fs::get_parent_dir("x:/y") == "x:"); + ASSERT(fs::get_parent_dir("//x/y") == "//x"); // Failure: - CHECK_ASSERTION(fs::get_parent_dir("").empty()); - CHECK_ASSERTION(fs::get_parent_dir("x/").empty()); - CHECK_ASSERTION(fs::get_parent_dir("x").empty()); - CHECK_ASSERTION(fs::get_parent_dir("x///").empty()); - CHECK_ASSERTION(fs::get_parent_dir("/x/").empty()); - CHECK_ASSERTION(fs::get_parent_dir("/x").empty()); - CHECK_ASSERTION(fs::get_parent_dir("/").empty()); - CHECK_ASSERTION(fs::get_parent_dir("//").empty()); - CHECK_ASSERTION(fs::get_parent_dir("//x").empty()); - CHECK_ASSERTION(fs::get_parent_dir("//x/").empty()); - CHECK_ASSERTION(fs::get_parent_dir("///").empty()); - CHECK_ASSERTION(fs::get_parent_dir("///x").empty()); - CHECK_ASSERTION(fs::get_parent_dir("///x/").empty()); + ASSERT(fs::get_parent_dir("").empty()); + ASSERT(fs::get_parent_dir("x/").empty()); + ASSERT(fs::get_parent_dir("x").empty()); + ASSERT(fs::get_parent_dir("x///").empty()); + ASSERT(fs::get_parent_dir("/x/").empty()); + ASSERT(fs::get_parent_dir("/x").empty()); + ASSERT(fs::get_parent_dir("/").empty()); + ASSERT(fs::get_parent_dir("//").empty()); + ASSERT(fs::get_parent_dir("//x").empty()); + ASSERT(fs::get_parent_dir("//x/").empty()); + ASSERT(fs::get_parent_dir("///").empty()); + ASSERT(fs::get_parent_dir("///x").empty()); + ASSERT(fs::get_parent_dir("///x/").empty()); return false; }(); bool fs::stat(const std::string& path, stat_t& info) { + if (auto device = get_virtual_device(path)) + { + return device->stat(path, info); + } + #ifdef _WIN32 WIN32_FILE_ATTRIBUTE_DATA attrs; if (!GetFileAttributesExW(to_wchar(path).get(), GetFileExInfoStandard, &attrs)) @@ -147,7 +217,7 @@ bool fs::stat(const std::string& path, stat_t& info) { case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x (%s).", error, path); + default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); } return false; @@ -179,6 +249,12 @@ bool fs::stat(const std::string& path, stat_t& info) bool fs::exists(const std::string& path) { + if (auto device = get_virtual_device(path)) + { + stat_t info; + return device->stat(path, info); + } + #ifdef _WIN32 if (GetFileAttributesW(to_wchar(path).get()) == INVALID_FILE_ATTRIBUTES) { @@ -187,7 +263,7 @@ bool fs::exists(const std::string& path) { case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x (%s).", error, path); + default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); } return false; @@ -202,6 +278,23 @@ bool fs::exists(const std::string& path) bool fs::is_file(const std::string& path) { + if (auto device = get_virtual_device(path)) + { + stat_t info; + if (!device->stat(path, info)) + { + return false; + } + + if (info.is_directory) + { + errno = EEXIST; + return false; + } + + return true; + } + #ifdef _WIN32 const DWORD attrs = GetFileAttributesW(to_wchar(path).get()); if (attrs == INVALID_FILE_ATTRIBUTES) @@ -211,7 +304,7 @@ bool fs::is_file(const std::string& path) { case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x (%s).", error, path); + default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); } return false; @@ -240,6 +333,23 @@ bool fs::is_file(const std::string& path) bool fs::is_dir(const std::string& path) { + if (auto device = get_virtual_device(path)) + { + stat_t info; + if (!device->stat(path, info)) + { + return false; + } + + if (info.is_directory == false) + { + errno = EEXIST; + return false; + } + + return true; + } + #ifdef _WIN32 const DWORD attrs = GetFileAttributesW(to_wchar(path).get()); if (attrs == INVALID_FILE_ATTRIBUTES) @@ -249,7 +359,7 @@ bool fs::is_dir(const std::string& path) { case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x (%s).", error, path); + default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); } return false; @@ -277,6 +387,11 @@ bool fs::is_dir(const std::string& path) bool fs::create_dir(const std::string& path) { + if (auto device = get_virtual_device(path)) + { + return device->create_dir(path); + } + #ifdef _WIN32 if (!CreateDirectoryW(to_wchar(path).get(), NULL)) { @@ -285,7 +400,7 @@ bool fs::create_dir(const std::string& path) { case ERROR_ALREADY_EXISTS: errno = EEXIST; break; case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x (%s).", error, path); + default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); } return false; @@ -311,6 +426,11 @@ bool fs::create_path(const std::string& path) bool fs::remove_dir(const std::string& path) { + if (auto device = get_virtual_device(path)) + { + return device->remove_dir(path); + } + #ifdef _WIN32 if (!RemoveDirectoryW(to_wchar(path).get())) { @@ -318,7 +438,7 @@ bool fs::remove_dir(const std::string& path) switch (DWORD error = GetLastError()) { case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x (%s).", error, path); + default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); } return false; @@ -332,6 +452,18 @@ bool fs::remove_dir(const std::string& path) bool fs::rename(const std::string& from, const std::string& to) { + const auto device = get_virtual_device(from); + + if (device != get_virtual_device(to)) + { + throw fmt::exception("fs::rename() between different devices not implemented.\nFrom: %s\nTo: %s", from, to); + } + + if (device) + { + return device->rename(from, to); + } + #ifdef _WIN32 if (!MoveFileW(to_wchar(from).get(), to_wchar(to).get())) { @@ -339,7 +471,7 @@ bool fs::rename(const std::string& from, const std::string& to) switch (DWORD error = GetLastError()) { case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x.\nFrom: %s\nTo: %s", error, from, to); + default: throw fmt::exception("Unknown Win32 error: %u.\nFrom: %s\nTo: %s" HERE, error, from, to); } return false; @@ -353,6 +485,13 @@ bool fs::rename(const std::string& from, const std::string& to) bool fs::copy_file(const std::string& from, const std::string& to, bool overwrite) { + const auto device = get_virtual_device(from); + + if (device != get_virtual_device(to) || device) // TODO + { + throw fmt::exception("fs::copy_file() for virtual devices not implemented.\nFrom: %s\nTo: %s", from, to); + } + #ifdef _WIN32 if (!CopyFileW(to_wchar(from).get(), to_wchar(to).get(), !overwrite)) { @@ -360,7 +499,7 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit switch (DWORD error = GetLastError()) { case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x.\nFrom: %s\nTo: %s", error, from, to); + default: throw fmt::exception("Unknown Win32 error: %u.\nFrom: %s\nTo: %s" HERE, error, from, to); } return false; @@ -413,6 +552,11 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit bool fs::remove_file(const std::string& path) { + if (auto device = get_virtual_device(path)) + { + return device->remove(path); + } + #ifdef _WIN32 if (!DeleteFileW(to_wchar(path).get())) { @@ -421,7 +565,7 @@ bool fs::remove_file(const std::string& path) { case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x (%s).", error, path); + default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); } return false; @@ -435,6 +579,11 @@ bool fs::remove_file(const std::string& path) bool fs::truncate_file(const std::string& path, u64 length) { + if (auto device = get_virtual_device(path)) + { + return device->trunc(path, length); + } + #ifdef _WIN32 // Open the file const auto handle = CreateFileW(to_wchar(path).get(), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); @@ -445,7 +594,7 @@ bool fs::truncate_file(const std::string& path, u64 length) { case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x (%s).", error, path); + default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); } return false; @@ -461,7 +610,7 @@ bool fs::truncate_file(const std::string& path, u64 length) switch (DWORD error = GetLastError()) { case ERROR_NEGATIVE_SEEK: errno = EINVAL; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x (length=0x%llx).", error, length); + default: throw fmt::exception("Unknown Win32 error: %u (length=0x%llx)." HERE, error, length); } CloseHandle(handle); @@ -475,51 +624,55 @@ bool fs::truncate_file(const std::string& path, u64 length) #endif } -fs::file::~file() +void fs::file::xnull() const { - if (m_fd != null) - { -#ifdef _WIN32 - CloseHandle((HANDLE)m_fd); -#else - ::close(m_fd); -#endif - } + throw std::logic_error("fs::file is null"); } -bool fs::file::open(const std::string& path, u32 mode) +void fs::file::xfail() const { - this->close(); + throw fmt::exception("Unexpected fs::file error %d", errno); +} -#ifdef _WIN32 - DWORD access = 0; - switch (mode & (fom::read | fom::write | fom::append)) +bool fs::file::open(const std::string& path, mset mode) +{ + if (auto device = get_virtual_device(path)) { - case fom::read: access |= GENERIC_READ; break; - case fom::read | fom::append: access |= GENERIC_READ; break; - case fom::write: access |= GENERIC_WRITE; break; - case fom::write | fom::append: access |= FILE_APPEND_DATA; break; - case fom::read | fom::write: access |= GENERIC_READ | GENERIC_WRITE; break; - case fom::read | fom::write | fom::append: access |= GENERIC_READ | FILE_APPEND_DATA; break; - } + if (auto&& _file = device->open(path, mode)) + { + m_file = std::move(_file); + return true; + } - DWORD disp = 0; - switch (mode & (fom::create | fom::trunc | fom::excl)) - { - case 0: disp = OPEN_EXISTING; break; - case fom::create: disp = OPEN_ALWAYS; break; - case fom::trunc: disp = TRUNCATE_EXISTING; break; - case fom::create | fom::trunc: disp = CREATE_ALWAYS; break; - case fom::create | fom::excl: disp = CREATE_NEW; break; - case fom::create | fom::excl | fom::trunc: disp = CREATE_NEW; break; - default: - errno = EINVAL; return false; } - m_fd = (std::intptr_t)CreateFileW(to_wchar(path).get(), access, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, disp, FILE_ATTRIBUTE_NORMAL, NULL); +#ifdef _WIN32 + DWORD access = 0; + if (mode & fs::read) access |= GENERIC_READ; + if (mode & fs::write) access |= mode & fs::append ? FILE_APPEND_DATA : GENERIC_WRITE; - if (m_fd == null) + DWORD disp = 0; + if (mode & fs::create) + { + disp = + mode & fs::excl ? CREATE_NEW : + mode & fs::trunc ? CREATE_ALWAYS : OPEN_ALWAYS; + } + else + { + if (mode & fs::excl) + { + errno = EINVAL; + return false; + } + + disp = mode & fs::trunc ? TRUNCATE_EXISTING : OPEN_EXISTING; + } + + const HANDLE handle = CreateFileW(to_wchar(path).get(), access, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, disp, FILE_ATTRIBUTE_NORMAL, NULL); + + if (handle == INVALID_HANDLE_VALUE) { // TODO: convert Win32 error code to errno switch (DWORD error = GetLastError()) @@ -527,457 +680,639 @@ bool fs::file::open(const std::string& path, u32 mode) case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; case ERROR_FILE_EXISTS: errno = EEXIST; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x (%s).", error, path); + default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); } return false; } - return true; + class windows_file final : public file_base + { + const HANDLE m_handle; + + public: + windows_file(HANDLE handle) + : m_handle(handle) + { + } + + ~windows_file() override + { + CloseHandle(m_handle); + } + + stat_t stat() override + { + FILE_BASIC_INFO basic_info; + if (!GetFileInformationByHandleEx(m_handle, FileBasicInfo, &basic_info, sizeof(FILE_BASIC_INFO))) + { + // TODO: convert Win32 error code to errno + switch (DWORD error = GetLastError()) + { + case 0: + default: throw fmt::exception("Win32 error: %u." HERE, error); + } + } + + stat_t info; + info.is_directory = (basic_info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; + info.is_writable = (basic_info.FileAttributes & FILE_ATTRIBUTE_READONLY) == 0; + info.size = this->size(); + info.atime = to_time(basic_info.LastAccessTime); + info.mtime = to_time(basic_info.ChangeTime); + info.ctime = to_time(basic_info.CreationTime); + + return info; + } + + bool trunc(u64 length) override + { + LARGE_INTEGER old, pos; + + pos.QuadPart = 0; + if (!SetFilePointerEx(m_handle, pos, &old, FILE_CURRENT)) // get old position + { + // TODO: convert Win32 error code to errno + switch (DWORD error = GetLastError()) + { + case 0: + default: throw fmt::exception("Unknown Win32 error: %u." HERE, error); + } + + return false; + } + + pos.QuadPart = length; + if (!SetFilePointerEx(m_handle, pos, NULL, FILE_BEGIN)) // set new position + { + // TODO: convert Win32 error code to errno + switch (DWORD error = GetLastError()) + { + case ERROR_NEGATIVE_SEEK: errno = EINVAL; break; + default: throw fmt::exception("Unknown Win32 error: %u." HERE, error); + } + + return false; + } + + const BOOL result = SetEndOfFile(m_handle); // change file size + + if (!result) + { + // TODO: convert Win32 error code to errno + switch (DWORD error = GetLastError()) + { + case 0: + default: throw fmt::exception("Unknown Win32 error: %u." HERE, error); + } + } + + if (!SetFilePointerEx(m_handle, old, NULL, FILE_BEGIN) && result) // restore position + { + if (DWORD error = GetLastError()) + { + throw fmt::exception("Win32 error: %u." HERE, error); + } + } + + return result != FALSE; + } + + u64 read(void* buffer, u64 count) override + { + // TODO (call ReadFile multiple times if count is too big) + const int size = ::narrow(count, "Too big count" HERE); + Expects(size >= 0); + + DWORD nread; + if (!ReadFile(m_handle, buffer, size, &nread, NULL)) + { + switch (DWORD error = GetLastError()) + { + case 0: + default: throw fmt::exception("Win32 error: %u." HERE, error); + } + } + + return nread; + } + + u64 write(const void* buffer, u64 count) override + { + // TODO (call WriteFile multiple times if count is too big) + const int size = ::narrow(count, "Too big count" HERE); + Expects(size >= 0); + + DWORD nwritten; + if (!WriteFile(m_handle, buffer, size, &nwritten, NULL)) + { + switch (DWORD error = GetLastError()) + { + case 0: + default: throw fmt::exception("Win32 error: %u." HERE, error); + } + } + + return nwritten; + } + + u64 seek(s64 offset, seek_mode whence) override + { + LARGE_INTEGER pos; + pos.QuadPart = offset; + + const DWORD mode = + whence == seek_set ? FILE_BEGIN : + whence == seek_cur ? FILE_CURRENT : + whence == seek_end ? FILE_END : + throw fmt::exception("Invalid whence (0x%x)" HERE, whence); + + if (!SetFilePointerEx(m_handle, pos, &pos, mode)) + { + switch (DWORD error = GetLastError()) + { + case 0: + default: throw fmt::exception("Win32 error: %u." HERE, error); + } + } + + return pos.QuadPart; + } + + u64 size() override + { + LARGE_INTEGER size; + if (!GetFileSizeEx(m_handle, &size)) + { + switch (DWORD error = GetLastError()) + { + case 0: + default: throw fmt::exception("Win32 error: %u." HERE, error); + } + } + + return size.QuadPart; + } + }; + + m_file = std::make_unique(handle); #else int flags = 0; - switch (mode & (fom::read | fom::write)) + if (mode & fs::read && mode & fs::write) flags |= O_RDWR; + else if (mode & fs::read) flags |= O_RDONLY; + else if (mode & fs::write) flags |= O_WRONLY; + + if (mode & fs::append) flags |= O_APPEND; + if (mode & fs::create) flags |= O_CREAT; + if (mode & fs::trunc) flags |= O_TRUNC; + if (mode & fs::excl) flags |= O_EXCL; + + const int fd = ::open(path.c_str(), flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + + if (fd == -1) { - case fom::read: flags |= O_RDONLY; break; - case fom::write: flags |= O_WRONLY; break; - case fom::read | fom::write: flags |= O_RDWR; break; - } - - if (mode & fom::append) flags |= O_APPEND; - if (mode & fom::create) flags |= O_CREAT; - if (mode & fom::trunc) flags |= O_TRUNC; - if (mode & fom::excl) flags |= O_EXCL; - - m_fd = ::open(path.c_str(), flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - - return m_fd != null; -#endif -} - -bool fs::file::trunc(u64 size) const -{ -#ifdef _WIN32 - LARGE_INTEGER old, pos; - - pos.QuadPart = 0; - if (!SetFilePointerEx((HANDLE)m_fd, pos, &old, FILE_CURRENT)) // get old position - { - switch (DWORD error = GetLastError()) - { - case ERROR_INVALID_HANDLE: errno = EBADF; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x.", error); - } - + // TODO: errno return false; } - pos.QuadPart = size; - if (!SetFilePointerEx((HANDLE)m_fd, pos, NULL, FILE_BEGIN)) // set new position + class unix_file final : public file_base { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) + const int m_fd; + + public: + unix_file(int fd) + : m_fd(fd) { - case ERROR_NEGATIVE_SEEK: errno = EINVAL; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x.", error); } - return false; - } - - const BOOL result = SetEndOfFile((HANDLE)m_fd); // change file size - - if (!result) - { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) + ~unix_file() override { - case 0: - default: throw EXCEPTION("Unknown Win32 error: 0x%x.", error); - } - } - - if (!SetFilePointerEx((HANDLE)m_fd, old, NULL, FILE_BEGIN) && result) // restore position - { - if (DWORD error = GetLastError()) - { - throw EXCEPTION("Unknown Win32 error: 0x%x.", error); - } - } - - return result != FALSE; -#else - return !::ftruncate(m_fd, size); -#endif -} - -bool fs::file::stat(stat_t& info) const -{ -#ifdef _WIN32 - FILE_BASIC_INFO basic_info; - if (!GetFileInformationByHandleEx((HANDLE)m_fd, FileBasicInfo, &basic_info, sizeof(FILE_BASIC_INFO))) - { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) - { - case ERROR_INVALID_HANDLE: errno = EBADF; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x.", error); + ::close(m_fd); } - return false; - } - - info.is_directory = (basic_info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; - info.is_writable = (basic_info.FileAttributes & FILE_ATTRIBUTE_READONLY) == 0; - info.size = this->size(); - info.atime = to_time(basic_info.LastAccessTime); - info.mtime = to_time(basic_info.ChangeTime); - info.ctime = to_time(basic_info.CreationTime); -#else - struct ::stat file_info; - if (::fstat(m_fd, &file_info) < 0) - { - return false; - } - - info.is_directory = S_ISDIR(file_info.st_mode); - info.is_writable = file_info.st_mode & 0200; // HACK: approximation - info.size = file_info.st_size; - info.atime = file_info.st_atime; - info.mtime = file_info.st_mtime; - info.ctime = file_info.st_ctime; -#endif - - return true; -} - -void fs::file::close() -{ - if (m_fd == null) - { - return /*true*/; - } - - const auto fd = m_fd; - m_fd = null; - -#ifdef _WIN32 - if (!CloseHandle((HANDLE)fd)) - { - throw EXCEPTION("CloseHandle() failed (fd=0x%llx, 0x%x)", fd, GetLastError()); - } -#else - if (::close(fd) != 0) - { - throw EXCEPTION("close() failed (fd=0x%llx, errno=%d)", fd, errno); - } -#endif -} - -u64 fs::file::read(void* buffer, u64 count) const -{ - // TODO (call ReadFile multiple times if count is too big) - const int size = count <= INT_MAX ? static_cast(count) : throw EXCEPTION("Invalid count (0x%llx)", count); - -#ifdef _WIN32 - DWORD nread; - if (!ReadFile((HANDLE)m_fd, buffer, size, &nread, NULL)) - { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) + stat_t stat() override { - case ERROR_INVALID_HANDLE: errno = EBADF; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x.", error); + struct ::stat file_info; + if (::fstat(m_fd, &file_info) != 0) + { + switch (int error = errno) + { + case 0: + default: throw fmt::exception("Unknown error: %d." HERE, error); + } + } + + stat_t info; + info.is_directory = S_ISDIR(file_info.st_mode); + info.is_writable = file_info.st_mode & 0200; // HACK: approximation + info.size = file_info.st_size; + info.atime = file_info.st_atime; + info.mtime = file_info.st_mtime; + info.ctime = file_info.st_ctime; + + return info; } - return -1; - } - - return nread; -#else - return ::read(m_fd, buffer, size); -#endif -} - -u64 fs::file::write(const void* buffer, u64 count) const -{ - // TODO (call WriteFile multiple times if count is too big) - const int size = count <= INT_MAX ? static_cast(count) : throw EXCEPTION("Invalid count (0x%llx)", count); - -#ifdef _WIN32 - DWORD nwritten; - if (!WriteFile((HANDLE)m_fd, buffer, size, &nwritten, NULL)) - { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) + bool trunc(u64 length) override { - case ERROR_INVALID_HANDLE: errno = EBADF; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x.", error); - } + if (::ftruncate(m_fd, length) != 0) + { + switch (int error = errno) + { + case 0: + default: throw fmt::exception("Unknown error: %d." HERE, error); + } - return -1; - } + return false; + } - return nwritten; -#else - return ::write(m_fd, buffer, size); -#endif -} - -u64 fs::file::seek(s64 offset, seek_mode whence) const -{ -#ifdef _WIN32 - LARGE_INTEGER pos; - pos.QuadPart = offset; - - DWORD mode; - switch (whence) - { - case seek_set: mode = FILE_BEGIN; break; - case seek_cur: mode = FILE_CURRENT; break; - case seek_end: mode = FILE_END; break; - default: - { - errno = EINVAL; - return -1; - } - } - - if (!SetFilePointerEx((HANDLE)m_fd, pos, &pos, mode)) - { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) - { - case ERROR_INVALID_HANDLE: errno = EBADF; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x.", error); - } - - return -1; - } - - return pos.QuadPart; -#else - int mode; - switch (whence) - { - case seek_set: mode = SEEK_SET; break; - case seek_cur: mode = SEEK_CUR; break; - case seek_end: mode = SEEK_END; break; - default: - { - errno = EINVAL; - return -1; - } - } - - return ::lseek(m_fd, offset, mode); -#endif -} - -u64 fs::file::size() const -{ -#ifdef _WIN32 - LARGE_INTEGER size; - if (!GetFileSizeEx((HANDLE)m_fd, &size)) - { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) - { - case ERROR_INVALID_HANDLE: errno = EBADF; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x.", error); - } - - return -1; - } - - return size.QuadPart; -#else - struct ::stat file_info; - if (::fstat(m_fd, &file_info) != 0) - { - return -1; - } - - return file_info.st_size; -#endif -} - -fs::dir::~dir() -{ - if (m_path) - { -#ifdef _WIN32 - if (m_dd != -1) FindClose((HANDLE)m_dd); -#else - ::closedir((DIR*)m_dd); -#endif - } -} - -void fs::file_read_map::reset(const file& f) -{ - reset(); - - if (f) - { -#ifdef _WIN32 - const HANDLE handle = ::CreateFileMapping((HANDLE)f.m_fd, NULL, PAGE_READONLY, 0, 0, NULL); - m_ptr = (char*)::MapViewOfFile(handle, FILE_MAP_READ, 0, 0, 0); - m_size = f.size(); - ::CloseHandle(handle); -#else - m_ptr = (char*)::mmap(nullptr, m_size = f.size(), PROT_READ, MAP_SHARED, f.m_fd, 0); - if (m_ptr == (void*)-1) m_ptr = nullptr; -#endif - } -} - -void fs::file_read_map::reset() -{ - if (m_ptr) - { -#ifdef _WIN32 - ::UnmapViewOfFile(m_ptr); -#else - ::munmap(m_ptr, m_size); -#endif - } -} - -bool fs::dir::open(const std::string& dirname) -{ - this->close(); - -#ifdef _WIN32 - if (!is_dir(dirname)) - { - return false; - } - - m_dd = -1; -#else - const auto ptr = ::opendir(dirname.c_str()); - if (!ptr) - { - return false; - } - - m_dd = reinterpret_cast(ptr); -#endif - - m_path.reset(new char[dirname.size() + 1]); - std::memcpy(m_path.get(), dirname.c_str(), dirname.size() + 1); - - return true; -} - -void fs::dir::close() -{ - if (!m_path) - { - return /*true*/; - } - - m_path.reset(); - -#ifdef _WIN32 - CHECK_ASSERTION(m_dd == -1 || FindClose((HANDLE)m_dd)); -#else - CHECK_ASSERTION(!::closedir((DIR*)m_dd)); -#endif -} - -bool fs::dir::read(std::string& name, stat_t& info) -{ - if (!m_path) - { - errno = EINVAL; - return false; - } - -#ifdef _WIN32 - const bool is_first = m_dd == -1; - - WIN32_FIND_DATAW found; - - if (is_first) - { - m_dd = (std::intptr_t)FindFirstFileW(to_wchar(m_path.get() + "/*"s).get(), &found); - } - - if (is_first && m_dd == -1 || !is_first && !FindNextFileW((HANDLE)m_dd, &found)) - { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) - { - case ERROR_NO_MORE_FILES: - { - name.clear(); return true; } - default: throw EXCEPTION("Unknown Win32 error: 0x%x.", error); + u64 read(void* buffer, u64 count) override + { + const auto result = ::read(m_fd, buffer, count); + if (result == -1) + { + switch (int error = errno) + { + case 0: + default: throw fmt::exception("Unknown error: %d." HERE, error); + } + } + + return result; } - return false; - } + u64 write(const void* buffer, u64 count) override + { + const auto result = ::write(m_fd, buffer, count); + if (result == -1) + { + switch (int error = errno) + { + case 0: + default: throw fmt::exception("Unknown error: %d." HERE, error); + } + } - to_utf8(name, found.cFileName); + return result; + } - 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(found.ftLastAccessTime); - info.mtime = to_time(found.ftLastWriteTime); - info.ctime = to_time(found.ftCreationTime); -#else - const auto found = ::readdir((DIR*)m_dd); - if (!found) - { - name.clear(); - return true; - } + u64 seek(s64 offset, seek_mode whence) override + { + const int mode = + whence == seek_set ? SEEK_SET : + whence == seek_cur ? SEEK_CUR : + whence == seek_end ? SEEK_END : + throw fmt::exception("Invalid whence (0x%x)" HERE, whence); - struct ::stat file_info; - if (::fstatat(::dirfd((DIR*)m_dd), found->d_name, &file_info, 0) != 0) - { - return false; - } + const auto result = ::lseek(m_fd, offset, mode); + if (result == -1) + { + switch (int error = errno) + { + case 0: + default: throw fmt::exception("Unknown error: %d." HERE, error); + } + } - name = found->d_name; + return result; + } - info.is_directory = S_ISDIR(file_info.st_mode); - info.is_writable = file_info.st_mode & 0200; // HACK: approximation - info.size = file_info.st_size; - info.atime = file_info.st_atime; - info.mtime = file_info.st_mtime; - info.ctime = file_info.st_ctime; + u64 size() override + { + struct ::stat file_info; + if (::fstat(m_fd, &file_info) != 0) + { + switch (int error = errno) + { + case 0: + default: throw fmt::exception("Unknown error: %d." HERE, error); + } + } + + return file_info.st_size; + } + }; + + m_file = std::make_unique(fd); #endif return true; } -bool fs::dir::first(std::string& name, stat_t& info) +fs::file::file(const void* ptr, std::size_t size) { + class memory_stream final : public file_base + { + u64 m_pos = 0; + u64 m_size; + + public: + const char* const ptr; + + memory_stream(const void* ptr, std::size_t size) + : m_size(size) + , ptr(static_cast(ptr)) + { + } + + fs::stat_t stat() override + { + throw std::logic_error("memory_stream doesn't support stat()"); + } + + bool trunc(u64 length) override + { + throw std::logic_error("memory_stream doesn't support trunc()"); + } + + u64 read(void* buffer, u64 count) override + { + const u64 start = m_pos; + const u64 end = seek(count, fs::seek_cur); + const u64 read_size = end >= start ? end - start : throw std::logic_error("memory_stream::read(): overflow"); + std::memcpy(buffer, ptr + start, read_size); + return read_size; + } + + u64 write(const void* buffer, u64 count) override + { + throw std::logic_error("memory_stream is not writable"); + } + + u64 seek(s64 offset, fs::seek_mode whence) override + { + return m_pos = + whence == fs::seek_set ? std::min(offset, m_size) : + whence == fs::seek_cur ? std::min(offset + m_pos, m_size) : + whence == fs::seek_end ? std::min(offset + m_size, m_size) : + throw std::logic_error("memory_stream::seek(): invalid whence"); + } + + u64 size() override + { + return m_size; + } + }; + + m_file = std::make_unique(ptr, size); +} + +fs::file::file(std::vector& vec) +{ + class vector_stream final : public file_base + { + u64 m_pos = 0; + + public: + std::vector& vec; + + vector_stream(std::vector& vec) + : vec(vec) + { + } + + fs::stat_t stat() override + { + throw std::logic_error("vector_stream doesn't support stat()"); + } + + bool trunc(u64 length) override + { + vec.resize(length); + return true; + } + + u64 read(void* buffer, u64 count) override + { + const u64 start = m_pos; + const u64 end = seek(count, fs::seek_cur); + const u64 read_size = end >= start ? end - start : throw std::logic_error("vector_stream::read(): overflow"); + std::memcpy(buffer, vec.data() + start, read_size); + return read_size; + } + + u64 write(const void* buffer, u64 count) override + { + throw std::logic_error("TODO: vector_stream doesn't support write()"); + } + + u64 seek(s64 offset, fs::seek_mode whence) override + { + return m_pos = + whence == fs::seek_set ? std::min(offset, vec.size()) : + whence == fs::seek_cur ? std::min(offset + m_pos, vec.size()) : + whence == fs::seek_end ? std::min(offset + vec.size(), vec.size()) : + throw std::logic_error("vector_stream::seek(): invalid whence"); + } + + u64 size() override + { + return vec.size(); + } + }; + + m_file = std::make_unique(vec); +} + +//void fs::file_read_map::reset(const file& f) +//{ +// reset(); +// +// if (f) +// { +//#ifdef _WIN32 +// const HANDLE handle = ::CreateFileMapping((HANDLE)f.m_fd, NULL, PAGE_READONLY, 0, 0, NULL); +// m_ptr = (char*)::MapViewOfFile(handle, FILE_MAP_READ, 0, 0, 0); +// m_size = f.size(); +// ::CloseHandle(handle); +//#else +// m_ptr = (char*)::mmap(nullptr, m_size = f.size(), PROT_READ, MAP_SHARED, f.m_fd, 0); +// if (m_ptr == (void*)-1) m_ptr = nullptr; +//#endif +// } +//} +// +//void fs::file_read_map::reset() +//{ +// if (m_ptr) +// { +//#ifdef _WIN32 +// ::UnmapViewOfFile(m_ptr); +//#else +// ::munmap(m_ptr, m_size); +//#endif +// } +//} + +void fs::dir::xnull() const +{ + throw std::logic_error("fs::dir is null"); +} + +bool fs::dir::open(const std::string& path) +{ + if (auto device = get_virtual_device(path)) + { + if (auto&& _dir = device->open_dir(path)) + { + m_dir = std::move(_dir); + return true; + } + + return false; + } + #ifdef _WIN32 - if (m_path && m_dd != -1) + WIN32_FIND_DATAW found; + const auto handle = FindFirstFileW(to_wchar(path + "/*").get(), &found); + + if (handle == INVALID_HANDLE_VALUE) { - CHECK_ASSERTION(FindClose((HANDLE)m_dd)); - m_dd = -1; + // TODO: convert Win32 error code to errno + switch (DWORD error = GetLastError()) + { + case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; + case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; + default: throw fmt::exception("Unknown Win32 error: %u." HERE, error); + } + + return false; } + + class windows_dir final : public dir_base + { + const HANDLE m_handle; + + std::vector m_entries; + std::size_t m_pos = 0; + + void add_entry(const WIN32_FIND_DATAW& found) + { + dir_entry info; + + to_utf8(info.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(found.ftLastAccessTime); + info.mtime = to_time(found.ftLastWriteTime); + info.ctime = to_time(found.ftCreationTime); + + m_entries.emplace_back(std::move(info)); + } + + public: + windows_dir(HANDLE handle, const WIN32_FIND_DATAW& found) + : m_handle(handle) + { + add_entry(found); + } + + ~windows_dir() + { + FindClose(m_handle); + } + + bool read(dir_entry& out) override + { + if (m_pos == m_entries.size()) + { + WIN32_FIND_DATAW found; + if (!FindNextFileW(m_handle, &found)) + { + switch (DWORD error = GetLastError()) + { + case ERROR_NO_MORE_FILES: return false; + default: throw fmt::exception("Unknown Win32 error: %u." HERE, error); + } + } + + add_entry(found); + } + + out = m_entries[m_pos++]; + return true; + } + + void rewind() override + { + m_pos = 0; + } + }; + + m_dir = std::make_unique(handle, found); #else - if (m_path) + ::DIR* const ptr = ::opendir(path.c_str()); + + if (!ptr) { - ::rewinddir((DIR*)m_dd); + // TODO: errno + return false; } + + class unix_dir final : public dir_base + { + ::DIR* m_dd; + + public: + unix_dir(::DIR* dd) + : m_dd(dd) + { + } + + ~unix_dir() override + { + ::closedir(m_dd); + } + + bool read(dir_entry& info) override + { + const auto found = ::readdir(m_dd); + if (!found) + { + return false; + } + + struct ::stat file_info; + if (::fstatat(::dirfd(m_dd), found->d_name, &file_info, 0) != 0) + { + switch (int error = errno) + { + case 0: + default: throw fmt::exception("Unknown error: %d." HERE, error); + } + } + + info.name = found->d_name; + info.is_directory = S_ISDIR(file_info.st_mode); + info.is_writable = file_info.st_mode & 0200; // HACK: approximation + info.size = file_info.st_size; + info.atime = file_info.st_atime; + info.mtime = file_info.st_mtime; + info.ctime = file_info.st_ctime; + + return true; + } + + void rewind() override + { + ::rewinddir(m_dd); + } + }; + + m_dir = std::make_unique(ptr); #endif - return read(name, info); + return true; } const std::string& fs::get_config_dir() { - // Use magic static for dir initialization + // Use magic static static const std::string s_dir = [] { #ifdef _WIN32 @@ -1009,7 +1344,7 @@ const std::string& fs::get_config_dir() const std::string& fs::get_executable_dir() { - // Use magic static for dir initialization + // Use magic static static const std::string s_dir = [] { std::string dir; @@ -1018,7 +1353,7 @@ const std::string& fs::get_executable_dir() wchar_t buf[2048]; if (GetModuleFileName(NULL, buf, ::size32(buf)) - 1 >= ::size32(buf) - 1) { - MessageBoxA(0, fmt::format("GetModuleFileName() failed (0x%x).", GetLastError()).c_str(), "fs::get_config_dir()", MB_ICONERROR); + MessageBoxA(0, fmt::format("GetModuleFileName() failed: error %u.", GetLastError()).c_str(), "fs::get_config_dir()", MB_ICONERROR); return dir; // empty } @@ -1055,3 +1390,51 @@ const std::string& fs::get_executable_dir() return s_dir; } + +void fs::remove_all(const std::string& path) +{ + for (const auto& entry : dir(path)) + { + if (entry.name == "." || entry.name == "..") + { + continue; + } + + if (entry.is_directory == false) + { + remove_file(path + '/' + entry.name); + } + + if (entry.is_directory == true) + { + remove_all(path + '/' + entry.name); + } + } + + remove_dir(path); +} + +u64 fs::get_dir_size(const std::string& path) +{ + u64 result = 0; + + for (const auto entry : dir(path)) + { + if (entry.name == "." || entry.name == "..") + { + continue; + } + + if (entry.is_directory == false) + { + result += entry.size; + } + + if (entry.is_directory == true) + { + result += get_dir_size(path + '/' + entry.name); + } + } + + return result; +} diff --git a/Utilities/File.h b/Utilities/File.h index 36af62704f..7a0605b872 100644 --- a/Utilities/File.h +++ b/Utilities/File.h @@ -1,29 +1,47 @@ #pragma once -namespace fom // file open mode -{ - enum open_mode : u32 - { - read = 1 << 0, // enable reading - write = 1 << 1, // enable writing - append = 1 << 2, // enable appending (always write to the end of file) - create = 1 << 3, // create file if it doesn't exist - trunc = 1 << 4, // clear opened file if it's not empty - excl = 1 << 5, // failure if the file already exists (used with `create`) +#include +#include +#include +#include - rewrite = write | create | trunc, - }; -}; +#include "types.h" namespace fs { - enum seek_mode : u32 // file seek mode + // File open mode flags + enum struct open_mode : u32 + { + read, + write, + append, + create, + trunc, + excl, + }; + + constexpr mset read = open_mode::read; // Enable reading + constexpr mset write = open_mode::write; // Enable writing + constexpr mset append = open_mode::append; // Always append to the end of the file + constexpr mset create = open_mode::create; // Create file if it doesn't exist + constexpr mset trunc = open_mode::trunc; // Clear opened file if it's not empty + constexpr mset excl = open_mode::excl; // Failure if the file already exists (used with `create`) + + constexpr mset rewrite = write + create + trunc; + + // File seek mode + enum class seek_mode : u32 { seek_set, seek_cur, seek_end, }; + constexpr auto seek_set = seek_mode::seek_set; // From beginning + constexpr auto seek_cur = seek_mode::seek_cur; // From current position + constexpr auto seek_end = seek_mode::seek_end; // From end + + // File attributes (TODO) struct stat_t { bool is_directory; @@ -34,7 +52,57 @@ namespace fs s64 ctime; }; - // Get parent directory for the path (returns empty string on failure) + // File handle base + struct file_base + { + virtual ~file_base() = default; + + virtual stat_t stat() = 0; + virtual bool trunc(u64 length) = 0; + virtual u64 read(void* buffer, u64 size) = 0; + virtual u64 write(const void* buffer, u64 size) = 0; + virtual u64 seek(s64 offset, seek_mode whence) = 0; + virtual u64 size() = 0; + }; + + // Directory entry (TODO) + struct dir_entry : stat_t + { + std::string name; + }; + + // Directory handle base + struct dir_base + { + virtual ~dir_base() = default; + + virtual bool read(dir_entry&) = 0; + virtual void rewind() = 0; + }; + + // Virtual device + struct device_base + { + virtual ~device_base() = default; + + virtual bool stat(const std::string& path, stat_t& info) = 0; + virtual bool remove_dir(const std::string& path) = 0; + virtual bool create_dir(const std::string& path) = 0; + virtual bool rename(const std::string& from, const std::string& to) = 0; + virtual bool remove(const std::string& path) = 0; + virtual bool trunc(const std::string& path, u64 length) = 0; + + virtual std::unique_ptr open(const std::string& path, mset mode) = 0; + virtual std::unique_ptr open_dir(const std::string& path) = 0; + }; + + // Get virtual device for specified path (nullptr for real path) + std::shared_ptr get_virtual_device(const std::string& path); + + // Set virtual device with specified name (nullptr for deletion) + std::shared_ptr set_virtual_device(const std::string& root_name, const std::shared_ptr&); + + // Try to get parent directory (returns empty string on failure) std::string get_parent_dir(const std::string& path); // Get file information @@ -72,77 +140,105 @@ namespace fs class file final { - using handle_type = std::intptr_t; + std::unique_ptr m_file; - constexpr static handle_type null = -1; - - handle_type m_fd = null; - - friend class file_read_map; - friend class file_write_map; + [[noreturn]] void xnull() const; + [[noreturn]] void xfail() const; public: + // Default constructor file() = default; - explicit file(const std::string& path, u32 mode = fom::read) + // Open file with specified mode + explicit file(const std::string& path, mset mode = ::fs::read) { open(path, mode); } - file(file&& other) - : m_fd(other.m_fd) - { - other.m_fd = null; - } + // Open file with specified mode + bool open(const std::string& path, mset mode = ::fs::read); - file& operator =(file&& right) - { - std::swap(m_fd, right.m_fd); - return *this; - } + // Open memory for read + explicit file(const void* ptr, std::size_t size); - ~file(); - - // Check whether the handle is valid (opened file) - bool is_opened() const - { - return m_fd != null; - } + // Open vector + explicit file(std::vector& vec); // Check whether the handle is valid (opened file) explicit operator bool() const { - return is_opened(); + return m_file.operator bool(); } - // Open specified file with specified mode - bool open(const std::string& path, u32 mode = fom::read); + // Close the file explicitly + void close() + { + m_file.reset(); + } + + void reset(std::unique_ptr&& ptr) + { + m_file = std::move(ptr); + } + + std::unique_ptr release() + { + return std::move(m_file); + } // Change file size (possibly appending zero bytes) - bool trunc(u64 size) const; + bool trunc(u64 length) const + { + if (!m_file) xnull(); + return m_file->trunc(length); + } // Get file information - bool stat(stat_t& info) const; - - // Close the file explicitly (destructor automatically closes the file) - void close(); + stat_t stat() const + { + if (!m_file) xnull(); + return m_file->stat(); + } // Read the data from the file and return the amount of data written in buffer - u64 read(void* buffer, u64 count) const; + u64 read(void* buffer, u64 count) const + { + if (!m_file) xnull(); + return m_file->read(buffer, count); + } // 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 void* buffer, u64 count) const + { + if (!m_file) xnull(); + return m_file->write(buffer, count); + } - // Move file pointer - u64 seek(s64 offset, seek_mode whence = seek_set) const; + // Change current position, returns previous position + u64 seek(s64 offset, seek_mode whence = seek_set) const + { + if (!m_file) xnull(); + return m_file->seek(offset, whence); + } // Get file size - u64 size() const; + u64 size() const + { + if (!m_file) xnull(); + return m_file->size(); + } + + // Get current position + u64 pos() const + { + if (!m_file) xnull(); + return m_file->seek(0, seek_cur); + } // Write std::string unconditionally const file& write(const std::string& str) const { - CHECK_ASSERTION(write(str.data(), str.size()) == str.size()); + if (write(str.data(), str.size()) != str.size()) xfail(); return *this; } @@ -150,7 +246,7 @@ namespace fs template std::enable_if_t::value && !std::is_pointer::value, const file&> write(const T& data) const { - CHECK_ASSERTION(write(std::addressof(data), sizeof(T)) == sizeof(T)); + if (write(std::addressof(data), sizeof(T)) != sizeof(T)) xfail(); return *this; } @@ -158,7 +254,7 @@ namespace fs template std::enable_if_t::value && !std::is_pointer::value, const file&> write(const std::vector& vec) const { - CHECK_ASSERTION(write(vec.data(), vec.size() * sizeof(T)) == vec.size() * sizeof(T)); + if (write(vec.data(), vec.size() * sizeof(T)) != vec.size() * sizeof(T)) xfail(); return *this; } @@ -187,7 +283,7 @@ namespace fs std::enable_if_t::value && !std::is_pointer::value, T> read() const { T result; - CHECK_ASSERTION(read(result)); + if (!read(result)) xfail(); return result; } @@ -196,7 +292,7 @@ namespace fs { std::string result; result.resize(size()); - CHECK_ASSERTION(seek(0) != -1 && read(result)); + if (seek(0), !read(result)) xfail(); return result; } @@ -206,164 +302,69 @@ namespace fs { std::vector result; result.resize(size() / sizeof(T)); - CHECK_ASSERTION(seek(0) != -1 && read(result)); + if (seek(0), !read(result)) xfail(); return result; } }; - // TODO - class file_read_map final - { - char* m_ptr = nullptr; - u64 m_size; - - public: - file_read_map() = default; - - file_read_map(file_read_map&& right) - : m_ptr(right.m_ptr) - , m_size(right.m_size) - { - right.m_ptr = 0; - } - - file_read_map& operator =(file_read_map&& right) - { - std::swap(m_ptr, right.m_ptr); - std::swap(m_size, right.m_size); - return *this; - } - - file_read_map(const file& f) - { - reset(f); - } - - ~file_read_map() - { - reset(); - } - - // Open file mapping - void reset(const file& f); - - // Close file mapping - void reset(); - - // Get pointer - operator const char*() const - { - return m_ptr; - } - }; - - // TODO - class file_write_map final - { - char* m_ptr = nullptr; - u64 m_size; - - public: - file_write_map() = default; - - file_write_map(file_write_map&& right) - : m_ptr(right.m_ptr) - , m_size(right.m_size) - { - right.m_ptr = 0; - } - - file_write_map& operator =(file_write_map&& right) - { - std::swap(m_ptr, right.m_ptr); - std::swap(m_size, right.m_size); - return *this; - } - - file_write_map(const file& f) - { - reset(f); - } - - ~file_write_map() - { - reset(); - } - - // Open file mapping - void reset(const file& f); - - // Close file mapping - void reset(); - - // Get pointer - operator char*() const - { - return m_ptr; - } - }; - class dir final { - std::unique_ptr m_path; - std::intptr_t m_dd; // handle (aux) + std::unique_ptr m_dir; + + [[noreturn]] void xnull() const; public: dir() = default; - explicit dir(const std::string& dirname) + // Open dir handle + explicit dir(const std::string& path) { - open(dirname); + open(path); } - dir(dir&& other) - : m_dd(other.m_dd) - , m_path(std::move(other.m_path)) - { - } - - dir& operator =(dir&& right) - { - std::swap(m_dd, right.m_dd); - std::swap(m_path, right.m_path); - return *this; - } - - ~dir(); - - // Check whether the handle is valid (opened directory) - bool is_opened() const - { - return m_path.operator bool(); - } + // Open specified directory + bool open(const std::string& path); // Check whether the handle is valid (opened directory) explicit operator bool() const { - return is_opened(); + return m_dir.operator bool(); } - // Open specified directory - bool open(const std::string& dirname); - - // Close the directory explicitly (destructor automatically closes the directory) - void close(); - - // Get next directory entry (UTF-8 name and file stat) - bool read(std::string& name, stat_t& info); - - bool first(std::string& name, stat_t& info); - - struct entry + // Close the directory explicitly + void close() { - std::string name; - stat_t info; - }; + m_dir.reset(); + } + + void reset(std::unique_ptr&& ptr) + { + m_dir = std::move(ptr); + } + + std::unique_ptr release() + { + return std::move(m_dir); + } + + // Get next directory entry + bool read(dir_entry& out) const + { + if (!m_dir) xnull(); + return m_dir->read(out); + } + + // Reset to the beginning + void rewind() const + { + if (!m_dir) xnull(); + return m_dir->rewind(); + } class iterator { - entry m_entry; dir* m_parent; + dir_entry m_entry; public: enum class mode @@ -382,20 +383,16 @@ namespace fs if (mode_ == mode::from_first) { - m_parent->first(m_entry.name, m_entry.info); - } - else - { - m_parent->read(m_entry.name, m_entry.info); + m_parent->rewind(); } - if (m_entry.name.empty()) + if (!m_parent->read(m_entry)) { m_parent = nullptr; } } - entry& operator *() + dir_entry& operator *() { return m_entry; } @@ -414,7 +411,7 @@ namespace fs iterator begin() { - return{ this }; + return{ m_dir ? this : nullptr }; } iterator end() @@ -428,4 +425,10 @@ namespace fs // Get executable directory const std::string& get_executable_dir(); + + // Delete directory and all its contents recursively + void remove_all(const std::string& path); + + // Get size of all files recursively + u64 get_dir_size(const std::string& path); } diff --git a/Utilities/Log.cpp b/Utilities/Log.cpp index d86e235c62..08d6d7197e 100644 --- a/Utilities/Log.cpp +++ b/Utilities/Log.cpp @@ -1,26 +1,17 @@ -#include "stdafx.h" -#include "Thread.h" -#include "File.h" -#include "Log.h" - -#ifdef _WIN32 -#include -#endif +#include "Log.h" namespace _log { - logger& get_logger() + static file_listener& get_logger() { - // Use magic static for global logger instance - static logger instance; - return instance; + // Use magic static + static file_listener logger("RPCS3.log"); + return logger; } - file_listener g_log_file(_PRGNAME_ ".log"); - file_writer g_tty_file("TTY.log"); - channel GENERAL("", level::notice); + channel GENERAL(nullptr, level::notice); channel LOADER("LDR", level::notice); channel MEMORY("MEM", level::notice); channel RSX("RSX", level::notice); @@ -28,72 +19,29 @@ namespace _log channel PPU("PPU", level::notice); channel SPU("SPU", level::notice); channel ARMv7("ARMv7"); -} -_log::listener::listener() -{ - // Register self - get_logger().add_listener(this); -} - -_log::listener::~listener() -{ - // Unregister self - get_logger().remove_listener(this); -} - -_log::channel::channel(const std::string& name, _log::level init_level) - : name{ name } - , enabled{ init_level } -{ - // TODO: register config property "name" associated with "enabled" member -} - -void _log::logger::add_listener(_log::listener* listener) -{ - std::lock_guard lock(m_mutex); - - m_listeners.emplace(listener); -} - -void _log::logger::remove_listener(_log::listener* listener) -{ - std::lock_guard lock(m_mutex); - - m_listeners.erase(listener); -} - -void _log::logger::broadcast(const _log::channel& ch, _log::level sev, const std::string& text) const -{ - reader_lock lock(m_mutex); - - for (auto listener : m_listeners) - { - listener->log(ch, sev, text); - } + thread_local std::string(*g_tls_make_prefix)(const channel&, level, const std::string&) = nullptr; } void _log::broadcast(const _log::channel& ch, _log::level sev, const std::string& text) { - get_logger().broadcast(ch, sev, text); + get_logger().log(ch, sev, text); } +[[noreturn]] extern void catch_all_exceptions(); + _log::file_writer::file_writer(const std::string& name) { try { - if (!m_file.open(fs::get_config_dir() + name, fom::rewrite | fom::append)) + if (!m_file.open(fs::get_config_dir() + name, fs::rewrite + fs::append)) { - throw EXCEPTION("Can't create log file %s (error %d)", name, errno); + throw fmt::exception("Can't create log file %s (error %d)", name, errno); } } - catch (const fmt::exception& e) + catch (...) { -#ifdef _WIN32 - MessageBoxA(0, e.what(), "_log::file_writer() failed", MB_ICONERROR); -#else - std::printf("_log::file_writer() failed: %s\n", e.what()); -#endif + catch_all_exceptions(); } } @@ -104,7 +52,7 @@ void _log::file_writer::log(const std::string& text) std::size_t _log::file_writer::size() const { - return m_file.seek(0, fs::seek_cur); + return m_file.pos(); } void _log::file_listener::log(const _log::channel& ch, _log::level sev, const std::string& text) @@ -126,14 +74,14 @@ void _log::file_listener::log(const _log::channel& ch, _log::level sev, const st // TODO: print time? - if (auto t = thread_ctrl::get_current()) + if (auto func = g_tls_make_prefix) { msg += '{'; - msg += t->get_name(); + msg += func(ch, sev, text); msg += "} "; } - - if (ch.name.size()) + + if (ch.name) { msg += ch.name; msg += sev == level::todo ? " TODO: " : ": "; diff --git a/Utilities/Log.h b/Utilities/Log.h index 11ef6c6c21..5f319ae480 100644 --- a/Utilities/Log.h +++ b/Utilities/Log.h @@ -1,6 +1,9 @@ #pragma once -#include "SharedMutex.h" +#include "types.h" +#include "Atomic.h" +#include "File.h" +#include "StrFmt.h" namespace _log { @@ -19,40 +22,24 @@ namespace _log struct channel; struct listener; - // Log manager - class logger final - { - mutable shared_mutex m_mutex; - - std::set m_listeners; - - public: - // Register listener - void add_listener(listener* listener); - - // Unregister listener - void remove_listener(listener* listener); - - // Send log message to all listeners - void broadcast(const channel& ch, level sev, const std::string& text) const; - }; - // Send log message to global logger instance void broadcast(const channel& ch, level sev, const std::string& text); - // Log channel (source) + // Log channel struct channel { - // Channel prefix (also used for identification) - const std::string name; + // Channel prefix (added to every log message) + const char* const name; // The lowest logging level enabled for this channel (used for early filtering) - std::atomic enabled; + atomic_t enabled; - // Initialization (max level enabled by default) - channel(const std::string& name, level = level::trace); - - virtual ~channel() = default; + // Constant initialization: name and initial log level + constexpr channel(const char* name, level enabled = level::trace) + : name{ name } + , enabled{ enabled } + { + } // Log without formatting force_inline void log(level sev, const std::string& text) const @@ -71,7 +58,7 @@ namespace _log #define GEN_LOG_METHOD(_sev)\ template\ - force_inline void _sev(const char* fmt, const Args&... args)\ + force_inline void _sev(const char* fmt, const Args&... args) const\ {\ return format(level::_sev, fmt, args...);\ } @@ -90,9 +77,9 @@ namespace _log // Log listener (destination) struct listener { - listener(); + listener() = default; - virtual ~listener(); + virtual ~listener() = default; virtual void log(const channel& ch, level sev, const std::string& text) = 0; }; @@ -126,9 +113,6 @@ namespace _log virtual void log(const channel& ch, level sev, const std::string& text) override; }; - // Global variable for RPCS3.log - extern file_listener g_log_file; - // Global variable for TTY.log extern file_writer g_tty_file; @@ -142,8 +126,26 @@ namespace _log extern channel PPU; extern channel SPU; extern channel ARMv7; + + extern thread_local std::string(*g_tls_make_prefix)(const channel&, level, const std::string&); } +template<> +struct bijective<_log::level, const char*> +{ + static constexpr std::pair<_log::level, const char*> map[] + { + { _log::level::always, "Nothing" }, + { _log::level::fatal, "Fatal" }, + { _log::level::error, "Error" }, + { _log::level::todo, "TODO" }, + { _log::level::success, "Success" }, + { _log::level::warning, "Warning" }, + { _log::level::notice, "Notice" }, + { _log::level::trace, "Trace" }, + }; +}; + // Legacy: #define LOG_SUCCESS(ch, fmt, ...) _log::ch.success(fmt, ##__VA_ARGS__) diff --git a/Utilities/Macro.h b/Utilities/Macro.h new file mode 100644 index 0000000000..d8fdc67f92 --- /dev/null +++ b/Utilities/Macro.h @@ -0,0 +1,79 @@ +#pragma once + +#include +#include + +template::value>> +constexpr T align(const T& value, std::uint64_t align) +{ + return static_cast((value + (align - 1)) & ~(align - 1)); +} + +template +constexpr To narrow_impl(const To& result, const From& value, const char* message) +{ + return static_cast(result) != value ? throw std::runtime_error(message) : result; +} + +// Narrow cast (similar to gsl::narrow) with fixed message +template +constexpr auto narrow(const From& value, const char* fixed_msg = "::narrow() failed") -> decltype(static_cast(static_cast(std::declval()))) +{ + return narrow_impl(static_cast(value), value, fixed_msg); +} + +// Return 32 bit .size() for container +template +constexpr auto size32(const CT& container, const char* fixed_msg = "::size32() failed") -> decltype(static_cast(container.size())) +{ + return narrow(container.size(), fixed_msg); +} + +// Return 32 bit size for an array +template +constexpr std::uint32_t size32(const T(&)[Size]) +{ + static_assert(Size <= UINT32_MAX, "size32() error: too big"); + return static_cast(Size); +} + +#define CHECK_SIZE(type, size) static_assert(sizeof(type) == size, "Invalid " #type " type size") +#define CHECK_ALIGN(type, align) static_assert(alignof(type) == align, "Invalid " #type " type alignment") +#define CHECK_MAX_SIZE(type, size) static_assert(sizeof(type) <= size, #type " type size is too big") +#define CHECK_SIZE_ALIGN(type, size, align) CHECK_SIZE(type, size); CHECK_ALIGN(type, align) + +// Return 32 bit sizeof() to avoid widening/narrowing conversions with size_t +#define SIZE_32(type) static_cast(sizeof(type)) + +// Return 32 bit alignof() to avoid widening/narrowing conversions with size_t +#define ALIGN_32(type) static_cast(alignof(type)) + +// Return 32 bit custom offsetof() +#define OFFSET_32(type, x) static_cast(reinterpret_cast(&reinterpret_cast(reinterpret_cast(0ull)->x))) + +// Sometimes to avoid writing std::remove_cv_t<>, example: std::is_same +#define CV const volatile + +#define CONCATENATE_DETAIL(x, y) x ## y +#define CONCATENATE(x, y) CONCATENATE_DETAIL(x, y) + +#define STRINGIZE_DETAIL(x) #x +#define STRINGIZE(x) STRINGIZE_DETAIL(x) + +// Macro set, allows to hide "return" in simple lambda expressions. +#define WRAP_EXPR(expr, ...) [&](__VA_ARGS__) { return expr; } +#define COPY_EXPR(expr, ...) [=](__VA_ARGS__) { return expr; } +#define PURE_EXPR(expr, ...) [] (__VA_ARGS__) { return expr; } + +#define HERE "\n(in file " __FILE__ ":" STRINGIZE(__LINE__) ")" + +// Ensure that the expression is evaluated to true. Always evaluated and allowed to have side effects (unlike assert() macro). +#define ASSERT(expr) if (!(expr)) throw std::runtime_error("Assertion failed: " #expr HERE) + +// Expects() and Ensures() are intended to check function arguments and results. +// Expressions are not guaranteed to evaluate. Redefinition with ASSERT macro for better unification. +#define Expects ASSERT +#define Ensures ASSERT + +#define DECLARE(static_member) decltype(static_member) static_member +#define STR_CASE(value) case value: return #value diff --git a/Utilities/GNU.cpp b/Utilities/Platform.cpp similarity index 98% rename from Utilities/GNU.cpp rename to Utilities/Platform.cpp index 29467b205f..9f2672997e 100644 --- a/Utilities/GNU.cpp +++ b/Utilities/Platform.cpp @@ -1,4 +1,4 @@ -#include "GNU.h" +#include "Platform.h" #ifdef __APPLE__ #include diff --git a/Utilities/GNU.h b/Utilities/Platform.h similarity index 58% rename from Utilities/GNU.h rename to Utilities/Platform.h index 268318e568..18d9297e24 100644 --- a/Utilities/GNU.h +++ b/Utilities/Platform.h @@ -1,17 +1,22 @@ #pragma once +#include +#include #include -#if defined(_MSC_VER) && _MSC_VER <= 1800 -#define thread_local __declspec(thread) -#elif __APPLE__ -#define thread_local __thread +#define IS_LE_MACHINE 1 +#define IS_BE_MACHINE 0 + +#ifdef _MSC_VER +#include +#else +#include #endif -#if defined(_MSC_VER) -#define never_inline __declspec(noinline) -#else -#define never_inline __attribute__((noinline)) +// Some platforms don't support thread_local well yet. +#ifndef _MSC_VER +#define thread_local __thread +#define __assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0) #endif #if defined(_MSC_VER) @@ -20,20 +25,21 @@ #define safe_buffers #endif +#if defined(_MSC_VER) +#define never_inline __declspec(noinline) +#else +#define never_inline __attribute__((noinline)) +#endif + #if defined(_MSC_VER) #define force_inline __forceinline #else #define force_inline __attribute__((always_inline)) inline #endif -#if defined(_MSC_VER) && _MSC_VER <= 1800 -#define alignas(x) _CRT_ALIGN(x) -#endif - #if defined(__GNUG__) #include -#include #define _fpclass(x) std::fpclassify(x) #define INFINITE 0xFFFFFFFF @@ -59,170 +65,6 @@ int clock_gettime(clockid_t clk_id, struct timespec *tp); #endif /* __APPLE__ */ #endif /* __GNUG__ */ -#if defined(_MSC_VER) - -// Unsigned 128-bit integer implementation -struct alignas(16) u128 -{ - std::uint64_t lo, hi; - - u128() = default; - - u128(const u128&) = default; - - u128(std::uint64_t l) - : lo(l) - , hi(0) - { - } - - u128 operator +(const u128& r) const - { - u128 value; - _addcarry_u64(_addcarry_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; - _addcarry_u64(_addcarry_u64(0, r, l.lo, &value.lo), l.hi, 0, &value.hi); - return value; - } - - 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; - } - - u128 operator -() const - { - u128 value; - _subborrow_u64(_subborrow_u64(0, lo, 0, &value.lo), hi, 0, &value.hi); - return value; - } - - u128& operator ++() - { - _addcarry_u64(_addcarry_u64(0, 1, lo, &lo), 0, hi, &hi); - return *this; - } - - u128 operator ++(int) - { - u128 value = *this; - _addcarry_u64(_addcarry_u64(0, 1, lo, &lo), 0, hi, &hi); - return value; - } - - u128& operator --() - { - _subborrow_u64(_subborrow_u64(0, 1, lo, &lo), 0, hi, &hi); - return *this; - } - - u128 operator --(int) - { - u128 value = *this; - _subborrow_u64(_subborrow_u64(0, 1, lo, &lo), 0, hi, &hi); - return value; - } - - u128 operator ~() const - { - u128 value; - value.lo = ~lo; - value.hi = ~hi; - return value; - } - - u128 operator &(const u128& r) const - { - u128 value; - value.lo = lo & r.lo; - value.hi = hi & r.hi; - return value; - } - - u128 operator |(const u128& r) const - { - u128 value; - value.lo = lo | r.lo; - value.hi = hi | r.hi; - return value; - } - - u128 operator ^(const u128& r) const - { - u128 value; - value.lo = lo ^ r.lo; - value.hi = hi ^ r.hi; - return value; - } - - u128& operator +=(const u128& r) - { - _addcarry_u64(_addcarry_u64(0, r.lo, lo, &lo), r.hi, hi, &hi); - return *this; - } - - u128& operator +=(uint64_t r) - { - _addcarry_u64(_addcarry_u64(0, r, lo, &lo), 0, hi, &hi); - return *this; - } - - u128& operator &=(const u128& r) - { - lo &= r.lo; - hi &= r.hi; - return *this; - } - - u128& operator |=(const u128& r) - { - lo |= r.lo; - hi |= r.hi; - return *this; - } - - u128& operator ^=(const u128& r) - { - lo ^= r.lo; - hi ^= r.hi; - return *this; - } -}; -#endif - inline std::uint32_t cntlz32(std::uint32_t arg) { #if defined(_MSC_VER) @@ -243,7 +85,67 @@ inline std::uint64_t cntlz64(std::uint64_t arg) #endif } -// compare 16 packed unsigned bytes (greater than) +template +struct add_flags_result_t +{ + T result; + bool carry; + //bool overflow; + bool zero; + bool sign; + + add_flags_result_t() = default; + + // Straighforward ADD with flags + add_flags_result_t(T a, T b) + : result(a + b) + , carry(result < a) + //, overflow((result ^ ~(a ^ b)) >> (sizeof(T) * 8 - 1) != 0) + , zero(result == 0) + , sign(result >> (sizeof(T) * 8 - 1) != 0) + { + } + + // Straighforward ADC with flags + add_flags_result_t(T a, T b, bool c) + : add_flags_result_t(a, b) + { + add_flags_result_t r(result, c); + result = r.result; + carry |= r.carry; + //overflow |= r.overflow; + zero = r.zero; + sign = r.sign; + } +}; + +inline add_flags_result_t add32_flags(std::uint32_t a, std::uint32_t b) +{ + //add_flags_result_t r; + //r.carry = _addcarry_u32(0, a, b, &r.result) != 0; + //r.zero = r.result == 0; + //r.sign = r.result >> 31; + //return r; + + return{ a, b }; +} + +inline add_flags_result_t add32_flags(std::uint32_t a, std::uint32_t b, bool c) +{ + return{ a, b, c }; +} + +inline add_flags_result_t add64_flags(std::uint64_t a, std::uint64_t b) +{ + return{ a, b }; +} + +inline add_flags_result_t add64_flags(std::uint64_t a, std::uint64_t b, bool c) +{ + return{ a, b, c }; +} + +// Compare 16 packed unsigned bytes (greater than) inline __m128i sse_cmpgt_epu8(__m128i A, __m128i B) { // (A xor 0x80) > (B xor 0x80) @@ -290,3 +192,36 @@ inline __m128 sse_log2_ps(__m128 A) const auto x8 = _mm_cvtepi32_ps(_mm_sub_epi32(_mm_srli_epi32(_mm_castps_si128(x0), 23), _mm_set1_epi32(127))); return _mm_add_ps(_mm_mul_ps(_mm_mul_ps(_mm_mul_ps(_mm_mul_ps(x5, x6), x7), x4), _c), _mm_add_ps(_mm_mul_ps(x4, _c), x8)); } + +// Helper function, used by ""_u16, ""_u32, ""_u64 +constexpr std::uint8_t to_u8(char c) +{ + return static_cast(c); +} + +// Convert 2-byte string to u16 value like reinterpret_cast does +constexpr std::uint16_t operator""_u16(const char* s, std::size_t length) +{ + return length != 2 ? throw s : +#if IS_LE_MACHINE == 1 + to_u8(s[1]) << 8 | to_u8(s[0]); +#endif +} + +// Convert 4-byte string to u32 value like reinterpret_cast does +constexpr std::uint32_t operator""_u32(const char* s, std::size_t length) +{ + return length != 4 ? throw s : +#if IS_LE_MACHINE == 1 + to_u8(s[3]) << 24 | to_u8(s[2]) << 16 | to_u8(s[1]) << 8 | to_u8(s[0]); +#endif +} + +// Convert 8-byte string to u64 value like reinterpret_cast does +constexpr std::uint64_t operator""_u64(const char* s, std::size_t length) +{ + return length != 8 ? throw s : +#if IS_LE_MACHINE == 1 + static_cast(to_u8(s[7]) << 24 | to_u8(s[6]) << 16 | to_u8(s[5]) << 8 | to_u8(s[4])) << 32 | to_u8(s[3]) << 24 | to_u8(s[2]) << 16 | to_u8(s[1]) << 8 | to_u8(s[0]); +#endif +} diff --git a/Utilities/Semaphore.cpp b/Utilities/Semaphore.cpp index ed3d419e12..e6ea21b123 100644 --- a/Utilities/Semaphore.cpp +++ b/Utilities/Semaphore.cpp @@ -10,7 +10,7 @@ bool semaphore_t::try_wait() } // try to decrement m_value atomically - const auto old = m_var.atomic_op([](sync_var_t& var) + const auto old = m_var.fetch_op([](sync_var_t& var) { if (var.value) { @@ -36,7 +36,7 @@ bool semaphore_t::try_post() } // try to increment m_value atomically - const auto old = m_var.atomic_op([&](sync_var_t& var) + const auto old = m_var.fetch_op([&](sync_var_t& var) { if (var.value < max_value) { diff --git a/Utilities/Semaphore.h b/Utilities/Semaphore.h index 8ed96f4275..ea3c2c4e5c 100644 --- a/Utilities/Semaphore.h +++ b/Utilities/Semaphore.h @@ -8,7 +8,7 @@ class semaphore_t // semaphore condition variable std::condition_variable m_cv; - struct sync_var_t + struct alignas(8) sync_var_t { u32 value; // current semaphore value u32 waiters; // current amount of waiters diff --git a/Utilities/SharedMutex.cpp b/Utilities/SharedMutex.cpp deleted file mode 100644 index 728e4e4437..0000000000 --- a/Utilities/SharedMutex.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include "stdafx.h" -#include "SharedMutex.h" - -void shared_mutex::impl_lock_shared(u32 old_value) -{ - // Throw if reader count breaks the "second" limit (it should be impossible) - CHECK_ASSERTION((old_value & SM_READER_COUNT) != SM_READER_COUNT); - - std::unique_lock lock(m_mutex); - - // Notify non-zero reader queue size - m_ctrl |= SM_READER_QUEUE; - - // Compensate incorrectly increased reader count - if ((--m_ctrl & SM_READER_COUNT) == 0 && m_wq_size) - { - // Notify current exclusive owner (condition passed) - m_ocv.notify_one(); - } - - CHECK_ASSERTION(++m_rq_size); - - // Obtain the reader lock - while (!atomic_op(m_ctrl, op_lock_shared)) - { - m_rcv.wait(lock); - } - - CHECK_ASSERTION(m_rq_size--); - - if (m_rq_size == 0) - { - m_ctrl &= ~SM_READER_QUEUE; - } -} - -void shared_mutex::impl_unlock_shared(u32 new_value) -{ - // Throw if reader count was zero - CHECK_ASSERTION((new_value & SM_READER_COUNT) != SM_READER_COUNT); - - // Mutex cannot be unlocked before notification because m_ctrl has been changed outside - std::lock_guard lock(m_mutex); - - if (m_wq_size && (new_value & SM_READER_COUNT) == 0) - { - // Notify current exclusive owner that the latest reader is gone - m_ocv.notify_one(); - } - else if (m_rq_size) - { - m_rcv.notify_one(); - } -} - -void shared_mutex::impl_lock_excl(u32 value) -{ - std::unique_lock lock(m_mutex); - - // Notify non-zero writer queue size - m_ctrl |= SM_WRITER_QUEUE; - - CHECK_ASSERTION(++m_wq_size); - - // Obtain the writer lock - while (!atomic_op(m_ctrl, op_lock_excl)) - { - m_wcv.wait(lock); - } - - // Wait for remaining readers - while ((m_ctrl & SM_READER_COUNT) != 0) - { - m_ocv.wait(lock); - } - - CHECK_ASSERTION(m_wq_size--); - - if (m_wq_size == 0) - { - m_ctrl &= ~SM_WRITER_QUEUE; - } -} - -void shared_mutex::impl_unlock_excl(u32 value) -{ - // Throw if was not locked exclusively - CHECK_ASSERTION(value & SM_WRITER_LOCK); - - // Mutex cannot be unlocked before notification because m_ctrl has been changed outside - std::lock_guard lock(m_mutex); - - if (m_wq_size) - { - // Notify next exclusive owner - m_wcv.notify_one(); - } - else if (m_rq_size) - { - // Notify all readers - m_rcv.notify_all(); - } -} diff --git a/Utilities/SharedMutex.h b/Utilities/SharedMutex.h index 961ef1dd23..361f94f2ee 100644 --- a/Utilities/SharedMutex.h +++ b/Utilities/SharedMutex.h @@ -1,49 +1,156 @@ #pragma once +#include +#include +#include +#include +#include + +#include "Atomic.h" + //! An attempt to create effective implementation of "shared mutex", lock-free in optimistic case. //! All locking and unlocking may be done by single LOCK XADD or LOCK CMPXCHG instructions. //! MSVC implementation of std::shared_timed_mutex seems suboptimal. //! std::shared_mutex is not available until C++17. class shared_mutex final { - enum : u32 - { - SM_WRITER_LOCK = 1u << 31, // Exclusive lock flag, must be MSB - SM_WRITER_QUEUE = 1u << 30, // Flag set if m_wq_size != 0 - SM_READER_QUEUE = 1u << 29, // Flag set if m_rq_size != 0 + using ctrl_type = u32; - SM_READER_COUNT = SM_READER_QUEUE - 1, // Valid reader count bit mask - SM_READER_MAX = 1u << 24, // Max reader count + enum : ctrl_type + { + SM_WRITER_LOCK = 1u << 31, // Exclusive lock flag, must be MSB + SM_WAITERS_BIT = 1u << 30, // Flag set if m_wq_size or m_rq_size is non-zero + SM_INVALID_BIT = 1u << 29, // Unreachable reader count bit (may be set by incorrect unlock_shared() call) + + SM_READER_MASK = SM_WAITERS_BIT - 1, // Valid reader count bit mask + SM_READER_MAX = 1u << 24, // Max reader count }; - std::atomic m_ctrl{}; // Control atomic variable: reader count | SM_* flags - std::thread::id m_owner{}; // Current exclusive owner (TODO: implement only for debug mode?) + atomic_t m_ctrl{}; // Control atomic variable: reader count | SM_* flags std::mutex m_mutex; - u32 m_rq_size{}; // Reader queue size (threads waiting on m_rcv) - u32 m_wq_size{}; // Writer queue size (threads waiting on m_wcv+m_ocv) + std::size_t m_rq_size{}; // Reader queue size (threads waiting on m_rcv) + std::size_t m_wq_size{}; // Writer queue size (threads waiting on m_wcv and m_ocv) std::condition_variable m_rcv; // Reader queue std::condition_variable m_wcv; // Writer queue std::condition_variable m_ocv; // For current exclusive owner - static bool op_lock_shared(u32& ctrl) + void lock_shared_hard() { - // Check writer flags and reader limit - return (ctrl & ~SM_READER_QUEUE) < SM_READER_MAX ? ctrl++, true : false; + std::unique_lock lock(m_mutex); + + // Validate + if ((m_ctrl & SM_INVALID_BIT) != 0) throw std::runtime_error("shared_mutex::lock_shared(): Invalid bit"); + if ((m_ctrl & SM_READER_MASK) == 0) throw std::runtime_error("shared_mutex::lock_shared(): No readers"); + + // Notify non-zero reader queue size + m_ctrl |= SM_WAITERS_BIT, m_rq_size++; + + // Fix excess reader count + if ((--m_ctrl & SM_READER_MASK) == 0 && m_wq_size) + { + // Notify exclusive owner + m_ocv.notify_one(); + } + + // Obtain the reader lock + while (true) + { + const auto ctrl = m_ctrl.load(); + + // Check writers and reader limit + if (m_wq_size || (ctrl & ~SM_WAITERS_BIT) >= SM_READER_MAX) + { + m_rcv.wait(lock); + continue; + } + + if (m_ctrl.compare_and_swap_test(ctrl, ctrl + 1)) + { + break; + } + } + + if (!--m_rq_size && !m_wq_size) + { + m_ctrl &= ~SM_WAITERS_BIT; + } } - static bool op_lock_excl(u32& ctrl) + void unlock_shared_notify() { - // Test and set writer lock - return (ctrl & SM_WRITER_LOCK) == 0 ? ctrl |= SM_WRITER_LOCK, true : false; + // Mutex is locked for reliable notification because m_ctrl has been changed outside + std::lock_guard lock(m_mutex); + + if ((m_ctrl & SM_READER_MASK) == 0 && m_wq_size) + { + // Notify exclusive owner + m_ocv.notify_one(); + } + else if (m_rq_size) + { + // Notify other readers + m_rcv.notify_one(); + } } - void impl_lock_shared(u32 old_ctrl); - void impl_unlock_shared(u32 new_ctrl); - void impl_lock_excl(u32 ctrl); - void impl_unlock_excl(u32 ctrl); + void lock_hard() + { + std::unique_lock lock(m_mutex); + + // Validate + if ((m_ctrl & SM_INVALID_BIT) != 0) throw std::runtime_error("shared_mutex::lock(): Invalid bit"); + + // Notify non-zero writer queue size + m_ctrl |= SM_WAITERS_BIT, m_wq_size++; + + // Obtain the writer lock + while (true) + { + const auto ctrl = m_ctrl.load(); + + if (ctrl & SM_WRITER_LOCK) + { + m_wcv.wait(lock); + continue; + } + + if (m_ctrl.compare_and_swap_test(ctrl, ctrl | SM_WRITER_LOCK)) + { + break; + } + } + + // Wait for remaining readers + while ((m_ctrl & SM_READER_MASK) != 0) + { + m_ocv.wait(lock); + } + + if (!--m_wq_size && !m_rq_size) + { + m_ctrl &= ~SM_WAITERS_BIT; + } + } + + void unlock_notify() + { + // Mutex is locked for reliable notification because m_ctrl has been changed outside + std::lock_guard lock(m_mutex); + + if (m_wq_size) + { + // Notify next exclusive owner + m_wcv.notify_one(); + } + else if (m_rq_size) + { + // Notify all readers + m_rcv.notify_all(); + } + } public: shared_mutex() = default; @@ -51,65 +158,49 @@ public: // Lock in shared mode void lock_shared() { - const u32 old_ctrl = m_ctrl++; - - // Check flags and reader limit - if (old_ctrl >= SM_READER_MAX) + if (m_ctrl++ >= SM_READER_MAX) { - impl_lock_shared(old_ctrl); + lock_shared_hard(); } } // Try to lock in shared mode bool try_lock_shared() { - return atomic_op(m_ctrl, [](u32& ctrl) - { - // Check flags and reader limit - return ctrl < SM_READER_MAX ? ctrl++, true : false; - }); + auto ctrl = m_ctrl.load(); + + return ctrl < SM_READER_MAX && m_ctrl.compare_and_swap_test(ctrl, ctrl + 1); } // Unlock in shared mode void unlock_shared() { - const u32 new_ctrl = --m_ctrl; - - // Check if notification required - if (new_ctrl >= SM_READER_MAX) + if (m_ctrl-- >= SM_READER_MAX) { - impl_unlock_shared(new_ctrl); - } - } - - // Lock exclusively - void lock() - { - u32 value = 0; - - if (!m_ctrl.compare_exchange_strong(value, SM_WRITER_LOCK)) - { - impl_lock_excl(value); + unlock_shared_notify(); } } // Try to lock exclusively bool try_lock() { - u32 value = 0; + return m_ctrl.compare_and_swap_test(0, SM_WRITER_LOCK); + } - return m_ctrl.compare_exchange_strong(value, SM_WRITER_LOCK); + // Lock exclusively + void lock() + { + if (m_ctrl.compare_and_swap_test(0, SM_WRITER_LOCK)) return; + + lock_hard(); } // Unlock exclusively void unlock() { - const u32 value = m_ctrl.fetch_add(SM_WRITER_LOCK); - - // Check if notification required - if (value != SM_WRITER_LOCK) + if (m_ctrl.fetch_sub(SM_WRITER_LOCK) != SM_WRITER_LOCK) { - impl_unlock_excl(value); + unlock_notify(); } } }; diff --git a/Utilities/SleepQueue.cpp b/Utilities/SleepQueue.cpp deleted file mode 100644 index d7f432cea6..0000000000 --- a/Utilities/SleepQueue.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "stdafx.h" -#include "Emu/CPU/CPUThread.h" - -#include "SleepQueue.h" - -void sleep_queue_entry_t::add_entry() -{ - m_queue.emplace_back(std::static_pointer_cast(m_thread.shared_from_this())); -} - -void sleep_queue_entry_t::remove_entry() -{ - for (auto it = m_queue.begin(); it != m_queue.end(); it++) - { - if (it->get() == &m_thread) - { - m_queue.erase(it); - return; - } - } -} - -bool sleep_queue_entry_t::find() const -{ - for (auto it = m_queue.begin(); it != m_queue.end(); it++) - { - if (it->get() == &m_thread) - { - return true; - } - } - - return false; -} - -sleep_queue_entry_t::sleep_queue_entry_t(sleep_entry_t& cpu, sleep_queue_t& queue) - : m_thread(cpu) - , m_queue(queue) -{ - add_entry(); - cpu.sleep(); -} - -sleep_queue_entry_t::sleep_queue_entry_t(sleep_entry_t& cpu, sleep_queue_t& queue, const defer_sleep_t&) - : m_thread(cpu) - , m_queue(queue) -{ - cpu.sleep(); -} - -sleep_queue_entry_t::~sleep_queue_entry_t() -{ - remove_entry(); - m_thread.awake(); -} diff --git a/Utilities/SleepQueue.h b/Utilities/SleepQueue.h index e66a284c65..fc97baad52 100644 --- a/Utilities/SleepQueue.h +++ b/Utilities/SleepQueue.h @@ -1,45 +1,75 @@ #pragma once -using sleep_entry_t = class CPUThread; -using sleep_queue_t = std::deque>; +#include -static struct defer_sleep_t {} const defer_sleep{}; +// Tag used in sleep_entry<> constructor +static struct defer_sleep_tag {} constexpr defer_sleep{}; -// automatic object handling a thread entry in the sleep queue -class sleep_queue_entry_t final +// Define sleep queue as std::deque with T* pointers, T - thread type +template using sleep_queue = std::deque; + +// Automatic object handling a thread pointer (T*) in the sleep queue +// Sleep is called in the constructor (if not null) +// Awake is called in the destructor (if not null) +// Sleep queue is actually std::deque with pointers, be careful about the lifetime +template +class sleep_entry final { - sleep_entry_t& m_thread; - sleep_queue_t& m_queue; - - void add_entry(); - void remove_entry(); - bool find() const; + sleep_queue& m_queue; + T& m_thread; public: - // add specified thread to the sleep queue - sleep_queue_entry_t(sleep_entry_t& entry, sleep_queue_t& queue); + // Constructor; enter() not called + sleep_entry(sleep_queue& queue, T& entry, const defer_sleep_tag&) + : m_queue(queue) + , m_thread(entry) + { + if (Sleep) (m_thread.*Sleep)(); + } - // don't add specified thread to the sleep queue - sleep_queue_entry_t(sleep_entry_t& entry, sleep_queue_t& queue, const defer_sleep_t&); + // Constructor; calls enter() + sleep_entry(sleep_queue& queue, T& entry) + : sleep_entry(queue, entry, defer_sleep) + { + enter(); + } - // removes specified thread from the sleep queue if added - ~sleep_queue_entry_t(); + // Destructor; calls leave() + ~sleep_entry() + { + leave(); + if (Awake) (m_thread.*Awake)(); + } - // add thread to the sleep queue + // Add thread to the sleep queue void enter() { - add_entry(); + for (auto t : m_queue) + { + if (t == &m_thread) + { + // Already exists, is it an error? + return; + } + } + + m_queue.emplace_back(&m_thread); } - // remove thread from the sleep queue + // Remove thread from the sleep queue void leave() { - remove_entry(); + auto it = std::find(m_queue.begin(), m_queue.end(), &m_thread); + + if (it != m_queue.end()) + { + m_queue.erase(it); + } } - // check whether the thread exists in the sleep queue + // Check whether the thread exists in the sleep queue explicit operator bool() const { - return find(); + return std::find(m_queue.begin(), m_queue.end(), &m_thread) != m_queue.end(); } }; diff --git a/Utilities/StrFmt.cpp b/Utilities/StrFmt.cpp index 8e67616579..1b7df25a4d 100644 --- a/Utilities/StrFmt.cpp +++ b/Utilities/StrFmt.cpp @@ -1,9 +1,5 @@ -#include "stdafx.h" -#pragma warning(push) -#pragma message("TODO: remove wx dependency: ") -#pragma warning(disable : 4996) -#include -#pragma warning(pop) +#include "StrFmt.h" +#include "BEType.h" std::string v128::to_hex() const { @@ -19,7 +15,7 @@ std::string fmt::to_hex(u64 value, u64 count) { if (count - 1 >= 16) { - throw EXCEPTION("Invalid count: 0x%llx", count); + throw exception("fmt::to_hex(): invalid count: 0x%llx", count); } count = std::max(count, 16 - cntlz64(value) / 4); @@ -78,8 +74,6 @@ std::string fmt::to_sdec(s64 svalue) return std::string(&res[first], sizeof(res) - first); } -//extern const std::string fmt::placeholder = "???"; - std::string fmt::replace_first(const std::string& src, const std::string& from, const std::string& to) { auto pos = src.find(from); @@ -104,83 +98,6 @@ std::string fmt::replace_all(const std::string &src, const std::string& from, co return target; } -//TODO: move this wx Stuff somewhere else -//convert a wxString to a std::string encoded in utf8 -//CAUTION, only use this to interface with wxWidgets classes -std::string fmt::ToUTF8(const wxString& right) -{ - auto ret = std::string(((const char *)right.utf8_str())); - return ret; -} - -//convert a std::string encoded in utf8 to a wxString -//CAUTION, only use this to interface with wxWidgets classes -wxString fmt::FromUTF8(const std::string& right) -{ - auto ret = wxString::FromUTF8(right.c_str()); - return ret; -} - -//TODO: remove this after every snippet that uses it is gone -//WARNING: not fully compatible with CmpNoCase from wxString -int fmt::CmpNoCase(const std::string& a, const std::string& b) -{ - if (a.length() != b.length()) - { - return -1; - } - else - { - return std::equal(a.begin(), - a.end(), - b.begin(), - [](const char& a, const char& b){return ::tolower(a) == ::tolower(b); }) - ? 0 : -1; - } -} - -//TODO: remove this after every snippet that uses it is gone -//WARNING: not fully compatible with CmpNoCase from wxString -void fmt::Replace(std::string &str, const std::string &searchterm, const std::string& replaceterm) -{ - size_t cursor = 0; - do - { - cursor = str.find(searchterm, cursor); - if (cursor != std::string::npos) - { - str.replace(cursor, searchterm.size(), replaceterm); - cursor += replaceterm.size(); - } - else - { - break; - } - } while (true); -} - -std::vector fmt::rSplit(const std::string& source, const std::string& delim) -{ - std::vector ret; - size_t cursor = 0; - do - { - size_t prevcurs = cursor; - cursor = source.find(delim, cursor); - if (cursor != std::string::npos) - { - ret.push_back(source.substr(prevcurs,cursor-prevcurs)); - cursor += delim.size(); - } - else - { - ret.push_back(source.substr(prevcurs)); - break; - } - } while (true); - return ret; -} - std::vector fmt::split(const std::string& source, std::initializer_list separators, bool is_skip_empty) { std::vector result; @@ -222,21 +139,7 @@ std::string fmt::trim(const std::string& source, const std::string& values) return source.substr(begin, source.find_last_not_of(values) + 1); } -std::string fmt::tolower(std::string source) -{ - std::transform(source.begin(), source.end(), source.begin(), ::tolower); - - return source; -} - -std::string fmt::toupper(std::string source) -{ - std::transform(source.begin(), source.end(), source.begin(), ::toupper); - - return source; -} - -std::string fmt::escape(std::string source) +std::string fmt::escape(const std::string& source, std::initializer_list more) { const std::pair escape_list[] = { @@ -244,20 +147,66 @@ std::string fmt::escape(std::string source) { "\a", "\\a" }, { "\b", "\\b" }, { "\f", "\\f" }, - { "\n", "\\n\n" }, + { "\n", "\\n" }, { "\r", "\\r" }, { "\t", "\\t" }, { "\v", "\\v" }, }; - source = fmt::replace_all(source, escape_list); + std::string result = fmt::replace_all(source, escape_list); for (char c = 0; c < 32; c++) { - if (c != '\n') source = fmt::replace_all(source, std::string(1, c), fmt::format("\\x%02X", c)); + result = fmt::replace_all(result, std::string(1, c), fmt::format("\\x%02X", c)); } - return source; + for (char c : more) + { + result = fmt::replace_all(result, std::string(1, c), fmt::format("\\x%02X", c)); + } + + return result; +} + +std::string fmt::unescape(const std::string& source) +{ + std::string result; + + for (auto it = source.begin(); it != source.end();) + { + const char bs = *it++; + + if (bs == '\\' && it != source.end()) + { + switch (const char code = *it++) + { + case 'a': result += '\a'; break; + case 'b': result += '\b'; break; + case 'f': result += '\f'; break; + case 'n': result += '\n'; break; + case 'r': result += '\r'; break; + case 't': result += '\t'; break; + case 'v': result += '\v'; break; + case 'x': + { + // Detect hexadecimal character code (TODO) + if (source.end() - it >= 2) + { + result += std::stoi(std::string{ *it++, *it++ }, 0, 16); + } + + } + // Octal/unicode not supported + default: result += code; + } + } + else + { + result += bs; + } + } + + return result; } bool fmt::match(const std::string &source, const std::string &mask) diff --git a/Utilities/StrFmt.h b/Utilities/StrFmt.h index 02f544a58b..d88a4a7cef 100644 --- a/Utilities/StrFmt.h +++ b/Utilities/StrFmt.h @@ -1,95 +1,38 @@ #pragma once -class wxString; +#include +#include +#include +#include +#include + +#include "Platform.h" +#include "types.h" #if defined(_MSC_VER) && _MSC_VER <= 1800 #define snprintf _snprintf #endif +// Copy null-terminated string from std::string to char array with truncation +template +inline void strcpy_trunc(char(&dst)[N], const std::string& src) +{ + const std::size_t count = src.size() >= N ? N - 1 : src.size(); + std::memcpy(dst, src.c_str(), count); + dst[count] = '\0'; +} + +// Copy null-terminated string from char array to another char array with truncation +template +inline void strcpy_trunc(char(&dst)[N], const char(&src)[N2]) +{ + const std::size_t count = N2 >= N ? N - 1 : N2; + std::memcpy(dst, src, count); + dst[count] = '\0'; +} + namespace fmt { - //struct empty_t{}; - - //extern const std::string placeholder; - - template - std::string AfterLast(const std::string& source, T searchstr) - { - size_t search_pos = source.rfind(searchstr); - search_pos = search_pos == std::string::npos ? 0 : search_pos; - return source.substr(search_pos); - } - - template - std::string BeforeLast(const std::string& source, T searchstr) - { - size_t search_pos = source.rfind(searchstr); - search_pos = search_pos == std::string::npos ? 0 : search_pos; - return source.substr(0, search_pos); - } - - template - std::string AfterFirst(const std::string& source, T searchstr) - { - size_t search_pos = source.find(searchstr); - search_pos = search_pos == std::string::npos ? 0 : search_pos; - return source.substr(search_pos); - } - - template - std::string BeforeFirst(const std::string& source, T searchstr) - { - size_t search_pos = source.find(searchstr); - search_pos = search_pos == std::string::npos ? 0 : search_pos; - return source.substr(0, search_pos); - } - - // write `fmt` from `pos` to the first occurence of `fmt::placeholder` to - // the stream `os`. Then write `arg` to to the stream. If there's no - // `fmt::placeholder` after `pos` everything in `fmt` after pos is written - // to `os`. Then `arg` is written to `os` after appending a space character - //template - //empty_t write(const std::string &fmt, std::ostream &os, std::string::size_type &pos, T &&arg) - //{ - // std::string::size_type ins = fmt.find(placeholder, pos); - - // if (ins == std::string::npos) - // { - // os.write(fmt.data() + pos, fmt.size() - pos); - // os << ' ' << arg; - - // pos = fmt.size(); - // } - // else - // { - // os.write(fmt.data() + pos, ins - pos); - // os << arg; - - // pos = ins + placeholder.size(); - // } - // return{}; - //} - - // typesafe version of a sprintf-like function. Returns the printed to - // string. To mark positions where the arguments are supposed to be - // inserted use `fmt::placeholder`. If there's not enough placeholders - // the rest of the arguments are appended at the end, seperated by spaces - //template - //std::string SFormat(const std::string &fmt, Args&& ... parameters) - //{ - // std::ostringstream os; - // std::string::size_type pos = 0; - // std::initializer_list { write(fmt, os, pos, parameters)... }; - - // if (!fmt.empty()) - // { - // os.write(fmt.data() + pos, fmt.size() - pos); - // } - - // std::string result = os.str(); - // return result; - //} - std::string replace_first(const std::string& src, const std::string& from, const std::string& to); std::string replace_all(const std::string &src, const std::string& from, const std::string& to); @@ -145,7 +88,8 @@ namespace fmt std::string to_udec(u64 value); std::string to_sdec(s64 value); - template::value> struct unveil + template + struct unveil { using result_type = T; @@ -155,37 +99,41 @@ namespace fmt } }; - template<> struct unveil + template<> + struct unveil { using result_type = const char* const; - force_inline static result_type get_value(const char* const& arg) + static result_type get_value(const char* const& arg) { return arg; } }; - template struct unveil + template + struct unveil { using result_type = const char* const; - force_inline static result_type get_value(const char(&arg)[N]) + static result_type get_value(const char(&arg)[N]) { return arg; } }; - template<> struct unveil + template<> + struct unveil { using result_type = const char*; - force_inline static result_type get_value(const std::string& arg) + static result_type get_value(const std::string& arg) { return arg.c_str(); } }; - template struct unveil + template + struct unveil::value>> { using result_type = std::underlying_type_t; @@ -195,31 +143,13 @@ namespace fmt } }; - template struct unveil, false> - { - using result_type = typename unveil::result_type; - - force_inline static result_type get_value(const se_t& arg) - { - return unveil::get_value(arg); - } - }; - template force_inline typename unveil::result_type do_unveil(const T& arg) { return unveil::get_value(arg); } - // Formatting function with special functionality: - // - // std::string is forced to .c_str() - // be_t<> is forced to .value() (fmt::do_unveil reverts byte order automatically) - // - // External specializations for fmt::do_unveil (can be found in another headers): - // vm::ptr, vm::bptr, ... (fmt::do_unveil) (vm_ptr.h) (with appropriate address type, using .addr() can be avoided) - // vm::ref, vm::bref, ... (fmt::do_unveil) (vm_ref.h) - // + // Formatting function with special functionality (fmt::unveil) template safe_buffers std::string format(const char* fmt, const Args&... args) { @@ -256,51 +186,28 @@ namespace fmt } } - struct exception : public std::exception + // Create exception of type T (std::runtime_error by default) with formatting + template + never_inline safe_buffers T exception(const char* fmt, const Args&... args) noexcept(noexcept(T{ fmt })) { - std::unique_ptr message; + return T{ format(fmt, do_unveil(args)...).c_str() }; + } - template never_inline safe_buffers exception(const char* file, int line, const char* func, const char* text, Args... args) noexcept - { - const std::string data = format(text, args...) + format("\n(in file %s:%d, in function %s)", file, line, func); + // Create exception of type T (std::runtime_error by default) without formatting + template + safe_buffers T exception(const char* msg) noexcept(noexcept(T{ msg })) + { + return T{ msg }; + } - message.reset(new char[data.size() + 1]); - - std::memcpy(message.get(), data.c_str(), data.size() + 1); - } - - exception(const exception& other) noexcept - { - const std::size_t size = std::strlen(other.message.get()); - - message.reset(new char[size + 1]); - - std::memcpy(message.get(), other.message.get(), size + 1); - } - - virtual const char* what() const noexcept override - { - return message.get(); - } - }; - - //convert a wxString to a std::string encoded in utf8 - //CAUTION, only use this to interface with wxWidgets classes - std::string ToUTF8(const wxString& right); - - //convert a std::string encoded in utf8 to a wxString - //CAUTION, only use this to interface with wxWidgets classes - wxString FromUTF8(const std::string& right); - - //TODO: remove this after every snippet that uses it is gone - //WARNING: not fully compatible with CmpNoCase from wxString - int CmpNoCase(const std::string& a, const std::string& b); - - //TODO: remove this after every snippet that uses it is gone - //WARNING: not fully compatible with Replace from wxString - void Replace(std::string &str, const std::string &searchterm, const std::string& replaceterm); - - std::vector rSplit(const std::string& source, const std::string& delim); + // Narrow cast (similar to gsl::narrow) with exception message formatting + template + inline auto narrow(const char* format_str, const From& value, const Args&... args) -> decltype(static_cast(static_cast(std::declval()))) + { + const auto result = static_cast(value); + if (static_cast(result) != value) throw fmt::exception(format_str, fmt::do_unveil(value), fmt::do_unveil(args)...); + return result; + } std::vector split(const std::string& source, std::initializer_list separators, bool is_skip_empty = true); std::string trim(const std::string& source, const std::string& values = " \t"); @@ -352,8 +259,35 @@ namespace fmt return result; } - std::string tolower(std::string source); - std::string toupper(std::string source); - std::string escape(std::string source); + template + std::string to_lower(IT _begin, IT _end) + { + std::string result; result.resize(_end - _begin); + std::transform(_begin, _end, result.begin(), ::tolower); + return result; + } + + template + std::string to_lower(const T& string) + { + return to_lower(std::begin(string), std::end(string)); + } + + template + std::string to_upper(IT _begin, IT _end) + { + std::string result; result.resize(_end - _begin); + std::transform(_begin, _end, result.begin(), ::toupper); + return result; + } + + template + std::string to_upper(const T& string) + { + return to_upper(std::begin(string), std::end(string)); + } + + std::string escape(const std::string& source, std::initializer_list more = {}); + std::string unescape(const std::string& source); bool match(const std::string &source, const std::string &mask); } diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index 61619466a3..1fd83ba5b0 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -1,11 +1,8 @@ #include "stdafx.h" -#include "Log.h" +#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/state.h" -#include "Emu/CPU/CPUThreadManager.h" -#include "Emu/CPU/CPUThread.h" +#include "Emu/IdManager.h" #include "Emu/Cell/RawSPUThread.h" -#include "Emu/SysCalls/SysCalls.h" #include "Thread.h" #ifdef _WIN32 @@ -21,10 +18,19 @@ static void report_fatal_error(const std::string& msg) { + std::string _msg = msg + "\n" + "HOW TO REPORT ERRORS:\n" + "1) Check the FAQ, readme, other sources. Please ensure that your hardware and software configuration is compliant.\n" + "2) You must provide FULL information: how to reproduce the error (your actions), RPCS3.log file, other *.log files whenever requested.\n" + "3) Please ensure that your software (game) is 'Playable' or close. Please note that 'Non-playable' games will be ignored.\n" + "4) If the software (game) is not 'Playable', please ensure that this error is unexpected, i.e. it didn't happen before or similar.\n" + "Please, don't send incorrect reports. Thanks for understanding.\n"; + #ifdef _WIN32 - MessageBoxA(0, msg.c_str(), "Fatal error", MB_ICONERROR); // TODO: unicode message + _msg += "Press (Ctrl+C) to copy this message."; + MessageBoxA(0, _msg.c_str(), "Fatal error", MB_ICONERROR); // TODO: unicode message #else - std::printf("Fatal error: %s\nPlease report this error to the developers.\n", msg.c_str()); + std::printf("Fatal error: \n%s", _msg.c_str()); #endif } @@ -34,9 +40,9 @@ static void report_fatal_error(const std::string& msg) { throw; } - catch (const std::exception& ex) + catch (const std::exception& e) { - report_fatal_error("Unhandled exception: "s + ex.what()); + report_fatal_error("Unhandled exception of type '"s + typeid(e).name() + "': "s + e.what()); } catch (...) { @@ -775,8 +781,7 @@ size_t get_x64_access_size(x64_context* context, x64_op_t op, x64_reg_t reg, siz if (op == X64OP_CMPXCHG) { - // detect whether this instruction can't actually modify memory to avoid breaking reservation; - // this may theoretically cause endless loop, but it shouldn't be a problem if only load_sync() generates such instruction + // Detect whether the instruction can't actually modify memory to avoid breaking reservation u64 cmp, exch; if (!get_x64_reg_value(context, reg, d_size, i_size, cmp) || !get_x64_reg_value(context, X64R_RAX, d_size, i_size, exch)) { @@ -843,7 +848,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) // check if address is RawSPU MMIO register if (addr - RAW_SPU_BASE_ADDR < (6 * RAW_SPU_OFFSET) && (addr % RAW_SPU_OFFSET) >= RAW_SPU_PROB_OFFSET) { - auto thread = Emu.GetCPU().GetRawSPUThread((addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET); + auto thread = idm::get((addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET); if (!thread) { @@ -1051,10 +1056,10 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) switch (d_size) { - 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; + case 1: reg_value = ((atomic_t*)vm::base_priv(addr))->exchange((u8)reg_value); break; + case 2: reg_value = ((atomic_t*)vm::base_priv(addr))->exchange((u16)reg_value); break; + case 4: reg_value = ((atomic_t*)vm::base_priv(addr))->exchange((u32)reg_value); break; + case 8: reg_value = ((atomic_t*)vm::base_priv(addr))->exchange((u64)reg_value); break; default: return false; } @@ -1074,10 +1079,10 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) switch (d_size) { - 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; + case 1: old_value = ((atomic_t*)vm::base_priv(addr))->compare_and_swap((u8)cmp_value, (u8)reg_value); break; + case 2: old_value = ((atomic_t*)vm::base_priv(addr))->compare_and_swap((u16)cmp_value, (u16)reg_value); break; + case 4: old_value = ((atomic_t*)vm::base_priv(addr))->compare_and_swap((u32)cmp_value, (u32)reg_value); break; + case 8: old_value = ((atomic_t*)vm::base_priv(addr))->compare_and_swap((u64)cmp_value, (u64)reg_value); break; default: return false; } @@ -1097,10 +1102,10 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) switch (d_size) { - 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; + case 1: value = *(atomic_t*)vm::base_priv(addr) &= (u8)value; break; + case 2: value = *(atomic_t*)vm::base_priv(addr) &= (u16)value; break; + case 4: value = *(atomic_t*)vm::base_priv(addr) &= (u32)value; break; + case 8: value = *(atomic_t*)vm::base_priv(addr) &= (u64)value; break; default: return false; } @@ -1126,14 +1131,14 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) // TODO: allow recovering from a page fault as a feature of PS3 virtual memory } -// Throw virtual memory access violation exception -[[noreturn]] void throw_access_violation(const char* cause, u32 address) // Don't change function definition +[[noreturn]] static void throw_access_violation(const char* cause, u64 addr) { - throw EXCEPTION("Access violation %s location 0x%08x", cause, address); + vm::throw_access_violation(addr, cause); + std::abort(); } // Modify context in order to convert hardware exception to C++ exception -void prepare_throw_access_violation(x64_context* context, const char* cause, u32 address) +static void prepare_throw_access_violation(x64_context* context, const char* cause, u32 address) { // Set throw_access_violation() call args (old register values are lost) ARG1(context) = (u64)cause; @@ -1151,14 +1156,17 @@ static LONG exception_handler(PEXCEPTION_POINTERS pExp) const u64 addr64 = pExp->ExceptionRecord->ExceptionInformation[1] - (u64)vm::base(0); const bool is_writing = pExp->ExceptionRecord->ExceptionInformation[0] != 0; - if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && addr64 < 0x100000000ull && thread_ctrl::get_current() && handle_access_violation((u32)addr64, is_writing, pExp->ContextRecord)) + if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && addr64 < 0x100000000ull) { - return EXCEPTION_CONTINUE_EXECUTION; - } - else - { - return EXCEPTION_CONTINUE_SEARCH; + vm::g_tls_fault_count++; + + if (thread_ctrl::get_current() && handle_access_violation((u32)addr64, is_writing, pExp->ContextRecord)) + { + return EXCEPTION_CONTINUE_EXECUTION; + } } + + return EXCEPTION_CONTINUE_SEARCH; } static LONG exception_filter(PEXCEPTION_POINTERS pExp) @@ -1170,8 +1178,9 @@ static LONG exception_filter(PEXCEPTION_POINTERS pExp) const u64 addr64 = pExp->ExceptionRecord->ExceptionInformation[1] - (u64)vm::base(0); const auto cause = pExp->ExceptionRecord->ExceptionInformation[0] != 0 ? "writing" : "reading"; - if (addr64 < 0x100000000ull) + if (!(vm::g_tls_fault_count & (1ull << 63)) && addr64 < 0x100000000ull) { + vm::g_tls_fault_count |= (1ull << 63); // Setup throw_access_violation() call on the context prepare_throw_access_violation(pExp->ContextRecord, cause, (u32)addr64); return EXCEPTION_CONTINUE_EXECUTION; @@ -1190,33 +1199,23 @@ static LONG exception_filter(PEXCEPTION_POINTERS pExp) } msg += fmt::format("Instruction address: %p.\n", pExp->ContextRecord->Rip); - msg += fmt::format("Image base: %p.", GetModuleHandle(NULL)); + msg += fmt::format("Image base: %p.\n", GetModuleHandle(NULL)); + + if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION) + { + msg += "\n" + "Illegal instruction exception occured.\n" + "Note that your CPU must support SSSE3 extension.\n"; + } // TODO: print registers and the callstack - // Exception specific messages - if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) - { - msg += "\n\nAn internal access violation has occured." - "\nPlease only report this error to the developers, if you're an advanced user and have obtained a stack trace."; - } - else if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION) - { - msg += "\n\nAn internal illegal instruction exception has occured." - "\nRPCS3 requires a modern x86-64 CPU that supports SSSE3 (and SSE4.1 for PPU LLVM recompiler)." - "\nPlease make sure that your CPU supports these extensions."; - } - else - { - msg += "\n\nAn unknown internal exception has occured. Please report this to the developers.\nYou can press (Ctrl+C) to copy this message."; - } - // Report fatal error report_fatal_error(msg); return EXCEPTION_CONTINUE_SEARCH; } -const bool g_exception_handler_set = []() -> bool +const bool s_exception_handler_set = []() -> bool { if (!AddVectoredExceptionHandler(1, (PVECTORED_EXCEPTION_HANDLER)exception_handler)) { @@ -1248,12 +1247,12 @@ static void signal_handler(int sig, siginfo_t* info, void* uct) const u64 addr64 = (u64)info->si_addr - (u64)vm::base(0); const auto cause = is_writing ? "writing" : "reading"; - // TODO: Exception specific informative messages - - if (addr64 < 0x100000000ull && thread_ctrl::get_current()) + if (addr64 < 0x100000000ull) { + vm::g_tls_fault_count++; + // Try to process access violation - if (!handle_access_violation((u32)addr64, is_writing, context)) + if (!thread_ctrl::get_current() || !handle_access_violation((u32)addr64, is_writing, context)) { // Setup throw_access_violation() call on the context prepare_throw_access_violation(context, cause, (u32)addr64); @@ -1267,7 +1266,7 @@ static void signal_handler(int sig, siginfo_t* info, void* uct) } } -const bool g_exception_handler_set = []() -> bool +const bool s_exception_handler_set = []() -> bool { struct ::sigaction sa; sa.sa_flags = SA_SIGINFO; @@ -1285,17 +1284,33 @@ const bool g_exception_handler_set = []() -> bool #endif -thread_local thread_ctrl* thread_ctrl::g_tls_this_thread = nullptr; +const bool s_self_test = []() -> bool +{ + // Find ret instruction + if ((*(u8*)throw_access_violation & 0xF6) == 0xC2) + { + std::abort(); + } + + return true; +}(); + +thread_local DECLARE(thread_ctrl::g_tls_this_thread) = nullptr; // TODO -std::atomic g_thread_count{ 0 }; +atomic_t g_thread_count{ 0 }; void thread_ctrl::initialize() { - SetCurrentThreadDebugName(g_tls_this_thread->m_name().c_str()); + SetCurrentThreadDebugName(g_tls_this_thread->m_name.c_str()); + + _log::g_tls_make_prefix = [](const auto&, auto, const auto&) + { + return g_tls_this_thread->m_name; + }; // TODO - g_thread_count++; + ++g_thread_count; } void thread_ctrl::finalize() noexcept @@ -1304,79 +1319,36 @@ void thread_ctrl::finalize() noexcept vm::reservation_free(); // TODO - g_thread_count--; + --g_thread_count; // Call atexit functions - for (const auto& func : decltype(m_atexit)(std::move(g_tls_this_thread->m_atexit))) - { - func(); - } + g_tls_this_thread->m_atexit.exec(); } -thread_ctrl::~thread_ctrl() -{ - m_thread.detach(); - - if (m_future.valid()) - { - try - { - m_future.get(); - } - catch (...) - { - catch_all_exceptions(); - } - } -} - -std::string thread_ctrl::get_name() const -{ - CHECK_ASSERTION(m_name); - - return m_name(); -} - -std::string named_thread_t::get_name() const +std::string named_thread::get_name() const { return fmt::format("('%s') Unnamed Thread", typeid(*this).name()); } -void named_thread_t::start() +void named_thread::start() { - CHECK_ASSERTION(!m_thread); + Expects(!m_thread); // Get shared_ptr instance (will throw if called from the constructor or the object has been created incorrectly) - auto ptr = shared_from_this(); - - // Make name getter - auto name = [wptr = std::weak_ptr(ptr), type = &typeid(*this)]() - { - // Return actual name if available - if (const auto ptr = wptr.lock()) - { - return ptr->get_name(); - } - else - { - return fmt::format("('%s') Deleted Thread", type->name()); - } - }; + auto&& ptr = shared_from_this(); // Run thread - m_thread = thread_ctrl::spawn(std::move(name), [thread = std::move(ptr)]() + m_thread = thread_ctrl::spawn(get_name(), [thread = std::move(ptr)]() { try { LOG_TRACE(GENERAL, "Thread started"); - thread->on_task(); - LOG_TRACE(GENERAL, "Thread ended"); } catch (const std::exception& e) { - LOG_FATAL(GENERAL, "Exception: %s", e.what()); + LOG_FATAL(GENERAL, "%s thrown: %s", typeid(e).name(), e.what()); Emu.Pause(); } catch (EmulationStopped) @@ -1388,9 +1360,9 @@ void named_thread_t::start() }); } -void named_thread_t::join() +void named_thread::join() { - CHECK_ASSERTION(m_thread != nullptr); + Expects(m_thread); try { @@ -1403,11 +1375,3 @@ void named_thread_t::join() throw; } } - -const std::function SQUEUE_ALWAYS_EXIT = [](){ return true; }; -const std::function SQUEUE_NEVER_EXIT = [](){ return false; }; - -bool squeue_test_exit() -{ - return Emu.IsStopped(); -} diff --git a/Utilities/Thread.h b/Utilities/Thread.h index 557a83d7a0..f8d098dfda 100644 --- a/Utilities/Thread.h +++ b/Utilities/Thread.h @@ -1,24 +1,96 @@ #pragma once +#include +#include +#include +#include +#include +#include + +#include "Platform.h" + // Will report exception and call std::abort() if put in catch(...) [[noreturn]] void catch_all_exceptions(); +// Simple list of void() functors +class task_stack +{ + struct task_base + { + std::unique_ptr next; + + virtual ~task_base() = default; + + virtual void exec() + { + if (next) + { + next->exec(); + } + } + }; + + std::unique_ptr m_stack; + + never_inline void push(std::unique_ptr task) + { + m_stack.swap(task->next); + m_stack.swap(task); + } + +public: + template + void push(F&& func) + { + struct task_t : task_base + { + std::remove_reference_t func; + + task_t(F&& func) + : func(std::forward(func)) + { + } + + void exec() override + { + func(); + task_base::exec(); + } + }; + + return push(std::unique_ptr{ new task_t(std::forward(func)) }); + } + + void reset() + { + m_stack.reset(); + } + + void exec() const + { + if (m_stack) + { + m_stack->exec(); + } + } +}; + // Thread control class class thread_ctrl final { static thread_local thread_ctrl* g_tls_this_thread; - // Name getter - std::function m_name; + // Fixed name + std::string m_name; // Thread handle (be careful) std::thread m_thread; - // Thread result - std::future m_future; + // Thread result (exception) + std::exception_ptr m_exception; // Functions scheduled at thread exit - std::deque> m_atexit; + task_stack m_atexit; // Called at the thread start static void initialize(); @@ -27,24 +99,41 @@ class thread_ctrl final static void finalize() noexcept; public: - template - thread_ctrl(T&& name) - : m_name(std::forward(name)) + template + thread_ctrl(N&& name) + : m_name(std::forward(name)) { } // Disable copy/move constructors and operators thread_ctrl(const thread_ctrl&) = delete; - ~thread_ctrl(); + ~thread_ctrl() + { + if (m_thread.joinable()) + { + m_thread.detach(); + } + } // Get thread name - std::string get_name() const; + const std::string& get_name() const + { + return m_name; + } - // Get future result (may throw) + // Get thread result (may throw) void join() { - return m_future.get(); + if (m_thread.joinable()) + { + m_thread.join(); + } + + if (auto&& e = std::move(m_exception)) + { + std::rethrow_exception(e); + } } // Get current thread (may be nullptr) @@ -54,12 +143,10 @@ public: } // Register function at thread exit (for the current thread) - template - static inline void at_exit(T&& func) + template + static inline void at_exit(F&& func) { - CHECK_ASSERTION(g_tls_this_thread); - - g_tls_this_thread->m_atexit.emplace_front(std::forward(func)); + return g_tls_this_thread->m_atexit.push(std::forward(func)); } // Named thread factory @@ -68,12 +155,9 @@ public: { auto ctrl = std::make_shared(std::forward(name)); - std::promise promise; - - ctrl->m_future = promise.get_future(); - - ctrl->m_thread = std::thread([ctrl, task = std::forward(func)](std::promise promise) + ctrl->m_thread = std::thread([ctrl, task = std::forward(func)]() { + // Initialize TLS variable g_tls_this_thread = ctrl.get(); try @@ -81,21 +165,21 @@ public: initialize(); task(); finalize(); - promise.set_value(); } catch (...) { finalize(); - promise.set_exception(std::current_exception()); - } - }, std::move(promise)); + // Set exception + ctrl->m_exception = std::current_exception(); + } + }); return ctrl; } }; -class named_thread_t : public std::enable_shared_from_this +class named_thread : public std::enable_shared_from_this { // Pointer to managed resource (shared with actual thread) std::shared_ptr m_thread; @@ -107,6 +191,27 @@ public: // Thread mutex for external use (can be used with `cv`) std::mutex mutex; + // Lock mutex, notify condition variable + void safe_notify() + { + // Lock for reliable notification, condition is assumed to be changed externally + std::unique_lock lock(mutex); + + cv.notify_one(); + } + + // ID initialization + virtual void on_init() + { + start(); + } + + // ID finalization + virtual void on_stop() + { + join(); + } + protected: // Thread task (called in the thread) virtual void on_task() = 0; @@ -114,19 +219,13 @@ protected: // Thread finalization (called after on_task) virtual void on_exit() {} - // ID initialization (called through id_aux_initialize) - virtual void on_id_aux_initialize() { start(); } - - // ID finalization (called through id_aux_finalize) - virtual void on_id_aux_finalize() { join(); } - public: - named_thread_t() = default; + named_thread() = default; - virtual ~named_thread_t() = default; + virtual ~named_thread() = default; // Deleted copy/move constructors + copy/move operators - named_thread_t(const named_thread_t&) = delete; + named_thread(const named_thread&) = delete; // Get thread name virtual std::string get_name() const; @@ -134,377 +233,40 @@ public: // Start thread (cannot be called from the constructor: should throw bad_weak_ptr in such case) void start(); - // Join thread (get future result) + // Join thread (get thread result) void join(); - // Check whether the thread is not in "empty state" - bool is_started() const { return m_thread.operator bool(); } + // Get thread_ctrl + const thread_ctrl* get_thread_ctrl() const + { + return m_thread.get(); + } // Compare with the current thread - bool is_current() const { CHECK_ASSERTION(m_thread); return thread_ctrl::get_current() == m_thread.get(); } - - // Get thread_ctrl - const thread_ctrl* get_thread_ctrl() const { return m_thread.get(); } - - friend void id_aux_initialize(named_thread_t* ptr) { ptr->on_id_aux_initialize(); } - friend void id_aux_finalize(named_thread_t* ptr) { ptr->on_id_aux_finalize(); } + bool is_current() const + { + return m_thread && thread_ctrl::get_current() == m_thread.get(); + } }; // Wrapper for named thread, joins automatically in the destructor, can only be used in function scope -class scope_thread_t final +class scope_thread final { std::shared_ptr m_thread; public: template - scope_thread_t(N&& name, F&& func) + scope_thread(N&& name, F&& func) : m_thread(thread_ctrl::spawn(std::forward(name), std::forward(func))) { } // Deleted copy/move constructors + copy/move operators - scope_thread_t(const scope_thread_t&) = delete; + scope_thread(const scope_thread&) = delete; // Destructor with exceptions allowed - ~scope_thread_t() noexcept(false) + ~scope_thread() noexcept(false) { m_thread->join(); } }; - -extern const std::function SQUEUE_ALWAYS_EXIT; -extern const std::function SQUEUE_NEVER_EXIT; - -bool squeue_test_exit(); - -template -class squeue_t -{ - struct squeue_sync_var_t - { - struct - { - u32 position : 31; - u32 pop_lock : 1; - }; - struct - { - u32 count : 31; - u32 push_lock : 1; - }; - }; - - atomic_t m_sync; - - mutable std::mutex m_rcv_mutex; - mutable std::mutex m_wcv_mutex; - mutable std::condition_variable m_rcv; - mutable std::condition_variable m_wcv; - - T m_data[sq_size]; - - enum squeue_sync_var_result : u32 - { - SQSVR_OK = 0, - SQSVR_LOCKED = 1, - SQSVR_FAILED = 2, - }; - -public: - squeue_t() - : m_sync(squeue_sync_var_t{}) - { - } - - u32 get_max_size() const - { - return sq_size; - } - - bool is_full() const - { - return m_sync.load().count == sq_size; - } - - bool push(const T& data, const std::function& test_exit) - { - u32 pos = 0; - - while (u32 res = m_sync.atomic_op([&pos](squeue_sync_var_t& sync) -> u32 - { - assert(sync.count <= sq_size); - assert(sync.position < sq_size); - - if (sync.push_lock) - { - return SQSVR_LOCKED; - } - if (sync.count == sq_size) - { - return SQSVR_FAILED; - } - - sync.push_lock = 1; - pos = sync.position + sync.count; - return SQSVR_OK; - })) - { - if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit())) - { - return false; - } - - std::unique_lock wcv_lock(m_wcv_mutex); - m_wcv.wait_for(wcv_lock, std::chrono::milliseconds(1)); - } - - m_data[pos >= sq_size ? pos - sq_size : pos] = data; - - m_sync.atomic_op([](squeue_sync_var_t& sync) - { - assert(sync.count <= sq_size); - assert(sync.position < sq_size); - assert(sync.push_lock); - sync.push_lock = 0; - sync.count++; - }); - - m_rcv.notify_one(); - m_wcv.notify_one(); - return true; - } - - bool push(const T& data, const volatile bool* do_exit) - { - return push(data, [do_exit](){ return do_exit && *do_exit; }); - } - - force_inline bool push(const T& data) - { - return push(data, SQUEUE_NEVER_EXIT); - } - - force_inline bool try_push(const T& data) - { - return push(data, SQUEUE_ALWAYS_EXIT); - } - - bool pop(T& data, const std::function& test_exit) - { - u32 pos = 0; - - while (u32 res = m_sync.atomic_op([&pos](squeue_sync_var_t& sync) -> u32 - { - assert(sync.count <= sq_size); - assert(sync.position < sq_size); - - if (!sync.count) - { - return SQSVR_FAILED; - } - if (sync.pop_lock) - { - return SQSVR_LOCKED; - } - - sync.pop_lock = 1; - pos = sync.position; - return SQSVR_OK; - })) - { - if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit())) - { - return false; - } - - std::unique_lock rcv_lock(m_rcv_mutex); - m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1)); - } - - data = m_data[pos]; - - m_sync.atomic_op([](squeue_sync_var_t& sync) - { - assert(sync.count <= sq_size); - assert(sync.position < sq_size); - assert(sync.pop_lock); - sync.pop_lock = 0; - sync.position++; - sync.count--; - if (sync.position == sq_size) - { - sync.position = 0; - } - }); - - m_rcv.notify_one(); - m_wcv.notify_one(); - return true; - } - - bool pop(T& data, const volatile bool* do_exit) - { - return pop(data, [do_exit](){ return do_exit && *do_exit; }); - } - - force_inline bool pop(T& data) - { - return pop(data, SQUEUE_NEVER_EXIT); - } - - force_inline bool try_pop(T& data) - { - return pop(data, SQUEUE_ALWAYS_EXIT); - } - - bool peek(T& data, u32 start_pos, const std::function& test_exit) - { - assert(start_pos < sq_size); - u32 pos = 0; - - while (u32 res = m_sync.atomic_op([&pos, start_pos](squeue_sync_var_t& sync) -> u32 - { - assert(sync.count <= sq_size); - assert(sync.position < sq_size); - - if (sync.count <= start_pos) - { - return SQSVR_FAILED; - } - if (sync.pop_lock) - { - return SQSVR_LOCKED; - } - - sync.pop_lock = 1; - pos = sync.position + start_pos; - return SQSVR_OK; - })) - { - if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit())) - { - return false; - } - - std::unique_lock rcv_lock(m_rcv_mutex); - m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1)); - } - - data = m_data[pos >= sq_size ? pos - sq_size : pos]; - - m_sync.atomic_op([](squeue_sync_var_t& sync) - { - assert(sync.count <= sq_size); - assert(sync.position < sq_size); - assert(sync.pop_lock); - sync.pop_lock = 0; - }); - - m_rcv.notify_one(); - return true; - } - - bool peek(T& data, u32 start_pos, const volatile bool* do_exit) - { - return peek(data, start_pos, [do_exit](){ return do_exit && *do_exit; }); - } - - force_inline bool peek(T& data, u32 start_pos = 0) - { - return peek(data, start_pos, SQUEUE_NEVER_EXIT); - } - - force_inline bool try_peek(T& data, u32 start_pos = 0) - { - return peek(data, start_pos, SQUEUE_ALWAYS_EXIT); - } - - class squeue_data_t - { - T* const m_data; - const u32 m_pos; - const u32 m_count; - - squeue_data_t(T* data, u32 pos, u32 count) - : m_data(data) - , m_pos(pos) - , m_count(count) - { - } - - public: - T& operator [] (u32 index) - { - assert(index < m_count); - index += m_pos; - index = index < sq_size ? index : index - sq_size; - return m_data[index]; - } - }; - - void process(void(*proc)(squeue_data_t data)) - { - u32 pos, count; - - while (m_sync.atomic_op([&pos, &count](squeue_sync_var_t& sync) -> u32 - { - assert(sync.count <= sq_size); - assert(sync.position < sq_size); - - if (sync.pop_lock || sync.push_lock) - { - return SQSVR_LOCKED; - } - - pos = sync.position; - count = sync.count; - sync.pop_lock = 1; - sync.push_lock = 1; - return SQSVR_OK; - })) - { - std::unique_lock rcv_lock(m_rcv_mutex); - m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1)); - } - - proc(squeue_data_t(m_data, pos, count)); - - m_sync.atomic_op([](squeue_sync_var_t& sync) - { - assert(sync.count <= sq_size); - assert(sync.position < sq_size); - assert(sync.pop_lock && sync.push_lock); - sync.pop_lock = 0; - sync.push_lock = 0; - }); - - m_wcv.notify_one(); - m_rcv.notify_one(); - } - - void clear() - { - while (m_sync.atomic_op([](squeue_sync_var_t& sync) -> u32 - { - assert(sync.count <= sq_size); - assert(sync.position < sq_size); - - if (sync.pop_lock || sync.push_lock) - { - return SQSVR_LOCKED; - } - - sync.pop_lock = 1; - sync.push_lock = 1; - return SQSVR_OK; - })) - { - std::unique_lock rcv_lock(m_rcv_mutex); - m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1)); - } - - m_sync.exchange({}); - m_wcv.notify_one(); - m_rcv.notify_one(); - } -}; diff --git a/Utilities/VirtualMemory.cpp b/Utilities/VirtualMemory.cpp index 5a2d00e901..e0b2b2ed61 100644 --- a/Utilities/VirtualMemory.cpp +++ b/Utilities/VirtualMemory.cpp @@ -17,10 +17,10 @@ namespace memory_helper { #ifdef _WIN32 void* ret = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS); - CHECK_ASSERTION(ret != NULL); + Ensures(ret != NULL); #else void* ret = mmap(nullptr, size, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0); - CHECK_ASSERTION(ret != 0); + Ensures(ret != 0); #endif return ret; } @@ -28,18 +28,18 @@ namespace memory_helper void commit_page_memory(void* pointer, size_t page_size) { #ifdef _WIN32 - CHECK_ASSERTION(VirtualAlloc((u8*)pointer, page_size, MEM_COMMIT, PAGE_READWRITE) != NULL); + ASSERT(VirtualAlloc((u8*)pointer, page_size, MEM_COMMIT, PAGE_READWRITE) != NULL); #else - CHECK_ASSERTION(mprotect((u8*)pointer, page_size, PROT_READ | PROT_WRITE) != -1); + ASSERT(mprotect((u8*)pointer, page_size, PROT_READ | PROT_WRITE) != -1); #endif } void free_reserved_memory(void* pointer, size_t size) { #ifdef _WIN32 - CHECK_ASSERTION(VirtualFree(pointer, 0, MEM_RELEASE) != 0); + ASSERT(VirtualFree(pointer, 0, MEM_RELEASE) != 0); #else - CHECK_ASSERTION(munmap(pointer, size) == 0); + ASSERT(munmap(pointer, size) == 0); #endif } } diff --git a/Utilities/config_context.cpp b/Utilities/config_context.cpp deleted file mode 100644 index 69b953d19d..0000000000 --- a/Utilities/config_context.cpp +++ /dev/null @@ -1,172 +0,0 @@ -#include "stdafx.h" -#include "config_context.h" -#include "StrFmt.h" -#include -#include - -void config_context_t::group::init() -{ - if(!m_cfg->m_groups[full_name()]) - m_cfg->m_groups[full_name()] = this; -} - -config_context_t::group::group(config_context_t* cfg, const std::string& name) - : m_cfg(cfg) - , m_name(name) - , m_parent(nullptr) -{ - init(); -} - -config_context_t::group::group(group* parent, const std::string& name) - : m_cfg(parent->m_cfg) - , m_name(name) - , m_parent(parent) -{ - init(); -} - -void config_context_t::group::set_parent(config_context_t* cfg) -{ - m_cfg = cfg; - init(); -} - -std::string config_context_t::group::name() const -{ - return m_name; -} - -std::string config_context_t::group::full_name() const -{ - if (m_parent) - return m_parent->full_name() + "/" + m_name; - - return m_name; -} - -void config_context_t::assign(const config_context_t& rhs) -{ - for (auto &rhs_g : rhs.m_groups) - { - auto g = m_groups.at(rhs_g.first); - - for (auto rhs_e : rhs_g.second->entries) - { - if (g->entries[rhs_e.first]) - g->entries[rhs_e.first]->value_from(rhs_e.second); - else - g->add_entry(rhs_e.first, rhs_e.second->string_value()); - } - } -} - -void config_context_t::deserialize(std::istream& stream) -{ - set_defaults(); - - uint line_index = 0; - std::string line; - group *current_group = nullptr; - - while (std::getline(stream, line)) - { - ++line_index; - line = fmt::trim(line); - - if (line.empty()) - continue; - - if (line.front() == '[' && line.back() == ']') - { - std::string group_name = line.substr(1, line.length() - 2); - - auto found = m_groups.find(group_name); - - if (found == m_groups.end()) - { - std::cerr << line_index << ": group '" << group_name << "' not exists. ignored" << std::endl; - current_group = nullptr; - continue; - } - - current_group = found->second; - continue; - } - - if (current_group == nullptr) - { - std::cerr << line_index << ": line '" << line << "' ignored, no group." << std::endl; - continue; - } - - auto name_value = fmt::split(line, { "=" }); - switch (name_value.size()) - { - case 1: - { - if (current_group->entries[fmt::trim(name_value[0])]) - current_group->entries[fmt::trim(name_value[0])]->string_value({}); - - else - current_group->add_entry(fmt::trim(name_value[0]), std::string{}); - } - break; - - default: - std::cerr << line_index << ": line '" << line << "' has more than one symbol '='. used only first" << std::endl; - case 2: - { - if (current_group->entries[fmt::trim(name_value[0])]) - current_group->entries[fmt::trim(name_value[0])]->string_value(fmt::trim(name_value[1])); - - else - current_group->add_entry(fmt::trim(name_value[0]), fmt::trim(name_value[1])); - } - break; - - } - } -} - -void config_context_t::serialize(std::ostream& stream) const -{ - for (auto &g : m_groups) - { - stream << "[" + g.first + "]" << std::endl; - - for (auto &e : g.second->entries) - { - stream << e.first << "=" << e.second->string_value() << std::endl; - } - - stream << std::endl; - } -} - -void config_context_t::set_defaults() -{ - for (auto &g : m_groups) - { - for (auto &e : g.second->entries) - { - e.second->to_default(); - } - } -} - -std::string config_context_t::to_string() const -{ - std::ostringstream result; - - serialize(result); - - return result.str(); -} - -void config_context_t::from_string(const std::string& str) -{ - std::istringstream source(str); - - deserialize(source); -} diff --git a/Utilities/config_context.h b/Utilities/config_context.h deleted file mode 100644 index 3263a38532..0000000000 --- a/Utilities/config_context.h +++ /dev/null @@ -1,164 +0,0 @@ -#pragma once -#include -#include -#include "convert.h" - -class config_context_t -{ -public: - class entry_base; - -protected: - class group - { - group* m_parent; - config_context_t* m_cfg; - std::string m_name; - std::vector> m_entries; - - void init(); - - public: - std::unordered_map entries; - - group(config_context_t* cfg, const std::string& name); - group(group* parent, const std::string& name); - void set_parent(config_context_t* cfg); - - std::string name() const; - std::string full_name() const; - - template - void add_entry(const std::string& name, const T& def_value) - { - m_entries.emplace_back(std::make_unique>(this, name, def_value)); - } - - template - T get_entry_value(const std::string& name, const T& def_value) - { - if (!entries[name]) - add_entry(name, def_value); - - return convert::to(entries[name]->string_value()); - } - - template - void set_entry_value(const std::string& name, const T& value) - { - if (entries[name]) - entries[name]->string_value(convert::to(value)); - - else - add_entry(name, value); - } - - friend config_context_t; - }; - -public: - class entry_base - { - public: - virtual ~entry_base() = default; - virtual std::string name() = 0; - virtual void to_default() = 0; - virtual std::string string_value() = 0; - virtual void string_value(const std::string& value) = 0; - virtual void value_from(const entry_base* rhs) = 0; - }; - - template - class entry : public entry_base - { - T m_default_value; - T m_value; - group* m_parent; - std::string m_name; - - public: - entry(group* parent, const std::string& name, const T& default_value) - : m_parent(parent) - , m_name(name) - , m_default_value(default_value) - , m_value(default_value) - { - if(!parent->entries[name]) - parent->entries[name] = this; - } - - T default_value() const - { - return m_default_value; - } - - T value() const - { - return m_value; - } - - void value(const T& new_value) - { - m_value = new_value; - } - - std::string name() override - { - return m_name; - } - - void to_default() override - { - value(default_value()); - } - - std::string string_value() override - { - return convert::to(value()); - } - - void string_value(const std::string &new_value) override - { - value(convert::to(new_value)); - } - - void value_from(const entry_base* rhs) override - { - value(static_cast(rhs)->value()); - } - - entry& operator = (const T& new_value) - { - value(new_value); - return *this; - } - - template - entry& operator = (const T2& new_value) - { - value(static_cast(new_value)); - return *this; - } - - explicit operator const T&() const - { - return m_value; - } - }; - -private: - std::unordered_map m_groups; - -public: - config_context_t() = default; - - void assign(const config_context_t& rhs); - - void serialize(std::ostream& stream) const; - void deserialize(std::istream& stream); - - void set_defaults(); - - std::string to_string() const; - void from_string(const std::string&); -}; diff --git a/Utilities/convert.h b/Utilities/convert.h deleted file mode 100644 index b190737fcb..0000000000 --- a/Utilities/convert.h +++ /dev/null @@ -1,279 +0,0 @@ -#pragma once -#include -#include "types.h" - -namespace convert -{ - template - struct to_impl_t; - - template - struct to_impl_t - { - static Type func(const Type& value) - { - return value; - } - }; - - template<> - struct to_impl_t - { - static std::string func(bool value) - { - return value ? "true" : "false"; - } - }; - - template<> - struct to_impl_t - { - static bool func(const std::string& value) - { - return value == "true" ? true : value == "false" ? false : throw std::invalid_argument(__FUNCTION__); - } - }; - - template<> - struct to_impl_t - { - static std::string func(signed char value) - { - return std::to_string(value); - } - }; - - template<> - struct to_impl_t - { - static std::string func(unsigned char value) - { - return std::to_string(value); - } - }; - - - template<> - struct to_impl_t - { - static std::string func(short value) - { - return std::to_string(value); - } - }; - - template<> - struct to_impl_t - { - static std::string func(unsigned short value) - { - return std::to_string(value); - } - }; - - template<> - struct to_impl_t - { - static std::string func(int value) - { - return std::to_string(value); - } - }; - - template<> - struct to_impl_t - { - static std::string func(unsigned int value) - { - return std::to_string(value); - } - }; - - template<> - struct to_impl_t - { - static std::string func(long value) - { - return std::to_string(value); - } - }; - - template<> - struct to_impl_t - { - static std::string func(unsigned long value) - { - return std::to_string(value); - } - }; - - template<> - struct to_impl_t - { - static std::string func(long long value) - { - return std::to_string(value); - } - }; - - template<> - struct to_impl_t - { - static std::string func(unsigned long long value) - { - return std::to_string(value); - } - }; - - template<> - struct to_impl_t - { - static std::string func(float value) - { - return std::to_string(value); - } - }; - - template<> - struct to_impl_t - { - static std::string func(double value) - { - return std::to_string(value); - } - }; - - template<> - struct to_impl_t - { - static std::string func(long double value) - { - return std::to_string(value); - } - }; - - template<> - struct to_impl_t - { - static std::string func(size2i value) - { - return std::to_string(value.width) + "x" + std::to_string(value.height); - } - }; - - template<> - struct to_impl_t - { - static std::string func(position2i value) - { - return std::to_string(value.x) + ":" + std::to_string(value.y); - } - }; - - template<> - struct to_impl_t - { - static int func(const std::string& value) - { - return std::stoi(value); - } - }; - - template<> - struct to_impl_t - { - static unsigned int func(const std::string& value) - { - return (unsigned long)std::stoul(value); - } - }; - - template<> - struct to_impl_t - { - static long func(const std::string& value) - { - return std::stol(value); - } - }; - - template<> - struct to_impl_t - { - static unsigned long func(const std::string& value) - { - return std::stoul(value); - } - }; - - template<> - struct to_impl_t - { - static long long func(const std::string& value) - { - return std::stoll(value); - } - }; - - template<> - struct to_impl_t - { - static unsigned long long func(const std::string& value) - { - return std::stoull(value); - } - }; - - template<> - struct to_impl_t - { - static float func(const std::string& value) - { - return std::stof(value); - } - }; - - template<> - struct to_impl_t - { - static double func(const std::string& value) - { - return std::stod(value); - } - }; - - template<> - struct to_impl_t - { - static long double func(const std::string& value) - { - return std::stold(value); - } - }; - - template<> - struct to_impl_t - { - static size2i func(const std::string& value) - { - const auto& data = fmt::split(value, { "x" }); - return { std::stoi(data[0]), std::stoi(data[1]) }; - } - }; - - template<> - struct to_impl_t - { - static position2i func(const std::string& value) - { - const auto& data = fmt::split(value, { ":" }); - return { std::stoi(data[0]), std::stoi(data[1]) }; - } - }; - - template - ReturnType to(FromType value) - { - return to_impl_t, std::remove_all_extents_t>::func(value); - } -} diff --git a/Utilities/rPlatform.cpp b/Utilities/rPlatform.cpp deleted file mode 100644 index 53f7e783d7..0000000000 --- a/Utilities/rPlatform.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "stdafx.h" -#include "restore_new.h" -#include "Utilities/Log.h" -#pragma warning(push) -#pragma message("TODO: remove wx dependency: ") -#pragma warning(disable : 4996) -#include -#pragma warning(pop) -#include "define_new_memleakdetect.h" - -#ifndef _WIN32 -#include -#endif - -#include "rPlatform.h" - -rImage::rImage() -{ - handle = static_cast(new wxImage()); -} - -rImage::~rImage() -{ - delete static_cast(handle); -} - -void rImage::Create(int width, int height, void *data, void *alpha) -{ - static_cast(handle)->Create(width, height, static_cast(data), static_cast(alpha)); -} -void rImage::SaveFile(const std::string& name, rImageType type) -{ - if (type == rBITMAP_TYPE_PNG) - { - static_cast(handle)->SaveFile(fmt::FromUTF8(name),wxBITMAP_TYPE_PNG); - } - else - { - throw EXCEPTION("unsupported type"); - } -} diff --git a/Utilities/rPlatform.h b/Utilities/rPlatform.h deleted file mode 100644 index 09308edb53..0000000000 --- a/Utilities/rPlatform.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -/********************************************************************** -*********** RSX Debugger -************************************************************************/ - -struct RSXDebuggerProgram -{ - u32 id; - u32 vp_id; - u32 fp_id; - std::string vp_shader; - std::string fp_shader; - bool modified; - - RSXDebuggerProgram() - : modified(false) - { - } -}; - -extern std::vector m_debug_programs; - -/********************************************************************** -*********** Image stuff -************************************************************************/ -enum rImageType -{ - rBITMAP_TYPE_PNG -}; -struct rImage -{ - rImage(); - rImage(const rImage &) = delete; - ~rImage(); - void Create(int width , int height, void *data, void *alpha); - void SaveFile(const std::string& name, rImageType type); - - void *handle; -}; diff --git a/Utilities/rTime.cpp b/Utilities/rTime.cpp deleted file mode 100644 index 9687141302..0000000000 --- a/Utilities/rTime.cpp +++ /dev/null @@ -1,235 +0,0 @@ -#include "stdafx.h" -#include "rTime.h" -#pragma warning(push) -#pragma message("TODO: remove wx dependency: ") -#pragma warning(disable : 4996) -#include -#pragma warning(pop) - -std::string rDefaultDateTimeFormat = "%c"; - -rTimeSpan::rTimeSpan() -{ - handle = static_cast(new wxTimeSpan()); -} - -rTimeSpan::~rTimeSpan() -{ - delete static_cast(handle); -} - -rTimeSpan::rTimeSpan(const rTimeSpan& other) - -{ - handle = static_cast(new wxTimeSpan(*static_cast(other.handle))); - -} - -rTimeSpan::rTimeSpan(int a, int b , int c, int d) -{ - handle = static_cast(new wxTimeSpan(a,b,c,d)); -} - - -rDateSpan::rDateSpan() -{ - handle = static_cast(new wxDateSpan()); -} - -rDateSpan::~rDateSpan() -{ - delete static_cast(handle); -} - -rDateSpan::rDateSpan(const rDateSpan& other) -{ - handle = static_cast(new wxDateSpan(*static_cast(other.handle))); -} - -rDateSpan::rDateSpan(int a, int b, int c, int d) -{ - handle = static_cast(new wxDateSpan(a,b,c,d)); -} - -rDateTime::rDateTime() -{ - handle = static_cast(new wxDateTime()); -} - -rDateTime::~rDateTime() -{ - delete static_cast(handle); -} - -rDateTime::rDateTime(const rDateTime& other) -{ - handle = static_cast(new wxDateTime(*static_cast(other.handle))); -} - -rDateTime::rDateTime(const time_t& time) -{ - handle = static_cast(new wxDateTime(time)); -} - -rDateTime::rDateTime(u16 day, rDateTime::Month month, u16 year, u16 hour, u16 minute, u16 second, u32 millisecond) -{ - handle = static_cast(new wxDateTime(day,(wxDateTime::Month)month,year,hour,minute,second,millisecond)); -} - -rDateTime rDateTime::UNow() -{ - rDateTime time; - delete static_cast(time.handle); - time.handle = static_cast(new wxDateTime(wxDateTime::UNow())); - - return time; -} - -rDateTime rDateTime::FromUTC(bool val) -{ - rDateTime time(*this); - void *temp = time.handle; - - time.handle = static_cast(new wxDateTime(static_cast(temp)->FromTimezone(wxDateTime::GMT0, val))); - delete static_cast(temp); - - return time; -} - -rDateTime rDateTime::ToUTC(bool val) -{ - rDateTime time(*this); - void *temp = time.handle; - - time.handle = static_cast(new wxDateTime(static_cast(temp)->ToTimezone(wxDateTime::GMT0, val))); - delete static_cast(temp); - - return time; -} - -time_t rDateTime::GetTicks() -{ - return static_cast(handle)->GetTicks(); -} - -void rDateTime::Add(const rTimeSpan& span) -{ - static_cast(handle)->Add(*static_cast(span.handle)); -} - -void rDateTime::Add(const rDateSpan& span) -{ - static_cast(handle)->Add(*static_cast(span.handle)); -} - -wxDateTime::TimeZone convertTZ(rDateTime::rTimeZone tz) -{ - switch (tz) - { - case rDateTime::Local: - return wxDateTime::Local; - case rDateTime::GMT0: - return wxDateTime::GMT0; - case rDateTime::UTC: - return wxDateTime::UTC; - default: - throw EXCEPTION("WRONG DATETIME"); - } -} - -std::string rDateTime::Format(const std::string &format, const rTimeZone &tz) const -{ - return fmt::ToUTF8(static_cast(handle)->Format(fmt::FromUTF8(format),convertTZ(tz))); -} - -void rDateTime::ParseDateTime(const char* format) -{ - static_cast(handle)->ParseDateTime(format); -} - -u32 rDateTime::GetAsDOS() -{ - return static_cast(handle)->GetAsDOS(); -} - -rDateTime &rDateTime::SetFromDOS(u32 fromdos) -{ - static_cast(handle)->SetFromDOS(fromdos); - return *this; -} - -bool rDateTime::IsLeapYear(int year, rDateTime::Calender cal) -{ - if (cal == Gregorian) - { - return wxDateTime::IsLeapYear(year, wxDateTime::Gregorian); - } - else - { - return wxDateTime::IsLeapYear(year, wxDateTime::Julian); - } -} - -int rDateTime::GetNumberOfDays(rDateTime::Month month, int year, rDateTime::Calender cal) -{ - if (cal == Gregorian) - { - return wxDateTime::GetNumberOfDays(static_cast(month), year, wxDateTime::Gregorian); - } - else - { - return wxDateTime::GetNumberOfDays(static_cast(month), year, wxDateTime::Julian); - } -} - -void rDateTime::SetToWeekDay(rDateTime::WeekDay day, int n, rDateTime::Month month, int year) -{ - static_cast(handle)->SetToWeekDay( - static_cast(day) - , n - , static_cast(month) - , year - ); -} - -int rDateTime::GetWeekDay() -{ - return static_cast(handle)->GetWeekDay(); -} - -u16 rDateTime::GetYear(rDateTime::TZ timezone) -{ - return static_cast(handle)->GetYear(convertTZ(timezone)); -} - -u16 rDateTime::GetMonth(rDateTime::TZ timezone) -{ - return static_cast(handle)->GetMonth(convertTZ(timezone)); -} - -u16 rDateTime::GetDay(rDateTime::TZ timezone) -{ - return static_cast(handle)->GetDay(convertTZ(timezone)); -} - -u16 rDateTime::GetHour(rDateTime::TZ timezone) -{ - return static_cast(handle)->GetHour(convertTZ(timezone)); -} - -u16 rDateTime::GetMinute(rDateTime::TZ timezone) -{ - return static_cast(handle)->GetMinute(convertTZ(timezone)); -} - -u16 rDateTime::GetSecond(rDateTime::TZ timezone) -{ - return static_cast(handle)->GetSecond(convertTZ(timezone)); -} - -u32 rDateTime::GetMillisecond(rDateTime::TZ timezone) -{ - return static_cast(handle)->GetMillisecond(convertTZ(timezone)); -} - - diff --git a/Utilities/rTime.h b/Utilities/rTime.h deleted file mode 100644 index 9c39c46b30..0000000000 --- a/Utilities/rTime.h +++ /dev/null @@ -1,102 +0,0 @@ -#pragma once - -extern std::string rDefaultDateTimeFormat; - - -struct rTimeSpan -{ - rTimeSpan(); - ~rTimeSpan(); - rTimeSpan(const rTimeSpan& other); - rTimeSpan(int, int, int, int); - - void *handle; -}; - -struct rDateSpan -{ - rDateSpan(); - ~rDateSpan(); - rDateSpan(const rDateSpan& other); - rDateSpan(int, int, int, int); - - void *handle; -}; - -struct rDateTime -{ - enum TZ - { - Local, GMT0,UTC - }; - enum Calender - { - Gregorian, Julian - }; - - using rTimeZone = TZ; - - enum WeekDay - { - Sun = 0, - Mon, - Tue, - Wed, - Thu, - Fri, - Sat, - Inv_WeekDay - }; - - enum Month { - Jan = 0, - Feb = 1, - Mar = 2, - Apr = 3, - May = 4, - Jun = 5, - Jul = 6, - Aug = 7, - Sep = 8, - Oct = 9, - Nov = 10, - Dec = 11, - Inv_Month = 12 - }; - - rDateTime(); - ~rDateTime(); - rDateTime(const rDateTime& other); - rDateTime(const time_t &time); - rDateTime(u16 day, rDateTime::Month month, u16 year, u16 hour, u16 minute, u16 second, u32 millisecond); - - static rDateTime UNow(); - rDateTime FromUTC(bool val); - rDateTime ToUTC(bool val); - time_t GetTicks(); - void Add(const rTimeSpan& span); - void Add(const rDateSpan& span); - void Close(); - std::string Format(const std::string &format = rDefaultDateTimeFormat, const rTimeZone &tz = Local) const; - - void ParseDateTime(const char* format); - - u32 GetAsDOS(); - rDateTime &SetFromDOS(u32 fromdos); - - static bool IsLeapYear(int year, rDateTime::Calender cal); - static int GetNumberOfDays(rDateTime::Month month, int year, rDateTime::Calender cal); - void SetToWeekDay(rDateTime::WeekDay day, int n, rDateTime::Month month, int year); - int GetWeekDay(); - - u16 GetYear( rDateTime::TZ timezone); - u16 GetMonth(rDateTime::TZ timezone); - u16 GetDay(rDateTime::TZ timezone); - u16 GetHour(rDateTime::TZ timezone); - u16 GetMinute(rDateTime::TZ timezone); - u16 GetSecond(rDateTime::TZ timezone); - u32 GetMillisecond(rDateTime::TZ timezone); - - void *handle; -}; - diff --git a/Utilities/types.h b/Utilities/types.h index ab011c2e3c..dd2f76e0a3 100644 --- a/Utilities/types.h +++ b/Utilities/types.h @@ -1,16 +1,21 @@ #pragma once +#include #include +#include +#include +#include #include #include -#include +#include "Platform.h" + +using schar = signed char; using uchar = unsigned char; using ushort = unsigned short; using uint = unsigned int; using ulong = unsigned long; using ullong = unsigned long long; - using llong = long long; using u8 = std::uint8_t; @@ -23,6 +28,350 @@ using s16 = std::int16_t; using s32 = std::int32_t; using s64 = std::int64_t; +// Specialization with static constexpr pair map[] member expected +template +struct bijective; + +template +struct atomic_storage; + +template +struct atomic_add; + +template +struct atomic_sub; + +template +struct atomic_and; + +template +struct atomic_or; + +template +struct atomic_xor; + +template +struct atomic_pre_inc; + +template +struct atomic_post_inc; + +template +struct atomic_pre_dec; + +template +struct atomic_post_dec; + +template +struct atomic_test_and_set; + +template +struct atomic_test_and_reset; + +template +struct atomic_test_and_complement; + +template +class atomic_t; + +namespace fmt +{ + template + struct unveil; +} + +// TODO: replace with std::void_t when available +namespace void_details +{ + template + struct make_void + { + using type = void; + }; +} + +template using void_t = typename void_details::make_void::type; + +// Extract T::simple_type if available, remove cv qualifiers +template +struct simple_type_helper +{ + using type = typename std::remove_cv::type; +}; + +template +struct simple_type_helper> +{ + using type = typename T::simple_type; +}; + +template using simple_t = typename simple_type_helper::type; + +// Bool type equivalent +class b8 +{ + std::uint8_t m_value; + +public: + b8() = default; + + constexpr b8(bool value) + : m_value(value) + { + } + + constexpr operator bool() const + { + return m_value != 0; + } +}; + +// Bool wrapper for restricting bool result conversions +struct explicit_bool_t +{ + const bool value; + + constexpr explicit_bool_t(bool value) + : value(value) + { + } + + explicit constexpr operator bool() const + { + return value; + } +}; + +#ifndef _MSC_VER +using u128 = __uint128_t; +using s128 = __int128_t; +#else + +#include "intrin.h" + +// Unsigned 128-bit integer implementation (TODO) +struct alignas(16) u128 +{ + std::uint64_t lo, hi; + + u128() = default; + + constexpr u128(std::uint64_t l) + : lo(l) + , hi(0) + { + } + + friend u128 operator +(const u128& l, const u128& r) + { + u128 value; + _addcarry_u64(_addcarry_u64(0, r.lo, l.lo, &value.lo), r.hi, l.hi, &value.hi); + return value; + } + + friend u128 operator +(const u128& l, std::uint64_t r) + { + u128 value; + _addcarry_u64(_addcarry_u64(0, r, l.lo, &value.lo), l.hi, 0, &value.hi); + return value; + } + + 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; + } + + friend u128 operator -(const u128& l, const u128& r) + { + u128 value; + _subborrow_u64(_subborrow_u64(0, r.lo, l.lo, &value.lo), r.hi, l.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; + } + + u128 operator -() const + { + u128 value; + _subborrow_u64(_subborrow_u64(0, lo, 0, &value.lo), hi, 0, &value.hi); + return value; + } + + u128& operator ++() + { + _addcarry_u64(_addcarry_u64(0, 1, lo, &lo), 0, hi, &hi); + return *this; + } + + u128 operator ++(int) + { + u128 value = *this; + _addcarry_u64(_addcarry_u64(0, 1, lo, &lo), 0, hi, &hi); + return value; + } + + u128& operator --() + { + _subborrow_u64(_subborrow_u64(0, 1, lo, &lo), 0, hi, &hi); + return *this; + } + + u128 operator --(int) + { + u128 value = *this; + _subborrow_u64(_subborrow_u64(0, 1, lo, &lo), 0, hi, &hi); + return value; + } + + u128 operator ~() const + { + u128 value; + value.lo = ~lo; + value.hi = ~hi; + return value; + } + + friend u128 operator &(const u128& l, const u128& r) + { + u128 value; + value.lo = l.lo & r.lo; + value.hi = l.hi & r.hi; + return value; + } + + friend u128 operator |(const u128& l, const u128& r) + { + u128 value; + value.lo = l.lo | r.lo; + value.hi = l.hi | r.hi; + return value; + } + + friend u128 operator ^(const u128& l, const u128& r) + { + u128 value; + value.lo = l.lo ^ r.lo; + value.hi = l.hi ^ r.hi; + return value; + } + + u128& operator +=(const u128& r) + { + _addcarry_u64(_addcarry_u64(0, r.lo, lo, &lo), r.hi, hi, &hi); + return *this; + } + + u128& operator +=(uint64_t r) + { + _addcarry_u64(_addcarry_u64(0, r, lo, &lo), 0, hi, &hi); + return *this; + } + + u128& operator &=(const u128& r) + { + lo &= r.lo; + hi &= r.hi; + return *this; + } + + u128& operator |=(const u128& r) + { + lo |= r.lo; + hi |= r.hi; + return *this; + } + + u128& operator ^=(const u128& r) + { + lo ^= r.lo; + hi ^= r.hi; + return *this; + } +}; + +// Signed 128-bit integer implementation (TODO) +struct alignas(16) s128 +{ + std::uint64_t lo; + std::int64_t hi; + + s128() = default; + + constexpr s128(std::int64_t l) + : hi(l >> 63) + , lo(l) + { + } + + constexpr s128(std::uint64_t l) + : hi(0) + , lo(l) + { + } +}; +#endif + +namespace std +{ + /* Let's hack. */ + + template<> + struct is_integral : true_type + { + }; + + template<> + struct is_integral : true_type + { + }; + + template<> + struct make_unsigned + { + using type = u128; + }; + + template<> + struct make_unsigned + { + using type = u128; + }; + + template<> + struct make_signed + { + using type = s128; + }; + + template<> + struct make_signed + { + using type = s128; + }; +} + +static_assert(std::is_arithmetic::value && std::is_integral::value && alignof(u128) == 16 && sizeof(u128) == 16, "Wrong u128 implementation"); +static_assert(std::is_arithmetic::value && std::is_integral::value && alignof(s128) == 16 && sizeof(s128) == 16, "Wrong s128 implementation"); + union alignas(2) f16 { u16 _u16; @@ -55,6 +404,313 @@ struct ignore } }; +// Allows to define integer convertible to multiple enum types +template +struct multicast : multicast +{ + static_assert(std::is_enum::value, "multicast<> error: invalid conversion type (enum type expected)"); + + multicast() = default; + + template + constexpr multicast(const UT& value) + : multicast(value) + , m_value{ value } // Forbid narrowing + { + } + + constexpr operator T() const + { + // Cast to enum type + return static_cast(m_value); + } + +private: + std::underlying_type_t m_value; +}; + +// Recursion terminator +template<> +struct multicast +{ + multicast() = default; + + template + constexpr multicast(const UT& value) + { + } +}; + +// Small bitset for enum class types with available values [0, bitsize). +// T must be either enum type or convertible to (registered with via simple_t). +// Internal representation is single value of type T. +template +struct mset +{ + using type = simple_t; + using under = std::underlying_type_t; + + static constexpr auto bitsize = sizeof(type) * CHAR_BIT; + + mset() = default; + + constexpr mset(type _enum_const) + : m_value(static_cast(shift(_enum_const))) + { + } + + constexpr mset(under raw_value, const std::nothrow_t&) + : m_value(static_cast(raw_value)) + { + } + + // Get underlying value + constexpr under _value() const + { + return static_cast(m_value); + } + + explicit constexpr operator bool() const + { + return _value() ? true : false; + } + + mset& operator +=(mset rhs) + { + return *this = { _value() | rhs._value(), std::nothrow }; + } + + mset& operator -=(mset rhs) + { + return *this = { _value() & ~rhs._value(), std::nothrow }; + } + + mset& operator &=(mset rhs) + { + return *this = { _value() & rhs._value(), std::nothrow }; + } + + mset& operator ^=(mset rhs) + { + return *this = { _value() ^ rhs._value(), std::nothrow }; + } + + friend constexpr mset operator +(mset lhs, mset rhs) + { + return{ lhs._value() | rhs._value(), std::nothrow }; + } + + friend constexpr mset operator -(mset lhs, mset rhs) + { + return{ lhs._value() & ~rhs._value(), std::nothrow }; + } + + friend constexpr mset operator &(mset lhs, mset rhs) + { + return{ lhs._value() & rhs._value(), std::nothrow }; + } + + friend constexpr mset operator ^(mset lhs, mset rhs) + { + return{ lhs._value() ^ rhs._value(), std::nothrow }; + } + + bool test(mset rhs) const + { + const under v = _value(); + const under s = rhs._value(); + return (v & s) != 0; + } + + bool test_and_set(mset rhs) + { + const under v = _value(); + const under s = rhs._value(); + *this = { v | s, std::nothrow }; + return (v & s) != 0; + } + + bool test_and_reset(mset rhs) + { + const under v = _value(); + const under s = rhs._value(); + *this = { v & ~s, std::nothrow }; + return (v & s) != 0; + } + + bool test_and_complement(mset rhs) + { + const under v = _value(); + const under s = rhs._value(); + *this = { v ^ s, std::nothrow }; + return (v & s) != 0; + } + +private: + [[noreturn]] static under xrange() + { + throw std::out_of_range("mset<>: bit out of range"); + } + + static constexpr under shift(const T& value) + { + return static_cast(value) < bitsize ? static_cast(1) << static_cast(value) : xrange(); + } + + T m_value; +}; + +template +constexpr RT to_mset() +{ + return RT{}; +} + +// Fold enum constants into mset<> +template::value, mset, T>> +constexpr RT to_mset(Arg&& _enum_const, Args&&... args) +{ + return RT{ std::forward(_enum_const) } + to_mset(std::forward(args)...); +} + +template +struct atomic_add, CT, std::enable_if_t::value>> +{ + using under = typename mset::under; + + static force_inline mset op1(mset& left, mset right) + { + return{ atomic_storage::fetch_or(reinterpret_cast(left), right._value()), std::nothrow }; + } + + static constexpr auto fetch_op = &op1; + + static force_inline mset op2(mset& left, mset right) + { + return{ atomic_storage::or_fetch(reinterpret_cast(left), right._value()), std::nothrow }; + } + + static constexpr auto op_fetch = &op2; + static constexpr auto atomic_op = &op2; +}; + +template +struct atomic_sub, CT, std::enable_if_t::value>> +{ + using under = typename mset::under; + + static force_inline mset op1(mset& left, mset right) + { + return{ atomic_storage::fetch_and(reinterpret_cast(left), ~right._value()), std::nothrow }; + } + + static constexpr auto fetch_op = &op1; + + static force_inline mset op2(mset& left, mset right) + { + return{ atomic_storage::and_fetch(reinterpret_cast(left), ~right._value()), std::nothrow }; + } + + static constexpr auto op_fetch = &op2; + static constexpr auto atomic_op = &op2; +}; + +template +struct atomic_and, CT, std::enable_if_t::value>> +{ + using under = typename mset::under; + + static force_inline mset op1(mset& left, mset right) + { + return{ atomic_storage::fetch_and(reinterpret_cast(left), right._value()), std::nothrow }; + } + + static constexpr auto fetch_op = &op1; + + static force_inline mset op2(mset& left, mset right) + { + return{ atomic_storage::and_fetch(reinterpret_cast(left), right._value()), std::nothrow }; + } + + static constexpr auto op_fetch = &op2; + static constexpr auto atomic_op = &op2; +}; + +template +struct atomic_xor, CT, std::enable_if_t::value>> +{ + using under = typename mset::under; + + static force_inline mset op1(mset& left, mset right) + { + return{ atomic_storage::fetch_xor(reinterpret_cast(left), right._value()), std::nothrow }; + } + + static constexpr auto fetch_op = &op1; + + static force_inline mset op2(mset& left, mset right) + { + return{ atomic_storage::xor_fetch(reinterpret_cast(left), right._value()), std::nothrow }; + } + + static constexpr auto op_fetch = &op2; + static constexpr auto atomic_op = &op2; +}; + +template +struct atomic_test_and_set, T, std::enable_if_t::value>> +{ + using under = typename mset::under; + + static force_inline bool _op(mset& left, const T& value) + { + return atomic_storage::bts(reinterpret_cast(left), static_cast(value)); + } + + static constexpr auto atomic_op = &_op; +}; + +template +struct atomic_test_and_reset, T, std::enable_if_t::value>> +{ + using under = typename mset::under; + + static force_inline bool _op(mset& left, const T& value) + { + return atomic_storage::btr(reinterpret_cast(left), static_cast(value)); + } + + static constexpr auto atomic_op = &_op; +}; + +template +struct atomic_test_and_complement, T, std::enable_if_t::value>> +{ + using under = typename mset::under; + + static force_inline bool _op(mset& left, const T& value) + { + return atomic_storage::btc(reinterpret_cast(left), static_cast(value)); + } + + static constexpr auto atomic_op = &_op; +}; + +template +T2 bijective_find(const T& left, const DT& def = {}) +{ + for (const auto& pair : bijective::map) + { + if (pair.first == left) + { + return pair.second; + } + } + + return def; +} + + template struct size2_base { @@ -1088,15 +1744,3 @@ using color2d = color2_base; using color1i = color1_base; using color1f = color1_base; using color1d = color1_base; - -namespace std -{ - template<> - struct hash<::position2i> - { - size_t operator()(const ::position2i& position) const - { - return (static_cast(position.x) << 32) | position.y; - } - }; -} diff --git a/Utilities/wxWidgets/setup.h b/Utilities/wxWidgets/setup.h index 9cfcf48126..ff342b42ac 100644 --- a/Utilities/wxWidgets/setup.h +++ b/Utilities/wxWidgets/setup.h @@ -300,7 +300,7 @@ // Recommended setting: 0 as the options below already provide a relatively // good level of interoperability and changing this option arguably isn't worth // diverging from the official builds of the library. -#define wxUSE_STL 0 +#define wxUSE_STL 1 // This is not a real option but is used as the default value for // wxUSE_STD_IOSTREAM, wxUSE_STD_STRING and wxUSE_STD_CONTAINERS_COMPATIBLY. diff --git a/Utilities/yaml-cpp.vcxproj b/Utilities/yaml-cpp.vcxproj new file mode 100644 index 0000000000..5eae51ce94 --- /dev/null +++ b/Utilities/yaml-cpp.vcxproj @@ -0,0 +1,99 @@ + + + + + Debug + x64 + + + Release + x64 + + + + {FDC361C5-7734-493B-8CFB-037308B35122} + yamlcpp + 8.1 + + + + StaticLibrary + Unicode + v140 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Utilities/yaml-cpp.vcxproj.filters b/Utilities/yaml-cpp.vcxproj.filters new file mode 100644 index 0000000000..7b035827f8 --- /dev/null +++ b/Utilities/yaml-cpp.vcxproj.filters @@ -0,0 +1,92 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/rpcs3/PPULLVMRecompiler.vcxproj.user b/Utilities/yaml-cpp.vcxproj.user similarity index 100% rename from rpcs3/PPULLVMRecompiler.vcxproj.user rename to Utilities/yaml-cpp.vcxproj.user diff --git a/appveyor.yml b/appveyor.yml index 65603cd216..8ce9345d6d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,7 +14,7 @@ branches: before_build: # until git for win 2.5 release with commit checkout - - git submodule update --init 3rdparty/ffmpeg 3rdparty/pugixml asmjit rsx_program_decompiler 3rdparty/GSL 3rdparty/libpng Vulkan/glslang Vulkan/Vulkan-LoaderAndValidationLayers + - git submodule update --init 3rdparty/ffmpeg 3rdparty/pugixml asmjit 3rdparty/GSL 3rdparty/libpng Vulkan/glslang Vulkan/Vulkan-LoaderAndValidationLayers Utilities/yaml-cpp - 7z x wxWidgets.7z -aos -oC:\rpcs3\wxWidgets > null - 7z x zlib.7z -aos -oC:\rpcs3\ > null - if %configuration%==Release (cmake -G "Visual Studio 14 Win64" -DZLIB_ROOT=C:/rpcs3/zlib/) diff --git a/rpcs3.sln b/rpcs3.sln index 180ae13212..89f3bf4ee3 100644 --- a/rpcs3.sln +++ b/rpcs3.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.24720.0 +VisualStudioVersion = 14.0.25123.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rpcs3", "rpcs3\rpcs3.vcxproj", "{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}" ProjectSection(ProjectDependencies) = postProject @@ -161,11 +161,6 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "asmjit", "asmjit", "{E2A982F2-4B1A-48B1-8D77-A17A589C58D7}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "emucore", "rpcs3\emucore.vcxproj", "{C4A10229-4712-4BD2-B63E-50D93C67A038}" - ProjectSection(ProjectDependencies) = postProject - {8BC303AB-25BE-4276-8E57-73F171B2D672} = {8BC303AB-25BE-4276-8E57-73F171B2D672} - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "llvm", "llvm", "{C8068CE9-D626-4FEA-BEE7-893F06A25BF3}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "llvm_build", "llvm_build\llvm_build.vcxproj", "{8BC303AB-25BE-4276-8E57-73F171B2D672}" EndProject @@ -209,8 +204,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "zlib", "zlib", "{F0C19EFA-E EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "3rdparty\libpng\projects\vstudio\zlib\zlib.vcxproj", "{60F89955-91C6-3A36-8000-13C592FEC2DF}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Vulkan", "Vulkan", "{09AD61F7-97FE-4FF8-8F7F-63FEA9B746F4}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Vulkan-build", "Vulkan\Vulkan-build\Vulkan-build.vcxproj", "{58B40697-B15E-429E-B325-D52C28AEBCBF}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "glslang-build", "Vulkan\glslang-build\glslang-build.vcxproj", "{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}" @@ -221,17 +214,19 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VKGSRender", "rpcs3\VKGSRen {8F85B6CC-250F-4ACA-A617-E820A74E3E3C} = {8F85B6CC-250F-4ACA-A617-E820A74E3E3C} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PPULLVMRecompiler", "rpcs3\PPULLVMRecompiler.vcxproj", "{304A6E8B-A311-4EC5-8045-BFA8D08175CE}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "webview", "wxWidgets\build\msw\wx_webview.vcxproj", "{A8E8442A-078A-5FC5-B495-8D71BA77EE6E}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "yaml-cpp", "yaml-cpp", "{DDF904CA-2771-441A-8629-5DF2EB922A79}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "__BUILD_BEFORE", "__BUILD_BEFORE", "{B0AC29FD-7B01-4B5E-9C8D-0A081E4C5668}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yaml-cpp", "Utilities\yaml-cpp.vcxproj", "{FDC361C5-7734-493B-8CFB-037308B35122}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug - LLVM|x64 = Debug - LLVM|x64 Debug - MemLeak|x64 = Debug - MemLeak|x64 Debug|x64 = Debug|x64 - DLL Debug|x64 = DLL Debug|x64 - DLL Release|x64 = DLL Release|x64 Release - LLVM|x64 = Release - LLVM|x64 Release|x64 = Release|x64 EndGlobalSection @@ -242,10 +237,6 @@ Global {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64 {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug|x64.ActiveCfg = Debug|x64 {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug|x64.Build.0 = Debug|x64 - {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.DLL Debug|x64.ActiveCfg = Debug|x64 - {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.DLL Debug|x64.Build.0 = Debug|x64 - {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.DLL Release|x64.ActiveCfg = Release|x64 - {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.DLL Release|x64.Build.0 = Release|x64 {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64 {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Release - LLVM|x64.Build.0 = Release - LLVM|x64 {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Release|x64.ActiveCfg = Release|x64 @@ -256,10 +247,6 @@ Global {24C45343-FD20-5C92-81C1-35A2AE841E79}.Debug - MemLeak|x64.Build.0 = Debug|x64 {24C45343-FD20-5C92-81C1-35A2AE841E79}.Debug|x64.ActiveCfg = Debug|x64 {24C45343-FD20-5C92-81C1-35A2AE841E79}.Debug|x64.Build.0 = Debug|x64 - {24C45343-FD20-5C92-81C1-35A2AE841E79}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {24C45343-FD20-5C92-81C1-35A2AE841E79}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {24C45343-FD20-5C92-81C1-35A2AE841E79}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {24C45343-FD20-5C92-81C1-35A2AE841E79}.DLL Release|x64.Build.0 = DLL Release|x64 {24C45343-FD20-5C92-81C1-35A2AE841E79}.Release - LLVM|x64.ActiveCfg = Release|x64 {24C45343-FD20-5C92-81C1-35A2AE841E79}.Release - LLVM|x64.Build.0 = Release|x64 {24C45343-FD20-5C92-81C1-35A2AE841E79}.Release|x64.ActiveCfg = Release|x64 @@ -270,10 +257,6 @@ Global {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Debug - MemLeak|x64.Build.0 = Debug|x64 {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Debug|x64.ActiveCfg = Debug|x64 {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Debug|x64.Build.0 = Debug|x64 - {A16D3832-0F42-57CE-8F48-50E06649ADE8}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {A16D3832-0F42-57CE-8F48-50E06649ADE8}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {A16D3832-0F42-57CE-8F48-50E06649ADE8}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {A16D3832-0F42-57CE-8F48-50E06649ADE8}.DLL Release|x64.Build.0 = DLL Release|x64 {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Release - LLVM|x64.ActiveCfg = Release|x64 {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Release - LLVM|x64.Build.0 = Release|x64 {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Release|x64.ActiveCfg = Release|x64 @@ -284,10 +267,6 @@ Global {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug - MemLeak|x64.Build.0 = Debug|x64 {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug|x64.ActiveCfg = Debug|x64 {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug|x64.Build.0 = Debug|x64 - {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.DLL Release|x64.Build.0 = DLL Release|x64 {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release - LLVM|x64.ActiveCfg = Release|x64 {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release - LLVM|x64.Build.0 = Release|x64 {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release|x64.ActiveCfg = Release|x64 @@ -298,10 +277,6 @@ Global {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Debug - MemLeak|x64.Build.0 = Debug|x64 {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Debug|x64.ActiveCfg = Debug|x64 {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Debug|x64.Build.0 = Debug|x64 - {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.DLL Release|x64.Build.0 = DLL Release|x64 {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Release - LLVM|x64.ActiveCfg = Release|x64 {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Release - LLVM|x64.Build.0 = Release|x64 {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Release|x64.ActiveCfg = Release|x64 @@ -312,10 +287,6 @@ Global {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Debug - MemLeak|x64.Build.0 = Debug|x64 {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Debug|x64.ActiveCfg = Debug|x64 {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Debug|x64.Build.0 = Debug|x64 - {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.DLL Release|x64.Build.0 = DLL Release|x64 {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Release - LLVM|x64.ActiveCfg = Release|x64 {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Release - LLVM|x64.Build.0 = Release|x64 {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Release|x64.ActiveCfg = Release|x64 @@ -326,10 +297,6 @@ Global {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Debug - MemLeak|x64.Build.0 = Debug|x64 {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Debug|x64.ActiveCfg = Debug|x64 {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Debug|x64.Build.0 = Debug|x64 - {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.DLL Release|x64.Build.0 = DLL Release|x64 {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Release - LLVM|x64.ActiveCfg = Release|x64 {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Release - LLVM|x64.Build.0 = Release|x64 {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Release|x64.ActiveCfg = Release|x64 @@ -338,13 +305,8 @@ Global {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug - LLVM|x64.Build.0 = Debug|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug - MemLeak|x64.Build.0 = Debug|x64 - {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug - MemLeak|x64.Deploy.0 = Debug|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug|x64.ActiveCfg = Debug|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug|x64.Build.0 = Debug|x64 - {33CC42F9-7756-5587-863C-8D4461B7C5DD}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {33CC42F9-7756-5587-863C-8D4461B7C5DD}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {33CC42F9-7756-5587-863C-8D4461B7C5DD}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {33CC42F9-7756-5587-863C-8D4461B7C5DD}.DLL Release|x64.Build.0 = DLL Release|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Release - LLVM|x64.ActiveCfg = Release|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Release - LLVM|x64.Build.0 = Release|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Release|x64.ActiveCfg = Release|x64 @@ -355,10 +317,6 @@ Global {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Debug - MemLeak|x64.Build.0 = Debug|x64 {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Debug|x64.ActiveCfg = Debug|x64 {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Debug|x64.Build.0 = Debug|x64 - {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.DLL Release|x64.Build.0 = DLL Release|x64 {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Release - LLVM|x64.ActiveCfg = Release|x64 {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Release - LLVM|x64.Build.0 = Release|x64 {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Release|x64.ActiveCfg = Release|x64 @@ -369,10 +327,6 @@ Global {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Debug - MemLeak|x64.Build.0 = Debug|x64 {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Debug|x64.ActiveCfg = Debug|x64 {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Debug|x64.Build.0 = Debug|x64 - {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.DLL Release|x64.Build.0 = DLL Release|x64 {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Release - LLVM|x64.ActiveCfg = Release|x64 {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Release - LLVM|x64.Build.0 = Release|x64 {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Release|x64.ActiveCfg = Release|x64 @@ -383,10 +337,6 @@ Global {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Debug - MemLeak|x64.Build.0 = Debug|x64 {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Debug|x64.ActiveCfg = Debug|x64 {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Debug|x64.Build.0 = Debug|x64 - {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.DLL Release|x64.Build.0 = DLL Release|x64 {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Release - LLVM|x64.ActiveCfg = Release|x64 {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Release - LLVM|x64.Build.0 = Release|x64 {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Release|x64.ActiveCfg = Release|x64 @@ -397,10 +347,6 @@ Global {7FB0902D-8579-5DCE-B883-DAF66A885005}.Debug - MemLeak|x64.Build.0 = Debug|x64 {7FB0902D-8579-5DCE-B883-DAF66A885005}.Debug|x64.ActiveCfg = Debug|x64 {7FB0902D-8579-5DCE-B883-DAF66A885005}.Debug|x64.Build.0 = Debug|x64 - {7FB0902D-8579-5DCE-B883-DAF66A885005}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {7FB0902D-8579-5DCE-B883-DAF66A885005}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {7FB0902D-8579-5DCE-B883-DAF66A885005}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {7FB0902D-8579-5DCE-B883-DAF66A885005}.DLL Release|x64.Build.0 = DLL Release|x64 {7FB0902D-8579-5DCE-B883-DAF66A885005}.Release - LLVM|x64.ActiveCfg = Release|x64 {7FB0902D-8579-5DCE-B883-DAF66A885005}.Release - LLVM|x64.Build.0 = Release|x64 {7FB0902D-8579-5DCE-B883-DAF66A885005}.Release|x64.ActiveCfg = Release|x64 @@ -411,10 +357,6 @@ Global {A1A8355B-0988-528E-9CC2-B971D6266669}.Debug - MemLeak|x64.Build.0 = Debug|x64 {A1A8355B-0988-528E-9CC2-B971D6266669}.Debug|x64.ActiveCfg = Debug|x64 {A1A8355B-0988-528E-9CC2-B971D6266669}.Debug|x64.Build.0 = Debug|x64 - {A1A8355B-0988-528E-9CC2-B971D6266669}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {A1A8355B-0988-528E-9CC2-B971D6266669}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {A1A8355B-0988-528E-9CC2-B971D6266669}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {A1A8355B-0988-528E-9CC2-B971D6266669}.DLL Release|x64.Build.0 = DLL Release|x64 {A1A8355B-0988-528E-9CC2-B971D6266669}.Release - LLVM|x64.ActiveCfg = Release|x64 {A1A8355B-0988-528E-9CC2-B971D6266669}.Release - LLVM|x64.Build.0 = Release|x64 {A1A8355B-0988-528E-9CC2-B971D6266669}.Release|x64.ActiveCfg = Release|x64 @@ -425,10 +367,6 @@ Global {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Debug - MemLeak|x64.Build.0 = Debug|x64 {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Debug|x64.ActiveCfg = Debug|x64 {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Debug|x64.Build.0 = Debug|x64 - {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.DLL Release|x64.Build.0 = DLL Release|x64 {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Release - LLVM|x64.ActiveCfg = Release|x64 {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Release - LLVM|x64.Build.0 = Release|x64 {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Release|x64.ActiveCfg = Release|x64 @@ -439,10 +377,6 @@ Global {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Debug - MemLeak|x64.Build.0 = Debug|x64 {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Debug|x64.ActiveCfg = Debug|x64 {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Debug|x64.Build.0 = Debug|x64 - {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.DLL Release|x64.Build.0 = DLL Release|x64 {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Release - LLVM|x64.ActiveCfg = Release|x64 {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Release - LLVM|x64.Build.0 = Release|x64 {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Release|x64.ActiveCfg = Release|x64 @@ -453,10 +387,6 @@ Global {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Debug - MemLeak|x64.Build.0 = Debug|x64 {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Debug|x64.ActiveCfg = Debug|x64 {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Debug|x64.Build.0 = Debug|x64 - {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.DLL Release|x64.Build.0 = DLL Release|x64 {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Release - LLVM|x64.ActiveCfg = Release|x64 {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Release - LLVM|x64.Build.0 = Release|x64 {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Release|x64.ActiveCfg = Release|x64 @@ -467,10 +397,6 @@ Global {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Debug - MemLeak|x64.Build.0 = Debug|x64 {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Debug|x64.ActiveCfg = Debug|x64 {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Debug|x64.Build.0 = Debug|x64 - {75596CE6-5AE7-55C9-B890-C07B0A657A83}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {75596CE6-5AE7-55C9-B890-C07B0A657A83}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {75596CE6-5AE7-55C9-B890-C07B0A657A83}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {75596CE6-5AE7-55C9-B890-C07B0A657A83}.DLL Release|x64.Build.0 = DLL Release|x64 {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Release - LLVM|x64.ActiveCfg = Release|x64 {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Release - LLVM|x64.Build.0 = Release|x64 {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Release|x64.ActiveCfg = Release|x64 @@ -481,10 +407,6 @@ Global {8B867186-A0B5-5479-B824-E176EDD27C40}.Debug - MemLeak|x64.Build.0 = Debug|x64 {8B867186-A0B5-5479-B824-E176EDD27C40}.Debug|x64.ActiveCfg = Debug|x64 {8B867186-A0B5-5479-B824-E176EDD27C40}.Debug|x64.Build.0 = Debug|x64 - {8B867186-A0B5-5479-B824-E176EDD27C40}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {8B867186-A0B5-5479-B824-E176EDD27C40}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {8B867186-A0B5-5479-B824-E176EDD27C40}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {8B867186-A0B5-5479-B824-E176EDD27C40}.DLL Release|x64.Build.0 = DLL Release|x64 {8B867186-A0B5-5479-B824-E176EDD27C40}.Release - LLVM|x64.ActiveCfg = Release|x64 {8B867186-A0B5-5479-B824-E176EDD27C40}.Release - LLVM|x64.Build.0 = Release|x64 {8B867186-A0B5-5479-B824-E176EDD27C40}.Release|x64.ActiveCfg = Release|x64 @@ -495,10 +417,6 @@ Global {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Debug - MemLeak|x64.Build.0 = Debug|x64 {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Debug|x64.ActiveCfg = Debug|x64 {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Debug|x64.Build.0 = Debug|x64 - {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.DLL Release|x64.Build.0 = DLL Release|x64 {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Release - LLVM|x64.ActiveCfg = Release|x64 {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Release - LLVM|x64.Build.0 = Release|x64 {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Release|x64.ActiveCfg = Release|x64 @@ -509,10 +427,6 @@ Global {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Debug - MemLeak|x64.Build.0 = Debug|x64 {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Debug|x64.ActiveCfg = Debug|x64 {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Debug|x64.Build.0 = Debug|x64 - {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.DLL Release|x64.Build.0 = DLL Release|x64 {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Release - LLVM|x64.ActiveCfg = Release|x64 {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Release - LLVM|x64.Build.0 = Release|x64 {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Release|x64.ActiveCfg = Release|x64 @@ -523,10 +437,6 @@ Global {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Debug - MemLeak|x64.Build.0 = Debug|x64 {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Debug|x64.ActiveCfg = Debug|x64 {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Debug|x64.Build.0 = Debug|x64 - {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.DLL Release|x64.Build.0 = DLL Release|x64 {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Release - LLVM|x64.ActiveCfg = Release|x64 {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Release - LLVM|x64.Build.0 = Release|x64 {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Release|x64.ActiveCfg = Release|x64 @@ -537,10 +447,6 @@ Global {23E1C437-A951-5943-8639-A17F3CF2E606}.Debug - MemLeak|x64.Build.0 = Debug|x64 {23E1C437-A951-5943-8639-A17F3CF2E606}.Debug|x64.ActiveCfg = Debug|x64 {23E1C437-A951-5943-8639-A17F3CF2E606}.Debug|x64.Build.0 = Debug|x64 - {23E1C437-A951-5943-8639-A17F3CF2E606}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {23E1C437-A951-5943-8639-A17F3CF2E606}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {23E1C437-A951-5943-8639-A17F3CF2E606}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {23E1C437-A951-5943-8639-A17F3CF2E606}.DLL Release|x64.Build.0 = DLL Release|x64 {23E1C437-A951-5943-8639-A17F3CF2E606}.Release - LLVM|x64.ActiveCfg = Release|x64 {23E1C437-A951-5943-8639-A17F3CF2E606}.Release - LLVM|x64.Build.0 = Release|x64 {23E1C437-A951-5943-8639-A17F3CF2E606}.Release|x64.ActiveCfg = Release|x64 @@ -551,10 +457,6 @@ Global {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Debug - MemLeak|x64.Build.0 = Debug|x64 {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Debug|x64.ActiveCfg = Debug|x64 {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Debug|x64.Build.0 = Debug|x64 - {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.DLL Release|x64.Build.0 = DLL Release|x64 {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Release - LLVM|x64.ActiveCfg = Release|x64 {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Release - LLVM|x64.Build.0 = Release|x64 {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Release|x64.ActiveCfg = Release|x64 @@ -565,10 +467,6 @@ Global {AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64 {AC40FF01-426E-4838-A317-66354CEFAE88}.Debug|x64.ActiveCfg = Debug|x64 {AC40FF01-426E-4838-A317-66354CEFAE88}.Debug|x64.Build.0 = Debug|x64 - {AC40FF01-426E-4838-A317-66354CEFAE88}.DLL Debug|x64.ActiveCfg = Debug|x64 - {AC40FF01-426E-4838-A317-66354CEFAE88}.DLL Debug|x64.Build.0 = Debug|x64 - {AC40FF01-426E-4838-A317-66354CEFAE88}.DLL Release|x64.ActiveCfg = Release|x64 - {AC40FF01-426E-4838-A317-66354CEFAE88}.DLL Release|x64.Build.0 = Release|x64 {AC40FF01-426E-4838-A317-66354CEFAE88}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64 {AC40FF01-426E-4838-A317-66354CEFAE88}.Release - LLVM|x64.Build.0 = Release - LLVM|x64 {AC40FF01-426E-4838-A317-66354CEFAE88}.Release|x64.ActiveCfg = Release|x64 @@ -579,24 +477,14 @@ Global {C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64 {C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug|x64.ActiveCfg = Debug|x64 {C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug|x64.Build.0 = Debug|x64 - {C4A10229-4712-4BD2-B63E-50D93C67A038}.DLL Debug|x64.ActiveCfg = Debug|x64 - {C4A10229-4712-4BD2-B63E-50D93C67A038}.DLL Debug|x64.Build.0 = Debug|x64 - {C4A10229-4712-4BD2-B63E-50D93C67A038}.DLL Release|x64.ActiveCfg = Release|x64 - {C4A10229-4712-4BD2-B63E-50D93C67A038}.DLL Release|x64.Build.0 = Release|x64 {C4A10229-4712-4BD2-B63E-50D93C67A038}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64 {C4A10229-4712-4BD2-B63E-50D93C67A038}.Release - LLVM|x64.Build.0 = Release - LLVM|x64 {C4A10229-4712-4BD2-B63E-50D93C67A038}.Release|x64.ActiveCfg = Release|x64 {C4A10229-4712-4BD2-B63E-50D93C67A038}.Release|x64.Build.0 = Release|x64 {8BC303AB-25BE-4276-8E57-73F171B2D672}.Debug - LLVM|x64.ActiveCfg = Debug|x64 - {8BC303AB-25BE-4276-8E57-73F171B2D672}.Debug - LLVM|x64.Build.0 = Debug|x64 {8BC303AB-25BE-4276-8E57-73F171B2D672}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 {8BC303AB-25BE-4276-8E57-73F171B2D672}.Debug|x64.ActiveCfg = Debug|x64 - {8BC303AB-25BE-4276-8E57-73F171B2D672}.DLL Debug|x64.ActiveCfg = Debug|x64 - {8BC303AB-25BE-4276-8E57-73F171B2D672}.DLL Debug|x64.Build.0 = Debug|x64 - {8BC303AB-25BE-4276-8E57-73F171B2D672}.DLL Release|x64.ActiveCfg = Release|x64 - {8BC303AB-25BE-4276-8E57-73F171B2D672}.DLL Release|x64.Build.0 = Release|x64 {8BC303AB-25BE-4276-8E57-73F171B2D672}.Release - LLVM|x64.ActiveCfg = Release|x64 - {8BC303AB-25BE-4276-8E57-73F171B2D672}.Release - LLVM|x64.Build.0 = Release|x64 {8BC303AB-25BE-4276-8E57-73F171B2D672}.Release|x64.ActiveCfg = Release|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug - LLVM|x64.Build.0 = Debug|x64 @@ -604,10 +492,6 @@ Global {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug - MemLeak|x64.Build.0 = Debug|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug|x64.ActiveCfg = Debug|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug|x64.Build.0 = Debug|x64 - {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.DLL Release|x64.Build.0 = DLL Release|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release - LLVM|x64.ActiveCfg = Release|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release - LLVM|x64.Build.0 = Release|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release|x64.ActiveCfg = Release|x64 @@ -618,10 +502,6 @@ Global {00D36322-6188-4A66-B514-3B3F183E998D}.Debug - MemLeak|x64.Build.0 = Debug|x64 {00D36322-6188-4A66-B514-3B3F183E998D}.Debug|x64.ActiveCfg = Debug|x64 {00D36322-6188-4A66-B514-3B3F183E998D}.Debug|x64.Build.0 = Debug|x64 - {00D36322-6188-4A66-B514-3B3F183E998D}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {00D36322-6188-4A66-B514-3B3F183E998D}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {00D36322-6188-4A66-B514-3B3F183E998D}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {00D36322-6188-4A66-B514-3B3F183E998D}.DLL Release|x64.Build.0 = DLL Release|x64 {00D36322-6188-4A66-B514-3B3F183E998D}.Release - LLVM|x64.ActiveCfg = Release|x64 {00D36322-6188-4A66-B514-3B3F183E998D}.Release - LLVM|x64.Build.0 = Release|x64 {00D36322-6188-4A66-B514-3B3F183E998D}.Release|x64.ActiveCfg = Release|x64 @@ -632,24 +512,14 @@ Global {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64 {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.Debug|x64.ActiveCfg = Debug|x64 {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.Debug|x64.Build.0 = Debug|x64 - {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.DLL Debug|x64.ActiveCfg = Debug|x64 - {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.DLL Debug|x64.Build.0 = Debug|x64 - {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.DLL Release|x64.ActiveCfg = Release|x64 - {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.DLL Release|x64.Build.0 = Release|x64 {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64 {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.Release - LLVM|x64.Build.0 = Release - LLVM|x64 {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.Release|x64.ActiveCfg = Release|x64 {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.Release|x64.Build.0 = Release|x64 {AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Debug - LLVM|x64.ActiveCfg = Debug|x64 - {AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Debug - LLVM|x64.Build.0 = Debug|x64 {AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 {AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Debug|x64.ActiveCfg = Debug|x64 - {AB222E8A-00CA-4ACF-A87E-5251C16C0587}.DLL Debug|x64.ActiveCfg = Debug|x64 - {AB222E8A-00CA-4ACF-A87E-5251C16C0587}.DLL Debug|x64.Build.0 = Debug|x64 - {AB222E8A-00CA-4ACF-A87E-5251C16C0587}.DLL Release|x64.ActiveCfg = Release|x64 - {AB222E8A-00CA-4ACF-A87E-5251C16C0587}.DLL Release|x64.Build.0 = Release|x64 {AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Release - LLVM|x64.ActiveCfg = Release|x64 - {AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Release - LLVM|x64.Build.0 = Release|x64 {AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Release|x64.ActiveCfg = Release|x64 {3384223A-6D97-4799-9862-359F85312892}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64 {3384223A-6D97-4799-9862-359F85312892}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64 @@ -657,10 +527,6 @@ Global {3384223A-6D97-4799-9862-359F85312892}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64 {3384223A-6D97-4799-9862-359F85312892}.Debug|x64.ActiveCfg = Debug|x64 {3384223A-6D97-4799-9862-359F85312892}.Debug|x64.Build.0 = Debug|x64 - {3384223A-6D97-4799-9862-359F85312892}.DLL Debug|x64.ActiveCfg = Debug|x64 - {3384223A-6D97-4799-9862-359F85312892}.DLL Debug|x64.Build.0 = Debug|x64 - {3384223A-6D97-4799-9862-359F85312892}.DLL Release|x64.ActiveCfg = Release|x64 - {3384223A-6D97-4799-9862-359F85312892}.DLL Release|x64.Build.0 = Release|x64 {3384223A-6D97-4799-9862-359F85312892}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64 {3384223A-6D97-4799-9862-359F85312892}.Release - LLVM|x64.Build.0 = Release - LLVM|x64 {3384223A-6D97-4799-9862-359F85312892}.Release|x64.ActiveCfg = Release|x64 @@ -671,10 +537,6 @@ Global {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.Debug - MemLeak|x64.Build.0 = Debug|x64 {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.Debug|x64.ActiveCfg = Debug|x64 {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.Debug|x64.Build.0 = Debug|x64 - {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.DLL Debug|x64.ActiveCfg = Debug|x64 - {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.DLL Debug|x64.Build.0 = Debug|x64 - {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.DLL Release|x64.ActiveCfg = Release|x64 - {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.DLL Release|x64.Build.0 = Release|x64 {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.Release - LLVM|x64.ActiveCfg = Release|x64 {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.Release - LLVM|x64.Build.0 = Release|x64 {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.Release|x64.ActiveCfg = Release|x64 @@ -685,10 +547,6 @@ Global {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.Debug - MemLeak|x64.Build.0 = Debug|x64 {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.Debug|x64.ActiveCfg = Debug|x64 {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.Debug|x64.Build.0 = Debug|x64 - {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.DLL Debug|x64.ActiveCfg = Debug|x64 - {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.DLL Debug|x64.Build.0 = Debug|x64 - {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.DLL Release|x64.ActiveCfg = Release|x64 - {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.DLL Release|x64.Build.0 = Release|x64 {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.Release - LLVM|x64.ActiveCfg = Release|x64 {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.Release - LLVM|x64.Build.0 = Release|x64 {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.Release|x64.ActiveCfg = Release|x64 @@ -699,10 +557,6 @@ Global {78CB2F39-B809-4A06-8329-8C0A19119D3D}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64 {78CB2F39-B809-4A06-8329-8C0A19119D3D}.Debug|x64.ActiveCfg = Debug|x64 {78CB2F39-B809-4A06-8329-8C0A19119D3D}.Debug|x64.Build.0 = Debug|x64 - {78CB2F39-B809-4A06-8329-8C0A19119D3D}.DLL Debug|x64.ActiveCfg = Debug|x64 - {78CB2F39-B809-4A06-8329-8C0A19119D3D}.DLL Debug|x64.Build.0 = Debug|x64 - {78CB2F39-B809-4A06-8329-8C0A19119D3D}.DLL Release|x64.ActiveCfg = Release|x64 - {78CB2F39-B809-4A06-8329-8C0A19119D3D}.DLL Release|x64.Build.0 = Release|x64 {78CB2F39-B809-4A06-8329-8C0A19119D3D}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64 {78CB2F39-B809-4A06-8329-8C0A19119D3D}.Release - LLVM|x64.Build.0 = Release - LLVM|x64 {78CB2F39-B809-4A06-8329-8C0A19119D3D}.Release|x64.ActiveCfg = Release|x64 @@ -713,10 +567,6 @@ Global {30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64 {30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Debug|x64.ActiveCfg = Debug|x64 {30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Debug|x64.Build.0 = Debug|x64 - {30A05C4D-F5FD-421C-A864-17A64BDEAA75}.DLL Debug|x64.ActiveCfg = Debug|x64 - {30A05C4D-F5FD-421C-A864-17A64BDEAA75}.DLL Debug|x64.Build.0 = Debug|x64 - {30A05C4D-F5FD-421C-A864-17A64BDEAA75}.DLL Release|x64.ActiveCfg = Release|x64 - {30A05C4D-F5FD-421C-A864-17A64BDEAA75}.DLL Release|x64.Build.0 = Release|x64 {30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64 {30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Release - LLVM|x64.Build.0 = Release - LLVM|x64 {30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Release|x64.ActiveCfg = Release|x64 @@ -727,10 +577,6 @@ Global {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug - MemLeak|x64.Build.0 = Debug Library|x64 {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.ActiveCfg = Debug Library|x64 {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.Build.0 = Debug Library|x64 - {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.DLL Debug|x64.ActiveCfg = Debug|x64 - {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.DLL Debug|x64.Build.0 = Debug|x64 - {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.DLL Release|x64.ActiveCfg = Release|x64 - {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.DLL Release|x64.Build.0 = Release|x64 {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release - LLVM|x64.ActiveCfg = Release Library|x64 {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release - LLVM|x64.Build.0 = Release Library|x64 {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release|x64.ActiveCfg = Release Library|x64 @@ -741,84 +587,50 @@ Global {60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug - MemLeak|x64.Build.0 = Debug Library|x64 {60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug|x64.ActiveCfg = Debug Library|x64 {60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug|x64.Build.0 = Debug Library|x64 - {60F89955-91C6-3A36-8000-13C592FEC2DF}.DLL Debug|x64.ActiveCfg = Debug Library|x64 - {60F89955-91C6-3A36-8000-13C592FEC2DF}.DLL Debug|x64.Build.0 = Debug Library|x64 - {60F89955-91C6-3A36-8000-13C592FEC2DF}.DLL Release|x64.ActiveCfg = Release Library|x64 - {60F89955-91C6-3A36-8000-13C592FEC2DF}.DLL Release|x64.Build.0 = Release Library|x64 {60F89955-91C6-3A36-8000-13C592FEC2DF}.Release - LLVM|x64.ActiveCfg = Release Library|x64 {60F89955-91C6-3A36-8000-13C592FEC2DF}.Release - LLVM|x64.Build.0 = Release Library|x64 {60F89955-91C6-3A36-8000-13C592FEC2DF}.Release|x64.ActiveCfg = Release Library|x64 {60F89955-91C6-3A36-8000-13C592FEC2DF}.Release|x64.Build.0 = Release Library|x64 {58B40697-B15E-429E-B325-D52C28AEBCBF}.Debug - LLVM|x64.ActiveCfg = Debug|x64 - {58B40697-B15E-429E-B325-D52C28AEBCBF}.Debug - LLVM|x64.Build.0 = Debug|x64 {58B40697-B15E-429E-B325-D52C28AEBCBF}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 - {58B40697-B15E-429E-B325-D52C28AEBCBF}.Debug - MemLeak|x64.Build.0 = Debug|x64 {58B40697-B15E-429E-B325-D52C28AEBCBF}.Debug|x64.ActiveCfg = Debug|x64 - {58B40697-B15E-429E-B325-D52C28AEBCBF}.Debug|x64.Build.0 = Debug|x64 - {58B40697-B15E-429E-B325-D52C28AEBCBF}.DLL Debug|x64.ActiveCfg = Debug|x64 - {58B40697-B15E-429E-B325-D52C28AEBCBF}.DLL Debug|x64.Build.0 = Debug|x64 - {58B40697-B15E-429E-B325-D52C28AEBCBF}.DLL Release|x64.ActiveCfg = Release|x64 - {58B40697-B15E-429E-B325-D52C28AEBCBF}.DLL Release|x64.Build.0 = Release|x64 {58B40697-B15E-429E-B325-D52C28AEBCBF}.Release - LLVM|x64.ActiveCfg = Release|x64 - {58B40697-B15E-429E-B325-D52C28AEBCBF}.Release - LLVM|x64.Build.0 = Release|x64 {58B40697-B15E-429E-B325-D52C28AEBCBF}.Release|x64.ActiveCfg = Release|x64 - {58B40697-B15E-429E-B325-D52C28AEBCBF}.Release|x64.Build.0 = Release|x64 {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Debug - LLVM|x64.ActiveCfg = Debug|x64 - {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Debug - LLVM|x64.Build.0 = Debug|x64 {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 - {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Debug - MemLeak|x64.Build.0 = Debug|x64 {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Debug|x64.ActiveCfg = Debug|x64 - {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Debug|x64.Build.0 = Debug|x64 - {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.DLL Debug|x64.ActiveCfg = Debug|x64 - {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.DLL Debug|x64.Build.0 = Debug|x64 - {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.DLL Release|x64.ActiveCfg = Release|x64 - {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.DLL Release|x64.Build.0 = Release|x64 {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Release - LLVM|x64.ActiveCfg = Release|x64 - {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Release - LLVM|x64.Build.0 = Release|x64 {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Release|x64.ActiveCfg = Release|x64 - {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Release|x64.Build.0 = Release|x64 - {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - LLVM|x64.ActiveCfg = Debug|x64 - {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - LLVM|x64.Build.0 = Debug|x64 - {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 - {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - MemLeak|x64.Build.0 = Debug|x64 + {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64 + {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64 + {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - MemLeak|x64.ActiveCfg = Debug - MemLeak|x64 + {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64 {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug|x64.ActiveCfg = Debug|x64 {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug|x64.Build.0 = Debug|x64 - {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.DLL Debug|x64.ActiveCfg = Debug|x64 - {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.DLL Debug|x64.Build.0 = Debug|x64 - {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.DLL Release|x64.ActiveCfg = Release|x64 - {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.DLL Release|x64.Build.0 = Release|x64 - {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Release - LLVM|x64.ActiveCfg = Release|x64 - {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Release - LLVM|x64.Build.0 = Release|x64 + {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64 + {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Release - LLVM|x64.Build.0 = Release - LLVM|x64 {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Release|x64.ActiveCfg = Release|x64 {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Release|x64.Build.0 = Release|x64 - {304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64 - {304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64 - {304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Debug - MemLeak|x64.ActiveCfg = Debug - MemLeak|x64 - {304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64 - {304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Debug|x64.ActiveCfg = Debug|x64 - {304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Debug|x64.Build.0 = Debug|x64 - {304A6E8B-A311-4EC5-8045-BFA8D08175CE}.DLL Debug|x64.ActiveCfg = Debug|x64 - {304A6E8B-A311-4EC5-8045-BFA8D08175CE}.DLL Debug|x64.Build.0 = Debug|x64 - {304A6E8B-A311-4EC5-8045-BFA8D08175CE}.DLL Release|x64.ActiveCfg = Release|x64 - {304A6E8B-A311-4EC5-8045-BFA8D08175CE}.DLL Release|x64.Build.0 = Release|x64 - {304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64 - {304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Release - LLVM|x64.Build.0 = Release - LLVM|x64 - {304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Release|x64.ActiveCfg = Release|x64 - {304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Release|x64.Build.0 = Release|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Debug - LLVM|x64.Build.0 = Debug|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Debug - MemLeak|x64.Build.0 = Debug|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Debug|x64.ActiveCfg = Debug|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Debug|x64.Build.0 = Debug|x64 - {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.DLL Release|x64.Build.0 = DLL Release|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Release - LLVM|x64.ActiveCfg = Release|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Release - LLVM|x64.Build.0 = Release|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Release|x64.ActiveCfg = Release|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Release|x64.Build.0 = Release|x64 + {FDC361C5-7734-493B-8CFB-037308B35122}.Debug - LLVM|x64.ActiveCfg = Debug|x64 + {FDC361C5-7734-493B-8CFB-037308B35122}.Debug - LLVM|x64.Build.0 = Debug|x64 + {FDC361C5-7734-493B-8CFB-037308B35122}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 + {FDC361C5-7734-493B-8CFB-037308B35122}.Debug - MemLeak|x64.Build.0 = Debug|x64 + {FDC361C5-7734-493B-8CFB-037308B35122}.Debug|x64.ActiveCfg = Debug|x64 + {FDC361C5-7734-493B-8CFB-037308B35122}.Debug|x64.Build.0 = Debug|x64 + {FDC361C5-7734-493B-8CFB-037308B35122}.Release - LLVM|x64.ActiveCfg = Release|x64 + {FDC361C5-7734-493B-8CFB-037308B35122}.Release - LLVM|x64.Build.0 = Release|x64 + {FDC361C5-7734-493B-8CFB-037308B35122}.Release|x64.ActiveCfg = Release|x64 + {FDC361C5-7734-493B-8CFB-037308B35122}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -848,8 +660,7 @@ Global {74827EBD-93DC-5110-BA95-3F2AB029B6B0} = {5812E712-6213-4372-B095-9EB9BAA1F2DF} {AC40FF01-426E-4838-A317-66354CEFAE88} = {E2A982F2-4B1A-48B1-8D77-A17A589C58D7} {C4A10229-4712-4BD2-B63E-50D93C67A038} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2} - {C8068CE9-D626-4FEA-BEE7-893F06A25BF3} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2} - {8BC303AB-25BE-4276-8E57-73F171B2D672} = {C8068CE9-D626-4FEA-BEE7-893F06A25BF3} + {8BC303AB-25BE-4276-8E57-73F171B2D672} = {B0AC29FD-7B01-4B5E-9C8D-0A081E4C5668} {01F4CE10-2CFB-41A8-B41F-E54337868A1D} = {5812E712-6213-4372-B095-9EB9BAA1F2DF} {00D36322-6188-4A66-B514-3B3F183E998D} = {5812E712-6213-4372-B095-9EB9BAA1F2DF} {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2} @@ -859,10 +670,10 @@ Global {30A05C4D-F5FD-421C-A864-17A64BDEAA75} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2} {D6973076-9317-4EF2-A0B8-B7A18AC0713E} = {A17D34F1-7E3E-4841-818D-3B7C6F5AF829} {60F89955-91C6-3A36-8000-13C592FEC2DF} = {F0C19EFA-EDD0-43F2-97C1-18E865E96B4E} - {58B40697-B15E-429E-B325-D52C28AEBCBF} = {09AD61F7-97FE-4FF8-8F7F-63FEA9B746F4} - {8F85B6CC-250F-4ACA-A617-E820A74E3E3C} = {09AD61F7-97FE-4FF8-8F7F-63FEA9B746F4} + {58B40697-B15E-429E-B325-D52C28AEBCBF} = {B0AC29FD-7B01-4B5E-9C8D-0A081E4C5668} + {8F85B6CC-250F-4ACA-A617-E820A74E3E3C} = {B0AC29FD-7B01-4B5E-9C8D-0A081E4C5668} {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2} - {304A6E8B-A311-4EC5-8045-BFA8D08175CE} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2} {A8E8442A-078A-5FC5-B495-8D71BA77EE6E} = {5812E712-6213-4372-B095-9EB9BAA1F2DF} + {FDC361C5-7734-493B-8CFB-037308B35122} = {DDF904CA-2771-441A-8629-5DF2EB922A79} EndGlobalSection EndGlobal diff --git a/rpcs3/BasicKeyboardHandler.cpp b/rpcs3/BasicKeyboardHandler.cpp new file mode 100644 index 0000000000..b0947155f4 --- /dev/null +++ b/rpcs3/BasicKeyboardHandler.cpp @@ -0,0 +1,170 @@ +#include "stdafx.h" +#include "stdafx_gui.h" +#include "rpcs3.h" +#include "BasicKeyboardHandler.h" + +void BasicKeyboardHandler::Init(const u32 max_connect) +{ + for (u32 i = 0; i(m_keyboards.size(), max_connect); + m_info.info = 0; // Ownership of keyboard data: 0=Application, 1=System + m_info.status[0] = CELL_KB_STATUS_CONNECTED; // (TODO: Support for more keyboards) +} + +BasicKeyboardHandler::BasicKeyboardHandler() +{ + wxGetApp().Bind(wxEVT_KEY_DOWN, &BasicKeyboardHandler::KeyDown, this); + wxGetApp().Bind(wxEVT_KEY_UP, &BasicKeyboardHandler::KeyUp, this); +} + +void BasicKeyboardHandler::KeyDown(wxKeyEvent& event) +{ + Key(event.GetKeyCode(), 1); + event.Skip(); +} + +void BasicKeyboardHandler::KeyUp(wxKeyEvent& event) +{ + Key(event.GetKeyCode(), 0); + event.Skip(); +} + +void BasicKeyboardHandler::LoadSettings() +{ + // Meta Keys + m_keyboards[0].m_buttons.emplace_back(WXK_CONTROL, CELL_KB_MKEY_L_CTRL); + m_keyboards[0].m_buttons.emplace_back(WXK_SHIFT, CELL_KB_MKEY_L_SHIFT); + m_keyboards[0].m_buttons.emplace_back(WXK_ALT, CELL_KB_MKEY_L_ALT); + m_keyboards[0].m_buttons.emplace_back(WXK_WINDOWS_LEFT, CELL_KB_MKEY_L_WIN); + m_keyboards[0].m_buttons.emplace_back(WXK_COMMAND, CELL_KB_MKEY_L_WIN); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KB_MKEY_R_CTRL); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KB_MKEY_R_SHIFT); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KB_MKEY_R_ALT); + m_keyboards[0].m_buttons.emplace_back(WXK_WINDOWS_RIGHT, CELL_KB_MKEY_R_WIN); + + // CELL_KB_RAWDAT + //m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_NO_EVENT); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_E_ROLLOVER); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_E_POSTFAIL); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_E_UNDEF); + m_keyboards[0].m_buttons.emplace_back(WXK_ESCAPE, CELL_KEYC_ESCAPE); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_106_KANJI); + m_keyboards[0].m_buttons.emplace_back(WXK_CAPITAL, CELL_KEYC_CAPS_LOCK); + m_keyboards[0].m_buttons.emplace_back(WXK_F1, CELL_KEYC_F1); + m_keyboards[0].m_buttons.emplace_back(WXK_F2, CELL_KEYC_F2); + m_keyboards[0].m_buttons.emplace_back(WXK_F3, CELL_KEYC_F3); + m_keyboards[0].m_buttons.emplace_back(WXK_F4, CELL_KEYC_F4); + m_keyboards[0].m_buttons.emplace_back(WXK_F5, CELL_KEYC_F5); + m_keyboards[0].m_buttons.emplace_back(WXK_F6, CELL_KEYC_F6); + m_keyboards[0].m_buttons.emplace_back(WXK_F7, CELL_KEYC_F7); + m_keyboards[0].m_buttons.emplace_back(WXK_F8, CELL_KEYC_F8); + m_keyboards[0].m_buttons.emplace_back(WXK_F9, CELL_KEYC_F9); + m_keyboards[0].m_buttons.emplace_back(WXK_F10, CELL_KEYC_F10); + m_keyboards[0].m_buttons.emplace_back(WXK_F11, CELL_KEYC_F11); + m_keyboards[0].m_buttons.emplace_back(WXK_F12, CELL_KEYC_F12); + m_keyboards[0].m_buttons.emplace_back(WXK_PRINT, CELL_KEYC_PRINTSCREEN); + m_keyboards[0].m_buttons.emplace_back(WXK_SCROLL, CELL_KEYC_SCROLL_LOCK); + m_keyboards[0].m_buttons.emplace_back(WXK_PAUSE, CELL_KEYC_PAUSE); + m_keyboards[0].m_buttons.emplace_back(WXK_INSERT, CELL_KEYC_INSERT); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_HOME); + m_keyboards[0].m_buttons.emplace_back(WXK_PAGEUP, CELL_KEYC_PAGE_UP); + m_keyboards[0].m_buttons.emplace_back(WXK_DELETE, CELL_KEYC_DELETE); + m_keyboards[0].m_buttons.emplace_back(WXK_END, CELL_KEYC_END); + m_keyboards[0].m_buttons.emplace_back(WXK_PAGEDOWN, CELL_KEYC_PAGE_DOWN); + m_keyboards[0].m_buttons.emplace_back(WXK_RIGHT, CELL_KEYC_RIGHT_ARROW); + m_keyboards[0].m_buttons.emplace_back(WXK_LEFT, CELL_KEYC_LEFT_ARROW); + m_keyboards[0].m_buttons.emplace_back(WXK_DOWN, CELL_KEYC_DOWN_ARROW); + m_keyboards[0].m_buttons.emplace_back(WXK_UP, CELL_KEYC_UP_ARROW); + //m_keyboards[0].m_buttons.emplace_back(WXK_NUMLOCK, CELL_KEYC_NUM_LOCK); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_APPLICATION); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_KANA); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_HENKAN); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_MUHENKAN); + + // CELL_KB_KEYPAD + m_keyboards[0].m_buttons.emplace_back(WXK_NUMLOCK, CELL_KEYC_KPAD_NUMLOCK); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD_DIVIDE, CELL_KEYC_KPAD_SLASH); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD_MULTIPLY, CELL_KEYC_KPAD_ASTERISK); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD_SUBTRACT, CELL_KEYC_KPAD_MINUS); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD_ADD, CELL_KEYC_KPAD_PLUS); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD_ENTER, CELL_KEYC_KPAD_ENTER); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD1, CELL_KEYC_KPAD_1); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD2, CELL_KEYC_KPAD_2); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD3, CELL_KEYC_KPAD_3); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD4, CELL_KEYC_KPAD_4); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD5, CELL_KEYC_KPAD_5); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD6, CELL_KEYC_KPAD_6); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD7, CELL_KEYC_KPAD_7); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD8, CELL_KEYC_KPAD_8); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD9, CELL_KEYC_KPAD_9); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD0, CELL_KEYC_KPAD_0); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD_DELETE, CELL_KEYC_KPAD_PERIOD); + + // ASCII Printable characters + m_keyboards[0].m_buttons.emplace_back('A', CELL_KEYC_A); + m_keyboards[0].m_buttons.emplace_back('B', CELL_KEYC_B); + m_keyboards[0].m_buttons.emplace_back('C', CELL_KEYC_C); + m_keyboards[0].m_buttons.emplace_back('D', CELL_KEYC_D); + m_keyboards[0].m_buttons.emplace_back('E', CELL_KEYC_E); + m_keyboards[0].m_buttons.emplace_back('F', CELL_KEYC_F); + m_keyboards[0].m_buttons.emplace_back('G', CELL_KEYC_G); + m_keyboards[0].m_buttons.emplace_back('H', CELL_KEYC_H); + m_keyboards[0].m_buttons.emplace_back('I', CELL_KEYC_I); + m_keyboards[0].m_buttons.emplace_back('J', CELL_KEYC_J); + m_keyboards[0].m_buttons.emplace_back('K', CELL_KEYC_K); + m_keyboards[0].m_buttons.emplace_back('L', CELL_KEYC_L); + m_keyboards[0].m_buttons.emplace_back('M', CELL_KEYC_M); + m_keyboards[0].m_buttons.emplace_back('N', CELL_KEYC_N); + m_keyboards[0].m_buttons.emplace_back('O', CELL_KEYC_O); + m_keyboards[0].m_buttons.emplace_back('P', CELL_KEYC_P); + m_keyboards[0].m_buttons.emplace_back('Q', CELL_KEYC_Q); + m_keyboards[0].m_buttons.emplace_back('R', CELL_KEYC_R); + m_keyboards[0].m_buttons.emplace_back('S', CELL_KEYC_S); + m_keyboards[0].m_buttons.emplace_back('T', CELL_KEYC_T); + m_keyboards[0].m_buttons.emplace_back('U', CELL_KEYC_U); + m_keyboards[0].m_buttons.emplace_back('V', CELL_KEYC_V); + m_keyboards[0].m_buttons.emplace_back('W', CELL_KEYC_W); + m_keyboards[0].m_buttons.emplace_back('X', CELL_KEYC_X); + m_keyboards[0].m_buttons.emplace_back('Y', CELL_KEYC_Y); + m_keyboards[0].m_buttons.emplace_back('Z', CELL_KEYC_Z); + + m_keyboards[0].m_buttons.emplace_back('1', CELL_KEYC_1); + m_keyboards[0].m_buttons.emplace_back('2', CELL_KEYC_2); + m_keyboards[0].m_buttons.emplace_back('3', CELL_KEYC_3); + m_keyboards[0].m_buttons.emplace_back('4', CELL_KEYC_4); + m_keyboards[0].m_buttons.emplace_back('5', CELL_KEYC_5); + m_keyboards[0].m_buttons.emplace_back('6', CELL_KEYC_6); + m_keyboards[0].m_buttons.emplace_back('7', CELL_KEYC_7); + m_keyboards[0].m_buttons.emplace_back('8', CELL_KEYC_8); + m_keyboards[0].m_buttons.emplace_back('9', CELL_KEYC_9); + m_keyboards[0].m_buttons.emplace_back('0', CELL_KEYC_0); + + m_keyboards[0].m_buttons.emplace_back(WXK_RETURN, CELL_KEYC_ENTER); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_ESC); + m_keyboards[0].m_buttons.emplace_back(WXK_TAB, CELL_KEYC_TAB); + m_keyboards[0].m_buttons.emplace_back(WXK_SPACE, CELL_KEYC_SPACE); + m_keyboards[0].m_buttons.emplace_back(WXK_SUBTRACT, CELL_KEYC_MINUS); + m_keyboards[0].m_buttons.emplace_back('=', CELL_KEYC_EQUAL_101); + m_keyboards[0].m_buttons.emplace_back('^', CELL_KEYC_ACCENT_CIRCONFLEX_106); + //m_keyboards[0].m_buttons.emplace_back('(', CELL_KEYC_LEFT_BRACKET_101); + m_keyboards[0].m_buttons.emplace_back('@', CELL_KEYC_ATMARK_106); + //m_keyboards[0].m_buttons.emplace_back(')', CELL_KEYC_RIGHT_BRACKET_101); + m_keyboards[0].m_buttons.emplace_back('(', CELL_KEYC_LEFT_BRACKET_106); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_BACKSLASH_101); + m_keyboards[0].m_buttons.emplace_back('(', CELL_KEYC_RIGHT_BRACKET_106); + m_keyboards[0].m_buttons.emplace_back(';', CELL_KEYC_SEMICOLON); + m_keyboards[0].m_buttons.emplace_back('"', CELL_KEYC_QUOTATION_101); + m_keyboards[0].m_buttons.emplace_back(':', CELL_KEYC_COLON_106); + m_keyboards[0].m_buttons.emplace_back(',', CELL_KEYC_COMMA); + m_keyboards[0].m_buttons.emplace_back('.', CELL_KEYC_PERIOD); + m_keyboards[0].m_buttons.emplace_back('/', CELL_KEYC_SLASH); + m_keyboards[0].m_buttons.emplace_back('\\', CELL_KEYC_BACKSLASH_106); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_YEN_106); +} diff --git a/rpcs3/BasicKeyboardHandler.h b/rpcs3/BasicKeyboardHandler.h new file mode 100644 index 0000000000..2c83265d23 --- /dev/null +++ b/rpcs3/BasicKeyboardHandler.h @@ -0,0 +1,15 @@ +#pragma once + +#include "Emu/Io/KeyboardHandler.h" + +class BasicKeyboardHandler final : public KeyboardHandlerBase, public wxWindow +{ +public: + virtual void Init(const u32 max_connect) override; + + BasicKeyboardHandler(); + + void KeyDown(wxKeyEvent& event); + void KeyUp(wxKeyEvent& event); + void LoadSettings(); +}; diff --git a/rpcs3/BasicMouseHandler.cpp b/rpcs3/BasicMouseHandler.cpp new file mode 100644 index 0000000000..3a6b55ca1f --- /dev/null +++ b/rpcs3/BasicMouseHandler.cpp @@ -0,0 +1,57 @@ +#include "stdafx.h" +#include "stdafx_gui.h" +#include "rpcs3.h" +#include "BasicMouseHandler.h" + +void BasicMouseHandler::Init(const u32 max_connect) +{ + m_mice.emplace_back(Mouse()); + memset(&m_info, 0, sizeof(MouseInfo)); + m_info.max_connect = max_connect; + m_info.now_connect = std::min(m_mice.size(), (size_t)max_connect); + m_info.info = 0; // Ownership of mouse data: 0=Application, 1=System + m_info.status[0] = CELL_MOUSE_STATUS_CONNECTED; // (TODO: Support for more mice) + for (u32 i = 1; i +#include + enum SELF_KEY_TYPE { KEY_LV0 = 1, KEY_LV1, diff --git a/rpcs3/Crypto/lz.cpp b/rpcs3/Crypto/lz.cpp index e2290e3793..b56ac78e6e 100644 --- a/rpcs3/Crypto/lz.cpp +++ b/rpcs3/Crypto/lz.cpp @@ -281,4 +281,4 @@ int decompress(unsigned char *out, unsigned char *in, unsigned int size) } delete[] tmp; return result; -} \ No newline at end of file +} diff --git a/rpcs3/Crypto/lz.h b/rpcs3/Crypto/lz.h index f84415623d..3c28ca48be 100644 --- a/rpcs3/Crypto/lz.h +++ b/rpcs3/Crypto/lz.h @@ -12,4 +12,4 @@ void decode_range(unsigned int *range, unsigned int *code, unsigned char **src); int decode_bit(unsigned int *range, unsigned int *code, int *index, unsigned char **src, unsigned char *c); int decode_number(unsigned char *ptr, int index, int *bit_flag, unsigned int *range, unsigned int *code, unsigned char **src); int decode_word(unsigned char *ptr, int index, int *bit_flag, unsigned int *range, unsigned int *code, unsigned char **src); -int decompress(unsigned char *out, unsigned char *in, unsigned int size); \ No newline at end of file +int decompress(unsigned char *out, unsigned char *in, unsigned int size); diff --git a/rpcs3/Crypto/sha1.cpp b/rpcs3/Crypto/sha1.cpp index 7cede4b205..37a54f0deb 100644 --- a/rpcs3/Crypto/sha1.cpp +++ b/rpcs3/Crypto/sha1.cpp @@ -28,7 +28,6 @@ * http://www.itl.nist.gov/fipspubs/fip180-1.htm */ -#include "stdafx.h" #include "sha1.h" /* @@ -394,4 +393,4 @@ void sha1_hmac( const unsigned char *key, size_t keylen, sha1_hmac_finish( &ctx, output ); memset( &ctx, 0, sizeof( sha1_context ) ); -} \ No newline at end of file +} diff --git a/rpcs3/Crypto/unedat.cpp b/rpcs3/Crypto/unedat.cpp index 39d17eecd2..09f743079f 100644 --- a/rpcs3/Crypto/unedat.cpp +++ b/rpcs3/Crypto/unedat.cpp @@ -170,7 +170,7 @@ int decrypt_data(const fs::file* in, const fs::file* out, EDAT_HEADER *edat, NPD { metadata_sec_offset = metadata_offset + (unsigned long long) i * metadata_section_size; - CHECK_ASSERTION(in->seek(metadata_sec_offset) != -1); + in->seek(metadata_sec_offset); unsigned char metadata[0x20]; memset(metadata, 0, 0x20); @@ -199,7 +199,7 @@ int decrypt_data(const fs::file* in, const fs::file* out, EDAT_HEADER *edat, NPD { // If FLAG 0x20, the metadata precedes each data block. metadata_sec_offset = metadata_offset + (unsigned long long) i * (metadata_section_size + length); - CHECK_ASSERTION(in->seek(metadata_sec_offset) != -1); + in->seek(metadata_sec_offset); unsigned char metadata[0x20]; memset(metadata, 0, 0x20); @@ -220,7 +220,7 @@ int decrypt_data(const fs::file* in, const fs::file* out, EDAT_HEADER *edat, NPD else { metadata_sec_offset = metadata_offset + (unsigned long long) i * metadata_section_size; - CHECK_ASSERTION(in->seek(metadata_sec_offset) != -1); + in->seek(metadata_sec_offset); in->read(hash_result, 0x10); offset = metadata_offset + (unsigned long long) i * edat->block_size + (unsigned long long) block_num * metadata_section_size; @@ -242,8 +242,7 @@ int decrypt_data(const fs::file* in, const fs::file* out, EDAT_HEADER *edat, NPD memset(hash, 0, 0x10); memset(key_result, 0, 0x10); - CHECK_ASSERTION(in->seek(offset) != -1); - + in->seek(offset); in->read(enc_data, length); // Generate a key for the current block. @@ -347,7 +346,7 @@ int decrypt_data(const fs::file* in, const fs::file* out, EDAT_HEADER *edat, NPD int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs::file* f, bool verbose) { - CHECK_ASSERTION(f->seek(0) != -1); + f->seek(0); unsigned char header[0xA0]; unsigned char empty_header[0xA0]; unsigned char header_hash[0x10]; @@ -392,8 +391,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs: f->read(header, 0xA0); // Read in the header and metadata section hashes. - CHECK_ASSERTION(f->seek(0x90) != -1); - + f->seek(0x90); f->read(metadata_hash, 0x10); f->read(header_hash, 0x10); @@ -449,7 +447,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs: while (bytes_to_read > 0) { // Locate the metadata blocks. - CHECK_ASSERTION(f->seek(metadata_section_offset) != -1); + f->seek(metadata_section_offset); // Read in the metadata. f->read(metadata + bytes_read, metadata_section_size); @@ -496,9 +494,9 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs: // Read in the metadata and header signatures. - CHECK_ASSERTION(f->seek(0xB0) != -1); + f->seek(0xB0); f->read(metadata_signature, 0x28); - CHECK_ASSERTION(f->seek(0xD8) != -1); + f->seek(0xD8); f->read(header_signature, 0x28); // Checking metadata signature. @@ -514,7 +512,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs: { int metadata_buf_size = block_num * 0x10; unsigned char *metadata_buf = new unsigned char[metadata_buf_size]; - CHECK_ASSERTION(f->seek(metadata_offset) != -1); + f->seek(metadata_offset); f->read(metadata_buf, metadata_buf_size); sha1(metadata_buf, metadata_buf_size, signature_hash); delete[] metadata_buf; @@ -547,7 +545,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs: // Setup header signature hash. memset(signature_hash, 0, 20); unsigned char *header_buf = new unsigned char[0xD8]; - CHECK_ASSERTION(f->seek(0x00) != -1); + f->seek(0x00); f->read(header_buf, 0xD8); sha1(header_buf, 0xD8, signature_hash ); delete[] header_buf; @@ -819,7 +817,7 @@ int DecryptEDAT(const std::string& input_file_name, const std::string& output_fi { // Prepare the files. fs::file input(input_file_name); - fs::file output(output_file_name, fom::rewrite); + fs::file output(output_file_name, fs::rewrite); // Set keys (RIF and DEVKLIC). unsigned char rifkey[0x10]; @@ -893,7 +891,7 @@ int DecryptEDAT(const std::string& input_file_name, const std::string& output_fi // Delete the bad output file if any errors arise. if (extract_data(&input, &output, input_file_name.c_str(), devklic, rifkey, verbose)) { - output.close(); + output.release(); fs::remove_file(output_file_name); return -1; } diff --git a/rpcs3/Crypto/unpkg.cpp b/rpcs3/Crypto/unpkg.cpp index 568e5aaa63..79f7fc59b5 100644 --- a/rpcs3/Crypto/unpkg.cpp +++ b/rpcs3/Crypto/unpkg.cpp @@ -62,12 +62,12 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, volatile f64& pr const std::size_t BUF_SIZE = 8192 * 1024; // 8 MB // Save current file offset (probably zero) - const u64 start_offset = pkg_f.seek(0, fs::seek_cur); + const u64 start_offset = pkg_f.pos(); // Get basic PKG information PKGHeader header; - if (pkg_f.read(&header, sizeof(PKGHeader)) != sizeof(PKGHeader)) + if (!pkg_f.read(header)) { LOG_ERROR(LOADER, "PKG: Package file is too short!"); return false; @@ -84,7 +84,7 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, volatile f64& pr // Define decryption subfunction (`psp` arg selects the key for specific block) auto decrypt = [&](u64 offset, u64 size, bool psp) -> u64 { - CHECK_ASSERTION(pkg_f.seek(start_offset + header.data_offset + offset) != -1); + pkg_f.seek(start_offset + header.data_offset + offset); // Read the data and set available size const u64 read = pkg_f.read(buf.get(), size); @@ -175,7 +175,7 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, volatile f64& pr const bool did_overwrite = fs::is_file(path); - if (fs::file out{ path, fom::write | fom::create | fom::trunc }) + if (fs::file out{ path, fs::rewrite }) { for (u64 pos = 0; pos < entry.file_size; pos += BUF_SIZE) { diff --git a/rpcs3/Crypto/unself.cpp b/rpcs3/Crypto/unself.cpp index a6390c7ac5..c911e6eb7a 100644 --- a/rpcs3/Crypto/unself.cpp +++ b/rpcs3/Crypto/unself.cpp @@ -2,131 +2,90 @@ #include "aes.h" #include "sha1.h" #include "utils.h" -#include "Emu/FS/vfsLocalFile.h" #include "unself.h" -#pragma warning(push) -#pragma message("TODO: remove wx dependencies: See comment below.") -#pragma warning(disable : 4996) // TODO: Still reliant on wxWidgets for zlib functions. Alternative solutions? #include -#pragma warning(pop) - -force_inline u8 Read8(vfsStream& f) +force_inline u8 Read8(const fs::file& f) { u8 ret; - f.Read(&ret, sizeof(ret)); + f.read(&ret, sizeof(ret)); return ret; } -force_inline u16 Read16(vfsStream& f) +force_inline u16 Read16(const fs::file& f) { be_t ret; - f.Read(&ret, sizeof(ret)); + f.read(&ret, sizeof(ret)); return ret; } -force_inline u32 Read32(vfsStream& f) +force_inline u32 Read32(const fs::file& f) { be_t ret; - f.Read(&ret, sizeof(ret)); + f.read(&ret, sizeof(ret)); return ret; } -force_inline u64 Read64(vfsStream& f) +force_inline u64 Read64(const fs::file& f) { be_t ret; - f.Read(&ret, sizeof(ret)); + f.read(&ret, sizeof(ret)); return ret; } -force_inline u16 Read16LE(vfsStream& f) +force_inline u16 Read16LE(const fs::file& f) { u16 ret; - f.Read(&ret, sizeof(ret)); + f.read(&ret, sizeof(ret)); return ret; } -force_inline u32 Read32LE(vfsStream& f) +force_inline u32 Read32LE(const fs::file& f) { u32 ret; - f.Read(&ret, sizeof(ret)); + f.read(&ret, sizeof(ret)); return ret; } -force_inline u64 Read64LE(vfsStream& f) +force_inline u64 Read64LE(const fs::file& f) { u64 ret; - f.Read(&ret, sizeof(ret)); + f.read(&ret, sizeof(ret)); return ret; } -force_inline void Write8(vfsStream& f, const u8 data) -{ - f.Write(&data, sizeof(data)); -} - force_inline void Write8(const fs::file& f, const u8 data) { f.write(&data, sizeof(data)); } -force_inline void Write16LE(vfsStream& f, const u16 data) -{ - f.Write(&data, sizeof(data)); -} - force_inline void Write16LE(const fs::file& f, const u16 data) { f.write(&data, sizeof(data)); } -force_inline void Write32LE(vfsStream& f, const u32 data) -{ - f.Write(&data, sizeof(data)); -} - force_inline void Write32LE(const fs::file& f, const u32 data) { f.write(&data, sizeof(data)); } -force_inline void Write64LE(vfsStream& f, const u64 data) -{ - f.Write(&data, sizeof(data)); -} - force_inline void Write64LE(const fs::file& f, const u64 data) { f.write(&data, sizeof(data)); } -force_inline void Write16(vfsStream& f, const be_t data) -{ - f.Write(&data, sizeof(data)); -} - force_inline void Write16(const fs::file& f, const be_t data) { f.write(&data, sizeof(data)); } -force_inline void Write32(vfsStream& f, const be_t data) -{ - f.Write(&data, sizeof(data)); -} - force_inline void Write32(const fs::file& f, const be_t data) { f.write(&data, sizeof(data)); } -force_inline void Write64(vfsStream& f, const be_t data) -{ - f.Write(&data, sizeof(data)); -} - force_inline void Write64(const fs::file& f, const be_t data) { f.write(&data, sizeof(data)); @@ -231,7 +190,7 @@ void WriteShdr(const fs::file& f, Elf32_Shdr& shdr) } -void AppInfo::Load(vfsStream& f) +void AppInfo::Load(const fs::file& f) { authid = Read64(f); vendor_id = Read32(f); @@ -248,7 +207,7 @@ void AppInfo::Show() LOG_NOTICE(LOADER, "Version: 0x%llx", version); } -void SectionInfo::Load(vfsStream& f) +void SectionInfo::Load(const fs::file& f) { offset = Read64(f); size = Read64(f); @@ -268,7 +227,7 @@ void SectionInfo::Show() LOG_NOTICE(LOADER, "Encrypted: 0x%08x", encrypted); } -void SCEVersionInfo::Load(vfsStream& f) +void SCEVersionInfo::Load(const fs::file& f) { subheader_type = Read32(f); present = Read32(f); @@ -284,7 +243,7 @@ void SCEVersionInfo::Show() LOG_NOTICE(LOADER, "Unknown: 0x%08x", unknown); } -void ControlInfo::Load(vfsStream& f) +void ControlInfo::Load(const fs::file& f) { type = Read32(f); size = Read32(f); @@ -305,13 +264,13 @@ void ControlInfo::Load(vfsStream& f) { if (size == 0x30) { - f.Read(file_digest_30.digest, 20); + f.read(file_digest_30.digest, 20); file_digest_30.unknown = Read64(f); } else if (size == 0x40) { - f.Read(file_digest_40.digest1, 20); - f.Read(file_digest_40.digest2, 20); + f.read(file_digest_40.digest1, 20); + f.read(file_digest_40.digest2, 20); file_digest_40.unknown = Read64(f); } } @@ -321,10 +280,10 @@ void ControlInfo::Load(vfsStream& f) npdrm.unknown1 = Read32(f); npdrm.license = Read32(f); npdrm.type = Read32(f); - f.Read(npdrm.content_id, 48); - f.Read(npdrm.digest, 16); - f.Read(npdrm.invdigest, 16); - f.Read(npdrm.xordigest, 16); + f.read(npdrm.content_id, 48); + f.read(npdrm.digest, 16); + f.read(npdrm.invdigest, 16); + f.read(npdrm.xordigest, 16); npdrm.unknown2 = Read64(f); npdrm.unknown3 = Read64(f); } @@ -500,14 +459,14 @@ void MetadataSectionHeader::Show() LOG_NOTICE(LOADER, "Compressed: 0x%08x", compressed); } -void SectionHash::Load(vfsStream& f) +void SectionHash::Load(const fs::file& f) { - f.Read(sha1, 20); - f.Read(padding, 12); - f.Read(hmac_key, 64); + f.read(sha1, 20); + f.read(padding, 12); + f.read(hmac_key, 64); } -void CapabilitiesInfo::Load(vfsStream& f) +void CapabilitiesInfo::Load(const fs::file& f) { type = Read32(f); capabilities_size = Read32(f); @@ -520,21 +479,21 @@ void CapabilitiesInfo::Load(vfsStream& f) unknown5 = Read32(f); } -void Signature::Load(vfsStream& f) +void Signature::Load(const fs::file& f) { - f.Read(r, 21); - f.Read(s, 21); - f.Read(padding, 6); + f.read(r, 21); + f.read(s, 21); + f.read(padding, 6); } -void SelfSection::Load(vfsStream& f) +void SelfSection::Load(const fs::file& f) { *data = Read32(f); size = Read64(f); offset = Read64(f); } -void Elf32_Ehdr::Load(vfsStream& f) +void Elf32_Ehdr::Load(const fs::file& f) { e_magic = Read32(f); e_class = Read8(f); @@ -578,7 +537,7 @@ void Elf32_Ehdr::Load(vfsStream& f) } } -void Elf32_Shdr::Load(vfsStream& f) +void Elf32_Shdr::Load(const fs::file& f) { sh_name = Read32(f); sh_type = Read32(f); @@ -592,12 +551,12 @@ void Elf32_Shdr::Load(vfsStream& f) sh_entsize = Read32(f); } -void Elf32_Shdr::LoadLE(vfsStream& f) +void Elf32_Shdr::LoadLE(const fs::file& f) { - f.Read(this, sizeof(*this)); + f.read(this, sizeof(*this)); } -void Elf32_Phdr::Load(vfsStream& f) +void Elf32_Phdr::Load(const fs::file& f) { p_type = Read32(f); p_offset = Read32(f); @@ -609,12 +568,12 @@ void Elf32_Phdr::Load(vfsStream& f) p_align = Read32(f); } -void Elf32_Phdr::LoadLE(vfsStream& f) +void Elf32_Phdr::LoadLE(const fs::file& f) { - f.Read(this, sizeof(*this)); + f.read(this, sizeof(*this)); } -void Elf64_Ehdr::Load(vfsStream& f) +void Elf64_Ehdr::Load(const fs::file& f) { e_magic = Read32(f); e_class = Read8(f); @@ -637,7 +596,7 @@ void Elf64_Ehdr::Load(vfsStream& f) e_shstrndx = Read16(f); } -void Elf64_Shdr::Load(vfsStream& f) +void Elf64_Shdr::Load(const fs::file& f) { sh_name = Read32(f); sh_type = Read32(f); @@ -651,7 +610,7 @@ void Elf64_Shdr::Load(vfsStream& f) sh_entsize = Read64(f); } -void Elf64_Phdr::Load(vfsStream& f) +void Elf64_Phdr::Load(const fs::file& f) { p_type = Read32(f); p_flags = Read32(f); @@ -663,7 +622,7 @@ void Elf64_Phdr::Load(vfsStream& f) p_align = Read64(f); } -void SceHeader::Load(vfsStream& f) +void SceHeader::Load(const fs::file& f) { se_magic = Read32(f); se_hver = Read32(f); @@ -674,7 +633,7 @@ void SceHeader::Load(vfsStream& f) se_esize = Read64(f); } -void SelfHeader::Load(vfsStream& f) +void SelfHeader::Load(const fs::file& f) { se_htype = Read64(f); se_appinfooff = Read64(f); @@ -688,7 +647,7 @@ void SelfHeader::Load(vfsStream& f) pad = Read64(f); } -SELFDecrypter::SELFDecrypter(vfsStream& s) +SELFDecrypter::SELFDecrypter(const fs::file& s) : self_f(s) , key_v() , data_buf_length(0) @@ -698,7 +657,7 @@ SELFDecrypter::SELFDecrypter(vfsStream& s) bool SELFDecrypter::LoadHeaders(bool isElf32) { // Read SCE header. - CHECK_ASSERTION(self_f.Seek(0) != -1); + self_f.seek(0); sce_hdr.Load(self_f); // Check SCE magic. @@ -712,11 +671,11 @@ bool SELFDecrypter::LoadHeaders(bool isElf32) self_hdr.Load(self_f); // Read the APP INFO. - CHECK_ASSERTION(self_f.Seek(self_hdr.se_appinfooff) != -1); + self_f.seek(self_hdr.se_appinfooff); app_info.Load(self_f); // Read ELF header. - CHECK_ASSERTION(self_f.Seek(self_hdr.se_elfoff) != -1); + self_f.seek(self_hdr.se_elfoff); if (isElf32) elf32_hdr.Load(self_f); @@ -732,7 +691,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32) LOG_ERROR(LOADER, "SELF: ELF program header offset is null!"); return false; } - self_f.Seek(self_hdr.se_phdroff); + self_f.seek(self_hdr.se_phdroff); for(u32 i = 0; i < elf32_hdr.e_phnum; ++i) { phdr32_arr.emplace_back(); @@ -749,7 +708,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32) return false; } - CHECK_ASSERTION(self_f.Seek(self_hdr.se_phdroff) != -1); + self_f.seek(self_hdr.se_phdroff); for (u32 i = 0; i < elf64_hdr.e_phnum; ++i) { @@ -761,7 +720,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32) // Read section info. secinfo_arr.clear(); - CHECK_ASSERTION(self_f.Seek(self_hdr.se_secinfoff) != -1); + self_f.seek(self_hdr.se_secinfoff); for(u32 i = 0; i < ((isElf32) ? elf32_hdr.e_phnum : elf64_hdr.e_phnum); ++i) { @@ -770,12 +729,12 @@ bool SELFDecrypter::LoadHeaders(bool isElf32) } // Read SCE version info. - CHECK_ASSERTION(self_f.Seek(self_hdr.se_sceveroff) != -1); + self_f.seek(self_hdr.se_sceveroff); scev_info.Load(self_f); // Read control info. ctrlinfo_arr.clear(); - CHECK_ASSERTION(self_f.Seek(self_hdr.se_controloff) != -1); + self_f.seek(self_hdr.se_controloff); u32 i = 0; while(i < self_hdr.se_controlsize) @@ -797,7 +756,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32) return true; } - CHECK_ASSERTION(self_f.Seek(self_hdr.se_shdroff) != -1); + self_f.seek(self_hdr.se_shdroff); for(u32 i = 0; i < elf32_hdr.e_shnum; ++i) { @@ -814,7 +773,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32) return true; } - CHECK_ASSERTION(self_f.Seek(self_hdr.se_shdroff) != -1); + self_f.seek(self_hdr.se_shdroff); for(u32 i = 0; i < elf64_hdr.e_shnum; ++i) { @@ -950,12 +909,12 @@ bool SELFDecrypter::LoadMetadata() u8 *metadata_headers = (u8 *)malloc(metadata_headers_size); // Locate and read the encrypted metadata info. - CHECK_ASSERTION(self_f.Seek(sce_hdr.se_meta + sizeof(sce_hdr)) != -1); - self_f.Read(metadata_info, metadata_info_size); + self_f.seek(sce_hdr.se_meta + sizeof(sce_hdr)); + self_f.read(metadata_info, metadata_info_size); // Locate and read the encrypted metadata header and section header. - CHECK_ASSERTION(self_f.Seek(sce_hdr.se_meta + sizeof(sce_hdr) + metadata_info_size) != -1); - self_f.Read(metadata_headers, metadata_headers_size); + self_f.seek(sce_hdr.se_meta + sizeof(sce_hdr) + metadata_info_size); + self_f.read(metadata_headers, metadata_headers_size); // Find the right keyset from the key vault. SELF_KEY keyset = key_v.FindSelfKey(app_info.self_type, sce_hdr.se_flags, app_info.version); @@ -1057,8 +1016,8 @@ bool SELFDecrypter::DecryptData() u8 *buf = (u8 *)malloc(meta_shdr[i].data_size); // Seek to the section data offset and read the encrypted data. - CHECK_ASSERTION(self_f.Seek(meta_shdr[i].data_offset) != -1); - self_f.Read(buf, meta_shdr[i].data_size); + self_f.seek(meta_shdr[i].data_offset); + self_f.read(buf, meta_shdr[i].data_size); // Zero out our ctr nonce. memset(ctr_stream_block, 0, sizeof(ctr_stream_block)); @@ -1085,7 +1044,7 @@ bool SELFDecrypter::DecryptData() bool SELFDecrypter::MakeElf(const std::string& elf, bool isElf32) { // Create a new ELF file. - fs::file e(elf, fom::rewrite); + fs::file e(elf, fs::rewrite); if(!e) { LOG_ERROR(LOADER, "Could not create ELF file! (%s)", elf.c_str()); @@ -1112,8 +1071,7 @@ bool SELFDecrypter::MakeElf(const std::string& elf, bool isElf32) if (meta_shdr[i].type == 2) { // Seek to the program header data offset and write the data. - CHECK_ASSERTION(e.seek(phdr32_arr[meta_shdr[i].program_idx].p_offset) != -1); - + e.seek(phdr32_arr[meta_shdr[i].program_idx].p_offset); e.write(data_buf + data_buf_offset, meta_shdr[i].data_size); // Advance the data buffer offset by data size. @@ -1124,7 +1082,7 @@ bool SELFDecrypter::MakeElf(const std::string& elf, bool isElf32) // Write section headers. if (self_hdr.se_shdroff != 0) { - CHECK_ASSERTION(e.seek(elf32_hdr.e_shoff) != -1); + e.seek(elf32_hdr.e_shoff); for (u32 i = 0; i < elf32_hdr.e_shnum; ++i) { @@ -1180,15 +1138,13 @@ bool SELFDecrypter::MakeElf(const std::string& elf, bool isElf32) } // Seek to the program header data offset and write the data. - CHECK_ASSERTION(e.seek(phdr64_arr[meta_shdr[i].program_idx].p_offset) != -1); + e.seek(phdr64_arr[meta_shdr[i].program_idx].p_offset); e.write(decomp_buf.get(), phdr64_arr[meta_shdr[i].program_idx].p_filesz); - } else { // Seek to the program header data offset and write the data. - CHECK_ASSERTION(e.seek(phdr64_arr[meta_shdr[i].program_idx].p_offset) != -1); - + e.seek(phdr64_arr[meta_shdr[i].program_idx].p_offset); e.write(data_buf + data_buf_offset, meta_shdr[i].data_size); } @@ -1200,7 +1156,7 @@ bool SELFDecrypter::MakeElf(const std::string& elf, bool isElf32) // Write section headers. if (self_hdr.se_shdroff != 0) { - CHECK_ASSERTION(e.seek(elf64_hdr.e_shoff) != -1); + e.seek(elf64_hdr.e_shoff); for (u32 i = 0; i < elf64_hdr.e_shnum; ++i) { @@ -1250,10 +1206,9 @@ bool SELFDecrypter::GetKeyFromRap(u8 *content_id, u8 *npdrm_key) bool IsSelf(const std::string& path) { - vfsLocalFile f(nullptr); + fs::file f(path); - if(!f.Open(path)) - return false; + if (!f) return false; SceHeader hdr; hdr.Load(f); @@ -1263,10 +1218,9 @@ bool IsSelf(const std::string& path) bool IsSelfElf32(const std::string& path) { - vfsLocalFile f(nullptr); + fs::file f(path); - if(!f.Open(path)) - return false; + if (!f) return false; SceHeader hdr; SelfHeader sh; @@ -1276,9 +1230,8 @@ bool IsSelfElf32(const std::string& path) // Locate the class byte and check it. u8 elf_class[0x8]; - CHECK_ASSERTION(f.Seek(sh.se_elfoff) != -1); - - f.Read(elf_class, 0x8); + f.seek(sh.se_elfoff); + f.read(elf_class, 0x8); return (elf_class[4] == 1); } @@ -1295,7 +1248,7 @@ bool CheckDebugSelf(const std::string& self, const std::string& elf) } // Get the key version. - CHECK_ASSERTION(s.seek(0x08) != -1); + s.seek(0x08); u16 key_version; s.read(&key_version, sizeof(key_version)); @@ -1306,7 +1259,7 @@ bool CheckDebugSelf(const std::string& self, const std::string& elf) LOG_WARNING(LOADER, "Debug SELF detected! Removing fake header..."); // Get the real elf offset. - CHECK_ASSERTION(s.seek(0x10) != -1); + s.seek(0x10); u64 elf_offset; s.read(&elf_offset, sizeof(elf_offset)); @@ -1314,10 +1267,10 @@ bool CheckDebugSelf(const std::string& self, const std::string& elf) // Start at the real elf offset. elf_offset = swap64(elf_offset); - CHECK_ASSERTION(s.seek(elf_offset) != -1); + s.seek(elf_offset); // Write the real ELF file back. - fs::file e(elf, fom::rewrite); + fs::file e(elf, fs::rewrite); if (!e) { LOG_ERROR(LOADER, "Could not create ELF file! (%s)", elf.c_str()); @@ -1326,7 +1279,7 @@ bool CheckDebugSelf(const std::string& self, const std::string& elf) // Copy the data. char buf[2048]; - while (u64 size = s.read(buf, 2048)) // read returns u64. + while (u64 size = s.read(buf, 2048)) { e.write(buf, size); } @@ -1346,9 +1299,9 @@ bool DecryptSelf(const std::string& elf, const std::string& self) if (!CheckDebugSelf(self, elf)) { // Set a virtual pointer to the SELF file. - vfsLocalFile self_vf(nullptr); + fs::file self_vf(self); - if (!self_vf.Open(self)) + if (!self_vf) return false; // Check the ELF file class (32 or 64 bit). diff --git a/rpcs3/Crypto/unself.h b/rpcs3/Crypto/unself.h index 337a933f4a..4741bc294b 100644 --- a/rpcs3/Crypto/unself.h +++ b/rpcs3/Crypto/unself.h @@ -1,7 +1,6 @@ #pragma once -#include "key_vault.h" -struct vfsStream; +#include "key_vault.h" struct AppInfo { @@ -11,7 +10,7 @@ struct AppInfo u64 version; u64 padding; - void Load(vfsStream& f); + void Load(const fs::file& f); void Show(); }; @@ -24,7 +23,7 @@ struct SectionInfo u32 unknown2; u32 encrypted; - void Load(vfsStream& f); + void Load(const fs::file& f); void Show(); }; @@ -35,7 +34,7 @@ struct SCEVersionInfo u32 size; u32 unknown; - void Load(vfsStream& f); + void Load(const fs::file& f); void Show(); }; @@ -95,7 +94,7 @@ struct ControlInfo } npdrm; }; - void Load(vfsStream& f); + void Load(const fs::file& f); void Show(); }; @@ -148,7 +147,7 @@ struct SectionHash u8 padding[12]; u8 hmac_key[64]; - void Load(vfsStream& f); + void Load(const fs::file& f); }; struct CapabilitiesInfo @@ -163,7 +162,7 @@ struct CapabilitiesInfo u32 unknown4; u32 unknown5; - void Load(vfsStream& f); + void Load(const fs::file& f); }; struct Signature @@ -172,7 +171,7 @@ struct Signature u8 s[21]; u8 padding[6]; - void Load(vfsStream& f); + void Load(const fs::file& f); }; struct SelfSection @@ -181,7 +180,7 @@ struct SelfSection u64 size; u64 offset; - void Load(vfsStream& f); + void Load(const fs::file& f); }; struct Elf32_Ehdr @@ -206,7 +205,7 @@ struct Elf32_Ehdr u16 e_shnum; u16 e_shstrndx; - void Load(vfsStream& f); + void Load(const fs::file& f); void Show() {} bool IsLittleEndian() const { return e_data == 1; } bool CheckMagic() const { return e_magic == 0x7F454C46; } @@ -226,8 +225,8 @@ struct Elf32_Shdr u32 sh_addralign; u32 sh_entsize; - void Load(vfsStream& f); - void LoadLE(vfsStream& f); + void Load(const fs::file& f); + void LoadLE(const fs::file& f); void Show() {} }; @@ -242,8 +241,8 @@ struct Elf32_Phdr u32 p_flags; u32 p_align; - void Load(vfsStream& f); - void LoadLE(vfsStream& f); + void Load(const fs::file& f); + void LoadLE(const fs::file& f); void Show() {} }; @@ -269,7 +268,7 @@ struct Elf64_Ehdr u16 e_shnum; u16 e_shstrndx; - void Load(vfsStream& f); + void Load(const fs::file& f); void Show() {} bool CheckMagic() const { return e_magic == 0x7F454C46; } u64 GetEntry() const { return e_entry; } @@ -288,7 +287,7 @@ struct Elf64_Shdr u64 sh_addralign; u64 sh_entsize; - void Load(vfsStream& f); + void Load(const fs::file& f); void Show(){} }; @@ -303,7 +302,7 @@ struct Elf64_Phdr u64 p_memsz; u64 p_align; - void Load(vfsStream& f); + void Load(const fs::file& f); void Show(){} }; @@ -317,7 +316,7 @@ struct SceHeader u64 se_hsize; u64 se_esize; - void Load(vfsStream& f); + void Load(const fs::file& f); void Show(){} bool CheckMagic() const { return se_magic == 0x53434500; } }; @@ -335,14 +334,14 @@ struct SelfHeader u64 se_controlsize; u64 pad; - void Load(vfsStream& f); + void Load(const fs::file& f); void Show(){} }; class SELFDecrypter { // Main SELF file stream. - vfsStream& self_f; + const fs::file& self_f; // SCE, SELF and APP headers. SceHeader sce_hdr; @@ -379,7 +378,7 @@ class SELFDecrypter KeyVault key_v; public: - SELFDecrypter(vfsStream& s); + SELFDecrypter(const fs::file& s); bool MakeElf(const std::string& elf, bool isElf32); bool LoadHeaders(bool isElf32); void ShowHeaders(bool isElf32); diff --git a/rpcs3/Crypto/utils.cpp b/rpcs3/Crypto/utils.cpp index 079d84edae..0bf2928ee6 100644 --- a/rpcs3/Crypto/utils.cpp +++ b/rpcs3/Crypto/utils.cpp @@ -2,7 +2,6 @@ // Licensed under the terms of the GNU GPL, version 3 // http://www.gnu.org/licenses/gpl-3.0.txt -#include "stdafx.h" #include "utils.h" #include #include @@ -208,4 +207,4 @@ char* extract_file_name(const char* file_path, char real_file_name[MAX_PATH]) strncpy(real_file_name, p ? (p + 1) : file_path, file_path_len + 1); return real_file_name; -} \ No newline at end of file +} diff --git a/rpcs3/Crypto/utils.h b/rpcs3/Crypto/utils.h index 1c27ddb182..a4471733c2 100644 --- a/rpcs3/Crypto/utils.h +++ b/rpcs3/Crypto/utils.h @@ -4,6 +4,8 @@ // Licensed under the terms of the GNU GPL, version 3 // http://www.gnu.org/licenses/gpl-3.0.txt +#include "../../Utilities/types.h" + #define MAX_PATH 4096 #include @@ -32,4 +34,4 @@ void aesecb128_encrypt(unsigned char *key, unsigned char *in, unsigned char *out bool hmac_hash_compare(unsigned char *key, int key_len, unsigned char *in, int in_len, unsigned char *hash, int hash_len); void hmac_hash_forge(unsigned char *key, int key_len, unsigned char *in, int in_len, unsigned char *hash); bool cmac_hash_compare(unsigned char *key, int key_len, unsigned char *in, int in_len, unsigned char *hash, int hash_len); -void cmac_hash_forge(unsigned char *key, int key_len, unsigned char *in, int in_len, unsigned char *hash); \ No newline at end of file +void cmac_hash_forge(unsigned char *key, int key_len, unsigned char *in, int in_len, unsigned char *hash); diff --git a/rpcs3/D3D12GSRender.vcxproj b/rpcs3/D3D12GSRender.vcxproj index a610917e18..d1c7dcd40f 100644 --- a/rpcs3/D3D12GSRender.vcxproj +++ b/rpcs3/D3D12GSRender.vcxproj @@ -61,11 +61,6 @@ - - - true - - diff --git a/rpcs3/Emu/ARMv7/ARMv7Callback.h b/rpcs3/Emu/ARMv7/ARMv7Callback.h index a1ddd72593..4455284084 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Callback.h +++ b/rpcs3/Emu/ARMv7/ARMv7Callback.h @@ -1,17 +1,17 @@ #pragma once -#include "Emu/Memory/Memory.h" -#include "Emu/ARMv7/PSVFuncList.h" + +#include "ARMv7Function.h" namespace vm { template - force_inline RT _ptr_base::operator()(ARMv7Thread& context, T... args) const + force_inline RT _ptr_base::operator()(ARMv7Thread& cpu, T... args) const { - return psv_func_detail::func_caller::call(context, VM_CAST(this->addr()), args...); + return arm_func_detail::func_caller::call(cpu, vm::cast(this->addr(), HERE), args...); } } -template inline RT cb_call(ARMv7Thread& context, u32 addr, T... args) +template inline RT cb_call(ARMv7Thread& cpu, u32 addr, T... args) { - return psv_func_detail::func_caller::call(context, addr, args...); + return arm_func_detail::func_caller::call(cpu, addr, args...); } diff --git a/rpcs3/Emu/ARMv7/ARMv7Context.h b/rpcs3/Emu/ARMv7/ARMv7Context.h deleted file mode 100644 index 3de2c17bc4..0000000000 --- a/rpcs3/Emu/ARMv7/ARMv7Context.h +++ /dev/null @@ -1,324 +0,0 @@ -#pragma once - -#include "Emu/Memory/Memory.h" - -enum ARMv7InstructionSet -{ - ARM, - Thumb, - Jazelle, - ThumbEE -}; - -enum armv7_debug_flags : u32 -{ - DF_DISASM = 1 << 0, - DF_PRINT = 1 << 1, - DF_NO_EXE = 1 << 2, -}; - -struct ARMv7Context -{ - union - { - u32 GPR[15]; - - struct - { - u32 pad[13]; - - union - { - u32 SP; - - struct { u16 SP_main, SP_process; }; - }; - - u32 LR; - - union - { - struct - { - u32 reserved0 : 16; - u32 GE : 4; - u32 reserved1 : 4; - u32 dummy : 3; - u32 Q : 1; // Set to 1 if an SSAT or USAT instruction changes (saturates) the input value for the signed or unsigned range of the result - u32 V : 1; // Overflow condition code flag - u32 C : 1; // Carry condition code flag - u32 Z : 1; // Zero condition code flag - u32 N : 1; // Negative condition code flag - }; - - u32 APSR; - - } APSR; - }; - - struct - { - u64 GPR_D[8]; - }; - }; - - union - { - struct - { - u32 dummy : 24; - u32 exception : 8; - }; - - u32 IPSR; - - } IPSR; - - ARMv7InstructionSet ISET; - - union - { - struct - { - u8 shift_state : 5; - u8 cond_base : 3; - }; - - struct - { - u8 check_state : 4; - u8 condition : 4; - }; - - u8 IT; - - u32 advance() - { - const u32 res = check_state ? condition : 0xe /* always true */; - - shift_state <<= 1; - if (!check_state) - { - IT = 0; // clear - } - - return res; - } - - operator bool() const - { - return check_state != 0; - } - - } ITSTATE; - - u32 TLS; - - struct perf_counter - { - u32 event; - u32 value; - }; - - std::array counters; - - u32 PC; - s32 prio; - u32 stack_addr; - u32 stack_size; - u32 hle_func; // current function ID - - u32 debug; - std::string debug_str; - - void write_pc(u32 value, u32 size) - { - ISET = value & 1 ? Thumb : ARM; - PC = (value & ~1) - size; - } - - u32 read_pc() - { - return ISET == ARM ? PC + 8 : PC + 4; - } - - u32 get_stack_arg(u32 pos) - { - return vm::psv::read32(SP + sizeof(u32) * (pos - 5)); - } - - void fast_call(u32 addr); - - void write_gpr(u32 n, u32 value, u32 size) - { - assert(n < 16); - - if (n < 15) - { - GPR[n] = value; - } - else - { - write_pc(value, size); - } - } - - u32 read_gpr(u32 n) - { - assert(n < 16); - - if (n < 15) - { - return GPR[n]; - } - - return read_pc(); - } - - // function for processing va_args in printf-like functions - u32 get_next_gpr_arg(u32& g_count, u32& f_count, u32& v_count) - { - assert(!f_count && !v_count); // not supported - - if (g_count < 4) - { - return GPR[g_count++]; - } - else - { - return get_stack_arg(g_count++); - } - } - - template - never_inline void fmt_debug_str(const char* fmt, T... args) - { - debug_str = fmt::format(fmt, args...); - } -}; - -template::value> -struct cast_armv7_gpr -{ - static_assert(is_enum, "Invalid type for cast_armv7_gpr"); - - force_inline static u32 to_gpr(const T& value) - { - return cast_armv7_gpr>::to_gpr(static_cast>(value)); - } - - force_inline static T from_gpr(const u32 reg) - { - return static_cast(cast_armv7_gpr>::from_gpr(reg)); - } -}; - -template<> -struct cast_armv7_gpr -{ - force_inline static u32 to_gpr(const u8& value) - { - return value; - } - - force_inline static u8 from_gpr(const u32 reg) - { - return static_cast(reg); - } -}; - -template<> -struct cast_armv7_gpr -{ - force_inline static u32 to_gpr(const u16& value) - { - return value; - } - - force_inline static u16 from_gpr(const u32 reg) - { - return static_cast(reg); - } -}; - -template<> -struct cast_armv7_gpr -{ - force_inline static u32 to_gpr(const u32& value) - { - return value; - } - - force_inline static u32 from_gpr(const u32 reg) - { - return reg; - } -}; - -template<> -struct cast_armv7_gpr -{ - force_inline static u32 to_gpr(const s8& value) - { - return value; - } - - force_inline static s8 from_gpr(const u32 reg) - { - return static_cast(reg); - } -}; - -template<> -struct cast_armv7_gpr -{ - force_inline static u32 to_gpr(const s16& value) - { - return value; - } - - force_inline static s16 from_gpr(const u32 reg) - { - return static_cast(reg); - } -}; - -template<> -struct cast_armv7_gpr -{ - force_inline static u32 to_gpr(const s32& value) - { - return value; - } - - force_inline static s32 from_gpr(const u32 reg) - { - return static_cast(reg); - } -}; - -template<> -struct cast_armv7_gpr -{ - force_inline static u32 to_gpr(const b8& value) - { - return value; - } - - force_inline static b8 from_gpr(const u32& reg) - { - return reg != 0; - } -}; - -template -force_inline u32 cast_to_armv7_gpr(const T& value) -{ - return cast_armv7_gpr::to_gpr(value); -} - -template -force_inline T cast_from_armv7_gpr(const u32 reg) -{ - return cast_armv7_gpr::from_gpr(reg); -} diff --git a/rpcs3/Emu/ARMv7/ARMv7Decoder.cpp b/rpcs3/Emu/ARMv7/ARMv7Decoder.cpp deleted file mode 100644 index 005c7a2e38..0000000000 --- a/rpcs3/Emu/ARMv7/ARMv7Decoder.cpp +++ /dev/null @@ -1,1371 +0,0 @@ -#include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "ARMv7Thread.h" -#include "ARMv7Interpreter.h" -#include "ARMv7Opcodes.h" -#include "ARMv7Decoder.h" - -struct ARMv7_opcode_t -{ - u32 mask; - u32 code; - u32 length; // 2 or 4 - const char* name; - ARMv7_encoding type; - void(*func)(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - bool(*skip)(u32 code); -}; - -// single 16-bit value -#define ARMv7_OP2(mask, code, type, name, ...) { (u32)((mask) << 16), (u32)((code) << 16), 2, #name "_" #type, type, ARMv7_instrs::name, __VA_ARGS__ } -// two 16-bit values -#define ARMv7_OP4(mask0, mask1, code0, code1, type, name, ...) { (u32)((mask0) << 16) | (mask1), (u32)((code0) << 16) | (code1), 4, #name "_" #type, type, ARMv7_instrs::name, __VA_ARGS__ } - -#define SKIP_IF(cond) [](u32 c) -> bool { return cond; } - -#define BF(start, end) ((c << (31 - (end))) >> ((start) + 31 - (end))) -#define BT(pos) ((c >> (pos)) & 1) - -const ARMv7_opcode_t ARMv7_opcode_table[] = -{ - ARMv7_OP4(0xffff, 0x0000, 0xf870, 0x0000, T1, HACK, nullptr), // "Undefined" Thumb opcode used - ARMv7_OP4(0x0ff0, 0x00f0, 0x0070, 0x0090, A1, HACK), // "Undefined" ARM opcode used - - ARMv7_OP4(0xfbe0, 0x8000, 0xf140, 0x0000, T1, ADC_IMM, nullptr), - ARMv7_OP4(0x0fe0, 0x0000, 0x02a0, 0x0000, A1, ADC_IMM), - ARMv7_OP2(0xffc0, 0x4140, T1, ADC_REG, nullptr), - ARMv7_OP4(0xffe0, 0x8000, 0xeb40, 0x0000, T2, ADC_REG, nullptr), - ARMv7_OP4(0x0fe0, 0x0010, 0x00a0, 0x0000, A1, ADC_REG), - ARMv7_OP4(0x0fe0, 0x0090, 0x00a0, 0x0010, A1, ADC_RSR), - - ARMv7_OP2(0xfe00, 0x1c00, T1, ADD_IMM, nullptr), - ARMv7_OP2(0xf800, 0x3000, T2, ADD_IMM, nullptr), - ARMv7_OP4(0xfbe0, 0x8000, 0xf100, 0x0000, T3, ADD_IMM, SKIP_IF( (BF(8, 11) == 15 && BT(20)) || BF(16, 19) == 13 )), - ARMv7_OP4(0xfbf0, 0x8000, 0xf200, 0x0000, T4, ADD_IMM, SKIP_IF( (BF(16, 19) & 13) == 13 )), - ARMv7_OP4(0x0fe0, 0x0000, 0x0280, 0x0000, A1, ADD_IMM), - ARMv7_OP2(0xfe00, 0x1800, T1, ADD_REG, nullptr), - ARMv7_OP2(0xff00, 0x4400, T2, ADD_REG, SKIP_IF( (c & 0x87) == 0x85 || BF(3, 6) == 13 )), - ARMv7_OP4(0xffe0, 0x8000, 0xeb00, 0x0000, T3, ADD_REG, SKIP_IF( (BF(8, 11) == 15 && BT(20)) || BF(16, 19) == 13 )), - ARMv7_OP4(0x0fe0, 0x0010, 0x0080, 0x0000, A1, ADD_REG), - ARMv7_OP4(0x0fe0, 0x0090, 0x0080, 0x0010, A1, ADD_RSR), - ARMv7_OP2(0xf800, 0xa800, T1, ADD_SPI, nullptr), - ARMv7_OP2(0xff80, 0xb000, T2, ADD_SPI, nullptr), - ARMv7_OP4(0xfbef, 0x8000, 0xf10d, 0x0000, T3, ADD_SPI, SKIP_IF( BF(8, 11) == 15 && BT(20) )), - ARMv7_OP4(0xfbff, 0x8000, 0xf20d, 0x0000, T4, ADD_SPI, nullptr), - ARMv7_OP4(0x0fef, 0x0000, 0x028d, 0x0000, A1, ADD_SPI), - ARMv7_OP2(0xff78, 0x4468, T1, ADD_SPR, nullptr), - ARMv7_OP2(0xff87, 0x4485, T2, ADD_SPR, SKIP_IF( BF(3, 6) == 13 )), - ARMv7_OP4(0xffef, 0x8000, 0xeb0d, 0x0000, T3, ADD_SPR, nullptr), - ARMv7_OP4(0x0fef, 0x0010, 0x008d, 0x0000, A1, ADD_SPR), - - ARMv7_OP2(0xf800, 0xa000, T1, ADR, nullptr), - ARMv7_OP4(0xfbff, 0x8000, 0xf2af, 0x0000, T2, ADR, nullptr), - ARMv7_OP4(0xfbff, 0x8000, 0xf20f, 0x0000, T3, ADR, nullptr), - ARMv7_OP4(0x0fff, 0x0000, 0x028f, 0x0000, A1, ADR), - ARMv7_OP4(0x0fff, 0x0000, 0x024f, 0x0000, A2, ADR), - - ARMv7_OP4(0xfbe0, 0x8000, 0xf000, 0x0000, T1, AND_IMM, SKIP_IF( BF(8, 11) == 15 && BT(20) )), - ARMv7_OP4(0x0fe0, 0x0000, 0x0200, 0x0000, A1, AND_IMM), - ARMv7_OP2(0xffc0, 0x4000, T1, AND_REG, nullptr), - ARMv7_OP4(0xffe0, 0x8000, 0xea00, 0x0000, T2, AND_REG, SKIP_IF( BF(8, 11) == 15 && BT(20) )), - ARMv7_OP4(0x0fe0, 0x0010, 0x0000, 0x0000, A1, AND_REG), - ARMv7_OP4(0x0fe0, 0x0090, 0x0000, 0x0010, A1, AND_RSR), - - ARMv7_OP2(0xf800, 0x1000, T1, ASR_IMM, nullptr), - ARMv7_OP4(0xffef, 0x8030, 0xea4f, 0x0020, T2, ASR_IMM, nullptr), - ARMv7_OP4(0x0fef, 0x0070, 0x01a0, 0x0040, A1, ASR_IMM), - ARMv7_OP2(0xffc0, 0x4100, T1, ASR_REG, nullptr), - ARMv7_OP4(0xffe0, 0xf0f0, 0xfa40, 0xf000, T2, ASR_REG, nullptr), - ARMv7_OP4(0x0fef, 0x00f0, 0x01a0, 0x0050, A1, ASR_REG), - - ARMv7_OP2(0xf000, 0xd000, T1, B, SKIP_IF( BF(9, 11) == 0x7 )), - ARMv7_OP2(0xf800, 0xe000, T2, B, nullptr), - ARMv7_OP4(0xf800, 0xd000, 0xf000, 0x8000, T3, B, SKIP_IF( BF(23, 25) == 0x7 )), - ARMv7_OP4(0xf800, 0xd000, 0xf000, 0x9000, T4, B, nullptr), - ARMv7_OP4(0x0f00, 0x0000, 0x0a00, 0x0000, A1, B), - - ARMv7_OP4(0xffff, 0x8020, 0xf36f, 0x0000, T1, BFC, nullptr), - ARMv7_OP4(0x0fe0, 0x007f, 0x07c0, 0x001f, A1, BFC), - - ARMv7_OP4(0xfff0, 0x8020, 0xf360, 0x0000, T1, BFI, SKIP_IF( BF(16, 19) == 15 )), - ARMv7_OP4(0x0fe0, 0x0070, 0x07c0, 0x0010, A1, BFI), - - ARMv7_OP4(0xfbe0, 0x8000, 0xf020, 0x0000, T1, BIC_IMM, nullptr), - ARMv7_OP4(0x0fe0, 0x0000, 0x03c0, 0x0000, A1, BIC_IMM), - ARMv7_OP2(0xffc0, 0x4380, T1, BIC_REG, nullptr), - ARMv7_OP4(0xffe0, 0x8000, 0xea20, 0x0000, T2, BIC_REG, nullptr), - ARMv7_OP4(0x0fe0, 0x0010, 0x01c0, 0x0000, A1, BIC_REG), - ARMv7_OP4(0x0fe0, 0x0090, 0x01c0, 0x0010, A1, BIC_RSR), - - ARMv7_OP2(0xff00, 0xbe00, T1, BKPT, nullptr), - ARMv7_OP4(0x0ff0, 0x00f0, 0x0120, 0x0070, A1, BKPT), - - ARMv7_OP4(0xf800, 0xd000, 0xf000, 0xd000, T1, BL, nullptr), - ARMv7_OP4(0x0f00, 0x0000, 0x0b00, 0x0000, A1, BL), - ARMv7_OP2(0xff80, 0x4780, T1, BLX, nullptr), - ARMv7_OP4(0xf800, 0xc001, 0xf000, 0xc000, T2, BLX, nullptr), - ARMv7_OP4(0x0fff, 0xfff0, 0x012f, 0xff30, A1, BLX), - ARMv7_OP4(0xfe00, 0x0000, 0xfa00, 0x0000, A2, BLX), - - ARMv7_OP2(0xff87, 0x4700, T1, BX, nullptr), - ARMv7_OP4(0x0fff, 0xfff0, 0x012f, 0xff10, A1, BX), - - ARMv7_OP2(0xf500, 0xb100, T1, CB_Z, nullptr), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfab0, 0xf080, T1, CLZ, nullptr), - ARMv7_OP4(0x0fff, 0x0ff0, 0x016f, 0x0f10, A1, CLZ), - - ARMv7_OP4(0xfbf0, 0x8f00, 0xf110, 0x0f00, T1, CMN_IMM, nullptr), - ARMv7_OP4(0x0ff0, 0xf000, 0x0370, 0x0000, A1, CMN_IMM), - ARMv7_OP2(0xffc0, 0x42c0, T1, CMN_REG, nullptr), - ARMv7_OP4(0xfff0, 0x8f00, 0xeb10, 0x0f00, T2, CMN_REG, nullptr), - ARMv7_OP4(0x0ff0, 0xf010, 0x0170, 0x0000, A1, CMN_REG), - ARMv7_OP4(0x0ff0, 0xf090, 0x0170, 0x0010, A1, CMN_RSR), - - ARMv7_OP2(0xf800, 0x2800, T1, CMP_IMM, nullptr), - ARMv7_OP4(0xfbf0, 0x8f00, 0xf1b0, 0x0f00, T2, CMP_IMM, nullptr), - ARMv7_OP4(0x0ff0, 0xf000, 0x0350, 0x0000, A1, CMP_IMM), - ARMv7_OP2(0xffc0, 0x4280, T1, CMP_REG, nullptr), - ARMv7_OP2(0xff00, 0x4500, T2, CMP_REG, nullptr), - ARMv7_OP4(0xfff0, 0x8f00, 0xebb0, 0x0f00, T3, CMP_REG, nullptr), - ARMv7_OP4(0x0ff0, 0xf010, 0x0150, 0x0000, A1, CMP_REG), - ARMv7_OP4(0x0ff0, 0xf090, 0x0150, 0x0010, A1, CMP_RSR), - - ARMv7_OP4(0xffff, 0xfff0, 0xf3af, 0x80f0, T1, DBG, nullptr), - ARMv7_OP4(0x0fff, 0xfff0, 0x0320, 0xf0f0, A1, DBG), - - ARMv7_OP4(0xffff, 0xfff0, 0xf3bf, 0x8f50, T1, DMB, nullptr), - ARMv7_OP4(0xffff, 0xfff0, 0xf57f, 0xf050, A1, DMB), - - ARMv7_OP4(0xffff, 0xfff0, 0xf3bf, 0x8f40, T1, DSB, nullptr), - ARMv7_OP4(0xffff, 0xfff0, 0xf57f, 0xf040, A1, DSB), - - ARMv7_OP4(0xfbe0, 0x8000, 0xf080, 0x0000, T1, EOR_IMM, SKIP_IF( BF(8, 11) == 15 && BT(20) )), - ARMv7_OP4(0x0fe0, 0x0000, 0x0220, 0x0000, A1, EOR_IMM), - ARMv7_OP2(0xffc0, 0x4040, T1, EOR_REG, nullptr), - ARMv7_OP4(0xffe0, 0x8000, 0xea80, 0x0000, T2, EOR_REG, SKIP_IF( BF(8, 11) == 15 && BT(20) )), - ARMv7_OP4(0x0fe0, 0x0010, 0x0020, 0x0000, A1, EOR_REG), - ARMv7_OP4(0x0fe0, 0x0090, 0x0020, 0x0010, A1, EOR_RSR), - - ARMv7_OP2(0xff00, 0xbf00, T1, IT, SKIP_IF( BF(0, 3) == 0 )), - - ARMv7_OP2(0xf800, 0xc800, T1, LDM, nullptr), - ARMv7_OP4(0xffd0, 0x2000, 0xe890, 0x0000, T2, LDM, SKIP_IF( BT(21) && BF(16, 19) == 13 )), - ARMv7_OP4(0x0fd0, 0x0000, 0x0890, 0x0000, A1, LDM), - ARMv7_OP4(0x0fd0, 0x0000, 0x0810, 0x0000, A1, LDMDA), - ARMv7_OP4(0xffd0, 0x2000, 0xe910, 0x0000, T1, LDMDB, nullptr), - ARMv7_OP4(0x0fd0, 0x0000, 0x0910, 0x0000, A1, LDMDB), - ARMv7_OP4(0x0fd0, 0x0000, 0x0990, 0x0000, A1, LDMIB), - - ARMv7_OP2(0xf800, 0x6800, T1, LDR_IMM, nullptr), - ARMv7_OP2(0xf800, 0x9800, T2, LDR_IMM, nullptr), - ARMv7_OP4(0xfff0, 0x0000, 0xf8d0, 0x0000, T3, LDR_IMM, SKIP_IF( BF(16, 19) == 15 )), - ARMv7_OP4(0xfff0, 0x0800, 0xf850, 0x0800, T4, LDR_IMM, SKIP_IF( BF(16, 19) == 15 || BF(8, 10) == 6 || (c & 0xf07ff) == 0xd0304 || (c & 0x500) == 0 )), - ARMv7_OP4(0x0e50, 0x0000, 0x0410, 0x0000, A1, LDR_IMM), - ARMv7_OP2(0xf800, 0x4800, T1, LDR_LIT, nullptr), - ARMv7_OP4(0xff7f, 0x0000, 0xf85f, 0x0000, T2, LDR_LIT, nullptr), - ARMv7_OP4(0x0f7f, 0x0000, 0x051f, 0x0000, A1, LDR_LIT), - ARMv7_OP2(0xfe00, 0x5800, T1, LDR_REG, nullptr), - ARMv7_OP4(0xfff0, 0x0fc0, 0xf850, 0x0000, T2, LDR_REG, SKIP_IF( BF(16, 19) == 15 )), - ARMv7_OP4(0x0e50, 0x0010, 0x0610, 0x0000, A1, LDR_REG), - - ARMv7_OP2(0xf800, 0x7800, T1, LDRB_IMM), - ARMv7_OP4(0xfff0, 0x0000, 0xf890, 0x0000, T2, LDRB_IMM), - ARMv7_OP4(0xfff0, 0x0800, 0xf810, 0x0800, T3, LDRB_IMM), - ARMv7_OP4(0x0e50, 0x0000, 0x0450, 0x0000, A1, LDRB_IMM), - ARMv7_OP4(0xff7f, 0x0000, 0xf81f, 0x0000, T1, LDRB_LIT), - ARMv7_OP4(0x0f7f, 0x0000, 0x055f, 0x0000, A1, LDRB_LIT), - ARMv7_OP2(0xfe00, 0x5c00, T1, LDRB_REG), - ARMv7_OP4(0xfff0, 0x0fc0, 0xf810, 0x0000, T2, LDRB_REG), - ARMv7_OP4(0x0e50, 0x0010, 0x0650, 0x0000, A1, LDRB_REG), - - ARMv7_OP4(0xfe50, 0x0000, 0xe850, 0x0000, T1, LDRD_IMM, SKIP_IF( (!BT(21) && !BT(24)) || BF(16, 19) == 15 )), - ARMv7_OP4(0x0e50, 0x00f0, 0x0040, 0x00d0, A1, LDRD_IMM), - ARMv7_OP4(0xfe7f, 0x0000, 0xe85f, 0x0000, T1, LDRD_LIT), - ARMv7_OP4(0x0f7f, 0x00f0, 0x014f, 0x00d0, A1, LDRD_LIT), - ARMv7_OP4(0x0e50, 0x0ff0, 0x0000, 0x00d0, A1, LDRD_REG), - - ARMv7_OP4(0xfff0, 0x0f00, 0xe850, 0x0f00, T1, LDREX), - ARMv7_OP4(0x0ff0, 0x0fff, 0x0190, 0x0f9f, A1, LDREX), - ARMv7_OP4(0xfff0, 0x0fff, 0xe8d0, 0x0f4f, T1, LDREXB), - ARMv7_OP4(0x0ff0, 0x0fff, 0x01d0, 0x0f9f, A1, LDREXB), - ARMv7_OP4(0xfff0, 0x00ff, 0xe8d0, 0x007f, T1, LDREXD), - ARMv7_OP4(0x0ff0, 0x0fff, 0x01b0, 0x0f9f, A1, LDREXD), - ARMv7_OP4(0xfff0, 0x0fff, 0xe8d0, 0x0f5f, T1, LDREXH), - ARMv7_OP4(0x0ff0, 0x0fff, 0x01f0, 0x0f9f, A1, LDREXH), - - ARMv7_OP2(0xf800, 0x8800, T1, LDRH_IMM), - ARMv7_OP4(0xfff0, 0x0000, 0xf8b0, 0x0000, T2, LDRH_IMM), - ARMv7_OP4(0xfff0, 0x0800, 0xf830, 0x0800, T3, LDRH_IMM), - ARMv7_OP4(0x0e50, 0x00f0, 0x0050, 0x00b0, A1, LDRH_IMM), - ARMv7_OP4(0xff7f, 0x0000, 0xf83f, 0x0000, T1, LDRH_LIT), - ARMv7_OP4(0x0f7f, 0x00f0, 0x015f, 0x00b0, A1, LDRH_LIT), - ARMv7_OP2(0xfe00, 0x5a00, T1, LDRH_REG), - ARMv7_OP4(0xfff0, 0x0fc0, 0xf830, 0x0000, T2, LDRH_REG), - ARMv7_OP4(0x0e50, 0x0ff0, 0x0010, 0x00b0, A1, LDRH_REG), - - ARMv7_OP4(0xfff0, 0x0000, 0xf990, 0x0000, T1, LDRSB_IMM), - ARMv7_OP4(0xfff0, 0x0800, 0xf910, 0x0800, T2, LDRSB_IMM), - ARMv7_OP4(0x0e50, 0x00f0, 0x0050, 0x00d0, A1, LDRSB_IMM), - ARMv7_OP4(0xff7f, 0x0000, 0xf91f, 0x0000, T1, LDRSB_LIT), - ARMv7_OP4(0x0f7f, 0x00f0, 0x015f, 0x00d0, A1, LDRSB_LIT), - ARMv7_OP2(0xfe00, 0x5600, T1, LDRSB_REG), - ARMv7_OP4(0xfff0, 0x0fc0, 0xf910, 0x0000, T2, LDRSB_REG), - ARMv7_OP4(0x0e50, 0x0ff0, 0x0010, 0x00d0, A1, LDRSB_REG), - - ARMv7_OP4(0xfff0, 0x0000, 0xf9b0, 0x0000, T1, LDRSH_IMM), - ARMv7_OP4(0xfff0, 0x0800, 0xf930, 0x0800, T2, LDRSH_IMM), - ARMv7_OP4(0x0e50, 0x00f0, 0x0050, 0x00f0, A1, LDRSH_IMM), - ARMv7_OP4(0xff7f, 0x0000, 0xf93f, 0x0000, T1, LDRSH_LIT), - ARMv7_OP4(0x0f7f, 0x00f0, 0x015f, 0x00f0, A1, LDRSH_LIT), - ARMv7_OP2(0xfe00, 0x5e00, T1, LDRSH_REG), - ARMv7_OP4(0xfff0, 0x0fc0, 0xf930, 0x0000, T2, LDRSH_REG), - ARMv7_OP4(0x0e50, 0x0ff0, 0x0010, 0x00f0, A1, LDRSH_REG), - - ARMv7_OP2(0xf800, 0x0000, T1, LSL_IMM), - ARMv7_OP4(0xffef, 0x8030, 0xea4f, 0x0000, T2, LSL_IMM), - ARMv7_OP4(0x0fef, 0x0070, 0x01a0, 0x0000, A1, LSL_IMM), - ARMv7_OP2(0xffc0, 0x4080, T1, LSL_REG), - ARMv7_OP4(0xffe0, 0xf0f0, 0xfa00, 0xf000, T2, LSL_REG), - ARMv7_OP4(0x0fef, 0x00f0, 0x01a0, 0x0010, A1, LSL_REG), - - ARMv7_OP2(0xf800, 0x0800, T1, LSR_IMM), - ARMv7_OP4(0xffef, 0x8030, 0xea4f, 0x0010, T2, LSR_IMM), - ARMv7_OP4(0x0fef, 0x0030, 0x01a0, 0x0020, A1, LSR_IMM), - ARMv7_OP2(0xffc0, 0x40c0, T1, LSR_REG), - ARMv7_OP4(0xffe0, 0xf0f0, 0xfa20, 0xf000, T2, LSR_REG), - ARMv7_OP4(0x0fef, 0x00f0, 0x01a0, 0x0030, A1, LSR_REG), - - ARMv7_OP4(0xfff0, 0x00f0, 0xfb00, 0x0000, T1, MLA, SKIP_IF( BF(12, 15) == 15 )), - ARMv7_OP4(0x0fe0, 0x00f0, 0x0020, 0x0090, A1, MLA), - - ARMv7_OP4(0xfff0, 0x00f0, 0xfb00, 0x0010, T1, MLS), - ARMv7_OP4(0x0ff0, 0x00f0, 0x0060, 0x0090, A1, MLS), - - ARMv7_OP2(0xf800, 0x2000, T1, MOV_IMM), - ARMv7_OP4(0xfbef, 0x8000, 0xf04f, 0x0000, T2, MOV_IMM), - ARMv7_OP4(0xfbf0, 0x8000, 0xf240, 0x0000, T3, MOV_IMM), - ARMv7_OP4(0x0fef, 0x0000, 0x03a0, 0x0000, A1, MOV_IMM), - ARMv7_OP4(0x0ff0, 0x0000, 0x0300, 0x0000, A2, MOV_IMM), - ARMv7_OP2(0xff00, 0x4600, T1, MOV_REG), - ARMv7_OP2(0xffc0, 0x0000, T2, MOV_REG), - ARMv7_OP4(0xffef, 0xf0f0, 0xea4f, 0x0000, T3, MOV_REG), - ARMv7_OP4(0x0fef, 0x0ff0, 0x01a0, 0x0000, A1, MOV_REG), - - ARMv7_OP4(0xfbf0, 0x8000, 0xf2c0, 0x0000, T1, MOVT), - ARMv7_OP4(0x0ff0, 0x0000, 0x0340, 0x0000, A1, MOVT), - - ARMv7_OP4(0xff10, 0x0010, 0xee10, 0x0010, T1, MRC_), - ARMv7_OP4(0x0f10, 0x0010, 0x0e10, 0x0010, A1, MRC_), - ARMv7_OP4(0xff10, 0x0010, 0xfe10, 0x0010, T2, MRC_), - ARMv7_OP4(0xff10, 0x0010, 0xfe10, 0x0010, A2, MRC_), - - ARMv7_OP4(0xffff, 0xf0ff, 0xf3ef, 0x8000, T1, MRS), - ARMv7_OP4(0x0fff, 0x0fff, 0x010f, 0x0000, A1, MRS), - - ARMv7_OP4(0x0ff3, 0xf000, 0x0320, 0xf000, A1, MSR_IMM), - ARMv7_OP4(0xfff0, 0xf3ff, 0xf380, 0x8000, T1, MSR_REG), - ARMv7_OP4(0x0ff3, 0xfff0, 0x0120, 0xf000, A1, MSR_REG), - - ARMv7_OP2(0xffc0, 0x4340, T1, MUL), - ARMv7_OP4(0xfff0, 0xf0f0, 0xfb00, 0xf000, T2, MUL), - ARMv7_OP4(0x0fe0, 0xf0f0, 0x0000, 0x0090, A1, MUL), - - ARMv7_OP4(0xfbef, 0x8000, 0xf06f, 0x0000, T1, MVN_IMM), - ARMv7_OP4(0x0fef, 0x0000, 0x03e0, 0x0000, A1, MVN_IMM), - ARMv7_OP2(0xffc0, 0x43c0, T1, MVN_REG), - ARMv7_OP4(0xffef, 0x8000, 0xea6f, 0x0000, T2, MVN_REG), - ARMv7_OP4(0xffef, 0x0010, 0x01e0, 0x0000, A1, MVN_REG), - ARMv7_OP4(0x0fef, 0x0090, 0x01e0, 0x0010, A1, MVN_RSR), - - ARMv7_OP2(0xffff, 0xbf00, T1, NOP), - ARMv7_OP4(0xffff, 0xffff, 0xf3af, 0x8000, T2, NOP), - ARMv7_OP4(0x0fff, 0xffff, 0x0320, 0xf000, A1, NOP), - - ARMv7_OP4(0xfbe0, 0x8000, 0xf060, 0x0000, T1, ORN_IMM), - ARMv7_OP4(0xffe0, 0x8000, 0xea60, 0x0000, T1, ORN_REG), - - ARMv7_OP4(0xfbe0, 0x8000, 0xf040, 0x0000, T1, ORR_IMM), - ARMv7_OP4(0x0fe0, 0x0000, 0x0380, 0x0000, A1, ORR_IMM), - ARMv7_OP2(0xffc0, 0x4300, T1, ORR_REG), - ARMv7_OP4(0xffe0, 0x8000, 0xea40, 0x0000, T2, ORR_REG, SKIP_IF( BF(16, 19) == 15 )), - ARMv7_OP4(0x0fe0, 0x0010, 0x0180, 0x0000, A1, ORR_REG), - ARMv7_OP4(0x0fe0, 0x0090, 0x0180, 0x0010, A1, ORR_RSR), - - ARMv7_OP4(0xfff0, 0x8010, 0xeac0, 0x0000, T1, PKH), - ARMv7_OP4(0x0ff0, 0x0030, 0x0680, 0x0010, A1, PKH), - - ARMv7_OP2(0xfe00, 0xbc00, T1, POP), - ARMv7_OP4(0xffff, 0x0000, 0xe8bd, 0x0000, T2, POP), - ARMv7_OP4(0xffff, 0x0fff, 0xf85d, 0x0b04, T3, POP), - ARMv7_OP4(0x0fff, 0x0000, 0x08bd, 0x0000, A1, POP), - ARMv7_OP4(0x0fff, 0x0fff, 0x049d, 0x0004, A2, POP), - - ARMv7_OP2(0xfe00, 0xb400, T1, PUSH), - ARMv7_OP4(0xffff, 0x0000, 0xe92d, 0x0000, T2, PUSH), // had an error in arch ref - ARMv7_OP4(0xffff, 0x0fff, 0xf84d, 0x0d04, T3, PUSH), - ARMv7_OP4(0x0fff, 0x0000, 0x092d, 0x0000, A1, PUSH), - ARMv7_OP4(0x0fff, 0x0fff, 0x052d, 0x0004, A2, PUSH), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfa80, 0xf080, T1, QADD), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0100, 0x0050, A1, QADD), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfa90, 0xf010, T1, QADD16), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0620, 0x0f10, A1, QADD16), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfa80, 0xf010, T1, QADD8), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0620, 0x0f90, A1, QADD8), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfaa0, 0xf010, T1, QASX), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0620, 0x0f30, A1, QASX), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfa80, 0xf090, T1, QDADD), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0140, 0x0050, A1, QDADD), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfa80, 0xf0b0, T1, QDSUB), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0160, 0x0050, A1, QDSUB), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfae0, 0xf010, T1, QSAX), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0620, 0x0f50, A1, QSAX), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfa80, 0xf0a0, T1, QSUB), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0120, 0x0050, A1, QSUB), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfad0, 0xf010, T1, QSUB16), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0620, 0x0f70, A1, QSUB16), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfac0, 0xf010, T1, QSUB8), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0620, 0x0ff0, A1, QSUB8), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfa90, 0xf0a0, T1, RBIT), - ARMv7_OP4(0x0fff, 0x0ff0, 0x06ff, 0x0f30, A1, RBIT), - - ARMv7_OP2(0xffc0, 0xba00, T1, REV), - ARMv7_OP4(0xfff0, 0xf0f0, 0xfa90, 0xf080, T2, REV), - ARMv7_OP4(0x0fff, 0x0ff0, 0x06bf, 0x0f30, A1, REV), - - ARMv7_OP2(0xffc0, 0xba40, T1, REV16), - ARMv7_OP4(0xfff0, 0xf0f0, 0xfa90, 0xf090, T2, REV16), - ARMv7_OP4(0x0fff, 0x0ff0, 0x06bf, 0x0fb0, A1, REV16), - - ARMv7_OP2(0xffc0, 0xbac0, T1, REVSH), - ARMv7_OP4(0xfff0, 0xf0f0, 0xfa90, 0xf0b0, T2, REVSH), - ARMv7_OP4(0x0fff, 0x0ff0, 0x06ff, 0x0fb0, A1, REVSH), - - ARMv7_OP4(0xffef, 0x8030, 0xea4f, 0x0030, T1, ROR_IMM), - ARMv7_OP4(0x0fef, 0x0070, 0x01a0, 0x0060, A1, ROR_IMM), - ARMv7_OP2(0xffc0, 0x41c0, T1, ROR_REG), - ARMv7_OP4(0xffe0, 0xf0f0, 0xfa60, 0xf000, T2, ROR_REG), - ARMv7_OP4(0x0fef, 0x00f0, 0x01a0, 0x0070, A1, ROR_REG), - ARMv7_OP4(0xffef, 0xf0f0, 0xea4f, 0x0030, T1, RRX), - ARMv7_OP4(0x0fef, 0x0ff0, 0x01a0, 0x0060, A1, RRX), - - ARMv7_OP2(0xffc0, 0x4240, T1, RSB_IMM), - ARMv7_OP4(0xfbe0, 0x8000, 0xf1c0, 0x0000, T2, RSB_IMM), - ARMv7_OP4(0x0fe0, 0x0000, 0x0260, 0x0000, A1, RSB_IMM), - ARMv7_OP4(0xffe0, 0x8000, 0xebc0, 0x0000, T1, RSB_REG), - ARMv7_OP4(0x0fe0, 0x0010, 0x0060, 0x0000, A1, RSB_REG), - ARMv7_OP4(0x0fe0, 0x0090, 0x0060, 0x0010, A1, RSB_RSR), - - ARMv7_OP4(0x0fe0, 0x0000, 0x02e0, 0x0000, A1, RSC_IMM), - ARMv7_OP4(0x0fe0, 0x0010, 0x00e0, 0x0000, A1, RSC_REG), - ARMv7_OP4(0x0fe0, 0x0090, 0x00e0, 0x0010, A1, RSC_RSR), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfa90, 0xf000, T1, SADD16), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0610, 0x0f10, A1, SADD16), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfa80, 0xf000, T1, SADD8), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0610, 0x0f90, A1, SADD8), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfaa0, 0xf000, T1, SASX), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0610, 0x0f30, A1, SASX), - - ARMv7_OP4(0xfbe0, 0x8000, 0xf160, 0x0000, T1, SBC_IMM), - ARMv7_OP4(0x0fe0, 0x0000, 0x02c0, 0x0000, A1, SBC_IMM), - ARMv7_OP2(0xffc0, 0x4180, T1, SBC_REG), - ARMv7_OP4(0xffe0, 0x8000, 0xeb60, 0x0000, T2, SBC_REG), - ARMv7_OP4(0x0fe0, 0x0010, 0x00c0, 0x0000, A1, SBC_REG), - ARMv7_OP4(0x0fe0, 0x0090, 0x00c0, 0x0010, A1, SBC_RSR), - - ARMv7_OP4(0xfff0, 0x8020, 0xf340, 0x0000, T1, SBFX), - ARMv7_OP4(0x0fe0, 0x0070, 0x07a0, 0x0050, A1, SBFX), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfb90, 0xf0f0, T1, SDIV), // ??? - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfaa0, 0xf080, T1, SEL), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0680, 0x0fb0, A1, SEL), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfa90, 0xf020, T1, SHADD16), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0630, 0x0f10, A1, SHADD16), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfa80, 0xf020, T1, SHADD8), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0630, 0x0f90, A1, SHADD8), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfaa0, 0xf020, T1, SHASX), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0630, 0x0f30, A1, SHASX), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfae0, 0xf020, T1, SHSAX), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0630, 0x0f50, A1, SHSAX), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfad0, 0xf020, T1, SHSUB16), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0630, 0x0f70, A1, SHSUB16), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfac0, 0xf020, T1, SHSUB8), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0630, 0x0ff0, A1, SHSUB8), - - ARMv7_OP4(0xfff0, 0x00c0, 0xfb10, 0x0000, T1, SMLA__), - ARMv7_OP4(0x0ff0, 0x0090, 0x0100, 0x0080, A1, SMLA__), - - ARMv7_OP4(0xfff0, 0x00e0, 0xfb20, 0x0000, T1, SMLAD), - ARMv7_OP4(0x0ff0, 0x00d0, 0x0700, 0x0010, A1, SMLAD), - - ARMv7_OP4(0xfff0, 0x00f0, 0xfbc0, 0x0000, T1, SMLAL), - ARMv7_OP4(0x0fe0, 0x00f0, 0x00e0, 0x0090, A1, SMLAL), - - ARMv7_OP4(0xfff0, 0x00c0, 0xfbc0, 0x0080, T1, SMLAL__), - ARMv7_OP4(0x0ff0, 0x0090, 0x0140, 0x0080, A1, SMLAL__), - - ARMv7_OP4(0xfff0, 0x00e0, 0xfbc0, 0x00c0, T1, SMLALD), - ARMv7_OP4(0x0ff0, 0x00d0, 0x0740, 0x0010, A1, SMLALD), - - ARMv7_OP4(0xfff0, 0x00e0, 0xfb30, 0x0000, T1, SMLAW_), - ARMv7_OP4(0x0ff0, 0x00b0, 0x0120, 0x0080, A1, SMLAW_), - - ARMv7_OP4(0xfff0, 0x00e0, 0xfb40, 0x0000, T1, SMLSD), - ARMv7_OP4(0x0ff0, 0x00d0, 0x0700, 0x0050, A1, SMLSD), - - ARMv7_OP4(0xfff0, 0x00e0, 0xfbd0, 0x00c0, T1, SMLSLD), - ARMv7_OP4(0x0ff0, 0x00d0, 0x0740, 0x0050, A1, SMLSLD), - - ARMv7_OP4(0xfff0, 0x00e0, 0xfb50, 0x0000, T1, SMMLA), - ARMv7_OP4(0x0ff0, 0x00d0, 0x0750, 0x0010, A1, SMMLA), - - ARMv7_OP4(0xfff0, 0x00e0, 0xfb60, 0x0000, T1, SMMLS), - ARMv7_OP4(0x0ff0, 0x00d0, 0x0750, 0x00d0, A1, SMMLS), - - ARMv7_OP4(0xfff0, 0xf0e0, 0xfb50, 0xf000, T1, SMMUL), - ARMv7_OP4(0x0ff0, 0xf0d0, 0x0750, 0xf010, A1, SMMUL), - - ARMv7_OP4(0xfff0, 0xf0e0, 0xfb20, 0xf000, T1, SMUAD), - ARMv7_OP4(0x0ff0, 0xf0d0, 0x0700, 0xf010, A1, SMUAD), - - ARMv7_OP4(0xfff0, 0xf0c0, 0xfb10, 0xf000, T1, SMUL__), - ARMv7_OP4(0x0ff0, 0xf090, 0x0160, 0x0080, A1, SMUL__), - - ARMv7_OP4(0xfff0, 0x00f0, 0xfb80, 0x0000, T1, SMULL), - ARMv7_OP4(0x0fe0, 0x00f0, 0x00c0, 0x0090, A1, SMULL), - - ARMv7_OP4(0xfff0, 0xf0e0, 0xfb30, 0xf000, T1, SMULW_), - ARMv7_OP4(0x0ff0, 0xf0b0, 0x0120, 0x00a0, A1, SMULW_), - - ARMv7_OP4(0xfff0, 0xf0e0, 0xfb40, 0xf000, T1, SMUSD), - ARMv7_OP4(0x0ff0, 0xf0d0, 0x0700, 0xf050, A1, SMUSD), - - ARMv7_OP4(0xffd0, 0x8020, 0xf300, 0x0000, T1, SSAT), - ARMv7_OP4(0x0fe0, 0x0030, 0x06a0, 0x0010, A1, SSAT), - - ARMv7_OP4(0xfff0, 0xf0e0, 0xf320, 0x0000, T1, SSAT16), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x06a0, 0x0f30, A1, SSAT16), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfae0, 0xf000, T1, SSAX), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0610, 0x0f50, A1, SSAX), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfad0, 0xf000, T1, SSUB16), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0610, 0x0f70, A1, SSUB16), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfac0, 0xf000, T1, SSUB8), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0610, 0x0ff0, A1, SSUB8), - - ARMv7_OP2(0xf800, 0xc000, T1, STM), - ARMv7_OP4(0xffd0, 0xa000, 0xe880, 0x0000, T2, STM), - ARMv7_OP4(0x0fd0, 0x0000, 0x0880, 0x0000, A1, STM), - ARMv7_OP4(0x0fd0, 0x0000, 0x0800, 0x0000, A1, STMDA), - ARMv7_OP4(0xffd0, 0xa000, 0xe900, 0x0000, T1, STMDB), - ARMv7_OP4(0x0fd0, 0x0000, 0x0900, 0x0000, A1, STMDB), - ARMv7_OP4(0x0fd0, 0x0000, 0x0980, 0x0000, A1, STMIB), - - ARMv7_OP2(0xf800, 0x6000, T1, STR_IMM), - ARMv7_OP2(0xf800, 0x9000, T2, STR_IMM), - ARMv7_OP4(0xfff0, 0x0000, 0xf8c0, 0x0000, T3, STR_IMM), - ARMv7_OP4(0xfff0, 0x0800, 0xf840, 0x0800, T4, STR_IMM), - ARMv7_OP4(0x0e50, 0x0000, 0x0400, 0x0000, A1, STR_IMM), - ARMv7_OP2(0xfe00, 0x5000, T1, STR_REG), - ARMv7_OP4(0xfff0, 0x0fc0, 0xf840, 0x0000, T2, STR_REG), - ARMv7_OP4(0x0e50, 0x0010, 0x0600, 0x0000, A1, STR_REG), - - ARMv7_OP2(0xf800, 0x7000, T1, STRB_IMM), - ARMv7_OP4(0xfff0, 0x0000, 0xf880, 0x0000, T2, STRB_IMM), - ARMv7_OP4(0xfff0, 0x0800, 0xf800, 0x0800, T3, STRB_IMM), - ARMv7_OP4(0x0e50, 0x0000, 0x0440, 0x0000, A1, STRB_IMM), - ARMv7_OP2(0xfe00, 0x5400, T1, STRB_REG), - ARMv7_OP4(0xfff0, 0x0fc0, 0xf800, 0x0000, T2, STRB_REG), - ARMv7_OP4(0x0e50, 0x0010, 0x0640, 0x0000, A1, STRB_REG), - - ARMv7_OP4(0xfe50, 0x0000, 0xe840, 0x0000, T1, STRD_IMM, SKIP_IF( !BT(21) && !BT(24) )), - ARMv7_OP4(0x0e50, 0x00f0, 0x0040, 0x00f0, A1, STRD_IMM), - ARMv7_OP4(0x0e50, 0x0ff0, 0x0000, 0x00f0, A1, STRD_REG), - - ARMv7_OP4(0xfff0, 0x0000, 0xe840, 0x0000, T1, STREX), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0180, 0x0f90, A1, STREX), - ARMv7_OP4(0xfff0, 0x0ff0, 0xe8c0, 0x0f40, T1, STREXB), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x01c0, 0x0f90, A1, STREXB), - ARMv7_OP4(0xfff0, 0x00f0, 0xe8c0, 0x0070, T1, STREXD), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x01a0, 0x0f90, A1, STREXD), - ARMv7_OP4(0xfff0, 0x0ff0, 0xe8c0, 0x0f50, T1, STREXH), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x01e0, 0x0f90, A1, STREXH), - - ARMv7_OP2(0xf800, 0x8000, T1, STRH_IMM), - ARMv7_OP4(0xfff0, 0x0000, 0xf8a0, 0x0000, T2, STRH_IMM), - ARMv7_OP4(0xfff0, 0x0800, 0xf820, 0x0800, T3, STRH_IMM), - ARMv7_OP4(0x0e50, 0x00f0, 0x0040, 0x00b0, A1, STRH_IMM), - ARMv7_OP2(0xfe00, 0x5200, T1, STRH_REG), - ARMv7_OP4(0xfff0, 0x0fc0, 0xf820, 0x0000, T2, STRH_REG), - ARMv7_OP4(0x0e50, 0x0ff0, 0x0000, 0x00b0, A1, STRH_REG), - - ARMv7_OP2(0xfe00, 0x1e00, T1, SUB_IMM), - ARMv7_OP2(0xf800, 0x3800, T2, SUB_IMM), - ARMv7_OP4(0xfbe0, 0x8000, 0xf1a0, 0x0000, T3, SUB_IMM, SKIP_IF( (BF(8, 11) == 15 && BT(20)) || BF(16, 19) == 13 )), - ARMv7_OP4(0xfbf0, 0x8000, 0xf2a0, 0x0000, T4, SUB_IMM), - ARMv7_OP4(0x0fe0, 0x0000, 0x0240, 0x0000, A1, SUB_IMM), - ARMv7_OP2(0xfe00, 0x1a00, T1, SUB_REG), - ARMv7_OP4(0xffe0, 0x8000, 0xeba0, 0x0000, T2, SUB_REG, SKIP_IF( (BF(8, 11) == 15 && BT(20)) || BF(16, 19) == 13 )), - ARMv7_OP4(0x0fe0, 0x0010, 0x0040, 0x0000, A1, SUB_REG), - ARMv7_OP4(0x0fe0, 0x0090, 0x0040, 0x0010, A1, SUB_RSR), - ARMv7_OP2(0xff80, 0xb080, T1, SUB_SPI), - ARMv7_OP4(0xfbef, 0x8000, 0xf1ad, 0x0000, T2, SUB_SPI), - ARMv7_OP4(0xfbff, 0x8000, 0xf2ad, 0x0000, T3, SUB_SPI), - ARMv7_OP4(0x0fef, 0x0000, 0x024d, 0x0000, A1, SUB_SPI), - ARMv7_OP4(0xffef, 0x8000, 0xebad, 0x0000, T1, SUB_SPR), - ARMv7_OP4(0x0fef, 0x0010, 0x004d, 0x0000, A1, SUB_SPR), - - ARMv7_OP2(0xff00, 0xdf00, T1, SVC), - ARMv7_OP4(0x0f00, 0x0000, 0x0f00, 0x0000, A1, SVC), - - ARMv7_OP4(0xfff0, 0xf0c0, 0xfa40, 0xf080, T1, SXTAB), - ARMv7_OP4(0x0ff0, 0x03f0, 0x06a0, 0x0070, A1, SXTAB), - - ARMv7_OP4(0xfff0, 0xf0c0, 0xfa20, 0xf080, T1, SXTAB16), - ARMv7_OP4(0x0ff0, 0x03f0, 0x0680, 0x0070, A1, SXTAB16), - - ARMv7_OP4(0xfff0, 0xf0c0, 0xfa00, 0xf080, T1, SXTAH), - ARMv7_OP4(0x0ff0, 0x03f0, 0x06b0, 0x0070, A1, SXTAH), - - ARMv7_OP2(0xffc0, 0xb240, T1, SXTB), - ARMv7_OP4(0xffff, 0xf0c0, 0xfa4f, 0xf080, T2, SXTB), - ARMv7_OP4(0x0fff, 0x03f0, 0x06af, 0x0070, A1, SXTB), - - ARMv7_OP4(0xffff, 0xf0c0, 0xfa2f, 0xf080, T1, SXTB16), - ARMv7_OP4(0x0fff, 0x03f0, 0x068f, 0x0070, A1, SXTB16), - - ARMv7_OP2(0xffc0, 0xb200, T1, SXTH), - ARMv7_OP4(0xffff, 0xf0c0, 0xfa0f, 0xf080, T2, SXTH), - ARMv7_OP4(0x0fff, 0x03f0, 0x06bf, 0x0070, A1, SXTH), - - ARMv7_OP4(0xfff0, 0xffe0, 0xe8d0, 0xf000, T1, TB_), - - ARMv7_OP4(0xfbf0, 0x8f00, 0xf090, 0x0f00, T1, TEQ_IMM), - ARMv7_OP4(0x0ff0, 0xf000, 0x0330, 0x0000, A1, TEQ_IMM), - ARMv7_OP4(0xfff0, 0x8f00, 0xea90, 0x0f00, T1, TEQ_REG), - ARMv7_OP4(0x0ff0, 0xf010, 0x0130, 0x0000, A1, TEQ_REG), - ARMv7_OP4(0x0ff0, 0xf090, 0x0130, 0x0010, A1, TEQ_RSR), - - ARMv7_OP4(0xfbf0, 0x8f00, 0xf010, 0x0f00, T1, TST_IMM), - ARMv7_OP4(0x0ff0, 0xf000, 0x0310, 0x0000, A1, TST_IMM), - ARMv7_OP2(0xffc0, 0x4200, T1, TST_REG), - ARMv7_OP4(0xfff0, 0x8f00, 0xea10, 0x0f00, T2, TST_REG), - ARMv7_OP4(0x0ff0, 0xf010, 0x0110, 0x0000, A1, TST_REG), - ARMv7_OP4(0x0ff0, 0xf090, 0x0110, 0x0010, A1, TST_RSR), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfa90, 0xf040, T1, UADD16), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0650, 0x0f10, A1, UADD16), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfa80, 0xf040, T1, UADD8), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0650, 0x0f90, A1, UADD8), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfaa0, 0xf040, T1, UASX), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0650, 0x0f30, A1, UASX), - - ARMv7_OP4(0xfff0, 0x8020, 0xf3c0, 0x0000, T1, UBFX), - ARMv7_OP4(0x0fe0, 0x0070, 0x07e0, 0x0050, A1, UBFX), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfbb0, 0xf0f0, T1, UDIV), // ??? - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfa90, 0xf060, T1, UHADD16), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0670, 0x0f10, A1, UHADD16), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfa80, 0xf060, T1, UHADD8), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0670, 0x0f90, A1, UHADD8), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfaa0, 0xf060, T1, UHASX), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0670, 0x0f30, A1, UHASX), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfae0, 0xf060, T1, UHSAX), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0670, 0x0f50, A1, UHSAX), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfad0, 0xf060, T1, UHSUB16), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0670, 0x0f70, A1, UHSUB16), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfac0, 0xf060, T1, UHSUB8), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0670, 0x0ff0, A1, UHSUB8), - - ARMv7_OP4(0xfff0, 0x00f0, 0xfbe0, 0x0060, T1, UMAAL), - ARMv7_OP4(0x0ff0, 0x00f0, 0x0040, 0x0090, A1, UMAAL), - - ARMv7_OP4(0xfff0, 0x00f0, 0xfbe0, 0x0000, T1, UMLAL), - ARMv7_OP4(0x0fe0, 0x00f0, 0x00a0, 0x0090, A1, UMLAL), - - ARMv7_OP4(0xfff0, 0x00f0, 0xfba0, 0x0000, T1, UMULL), - ARMv7_OP4(0x0fe0, 0x00f0, 0x0080, 0x0090, A1, UMULL), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfa90, 0xf050, T1, UQADD16), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0660, 0x0f10, A1, UQADD16), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfa80, 0xf050, T1, UQADD8), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0660, 0x0f90, A1, UQADD8), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfaa0, 0xf050, T1, UQASX), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0660, 0x0f30, A1, UQASX), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfae0, 0xf050, T1, UQSAX), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0660, 0x0f50, A1, UQSAX), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfad0, 0xf050, T1, UQSUB16), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0660, 0x0f70, A1, UQSUB16), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfac0, 0xf050, T1, UQSUB8), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0660, 0x0ff0, A1, UQSUB8), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfb70, 0xf000, T1, USAD8), - ARMv7_OP4(0x0ff0, 0xf0f0, 0x0780, 0xf010, A1, USAD8), - - ARMv7_OP4(0xfff0, 0x00f0, 0xfb70, 0x0000, T1, USADA8), - ARMv7_OP4(0x0ff0, 0x00f0, 0x0780, 0x0010, A1, USADA8), - - ARMv7_OP4(0xffd0, 0x8020, 0xf380, 0x0000, T1, USAT), - ARMv7_OP4(0x0fe0, 0x0030, 0x06e0, 0x0010, A1, USAT), - - ARMv7_OP4(0xfff0, 0xf0e0, 0xf3a0, 0x0000, T1, USAT16), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x06e0, 0x0f30, A1, USAT16), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfae0, 0xf040, T1, USAX), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0650, 0x0f50, A1, USAX), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfad0, 0xf040, T1, USUB16), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0650, 0x0f70, A1, USUB16), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfac0, 0xf040, T1, USUB8), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0650, 0x0ff0, A1, USUB8), - - ARMv7_OP4(0xfff0, 0xf0c0, 0xfa50, 0xf080, T1, UXTAB, SKIP_IF( BF(16, 19) == 15 )), - ARMv7_OP4(0x0ff0, 0x03f0, 0x06e0, 0x0070, A1, UXTAB, SKIP_IF( BF(16, 19) == 15 )), - - ARMv7_OP4(0xfff0, 0xf0c0, 0xfa30, 0xf080, T1, UXTAB16), - ARMv7_OP4(0x0ff0, 0x03f0, 0x06c0, 0x0070, A1, UXTAB16), - - ARMv7_OP4(0xfff0, 0xf0c0, 0xfa10, 0xf080, T1, UXTAH), - ARMv7_OP4(0x0ff0, 0x03f0, 0x06f0, 0x0070, A1, UXTAH), - - ARMv7_OP2(0xffc0, 0xb2c0, T1, UXTB), - ARMv7_OP4(0xffff, 0xf0c0, 0xfa5f, 0xf080, T2, UXTB), - ARMv7_OP4(0x0fff, 0x03f0, 0x06ef, 0x0070, A1, UXTB), - - ARMv7_OP4(0xffff, 0xf0c0, 0xfa3f, 0xf080, T1, UXTB16), - ARMv7_OP4(0x0fff, 0x03f0, 0x06cf, 0x0070, A1, UXTB16), - - ARMv7_OP2(0xffc0, 0xb280, T1, UXTH), - ARMv7_OP4(0xffff, 0xf0c0, 0xfa1f, 0xf080, T2, UXTH), - ARMv7_OP4(0x0fff, 0x03f0, 0x06ff, 0x0070, A1, UXTH), - - ARMv7_OP4(0xef80, 0x0f10, 0xef00, 0x0710, T1, VABA_), - ARMv7_OP4(0xfe80, 0x0f10, 0xf200, 0x0710, A1, VABA_), - ARMv7_OP4(0xef80, 0x0f50, 0xef80, 0x0500, T2, VABA_), - ARMv7_OP4(0xfe80, 0x0f50, 0xf280, 0x0500, A2, VABA_), - - ARMv7_OP4(0xef80, 0x0f10, 0xef00, 0x0700, T1, VABD_), - ARMv7_OP4(0xfe80, 0x0f10, 0xf200, 0x0700, A1, VABD_), - ARMv7_OP4(0xef80, 0x0f50, 0xef80, 0x0700, T2, VABD_), - ARMv7_OP4(0xfe80, 0x0f50, 0xf280, 0x0700, A2, VABD_), - - ARMv7_OP4(0xffa0, 0x0f10, 0xff20, 0x0d00, T1, VABD_FP), - ARMv7_OP4(0xffa0, 0x0f10, 0xf320, 0x0d00, A1, VABD_FP), - - ARMv7_OP4(0xffb3, 0x0b90, 0xffb1, 0x0300, T1, VABS), - ARMv7_OP4(0xffb3, 0x0b90, 0xf3b1, 0x0300, A1, VABS), - ARMv7_OP4(0xffbf, 0x0ed0, 0xeeb0, 0x0ac0, T2, VABS), - ARMv7_OP4(0x0fbf, 0x0ed0, 0x0eb0, 0x0ac0, A2, VABS), - - ARMv7_OP4(0xff80, 0x0f10, 0xff00, 0x0e10, T1, VAC__), - ARMv7_OP4(0xff80, 0x0f10, 0xf300, 0x0e10, A1, VAC__), - - ARMv7_OP4(0xff80, 0x0f10, 0xef00, 0x0800, T1, VADD), - ARMv7_OP4(0xff80, 0x0f10, 0xf200, 0x0800, A1, VADD), - - ARMv7_OP4(0xffa0, 0x0f10, 0xef00, 0x0d00, T1, VADD_FP), - ARMv7_OP4(0xffa0, 0x0f10, 0xf200, 0x0d00, A1, VADD_FP), - ARMv7_OP4(0xffb0, 0x0e50, 0xee30, 0x0a00, T2, VADD_FP), - ARMv7_OP4(0x0fb0, 0x0e50, 0x0e30, 0x0a00, A2, VADD_FP), - - ARMv7_OP4(0xff80, 0x0f50, 0xef80, 0x0400, T1, VADDHN), - ARMv7_OP4(0xff80, 0x0f50, 0xf280, 0x0400, A1, VADDHN), - - ARMv7_OP4(0xef80, 0x0e50, 0xef80, 0x0000, T1, VADD_), - ARMv7_OP4(0xfe80, 0x0e50, 0xf280, 0x0000, A1, VADD_), - - ARMv7_OP4(0xffb0, 0x0f10, 0xef00, 0x0110, T1, VAND), - ARMv7_OP4(0xffb0, 0x0f10, 0xf200, 0x0110, A1, VAND), - - ARMv7_OP4(0xefb8, 0x00b0, 0xef80, 0x0030, T1, VBIC_IMM), - ARMv7_OP4(0xfeb0, 0x00b0, 0xf280, 0x0030, A1, VBIC_IMM), - - ARMv7_OP4(0xffb0, 0x0f10, 0xef10, 0x0110, T1, VBIC_REG), - ARMv7_OP4(0xffb0, 0x0f10, 0xf210, 0x0110, A1, VBIC_REG), - - ARMv7_OP4(0xff80, 0x0f10, 0xff00, 0x0110, T1, VB__), - ARMv7_OP4(0xff80, 0x0f10, 0xf300, 0x0110, A1, VB__), - - ARMv7_OP4(0xff80, 0x0f10, 0xff00, 0x0810, T1, VCEQ_REG), - ARMv7_OP4(0xff80, 0x0f10, 0xf300, 0x0810, A1, VCEQ_REG), - ARMv7_OP4(0xffa0, 0x0f10, 0xef00, 0x0e00, T2, VCEQ_REG), - ARMv7_OP4(0xffa0, 0x0f10, 0xf200, 0x0e00, A2, VCEQ_REG), - - ARMv7_OP4(0xffb3, 0x0b90, 0xffb1, 0x0100, T1, VCEQ_ZERO), - ARMv7_OP4(0xffb3, 0x0b90, 0xf3b1, 0x0100, A1, VCEQ_ZERO), - - ARMv7_OP4(0xef80, 0x0f10, 0xef00, 0x0310, T1, VCGE_REG), - ARMv7_OP4(0xfe80, 0x0f10, 0xf200, 0x0310, A1, VCGE_REG), - ARMv7_OP4(0xffa0, 0x0f10, 0xff00, 0x0e00, T2, VCGE_REG), - ARMv7_OP4(0xffa0, 0x0f10, 0xf300, 0x0e00, A2, VCGE_REG), - - ARMv7_OP4(0xffb3, 0x0b90, 0xffb1, 0x0080, T1, VCGE_ZERO), - ARMv7_OP4(0xffb3, 0x0b90, 0xf3b1, 0x0080, A1, VCGE_ZERO), - - ARMv7_OP4(0xef80, 0x0f10, 0xef00, 0x0300, T1, VCGT_REG), - ARMv7_OP4(0xfe80, 0x0f10, 0xf200, 0x0300, A1, VCGT_REG), - ARMv7_OP4(0xffa0, 0x0f10, 0xff20, 0x0e00, T2, VCGT_REG), - ARMv7_OP4(0xffa0, 0x0f10, 0xf320, 0x0e00, A2, VCGT_REG), - - ARMv7_OP4(0xffb3, 0x0b90, 0xffb1, 0x0000, T1, VCGT_ZERO), - ARMv7_OP4(0xffb3, 0x0b90, 0xf3b1, 0x0000, A1, VCGT_ZERO), - - ARMv7_OP4(0xffb3, 0x0b90, 0xffb1, 0x0180, T1, VCLE_ZERO), - ARMv7_OP4(0xffb3, 0x0b90, 0xf3b1, 0x0180, A1, VCLE_ZERO), - - ARMv7_OP4(0xffb3, 0x0f90, 0xffb0, 0x0400, T1, VCLS), - ARMv7_OP4(0xffb3, 0x0f90, 0xf3b0, 0x0400, A1, VCLS), - - ARMv7_OP4(0xffb3, 0x0b90, 0xffb1, 0x0200, T1, VCLT_ZERO), - ARMv7_OP4(0xffb3, 0x0b90, 0xf3b1, 0x0200, A1, VCLT_ZERO), - - ARMv7_OP4(0xffb3, 0x0f90, 0xffb0, 0x0480, T1, VCLZ), - ARMv7_OP4(0xffb3, 0x0f90, 0xf3b0, 0x0480, A1, VCLZ), - - ARMv7_OP4(0xffbf, 0x0e50, 0xeeb4, 0x0a40, T1, VCMP_), - ARMv7_OP4(0x0fbf, 0x0e50, 0x0eb4, 0x0a40, A1, VCMP_), - ARMv7_OP4(0xffbf, 0x0e7f, 0xeeb5, 0x0a40, T2, VCMP_), - ARMv7_OP4(0x0fbf, 0x0e7f, 0x0eb5, 0x0a40, A2, VCMP_), - - ARMv7_OP4(0xffb3, 0x0f90, 0xffb0, 0x0500, T1, VCNT), - ARMv7_OP4(0xffb3, 0x0f90, 0xf3b0, 0x0500, A1, VCNT), - - ARMv7_OP4(0xffb3, 0x0e10, 0xffb3, 0x0600, T1, VCVT_FIA), - ARMv7_OP4(0xffb3, 0x0e10, 0xf3b3, 0x0600, A1, VCVT_FIA), - - ARMv7_OP4(0xffb8, 0x0e50, 0xeeb8, 0x0a40, T1, VCVT_FIF), - ARMv7_OP4(0x0fb8, 0x0e50, 0x0eb8, 0x0a40, A1, VCVT_FIF), - - ARMv7_OP4(0xef80, 0x0e90, 0xef80, 0x0e10, T1, VCVT_FFA), - ARMv7_OP4(0xfe80, 0x0e90, 0xf280, 0x0e10, A1, VCVT_FFA), - - ARMv7_OP4(0xffba, 0x0e50, 0xeeba, 0x0a40, T1, VCVT_FFF), - ARMv7_OP4(0x0fba, 0x0e50, 0x0eba, 0x0a40, A1, VCVT_FFF), - - ARMv7_OP4(0xffbf, 0x0ed0, 0xeeb7, 0x0ac0, T1, VCVT_DF), - ARMv7_OP4(0x0fbf, 0x0ed0, 0x0eb7, 0x0ac0, A1, VCVT_DF), - - ARMv7_OP4(0xffb3, 0x0ed0, 0xffb2, 0x0600, T1, VCVT_HFA), - ARMv7_OP4(0xffb3, 0x0ed0, 0xf3b2, 0x0600, A1, VCVT_HFA), - - ARMv7_OP4(0xffbe, 0x0f50, 0xeeb2, 0x0a40, T1, VCVT_HFF), - ARMv7_OP4(0x0fbe, 0x0f50, 0x0eb2, 0x0a40, A1, VCVT_HFF), - - ARMv7_OP4(0xffb0, 0x0e50, 0xee80, 0x0a00, T1, VDIV), - ARMv7_OP4(0x0fb0, 0x0e50, 0x0e80, 0x0a00, A1, VDIV), - - ARMv7_OP4(0xffb0, 0x0f90, 0xffb0, 0x0c00, T1, VDUP_S), - ARMv7_OP4(0xffb0, 0x0f90, 0xf3b0, 0x0c00, A1, VDUP_S), - - ARMv7_OP4(0xff90, 0x0f5f, 0xee80, 0x0b10, T1, VDUP_R), - ARMv7_OP4(0x0f90, 0x0f5f, 0x0e80, 0x0b10, A1, VDUP_R), - - ARMv7_OP4(0xffb0, 0x0f10, 0xff00, 0x0110, T1, VEOR), - ARMv7_OP4(0xffb0, 0x0f10, 0xf300, 0x0110, A1, VEOR), - - ARMv7_OP4(0xffb0, 0x0010, 0xefb0, 0x0000, T1, VEXT), - ARMv7_OP4(0xffb0, 0x0010, 0xf2b0, 0x0000, A1, VEXT), - - ARMv7_OP4(0xef80, 0x0b10, 0xef00, 0x0000, T1, VHADDSUB), - ARMv7_OP4(0xfe80, 0x0b10, 0xf200, 0x0000, A1, VHADDSUB), - - ARMv7_OP4(0xffb0, 0x0000, 0xf920, 0x0000, T1, VLD__MS), // VLD1, VLD2, VLD3, VLD4 - ARMv7_OP4(0xffb0, 0x0000, 0xf420, 0x0000, A1, VLD__MS), - - ARMv7_OP4(0xffb0, 0x0f00, 0xf9a0, 0x0c00, T1, VLD1_SAL), - ARMv7_OP4(0xffb0, 0x0f00, 0xf4a0, 0x0c00, A1, VLD1_SAL), - - ARMv7_OP4(0xffb0, 0x0300, 0xf9a0, 0x0000, T1, VLD1_SL), - ARMv7_OP4(0xffb0, 0x0300, 0xf4a0, 0x0000, A1, VLD1_SL), - - ARMv7_OP4(0xffb0, 0x0f00, 0xf9a0, 0x0d00, T1, VLD2_SAL), - ARMv7_OP4(0xffb0, 0x0f00, 0xf4a0, 0x0d00, A1, VLD2_SAL), - - ARMv7_OP4(0xffb0, 0x0300, 0xf9a0, 0x0100, T1, VLD2_SL), - ARMv7_OP4(0xffb0, 0x0300, 0xf4a0, 0x0100, A1, VLD2_SL), - - ARMv7_OP4(0xffb0, 0x0f00, 0xf9a0, 0x0e00, T1, VLD3_SAL), - ARMv7_OP4(0xffb0, 0x0f00, 0xf4a0, 0x0e00, A1, VLD3_SAL), - - ARMv7_OP4(0xffb0, 0x0300, 0xf9a0, 0x0200, T1, VLD3_SL), - ARMv7_OP4(0xffb0, 0x0300, 0xf4a0, 0x0200, A1, VLD3_SL), - - ARMv7_OP4(0xffb0, 0x0f00, 0xf9a0, 0x0f00, T1, VLD4_SAL), - ARMv7_OP4(0xffb0, 0x0f00, 0xf4a0, 0x0f00, A1, VLD4_SAL), - - ARMv7_OP4(0xffb0, 0x0300, 0xf9a0, 0x0300, T1, VLD4_SL), - ARMv7_OP4(0xffb0, 0x0300, 0xf4a0, 0x0300, A1, VLD4_SL), - - ARMv7_OP4(0xfe10, 0x0f00, 0xec10, 0x0b00, T1, VLDM), - ARMv7_OP4(0x0e10, 0x0f00, 0x0c10, 0x0b00, A1, VLDM), - ARMv7_OP4(0xfe10, 0x0f00, 0xec10, 0x0a00, T2, VLDM), - ARMv7_OP4(0x0e10, 0x0f00, 0x0c10, 0x0a00, A2, VLDM), - - ARMv7_OP4(0xff30, 0x0f00, 0xed10, 0x0b00, T1, VLDR), - ARMv7_OP4(0x0f30, 0x0f00, 0x0d10, 0x0b00, A1, VLDR), - ARMv7_OP4(0xff30, 0x0f00, 0xed10, 0x0a00, T2, VLDR), - ARMv7_OP4(0x0f30, 0x0f00, 0x0d10, 0x0a00, A2, VLDR), - - ARMv7_OP4(0xef80, 0x0f00, 0xef00, 0x0600, T1, VMAXMIN), - ARMv7_OP4(0xfe80, 0x0f00, 0xf200, 0x0600, A1, VMAXMIN), - - ARMv7_OP4(0xff80, 0x0f10, 0xef00, 0x0f00, T1, VMAXMIN_FP), - ARMv7_OP4(0xff80, 0x0f10, 0xf200, 0x0f00, A1, VMAXMIN_FP), - - ARMv7_OP4(0xef80, 0x0f10, 0xef00, 0x0900, T1, VML__), - ARMv7_OP4(0xfe80, 0x0f10, 0xf200, 0x0900, A1, VML__), - ARMv7_OP4(0xef80, 0x0d50, 0xef80, 0x0800, T2, VML__), - ARMv7_OP4(0xfe80, 0x0d50, 0xf280, 0x0800, A2, VML__), - - ARMv7_OP4(0xff80, 0x0f10, 0xef00, 0x0d10, T1, VML__FP), - ARMv7_OP4(0xff80, 0x0f10, 0xf200, 0x0d10, A1, VML__FP), - ARMv7_OP4(0xffb0, 0x0e10, 0xee00, 0x0a00, T2, VML__FP), - ARMv7_OP4(0x0fb0, 0x0e10, 0x0e00, 0x0a00, A2, VML__FP), - - ARMv7_OP4(0xef80, 0x0a50, 0xef80, 0x0040, T1, VML__S), - ARMv7_OP4(0xfe80, 0x0a50, 0xf280, 0x0040, A1, VML__S), - ARMv7_OP4(0xef80, 0x0b50, 0xef80, 0x0240, T2, VML__S), - ARMv7_OP4(0xfe80, 0x0b50, 0xf280, 0x0240, A2, VML__S), - - ARMv7_OP4(0xefb8, 0x0090, 0xef80, 0x0010, T1, VMOV_IMM), - ARMv7_OP4(0xfeb8, 0x0090, 0xf280, 0x0010, A1, VMOV_IMM), - ARMv7_OP4(0xffb0, 0x0ef0, 0xeeb0, 0x0a00, T2, VMOV_IMM), - ARMv7_OP4(0x0fb0, 0x0ef0, 0x0eb0, 0x0a00, A2, VMOV_IMM), - - ARMv7_OP4(0xffb0, 0x0f10, 0xef20, 0x0110, T1, VMOV_REG), - ARMv7_OP4(0xffb0, 0x0f10, 0xf220, 0x0110, A1, VMOV_REG), - ARMv7_OP4(0xffbf, 0x0ed0, 0xeeb0, 0x0a40, T2, VMOV_REG), - ARMv7_OP4(0x0fbf, 0x0ed0, 0x0eb0, 0x0a40, A2, VMOV_REG), - - ARMv7_OP4(0xff90, 0x0f1f, 0xee00, 0x0b10, T1, VMOV_RS), - ARMv7_OP4(0x0f90, 0x0f1f, 0x0e00, 0x0b10, A1, VMOV_RS), - - ARMv7_OP4(0xff10, 0x0f1f, 0xee10, 0x0b10, T1, VMOV_SR), - ARMv7_OP4(0x0f10, 0x0f1f, 0x0e10, 0x0b10, A1, VMOV_SR), - - ARMv7_OP4(0xffe0, 0x0f7f, 0xee00, 0x0a10, T1, VMOV_RF), - ARMv7_OP4(0x0fe0, 0x0f7f, 0x0e00, 0x0a10, A1, VMOV_RF), - - ARMv7_OP4(0xffe0, 0x0fd0, 0xec40, 0x0a10, T1, VMOV_2RF), - ARMv7_OP4(0x0fe0, 0x0fd0, 0x0c40, 0x0a10, A1, VMOV_2RF), - - ARMv7_OP4(0xffe0, 0x0fd0, 0xec40, 0x0b10, T1, VMOV_2RD), - ARMv7_OP4(0x0fe0, 0x0fd0, 0x0c40, 0x0b10, A1, VMOV_2RD), - - ARMv7_OP4(0xef87, 0x0fd0, 0xef80, 0x0a10, T1, VMOVL), - ARMv7_OP4(0xfe87, 0x0fd0, 0xf280, 0x0a10, A1, VMOVL), - - ARMv7_OP4(0xffb3, 0x0fd0, 0xffb2, 0x0200, T1, VMOVN), - ARMv7_OP4(0xffb3, 0x0fd0, 0xf3b2, 0x0200, A1, VMOVN), - - ARMv7_OP4(0xffff, 0x0fff, 0xeef1, 0x0a10, T1, VMRS), - ARMv7_OP4(0x0fff, 0x0fff, 0x0ef1, 0x0a10, A1, VMRS), - - ARMv7_OP4(0xffff, 0x0fff, 0xeee1, 0x0a10, T1, VMSR), - ARMv7_OP4(0x0fff, 0x0fff, 0x0ee1, 0x0a10, A1, VMSR), - - ARMv7_OP4(0xef80, 0x0f10, 0xef00, 0x0910, T1, VMUL_), - ARMv7_OP4(0xfe80, 0x0f10, 0xf200, 0x0910, A1, VMUL_), - ARMv7_OP4(0xef80, 0x0d50, 0xef80, 0x0c00, T2, VMUL_), - ARMv7_OP4(0xfe80, 0x0d50, 0xf280, 0x0c00, A2, VMUL_), - - ARMv7_OP4(0xffa0, 0x0f10, 0xff00, 0x0d10, T1, VMUL_FP), - ARMv7_OP4(0xffa0, 0x0f10, 0xf300, 0x0d10, A1, VMUL_FP), - ARMv7_OP4(0xffb0, 0x0e50, 0xee20, 0x0a00, T2, VMUL_FP), - ARMv7_OP4(0x0fb0, 0x0e50, 0x0e20, 0x0a00, A2, VMUL_FP), - - ARMv7_OP4(0xef80, 0x0e50, 0xef80, 0x0840, T1, VMUL_S), - ARMv7_OP4(0xfe80, 0x0e50, 0xf280, 0x0840, A1, VMUL_S), - ARMv7_OP4(0xef80, 0x0f50, 0xef80, 0x0a40, T2, VMUL_S), - ARMv7_OP4(0xfe80, 0x0f50, 0xf280, 0x0a40, A2, VMUL_S), - - ARMv7_OP4(0xefb8, 0x00b0, 0xef80, 0x0030, T1, VMVN_IMM), - ARMv7_OP4(0xfeb8, 0x00b0, 0xf280, 0x0030, A1, VMVN_IMM), - - ARMv7_OP4(0xffb3, 0x0f90, 0xffb0, 0x0580, T1, VMVN_REG), - ARMv7_OP4(0xffb3, 0x0f90, 0xf3b0, 0x0580, A1, VMVN_REG), - - ARMv7_OP4(0xffb3, 0x0b90, 0xffb1, 0x0380, T1, VNEG), - ARMv7_OP4(0xffb3, 0x0b90, 0xf3b1, 0x0380, A1, VNEG), - ARMv7_OP4(0xffbf, 0x0ed0, 0xeeb1, 0x0a40, T2, VNEG), - ARMv7_OP4(0x0fbf, 0x0ed0, 0x0eb1, 0x0a40, A2, VNEG), - - ARMv7_OP4(0xffb0, 0x0e10, 0xee10, 0x0a00, T1, VNM__), - ARMv7_OP4(0x0fb0, 0x0e10, 0x0e10, 0x0a00, A1, VNM__), - ARMv7_OP4(0xffb0, 0x0e50, 0xee20, 0x0a40, T2, VNM__), - ARMv7_OP4(0x0fb0, 0x0e50, 0x0e20, 0x0a40, A2, VNM__), - - ARMv7_OP4(0xffb0, 0x0f10, 0xef30, 0x0110, T1, VORN_REG), - ARMv7_OP4(0xffb0, 0x0f10, 0xf230, 0x0110, A1, VORN_REG), - - ARMv7_OP4(0xefb8, 0x00b0, 0xef80, 0x0010, T1, VORR_IMM), - ARMv7_OP4(0xfeb8, 0x00b0, 0xf280, 0x0010, A1, VORR_IMM), - - ARMv7_OP4(0xffb0, 0x0f10, 0xef20, 0x0110, T1, VORR_REG), - ARMv7_OP4(0xffb0, 0x0f10, 0xf220, 0x0110, A1, VORR_REG), - - ARMv7_OP4(0xffb3, 0x0f10, 0xffb0, 0x0600, T1, VPADAL), - ARMv7_OP4(0xffb3, 0x0f10, 0xf3b0, 0x0600, A1, VPADAL), - - ARMv7_OP4(0xff80, 0x0f10, 0xef00, 0x0b10, T1, VPADD), - ARMv7_OP4(0xff80, 0x0f10, 0xf200, 0x0b10, A1, VPADD), - - ARMv7_OP4(0xffa0, 0x0f10, 0xff00, 0x0d00, T1, VPADD_FP), - ARMv7_OP4(0xffa0, 0x0f10, 0xf300, 0x0d00, A1, VPADD_FP), - - ARMv7_OP4(0xffb3, 0x0f10, 0xffb0, 0x0200, T1, VPADDL), - ARMv7_OP4(0xffb3, 0x0f10, 0xf3b0, 0x0200, A1, VPADDL), - - ARMv7_OP4(0xef80, 0x0f00, 0xef00, 0x0a00, T1, VPMAXMIN), - ARMv7_OP4(0xfe80, 0x0f00, 0xf200, 0x0a00, A1, VPMAXMIN), - - ARMv7_OP4(0xff80, 0x0f10, 0xff00, 0x0f00, T1, VPMAXMIN_FP), - ARMv7_OP4(0xff80, 0x0f10, 0xf300, 0x0f00, A1, VPMAXMIN_FP), - - ARMv7_OP4(0xffbf, 0x0f00, 0xecbd, 0x0b00, T1, VPOP), - ARMv7_OP4(0x0fbf, 0x0f00, 0x0cbd, 0x0b00, A1, VPOP), - ARMv7_OP4(0xffbf, 0x0f00, 0xecbd, 0x0a00, T2, VPOP), - ARMv7_OP4(0x0fbf, 0x0f00, 0x0cbd, 0x0a00, A2, VPOP), - - ARMv7_OP4(0xffbf, 0x0f00, 0xed2d, 0x0b00, T1, VPUSH), - ARMv7_OP4(0x0fbf, 0x0f00, 0x0d2d, 0x0b00, A1, VPUSH), - ARMv7_OP4(0xffbf, 0x0f00, 0xed2d, 0x0a00, T2, VPUSH), - ARMv7_OP4(0x0fbf, 0x0f00, 0x0d2d, 0x0a00, A2, VPUSH), - - // TODO: VQ* instructions - - ARMv7_OP4(0xff80, 0x0f50, 0xff80, 0x0400, T1, VRADDHN), - ARMv7_OP4(0xff80, 0x0f50, 0xf380, 0x0400, A1, VRADDHN), - - ARMv7_OP4(0xffb3, 0x0e90, 0xffb3, 0x0400, T1, VRECPE), - ARMv7_OP4(0xffb3, 0x0e90, 0xf3b3, 0x0400, A1, VRECPE), - - ARMv7_OP4(0xffa0, 0x0f10, 0xef00, 0x0f10, T1, VRECPS), - ARMv7_OP4(0xffa0, 0x0f10, 0xf200, 0x0f10, A1, VRECPS), - - ARMv7_OP4(0xffb3, 0x0e10, 0xffb0, 0x0000, T1, VREV__), - ARMv7_OP4(0xffb3, 0x0e10, 0xf3b0, 0x0000, A1, VREV__), - - ARMv7_OP4(0xef80, 0x0f10, 0xef00, 0x0100, T1, VRHADD), - ARMv7_OP4(0xfe80, 0x0f10, 0xf200, 0x0100, A1, VRHADD), - - ARMv7_OP4(0xef80, 0x0f10, 0xef00, 0x0500, T1, VRSHL), - ARMv7_OP4(0xfe80, 0x0f10, 0xf200, 0x0500, A1, VRSHL), - - ARMv7_OP4(0xef80, 0x0f10, 0xef80, 0x0210, T1, VRSHR), - ARMv7_OP4(0xfe80, 0x0f10, 0xf280, 0x0210, A1, VRSHR), - - ARMv7_OP4(0xff80, 0x0fd0, 0xef80, 0x0850, T1, VRSHRN), - ARMv7_OP4(0xff80, 0x0fd0, 0xf280, 0x0850, A1, VRSHRN), - - ARMv7_OP4(0xffb3, 0x0e90, 0xffb3, 0x0480, T1, VRSQRTE), - ARMv7_OP4(0xffb3, 0x0e90, 0xf3b3, 0x0480, A1, VRSQRTE), - - ARMv7_OP4(0xffa0, 0x0f10, 0xef20, 0x0f10, T1, VRSQRTS), - ARMv7_OP4(0xffa0, 0x0f10, 0xf220, 0x0f10, A1, VRSQRTS), - - ARMv7_OP4(0xef80, 0x0f10, 0xef80, 0x0310, T1, VRSRA), - ARMv7_OP4(0xfe80, 0x0f10, 0xf280, 0x0310, A1, VRSRA), - - ARMv7_OP4(0xff80, 0x0f50, 0xff80, 0x0600, T1, VRSUBHN), - ARMv7_OP4(0xff80, 0x0f50, 0xf380, 0x0600, A1, VRSUBHN), - - ARMv7_OP4(0xff80, 0x0f10, 0xef80, 0x0510, T1, VSHL_IMM), - ARMv7_OP4(0xff80, 0x0f10, 0xf280, 0x0510, A1, VSHL_IMM), - - ARMv7_OP4(0xef80, 0x0f10, 0xef00, 0x0400, T1, VSHL_REG), - ARMv7_OP4(0xfe80, 0x0f10, 0xf200, 0x0400, A1, VSHL_REG), - - ARMv7_OP4(0xef80, 0x0fd0, 0xef80, 0x0a10, T1, VSHLL), - ARMv7_OP4(0xfe80, 0x0fd0, 0xf280, 0x0a10, A1, VSHLL), - ARMv7_OP4(0xffb3, 0x0fd0, 0xffb2, 0x0300, T2, VSHLL), - ARMv7_OP4(0xffb3, 0x0fd0, 0xf3b2, 0x0300, A2, VSHLL), - - ARMv7_OP4(0xef80, 0x0f10, 0xef80, 0x0010, T1, VSHR), - ARMv7_OP4(0xfe80, 0x0f10, 0xf280, 0x0010, A1, VSHR), - - ARMv7_OP4(0xff80, 0x0fd0, 0xef80, 0x0810, T1, VSHRN), - ARMv7_OP4(0xff80, 0x0fd0, 0xf280, 0x0810, A1, VSHRN), - - ARMv7_OP4(0xff80, 0x0f10, 0xff80, 0x0510, T1, VSLI), - ARMv7_OP4(0xff80, 0x0f10, 0xf380, 0x0510, A1, VSLI), - - ARMv7_OP4(0xffbf, 0x0ed0, 0xeeb1, 0x0ac0, T1, VSQRT), - ARMv7_OP4(0x0fbf, 0x0ed0, 0x0eb1, 0x0ac0, A1, VSQRT), - - ARMv7_OP4(0xef80, 0x0f10, 0xef80, 0x0110, T1, VSRA), - ARMv7_OP4(0xfe80, 0x0f10, 0xf280, 0x0110, A1, VSRA), - - ARMv7_OP4(0xff80, 0x0f10, 0xff80, 0x0410, T1, VSRI), - ARMv7_OP4(0xff80, 0x0f10, 0xf380, 0x0410, A1, VSRI), - - ARMv7_OP4(0xffb0, 0x0000, 0xf900, 0x0000, T1, VST__MS), // VST1, VST2, VST3, VST4 - ARMv7_OP4(0xffb0, 0x0000, 0xf400, 0x0000, A1, VST__MS), - - ARMv7_OP4(0xffb0, 0x0300, 0xf980, 0x0000, T1, VST1_SL), - ARMv7_OP4(0xffb0, 0x0300, 0xf480, 0x0000, A1, VST1_SL), - - ARMv7_OP4(0xffb0, 0x0300, 0xf980, 0x0100, T1, VST2_SL), - ARMv7_OP4(0xffb0, 0x0300, 0xf480, 0x0100, A1, VST2_SL), - - ARMv7_OP4(0xffb0, 0x0300, 0xf980, 0x0200, T1, VST3_SL), - ARMv7_OP4(0xffb0, 0x0300, 0xf480, 0x0200, A1, VST3_SL), - - ARMv7_OP4(0xffb0, 0x0300, 0xf980, 0x0300, T1, VST4_SL), - ARMv7_OP4(0xffb0, 0x0300, 0xf480, 0x0300, A1, VST4_SL), - - ARMv7_OP4(0xfe10, 0x0f00, 0xec00, 0x0b00, T1, VSTM), - ARMv7_OP4(0x0e10, 0x0f00, 0x0c00, 0x0b00, A1, VSTM), - ARMv7_OP4(0xfe10, 0x0f00, 0xec00, 0x0a00, T2, VSTM), - ARMv7_OP4(0x0e10, 0x0f00, 0x0c00, 0x0a00, A2, VSTM), - - ARMv7_OP4(0xff30, 0x0f00, 0xed00, 0x0b00, T1, VSTR), - ARMv7_OP4(0x0f30, 0x0f00, 0x0d00, 0x0b00, A1, VSTR), - ARMv7_OP4(0xff30, 0x0f00, 0xed00, 0x0a00, T2, VSTR), - ARMv7_OP4(0x0f30, 0x0f00, 0x0d00, 0x0a00, A2, VSTR), - - ARMv7_OP4(0xff80, 0x0f10, 0xff00, 0x0800, T1, VSUB), - ARMv7_OP4(0xff80, 0x0f10, 0xf300, 0x0800, A1, VSUB), - - ARMv7_OP4(0xffa0, 0x0f10, 0xef20, 0x0d00, T1, VSUB_FP), - ARMv7_OP4(0xffa0, 0x0f10, 0xf220, 0x0d00, A1, VSUB_FP), - ARMv7_OP4(0xffb0, 0x0e50, 0xee30, 0x0a40, T2, VSUB_FP), - ARMv7_OP4(0x0fb0, 0x0e50, 0x0e30, 0x0a40, A2, VSUB_FP), - - ARMv7_OP4(0xff80, 0x0f50, 0xef80, 0x0600, T1, VSUBHN), - ARMv7_OP4(0xff80, 0x0f50, 0xf280, 0x0600, A1, VSUBHN), - - ARMv7_OP4(0xef80, 0x0e50, 0xef80, 0x0200, T1, VSUB_), - ARMv7_OP4(0xfe80, 0x0e50, 0xf280, 0x0200, A1, VSUB_), - - ARMv7_OP4(0xffb3, 0x0f90, 0xffb2, 0x0000, T1, VSWP), - ARMv7_OP4(0xffb3, 0x0f90, 0xf3b2, 0x0000, A1, VSWP), - - ARMv7_OP4(0xffb0, 0x0c10, 0xffb0, 0x0800, T1, VTB_), - ARMv7_OP4(0xffb0, 0x0c10, 0xf3b0, 0x0800, A1, VTB_), - - ARMv7_OP4(0xffb3, 0x0f90, 0xffb2, 0x0080, T1, VTRN), - ARMv7_OP4(0xffb3, 0x0f90, 0xf3b2, 0x0080, A1, VTRN), - - ARMv7_OP4(0xff80, 0x0f10, 0xef00, 0x0810, T1, VTST), - ARMv7_OP4(0xff80, 0x0f10, 0xf200, 0x0810, A1, VTST), - - ARMv7_OP4(0xffb3, 0x0f90, 0xffb2, 0x0100, T1, VUZP), - ARMv7_OP4(0xffb3, 0x0f90, 0xf3b2, 0x0100, A1, VUZP), - - ARMv7_OP4(0xffb3, 0x0f90, 0xffb2, 0x0180, T1, VZIP), - ARMv7_OP4(0xffb3, 0x0f90, 0xf3b2, 0x0180, A1, VZIP), - - ARMv7_OP2(0xffff, 0xbf20, T1, WFE), - ARMv7_OP4(0xffff, 0xffff, 0xf3af, 0x8002, T2, WFE), - ARMv7_OP4(0x0fff, 0xffff, 0x0320, 0xf002, A1, WFE), - ARMv7_OP2(0xffff, 0xbf30, T1, WFI), - ARMv7_OP4(0xffff, 0xffff, 0xf3af, 0x8003, T2, WFI), - ARMv7_OP4(0x0fff, 0xffff, 0x0320, 0xf003, A1, WFI), - ARMv7_OP2(0xffff, 0xbf10, T1, YIELD), - ARMv7_OP4(0xffff, 0xffff, 0xf3af, 0x8001, T2, YIELD), - ARMv7_OP4(0x0fff, 0xffff, 0x0320, 0xf001, A1, YIELD), -}; - -#undef ARMv7_OP2 -#undef ARMv7_OP4 -#undef SKIP_IF -#undef BF -#undef BT - -struct ARMv7_op2_table_t -{ - const ARMv7_opcode_t* data[0x10000]; - u32 null_ops; - - ARMv7_op2_table_t() - { - std::vector t2; - - for (auto& opcode : ARMv7_opcode_table) - { - if (opcode.length == 2) - { - if (opcode.code & ~opcode.mask) - { - LOG_ERROR(ARMv7, "%s: wrong opcode mask (mask=0x%04x, code=0x%04x)", opcode.name, opcode.mask >> 16, opcode.code >> 16); - } - - t2.push_back(&opcode); - } - } - - null_ops = 0x10000; - - for (u32 i = 0; i < 0x10000; i++) - { - data[i] = nullptr; - - for (auto& opcode : t2) - { - if (((i << 16) & opcode->mask) == opcode->code && (!opcode->skip || !opcode->skip(i))) - { - data[i] = opcode; - null_ops--; - break; - } - } - } - } - -} g_op2t; - -struct ARMv7_op4t_table_t -{ - std::vector table; - - ARMv7_op4t_table_t() - { - for (auto& opcode : ARMv7_opcode_table) - { - if (opcode.length == 4 && opcode.type < A1) - { - if (opcode.code & ~opcode.mask) - { - LOG_ERROR(ARMv7, "%s: wrong opcode mask (mask=0x%04x 0x%04x, code=0x%04x 0x%04x)", opcode.name, opcode.mask >> 16, (u16)opcode.mask, opcode.code >> 16, (u16)opcode.code); - } - - table.push_back(&opcode); - } - } - } - - const ARMv7_opcode_t* HACK() - { - for (auto& opcode : table) - { - if (opcode->func == ARMv7_instrs::HACK) - { - return opcode; - } - } - - throw EXCEPTION("HACK instruction not found"); - } - -} g_op4t; - -struct ARMv7_op4arm_table_t -{ - std::vector table; - - ARMv7_op4arm_table_t() - { - for (auto& opcode : ARMv7_opcode_table) - { - if (opcode.type >= A1) - { - if (opcode.code & ~opcode.mask) - { - LOG_ERROR(ARMv7, "%s: wrong opcode mask (mask=0x%08x, code=0x%08x)", opcode.name, opcode.mask, opcode.code); - } - - table.push_back(&opcode); - } - } - } - -} g_op4arm; - -std::unordered_map g_opct; - -void armv7_decoder_initialize(u32 addr, u32 end_addr, bool dump) -{ - // 1. Find every 4-byte Thumb instruction and cache it - // 2. If some instruction is not recognized, print the error - // 3. Possibly print disasm - - //g_opct.clear(); - //g_opct.reserve(end_addr - addr); - - const auto hack = g_op4t.HACK(); - - while (addr < end_addr) - { - ARMv7Code code = {}; - code.code0 = vm::psv::read16(addr); - - auto found = g_op2t.data[code.code0]; - - if (!found) - { - code.code1 = code.code0; - code.code0 = vm::psv::read16(addr + 2); - - auto op = g_opct.find(code.data); - if (op != g_opct.end()) - { - found = op->second; - } - } - - if (!found) - { - for (auto opcode : g_op4t.table) - { - if ((code.data & opcode->mask) == opcode->code && (!opcode->skip || !opcode->skip(code.data))) - { - g_opct[code.data] = (found = opcode); - break; - } - } - } - - if (!found) - { - LOG_ERROR(ARMv7, "Unknown instruction found at address 0x%08x: %04x %04x", addr, code.code1, code.code0); - addr += 4; - continue; - } - - // Proceed with found: - - if (dump) - { - if (found->length == 2) - { - LOG_NOTICE(ARMv7, "0x%08x: %04x %s", addr, code.code0, found->name); - } - else - { - LOG_NOTICE(ARMv7, "0x%08x: %04x %04x %s", addr, code.code1, code.code0, found->name); - } - } - - if (found->func == ARMv7_instrs::BLX && found->type == T2) - { - const u32 s = (code.data >> 26) & 0x1; - const u32 i1 = (code.data >> 13) & 0x1 ^ s ^ 1; - const u32 i2 = (code.data >> 11) & 0x1 ^ s ^ 1; - const u32 target = (addr + 4 & ~3) + sign<25, u32>(s << 24 | i2 << 23 | i1 << 22 | (code.data & 0x3ff0000) >> 4 | (code.data & 0x7ff) << 1); - - const u32 instr = vm::check_addr(target, 4) ? vm::psv::read32(target).value() : 0; - - // possibly a call to imported function: - if (target >= end_addr && ((target - end_addr) % 16) == 0 && (instr & 0xfff000f0) == 0xe0700090) - { - // replace BLX with "HACK" instruction directly (in Thumb form), it can help to see where it was called from - const u32 index = (instr & 0xfff00) >> 4 | (instr & 0xf); - vm::psv::write32(addr, 0xf870 | index << 16); - g_opct[0xf8700000 | index] = hack; - } - else - { - LOG_ERROR(ARMv7, "Unrecognized BLX call found at adddress 0x%08x (target=0x%08x)", addr, target); - } - } - - //if (found->func == ARMv7_instrs::IT) - //{ - // LOG_ERROR(ARMv7, "IT instruction found at address 0x%08x", addr); - //} - - addr += found->length; - } - - LOG_NOTICE(ARMv7, "armv7_decoder_initialize() finished, g_opct.size() = %lld, g_op2t.null_ops=0x%x", (u64)g_opct.size(), g_op2t.null_ops); -} - -u32 ARMv7Decoder::DecodeMemory(const u32 address) -{ - ARMv7Code code = {}; - - if (m_ctx.ISET == Thumb) - { - code.code0 = vm::psv::read16(address); - - if (auto opcode = g_op2t.data[code.code0]) - { - (*opcode->func)(m_ctx, code, opcode->type); - return 2; - } - - code.code1 = code.code0; - code.code0 = vm::psv::read16(address + 2); - - auto op = g_opct.find(code.data); - if (op != g_opct.end()) - { - (*op->second->func)(m_ctx, code, op->second->type); - return 4; - } - - //for (auto opcode : g_op4t.table) - //{ - // if ((code.data & opcode->mask) == opcode->code && (!opcode->skip || !opcode->skip(code.data))) - // { - // (*opcode->func)(m_ctx, code, opcode->type); - // return 4; - // } - //} - } - else if (m_ctx.ISET == ARM) - { - code.data = vm::psv::read32(address); - - for (auto opcode : g_op4arm.table) - { - if ((code.data & opcode->mask) == opcode->code && (!opcode->skip || !opcode->skip(code.data))) - { - (*opcode->func)(m_ctx, code, opcode->type); - return 4; - } - } - } - else - { - throw EXCEPTION("Invalid instruction set"); - } - - ARMv7_instrs::UNK(m_ctx, code); - return 4; - - // "group" decoding algorithm (temporarily disabled) - - //execute_main_group(&m_thr); - //// LOG_NOTICE(ARMv7, "%s, %d \n\n", m_thr.m_last_instr_name, m_thr.m_last_instr_size); - //m_thr.m_last_instr_name = "Unknown"; - //return m_thr.m_last_instr_size; -} diff --git a/rpcs3/Emu/ARMv7/ARMv7Decoder.h b/rpcs3/Emu/ARMv7/ARMv7Decoder.h deleted file mode 100644 index 229f74014b..0000000000 --- a/rpcs3/Emu/ARMv7/ARMv7Decoder.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -#include "Emu/CPU/CPUDecoder.h" - -struct ARMv7Context; - -class ARMv7Decoder : public CPUDecoder -{ - ARMv7Context& m_ctx; - -public: - ARMv7Decoder(ARMv7Context& context) : m_ctx(context) - { - } - - virtual u32 DecodeMemory(const u32 address); -}; - -void armv7_decoder_initialize(u32 addr, u32 end_addr, bool dump = false); diff --git a/rpcs3/Emu/ARMv7/ARMv7DisAsm.cpp b/rpcs3/Emu/ARMv7/ARMv7DisAsm.cpp index a9524d664b..f7cd9178cd 100644 --- a/rpcs3/Emu/ARMv7/ARMv7DisAsm.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7DisAsm.cpp @@ -1,1123 +1,3758 @@ #include "stdafx.h" -#if 0 +#include "ARMv7Opcodes.h" #include "ARMv7DisAsm.h" -void ARMv7DisAsm::UNK(const u32 data) +using namespace arm_code::arm_encoding_alias; + +const arm_decoder s_arm_disasm; + +template +static const char* fmt_encoding() { - Write("Unknown/illegal opcode"); + switch (type) + { + case T1: return "T1"; + case T2: return "T2"; + case T3: return "T3"; + case T4: return "T4"; + case A1: return "A1"; + case A2: return "A2"; + } + + return nullptr; } -void ARMv7DisAsm::NULL_OP(const u32 data, const ARMv7_encoding type) +static const char* fmt_cond(u32 cond) { - Write("Illegal opcode (null)"); + switch (cond) + { + case 0: return "eq"; + case 1: return "ne"; + case 2: return "cs"; + case 3: return "cc"; + case 4: return "mi"; + case 5: return "pl"; + case 6: return "vs"; + case 7: return "vc"; + case 8: return "hi"; + case 9: return "ls"; + case 10: return "ge"; + case 11: return "lt"; + case 12: return "gt"; + case 13: return "le"; + case 14: return "al"; + case 15: return ""; + default: return "??"; + } } -void ARMv7DisAsm::HACK(const u32 data, const ARMv7_encoding type) +static const char* fmt_it(u32 state) { - Write(__FUNCTION__); + switch (state & ~0x10) + { + case 0x8: return ""; + + case 0x4: return state & 0x10 ? "e" : "t"; + case 0xc: return state & 0x10 ? "t" : "e"; + + case 0x2: return state & 0x10 ? "ee" : "tt"; + case 0x6: return state & 0x10 ? "et" : "te"; + case 0xa: return state & 0x10 ? "te" : "et"; + case 0xe: return state & 0x10 ? "tt" : "ee"; + + case 0x1: return state & 0x10 ? "eee" : "ttt"; + case 0x3: return state & 0x10 ? "eet" : "tte"; + case 0x5: return state & 0x10 ? "ete" : "tet"; + case 0x7: return state & 0x10 ? "ett" : "tee"; + case 0x9: return state & 0x10 ? "tee" : "ett"; + case 0xb: return state & 0x10 ? "tet" : "ete"; + case 0xd: return state & 0x10 ? "tte" : "eet"; + case 0xf: return state & 0x10 ? "ttt" : "eee"; + + default: return "???"; + } } -void ARMv7DisAsm::ADC_IMM(const u32 data, const ARMv7_encoding type) +static const char* fmt_reg(u32 reg) { - Write(__FUNCTION__); + switch (reg) + { + case 0: return "r0"; + case 1: return "r1"; + case 2: return "r2"; + case 3: return "r3"; + case 4: return "r4"; + case 5: return "r5"; + case 6: return "r6"; + case 7: return "r7"; + case 8: return "r8"; + case 9: return "r9"; + case 10: return "r10"; + case 11: return "r11"; + case 12: return "r12"; + case 13: return "sp"; + case 14: return "lr"; + case 15: return "pc"; + default: return "r???"; + } } -void ARMv7DisAsm::ADC_REG(const u32 data, const ARMv7_encoding type) +static std::string fmt_shift(u32 type, u32 amount) { - Write(__FUNCTION__); + Expects(type != arm_code::SRType_RRX || amount == 1); + Expects(amount <= 32); + + if (amount) + { + switch (type) + { + case arm_code::SRType_LSL: return ",lsl #" + fmt::to_udec(amount); + case arm_code::SRType_LSR: return ",lsr #" + fmt::to_udec(amount); + case arm_code::SRType_ASR: return ",asr #" + fmt::to_udec(amount); + case arm_code::SRType_ROR: return ",ror #" + fmt::to_udec(amount); + case arm_code::SRType_RRX: return ",rrx"; + default: return ",?????"; + } + } + + return{}; } -void ARMv7DisAsm::ADC_RSR(const u32 data, const ARMv7_encoding type) +static std::string fmt_reg_list(u32 reg_list) { - Write(__FUNCTION__); + std::vector> lines; + + for (u32 i = 0; i < 13; i++) + { + if (reg_list & (1 << i)) + { + if (lines.size() && lines.rbegin()->second == i - 1) + { + lines.rbegin()->second = i; + } + else + { + lines.push_back({ i, i }); + } + } + } + + if (reg_list & 0x2000) lines.push_back({ 13, 13 }); // sp + if (reg_list & 0x4000) lines.push_back({ 14, 14 }); // lr + if (reg_list & 0x8000) lines.push_back({ 15, 15 }); // pc + + std::string result; + + if (reg_list >> 16) result = "???"; // invalid bits + + for (auto& line : lines) + { + if (!result.empty()) + { + result += ","; + } + + if (line.first == line.second) + { + result += fmt_reg(line.first); + } + else + { + result += fmt_reg(line.first); + result += '-'; + result += fmt_reg(line.second); + } + } + + return result; +} + +static std::string fmt_mem_imm(u32 reg, u32 imm, u32 index, u32 add, u32 wback) +{ + if (index) + { + return fmt::format("[%s,#%s0x%X]%s", fmt_reg(reg), add ? "" : "-", imm, wback ? "!" : ""); + } + else + { + return fmt::format("[%s],#%s0x%X%s", fmt_reg(reg), add ? "" : "-", imm, wback ? "" : "???"); + } +} + +static std::string fmt_mem_reg(u32 n, u32 m, u32 index, u32 add, u32 wback, u32 shift_t = 0, u32 shift_n = 0) +{ + if (index) + { + return fmt::format("[%s,%s%s%s]%s", fmt_reg(n), add ? "" : "-", fmt_reg(m), fmt_shift(shift_t, shift_n), wback ? "!" : ""); + } + else + { + return fmt::format("[%s],%s%s%s%s", fmt_reg(n), add ? "" : "-", fmt_reg(m), fmt_shift(shift_t, shift_n), wback ? "" : "???"); + } +} + +u32 ARMv7DisAsm::disasm(u32 pc) +{ + const u16 op16 = *(le_t*)(offset + pc); + const u32 cond = -1; // TODO + + if (const auto func16 = s_arm_disasm.decode_thumb(op16)) + { + (this->*func16)(op16, cond); + return 2; + } + else + { + const u32 op32 = (op16 << 16) | *(le_t*)(offset + pc + 2); + (this->*s_arm_disasm.decode_thumb(op32))(op32, cond); + return 4; + } +} + +void ARMv7DisAsm::Write(const std::string& value) +{ + switch (m_mode) + { + case CPUDisAsm_DumpMode: + last_opcode = fmt::format("\t%08x:\t", dump_pc); + break; + + case CPUDisAsm_InterpreterMode: + last_opcode = fmt::format("[%08x] ", dump_pc); + break; + + case CPUDisAsm_CompilerElfMode: + last_opcode = value + "\n"; + return; + } + + const u16 op16 = *(le_t*)(offset + dump_pc); + + // TODO: ARM + if (false) + { + const u32 op_arm = *(le_t*)(offset + dump_pc); + + last_opcode += fmt::format("%08x ", op_arm); + } + else if (arm_op_thumb_is_32(op16)) + { + const u16 op_second = *(le_t*)(offset + dump_pc + 2); + + last_opcode += fmt::format("%04x %04x ", op16, op_second); + } + else + { + last_opcode += fmt::format("%04x ", op16); + } + + auto str = value; + const auto found = str.find_first_of(' '); + if (found < 10) str.insert(str.begin() + found, 10 - found, ' '); + + switch (m_mode) + { + case CPUDisAsm_DumpMode: + last_opcode += fmt::format("\t%s\n", str); + break; + + case CPUDisAsm_InterpreterMode: + last_opcode += fmt::format(": %s", str); + break; + } +} + +#define ARG(arg, ...) const u32 arg = args::arg::extract(__VA_ARGS__); + +void ARMv7DisAsm::UNK(const u32 op, const u32 cond) +{ + // TODO: ARM + if (false) + { + write("Unknown/Illegal opcode: 0x%08X (ARM)", op); + } + else if (op > 0xffff) + { + write("Unknown/Illegal opcode: 0x%04X 0x%04X (Thumb)", op >> 16, op & 0xffff); + } + else + { + write("Unknown/Illegal opcode: 0x%04X (Thumb)", op); + } + +} + +template +void ARMv7DisAsm::HACK(const u32 op, const u32 cond) +{ + using args = arm_code::hack; + ARG(index, op); + + write("hack%s %d", fmt_cond(cond), index); +} + +template +void ARMv7DisAsm::MRC_(const u32 op, const u32 cond) +{ + using args = arm_code::mrc; + ARG(t, op); + ARG(cp, op); + ARG(opc1, op); + ARG(opc2, op); + ARG(cn, op); + ARG(cm, op); + + write("mrc%s p%d,%d,r%d,c%d,c%d,%d", fmt_cond(cond), cp, opc1, t, cn, cm, opc2); } -void ARMv7DisAsm::ADD_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::ADC_IMM(const u32 op, const u32 cond) { - Write(__FUNCTION__); + using args = arm_code::adc_imm; + ARG(d, op); + ARG(n, op); + ARG(imm32, op); + ARG(set_flags, op, cond); + + write("adc%s%s %s,%s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), imm32); } -void ARMv7DisAsm::ADD_REG(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::ADC_REG(const u32 op, const u32 cond) { - Write(__FUNCTION__); + using args = arm_code::adc_reg; + ARG(d, op); + ARG(n, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + ARG(set_flags, op, cond); + + write("adc%s%s %s,%s,%s%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m), fmt_shift(shift_t, shift_n)); } -void ARMv7DisAsm::ADD_RSR(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::ADC_RSR(const u32 op, const u32 cond) { - Write(__FUNCTION__); -} - -void ARMv7DisAsm::ADD_SPI(const u32 data, const ARMv7_encoding type) -{ - Write(__FUNCTION__); -} - -void ARMv7DisAsm::ADD_SPR(const u32 data, const ARMv7_encoding type) -{ - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::ADR(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::ADD_IMM(const u32 op, const u32 cond) { - Write(__FUNCTION__); + using args = arm_code::add_imm; + ARG(d, op); + ARG(n, op); + ARG(imm32, op); + ARG(set_flags, op, cond); + + write("add%s%s %s,%s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), imm32); +} + +template +void ARMv7DisAsm::ADD_REG(const u32 op, const u32 cond) +{ + using args = arm_code::add_reg; + ARG(d, op); + ARG(n, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + ARG(set_flags, op, cond); + + write("add%s%s %s,%s,%s%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m), fmt_shift(shift_t, shift_n)); +} + +template +void ARMv7DisAsm::ADD_RSR(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::ADD_SPI(const u32 op, const u32 cond) +{ + using args = arm_code::add_spi; + ARG(d, op); + ARG(imm32, op); + ARG(set_flags, op, cond); + + write("add%s%s %s,sp,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), imm32); +} + +template +void ARMv7DisAsm::ADD_SPR(const u32 op, const u32 cond) +{ + using args = arm_code::add_spr; + ARG(d, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + ARG(set_flags, op, cond); + + write("add%s%s %s,sp,%s%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(m), fmt_shift(shift_t, shift_n)); } -void ARMv7DisAsm::AND_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::ADR(const u32 op, const u32 cond) { - Write(__FUNCTION__); -} + using args = arm_code::adr; + ARG(d, op); + ARG(i, op); -void ARMv7DisAsm::AND_REG(const u32 data, const ARMv7_encoding type) -{ - Write(__FUNCTION__); -} - -void ARMv7DisAsm::AND_RSR(const u32 data, const ARMv7_encoding type) -{ - Write(__FUNCTION__); + write("adr%s r%d, 0x%08X", fmt_cond(cond), d, (DisAsmBranchTarget(0) & ~3) + i); } -void ARMv7DisAsm::ASR_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::AND_IMM(const u32 op, const u32 cond) { - Write(__FUNCTION__); + using args = arm_code::and_imm; + ARG(d, op); + ARG(n, op); + ARG(imm32, op); + ARG(set_flags, op, cond); + + write("and%s%s %s,%s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), imm32); } -void ARMv7DisAsm::ASR_REG(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::AND_REG(const u32 op, const u32 cond) { - Write(__FUNCTION__); + using args = arm_code::and_reg; + ARG(d, op); + ARG(n, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + ARG(set_flags, op, cond); + + write("and%s%s %s,%s,%s%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m), fmt_shift(shift_t, shift_n)); +} + +template +void ARMv7DisAsm::AND_RSR(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::B(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::ASR_IMM(const u32 op, const u32 cond) { - Write(__FUNCTION__); - //if ((cond & 0xe) == 0xe) + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::ASR_REG(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + + +template +void ARMv7DisAsm::B(const u32 op, const u32 cond) +{ + using args = arm_code::b; + ARG(imm32, op); + + write("b%s 0x%08X", fmt_cond(cond), DisAsmBranchTarget(imm32)); +} + + +template +void ARMv7DisAsm::BFC(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::BFI(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + + +template +void ARMv7DisAsm::BIC_IMM(const u32 op, const u32 cond) +{ + using args = arm_code::bic_imm; + ARG(d, op); + ARG(n, op); + ARG(imm32, op); + ARG(set_flags, op, cond); + + write("bic%s%s %s,%s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), imm32); +} + +template +void ARMv7DisAsm::BIC_REG(const u32 op, const u32 cond) +{ + using args = arm_code::bic_reg; + ARG(d, op); + ARG(n, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + ARG(set_flags, op, cond); + + write("bic%s%s %s,%s,%s%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m), fmt_shift(shift_t, shift_n)); +} + +template +void ARMv7DisAsm::BIC_RSR(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + + +template +void ARMv7DisAsm::BKPT(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + + +template +void ARMv7DisAsm::BL(const u32 op, const u32 cond) +{ + using args = arm_code::bl; + ARG(imm32, op); + ARG(to_arm); + + write("bl%s%s 0x%08X", (to_arm != 0) != (type >= A1) ? "x" : "", fmt_cond(cond), DisAsmBranchTarget(imm32)); +} + +template +void ARMv7DisAsm::BLX(const u32 op, const u32 cond) +{ + using args = arm_code::blx; + ARG(m, op); + + write("blx%s %s", fmt_cond(cond), fmt_reg(m)); +} + +template +void ARMv7DisAsm::BX(const u32 op, const u32 cond) +{ + using args = arm_code::bx; + ARG(m, op); + + write("bx%s %s", fmt_cond(cond), fmt_reg(m)); +} + + +template +void ARMv7DisAsm::CB_Z(const u32 op, const u32 cond) +{ + using args = arm_code::cb_z; + ARG(n, op); + ARG(imm32, op); + ARG(nonzero, op); + + write("cb%sz 0x%08X", nonzero ? "n" : "", DisAsmBranchTarget(imm32)); +} + + +template +void ARMv7DisAsm::CLZ(const u32 op, const u32 cond) +{ + using args = arm_code::clz; + ARG(d, op); + ARG(m, op); + + write("clz%s %s,%s", fmt_cond(cond), fmt_reg(d), fmt_reg(m)); +} + + +template +void ARMv7DisAsm::CMN_IMM(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::CMN_REG(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::CMN_RSR(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + + +template +void ARMv7DisAsm::CMP_IMM(const u32 op, const u32 cond) +{ + using args = arm_code::cmp_imm; + ARG(n, op); + ARG(imm32, op); + + write("cmp%s %s,#0x%X", fmt_cond(cond), fmt_reg(n), imm32); +} + +template +void ARMv7DisAsm::CMP_REG(const u32 op, const u32 cond) +{ + using args = arm_code::cmp_reg; + ARG(n, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + + write("cmp%s %s,%s%s", fmt_cond(cond), fmt_reg(n), fmt_reg(m), fmt_shift(shift_t, shift_n)); +} + +template +void ARMv7DisAsm::CMP_RSR(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + + +template +void ARMv7DisAsm::DBG(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::DMB(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::DSB(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + + +template +void ARMv7DisAsm::EOR_IMM(const u32 op, const u32 cond) +{ + using args = arm_code::eor_imm; + ARG(d, op); + ARG(n, op); + ARG(imm32, op); + ARG(set_flags, op, cond); + + write("eor%s%s %s,%s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), imm32); +} + +template +void ARMv7DisAsm::EOR_REG(const u32 op, const u32 cond) +{ + using args = arm_code::eor_reg; + ARG(d, op); + ARG(n, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + ARG(set_flags, op, cond); + + write("eor%s%s %s,%s,%s%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m), fmt_shift(shift_t, shift_n)); +} + +template +void ARMv7DisAsm::EOR_RSR(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + + +template +void ARMv7DisAsm::IT(const u32 op, const u32 cond) +{ + static_assert(type == T1, "IT"); + + const u32 mask = (op & 0xf); + const u32 first = (op & 0xf0) >> 4; + + write("IT%s %s", fmt_it(mask), fmt_cond(first)); +} + + +template +void ARMv7DisAsm::LDM(const u32 op, const u32 cond) +{ + using args = arm_code::ldm; + ARG(n, op); + ARG(registers, op); + ARG(wback, op); + + write("ldm%s %s%s,{%s}", fmt_cond(cond), fmt_reg(n), wback ? "!" : "", fmt_reg_list(registers)); +} + +template +void ARMv7DisAsm::LDMDA(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::LDMDB(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::LDMIB(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + + +template +void ARMv7DisAsm::LDR_IMM(const u32 op, const u32 cond) +{ + using args = arm_code::ldr_imm; + ARG(t, op); + ARG(n, op); + ARG(imm32, op); + ARG(index, op); + ARG(add, op); + ARG(wback, op); + + write("ldr%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_imm(n, imm32, index, add, wback)); +} + +template +void ARMv7DisAsm::LDR_LIT(const u32 op, const u32 cond) +{ + using args = arm_code::ldr_lit; + ARG(t, op); + ARG(imm32, op); + ARG(add, op); + + const u32 base = DisAsmBranchTarget(0) & ~3; + const u32 addr = add ? base + imm32 : base - imm32; + + write("ldr%s %s,0x%08X", fmt_cond(cond), fmt_reg(t), addr); +} + +template +void ARMv7DisAsm::LDR_REG(const u32 op, const u32 cond) +{ + using args = arm_code::ldr_reg; + ARG(t, op); + ARG(n, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + ARG(index, op); + ARG(add, op); + ARG(wback, op); + + write("ldr%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_reg(n, m, index, add, wback, shift_t, shift_n)); +} + + +template +void ARMv7DisAsm::LDRB_IMM(const u32 op, const u32 cond) +{ + using args = arm_code::ldrb_imm; + ARG(t, op); + ARG(n, op); + ARG(imm32, op); + ARG(index, op); + ARG(add, op); + ARG(wback, op); + + write("ldrb%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_imm(n, imm32, index, add, wback)); +} + +template +void ARMv7DisAsm::LDRB_LIT(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::LDRB_REG(const u32 op, const u32 cond) +{ + using args = arm_code::ldrb_reg; + ARG(t, op); + ARG(n, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + ARG(index, op); + ARG(add, op); + ARG(wback, op); + + write("ldrb%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_reg(n, m, index, add, wback, shift_t, shift_n)); +} + + +template +void ARMv7DisAsm::LDRD_IMM(const u32 op, const u32 cond) +{ + using args = arm_code::ldrd_imm; + ARG(t, op); + ARG(t2, op); + ARG(n, op); + ARG(imm32, op); + ARG(index, op); + ARG(add, op); + ARG(wback, op); + + write("ldrd%s %s,%s,%s", fmt_cond(cond), fmt_reg(t), fmt_reg(t2), fmt_mem_imm(n, imm32, index, add, wback)); +} + +template +void ARMv7DisAsm::LDRD_LIT(const u32 op, const u32 cond) +{ + using args = arm_code::ldrd_lit; + ARG(t, op); + ARG(t2, op); + ARG(imm32, op); + ARG(add, op); + + const u32 base = DisAsmBranchTarget(0) & ~3; + const u32 addr = add ? base + imm32 : base - imm32; + + write("ldrd%s %s,%s,0x%08X", fmt_cond(cond), fmt_reg(t), fmt_reg(t2), addr); +} + +template +void ARMv7DisAsm::LDRD_REG(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + + +template +void ARMv7DisAsm::LDRH_IMM(const u32 op, const u32 cond) +{ + using args = arm_code::ldrh_imm; + ARG(t, op); + ARG(n, op); + ARG(imm32, op); + ARG(index, op); + ARG(add, op); + ARG(wback, op); + + write("ldrh%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_imm(n, imm32, index, add, wback)); +} + +template +void ARMv7DisAsm::LDRH_LIT(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::LDRH_REG(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + + +template +void ARMv7DisAsm::LDRSB_IMM(const u32 op, const u32 cond) +{ + using args = arm_code::ldrsb_imm; + ARG(t, op); + ARG(n, op); + ARG(imm32, op); + ARG(index, op); + ARG(add, op); + ARG(wback, op); + + write("ldrsb%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_imm(n, imm32, index, add, wback)); +} + +template +void ARMv7DisAsm::LDRSB_LIT(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::LDRSB_REG(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + + +template +void ARMv7DisAsm::LDRSH_IMM(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::LDRSH_LIT(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::LDRSH_REG(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + + +template +void ARMv7DisAsm::LDREX(const u32 op, const u32 cond) +{ + using args = arm_code::ldrex; + ARG(t, op); + ARG(n, op); + ARG(imm32, op); + + write("ldrex%s %s,[%s,#0x%X]", fmt_cond(cond), fmt_reg(t), fmt_reg(n), imm32); +} + +template +void ARMv7DisAsm::LDREXB(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::LDREXD(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::LDREXH(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + + +template +void ARMv7DisAsm::LSL_IMM(const u32 op, const u32 cond) +{ + using args = arm_code::lsl_imm; + ARG(d, op); + ARG(m, op); + ARG(shift_n, op); + ARG(set_flags, op, cond); + + write("lsl%s%s %s,%s,#%d", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(m), shift_n); +} + +template +void ARMv7DisAsm::LSL_REG(const u32 op, const u32 cond) +{ + using args = arm_code::lsl_reg; + ARG(d, op); + ARG(n, op); + ARG(m, op); + ARG(set_flags, op, cond); + + write("lsl%s%s %s,%s,%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m)); +} + + +template +void ARMv7DisAsm::LSR_IMM(const u32 op, const u32 cond) +{ + using args = arm_code::lsr_imm; + ARG(d, op); + ARG(m, op); + ARG(shift_n, op); + ARG(set_flags, op, cond); + + write("lsr%s%s %s,%s,#%d", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(m), shift_n); +} + +template +void ARMv7DisAsm::LSR_REG(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + + +template +void ARMv7DisAsm::MLA(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::MLS(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + + +template +void ARMv7DisAsm::MOV_IMM(const u32 op, const u32 cond) +{ + using args = arm_code::mov_imm; + ARG(d, op); + ARG(imm32, op); + ARG(set_flags, op, cond); + + //switch (type) //{ - // Write(fmt::format("b 0x%x", DisAsmBranchTarget(imm) + intstr_size)); - //} - //else - //{ - // Write(fmt::format("b[%s] 0x%x", g_arm_cond_name[cond], DisAsmBranchTarget(imm) + intstr_size)); + //case T3: + //case A2: write("movw%s%s %s,#0x%04X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), imm32); break; + //default: write("mov%s%s %s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), imm32); //} } +template +void ARMv7DisAsm::MOV_REG(const u32 op, const u32 cond) +{ + using args = arm_code::mov_reg; + ARG(d, op); + ARG(m, op); + ARG(set_flags, op, cond); + + write("mov%s%s %s,%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(m)); +} + +template +void ARMv7DisAsm::MOVT(const u32 op, const u32 cond) +{ + using args = arm_code::movt; + ARG(d, op); + ARG(imm16, op); + + write("movt%s %s,#0x%04X", fmt_cond(cond), fmt_reg(d), imm16); +} + + +template +void ARMv7DisAsm::MRS(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::MSR_IMM(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::MSR_REG(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + + +template +void ARMv7DisAsm::MUL(const u32 op, const u32 cond) +{ + using args = arm_code::mul; + ARG(d, op); + ARG(n, op); + ARG(m, op); + ARG(set_flags, op, cond); + + write("mul%s%s %s,%s,%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m)); +} + + +template +void ARMv7DisAsm::MVN_IMM(const u32 op, const u32 cond) +{ + using args = arm_code::mvn_imm; + ARG(d, op); + ARG(imm32, op); + ARG(set_flags, op, cond); + + write("mvn%s%s %s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), imm32); +} + +template +void ARMv7DisAsm::MVN_REG(const u32 op, const u32 cond) +{ + using args = arm_code::mvn_reg; + ARG(d, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + ARG(set_flags, op, cond); + + write("mvn%s%s %s,%s%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(m), fmt_shift(shift_t, shift_n)); +} + +template +void ARMv7DisAsm::MVN_RSR(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + + +template +void ARMv7DisAsm::NOP(const u32 op, const u32 cond) +{ + write("nop%s", fmt_cond(cond)); +} + + +template +void ARMv7DisAsm::ORN_IMM(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::ORN_REG(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + + +template +void ARMv7DisAsm::ORR_IMM(const u32 op, const u32 cond) +{ + using args = arm_code::orr_imm; + ARG(d, op); + ARG(n, op); + ARG(imm32, op); + ARG(set_flags, op, cond); + + write("orr%s%s %s,%s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), imm32); +} + +template +void ARMv7DisAsm::ORR_REG(const u32 op, const u32 cond) +{ + using args = arm_code::orr_reg; + ARG(d, op); + ARG(n, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + ARG(set_flags, op, cond); + + write("orr%s%s %s,%s,%s%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m), fmt_shift(shift_t, shift_n)); +} + +template +void ARMv7DisAsm::ORR_RSR(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + + +template +void ARMv7DisAsm::PKH(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + + +template +void ARMv7DisAsm::POP(const u32 op, const u32 cond) +{ + const u32 registers = arm_code::pop::registers::extract(op); + + write("pop%s {%s}", fmt_cond(cond), fmt_reg_list(registers)); +} + +template +void ARMv7DisAsm::PUSH(const u32 op, const u32 cond) +{ + const u32 registers = arm_code::push::registers::extract(op); + + write("push%s {%s}", fmt_cond(cond), fmt_reg_list(registers)); +} + + +template +void ARMv7DisAsm::QADD(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::QADD16(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::QADD8(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::QASX(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::QDADD(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::QDSUB(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::QSAX(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::QSUB(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::QSUB16(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::QSUB8(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + + +template +void ARMv7DisAsm::RBIT(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::REV(const u32 op, const u32 cond) +{ + using args = arm_code::rev; + ARG(d, op); + ARG(m, op); + + write("rev%s %s,%s", fmt_cond(cond), fmt_reg(d), fmt_reg(m)); +} + +template +void ARMv7DisAsm::REV16(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::REVSH(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + + +template +void ARMv7DisAsm::ROR_IMM(const u32 op, const u32 cond) +{ + using args = arm_code::ror_imm; + ARG(d, op); + ARG(m, op); + ARG(shift_n, op); + ARG(set_flags, op, cond); + + write("ror%s%s %s,%s,#%d", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(m), shift_n); +} + +template +void ARMv7DisAsm::ROR_REG(const u32 op, const u32 cond) +{ + using args = arm_code::ror_reg; + ARG(d, op); + ARG(n, op); + ARG(m, op); + ARG(set_flags, op, cond); + + write("ror%s%s %s,%s,%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m)); +} + + +template +void ARMv7DisAsm::RRX(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + + +template +void ARMv7DisAsm::RSB_IMM(const u32 op, const u32 cond) +{ + using args = arm_code::rsb_imm; + ARG(d, op); + ARG(n, op); + ARG(imm32, op); + ARG(set_flags, op, cond); + + write("rsb%s%s %s,%s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), imm32); +} + +template +void ARMv7DisAsm::RSB_REG(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::RSB_RSR(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + + +template +void ARMv7DisAsm::RSC_IMM(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::RSC_REG(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::RSC_RSR(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + + +template +void ARMv7DisAsm::SADD16(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::BFC(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SADD8(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::BFI(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SASX(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::BIC_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SBC_IMM(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::BIC_REG(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SBC_REG(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::BIC_RSR(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SBC_RSR(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::BKPT(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SBFX(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::BL(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SDIV(const u32 op, const u32 cond) { - Write(__FUNCTION__); - //Write(fmt::format("bl 0x%x", DisAsmBranchTarget(imm) + intstr_size)); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::BLX(const u32 data, const ARMv7_encoding type) + +template +void ARMv7DisAsm::SEL(const u32 op, const u32 cond) { - Write(__FUNCTION__); - //Write(fmt::format("bl 0x%x", DisAsmBranchTarget(imm) + intstr_size)); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::BX(const u32 data, const ARMv7_encoding type) + +template +void ARMv7DisAsm::SHADD16(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::SHADD8(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::CB_Z(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SHASX(const u32 op, const u32 cond) { - Write(__FUNCTION__); - //Write(fmt::format("cbz 0x%x,%s", DisAsmBranchTarget(imm) + intstr_size, g_arm_reg_name[rn])); - //Write(fmt::format("cbnz 0x%x,%s", DisAsmBranchTarget(imm) + intstr_size, g_arm_reg_name[rn])); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::SHSAX(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::SHSUB16(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::CLZ(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SHSUB8(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::CMN_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SMLA__(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::CMN_REG(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SMLAD(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::CMN_RSR(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SMLAL(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::SMLAL__(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::CMP_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SMLALD(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::CMP_REG(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SMLAW_(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::CMP_RSR(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SMLSD(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::SMLSLD(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::EOR_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SMMLA(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::EOR_REG(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SMMLS(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::EOR_RSR(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SMMUL(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::SMUAD(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::SMUL__(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::IT(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SMULL(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::SMULW_(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::LDM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SMUSD(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::LDMDA(const u32 data, const ARMv7_encoding type) + +template +void ARMv7DisAsm::SSAT(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::LDMDB(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SSAT16(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::LDMIB(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SSAX(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::SSUB16(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::LDR_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SSUB8(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::LDR_LIT(const u32 data, const ARMv7_encoding type) + +template +void ARMv7DisAsm::STM(const u32 op, const u32 cond) { - Write(__FUNCTION__); + using args = arm_code::stm; + ARG(n, op); + ARG(registers, op); + ARG(wback, op); + + write("stm%s %s%s,{%s}", fmt_cond(cond), fmt_reg(n), wback ? "!" : "", fmt_reg_list(registers)); } -void ARMv7DisAsm::LDR_REG(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::STMDA(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::STMDB(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::LDRB_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::STMIB(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::LDRB_LIT(const u32 data, const ARMv7_encoding type) + +template +void ARMv7DisAsm::STR_IMM(const u32 op, const u32 cond) { - Write(__FUNCTION__); + using args = arm_code::str_imm; + ARG(t, op); + ARG(n, op); + ARG(imm32, op); + ARG(index, op); + ARG(add, op); + ARG(wback, op); + + write("str%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_imm(n, imm32, index, add, wback)); } -void ARMv7DisAsm::LDRB_REG(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::STR_REG(const u32 op, const u32 cond) { - Write(__FUNCTION__); + using args = arm_code::str_reg; + ARG(t, op); + ARG(n, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + ARG(index, op); + ARG(add, op); + ARG(wback, op); + + write("str%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_reg(n, m, index, add, wback, shift_t, shift_n)); } -void ARMv7DisAsm::LDRD_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::STRB_IMM(const u32 op, const u32 cond) { - Write(__FUNCTION__); + using args = arm_code::strb_imm; + ARG(t, op); + ARG(n, op); + ARG(imm32, op); + ARG(index, op); + ARG(add, op); + ARG(wback, op); + + write("strb%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_imm(n, imm32, index, add, wback)); } -void ARMv7DisAsm::LDRD_LIT(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::STRB_REG(const u32 op, const u32 cond) +{ + using args = arm_code::strb_reg; + ARG(t, op); + ARG(n, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + ARG(index, op); + ARG(add, op); + ARG(wback, op); + + write("strb%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_reg(n, m, index, add, wback, shift_t, shift_n)); +} + + +template +void ARMv7DisAsm::STRD_IMM(const u32 op, const u32 cond) { - Write(__FUNCTION__); + using args = arm_code::strd_imm; + ARG(t, op); + ARG(t2, op); + ARG(n, op); + ARG(imm32, op); + ARG(index, op); + ARG(add, op); + ARG(wback, op); + + write("strd%s %s,%s,%s", fmt_cond(cond), fmt_reg(t), fmt_reg(t2), fmt_mem_imm(n, imm32, index, add, wback)); } -void ARMv7DisAsm::LDRD_REG(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::STRD_REG(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::LDRH_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::STRH_IMM(const u32 op, const u32 cond) { - Write(__FUNCTION__); + using args = arm_code::strh_imm; + ARG(t, op); + ARG(n, op); + ARG(imm32, op); + ARG(index, op); + ARG(add, op); + ARG(wback, op); + + write("strh%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_imm(n, imm32, index, add, wback)); } -void ARMv7DisAsm::LDRH_LIT(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::STRH_REG(const u32 op, const u32 cond) { - Write(__FUNCTION__); + using args = arm_code::strh_reg; + ARG(t, op); + ARG(n, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + ARG(index, op); + ARG(add, op); + ARG(wback, op); + + write("strh%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_reg(n, m, index, add, wback, shift_t, shift_n)); } -void ARMv7DisAsm::LDRH_REG(const u32 data, const ARMv7_encoding type) + +template +void ARMv7DisAsm::STREX(const u32 op, const u32 cond) { - Write(__FUNCTION__); + using args = arm_code::strex; + ARG(d, op); + ARG(t, op); + ARG(n, op); + ARG(imm32, op); + + write("strex%s %s,%s,[%s,#0x%x]", fmt_cond(cond), fmt_reg(d), fmt_reg(t), fmt_reg(n), imm32); } +template +void ARMv7DisAsm::STREXB(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::LDRSB_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::STREXD(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::LDRSB_LIT(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::STREXH(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::LDRSB_REG(const u32 data, const ARMv7_encoding type) + +template +void ARMv7DisAsm::SUB_IMM(const u32 op, const u32 cond) { - Write(__FUNCTION__); + using args = arm_code::sub_imm; + ARG(d, op); + ARG(n, op); + ARG(imm32, op); + ARG(set_flags, op, cond); + + write("sub%s%s %s,%s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), imm32); } +template +void ARMv7DisAsm::SUB_REG(const u32 op, const u32 cond) +{ + using args = arm_code::sub_reg; + ARG(d, op); + ARG(n, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + ARG(set_flags, op, cond); + + write("sub%s%s %s,%s,%s%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m), fmt_shift(shift_t, shift_n)); +} -void ARMv7DisAsm::LDRSH_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SUB_RSR(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::LDRSH_LIT(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SUB_SPI(const u32 op, const u32 cond) { - Write(__FUNCTION__); + using args = arm_code::sub_spi; + ARG(d, op); + ARG(imm32, op); + ARG(set_flags, op, cond); + + write("sub%s%s %s,sp,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), imm32); } -void ARMv7DisAsm::LDRSH_REG(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SUB_SPR(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::LSL_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SVC(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::LSL_REG(const u32 data, const ARMv7_encoding type) + +template +void ARMv7DisAsm::SXTAB(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::SXTAB16(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::LSR_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SXTAH(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::LSR_REG(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SXTB(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::SXTB16(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::MLA(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::SXTH(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::MLS(const u32 data, const ARMv7_encoding type) + +template +void ARMv7DisAsm::TB_(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::MOV_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::TEQ_IMM(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::MOV_REG(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::TEQ_REG(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::MOVT(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::TEQ_RSR(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::MRS(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::TST_IMM(const u32 op, const u32 cond) +{ + using args = arm_code::tst_imm; + ARG(n, op); + ARG(imm32, op); + + write("tst%s %s,#0x%X", fmt_cond(cond), fmt_reg(n), imm32); +} + +template +void ARMv7DisAsm::TST_REG(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::MSR_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::TST_RSR(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + + +template +void ARMv7DisAsm::UADD16(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::MSR_REG(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::UADD8(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::UASX(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::MUL(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::UBFX(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::UDIV(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::MVN_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::UHADD16(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::MVN_REG(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::UHADD8(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::MVN_RSR(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::UHASX(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::UHSAX(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::NOP(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::UHSUB16(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::UHSUB8(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::ORN_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::UMAAL(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::ORN_REG(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::UMLAL(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::UMULL(const u32 op, const u32 cond) +{ + using args = arm_code::umull; + ARG(d0, op); + ARG(d1, op); + ARG(n, op); + ARG(m, op); + ARG(set_flags, op, cond); + + write("umull%s%s %s,%s,%s,%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d0), fmt_reg(d1), fmt_reg(n), fmt_reg(m)); +} -void ARMv7DisAsm::ORR_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::UQADD16(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::ORR_REG(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::UQADD8(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::ORR_RSR(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::UQASX(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::UQSAX(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::PKH(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::UQSUB16(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::UQSUB8(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::POP(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::USAD8(const u32 op, const u32 cond) { - Write(__FUNCTION__); - //Write(fmt::format("pop {%s}", GetRegsListString(regs_list).c_str())); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::PUSH(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::USADA8(const u32 op, const u32 cond) { - Write(__FUNCTION__); - //Write(fmt::format("push {%s}", GetRegsListString(regs_list).c_str())); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::USAT(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::QADD(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::USAT16(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::QADD16(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::USAX(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::QADD8(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::USUB16(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::QASX(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::USUB8(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::QDADD(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::UXTAB(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::QDSUB(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::UXTAB16(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::QSAX(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::UXTAH(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::QSUB(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::UXTB(const u32 op, const u32 cond) { - Write(__FUNCTION__); + using args = arm_code::uxtb; + ARG(d, op); + ARG(m, op); + ARG(rotation, op); + + write("uxtb%s %s,%s%s", fmt_cond(cond), fmt_reg(d), fmt_reg(m), fmt_shift(arm_code::SRType_ROR, rotation)); } -void ARMv7DisAsm::QSUB16(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::UXTB16(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::QSUB8(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::UXTH(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::RBIT(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VABA_(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::REV(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VABD_(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::REV16(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VABD_FP(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::REVSH(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VABS(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::VAC__(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::ROR_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VADD(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::ROR_REG(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VADD_FP(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::VADDHN(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::RRX(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VADD_(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::VAND(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} + +template +void ARMv7DisAsm::VBIC_IMM(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::RSB_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VBIC_REG(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::RSB_REG(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VB__(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::RSB_RSR(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VCEQ_REG(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::VCEQ_ZERO(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::RSC_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VCGE_REG(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::RSC_REG(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VCGE_ZERO(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::RSC_RSR(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VCGT_REG(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::VCGT_ZERO(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::SADD16(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VCLE_ZERO(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SADD8(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VCLS(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SASX(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VCLT_ZERO(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::VCLZ(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::SBC_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VCMP_(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SBC_REG(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VCNT(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SBC_RSR(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VCVT_FIA(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::VCVT_FIF(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::SBFX(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VCVT_FFA(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::VCVT_FFF(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::SDIV(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VCVT_DF(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::VCVT_HFA(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::SEL(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VCVT_HFF(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::VDIV(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::SHADD16(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VDUP_S(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SHADD8(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VDUP_R(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SHASX(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VEOR(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SHSAX(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VEXT(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SHSUB16(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VHADDSUB(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SHSUB8(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VLD__MS(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::VLD1_SL(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::SMLA__(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VLD1_SAL(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SMLAD(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VLD2_SL(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SMLAL(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VLD2_SAL(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SMLAL__(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VLD3_SL(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SMLALD(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VLD3_SAL(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SMLAW_(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VLD4_SL(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SMLSD(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VLD4_SAL(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SMLSLD(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VLDM(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SMMLA(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VLDR(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SMMLS(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VMAXMIN(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SMMUL(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VMAXMIN_FP(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SMUAD(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VML__(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SMUL__(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VML__FP(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SMULL(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VML__S(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SMULW_(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VMOV_IMM(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SMUSD(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VMOV_REG(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::VMOV_RS(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::SSAT(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VMOV_SR(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SSAT16(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VMOV_RF(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SSAX(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VMOV_2RF(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SSUB16(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VMOV_2RD(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SSUB8(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VMOVL(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::VMOVN(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::STM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VMRS(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::STMDA(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VMSR(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::STMDB(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VMUL_(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::STMIB(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VMUL_FP(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::VMUL_S(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::STR_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VMVN_IMM(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::STR_REG(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VMVN_REG(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::VNEG(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::STRB_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VNM__(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::STRB_REG(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VORN_REG(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::VORR_IMM(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::STRD_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VORR_REG(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::STRD_REG(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VPADAL(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::VPADD(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::STRH_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VPADD_FP(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::STRH_REG(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VPADDL(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::VPMAXMIN(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::SUB_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VPMAXMIN_FP(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SUB_REG(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VPOP(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SUB_RSR(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VPUSH(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SUB_SPI(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VQABS(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SUB_SPR(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VQADD(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::VQDML_L(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::SVC(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VQDMULH(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::VQDMULL(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::SXTAB(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VQMOV_N(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SXTAB16(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VQNEG(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SXTAH(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VQRDMULH(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SXTB(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VQRSHL(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SXTB16(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VQRSHR_N(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::SXTH(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VQSHL_REG(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::VQSHL_IMM(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::TB_(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VQSHR_N(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::VQSUB(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::TEQ_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VRADDHN(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::TEQ_REG(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VRECPE(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::TEQ_RSR(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VRECPS(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::VREV__(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::TST_IMM(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VRHADD(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::TST_REG(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VRSHL(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::TST_RSR(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VRSHR(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } +template +void ARMv7DisAsm::VRSHRN(const u32 op, const u32 cond) +{ + write("%s<%s>", __func__, fmt_encoding()); +} -void ARMv7DisAsm::UADD16(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VRSQRTE(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::UADD8(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VRSQRTS(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::UASX(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VRSRA(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::UBFX(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VRSUBHN(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::UDIV(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VSHL_IMM(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::UHADD16(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VSHL_REG(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::UHADD8(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VSHLL(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::UHASX(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VSHR(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::UHSAX(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VSHRN(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::UHSUB16(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VSLI(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::UHSUB8(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VSQRT(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::UMAAL(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VSRA(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::UMLAL(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VSRI(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::UMULL(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VST__MS(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::UQADD16(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VST1_SL(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::UQADD8(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VST2_SL(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::UQASX(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VST3_SL(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::UQSAX(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VST4_SL(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::UQSUB16(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VSTM(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::UQSUB8(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VSTR(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::USAD8(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VSUB(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::USADA8(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VSUB_FP(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::USAT(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VSUBHN(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::USAT16(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VSUB_(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::USAX(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VSWP(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::USUB16(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VTB_(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::USUB8(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VTRN(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::UXTAB(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VTST(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::UXTAB16(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VUZP(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::UXTAH(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::VZIP(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::UXTB(const u32 data, const ARMv7_encoding type) + +template +void ARMv7DisAsm::WFE(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::UXTB16(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::WFI(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -void ARMv7DisAsm::UXTH(const u32 data, const ARMv7_encoding type) +template +void ARMv7DisAsm::YIELD(const u32 op, const u32 cond) { - Write(__FUNCTION__); + write("%s<%s>", __func__, fmt_encoding()); } -#endif + + +template void ARMv7DisAsm::HACK(const u32, const u32); +template void ARMv7DisAsm::HACK(const u32, const u32); +template void ARMv7DisAsm::ADC_IMM(const u32, const u32); +template void ARMv7DisAsm::ADC_IMM(const u32, const u32); +template void ARMv7DisAsm::ADC_REG(const u32, const u32); +template void ARMv7DisAsm::ADC_REG(const u32, const u32); +template void ARMv7DisAsm::ADC_REG(const u32, const u32); +template void ARMv7DisAsm::ADC_RSR(const u32, const u32); +template void ARMv7DisAsm::ADD_IMM(const u32, const u32); +template void ARMv7DisAsm::ADD_IMM(const u32, const u32); +template void ARMv7DisAsm::ADD_IMM(const u32, const u32); +template void ARMv7DisAsm::ADD_IMM(const u32, const u32); +template void ARMv7DisAsm::ADD_IMM(const u32, const u32); +template void ARMv7DisAsm::ADD_REG(const u32, const u32); +template void ARMv7DisAsm::ADD_REG(const u32, const u32); +template void ARMv7DisAsm::ADD_REG(const u32, const u32); +template void ARMv7DisAsm::ADD_REG(const u32, const u32); +template void ARMv7DisAsm::ADD_RSR(const u32, const u32); +template void ARMv7DisAsm::ADD_SPI(const u32, const u32); +template void ARMv7DisAsm::ADD_SPI(const u32, const u32); +template void ARMv7DisAsm::ADD_SPI(const u32, const u32); +template void ARMv7DisAsm::ADD_SPI(const u32, const u32); +template void ARMv7DisAsm::ADD_SPI(const u32, const u32); +template void ARMv7DisAsm::ADD_SPR(const u32, const u32); +template void ARMv7DisAsm::ADD_SPR(const u32, const u32); +template void ARMv7DisAsm::ADD_SPR(const u32, const u32); +template void ARMv7DisAsm::ADD_SPR(const u32, const u32); +template void ARMv7DisAsm::ADR(const u32, const u32); +template void ARMv7DisAsm::ADR(const u32, const u32); +template void ARMv7DisAsm::ADR(const u32, const u32); +template void ARMv7DisAsm::ADR(const u32, const u32); +template void ARMv7DisAsm::ADR(const u32, const u32); +template void ARMv7DisAsm::AND_IMM(const u32, const u32); +template void ARMv7DisAsm::AND_IMM(const u32, const u32); +template void ARMv7DisAsm::AND_REG(const u32, const u32); +template void ARMv7DisAsm::AND_REG(const u32, const u32); +template void ARMv7DisAsm::AND_REG(const u32, const u32); +template void ARMv7DisAsm::AND_RSR(const u32, const u32); +template void ARMv7DisAsm::ASR_IMM(const u32, const u32); +template void ARMv7DisAsm::ASR_IMM(const u32, const u32); +template void ARMv7DisAsm::ASR_IMM(const u32, const u32); +template void ARMv7DisAsm::ASR_REG(const u32, const u32); +template void ARMv7DisAsm::ASR_REG(const u32, const u32); +template void ARMv7DisAsm::ASR_REG(const u32, const u32); +template void ARMv7DisAsm::B(const u32, const u32); +template void ARMv7DisAsm::B(const u32, const u32); +template void ARMv7DisAsm::B(const u32, const u32); +template void ARMv7DisAsm::B(const u32, const u32); +template void ARMv7DisAsm::B(const u32, const u32); +template void ARMv7DisAsm::BFC(const u32, const u32); +template void ARMv7DisAsm::BFC(const u32, const u32); +template void ARMv7DisAsm::BFI(const u32, const u32); +template void ARMv7DisAsm::BFI(const u32, const u32); +template void ARMv7DisAsm::BIC_IMM(const u32, const u32); +template void ARMv7DisAsm::BIC_IMM(const u32, const u32); +template void ARMv7DisAsm::BIC_REG(const u32, const u32); +template void ARMv7DisAsm::BIC_REG(const u32, const u32); +template void ARMv7DisAsm::BIC_REG(const u32, const u32); +template void ARMv7DisAsm::BIC_RSR(const u32, const u32); +template void ARMv7DisAsm::BKPT(const u32, const u32); +template void ARMv7DisAsm::BKPT(const u32, const u32); +template void ARMv7DisAsm::BL(const u32, const u32); +template void ARMv7DisAsm::BL(const u32, const u32); +template void ARMv7DisAsm::BL(const u32, const u32); +template void ARMv7DisAsm::BL(const u32, const u32); +template void ARMv7DisAsm::BLX(const u32, const u32); +template void ARMv7DisAsm::BLX(const u32, const u32); +template void ARMv7DisAsm::BX(const u32, const u32); +template void ARMv7DisAsm::BX(const u32, const u32); +template void ARMv7DisAsm::CB_Z(const u32, const u32); +template void ARMv7DisAsm::CLZ(const u32, const u32); +template void ARMv7DisAsm::CLZ(const u32, const u32); +template void ARMv7DisAsm::CMN_IMM(const u32, const u32); +template void ARMv7DisAsm::CMN_IMM(const u32, const u32); +template void ARMv7DisAsm::CMN_REG(const u32, const u32); +template void ARMv7DisAsm::CMN_REG(const u32, const u32); +template void ARMv7DisAsm::CMN_REG(const u32, const u32); +template void ARMv7DisAsm::CMN_RSR(const u32, const u32); +template void ARMv7DisAsm::CMP_IMM(const u32, const u32); +template void ARMv7DisAsm::CMP_IMM(const u32, const u32); +template void ARMv7DisAsm::CMP_IMM(const u32, const u32); +template void ARMv7DisAsm::CMP_REG(const u32, const u32); +template void ARMv7DisAsm::CMP_REG(const u32, const u32); +template void ARMv7DisAsm::CMP_REG(const u32, const u32); +template void ARMv7DisAsm::CMP_REG(const u32, const u32); +template void ARMv7DisAsm::CMP_RSR(const u32, const u32); +template void ARMv7DisAsm::DBG(const u32, const u32); +template void ARMv7DisAsm::DBG(const u32, const u32); +template void ARMv7DisAsm::DMB(const u32, const u32); +template void ARMv7DisAsm::DMB(const u32, const u32); +template void ARMv7DisAsm::DSB(const u32, const u32); +template void ARMv7DisAsm::DSB(const u32, const u32); +template void ARMv7DisAsm::EOR_IMM(const u32, const u32); +template void ARMv7DisAsm::EOR_IMM(const u32, const u32); +template void ARMv7DisAsm::EOR_REG(const u32, const u32); +template void ARMv7DisAsm::EOR_REG(const u32, const u32); +template void ARMv7DisAsm::EOR_REG(const u32, const u32); +template void ARMv7DisAsm::EOR_RSR(const u32, const u32); +template void ARMv7DisAsm::IT(const u32, const u32); +template void ARMv7DisAsm::LDM(const u32, const u32); +template void ARMv7DisAsm::LDM(const u32, const u32); +template void ARMv7DisAsm::LDM(const u32, const u32); +template void ARMv7DisAsm::LDMDA(const u32, const u32); +template void ARMv7DisAsm::LDMDB(const u32, const u32); +template void ARMv7DisAsm::LDMDB(const u32, const u32); +template void ARMv7DisAsm::LDMIB(const u32, const u32); +template void ARMv7DisAsm::LDR_IMM(const u32, const u32); +template void ARMv7DisAsm::LDR_IMM(const u32, const u32); +template void ARMv7DisAsm::LDR_IMM(const u32, const u32); +template void ARMv7DisAsm::LDR_IMM(const u32, const u32); +template void ARMv7DisAsm::LDR_IMM(const u32, const u32); +template void ARMv7DisAsm::LDR_LIT(const u32, const u32); +template void ARMv7DisAsm::LDR_LIT(const u32, const u32); +template void ARMv7DisAsm::LDR_LIT(const u32, const u32); +template void ARMv7DisAsm::LDR_REG(const u32, const u32); +template void ARMv7DisAsm::LDR_REG(const u32, const u32); +template void ARMv7DisAsm::LDR_REG(const u32, const u32); +template void ARMv7DisAsm::LDRB_IMM(const u32, const u32); +template void ARMv7DisAsm::LDRB_IMM(const u32, const u32); +template void ARMv7DisAsm::LDRB_IMM(const u32, const u32); +template void ARMv7DisAsm::LDRB_IMM(const u32, const u32); +template void ARMv7DisAsm::LDRB_LIT(const u32, const u32); +template void ARMv7DisAsm::LDRB_LIT(const u32, const u32); +template void ARMv7DisAsm::LDRB_REG(const u32, const u32); +template void ARMv7DisAsm::LDRB_REG(const u32, const u32); +template void ARMv7DisAsm::LDRB_REG(const u32, const u32); +template void ARMv7DisAsm::LDRD_IMM(const u32, const u32); +template void ARMv7DisAsm::LDRD_IMM(const u32, const u32); +template void ARMv7DisAsm::LDRD_LIT(const u32, const u32); +template void ARMv7DisAsm::LDRD_LIT(const u32, const u32); +template void ARMv7DisAsm::LDRD_REG(const u32, const u32); +template void ARMv7DisAsm::LDREX(const u32, const u32); +template void ARMv7DisAsm::LDREX(const u32, const u32); +template void ARMv7DisAsm::LDREXB(const u32, const u32); +template void ARMv7DisAsm::LDREXB(const u32, const u32); +template void ARMv7DisAsm::LDREXD(const u32, const u32); +template void ARMv7DisAsm::LDREXD(const u32, const u32); +template void ARMv7DisAsm::LDREXH(const u32, const u32); +template void ARMv7DisAsm::LDREXH(const u32, const u32); +template void ARMv7DisAsm::LDRH_IMM(const u32, const u32); +template void ARMv7DisAsm::LDRH_IMM(const u32, const u32); +template void ARMv7DisAsm::LDRH_IMM(const u32, const u32); +template void ARMv7DisAsm::LDRH_IMM(const u32, const u32); +template void ARMv7DisAsm::LDRH_LIT(const u32, const u32); +template void ARMv7DisAsm::LDRH_LIT(const u32, const u32); +template void ARMv7DisAsm::LDRH_REG(const u32, const u32); +template void ARMv7DisAsm::LDRH_REG(const u32, const u32); +template void ARMv7DisAsm::LDRH_REG(const u32, const u32); +template void ARMv7DisAsm::LDRSB_IMM(const u32, const u32); +template void ARMv7DisAsm::LDRSB_IMM(const u32, const u32); +template void ARMv7DisAsm::LDRSB_IMM(const u32, const u32); +template void ARMv7DisAsm::LDRSB_LIT(const u32, const u32); +template void ARMv7DisAsm::LDRSB_LIT(const u32, const u32); +template void ARMv7DisAsm::LDRSB_REG(const u32, const u32); +template void ARMv7DisAsm::LDRSB_REG(const u32, const u32); +template void ARMv7DisAsm::LDRSB_REG(const u32, const u32); +template void ARMv7DisAsm::LDRSH_IMM(const u32, const u32); +template void ARMv7DisAsm::LDRSH_IMM(const u32, const u32); +template void ARMv7DisAsm::LDRSH_IMM(const u32, const u32); +template void ARMv7DisAsm::LDRSH_LIT(const u32, const u32); +template void ARMv7DisAsm::LDRSH_LIT(const u32, const u32); +template void ARMv7DisAsm::LDRSH_REG(const u32, const u32); +template void ARMv7DisAsm::LDRSH_REG(const u32, const u32); +template void ARMv7DisAsm::LDRSH_REG(const u32, const u32); +template void ARMv7DisAsm::LSL_IMM(const u32, const u32); +template void ARMv7DisAsm::LSL_IMM(const u32, const u32); +template void ARMv7DisAsm::LSL_IMM(const u32, const u32); +template void ARMv7DisAsm::LSL_REG(const u32, const u32); +template void ARMv7DisAsm::LSL_REG(const u32, const u32); +template void ARMv7DisAsm::LSL_REG(const u32, const u32); +template void ARMv7DisAsm::LSR_IMM(const u32, const u32); +template void ARMv7DisAsm::LSR_IMM(const u32, const u32); +template void ARMv7DisAsm::LSR_IMM(const u32, const u32); +template void ARMv7DisAsm::LSR_REG(const u32, const u32); +template void ARMv7DisAsm::LSR_REG(const u32, const u32); +template void ARMv7DisAsm::LSR_REG(const u32, const u32); +template void ARMv7DisAsm::MLA(const u32, const u32); +template void ARMv7DisAsm::MLA(const u32, const u32); +template void ARMv7DisAsm::MLS(const u32, const u32); +template void ARMv7DisAsm::MLS(const u32, const u32); +template void ARMv7DisAsm::MOV_IMM(const u32, const u32); +template void ARMv7DisAsm::MOV_IMM(const u32, const u32); +template void ARMv7DisAsm::MOV_IMM(const u32, const u32); +template void ARMv7DisAsm::MOV_IMM(const u32, const u32); +template void ARMv7DisAsm::MOV_IMM(const u32, const u32); +template void ARMv7DisAsm::MOV_REG(const u32, const u32); +template void ARMv7DisAsm::MOV_REG(const u32, const u32); +template void ARMv7DisAsm::MOV_REG(const u32, const u32); +template void ARMv7DisAsm::MOV_REG(const u32, const u32); +template void ARMv7DisAsm::MOVT(const u32, const u32); +template void ARMv7DisAsm::MOVT(const u32, const u32); +template void ARMv7DisAsm::MRC_(const u32, const u32); +template void ARMv7DisAsm::MRC_(const u32, const u32); +template void ARMv7DisAsm::MRC_(const u32, const u32); +template void ARMv7DisAsm::MRC_(const u32, const u32); +template void ARMv7DisAsm::MRS(const u32, const u32); +template void ARMv7DisAsm::MRS(const u32, const u32); +template void ARMv7DisAsm::MSR_IMM(const u32, const u32); +template void ARMv7DisAsm::MSR_REG(const u32, const u32); +template void ARMv7DisAsm::MSR_REG(const u32, const u32); +template void ARMv7DisAsm::MUL(const u32, const u32); +template void ARMv7DisAsm::MUL(const u32, const u32); +template void ARMv7DisAsm::MUL(const u32, const u32); +template void ARMv7DisAsm::MVN_IMM(const u32, const u32); +template void ARMv7DisAsm::MVN_IMM(const u32, const u32); +template void ARMv7DisAsm::MVN_REG(const u32, const u32); +template void ARMv7DisAsm::MVN_REG(const u32, const u32); +template void ARMv7DisAsm::MVN_REG(const u32, const u32); +template void ARMv7DisAsm::MVN_RSR(const u32, const u32); +template void ARMv7DisAsm::NOP(const u32, const u32); +template void ARMv7DisAsm::NOP(const u32, const u32); +template void ARMv7DisAsm::NOP(const u32, const u32); +template void ARMv7DisAsm::ORN_IMM(const u32, const u32); +template void ARMv7DisAsm::ORN_REG(const u32, const u32); +template void ARMv7DisAsm::ORR_IMM(const u32, const u32); +template void ARMv7DisAsm::ORR_IMM(const u32, const u32); +template void ARMv7DisAsm::ORR_REG(const u32, const u32); +template void ARMv7DisAsm::ORR_REG(const u32, const u32); +template void ARMv7DisAsm::ORR_REG(const u32, const u32); +template void ARMv7DisAsm::ORR_RSR(const u32, const u32); +template void ARMv7DisAsm::PKH(const u32, const u32); +template void ARMv7DisAsm::PKH(const u32, const u32); +template void ARMv7DisAsm::POP(const u32, const u32); +template void ARMv7DisAsm::POP(const u32, const u32); +template void ARMv7DisAsm::POP(const u32, const u32); +template void ARMv7DisAsm::POP(const u32, const u32); +template void ARMv7DisAsm::POP(const u32, const u32); +template void ARMv7DisAsm::PUSH(const u32, const u32); +template void ARMv7DisAsm::PUSH(const u32, const u32); +template void ARMv7DisAsm::PUSH(const u32, const u32); +template void ARMv7DisAsm::PUSH(const u32, const u32); +template void ARMv7DisAsm::PUSH(const u32, const u32); +template void ARMv7DisAsm::QADD(const u32, const u32); +template void ARMv7DisAsm::QADD(const u32, const u32); +template void ARMv7DisAsm::QADD16(const u32, const u32); +template void ARMv7DisAsm::QADD16(const u32, const u32); +template void ARMv7DisAsm::QADD8(const u32, const u32); +template void ARMv7DisAsm::QADD8(const u32, const u32); +template void ARMv7DisAsm::QASX(const u32, const u32); +template void ARMv7DisAsm::QASX(const u32, const u32); +template void ARMv7DisAsm::QDADD(const u32, const u32); +template void ARMv7DisAsm::QDADD(const u32, const u32); +template void ARMv7DisAsm::QDSUB(const u32, const u32); +template void ARMv7DisAsm::QDSUB(const u32, const u32); +template void ARMv7DisAsm::QSAX(const u32, const u32); +template void ARMv7DisAsm::QSAX(const u32, const u32); +template void ARMv7DisAsm::QSUB(const u32, const u32); +template void ARMv7DisAsm::QSUB(const u32, const u32); +template void ARMv7DisAsm::QSUB16(const u32, const u32); +template void ARMv7DisAsm::QSUB16(const u32, const u32); +template void ARMv7DisAsm::QSUB8(const u32, const u32); +template void ARMv7DisAsm::QSUB8(const u32, const u32); +template void ARMv7DisAsm::RBIT(const u32, const u32); +template void ARMv7DisAsm::RBIT(const u32, const u32); +template void ARMv7DisAsm::REV(const u32, const u32); +template void ARMv7DisAsm::REV(const u32, const u32); +template void ARMv7DisAsm::REV(const u32, const u32); +template void ARMv7DisAsm::REV16(const u32, const u32); +template void ARMv7DisAsm::REV16(const u32, const u32); +template void ARMv7DisAsm::REV16(const u32, const u32); +template void ARMv7DisAsm::REVSH(const u32, const u32); +template void ARMv7DisAsm::REVSH(const u32, const u32); +template void ARMv7DisAsm::REVSH(const u32, const u32); +template void ARMv7DisAsm::ROR_IMM(const u32, const u32); +template void ARMv7DisAsm::ROR_IMM(const u32, const u32); +template void ARMv7DisAsm::ROR_REG(const u32, const u32); +template void ARMv7DisAsm::ROR_REG(const u32, const u32); +template void ARMv7DisAsm::ROR_REG(const u32, const u32); +template void ARMv7DisAsm::RRX(const u32, const u32); +template void ARMv7DisAsm::RRX(const u32, const u32); +template void ARMv7DisAsm::RSB_IMM(const u32, const u32); +template void ARMv7DisAsm::RSB_IMM(const u32, const u32); +template void ARMv7DisAsm::RSB_IMM(const u32, const u32); +template void ARMv7DisAsm::RSB_REG(const u32, const u32); +template void ARMv7DisAsm::RSB_REG(const u32, const u32); +template void ARMv7DisAsm::RSB_RSR(const u32, const u32); +template void ARMv7DisAsm::RSC_IMM(const u32, const u32); +template void ARMv7DisAsm::RSC_REG(const u32, const u32); +template void ARMv7DisAsm::RSC_RSR(const u32, const u32); +template void ARMv7DisAsm::SADD16(const u32, const u32); +template void ARMv7DisAsm::SADD16(const u32, const u32); +template void ARMv7DisAsm::SADD8(const u32, const u32); +template void ARMv7DisAsm::SADD8(const u32, const u32); +template void ARMv7DisAsm::SASX(const u32, const u32); +template void ARMv7DisAsm::SASX(const u32, const u32); +template void ARMv7DisAsm::SBC_IMM(const u32, const u32); +template void ARMv7DisAsm::SBC_IMM(const u32, const u32); +template void ARMv7DisAsm::SBC_REG(const u32, const u32); +template void ARMv7DisAsm::SBC_REG(const u32, const u32); +template void ARMv7DisAsm::SBC_REG(const u32, const u32); +template void ARMv7DisAsm::SBC_RSR(const u32, const u32); +template void ARMv7DisAsm::SBFX(const u32, const u32); +template void ARMv7DisAsm::SBFX(const u32, const u32); +template void ARMv7DisAsm::SDIV(const u32, const u32); +template void ARMv7DisAsm::SEL(const u32, const u32); +template void ARMv7DisAsm::SEL(const u32, const u32); +template void ARMv7DisAsm::SHADD16(const u32, const u32); +template void ARMv7DisAsm::SHADD16(const u32, const u32); +template void ARMv7DisAsm::SHADD8(const u32, const u32); +template void ARMv7DisAsm::SHADD8(const u32, const u32); +template void ARMv7DisAsm::SHASX(const u32, const u32); +template void ARMv7DisAsm::SHASX(const u32, const u32); +template void ARMv7DisAsm::SHSAX(const u32, const u32); +template void ARMv7DisAsm::SHSAX(const u32, const u32); +template void ARMv7DisAsm::SHSUB16(const u32, const u32); +template void ARMv7DisAsm::SHSUB16(const u32, const u32); +template void ARMv7DisAsm::SHSUB8(const u32, const u32); +template void ARMv7DisAsm::SHSUB8(const u32, const u32); +template void ARMv7DisAsm::SMLA__(const u32, const u32); +template void ARMv7DisAsm::SMLA__(const u32, const u32); +template void ARMv7DisAsm::SMLAD(const u32, const u32); +template void ARMv7DisAsm::SMLAD(const u32, const u32); +template void ARMv7DisAsm::SMLAL(const u32, const u32); +template void ARMv7DisAsm::SMLAL(const u32, const u32); +template void ARMv7DisAsm::SMLAL__(const u32, const u32); +template void ARMv7DisAsm::SMLAL__(const u32, const u32); +template void ARMv7DisAsm::SMLALD(const u32, const u32); +template void ARMv7DisAsm::SMLALD(const u32, const u32); +template void ARMv7DisAsm::SMLAW_(const u32, const u32); +template void ARMv7DisAsm::SMLAW_(const u32, const u32); +template void ARMv7DisAsm::SMLSD(const u32, const u32); +template void ARMv7DisAsm::SMLSD(const u32, const u32); +template void ARMv7DisAsm::SMLSLD(const u32, const u32); +template void ARMv7DisAsm::SMLSLD(const u32, const u32); +template void ARMv7DisAsm::SMMLA(const u32, const u32); +template void ARMv7DisAsm::SMMLA(const u32, const u32); +template void ARMv7DisAsm::SMMLS(const u32, const u32); +template void ARMv7DisAsm::SMMLS(const u32, const u32); +template void ARMv7DisAsm::SMMUL(const u32, const u32); +template void ARMv7DisAsm::SMMUL(const u32, const u32); +template void ARMv7DisAsm::SMUAD(const u32, const u32); +template void ARMv7DisAsm::SMUAD(const u32, const u32); +template void ARMv7DisAsm::SMUL__(const u32, const u32); +template void ARMv7DisAsm::SMUL__(const u32, const u32); +template void ARMv7DisAsm::SMULL(const u32, const u32); +template void ARMv7DisAsm::SMULL(const u32, const u32); +template void ARMv7DisAsm::SMULW_(const u32, const u32); +template void ARMv7DisAsm::SMULW_(const u32, const u32); +template void ARMv7DisAsm::SMUSD(const u32, const u32); +template void ARMv7DisAsm::SMUSD(const u32, const u32); +template void ARMv7DisAsm::SSAT(const u32, const u32); +template void ARMv7DisAsm::SSAT(const u32, const u32); +template void ARMv7DisAsm::SSAT16(const u32, const u32); +template void ARMv7DisAsm::SSAT16(const u32, const u32); +template void ARMv7DisAsm::SSAX(const u32, const u32); +template void ARMv7DisAsm::SSAX(const u32, const u32); +template void ARMv7DisAsm::SSUB16(const u32, const u32); +template void ARMv7DisAsm::SSUB16(const u32, const u32); +template void ARMv7DisAsm::SSUB8(const u32, const u32); +template void ARMv7DisAsm::SSUB8(const u32, const u32); +template void ARMv7DisAsm::STM(const u32, const u32); +template void ARMv7DisAsm::STM(const u32, const u32); +template void ARMv7DisAsm::STM(const u32, const u32); +template void ARMv7DisAsm::STMDA(const u32, const u32); +template void ARMv7DisAsm::STMDB(const u32, const u32); +template void ARMv7DisAsm::STMDB(const u32, const u32); +template void ARMv7DisAsm::STMIB(const u32, const u32); +template void ARMv7DisAsm::STR_IMM(const u32, const u32); +template void ARMv7DisAsm::STR_IMM(const u32, const u32); +template void ARMv7DisAsm::STR_IMM(const u32, const u32); +template void ARMv7DisAsm::STR_IMM(const u32, const u32); +template void ARMv7DisAsm::STR_IMM(const u32, const u32); +template void ARMv7DisAsm::STR_REG(const u32, const u32); +template void ARMv7DisAsm::STR_REG(const u32, const u32); +template void ARMv7DisAsm::STR_REG(const u32, const u32); +template void ARMv7DisAsm::STRB_IMM(const u32, const u32); +template void ARMv7DisAsm::STRB_IMM(const u32, const u32); +template void ARMv7DisAsm::STRB_IMM(const u32, const u32); +template void ARMv7DisAsm::STRB_IMM(const u32, const u32); +template void ARMv7DisAsm::STRB_REG(const u32, const u32); +template void ARMv7DisAsm::STRB_REG(const u32, const u32); +template void ARMv7DisAsm::STRB_REG(const u32, const u32); +template void ARMv7DisAsm::STRD_IMM(const u32, const u32); +template void ARMv7DisAsm::STRD_IMM(const u32, const u32); +template void ARMv7DisAsm::STRD_REG(const u32, const u32); +template void ARMv7DisAsm::STREX(const u32, const u32); +template void ARMv7DisAsm::STREX(const u32, const u32); +template void ARMv7DisAsm::STREXB(const u32, const u32); +template void ARMv7DisAsm::STREXB(const u32, const u32); +template void ARMv7DisAsm::STREXD(const u32, const u32); +template void ARMv7DisAsm::STREXD(const u32, const u32); +template void ARMv7DisAsm::STREXH(const u32, const u32); +template void ARMv7DisAsm::STREXH(const u32, const u32); +template void ARMv7DisAsm::STRH_IMM(const u32, const u32); +template void ARMv7DisAsm::STRH_IMM(const u32, const u32); +template void ARMv7DisAsm::STRH_IMM(const u32, const u32); +template void ARMv7DisAsm::STRH_IMM(const u32, const u32); +template void ARMv7DisAsm::STRH_REG(const u32, const u32); +template void ARMv7DisAsm::STRH_REG(const u32, const u32); +template void ARMv7DisAsm::STRH_REG(const u32, const u32); +template void ARMv7DisAsm::SUB_IMM(const u32, const u32); +template void ARMv7DisAsm::SUB_IMM(const u32, const u32); +template void ARMv7DisAsm::SUB_IMM(const u32, const u32); +template void ARMv7DisAsm::SUB_IMM(const u32, const u32); +template void ARMv7DisAsm::SUB_IMM(const u32, const u32); +template void ARMv7DisAsm::SUB_REG(const u32, const u32); +template void ARMv7DisAsm::SUB_REG(const u32, const u32); +template void ARMv7DisAsm::SUB_REG(const u32, const u32); +template void ARMv7DisAsm::SUB_RSR(const u32, const u32); +template void ARMv7DisAsm::SUB_SPI(const u32, const u32); +template void ARMv7DisAsm::SUB_SPI(const u32, const u32); +template void ARMv7DisAsm::SUB_SPI(const u32, const u32); +template void ARMv7DisAsm::SUB_SPI(const u32, const u32); +template void ARMv7DisAsm::SUB_SPR(const u32, const u32); +template void ARMv7DisAsm::SUB_SPR(const u32, const u32); +template void ARMv7DisAsm::SVC(const u32, const u32); +template void ARMv7DisAsm::SVC(const u32, const u32); +template void ARMv7DisAsm::SXTAB(const u32, const u32); +template void ARMv7DisAsm::SXTAB(const u32, const u32); +template void ARMv7DisAsm::SXTAB16(const u32, const u32); +template void ARMv7DisAsm::SXTAB16(const u32, const u32); +template void ARMv7DisAsm::SXTAH(const u32, const u32); +template void ARMv7DisAsm::SXTAH(const u32, const u32); +template void ARMv7DisAsm::SXTB(const u32, const u32); +template void ARMv7DisAsm::SXTB(const u32, const u32); +template void ARMv7DisAsm::SXTB(const u32, const u32); +template void ARMv7DisAsm::SXTB16(const u32, const u32); +template void ARMv7DisAsm::SXTB16(const u32, const u32); +template void ARMv7DisAsm::SXTH(const u32, const u32); +template void ARMv7DisAsm::SXTH(const u32, const u32); +template void ARMv7DisAsm::SXTH(const u32, const u32); +template void ARMv7DisAsm::TB_(const u32, const u32); +template void ARMv7DisAsm::TEQ_IMM(const u32, const u32); +template void ARMv7DisAsm::TEQ_IMM(const u32, const u32); +template void ARMv7DisAsm::TEQ_REG(const u32, const u32); +template void ARMv7DisAsm::TEQ_REG(const u32, const u32); +template void ARMv7DisAsm::TEQ_RSR(const u32, const u32); +template void ARMv7DisAsm::TST_IMM(const u32, const u32); +template void ARMv7DisAsm::TST_IMM(const u32, const u32); +template void ARMv7DisAsm::TST_REG(const u32, const u32); +template void ARMv7DisAsm::TST_REG(const u32, const u32); +template void ARMv7DisAsm::TST_REG(const u32, const u32); +template void ARMv7DisAsm::TST_RSR(const u32, const u32); +template void ARMv7DisAsm::UADD16(const u32, const u32); +template void ARMv7DisAsm::UADD16(const u32, const u32); +template void ARMv7DisAsm::UADD8(const u32, const u32); +template void ARMv7DisAsm::UADD8(const u32, const u32); +template void ARMv7DisAsm::UASX(const u32, const u32); +template void ARMv7DisAsm::UASX(const u32, const u32); +template void ARMv7DisAsm::UBFX(const u32, const u32); +template void ARMv7DisAsm::UBFX(const u32, const u32); +template void ARMv7DisAsm::UDIV(const u32, const u32); +template void ARMv7DisAsm::UHADD16(const u32, const u32); +template void ARMv7DisAsm::UHADD16(const u32, const u32); +template void ARMv7DisAsm::UHADD8(const u32, const u32); +template void ARMv7DisAsm::UHADD8(const u32, const u32); +template void ARMv7DisAsm::UHASX(const u32, const u32); +template void ARMv7DisAsm::UHASX(const u32, const u32); +template void ARMv7DisAsm::UHSAX(const u32, const u32); +template void ARMv7DisAsm::UHSAX(const u32, const u32); +template void ARMv7DisAsm::UHSUB16(const u32, const u32); +template void ARMv7DisAsm::UHSUB16(const u32, const u32); +template void ARMv7DisAsm::UHSUB8(const u32, const u32); +template void ARMv7DisAsm::UHSUB8(const u32, const u32); +template void ARMv7DisAsm::UMAAL(const u32, const u32); +template void ARMv7DisAsm::UMAAL(const u32, const u32); +template void ARMv7DisAsm::UMLAL(const u32, const u32); +template void ARMv7DisAsm::UMLAL(const u32, const u32); +template void ARMv7DisAsm::UMULL(const u32, const u32); +template void ARMv7DisAsm::UMULL(const u32, const u32); +template void ARMv7DisAsm::UQADD16(const u32, const u32); +template void ARMv7DisAsm::UQADD16(const u32, const u32); +template void ARMv7DisAsm::UQADD8(const u32, const u32); +template void ARMv7DisAsm::UQADD8(const u32, const u32); +template void ARMv7DisAsm::UQASX(const u32, const u32); +template void ARMv7DisAsm::UQASX(const u32, const u32); +template void ARMv7DisAsm::UQSAX(const u32, const u32); +template void ARMv7DisAsm::UQSAX(const u32, const u32); +template void ARMv7DisAsm::UQSUB16(const u32, const u32); +template void ARMv7DisAsm::UQSUB16(const u32, const u32); +template void ARMv7DisAsm::UQSUB8(const u32, const u32); +template void ARMv7DisAsm::UQSUB8(const u32, const u32); +template void ARMv7DisAsm::USAD8(const u32, const u32); +template void ARMv7DisAsm::USAD8(const u32, const u32); +template void ARMv7DisAsm::USADA8(const u32, const u32); +template void ARMv7DisAsm::USADA8(const u32, const u32); +template void ARMv7DisAsm::USAT(const u32, const u32); +template void ARMv7DisAsm::USAT(const u32, const u32); +template void ARMv7DisAsm::USAT16(const u32, const u32); +template void ARMv7DisAsm::USAT16(const u32, const u32); +template void ARMv7DisAsm::USAX(const u32, const u32); +template void ARMv7DisAsm::USAX(const u32, const u32); +template void ARMv7DisAsm::USUB16(const u32, const u32); +template void ARMv7DisAsm::USUB16(const u32, const u32); +template void ARMv7DisAsm::USUB8(const u32, const u32); +template void ARMv7DisAsm::USUB8(const u32, const u32); +template void ARMv7DisAsm::UXTAB(const u32, const u32); +template void ARMv7DisAsm::UXTAB(const u32, const u32); +template void ARMv7DisAsm::UXTAB16(const u32, const u32); +template void ARMv7DisAsm::UXTAB16(const u32, const u32); +template void ARMv7DisAsm::UXTAH(const u32, const u32); +template void ARMv7DisAsm::UXTAH(const u32, const u32); +template void ARMv7DisAsm::UXTB(const u32, const u32); +template void ARMv7DisAsm::UXTB(const u32, const u32); +template void ARMv7DisAsm::UXTB(const u32, const u32); +template void ARMv7DisAsm::UXTB16(const u32, const u32); +template void ARMv7DisAsm::UXTB16(const u32, const u32); +template void ARMv7DisAsm::UXTH(const u32, const u32); +template void ARMv7DisAsm::UXTH(const u32, const u32); +template void ARMv7DisAsm::UXTH(const u32, const u32); +template void ARMv7DisAsm::VABA_(const u32, const u32); +template void ARMv7DisAsm::VABA_(const u32, const u32); +template void ARMv7DisAsm::VABA_(const u32, const u32); +template void ARMv7DisAsm::VABA_(const u32, const u32); +template void ARMv7DisAsm::VABD_(const u32, const u32); +template void ARMv7DisAsm::VABD_(const u32, const u32); +template void ARMv7DisAsm::VABD_(const u32, const u32); +template void ARMv7DisAsm::VABD_(const u32, const u32); +template void ARMv7DisAsm::VABD_FP(const u32, const u32); +template void ARMv7DisAsm::VABD_FP(const u32, const u32); +template void ARMv7DisAsm::VABS(const u32, const u32); +template void ARMv7DisAsm::VABS(const u32, const u32); +template void ARMv7DisAsm::VABS(const u32, const u32); +template void ARMv7DisAsm::VABS(const u32, const u32); +template void ARMv7DisAsm::VAC__(const u32, const u32); +template void ARMv7DisAsm::VAC__(const u32, const u32); +template void ARMv7DisAsm::VADD(const u32, const u32); +template void ARMv7DisAsm::VADD(const u32, const u32); +template void ARMv7DisAsm::VADD_FP(const u32, const u32); +template void ARMv7DisAsm::VADD_FP(const u32, const u32); +template void ARMv7DisAsm::VADD_FP(const u32, const u32); +template void ARMv7DisAsm::VADD_FP(const u32, const u32); +template void ARMv7DisAsm::VADDHN(const u32, const u32); +template void ARMv7DisAsm::VADDHN(const u32, const u32); +template void ARMv7DisAsm::VADD_(const u32, const u32); +template void ARMv7DisAsm::VADD_(const u32, const u32); +template void ARMv7DisAsm::VAND(const u32, const u32); +template void ARMv7DisAsm::VAND(const u32, const u32); +template void ARMv7DisAsm::VBIC_IMM(const u32, const u32); +template void ARMv7DisAsm::VBIC_IMM(const u32, const u32); +template void ARMv7DisAsm::VBIC_REG(const u32, const u32); +template void ARMv7DisAsm::VBIC_REG(const u32, const u32); +template void ARMv7DisAsm::VB__(const u32, const u32); +template void ARMv7DisAsm::VB__(const u32, const u32); +template void ARMv7DisAsm::VCEQ_REG(const u32, const u32); +template void ARMv7DisAsm::VCEQ_REG(const u32, const u32); +template void ARMv7DisAsm::VCEQ_REG(const u32, const u32); +template void ARMv7DisAsm::VCEQ_REG(const u32, const u32); +template void ARMv7DisAsm::VCEQ_ZERO(const u32, const u32); +template void ARMv7DisAsm::VCEQ_ZERO(const u32, const u32); +template void ARMv7DisAsm::VCGE_REG(const u32, const u32); +template void ARMv7DisAsm::VCGE_REG(const u32, const u32); +template void ARMv7DisAsm::VCGE_REG(const u32, const u32); +template void ARMv7DisAsm::VCGE_REG(const u32, const u32); +template void ARMv7DisAsm::VCGE_ZERO(const u32, const u32); +template void ARMv7DisAsm::VCGE_ZERO(const u32, const u32); +template void ARMv7DisAsm::VCGT_REG(const u32, const u32); +template void ARMv7DisAsm::VCGT_REG(const u32, const u32); +template void ARMv7DisAsm::VCGT_REG(const u32, const u32); +template void ARMv7DisAsm::VCGT_REG(const u32, const u32); +template void ARMv7DisAsm::VCGT_ZERO(const u32, const u32); +template void ARMv7DisAsm::VCGT_ZERO(const u32, const u32); +template void ARMv7DisAsm::VCLE_ZERO(const u32, const u32); +template void ARMv7DisAsm::VCLE_ZERO(const u32, const u32); +template void ARMv7DisAsm::VCLS(const u32, const u32); +template void ARMv7DisAsm::VCLS(const u32, const u32); +template void ARMv7DisAsm::VCLT_ZERO(const u32, const u32); +template void ARMv7DisAsm::VCLT_ZERO(const u32, const u32); +template void ARMv7DisAsm::VCLZ(const u32, const u32); +template void ARMv7DisAsm::VCLZ(const u32, const u32); +template void ARMv7DisAsm::VCMP_(const u32, const u32); +template void ARMv7DisAsm::VCMP_(const u32, const u32); +template void ARMv7DisAsm::VCMP_(const u32, const u32); +template void ARMv7DisAsm::VCMP_(const u32, const u32); +template void ARMv7DisAsm::VCNT(const u32, const u32); +template void ARMv7DisAsm::VCNT(const u32, const u32); +template void ARMv7DisAsm::VCVT_FIA(const u32, const u32); +template void ARMv7DisAsm::VCVT_FIA(const u32, const u32); +template void ARMv7DisAsm::VCVT_FIF(const u32, const u32); +template void ARMv7DisAsm::VCVT_FIF(const u32, const u32); +template void ARMv7DisAsm::VCVT_FFA(const u32, const u32); +template void ARMv7DisAsm::VCVT_FFA(const u32, const u32); +template void ARMv7DisAsm::VCVT_FFF(const u32, const u32); +template void ARMv7DisAsm::VCVT_FFF(const u32, const u32); +template void ARMv7DisAsm::VCVT_DF(const u32, const u32); +template void ARMv7DisAsm::VCVT_DF(const u32, const u32); +template void ARMv7DisAsm::VCVT_HFA(const u32, const u32); +template void ARMv7DisAsm::VCVT_HFA(const u32, const u32); +template void ARMv7DisAsm::VCVT_HFF(const u32, const u32); +template void ARMv7DisAsm::VCVT_HFF(const u32, const u32); +template void ARMv7DisAsm::VDIV(const u32, const u32); +template void ARMv7DisAsm::VDIV(const u32, const u32); +template void ARMv7DisAsm::VDUP_S(const u32, const u32); +template void ARMv7DisAsm::VDUP_S(const u32, const u32); +template void ARMv7DisAsm::VDUP_R(const u32, const u32); +template void ARMv7DisAsm::VDUP_R(const u32, const u32); +template void ARMv7DisAsm::VEOR(const u32, const u32); +template void ARMv7DisAsm::VEOR(const u32, const u32); +template void ARMv7DisAsm::VEXT(const u32, const u32); +template void ARMv7DisAsm::VEXT(const u32, const u32); +template void ARMv7DisAsm::VHADDSUB(const u32, const u32); +template void ARMv7DisAsm::VHADDSUB(const u32, const u32); +template void ARMv7DisAsm::VLD__MS(const u32, const u32); +template void ARMv7DisAsm::VLD__MS(const u32, const u32); +template void ARMv7DisAsm::VLD1_SAL(const u32, const u32); +template void ARMv7DisAsm::VLD1_SAL(const u32, const u32); +template void ARMv7DisAsm::VLD1_SL(const u32, const u32); +template void ARMv7DisAsm::VLD1_SL(const u32, const u32); +template void ARMv7DisAsm::VLD2_SAL(const u32, const u32); +template void ARMv7DisAsm::VLD2_SAL(const u32, const u32); +template void ARMv7DisAsm::VLD2_SL(const u32, const u32); +template void ARMv7DisAsm::VLD2_SL(const u32, const u32); +template void ARMv7DisAsm::VLD3_SAL(const u32, const u32); +template void ARMv7DisAsm::VLD3_SAL(const u32, const u32); +template void ARMv7DisAsm::VLD3_SL(const u32, const u32); +template void ARMv7DisAsm::VLD3_SL(const u32, const u32); +template void ARMv7DisAsm::VLD4_SAL(const u32, const u32); +template void ARMv7DisAsm::VLD4_SAL(const u32, const u32); +template void ARMv7DisAsm::VLD4_SL(const u32, const u32); +template void ARMv7DisAsm::VLD4_SL(const u32, const u32); +template void ARMv7DisAsm::VLDM(const u32, const u32); +template void ARMv7DisAsm::VLDM(const u32, const u32); +template void ARMv7DisAsm::VLDM(const u32, const u32); +template void ARMv7DisAsm::VLDM(const u32, const u32); +template void ARMv7DisAsm::VLDR(const u32, const u32); +template void ARMv7DisAsm::VLDR(const u32, const u32); +template void ARMv7DisAsm::VLDR(const u32, const u32); +template void ARMv7DisAsm::VLDR(const u32, const u32); +template void ARMv7DisAsm::VMAXMIN(const u32, const u32); +template void ARMv7DisAsm::VMAXMIN(const u32, const u32); +template void ARMv7DisAsm::VMAXMIN_FP(const u32, const u32); +template void ARMv7DisAsm::VMAXMIN_FP(const u32, const u32); +template void ARMv7DisAsm::VML__(const u32, const u32); +template void ARMv7DisAsm::VML__(const u32, const u32); +template void ARMv7DisAsm::VML__(const u32, const u32); +template void ARMv7DisAsm::VML__(const u32, const u32); +template void ARMv7DisAsm::VML__FP(const u32, const u32); +template void ARMv7DisAsm::VML__FP(const u32, const u32); +template void ARMv7DisAsm::VML__FP(const u32, const u32); +template void ARMv7DisAsm::VML__FP(const u32, const u32); +template void ARMv7DisAsm::VML__S(const u32, const u32); +template void ARMv7DisAsm::VML__S(const u32, const u32); +template void ARMv7DisAsm::VML__S(const u32, const u32); +template void ARMv7DisAsm::VML__S(const u32, const u32); +template void ARMv7DisAsm::VMOV_IMM(const u32, const u32); +template void ARMv7DisAsm::VMOV_IMM(const u32, const u32); +template void ARMv7DisAsm::VMOV_IMM(const u32, const u32); +template void ARMv7DisAsm::VMOV_IMM(const u32, const u32); +template void ARMv7DisAsm::VMOV_REG(const u32, const u32); +template void ARMv7DisAsm::VMOV_REG(const u32, const u32); +template void ARMv7DisAsm::VMOV_REG(const u32, const u32); +template void ARMv7DisAsm::VMOV_REG(const u32, const u32); +template void ARMv7DisAsm::VMOV_RS(const u32, const u32); +template void ARMv7DisAsm::VMOV_RS(const u32, const u32); +template void ARMv7DisAsm::VMOV_SR(const u32, const u32); +template void ARMv7DisAsm::VMOV_SR(const u32, const u32); +template void ARMv7DisAsm::VMOV_RF(const u32, const u32); +template void ARMv7DisAsm::VMOV_RF(const u32, const u32); +template void ARMv7DisAsm::VMOV_2RF(const u32, const u32); +template void ARMv7DisAsm::VMOV_2RF(const u32, const u32); +template void ARMv7DisAsm::VMOV_2RD(const u32, const u32); +template void ARMv7DisAsm::VMOV_2RD(const u32, const u32); +template void ARMv7DisAsm::VMOVL(const u32, const u32); +template void ARMv7DisAsm::VMOVL(const u32, const u32); +template void ARMv7DisAsm::VMOVN(const u32, const u32); +template void ARMv7DisAsm::VMOVN(const u32, const u32); +template void ARMv7DisAsm::VMRS(const u32, const u32); +template void ARMv7DisAsm::VMRS(const u32, const u32); +template void ARMv7DisAsm::VMSR(const u32, const u32); +template void ARMv7DisAsm::VMSR(const u32, const u32); +template void ARMv7DisAsm::VMUL_(const u32, const u32); +template void ARMv7DisAsm::VMUL_(const u32, const u32); +template void ARMv7DisAsm::VMUL_(const u32, const u32); +template void ARMv7DisAsm::VMUL_(const u32, const u32); +template void ARMv7DisAsm::VMUL_FP(const u32, const u32); +template void ARMv7DisAsm::VMUL_FP(const u32, const u32); +template void ARMv7DisAsm::VMUL_FP(const u32, const u32); +template void ARMv7DisAsm::VMUL_FP(const u32, const u32); +template void ARMv7DisAsm::VMUL_S(const u32, const u32); +template void ARMv7DisAsm::VMUL_S(const u32, const u32); +template void ARMv7DisAsm::VMUL_S(const u32, const u32); +template void ARMv7DisAsm::VMUL_S(const u32, const u32); +template void ARMv7DisAsm::VMVN_IMM(const u32, const u32); +template void ARMv7DisAsm::VMVN_IMM(const u32, const u32); +template void ARMv7DisAsm::VMVN_REG(const u32, const u32); +template void ARMv7DisAsm::VMVN_REG(const u32, const u32); +template void ARMv7DisAsm::VNEG(const u32, const u32); +template void ARMv7DisAsm::VNEG(const u32, const u32); +template void ARMv7DisAsm::VNEG(const u32, const u32); +template void ARMv7DisAsm::VNEG(const u32, const u32); +template void ARMv7DisAsm::VNM__(const u32, const u32); +template void ARMv7DisAsm::VNM__(const u32, const u32); +template void ARMv7DisAsm::VNM__(const u32, const u32); +template void ARMv7DisAsm::VNM__(const u32, const u32); +template void ARMv7DisAsm::VORN_REG(const u32, const u32); +template void ARMv7DisAsm::VORN_REG(const u32, const u32); +template void ARMv7DisAsm::VORR_IMM(const u32, const u32); +template void ARMv7DisAsm::VORR_IMM(const u32, const u32); +template void ARMv7DisAsm::VORR_REG(const u32, const u32); +template void ARMv7DisAsm::VORR_REG(const u32, const u32); +template void ARMv7DisAsm::VPADAL(const u32, const u32); +template void ARMv7DisAsm::VPADAL(const u32, const u32); +template void ARMv7DisAsm::VPADD(const u32, const u32); +template void ARMv7DisAsm::VPADD(const u32, const u32); +template void ARMv7DisAsm::VPADD_FP(const u32, const u32); +template void ARMv7DisAsm::VPADD_FP(const u32, const u32); +template void ARMv7DisAsm::VPADDL(const u32, const u32); +template void ARMv7DisAsm::VPADDL(const u32, const u32); +template void ARMv7DisAsm::VPMAXMIN(const u32, const u32); +template void ARMv7DisAsm::VPMAXMIN(const u32, const u32); +template void ARMv7DisAsm::VPMAXMIN_FP(const u32, const u32); +template void ARMv7DisAsm::VPMAXMIN_FP(const u32, const u32); +template void ARMv7DisAsm::VPOP(const u32, const u32); +template void ARMv7DisAsm::VPOP(const u32, const u32); +template void ARMv7DisAsm::VPOP(const u32, const u32); +template void ARMv7DisAsm::VPOP(const u32, const u32); +template void ARMv7DisAsm::VPUSH(const u32, const u32); +template void ARMv7DisAsm::VPUSH(const u32, const u32); +template void ARMv7DisAsm::VPUSH(const u32, const u32); +template void ARMv7DisAsm::VPUSH(const u32, const u32); +template void ARMv7DisAsm::VQABS(const u32, const u32); +template void ARMv7DisAsm::VQABS(const u32, const u32); +template void ARMv7DisAsm::VQADD(const u32, const u32); +template void ARMv7DisAsm::VQADD(const u32, const u32); +template void ARMv7DisAsm::VQDML_L(const u32, const u32); +template void ARMv7DisAsm::VQDML_L(const u32, const u32); +template void ARMv7DisAsm::VQDML_L(const u32, const u32); +template void ARMv7DisAsm::VQDML_L(const u32, const u32); +template void ARMv7DisAsm::VQDMULH(const u32, const u32); +template void ARMv7DisAsm::VQDMULH(const u32, const u32); +template void ARMv7DisAsm::VQDMULH(const u32, const u32); +template void ARMv7DisAsm::VQDMULH(const u32, const u32); +template void ARMv7DisAsm::VQDMULL(const u32, const u32); +template void ARMv7DisAsm::VQDMULL(const u32, const u32); +template void ARMv7DisAsm::VQDMULL(const u32, const u32); +template void ARMv7DisAsm::VQDMULL(const u32, const u32); +template void ARMv7DisAsm::VQMOV_N(const u32, const u32); +template void ARMv7DisAsm::VQMOV_N(const u32, const u32); +template void ARMv7DisAsm::VQNEG(const u32, const u32); +template void ARMv7DisAsm::VQNEG(const u32, const u32); +template void ARMv7DisAsm::VQRDMULH(const u32, const u32); +template void ARMv7DisAsm::VQRDMULH(const u32, const u32); +template void ARMv7DisAsm::VQRDMULH(const u32, const u32); +template void ARMv7DisAsm::VQRDMULH(const u32, const u32); +template void ARMv7DisAsm::VQRSHL(const u32, const u32); +template void ARMv7DisAsm::VQRSHL(const u32, const u32); +template void ARMv7DisAsm::VQRSHR_N(const u32, const u32); +template void ARMv7DisAsm::VQRSHR_N(const u32, const u32); +template void ARMv7DisAsm::VQSHL_REG(const u32, const u32); +template void ARMv7DisAsm::VQSHL_REG(const u32, const u32); +template void ARMv7DisAsm::VQSHL_IMM(const u32, const u32); +template void ARMv7DisAsm::VQSHL_IMM(const u32, const u32); +template void ARMv7DisAsm::VQSHR_N(const u32, const u32); +template void ARMv7DisAsm::VQSHR_N(const u32, const u32); +template void ARMv7DisAsm::VQSUB(const u32, const u32); +template void ARMv7DisAsm::VQSUB(const u32, const u32); +template void ARMv7DisAsm::VRADDHN(const u32, const u32); +template void ARMv7DisAsm::VRADDHN(const u32, const u32); +template void ARMv7DisAsm::VRECPE(const u32, const u32); +template void ARMv7DisAsm::VRECPE(const u32, const u32); +template void ARMv7DisAsm::VRECPS(const u32, const u32); +template void ARMv7DisAsm::VRECPS(const u32, const u32); +template void ARMv7DisAsm::VREV__(const u32, const u32); +template void ARMv7DisAsm::VREV__(const u32, const u32); +template void ARMv7DisAsm::VRHADD(const u32, const u32); +template void ARMv7DisAsm::VRHADD(const u32, const u32); +template void ARMv7DisAsm::VRSHL(const u32, const u32); +template void ARMv7DisAsm::VRSHL(const u32, const u32); +template void ARMv7DisAsm::VRSHR(const u32, const u32); +template void ARMv7DisAsm::VRSHR(const u32, const u32); +template void ARMv7DisAsm::VRSHRN(const u32, const u32); +template void ARMv7DisAsm::VRSHRN(const u32, const u32); +template void ARMv7DisAsm::VRSQRTE(const u32, const u32); +template void ARMv7DisAsm::VRSQRTE(const u32, const u32); +template void ARMv7DisAsm::VRSQRTS(const u32, const u32); +template void ARMv7DisAsm::VRSQRTS(const u32, const u32); +template void ARMv7DisAsm::VRSRA(const u32, const u32); +template void ARMv7DisAsm::VRSRA(const u32, const u32); +template void ARMv7DisAsm::VRSUBHN(const u32, const u32); +template void ARMv7DisAsm::VRSUBHN(const u32, const u32); +template void ARMv7DisAsm::VSHL_IMM(const u32, const u32); +template void ARMv7DisAsm::VSHL_IMM(const u32, const u32); +template void ARMv7DisAsm::VSHL_REG(const u32, const u32); +template void ARMv7DisAsm::VSHL_REG(const u32, const u32); +template void ARMv7DisAsm::VSHLL(const u32, const u32); +template void ARMv7DisAsm::VSHLL(const u32, const u32); +template void ARMv7DisAsm::VSHLL(const u32, const u32); +template void ARMv7DisAsm::VSHLL(const u32, const u32); +template void ARMv7DisAsm::VSHR(const u32, const u32); +template void ARMv7DisAsm::VSHR(const u32, const u32); +template void ARMv7DisAsm::VSHRN(const u32, const u32); +template void ARMv7DisAsm::VSHRN(const u32, const u32); +template void ARMv7DisAsm::VSLI(const u32, const u32); +template void ARMv7DisAsm::VSLI(const u32, const u32); +template void ARMv7DisAsm::VSQRT(const u32, const u32); +template void ARMv7DisAsm::VSQRT(const u32, const u32); +template void ARMv7DisAsm::VSRA(const u32, const u32); +template void ARMv7DisAsm::VSRA(const u32, const u32); +template void ARMv7DisAsm::VSRI(const u32, const u32); +template void ARMv7DisAsm::VSRI(const u32, const u32); +template void ARMv7DisAsm::VST__MS(const u32, const u32); +template void ARMv7DisAsm::VST__MS(const u32, const u32); +template void ARMv7DisAsm::VST1_SL(const u32, const u32); +template void ARMv7DisAsm::VST1_SL(const u32, const u32); +template void ARMv7DisAsm::VST2_SL(const u32, const u32); +template void ARMv7DisAsm::VST2_SL(const u32, const u32); +template void ARMv7DisAsm::VST3_SL(const u32, const u32); +template void ARMv7DisAsm::VST3_SL(const u32, const u32); +template void ARMv7DisAsm::VST4_SL(const u32, const u32); +template void ARMv7DisAsm::VST4_SL(const u32, const u32); +template void ARMv7DisAsm::VSTM(const u32, const u32); +template void ARMv7DisAsm::VSTM(const u32, const u32); +template void ARMv7DisAsm::VSTM(const u32, const u32); +template void ARMv7DisAsm::VSTM(const u32, const u32); +template void ARMv7DisAsm::VSTR(const u32, const u32); +template void ARMv7DisAsm::VSTR(const u32, const u32); +template void ARMv7DisAsm::VSTR(const u32, const u32); +template void ARMv7DisAsm::VSTR(const u32, const u32); +template void ARMv7DisAsm::VSUB(const u32, const u32); +template void ARMv7DisAsm::VSUB(const u32, const u32); +template void ARMv7DisAsm::VSUB_FP(const u32, const u32); +template void ARMv7DisAsm::VSUB_FP(const u32, const u32); +template void ARMv7DisAsm::VSUB_FP(const u32, const u32); +template void ARMv7DisAsm::VSUB_FP(const u32, const u32); +template void ARMv7DisAsm::VSUBHN(const u32, const u32); +template void ARMv7DisAsm::VSUBHN(const u32, const u32); +template void ARMv7DisAsm::VSUB_(const u32, const u32); +template void ARMv7DisAsm::VSUB_(const u32, const u32); +template void ARMv7DisAsm::VSWP(const u32, const u32); +template void ARMv7DisAsm::VSWP(const u32, const u32); +template void ARMv7DisAsm::VTB_(const u32, const u32); +template void ARMv7DisAsm::VTB_(const u32, const u32); +template void ARMv7DisAsm::VTRN(const u32, const u32); +template void ARMv7DisAsm::VTRN(const u32, const u32); +template void ARMv7DisAsm::VTST(const u32, const u32); +template void ARMv7DisAsm::VTST(const u32, const u32); +template void ARMv7DisAsm::VUZP(const u32, const u32); +template void ARMv7DisAsm::VUZP(const u32, const u32); +template void ARMv7DisAsm::VZIP(const u32, const u32); +template void ARMv7DisAsm::VZIP(const u32, const u32); +template void ARMv7DisAsm::WFE(const u32, const u32); +template void ARMv7DisAsm::WFE(const u32, const u32); +template void ARMv7DisAsm::WFE(const u32, const u32); +template void ARMv7DisAsm::WFI(const u32, const u32); +template void ARMv7DisAsm::WFI(const u32, const u32); +template void ARMv7DisAsm::WFI(const u32, const u32); +template void ARMv7DisAsm::YIELD(const u32, const u32); +template void ARMv7DisAsm::YIELD(const u32, const u32); +template void ARMv7DisAsm::YIELD(const u32, const u32); diff --git a/rpcs3/Emu/ARMv7/ARMv7DisAsm.h b/rpcs3/Emu/ARMv7/ARMv7DisAsm.h index 848baaf7cb..68b60dc20f 100644 --- a/rpcs3/Emu/ARMv7/ARMv7DisAsm.h +++ b/rpcs3/Emu/ARMv7/ARMv7DisAsm.h @@ -1,328 +1,459 @@ #pragma once + #include "Emu/CPU/CPUDisAsm.h" -static const char* g_arm_cond_name[16] = -{ - "eq", "ne", "cs", "cc", - "mi", "pl", "vs", "vc", - "hi", "ls", "ge", "lt", - "gt", "le", "al", "al", -}; +enum class arm_encoding; -static const char* g_arm_reg_name[16] = -{ - "r0", "r1", "r2", "r3", - "r4", "r5", "r6", "r7", - "r8", "r9", "r10", "r11", - "r12", "sp", "lr", "pc", -}; - -class ARMv7DisAsm - : public CPUDisAsm +class ARMv7DisAsm final : public CPUDisAsm { public: - ARMv7DisAsm() : CPUDisAsm(CPUDisAsm_InterpreterMode) + ARMv7DisAsm(CPUDisAsmMode mode) : CPUDisAsm(mode) { } protected: - virtual u32 DisAsmBranchTarget(const s32 imm) + virtual u32 DisAsmBranchTarget(const s32 imm) override { - return (u32)dump_pc + imm; + // TODO: ARM + return dump_pc + (true ? 4 : 8) + imm; } -#if 0 - std::string GetRegsListString(u16 regs_list) + virtual void Write(const std::string& value) override; + +private: + template + void write(const char* fmt, const Args&... args) { - std::string regs_str; - - for(u16 mask=0x1, i=0; mask; mask <<= 1, i++) - { - if(regs_list & mask) - { - if(!regs_str.empty()) - { - regs_str += ", "; - } - - regs_str += g_arm_reg_name[i]; - } - } - - return regs_str; + Write(fmt::format(fmt, args...)); } - virtual void UNK(const u32 data); +public: + void UNK(const u32 op, const u32 cond); - virtual void NULL_OP(const u32 data, const ARMv7_encoding type); + template void HACK(const u32, const u32); + template void MRC_(const u32, const u32); - virtual void HACK(const u32 data, const ARMv7_encoding type); + template void ADC_IMM(const u32, const u32); + template void ADC_REG(const u32, const u32); + template void ADC_RSR(const u32, const u32); - virtual void ADC_IMM(const u32 data, const ARMv7_encoding type); - virtual void ADC_REG(const u32 data, const ARMv7_encoding type); - virtual void ADC_RSR(const u32 data, const ARMv7_encoding type); + template void ADD_IMM(const u32, const u32); + template void ADD_REG(const u32, const u32); + template void ADD_RSR(const u32, const u32); + template void ADD_SPI(const u32, const u32); + template void ADD_SPR(const u32, const u32); - virtual void ADD_IMM(const u32 data, const ARMv7_encoding type); - virtual void ADD_REG(const u32 data, const ARMv7_encoding type); - virtual void ADD_RSR(const u32 data, const ARMv7_encoding type); - virtual void ADD_SPI(const u32 data, const ARMv7_encoding type); - virtual void ADD_SPR(const u32 data, const ARMv7_encoding type); + template void ADR(const u32, const u32); - virtual void ADR(const u32 data, const ARMv7_encoding type); + template void AND_IMM(const u32, const u32); + template void AND_REG(const u32, const u32); + template void AND_RSR(const u32, const u32); - virtual void AND_IMM(const u32 data, const ARMv7_encoding type); - virtual void AND_REG(const u32 data, const ARMv7_encoding type); - virtual void AND_RSR(const u32 data, const ARMv7_encoding type); + template void ASR_IMM(const u32, const u32); + template void ASR_REG(const u32, const u32); - virtual void ASR_IMM(const u32 data, const ARMv7_encoding type); - virtual void ASR_REG(const u32 data, const ARMv7_encoding type); + template void B(const u32, const u32); - virtual void B(const u32 data, const ARMv7_encoding type); + template void BFC(const u32, const u32); + template void BFI(const u32, const u32); - virtual void BFC(const u32 data, const ARMv7_encoding type); - virtual void BFI(const u32 data, const ARMv7_encoding type); + template void BIC_IMM(const u32, const u32); + template void BIC_REG(const u32, const u32); + template void BIC_RSR(const u32, const u32); - virtual void BIC_IMM(const u32 data, const ARMv7_encoding type); - virtual void BIC_REG(const u32 data, const ARMv7_encoding type); - virtual void BIC_RSR(const u32 data, const ARMv7_encoding type); + template void BKPT(const u32, const u32); - virtual void BKPT(const u32 data, const ARMv7_encoding type); + template void BL(const u32, const u32); + template void BLX(const u32, const u32); + template void BX(const u32, const u32); - virtual void BL(const u32 data, const ARMv7_encoding type); - virtual void BLX(const u32 data, const ARMv7_encoding type); - virtual void BX(const u32 data, const ARMv7_encoding type); + template void CB_Z(const u32, const u32); - virtual void CB_Z(const u32 data, const ARMv7_encoding type); + template void CLZ(const u32, const u32); - virtual void CLZ(const u32 data, const ARMv7_encoding type); + template void CMN_IMM(const u32, const u32); + template void CMN_REG(const u32, const u32); + template void CMN_RSR(const u32, const u32); - virtual void CMN_IMM(const u32 data, const ARMv7_encoding type); - virtual void CMN_REG(const u32 data, const ARMv7_encoding type); - virtual void CMN_RSR(const u32 data, const ARMv7_encoding type); + template void CMP_IMM(const u32, const u32); + template void CMP_REG(const u32, const u32); + template void CMP_RSR(const u32, const u32); - virtual void CMP_IMM(const u32 data, const ARMv7_encoding type); - virtual void CMP_REG(const u32 data, const ARMv7_encoding type); - virtual void CMP_RSR(const u32 data, const ARMv7_encoding type); + template void DBG(const u32, const u32); + template void DMB(const u32, const u32); + template void DSB(const u32, const u32); - virtual void EOR_IMM(const u32 data, const ARMv7_encoding type); - virtual void EOR_REG(const u32 data, const ARMv7_encoding type); - virtual void EOR_RSR(const u32 data, const ARMv7_encoding type); + template void EOR_IMM(const u32, const u32); + template void EOR_REG(const u32, const u32); + template void EOR_RSR(const u32, const u32); - virtual void IT(const u32 data, const ARMv7_encoding type); + template void IT(const u32, const u32); - virtual void LDM(const u32 data, const ARMv7_encoding type); - virtual void LDMDA(const u32 data, const ARMv7_encoding type); - virtual void LDMDB(const u32 data, const ARMv7_encoding type); - virtual void LDMIB(const u32 data, const ARMv7_encoding type); + template void LDM(const u32, const u32); + template void LDMDA(const u32, const u32); + template void LDMDB(const u32, const u32); + template void LDMIB(const u32, const u32); - virtual void LDR_IMM(const u32 data, const ARMv7_encoding type); - virtual void LDR_LIT(const u32 data, const ARMv7_encoding type); - virtual void LDR_REG(const u32 data, const ARMv7_encoding type); + template void LDR_IMM(const u32, const u32); + template void LDR_LIT(const u32, const u32); + template void LDR_REG(const u32, const u32); - virtual void LDRB_IMM(const u32 data, const ARMv7_encoding type); - virtual void LDRB_LIT(const u32 data, const ARMv7_encoding type); - virtual void LDRB_REG(const u32 data, const ARMv7_encoding type); + template void LDRB_IMM(const u32, const u32); + template void LDRB_LIT(const u32, const u32); + template void LDRB_REG(const u32, const u32); - virtual void LDRD_IMM(const u32 data, const ARMv7_encoding type); - virtual void LDRD_LIT(const u32 data, const ARMv7_encoding type); - virtual void LDRD_REG(const u32 data, const ARMv7_encoding type); + template void LDRD_IMM(const u32, const u32); + template void LDRD_LIT(const u32, const u32); + template void LDRD_REG(const u32, const u32); - virtual void LDRH_IMM(const u32 data, const ARMv7_encoding type); - virtual void LDRH_LIT(const u32 data, const ARMv7_encoding type); - virtual void LDRH_REG(const u32 data, const ARMv7_encoding type); + template void LDRH_IMM(const u32, const u32); + template void LDRH_LIT(const u32, const u32); + template void LDRH_REG(const u32, const u32); - virtual void LDRSB_IMM(const u32 data, const ARMv7_encoding type); - virtual void LDRSB_LIT(const u32 data, const ARMv7_encoding type); - virtual void LDRSB_REG(const u32 data, const ARMv7_encoding type); + template void LDRSB_IMM(const u32, const u32); + template void LDRSB_LIT(const u32, const u32); + template void LDRSB_REG(const u32, const u32); - virtual void LDRSH_IMM(const u32 data, const ARMv7_encoding type); - virtual void LDRSH_LIT(const u32 data, const ARMv7_encoding type); - virtual void LDRSH_REG(const u32 data, const ARMv7_encoding type); + template void LDRSH_IMM(const u32, const u32); + template void LDRSH_LIT(const u32, const u32); + template void LDRSH_REG(const u32, const u32); - virtual void LSL_IMM(const u32 data, const ARMv7_encoding type); - virtual void LSL_REG(const u32 data, const ARMv7_encoding type); + template void LDREX(const u32, const u32); + template void LDREXB(const u32, const u32); + template void LDREXD(const u32, const u32); + template void LDREXH(const u32, const u32); - virtual void LSR_IMM(const u32 data, const ARMv7_encoding type); - virtual void LSR_REG(const u32 data, const ARMv7_encoding type); + template void LSL_IMM(const u32, const u32); + template void LSL_REG(const u32, const u32); - virtual void MLA(const u32 data, const ARMv7_encoding type); - virtual void MLS(const u32 data, const ARMv7_encoding type); + template void LSR_IMM(const u32, const u32); + template void LSR_REG(const u32, const u32); - virtual void MOV_IMM(const u32 data, const ARMv7_encoding type); - virtual void MOV_REG(const u32 data, const ARMv7_encoding type); - virtual void MOVT(const u32 data, const ARMv7_encoding type); + template void MLA(const u32, const u32); + template void MLS(const u32, const u32); - virtual void MRS(const u32 data, const ARMv7_encoding type); - virtual void MSR_IMM(const u32 data, const ARMv7_encoding type); - virtual void MSR_REG(const u32 data, const ARMv7_encoding type); + template void MOV_IMM(const u32, const u32); + template void MOV_REG(const u32, const u32); + template void MOVT(const u32, const u32); - virtual void MUL(const u32 data, const ARMv7_encoding type); + template void MRS(const u32, const u32); + template void MSR_IMM(const u32, const u32); + template void MSR_REG(const u32, const u32); - virtual void MVN_IMM(const u32 data, const ARMv7_encoding type); - virtual void MVN_REG(const u32 data, const ARMv7_encoding type); - virtual void MVN_RSR(const u32 data, const ARMv7_encoding type); + template void MUL(const u32, const u32); - virtual void NOP(const u32 data, const ARMv7_encoding type); + template void MVN_IMM(const u32, const u32); + template void MVN_REG(const u32, const u32); + template void MVN_RSR(const u32, const u32); - virtual void ORN_IMM(const u32 data, const ARMv7_encoding type); - virtual void ORN_REG(const u32 data, const ARMv7_encoding type); + template void NOP(const u32, const u32); - virtual void ORR_IMM(const u32 data, const ARMv7_encoding type); - virtual void ORR_REG(const u32 data, const ARMv7_encoding type); - virtual void ORR_RSR(const u32 data, const ARMv7_encoding type); + template void ORN_IMM(const u32, const u32); + template void ORN_REG(const u32, const u32); - virtual void PKH(const u32 data, const ARMv7_encoding type); + template void ORR_IMM(const u32, const u32); + template void ORR_REG(const u32, const u32); + template void ORR_RSR(const u32, const u32); - virtual void POP(const u32 data, const ARMv7_encoding type); - virtual void PUSH(const u32 data, const ARMv7_encoding type); + template void PKH(const u32, const u32); - virtual void QADD(const u32 data, const ARMv7_encoding type); - virtual void QADD16(const u32 data, const ARMv7_encoding type); - virtual void QADD8(const u32 data, const ARMv7_encoding type); - virtual void QASX(const u32 data, const ARMv7_encoding type); - virtual void QDADD(const u32 data, const ARMv7_encoding type); - virtual void QDSUB(const u32 data, const ARMv7_encoding type); - virtual void QSAX(const u32 data, const ARMv7_encoding type); - virtual void QSUB(const u32 data, const ARMv7_encoding type); - virtual void QSUB16(const u32 data, const ARMv7_encoding type); - virtual void QSUB8(const u32 data, const ARMv7_encoding type); + template void POP(const u32, const u32); + template void PUSH(const u32, const u32); - virtual void RBIT(const u32 data, const ARMv7_encoding type); - virtual void REV(const u32 data, const ARMv7_encoding type); - virtual void REV16(const u32 data, const ARMv7_encoding type); - virtual void REVSH(const u32 data, const ARMv7_encoding type); + template void QADD(const u32, const u32); + template void QADD16(const u32, const u32); + template void QADD8(const u32, const u32); + template void QASX(const u32, const u32); + template void QDADD(const u32, const u32); + template void QDSUB(const u32, const u32); + template void QSAX(const u32, const u32); + template void QSUB(const u32, const u32); + template void QSUB16(const u32, const u32); + template void QSUB8(const u32, const u32); - virtual void ROR_IMM(const u32 data, const ARMv7_encoding type); - virtual void ROR_REG(const u32 data, const ARMv7_encoding type); + template void RBIT(const u32, const u32); + template void REV(const u32, const u32); + template void REV16(const u32, const u32); + template void REVSH(const u32, const u32); - virtual void RRX(const u32 data, const ARMv7_encoding type); + template void ROR_IMM(const u32, const u32); + template void ROR_REG(const u32, const u32); - virtual void RSB_IMM(const u32 data, const ARMv7_encoding type); - virtual void RSB_REG(const u32 data, const ARMv7_encoding type); - virtual void RSB_RSR(const u32 data, const ARMv7_encoding type); + template void RRX(const u32, const u32); - virtual void RSC_IMM(const u32 data, const ARMv7_encoding type); - virtual void RSC_REG(const u32 data, const ARMv7_encoding type); - virtual void RSC_RSR(const u32 data, const ARMv7_encoding type); + template void RSB_IMM(const u32, const u32); + template void RSB_REG(const u32, const u32); + template void RSB_RSR(const u32, const u32); - virtual void SADD16(const u32 data, const ARMv7_encoding type); - virtual void SADD8(const u32 data, const ARMv7_encoding type); - virtual void SASX(const u32 data, const ARMv7_encoding type); + template void RSC_IMM(const u32, const u32); + template void RSC_REG(const u32, const u32); + template void RSC_RSR(const u32, const u32); - virtual void SBC_IMM(const u32 data, const ARMv7_encoding type); - virtual void SBC_REG(const u32 data, const ARMv7_encoding type); - virtual void SBC_RSR(const u32 data, const ARMv7_encoding type); + template void SADD16(const u32, const u32); + template void SADD8(const u32, const u32); + template void SASX(const u32, const u32); - virtual void SBFX(const u32 data, const ARMv7_encoding type); + template void SBC_IMM(const u32, const u32); + template void SBC_REG(const u32, const u32); + template void SBC_RSR(const u32, const u32); - virtual void SDIV(const u32 data, const ARMv7_encoding type); + template void SBFX(const u32, const u32); - virtual void SEL(const u32 data, const ARMv7_encoding type); + template void SDIV(const u32, const u32); - virtual void SHADD16(const u32 data, const ARMv7_encoding type); - virtual void SHADD8(const u32 data, const ARMv7_encoding type); - virtual void SHASX(const u32 data, const ARMv7_encoding type); - virtual void SHSAX(const u32 data, const ARMv7_encoding type); - virtual void SHSUB16(const u32 data, const ARMv7_encoding type); - virtual void SHSUB8(const u32 data, const ARMv7_encoding type); + template void SEL(const u32, const u32); - virtual void SMLA__(const u32 data, const ARMv7_encoding type); - virtual void SMLAD(const u32 data, const ARMv7_encoding type); - virtual void SMLAL(const u32 data, const ARMv7_encoding type); - virtual void SMLAL__(const u32 data, const ARMv7_encoding type); - virtual void SMLALD(const u32 data, const ARMv7_encoding type); - virtual void SMLAW_(const u32 data, const ARMv7_encoding type); - virtual void SMLSD(const u32 data, const ARMv7_encoding type); - virtual void SMLSLD(const u32 data, const ARMv7_encoding type); - virtual void SMMLA(const u32 data, const ARMv7_encoding type); - virtual void SMMLS(const u32 data, const ARMv7_encoding type); - virtual void SMMUL(const u32 data, const ARMv7_encoding type); - virtual void SMUAD(const u32 data, const ARMv7_encoding type); - virtual void SMUL__(const u32 data, const ARMv7_encoding type); - virtual void SMULL(const u32 data, const ARMv7_encoding type); - virtual void SMULW_(const u32 data, const ARMv7_encoding type); - virtual void SMUSD(const u32 data, const ARMv7_encoding type); + template void SHADD16(const u32, const u32); + template void SHADD8(const u32, const u32); + template void SHASX(const u32, const u32); + template void SHSAX(const u32, const u32); + template void SHSUB16(const u32, const u32); + template void SHSUB8(const u32, const u32); - virtual void SSAT(const u32 data, const ARMv7_encoding type); - virtual void SSAT16(const u32 data, const ARMv7_encoding type); - virtual void SSAX(const u32 data, const ARMv7_encoding type); - virtual void SSUB16(const u32 data, const ARMv7_encoding type); - virtual void SSUB8(const u32 data, const ARMv7_encoding type); + template void SMLA__(const u32, const u32); + template void SMLAD(const u32, const u32); + template void SMLAL(const u32, const u32); + template void SMLAL__(const u32, const u32); + template void SMLALD(const u32, const u32); + template void SMLAW_(const u32, const u32); + template void SMLSD(const u32, const u32); + template void SMLSLD(const u32, const u32); + template void SMMLA(const u32, const u32); + template void SMMLS(const u32, const u32); + template void SMMUL(const u32, const u32); + template void SMUAD(const u32, const u32); + template void SMUL__(const u32, const u32); + template void SMULL(const u32, const u32); + template void SMULW_(const u32, const u32); + template void SMUSD(const u32, const u32); - virtual void STM(const u32 data, const ARMv7_encoding type); - virtual void STMDA(const u32 data, const ARMv7_encoding type); - virtual void STMDB(const u32 data, const ARMv7_encoding type); - virtual void STMIB(const u32 data, const ARMv7_encoding type); + template void SSAT(const u32, const u32); + template void SSAT16(const u32, const u32); + template void SSAX(const u32, const u32); + template void SSUB16(const u32, const u32); + template void SSUB8(const u32, const u32); - virtual void STR_IMM(const u32 data, const ARMv7_encoding type); - virtual void STR_REG(const u32 data, const ARMv7_encoding type); + template void STM(const u32, const u32); + template void STMDA(const u32, const u32); + template void STMDB(const u32, const u32); + template void STMIB(const u32, const u32); - virtual void STRB_IMM(const u32 data, const ARMv7_encoding type); - virtual void STRB_REG(const u32 data, const ARMv7_encoding type); + template void STR_IMM(const u32, const u32); + template void STR_REG(const u32, const u32); - virtual void STRD_IMM(const u32 data, const ARMv7_encoding type); - virtual void STRD_REG(const u32 data, const ARMv7_encoding type); + template void STRB_IMM(const u32, const u32); + template void STRB_REG(const u32, const u32); - virtual void STRH_IMM(const u32 data, const ARMv7_encoding type); - virtual void STRH_REG(const u32 data, const ARMv7_encoding type); + template void STRD_IMM(const u32, const u32); + template void STRD_REG(const u32, const u32); - virtual void SUB_IMM(const u32 data, const ARMv7_encoding type); - virtual void SUB_REG(const u32 data, const ARMv7_encoding type); - virtual void SUB_RSR(const u32 data, const ARMv7_encoding type); - virtual void SUB_SPI(const u32 data, const ARMv7_encoding type); - virtual void SUB_SPR(const u32 data, const ARMv7_encoding type); + template void STRH_IMM(const u32, const u32); + template void STRH_REG(const u32, const u32); - virtual void SVC(const u32 data, const ARMv7_encoding type); + template void STREX(const u32, const u32); + template void STREXB(const u32, const u32); + template void STREXD(const u32, const u32); + template void STREXH(const u32, const u32); - virtual void SXTAB(const u32 data, const ARMv7_encoding type); - virtual void SXTAB16(const u32 data, const ARMv7_encoding type); - virtual void SXTAH(const u32 data, const ARMv7_encoding type); - virtual void SXTB(const u32 data, const ARMv7_encoding type); - virtual void SXTB16(const u32 data, const ARMv7_encoding type); - virtual void SXTH(const u32 data, const ARMv7_encoding type); + template void SUB_IMM(const u32, const u32); + template void SUB_REG(const u32, const u32); + template void SUB_RSR(const u32, const u32); + template void SUB_SPI(const u32, const u32); + template void SUB_SPR(const u32, const u32); - virtual void TB_(const u32 data, const ARMv7_encoding type); + template void SVC(const u32, const u32); - virtual void TEQ_IMM(const u32 data, const ARMv7_encoding type); - virtual void TEQ_REG(const u32 data, const ARMv7_encoding type); - virtual void TEQ_RSR(const u32 data, const ARMv7_encoding type); + template void SXTAB(const u32, const u32); + template void SXTAB16(const u32, const u32); + template void SXTAH(const u32, const u32); + template void SXTB(const u32, const u32); + template void SXTB16(const u32, const u32); + template void SXTH(const u32, const u32); - virtual void TST_IMM(const u32 data, const ARMv7_encoding type); - virtual void TST_REG(const u32 data, const ARMv7_encoding type); - virtual void TST_RSR(const u32 data, const ARMv7_encoding type); + template void TB_(const u32, const u32); - virtual void UADD16(const u32 data, const ARMv7_encoding type); - virtual void UADD8(const u32 data, const ARMv7_encoding type); - virtual void UASX(const u32 data, const ARMv7_encoding type); - virtual void UBFX(const u32 data, const ARMv7_encoding type); - virtual void UDIV(const u32 data, const ARMv7_encoding type); - virtual void UHADD16(const u32 data, const ARMv7_encoding type); - virtual void UHADD8(const u32 data, const ARMv7_encoding type); - virtual void UHASX(const u32 data, const ARMv7_encoding type); - virtual void UHSAX(const u32 data, const ARMv7_encoding type); - virtual void UHSUB16(const u32 data, const ARMv7_encoding type); - virtual void UHSUB8(const u32 data, const ARMv7_encoding type); - virtual void UMAAL(const u32 data, const ARMv7_encoding type); - virtual void UMLAL(const u32 data, const ARMv7_encoding type); - virtual void UMULL(const u32 data, const ARMv7_encoding type); - virtual void UQADD16(const u32 data, const ARMv7_encoding type); - virtual void UQADD8(const u32 data, const ARMv7_encoding type); - virtual void UQASX(const u32 data, const ARMv7_encoding type); - virtual void UQSAX(const u32 data, const ARMv7_encoding type); - virtual void UQSUB16(const u32 data, const ARMv7_encoding type); - virtual void UQSUB8(const u32 data, const ARMv7_encoding type); - virtual void USAD8(const u32 data, const ARMv7_encoding type); - virtual void USADA8(const u32 data, const ARMv7_encoding type); - virtual void USAT(const u32 data, const ARMv7_encoding type); - virtual void USAT16(const u32 data, const ARMv7_encoding type); - virtual void USAX(const u32 data, const ARMv7_encoding type); - virtual void USUB16(const u32 data, const ARMv7_encoding type); - virtual void USUB8(const u32 data, const ARMv7_encoding type); - virtual void UXTAB(const u32 data, const ARMv7_encoding type); - virtual void UXTAB16(const u32 data, const ARMv7_encoding type); - virtual void UXTAH(const u32 data, const ARMv7_encoding type); - virtual void UXTB(const u32 data, const ARMv7_encoding type); - virtual void UXTB16(const u32 data, const ARMv7_encoding type); - virtual void UXTH(const u32 data, const ARMv7_encoding type); -#endif + template void TEQ_IMM(const u32, const u32); + template void TEQ_REG(const u32, const u32); + template void TEQ_RSR(const u32, const u32); + + template void TST_IMM(const u32, const u32); + template void TST_REG(const u32, const u32); + template void TST_RSR(const u32, const u32); + + template void UADD16(const u32, const u32); + template void UADD8(const u32, const u32); + template void UASX(const u32, const u32); + template void UBFX(const u32, const u32); + template void UDIV(const u32, const u32); + template void UHADD16(const u32, const u32); + template void UHADD8(const u32, const u32); + template void UHASX(const u32, const u32); + template void UHSAX(const u32, const u32); + template void UHSUB16(const u32, const u32); + template void UHSUB8(const u32, const u32); + template void UMAAL(const u32, const u32); + template void UMLAL(const u32, const u32); + template void UMULL(const u32, const u32); + template void UQADD16(const u32, const u32); + template void UQADD8(const u32, const u32); + template void UQASX(const u32, const u32); + template void UQSAX(const u32, const u32); + template void UQSUB16(const u32, const u32); + template void UQSUB8(const u32, const u32); + template void USAD8(const u32, const u32); + template void USADA8(const u32, const u32); + template void USAT(const u32, const u32); + template void USAT16(const u32, const u32); + template void USAX(const u32, const u32); + template void USUB16(const u32, const u32); + template void USUB8(const u32, const u32); + template void UXTAB(const u32, const u32); + template void UXTAB16(const u32, const u32); + template void UXTAH(const u32, const u32); + template void UXTB(const u32, const u32); + template void UXTB16(const u32, const u32); + template void UXTH(const u32, const u32); + + template void VABA_(const u32, const u32); + template void VABD_(const u32, const u32); + template void VABD_FP(const u32, const u32); + template void VABS(const u32, const u32); + template void VAC__(const u32, const u32); + template void VADD(const u32, const u32); + template void VADD_FP(const u32, const u32); + template void VADDHN(const u32, const u32); + template void VADD_(const u32, const u32); + template void VAND(const u32, const u32); + template void VBIC_IMM(const u32, const u32); + template void VBIC_REG(const u32, const u32); + template void VB__(const u32, const u32); + template void VCEQ_REG(const u32, const u32); + template void VCEQ_ZERO(const u32, const u32); + template void VCGE_REG(const u32, const u32); + template void VCGE_ZERO(const u32, const u32); + template void VCGT_REG(const u32, const u32); + template void VCGT_ZERO(const u32, const u32); + template void VCLE_ZERO(const u32, const u32); + template void VCLS(const u32, const u32); + template void VCLT_ZERO(const u32, const u32); + template void VCLZ(const u32, const u32); + template void VCMP_(const u32, const u32); + template void VCNT(const u32, const u32); + template void VCVT_FIA(const u32, const u32); + template void VCVT_FIF(const u32, const u32); + template void VCVT_FFA(const u32, const u32); + template void VCVT_FFF(const u32, const u32); + template void VCVT_DF(const u32, const u32); + template void VCVT_HFA(const u32, const u32); + template void VCVT_HFF(const u32, const u32); + template void VDIV(const u32, const u32); + template void VDUP_S(const u32, const u32); + template void VDUP_R(const u32, const u32); + template void VEOR(const u32, const u32); + template void VEXT(const u32, const u32); + template void VHADDSUB(const u32, const u32); + template void VLD__MS(const u32, const u32); + template void VLD1_SL(const u32, const u32); + template void VLD1_SAL(const u32, const u32); + template void VLD2_SL(const u32, const u32); + template void VLD2_SAL(const u32, const u32); + template void VLD3_SL(const u32, const u32); + template void VLD3_SAL(const u32, const u32); + template void VLD4_SL(const u32, const u32); + template void VLD4_SAL(const u32, const u32); + template void VLDM(const u32, const u32); + template void VLDR(const u32, const u32); + template void VMAXMIN(const u32, const u32); + template void VMAXMIN_FP(const u32, const u32); + template void VML__(const u32, const u32); + template void VML__FP(const u32, const u32); + template void VML__S(const u32, const u32); + template void VMOV_IMM(const u32, const u32); + template void VMOV_REG(const u32, const u32); + template void VMOV_RS(const u32, const u32); + template void VMOV_SR(const u32, const u32); + template void VMOV_RF(const u32, const u32); + template void VMOV_2RF(const u32, const u32); + template void VMOV_2RD(const u32, const u32); + template void VMOVL(const u32, const u32); + template void VMOVN(const u32, const u32); + template void VMRS(const u32, const u32); + template void VMSR(const u32, const u32); + template void VMUL_(const u32, const u32); + template void VMUL_FP(const u32, const u32); + template void VMUL_S(const u32, const u32); + template void VMVN_IMM(const u32, const u32); + template void VMVN_REG(const u32, const u32); + template void VNEG(const u32, const u32); + template void VNM__(const u32, const u32); + template void VORN_REG(const u32, const u32); + template void VORR_IMM(const u32, const u32); + template void VORR_REG(const u32, const u32); + template void VPADAL(const u32, const u32); + template void VPADD(const u32, const u32); + template void VPADD_FP(const u32, const u32); + template void VPADDL(const u32, const u32); + template void VPMAXMIN(const u32, const u32); + template void VPMAXMIN_FP(const u32, const u32); + template void VPOP(const u32, const u32); + template void VPUSH(const u32, const u32); + template void VQABS(const u32, const u32); + template void VQADD(const u32, const u32); + template void VQDML_L(const u32, const u32); + template void VQDMULH(const u32, const u32); + template void VQDMULL(const u32, const u32); + template void VQMOV_N(const u32, const u32); + template void VQNEG(const u32, const u32); + template void VQRDMULH(const u32, const u32); + template void VQRSHL(const u32, const u32); + template void VQRSHR_N(const u32, const u32); + template void VQSHL_REG(const u32, const u32); + template void VQSHL_IMM(const u32, const u32); + template void VQSHR_N(const u32, const u32); + template void VQSUB(const u32, const u32); + template void VRADDHN(const u32, const u32); + template void VRECPE(const u32, const u32); + template void VRECPS(const u32, const u32); + template void VREV__(const u32, const u32); + template void VRHADD(const u32, const u32); + template void VRSHL(const u32, const u32); + template void VRSHR(const u32, const u32); + template void VRSHRN(const u32, const u32); + template void VRSQRTE(const u32, const u32); + template void VRSQRTS(const u32, const u32); + template void VRSRA(const u32, const u32); + template void VRSUBHN(const u32, const u32); + template void VSHL_IMM(const u32, const u32); + template void VSHL_REG(const u32, const u32); + template void VSHLL(const u32, const u32); + template void VSHR(const u32, const u32); + template void VSHRN(const u32, const u32); + template void VSLI(const u32, const u32); + template void VSQRT(const u32, const u32); + template void VSRA(const u32, const u32); + template void VSRI(const u32, const u32); + template void VST__MS(const u32, const u32); + template void VST1_SL(const u32, const u32); + template void VST2_SL(const u32, const u32); + template void VST3_SL(const u32, const u32); + template void VST4_SL(const u32, const u32); + template void VSTM(const u32, const u32); + template void VSTR(const u32, const u32); + template void VSUB(const u32, const u32); + template void VSUB_FP(const u32, const u32); + template void VSUBHN(const u32, const u32); + template void VSUB_(const u32, const u32); + template void VSWP(const u32, const u32); + template void VTB_(const u32, const u32); + template void VTRN(const u32, const u32); + template void VTST(const u32, const u32); + template void VUZP(const u32, const u32); + template void VZIP(const u32, const u32); + + template void WFE(const u32, const u32); + template void WFI(const u32, const u32); + template void YIELD(const u32, const u32); + +public: + u32 disasm(u32 pc) override; }; diff --git a/rpcs3/Emu/ARMv7/ARMv7Function.cpp b/rpcs3/Emu/ARMv7/ARMv7Function.cpp new file mode 100644 index 0000000000..f61bc3486f --- /dev/null +++ b/rpcs3/Emu/ARMv7/ARMv7Function.cpp @@ -0,0 +1,59 @@ +#include "stdafx.h" +#include "ARMv7Module.h" + +// Get function name by FNID +extern std::string arm_get_function_name(const std::string& module, u32 fnid) +{ + // Check registered functions + if (const auto sm = arm_module_manager::get_module(module)) + { + const auto found = sm->functions.find(fnid); + + if (found != sm->functions.end()) + { + return found->second.name; + } + } + + return fmt::format("0x%08X", fnid); +} + +// Get variable name by VNID +extern std::string arm_get_variable_name(const std::string& module, u32 vnid) +{ + // Check registered variables + if (const auto sm = arm_module_manager::get_module(module)) + { + const auto found = sm->variables.find(vnid); + + if (found != sm->variables.end()) + { + return found->second.name; + } + } + + return fmt::format("0x%08X", vnid); +} + +s32 arm_error_code::report(s32 error, const char* text) +{ + if (auto thread = get_current_cpu_thread()) + { + if (thread->type == cpu_type::arm) + { + if (auto func = static_cast(thread)->last_function) + { + LOG_ERROR(ARMv7, "Function '%s' failed with 0x%08x : %s", func, error, text); + } + else + { + LOG_ERROR(ARMv7, "Unknown function failed with 0x%08x : %s", error, text); + } + + return error; + } + } + + LOG_ERROR(ARMv7, "Illegal call to ppu_report_error(0x%x, '%s')!"); + return error; +} diff --git a/rpcs3/Emu/ARMv7/ARMv7Function.h b/rpcs3/Emu/ARMv7/ARMv7Function.h new file mode 100644 index 0000000000..ebbf02a119 --- /dev/null +++ b/rpcs3/Emu/ARMv7/ARMv7Function.h @@ -0,0 +1,487 @@ +#pragma once + +#include "ARMv7Thread.h" + +using arm_function_t = void(*)(ARMv7Thread&); + +#define BIND_FUNC(func) [](ARMv7Thread& cpu){ cpu.last_function = #func; arm_func_detail::do_call(cpu, func); } + +struct arm_va_args_t +{ + u32 count; // Number of 32-bit args passed +}; + +namespace arm_func_detail +{ + enum arg_class : u32 + { + ARG_GENERAL, + ARG_FLOAT, + ARG_VECTOR, + ARG_STACK, + ARG_CONTEXT, + ARG_VARIADIC, + ARG_UNKNOWN, + }; + + static const auto FIXED_STACK_FRAME_SIZE = 0x80; + + template + struct bind_arg + { + static_assert(type == ARG_GENERAL, "Unknown function argument type"); + static_assert(!std::is_pointer::value, "Invalid function argument type (pointer)"); + static_assert(!std::is_reference::value, "Invalid function argument type (reference)"); + static_assert(sizeof(T) <= 4, "Invalid function argument type for ARG_GENERAL"); + + force_inline static T get_arg(ARMv7Thread& cpu) + { + return arm_gpr_cast(cpu.GPR[g_count - 1]); + } + + force_inline static void put_arg(ARMv7Thread& cpu, const T& arg) + { + cpu.GPR[g_count - 1] = arm_gpr_cast(arg); + } + }; + + template + struct bind_arg + { + // first u64 argument is passed in r0-r1, second one is passed in r2-r3 (if g_count = 3) + static_assert(g_count == 2 || g_count == 4, "Wrong u64 argument position"); + + force_inline static u64 get_arg(ARMv7Thread& cpu) + { + return cpu.GPR_D[(g_count - 1) >> 1]; + } + + force_inline static void put_arg(ARMv7Thread& cpu, u64 arg) + { + cpu.GPR_D[(g_count - 1) >> 1] = arg; + } + }; + + template + struct bind_arg + { + static_assert(g_count == 2 || g_count == 4, "Wrong s64 argument position"); + + force_inline static s64 get_arg(ARMv7Thread& cpu) + { + return cpu.GPR_D[(g_count - 1) >> 1]; + } + + force_inline static void put_arg(ARMv7Thread& cpu, s64 arg) + { + cpu.GPR_D[(g_count - 1) >> 1] = arg; + } + }; + + template + struct bind_arg + { + static_assert(f_count <= 0, "TODO: Unsupported argument type (float)"); + static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_FLOAT"); + + force_inline static T get_arg(ARMv7Thread& cpu) + { + } + + force_inline static void put_arg(ARMv7Thread& cpu, const T& arg) + { + } + }; + + template + struct bind_arg + { + static_assert(v_count <= 0, "TODO: Unsupported argument type (vector)"); + static_assert(std::is_same::value, "Invalid function argument type for ARG_VECTOR"); + + force_inline static T get_arg(ARMv7Thread& cpu) + { + } + + force_inline static void put_arg(ARMv7Thread& cpu, const T& arg) + { + } + }; + + template + struct bind_arg + { + static_assert(f_count <= 0, "TODO: Unsupported stack argument type (float)"); + static_assert(v_count <= 0, "TODO: Unsupported stack argument type (vector)"); + static_assert(sizeof(T) <= 4, "Invalid function argument type for ARG_STACK"); + + force_inline static T get_arg(ARMv7Thread& cpu) + { + // TODO: check + return arm_gpr_cast(vm::psv::read32(cpu.SP + sizeof(u32) * (g_count - 5))); + } + + force_inline static void put_arg(ARMv7Thread& cpu, const T& arg) + { + // TODO: check + const int stack_pos = (g_count - 5) * 4 - FIXED_STACK_FRAME_SIZE; + static_assert(stack_pos < 0, "TODO: Increase fixed stack frame size (arg count limit broken)"); + + vm::psv::write32(cpu.SP + stack_pos, arm_gpr_cast(arg)); + } + }; + + template + struct bind_arg + { + force_inline static u64 get_arg(ARMv7Thread& cpu) + { + // TODO: check + return vm::psv::read64(cpu.SP + sizeof(u32) * (g_count - 6)); + } + + force_inline static void put_arg(ARMv7Thread& cpu, u64 arg) + { + // TODO: check + const int stack_pos = (g_count - 6) * 4 - FIXED_STACK_FRAME_SIZE; + static_assert(stack_pos < -4, "TODO: Increase fixed stack frame size (arg count limit broken)"); + + vm::psv::write64(cpu.SP + stack_pos, arg); + } + }; + + template + struct bind_arg + { + force_inline static s64 get_arg(ARMv7Thread& cpu) + { + // TODO: check + return vm::psv::read64(cpu.SP + sizeof(u32) * (g_count - 6)); + } + + force_inline static void put_arg(ARMv7Thread& cpu, s64 arg) + { + // TODO: check + const int stack_pos = (g_count - 6) * 4 - FIXED_STACK_FRAME_SIZE; + static_assert(stack_pos < -4, "TODO: Increase fixed stack frame size (arg count limit broken)"); + + vm::psv::write64(cpu.SP + stack_pos, arg); + } + }; + + template + struct bind_arg + { + static_assert(std::is_same::value, "Invalid function argument type for ARG_CONTEXT"); + + force_inline static ARMv7Thread& get_arg(ARMv7Thread& cpu) + { + return cpu; + } + + force_inline static void put_arg(ARMv7Thread& cpu, ARMv7Thread& arg) + { + } + }; + + template + struct bind_arg + { + static_assert(std::is_same::value, "Invalid function argument type for ARG_VARIADIC"); + + force_inline static arm_va_args_t get_arg(ARMv7Thread& cpu) + { + return{ g_count }; + } + }; + + template + struct bind_result + { + static_assert(type != ARG_FLOAT, "TODO: Unsupported funcion result type (float)"); + static_assert(type != ARG_VECTOR, "TODO: Unsupported funcion result type (vector)"); + static_assert(type == ARG_GENERAL, "Wrong use of bind_result template"); + static_assert(sizeof(T) <= 4, "Invalid function result type for ARG_GENERAL"); + + force_inline static T get_result(ARMv7Thread& cpu) + { + return arm_gpr_cast(cpu.GPR[0]); + } + + force_inline static void put_result(ARMv7Thread& cpu, const T& result) + { + cpu.GPR[0] = arm_gpr_cast(result); + } + }; + + template<> + struct bind_result + { + force_inline static u64 get_result(ARMv7Thread& cpu) + { + return cpu.GPR_D[0]; + } + + force_inline static void put_result(ARMv7Thread& cpu, u64 result) + { + cpu.GPR_D[0] = result; + } + }; + + template<> + struct bind_result + { + force_inline static s64 get_result(ARMv7Thread& cpu) + { + return cpu.GPR_D[0]; + } + + force_inline static void put_result(ARMv7Thread& cpu, s64 result) + { + cpu.GPR_D[0] = result; + } + }; + + //template + //struct bind_result + //{ + // static_assert(sizeof(T) <= 8, "Invalid function result type for ARG_FLOAT"); + + // static force_inline void put_result(ARMv7Thread& cpu, const T& result) + // { + // } + //}; + + //template + //struct bind_result + //{ + // static_assert(std::is_same, v128>::value, "Invalid function result type for ARG_VECTOR"); + + // static force_inline void put_result(ARMv7Thread& cpu, const T& result) + // { + // } + //}; + + template + struct result_type + { + static_assert(!std::is_pointer::value, "Invalid function result type (pointer)"); + static_assert(!std::is_reference::value, "Invalid function result type (reference)"); + static const bool is_float = std::is_floating_point::value; + static const bool is_vector = std::is_same::value; + static const arg_class value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); + }; + + template + struct arg_type + { + // TODO: check calculations + static const bool is_float = std::is_floating_point::value; + static const bool is_vector = std::is_same::value; + static const bool is_context = std::is_same::value; + static const bool is_variadic = std::is_same::value; + static const bool is_general = !is_float && !is_vector && !is_context && !is_variadic; + + static const u32 g_align = ALIGN_32(T) > 4 ? ALIGN_32(T) >> 2 : 1; + static const u32 g_value = is_general ? ((g_count + (g_align - 1)) & ~(g_align - 1)) + (g_align) : g_count; + static const u32 f_value = f_count + is_float; + static const u32 v_value = v_count + is_vector; + + static const arg_class value = + is_general ? (g_value > 4 ? ARG_STACK : ARG_GENERAL) : + is_float ? (f_value > 9000 ? ARG_STACK : ARG_FLOAT) : + is_vector ? (v_value > 9000 ? ARG_STACK : ARG_VECTOR) : + is_context ? ARG_CONTEXT : + is_variadic ? ARG_VARIADIC : + ARG_UNKNOWN; + }; + + // wrapper for variadic argument info list, each value contains packed argument type and counts of GENERAL, FLOAT and VECTOR arguments + template struct arg_info_pack_t; + + template struct arg_info_pack_t + { + static const u32 last_value = arg_info_pack_t::last_value; + }; + + template struct arg_info_pack_t + { + static const u32 last_value = First; + }; + + template<> struct arg_info_pack_t<> + { + static const u32 last_value = 0; + }; + + // argument type + g/f/v_count unpacker + template struct bind_arg_packed + { + force_inline static T get_arg(ARMv7Thread& cpu) + { + return bind_arg(type_pack & 0xff), (type_pack >> 8) & 0xff, (type_pack >> 16) & 0xff, (type_pack >> 24)>::get_arg(cpu); + } + }; + + template + force_inline RT call(ARMv7Thread& cpu, RT(*func)(Args...), arg_info_pack_t info) + { + // do the actual function call when all arguments are prepared (simultaneous unpacking of Args... and Info...) + return func(bind_arg_packed::get_arg(cpu)...); + } + + template + force_inline RT call(ARMv7Thread& cpu, RT(*func)(Args...), arg_info_pack_t info) + { + // unpack previous type counts (0/0/0 for the first time) + const u32 g_count = (info.last_value >> 8) & 0xff; + const u32 f_count = (info.last_value >> 16) & 0xff; + const u32 v_count = (info.last_value >> 24); + + using type = arg_type; + const arg_class t = type::value; + const u32 g = type::g_value; + const u32 f = type::f_value; + const u32 v = type::v_value; + + return call(cpu, func, arg_info_pack_t{}); + } + + template + force_inline static bool put_func_args(ARMv7Thread& cpu) + { + // terminator + return false; + } + + template + force_inline static bool put_func_args(ARMv7Thread& cpu, T1 arg, T... args) + { + using type = arg_type; + const arg_class t = type::value; + const u32 g = type::g_value; + const u32 f = type::f_value; + const u32 v = type::v_value; + + bind_arg::put_arg(cpu, arg); + + // return true if stack was used + return put_func_args(cpu, args...) || (t == ARG_STACK); + } + + template + struct func_binder; + + template + struct func_binder + { + using func_t = void(*)(T...); + + static void do_call(ARMv7Thread& cpu, func_t func) + { + call(cpu, func, arg_info_pack_t<>{}); + } + }; + + template + struct func_binder + { + using func_t = RT(*)(T...); + + static void do_call(ARMv7Thread& cpu, func_t func) + { + bind_result::value>::put_result(cpu, call(cpu, func, arg_info_pack_t<>{})); + } + }; + + template + struct func_caller + { + force_inline static RT call(ARMv7Thread& cpu, u32 addr, T... args) + { + func_caller::call(cpu, addr, args...); + + return bind_result::value>::get_result(cpu); + } + }; + + template + struct func_caller + { + force_inline static void call(ARMv7Thread& cpu, u32 addr, T... args) + { + if (put_func_args<0, 0, 0, T...>(cpu, args...)) + { + cpu.SP -= FIXED_STACK_FRAME_SIZE; + cpu.fast_call(addr); + cpu.SP += FIXED_STACK_FRAME_SIZE; + } + else + { + cpu.fast_call(addr); + } + } + }; + + template force_inline void do_call(ARMv7Thread& cpu, RT(*func)(T...)) + { + func_binder::do_call(cpu, func); + } +} + +class arm_function_manager +{ + // Global variable for each registered function + template + struct registered + { + static u32 index; + }; + + // Access global function list + static never_inline auto& access() + { + static std::vector list + { + nullptr, + [](ARMv7Thread& cpu) { cpu.state += cpu_state::ret; }, + }; + + return list; + } + + static never_inline u32 add_function(arm_function_t function) + { + auto& list = access(); + + list.push_back(function); + + return ::size32(list) - 1; + } + +public: + // Register function (shall only be called during global initialization) + template + static inline u32 register_function(arm_function_t func) + { + return registered::index = add_function(func); + } + + // Get function index + template + static inline u32 get_index() + { + return registered::index; + } + + // Read all registered functions + static inline const auto& get() + { + return access(); + } +}; + +template +u32 arm_function_manager::registered::index = 0; + +#define FIND_FUNC(func) arm_function_manager::get_index() diff --git a/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp b/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp index 91a96411c3..30330a477a 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp @@ -1,585 +1,62 @@ #include "stdafx.h" -#include "Emu/System.h" #include "Emu/Memory/Memory.h" -#include "Emu/CPU/CPUDecoder.h" +#include "Emu/System.h" #include "ARMv7Thread.h" -#include "PSVFuncList.h" #include "ARMv7Interpreter.h" -#define reject(cond, info) { if (cond) throw EXCEPTION("%s ('%s', type=%s)", info, #cond, fmt_encoding(type)); } +using namespace arm_code::arm_encoding_alias; -std::map g_armv7_dump; +#define ARG(arg, ...) const u32 arg = args::arg::extract(__VA_ARGS__); -namespace ARMv7_instrs +extern void arm_execute_function(ARMv7Thread& cpu, u32 index); + +namespace vm { using namespace psv; } + +void arm_interpreter::UNK(ARMv7Thread& cpu, const u32 op, const u32 cond) { - template - u32 BitCount(T x, size_t len = sizeof(T) * 8) + if (cpu.ISET == Thumb) { - u32 result = 0; - - for (T mask = static_cast(1) << (len - 1); mask; mask >>= 1) + if (op > 0xffff) { - if (x & mask) result++; - } - - return result; - } - - //template - //s8 LowestSetBit(T x, u8 len) - //{ - // if (!x) return len; - - // u8 result = 0; - - // for (T mask = 1, i = 0; i - //s8 HighestSetBit(T x, u8 len) - //{ - // if (!x) return -1; - - // u8 result = len; - - // for (T mask = T(1) << (len - 1); (x & mask) == 0; mask >>= 1) - // { - // result--; - // } - - // return result; - //} - - //template - //s8 CountLeadingZeroBits(T x, u8 len) - //{ - // return len - 1 - HighestSetBit(x, len); - //} - - SRType DecodeImmShift(u32 type, u32 imm5, u32* shift_n) - { - SRType shift_t; - - switch (type) - { - case 0: shift_t = SRType_LSL; if (shift_n) *shift_n = imm5; break; - case 1: shift_t = SRType_LSR; if (shift_n) *shift_n = imm5 == 0 ? 32 : imm5; break; - case 2: shift_t = SRType_ASR; if (shift_n) *shift_n = imm5 == 0 ? 32 : imm5; break; - case 3: - if (imm5 == 0) - { - shift_t = SRType_RRX; if (shift_n) *shift_n = 1; - } - else - { - shift_t = SRType_ROR; if (shift_n) *shift_n = imm5; - } - break; - - default: throw EXCEPTION(""); - } - - return shift_t; - } - - //SRType DecodeRegShift(u8 type) - //{ - // SRType shift_t; - - // switch (type) - // { - // case 0: shift_t = SRType_LSL; break; - // case 1: shift_t = SRType_LSR; break; - // case 2: shift_t = SRType_ASR; break; - // case 3: shift_t = SRType_ROR; break; - // default: throw EXCEPTION(""); - // } - - // return shift_t; - //} - - u32 LSL_C(u32 x, s32 shift, bool& carry_out) - { - assert(shift > 0); - carry_out = shift <= 32 ? (x & (1 << (32 - shift))) != 0 : false; - return shift < 32 ? x << shift : 0; - } - - u32 LSL_(u32 x, s32 shift) - { - assert(shift >= 0); - return shift < 32 ? x << shift : 0; - } - - u32 LSR_C(u32 x, s32 shift, bool& carry_out) - { - assert(shift > 0); - carry_out = shift <= 32 ? (x & (1 << (shift - 1))) != 0 : false; - return shift < 32 ? x >> shift : 0; - } - - u32 LSR_(u32 x, s32 shift) - { - assert(shift >= 0); - return shift < 32 ? x >> shift : 0; - } - - s32 ASR_C(s32 x, s32 shift, bool& carry_out) - { - assert(shift > 0); - carry_out = shift <= 32 ? (x & (1 << (shift - 1))) != 0 : x < 0; - return shift < 32 ? x >> shift : x >> 31; - } - - s32 ASR_(s32 x, s32 shift) - { - assert(shift >= 0); - return shift < 32 ? x >> shift : x >> 31; - } - - u32 ROR_C(u32 x, s32 shift, bool& carry_out) - { - assert(shift); - const u32 result = x >> shift | x << (32 - shift); - carry_out = (result >> 31) != 0; - return result; - } - - u32 ROR_(u32 x, s32 shift) - { - return x >> shift | x << (32 - shift); - } - - u32 RRX_C(u32 x, bool carry_in, bool& carry_out) - { - carry_out = x & 0x1; - return ((u32)carry_in << 31) | (x >> 1); - } - - u32 RRX_(u32 x, bool carry_in) - { - return ((u32)carry_in << 31) | (x >> 1); - } - - u32 Shift_C(u32 value, u32 type, s32 amount, bool carry_in, bool& carry_out) - { - assert(type != SRType_RRX || amount == 1); - - if (amount) - { - switch (type) - { - case SRType_LSL: return LSL_C(value, amount, carry_out); - case SRType_LSR: return LSR_C(value, amount, carry_out); - case SRType_ASR: return ASR_C(value, amount, carry_out); - case SRType_ROR: return ROR_C(value, amount, carry_out); - case SRType_RRX: return RRX_C(value, carry_in, carry_out); - default: throw EXCEPTION(""); - } - } - - carry_out = carry_in; - return value; - } - - u32 Shift(u32 value, u32 type, s32 amount, bool carry_in) - { - bool carry_out; - return Shift_C(value, type, amount, carry_in, carry_out); - } - - template T AddWithCarry(T x, T y, bool carry_in, bool& carry_out, bool& overflow) - { - const T sign_mask = (T)1 << (sizeof(T) * 8 - 1); - - T result = x + y; - carry_out = (((x & y) | ((x ^ y) & ~result)) & sign_mask) != 0; - overflow = ((x ^ result) & (y ^ result) & sign_mask) != 0; - if (carry_in) - { - result += 1; - carry_out ^= (result == 0); - overflow ^= (result == sign_mask); - } - return result; - } - - u32 ThumbExpandImm_C(u32 imm12, bool carry_in, bool& carry_out) - { - if ((imm12 & 0xc00) >> 10) - { - u32 unrotated_value = (imm12 & 0x7f) | 0x80; - - return ROR_C(unrotated_value, (imm12 & 0xf80) >> 7, carry_out); + throw fmt::exception("Unknown/Illegal opcode: 0x%04X 0x%04X (cond=0x%x)", op >> 16, op & 0xffff, cond); } else { - carry_out = carry_in; - - u32 imm8 = imm12 & 0xff; - switch ((imm12 & 0x300) >> 8) - { - case 0: return imm8; - case 1: return imm8 << 16 | imm8; - case 2: return imm8 << 24 | imm8 << 8; - default: return imm8 << 24 | imm8 << 16 | imm8 << 8 | imm8; - } + throw fmt::exception("Unknown/Illegal opcode: 0x%04X (cond=0x%x)", op, cond); } } - - u32 ThumbExpandImm(u32 imm12) - { - bool carry = false; - return ThumbExpandImm_C(imm12, carry, carry); - } - - bool ConditionPassed(ARMv7Context& context, u32 cond) - { - bool result = false; - - switch (cond >> 1) - { - case 0: result = (context.APSR.Z == 1); break; - case 1: result = (context.APSR.C == 1); break; - case 2: result = (context.APSR.N == 1); break; - case 3: result = (context.APSR.V == 1); break; - case 4: result = (context.APSR.C == 1) && (context.APSR.Z == 0); break; - case 5: result = (context.APSR.N == context.APSR.V); break; - case 6: result = (context.APSR.N == context.APSR.V) && (context.APSR.Z == 0); break; - case 7: return true; - } - - if (cond & 0x1) - { - return !result; - } - - return result; - } - - bool process_debug(ARMv7Context& context) - { - if (context.debug & DF_PRINT) - { - auto pos = context.debug_str.find(' '); - if (pos != std::string::npos && pos < 8) - { - context.debug_str.insert(pos, 8 - pos, ' '); - } - - context.fmt_debug_str("0x%08x: %s", context.PC, context.debug_str); - - LV2_LOCK; - - auto found = g_armv7_dump.find(context.PC); - if (found != g_armv7_dump.end()) - { - if (found->second != context.debug_str) - { - throw EXCEPTION("Disasm inconsistency: '%s' != '%s'", found->second.c_str(), context.debug_str.c_str()); - } - } - else - { - g_armv7_dump[context.PC] = context.debug_str; - } - } - - if (context.debug & DF_NO_EXE) - { - return true; - } - - return false; - } - - const char* fmt_encoding(const ARMv7_encoding type) - { - switch (type) - { - case T1: return "T1"; - case T2: return "T2"; - case T3: return "T3"; - case T4: return "T4"; - case A1: return "A1"; - case A2: return "A2"; - default: return "???"; - } - }; - - const char* fmt_cond(u32 cond) - { - switch (cond) - { - case 0: return "eq"; - case 1: return "ne"; - case 2: return "cs"; - case 3: return "cc"; - case 4: return "mi"; - case 5: return "pl"; - case 6: return "vs"; - case 7: return "vc"; - case 8: return "hi"; - case 9: return "ls"; - case 10: return "ge"; - case 11: return "lt"; - case 12: return "gt"; - case 13: return "le"; - case 14: return ""; - default: return "???"; - } - } - - const char* fmt_it(u32 state) - { - switch (state & ~0x10) - { - case 0x8: return ""; - - case 0x4: return state & 0x10 ? "e" : "t"; - case 0xc: return state & 0x10 ? "t" : "e"; - - case 0x2: return state & 0x10 ? "ee" : "tt"; - case 0x6: return state & 0x10 ? "et" : "te"; - case 0xa: return state & 0x10 ? "te" : "et"; - case 0xe: return state & 0x10 ? "tt" : "ee"; - - case 0x1: return state & 0x10 ? "eee" : "ttt"; - case 0x3: return state & 0x10 ? "eet" : "tte"; - case 0x5: return state & 0x10 ? "ete" : "tet"; - case 0x7: return state & 0x10 ? "ett" : "tee"; - case 0x9: return state & 0x10 ? "tee" : "ett"; - case 0xb: return state & 0x10 ? "tet" : "ete"; - case 0xd: return state & 0x10 ? "tte" : "eet"; - case 0xf: return state & 0x10 ? "ttt" : "eee"; - - default: return "???"; - } - } - - const char* fmt_reg(u32 reg) - { - switch (reg) - { - case 0: return "r0"; - case 1: return "r1"; - case 2: return "r2"; - case 3: return "r3"; - case 4: return "r4"; - case 5: return "r5"; - case 6: return "r6"; - case 7: return "r7"; - case 8: return "r8"; - case 9: return "r9"; - case 10: return "r10"; - case 11: return "r11"; - case 12: return "r12"; - case 13: return "sp"; - case 14: return "lr"; - case 15: return "pc"; - default: return "r???"; - } - } - - std::string fmt_shift(u32 type, u32 amount) - { - assert(type != SRType_RRX || amount == 1); - assert(amount <= 32); - - if (amount) - { - switch (type) - { - case SRType_LSL: return ",lsl #" + fmt::to_udec(amount); - case SRType_LSR: return ",lsr #" + fmt::to_udec(amount); - case SRType_ASR: return ",asr #" + fmt::to_udec(amount); - case SRType_ROR: return ",ror #" + fmt::to_udec(amount); - case SRType_RRX: return ",rrx"; - default: return ",?????"; - } - } - - return{}; - } - - std::string fmt_reg_list(u32 reg_list) - { - std::vector> lines; - - for (u32 i = 0; i < 13; i++) - { - if (reg_list & (1 << i)) - { - if (lines.size() && lines.rbegin()->second == i - 1) - { - lines.rbegin()->second = i; - } - else - { - lines.push_back({ i, i }); - } - } - } - - if (reg_list & 0x2000) lines.push_back({ 13, 13 }); // sp - if (reg_list & 0x4000) lines.push_back({ 14, 14 }); // lr - if (reg_list & 0x8000) lines.push_back({ 15, 15 }); // pc - - std::string result; - - if (reg_list >> 16) result = "???"; // invalid bits - - for (auto& line : lines) - { - if (!result.empty()) - { - result += ","; - } - - if (line.first == line.second) - { - result += fmt_reg(line.first); - } - else - { - result += fmt_reg(line.first); - result += '-'; - result += fmt_reg(line.second); - } - } - - return result; - } - - std::string fmt_mem_imm(u32 reg, u32 imm, bool index, bool add, bool wback) - { - if (index) - { - return fmt::format("[%s,#%s0x%X]%s", fmt_reg(reg), add ? "" : "-", imm, wback ? "!" : ""); - } - else - { - return fmt::format("[%s],#%s0x%X%s", fmt_reg(reg), add ? "" : "-", imm, wback ? "" : "???"); - } - } - - std::string fmt_mem_reg(u32 n, u32 m, bool index, bool add, bool wback, u32 shift_t = SRType_LSL, u32 shift_n = 0) - { - if (index) - { - return fmt::format("[%s,%s%s%s]%s", fmt_reg(n), add ? "" : "-", fmt_reg(m), fmt_shift(shift_t, shift_n), wback ? "!" : ""); - } - else - { - return fmt::format("[%s],%s%s%s%s", fmt_reg(n), add ? "" : "-", fmt_reg(m), fmt_shift(shift_t, shift_n), wback ? "" : "???"); - } - } -} - -void ARMv7_instrs::UNK(ARMv7Context& context, const ARMv7Code code) -{ - if (context.ISET == Thumb) - { - throw EXCEPTION("Unknown/illegal opcode: 0x%04X 0x%04X", code.code1, code.code0); - } else { - throw EXCEPTION("Unknown/illegal opcode: 0x%08X", code.data); + throw fmt::exception("Unknown/Illegal opcode: 0x%08X", op); } } -void ARMv7_instrs::HACK(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::HACK(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, index; + using args = arm_code::hack; + ARG(index, op); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - index = code.data & 0xffff; - break; - } - case A1: - { - cond = code.data >> 28; - index = (code.data & 0xfff00) >> 4 | (code.data & 0xf); - break; - } - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) - { - if (auto func = get_psv_func_by_index(index)) - { - if (func->func) - { - context.fmt_debug_str("hack%s %s", fmt_cond(cond), func->name); - } - else - { - context.fmt_debug_str("hack%s UNIMPLEMENTED:0x%08X (%s)", fmt_cond(cond), func->nid, func->name); - } - } - else - { - context.fmt_debug_str("hack%s %d", fmt_cond(cond), index); - } - } - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - execute_psv_func_by_index(static_cast(context), index); + arm_execute_function(cpu, index); } } -void ARMv7_instrs::MRC_(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) + +template +void arm_interpreter::MRC_(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, t, cp, opc1, opc2, cn, cm; + using args = arm_code::mrc; + ARG(t, op); + ARG(cp, op); + ARG(opc1, op); + ARG(opc2, op); + ARG(cn, op); + ARG(cm, op); - switch (type) - { - case T1: case A1: - case T2: case A2: - { - cond = type == A1 ? code.data >> 28 : context.ITSTATE.advance(); - t = (code.data & 0xf000) >> 12; - cp = (code.data & 0xf00) >> 8; - opc1 = (code.data & 0xe00000) >> 21; - opc2 = (code.data & 0xe0) >> 5; - cn = (code.data & 0xf0000) >> 16; - cm = (code.data & 0xf); - - reject(cp - 10 < 2 && (type == T1 || type == A1), "Advanced SIMD and VFP"); - reject(t == 13 && (type == T1 || type == T2), "UNPREDICTABLE"); - break; - } - default: throw EXCEPTION(""); - } - - auto disasm = [&]() - { - context.fmt_debug_str("mrc%s p%d,%d,r%d,c%d,c%d,%d", fmt_cond(cond), cp, opc1, t, cn, cm, opc2); - }; - - if (context.debug) - { - if (context.debug & DF_DISASM) disasm(); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) + if (ConditionPassed(cpu, cond)) { // APSR flags are written if t = 15 @@ -587,6252 +64,4122 @@ void ARMv7_instrs::MRC_(ARMv7Context& context, const ARMv7Code code, const ARMv7 { // Read CP15 User Read-only Thread ID Register (seems used as TLS address) - if (!context.TLS) + if (!cpu.TLS) { - throw EXCEPTION("TLS not initialized"); + throw fmt::exception("TLS not initialized" HERE); } - context.GPR[t] = context.TLS; + cpu.GPR[t] = cpu.TLS; return; } - throw EXCEPTION("Bad instruction: '%s' (code=0x%x, type=%d)", (disasm(), context.debug_str.c_str()), code.data, type); + throw fmt::exception("mrc?? p%d,%d,r%d,c%d,c%d,%d" HERE, cp, opc1, t, cn, cm, opc2); } } -void ARMv7_instrs::ADC_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::ADC_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, d, n, imm32; - bool set_flags; + using args = arm_code::adc_imm; + ARG(d, op); + ARG(n, op); + ARG(imm32, op); + ARG(set_flags, op, cond); - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - n = (code.data & 0xf0000) >> 16; - set_flags = (code.data & 0x100000) != 0; - imm32 = ThumbExpandImm((code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff)); - - reject(d == 13 || d == 15 || n == 13 || n == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("adc%s%s %s,%s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), imm32); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) + if (ConditionPassed(cpu, cond)) { bool carry, overflow; - const u32 result = AddWithCarry(context.read_gpr(n), imm32, context.APSR.C, carry, overflow); - context.write_gpr(d, result, 4); + const u32 result = AddWithCarry(cpu.read_gpr(n), imm32, cpu.APSR.C, carry, overflow); + cpu.write_gpr(d, result, 4); if (set_flags) { - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; - context.APSR.V = overflow; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = carry; + cpu.APSR.V = overflow; } } } -void ARMv7_instrs::ADC_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::ADC_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - bool set_flags = !context.ITSTATE; - u32 cond, d, n, m, shift_t, shift_n; + using args = arm_code::adc_reg; + ARG(d, op); + ARG(n, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + ARG(set_flags, op, cond); - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - d = n = (code.data & 0x7); - m = (code.data & 0x38) >> 3; - shift_t = SRType_LSL; - shift_n = 0; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - n = (code.data & 0xf0000) >> 16; - m = (code.data & 0xf); - set_flags = (code.data & 0x100000) != 0; - shift_t = DecodeImmShift((code.data & 0x30) >> 4, (code.data & 0x7000) >> 10 | (code.data & 0xc0) >> 6, &shift_n); - - reject(d == 13 || d == 15 || n == 13 || n == 15 || m == 13 || m == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("adc%s%s %s,%s,%s%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m), fmt_shift(shift_t, shift_n)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) + if (ConditionPassed(cpu, cond)) { bool carry, overflow; - const u32 shifted = Shift(context.read_gpr(m), shift_t, shift_n, context.APSR.C); - const u32 result = AddWithCarry(context.read_gpr(n), shifted, context.APSR.C, carry, overflow); - context.write_gpr(d, result, type == T1 ? 2 : 4); + const u32 shifted = Shift(cpu.read_gpr(m), shift_t, shift_n, cpu.APSR.C); + const u32 result = AddWithCarry(cpu.read_gpr(n), shifted, cpu.APSR.C, carry, overflow); + cpu.write_gpr(d, result, type == T1 ? 2 : 4); if (set_flags) { - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; - context.APSR.V = overflow; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = carry; + cpu.APSR.V = overflow; } } } -void ARMv7_instrs::ADC_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::ADC_RSR(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::ADD_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::ADD_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - bool set_flags = !context.ITSTATE; - u32 cond, d, n, imm32; + using args = arm_code::add_imm; + ARG(d, op); + ARG(n, op); + ARG(imm32, op); + ARG(set_flags, op, cond); - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0x7); - n = (code.data & 0x38) >> 3; - imm32 = (code.data & 0x1c0) >> 6; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - d = n = (code.data & 0x700) >> 8; - imm32 = (code.data & 0xff); - break; - } - case T3: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - n = (code.data & 0xf0000) >> 16; - set_flags = (code.data & 0x100000) != 0; - imm32 = ThumbExpandImm((code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff)); - - reject(d == 15 && set_flags, "CMN (immediate)"); - reject(n == 13, "ADD (SP plus immediate)"); - reject(d == 13 || n == 15, "UNPREDICTABLE"); - break; - } - case T4: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - n = (code.data & 0xf0000) >> 16; - set_flags = false; - imm32 = (code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff); - - reject(n == 15, "ADR"); - reject(n == 13, "ADD (SP plus immediate)"); - reject(d == 13 || d == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("add%s%s %s,%s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), imm32); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) + if (ConditionPassed(cpu, cond)) { bool carry, overflow; - const u32 result = AddWithCarry(context.read_gpr(n), imm32, false, carry, overflow); - context.write_gpr(d, result, type < T3 ? 2 : 4); + const u32 result = AddWithCarry(cpu.read_gpr(n), imm32, false, carry, overflow); + cpu.write_gpr(d, result, type < T3 ? 2 : 4); if (set_flags) { - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; - context.APSR.V = overflow; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = carry; + cpu.APSR.V = overflow; } } } -void ARMv7_instrs::ADD_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::ADD_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - bool set_flags = !context.ITSTATE; - u32 cond, d, n, m, shift_t, shift_n; + using args = arm_code::add_reg; + ARG(d, op); + ARG(n, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + ARG(set_flags, op, cond); - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0x7); - n = (code.data & 0x38) >> 3; - m = (code.data & 0x1c0) >> 6; - shift_t = SRType_LSL; - shift_n = 0; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - n = d = (code.data & 0x80) >> 4 | (code.data & 0x7); - m = (code.data & 0x78) >> 3; - set_flags = false; - shift_t = SRType_LSL; - shift_n = 0; - - reject(n == 13 || m == 13, "ADD (SP plus register)"); - reject(n == 15 && m == 15, "UNPREDICTABLE"); - reject(d == 15 && context.ITSTATE, "UNPREDICTABLE"); - break; - } - case T3: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - n = (code.data & 0xf0000) >> 16; - m = (code.data & 0xf); - set_flags = (code.data & 0x100000) != 0; - shift_t = DecodeImmShift((code.data & 0x30) >> 4, (code.data & 0x7000) >> 10 | (code.data & 0xc0) >> 6, &shift_n); - - reject(d == 15 && set_flags, "CMN (register)"); - reject(n == 13, "ADD (SP plus register)"); - reject(d == 13 || n == 15 || m == 13 || m == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("add%s%s %s,%s,%s%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m), fmt_shift(shift_t, shift_n)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) + if (ConditionPassed(cpu, cond)) { bool carry, overflow; - const u32 shifted = Shift(context.read_gpr(m), shift_t, shift_n, true); - const u32 result = AddWithCarry(context.read_gpr(n), shifted, false, carry, overflow); - context.write_gpr(d, result, type < T3 ? 2 : 4); + const u32 shifted = Shift(cpu.read_gpr(m), shift_t, shift_n, true); + const u32 result = AddWithCarry(cpu.read_gpr(n), shifted, false, carry, overflow); + cpu.write_gpr(d, result, type < T3 ? 2 : 4); if (set_flags) { - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; - context.APSR.V = overflow; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = carry; + cpu.APSR.V = overflow; } } } -void ARMv7_instrs::ADD_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::ADD_RSR(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::ADD_SPI(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::ADD_SPI(ARMv7Thread& cpu, const u32 op, const u32 cond) { - bool set_flags; - u32 cond, d, imm32; + using args = arm_code::add_spi; + ARG(d, op); + ARG(imm32, op); + ARG(set_flags, op, cond); - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0x700) >> 8; - set_flags = false; - imm32 = (code.data & 0xff) << 2; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - d = 13; - set_flags = false; - imm32 = (code.data & 0x7f) << 2; - break; - } - case T3: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - set_flags = (code.data & 0x100000) != 0; - imm32 = ThumbExpandImm((code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff)); - - reject(d == 15 && set_flags, "CMN (immediate)"); - reject(d == 15, "UNPREDICTABLE"); - break; - } - case T4: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - set_flags = false; - imm32 = (code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff); - - reject(d == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("add%s%s %s,sp,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), imm32); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) + if (ConditionPassed(cpu, cond)) { bool carry, overflow; - const u32 result = AddWithCarry(context.SP, imm32, false, carry, overflow); - context.write_gpr(d, result, type < T3 ? 2 : 4); + const u32 result = AddWithCarry(cpu.SP, imm32, false, carry, overflow); + cpu.write_gpr(d, result, type < T3 ? 2 : 4); if (set_flags) { - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; - context.APSR.V = overflow; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = carry; + cpu.APSR.V = overflow; } } } -void ARMv7_instrs::ADD_SPR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::ADD_SPR(ARMv7Thread& cpu, const u32 op, const u32 cond) { - bool set_flags; - u32 cond, d, m, shift_t, shift_n; + using args = arm_code::add_spr; + ARG(d, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + ARG(set_flags, op, cond); - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - d = m = (code.data & 0x80) >> 4 | (code.data & 0x7); - set_flags = false; - shift_t = SRType_LSL; - shift_n = 0; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - d = 13; - m = (code.data & 0x78) >> 3; - set_flags = false; - shift_t = SRType_LSL; - shift_n = 0; - - reject(m == 13, "encoding T1"); - break; - } - case T3: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - m = (code.data & 0xf); - set_flags = (code.data & 0x100000) != 0; - shift_t = DecodeImmShift((code.data & 0x30) >> 4, (code.data & 0x7000) >> 10 | (code.data & 0xc0) >> 6, &shift_n); - - reject(d == 13 && (shift_t != SRType_LSL || shift_n > 3), "UNPREDICTABLE"); - reject(d == 15 || m == 13 || m == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("add%s%s %s,sp,%s%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(m), fmt_shift(shift_t, shift_n)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) + if (ConditionPassed(cpu, cond)) { bool carry, overflow; - const u32 shifted = Shift(context.read_gpr(m), shift_t, shift_n, context.APSR.C); - const u32 result = AddWithCarry(context.SP, shifted, false, carry, overflow); - context.write_gpr(d, result, type < T3 ? 2 : 4); + const u32 shifted = Shift(cpu.read_gpr(m), shift_t, shift_n, cpu.APSR.C); + const u32 result = AddWithCarry(cpu.SP, shifted, false, carry, overflow); + cpu.write_gpr(d, result, type < T3 ? 2 : 4); if (set_flags) { - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; - context.APSR.V = overflow; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = carry; + cpu.APSR.V = overflow; } } } -void ARMv7_instrs::ADR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::ADR(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, d, imm32; - bool add; + using args = arm_code::adr; + ARG(d, op); + ARG(i, op); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0x700) >> 8; - imm32 = (code.data & 0xff) << 2; - add = true; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - imm32 = (code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff); - add = false; - - reject(d == 13 || d == 15, "UNPREDICTABLE"); - break; - } - case T3: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - imm32 = (code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff); - add = true; - - reject(d == 13 || d == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - const u32 base = context.read_pc() & ~3; - const u32 result = add ? base + imm32 : base - imm32; - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("adr%s r%d, 0x%08X", fmt_cond(cond), d, result); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - context.write_gpr(d, result, type == T1 ? 2 : 4); + cpu.write_gpr(d, (cpu.read_pc() & ~3) + i, type == T1 ? 2 : 4); } } -void ARMv7_instrs::AND_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::AND_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, d, n, imm32; - bool set_flags, carry = context.APSR.C; + using args = arm_code::and_imm; + ARG(d, op); + ARG(n, op); + ARG(imm32, op); + ARG(set_flags, op, cond); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - n = (code.data & 0xf0000) >> 16; - set_flags = (code.data & 0x100000) != 0; - imm32 = ThumbExpandImm_C((code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff), carry, carry); - - reject(d == 15 && set_flags, "TST (immediate)"); - reject(d == 13 || d == 15 || n == 13 || n == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("and%s%s %s,%s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), imm32); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - const u32 result = context.read_gpr(n) & imm32; - context.write_gpr(d, result, 4); + const u32 result = cpu.read_gpr(n) & imm32; + cpu.write_gpr(d, result, 4); if (set_flags) { - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = args::carry::extract(op, cpu.APSR.C); } } } -void ARMv7_instrs::AND_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::AND_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - bool set_flags = !context.ITSTATE; - u32 cond, d, n, m, shift_t, shift_n; + using args = arm_code::and_reg; + ARG(d, op); + ARG(n, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + ARG(set_flags, op, cond); - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - d = n = (code.data & 0x7); - m = (code.data & 0x38) >> 3; - shift_t = SRType_LSL; - shift_n = 0; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - n = (code.data & 0xf0000) >> 16; - m = (code.data & 0xf); - set_flags = (code.data & 0x100000) != 0; - shift_t = DecodeImmShift((code.data & 0x30) >> 4, (code.data & 0x7000) >> 10 | (code.data & 0xc0) >> 6, &shift_n); - - reject(d == 15 && set_flags, "TST (register)"); - reject(d == 13 || d == 15 || n == 13 || n == 15 || m == 13 || m == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("and%s%s %s,%s,%s%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m), fmt_shift(shift_t, shift_n)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) + if (ConditionPassed(cpu, cond)) { bool carry; - const u32 shifted = Shift_C(context.read_gpr(m), shift_t, shift_n, context.APSR.C, carry); - const u32 result = context.read_gpr(n) & shifted; - context.write_gpr(d, result, type == T1 ? 2 : 4); + const u32 shifted = Shift_C(cpu.read_gpr(m), shift_t, shift_n, cpu.APSR.C, carry); + const u32 result = cpu.read_gpr(n) & shifted; + cpu.write_gpr(d, result, type == T1 ? 2 : 4); if (set_flags) { - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = carry; } } } -void ARMv7_instrs::AND_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::AND_RSR(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) + throw EXCEPTION("TODO"); +} + + +template +void arm_interpreter::ASR_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) +{ + throw EXCEPTION("TODO"); +} + +template +void arm_interpreter::ASR_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) +{ + throw EXCEPTION("TODO"); +} + + +template +void arm_interpreter::B(ARMv7Thread& cpu, const u32 op, const u32 _cond) +{ + using args = arm_code::b; + ARG(imm32, op); + + if (ConditionPassed(cpu, args::cond::extract(op, _cond))) { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); + cpu.PC = cpu.read_pc() + imm32 - (type < T3 ? 2 : 4); } } -void ARMv7_instrs::ASR_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::BFC(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::ASR_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::BFI(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::B(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::BIC_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, imm32; + using args = arm_code::bic_imm; + ARG(d, op); + ARG(n, op); + ARG(imm32, op); + ARG(set_flags, op, cond); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = (code.data >> 8) & 0xf; - imm32 = sign<9, u32>((code.data & 0xff) << 1); - - reject(cond == 14, "UNDEFINED"); - reject(cond == 15, "SVC"); - reject(context.ITSTATE, "UNPREDICTABLE"); - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - imm32 = sign<12, u32>((code.data & 0x7ff) << 1); - - reject(context.ITSTATE, "UNPREDICTABLE"); - break; - } - case T3: - { - cond = (code.data >> 22) & 0xf; - { - const u32 s = (code.data >> 26) & 0x1; - const u32 j1 = (code.data >> 13) & 0x1; - const u32 j2 = (code.data >> 11) & 0x1; - imm32 = sign<21, u32>(s << 20 | j2 << 19 | j1 << 18 | (code.data & 0x3f0000) >> 4 | (code.data & 0x7ff) << 1); - } - - reject(cond >= 14, "Related encodings"); - reject(context.ITSTATE, "UNPREDICTABLE"); - break; - } - case T4: - { - cond = context.ITSTATE.advance(); - { - const u32 s = (code.data >> 26) & 0x1; - const u32 i1 = (code.data >> 13) & 0x1 ^ s ^ 1; - const u32 i2 = (code.data >> 11) & 0x1 ^ s ^ 1; - imm32 = sign<25, u32>(s << 24 | i2 << 23 | i1 << 22 | (code.data & 0x3ff0000) >> 4 | (code.data & 0x7ff) << 1); - } - - reject(context.ITSTATE, "UNPREDICTABLE"); - break; - } - case A1: - { - cond = code.data >> 28; - imm32 = sign<26, u32>((code.data & 0xffffff) << 2); - break; - } - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("b%s 0x%08X", fmt_cond(cond), context.read_pc() + imm32); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - context.PC = context.read_pc() + imm32 - (type < T3 ? 2 : 4); - } -} - - -void ARMv7_instrs::BFC(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } -} - -void ARMv7_instrs::BFI(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } -} - - -void ARMv7_instrs::BIC_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - bool set_flags, carry = context.APSR.C; - u32 cond, d, n, imm32; - - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - n = (code.data & 0xf0000) >> 16; - set_flags = (code.data & 0x100000) != 0; - imm32 = ThumbExpandImm_C((code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff), carry, carry); - - reject(d == 13 || d == 15 || n == 13 || n == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("bic%s%s %s,%s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), imm32); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - const u32 result = context.read_gpr(n) & ~imm32; - context.write_gpr(d, result, 4); + const u32 result = cpu.read_gpr(n) & ~imm32; + cpu.write_gpr(d, result, 4); if (set_flags) { - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = args::carry::extract(op, cpu.APSR.C); } } } -void ARMv7_instrs::BIC_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::BIC_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - bool set_flags = !context.ITSTATE; - u32 cond, d, n, m, shift_t, shift_n; + using args = arm_code::bic_reg; + ARG(d, op); + ARG(n, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + ARG(set_flags, op, cond); - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - d = n = (code.data & 0x7); - m = (code.data & 0x38) >> 3; - shift_t = SRType_LSL; - shift_n = 0; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - n = (code.data & 0xf0000) >> 16; - m = (code.data & 0xf); - set_flags = (code.data & 0x100000) != 0; - shift_t = DecodeImmShift((code.data & 0x30) >> 4, (code.data & 0x7000) >> 10 | (code.data & 0xc0) >> 6, &shift_n); - - reject(d == 13 || d == 15 || n == 13 || n == 15 || m == 13 || m == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("bic%s%s %s,%s,%s%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m), fmt_shift(shift_t, shift_n)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) + if (ConditionPassed(cpu, cond)) { bool carry; - const u32 shifted = Shift_C(context.read_gpr(m), shift_t, shift_n, context.APSR.C, carry); - const u32 result = context.read_gpr(n) & ~shifted; - context.write_gpr(d, result, type == T1 ? 2 : 4); + const u32 shifted = Shift_C(cpu.read_gpr(m), shift_t, shift_n, cpu.APSR.C, carry); + const u32 result = cpu.read_gpr(n) & ~shifted; + cpu.write_gpr(d, result, type == T1 ? 2 : 4); if (set_flags) { - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = carry; } } } -void ARMv7_instrs::BIC_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::BIC_RSR(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::BKPT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::BKPT(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::BL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::BL(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, imm32; + using args = arm_code::bl; + ARG(imm32, op); + ARG(to_arm); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); + cpu.LR = (cpu.PC + 4) | (cpu.ISET != ARM); + + // TODO: this is quite a mess + if ((cpu.ISET == ARM) == to_arm) { - const u32 s = (code.data >> 26) & 0x1; - const u32 i1 = (code.data >> 13) & 0x1 ^ s ^ 1; - const u32 i2 = (code.data >> 11) & 0x1 ^ s ^ 1; - imm32 = sign<25, u32>(s << 24 | i2 << 23 | i1 << 22 | (code.data & 0x3ff0000) >> 4 | (code.data & 0x7ff) << 1); + const u32 pc = cpu.ISET == ARM ? (cpu.read_pc() & ~3) + imm32 : cpu.read_pc() + imm32; + + cpu.PC = pc - 4; } - - reject(context.ITSTATE, "UNPREDICTABLE"); - break; - } - case A1: - { - cond = code.data >> 28; - imm32 = sign<26, u32>((code.data & 0xffffff) << 2); - break; - } - default: throw EXCEPTION(""); - } - - const u32 lr = context.ISET == ARM ? context.read_pc() - 4 : context.read_pc() | 1; - const u32 pc = context.ISET == ARM ? (context.read_pc() & ~3) + imm32 : context.read_pc() + imm32; - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("bl%s 0x%08X", fmt_cond(cond), pc); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - context.LR = lr; - context.PC = pc - 4; - } -} - -void ARMv7_instrs::BLX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 cond, target, newLR; - - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - newLR = (context.PC + 2) | 1; + else { - const u32 m = (code.data >> 3) & 0xf; - reject(m == 15, "UNPREDICTABLE"); - target = context.read_gpr(m); + const u32 pc = type == T2 ? ~3 & cpu.PC + 4 + imm32 : 1 | cpu.PC + 8 + imm32; + + cpu.write_pc(pc, type == T1 ? 2 : 4); } - - reject(context.ITSTATE, "UNPREDICTABLE"); - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - newLR = (context.PC + 4) | 1; - { - const u32 s = (code.data >> 26) & 0x1; - const u32 i1 = (code.data >> 13) & 0x1 ^ s ^ 1; - const u32 i2 = (code.data >> 11) & 0x1 ^ s ^ 1; - target = ~3 & context.PC + 4 + sign<25, u32>(s << 24 | i2 << 23 | i1 << 22 | (code.data & 0x3ff0000) >> 4 | (code.data & 0x7ff) << 1); - } - - reject(context.ITSTATE, "UNPREDICTABLE"); - break; - } - case A1: - { - cond = code.data >> 28; - newLR = context.PC + 4; - target = context.read_gpr(code.data & 0xf); - break; - } - case A2: - { - cond = 0xe; // always true - newLR = context.PC + 4; - target = 1 | context.PC + 8 + sign<25, u32>((code.data & 0xffffff) << 2 | (code.data & 0x1000000) >> 23); - break; - } - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) - { - switch (type) - { - case T1: context.fmt_debug_str("blx%s %s", fmt_cond(cond), fmt_reg((code.data >> 3) & 0xf)); break; - case T2: context.fmt_debug_str("blx%s 0x%08X", fmt_cond(cond), target); break; - case A1: context.fmt_debug_str("blx%s %s", fmt_cond(cond), fmt_reg(code.data & 0xf)); break; - default: context.fmt_debug_str("blx%s ???", fmt_cond(cond)); - } - } - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - context.LR = newLR; - context.write_pc(target, type == T1 ? 2 : 4); } } -void ARMv7_instrs::BX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::BLX(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, m; + using args = arm_code::blx; + ARG(m, op); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - m = (code.data >> 3) & 0xf; + cpu.LR = type == T1 ? (cpu.PC + 2) | 1 : cpu.PC + 4; + cpu.write_pc(cpu.read_gpr(m), type == T1 ? 2 : 4); + } +} - reject(context.ITSTATE, "UNPREDICTABLE"); - break; - } - case A1: - { - cond = code.data >> 28; - m = (code.data & 0xf); - break; - } - default: throw EXCEPTION(""); - } +template +void arm_interpreter::BX(ARMv7Thread& cpu, const u32 op, const u32 cond) +{ + using args = arm_code::bx; + ARG(m, op); - if (context.debug) + if (ConditionPassed(cpu, cond)) { - if (context.debug & DF_DISASM) context.fmt_debug_str("bx%s %s", fmt_cond(cond), fmt_reg(m)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - context.write_pc(context.read_gpr(m), type == T1 ? 2 : 4); + cpu.write_pc(cpu.read_gpr(m), type == T1 ? 2 : 4); } } -void ARMv7_instrs::CB_Z(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::CB_Z(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 n, imm32; - bool nonzero; + using args = arm_code::cb_z; + ARG(n, op); + ARG(imm32, op); + ARG(nonzero, op); - switch (type) + if ((cpu.read_gpr(n) == 0) ^ nonzero) { - case T1: - { - n = code.data & 0x7; - imm32 = (code.data & 0xf8) >> 2 | (code.data & 0x200) >> 3; - nonzero = (code.data & 0x800) != 0; - - reject(context.ITSTATE, "UNPREDICTABLE"); - break; - } - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("cb%sz 0x%08X", nonzero ? "n" : "", context.read_pc() + imm32); - if (process_debug(context)) return; - } - - if ((context.read_gpr(n) == 0) ^ nonzero) - { - context.PC = context.read_pc() + imm32 - 2; + cpu.PC = cpu.read_pc() + imm32 - 2; } } -void ARMv7_instrs::CLZ(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::CLZ(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, d, m; + using args = arm_code::clz; + ARG(d, op); + ARG(m, op); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - m = (code.data & 0xf); - - reject(m != (code.data & 0xf0000) >> 16, "UNPREDICTABLE"); - reject(d == 13 || d == 15 || m == 13 || m == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("clz%s %s,%s", fmt_cond(cond), fmt_reg(d), fmt_reg(m)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - context.write_gpr(d, cntlz32(context.read_gpr(m)), 4); + cpu.write_gpr(d, cntlz32(cpu.read_gpr(m)), 4); } } -void ARMv7_instrs::CMN_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::CMN_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::CMN_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::CMN_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::CMN_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::CMN_RSR(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::CMP_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::CMP_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, n, imm32; + using args = arm_code::cmp_imm; + ARG(n, op); + ARG(imm32, op); - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - n = (code.data & 0x700) >> 8; - imm32 = (code.data & 0xff); - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - n = (code.data & 0xf0000) >> 16; - imm32 = ThumbExpandImm((code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff)); - - reject(n == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("cmp%s %s,#0x%X", fmt_cond(cond), fmt_reg(n), imm32); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) + if (ConditionPassed(cpu, cond)) { bool carry, overflow; - const u32 n_value = context.read_gpr(n); + const u32 n_value = cpu.read_gpr(n); const u32 result = AddWithCarry(n_value, ~imm32, true, carry, overflow); - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; - context.APSR.V = overflow; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = carry; + cpu.APSR.V = overflow; //LOG_NOTICE(ARMv7, "CMP: r%d=0x%08x <> 0x%08x, res=0x%08x", n, n_value, imm32, res); } } -void ARMv7_instrs::CMP_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::CMP_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, n, m, shift_t, shift_n; + using args = arm_code::cmp_reg; + ARG(n, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - n = (code.data & 0x7); - m = (code.data & 0x38) >> 3; - shift_t = SRType_LSL; - shift_n = 0; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - n = (code.data & 0x80) >> 4 | (code.data & 0x7); - m = (code.data & 0x78) >> 3; - shift_t = SRType_LSL; - shift_n = 0; - - reject(n < 8 && m < 8, "UNPREDICTABLE"); - reject(n == 15 || m == 15, "UNPREDICTABLE"); - break; - } - case T3: - { - cond = context.ITSTATE.advance(); - n = (code.data & 0xf0000) >> 16; - m = (code.data & 0xf); - shift_t = DecodeImmShift((code.data & 0x30) >> 4, (code.data & 0x7000) >> 10 | (code.data & 0xc0) >> 6, &shift_n); - - reject(n == 15 || m == 13 || m == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("cmp%s %s,%s%s", fmt_cond(cond), fmt_reg(n), fmt_reg(m), fmt_shift(shift_t, shift_n)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) + if (ConditionPassed(cpu, cond)) { bool carry, overflow; - const u32 m_value = context.read_gpr(m); - const u32 n_value = context.read_gpr(n); + const u32 m_value = cpu.read_gpr(m); + const u32 n_value = cpu.read_gpr(n); const u32 shifted = Shift(m_value, shift_t, shift_n, true); const u32 result = AddWithCarry(n_value, ~shifted, true, carry, overflow); - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; - context.APSR.V = overflow; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = carry; + cpu.APSR.V = overflow; //LOG_NOTICE(ARMv7, "CMP: r%d=0x%08x <> r%d=0x%08x, shifted=0x%08x, res=0x%08x", n, n_value, m, m_value, shifted, res); } } -void ARMv7_instrs::CMP_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::CMP_RSR(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::DBG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::DBG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::DMB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::DMB(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::DSB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::DSB(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::EOR_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::EOR_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - bool set_flags, carry = context.APSR.C; - u32 cond, d, n, imm32; + using args = arm_code::eor_imm; + ARG(d, op); + ARG(n, op); + ARG(imm32, op); + ARG(set_flags, op, cond); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - n = (code.data & 0xf0000) >> 16; - set_flags = (code.data & 0x100000) != 0; - imm32 = ThumbExpandImm_C((code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff), carry, carry); - - reject(d == 15 && set_flags, "TEQ (immediate)"); - reject(d == 13 || d == 15 || n == 13 || n == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("eor%s%s %s,%s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), imm32); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - const u32 result = context.read_gpr(n) ^ imm32; - context.write_gpr(d, result, 4); + const u32 result = cpu.read_gpr(n) ^ imm32; + cpu.write_gpr(d, result, 4); if (set_flags) { - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = args::carry::extract(op, cpu.APSR.C); } } } -void ARMv7_instrs::EOR_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::EOR_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - bool set_flags = !context.ITSTATE; - u32 cond, d, n, m, shift_t, shift_n; + using args = arm_code::eor_reg; + ARG(d, op); + ARG(n, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + ARG(set_flags, op, cond); - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - d = n = (code.data & 0x7); - m = (code.data & 0x38) >> 3; - shift_t = SRType_LSL; - shift_n = 0; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - n = (code.data & 0xf0000) >> 16; - m = (code.data & 0xf); - set_flags = (code.data & 0x100000) != 0; - shift_t = DecodeImmShift((code.data & 0x30) >> 4, (code.data & 0x7000) >> 10 | (code.data & 0xc0) >> 6, &shift_n); - - reject(d == 15 && set_flags, "TEQ (register)"); - reject(d == 13 || d == 15 || n == 13 || n == 15 || m == 13 || m == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("eor%s%s %s,%s,%s%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m), fmt_shift(shift_t, shift_n)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) + if (ConditionPassed(cpu, cond)) { bool carry; - const u32 shifted = Shift_C(context.read_gpr(m), shift_t, shift_n, context.APSR.C, carry); - const u32 result = context.read_gpr(n) ^ shifted; - context.write_gpr(d, result, type == T1 ? 2 : 4); + const u32 shifted = Shift_C(cpu.read_gpr(m), shift_t, shift_n, cpu.APSR.C, carry); + const u32 result = cpu.read_gpr(n) ^ shifted; + cpu.write_gpr(d, result, type == T1 ? 2 : 4); if (set_flags) { - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = carry; } } } -void ARMv7_instrs::EOR_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::EOR_RSR(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::IT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::IT(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case T1: - { - const u32 mask = (code.data & 0xf); - const u32 first = (code.data & 0xf0) >> 4; - - reject(mask == 0, "Related encodings"); - reject(first == 15, "UNPREDICTABLE"); - reject(first == 14 && BitCount(mask, 4) != 1, "UNPREDICTABLE"); - reject(context.ITSTATE, "UNPREDICTABLE"); - - context.ITSTATE.IT = code.data & 0xff; - break; - } - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("IT%s %s", fmt_it(context.ITSTATE.shift_state), fmt_cond(context.ITSTATE.condition)); - if (process_debug(context)) return; - } + cpu.ITSTATE.IT = op & 0xff; } -void ARMv7_instrs::LDM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LDM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, n, reg_list; - bool wback; + using args = arm_code::ldm; + ARG(n, op); + ARG(registers, op); + ARG(wback, op); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - n = (code.data & 0x700) >> 8; - reg_list = (code.data & 0xff); - wback = !(reg_list & (1 << n)); - - reject(reg_list == 0, "UNPREDICTABLE"); - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - n = (code.data & 0xf0000) >> 16; - reg_list = (code.data & 0xdfff); - wback = (code.data & 0x200000) != 0; - - reject(wback && n == 13, "POP"); - reject(n == 15 || BitCount(reg_list, 16) < 2 || reg_list >= 0xc000, "UNPREDICTABLE"); - reject(reg_list & 0x8000 && context.ITSTATE, "UNPREDICTABLE"); - reject(wback && reg_list & (1 << n), "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("ldm%s %s%s,{%s}", fmt_cond(cond), fmt_reg(n), wback ? "!" : "", fmt_reg_list(reg_list)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - vm::ptr memory{ context.read_gpr(n), vm::addr }; + vm::ptr memory(cpu.read_gpr(n), vm::addr); for (u32 i = 0; i < 16; i++) { - if (reg_list & (1 << i)) + if (registers & (1 << i)) { - context.write_gpr(i, *memory++, type == T1 ? 2 : 4); + cpu.write_gpr(i, *memory++, type == T1 ? 2 : 4); } } - - if (wback) + + // Warning: wback set true for T1 + if (wback && ~registers & (1 << n)) { - context.write_gpr(n, memory.addr(), type == T1 ? 2 : 4); + cpu.write_gpr(n, memory.addr(), type == T1 ? 2 : 4); } } } -void ARMv7_instrs::LDMDA(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LDMDA(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::LDMDB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LDMDB(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::LDMIB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LDMIB(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::LDR_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LDR_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, t, n, imm32; - bool index, add, wback; + using args = arm_code::ldr_imm; + ARG(t, op); + ARG(n, op); + ARG(imm32, op); + ARG(index, op); + ARG(add, op); + ARG(wback, op); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0x7); - n = (code.data & 0x38) >> 3; - imm32 = (code.data & 0x7c0) >> 4; - index = true; - add = true; - wback = false; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0x700) >> 8; - n = 13; - imm32 = (code.data & 0xff) << 2; - index = true; - add = true; - wback = false; - break; - } - case T3: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0xf000) >> 12; - n = (code.data & 0xf0000) >> 16; - imm32 = (code.data & 0xfff); - index = true; - add = true; - wback = false; - - reject(n == 15, "LDR (literal)"); - reject(t == 15 && context.ITSTATE, "UNPREDICTABLE"); - break; - } - case T4: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0xf000) >> 12; - n = (code.data & 0xf0000) >> 16; - imm32 = (code.data & 0xff); - index = (code.data & 0x400) != 0; - add = (code.data & 0x200) != 0; - wback = (code.data & 0x100) != 0; - - reject(n == 15, "LDR (literal)"); - reject(index && add && !wback, "LDRT"); - reject(n == 13 && !index && add && wback && imm32 == 4, "POP"); - reject(!index && !wback, "UNDEFINED"); - reject((wback && n == t) || (t == 15 && context.ITSTATE), "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("ldr%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_imm(n, imm32, index, add, wback)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - const u32 offset_addr = add ? context.read_gpr(n) + imm32 : context.read_gpr(n) - imm32; - const u32 addr = index ? offset_addr : context.read_gpr(n); - context.write_gpr(t, vm::read32(addr), type < T3 ? 2 : 4); + const u32 offset_addr = add ? cpu.read_gpr(n) + imm32 : cpu.read_gpr(n) - imm32; + const u32 addr = index ? offset_addr : cpu.read_gpr(n); + cpu.write_gpr(t, vm::read32(addr), type < T3 ? 2 : 4); if (wback) { - context.write_gpr(n, offset_addr, type < T3 ? 2 : 4); + cpu.write_gpr(n, offset_addr, type < T3 ? 2 : 4); } } } -void ARMv7_instrs::LDR_LIT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LDR_LIT(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, t, imm32; - bool add; + using args = arm_code::ldr_lit; + ARG(t, op); + ARG(imm32, op); + ARG(add, op); - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0x700) >> 8; - imm32 = (code.data & 0xff) << 2; - add = true; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0xf000) >> 12; - imm32 = (code.data & 0xfff); - add = (code.data & 0x800000) != 0; - - reject(t == 15 && context.ITSTATE, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - const u32 base = context.read_pc() & ~3; + const u32 base = cpu.read_pc() & ~3; const u32 addr = add ? base + imm32 : base - imm32; - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("ldr%s %s,0x%08X", fmt_cond(cond), fmt_reg(t), addr); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) + if (ConditionPassed(cpu, cond)) { const u32 data = vm::read32(addr); - context.write_gpr(t, data, type == T1 ? 2 : 4); + cpu.write_gpr(t, data, type == T1 ? 2 : 4); } } -void ARMv7_instrs::LDR_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LDR_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, t, n, m, shift_t, shift_n; - bool index, add, wback; + using args = arm_code::ldr_reg; + ARG(t, op); + ARG(n, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + ARG(index, op); + ARG(add, op); + ARG(wback, op); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0x7); - n = (code.data & 0x38) >> 3; - m = (code.data & 0x1c0) >> 6; - index = true; - add = true; - wback = false; - shift_t = SRType_LSL; - shift_n = 0; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0xf000) >> 12; - n = (code.data & 0xf0000) >> 16; - m = (code.data & 0xf); - index = true; - add = true; - wback = false; - shift_t = SRType_LSL; - shift_n = (code.data & 0x30) >> 4; - - reject(n == 15, "LDR (literal)"); - reject(m == 13 || m == 15, "UNPREDICTABLE"); - reject(t == 15 && context.ITSTATE, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("ldr%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_reg(n, m, index, add, wback, shift_t, shift_n)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - const u32 offset = Shift(context.read_gpr(m), shift_t, shift_n, context.APSR.C); - const u32 offset_addr = add ? context.read_gpr(n) + offset : context.read_gpr(n) - offset; - const u32 addr = index ? offset_addr : context.read_gpr(n); - context.write_gpr(t, vm::read32(addr), type == T1 ? 2 : 4); + const u32 offset = Shift(cpu.read_gpr(m), shift_t, shift_n, cpu.APSR.C); + const u32 offset_addr = add ? cpu.read_gpr(n) + offset : cpu.read_gpr(n) - offset; + const u32 addr = index ? offset_addr : cpu.read_gpr(n); + cpu.write_gpr(t, vm::read32(addr), type == T1 ? 2 : 4); if (wback) { - context.write_gpr(n, offset_addr, type == T1 ? 2 : 4); + cpu.write_gpr(n, offset_addr, type == T1 ? 2 : 4); } } } -void ARMv7_instrs::LDRB_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LDRB_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, t, n, imm32; - bool index, add, wback; + using args = arm_code::ldrb_imm; + ARG(t, op); + ARG(n, op); + ARG(imm32, op); + ARG(index, op); + ARG(add, op); + ARG(wback, op); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0x7); - n = (code.data & 0x38) >> 3; - imm32 = (code.data & 0x7c0) >> 6; - index = true; - add = true; - wback = false; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0xf000) >> 12; - n = (code.data & 0xf0000) >> 16; - imm32 = (code.data & 0xfff); - index = true; - add = true; - wback = false; - - reject(t == 15, "PLD"); - reject(n == 15, "LDRB (literal)"); - reject(t == 13, "UNPREDICTABLE"); - break; - } - case T3: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0xf000) >> 12; - n = (code.data & 0xf0000) >> 16; - imm32 = (code.data & 0xff); - index = (code.data & 0x400) != 0; - add = (code.data & 0x200) != 0; - wback = (code.data & 0x100) != 0; - - reject(t == 15 && index && !add && !wback, "PLD"); - reject(n == 15, "LDRB (literal)"); - reject(index && add && !wback, "LDRBT"); - reject(!index && !wback, "UNDEFINED"); - reject(t == 13 || t == 15 || (wback && n == t), "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("ldrb%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_imm(n, imm32, index, add, wback)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - const u32 offset_addr = add ? context.read_gpr(n) + imm32 : context.read_gpr(n) - imm32; - const u32 addr = index ? offset_addr : context.read_gpr(n); - context.write_gpr(t, vm::read8(addr), type == T1 ? 2 : 4); + const u32 offset_addr = add ? cpu.read_gpr(n) + imm32 : cpu.read_gpr(n) - imm32; + const u32 addr = index ? offset_addr : cpu.read_gpr(n); + cpu.write_gpr(t, vm::read8(addr), type == T1 ? 2 : 4); if (wback) { - context.write_gpr(n, offset_addr, type == T1 ? 2 : 4); + cpu.write_gpr(n, offset_addr, type == T1 ? 2 : 4); } } } -void ARMv7_instrs::LDRB_LIT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LDRB_LIT(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::LDRB_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LDRB_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, t, n, m, shift_t, shift_n; - bool index, add, wback; + using args = arm_code::ldrb_reg; + ARG(t, op); + ARG(n, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + ARG(index, op); + ARG(add, op); + ARG(wback, op); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0x7); - n = (code.data & 0x38) >> 3; - m = (code.data & 0x1c0) >> 6; - index = true; - add = true; - wback = false; - shift_t = SRType_LSL; - shift_n = 0; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0xf000) >> 12; - n = (code.data & 0xf0000) >> 16; - m = (code.data & 0xf); - index = true; - add = true; - wback = false; - shift_t = SRType_LSL; - shift_n = (code.data & 0x30) >> 4; - - reject(t == 15, "PLD"); - reject(n == 15, "LDRB (literal)"); - reject(t == 13 || m == 13 || m == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("ldrb%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_reg(n, m, index, add, wback, shift_t, shift_n)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - const u32 offset = Shift(context.read_gpr(m), shift_t, shift_n, context.APSR.C); - const u32 offset_addr = add ? context.read_gpr(n) + offset : context.read_gpr(n) - offset; - const u32 addr = index ? offset_addr : context.read_gpr(n); - context.write_gpr(t, vm::read8(addr), type == T1 ? 2 : 4); + const u32 offset = Shift(cpu.read_gpr(m), shift_t, shift_n, cpu.APSR.C); + const u32 offset_addr = add ? cpu.read_gpr(n) + offset : cpu.read_gpr(n) - offset; + const u32 addr = index ? offset_addr : cpu.read_gpr(n); + cpu.write_gpr(t, vm::read8(addr), type == T1 ? 2 : 4); if (wback) { - context.write_gpr(n, offset_addr, type == T1 ? 2 : 4); + cpu.write_gpr(n, offset_addr, type == T1 ? 2 : 4); } } } -void ARMv7_instrs::LDRD_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LDRD_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, t, t2, n, imm32; - bool index, add, wback; + using args = arm_code::ldrd_imm; + ARG(t, op); + ARG(t2, op); + ARG(n, op); + ARG(imm32, op); + ARG(index, op); + ARG(add, op); + ARG(wback, op); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0xf000) >> 12; - t2 = (code.data & 0xf00) >> 8; - n = (code.data & 0xf0000) >> 16; - imm32 = (code.data & 0xff) << 2; - index = (code.data & 0x1000000) != 0; - add = (code.data & 0x800000) != 0; - wback = (code.data & 0x200000) != 0; - - reject(!index && !wback, "Related encodings"); - reject(n == 15, "LDRD (literal)"); - reject(wback && (n == t || n == t2), "UNPREDICTABLE"); - reject(t == 13 || t == 15 || t2 == 13 || t2 == 15 || t == t2, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("ldrd%s %s,%s,%s", fmt_cond(cond), fmt_reg(t), fmt_reg(t2), fmt_mem_imm(n, imm32, index, add, wback)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - const u32 offset_addr = add ? context.read_gpr(n) + imm32 : context.read_gpr(n) - imm32; - const u32 addr = index ? offset_addr : context.read_gpr(n); + const u32 offset_addr = add ? cpu.read_gpr(n) + imm32 : cpu.read_gpr(n) - imm32; + const u32 addr = index ? offset_addr : cpu.read_gpr(n); const u64 value = vm::read64(addr); - context.write_gpr(t, (u32)(value), 4); - context.write_gpr(t2, (u32)(value >> 32), 4); + cpu.write_gpr(t, (u32)(value), 4); + cpu.write_gpr(t2, (u32)(value >> 32), 4); if (wback) { - context.write_gpr(n, offset_addr, 4); + cpu.write_gpr(n, offset_addr, 4); } } } -void ARMv7_instrs::LDRD_LIT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LDRD_LIT(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, t, t2, imm32; - bool add; + using args = arm_code::ldrd_lit; + ARG(t, op); + ARG(t2, op); + ARG(imm32, op); + ARG(add, op); - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0xf000) >> 12; - t2 = (code.data & 0xf00) >> 8; - imm32 = (code.data & 0xff) << 2; - add = (code.data & 0x800000) != 0; - - reject(!(code.data & 0x1000000), "Related encodings"); // ??? - reject(t == 13 || t == 15 || t2 == 13 || t2 == 15 || t == t2, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - const u32 base = context.read_pc() & ~3; + const u32 base = cpu.read_pc() & ~3; const u32 addr = add ? base + imm32 : base - imm32; - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("ldrd%s %s,%s,0x%08X", fmt_cond(cond), fmt_reg(t), fmt_reg(t2), addr); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) + if (ConditionPassed(cpu, cond)) { const u64 value = vm::read64(addr); - context.write_gpr(t, (u32)(value), 4); - context.write_gpr(t2, (u32)(value >> 32), 4); + cpu.write_gpr(t, (u32)(value), 4); + cpu.write_gpr(t2, (u32)(value >> 32), 4); } } -void ARMv7_instrs::LDRD_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LDRD_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::LDRH_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LDRH_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, t, n, imm32; - bool index, add, wback; + using args = arm_code::ldrh_imm; + ARG(t, op); + ARG(n, op); + ARG(imm32, op); + ARG(index, op); + ARG(add, op); + ARG(wback, op); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0x7); - n = (code.data & 0x38) >> 3; - imm32 = (code.data & 0x7c0) >> 5; - index = true; - add = true; - wback = false; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0xf000) >> 12; - n = (code.data & 0xf0000) >> 16; - imm32 = (code.data & 0xfff); - index = true; - add = true; - wback = false; - - reject(t == 15, "Unallocated memory hints"); - reject(n == 15, "LDRH (literal)"); - reject(t == 13, "UNPREDICTABLE"); - break; - } - case T3: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0xf000) >> 12; - n = (code.data & 0xf0000) >> 16; - imm32 = (code.data & 0xff); - index = (code.data & 0x400) != 0; - add = (code.data & 0x200) != 0; - wback = (code.data & 0x100) != 0; - - reject(n == 15, "LDRH (literal)"); - reject(t == 15 && index && !add && !wback, "Unallocated memory hints"); - reject(index && add && !wback, "LDRHT"); - reject(!index && !wback, "UNDEFINED"); - reject(t == 13 || t == 15 || (wback && n == t), "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("ldrh%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_imm(n, imm32, index, add, wback)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - const u32 offset_addr = add ? context.read_gpr(n) + imm32 : context.read_gpr(n) - imm32; - const u32 addr = index ? offset_addr : context.read_gpr(n); - context.write_gpr(t, vm::read16(addr), type == T1 ? 2 : 4); + const u32 offset_addr = add ? cpu.read_gpr(n) + imm32 : cpu.read_gpr(n) - imm32; + const u32 addr = index ? offset_addr : cpu.read_gpr(n); + cpu.write_gpr(t, vm::read16(addr), type == T1 ? 2 : 4); if (wback) { - context.write_gpr(n, offset_addr, type == T1 ? 2 : 4); + cpu.write_gpr(n, offset_addr, type == T1 ? 2 : 4); } } } -void ARMv7_instrs::LDRH_LIT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LDRH_LIT(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::LDRH_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LDRH_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::LDRSB_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LDRSB_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, t, n, imm32; - bool index, add, wback; + using args = arm_code::ldrsb_imm; + ARG(t, op); + ARG(n, op); + ARG(imm32, op); + ARG(index, op); + ARG(add, op); + ARG(wback, op); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0xf000) >> 12; - n = (code.data & 0xf0000) >> 16; - imm32 = (code.data & 0xfff); - index = true; - add = true; - wback = false; - - reject(t == 15, "PLI"); - reject(n == 15, "LDRSB (literal)"); - reject(t == 13, "UNPREDICTABLE"); - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0xf000) >> 12; - n = (code.data & 0xf0000) >> 16; - imm32 = (code.data & 0xff); - index = (code.data & 0x400) != 0; - add = (code.data & 0x200) != 0; - wback = (code.data & 0x100) != 0; - - reject(t == 15 && index && !add && !wback, "PLI"); - reject(n == 15, "LDRSB (literal)"); - reject(index && add && !wback, "LDRSBT"); - reject(!index && !wback, "UNDEFINED"); - reject(t == 13 || t == 15 || (wback && n == t), "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("ldrsb%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_imm(n, imm32, index, add, wback)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - const u32 offset_addr = add ? context.read_gpr(n) + imm32 : context.read_gpr(n) - imm32; - const u32 addr = index ? offset_addr : context.read_gpr(n); + const u32 offset_addr = add ? cpu.read_gpr(n) + imm32 : cpu.read_gpr(n) - imm32; + const u32 addr = index ? offset_addr : cpu.read_gpr(n); const s8 value = vm::read8(addr); - context.write_gpr(t, value, 4); // sign-extend + cpu.write_gpr(t, value, 4); // sign-extend if (wback) { - context.write_gpr(n, offset_addr, 4); + cpu.write_gpr(n, offset_addr, 4); } } } -void ARMv7_instrs::LDRSB_LIT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LDRSB_LIT(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::LDRSB_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LDRSB_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::LDRSH_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LDRSH_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::LDRSH_LIT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LDRSH_LIT(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::LDRSH_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LDRSH_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::LDREX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LDREX(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, t, n, imm32; + using args = arm_code::ldrex; + ARG(t, op); + ARG(n, op); + ARG(imm32, op); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0xf000) >> 12; - n = (code.data & 0xf0000) >> 16; - imm32 = (code.data & 0xff) << 2; - - reject(t == 13 || t == 15 || n == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("ldrex%s %s,[%s,#0x%X]", fmt_cond(cond), fmt_reg(t), fmt_reg(n), imm32); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - const u32 addr = context.read_gpr(n) + imm32; + const u32 addr = cpu.read_gpr(n) + imm32; u32 value; vm::reservation_acquire(&value, addr, sizeof(value)); - context.write_gpr(t, value, 4); + cpu.write_gpr(t, value, 4); } } -void ARMv7_instrs::LDREXB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LDREXB(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::LDREXD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LDREXD(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::LDREXH(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LDREXH(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::LSL_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LSL_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - bool set_flags = !context.ITSTATE; - u32 cond, d, m, shift_n; + using args = arm_code::lsl_imm; + ARG(d, op); + ARG(m, op); + ARG(shift_n, op); + ARG(set_flags, op, cond); - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0x7); - m = (code.data & 0x38) >> 3; - DecodeImmShift(0, (code.data & 0x7c0) >> 6, &shift_n); - - reject(!shift_n, "MOV (register)"); - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - m = (code.data & 0xf); - set_flags = (code.data & 0x100000) != 0; - DecodeImmShift(0, (code.data & 0x7000) >> 10 | (code.data & 0xc0) >> 6, &shift_n); - - reject(!shift_n, "MOV (register)"); - reject(d == 13 || d == 15 || m == 13 || m == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("lsl%s%s %s,%s,#%d", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(m), shift_n); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) + if (ConditionPassed(cpu, cond)) { bool carry; - const u32 result = Shift_C(context.read_gpr(m), SRType_LSL, shift_n, context.APSR.C, carry); - context.write_gpr(d, result, type == T1 ? 2 : 4); + const u32 result = Shift_C(cpu.read_gpr(m), arm_code::SRType_LSL, shift_n, cpu.APSR.C, carry); + cpu.write_gpr(d, result, type == T1 ? 2 : 4); if (set_flags) { - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = carry; } } } -void ARMv7_instrs::LSL_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LSL_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - bool set_flags = !context.ITSTATE; - u32 cond, d, n, m; + using args = arm_code::lsl_reg; + ARG(d, op); + ARG(n, op); + ARG(m, op); + ARG(set_flags, op, cond); - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - d = n = (code.data & 0x7); - m = (code.data & 0x38) >> 3; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - n = (code.data & 0xf0000) >> 16; - m = (code.data & 0xf); - set_flags = (code.data & 0x100000) != 0; - - reject(d == 13 || d == 15 || n == 13 || n == 15 || m == 13 || m == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("lsl%s%s %s,%s,%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) + if (ConditionPassed(cpu, cond)) { bool carry; - const u32 result = Shift_C(context.read_gpr(n), SRType_LSL, (context.read_gpr(m) & 0xff), context.APSR.C, carry); - context.write_gpr(d, result, type == T1 ? 2 : 4); + const u32 result = Shift_C(cpu.read_gpr(n), arm_code::SRType_LSL, (cpu.read_gpr(m) & 0xff), cpu.APSR.C, carry); + cpu.write_gpr(d, result, type == T1 ? 2 : 4); if (set_flags) { - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = carry; } } } -void ARMv7_instrs::LSR_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LSR_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - bool set_flags = !context.ITSTATE; - u32 cond, d, m, shift_n; + using args = arm_code::lsr_imm; + ARG(d, op); + ARG(m, op); + ARG(shift_n, op); + ARG(set_flags, op, cond); - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0x7); - m = (code.data & 0x38) >> 3; - DecodeImmShift(1, (code.data & 0x7c0) >> 6, &shift_n); - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - m = (code.data & 0xf); - set_flags = (code.data & 0x100000) != 0; - DecodeImmShift(1, (code.data & 0x7000) >> 10 | (code.data & 0xc0) >> 6, &shift_n); - - reject(d == 13 || d == 15 || m == 13 || m == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("lsr%s%s %s,%s,#%d", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(m), shift_n); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) + if (ConditionPassed(cpu, cond)) { bool carry; - const u32 result = Shift_C(context.read_gpr(m), SRType_LSR, shift_n, context.APSR.C, carry); - context.write_gpr(d, result, type == T1 ? 2 : 4); + const u32 result = Shift_C(cpu.read_gpr(m), arm_code::SRType_LSR, shift_n, cpu.APSR.C, carry); + cpu.write_gpr(d, result, type == T1 ? 2 : 4); if (set_flags) { - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = carry; } } } -void ARMv7_instrs::LSR_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::LSR_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::MLA(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::MLA(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::MLS(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::MLS(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::MOV_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::MOV_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - bool set_flags = !context.ITSTATE; - bool carry = context.APSR.C; - u32 cond, d, imm32; + using args = arm_code::mov_imm; + ARG(d, op); + ARG(imm32, op); + ARG(set_flags, op, cond); - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - d = (code.data >> 8) & 0x7; - imm32 = sign<8, u32>(code.data & 0xff); - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - set_flags = (code.data & 0x100000) != 0; - d = (code.data >> 8) & 0xf; - imm32 = ThumbExpandImm_C((code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff), carry, carry); - - reject(d == 13 || d == 15, "UNPREDICTABLE"); - break; - } - case T3: - { - cond = context.ITSTATE.advance(); - set_flags = false; - d = (code.data >> 8) & 0xf; - imm32 = (code.data & 0xf0000) >> 4 | (code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff); - - reject(d == 13 || d == 15, "UNPREDICTABLE"); - break; - } - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) - { - switch (type) - { - case T3: case A2: context.fmt_debug_str("movw%s%s %s,#0x%04X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), imm32); break; - default: context.fmt_debug_str("mov%s%s %s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), imm32); - } - } - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) + if (ConditionPassed(cpu, cond)) { const u32 result = imm32; - context.write_gpr(d, result, type == T1 ? 2 : 4); + cpu.write_gpr(d, result, type == T1 ? 2 : 4); if (set_flags) { - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = args::carry::extract(op, cpu.APSR.C); } } } -void ARMv7_instrs::MOV_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::MOV_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, d, m; - bool set_flags; + using args = arm_code::mov_reg; + ARG(d, op); + ARG(m, op); + ARG(set_flags, op, cond); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0x80) >> 4 | (code.data & 0x7); - m = (code.data & 0x78) >> 3; - set_flags = false; + const u32 result = cpu.read_gpr(m); + cpu.write_gpr(d, result, type < T3 ? 2 : 4); - reject(d == 15 && context.ITSTATE, "UNPREDICTABLE"); - break; - } - case T2: - { - cond = 0xe; // always true - d = (code.data & 0x7); - m = (code.data & 0x38) >> 3; - set_flags = true; - - reject(context.ITSTATE, "UNPREDICTABLE"); - break; - } - case T3: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - m = (code.data & 0xf); - set_flags = (code.data & 0x100000) != 0; - - reject((d == 13 || m == 13 || m == 15) && set_flags, "UNPREDICTABLE"); - reject((d == 13 && (m == 13 || m == 15)) || d == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("mov%s%s %s,%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(m)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - const u32 result = context.read_gpr(m); - context.write_gpr(d, result, type < T3 ? 2 : 4); - - if (set_flags) + if (set_flags) // cond is not used { - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - //context.APSR.C = carry; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + //cpu.APSR.C = carry; } } } -void ARMv7_instrs::MOVT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::MOVT(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, d, imm16; + using args = arm_code::movt; + ARG(d, op); + ARG(imm16, op); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - imm16 = (code.data & 0xf0000) >> 4 | (code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff); - - reject(d == 13 || d == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("movt%s %s,#0x%04X", fmt_cond(cond), fmt_reg(d), imm16); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - context.write_gpr(d, (context.read_gpr(d) & 0xffff) | (imm16 << 16), 4); + cpu.write_gpr(d, (cpu.read_gpr(d) & 0xffff) | (imm16 << 16), 4); } } -void ARMv7_instrs::MRS(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::MRS(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::MSR_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::MSR_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::MSR_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::MSR_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::MUL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::MUL(ARMv7Thread& cpu, const u32 op, const u32 cond) { - bool set_flags = !context.ITSTATE; - u32 cond, d, n, m; + using args = arm_code::mul; + ARG(d, op); + ARG(n, op); + ARG(m, op); + ARG(set_flags, op, cond); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - d = m = code.data & 0x7; - n = (code.data & 0x38) >> 3; - - //reject(ArchVersion() < 6 && d == n, "UNPREDICTABLE"); - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - n = (code.data & 0xf0000) >> 16; - m = (code.data & 0xf); - set_flags = false; - - reject(d == 13 || d == 15 || n == 13 || n == 15 || m == 13 || m == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("mul%s%s %s,%s,%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - const u32 op1 = context.read_gpr(n); - const u32 op2 = context.read_gpr(m); + const u32 op1 = cpu.read_gpr(n); + const u32 op2 = cpu.read_gpr(m); const u32 result = op1 * op2; - context.write_gpr(d, result, type == T1 ? 2 : 4); + cpu.write_gpr(d, result, type == T1 ? 2 : 4); if (set_flags) { - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; } } } -void ARMv7_instrs::MVN_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::MVN_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, d, imm32; - bool set_flags, carry; + using args = arm_code::mvn_imm; + ARG(d, op); + ARG(imm32, op); + ARG(set_flags, op, cond); - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - set_flags = (code.data & 0x100000) != 0; - imm32 = ThumbExpandImm_C((code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff), context.APSR.C, carry); - - reject(d == 13 || d == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("mvn%s%s %s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), imm32); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) + if (ConditionPassed(cpu, cond)) { const u32 result = ~imm32; - context.write_gpr(d, result, 4); + cpu.write_gpr(d, result, 4); if (set_flags) { - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = args::carry::extract(op, cpu.APSR.C); } } } -void ARMv7_instrs::MVN_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::MVN_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - bool set_flags = !context.ITSTATE; - u32 cond, d, m, shift_t, shift_n; + using args = arm_code::mvn_reg; + ARG(d, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + ARG(set_flags, op, cond); - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0x7); - m = (code.data & 0x38) >> 3; - shift_t = SRType_LSL; - shift_n = 0; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - m = (code.data & 0xf); - set_flags = (code.data & 0x100000) != 0; - shift_t = DecodeImmShift((code.data & 0x30) >> 4, (code.data & 0x7000) >> 10 | (code.data & 0xc0) >> 6, &shift_n); - - reject(d == 13 || d == 15 || m == 13 || m == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("mvn%s%s %s,%s%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(m), fmt_shift(shift_t, shift_n)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) + if (ConditionPassed(cpu, cond)) { bool carry; - const u32 shifted = Shift_C(context.read_gpr(m), shift_t, shift_n, context.APSR.C, carry); + const u32 shifted = Shift_C(cpu.read_gpr(m), shift_t, shift_n, cpu.APSR.C, carry); const u32 result = ~shifted; - context.write_gpr(d, result, type == T1 ? 2 : 4); + cpu.write_gpr(d, result, type == T1 ? 2 : 4); if (set_flags) { - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = carry; } } } -void ARMv7_instrs::MVN_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::MVN_RSR(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::NOP(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::NOP(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond; - - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - break; - } - case A1: - { - cond = code.data >> 28; - break; - } - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("nop%s", fmt_cond(cond)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) + if (ConditionPassed(cpu, cond)) { } } -void ARMv7_instrs::ORN_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::ORN_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::ORN_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::ORN_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::ORR_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::ORR_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, d, n, imm32; - bool set_flags, carry = context.APSR.C; + using args = arm_code::orr_imm; + ARG(d, op); + ARG(n, op); + ARG(imm32, op); + ARG(set_flags, op, cond); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - n = (code.data & 0xf0000) >> 16; - set_flags = (code.data & 0x100000) != 0; - imm32 = ThumbExpandImm_C((code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff), carry, carry); - - reject(n == 15, "MOV (immediate)"); - reject(d == 13 || d == 15 || n == 13, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("orr%s%s %s,%s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), imm32); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - const u32 result = context.read_gpr(n) | imm32; - context.write_gpr(d, result, 4); + const u32 result = cpu.read_gpr(n) | imm32; + cpu.write_gpr(d, result, 4); if (set_flags) { - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = args::carry::extract(op, cpu.APSR.C); } } } -void ARMv7_instrs::ORR_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::ORR_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - bool set_flags = !context.ITSTATE; - u32 cond, d, n, m, shift_t, shift_n; + using args = arm_code::orr_reg; + ARG(d, op); + ARG(n, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + ARG(set_flags, op, cond); - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - d = n = (code.data & 0x7); - m = (code.data & 0x38) >> 3; - shift_t = SRType_LSL; - shift_n = 0; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - n = (code.data & 0xf0000) >> 16; - m = (code.data & 0xf); - set_flags = (code.data & 0x100000) != 0; - shift_t = DecodeImmShift((code.data & 0x30) >> 4, (code.data & 0x7000) >> 10 | (code.data & 0xc0) >> 6, &shift_n); - - reject(n == 15, "ROR (immediate)"); - reject(d == 13 || d == 15 || n == 13 || m == 13 || m == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("orr%s%s %s,%s,%s%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m), fmt_shift(shift_t, shift_n)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) + if (ConditionPassed(cpu, cond)) { bool carry; - const u32 shifted = Shift_C(context.read_gpr(m), shift_t, shift_n, context.APSR.C, carry); - const u32 result = context.read_gpr(n) | shifted; - context.write_gpr(d, result, type == T1 ? 2 : 4); + const u32 shifted = Shift_C(cpu.read_gpr(m), shift_t, shift_n, cpu.APSR.C, carry); + const u32 result = cpu.read_gpr(n) | shifted; + cpu.write_gpr(d, result, type == T1 ? 2 : 4); if (set_flags) { - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = carry; } } } -void ARMv7_instrs::ORR_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::ORR_RSR(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::PKH(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::PKH(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::POP(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::POP(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, reg_list; + const u32 registers = arm_code::pop::registers::extract(op); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - reg_list = ((code.data & 0x100) << 7) | (code.data & 0xff); - - reject(!reg_list, "UNPREDICTABLE"); - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - reg_list = code.data & 0xdfff; - - reject(BitCount(reg_list, 16) < 2 || ((reg_list & 0x8000) && (reg_list & 0x4000)), "UNPREDICTABLE"); - reject((reg_list & 0x8000) && context.ITSTATE, "UNPREDICTABLE"); - break; - } - case T3: - { - cond = context.ITSTATE.advance(); - reg_list = 1 << ((code.data & 0xf000) >> 12); - - reject((reg_list & 0x2000) || ((reg_list & 0x8000) && context.ITSTATE), "UNPREDICTABLE"); - break; - } - case A1: - { - cond = code.data >> 28; - reg_list = code.data & 0xffff; - - reject(BitCount(reg_list, 16) < 2, "LDM / LDMIA / LDMFD"); - reject((reg_list & 0x2000) /* && ArchVersion() >= 7*/, "UNPREDICTABLE"); - break; - } - case A2: - { - cond = code.data >> 28; - reg_list = 1 << ((code.data & 0xf000) >> 12); - - reject(reg_list & 0x2000, "UNPREDICTABLE"); - break; - } - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("pop%s {%s}", fmt_cond(cond), fmt_reg_list(reg_list)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - auto stack = vm::ptr::make(context.SP); + auto stack = vm::ptr::make(cpu.SP); for (u32 i = 0; i < 16; i++) { - if (reg_list & (1 << i)) + if (registers & (1 << i)) { - context.write_gpr(i, *stack++, type == T1 ? 2 : 4); + cpu.write_gpr(i, *stack++, type == T1 ? 2 : 4); } } - context.SP = stack.addr(); + cpu.SP = stack.addr(); } } -void ARMv7_instrs::PUSH(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::PUSH(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, reg_list; + const u32 registers = arm_code::push::registers::extract(op); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - reg_list = ((code.data & 0x100) << 6) | (code.data & 0xff); - - reject(!reg_list, "UNPREDICTABLE"); - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - reg_list = code.data & 0x5fff; - - reject(BitCount(reg_list, 16) < 2, "UNPREDICTABLE"); - break; - } - case T3: - { - cond = context.ITSTATE.advance(); - reg_list = 1 << ((code.data & 0xf000) >> 12); - - reject((reg_list & 0x8000) || (reg_list & 0x2000), "UNPREDICTABLE"); - break; - } - case A1: - { - cond = code.data >> 28; - reg_list = code.data & 0xffff; - - reject(BitCount(reg_list) < 2, "STMDB / STMFD"); - break; - } - case A2: - { - cond = code.data >> 28; - reg_list = 1 << ((code.data & 0xf000) >> 12); - - reject(reg_list & 0x2000, "UNPREDICTABLE"); - break; - } - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("push%s {%s}", fmt_cond(cond), fmt_reg_list(reg_list)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - vm::ptr memory{ context.SP, vm::addr }; + vm::ptr memory(cpu.SP, vm::addr); for (u32 i = 15; ~i; i--) { - if (reg_list & (1 << i)) + if (registers & (1 << i)) { - *--memory = context.read_gpr(i); + *--memory = cpu.read_gpr(i); } } - context.SP = memory.addr(); + cpu.SP = memory.addr(); } } -void ARMv7_instrs::QADD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::QADD(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::QADD16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::QADD16(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::QADD8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::QADD8(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::QASX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::QASX(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::QDADD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::QDADD(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::QDSUB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::QDSUB(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::QSAX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::QSAX(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::QSUB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::QSUB(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::QSUB16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::QSUB16(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::QSUB8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::QSUB8(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::RBIT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::RBIT(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) + throw EXCEPTION("TODO"); +} + +template +void arm_interpreter::REV(ARMv7Thread& cpu, const u32 op, const u32 cond) +{ + using args = arm_code::rev; + ARG(d, op); + ARG(m, op); + + if (ConditionPassed(cpu, cond)) { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); + cpu.write_gpr(d, se_storage::swap(cpu.read_gpr(m)), type == T1 ? 2 : 4); } } -void ARMv7_instrs::REV(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::REV16(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, d, m; - - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0x7); - m = (code.data & 0x38) >> 3; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - m = (code.data & 0xf); - - reject(m != (code.data & 0xf0000) >> 16, "UNPREDICTABLE"); - reject(d == 13 || d == 15 || m == 13 || m == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("rev%s %s,%s", fmt_cond(cond), fmt_reg(d), fmt_reg(m)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - context.write_gpr(d, se_storage::swap(context.read_gpr(m)), type == T1 ? 2 : 4); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::REV16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::REVSH(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } -} - -void ARMv7_instrs::REVSH(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::ROR_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::ROR_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, d, m, shift_n; - bool set_flags; + using args = arm_code::ror_imm; + ARG(d, op); + ARG(m, op); + ARG(shift_n, op); + ARG(set_flags, op, cond); - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - m = (code.data & 0xf); - set_flags = (code.data & 0x100000) != 0; - const u32 shift_t = DecodeImmShift(3, (code.data & 0x7000) >> 10 | (code.data & 0xc0) >> 6, &shift_n); - - reject(shift_t == SRType_RRX, "RRX"); - reject(d == 13 || d == 15 || m == 13 || m == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("ror%s%s %s,%s,#%d", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(m), shift_n); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) + if (ConditionPassed(cpu, cond)) { bool carry; - const u32 result = Shift_C(context.read_gpr(m), SRType_ROR, shift_n, context.APSR.C, carry); - context.write_gpr(d, result, 4); + const u32 result = Shift_C(cpu.read_gpr(m), arm_code::SRType_ROR, shift_n, cpu.APSR.C, carry); + cpu.write_gpr(d, result, 4); if (set_flags) { - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = carry; } } } -void ARMv7_instrs::ROR_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::ROR_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - bool set_flags = !context.ITSTATE; - u32 cond, d, n, m; + using args = arm_code::ror_reg; + ARG(d, op); + ARG(n, op); + ARG(m, op); + ARG(set_flags, op, cond); - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - d = n = (code.data & 0x7); - m = (code.data & 0x38) >> 3; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - n = (code.data & 0xf0000) >> 16; - m = (code.data & 0xf); - set_flags = (code.data & 0x100000) != 0; - - reject(d == 13 || d == 15 || n == 13 || n == 15 || m == 13 || m == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("ror%s%s %s,%s,%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) + if (ConditionPassed(cpu, cond)) { bool carry; - const u32 shift_n = context.read_gpr(m) & 0xff; - const u32 result = Shift_C(context.read_gpr(n), SRType_ROR, shift_n, context.APSR.C, carry); - context.write_gpr(d, result, type == T1 ? 2 : 4); + const u32 shift_n = cpu.read_gpr(m) & 0xff; + const u32 result = Shift_C(cpu.read_gpr(n), arm_code::SRType_ROR, shift_n, cpu.APSR.C, carry); + cpu.write_gpr(d, result, type == T1 ? 2 : 4); if (set_flags) { - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = carry; } } } -void ARMv7_instrs::RRX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::RRX(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::RSB_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::RSB_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - bool set_flags = !context.ITSTATE; - u32 cond, d, n, imm32; + using args = arm_code::rsb_imm; + ARG(d, op); + ARG(n, op); + ARG(imm32, op); + ARG(set_flags, op, cond); - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0x7); - n = (code.data & 0x38) >> 3; - imm32 = 0; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - n = (code.data & 0xf0000) >> 16; - set_flags = (code.data & 0x100000) != 0; - imm32 = ThumbExpandImm((code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff)); - - reject(d == 13 || d == 15 || n == 13 || n == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("rsb%s%s %s,%s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), imm32); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) + if (ConditionPassed(cpu, cond)) { bool carry, overflow; - const u32 result = AddWithCarry(~context.read_gpr(n), imm32, true, carry, overflow); - context.write_gpr(d, result, type == T1 ? 2 : 4); + const u32 result = AddWithCarry(~cpu.read_gpr(n), imm32, true, carry, overflow); + cpu.write_gpr(d, result, type == T1 ? 2 : 4); if (set_flags) { - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; - context.APSR.V = overflow; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = carry; + cpu.APSR.V = overflow; } } } -void ARMv7_instrs::RSB_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::RSB_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::RSB_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::RSB_RSR(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::RSC_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::RSC_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::RSC_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::RSC_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::RSC_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::RSC_RSR(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SADD16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SADD16(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SADD8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SADD8(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SASX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SASX(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SBC_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SBC_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SBC_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SBC_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SBC_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SBC_RSR(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SBFX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SBFX(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SDIV(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SDIV(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SEL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SEL(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SHADD16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SHADD16(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SHADD8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SHADD8(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SHASX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SHASX(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SHSAX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SHSAX(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SHSUB16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SHSUB16(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SHSUB8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SHSUB8(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SMLA__(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SMLA__(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SMLAD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SMLAD(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SMLAL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SMLAL(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SMLAL__(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SMLAL__(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SMLALD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SMLALD(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SMLAW_(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SMLAW_(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SMLSD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SMLSD(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SMLSLD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SMLSLD(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SMMLA(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SMMLA(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SMMLS(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SMMLS(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SMMUL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SMMUL(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SMUAD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SMUAD(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SMUL__(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SMUL__(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SMULL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SMULL(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SMULW_(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SMULW_(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SMUSD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SMUSD(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SSAT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SSAT(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SSAT16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SSAT16(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SSAX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SSAX(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SSUB16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SSUB16(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SSUB8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SSUB8(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::STM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::STM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, n, reg_list; - bool wback; + using args = arm_code::stm; + ARG(n, op); + ARG(registers, op); + ARG(wback, op); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - n = (code.data & 0x700) >> 8; - reg_list = (code.data & 0xff); - wback = true; - - reject(reg_list == 0, "UNPREDICTABLE"); - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - n = (code.data & 0xf0000) >> 16; - reg_list = (code.data & 0x5fff); - wback = (code.data & 0x200000) != 0; - - reject(n == 15 || BitCount(reg_list, 16) < 2, "UNPREDICTABLE"); - reject(wback && reg_list & (1 << n), "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("stm%s %s%s,{%s}", fmt_cond(cond), fmt_reg(n), wback ? "!" : "", fmt_reg_list(reg_list)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - auto memory = vm::ptr::make(context.read_gpr(n)); + auto memory = vm::ptr::make(cpu.read_gpr(n)); for (u32 i = 0; i < 16; i++) { - if (reg_list & (1 << i)) + if (registers & (1 << i)) { - *memory++ = context.read_gpr(i); + *memory++ = cpu.read_gpr(i); } } if (wback) { - context.write_gpr(n, memory.addr(), type == T1 ? 2 : 4); + cpu.write_gpr(n, memory.addr(), type == T1 ? 2 : 4); } } } -void ARMv7_instrs::STMDA(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::STMDA(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::STMDB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::STMDB(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::STMIB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::STMIB(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::STR_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::STR_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, t, n, imm32; - bool index, add, wback; + using args = arm_code::str_imm; + ARG(t, op); + ARG(n, op); + ARG(imm32, op); + ARG(index, op); + ARG(add, op); + ARG(wback, op); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0x7); - n = (code.data & 0x38) >> 3; - imm32 = (code.data & 0x7c0) >> 4; - index = true; - add = true; - wback = false; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0x700) >> 8; - n = 13; - imm32 = (code.data & 0xff) << 2; - index = true; - add = true; - wback = false; - break; - } - case T3: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0xf000) >> 12; - n = (code.data & 0xf0000) >> 16; - imm32 = (code.data & 0xfff); - index = true; - add = true; - wback = false; - - reject(n == 15, "UNDEFINED"); - reject(t == 15, "UNPREDICTABLE"); - break; - } - case T4: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0xf000) >> 12; - n = (code.data & 0xf0000) >> 16; - imm32 = (code.data & 0xff); - index = (code.data & 0x400) != 0; - add = (code.data & 0x200) != 0; - wback = (code.data & 0x100) != 0; - - reject(index && add && !wback, "STRT"); - reject(n == 13 && index && !add && wback && imm32 == 4, "PUSH"); - reject(n == 15 || (!index && !wback), "UNDEFINED"); - reject(t == 15 || (wback && n == t), "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("str%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_imm(n, imm32, index, add, wback)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - const u32 offset_addr = add ? context.read_gpr(n) + imm32 : context.read_gpr(n) - imm32; - const u32 addr = index ? offset_addr : context.read_gpr(n); - vm::write32(addr, context.read_gpr(t)); + const u32 offset_addr = add ? cpu.read_gpr(n) + imm32 : cpu.read_gpr(n) - imm32; + const u32 addr = index ? offset_addr : cpu.read_gpr(n); + vm::write32(addr, cpu.read_gpr(t)); if (wback) { - context.write_gpr(n, offset_addr, type < T3 ? 2 : 4); + cpu.write_gpr(n, offset_addr, type < T3 ? 2 : 4); } } } -void ARMv7_instrs::STR_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::STR_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, t, n, m, shift_t, shift_n; - bool index, add, wback; + using args = arm_code::str_reg; + ARG(t, op); + ARG(n, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + ARG(index, op); + ARG(add, op); + ARG(wback, op); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0x7); - n = (code.data & 0x38) >> 3; - m = (code.data & 0x1c0) >> 6; - index = true; - add = true; - wback = false; - shift_t = SRType_LSL; - shift_n = 0; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0xf000) >> 12; - n = (code.data & 0xf0000) >> 16; - m = (code.data & 0xf); - index = true; - add = true; - wback = false; - shift_t = SRType_LSL; - shift_n = (code.data & 0x30) >> 4; - - reject(n == 15, "UNDEFINED"); - reject(t == 15 || m == 13 || m == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("str%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_reg(n, m, index, add, wback, shift_t, shift_n)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - const u32 offset = Shift(context.read_gpr(m), shift_t, shift_n, context.APSR.C); - const u32 offset_addr = add ? context.read_gpr(n) + offset : context.read_gpr(n) - offset; - const u32 addr = index ? offset_addr : context.read_gpr(n); - vm::write32(addr, context.read_gpr(t)); + const u32 offset = Shift(cpu.read_gpr(m), shift_t, shift_n, cpu.APSR.C); + const u32 offset_addr = add ? cpu.read_gpr(n) + offset : cpu.read_gpr(n) - offset; + const u32 addr = index ? offset_addr : cpu.read_gpr(n); + vm::write32(addr, cpu.read_gpr(t)); if (wback) { - context.write_gpr(n, offset_addr, type == T1 ? 2 : 4); + cpu.write_gpr(n, offset_addr, type == T1 ? 2 : 4); } } } -void ARMv7_instrs::STRB_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::STRB_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, t, n, imm32; - bool index, add, wback; + using args = arm_code::strb_imm; + ARG(t, op); + ARG(n, op); + ARG(imm32, op); + ARG(index, op); + ARG(add, op); + ARG(wback, op); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0x7); - n = (code.data & 0x38) >> 3; - imm32 = (code.data & 0x7c0) >> 6; - index = true; - add = true; - wback = false; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0xf000) >> 12; - n = (code.data & 0xf0000) >> 16; - imm32 = (code.data & 0xfff); - index = true; - add = true; - wback = false; - - reject(n == 15, "UNDEFINED"); - reject(t == 13 || t == 15, "UNPREDICTABLE"); - break; - } - case T3: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0xf000) >> 12; - n = (code.data & 0xf0000) >> 16; - imm32 = (code.data & 0xff); - index = (code.data & 0x400) != 0; - add = (code.data & 0x200) != 0; - wback = (code.data & 0x100) != 0; - - reject(index && add && !wback, "STRBT"); - reject(n == 15 || (!index && !wback), "UNDEFINED"); - reject(t == 13 || t == 15 || (wback && n == t), "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("strb%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_imm(n, imm32, index, add, wback)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - const u32 offset_addr = add ? context.read_gpr(n) + imm32 : context.read_gpr(n) - imm32; - const u32 addr = index ? offset_addr : context.read_gpr(n); - vm::write8(addr, (u8)context.read_gpr(t)); + const u32 offset_addr = add ? cpu.read_gpr(n) + imm32 : cpu.read_gpr(n) - imm32; + const u32 addr = index ? offset_addr : cpu.read_gpr(n); + vm::write8(addr, (u8)cpu.read_gpr(t)); if (wback) { - context.write_gpr(n, offset_addr, type == T1 ? 2 : 4); + cpu.write_gpr(n, offset_addr, type == T1 ? 2 : 4); } } } -void ARMv7_instrs::STRB_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::STRB_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, t, n, m, shift_t, shift_n; - bool index, add, wback; + using args = arm_code::strb_reg; + ARG(t, op); + ARG(n, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + ARG(index, op); + ARG(add, op); + ARG(wback, op); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0x7); - n = (code.data & 0x38) >> 3; - m = (code.data & 0x1c0) >> 6; - index = true; - add = true; - wback = false; - shift_t = SRType_LSL; - shift_n = 0; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0xf000) >> 12; - n = (code.data & 0xf0000) >> 16; - m = (code.data & 0xf); - index = true; - add = true; - wback = false; - shift_t = SRType_LSL; - shift_n = (code.data & 0x30) >> 4; - - reject(n == 15, "UNDEFINED"); - reject(t == 13 || t == 15 || m == 13 || m == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("strb%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_reg(n, m, index, add, wback, shift_t, shift_n)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - const u32 offset = Shift(context.read_gpr(m), shift_t, shift_n, context.APSR.C); - const u32 offset_addr = add ? context.read_gpr(n) + offset : context.read_gpr(n) - offset; - const u32 addr = index ? offset_addr : context.read_gpr(n); - vm::write8(addr, (u8)context.read_gpr(t)); + const u32 offset = Shift(cpu.read_gpr(m), shift_t, shift_n, cpu.APSR.C); + const u32 offset_addr = add ? cpu.read_gpr(n) + offset : cpu.read_gpr(n) - offset; + const u32 addr = index ? offset_addr : cpu.read_gpr(n); + vm::write8(addr, (u8)cpu.read_gpr(t)); if (wback) { - context.write_gpr(n, offset_addr, type == T1 ? 2 : 4); + cpu.write_gpr(n, offset_addr, type == T1 ? 2 : 4); } } } -void ARMv7_instrs::STRD_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::STRD_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, t, t2, n, imm32; - bool index, add, wback; + using args = arm_code::strd_imm; + ARG(t, op); + ARG(t2, op); + ARG(n, op); + ARG(imm32, op); + ARG(index, op); + ARG(add, op); + ARG(wback, op); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0xf000) >> 12; - t2 = (code.data & 0xf00) >> 8; - n = (code.data & 0xf0000) >> 16; - imm32 = (code.data & 0xff) << 2; - index = (code.data & 0x1000000) != 0; - add = (code.data & 0x800000) != 0; - wback = (code.data & 0x200000) != 0; - - reject(!index && !wback, "Related encodings"); - reject(wback && (n == t || n == t2), "UNPREDICTABLE"); - reject(n == 15 || t == 13 || t == 15 || t2 == 13 || t2 == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("strd%s %s,%s,%s", fmt_cond(cond), fmt_reg(t), fmt_reg(t2), fmt_mem_imm(n, imm32, index, add, wback)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - const u32 n_value = context.read_gpr(n); + const u32 n_value = cpu.read_gpr(n); const u32 offset = add ? n_value + imm32 : n_value - imm32; const u32 addr = index ? offset : n_value; - vm::write64(addr, (u64)context.read_gpr(t2) << 32 | (u64)context.read_gpr(t)); + vm::write64(addr, (u64)cpu.read_gpr(t2) << 32 | (u64)cpu.read_gpr(t)); if (wback) { - context.write_gpr(n, offset, 4); + cpu.write_gpr(n, offset, 4); } } } -void ARMv7_instrs::STRD_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::STRD_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::STRH_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::STRH_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, t, n, imm32; - bool index, add, wback; + using args = arm_code::strh_imm; + ARG(t, op); + ARG(n, op); + ARG(imm32, op); + ARG(index, op); + ARG(add, op); + ARG(wback, op); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0x7); - n = (code.data & 0x38) >> 3; - imm32 = (code.data & 0x7c0) >> 5; - index = true; - add = true; - wback = false; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0xf000) >> 12; - n = (code.data & 0xf0000) >> 16; - imm32 = (code.data & 0xfff); - index = true; - add = true; - wback = false; - - reject(n == 15, "UNDEFINED"); - reject(t == 13 || t == 15, "UNPREDICTABLE"); - break; - } - case T3: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0xf000) >> 12; - n = (code.data & 0xf0000) >> 16; - imm32 = (code.data & 0xff); - index = (code.data & 0x400) != 0; - add = (code.data & 0x200) != 0; - wback = (code.data & 0x100) != 0; - - reject(index && add && !wback, "STRHT"); - reject(n == 15 || (!index && !wback), "UNDEFINED"); - reject(t == 13 || t == 15 || (wback && n == t), "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("strh%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_imm(n, imm32, index, add, wback)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - const u32 offset_addr = add ? context.read_gpr(n) + imm32 : context.read_gpr(n) - imm32; - const u32 addr = index ? offset_addr : context.read_gpr(n); - vm::write16(addr, (u16)context.read_gpr(t)); + const u32 offset_addr = add ? cpu.read_gpr(n) + imm32 : cpu.read_gpr(n) - imm32; + const u32 addr = index ? offset_addr : cpu.read_gpr(n); + vm::write16(addr, (u16)cpu.read_gpr(t)); if (wback) { - context.write_gpr(n, offset_addr, type == T1 ? 2 : 4); + cpu.write_gpr(n, offset_addr, type == T1 ? 2 : 4); } } } -void ARMv7_instrs::STRH_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::STRH_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, t, n, m, shift_t, shift_n; - bool index, add, wback; + using args = arm_code::strh_reg; + ARG(t, op); + ARG(n, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + ARG(index, op); + ARG(add, op); + ARG(wback, op); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0x7); - n = (code.data & 0x38) >> 3; - m = (code.data & 0x1c0) >> 6; - index = true; - add = true; - wback = false; - shift_t = SRType_LSL; - shift_n = 0; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - t = (code.data & 0xf000) >> 12; - n = (code.data & 0xf0000) >> 16; - m = (code.data & 0xf); - index = true; - add = true; - wback = false; - shift_t = SRType_LSL; - shift_n = (code.data & 0x30) >> 4; - - reject(n == 15, "UNDEFINED"); - reject(t == 13 || t == 15 || m == 13 || m == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("strh%s %s,%s", fmt_cond(cond), fmt_reg(t), fmt_mem_reg(n, m, index, add, wback, shift_t, shift_n)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - const u32 offset = Shift(context.read_gpr(m), shift_t, shift_n, context.APSR.C); - const u32 offset_addr = add ? context.read_gpr(n) + offset : context.read_gpr(n) - offset; - const u32 addr = index ? offset_addr : context.read_gpr(n); - vm::write16(addr, (u16)context.read_gpr(t)); + const u32 offset = Shift(cpu.read_gpr(m), shift_t, shift_n, cpu.APSR.C); + const u32 offset_addr = add ? cpu.read_gpr(n) + offset : cpu.read_gpr(n) - offset; + const u32 addr = index ? offset_addr : cpu.read_gpr(n); + vm::write16(addr, (u16)cpu.read_gpr(t)); if (wback) { - context.write_gpr(n, offset_addr, type == T1 ? 2 : 4); + cpu.write_gpr(n, offset_addr, type == T1 ? 2 : 4); } } } -void ARMv7_instrs::STREX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::STREX(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, d, t, n, imm32; + using args = arm_code::strex; + ARG(d, op); + ARG(t, op); + ARG(n, op); + ARG(imm32, op); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - t = (code.data & 0xf000) >> 12; - n = (code.data & 0xf0000) >> 16; - imm32 = (code.data & 0xff) << 2; - - reject(d == 13 || d == 15 || t == 13 || t == 15 || n == 15, "UNPREDICTABLE"); - reject(d == n || d == t, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("strex%s %s,%s,[%s,#0x%x]", fmt_cond(cond), fmt_reg(d), fmt_reg(t), fmt_reg(n), imm32); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - const u32 addr = context.read_gpr(n) + imm32; - const u32 value = context.read_gpr(t); - context.write_gpr(d, !vm::reservation_update(addr, &value, sizeof(value)), 4); + const u32 addr = cpu.read_gpr(n) + imm32; + const u32 value = cpu.read_gpr(t); + cpu.write_gpr(d, !vm::reservation_update(addr, &value, sizeof(value)), 4); } } -void ARMv7_instrs::STREXB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::STREXB(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::STREXD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::STREXD(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::STREXH(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::STREXH(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SUB_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SUB_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - bool set_flags = !context.ITSTATE; - u32 cond, d, n, imm32; + using args = arm_code::sub_imm; + ARG(d, op); + ARG(n, op); + ARG(imm32, op); + ARG(set_flags, op, cond); - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0x7); - n = (code.data & 0x38) >> 3; - imm32 = (code.data & 0x1c) >> 6; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - d = n = (code.data & 0x700) >> 8; - imm32 = (code.data & 0xff); - break; - } - case T3: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - n = (code.data & 0xf0000) >> 16; - set_flags = (code.data & 0x100000) != 0; - imm32 = ThumbExpandImm((code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff)); - - reject(d == 15 && set_flags, "CMP (immediate)"); - reject(n == 13, "SUB (SP minus immediate)"); - reject(d == 13 || d == 15 || n == 15, "UNPREDICTABLE"); - break; - } - case T4: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - n = (code.data & 0xf0000) >> 16; - set_flags = false; - imm32 = (code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff); - - reject(d == 15, "ADR"); - reject(n == 13, "SUB (SP minus immediate)"); - reject(d == 13 || d == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("sub%s%s %s,%s,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), imm32); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) + if (ConditionPassed(cpu, cond)) { bool carry, overflow; - const u32 result = AddWithCarry(context.read_gpr(n), ~imm32, true, carry, overflow); - context.write_gpr(d, result, type < T3 ? 2 : 4); + const u32 result = AddWithCarry(cpu.read_gpr(n), ~imm32, true, carry, overflow); + cpu.write_gpr(d, result, type < T3 ? 2 : 4); if (set_flags) { - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; - context.APSR.V = overflow; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = carry; + cpu.APSR.V = overflow; } } } -void ARMv7_instrs::SUB_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SUB_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - bool set_flags = !context.ITSTATE; - u32 cond, d, n, m, shift_t, shift_n; + using args = arm_code::sub_reg; + ARG(d, op); + ARG(n, op); + ARG(m, op); + ARG(shift_t, op); + ARG(shift_n, op); + ARG(set_flags, op, cond); - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0x7); - n = (code.data & 0x38) >> 3; - m = (code.data & 0x1c0) >> 6; - shift_t = SRType_LSL; - shift_n = 0; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - n = (code.data & 0xf0000) >> 16; - m = (code.data & 0xf); - set_flags = (code.data & 0x100000) != 0; - shift_t = DecodeImmShift((code.data & 0x30) >> 4, (code.data & 0x7000) >> 10 | (code.data & 0xc0) >> 6, &shift_n); - - reject(d == 15 && set_flags, "CMP (register)"); - reject(n == 13, "SUB (SP minus register)"); - reject(d == 13 || d == 15 || n == 15 || m == 13 || m == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("sub%s%s %s,%s,%s%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), fmt_reg(n), fmt_reg(m), fmt_shift(shift_t, shift_n)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) + if (ConditionPassed(cpu, cond)) { bool carry, overflow; - const u32 shifted = Shift(context.read_gpr(m), shift_t, shift_n, context.APSR.C); - const u32 result = AddWithCarry(context.read_gpr(n), ~shifted, true, carry, overflow); - context.write_gpr(d, result, type == T1 ? 2 : 4); + const u32 shifted = Shift(cpu.read_gpr(m), shift_t, shift_n, cpu.APSR.C); + const u32 result = AddWithCarry(cpu.read_gpr(n), ~shifted, true, carry, overflow); + cpu.write_gpr(d, result, type == T1 ? 2 : 4); if (set_flags) { - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; - context.APSR.V = overflow; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = carry; + cpu.APSR.V = overflow; } } } -void ARMv7_instrs::SUB_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SUB_RSR(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SUB_SPI(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SUB_SPI(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, d, imm32; - bool set_flags; + using args = arm_code::sub_spi; + ARG(d, op); + ARG(imm32, op); + ARG(set_flags, op, cond); - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - d = 13; - set_flags = false; - imm32 = (code.data & 0x7f) << 2; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - set_flags = (code.data & 0x100000) != 0; - imm32 = ThumbExpandImm((code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff)); - - reject(d == 15 && set_flags, "CMP (immediate)"); - reject(d == 15, "UNPREDICTABLE"); - break; - } - case T3: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - set_flags = false; - imm32 = (code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff); - - reject(d == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("sub%s%s %s,sp,#0x%X", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d), imm32); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) + if (ConditionPassed(cpu, cond)) { bool carry, overflow; - const u32 result = AddWithCarry(context.SP, ~imm32, true, carry, overflow); - context.write_gpr(d, result, type == T1 ? 2 : 4); + const u32 result = AddWithCarry(cpu.SP, ~imm32, true, carry, overflow); + cpu.write_gpr(d, result, type == T1 ? 2 : 4); if (set_flags) { - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; - context.APSR.V = overflow; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = carry; + cpu.APSR.V = overflow; } } } -void ARMv7_instrs::SUB_SPR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SUB_SPR(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SVC(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SVC(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SXTAB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SXTAB(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SXTAB16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SXTAB16(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SXTAH(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SXTAH(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SXTB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SXTB(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SXTB16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SXTB16(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::SXTH(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::SXTH(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::TB_(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::TB_(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::TEQ_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::TEQ_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::TEQ_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::TEQ_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::TEQ_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::TEQ_RSR(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::TST_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::TST_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - bool carry = context.APSR.C; - u32 cond, n, imm32; + using args = arm_code::tst_imm; + ARG(n, op); + ARG(imm32, op); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - n = (code.data & 0xf0000) >> 16; - imm32 = ThumbExpandImm_C((code.data & 0x4000000) >> 15 | (code.data & 0x7000) >> 4 | (code.data & 0xff), carry, carry); - - reject(n == 13 || n == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("tst%s %s,#0x%X", fmt_cond(cond), fmt_reg(n), imm32); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - const u32 result = context.read_gpr(n) & imm32; - context.APSR.N = result >> 31; - context.APSR.Z = result == 0; - context.APSR.C = carry; + const u32 result = cpu.read_gpr(n) & imm32; + cpu.APSR.N = result >> 31; + cpu.APSR.Z = result == 0; + cpu.APSR.C = args::carry::extract(op, cpu.APSR.C); } } -void ARMv7_instrs::TST_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::TST_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::TST_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::TST_RSR(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::UADD16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::UADD16(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::UADD8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::UADD8(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::UASX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::UASX(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::UBFX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::UBFX(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::UDIV(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::UDIV(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::UHADD16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::UHADD16(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::UHADD8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::UHADD8(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::UHASX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::UHASX(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::UHSAX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::UHSAX(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::UHSUB16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::UHSUB16(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::UHSUB8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::UHSUB8(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::UMAAL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::UMAAL(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::UMLAL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::UMLAL(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::UMULL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::UMULL(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, d0, d1, n, m; - bool set_flags; + using args = arm_code::umull; + ARG(d0, op); + ARG(d1, op); + ARG(n, op); + ARG(m, op); + ARG(set_flags, op, cond); - switch (type) + if (ConditionPassed(cpu, cond)) { - case T1: - { - cond = context.ITSTATE.advance(); - d0 = (code.data & 0xf000) >> 12; - d1 = (code.data & 0xf00) >> 8; - n = (code.data & 0xf0000) >> 16; - m = (code.data & 0xf); - set_flags = false; - - reject(d0 == 13 || d0 == 15 || d1 == 13 || d1 == 15 || n == 13 || n == 15 || m == 13 || m == 15, "UNPREDICTABLE"); - reject(d0 == d1, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) - { - if (context.debug & DF_DISASM) context.fmt_debug_str("umull%s%s %s,%s,%s,%s", set_flags ? "s" : "", fmt_cond(cond), fmt_reg(d0), fmt_reg(d1), fmt_reg(n), fmt_reg(m)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - const u64 result = (u64)context.read_gpr(n) * (u64)context.read_gpr(m); - context.write_gpr(d1, (u32)(result >> 32), 4); - context.write_gpr(d0, (u32)(result), 4); + const u64 result = (u64)cpu.read_gpr(n) * (u64)cpu.read_gpr(m); + cpu.write_gpr(d1, (u32)(result >> 32), 4); + cpu.write_gpr(d0, (u32)(result), 4); if (set_flags) { - context.APSR.N = result >> 63 != 0; - context.APSR.Z = result == 0; + cpu.APSR.N = result >> 63 != 0; + cpu.APSR.Z = result == 0; } } } -void ARMv7_instrs::UQADD16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::UQADD16(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::UQADD8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::UQADD8(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::UQASX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::UQASX(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::UQSAX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::UQSAX(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::UQSUB16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::UQSUB16(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::UQSUB8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::UQSUB8(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::USAD8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::USAD8(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::USADA8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::USADA8(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::USAT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::USAT(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::USAT16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::USAT16(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::USAX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::USAX(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::USUB16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::USUB16(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::USUB8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::USUB8(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::UXTAB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::UXTAB(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::UXTAB16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::UXTAB16(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::UXTAH(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::UXTAH(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::UXTB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::UXTB(ARMv7Thread& cpu, const u32 op, const u32 cond) { - u32 cond, d, m, rot; - - switch (type) - { - case T1: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0x7); - m = (code.data & 0x38) >> 3; - rot = 0; - break; - } - case T2: - { - cond = context.ITSTATE.advance(); - d = (code.data & 0xf00) >> 8; - m = (code.data & 0xf); - rot = (code.data & 0x30) >> 1; + using args = arm_code::uxtb; + ARG(d, op); + ARG(m, op); + ARG(rotation, op); - reject(d == 13 || d == 15 || m == 13 || m == 15, "UNPREDICTABLE"); - break; - } - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } - - if (context.debug) + if (ConditionPassed(cpu, cond)) { - if (context.debug & DF_DISASM) context.fmt_debug_str("uxtb%s %s,%s%s", fmt_cond(cond), fmt_reg(d), fmt_reg(m), fmt_shift(SRType_ROR, rot)); - if (process_debug(context)) return; - } - - if (ConditionPassed(context, cond)) - { - context.write_gpr(d, (context.read_gpr(m) >> rot) & 0xff, type == T1 ? 2 : 4); + cpu.write_gpr(d, u8(cpu.read_gpr(m) >> rotation), type == T1 ? 2 : 4); } } -void ARMv7_instrs::UXTB16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::UXTB16(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::UXTH(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::UXTH(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VABA_(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VABA_(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VABD_(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VABD_(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VABD_FP(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VABD_FP(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VABS(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VABS(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VAC__(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VAC__(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VADD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VADD(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VADD_FP(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VADD_FP(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VADDHN(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VADDHN(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VADD_(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VADD_(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VAND(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VAND(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VBIC_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VBIC_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VBIC_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VBIC_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VB__(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VB__(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VCEQ_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VCEQ_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VCEQ_ZERO(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VCEQ_ZERO(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VCGE_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VCGE_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VCGE_ZERO(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VCGE_ZERO(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VCGT_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VCGT_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VCGT_ZERO(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VCGT_ZERO(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VCLE_ZERO(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VCLE_ZERO(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VCLS(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VCLS(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VCLT_ZERO(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VCLT_ZERO(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VCLZ(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VCLZ(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VCMP_(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VCMP_(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VCNT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VCNT(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VCVT_FIA(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VCVT_FIA(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VCVT_FIF(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VCVT_FIF(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VCVT_FFA(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VCVT_FFA(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VCVT_FFF(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VCVT_FFF(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VCVT_DF(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VCVT_DF(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VCVT_HFA(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VCVT_HFA(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VCVT_HFF(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VCVT_HFF(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VDIV(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VDIV(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VDUP_S(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VDUP_S(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VDUP_R(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VDUP_R(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VEOR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VEOR(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VEXT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VEXT(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VHADDSUB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VHADDSUB(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VLD__MS(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VLD__MS(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VLD1_SL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VLD1_SL(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VLD1_SAL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VLD1_SAL(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VLD2_SL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VLD2_SL(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VLD2_SAL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VLD2_SAL(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VLD3_SL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VLD3_SL(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VLD3_SAL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VLD3_SAL(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VLD4_SL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VLD4_SL(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VLD4_SAL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VLD4_SAL(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VLDM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VLDM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VLDR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VLDR(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VMAXMIN(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VMAXMIN(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VMAXMIN_FP(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VMAXMIN_FP(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VML__(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VML__(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VML__FP(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VML__FP(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VML__S(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VML__S(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VMOV_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VMOV_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VMOV_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VMOV_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VMOV_RS(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VMOV_RS(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VMOV_SR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VMOV_SR(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VMOV_RF(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VMOV_RF(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VMOV_2RF(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VMOV_2RF(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VMOV_2RD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VMOV_2RD(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VMOVL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VMOVL(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VMOVN(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VMOVN(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VMRS(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VMRS(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VMSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VMSR(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VMUL_(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VMUL_(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VMUL_FP(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VMUL_FP(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VMUL_S(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VMUL_S(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VMVN_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VMVN_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VMVN_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VMVN_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VNEG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VNEG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VNM__(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VNM__(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VORN_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VORN_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VORR_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VORR_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VORR_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VORR_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VPADAL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VPADAL(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VPADD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VPADD(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VPADD_FP(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VPADD_FP(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VPADDL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VPADDL(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VPMAXMIN(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VPMAXMIN(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VPMAXMIN_FP(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VPMAXMIN_FP(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VPOP(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VPOP(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VPUSH(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VPUSH(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VQABS(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VQABS(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VQADD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VQADD(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VQDML_L(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VQDML_L(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VQDMULH(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VQDMULH(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VQDMULL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VQDMULL(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VQMOV_N(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VQMOV_N(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VQNEG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VQNEG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VQRDMULH(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VQRDMULH(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VQRSHL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VQRSHL(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VQRSHR_N(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VQRSHR_N(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VQSHL_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VQSHL_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VQSHL_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VQSHL_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VQSHR_N(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VQSHR_N(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VQSUB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VQSUB(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VRADDHN(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VRADDHN(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VRECPE(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VRECPE(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VRECPS(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VRECPS(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VREV__(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VREV__(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VRHADD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VRHADD(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VRSHL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VRSHL(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VRSHR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VRSHR(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VRSHRN(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VRSHRN(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VRSQRTE(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VRSQRTE(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VRSQRTS(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VRSQRTS(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VRSRA(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VRSRA(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VRSUBHN(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VRSUBHN(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VSHL_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VSHL_IMM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VSHL_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VSHL_REG(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VSHLL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VSHLL(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VSHR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VSHR(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VSHRN(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VSHRN(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VSLI(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VSLI(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VSQRT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VSQRT(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VSRA(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VSRA(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VSRI(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VSRI(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VST__MS(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VST__MS(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VST1_SL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VST1_SL(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VST2_SL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VST2_SL(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VST3_SL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VST3_SL(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VST4_SL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VST4_SL(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VSTM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VSTM(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VSTR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VSTR(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VSUB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VSUB(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VSUB_FP(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VSUB_FP(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VSUBHN(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VSUBHN(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VSUB_(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VSUB_(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VSWP(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VSWP(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VTB_(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VTB_(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VTRN(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VTRN(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VTST(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VTST(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VUZP(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VUZP(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::VZIP(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::VZIP(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::WFE(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::WFE(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::WFI(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::WFI(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } -void ARMv7_instrs::YIELD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) +template +void arm_interpreter::YIELD(ARMv7Thread& cpu, const u32 op, const u32 cond) { - switch (type) - { - case A1: throw EXCEPTION(""); - default: throw EXCEPTION(""); - } + throw EXCEPTION("TODO"); } + +template void arm_interpreter::HACK(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::HACK(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADC_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADC_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADC_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADC_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADC_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADC_RSR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADD_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADD_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADD_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADD_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADD_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADD_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADD_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADD_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADD_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADD_RSR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADD_SPI(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADD_SPI(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADD_SPI(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADD_SPI(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADD_SPI(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADD_SPR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADD_SPR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADD_SPR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADD_SPR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ADR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::AND_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::AND_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::AND_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::AND_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::AND_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::AND_RSR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ASR_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ASR_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ASR_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ASR_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ASR_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ASR_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::B(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::B(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::B(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::B(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::B(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::BFC(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::BFC(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::BFI(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::BFI(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::BIC_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::BIC_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::BIC_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::BIC_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::BIC_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::BIC_RSR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::BKPT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::BKPT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::BL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::BL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::BL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::BL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::BLX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::BLX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::BX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::BX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::CB_Z(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::CLZ(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::CLZ(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::CMN_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::CMN_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::CMN_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::CMN_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::CMN_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::CMN_RSR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::CMP_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::CMP_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::CMP_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::CMP_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::CMP_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::CMP_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::CMP_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::CMP_RSR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::DBG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::DBG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::DMB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::DMB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::DSB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::DSB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::EOR_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::EOR_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::EOR_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::EOR_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::EOR_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::EOR_RSR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::IT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDMDA(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDMDB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDMDB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDMIB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDR_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDR_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDR_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDR_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDR_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDR_LIT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDR_LIT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDR_LIT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDR_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDR_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDR_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRB_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRB_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRB_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRB_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRB_LIT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRB_LIT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRB_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRB_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRB_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRD_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRD_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRD_LIT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRD_LIT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRD_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDREX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDREX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDREXB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDREXB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDREXD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDREXD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDREXH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDREXH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRH_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRH_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRH_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRH_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRH_LIT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRH_LIT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRH_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRH_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRH_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRSB_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRSB_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRSB_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRSB_LIT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRSB_LIT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRSB_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRSB_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRSB_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRSH_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRSH_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRSH_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRSH_LIT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRSH_LIT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRSH_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRSH_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LDRSH_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LSL_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LSL_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LSL_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LSL_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LSL_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LSL_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LSR_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LSR_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LSR_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LSR_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LSR_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::LSR_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MLA(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MLA(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MLS(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MLS(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MOV_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MOV_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MOV_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MOV_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MOV_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MOV_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MOV_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MOV_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MOV_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MOVT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MOVT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MRC_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MRC_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MRC_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MRC_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MRS(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MRS(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MSR_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MSR_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MSR_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MUL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MUL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MUL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MVN_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MVN_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MVN_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MVN_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MVN_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::MVN_RSR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::NOP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::NOP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::NOP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ORN_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ORN_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ORR_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ORR_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ORR_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ORR_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ORR_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ORR_RSR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::PKH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::PKH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::POP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::POP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::POP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::POP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::POP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::PUSH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::PUSH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::PUSH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::PUSH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::PUSH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::QADD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::QADD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::QADD16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::QADD16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::QADD8(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::QADD8(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::QASX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::QASX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::QDADD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::QDADD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::QDSUB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::QDSUB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::QSAX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::QSAX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::QSUB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::QSUB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::QSUB16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::QSUB16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::QSUB8(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::QSUB8(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::RBIT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::RBIT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::REV(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::REV(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::REV(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::REV16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::REV16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::REV16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::REVSH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::REVSH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::REVSH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ROR_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ROR_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ROR_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ROR_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::ROR_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::RRX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::RRX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::RSB_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::RSB_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::RSB_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::RSB_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::RSB_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::RSB_RSR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::RSC_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::RSC_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::RSC_RSR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SADD16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SADD16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SADD8(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SADD8(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SASX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SASX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SBC_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SBC_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SBC_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SBC_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SBC_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SBC_RSR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SBFX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SBFX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SDIV(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SEL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SEL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SHADD16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SHADD16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SHADD8(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SHADD8(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SHASX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SHASX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SHSAX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SHSAX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SHSUB16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SHSUB16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SHSUB8(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SHSUB8(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMLA__(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMLA__(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMLAD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMLAD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMLAL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMLAL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMLAL__(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMLAL__(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMLALD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMLALD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMLAW_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMLAW_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMLSD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMLSD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMLSLD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMLSLD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMMLA(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMMLA(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMMLS(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMMLS(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMMUL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMMUL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMUAD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMUAD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMUL__(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMUL__(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMULL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMULL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMULW_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMULW_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMUSD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SMUSD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SSAT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SSAT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SSAT16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SSAT16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SSAX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SSAX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SSUB16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SSUB16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SSUB8(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SSUB8(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STMDA(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STMDB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STMDB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STMIB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STR_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STR_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STR_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STR_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STR_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STR_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STR_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STR_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STRB_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STRB_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STRB_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STRB_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STRB_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STRB_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STRB_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STRD_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STRD_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STRD_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STREX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STREX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STREXB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STREXB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STREXD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STREXD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STREXH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STREXH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STRH_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STRH_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STRH_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STRH_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STRH_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STRH_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::STRH_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SUB_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SUB_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SUB_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SUB_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SUB_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SUB_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SUB_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SUB_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SUB_RSR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SUB_SPI(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SUB_SPI(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SUB_SPI(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SUB_SPI(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SUB_SPR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SUB_SPR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SVC(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SVC(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SXTAB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SXTAB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SXTAB16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SXTAB16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SXTAH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SXTAH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SXTB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SXTB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SXTB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SXTB16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SXTB16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SXTH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SXTH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::SXTH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::TB_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::TEQ_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::TEQ_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::TEQ_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::TEQ_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::TEQ_RSR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::TST_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::TST_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::TST_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::TST_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::TST_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::TST_RSR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UADD16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UADD16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UADD8(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UADD8(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UASX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UASX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UBFX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UBFX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UDIV(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UHADD16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UHADD16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UHADD8(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UHADD8(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UHASX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UHASX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UHSAX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UHSAX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UHSUB16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UHSUB16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UHSUB8(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UHSUB8(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UMAAL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UMAAL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UMLAL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UMLAL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UMULL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UMULL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UQADD16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UQADD16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UQADD8(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UQADD8(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UQASX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UQASX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UQSAX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UQSAX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UQSUB16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UQSUB16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UQSUB8(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UQSUB8(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::USAD8(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::USAD8(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::USADA8(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::USADA8(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::USAT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::USAT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::USAT16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::USAT16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::USAX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::USAX(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::USUB16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::USUB16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::USUB8(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::USUB8(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UXTAB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UXTAB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UXTAB16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UXTAB16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UXTAH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UXTAH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UXTB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UXTB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UXTB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UXTB16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UXTB16(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UXTH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UXTH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::UXTH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VABA_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VABA_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VABA_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VABA_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VABD_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VABD_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VABD_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VABD_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VABD_FP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VABD_FP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VABS(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VABS(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VABS(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VABS(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VAC__(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VAC__(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VADD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VADD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VADD_FP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VADD_FP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VADD_FP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VADD_FP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VADDHN(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VADDHN(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VADD_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VADD_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VAND(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VAND(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VBIC_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VBIC_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VBIC_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VBIC_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VB__(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VB__(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCEQ_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCEQ_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCEQ_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCEQ_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCEQ_ZERO(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCEQ_ZERO(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCGE_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCGE_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCGE_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCGE_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCGE_ZERO(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCGE_ZERO(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCGT_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCGT_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCGT_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCGT_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCGT_ZERO(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCGT_ZERO(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCLE_ZERO(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCLE_ZERO(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCLS(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCLS(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCLT_ZERO(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCLT_ZERO(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCLZ(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCLZ(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCMP_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCMP_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCMP_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCMP_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCNT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCNT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCVT_FIA(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCVT_FIA(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCVT_FIF(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCVT_FIF(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCVT_FFA(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCVT_FFA(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCVT_FFF(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCVT_FFF(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCVT_DF(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCVT_DF(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCVT_HFA(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCVT_HFA(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCVT_HFF(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VCVT_HFF(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VDIV(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VDIV(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VDUP_S(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VDUP_S(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VDUP_R(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VDUP_R(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VEOR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VEOR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VEXT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VEXT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VHADDSUB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VHADDSUB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VLD__MS(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VLD__MS(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VLD1_SAL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VLD1_SAL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VLD1_SL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VLD1_SL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VLD2_SAL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VLD2_SAL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VLD2_SL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VLD2_SL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VLD3_SAL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VLD3_SAL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VLD3_SL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VLD3_SL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VLD4_SAL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VLD4_SAL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VLD4_SL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VLD4_SL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VLDM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VLDM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VLDM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VLDM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VLDR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VLDR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VLDR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VLDR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMAXMIN(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMAXMIN(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMAXMIN_FP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMAXMIN_FP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VML__(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VML__(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VML__(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VML__(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VML__FP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VML__FP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VML__FP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VML__FP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VML__S(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VML__S(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VML__S(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VML__S(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMOV_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMOV_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMOV_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMOV_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMOV_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMOV_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMOV_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMOV_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMOV_RS(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMOV_RS(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMOV_SR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMOV_SR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMOV_RF(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMOV_RF(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMOV_2RF(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMOV_2RF(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMOV_2RD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMOV_2RD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMOVL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMOVL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMOVN(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMOVN(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMRS(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMRS(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMSR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMSR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMUL_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMUL_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMUL_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMUL_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMUL_FP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMUL_FP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMUL_FP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMUL_FP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMUL_S(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMUL_S(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMUL_S(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMUL_S(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMVN_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMVN_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMVN_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VMVN_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VNEG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VNEG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VNEG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VNEG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VNM__(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VNM__(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VNM__(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VNM__(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VORN_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VORN_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VORR_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VORR_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VORR_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VORR_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VPADAL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VPADAL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VPADD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VPADD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VPADD_FP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VPADD_FP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VPADDL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VPADDL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VPMAXMIN(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VPMAXMIN(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VPMAXMIN_FP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VPMAXMIN_FP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VPOP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VPOP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VPOP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VPOP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VPUSH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VPUSH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VPUSH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VPUSH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQABS(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQABS(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQADD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQADD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQDML_L(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQDML_L(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQDML_L(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQDML_L(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQDMULH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQDMULH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQDMULH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQDMULH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQDMULL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQDMULL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQDMULL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQDMULL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQMOV_N(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQMOV_N(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQNEG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQNEG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQRDMULH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQRDMULH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQRDMULH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQRDMULH(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQRSHL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQRSHL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQRSHR_N(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQRSHR_N(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQSHL_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQSHL_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQSHL_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQSHL_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQSHR_N(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQSHR_N(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQSUB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VQSUB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VRADDHN(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VRADDHN(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VRECPE(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VRECPE(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VRECPS(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VRECPS(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VREV__(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VREV__(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VRHADD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VRHADD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VRSHL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VRSHL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VRSHR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VRSHR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VRSHRN(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VRSHRN(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VRSQRTE(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VRSQRTE(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VRSQRTS(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VRSQRTS(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VRSRA(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VRSRA(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VRSUBHN(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VRSUBHN(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSHL_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSHL_IMM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSHL_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSHL_REG(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSHLL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSHLL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSHLL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSHLL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSHR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSHR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSHRN(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSHRN(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSLI(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSLI(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSQRT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSQRT(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSRA(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSRA(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSRI(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSRI(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VST__MS(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VST__MS(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VST1_SL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VST1_SL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VST2_SL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VST2_SL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VST3_SL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VST3_SL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VST4_SL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VST4_SL(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSTM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSTM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSTM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSTM(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSTR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSTR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSTR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSTR(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSUB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSUB(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSUB_FP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSUB_FP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSUB_FP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSUB_FP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSUBHN(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSUBHN(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSUB_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSUB_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSWP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VSWP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VTB_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VTB_(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VTRN(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VTRN(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VTST(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VTST(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VUZP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VUZP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VZIP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::VZIP(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::WFE(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::WFE(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::WFE(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::WFI(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::WFI(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::WFI(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::YIELD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::YIELD(ARMv7Thread&, const u32, const u32); +template void arm_interpreter::YIELD(ARMv7Thread&, const u32, const u32); diff --git a/rpcs3/Emu/ARMv7/ARMv7Interpreter.h b/rpcs3/Emu/ARMv7/ARMv7Interpreter.h index e759f5e40b..33f3b3d622 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Interpreter.h +++ b/rpcs3/Emu/ARMv7/ARMv7Interpreter.h @@ -1,455 +1,604 @@ #pragma once -union ARMv7Code +#include "ARMv7Thread.h" +#include "ARMv7Opcodes.h" + +struct arm_interpreter { - struct + template + static u32 BitCount(T x, size_t len) { - u16 code0; - u16 code1; - }; + u32 result = 0; - u32 data; -}; - -enum ARMv7_encoding -{ - T1, T2, T3, T4, A1, A2 -}; - -enum SRType : u32 -{ - SRType_LSL, - SRType_LSR, - SRType_ASR, - SRType_ROR, - SRType_RRX, -}; - -namespace ARMv7_instrs -{ - void UNK(ARMv7Context& context, const ARMv7Code code); - - void HACK(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void MRC_(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void ADC_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void ADC_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void ADC_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void ADD_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void ADD_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void ADD_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void ADD_SPI(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void ADD_SPR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void ADR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void AND_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void AND_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void AND_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void ASR_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void ASR_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void B(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void BFC(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void BFI(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void BIC_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void BIC_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void BIC_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void BKPT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void BL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void BLX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void BX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void CB_Z(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void CLZ(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void CMN_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void CMN_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void CMN_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void CMP_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void CMP_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void CMP_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void DBG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void DMB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void DSB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void EOR_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void EOR_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void EOR_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void IT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void LDM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void LDMDA(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void LDMDB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void LDMIB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void LDR_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void LDR_LIT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void LDR_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void LDRB_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void LDRB_LIT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void LDRB_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void LDRD_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void LDRD_LIT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void LDRD_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void LDRH_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void LDRH_LIT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void LDRH_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void LDRSB_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void LDRSB_LIT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void LDRSB_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void LDRSH_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void LDRSH_LIT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void LDRSH_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void LDREX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void LDREXB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void LDREXD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void LDREXH(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void LSL_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void LSL_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void LSR_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void LSR_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void MLA(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void MLS(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void MOV_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void MOV_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void MOVT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void MRS(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void MSR_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void MSR_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void MUL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void MVN_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void MVN_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void MVN_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void NOP(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void ORN_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void ORN_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void ORR_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void ORR_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void ORR_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void PKH(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void POP(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void PUSH(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void QADD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void QADD16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void QADD8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void QASX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void QDADD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void QDSUB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void QSAX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void QSUB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void QSUB16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void QSUB8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void RBIT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void REV(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void REV16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void REVSH(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void ROR_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void ROR_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void RRX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void RSB_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void RSB_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void RSB_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void RSC_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void RSC_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void RSC_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void SADD16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SADD8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SASX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void SBC_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SBC_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SBC_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void SBFX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void SDIV(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void SEL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void SHADD16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SHADD8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SHASX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SHSAX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SHSUB16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SHSUB8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void SMLA__(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SMLAD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SMLAL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SMLAL__(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SMLALD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SMLAW_(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SMLSD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SMLSLD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SMMLA(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SMMLS(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SMMUL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SMUAD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SMUL__(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SMULL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SMULW_(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SMUSD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void SSAT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SSAT16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SSAX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SSUB16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SSUB8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void STM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void STMDA(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void STMDB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void STMIB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void STR_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void STR_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void STRB_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void STRB_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void STRD_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void STRD_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void STRH_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void STRH_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void STREX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void STREXB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void STREXD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void STREXH(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void SUB_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SUB_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SUB_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SUB_SPI(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SUB_SPR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void SVC(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void SXTAB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SXTAB16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SXTAH(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SXTB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SXTB16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void SXTH(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void TB_(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void TEQ_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void TEQ_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void TEQ_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void TST_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void TST_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void TST_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void UADD16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void UADD8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void UASX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void UBFX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void UDIV(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void UHADD16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void UHADD8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void UHASX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void UHSAX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void UHSUB16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void UHSUB8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void UMAAL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void UMLAL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void UMULL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void UQADD16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void UQADD8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void UQASX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void UQSAX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void UQSUB16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void UQSUB8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void USAD8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void USADA8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void USAT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void USAT16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void USAX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void USUB16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void USUB8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void UXTAB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void UXTAB16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void UXTAH(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void UXTB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void UXTB16(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void UXTH(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void VABA_(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VABD_(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VABD_FP(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VABS(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VAC__(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VADD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VADD_FP(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VADDHN(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VADD_(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VAND(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VBIC_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VBIC_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VB__(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VCEQ_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VCEQ_ZERO(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VCGE_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VCGE_ZERO(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VCGT_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VCGT_ZERO(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VCLE_ZERO(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VCLS(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VCLT_ZERO(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VCLZ(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VCMP_(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VCNT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VCVT_FIA(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VCVT_FIF(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VCVT_FFA(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VCVT_FFF(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VCVT_DF(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VCVT_HFA(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VCVT_HFF(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VDIV(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VDUP_S(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VDUP_R(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VEOR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VEXT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VHADDSUB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VLD__MS(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VLD1_SL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VLD1_SAL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VLD2_SL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VLD2_SAL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VLD3_SL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VLD3_SAL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VLD4_SL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VLD4_SAL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VLDM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VLDR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VMAXMIN(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VMAXMIN_FP(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VML__(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VML__FP(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VML__S(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VMOV_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VMOV_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VMOV_RS(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VMOV_SR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VMOV_RF(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VMOV_2RF(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VMOV_2RD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VMOVL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VMOVN(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VMRS(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VMSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VMUL_(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VMUL_FP(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VMUL_S(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VMVN_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VMVN_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VNEG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VNM__(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VORN_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VORR_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VORR_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VPADAL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VPADD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VPADD_FP(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VPADDL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VPMAXMIN(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VPMAXMIN_FP(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VPOP(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VPUSH(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VQABS(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VQADD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VQDML_L(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VQDMULH(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VQDMULL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VQMOV_N(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VQNEG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VQRDMULH(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VQRSHL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VQRSHR_N(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VQSHL_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VQSHL_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VQSHR_N(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VQSUB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VRADDHN(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VRECPE(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VRECPS(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VREV__(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VRHADD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VRSHL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VRSHR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VRSHRN(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VRSQRTE(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VRSQRTS(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VRSRA(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VRSUBHN(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VSHL_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VSHL_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VSHLL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VSHR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VSHRN(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VSLI(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VSQRT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VSRA(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VSRI(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VST__MS(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VST1_SL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VST2_SL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VST3_SL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VST4_SL(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VSTM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VSTR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VSUB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VSUB_FP(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VSUBHN(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VSUB_(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VSWP(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VTB_(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VTRN(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VTST(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VUZP(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void VZIP(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - void WFE(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void WFI(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - void YIELD(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); + for (T mask = static_cast(1) << (len - 1); mask; mask >>= 1) + { + if (x & mask) result++; + } + + return result; + } + + static u32 DecodeImmShift(u32 type, u32 imm5, u32* shift_n) + { + using namespace arm_code; + + SRType shift_t; + + switch (type) + { + case 0: shift_t = SRType_LSL; if (shift_n) *shift_n = imm5; break; + case 1: shift_t = SRType_LSR; if (shift_n) *shift_n = imm5 == 0 ? 32 : imm5; break; + case 2: shift_t = SRType_ASR; if (shift_n) *shift_n = imm5 == 0 ? 32 : imm5; break; + case 3: + if (imm5 == 0) + { + shift_t = SRType_RRX; if (shift_n) *shift_n = 1; + } + else + { + shift_t = SRType_ROR; if (shift_n) *shift_n = imm5; + } + break; + + default: throw EXCEPTION(""); + } + + return shift_t; + } + + static u32 LSL_C(u32 x, s32 shift, bool& carry_out) + { + Expects(shift > 0); + carry_out = shift <= 32 ? (x & (1 << (32 - shift))) != 0 : false; + return shift < 32 ? x << shift : 0; + } + + static u32 LSL_(u32 x, s32 shift) + { + Expects(shift >= 0); + return shift < 32 ? x << shift : 0; + } + + static u32 LSR_C(u32 x, s32 shift, bool& carry_out) + { + Expects(shift > 0); + carry_out = shift <= 32 ? (x & (1 << (shift - 1))) != 0 : false; + return shift < 32 ? x >> shift : 0; + } + + static u32 LSR_(u32 x, s32 shift) + { + Expects(shift >= 0); + return shift < 32 ? x >> shift : 0; + } + + static s32 ASR_C(s32 x, s32 shift, bool& carry_out) + { + Expects(shift > 0); + carry_out = shift <= 32 ? (x & (1 << (shift - 1))) != 0 : x < 0; + return shift < 32 ? x >> shift : x >> 31; + } + + static s32 ASR_(s32 x, s32 shift) + { + Expects(shift >= 0); + return shift < 32 ? x >> shift : x >> 31; + } + + static u32 ROR_C(u32 x, s32 shift, bool& carry_out) + { + Expects(shift); + const u32 result = x >> shift | x << (32 - shift); + carry_out = (result >> 31) != 0; + return result; + } + + static u32 ROR_(u32 x, s32 shift) + { + return x >> shift | x << (32 - shift); + } + + static u32 RRX_C(u32 x, bool carry_in, bool& carry_out) + { + carry_out = x & 0x1; + return ((u32)carry_in << 31) | (x >> 1); + } + + static u32 RRX_(u32 x, bool carry_in) + { + return ((u32)carry_in << 31) | (x >> 1); + } + + static u32 Shift_C(u32 value, u32 type, s32 amount, bool carry_in, bool& carry_out) + { + Expects(type != arm_code::SRType_RRX || amount == 1); + + if (amount) + { + switch (type) + { + case arm_code::SRType_LSL: return LSL_C(value, amount, carry_out); + case arm_code::SRType_LSR: return LSR_C(value, amount, carry_out); + case arm_code::SRType_ASR: return ASR_C(value, amount, carry_out); + case arm_code::SRType_ROR: return ROR_C(value, amount, carry_out); + case arm_code::SRType_RRX: return RRX_C(value, carry_in, carry_out); + default: throw EXCEPTION(""); + } + } + + carry_out = carry_in; + return value; + } + + static u32 Shift(u32 value, u32 type, s32 amount, bool carry_in) + { + bool carry_out; + return Shift_C(value, type, amount, carry_in, carry_out); + } + + template static T AddWithCarry(T x, T y, bool carry_in, bool& carry_out, bool& overflow) + { + const T sign_mask = (T)1 << (sizeof(T) * 8 - 1); + + T result = x + y; + carry_out = (((x & y) | ((x ^ y) & ~result)) & sign_mask) != 0; + overflow = ((x ^ result) & (y ^ result) & sign_mask) != 0; + if (carry_in) + { + result += 1; + carry_out ^= (result == 0); + overflow ^= (result == sign_mask); + } + return result; + } + + static bool ConditionPassed(ARMv7Thread& cpu, u32 cond) + { + bool result = false; + + switch (cond >> 1) + { + case 0: result = (cpu.APSR.Z == 1); break; + case 1: result = (cpu.APSR.C == 1); break; + case 2: result = (cpu.APSR.N == 1); break; + case 3: result = (cpu.APSR.V == 1); break; + case 4: result = (cpu.APSR.C == 1) && (cpu.APSR.Z == 0); break; + case 5: result = (cpu.APSR.N == cpu.APSR.V); break; + case 6: result = (cpu.APSR.N == cpu.APSR.V) && (cpu.APSR.Z == 0); break; + case 7: return true; + } + + if (cond & 0x1) + { + return !result; + } + + return result; + } + + static void UNK(ARMv7Thread&, const u32 op, const u32 cond); + + template static void HACK(ARMv7Thread&, const u32, const u32); + template static void MRC_(ARMv7Thread&, const u32, const u32); + + template static void ADC_IMM(ARMv7Thread&, const u32, const u32); + template static void ADC_REG(ARMv7Thread&, const u32, const u32); + template static void ADC_RSR(ARMv7Thread&, const u32, const u32); + + template static void ADD_IMM(ARMv7Thread&, const u32, const u32); + template static void ADD_REG(ARMv7Thread&, const u32, const u32); + template static void ADD_RSR(ARMv7Thread&, const u32, const u32); + template static void ADD_SPI(ARMv7Thread&, const u32, const u32); + template static void ADD_SPR(ARMv7Thread&, const u32, const u32); + + template static void ADR(ARMv7Thread&, const u32, const u32); + + template static void AND_IMM(ARMv7Thread&, const u32, const u32); + template static void AND_REG(ARMv7Thread&, const u32, const u32); + template static void AND_RSR(ARMv7Thread&, const u32, const u32); + + template static void ASR_IMM(ARMv7Thread&, const u32, const u32); + template static void ASR_REG(ARMv7Thread&, const u32, const u32); + + template static void B(ARMv7Thread&, const u32, const u32); + + template static void BFC(ARMv7Thread&, const u32, const u32); + template static void BFI(ARMv7Thread&, const u32, const u32); + + template static void BIC_IMM(ARMv7Thread&, const u32, const u32); + template static void BIC_REG(ARMv7Thread&, const u32, const u32); + template static void BIC_RSR(ARMv7Thread&, const u32, const u32); + + template static void BKPT(ARMv7Thread&, const u32, const u32); + + template static void BL(ARMv7Thread&, const u32, const u32); + template static void BLX(ARMv7Thread&, const u32, const u32); + template static void BX(ARMv7Thread&, const u32, const u32); + + template static void CB_Z(ARMv7Thread&, const u32, const u32); + + template static void CLZ(ARMv7Thread&, const u32, const u32); + + template static void CMN_IMM(ARMv7Thread&, const u32, const u32); + template static void CMN_REG(ARMv7Thread&, const u32, const u32); + template static void CMN_RSR(ARMv7Thread&, const u32, const u32); + + template static void CMP_IMM(ARMv7Thread&, const u32, const u32); + template static void CMP_REG(ARMv7Thread&, const u32, const u32); + template static void CMP_RSR(ARMv7Thread&, const u32, const u32); + + template static void DBG(ARMv7Thread&, const u32, const u32); + template static void DMB(ARMv7Thread&, const u32, const u32); + template static void DSB(ARMv7Thread&, const u32, const u32); + + template static void EOR_IMM(ARMv7Thread&, const u32, const u32); + template static void EOR_REG(ARMv7Thread&, const u32, const u32); + template static void EOR_RSR(ARMv7Thread&, const u32, const u32); + + template static void IT(ARMv7Thread&, const u32, const u32); + + template static void LDM(ARMv7Thread&, const u32, const u32); + template static void LDMDA(ARMv7Thread&, const u32, const u32); + template static void LDMDB(ARMv7Thread&, const u32, const u32); + template static void LDMIB(ARMv7Thread&, const u32, const u32); + + template static void LDR_IMM(ARMv7Thread&, const u32, const u32); + template static void LDR_LIT(ARMv7Thread&, const u32, const u32); + template static void LDR_REG(ARMv7Thread&, const u32, const u32); + + template static void LDRB_IMM(ARMv7Thread&, const u32, const u32); + template static void LDRB_LIT(ARMv7Thread&, const u32, const u32); + template static void LDRB_REG(ARMv7Thread&, const u32, const u32); + + template static void LDRD_IMM(ARMv7Thread&, const u32, const u32); + template static void LDRD_LIT(ARMv7Thread&, const u32, const u32); + template static void LDRD_REG(ARMv7Thread&, const u32, const u32); + + template static void LDRH_IMM(ARMv7Thread&, const u32, const u32); + template static void LDRH_LIT(ARMv7Thread&, const u32, const u32); + template static void LDRH_REG(ARMv7Thread&, const u32, const u32); + + template static void LDRSB_IMM(ARMv7Thread&, const u32, const u32); + template static void LDRSB_LIT(ARMv7Thread&, const u32, const u32); + template static void LDRSB_REG(ARMv7Thread&, const u32, const u32); + + template static void LDRSH_IMM(ARMv7Thread&, const u32, const u32); + template static void LDRSH_LIT(ARMv7Thread&, const u32, const u32); + template static void LDRSH_REG(ARMv7Thread&, const u32, const u32); + + template static void LDREX(ARMv7Thread&, const u32, const u32); + template static void LDREXB(ARMv7Thread&, const u32, const u32); + template static void LDREXD(ARMv7Thread&, const u32, const u32); + template static void LDREXH(ARMv7Thread&, const u32, const u32); + + template static void LSL_IMM(ARMv7Thread&, const u32, const u32); + template static void LSL_REG(ARMv7Thread&, const u32, const u32); + + template static void LSR_IMM(ARMv7Thread&, const u32, const u32); + template static void LSR_REG(ARMv7Thread&, const u32, const u32); + + template static void MLA(ARMv7Thread&, const u32, const u32); + template static void MLS(ARMv7Thread&, const u32, const u32); + + template static void MOV_IMM(ARMv7Thread&, const u32, const u32); + template static void MOV_REG(ARMv7Thread&, const u32, const u32); + template static void MOVT(ARMv7Thread&, const u32, const u32); + + template static void MRS(ARMv7Thread&, const u32, const u32); + template static void MSR_IMM(ARMv7Thread&, const u32, const u32); + template static void MSR_REG(ARMv7Thread&, const u32, const u32); + + template static void MUL(ARMv7Thread&, const u32, const u32); + + template static void MVN_IMM(ARMv7Thread&, const u32, const u32); + template static void MVN_REG(ARMv7Thread&, const u32, const u32); + template static void MVN_RSR(ARMv7Thread&, const u32, const u32); + + template static void NOP(ARMv7Thread&, const u32, const u32); + + template static void ORN_IMM(ARMv7Thread&, const u32, const u32); + template static void ORN_REG(ARMv7Thread&, const u32, const u32); + + template static void ORR_IMM(ARMv7Thread&, const u32, const u32); + template static void ORR_REG(ARMv7Thread&, const u32, const u32); + template static void ORR_RSR(ARMv7Thread&, const u32, const u32); + + template static void PKH(ARMv7Thread&, const u32, const u32); + + template static void POP(ARMv7Thread&, const u32, const u32); + template static void PUSH(ARMv7Thread&, const u32, const u32); + + template static void QADD(ARMv7Thread&, const u32, const u32); + template static void QADD16(ARMv7Thread&, const u32, const u32); + template static void QADD8(ARMv7Thread&, const u32, const u32); + template static void QASX(ARMv7Thread&, const u32, const u32); + template static void QDADD(ARMv7Thread&, const u32, const u32); + template static void QDSUB(ARMv7Thread&, const u32, const u32); + template static void QSAX(ARMv7Thread&, const u32, const u32); + template static void QSUB(ARMv7Thread&, const u32, const u32); + template static void QSUB16(ARMv7Thread&, const u32, const u32); + template static void QSUB8(ARMv7Thread&, const u32, const u32); + + template static void RBIT(ARMv7Thread&, const u32, const u32); + template static void REV(ARMv7Thread&, const u32, const u32); + template static void REV16(ARMv7Thread&, const u32, const u32); + template static void REVSH(ARMv7Thread&, const u32, const u32); + + template static void ROR_IMM(ARMv7Thread&, const u32, const u32); + template static void ROR_REG(ARMv7Thread&, const u32, const u32); + + template static void RRX(ARMv7Thread&, const u32, const u32); + + template static void RSB_IMM(ARMv7Thread&, const u32, const u32); + template static void RSB_REG(ARMv7Thread&, const u32, const u32); + template static void RSB_RSR(ARMv7Thread&, const u32, const u32); + + template static void RSC_IMM(ARMv7Thread&, const u32, const u32); + template static void RSC_REG(ARMv7Thread&, const u32, const u32); + template static void RSC_RSR(ARMv7Thread&, const u32, const u32); + + template static void SADD16(ARMv7Thread&, const u32, const u32); + template static void SADD8(ARMv7Thread&, const u32, const u32); + template static void SASX(ARMv7Thread&, const u32, const u32); + + template static void SBC_IMM(ARMv7Thread&, const u32, const u32); + template static void SBC_REG(ARMv7Thread&, const u32, const u32); + template static void SBC_RSR(ARMv7Thread&, const u32, const u32); + + template static void SBFX(ARMv7Thread&, const u32, const u32); + + template static void SDIV(ARMv7Thread&, const u32, const u32); + + template static void SEL(ARMv7Thread&, const u32, const u32); + + template static void SHADD16(ARMv7Thread&, const u32, const u32); + template static void SHADD8(ARMv7Thread&, const u32, const u32); + template static void SHASX(ARMv7Thread&, const u32, const u32); + template static void SHSAX(ARMv7Thread&, const u32, const u32); + template static void SHSUB16(ARMv7Thread&, const u32, const u32); + template static void SHSUB8(ARMv7Thread&, const u32, const u32); + + template static void SMLA__(ARMv7Thread&, const u32, const u32); + template static void SMLAD(ARMv7Thread&, const u32, const u32); + template static void SMLAL(ARMv7Thread&, const u32, const u32); + template static void SMLAL__(ARMv7Thread&, const u32, const u32); + template static void SMLALD(ARMv7Thread&, const u32, const u32); + template static void SMLAW_(ARMv7Thread&, const u32, const u32); + template static void SMLSD(ARMv7Thread&, const u32, const u32); + template static void SMLSLD(ARMv7Thread&, const u32, const u32); + template static void SMMLA(ARMv7Thread&, const u32, const u32); + template static void SMMLS(ARMv7Thread&, const u32, const u32); + template static void SMMUL(ARMv7Thread&, const u32, const u32); + template static void SMUAD(ARMv7Thread&, const u32, const u32); + template static void SMUL__(ARMv7Thread&, const u32, const u32); + template static void SMULL(ARMv7Thread&, const u32, const u32); + template static void SMULW_(ARMv7Thread&, const u32, const u32); + template static void SMUSD(ARMv7Thread&, const u32, const u32); + + template static void SSAT(ARMv7Thread&, const u32, const u32); + template static void SSAT16(ARMv7Thread&, const u32, const u32); + template static void SSAX(ARMv7Thread&, const u32, const u32); + template static void SSUB16(ARMv7Thread&, const u32, const u32); + template static void SSUB8(ARMv7Thread&, const u32, const u32); + + template static void STM(ARMv7Thread&, const u32, const u32); + template static void STMDA(ARMv7Thread&, const u32, const u32); + template static void STMDB(ARMv7Thread&, const u32, const u32); + template static void STMIB(ARMv7Thread&, const u32, const u32); + + template static void STR_IMM(ARMv7Thread&, const u32, const u32); + template static void STR_REG(ARMv7Thread&, const u32, const u32); + + template static void STRB_IMM(ARMv7Thread&, const u32, const u32); + template static void STRB_REG(ARMv7Thread&, const u32, const u32); + + template static void STRD_IMM(ARMv7Thread&, const u32, const u32); + template static void STRD_REG(ARMv7Thread&, const u32, const u32); + + template static void STRH_IMM(ARMv7Thread&, const u32, const u32); + template static void STRH_REG(ARMv7Thread&, const u32, const u32); + + template static void STREX(ARMv7Thread&, const u32, const u32); + template static void STREXB(ARMv7Thread&, const u32, const u32); + template static void STREXD(ARMv7Thread&, const u32, const u32); + template static void STREXH(ARMv7Thread&, const u32, const u32); + + template static void SUB_IMM(ARMv7Thread&, const u32, const u32); + template static void SUB_REG(ARMv7Thread&, const u32, const u32); + template static void SUB_RSR(ARMv7Thread&, const u32, const u32); + template static void SUB_SPI(ARMv7Thread&, const u32, const u32); + template static void SUB_SPR(ARMv7Thread&, const u32, const u32); + + template static void SVC(ARMv7Thread&, const u32, const u32); + + template static void SXTAB(ARMv7Thread&, const u32, const u32); + template static void SXTAB16(ARMv7Thread&, const u32, const u32); + template static void SXTAH(ARMv7Thread&, const u32, const u32); + template static void SXTB(ARMv7Thread&, const u32, const u32); + template static void SXTB16(ARMv7Thread&, const u32, const u32); + template static void SXTH(ARMv7Thread&, const u32, const u32); + + template static void TB_(ARMv7Thread&, const u32, const u32); + + template static void TEQ_IMM(ARMv7Thread&, const u32, const u32); + template static void TEQ_REG(ARMv7Thread&, const u32, const u32); + template static void TEQ_RSR(ARMv7Thread&, const u32, const u32); + + template static void TST_IMM(ARMv7Thread&, const u32, const u32); + template static void TST_REG(ARMv7Thread&, const u32, const u32); + template static void TST_RSR(ARMv7Thread&, const u32, const u32); + + template static void UADD16(ARMv7Thread&, const u32, const u32); + template static void UADD8(ARMv7Thread&, const u32, const u32); + template static void UASX(ARMv7Thread&, const u32, const u32); + template static void UBFX(ARMv7Thread&, const u32, const u32); + template static void UDIV(ARMv7Thread&, const u32, const u32); + template static void UHADD16(ARMv7Thread&, const u32, const u32); + template static void UHADD8(ARMv7Thread&, const u32, const u32); + template static void UHASX(ARMv7Thread&, const u32, const u32); + template static void UHSAX(ARMv7Thread&, const u32, const u32); + template static void UHSUB16(ARMv7Thread&, const u32, const u32); + template static void UHSUB8(ARMv7Thread&, const u32, const u32); + template static void UMAAL(ARMv7Thread&, const u32, const u32); + template static void UMLAL(ARMv7Thread&, const u32, const u32); + template static void UMULL(ARMv7Thread&, const u32, const u32); + template static void UQADD16(ARMv7Thread&, const u32, const u32); + template static void UQADD8(ARMv7Thread&, const u32, const u32); + template static void UQASX(ARMv7Thread&, const u32, const u32); + template static void UQSAX(ARMv7Thread&, const u32, const u32); + template static void UQSUB16(ARMv7Thread&, const u32, const u32); + template static void UQSUB8(ARMv7Thread&, const u32, const u32); + template static void USAD8(ARMv7Thread&, const u32, const u32); + template static void USADA8(ARMv7Thread&, const u32, const u32); + template static void USAT(ARMv7Thread&, const u32, const u32); + template static void USAT16(ARMv7Thread&, const u32, const u32); + template static void USAX(ARMv7Thread&, const u32, const u32); + template static void USUB16(ARMv7Thread&, const u32, const u32); + template static void USUB8(ARMv7Thread&, const u32, const u32); + template static void UXTAB(ARMv7Thread&, const u32, const u32); + template static void UXTAB16(ARMv7Thread&, const u32, const u32); + template static void UXTAH(ARMv7Thread&, const u32, const u32); + template static void UXTB(ARMv7Thread&, const u32, const u32); + template static void UXTB16(ARMv7Thread&, const u32, const u32); + template static void UXTH(ARMv7Thread&, const u32, const u32); + + template static void VABA_(ARMv7Thread&, const u32, const u32); + template static void VABD_(ARMv7Thread&, const u32, const u32); + template static void VABD_FP(ARMv7Thread&, const u32, const u32); + template static void VABS(ARMv7Thread&, const u32, const u32); + template static void VAC__(ARMv7Thread&, const u32, const u32); + template static void VADD(ARMv7Thread&, const u32, const u32); + template static void VADD_FP(ARMv7Thread&, const u32, const u32); + template static void VADDHN(ARMv7Thread&, const u32, const u32); + template static void VADD_(ARMv7Thread&, const u32, const u32); + template static void VAND(ARMv7Thread&, const u32, const u32); + template static void VBIC_IMM(ARMv7Thread&, const u32, const u32); + template static void VBIC_REG(ARMv7Thread&, const u32, const u32); + template static void VB__(ARMv7Thread&, const u32, const u32); + template static void VCEQ_REG(ARMv7Thread&, const u32, const u32); + template static void VCEQ_ZERO(ARMv7Thread&, const u32, const u32); + template static void VCGE_REG(ARMv7Thread&, const u32, const u32); + template static void VCGE_ZERO(ARMv7Thread&, const u32, const u32); + template static void VCGT_REG(ARMv7Thread&, const u32, const u32); + template static void VCGT_ZERO(ARMv7Thread&, const u32, const u32); + template static void VCLE_ZERO(ARMv7Thread&, const u32, const u32); + template static void VCLS(ARMv7Thread&, const u32, const u32); + template static void VCLT_ZERO(ARMv7Thread&, const u32, const u32); + template static void VCLZ(ARMv7Thread&, const u32, const u32); + template static void VCMP_(ARMv7Thread&, const u32, const u32); + template static void VCNT(ARMv7Thread&, const u32, const u32); + template static void VCVT_FIA(ARMv7Thread&, const u32, const u32); + template static void VCVT_FIF(ARMv7Thread&, const u32, const u32); + template static void VCVT_FFA(ARMv7Thread&, const u32, const u32); + template static void VCVT_FFF(ARMv7Thread&, const u32, const u32); + template static void VCVT_DF(ARMv7Thread&, const u32, const u32); + template static void VCVT_HFA(ARMv7Thread&, const u32, const u32); + template static void VCVT_HFF(ARMv7Thread&, const u32, const u32); + template static void VDIV(ARMv7Thread&, const u32, const u32); + template static void VDUP_S(ARMv7Thread&, const u32, const u32); + template static void VDUP_R(ARMv7Thread&, const u32, const u32); + template static void VEOR(ARMv7Thread&, const u32, const u32); + template static void VEXT(ARMv7Thread&, const u32, const u32); + template static void VHADDSUB(ARMv7Thread&, const u32, const u32); + template static void VLD__MS(ARMv7Thread&, const u32, const u32); + template static void VLD1_SL(ARMv7Thread&, const u32, const u32); + template static void VLD1_SAL(ARMv7Thread&, const u32, const u32); + template static void VLD2_SL(ARMv7Thread&, const u32, const u32); + template static void VLD2_SAL(ARMv7Thread&, const u32, const u32); + template static void VLD3_SL(ARMv7Thread&, const u32, const u32); + template static void VLD3_SAL(ARMv7Thread&, const u32, const u32); + template static void VLD4_SL(ARMv7Thread&, const u32, const u32); + template static void VLD4_SAL(ARMv7Thread&, const u32, const u32); + template static void VLDM(ARMv7Thread&, const u32, const u32); + template static void VLDR(ARMv7Thread&, const u32, const u32); + template static void VMAXMIN(ARMv7Thread&, const u32, const u32); + template static void VMAXMIN_FP(ARMv7Thread&, const u32, const u32); + template static void VML__(ARMv7Thread&, const u32, const u32); + template static void VML__FP(ARMv7Thread&, const u32, const u32); + template static void VML__S(ARMv7Thread&, const u32, const u32); + template static void VMOV_IMM(ARMv7Thread&, const u32, const u32); + template static void VMOV_REG(ARMv7Thread&, const u32, const u32); + template static void VMOV_RS(ARMv7Thread&, const u32, const u32); + template static void VMOV_SR(ARMv7Thread&, const u32, const u32); + template static void VMOV_RF(ARMv7Thread&, const u32, const u32); + template static void VMOV_2RF(ARMv7Thread&, const u32, const u32); + template static void VMOV_2RD(ARMv7Thread&, const u32, const u32); + template static void VMOVL(ARMv7Thread&, const u32, const u32); + template static void VMOVN(ARMv7Thread&, const u32, const u32); + template static void VMRS(ARMv7Thread&, const u32, const u32); + template static void VMSR(ARMv7Thread&, const u32, const u32); + template static void VMUL_(ARMv7Thread&, const u32, const u32); + template static void VMUL_FP(ARMv7Thread&, const u32, const u32); + template static void VMUL_S(ARMv7Thread&, const u32, const u32); + template static void VMVN_IMM(ARMv7Thread&, const u32, const u32); + template static void VMVN_REG(ARMv7Thread&, const u32, const u32); + template static void VNEG(ARMv7Thread&, const u32, const u32); + template static void VNM__(ARMv7Thread&, const u32, const u32); + template static void VORN_REG(ARMv7Thread&, const u32, const u32); + template static void VORR_IMM(ARMv7Thread&, const u32, const u32); + template static void VORR_REG(ARMv7Thread&, const u32, const u32); + template static void VPADAL(ARMv7Thread&, const u32, const u32); + template static void VPADD(ARMv7Thread&, const u32, const u32); + template static void VPADD_FP(ARMv7Thread&, const u32, const u32); + template static void VPADDL(ARMv7Thread&, const u32, const u32); + template static void VPMAXMIN(ARMv7Thread&, const u32, const u32); + template static void VPMAXMIN_FP(ARMv7Thread&, const u32, const u32); + template static void VPOP(ARMv7Thread&, const u32, const u32); + template static void VPUSH(ARMv7Thread&, const u32, const u32); + template static void VQABS(ARMv7Thread&, const u32, const u32); + template static void VQADD(ARMv7Thread&, const u32, const u32); + template static void VQDML_L(ARMv7Thread&, const u32, const u32); + template static void VQDMULH(ARMv7Thread&, const u32, const u32); + template static void VQDMULL(ARMv7Thread&, const u32, const u32); + template static void VQMOV_N(ARMv7Thread&, const u32, const u32); + template static void VQNEG(ARMv7Thread&, const u32, const u32); + template static void VQRDMULH(ARMv7Thread&, const u32, const u32); + template static void VQRSHL(ARMv7Thread&, const u32, const u32); + template static void VQRSHR_N(ARMv7Thread&, const u32, const u32); + template static void VQSHL_REG(ARMv7Thread&, const u32, const u32); + template static void VQSHL_IMM(ARMv7Thread&, const u32, const u32); + template static void VQSHR_N(ARMv7Thread&, const u32, const u32); + template static void VQSUB(ARMv7Thread&, const u32, const u32); + template static void VRADDHN(ARMv7Thread&, const u32, const u32); + template static void VRECPE(ARMv7Thread&, const u32, const u32); + template static void VRECPS(ARMv7Thread&, const u32, const u32); + template static void VREV__(ARMv7Thread&, const u32, const u32); + template static void VRHADD(ARMv7Thread&, const u32, const u32); + template static void VRSHL(ARMv7Thread&, const u32, const u32); + template static void VRSHR(ARMv7Thread&, const u32, const u32); + template static void VRSHRN(ARMv7Thread&, const u32, const u32); + template static void VRSQRTE(ARMv7Thread&, const u32, const u32); + template static void VRSQRTS(ARMv7Thread&, const u32, const u32); + template static void VRSRA(ARMv7Thread&, const u32, const u32); + template static void VRSUBHN(ARMv7Thread&, const u32, const u32); + template static void VSHL_IMM(ARMv7Thread&, const u32, const u32); + template static void VSHL_REG(ARMv7Thread&, const u32, const u32); + template static void VSHLL(ARMv7Thread&, const u32, const u32); + template static void VSHR(ARMv7Thread&, const u32, const u32); + template static void VSHRN(ARMv7Thread&, const u32, const u32); + template static void VSLI(ARMv7Thread&, const u32, const u32); + template static void VSQRT(ARMv7Thread&, const u32, const u32); + template static void VSRA(ARMv7Thread&, const u32, const u32); + template static void VSRI(ARMv7Thread&, const u32, const u32); + template static void VST__MS(ARMv7Thread&, const u32, const u32); + template static void VST1_SL(ARMv7Thread&, const u32, const u32); + template static void VST2_SL(ARMv7Thread&, const u32, const u32); + template static void VST3_SL(ARMv7Thread&, const u32, const u32); + template static void VST4_SL(ARMv7Thread&, const u32, const u32); + template static void VSTM(ARMv7Thread&, const u32, const u32); + template static void VSTR(ARMv7Thread&, const u32, const u32); + template static void VSUB(ARMv7Thread&, const u32, const u32); + template static void VSUB_FP(ARMv7Thread&, const u32, const u32); + template static void VSUBHN(ARMv7Thread&, const u32, const u32); + template static void VSUB_(ARMv7Thread&, const u32, const u32); + template static void VSWP(ARMv7Thread&, const u32, const u32); + template static void VTB_(ARMv7Thread&, const u32, const u32); + template static void VTRN(ARMv7Thread&, const u32, const u32); + template static void VTST(ARMv7Thread&, const u32, const u32); + template static void VUZP(ARMv7Thread&, const u32, const u32); + template static void VZIP(ARMv7Thread&, const u32, const u32); + + template static void WFE(ARMv7Thread&, const u32, const u32); + template static void WFI(ARMv7Thread&, const u32, const u32); + template static void YIELD(ARMv7Thread&, const u32, const u32); }; diff --git a/rpcs3/Emu/ARMv7/ARMv7Module.cpp b/rpcs3/Emu/ARMv7/ARMv7Module.cpp new file mode 100644 index 0000000000..8f0f2785a6 --- /dev/null +++ b/rpcs3/Emu/ARMv7/ARMv7Module.cpp @@ -0,0 +1,578 @@ +#include "stdafx.h" +#include "Loader/ELF.h" +#include "Emu/Memory/Memory.h" +#include "Emu/System.h" +#include "Emu/IdManager.h" + +#include "ARMv7Thread.h" +#include "ARMv7Opcodes.h" +#include "ARMv7Function.h" +#include "ARMv7Module.h" + +extern void armv7_init_tls(); + +extern std::string arm_get_function_name(const std::string& module, u32 fnid); +extern std::string arm_get_variable_name(const std::string& module, u32 vnid); + +// Function lookup table. Not supposed to grow after emulation start. +std::vector g_arm_function_cache; + +extern void arm_execute_function(ARMv7Thread& cpu, u32 index) +{ + if (index < g_arm_function_cache.size()) + { + if (const auto func = g_arm_function_cache[index]) + { + const auto previous_function = cpu.last_function; // TODO: use gsl::finally or something + + try + { + func(cpu); + } + catch (const std::exception&) + { + LOG_ERROR(ARMv7, "Function '%s' aborted", cpu.last_function); + cpu.last_function = previous_function; + throw; + } + catch (EmulationStopped) + { + LOG_WARNING(ARMv7, "Function '%s' aborted", cpu.last_function); + cpu.last_function = previous_function; + throw; + } + + LOG_TRACE(ARMv7, "Function '%s' finished, r0=0x%x", cpu.last_function, cpu.GPR[0]); + cpu.last_function = previous_function; + return; + } + } + + throw fmt::exception("Function not registered (%u)" HERE, index); +} + +arm_static_module::arm_static_module(const char* name) + : name(name) +{ + arm_module_manager::register_module(this); +} + +static void arm_initialize_modules() +{ + const std::initializer_list registered + { + &arm_module_manager::SceAppMgr, + &arm_module_manager::SceAppUtil, + &arm_module_manager::SceAudio, + &arm_module_manager::SceAudiodec, + &arm_module_manager::SceAudioenc, + &arm_module_manager::SceAudioIn, + &arm_module_manager::SceCamera, + &arm_module_manager::SceCodecEngine, + &arm_module_manager::SceCommonDialog, + &arm_module_manager::SceCpu, + &arm_module_manager::SceCtrl, + &arm_module_manager::SceDbg, + &arm_module_manager::SceDebugLed, + &arm_module_manager::SceDeci4p, + &arm_module_manager::SceDeflt, + &arm_module_manager::SceDipsw, + &arm_module_manager::SceDisplay, + &arm_module_manager::SceDisplayUser, + &arm_module_manager::SceFiber, + &arm_module_manager::SceFios, + &arm_module_manager::SceFpu, + &arm_module_manager::SceGxm, + &arm_module_manager::SceHttp, + &arm_module_manager::SceIme, + &arm_module_manager::SceIofilemgr, + &arm_module_manager::SceJpeg, + &arm_module_manager::SceJpegEnc, + &arm_module_manager::SceLibc, + &arm_module_manager::SceLibKernel, + &arm_module_manager::SceLibm, + &arm_module_manager::SceLibstdcxx, + &arm_module_manager::SceLibXml, + &arm_module_manager::SceLiveArea, + &arm_module_manager::SceLocation, + &arm_module_manager::SceMd5, + &arm_module_manager::SceModulemgr, + &arm_module_manager::SceMotion, + &arm_module_manager::SceMt19937, + &arm_module_manager::SceNet, + &arm_module_manager::SceNetCtl, + &arm_module_manager::SceNgs, + &arm_module_manager::SceNpBasic, + &arm_module_manager::SceNpCommon, + &arm_module_manager::SceNpManager, + &arm_module_manager::SceNpMatching, + &arm_module_manager::SceNpScore, + &arm_module_manager::SceNpUtility, + &arm_module_manager::ScePerf, + &arm_module_manager::ScePgf, + &arm_module_manager::ScePhotoExport, + &arm_module_manager::SceProcessmgr, + &arm_module_manager::SceRazorCapture, + &arm_module_manager::SceRtc, + &arm_module_manager::SceSas, + &arm_module_manager::SceScreenShot, + &arm_module_manager::SceSfmt, + &arm_module_manager::SceSha, + &arm_module_manager::SceSqlite, + &arm_module_manager::SceSsl, + &arm_module_manager::SceStdio, + &arm_module_manager::SceSulpha, + &arm_module_manager::SceSysmem, + &arm_module_manager::SceSysmodule, + &arm_module_manager::SceSystemGesture, + &arm_module_manager::SceThreadmgr, + &arm_module_manager::SceTouch, + &arm_module_manager::SceUlt, + &arm_module_manager::SceVideodec, + &arm_module_manager::SceVoice, + &arm_module_manager::SceVoiceQoS, + }; + + // Reinitialize function cache + g_arm_function_cache = arm_function_manager::get(); + + // "Use" all the modules for correct linkage + for (auto& module : registered) + { + LOG_TRACE(LOADER, "Registered static module: %s", module->name); + + for (auto& function : module->functions) + { + LOG_TRACE(LOADER, "** 0x%08X: %s", function.first, function.second.name); + } + + for (auto& variable : module->variables) + { + LOG_TRACE(LOADER, "** &0x%08X: %s (size=0x%x, align=0x%x)", variable.first, variable.second.name, variable.second.size, variable.second.align); + variable.second.var->set(0); + } + } +} + +struct psv_moduleinfo_t +{ + le_t attr; // ??? + u8 major; // ??? + u8 minor; // ??? + char name[24]; // ??? + le_t unk0; + le_t unk1; + le_t libent_top; + le_t libent_end; + le_t libstub_top; + le_t libstub_end; + le_t data[1]; // ... +}; + +struct psv_libent_t +{ + le_t size; // ??? + le_t unk0; + le_t unk1; + le_t fcount; + le_t vcount; + le_t unk2; + le_t unk3; + le_t data[1]; // ... +}; + +struct psv_libstub_t +{ + le_t size; // 0x2C, 0x34 + le_t unk0; // (usually 1, 5 for sceLibKernel) + le_t unk1; // (usually 0) + le_t fcount; + le_t vcount; + le_t unk2; + le_t unk3; + le_t data[1]; // ... +}; + +struct psv_libcparam_t +{ + le_t size; + le_t unk0; + + vm::lcptr sceLibcHeapSize; + vm::lcptr sceLibcHeapSizeDefault; + vm::lcptr sceLibcHeapExtendedAlloc; + vm::lcptr sceLibcHeapDelayedAlloc; + + le_t unk1; + le_t unk2; + + vm::lptr __sce_libcmallocreplace; + vm::lptr __sce_libcnewreplace; +}; + +struct psv_process_param_t +{ + le_t size; // 0x00000030 + nse_t ver; // 'PSP2' + le_t unk0; // 0x00000005 + le_t unk1; + + vm::lcptr sceUserMainThreadName; + vm::lcptr sceUserMainThreadPriority; + vm::lcptr sceUserMainThreadStackSize; + vm::lcptr sceUserMainThreadAttribute; + vm::lcptr sceProcessName; + vm::lcptr sce_process_preload_disabled; + vm::lcptr sceUserMainThreadCpuAffinityMask; + + vm::lcptr sce_libcparam; +}; + +static void arm_patch_refs(u32 refs, u32 addr) +{ + auto ptr = vm::cptr::make(refs); + LOG_NOTICE(LOADER, "**** Processing refs at 0x%x:", ptr); + + if (ptr[0] != 0xff || ptr[1] != addr) + { + LOG_ERROR(LOADER, "**** Unexpected ref format ([0]=0x%x, [1]=0x%x)", ptr[0], ptr[1]); + } + else for (ptr += 2; *ptr; ptr++) + { + switch (u32 code = *ptr) + { + case 0x0000002f: // movw r*,# instruction + { + const u32 raddr = *++ptr; + vm::write16(raddr + 0, vm::read16(raddr + 0) | (addr & 0x800) >> 1 | (addr & 0xf000) >> 12); + vm::write16(raddr + 2, vm::read16(raddr + 2) | (addr & 0x700) << 4 | (addr & 0xff)); + + LOG_NOTICE(LOADER, "**** MOVW written at *0x%x", raddr); + break; + } + case 0x00000030: // movt r*,# instruction + { + const u32 raddr = *++ptr; + vm::write16(raddr + 0, vm::read16(raddr + 0) | (addr & 0x8000000) >> 17 | (addr & 0xf0000000) >> 28); + vm::write16(raddr + 2, vm::read16(raddr + 2) | (addr & 0x7000000) >> 12 | (addr & 0xff0000) >> 16); + + LOG_NOTICE(LOADER, "**** MOVT written at *0x%x", raddr); + break; + } + default: + { + LOG_ERROR(LOADER, "**** Unknown ref code found (0x%08x)", code); + } + } + } + +} + +template<> +void arm_exec_loader::load() const +{ + arm_initialize_modules(); + + vm::cptr module_info{}; + vm::cptr libent{}; + vm::cptr libstub{}; + vm::cptr proc_param{}; + + u32 entry_point{}; + u32 start_addr{}; + u32 arm_exidx{}; + u32 arm_extab{}; + u32 tls_faddr{}; + u32 tls_fsize{}; + u32 tls_vsize{}; + + for (const auto& prog : progs) + { + if (prog.p_type == 0x1 /* LOAD */ && prog.p_memsz) + { + if (!vm::falloc(prog.p_vaddr, prog.p_memsz, vm::main)) + { + throw fmt::exception("vm::falloc() failed (addr=0x%x, size=0x%x)", prog.p_vaddr, prog.p_memsz); + } + + if (prog.p_paddr) + { + module_info.set(prog.p_vaddr + (prog.p_paddr - prog.p_offset)); + LOG_NOTICE(LOADER, "Found program with p_paddr=0x%x", prog.p_paddr); + } + + if (!start_addr) + { + start_addr = prog.p_vaddr; + } + + std::memcpy(vm::base(prog.p_vaddr), prog.bin.data(), prog.p_filesz); + } + } + + if (!module_info) module_info.set(start_addr + header.e_entry); + if (!libent) libent.set(start_addr + module_info->libent_top); + if (!libstub) libstub.set(start_addr + module_info->libstub_top); + + LOG_NOTICE(LOADER, "__sce_moduleinfo(*0x%x) analysis...", module_info); + + if (module_info->data[2] == 0xffffffff) + { + arm_exidx = module_info->data[3]; + arm_extab = module_info->data[4]; + tls_faddr = module_info->data[5]; + tls_fsize = module_info->data[6]; + tls_vsize = module_info->data[7]; + } + else if (module_info->data[5] == 0xffffffff) + { + tls_faddr = module_info->data[1]; // Guess + tls_fsize = module_info->data[2]; + tls_vsize = module_info->data[3]; + arm_exidx = module_info->data[6]; + arm_extab = module_info->data[8]; + } + else + { + LOG_ERROR(LOADER, "Failed to recognize __sce_moduleinfo format"); + } + + LOG_NOTICE(LOADER, "** arm_exidx=0x%x", arm_exidx); + LOG_NOTICE(LOADER, "** arm_extab=0x%x", arm_extab); + LOG_NOTICE(LOADER, "** tls_faddr=0x%x", tls_faddr); + LOG_NOTICE(LOADER, "** tls_fsize=0x%x", tls_fsize); + LOG_NOTICE(LOADER, "** tls_vsize=0x%x", tls_vsize); + + Emu.SetTLSData(tls_faddr + start_addr, tls_fsize, tls_vsize); + + // Process exports + while (libent.addr() < start_addr + module_info->libent_end) + { + const u32 size = libent->size; + + // TODO: check addresses + if (size != 0x1c && size != 0x20) + { + LOG_ERROR(LOADER, "Unknown libent size (0x%x) at *0x%x", libent->size, libent); + } + else + { + LOG_NOTICE(LOADER, "Loading libent at *0x%x", libent); + LOG_NOTICE(LOADER, "** 0x%x, 0x%x", libent->unk0, libent->unk1); + LOG_NOTICE(LOADER, "** Functions: %u", libent->fcount); + LOG_NOTICE(LOADER, "** Variables: %u", libent->vcount); + LOG_NOTICE(LOADER, "** 0x%x, 0x%08x", libent->unk2, libent->unk3); + + const auto export_nids = vm::cptr::make(libent->data[size == 0x20 ? 2 : 1]); + const auto export_data = vm::cptr::make(libent->data[size == 0x20 ? 3 : 2]); + + for (u32 i = 0, count = export_data - export_nids; i < count; i++) + { + const u32 nid = export_nids[i]; + const u32 addr = export_data[i]; + + // Known exports + switch (nid) + { + case 0x935cd196: // set entry point + { + entry_point = addr; + break; + } + + case 0x6c2224ba: // __sce_moduleinfo + { + ASSERT(addr == module_info.addr()); + break; + } + + case 0x70fba1e7: // __sce_process_param + { + proc_param.set(addr); + break; + } + + default: + { + LOG_ERROR(LOADER, "** Unknown export '0x%08X' (*0x%x)", nid, addr); + } + } + } + } + + // Next entry + libent.set(libent.addr() + libent->size); + } + + // Process imports + while (libstub.addr() < start_addr + module_info->libstub_end) + { + const u32 size = libstub->size; + + // TODO: check addresses + if (size != 0x2c && size != 0x34) + { + LOG_ERROR(LOADER, "Unknown libstub size (0x%x) at *0x%x)", libstub->size, libstub); + } + else + { + const std::string module_name(vm::_ptr(libstub->data[size == 0x34 ? 1 : 0])); + + LOG_NOTICE(LOADER, "Loading libstub at 0x%x: %s", libstub, module_name); + + const auto _sm = arm_module_manager::get_module(module_name); + + if (!_sm) + { + LOG_ERROR(LOADER, "** Unknown module '%s'", module_name); + } + else + { + // Allocate HLE variables (TODO) + for (auto& var : _sm->variables) + { + var.second.var->set(vm::alloc(var.second.size, vm::main, std::max(var.second.align, 4096))); + LOG_WARNING(LOADER, "** Allocated variable '%s' in module '%s' at *0x%x", var.second.name, module_name, var.second.var->addr()); + } + + // Initialize HLE variables (TODO) + for (auto& var : _sm->variables) + { + var.second.init(); + } + } + + LOG_NOTICE(LOADER, "** 0x%x, 0x%x", libstub->unk0, libstub->unk1); + LOG_NOTICE(LOADER, "** Functions: %u", libstub->fcount); + LOG_NOTICE(LOADER, "** Variables: %u", libstub->vcount); + LOG_NOTICE(LOADER, "** 0x%x, 0x%08x", libstub->unk2, libstub->unk3); + + const auto fnids = vm::cptr::make(libstub->data[size == 0x34 ? 3 : 1]); + const auto fstubs = vm::cptr::make(libstub->data[size == 0x34 ? 4 : 2]); + + for (u32 j = 0; j < libstub->fcount; j++) + { + const u32 fnid = fnids[j]; + const u32 faddr = fstubs[j]; + + u32 index = 0; + + const auto fstub = vm::ptr::make(faddr); + const auto fname = arm_get_function_name(module_name, fnid); + + if (_sm && _sm->functions.count(fnid)) + { + index = _sm->functions.at(fnid).index; + LOG_NOTICE(LOADER, "** Imported function '%s' in module '%s' (*0x%x)", fname, module_name, faddr); + } + else + { + // TODO + index = ::size32(g_arm_function_cache); + g_arm_function_cache.emplace_back(); + + LOG_ERROR(LOADER, "** Unknown function '%s' in module '%s' (*0x%x) -> index %u", fname, module_name, faddr, index); + } + + // Check import stub + if (fstub[2] != 0xE1A00000) + { + LOG_ERROR(LOADER, "**** Unexpected import function stub (*0x%x, [2]=0x%08x)", faddr, fstub[2]); + } + + // Process refs + if (const u32 refs = fstub[3]) + { + arm_patch_refs(refs, faddr); + } + + // Install HACK instruction (ARM) + fstub[0] = 0xe0700090 | arm_code::hack::index::insert(index); + } + + const auto vnids = vm::cptr::make(libstub->data[size == 0x34 ? 5 : 3]); + const auto vstub = vm::cptr::make(libstub->data[size == 0x34 ? 6 : 4]); + + for (u32 j = 0; j < libstub->vcount; j++) + { + const u32 vnid = vnids[j]; + const u32 refs = vstub[j]; + + // Static variable + if (const auto _sv = _sm && _sm->variables.count(vnid) ? &_sm->variables.at(vnid) : nullptr) + { + LOG_NOTICE(LOADER, "** Imported variable '%s' in module '%s' (refs=*0x%x)", arm_get_variable_name(module_name, vnid), module_name, refs); + arm_patch_refs(refs, _sv->var->addr()); + } + else + { + LOG_FATAL(LOADER, "** Unknown variable '%s' in module '%s' (refs=*0x%x)", arm_get_variable_name(module_name, vnid), module_name, refs); + } + } + } + + // Next lib + libstub.set(libstub.addr() + size); + } + + LOG_NOTICE(LOADER, "__sce_process_param(*0x%x) analysis...", proc_param); + + ASSERT(proc_param->size >= sizeof(psv_process_param_t)); + ASSERT(proc_param->ver == "PSP2"_u32); + + LOG_NOTICE(LOADER, "*** size=0x%x; 0x%x, 0x%x, 0x%x", proc_param->size, proc_param->ver, proc_param->unk0, proc_param->unk1); + + LOG_NOTICE(LOADER, "*** &sceUserMainThreadName = 0x%x", proc_param->sceUserMainThreadName); + LOG_NOTICE(LOADER, "*** &sceUserMainThreadPriority = 0x%x", proc_param->sceUserMainThreadPriority); + LOG_NOTICE(LOADER, "*** &sceUserMainThreadStackSize = 0x%x", proc_param->sceUserMainThreadStackSize); + LOG_NOTICE(LOADER, "*** &sceUserMainThreadAttribute = 0x%x", proc_param->sceUserMainThreadAttribute); + LOG_NOTICE(LOADER, "*** &sceProcessName = 0x%x", proc_param->sceProcessName); + LOG_NOTICE(LOADER, "*** &sce_process_preload_disabled = 0x%x", proc_param->sce_process_preload_disabled); + LOG_NOTICE(LOADER, "*** &sceUserMainThreadCpuAffinityMask = 0x%x", proc_param->sceUserMainThreadCpuAffinityMask); + + const auto libc_param = proc_param->sce_libcparam; + + LOG_NOTICE(LOADER, "__sce_libcparam(*0x%x) analysis...", libc_param); + + ASSERT(libc_param->size >= 0x1c); + + LOG_NOTICE(LOADER, "*** size=0x%x; 0x%x, 0x%x, 0x%x", libc_param->size, libc_param->unk0, libc_param->unk1, libc_param->unk2); + + LOG_NOTICE(LOADER, "*** &sceLibcHeapSize = 0x%x", libc_param->sceLibcHeapSize); + LOG_NOTICE(LOADER, "*** &sceLibcHeapSizeDefault = 0x%x", libc_param->sceLibcHeapSizeDefault); + LOG_NOTICE(LOADER, "*** &sceLibcHeapExtendedAlloc = 0x%x", libc_param->sceLibcHeapExtendedAlloc); + LOG_NOTICE(LOADER, "*** &sceLibcHeapDelayedAlloc = 0x%x", libc_param->sceLibcHeapDelayedAlloc); + + const auto stop_code = vm::ptr::make(vm::alloc(3 * 4, vm::main)); + stop_code[0] = 0xf870; // HACK instruction (Thumb) + stop_code[1] = 1; // Predefined function index (HLE return) + Emu.SetCPUThreadStop(stop_code.addr()); + + armv7_init_tls(); + + const std::string& thread_name = proc_param->sceUserMainThreadName ? proc_param->sceUserMainThreadName.get_ptr() : "main_thread"; + const u32 stack_size = proc_param->sceUserMainThreadStackSize ? proc_param->sceUserMainThreadStackSize->value() : 256 * 1024; + const u32 priority = proc_param->sceUserMainThreadPriority ? proc_param->sceUserMainThreadPriority->value() : 160; + + auto thread = idm::make_ptr(thread_name); + + thread->PC = entry_point; + thread->stack_size = stack_size; + thread->prio = priority; + thread->cpu_init(); + + // Initialize args + std::vector argv_data; + + for (const auto& arg : { Emu.GetPath(), "-emu"s }) + { + argv_data.insert(argv_data.end(), arg.begin(), arg.end()); + argv_data.insert(argv_data.end(), '\0'); + + thread->GPR[0]++; // argc + } + + const u32 argv = vm::alloc(::size32(argv_data), vm::main); + std::memcpy(vm::base(argv), argv_data.data(), argv_data.size()); // copy arg list + thread->GPR[1] = argv; +} diff --git a/rpcs3/Emu/ARMv7/ARMv7Module.h b/rpcs3/Emu/ARMv7/ARMv7Module.h new file mode 100644 index 0000000000..95261f5b80 --- /dev/null +++ b/rpcs3/Emu/ARMv7/ARMv7Module.h @@ -0,0 +1,222 @@ +#pragma once + +#include "Utilities/Config.h" +#include "ARMv7Function.h" +#include "ARMv7Callback.h" +#include "ErrorCodes.h" + +namespace vm { using namespace psv; } + +// HLE function information +struct arm_static_function +{ + const char* name; + u32 index; // Index for arm_function_manager + u32 flags; +}; + +// HLE variable information +struct arm_static_variable +{ + const char* name; + vm::gvar* var; // Pointer to variable address storage + void(*init)(); // Variable initialization function + u32 size; + u32 align; +}; + +// HLE module information +class arm_static_module final +{ +public: + const std::string name; + + task_stack on_load; + task_stack on_unload; + + std::unordered_map functions; + std::unordered_map variables; + +public: + arm_static_module(const char* name); + + arm_static_module(const char* name, void(*init)()) + : arm_static_module(name) + { + init(); + } + + arm_static_module(const char* name, void(*init)(arm_static_module* _this)) + : arm_static_module(name) + { + init(this); + } +}; + +class arm_module_manager final +{ + friend class arm_static_module; + + static never_inline auto& access() + { + static std::unordered_map map; + + return map; + } + + static never_inline void register_module(arm_static_module* module) + { + access().emplace(module->name, module); + } + + static never_inline auto& access_static_function(const char* module, u32 fnid) + { + return access().at(module)->functions[fnid]; + } + + static never_inline auto& access_static_variable(const char* module, u32 vnid) + { + return access().at(module)->variables[vnid]; + } + +public: + static never_inline const arm_static_module* get_module(const std::string& name) + { + const auto& map = access(); + const auto found = map.find(name); + return found != map.end() ? found->second : nullptr; + } + + template + static void register_static_function(const char* module, const char* name, arm_function_t func, u32 fnid, u32 flags) + { + auto& info = access_static_function(module, fnid); + + info.name = name; + info.index = arm_function_manager::register_function(func); + info.flags = flags; + } + + template + static void register_static_variable(const char* module, const char* name, u32 vnid, void(*init)()) + { + static_assert(std::is_same::value, "Static variable registration: vm::gvar expected"); + + auto& info = access_static_variable(module, vnid); + + info.name = name; + info.var = reinterpret_cast*>(Var); + info.init = init ? init : [] {}; + info.size = SIZE_32(typename T::type); + info.align = ALIGN_32(typename T::type); + } + + static const arm_static_module SceAppMgr; + static const arm_static_module SceAppUtil; + static const arm_static_module SceAudio; + static const arm_static_module SceAudiodec; + static const arm_static_module SceAudioenc; + static const arm_static_module SceAudioIn; + static const arm_static_module SceCamera; + static const arm_static_module SceCodecEngine; + static const arm_static_module SceCommonDialog; + static const arm_static_module SceCpu; + static const arm_static_module SceCtrl; + static const arm_static_module SceDbg; + static const arm_static_module SceDebugLed; + static const arm_static_module SceDeci4p; + static const arm_static_module SceDeflt; + static const arm_static_module SceDipsw; + static const arm_static_module SceDisplay; + static const arm_static_module SceDisplayUser; + static const arm_static_module SceFiber; + static const arm_static_module SceFios; + static const arm_static_module SceFpu; + static const arm_static_module SceGxm; + static const arm_static_module SceHttp; + static const arm_static_module SceIme; + static const arm_static_module SceIofilemgr; + static const arm_static_module SceJpeg; + static const arm_static_module SceJpegEnc; + static const arm_static_module SceLibc; + static const arm_static_module SceLibKernel; + static const arm_static_module SceLibm; + static const arm_static_module SceLibstdcxx; + static const arm_static_module SceLibXml; + static const arm_static_module SceLiveArea; + static const arm_static_module SceLocation; + static const arm_static_module SceMd5; + static const arm_static_module SceModulemgr; + static const arm_static_module SceMotion; + static const arm_static_module SceMt19937; + static const arm_static_module SceNet; + static const arm_static_module SceNetCtl; + static const arm_static_module SceNgs; + static const arm_static_module SceNpBasic; + static const arm_static_module SceNpCommon; + static const arm_static_module SceNpManager; + static const arm_static_module SceNpMatching; + static const arm_static_module SceNpScore; + static const arm_static_module SceNpUtility; + static const arm_static_module ScePerf; + static const arm_static_module ScePgf; + static const arm_static_module ScePhotoExport; + static const arm_static_module SceProcessmgr; + static const arm_static_module SceRazorCapture; + static const arm_static_module SceRtc; + static const arm_static_module SceSas; + static const arm_static_module SceScreenShot; + static const arm_static_module SceSfmt; + static const arm_static_module SceSha; + static const arm_static_module SceSqlite; + static const arm_static_module SceSsl; + static const arm_static_module SceStdio; + static const arm_static_module SceSulpha; + static const arm_static_module SceSysmem; + static const arm_static_module SceSysmodule; + static const arm_static_module SceSystemGesture; + static const arm_static_module SceThreadmgr; + static const arm_static_module SceTouch; + static const arm_static_module SceUlt; + static const arm_static_module SceVideodec; + static const arm_static_module SceVoice; + static const arm_static_module SceVoiceQoS; +}; + +#define REG_FNID(module, nid, func, ...) arm_module_manager::register_static_function(#module, #func, BIND_FUNC(func), nid, {__VA_ARGS__}) + +#define REG_VNID(module, nid, var, ...) arm_module_manager::register_static_variable(#module, #var, nid, {__VA_ARGS__}) + +struct SceDateTime +{ + le_t year; + le_t month; + le_t day; + le_t hour; + le_t minute; + le_t second; + le_t microsecond; +}; + +struct SceFVector3 +{ + le_t x, y, z; +}; + +struct SceFQuaternion +{ + le_t x, y, z, w; +}; + +union SceUMatrix4 +{ + struct + { + le_t f[4][4]; + }; + + struct + { + le_t i[4][4]; + }; +}; diff --git a/rpcs3/Emu/ARMv7/ARMv7Opcodes.h b/rpcs3/Emu/ARMv7/ARMv7Opcodes.h index 7afe804363..61f740336e 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Opcodes.h +++ b/rpcs3/Emu/ARMv7/ARMv7Opcodes.h @@ -1,2015 +1,2612 @@ #pragma once -#if 0 -#include "Emu/ARMv7/ARMv7Thread.h" -#include "Emu/ARMv7/ARMv7Interpreter.h" -using namespace ARMv7_instrs; +#include "../../../Utilities/BitField.h" -struct ARMv7_Instruction +#include + +enum class arm_encoding { - void(*func)(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - u8 size; - ARMv7_encoding type; - const char* name; + T1, T2, T3, T4, A1, A2, }; -#define ARMv7_OP_2(func, type) { func, 2, type, #func "_" #type } -#define ARMv7_OP_4(func, type) { func, 4, type, #func "_" #type } -#define ARMv7_NULL_OP { NULL_OP, 2, T1, "NULL_OP" } - - -// 0x1... -static void group_0x1(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - -static const ARMv7_Instruction g_table_0x1_main[] = +// Get Thumb instruction size +inline bool arm_op_thumb_is_32(u32 op16) { - ARMv7_OP_2(ASR_IMM, T1), // 0 0xf800 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_OP_2(ADD_REG, T1), // 8 0xfe00 - ARMv7_NULL_OP, // 9 - ARMv7_OP_2(SUB_REG, T1), // A 0xfe00 - ARMv7_NULL_OP, // B - ARMv7_OP_2(ADD_IMM, T1), // C 0xfe00 - ARMv7_NULL_OP, // D - ARMv7_OP_2(SUB_IMM, T1) // E 0xfe00 -}; - -static const ARMv7_Instruction g_table_0x1[] = -{ - { group_0x1 } -}; - -static void group_0x1(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = (thr->code.code0 & 0x0e00) >> 8; - - if ((thr->code.code0 & 0xf800) == 0x1000) index = 0x0; - - thr->m_last_instr_name = g_table_0x1_main[index].name; - thr->m_last_instr_size = g_table_0x1_main[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0x1_main[index].func(thr, g_table_0x1_main[index].type); + return (op16 >> 11) >= 29; } -// 0x2... -static void group_0x2(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - -static const ARMv7_Instruction g_table_0x2_main[] = +namespace arm_code { - ARMv7_OP_2(MOV_IMM, T1), // 0 0xf800 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_OP_2(CMP_IMM, T1) // 8 0xf800 -}; - -static const ARMv7_Instruction g_table_0x2[] = -{ - { group_0x2 } -}; - -static void group_0x2(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - const u32 index = (thr->code.code0 & 0x0800) >> 8; - thr->m_last_instr_name = g_table_0x2_main[index].name; - thr->m_last_instr_size = g_table_0x2_main[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0x2_main[index].func(thr, g_table_0x2_main[index].type); -} - -// 0x3... -static void group_0x3(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - -static const ARMv7_Instruction g_table_0x3_main[] = -{ - ARMv7_OP_2(ADD_IMM, T2), // 0 0xf800 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_OP_2(SUB_IMM, T2) // 8 0xf800 -}; - -static const ARMv7_Instruction g_table_0x3[] = -{ - { group_0x3 } -}; - -static void group_0x3(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - const u32 index = (thr->code.code0 & 0x0800) >> 8; - thr->m_last_instr_name = g_table_0x3_main[index].name; - thr->m_last_instr_size = g_table_0x3_main[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0x3_main[index].func(thr, g_table_0x3_main[index].type); -} - -// 0x4... -static void group_0x4(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0x40(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0x41(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0x42(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0x43(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0x44(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0x47(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - -static const ARMv7_Instruction g_table_0x4[] = -{ - { group_0x4 } -}; - -static const ARMv7_Instruction g_table_0x40[] = -{ - ARMv7_OP_2(AND_REG, T1), // 0 0xffc0 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_OP_2(ADC_REG, T1), // 4 0xffc0 - // ARMv7_OP_2(EOR_REG, T1), // 4 0xffc0 code(ADC_REG, T1) == code(EOR_REG, T1) ??? - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_OP_2(LSL_REG, T1), // 8 0xffc0 - ARMv7_NULL_OP, // 9 - ARMv7_NULL_OP, // A - ARMv7_NULL_OP, // B - ARMv7_OP_2(LSR_REG, T1) // C 0xffc0 -}; - -static void group_0x40(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - const u32 index = (thr->code.code0 & 0x00c0) >> 4; - thr->m_last_instr_name = g_table_0x40[index].name; - thr->m_last_instr_size = g_table_0x40[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0x40[index].func(thr, g_table_0x40[index].type); -} - -static const ARMv7_Instruction g_table_0x41[] = -{ - ARMv7_OP_2(ASR_REG, T1), // 0 0xffc0 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_OP_2(SBC_REG, T1), // 8 0xffc0 - ARMv7_NULL_OP, // 9 - ARMv7_NULL_OP, // A - ARMv7_NULL_OP, // B - ARMv7_OP_2(ROR_REG, T1) // C 0xffc0 -}; - -static void group_0x41(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - const u32 index = (thr->code.code0 & 0x00c0) >> 4; - thr->m_last_instr_name = g_table_0x41[index].name; - thr->m_last_instr_size = g_table_0x41[index].size; - g_table_0x41[index].func(thr, g_table_0x41[index].type); -} - -static const ARMv7_Instruction g_table_0x42[] = -{ - ARMv7_OP_2(TST_REG, T1), // 0 0xffc0 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_OP_2(RSB_IMM, T1), // 4 0xffc0 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_OP_2(CMP_REG, T1), // 8 0xffc0 - ARMv7_NULL_OP, // 9 - ARMv7_NULL_OP, // A - ARMv7_NULL_OP, // B - ARMv7_OP_2(CMN_REG, T1) // C 0xffc0 -}; - -static void group_0x42(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - const u32 index = (thr->code.code0 & 0x00c0) >> 4; - thr->m_last_instr_name = g_table_0x42[index].name; - thr->m_last_instr_size = g_table_0x42[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0x42[index].func(thr, g_table_0x42[index].type); -} - -static const ARMv7_Instruction g_table_0x43[] = -{ - ARMv7_OP_2(ORR_REG, T1), // 0 0xffc0 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_OP_2(MUL, T1), // 4 0xffc0 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_OP_2(BIC_REG, T1), // 8 0xffc0 - ARMv7_NULL_OP, // 9 - ARMv7_NULL_OP, // A - ARMv7_NULL_OP, // B - ARMv7_OP_2(MVN_REG, T1) // C 0xffc0 -}; - -static void group_0x43(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - const u32 index = (thr->code.code0 & 0x00c0) >> 4; - thr->m_last_instr_name = g_table_0x43[index].name; - thr->m_last_instr_size = g_table_0x43[index].size; - g_table_0x43[index].func(thr, g_table_0x43[index].type); -} - -static const ARMv7_Instruction g_table_0x44[] = -{ - ARMv7_OP_2(ADD_REG, T2), // 0 0xff00 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_OP_2(ADD_SPR, T1), // 6 0xff78 - ARMv7_NULL_OP, // 7 - ARMv7_OP_2(ADD_SPR, T2) // 8 0xff87 -}; - -static void group_0x44(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = (thr->code.code0 & 0x0080) >> 4; - - if ((thr->code.code0 & 0xff00) == 0x4400) index = 0x0; - if ((thr->code.code0 & 0xff78) == 0x4468) index = 0x6; - - thr->m_last_instr_name = g_table_0x44[index].name; - thr->m_last_instr_size = g_table_0x44[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0x44[index].func(thr, g_table_0x44[index].type); -} - -static const ARMv7_Instruction g_table_0x47[] = -{ - ARMv7_OP_2(BX, T1), // 0 0xff87 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_OP_2(BLX, T1) // 8 0xff80 -}; - -static void group_0x47(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - const u32 index = (thr->code.code0 & 0x0080) >> 4; - thr->m_last_instr_name = g_table_0x47[index].name; - thr->m_last_instr_size = g_table_0x47[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0x47[index].func(thr, g_table_0x47[index].type); -} - -static const ARMv7_Instruction g_table_0x4_main[] = -{ - { group_0x40 }, // 0 - { group_0x41 }, // 1 - { group_0x42 }, // 2 - { group_0x43 }, // 3 - { group_0x44 }, // 4 - ARMv7_OP_2(CMP_REG, T2), // 5 0xff00 - ARMv7_OP_2(MOV_REG, T1), // 6 0xff00 - { group_0x47 }, // 7 - ARMv7_OP_2(LDR_LIT, T1) // 8 0xf800 -}; - -static void group_0x4(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = (thr->code.code0 & 0x0f00) >> 8; - - if ((index & 0xf800) == 0x4800) index = 0x8; - - thr->m_last_instr_name = g_table_0x4_main[index].name; - thr->m_last_instr_size = g_table_0x4_main[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0x4_main[index].func(thr, g_table_0x4_main[index].type); -} - -// 0x5... -static void group_0x5(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - -static const ARMv7_Instruction g_table_0x5_main[] = -{ - ARMv7_OP_2(STR_REG, T1), // 0 0xfe00 - ARMv7_NULL_OP, // 1 - ARMv7_OP_2(STRH_REG, T1), // 2 0xfe00 - ARMv7_NULL_OP, // 3 - ARMv7_OP_2(STRB_REG, T1), // 4 0xfe00 - ARMv7_NULL_OP, // 5 - ARMv7_OP_2(LDRSB_REG, T1), // 6 0xfe00 - ARMv7_NULL_OP, // 7 - ARMv7_OP_2(LDR_REG, T1), // 8 0xfe00 - ARMv7_NULL_OP, // 9 - ARMv7_NULL_OP, // A - ARMv7_NULL_OP, // B - ARMv7_OP_2(LDRB_REG, T1), // C 0xfe00 - ARMv7_NULL_OP, // D - ARMv7_OP_2(LDRSH_REG, T1) // E 0xfe00 -}; - -static const ARMv7_Instruction g_table_0x5[] = -{ - { group_0x5 } -}; - -static void group_0x5(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - const u32 index = (thr->code.code0 & 0x0e00) >> 8; - thr->m_last_instr_name = g_table_0x5_main[index].name; - thr->m_last_instr_size = g_table_0x5_main[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0x5_main[index].func(thr, g_table_0x5_main[index].type); -} - -// 0x6... -static void group_0x6(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - -static const ARMv7_Instruction g_table_0x6_main[] = -{ - ARMv7_OP_2(STR_IMM, T1), // 0 0xf800 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_OP_2(LDR_IMM, T1) // 8 0xf800 -}; - -static const ARMv7_Instruction g_table_0x6[] = -{ - { group_0x6 } -}; - -static void group_0x6(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - const u32 index = (thr->code.code0 & 0x0800) >> 8; - thr->m_last_instr_name = g_table_0x6_main[index].name; - thr->m_last_instr_size = g_table_0x6_main[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0x6_main[index].func(thr, g_table_0x6_main[index].type); -} - -// 0x7... -static void group_0x7(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - -static const ARMv7_Instruction g_table_0x7_main[] = -{ - ARMv7_OP_2(STRB_IMM, T1), // 0 0xf800 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_OP_2(LDRB_IMM, T1) // 8 0xf800 -}; - -static const ARMv7_Instruction g_table_0x7[] = -{ - { group_0x7 } -}; - -static void group_0x7(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - const u32 index = (thr->code.code0 & 0x0800) >> 8; - thr->m_last_instr_name = g_table_0x7_main[index].name; - thr->m_last_instr_size = g_table_0x7_main[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0x7_main[index].func(thr, g_table_0x7_main[index].type); -} - -// 0x8... -static void group_0x8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - -static const ARMv7_Instruction g_table_0x8_main[] = -{ - ARMv7_OP_2(STRH_IMM, T1) // 0 0xf800 -}; - -static const ARMv7_Instruction g_table_0x8[] = -{ - { group_0x8 } -}; - -static void group_0x8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - const u32 index = (thr->code.code0 & 0x0800) >> 8; - thr->m_last_instr_name = g_table_0x8_main[index].name; - thr->m_last_instr_size = g_table_0x8_main[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0x8_main[index].func(thr, g_table_0x8_main[index].type); -} - -// 0x9... -static void group_0x9(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - -static const ARMv7_Instruction g_table_0x9_main[] = -{ - ARMv7_OP_2(STR_IMM, T2), // 0 0xf800 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_OP_2(LDR_IMM, T2) // 8 0xf800 -}; - -static const ARMv7_Instruction g_table_0x9[] = -{ - { group_0x9 } -}; - -static void group_0x9(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - const u32 index = (thr->code.code0 & 0x0800) >> 8; - thr->m_last_instr_name = g_table_0x9_main[index].name; - thr->m_last_instr_size = g_table_0x9_main[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0x9_main[index].func(thr, g_table_0x9_main[index].type); -} - -// 0xa... -static void group_0xa(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - -static const ARMv7_Instruction g_table_0xa_main[] = -{ - ARMv7_OP_2(ADR, T1), // 0 0xf800 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_OP_2(ADD_SPI, T1) // 8 0xf800 -}; - -static const ARMv7_Instruction g_table_0xa[] = -{ - { group_0xa } -}; - -static void group_0xa(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = (thr->code.code0 & 0x0800) >> 8; - thr->m_last_instr_name = g_table_0xa_main[index].name; - thr->m_last_instr_size = g_table_0xa_main[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xa_main[index].func(thr, g_table_0xa_main[index].type); -} - -// 0xb... -static void group_0xb(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xb0(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xba(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - -static const ARMv7_Instruction g_table_0xb0[] = -{ - ARMv7_OP_2(ADD_SPI, T2), // 0 0xff80 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_OP_2(SUB_SPI, T1) // 8 0xff80 -}; - -static void group_0xb0(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - const u32 index = (thr->code.code0 & 0x0080) >> 4; - thr->m_last_instr_name = g_table_0xb0[index].name; - thr->m_last_instr_size = g_table_0xb0[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xb0[index].func(thr, g_table_0xb0[index].type); -} - -static const ARMv7_Instruction g_table_0xba[] = -{ - ARMv7_OP_2(REV, T1), // 0 0xffc0 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_OP_2(REV16, T1), // 4 0xffc0 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_NULL_OP, // 8 - ARMv7_NULL_OP, // 9 - ARMv7_NULL_OP, // A - ARMv7_NULL_OP, // B - ARMv7_OP_2(REVSH, T1) // C 0xffc0 -}; - -static void group_0xba(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - const u32 index = (thr->code.code0 & 0x00c0) >> 4; // mask 0xffc0 - thr->m_last_instr_name = g_table_0xba[index].name; - thr->m_last_instr_size = g_table_0xba[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xba[index].func(thr, g_table_0xba[index].type); -} - -static const ARMv7_Instruction g_table_0xb_main[] = -{ - { group_0xb0 }, // 0 - ARMv7_OP_2(CB_Z, T1), // 1 0xf500 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_OP_2(PUSH, T1), // 4 0xfe00 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_NULL_OP, // 8 - ARMv7_NULL_OP, // 9 - { group_0xba }, // A - ARMv7_NULL_OP, // B - ARMv7_OP_2(POP, T1), // C 0xfe00 - ARMv7_NULL_OP, // D - ARMv7_OP_2(BKPT, T1), // E 0xff00 - ARMv7_OP_2(NOP, T1), // F 0xffff - ARMv7_OP_2(IT, T1), // 10 0xff00 -}; - -static const ARMv7_Instruction g_table_0xb[] = -{ - { group_0xb } -}; - -static void group_0xb(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = (thr->code.code0 & 0x0e00) >> 8; - - if ((thr->code.code0 & 0xf500) == 0xb100) index = 0x1; // CB_Z, T1 - if ((thr->code.code0 & 0xff00) == 0xbe00) index = 0xe; // BKPT, T1 - if ((thr->code.code0 & 0xffff) == 0xbf00) index = 0xf; // NOP, T1 - if ((thr->code.code0 & 0xff00) == 0xbf00) index = 0x10; // IT, T1 - - thr->m_last_instr_name = g_table_0xb_main[index].name; - thr->m_last_instr_size = g_table_0xb_main[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xb_main[index].func(thr, g_table_0xb_main[index].type); -} - -// 0xc... -static void group_0xc(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - -static const ARMv7_Instruction g_table_0xc_main[] = -{ - ARMv7_OP_2(STM, T1), // 0 0xf800 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_OP_2(LDM, T1) // 8 0xf800 -}; - -static const ARMv7_Instruction g_table_0xc[] = -{ - { group_0xc } -}; - -static void group_0xc(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - const u32 index = (thr->code.code0 & 0x0800) >> 8; - thr->m_last_instr_name = g_table_0xc_main[index].name; - thr->m_last_instr_size = g_table_0xc_main[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xc_main[index].func(thr, g_table_0xc_main[index].type); -} - -// 0xd... -static void group_0xd(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - -static const ARMv7_Instruction g_table_0xd_main[] = -{ - ARMv7_OP_2(B, T1), // 0 0xf000 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_NULL_OP, // 8 - ARMv7_NULL_OP, // 9 - ARMv7_NULL_OP, // A - ARMv7_NULL_OP, // B - ARMv7_NULL_OP, // C - ARMv7_NULL_OP, // D - ARMv7_NULL_OP, // E - ARMv7_OP_2(SVC, T1) // F 0xff00 -}; - -static const ARMv7_Instruction g_table_0xd[] = -{ - { group_0xd } -}; - -static void group_0xd(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - //u32 index = (thr->code.code0 & 0x0f00) >> 8; - //if ((thr->code.code0 & 0xf000) == 0xd000) index = 0; - - const u32 index = (thr->code.code0 & 0xff00) == 0xdf00 ? 0xf : 0x0; // check me - thr->m_last_instr_name = g_table_0xd_main[index].name; - thr->m_last_instr_size = g_table_0xd_main[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xd_main[index].func(thr, g_table_0xd_main[index].type); -} - -// 0xe... -static void group_0xe(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xe85(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xe8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xe9(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xea(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xea4(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xea4f(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xea4f0000(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xea4f0030(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xea6(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xeb(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xeb0(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xeba(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - - -static const ARMv7_Instruction g_table_0xe85[] = -{ - ARMv7_OP_4(LDRD_IMM, T1), // 0 0xfe50, 0x0000 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_NULL_OP, // 8 - ARMv7_NULL_OP, // 9 - ARMv7_NULL_OP, // A - ARMv7_NULL_OP, // B - ARMv7_NULL_OP, // C - ARMv7_NULL_OP, // D - ARMv7_NULL_OP, // E - ARMv7_OP_4(LDRD_LIT, T1) // F 0xfe7f, 0x0000 -}; - -static void group_0xe85(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - //u32 index = thr->code.code0 & 0x000f; - //if ((thr->code.code0 & 0xfe50) == 0xe850) index = 0x0; - - const u32 index = (thr->code.code0 & 0xfe7f) == 0xe85f ? 0xf : 0x0; // check me - thr->m_last_instr_name = g_table_0xe85[index].name; - thr->m_last_instr_size = g_table_0xe85[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xe85[index].func(thr, g_table_0xe85[index].type); -}; - -static const ARMv7_Instruction g_table_0xe8[] = -{ - ARMv7_NULL_OP, // 0 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_OP_4(STRD_IMM, T1), // 4 0xfe50, 0x0000 - { group_0xe85 }, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_OP_4(STM, T2), // 8 0xffd0, 0xa000 - ARMv7_OP_4(LDM, T2), // 9 0xffd0, 0x2000 - ARMv7_NULL_OP, // A - ARMv7_OP_4(POP, T2), // B 0xffff, 0x0000 - ARMv7_NULL_OP, // C - ARMv7_OP_4(TB_, T1) // D 0xfff0, 0xffe0 -}; - -static void group_0xe8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = (thr->code.code0 & 0x00f0) >> 4; - - if ((thr->code.code0 & 0xfe50) == 0xe840) index = 0x4; - if ((thr->code.code0 & 0xffd0) == 0xe880) index = 0x8; - if ((thr->code.code0 & 0xffd0) == 0xe890) index = 0x9; - - thr->m_last_instr_name = g_table_0xe8[index].name; - thr->m_last_instr_size = g_table_0xe8[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xe8[index].func(thr, g_table_0xe8[index].type); -} - -static const ARMv7_Instruction g_table_0xe9[] = -{ - ARMv7_OP_4(STMDB, T1), // 0 0xffd0, 0xa000 - ARMv7_OP_4(LDMDB, T1), // 1 0xffd0, 0x2000 - ARMv7_OP_4(PUSH, T2) // 2 0xffff, 0x0000 -}; - -static void group_0xe9(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = (thr->code.code0 & 0x00d0) >> 4; - - if ((thr->code.code0 & 0xffff) == 0xe92d) index = 0x2; - - thr->m_last_instr_name = g_table_0xe9[index].name; - thr->m_last_instr_size = g_table_0xe9[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xe9[index].func(thr, g_table_0xe9[index].type); -} - -static const ARMv7_Instruction g_table_0xea4[] = -{ - ARMv7_OP_4(ORR_REG, T2), // 0 0xffe0, 0x8000 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_NULL_OP, // 8 - ARMv7_NULL_OP, // 9 - ARMv7_NULL_OP, // A - ARMv7_NULL_OP, // B - ARMv7_NULL_OP, // C - ARMv7_NULL_OP, // D - ARMv7_NULL_OP, // E - { group_0xea4f } // F -}; - -static void group_0xea4(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = 0x0; - if ((thr->code.code0 & 0xffef) == 0xea4f) index = 0xf; // check me - - thr->m_last_instr_name = g_table_0xea4[index].name; - thr->m_last_instr_size = g_table_0xea4[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xea4[index].func(thr, g_table_0xea4[index].type); -} - -static const ARMv7_Instruction g_table_0xea4f[] = -{ - { group_0xea4f0000 }, // 0 - ARMv7_OP_4(ASR_IMM, T2), // 1 0xffef, 0x8030 - ARMv7_OP_4(ASR_IMM, T2), // 2 0xffef, 0x8030 - { group_0xea4f0030 } // 3 -}; - -static void group_0xea4f(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - const u32 index = (thr->code.code1 & 0x0030) >> 4; - thr->m_last_instr_name = g_table_0xea4f[index].name; - thr->m_last_instr_size = g_table_0xea4f[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xea4f[index].func(thr, g_table_0xea4f[index].type); -} - -static const ARMv7_Instruction g_table_0xea4f0000[] = -{ - ARMv7_OP_4(MOV_REG, T3), // 0 0xffef, 0xf0f0 - ARMv7_OP_4(LSL_IMM, T2) // 1 0xffef, 0x8030 -}; - -static void group_0xea4f0000(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - const u32 index = thr->code.code1 & 0x8030 ? 0x0 : 0x1; - thr->m_last_instr_name = g_table_0xea4f0000[index].name; - thr->m_last_instr_size = g_table_0xea4f0000[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xea4f0000[index].func(thr, g_table_0xea4f0000[index].type); -} - -static const ARMv7_Instruction g_table_0xea4f0030[] = -{ - ARMv7_OP_4(RRX, T1), // 1 0xffef, 0xf0f0 - ARMv7_OP_4(ROR_IMM, T1) // 2 0xffef, 0x8030 -}; - -static void group_0xea4f0030(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - const u32 index = thr->code.code1 & 0x8030 ? 0x0 : 0x1; - thr->m_last_instr_name = g_table_0xea4f0030[index].name; - thr->m_last_instr_size = g_table_0xea4f0030[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xea4f0030[index].func(thr, g_table_0xea4f0030[index].type); -} - -static const ARMv7_Instruction g_table_0xea6[] = -{ - ARMv7_OP_4(ORN_REG, T1), // 0 0xffe0, 0x8000 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_NULL_OP, // 8 - ARMv7_NULL_OP, // 9 - ARMv7_NULL_OP, // A - ARMv7_NULL_OP, // B - ARMv7_NULL_OP, // C - ARMv7_NULL_OP, // D - ARMv7_NULL_OP, // E - ARMv7_OP_4(MVN_REG, T2) // F 0xffef, 0x8000 -}; - -static void group_0xea6(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = thr->code.code0 & 0x000f; - - if ((thr->m_arg & 0xffe08000) == 0xea600000) index = 0x0; - - thr->m_last_instr_name = g_table_0xea6[index].name; - thr->m_last_instr_size = g_table_0xea6[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xea6[index].func(thr, g_table_0xea6[index].type); -} - -static const ARMv7_Instruction g_table_0xea[] = -{ - ARMv7_OP_4(AND_REG, T2), // 0 0xffe0, 0x8000 - ARMv7_OP_4(TST_REG, T2), // 1 0xfff0, 0x8f00 - ARMv7_OP_4(BIC_REG, T2), // 2 0xffe0, 0x8000 - ARMv7_NULL_OP, // 3 - { group_0xea4 }, // 4 - ARMv7_NULL_OP, // 5 - { group_0xea6 }, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_OP_4(EOR_REG, T2), // 8 0xffe0, 0x8000 - ARMv7_OP_4(TEQ_REG, T1), // 9 0xfff0, 0x8f00 - ARMv7_NULL_OP, // A - ARMv7_NULL_OP, // B - ARMv7_OP_4(PKH, T1) // C 0xfff0, 0x8010 -}; - -static void group_0xea(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = (thr->code.code0 & 0x00e0) >> 4; - - if ((thr->m_arg & 0xfff08f00) == 0xea100f00) index = 0x1; - if ((thr->m_arg & 0xfff08f00) == 0xea900f00) index = 0x9; - if ((thr->m_arg & 0xfff08010) == 0xeac00000) index = 0xc; - - thr->m_last_instr_name = g_table_0xea[index].name; - thr->m_last_instr_size = g_table_0xea[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xea[index].func(thr, g_table_0xea[index].type); -} - -static const ARMv7_Instruction g_table_0xeb0[] = -{ - ARMv7_OP_4(ADD_REG, T3), // 0 0xffe0, 0x8000 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_NULL_OP, // 8 - ARMv7_NULL_OP, // 9 - ARMv7_NULL_OP, // A - ARMv7_NULL_OP, // B - ARMv7_NULL_OP, // C - ARMv7_OP_4(ADD_SPR, T3) // D 0xffef, 0x8000 -}; - -static void group_0xeb0(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = thr->code.code0 & 0x000f; - - if ((thr->m_arg & 0xffe08000) == 0xeb000000) index = 0x0; - - thr->m_last_instr_name = g_table_0xeb0[index].name; - thr->m_last_instr_size = g_table_0xeb0[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xeb0[index].func(thr, g_table_0xeb0[index].type); -} - -static const ARMv7_Instruction g_table_0xeba[] = -{ - ARMv7_OP_4(SUB_REG, T2), // 0 0xffe0, 0x8000 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_NULL_OP, // 8 - ARMv7_NULL_OP, // 9 - ARMv7_NULL_OP, // A - ARMv7_NULL_OP, // B - ARMv7_NULL_OP, // C - ARMv7_OP_4(SUB_SPR, T1) // D 0xffef, 0x8000 -}; - -static void group_0xeba(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = thr->code.code0 & 0x000f; - - if ((thr->m_arg & 0xffe08000) == 0xeba00000) index = 0x0; - - thr->m_last_instr_name = g_table_0xeba[index].name; - thr->m_last_instr_size = g_table_0xeba[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xeba[index].func(thr, g_table_0xeba[index].type); -} - -static const ARMv7_Instruction g_table_0xeb[] = -{ - { group_0xeb0 }, // 0 0xffe0 - ARMv7_OP_4(CMN_REG, T2), // 1 0xfff0, 0x8f00 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_OP_4(ADC_REG, T2), // 4 0xffe0, 0x8000 - ARMv7_NULL_OP, // 5 - ARMv7_OP_4(SBC_REG, T2), // 6 0xffe0, 0x8000 - ARMv7_NULL_OP, // 7 - ARMv7_NULL_OP, // 8 - ARMv7_NULL_OP, // 9 - { group_0xeba }, // A 0xffe0 - ARMv7_OP_4(CMP_REG, T3), // B 0xfff0, 0x8f00 - ARMv7_OP_4(RSB_REG, T1) // C 0xffe0, 0x8000 -}; - -static void group_0xeb(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = (thr->code.code0 & 0x00e0) >> 4; - - if ((thr->m_arg & 0xfff08f00) == 0xeb100f00) index = 0x1; - if ((thr->m_arg & 0xfff08f00) == 0xebb00f00) index = 0xb; - - thr->m_last_instr_name = g_table_0xeb[index].name; - thr->m_last_instr_size = g_table_0xeb[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xeb[index].func(thr, g_table_0xeb[index].type); -} - -static const ARMv7_Instruction g_table_0xe_main[] = -{ - ARMv7_OP_2(B, T2), // 0 0xf800 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - { group_0xe8 }, // 8 - { group_0xe9 }, // 9 - { group_0xea }, // A - { group_0xeb }, // B - ARMv7_NULL_OP, // C - ARMv7_NULL_OP, // D - ARMv7_NULL_OP, // E - ARMv7_NULL_OP, // F -}; - -static const ARMv7_Instruction g_table_0xe[] = -{ - { group_0xe } -}; - -static void group_0xe(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = (thr->code.code0 & 0x0f00) >> 8; - - if ((thr->code.code0 & 0xf800) == 0xe000) index = 0x0; - - thr->m_last_instr_name = g_table_0xe_main[index].name; - thr->m_last_instr_size = g_table_0xe_main[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xe_main[index].func(thr, g_table_0xe_main[index].type); -} - -// 0xf... -static void group_0xf(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xf000(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xf04(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xf06(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xf0(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xf1(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xf1a(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xf10(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xf20(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xf2a(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xf2(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xf36(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xf3(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xf810(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xf800(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xf81(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xf820(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xf840(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xf84(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xf850(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xf85(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xf8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xf910(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xf91(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xf930(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xf93(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xf9(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xfa00(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xfa90(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); -static void group_0xfa(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type); - -static const ARMv7_Instruction g_table_0xf000[] = -{ - ARMv7_OP_4(AND_IMM, T1), // 0 0xfbe0, 0x8000 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_OP_4(B, T3), // 8 0xf800, 0xd000 - ARMv7_OP_4(B, T4), // 9 0xf800, 0xd000 - ARMv7_NULL_OP, // A - ARMv7_NULL_OP, // B - ARMv7_OP_4(BLX, T2), // C 0xf800, 0xc001 - ARMv7_OP_4(BL, T1) // D 0xf800, 0xd000 -}; - -static void group_0xf000(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = (thr->code.code1 & 0xd000) >> 12; - - if ((thr->code.code1 & 0x8000) == 0x0000) index = 0x0; - if ((thr->code.code1 & 0xc001) == 0xc000) index = 0xc; - - thr->m_last_instr_size = g_table_0xf000[index].size; - thr->m_last_instr_name = g_table_0xf000[index].name; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xf000[index].func(thr, g_table_0xf000[index].type); -} - -static const ARMv7_Instruction g_table_0xf04[] = -{ - ARMv7_OP_4(ORR_IMM, T1), // 0 0xfbe0, 0x8000 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_NULL_OP, // 8 - ARMv7_NULL_OP, // 9 - ARMv7_NULL_OP, // A - ARMv7_NULL_OP, // B - ARMv7_NULL_OP, // C - ARMv7_NULL_OP, // D - ARMv7_NULL_OP, // E - ARMv7_OP_4(MOV_IMM, T2) // F 0xfbef, 0x8000 -}; - -static void group_0xf04(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = thr->code.code0 & 0x000f; - - if ((thr->m_arg & 0xfbe08000) == 0xf0400000) index = 0x0; - - thr->m_last_instr_size = g_table_0xf04[index].size; - thr->m_last_instr_name = g_table_0xf04[index].name; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xf04[index].func(thr, g_table_0xf04[index].type); -} - -static const ARMv7_Instruction g_table_0xf06[] = -{ - ARMv7_OP_4(ORN_IMM, T1), // 0 0xfbe0, 0x8000 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_NULL_OP, // 8 - ARMv7_NULL_OP, // 9 - ARMv7_NULL_OP, // A - ARMv7_NULL_OP, // B - ARMv7_NULL_OP, // C - ARMv7_NULL_OP, // D - ARMv7_NULL_OP, // E - ARMv7_OP_4(MVN_IMM, T1) // F 0xfbef, 0x8000 -}; - -static void group_0xf06(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = thr->code.code0 & 0x000f; - - if ((thr->m_arg & 0xfbe08000) == 0xf0600000) index = 0x0; - - thr->m_last_instr_size = g_table_0xf06[index].size; - thr->m_last_instr_name = g_table_0xf06[index].name; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xf06[index].func(thr, g_table_0xf06[index].type); -} - -static const ARMv7_Instruction g_table_0xf0[] = -{ - /* - { group_0xf000 }, // 0 0xfbe0 - ARMv7_OP_4(TST_IMM, T1), // 1 0xfbf0, 0x8f00 - ARMv7_OP_4(BIC_IMM, T1), // 2 0xfbe0, 0x8000 - ARMv7_NULL_OP, // 3 - { group_0xf04 }, // 4 0xfbef - ARMv7_NULL_OP, // 5 - { group_0xf06 }, // 6 0xfbef - ARMv7_NULL_OP, // 7 - ARMv7_OP_4(EOR_IMM, T1), // 8 0xfbe0, 0x8000 - ARMv7_OP_4(TEQ_IMM, T1) // 9 0xfbf0, 0x8f00 - */ - - ARMv7_OP_4(AND_IMM, T1), // f0 000 // 0 - ARMv7_OP_4(B, T3), // f0 008 // 1 - ARMv7_OP_4(B, T4), // f0 009 // 2 - ARMv7_OP_4(BLX, T2), // f0 00C // 3 - ARMv7_OP_4(BL, T1), // f0 00D // 4 - - ARMv7_OP_4(TST_IMM, T1), // f0 1 // 5 - ARMv7_OP_4(BIC_IMM, T1), // f0 2 // 6 - ARMv7_NULL_OP, // f0 3 // 7 - - - ARMv7_OP_4(ORR_IMM, T1), // f0 40 // 8 - ARMv7_OP_4(MOV_IMM, T2), // f0 4F // 9 - - ARMv7_NULL_OP, // f0 5 // A - - ARMv7_OP_4(ORN_IMM, T1), // f0 60 // B - ARMv7_OP_4(MVN_IMM, T1), // f0 6F // C - - ARMv7_NULL_OP, // f0 7 // D - ARMv7_OP_4(EOR_IMM, T1), // f0 8 // E - ARMv7_OP_4(TEQ_IMM, T1) // f0 9 // F - -}; - -static void group_0xf0(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) // TODO: optimize this group -{ - u32 index = 0; - if ((thr->m_arg & 0xfbe08000) == 0xf0000000) index = 0x0; - if ((thr->m_arg & 0xf800d000) == 0xf0008000) index = 0x1; - if ((thr->m_arg & 0xf800d000) == 0xf0009000) index = 0x2; - if ((thr->m_arg & 0xf800c001) == 0xf000c000) index = 0x3; - if ((thr->m_arg & 0xf800d000) == 0xf000d000) index = 0x4; - if ((thr->m_arg & 0xfbf08f00) == 0xf0100f00) index = 0x5; - if ((thr->m_arg & 0xfbe08000) == 0xf0200000) index = 0x6; - if ((thr->m_arg & 0xfbe08000) == 0xf0400000) index = 0x8; - if ((thr->m_arg & 0xfbef8000) == 0xf04f0000) index = 0x9; - if ((thr->m_arg & 0xfbe08000) == 0xf0600000) index = 0xb; - if ((thr->m_arg & 0xfbef8000) == 0xf06f0000) index = 0xc; - if ((thr->m_arg & 0xfbe08000) == 0xf0800000) index = 0xe; - if ((thr->m_arg & 0xfbf08f00) == 0xf0900f00) index = 0xf; - - /* - u32 index = (thr->code.code0 & 0x00e0) >> 4; // 0xfbef - - if ((thr->code.code0 & 0xfbf0) == 0xf010) index = 0x1; - if ((thr->code.code0 & 0xfbf0) == 0xf090) index = 0x9; - */ - - thr->m_last_instr_size = g_table_0xf0[index].size; - thr->m_last_instr_name = g_table_0xf0[index].name; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xf0[index].func(thr, g_table_0xf0[index].type); -} - -static const ARMv7_Instruction g_table_0xf10[] = -{ - ARMv7_OP_4(ADD_IMM, T3), // 0 0xfbe0, 0x8000 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_NULL_OP, // 8 - ARMv7_NULL_OP, // 9 - ARMv7_NULL_OP, // A - ARMv7_NULL_OP, // B - ARMv7_NULL_OP, // C - ARMv7_OP_4(ADD_SPI, T3) // D 0xfbef, 0x8000 -}; - -static void group_0xf10(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = thr->code.code0 & 0x000f; - - if ((thr->m_arg & 0xfbe08000) == 0xf1000000) index = 0x0; - - thr->m_last_instr_name = g_table_0xf10[index].name; - thr->m_last_instr_size = g_table_0xf10[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xf10[index].func(thr, g_table_0xf10[index].type); -} - -static const ARMv7_Instruction g_table_0xf1a[] = -{ - ARMv7_OP_4(SUB_IMM, T3), // 0 0xfbe0, 0x8000 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_NULL_OP, // 8 - ARMv7_NULL_OP, // 9 - ARMv7_NULL_OP, // A - ARMv7_NULL_OP, // B - ARMv7_NULL_OP, // C - ARMv7_OP_4(SUB_SPI, T2) // D 0xfbef, 0x8000 -}; - -static void group_0xf1a(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = thr->code.code0 & 0x000f; - - if ((thr->m_arg & 0xfbe08000) == 0xf1a00000) index = 0x0; - - thr->m_last_instr_name = g_table_0xf1a[index].name; - thr->m_last_instr_size = g_table_0xf1a[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xf1a[index].func(thr, g_table_0xf1a[index].type); -} - -static const ARMv7_Instruction g_table_0xf1[] = -{ - { group_0xf10 }, // 0 - ARMv7_OP_4(CMN_IMM, T1), // 1 0xfbf0, 0x8f00 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_OP_4(ADC_IMM, T1), // 4 0xfbe0, 0x8000 - ARMv7_NULL_OP, // 5 - ARMv7_OP_4(SBC_IMM, T1), // 6 0xfbe0, 0x8000 - ARMv7_NULL_OP, // 7 - ARMv7_NULL_OP, // 8 - ARMv7_NULL_OP, // 9 - { group_0xf1a }, // A - ARMv7_OP_4(CMP_IMM, T2), // B 0xfbf0, 0x8f00 - ARMv7_OP_4(RSB_IMM, T2) // C 0xfbe0, 0x8000 -}; - -static void group_0xf1(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = (thr->code.code0 & 0x00e0) >> 4; - - if ((thr->m_arg & 0xfbf08f00) == 0xf1100f00) index = 0x1; - if ((thr->m_arg & 0xfbf08f00) == 0xf1b00f00) index = 0xb; - - thr->m_last_instr_name = g_table_0xf1[index].name; - thr->m_last_instr_size = g_table_0xf1[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xf1[index].func(thr, g_table_0xf1[index].type); -} - -static const ARMv7_Instruction g_table_0xf20[] = -{ - ARMv7_OP_4(ADD_IMM, T4), // 0 0xfbf0, 0x8000 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_NULL_OP, // 8 - ARMv7_NULL_OP, // 9 - ARMv7_NULL_OP, // A - ARMv7_NULL_OP, // B - ARMv7_NULL_OP, // C - ARMv7_OP_4(ADD_SPI, T4), // D 0xfbff, 0x8000 - ARMv7_NULL_OP, // E - ARMv7_OP_4(ADR, T3) // F 0xfbff, 0x8000 -}; - -static void group_0xf20(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = thr->code.code0 & 0x000f; - - if ((thr->m_arg & 0xfbf08000) == 0xf2000000) index = 0x0; - - thr->m_last_instr_name = g_table_0xf20[index].name; - thr->m_last_instr_size = g_table_0xf20[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xf20[index].func(thr, g_table_0xf20[index].type); -} - -static const ARMv7_Instruction g_table_0xf2a[] = -{ - ARMv7_OP_4(SUB_IMM, T4), // 0 0xfbf0, 0x8000 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_NULL_OP, // 8 - ARMv7_NULL_OP, // 9 - ARMv7_NULL_OP, // A - ARMv7_NULL_OP, // B - ARMv7_NULL_OP, // C - ARMv7_OP_4(SUB_SPI, T3), // D 0xfbff, 0x8000 - ARMv7_NULL_OP, // E - ARMv7_OP_4(ADR, T2) // F 0xfbff, 0x8000 -}; - -static void group_0xf2a(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = thr->code.code0 & 0x000f; - - if ((thr->m_arg & 0xfbf08000) == 0xf2a00000) index = 0x0; - - thr->m_last_instr_name = g_table_0xf2a[index].name; - thr->m_last_instr_size = g_table_0xf2a[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xf2a[index].func(thr, g_table_0xf2a[index].type); -} - -static const ARMv7_Instruction g_table_0xf2[] = -{ - { group_0xf20 }, // 0 0xfbff - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_OP_4(MOV_IMM, T3), // 4 0xfbf0, 0x8000 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_NULL_OP, // 8 - ARMv7_NULL_OP, // 9 - { group_0xf2a }, // A 0xfbff - ARMv7_NULL_OP, // B - ARMv7_OP_4(MOVT, T1) // C 0xfbf0, 0x8000 -}; - -static void group_0xf2(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - const u32 index = (thr->code.code0 & 0x00f0) >> 4; // mask 0xfbf0 - thr->m_last_instr_name = g_table_0xf2[index].name; - thr->m_last_instr_size = g_table_0xf2[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xf2[index].func(thr, g_table_0xf2[index].type); -} - -static const ARMv7_Instruction g_table_0xf36[] = -{ - ARMv7_OP_4(BFI, T1), // 0 0xfff0, 0x8020 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_NULL_OP, // 8 - ARMv7_NULL_OP, // 9 - ARMv7_NULL_OP, // A - ARMv7_NULL_OP, // B - ARMv7_NULL_OP, // C - ARMv7_NULL_OP, // C - ARMv7_NULL_OP, // E - ARMv7_OP_4(BFC, T1) // F 0xffff, 0x8020 -}; - -static void group_0xf36(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = thr->code.code0 & 0x000f; - - if ((thr->m_arg & 0xfff08020) == 0xf3600000) index = 0x0; - - thr->m_last_instr_name = g_table_0xf36[index].name; - thr->m_last_instr_size = g_table_0xf36[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xf36[index].func(thr, g_table_0xf36[index].type); -} - -static const ARMv7_Instruction g_table_0xf3[] = -{ - ARMv7_NULL_OP, // 0 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_OP_4(SBFX, T1), // 4 0xfff0, 0x8020 - ARMv7_NULL_OP, // 5 - { group_0xf36 }, // 6 0xffff - ARMv7_NULL_OP, // 7 - ARMv7_OP_4(MSR_REG, T1), // 8 0xfff0, 0xf3ff - ARMv7_NULL_OP, // 9 - ARMv7_OP_4(NOP, T2), // A 0xffff, 0xffff - ARMv7_NULL_OP, // B - ARMv7_NULL_OP, // C - ARMv7_NULL_OP, // D - ARMv7_OP_4(MRS, T1), // E 0xffff, 0xf0ff -}; - -static void group_0xf3(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - const u32 index = (thr->code.code0 & 0x00f0) >> 4; - thr->m_last_instr_name = g_table_0xf3[index].name; - thr->m_last_instr_size = g_table_0xf3[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xf3[index].func(thr, g_table_0xf3[index].type); -} - -static const ARMv7_Instruction g_table_0xf800[] = -{ - ARMv7_OP_4(STRB_REG, T2), // 0 0xfff0, 0x0fc0 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_OP_4(STRB_IMM, T3) // 8 0xfff0, 0x0800 -}; - -static void group_0xf800(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = (thr->code.code1 & 0x0f00) >> 8; - - if ((thr->code.code1 & 0x0800) == 0x0800) index = 0x8; - - thr->m_last_instr_name = g_table_0xf800[index].name; - thr->m_last_instr_size = g_table_0xf800[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xf800[index].func(thr, g_table_0xf800[index].type); -} - -static const ARMv7_Instruction g_table_0xf810[] = -{ - ARMv7_OP_4(LDRB_REG, T2), // 0 0xfff0, 0x0fc0 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_OP_4(LDRB_IMM, T3) // 8 0xfff0, 0x0800 -}; - -static void group_0xf810(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = (thr->code.code1 & 0x0f00) >> 8; - - if ((thr->code.code1 & 0x0800) == 0x0800) index = 0x8; - - thr->m_last_instr_name = g_table_0xf810[index].name; - thr->m_last_instr_size = g_table_0xf810[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xf810[index].func(thr, g_table_0xf810[index].type); -} - -static const ARMv7_Instruction g_table_0xf81[] = -{ - { group_0xf810 }, // 0 0xfff0 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_NULL_OP, // 8 - ARMv7_NULL_OP, // 9 - ARMv7_NULL_OP, // A - ARMv7_NULL_OP, // B - ARMv7_NULL_OP, // C - ARMv7_NULL_OP, // C - ARMv7_NULL_OP, // E - ARMv7_OP_4(LDRB_LIT, T1) // F 0xff7f, 0x0000 -}; - -static void group_0xf81(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = thr->code.code0 & 0x000f; - - if (((thr->m_arg & 0xfff00fc0) == 0xf8100000) || ((thr->m_arg & 0xfff00800) == 0xf8100800)) index = 0x0; - - thr->m_last_instr_name = g_table_0xf81[index].name; - thr->m_last_instr_size = g_table_0xf81[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xf81[index].func(thr, g_table_0xf81[index].type); -} - -static const ARMv7_Instruction g_table_0xf820[] = -{ - ARMv7_OP_4(STRH_REG, T2), // 0 0xfff0, 0x0fc0 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_OP_4(STRH_IMM, T3) // 8 0xfff0, 0x0800 -}; - -static void group_0xf820(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = (thr->code.code1 & 0x0f00) >> 8; - - if ((thr->code.code1 & 0x0800) == 0x0800) index = 0x8; - - thr->m_last_instr_name = g_table_0xf820[index].name; - thr->m_last_instr_size = g_table_0xf820[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xf820[index].func(thr, g_table_0xf820[index].type); -} - -static const ARMv7_Instruction g_table_0xf840[] = -{ - ARMv7_OP_4(STR_REG, T2), // 0 0xfff0, 0x0fc0 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_OP_4(STR_IMM, T4) // 8 0xfff0, 0x0800 -}; - -static void group_0xf840(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = (thr->code.code1 & 0x0f00) >> 8; - - if ((thr->code.code1 & 0x0800) == 0x0800) index = 0x8; - - thr->m_last_instr_name = g_table_0xf840[index].name; - thr->m_last_instr_size = g_table_0xf840[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xf840[index].func(thr, g_table_0xf840[index].type); -} - -static const ARMv7_Instruction g_table_0xf84[] = -{ - { group_0xf840 }, // 0 0xfff0 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_NULL_OP, // 8 - ARMv7_NULL_OP, // 9 - ARMv7_NULL_OP, // A - ARMv7_NULL_OP, // B - ARMv7_NULL_OP, // C - ARMv7_OP_4(PUSH, T3) // D 0xffff, 0x0fff -}; - -static void group_0xf84(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = thr->code.code0 & 0x000f; - - if (((thr->m_arg & 0xfff00fc0) == 0xf8400000) || ((thr->m_arg & 0xfff00800) == 0xf8400800)) index = 0x0; - - thr->m_last_instr_name = g_table_0xf84[index].name; - thr->m_last_instr_size = g_table_0xf84[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xf84[index].func(thr, g_table_0xf84[index].type); -} - -static const ARMv7_Instruction g_table_0xf850[] = -{ - ARMv7_OP_4(LDR_REG, T2), // 0 0xfff0, 0x0fc0 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_OP_4(LDR_IMM, T4) // 8 0xfff0, 0x0800 -}; - -static void group_0xf850(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = (thr->code.code1 & 0x0f00) >> 8; - - if ((thr->code.code1 & 0x0800) == 0x0800) index = 0x8; - - thr->m_last_instr_name = g_table_0xf850[index].name; - thr->m_last_instr_size = g_table_0xf850[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xf850[index].func(thr, g_table_0xf850[index].type); -} - -static const ARMv7_Instruction g_table_0xf85[] = -{ - { group_0xf850 }, // 0 0xfff0 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_NULL_OP, // 8 - ARMv7_NULL_OP, // 9 - ARMv7_NULL_OP, // A - ARMv7_NULL_OP, // B - ARMv7_NULL_OP, // C - ARMv7_OP_4(POP, T3), // D 0xffff, 0x0fff - ARMv7_NULL_OP, // C - ARMv7_OP_4(LDR_LIT, T2) // F 0xff7f, 0x0000 -}; - -static void group_0xf85(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = thr->code.code0 & 0x000f; - - if (((thr->m_arg & 0xfff00fc0) == 0xf8500000) || ((thr->m_arg & 0xfff00800) == 0xf8500800)) index = 0x0; - - thr->m_last_instr_name = g_table_0xf85[index].name; - thr->m_last_instr_size = g_table_0xf85[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xf85[index].func(thr, g_table_0xf85[index].type); -} - -static const ARMv7_Instruction g_table_0xf8[] = -{ - { group_0xf800 }, // 0 0xfff0 - { group_0xf81 }, // 1 0xfff0 - { group_0xf820 }, // 2 0xfff0 - ARMv7_NULL_OP, // 3 - { group_0xf84 }, // 4 0xfff0 - { group_0xf85 }, // 5 0xfff0 - ARMv7_NULL_OP, // 6 - ARMv7_OP_4(HACK, T1), // 7 0xffff, 0x0000 - ARMv7_OP_4(STRB_IMM, T2), // 8 0xfff0, 0x0000 - ARMv7_OP_4(LDRB_IMM, T2), // 9 0xfff0, 0x0000 - ARMv7_OP_4(STRH_IMM, T2), // A 0xfff0, 0x0000 - ARMv7_NULL_OP, // B - ARMv7_OP_4(STR_IMM, T3), // C 0xfff0, 0x0000 - ARMv7_OP_4(LDR_IMM, T3) // D 0xfff0, 0x0000 -}; - -static void group_0xf8(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - const u32 index = (thr->code.code0 & 0x00f0) >> 4; - thr->m_last_instr_name = g_table_0xf8[index].name; - thr->m_last_instr_size = g_table_0xf8[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xf8[index].func(thr, g_table_0xf8[index].type); -} - -static const ARMv7_Instruction g_table_0xf910[] = -{ - ARMv7_OP_4(LDRSB_REG, T2), // 0 0xfff0, 0x0fc0 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_OP_4(LDRSB_IMM, T2) // 8 0xfff0, 0x0800 -}; - -static void group_0xf910(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = (thr->code.code1 & 0x0f00) >> 8; - - if ((thr->code.code1 & 0x0800) == 0x0800) index = 0x8; - - thr->m_last_instr_name = g_table_0xf910[index].name; - thr->m_last_instr_size = g_table_0xf910[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xf910[index].func(thr, g_table_0xf910[index].type); -} - -static const ARMv7_Instruction g_table_0xf91[] = -{ - { group_0xf910 }, // 0 0xfff0 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_NULL_OP, // 8 - ARMv7_NULL_OP, // 9 - ARMv7_NULL_OP, // A - ARMv7_NULL_OP, // B - ARMv7_NULL_OP, // C - ARMv7_NULL_OP, // D - ARMv7_NULL_OP, // C - ARMv7_OP_4(LDRSB_LIT, T1) // F 0xff7f, 0x0000 -}; - -static void group_0xf91(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = thr->code.code0 & 0x000f; - - if (((thr->m_arg & 0xfff00fc0) == 0xf9100000) || ((thr->m_arg & 0xfff00800) == 0xf9100800)) index = 0x0; - - thr->m_last_instr_name = g_table_0xf91[index].name; - thr->m_last_instr_size = g_table_0xf91[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xf91[index].func(thr, g_table_0xf91[index].type); -} - -static const ARMv7_Instruction g_table_0xf930[] = -{ - ARMv7_OP_4(LDRSH_REG, T2), // 0 0xfff0, 0x0fc0 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_OP_4(LDRSH_IMM, T2) // 8 0xfff0, 0x0800 -}; - -static void group_0xf930(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = (thr->code.code1 & 0x0f00) >> 8; - - if ((thr->code.code1 & 0x0800) == 0x0800) index = 0x8; - - thr->m_last_instr_name = g_table_0xf930[index].name; - thr->m_last_instr_size = g_table_0xf930[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xf930[index].func(thr, g_table_0xf930[index].type); -} - -static const ARMv7_Instruction g_table_0xf93[] = -{ - { group_0xf930 }, // 0 0xfff0 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_NULL_OP, // 8 - ARMv7_NULL_OP, // 9 - ARMv7_NULL_OP, // A - ARMv7_NULL_OP, // B - ARMv7_NULL_OP, // C - ARMv7_NULL_OP, // D - ARMv7_NULL_OP, // C - ARMv7_OP_4(LDRSH_LIT, T1) // F 0xff7f, 0x0000 -}; - -static void group_0xf93(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = thr->code.code0 & 0x000f; - - if (((thr->m_arg & 0xfff00fc0) == 0xf9300000) || ((thr->m_arg & 0xfff00800) == 0xf9300800)) index = 0x0; - - thr->m_last_instr_name = g_table_0xf93[index].name; - thr->m_last_instr_size = g_table_0xf93[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xf93[index].func(thr, g_table_0xf93[index].type); -} - -static const ARMv7_Instruction g_table_0xf9[] = -{ - ARMv7_NULL_OP, // 0 - { group_0xf91 }, // 1 0xff7f - ARMv7_NULL_OP, // 2 - { group_0xf93 }, // 3 0xff7f - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_NULL_OP, // 8 - ARMv7_OP_4(LDRSB_IMM, T1), // 9 0xfff0, 0x0000 - ARMv7_NULL_OP, // A - ARMv7_OP_4(LDRSH_IMM, T1), // B 0xfff0, 0x0000 -}; - -static void group_0xf9(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = (thr->code.code0 & 0x00f0) >> 4; - - if ((thr->code.code0 & 0xff7) == 0xf91) index = 0x1; // check me - if ((thr->code.code0 & 0xff7) == 0xf93) index = 0x3; - - thr->m_last_instr_name = g_table_0xf9[index].name; - thr->m_last_instr_size = g_table_0xf9[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xf9[index].func(thr, g_table_0xf9[index].type); -} - -static const ARMv7_Instruction g_table_0xfa00[] = -{ - ARMv7_OP_4(BLX, A2), // 0 0xfe00, 0x0000 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_NULL_OP, // 8 - ARMv7_NULL_OP, // 9 - ARMv7_NULL_OP, // A - ARMv7_NULL_OP, // B - ARMv7_NULL_OP, // C - ARMv7_NULL_OP, // D - ARMv7_NULL_OP, // E - ARMv7_OP_4(LSL_REG, T2) // F 0xffe0, 0xf0f0 -}; - -static void group_0xfa00(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - const u32 index = (thr->code.code1 & 0xf0f0) == 0xf000 ? 0xf : 0x0; - thr->m_last_instr_name = g_table_0xfa00[index].name; - thr->m_last_instr_size = g_table_0xfa00[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xfa00[index].func(thr, g_table_0xfa00[index].type); -} - -static const ARMv7_Instruction g_table_0xfa90[] = -{ - ARMv7_NULL_OP, // 0 - ARMv7_NULL_OP, // 1 - ARMv7_NULL_OP, // 2 - ARMv7_NULL_OP, // 3 - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - ARMv7_OP_4(REV, T2), // 8 0xfff0, 0xf0f0 - ARMv7_OP_4(REV16, T2), // 9 0xfff0, 0xf0f0 - ARMv7_OP_4(RBIT, T1), // A 0xfff0, 0xf0f0 - ARMv7_OP_4(REVSH, T2) // B 0xfff0, 0xf0f0 -}; - -static void group_0xfa90(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - const u32 index = (thr->code.code1 & 0x00f0) >> 4; - thr->m_last_instr_name = g_table_0xfa90[index].name; - thr->m_last_instr_size = g_table_0xfa90[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xfa90[index].func(thr, g_table_0xfa90[index].type); -} - -static const ARMv7_Instruction g_table_0xfa[] = -{ - { group_0xfa00 }, // 0 0xffe0 - ARMv7_NULL_OP, // 1 - ARMv7_OP_4(LSR_REG, T2), // 2 0xffe0, 0xf0f0 - ARMv7_NULL_OP, // 3 - ARMv7_OP_4(ASR_REG, T2), // 4 0xffe0, 0xf0f0 - ARMv7_NULL_OP, // 5 - ARMv7_OP_4(ROR_REG, T2), // 6 0xffe0, 0xf0f0 - ARMv7_NULL_OP, // 7 - ARMv7_NULL_OP, // 8 - { group_0xfa90 }, // 9 0xfff0 - ARMv7_OP_4(SEL, T1), // A 0xfff0, 0xf0f0 - ARMv7_OP_4(CLZ, T1) // B 0xfff0, 0xf0f0 -}; - -static void group_0xfa(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = (thr->code.code0 & 0x00e0) >> 4; - - switch ((thr->code.code0 & 0x00f0) >> 4) + inline namespace arm_encoding_alias { - case 0x9: index = 0x9; break; - case 0xa: index = 0xa; break; - case 0xb: index = 0xb; break; - - default: break; + constexpr auto T1 = arm_encoding ::T1; + constexpr auto T2 = arm_encoding ::T2; + constexpr auto T3 = arm_encoding ::T3; + constexpr auto T4 = arm_encoding ::T4; + constexpr auto A1 = arm_encoding ::A1; + constexpr auto A2 = arm_encoding ::A2; } - thr->m_last_instr_name = g_table_0xfa[index].name; - thr->m_last_instr_size = g_table_0xfa[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xfa[index].func(thr, g_table_0xfa[index].type); + // Bitfield aliases (because only u32 base type is used) + template using bf = bf_t; + template using sf = bf_t; + template using ff = ff_t; + + template using cf = cf_t; + + // Nullary op + template + struct nullary + { + static inline u32 extract() + { + return F::extract(0); + } + }; + + // Pair op: first field selection + template + struct from_first + { + static inline u32 extract(u32 first, u32) + { + return F::extract(first); + } + }; + + // Pair op: second field selection + template + struct from_second + { + static inline u32 extract(u32, u32 second) + { + return F::extract(second); + } + }; + + // No operation + struct nopf + { + static inline u32 extract(u32 value) + { + return value; + } + }; + + // Negate unary op + template + struct negatef : bf_base + { + static inline u32 extract(u32 value) + { + return (0u - F::extract(value)) & (~0u >> (32 - N)); + } + }; + + // NOT unary op + template + struct notf : bf_base + { + static inline u32 extract(u32 value) + { + return F::extract(value) ^ (~0u >> (32 - N)); + } + }; + + // XOR binary op + template + struct xorf : bf_base + { + static inline u32 extract(u32 value) + { + return F1::extract(value) ^ F2::extract(value); + } + }; + + // AND binary op + template + struct andf : bf_base + { + static inline u32 extract(u32 value) + { + return F1::extract(value) & F2::extract(value); + } + }; + + // OR binary op + template + struct orf : bf_base + { + static inline u32 extract(u32 value) + { + return F1::extract(value) | F2::extract(value); + } + }; + + // SHL binary op + template + struct shlf : bf_base + { + static inline u32 extract(u32 value) + { + return F1::extract(value) << F2::extract(value); + } + }; + + // EQ with constant binary op + template + struct eqcf : bf_base + { + static inline u32 extract(u32 value) + { + return F1::extract(value) == C; + } + }; + + using imm12i38 = cf, bf<12, 3>, bf<0, 8>>; + + // ThumbExpandImm(...) + struct thumb_expand_imm + { + static constexpr uint bitsize() + { + return 32; + } + + static u32 extract(u32 value) + { + const u32 imm12 = imm12i38::extract(value); + + if ((imm12 & 0xc00) >> 10) + { + const u32 x = (imm12 & 0x7f) | 0x80; + const u32 s = (imm12 & 0xf80) >> 7; + const u32 r = x >> s | x << (32 - s); // Rotate + return r; + } + else + { + const u32 imm8 = imm12 & 0xff; + switch ((imm12 & 0x300) >> 8) + { + case 0: return imm8; + case 1: return imm8 << 16 | imm8; + case 2: return imm8 << 24 | imm8 << 8; + default: return imm8 << 24 | imm8 << 16 | imm8 << 8 | imm8; + } + } + } + }; + + // ThumbExpandImm_C(..., carry) -> carry + struct thumb_expand_imm_c + { + static u32 extract(u32 value, u32 carry_in) + { + const u32 imm12 = imm12i38::extract(value); + + if ((imm12 & 0xc00) >> 10) + { + const u32 x = (imm12 & 0x7f) | 0x80; + const u32 s = (imm12 & 0xf80) >> 7; + const u32 r = x >> s | x << (32 - s); // Rotate + return (s ? r >> 31 : carry_in) & 1; + } + else + { + return carry_in & 1; + } + } + }; + + // ARMExpandImm(...) + struct arm_expand_imm + { + static constexpr uint bitsize() + { + return 32; + } + + static u32 extract(u32 value) + { + const u32 imm12 = bf<0, 12>::extract(value); + + const u32 x = imm12 & 0xff; + const u32 s = (imm12 & 0xf00) >> 7; + const u32 r = x >> s | x << (32 - s); // Rotate + + return r; + } + }; + + // ARMExpandImm_C(..., carry) -> carry + struct arm_expand_imm_c + { + static u32 extract(u32 value, u32 carry_in) + { + const u32 imm12 = bf<0, 12>::extract(value); + + const u32 x = imm12 & 0xff; + const u32 s = (imm12 & 0xf00) >> 7; + const u32 r = x >> s | x << (32 - s); // Rotate + + return (s ? r >> 31 : carry_in) & 1; + } + }; + + // !InITBlock() + struct not_in_it_block + { + static u32 extract(u32 value, u32 cond) + { + return cond != 0xf; + } + }; + + enum SRType : u32 + { + SRType_LSL, + SRType_LSR, + SRType_ASR, + SRType_ROR, + SRType_RRX, + }; + + template + struct decode_imm_shift_type + { + static u32 extract(u32 value) + { + const u32 type = T::extract(value); + const u32 imm5 = N::extract(value); + + return type < SRType_ROR ? type : (imm5 ? SRType_ROR : SRType_RRX); + } + }; + + template + struct decode_imm_shift_num + { + static u32 extract(u32 value) + { + const u32 type = T::extract(value); + const u32 imm5 = N::extract(value); + + return imm5 || type == SRType_LSL ? imm5 : (type < SRType_ROR ? 32 : 1); + } + }; + + using decode_imm_shift_type_thumb = decode_imm_shift_type, cf, bf<6, 2>>>; + using decode_imm_shift_num_thumb = decode_imm_shift_num, cf, bf<6, 2>>>; + using decode_imm_shift_type_arm = decode_imm_shift_type, bf<7, 5>>; + using decode_imm_shift_num_arm = decode_imm_shift_num, bf<7, 5>>; + + template struct it; // + + template<> struct it + { + using mask = bf<0, 4>; + using first = bf<4, 4>; + + using skip_if = eqcf; // Skip if mask==0 + }; + + template struct hack; // + + template<> struct hack + { + using index = bf<0, 16>; + + using skip_if = void; + }; + + template<> struct hack + { + using index = cf, bf<0, 4>>; + + using skip_if = void; + }; + + template struct mrc; // + + template<> struct mrc + { + using t = bf<12, 4>; + using cp = bf<8, 4>; + using opc1 = bf<21, 3>; + using opc2 = bf<5, 3>; + using cn = bf<16, 4>; + using cm = bf<0, 4>; + + using skip_if = eqcf, 5>; + }; + + template<> struct mrc : mrc + { + using skip_if = void; + }; + + template<> struct mrc : mrc + { + using skip_if = eqcf, 5>; + }; + + template<> struct mrc : mrc + { + using skip_if = void; + }; + + template struct add_imm; // + + template<> struct add_imm + { + using d = bf<0, 3>; + using n = bf<3, 3>; + using set_flags = not_in_it_block; + using imm32 = bf<6, 3>; + + using skip_if = void; + }; + + template<> struct add_imm + { + using d = bf<8, 3>; + using n = d; + using set_flags = not_in_it_block; + using imm32 = bf<0, 8>; + + using skip_if = void; + }; + + template<> struct add_imm + { + using d = bf<8, 4>; + using n = bf<16, 4>; + using set_flags = from_first>; + using imm32 = thumb_expand_imm; + + using skip_if = orf, bf<20, 1>>, eqcf>; + }; + + template<> struct add_imm : add_imm + { + using add_imm::n; + using set_flags = from_first>; + using imm32 = imm12i38; + + using skip_if = orf, eqcf>; + }; + + template<> struct add_imm + { + using d = bf<12, 4>; + using n = bf<16, 4>; + using set_flags = from_first>; + using imm32 = arm_expand_imm; + + using skip_if = orf, notf>>, eqcf>, andf, bf<20, 1>>>; + }; + + template struct add_reg; // + + template<> struct add_reg + { + using d = bf<0, 3>; + using n = bf<3, 3>; + using m = bf<6, 3>; + using set_flags = not_in_it_block; + using shift_t = ff; + using shift_n = ff<0u>; + + using skip_if = void; + }; + + template<> struct add_reg + { + using d = cf, bf<0, 3>>; + using n = d; + using m = bf<3, 4>; + using set_flags = from_first>; + using shift_t = ff; + using shift_n = ff<0u>; + + using skip_if = orf, eqcf>; + }; + + template<> struct add_reg + { + using d = bf<8, 4>; + using n = bf<16, 4>; + using m = bf<0, 4>; + using set_flags = from_first>; + using shift_t = decode_imm_shift_type_thumb; + using shift_n = decode_imm_shift_num_thumb; + + using skip_if = orf, bf<20, 1>>, eqcf>; + }; + + template<> struct add_reg : add_reg + { + using d = bf<12, 4>; + using n = bf<16, 4>; + using shift_t = decode_imm_shift_type_arm; + using shift_n = decode_imm_shift_num_arm; + + using skip_if = orf, bf<20, 1>>, eqcf>; + }; + + template struct add_spi; // + + template<> struct add_spi + { + using d = bf<8, 3>; + using set_flags = from_first>; + using imm32 = cf, ff<0u, 2>>; + + using skip_if = void; + }; + + template<> struct add_spi + { + using d = ff<13u>; + using set_flags = from_first>; + using imm32 = cf, ff<0u, 2>>; + + using skip_if = void; + }; + + template<> struct add_spi + { + using d = bf<8, 4>; + using set_flags = from_first>; + using imm32 = thumb_expand_imm; + + using skip_if = andf, bf<20, 1>>; + }; + + template<> struct add_spi + { + using d = bf<8, 4>; + using set_flags = from_first>; + using imm32 = imm12i38; + + using skip_if = void; + }; + + template<> struct add_spi + { + using d = bf<12, 4>; + using set_flags = from_first>; + using imm32 = arm_expand_imm; + + using skip_if = andf, bf<20, 1>>; + }; + + template struct add_spr; // + + template<> struct add_spr + { + using d = cf, bf<0, 3>>; + using m = d; + using set_flags = from_first>; + using shift_t = ff; + using shift_n = ff<0u>; + + using skip_if = void; + }; + + template<> struct add_spr + { + using d = ff<13u>; + using m = bf<3, 4>; + using set_flags = from_first>; + using shift_t = ff; + using shift_n = ff<0u>; + + using skip_if = eqcf; + }; + + template<> struct add_spr + { + using d = bf<8, 4>; + using m = bf<0, 4>; + using set_flags = from_first>; + using shift_t = decode_imm_shift_type_thumb; + using shift_n = decode_imm_shift_num_thumb; + + using skip_if = void; + }; + + template<> struct add_spr + { + using d = bf<12, 4>; + using m = bf<0, 4>; + using set_flags = from_first>; + using shift_t = decode_imm_shift_type_arm; + using shift_n = decode_imm_shift_num_arm; + + using skip_if = andf, bf<20, 1>>; + }; + + template struct adc_imm; // + + template<> struct adc_imm : add_imm + { + using skip_if = void; + }; + + template<> struct adc_imm : add_imm + { + using skip_if = void; + }; + + template struct adc_reg; // + + template<> struct adc_reg + { + using d = bf<0, 3>; + using n = d; + using m = bf<3, 3>; + using set_flags = not_in_it_block; + using shift_t = ff; + using shift_n = ff<0u>; + + using skip_if = void; + }; + + template<> struct adc_reg : add_reg + { + using skip_if = void; + }; + + template<> struct adc_reg : add_reg + { + using add_reg::d; + + using skip_if = andf, bf<20, 1>>; + }; + + template struct adr; // + + template<> struct adr + { + using d = bf<8, 3>; + using i = cf, ff<0u, 2>>; + + using skip_if = void; + }; + + template<> struct adr + { + using d = bf<8, 4>; + using i = negatef; + + using skip_if = void; + }; + + template<> struct adr + { + using d = bf<8, 4>; + using i = imm12i38; + + using skip_if = void; + }; + + template<> struct adr + { + using d = bf<12, 4>; + using i = arm_expand_imm; + + using skip_if = void; + }; + + template<> struct adr + { + using d = bf<12, 4>; + using i = negatef; + + using skip_if = void; + }; + + template struct and_imm; // + + template<> struct and_imm + { + using d = bf<8, 4>; + using n = bf<16, 4>; + using set_flags = from_first>; + using imm32 = thumb_expand_imm; + using carry = thumb_expand_imm_c; + + using skip_if = andf, bf<20, 1>>; + }; + + template<> struct and_imm : and_imm + { + using d = bf<12, 4>; + using imm32 = arm_expand_imm; + using carry = arm_expand_imm_c; + + using skip_if = andf, bf<20, 1>>; + }; + + template struct and_reg; // + + template<> struct and_reg : adc_reg + { + using skip_if = void; + }; + + template<> struct and_reg : adc_reg + { + using adc_reg::d; + + using skip_if = andf, bf<20, 1>>; + }; + + template<> struct and_reg : adc_reg + { + using adc_reg::d; + + using skip_if = andf, bf<20, 1>>; + }; + + template struct b; // + + template<> struct b + { + using imm32 = cf, ff<0u, 1>>; + using cond = from_first>; + + using skip_if = eqcf; + }; + + template<> struct b + { + using imm32 = cf, ff<0u, 1>>; + using cond = from_second<>; + + using skip_if = void; + }; + + template<> struct b + { + using imm32 = cf, bf<11, 1>, bf<13, 1>, bf<16, 6>, bf<0, 11>, ff<0u, 1>>; + using cond = from_first>; + + using skip_if = eqcf, 7>; + }; + + template<> struct b + { + using imm32 = cf, notf, bf<26, 1>>>, notf, bf<26, 1>>>, bf<16, 10>, bf<0, 11>, ff<0u, 1>>; + using cond = from_second<>; + + using skip_if = void; + }; + + template<> struct b + { + using imm32 = cf, ff<0u, 2>>; + using cond = from_second<>; + + using skip_if = void; + }; + + template struct bic_imm; // + + template<> struct bic_imm : and_imm + { + using skip_if = void; + }; + + template<> struct bic_imm : and_imm + { + using and_imm::d; + + using skip_if = andf, bf<20, 1>>; + }; + + template struct bic_reg; // + + template<> struct bic_reg : adc_reg + { + using skip_if = void; + }; + + template<> struct bic_reg : adc_reg + { + using skip_if = void; + }; + + template<> struct bic_reg : adc_reg + { + using adc_reg::d; + + using skip_if = andf, bf<20, 1>>; + }; + + template struct bl; // + + template<> struct bl + { + using imm32 = b::imm32; + using to_arm = nullary>; + + using skip_if = void; + }; + + template<> struct bl + { + using imm32 = cf, notf, bf<26, 1>>>, notf, bf<26, 1>>>, bf<16, 10>, bf<1, 10>, ff<0u, 2>>; + using to_arm = nullary>; + + using skip_if = void; + }; + + template<> struct bl + { + using imm32 = b::imm32; + using to_arm = nullary>; + + using skip_if = void; + }; + + template<> struct bl + { + using imm32 = cf, bf<24, 1>, ff<0u, 1>>; + using to_arm = nullary>; + + using skip_if = void; + }; + + template struct blx; // + + template<> struct blx + { + using m = bf<3, 4>; + + using skip_if = void; + }; + + template<> struct blx + { + using m = bf<0, 4>; + + using skip_if = void; + }; + + template struct bx; // + + template<> struct bx : blx + { + using skip_if = void; + }; + + template<> struct bx : blx + { + using skip_if = void; + }; + + template struct cb_z; // + + template<> struct cb_z + { + using n = bf<0, 3>; + using imm32 = cf, bf<3, 5>, ff<0u, 1>>; + using nonzero = bf<11, 1>; + + using skip_if = void; + }; + + template struct clz; // + + template<> struct clz + { + using d = bf<8, 4>; + using m = bf<0, 4>; + + using skip_if = void; + }; + + template<> struct clz + { + using d = bf<12, 4>; + using m = bf<0, 4>; + + using skip_if = void; + }; + + template struct cmp_imm; // + + template<> struct cmp_imm + { + using n = bf<8, 3>; + using imm32 = bf<0, 8>; + + using skip_if = void; + }; + + template<> struct cmp_imm + { + using n = bf<16, 4>; + using imm32 = thumb_expand_imm; + + using skip_if = void; + }; + + template<> struct cmp_imm + { + using n = bf<16, 4>; + using imm32 = arm_expand_imm; + + using skip_if = void; + }; + + template struct cmp_reg; // + + template<> struct cmp_reg + { + using n = bf<0, 3>; + using m = bf<3, 3>; + using shift_t = ff; + using shift_n = ff<0u>; + + using skip_if = void; + }; + + template<> struct cmp_reg : cmp_reg + { + using n = cf, bf<0, 3>>; + using m = bf<3, 4>; + + using skip_if = void; + }; + + template<> struct cmp_reg + { + using n = bf<16, 4>; + using m = bf<0, 4>; + using shift_t = decode_imm_shift_type_thumb; + using shift_n = decode_imm_shift_num_thumb; + + using skip_if = void; + }; + + template<> struct cmp_reg : cmp_reg + { + using shift_t = decode_imm_shift_type_arm; + using shift_n = decode_imm_shift_num_arm; + + using skip_if = void; + }; + + template struct eor_imm; // + + template<> struct eor_imm : and_imm + { + using and_imm::d; + + using skip_if = andf, bf<20, 1>>; + }; + + template<> struct eor_imm : and_imm + { + using and_imm::d; + + using skip_if = andf, bf<20, 1>>; + }; + + template struct eor_reg; // + + template<> struct eor_reg : adc_reg + { + using skip_if = void; + }; + + template<> struct eor_reg : adc_reg + { + using adc_reg::d; + + using skip_if = andf, bf<20, 1>>; + }; + + template<> struct eor_reg : adc_reg + { + using adc_reg::d; + + using skip_if = andf, bf<20, 1>>; + }; + + template struct ldm; // + + template<> struct ldm + { + using n = bf<8, 3>; + using registers = bf<0, 8>; + using wback = ff; // TODO + + using skip_if = void; + }; + + template<> struct ldm + { + using n = bf<16, 4>; + using registers = andf, ff<0xdfffu, 16>>; // TODO + using wback = bf<21, 1>; + + using skip_if = andf>; + }; + + template<> struct ldm : ldm + { + using registers = bf<0, 16>; + + using skip_if = class TODO; + }; + + template struct ldr_imm; // + + template<> struct ldr_imm + { + using t = bf<0, 3>; + using n = bf<3, 3>; + using imm32 = cf, ff<0u, 2>>; + using index = ff; + using add = ff; + using wback = ff; + + using skip_if = void; + }; + + template<> struct ldr_imm : ldr_imm + { + using t = bf<8, 3>; + using n = ff<13u>; + using imm32 = cf, ff<0u, 2>>; + + using skip_if = void; + }; + + template<> struct ldr_imm : ldr_imm + { + using t = bf<12, 4>; + using n = bf<16, 4>; + using imm32 = bf<0, 12>; + + using skip_if = eqcf; + }; + + template<> struct ldr_imm + { + using t = bf<12, 4>; + using n = bf<16, 4>; + using imm32 = bf<0, 8>; + using index = bf<10, 1>; + using add = bf<9, 1>; + using wback = bf<8, 1>; + + using skip_if = orf, orf, 6>, andf, eqcf, 512 + 256 + 4>>>>; + }; + + template<> struct ldr_imm : ldr_imm + { + using imm32 = bf<0, 12>; + using index = bf<24, 1>; + using add = bf<23, 1>; + using wback = orf>, bf<21, 1>>; + + using skip_if = class TODO; + }; + + template struct ldr_lit; // + + template<> struct ldr_lit + { + using t = bf<8, 3>; + using imm32 = cf, ff<0u, 2>>; + using add = ff; + + using skip_if = void; + }; + + template<> struct ldr_lit + { + using t = bf<12, 4>; + using imm32 = bf<0, 12>; + using add = bf<23, 1>; + + using skip_if = void; + }; + + template<> struct ldr_lit : ldr_lit + { + using skip_if = void; + }; + + template struct ldr_reg; // + + template<> struct ldr_reg + { + using t = bf<0, 3>; + using n = bf<3, 3>; + using m = bf<6, 3>; + using index = ff; + using add = ff; + using wback = ff; + using shift_t = ff; + using shift_n = ff<0u>; + + using skip_if = void; + }; + + template<> struct ldr_reg : ldr_reg + { + using t = bf<12, 4>; + using n = bf<16, 4>; + using m = bf<0, 4>; + using shift_n = bf<4, 2>; + + using skip_if = eqcf; + }; + + template<> struct ldr_reg : ldr_reg + { + using index = bf<24, 1>; + using add = bf<23, 1>; + using wback = orf>, bf<21, 1>>; + using shift_t = decode_imm_shift_type_arm; + using shift_n = decode_imm_shift_num_arm; + + using skip_if = class TODO; + }; + + template struct ldrb_imm; // + + template<> struct ldrb_imm : ldr_imm + { + using imm32 = bf<6, 5>; + + using skip_if = void; + }; + + template<> struct ldrb_imm : ldr_imm + { + using ldr_imm::t; + using ldr_imm::n; + + using skip_if = orf, eqcf>; + }; + + template<> struct ldrb_imm : ldr_imm + { + using ldr_imm::t; + using ldr_imm::n; + + using skip_if = orf, eqcf, 4>>, orf, eqcf, 6>>>; + }; + + template<> struct ldrb_imm : ldr_imm + { + using skip_if = class TODO; + }; + + template struct ldrb_reg; // + + template<> struct ldrb_reg : ldr_reg + { + using skip_if = void; + }; + + template<> struct ldrb_reg : ldr_reg + { + using ldr_reg::t; + using ldr_reg::n; + + using skip_if = orf, eqcf>; + }; + + template<> struct ldrb_reg : ldr_reg + { + using skip_if = class TODO; + }; + + template struct ldrd_imm; // + + template<> struct ldrd_imm + { + using t = bf<12, 4>; + using t2 = bf<8, 4>; + using n = bf<16, 4>; + using imm32 = cf, ff<0u, 2>>; + using index = bf<24, 1>; + using add = bf<23, 1>; + using wback = bf<21, 1>; + }; + + template<> struct ldrd_imm : ldrd_imm + { + using t2 = orf, ff<1u, 4>>; // t+1 for even t + using imm32 = cf, bf<0, 4>>; + using wback = orf>, bf<21, 1>>; + }; + + template struct ldrd_lit; // + + template<> struct ldrd_lit + { + using t = bf<12, 4>; + using t2 = bf<8, 4>; + using imm32 = cf, ff<0u, 2>>; + using add = bf<23, 1>; + }; + + template<> struct ldrd_lit : ldrd_lit + { + using t2 = orf, ff<1u, 4>>; // t+1 for even t + using imm32 = cf, bf<0, 4>>; + }; + + template struct ldrh_imm; // + + template<> struct ldrh_imm : ldr_imm + { + using imm32 = cf, ff<0u, 1>>; + }; + + template<> struct ldrh_imm : ldr_imm {}; + template<> struct ldrh_imm : ldr_imm {}; + + template<> struct ldrh_imm : ldr_imm + { + using imm32 = cf, bf<0, 4>>; + }; + + template struct ldrh_reg; // + + template<> struct ldrh_reg : ldr_reg {}; + template<> struct ldrh_reg : ldr_reg {}; + + template<> struct ldrh_reg : ldr_reg + { + using shift_t = ff; // ??? + using shift_n = ff<0u>; + }; + + template struct ldrsb_imm; // + + template<> struct ldrsb_imm : ldr_imm {}; + template<> struct ldrsb_imm : ldr_imm {}; + template<> struct ldrsb_imm : ldrh_imm {}; + + template struct ldrex; // + + template<> struct ldrex + { + using t = bf<12, 4>; + using n = bf<16, 4>; + using imm32 = cf, ff<0u, 2>>; + }; + + template<> struct ldrex : ldrex + { + using imm32 = ff<0u>; // Zero offset + }; + + template struct _shift_imm; // + + template struct _shift_imm + { + using d = bf<0, 3>; + using m = bf<3, 3>; + using set_flags = not_in_it_block; + using shift_n = decode_imm_shift_num, bf<6, 5>>; + }; + + template struct _shift_imm + { + using d = bf<8, 4>; + using m = bf<0, 4>; + using set_flags = from_first>; + using shift_n = decode_imm_shift_num, cf, bf<6, 2>>>; + }; + + template struct _shift_imm : _shift_imm + { + using d = bf<12, 4>; + using shift_n = decode_imm_shift_num, bf<7, 5>>; + }; + + template struct lsl_imm : _shift_imm {}; // + template struct lsr_imm : _shift_imm {}; // + template struct asr_imm : _shift_imm {}; // + + template struct lsl_reg; // + + template<> struct lsl_reg + { + using d = bf<0, 3>; + using n = d; + using m = bf<3, 3>; + using set_flags = not_in_it_block; + }; + + template<> struct lsl_reg + { + using d = bf<8, 4>; + using n = bf<16, 4>; + using m = bf<0, 4>; + using set_flags = from_first>; + }; + + template<> struct lsl_reg : lsl_reg + { + using d = bf<12, 4>; + using n = bf<0, 4>; + using m = bf<8, 4>; + }; + + template struct lsr_reg; // + + template<> struct lsr_reg : lsl_reg {}; + template<> struct lsr_reg : lsl_reg {}; + template<> struct lsr_reg : lsl_reg {}; + + //template struct asr_reg; // + + //template<> struct asr_reg : lsl_reg {}; + //template<> struct asr_reg : lsl_reg {}; + //template<> struct asr_reg : lsl_reg {}; + + template struct mov_imm; // + + template<> struct mov_imm + { + using d = bf<8, 3>; + using set_flags = not_in_it_block; + using imm32 = bf<0, 8>; + using carry = from_second<>; + }; + + template<> struct mov_imm + { + using d = bf<8, 4>; + using set_flags = from_first>; + using imm32 = thumb_expand_imm; + using carry = thumb_expand_imm_c; + }; + + template<> struct mov_imm + { + using d = bf<8, 4>; + using set_flags = from_first>; + using imm32 = cf, imm12i38>; + using carry = from_second<>; + }; + + template<> struct mov_imm + { + using d = bf<12, 4>; + using set_flags = from_first>; + using imm32 = arm_expand_imm; + using carry = arm_expand_imm_c; + }; + + template<> struct mov_imm + { + using d = bf<12, 4>; + using set_flags = from_first>; + using imm32 = cf, bf<0, 12>>; + using carry = from_second<>; + }; + + template struct mov_reg; // + + template<> struct mov_reg + { + using d = cf, bf<0, 3>>; + using m = bf<3, 4>; + using set_flags = from_first>; + }; + + template<> struct mov_reg + { + using d = bf<0, 3>; + using m = bf<3, 3>; + using set_flags = from_first>; + }; + + template<> struct mov_reg + { + using d = bf<8, 4>; + using m = bf<0, 4>; + using set_flags = from_first>; + }; + + template<> struct mov_reg : mov_reg + { + using d = bf<12, 4>; + }; + + template struct movt; // + + template<> struct movt + { + using d = bf<8, 4>; + using imm16 = cf, imm12i38>; + }; + + template<> struct movt + { + using d = bf<12, 4>; + using imm16 = cf, bf<0, 12>>; + }; + + template struct mul; // + + template<> struct mul + { + using d = bf<0, 3>; + using n = bf<3, 3>; + using m = d; + using set_flags = not_in_it_block; + }; + + template<> struct mul + { + using d = bf<8, 4>; + using n = bf<16, 4>; + using m = bf<0, 4>; + using set_flags = from_first>; + }; + + template<> struct mul + { + using d = bf<16, 4>; + using n = bf<0, 4>; + using m = bf<8, 4>; + using set_flags = from_first>; + }; + + template struct mvn_imm; // + + template<> struct mvn_imm : mov_imm {}; + template<> struct mvn_imm : mov_imm {}; + + template struct mvn_reg; // + + template<> struct mvn_reg + { + using d = bf<0, 3>; + using m = bf<3, 3>; + using set_flags = not_in_it_block; + using shift_t = ff; + using shift_n = ff<0u>; + }; + + template<> struct mvn_reg + { + using d = bf<8, 4>; + using m = bf<0, 4>; + using set_flags = from_first>; + using shift_t = decode_imm_shift_type_thumb; + using shift_n = decode_imm_shift_num_thumb; + }; + + template<> struct mvn_reg : mvn_reg + { + using d = bf<12, 4>; + using shift_t = decode_imm_shift_type_arm; + using shift_n = decode_imm_shift_num_arm; + }; + + template struct orr_imm; // + + template<> struct orr_imm : and_imm {}; + template<> struct orr_imm : and_imm {}; + + template struct orr_reg; // + + template<> struct orr_reg : adc_reg {}; + template<> struct orr_reg : adc_reg {}; + template<> struct orr_reg : adc_reg {}; + + template struct pop; // + + template<> struct pop + { + using registers = cf, ff<0u, 7>, bf<0, 8>>; + }; + + template<> struct pop + { + using registers = andf, ff<0xdfffu, 16>>; + }; + + template<> struct pop + { + using registers = shlf, bf<12, 4>>; // 1 << Rt + }; + + template<> struct pop + { + using registers = bf<0, 16>; + }; + + template<> struct pop : pop + { + }; + + template struct push; // + + template<> struct push + { + using registers = cf, ff<0u, 6>, bf<0, 8>>; + }; + + template<> struct push + { + using registers = andf, ff<0x5fffu, 16>>; + }; + + template<> struct push : pop {}; + template<> struct push : pop {}; + template<> struct push : pop {}; + + template struct rev; // + + template<> struct rev + { + using d = bf<0, 3>; + using m = bf<3, 3>; + }; + + template<> struct rev : clz {}; + template<> struct rev : clz {}; + + template struct ror_imm; // + + template<> struct ror_imm : _shift_imm {}; + template<> struct ror_imm : _shift_imm {}; + + template struct ror_reg; // + + template<> struct ror_reg : lsl_reg {}; + template<> struct ror_reg : lsl_reg {}; + template<> struct ror_reg : lsl_reg {}; + + template struct rsb_imm; // + + template<> struct rsb_imm : add_imm + { + using imm32 = ff<0u>; + }; + + template<> struct rsb_imm : add_imm {}; + template<> struct rsb_imm : add_imm {}; + + template struct stm; // + + template<> struct stm : ldm + { + using wback = ff; + }; + + template<> struct stm : ldm + { + using registers = andf, ff<0x5fffu, 16>>; // TODO + }; + + template<> struct stm : ldm {}; + + template struct str_imm; // + + template<> struct str_imm : ldr_imm {}; + template<> struct str_imm : ldr_imm {}; + template<> struct str_imm : ldr_imm {}; + template<> struct str_imm : ldr_imm {}; + template<> struct str_imm : ldr_imm {}; + + template struct str_reg; // + + template<> struct str_reg : ldr_reg {}; + template<> struct str_reg : ldr_reg {}; + template<> struct str_reg : ldr_reg {}; + + template struct strb_imm; // + + template<> struct strb_imm : ldrb_imm {}; + template<> struct strb_imm : ldrb_imm {}; + template<> struct strb_imm : ldrb_imm {}; + template<> struct strb_imm : ldrb_imm {}; + + template struct strb_reg; // + + template<> struct strb_reg : ldrb_reg {}; + template<> struct strb_reg : ldrb_reg {}; + template<> struct strb_reg : ldrb_reg {}; + + template struct strd_imm; // + + template<> struct strd_imm : ldrd_imm {}; + template<> struct strd_imm : ldrd_imm {}; + + template struct strh_imm; // + + template<> struct strh_imm : ldrh_imm {}; + template<> struct strh_imm : ldrh_imm {}; + template<> struct strh_imm : ldrh_imm {}; + template<> struct strh_imm : ldrh_imm {}; + + template struct strh_reg; // + + template<> struct strh_reg : ldrh_reg {}; + template<> struct strh_reg : ldrh_reg {}; + template<> struct strh_reg : ldrh_reg {}; + + template struct strex; // + + template<> struct strex + { + using d = bf<8, 4>; + using t = bf<12, 4>; + using n = bf<16, 4>; + using imm32 = cf, ff<0u, 2>>; + }; + + template<> struct strex + { + using d = bf<12, 4>; + using t = bf<0, 4>; + using n = bf<16, 4>; + using imm32 = ff<0u>; // Zero offset + }; + + template struct sub_imm; // + + template<> struct sub_imm : add_imm {}; + template<> struct sub_imm : add_imm {}; + template<> struct sub_imm : add_imm {}; + template<> struct sub_imm : add_imm {}; + template<> struct sub_imm : add_imm {}; + + template struct sub_reg; // + + template<> struct sub_reg : add_reg {}; + template<> struct sub_reg : add_reg {}; + template<> struct sub_reg : add_reg {}; + + template struct sub_spi; // + + template<> struct sub_spi : add_spi {}; + template<> struct sub_spi : add_spi {}; + template<> struct sub_spi : add_spi {}; + template<> struct sub_spi : add_spi {}; + + template struct tst_imm; // + + template<> struct tst_imm + { + using n = bf<16, 4>; + using imm32 = thumb_expand_imm; + using carry = thumb_expand_imm_c; + }; + + template<> struct tst_imm + { + using n = bf<16, 4>; + using imm32 = arm_expand_imm; + using carry = arm_expand_imm_c; + }; + + template struct umull; // + + template<> struct umull + { + using d0 = bf<12, 4>; + using d1 = bf<8, 4>; + using n = bf<16, 4>; + using m = bf<0, 4>; + using set_flags = from_first>; + }; + + template<> struct umull + { + using d0 = bf<12, 4>; + using d1 = bf<16, 4>; + using n = bf<0, 4>; + using m = bf<8, 4>; + using set_flags = from_first>; + }; + + template struct uxtb; // + + template<> struct uxtb + { + using d = bf<0, 3>; + using m = bf<3, 3>; + using rotation = ff<0u, 5>; + }; + + template<> struct uxtb + { + using d = bf<8, 4>; + using m = bf<0, 4>; + using rotation = cf, ff<0u, 3>>; + }; + + template<> struct uxtb + { + using d = bf<12, 4>; + using m = bf<0, 4>; + using rotation = cf, ff<0u, 3>>; + }; } -static const ARMv7_Instruction g_table_0xf_main[] = -{ - { group_0xf0 }, // 0 0xfbef - { group_0xf1 }, // 1 0xfbef - { group_0xf2 }, // 2 0xfbff - { group_0xf3 }, // 3 0xffff - ARMv7_NULL_OP, // 4 - ARMv7_NULL_OP, // 5 - ARMv7_NULL_OP, // 6 - ARMv7_NULL_OP, // 7 - { group_0xf8 }, // 8 0xfff0 - { group_0xf9 }, // 9 0xfff0 - { group_0xfa }, // A 0xfff0 +// TODO +#define SKIP_IF(cond) [](u32 c) -> bool { return cond; } +#define BF(start, end) ((c << (31 - (end))) >> ((start) + 31 - (end))) +#define BT(pos) ((c >> (pos)) & 1) +// ARMv7 decoder object. D provides function templates. T is function pointer type returned. +template +class arm_decoder +{ + // Fast lookup table for 2-byte Thumb instructions + std::array m_op16_table{}; + + // Fix for std::initializer_list (???) + static inline T fix(T ptr) + { + return ptr; + } + + struct instruction_info + { + u32 mask; + u32 code; + T pointer; + bool(*skip)(u32 code); // TODO (if not nullptr, must be specified yet) + + bool match(u32 op) const + { + return (op & mask) == code && (!skip || !skip(op)); + } + }; + + // Lookup table for 4-byte Thumb instructions (points to the best appropriate position in sorted vector) + std::array::const_iterator, 0x10000> m_op32_table{}; + + std::vector m_op16_list; + std::vector m_op32_list; + std::vector m_arm_list; + +public: + arm_decoder() + { + using namespace arm_code::arm_encoding_alias; + + m_op16_list.assign( + { + { 0xffc0, 0x4140, fix(&D:: template ADC_REG), nullptr }, + { 0xfe00, 0x1c00, fix(&D:: template ADD_IMM), nullptr }, + { 0xf800, 0x3000, fix(&D:: template ADD_IMM), nullptr }, + { 0xfe00, 0x1800, fix(&D:: template ADD_REG), nullptr }, + { 0xff00, 0x4400, fix(&D:: template ADD_REG), SKIP_IF((c & 0x87) == 0x85 || BF(3, 6) == 13) }, + { 0xf800, 0xa800, fix(&D:: template ADD_SPI), nullptr }, + { 0xff80, 0xb000, fix(&D:: template ADD_SPI), nullptr }, + { 0xff78, 0x4468, fix(&D:: template ADD_SPR), nullptr }, + { 0xff87, 0x4485, fix(&D:: template ADD_SPR), SKIP_IF(BF(3, 6) == 13) }, + { 0xf800, 0xa000, fix(&D:: template ADR), nullptr }, + { 0xffc0, 0x4000, fix(&D:: template AND_REG), nullptr }, + { 0xf800, 0x1000, fix(&D:: template ASR_IMM), nullptr }, + { 0xffc0, 0x4100, fix(&D:: template ASR_REG), nullptr }, + { 0xf000, 0xd000, fix(&D:: template B), SKIP_IF(BF(9, 11) == 0x7) }, + { 0xf800, 0xe000, fix(&D:: template B), nullptr }, + { 0xffc0, 0x4380, fix(&D:: template BIC_REG), nullptr }, + { 0xff00, 0xbe00, fix(&D:: template BKPT), nullptr }, + { 0xff80, 0x4780, fix(&D:: template BLX), nullptr }, + { 0xff87, 0x4700, fix(&D:: template BX), nullptr }, + { 0xf500, 0xb100, fix(&D:: template CB_Z), nullptr }, + { 0xffc0, 0x42c0, fix(&D:: template CMN_REG), nullptr }, + { 0xf800, 0x2800, fix(&D:: template CMP_IMM), nullptr }, + { 0xffc0, 0x4280, fix(&D:: template CMP_REG), nullptr }, + { 0xff00, 0x4500, fix(&D:: template CMP_REG), nullptr }, + { 0xffc0, 0x4040, fix(&D:: template EOR_REG), nullptr }, + { 0xff00, 0xbf00, fix(&D:: template IT), SKIP_IF(BF(0, 3) == 0) }, + { 0xf800, 0xc800, fix(&D:: template LDM), nullptr }, + { 0xf800, 0x6800, fix(&D:: template LDR_IMM), nullptr }, + { 0xf800, 0x9800, fix(&D:: template LDR_IMM), nullptr }, + { 0xf800, 0x4800, fix(&D:: template LDR_LIT), nullptr }, + { 0xfe00, 0x5800, fix(&D:: template LDR_REG), nullptr }, + { 0xf800, 0x7800, fix(&D:: template LDRB_IMM) }, + { 0xfe00, 0x5c00, fix(&D:: template LDRB_REG) }, + { 0xf800, 0x8800, fix(&D:: template LDRH_IMM) }, + { 0xfe00, 0x5a00, fix(&D:: template LDRH_REG) }, + { 0xfe00, 0x5600, fix(&D:: template LDRSB_REG) }, + { 0xfe00, 0x5e00, fix(&D:: template LDRSH_REG) }, + { 0xf800, 0x0000, fix(&D:: template LSL_IMM) }, + { 0xffc0, 0x4080, fix(&D:: template LSL_REG) }, + { 0xf800, 0x0800, fix(&D:: template LSR_IMM) }, + { 0xffc0, 0x40c0, fix(&D:: template LSR_REG) }, + { 0xf800, 0x2000, fix(&D:: template MOV_IMM) }, + { 0xff00, 0x4600, fix(&D:: template MOV_REG) }, + { 0xffc0, 0x0000, fix(&D:: template MOV_REG) }, + { 0xffc0, 0x4340, fix(&D:: template MUL) }, + { 0xffc0, 0x43c0, fix(&D:: template MVN_REG) }, + { 0xffff, 0xbf00, fix(&D:: template NOP) }, + { 0xffc0, 0x4300, fix(&D:: template ORR_REG) }, + { 0xfe00, 0xbc00, fix(&D:: template POP) }, + { 0xfe00, 0xb400, fix(&D:: template PUSH) }, + { 0xffc0, 0xba00, fix(&D:: template REV) }, + { 0xffc0, 0xba40, fix(&D:: template REV16) }, + { 0xffc0, 0xbac0, fix(&D:: template REVSH) }, + { 0xffc0, 0x41c0, fix(&D:: template ROR_REG) }, + { 0xffc0, 0x4240, fix(&D:: template RSB_IMM) }, + { 0xffc0, 0x4180, fix(&D:: template SBC_REG) }, + { 0xf800, 0xc000, fix(&D:: template STM) }, + { 0xf800, 0x6000, fix(&D:: template STR_IMM) }, + { 0xf800, 0x9000, fix(&D:: template STR_IMM) }, + { 0xfe00, 0x5000, fix(&D:: template STR_REG) }, + { 0xf800, 0x7000, fix(&D:: template STRB_IMM) }, + { 0xfe00, 0x5400, fix(&D:: template STRB_REG) }, + { 0xf800, 0x8000, fix(&D:: template STRH_IMM) }, + { 0xfe00, 0x5200, fix(&D:: template STRH_REG) }, + { 0xfe00, 0x1e00, fix(&D:: template SUB_IMM) }, + { 0xf800, 0x3800, fix(&D:: template SUB_IMM) }, + { 0xfe00, 0x1a00, fix(&D:: template SUB_REG) }, + { 0xff80, 0xb080, fix(&D:: template SUB_SPI) }, + { 0xff00, 0xdf00, fix(&D:: template SVC) }, + { 0xffc0, 0xb240, fix(&D:: template SXTB) }, + { 0xffc0, 0xb200, fix(&D:: template SXTH) }, + { 0xffc0, 0x4200, fix(&D:: template TST_REG) }, + { 0xffc0, 0xb2c0, fix(&D:: template UXTB) }, + { 0xffc0, 0xb280, fix(&D:: template UXTH) }, + { 0xffff, 0xbf20, fix(&D:: template WFE) }, + { 0xffff, 0xbf30, fix(&D:: template WFI) }, + { 0xffff, 0xbf10, fix(&D:: template YIELD) }, + }); + + m_op32_list.assign( + { + { 0xffff0000, 0xf8700000, fix(&D:: template HACK), nullptr }, // "Undefined" Thumb opcode used + { 0xfbe08000, 0xf1400000, fix(&D:: template ADC_IMM), nullptr }, + { 0xffe08000, 0xeb400000, fix(&D:: template ADC_REG), nullptr }, + { 0xfbe08000, 0xf1000000, fix(&D:: template ADD_IMM), SKIP_IF((BF(8, 11) == 15 && BT(20)) || BF(16, 19) == 13) }, + { 0xfbf08000, 0xf2000000, fix(&D:: template ADD_IMM), SKIP_IF((BF(16, 19) & 13) == 13) }, + { 0xffe08000, 0xeb000000, fix(&D:: template ADD_REG), SKIP_IF((BF(8, 11) == 15 && BT(20)) || BF(16, 19) == 13) }, + { 0xfbef8000, 0xf10d0000, fix(&D:: template ADD_SPI), SKIP_IF(BF(8, 11) == 15 && BT(20)) }, + { 0xfbff8000, 0xf20d0000, fix(&D:: template ADD_SPI), nullptr }, + { 0xffef8000, 0xeb0d0000, fix(&D:: template ADD_SPR), nullptr }, + { 0xfbff8000, 0xf2af0000, fix(&D:: template ADR), nullptr }, + { 0xfbff8000, 0xf20f0000, fix(&D:: template ADR), nullptr }, + { 0xfbe08000, 0xf0000000, fix(&D:: template AND_IMM), SKIP_IF(BF(8, 11) == 15 && BT(20)) }, + { 0xffe08000, 0xea000000, fix(&D:: template AND_REG), SKIP_IF(BF(8, 11) == 15 && BT(20)) }, + { 0xffef8030, 0xea4f0020, fix(&D:: template ASR_IMM), nullptr }, + { 0xffe0f0f0, 0xfa40f000, fix(&D:: template ASR_REG), nullptr }, + { 0xf800d000, 0xf0008000, fix(&D:: template B), SKIP_IF(BF(23, 25) == 0x7) }, + { 0xf800d000, 0xf0009000, fix(&D:: template B), nullptr }, + { 0xffff8020, 0xf36f0000, fix(&D:: template BFC), nullptr }, + { 0xfff08020, 0xf3600000, fix(&D:: template BFI), SKIP_IF(BF(16, 19) == 15) }, + { 0xfbe08000, 0xf0200000, fix(&D:: template BIC_IMM), nullptr }, + { 0xffe08000, 0xea200000, fix(&D:: template BIC_REG), nullptr }, + { 0xf800d000, 0xf000d000, fix(&D:: template BL), nullptr }, + { 0xf800c001, 0xf000c000, fix(&D:: template BL), nullptr }, + { 0xfff0f0f0, 0xfab0f080, fix(&D:: template CLZ), nullptr }, + { 0xfbf08f00, 0xf1100f00, fix(&D:: template CMN_IMM), nullptr }, + { 0xfff08f00, 0xeb100f00, fix(&D:: template CMN_REG), nullptr }, + { 0xfbf08f00, 0xf1b00f00, fix(&D:: template CMP_IMM), nullptr }, + { 0xfff08f00, 0xebb00f00, fix(&D:: template CMP_REG), nullptr }, + { 0xfffffff0, 0xf3af80f0, fix(&D:: template DBG), nullptr }, + { 0xfffffff0, 0xf3bf8f50, fix(&D:: template DMB), nullptr }, + { 0xfffffff0, 0xf3bf8f40, fix(&D:: template DSB), nullptr }, + { 0xfbe08000, 0xf0800000, fix(&D:: template EOR_IMM), SKIP_IF(BF(8, 11) == 15 && BT(20)) }, + { 0xffe08000, 0xea800000, fix(&D:: template EOR_REG), SKIP_IF(BF(8, 11) == 15 && BT(20)) }, + { 0xffd02000, 0xe8900000, fix(&D:: template LDM), SKIP_IF(BT(21) && BF(16, 19) == 13) }, + { 0xffd02000, 0xe9100000, fix(&D:: template LDMDB), nullptr }, + { 0xfff00000, 0xf8d00000, fix(&D:: template LDR_IMM), SKIP_IF(BF(16, 19) == 15) }, + { 0xfff00800, 0xf8500800, fix(&D:: template LDR_IMM), SKIP_IF(BF(16, 19) == 15 || BF(8, 10) == 6 || (c & 0xf07ff) == 0xd0304 || (c & 0x500) == 0) }, + { 0xff7f0000, 0xf85f0000, fix(&D:: template LDR_LIT), nullptr }, + { 0xfff00fc0, 0xf8500000, fix(&D:: template LDR_REG), SKIP_IF(BF(16, 19) == 15) }, + { 0xfff00000, 0xf8900000, fix(&D:: template LDRB_IMM) }, + { 0xfff00800, 0xf8100800, fix(&D:: template LDRB_IMM) }, + { 0xff7f0000, 0xf81f0000, fix(&D:: template LDRB_LIT) }, + { 0xfff00fc0, 0xf8100000, fix(&D:: template LDRB_REG) }, + { 0xfe500000, 0xe8500000, fix(&D:: template LDRD_IMM), SKIP_IF((!BT(21) && !BT(24)) || BF(16, 19) == 15) }, + { 0xfe7f0000, 0xe85f0000, fix(&D:: template LDRD_LIT) }, + { 0xfff00f00, 0xe8500f00, fix(&D:: template LDREX) }, + { 0xfff00fff, 0xe8d00f4f, fix(&D:: template LDREXB) }, + { 0xfff000ff, 0xe8d0007f, fix(&D:: template LDREXD) }, + { 0xfff00fff, 0xe8d00f5f, fix(&D:: template LDREXH) }, + { 0xfff00000, 0xf8b00000, fix(&D:: template LDRH_IMM) }, + { 0xfff00800, 0xf8300800, fix(&D:: template LDRH_IMM) }, + { 0xff7f0000, 0xf83f0000, fix(&D:: template LDRH_LIT) }, + { 0xfff00fc0, 0xf8300000, fix(&D:: template LDRH_REG) }, + { 0xfff00000, 0xf9900000, fix(&D:: template LDRSB_IMM) }, + { 0xfff00800, 0xf9100800, fix(&D:: template LDRSB_IMM) }, + { 0xff7f0000, 0xf91f0000, fix(&D:: template LDRSB_LIT) }, + { 0xfff00fc0, 0xf9100000, fix(&D:: template LDRSB_REG) }, + { 0xfff00000, 0xf9b00000, fix(&D:: template LDRSH_IMM) }, + { 0xfff00800, 0xf9300800, fix(&D:: template LDRSH_IMM) }, + { 0xff7f0000, 0xf93f0000, fix(&D:: template LDRSH_LIT) }, + { 0xfff00fc0, 0xf9300000, fix(&D:: template LDRSH_REG) }, + { 0xffef8030, 0xea4f0000, fix(&D:: template LSL_IMM) }, + { 0xffe0f0f0, 0xfa00f000, fix(&D:: template LSL_REG) }, + { 0xffef8030, 0xea4f0010, fix(&D:: template LSR_IMM) }, + { 0xffe0f0f0, 0xfa20f000, fix(&D:: template LSR_REG) }, + { 0xfff000f0, 0xfb000000, fix(&D:: template MLA), SKIP_IF(BF(12, 15) == 15) }, + { 0xfff000f0, 0xfb000010, fix(&D:: template MLS) }, + { 0xfbef8000, 0xf04f0000, fix(&D:: template MOV_IMM) }, + { 0xfbf08000, 0xf2400000, fix(&D:: template MOV_IMM) }, + { 0xffeff0f0, 0xea4f0000, fix(&D:: template MOV_REG) }, + { 0xfbf08000, 0xf2c00000, fix(&D:: template MOVT) }, + { 0xff100010, 0xee100010, fix(&D:: template MRC_) }, + { 0xff100010, 0xfe100010, fix(&D:: template MRC_) }, + { 0xfffff0ff, 0xf3ef8000, fix(&D:: template MRS) }, + { 0xfff0f3ff, 0xf3808000, fix(&D:: template MSR_REG) }, + { 0xfff0f0f0, 0xfb00f000, fix(&D:: template MUL) }, + { 0xfbef8000, 0xf06f0000, fix(&D:: template MVN_IMM) }, + { 0xffef8000, 0xea6f0000, fix(&D:: template MVN_REG) }, + { 0xffffffff, 0xf3af8000, fix(&D:: template NOP) }, + { 0xfbe08000, 0xf0600000, fix(&D:: template ORN_IMM) }, + { 0xffe08000, 0xea600000, fix(&D:: template ORN_REG) }, + { 0xfbe08000, 0xf0400000, fix(&D:: template ORR_IMM) }, + { 0xffe08000, 0xea400000, fix(&D:: template ORR_REG), SKIP_IF(BF(16, 19) == 15) }, + { 0xfff08010, 0xeac00000, fix(&D:: template PKH) }, + { 0xffff0000, 0xe8bd0000, fix(&D:: template POP) }, + { 0xffff0fff, 0xf85d0b04, fix(&D:: template POP) }, + { 0xffff0000, 0xe92d0000, fix(&D:: template PUSH) }, // had an error in arch ref + { 0xffff0fff, 0xf84d0d04, fix(&D:: template PUSH) }, + { 0xfff0f0f0, 0xfa80f080, fix(&D:: template QADD) }, + { 0xfff0f0f0, 0xfa90f010, fix(&D:: template QADD16) }, + { 0xfff0f0f0, 0xfa80f010, fix(&D:: template QADD8) }, + { 0xfff0f0f0, 0xfaa0f010, fix(&D:: template QASX) }, + { 0xfff0f0f0, 0xfa80f090, fix(&D:: template QDADD) }, + { 0xfff0f0f0, 0xfa80f0b0, fix(&D:: template QDSUB) }, + { 0xfff0f0f0, 0xfae0f010, fix(&D:: template QSAX) }, + { 0xfff0f0f0, 0xfa80f0a0, fix(&D:: template QSUB) }, + { 0xfff0f0f0, 0xfad0f010, fix(&D:: template QSUB16) }, + { 0xfff0f0f0, 0xfac0f010, fix(&D:: template QSUB8) }, + { 0xfff0f0f0, 0xfa90f0a0, fix(&D:: template RBIT) }, + { 0xfff0f0f0, 0xfa90f080, fix(&D:: template REV) }, + { 0xfff0f0f0, 0xfa90f090, fix(&D:: template REV16) }, + { 0xfff0f0f0, 0xfa90f0b0, fix(&D:: template REVSH) }, + { 0xffef8030, 0xea4f0030, fix(&D:: template ROR_IMM) }, + { 0xffe0f0f0, 0xfa60f000, fix(&D:: template ROR_REG) }, + { 0xffeff0f0, 0xea4f0030, fix(&D:: template RRX) }, + { 0xfbe08000, 0xf1c00000, fix(&D:: template RSB_IMM) }, + { 0xffe08000, 0xebc00000, fix(&D:: template RSB_REG) }, + { 0xfff0f0f0, 0xfa90f000, fix(&D:: template SADD16) }, + { 0xfff0f0f0, 0xfa80f000, fix(&D:: template SADD8) }, + { 0xfff0f0f0, 0xfaa0f000, fix(&D:: template SASX) }, + { 0xfbe08000, 0xf1600000, fix(&D:: template SBC_IMM) }, + { 0xffe08000, 0xeb600000, fix(&D:: template SBC_REG) }, + { 0xfff08020, 0xf3400000, fix(&D:: template SBFX) }, + { 0xfff0f0f0, 0xfb90f0f0, fix(&D:: template SDIV) }, // ??? + { 0xfff0f0f0, 0xfaa0f080, fix(&D:: template SEL) }, + { 0xfff0f0f0, 0xfa90f020, fix(&D:: template SHADD16) }, + { 0xfff0f0f0, 0xfa80f020, fix(&D:: template SHADD8) }, + { 0xfff0f0f0, 0xfaa0f020, fix(&D:: template SHASX) }, + { 0xfff0f0f0, 0xfae0f020, fix(&D:: template SHSAX) }, + { 0xfff0f0f0, 0xfad0f020, fix(&D:: template SHSUB16) }, + { 0xfff0f0f0, 0xfac0f020, fix(&D:: template SHSUB8) }, + { 0xfff000c0, 0xfb100000, fix(&D:: template SMLA__) }, + { 0xfff000e0, 0xfb200000, fix(&D:: template SMLAD) }, + { 0xfff000f0, 0xfbc00000, fix(&D:: template SMLAL) }, + { 0xfff000c0, 0xfbc00080, fix(&D:: template SMLAL__) }, + { 0xfff000e0, 0xfbc000c0, fix(&D:: template SMLALD) }, + { 0xfff000e0, 0xfb300000, fix(&D:: template SMLAW_) }, + { 0xfff000e0, 0xfb400000, fix(&D:: template SMLSD) }, + { 0xfff000e0, 0xfbd000c0, fix(&D:: template SMLSLD) }, + { 0xfff000e0, 0xfb500000, fix(&D:: template SMMLA) }, + { 0xfff000e0, 0xfb600000, fix(&D:: template SMMLS) }, + { 0xfff0f0e0, 0xfb50f000, fix(&D:: template SMMUL) }, + { 0xfff0f0e0, 0xfb20f000, fix(&D:: template SMUAD) }, + { 0xfff0f0c0, 0xfb10f000, fix(&D:: template SMUL__) }, + { 0xfff000f0, 0xfb800000, fix(&D:: template SMULL) }, + { 0xfff0f0e0, 0xfb30f000, fix(&D:: template SMULW_) }, + { 0xfff0f0e0, 0xfb40f000, fix(&D:: template SMUSD) }, + { 0xffd08020, 0xf3000000, fix(&D:: template SSAT) }, + { 0xfff0f0e0, 0xf3200000, fix(&D:: template SSAT16) }, + { 0xfff0f0f0, 0xfae0f000, fix(&D:: template SSAX) }, + { 0xfff0f0f0, 0xfad0f000, fix(&D:: template SSUB16) }, + { 0xfff0f0f0, 0xfac0f000, fix(&D:: template SSUB8) }, + { 0xffd0a000, 0xe8800000, fix(&D:: template STM) }, + { 0xffd0a000, 0xe9000000, fix(&D:: template STMDB) }, + { 0xfff00000, 0xf8c00000, fix(&D:: template STR_IMM) }, + { 0xfff00800, 0xf8400800, fix(&D:: template STR_IMM) }, + { 0xfff00fc0, 0xf8400000, fix(&D:: template STR_REG) }, + { 0xfff00000, 0xf8800000, fix(&D:: template STRB_IMM) }, + { 0xfff00800, 0xf8000800, fix(&D:: template STRB_IMM) }, + { 0xfff00fc0, 0xf8000000, fix(&D:: template STRB_REG) }, + { 0xfe500000, 0xe8400000, fix(&D:: template STRD_IMM), SKIP_IF(!BT(21) && !BT(24)) }, + { 0xfff00000, 0xe8400000, fix(&D:: template STREX) }, + { 0xfff00ff0, 0xe8c00f40, fix(&D:: template STREXB) }, + { 0xfff000f0, 0xe8c00070, fix(&D:: template STREXD) }, + { 0xfff00ff0, 0xe8c00f50, fix(&D:: template STREXH) }, + { 0xfff00000, 0xf8a00000, fix(&D:: template STRH_IMM) }, + { 0xfff00800, 0xf8200800, fix(&D:: template STRH_IMM) }, + { 0xfff00fc0, 0xf8200000, fix(&D:: template STRH_REG) }, + { 0xfbe08000, 0xf1a00000, fix(&D:: template SUB_IMM), SKIP_IF((BF(8, 11) == 15 && BT(20)) || BF(16, 19) == 13) }, + { 0xfbf08000, 0xf2a00000, fix(&D:: template SUB_IMM) }, + { 0xffe08000, 0xeba00000, fix(&D:: template SUB_REG), SKIP_IF((BF(8, 11) == 15 && BT(20)) || BF(16, 19) == 13) }, + { 0xfbef8000, 0xf1ad0000, fix(&D:: template SUB_SPI) }, + { 0xfbff8000, 0xf2ad0000, fix(&D:: template SUB_SPI) }, + { 0xffef8000, 0xebad0000, fix(&D:: template SUB_SPR) }, + { 0xfff0f0c0, 0xfa40f080, fix(&D:: template SXTAB) }, + { 0xfff0f0c0, 0xfa20f080, fix(&D:: template SXTAB16) }, + { 0xfff0f0c0, 0xfa00f080, fix(&D:: template SXTAH) }, + { 0xfffff0c0, 0xfa4ff080, fix(&D:: template SXTB) }, + { 0xfffff0c0, 0xfa2ff080, fix(&D:: template SXTB16) }, + { 0xfffff0c0, 0xfa0ff080, fix(&D:: template SXTH) }, + { 0xfff0ffe0, 0xe8d0f000, fix(&D:: template TB_) }, + { 0xfbf08f00, 0xf0900f00, fix(&D:: template TEQ_IMM) }, + { 0xfff08f00, 0xea900f00, fix(&D:: template TEQ_REG) }, + { 0xfbf08f00, 0xf0100f00, fix(&D:: template TST_IMM) }, + { 0xfff08f00, 0xea100f00, fix(&D:: template TST_REG) }, + { 0xfff0f0f0, 0xfa90f040, fix(&D:: template UADD16) }, + { 0xfff0f0f0, 0xfa80f040, fix(&D:: template UADD8) }, + { 0xfff0f0f0, 0xfaa0f040, fix(&D:: template UASX) }, + { 0xfff08020, 0xf3c00000, fix(&D:: template UBFX) }, + { 0xfff0f0f0, 0xfbb0f0f0, fix(&D:: template UDIV) }, // ??? + { 0xfff0f0f0, 0xfa90f060, fix(&D:: template UHADD16) }, + { 0xfff0f0f0, 0xfa80f060, fix(&D:: template UHADD8) }, + { 0xfff0f0f0, 0xfaa0f060, fix(&D:: template UHASX) }, + { 0xfff0f0f0, 0xfae0f060, fix(&D:: template UHSAX) }, + { 0xfff0f0f0, 0xfad0f060, fix(&D:: template UHSUB16) }, + { 0xfff0f0f0, 0xfac0f060, fix(&D:: template UHSUB8) }, + { 0xfff000f0, 0xfbe00060, fix(&D:: template UMAAL) }, + { 0xfff000f0, 0xfbe00000, fix(&D:: template UMLAL) }, + { 0xfff000f0, 0xfba00000, fix(&D:: template UMULL) }, + { 0xfff0f0f0, 0xfa90f050, fix(&D:: template UQADD16) }, + { 0xfff0f0f0, 0xfa80f050, fix(&D:: template UQADD8) }, + { 0xfff0f0f0, 0xfaa0f050, fix(&D:: template UQASX) }, + { 0xfff0f0f0, 0xfae0f050, fix(&D:: template UQSAX) }, + { 0xfff0f0f0, 0xfad0f050, fix(&D:: template UQSUB16) }, + { 0xfff0f0f0, 0xfac0f050, fix(&D:: template UQSUB8) }, + { 0xfff0f0f0, 0xfb70f000, fix(&D:: template USAD8) }, + { 0xfff000f0, 0xfb700000, fix(&D:: template USADA8) }, + { 0xffd08020, 0xf3800000, fix(&D:: template USAT) }, + { 0xfff0f0e0, 0xf3a00000, fix(&D:: template USAT16) }, + { 0xfff0f0f0, 0xfae0f040, fix(&D:: template USAX) }, + { 0xfff0f0f0, 0xfad0f040, fix(&D:: template USUB16) }, + { 0xfff0f0f0, 0xfac0f040, fix(&D:: template USUB8) }, + { 0xfff0f0c0, 0xfa50f080, fix(&D:: template UXTAB), SKIP_IF(BF(16, 19) == 15) }, + { 0xfff0f0c0, 0xfa30f080, fix(&D:: template UXTAB16) }, + { 0xfff0f0c0, 0xfa10f080, fix(&D:: template UXTAH) }, + { 0xfffff0c0, 0xfa5ff080, fix(&D:: template UXTB) }, + { 0xfffff0c0, 0xfa3ff080, fix(&D:: template UXTB16) }, + { 0xfffff0c0, 0xfa1ff080, fix(&D:: template UXTH) }, + { 0xef800f10, 0xef000710, fix(&D:: template VABA_) }, + { 0xef800f50, 0xef800500, fix(&D:: template VABA_) }, + { 0xef800f10, 0xef000700, fix(&D:: template VABD_) }, + { 0xef800f50, 0xef800700, fix(&D:: template VABD_) }, + { 0xffa00f10, 0xff200d00, fix(&D:: template VABD_FP) }, + { 0xffb30b90, 0xffb10300, fix(&D:: template VABS) }, + { 0xffbf0ed0, 0xeeb00ac0, fix(&D:: template VABS) }, + { 0xff800f10, 0xff000e10, fix(&D:: template VAC__) }, + { 0xff800f10, 0xef000800, fix(&D:: template VADD) }, + { 0xffa00f10, 0xef000d00, fix(&D:: template VADD_FP) }, + { 0xffb00e50, 0xee300a00, fix(&D:: template VADD_FP) }, + { 0xff800f50, 0xef800400, fix(&D:: template VADDHN) }, + { 0xef800e50, 0xef800000, fix(&D:: template VADD_) }, + { 0xffb00f10, 0xef000110, fix(&D:: template VAND) }, + { 0xefb800b0, 0xef800030, fix(&D:: template VBIC_IMM) }, + { 0xffb00f10, 0xef100110, fix(&D:: template VBIC_REG) }, + { 0xff800f10, 0xff000110, fix(&D:: template VB__) }, + { 0xff800f10, 0xff000810, fix(&D:: template VCEQ_REG) }, + { 0xffa00f10, 0xef000e00, fix(&D:: template VCEQ_REG) }, + { 0xffb30b90, 0xffb10100, fix(&D:: template VCEQ_ZERO) }, + { 0xef800f10, 0xef000310, fix(&D:: template VCGE_REG) }, + { 0xffa00f10, 0xff000e00, fix(&D:: template VCGE_REG) }, + { 0xffb30b90, 0xffb10080, fix(&D:: template VCGE_ZERO) }, + { 0xef800f10, 0xef000300, fix(&D:: template VCGT_REG) }, + { 0xffa00f10, 0xff200e00, fix(&D:: template VCGT_REG) }, + { 0xffb30b90, 0xffb10000, fix(&D:: template VCGT_ZERO) }, + { 0xffb30b90, 0xffb10180, fix(&D:: template VCLE_ZERO) }, + { 0xffb30f90, 0xffb00400, fix(&D:: template VCLS) }, + { 0xffb30b90, 0xffb10200, fix(&D:: template VCLT_ZERO) }, + { 0xffb30f90, 0xffb00480, fix(&D:: template VCLZ) }, + { 0xffbf0e50, 0xeeb40a40, fix(&D:: template VCMP_) }, + { 0xffbf0e7f, 0xeeb50a40, fix(&D:: template VCMP_) }, + { 0xffb30f90, 0xffb00500, fix(&D:: template VCNT) }, + { 0xffb30e10, 0xffb30600, fix(&D:: template VCVT_FIA) }, + { 0xffb80e50, 0xeeb80a40, fix(&D:: template VCVT_FIF) }, + { 0xef800e90, 0xef800e10, fix(&D:: template VCVT_FFA) }, + { 0xffba0e50, 0xeeba0a40, fix(&D:: template VCVT_FFF) }, + { 0xffbf0ed0, 0xeeb70ac0, fix(&D:: template VCVT_DF) }, + { 0xffb30ed0, 0xffb20600, fix(&D:: template VCVT_HFA) }, + { 0xffbe0f50, 0xeeb20a40, fix(&D:: template VCVT_HFF) }, + { 0xffb00e50, 0xee800a00, fix(&D:: template VDIV) }, + { 0xffb00f90, 0xffb00c00, fix(&D:: template VDUP_S) }, + { 0xff900f5f, 0xee800b10, fix(&D:: template VDUP_R) }, + { 0xffb00f10, 0xff000110, fix(&D:: template VEOR) }, + { 0xffb00010, 0xefb00000, fix(&D:: template VEXT) }, + { 0xef800b10, 0xef000000, fix(&D:: template VHADDSUB) }, + { 0xffb00000, 0xf9200000, fix(&D:: template VLD__MS) }, // VLD1, VLD2, VLD3, VLD4 + { 0xffb00f00, 0xf9a00c00, fix(&D:: template VLD1_SAL) }, + { 0xffb00300, 0xf9a00000, fix(&D:: template VLD1_SL) }, + { 0xffb00f00, 0xf9a00d00, fix(&D:: template VLD2_SAL) }, + { 0xffb00300, 0xf9a00100, fix(&D:: template VLD2_SL) }, + { 0xffb00f00, 0xf9a00e00, fix(&D:: template VLD3_SAL) }, + { 0xffb00300, 0xf9a00200, fix(&D:: template VLD3_SL) }, + { 0xffb00f00, 0xf9a00f00, fix(&D:: template VLD4_SAL) }, + { 0xffb00300, 0xf9a00300, fix(&D:: template VLD4_SL) }, + { 0xfe100f00, 0xec100b00, fix(&D:: template VLDM) }, + { 0xfe100f00, 0xec100a00, fix(&D:: template VLDM) }, + { 0xff300f00, 0xed100b00, fix(&D:: template VLDR) }, + { 0xff300f00, 0xed100a00, fix(&D:: template VLDR) }, + { 0xef800f00, 0xef000600, fix(&D:: template VMAXMIN) }, + { 0xff800f10, 0xef000f00, fix(&D:: template VMAXMIN_FP) }, + { 0xef800f10, 0xef000900, fix(&D:: template VML__) }, + { 0xef800d50, 0xef800800, fix(&D:: template VML__) }, + { 0xff800f10, 0xef000d10, fix(&D:: template VML__FP) }, + { 0xffb00e10, 0xee000a00, fix(&D:: template VML__FP) }, + { 0xef800a50, 0xef800040, fix(&D:: template VML__S) }, + { 0xef800b50, 0xef800240, fix(&D:: template VML__S) }, + { 0xefb80090, 0xef800010, fix(&D:: template VMOV_IMM) }, + { 0xffb00ef0, 0xeeb00a00, fix(&D:: template VMOV_IMM) }, + { 0xffb00f10, 0xef200110, fix(&D:: template VMOV_REG) }, + { 0xffbf0ed0, 0xeeb00a40, fix(&D:: template VMOV_REG) }, + { 0xff900f1f, 0xee000b10, fix(&D:: template VMOV_RS) }, + { 0xff100f1f, 0xee100b10, fix(&D:: template VMOV_SR) }, + { 0xffe00f7f, 0xee000a10, fix(&D:: template VMOV_RF) }, + { 0xffe00fd0, 0xec400a10, fix(&D:: template VMOV_2RF) }, + { 0xffe00fd0, 0xec400b10, fix(&D:: template VMOV_2RD) }, + { 0xef870fd0, 0xef800a10, fix(&D:: template VMOVL) }, + { 0xffb30fd0, 0xffb20200, fix(&D:: template VMOVN) }, + { 0xffff0fff, 0xeef10a10, fix(&D:: template VMRS) }, + { 0xffff0fff, 0xeee10a10, fix(&D:: template VMSR) }, + { 0xef800f10, 0xef000910, fix(&D:: template VMUL_) }, + { 0xef800d50, 0xef800c00, fix(&D:: template VMUL_) }, + { 0xffa00f10, 0xff000d10, fix(&D:: template VMUL_FP) }, + { 0xffb00e50, 0xee200a00, fix(&D:: template VMUL_FP) }, + { 0xef800e50, 0xef800840, fix(&D:: template VMUL_S) }, + { 0xef800f50, 0xef800a40, fix(&D:: template VMUL_S) }, + { 0xefb800b0, 0xef800030, fix(&D:: template VMVN_IMM) }, + { 0xffb30f90, 0xffb00580, fix(&D:: template VMVN_REG) }, + { 0xffb30b90, 0xffb10380, fix(&D:: template VNEG) }, + { 0xffbf0ed0, 0xeeb10a40, fix(&D:: template VNEG) }, + { 0xffb00e10, 0xee100a00, fix(&D:: template VNM__) }, + { 0xffb00e50, 0xee200a40, fix(&D:: template VNM__) }, + { 0xffb00f10, 0xef300110, fix(&D:: template VORN_REG) }, + { 0xefb800b0, 0xef800010, fix(&D:: template VORR_IMM) }, + { 0xffb00f10, 0xef200110, fix(&D:: template VORR_REG) }, + { 0xffb30f10, 0xffb00600, fix(&D:: template VPADAL) }, + { 0xff800f10, 0xef000b10, fix(&D:: template VPADD) }, + { 0xffa00f10, 0xff000d00, fix(&D:: template VPADD_FP) }, + { 0xffb30f10, 0xffb00200, fix(&D:: template VPADDL) }, + { 0xef800f00, 0xef000a00, fix(&D:: template VPMAXMIN) }, + { 0xff800f10, 0xff000f00, fix(&D:: template VPMAXMIN_FP) }, + { 0xffbf0f00, 0xecbd0b00, fix(&D:: template VPOP) }, + { 0xffbf0f00, 0xecbd0a00, fix(&D:: template VPOP) }, + { 0xffbf0f00, 0xed2d0b00, fix(&D:: template VPUSH) }, + { 0xffbf0f00, 0xed2d0a00, fix(&D:: template VPUSH) }, + { 0xffb30f90, 0xffb00700, fix(&D:: template VQABS) }, + { 0xef800f10, 0xef000010, fix(&D:: template VQADD) }, + { 0xff800d50, 0xef800900, fix(&D:: template VQDML_L) }, + { 0xff800b50, 0xef800340, fix(&D:: template VQDML_L) }, + { 0xff800f10, 0xef000b00, fix(&D:: template VQDMULH) }, + { 0xef800f50, 0xef800c40, fix(&D:: template VQDMULH) }, + { 0xff800f50, 0xef800d00, fix(&D:: template VQDMULL) }, + { 0xff800f50, 0xef800b40, fix(&D:: template VQDMULL) }, + { 0xffb30f10, 0xffb20200, fix(&D:: template VQMOV_N) }, + { 0xffb30f90, 0xffb00780, fix(&D:: template VQNEG) }, + { 0xff800f10, 0xff000b00, fix(&D:: template VQRDMULH) }, + { 0xef800f50, 0xef800d40, fix(&D:: template VQRDMULH) }, + { 0xef800f10, 0xef000510, fix(&D:: template VQRSHL) }, + { 0xef800ed0, 0xef800850, fix(&D:: template VQRSHR_N) }, + { 0xef800f10, 0xef000410, fix(&D:: template VQSHL_REG) }, + { 0xef800e10, 0xef800610, fix(&D:: template VQSHL_IMM) }, + { 0xef800ed0, 0xef800810, fix(&D:: template VQSHR_N) }, + { 0xef800f10, 0xef000210, fix(&D:: template VQSUB) }, + { 0xff800f50, 0xff800400, fix(&D:: template VRADDHN) }, + { 0xffb30e90, 0xffb30400, fix(&D:: template VRECPE) }, + { 0xffa00f10, 0xef000f10, fix(&D:: template VRECPS) }, + { 0xffb30e10, 0xffb00000, fix(&D:: template VREV__) }, + { 0xef800f10, 0xef000100, fix(&D:: template VRHADD) }, + { 0xef800f10, 0xef000500, fix(&D:: template VRSHL) }, + { 0xef800f10, 0xef800210, fix(&D:: template VRSHR) }, + { 0xff800fd0, 0xef800850, fix(&D:: template VRSHRN) }, + { 0xffb30e90, 0xffb30480, fix(&D:: template VRSQRTE) }, + { 0xffa00f10, 0xef200f10, fix(&D:: template VRSQRTS) }, + { 0xef800f10, 0xef800310, fix(&D:: template VRSRA) }, + { 0xff800f50, 0xff800600, fix(&D:: template VRSUBHN) }, + { 0xff800f10, 0xef800510, fix(&D:: template VSHL_IMM) }, + { 0xef800f10, 0xef000400, fix(&D:: template VSHL_REG) }, + { 0xef800fd0, 0xef800a10, fix(&D:: template VSHLL) }, + { 0xffb30fd0, 0xffb20300, fix(&D:: template VSHLL) }, + { 0xef800f10, 0xef800010, fix(&D:: template VSHR) }, + { 0xff800fd0, 0xef800810, fix(&D:: template VSHRN) }, + { 0xff800f10, 0xff800510, fix(&D:: template VSLI) }, + { 0xffbf0ed0, 0xeeb10ac0, fix(&D:: template VSQRT) }, + { 0xef800f10, 0xef800110, fix(&D:: template VSRA) }, + { 0xff800f10, 0xff800410, fix(&D:: template VSRI) }, + { 0xffb00000, 0xf9000000, fix(&D:: template VST__MS) }, // VST1, VST2, VST3, VST4 + { 0xffb00300, 0xf9800000, fix(&D:: template VST1_SL) }, + { 0xffb00300, 0xf9800100, fix(&D:: template VST2_SL) }, + { 0xffb00300, 0xf9800200, fix(&D:: template VST3_SL) }, + { 0xffb00300, 0xf9800300, fix(&D:: template VST4_SL) }, + { 0xfe100f00, 0xec000b00, fix(&D:: template VSTM) }, + { 0xfe100f00, 0xec000a00, fix(&D:: template VSTM) }, + { 0xff300f00, 0xed000b00, fix(&D:: template VSTR) }, + { 0xff300f00, 0xed000a00, fix(&D:: template VSTR) }, + { 0xff800f10, 0xff000800, fix(&D:: template VSUB) }, + { 0xffa00f10, 0xef200d00, fix(&D:: template VSUB_FP) }, + { 0xffb00e50, 0xee300a40, fix(&D:: template VSUB_FP) }, + { 0xff800f50, 0xef800600, fix(&D:: template VSUBHN) }, + { 0xef800e50, 0xef800200, fix(&D:: template VSUB_) }, + { 0xffb30f90, 0xffb20000, fix(&D:: template VSWP) }, + { 0xffb00c10, 0xffb00800, fix(&D:: template VTB_) }, + { 0xffb30f90, 0xffb20080, fix(&D:: template VTRN) }, + { 0xff800f10, 0xef000810, fix(&D:: template VTST) }, + { 0xffb30f90, 0xffb20100, fix(&D:: template VUZP) }, + { 0xffb30f90, 0xffb20180, fix(&D:: template VZIP) }, + { 0xffffffff, 0xf3af8002, fix(&D:: template WFE) }, + { 0xffffffff, 0xf3af8003, fix(&D:: template WFI) }, + { 0xffffffff, 0xf3af8001, fix(&D:: template YIELD) }, + }); + + m_arm_list.assign( + { + { 0x0ff000f0, 0x00700090, fix(&D:: template HACK), nullptr }, // "Undefined" ARM opcode used + { 0x0ffffff0, 0x012fff10, fix(&D:: template BX), nullptr }, + + { 0x0fe00000, 0x02a00000, fix(&D:: template ADC_IMM) }, + { 0x0fe00010, 0x00a00000, fix(&D:: template ADC_REG) }, + { 0x0fe00090, 0x00a00010, fix(&D:: template ADC_RSR) }, + { 0x0fe00000, 0x02800000, fix(&D:: template ADD_IMM) }, + { 0x0fe00010, 0x00800000, fix(&D:: template ADD_REG) }, + { 0x0fe00090, 0x00800010, fix(&D:: template ADD_RSR) }, + { 0x0fef0000, 0x028d0000, fix(&D:: template ADD_SPI) }, + { 0x0fef0010, 0x008d0000, fix(&D:: template ADD_SPR) }, + { 0x0fff0000, 0x028f0000, fix(&D:: template ADR) }, + { 0x0fff0000, 0x024f0000, fix(&D:: template ADR) }, + { 0x0fe00000, 0x02000000, fix(&D:: template AND_IMM) }, + { 0x0fe00010, 0x00000000, fix(&D:: template AND_REG) }, + { 0x0fe00090, 0x00000010, fix(&D:: template AND_RSR) }, + { 0x0fef0070, 0x01a00040, fix(&D:: template ASR_IMM) }, + { 0x0fef00f0, 0x01a00050, fix(&D:: template ASR_REG) }, + { 0x0f000000, 0x0a000000, fix(&D:: template B) }, + { 0x0fe0007f, 0x07c0001f, fix(&D:: template BFC) }, + { 0x0fe00070, 0x07c00010, fix(&D:: template BFI) }, + { 0x0fe00000, 0x03c00000, fix(&D:: template BIC_IMM) }, + { 0x0fe00010, 0x01c00000, fix(&D:: template BIC_REG) }, + { 0x0fe00090, 0x01c00010, fix(&D:: template BIC_RSR) }, + { 0x0ff000f0, 0x01200070, fix(&D:: template BKPT) }, + { 0x0f000000, 0x0b000000, fix(&D:: template BL) }, + { 0xfe000000, 0xfa000000, fix(&D:: template BL) }, + { 0x0ffffff0, 0x012fff30, fix(&D:: template BLX) }, + { 0x0fff0ff0, 0x016f0f10, fix(&D:: template CLZ) }, + { 0x0ff0f000, 0x03700000, fix(&D:: template CMN_IMM) }, + { 0x0ff0f010, 0x01700000, fix(&D:: template CMN_REG) }, + { 0x0ff0f090, 0x01700010, fix(&D:: template CMN_RSR) }, + { 0x0ff0f000, 0x03500000, fix(&D:: template CMP_IMM) }, + { 0x0ff0f010, 0x01500000, fix(&D:: template CMP_REG) }, + { 0x0ff0f090, 0x01500010, fix(&D:: template CMP_RSR) }, + { 0x0ffffff0, 0x0320f0f0, fix(&D:: template DBG) }, + { 0xfffffff0, 0xf57ff050, fix(&D:: template DMB) }, + { 0xfffffff0, 0xf57ff040, fix(&D:: template DSB) }, + { 0x0fe00000, 0x02200000, fix(&D:: template EOR_IMM) }, + { 0x0fe00010, 0x00200000, fix(&D:: template EOR_REG) }, + { 0x0fe00090, 0x00200010, fix(&D:: template EOR_RSR) }, + { 0x0fd00000, 0x08900000, fix(&D:: template LDM) }, + { 0x0fd00000, 0x08100000, fix(&D:: template LDMDA) }, + { 0x0fd00000, 0x09100000, fix(&D:: template LDMDB) }, + { 0x0fd00000, 0x09900000, fix(&D:: template LDMIB) }, + { 0x0e500000, 0x04100000, fix(&D:: template LDR_IMM) }, + { 0x0f7f0000, 0x051f0000, fix(&D:: template LDR_LIT) }, + { 0x0e500010, 0x06100000, fix(&D:: template LDR_REG) }, + { 0x0e500000, 0x04500000, fix(&D:: template LDRB_IMM) }, + { 0x0f7f0000, 0x055f0000, fix(&D:: template LDRB_LIT) }, + { 0x0e500010, 0x06500000, fix(&D:: template LDRB_REG) }, + { 0x0e5000f0, 0x004000d0, fix(&D:: template LDRD_IMM) }, + { 0x0f7f00f0, 0x014f00d0, fix(&D:: template LDRD_LIT) }, + { 0x0e500ff0, 0x000000d0, fix(&D:: template LDRD_REG) }, + { 0x0ff00fff, 0x01900f9f, fix(&D:: template LDREX) }, + { 0x0ff00fff, 0x01d00f9f, fix(&D:: template LDREXB) }, + { 0x0ff00fff, 0x01b00f9f, fix(&D:: template LDREXD) }, + { 0x0ff00fff, 0x01f00f9f, fix(&D:: template LDREXH) }, + { 0x0e5000f0, 0x005000b0, fix(&D:: template LDRH_IMM) }, + { 0x0f7f00f0, 0x015f00b0, fix(&D:: template LDRH_LIT) }, + { 0x0e500ff0, 0x001000b0, fix(&D:: template LDRH_REG) }, + { 0x0e5000f0, 0x005000d0, fix(&D:: template LDRSB_IMM) }, + { 0x0f7f00f0, 0x015f00d0, fix(&D:: template LDRSB_LIT) }, + { 0x0e500ff0, 0x001000d0, fix(&D:: template LDRSB_REG) }, + { 0x0e5000f0, 0x005000f0, fix(&D:: template LDRSH_IMM) }, + { 0x0f7f00f0, 0x015f00f0, fix(&D:: template LDRSH_LIT) }, + { 0x0e500ff0, 0x001000f0, fix(&D:: template LDRSH_REG) }, + { 0x0fef0070, 0x01a00000, fix(&D:: template LSL_IMM) }, + { 0x0fef00f0, 0x01a00010, fix(&D:: template LSL_REG) }, + { 0x0fef0030, 0x01a00020, fix(&D:: template LSR_IMM) }, + { 0x0fef00f0, 0x01a00030, fix(&D:: template LSR_REG) }, + { 0x0fe000f0, 0x00200090, fix(&D:: template MLA) }, + { 0x0ff000f0, 0x00600090, fix(&D:: template MLS) }, + { 0x0fef0000, 0x03a00000, fix(&D:: template MOV_IMM) }, + { 0x0ff00000, 0x03000000, fix(&D:: template MOV_IMM) }, + { 0x0fef0ff0, 0x01a00000, fix(&D:: template MOV_REG) }, + { 0x0ff00000, 0x03400000, fix(&D:: template MOVT) }, + { 0x0f100010, 0x0e100010, fix(&D:: template MRC_) }, + { 0xff100010, 0xfe100010, fix(&D:: template MRC_) }, + { 0x0fff0fff, 0x010f0000, fix(&D:: template MRS) }, + { 0x0ff3f000, 0x0320f000, fix(&D:: template MSR_IMM) }, + { 0x0ff3fff0, 0x0120f000, fix(&D:: template MSR_REG) }, + { 0x0fe0f0f0, 0x00000090, fix(&D:: template MUL) }, + { 0x0fef0000, 0x03e00000, fix(&D:: template MVN_IMM) }, + { 0xffef0010, 0x01e00000, fix(&D:: template MVN_REG) }, + { 0x0fef0090, 0x01e00010, fix(&D:: template MVN_RSR) }, + { 0x0fffffff, 0x0320f000, fix(&D:: template NOP) }, + { 0x0fe00000, 0x03800000, fix(&D:: template ORR_IMM) }, + { 0x0fe00010, 0x01800000, fix(&D:: template ORR_REG) }, + { 0x0fe00090, 0x01800010, fix(&D:: template ORR_RSR) }, + { 0x0ff00030, 0x06800010, fix(&D:: template PKH) }, + { 0x0fff0000, 0x08bd0000, fix(&D:: template POP) }, + { 0x0fff0fff, 0x049d0004, fix(&D:: template POP) }, + { 0x0fff0000, 0x092d0000, fix(&D:: template PUSH) }, + { 0x0fff0fff, 0x052d0004, fix(&D:: template PUSH) }, + { 0x0ff00ff0, 0x01000050, fix(&D:: template QADD) }, + { 0x0ff00ff0, 0x06200f10, fix(&D:: template QADD16) }, + { 0x0ff00ff0, 0x06200f90, fix(&D:: template QADD8) }, + { 0x0ff00ff0, 0x06200f30, fix(&D:: template QASX) }, + { 0x0ff00ff0, 0x01400050, fix(&D:: template QDADD) }, + { 0x0ff00ff0, 0x01600050, fix(&D:: template QDSUB) }, + { 0x0ff00ff0, 0x06200f50, fix(&D:: template QSAX) }, + { 0x0ff00ff0, 0x01200050, fix(&D:: template QSUB) }, + { 0x0ff00ff0, 0x06200f70, fix(&D:: template QSUB16) }, + { 0x0ff00ff0, 0x06200ff0, fix(&D:: template QSUB8) }, + { 0x0fff0ff0, 0x06ff0f30, fix(&D:: template RBIT) }, + { 0x0fff0ff0, 0x06bf0f30, fix(&D:: template REV) }, + { 0x0fff0ff0, 0x06bf0fb0, fix(&D:: template REV16) }, + { 0x0fff0ff0, 0x06ff0fb0, fix(&D:: template REVSH) }, + { 0x0fef0070, 0x01a00060, fix(&D:: template ROR_IMM) }, + { 0x0fef00f0, 0x01a00070, fix(&D:: template ROR_REG) }, + { 0x0fef0ff0, 0x01a00060, fix(&D:: template RRX) }, + { 0x0fe00000, 0x02600000, fix(&D:: template RSB_IMM) }, + { 0x0fe00010, 0x00600000, fix(&D:: template RSB_REG) }, + { 0x0fe00090, 0x00600010, fix(&D:: template RSB_RSR) }, + { 0x0fe00000, 0x02e00000, fix(&D:: template RSC_IMM) }, + { 0x0fe00010, 0x00e00000, fix(&D:: template RSC_REG) }, + { 0x0fe00090, 0x00e00010, fix(&D:: template RSC_RSR) }, + { 0x0ff00ff0, 0x06100f10, fix(&D:: template SADD16) }, + { 0x0ff00ff0, 0x06100f90, fix(&D:: template SADD8) }, + { 0x0ff00ff0, 0x06100f30, fix(&D:: template SASX) }, + { 0x0fe00000, 0x02c00000, fix(&D:: template SBC_IMM) }, + { 0x0fe00010, 0x00c00000, fix(&D:: template SBC_REG) }, + { 0x0fe00090, 0x00c00010, fix(&D:: template SBC_RSR) }, + { 0x0fe00070, 0x07a00050, fix(&D:: template SBFX) }, + { 0x0ff00ff0, 0x06800fb0, fix(&D:: template SEL) }, + { 0x0ff00ff0, 0x06300f10, fix(&D:: template SHADD16) }, + { 0x0ff00ff0, 0x06300f90, fix(&D:: template SHADD8) }, + { 0x0ff00ff0, 0x06300f30, fix(&D:: template SHASX) }, + { 0x0ff00ff0, 0x06300f50, fix(&D:: template SHSAX) }, + { 0x0ff00ff0, 0x06300f70, fix(&D:: template SHSUB16) }, + { 0x0ff00ff0, 0x06300ff0, fix(&D:: template SHSUB8) }, + { 0x0ff00090, 0x01000080, fix(&D:: template SMLA__) }, + { 0x0ff000d0, 0x07000010, fix(&D:: template SMLAD) }, + { 0x0fe000f0, 0x00e00090, fix(&D:: template SMLAL) }, + { 0x0ff00090, 0x01400080, fix(&D:: template SMLAL__) }, + { 0x0ff000d0, 0x07400010, fix(&D:: template SMLALD) }, + { 0x0ff000b0, 0x01200080, fix(&D:: template SMLAW_) }, + { 0x0ff000d0, 0x07000050, fix(&D:: template SMLSD) }, + { 0x0ff000d0, 0x07400050, fix(&D:: template SMLSLD) }, + { 0x0ff000d0, 0x07500010, fix(&D:: template SMMLA) }, + { 0x0ff000d0, 0x075000d0, fix(&D:: template SMMLS) }, + { 0x0ff0f0d0, 0x0750f010, fix(&D:: template SMMUL) }, + { 0x0ff0f0d0, 0x0700f010, fix(&D:: template SMUAD) }, + { 0x0ff0f090, 0x01600080, fix(&D:: template SMUL__) }, + { 0x0fe000f0, 0x00c00090, fix(&D:: template SMULL) }, + { 0x0ff0f0b0, 0x012000a0, fix(&D:: template SMULW_) }, + { 0x0ff0f0d0, 0x0700f050, fix(&D:: template SMUSD) }, + { 0x0fe00030, 0x06a00010, fix(&D:: template SSAT) }, + { 0x0ff00ff0, 0x06a00f30, fix(&D:: template SSAT16) }, + { 0x0ff00ff0, 0x06100f50, fix(&D:: template SSAX) }, + { 0x0ff00ff0, 0x06100f70, fix(&D:: template SSUB16) }, + { 0x0ff00ff0, 0x06100ff0, fix(&D:: template SSUB8) }, + { 0x0fd00000, 0x08800000, fix(&D:: template STM) }, + { 0x0fd00000, 0x08000000, fix(&D:: template STMDA) }, + { 0x0fd00000, 0x09000000, fix(&D:: template STMDB) }, + { 0x0fd00000, 0x09800000, fix(&D:: template STMIB) }, + { 0x0e500000, 0x04000000, fix(&D:: template STR_IMM) }, + { 0x0e500010, 0x06000000, fix(&D:: template STR_REG) }, + { 0x0e500000, 0x04400000, fix(&D:: template STRB_IMM) }, + { 0x0e500010, 0x06400000, fix(&D:: template STRB_REG) }, + { 0x0e5000f0, 0x004000f0, fix(&D:: template STRD_IMM) }, + { 0x0e500ff0, 0x000000f0, fix(&D:: template STRD_REG) }, + { 0x0ff00ff0, 0x01800f90, fix(&D:: template STREX) }, + { 0x0ff00ff0, 0x01c00f90, fix(&D:: template STREXB) }, + { 0x0ff00ff0, 0x01a00f90, fix(&D:: template STREXD) }, + { 0x0ff00ff0, 0x01e00f90, fix(&D:: template STREXH) }, + { 0x0e5000f0, 0x004000b0, fix(&D:: template STRH_IMM) }, + { 0x0e500ff0, 0x000000b0, fix(&D:: template STRH_REG) }, + { 0x0fe00000, 0x02400000, fix(&D:: template SUB_IMM) }, + { 0x0fe00010, 0x00400000, fix(&D:: template SUB_REG) }, + { 0x0fe00090, 0x00400010, fix(&D:: template SUB_RSR) }, + { 0x0fef0000, 0x024d0000, fix(&D:: template SUB_SPI) }, + { 0x0fef0010, 0x004d0000, fix(&D:: template SUB_SPR) }, + { 0x0f000000, 0x0f000000, fix(&D:: template SVC) }, + { 0x0ff003f0, 0x06a00070, fix(&D:: template SXTAB) }, + { 0x0ff003f0, 0x06800070, fix(&D:: template SXTAB16) }, + { 0x0ff003f0, 0x06b00070, fix(&D:: template SXTAH) }, + { 0x0fff03f0, 0x06af0070, fix(&D:: template SXTB) }, + { 0x0fff03f0, 0x068f0070, fix(&D:: template SXTB16) }, + { 0x0fff03f0, 0x06bf0070, fix(&D:: template SXTH) }, + { 0x0ff0f000, 0x03300000, fix(&D:: template TEQ_IMM) }, + { 0x0ff0f010, 0x01300000, fix(&D:: template TEQ_REG) }, + { 0x0ff0f090, 0x01300010, fix(&D:: template TEQ_RSR) }, + { 0x0ff0f000, 0x03100000, fix(&D:: template TST_IMM) }, + { 0x0ff0f010, 0x01100000, fix(&D:: template TST_REG) }, + { 0x0ff0f090, 0x01100010, fix(&D:: template TST_RSR) }, + { 0x0ff00ff0, 0x06500f10, fix(&D:: template UADD16) }, + { 0x0ff00ff0, 0x06500f90, fix(&D:: template UADD8) }, + { 0x0ff00ff0, 0x06500f30, fix(&D:: template UASX) }, + { 0x0fe00070, 0x07e00050, fix(&D:: template UBFX) }, + { 0x0ff00ff0, 0x06700f10, fix(&D:: template UHADD16) }, + { 0x0ff00ff0, 0x06700f90, fix(&D:: template UHADD8) }, + { 0x0ff00ff0, 0x06700f30, fix(&D:: template UHASX) }, + { 0x0ff00ff0, 0x06700f50, fix(&D:: template UHSAX) }, + { 0x0ff00ff0, 0x06700f70, fix(&D:: template UHSUB16) }, + { 0x0ff00ff0, 0x06700ff0, fix(&D:: template UHSUB8) }, + { 0x0ff000f0, 0x00400090, fix(&D:: template UMAAL) }, + { 0x0fe000f0, 0x00a00090, fix(&D:: template UMLAL) }, + { 0x0fe000f0, 0x00800090, fix(&D:: template UMULL) }, + { 0x0ff00ff0, 0x06600f10, fix(&D:: template UQADD16) }, + { 0x0ff00ff0, 0x06600f90, fix(&D:: template UQADD8) }, + { 0x0ff00ff0, 0x06600f30, fix(&D:: template UQASX) }, + { 0x0ff00ff0, 0x06600f50, fix(&D:: template UQSAX) }, + { 0x0ff00ff0, 0x06600f70, fix(&D:: template UQSUB16) }, + { 0x0ff00ff0, 0x06600ff0, fix(&D:: template UQSUB8) }, + { 0x0ff0f0f0, 0x0780f010, fix(&D:: template USAD8) }, + { 0x0ff000f0, 0x07800010, fix(&D:: template USADA8) }, + { 0x0fe00030, 0x06e00010, fix(&D:: template USAT) }, + { 0x0ff00ff0, 0x06e00f30, fix(&D:: template USAT16) }, + { 0x0ff00ff0, 0x06500f50, fix(&D:: template USAX) }, + { 0x0ff00ff0, 0x06500f70, fix(&D:: template USUB16) }, + { 0x0ff00ff0, 0x06500ff0, fix(&D:: template USUB8) }, + { 0x0ff003f0, 0x06e00070, fix(&D:: template UXTAB), SKIP_IF(BF(16, 19) == 15) }, + { 0x0ff003f0, 0x06c00070, fix(&D:: template UXTAB16) }, + { 0x0ff003f0, 0x06f00070, fix(&D:: template UXTAH) }, + { 0x0fff03f0, 0x06ef0070, fix(&D:: template UXTB) }, + { 0x0fff03f0, 0x06cf0070, fix(&D:: template UXTB16) }, + { 0x0fff03f0, 0x06ff0070, fix(&D:: template UXTH) }, + { 0xfe800f10, 0xf2000710, fix(&D:: template VABA_) }, + { 0xfe800f50, 0xf2800500, fix(&D:: template VABA_) }, + { 0xfe800f10, 0xf2000700, fix(&D:: template VABD_) }, + { 0xfe800f50, 0xf2800700, fix(&D:: template VABD_) }, + { 0xffa00f10, 0xf3200d00, fix(&D:: template VABD_FP) }, + { 0xffb30b90, 0xf3b10300, fix(&D:: template VABS) }, + { 0x0fbf0ed0, 0x0eb00ac0, fix(&D:: template VABS) }, + { 0xff800f10, 0xf3000e10, fix(&D:: template VAC__) }, + { 0xff800f10, 0xf2000800, fix(&D:: template VADD) }, + { 0xffa00f10, 0xf2000d00, fix(&D:: template VADD_FP) }, + { 0x0fb00e50, 0x0e300a00, fix(&D:: template VADD_FP) }, + { 0xff800f50, 0xf2800400, fix(&D:: template VADDHN) }, + { 0xfe800e50, 0xf2800000, fix(&D:: template VADD_) }, + { 0xffb00f10, 0xf2000110, fix(&D:: template VAND) }, + { 0xfeb000b0, 0xf2800030, fix(&D:: template VBIC_IMM) }, + { 0xffb00f10, 0xf2100110, fix(&D:: template VBIC_REG) }, + { 0xff800f10, 0xf3000110, fix(&D:: template VB__) }, + { 0xff800f10, 0xf3000810, fix(&D:: template VCEQ_REG) }, + { 0xffa00f10, 0xf2000e00, fix(&D:: template VCEQ_REG) }, + { 0xffb30b90, 0xf3b10100, fix(&D:: template VCEQ_ZERO) }, + { 0xfe800f10, 0xf2000310, fix(&D:: template VCGE_REG) }, + { 0xffa00f10, 0xf3000e00, fix(&D:: template VCGE_REG) }, + { 0xffb30b90, 0xf3b10080, fix(&D:: template VCGE_ZERO) }, + { 0xfe800f10, 0xf2000300, fix(&D:: template VCGT_REG) }, + { 0xffa00f10, 0xf3200e00, fix(&D:: template VCGT_REG) }, + { 0xffb30b90, 0xf3b10000, fix(&D:: template VCGT_ZERO) }, + { 0xffb30b90, 0xf3b10180, fix(&D:: template VCLE_ZERO) }, + { 0xffb30f90, 0xf3b00400, fix(&D:: template VCLS) }, + { 0xffb30b90, 0xf3b10200, fix(&D:: template VCLT_ZERO) }, + { 0xffb30f90, 0xf3b00480, fix(&D:: template VCLZ) }, + { 0x0fbf0e50, 0x0eb40a40, fix(&D:: template VCMP_) }, + { 0x0fbf0e7f, 0x0eb50a40, fix(&D:: template VCMP_) }, + { 0xffb30f90, 0xf3b00500, fix(&D:: template VCNT) }, + { 0xffb30e10, 0xf3b30600, fix(&D:: template VCVT_FIA) }, + { 0x0fb80e50, 0x0eb80a40, fix(&D:: template VCVT_FIF) }, + { 0xfe800e90, 0xf2800e10, fix(&D:: template VCVT_FFA) }, + { 0x0fba0e50, 0x0eba0a40, fix(&D:: template VCVT_FFF) }, + { 0x0fbf0ed0, 0x0eb70ac0, fix(&D:: template VCVT_DF) }, + { 0xffb30ed0, 0xf3b20600, fix(&D:: template VCVT_HFA) }, + { 0x0fbe0f50, 0x0eb20a40, fix(&D:: template VCVT_HFF) }, + { 0x0fb00e50, 0x0e800a00, fix(&D:: template VDIV) }, + { 0xffb00f90, 0xf3b00c00, fix(&D:: template VDUP_S) }, + { 0x0f900f5f, 0x0e800b10, fix(&D:: template VDUP_R) }, + { 0xffb00f10, 0xf3000110, fix(&D:: template VEOR) }, + { 0xffb00010, 0xf2b00000, fix(&D:: template VEXT) }, + { 0xfe800b10, 0xf2000000, fix(&D:: template VHADDSUB) }, + { 0xffb00000, 0xf4200000, fix(&D:: template VLD__MS) }, + { 0xffb00f00, 0xf4a00c00, fix(&D:: template VLD1_SAL) }, + { 0xffb00300, 0xf4a00000, fix(&D:: template VLD1_SL) }, + { 0xffb00f00, 0xf4a00d00, fix(&D:: template VLD2_SAL) }, + { 0xffb00300, 0xf4a00100, fix(&D:: template VLD2_SL) }, + { 0xffb00f00, 0xf4a00e00, fix(&D:: template VLD3_SAL) }, + { 0xffb00300, 0xf4a00200, fix(&D:: template VLD3_SL) }, + { 0xffb00f00, 0xf4a00f00, fix(&D:: template VLD4_SAL) }, + { 0xffb00300, 0xf4a00300, fix(&D:: template VLD4_SL) }, + { 0x0e100f00, 0x0c100b00, fix(&D:: template VLDM) }, + { 0x0e100f00, 0x0c100a00, fix(&D:: template VLDM) }, + { 0x0f300f00, 0x0d100b00, fix(&D:: template VLDR) }, + { 0x0f300f00, 0x0d100a00, fix(&D:: template VLDR) }, + { 0xfe800f00, 0xf2000600, fix(&D:: template VMAXMIN) }, + { 0xff800f10, 0xf2000f00, fix(&D:: template VMAXMIN_FP) }, + { 0xfe800f10, 0xf2000900, fix(&D:: template VML__) }, + { 0xfe800d50, 0xf2800800, fix(&D:: template VML__) }, + { 0xff800f10, 0xf2000d10, fix(&D:: template VML__FP) }, + { 0x0fb00e10, 0x0e000a00, fix(&D:: template VML__FP) }, + { 0xfe800a50, 0xf2800040, fix(&D:: template VML__S) }, + { 0xfe800b50, 0xf2800240, fix(&D:: template VML__S) }, + { 0xfeb80090, 0xf2800010, fix(&D:: template VMOV_IMM) }, + { 0x0fb00ef0, 0x0eb00a00, fix(&D:: template VMOV_IMM) }, + { 0xffb00f10, 0xf2200110, fix(&D:: template VMOV_REG) }, + { 0x0fbf0ed0, 0x0eb00a40, fix(&D:: template VMOV_REG) }, + { 0x0f900f1f, 0x0e000b10, fix(&D:: template VMOV_RS) }, + { 0x0f100f1f, 0x0e100b10, fix(&D:: template VMOV_SR) }, + { 0x0fe00f7f, 0x0e000a10, fix(&D:: template VMOV_RF) }, + { 0x0fe00fd0, 0x0c400a10, fix(&D:: template VMOV_2RF) }, + { 0x0fe00fd0, 0x0c400b10, fix(&D:: template VMOV_2RD) }, + { 0xfe870fd0, 0xf2800a10, fix(&D:: template VMOVL) }, + { 0xffb30fd0, 0xf3b20200, fix(&D:: template VMOVN) }, + { 0x0fff0fff, 0x0ef10a10, fix(&D:: template VMRS) }, + { 0x0fff0fff, 0x0ee10a10, fix(&D:: template VMSR) }, + { 0xfe800f10, 0xf2000910, fix(&D:: template VMUL_) }, + { 0xfe800d50, 0xf2800c00, fix(&D:: template VMUL_) }, + { 0xffa00f10, 0xf3000d10, fix(&D:: template VMUL_FP) }, + { 0x0fb00e50, 0x0e200a00, fix(&D:: template VMUL_FP) }, + { 0xfe800e50, 0xf2800840, fix(&D:: template VMUL_S) }, + { 0xfe800f50, 0xf2800a40, fix(&D:: template VMUL_S) }, + { 0xfeb800b0, 0xf2800030, fix(&D:: template VMVN_IMM) }, + { 0xffb30f90, 0xf3b00580, fix(&D:: template VMVN_REG) }, + { 0xffb30b90, 0xf3b10380, fix(&D:: template VNEG) }, + { 0x0fbf0ed0, 0x0eb10a40, fix(&D:: template VNEG) }, + { 0x0fb00e10, 0x0e100a00, fix(&D:: template VNM__) }, + { 0x0fb00e50, 0x0e200a40, fix(&D:: template VNM__) }, + { 0xffb00f10, 0xf2300110, fix(&D:: template VORN_REG) }, + { 0xfeb800b0, 0xf2800010, fix(&D:: template VORR_IMM) }, + { 0xffb00f10, 0xf2200110, fix(&D:: template VORR_REG) }, + { 0xffb30f10, 0xf3b00600, fix(&D:: template VPADAL) }, + { 0xff800f10, 0xf2000b10, fix(&D:: template VPADD) }, + { 0xffa00f10, 0xf3000d00, fix(&D:: template VPADD_FP) }, + { 0xffb30f10, 0xf3b00200, fix(&D:: template VPADDL) }, + { 0xfe800f00, 0xf2000a00, fix(&D:: template VPMAXMIN) }, + { 0xff800f10, 0xf3000f00, fix(&D:: template VPMAXMIN_FP) }, + { 0x0fbf0f00, 0x0cbd0b00, fix(&D:: template VPOP) }, + { 0x0fbf0f00, 0x0cbd0a00, fix(&D:: template VPOP) }, + { 0x0fbf0f00, 0x0d2d0b00, fix(&D:: template VPUSH) }, + { 0x0fbf0f00, 0x0d2d0a00, fix(&D:: template VPUSH) }, + // TODO: VQ* instructions + { 0xff800f50, 0xf3800400, fix(&D:: template VRADDHN) }, + { 0xffb30e90, 0xf3b30400, fix(&D:: template VRECPE) }, + { 0xffa00f10, 0xf2000f10, fix(&D:: template VRECPS) }, + { 0xffb30e10, 0xf3b00000, fix(&D:: template VREV__) }, + { 0xfe800f10, 0xf2000100, fix(&D:: template VRHADD) }, + { 0xfe800f10, 0xf2000500, fix(&D:: template VRSHL) }, + { 0xfe800f10, 0xf2800210, fix(&D:: template VRSHR) }, + { 0xff800fd0, 0xf2800850, fix(&D:: template VRSHRN) }, + { 0xffb30e90, 0xf3b30480, fix(&D:: template VRSQRTE) }, + { 0xffa00f10, 0xf2200f10, fix(&D:: template VRSQRTS) }, + { 0xfe800f10, 0xf2800310, fix(&D:: template VRSRA) }, + { 0xff800f50, 0xf3800600, fix(&D:: template VRSUBHN) }, + { 0xff800f10, 0xf2800510, fix(&D:: template VSHL_IMM) }, + { 0xfe800f10, 0xf2000400, fix(&D:: template VSHL_REG) }, + { 0xfe800fd0, 0xf2800a10, fix(&D:: template VSHLL) }, + { 0xffb30fd0, 0xf3b20300, fix(&D:: template VSHLL) }, + { 0xfe800f10, 0xf2800010, fix(&D:: template VSHR) }, + { 0xff800fd0, 0xf2800810, fix(&D:: template VSHRN) }, + { 0xff800f10, 0xf3800510, fix(&D:: template VSLI) }, + { 0x0fbf0ed0, 0x0eb10ac0, fix(&D:: template VSQRT) }, + { 0xfe800f10, 0xf2800110, fix(&D:: template VSRA) }, + { 0xff800f10, 0xf3800410, fix(&D:: template VSRI) }, + { 0xffb00000, 0xf4000000, fix(&D:: template VST__MS) }, + { 0xffb00300, 0xf4800000, fix(&D:: template VST1_SL) }, + { 0xffb00300, 0xf4800100, fix(&D:: template VST2_SL) }, + { 0xffb00300, 0xf4800200, fix(&D:: template VST3_SL) }, + { 0xffb00300, 0xf4800300, fix(&D:: template VST4_SL) }, + { 0x0e100f00, 0x0c000b00, fix(&D:: template VSTM) }, + { 0x0e100f00, 0x0c000a00, fix(&D:: template VSTM) }, + { 0x0f300f00, 0x0d000b00, fix(&D:: template VSTR) }, + { 0x0f300f00, 0x0d000a00, fix(&D:: template VSTR) }, + { 0xff800f10, 0xf3000800, fix(&D:: template VSUB) }, + { 0xffa00f10, 0xf2200d00, fix(&D:: template VSUB_FP) }, + { 0x0fb00e50, 0x0e300a40, fix(&D:: template VSUB_FP) }, + { 0xff800f50, 0xf2800600, fix(&D:: template VSUBHN) }, + { 0xfe800e50, 0xf2800200, fix(&D:: template VSUB_) }, + { 0xffb30f90, 0xf3b20000, fix(&D:: template VSWP) }, + { 0xffb00c10, 0xf3b00800, fix(&D:: template VTB_) }, + { 0xffb30f90, 0xf3b20080, fix(&D:: template VTRN) }, + { 0xff800f10, 0xf2000810, fix(&D:: template VTST) }, + { 0xffb30f90, 0xf3b20100, fix(&D:: template VUZP) }, + { 0xffb30f90, 0xf3b20180, fix(&D:: template VZIP) }, + { 0x0fffffff, 0x0320f002, fix(&D:: template WFE) }, + { 0x0fffffff, 0x0320f003, fix(&D:: template WFI) }, + { 0x0fffffff, 0x0320f001, fix(&D:: template YIELD) }, + }); + + m_op32_table.fill(m_op32_list.cbegin()); + + for (u32 i = 0; i < 0x10000; i++) + { + for (auto& opcode : m_op16_list) + { + if (opcode.match(i)) + { + m_op16_table[i] = opcode.pointer; + break; + } + } + + if (!m_op16_table[i] && !arm_op_thumb_is_32(i)) + { + m_op16_table[i] = &D::UNK; + } + } + + std::set> result; + + for (u32 i = 0xe800; i < 0x10000; i++) + { + if (m_op16_table[i]) LOG_ERROR(ARMv7, "Invalid m_op16_table entry 0x%04x", i); + + //std::set matches; + + //for (u32 j = 0; j < 0x10000; j++) + //{ + // for (auto& o : m_op32_list) + // { + // if (o.match(i << 16 | j)) + // { + // matches.emplace(&o); + // break; + // } + // } + //} + + //result.emplace(std::move(matches)); + } + + for (const auto& s : result) + { + LOG_NOTICE(ARMv7, "Set found (%u):", s.size()); + for (const auto& e : s) + { + LOG_NOTICE(ARMv7, "** 0x%08x, 0x%08x", e->mask, e->code); + } + } + } + + // First chance + T decode_thumb(u16 op16) const + { + return m_op16_table[op16]; + } + + // Second step + T decode_thumb(u32 op32) const + { + for (auto i = m_op32_table[op32 >> 16], end = m_op32_list.end(); i != end; i++) + { + if (i->match(op32)) + { + return i->pointer; + } + } + + return &D::UNK; + } + + T decode_arm(u32 op) const + { + for (auto& i : m_arm_list) + { + if (i.match(op)) + { + return i.pointer; + } + } + + return &D::UNK; + } }; -static void group_0xf(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) -{ - u32 index = (thr->code.code0 & 0x0b00) >> 8; - - switch ((thr->m_arg & 0x0800d000) >> 12) - { - case 0x8: // B, T3 - case 0x9: // B, T4 - case 0xd: index = 0x0; break; // BL, T1 - - default: break; - } - - if ((thr->m_arg & 0xf800c001) == 0xf000c000) index = 0x0; // BLX, T2 - - switch ((thr->code.code0 & 0x0f00) >> 8) - { - case 0x3: index = 0x3; break; - case 0x8: index = 0x8; break; - case 0x9: index = 0x9; break; - case 0xa: index = 0xa; break; - - default: break; - } - - thr->m_last_instr_name = g_table_0xf_main[index].name; - thr->m_last_instr_size = g_table_0xf_main[index].size; - thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; - g_table_0xf_main[index].func(thr, g_table_0xf_main[index].type); -} - -static const ARMv7_Instruction g_table_0xf[] = -{ - { group_0xf } -}; - - -static void execute_main_group(ARMv7Thread* thr) -{ - switch ((thr->code.code0 & 0xf000) >> 12) - { - //case 0x0: (*g_table_0x0).func(thr, (*g_table_0x0).type); break; // TODO - case 0x1: (*g_table_0x1).func(thr, (*g_table_0x1).type); break; - case 0x2: (*g_table_0x2).func(thr, (*g_table_0x2).type); break; - case 0x3: (*g_table_0x3).func(thr, (*g_table_0x3).type); break; - case 0x4: (*g_table_0x4).func(thr, (*g_table_0x4).type); break; - case 0x5: (*g_table_0x5).func(thr, (*g_table_0x5).type); break; - case 0x6: (*g_table_0x6).func(thr, (*g_table_0x6).type); break; - case 0x7: (*g_table_0x7).func(thr, (*g_table_0x7).type); break; - case 0x8: (*g_table_0x8).func(thr, (*g_table_0x8).type); break; - case 0x9: (*g_table_0x9).func(thr, (*g_table_0x9).type); break; - case 0xa: (*g_table_0xa).func(thr, (*g_table_0xa).type); break; - case 0xb: (*g_table_0xb).func(thr, (*g_table_0xb).type); break; - case 0xc: (*g_table_0xc).func(thr, (*g_table_0xc).type); break; - case 0xd: (*g_table_0xd).func(thr, (*g_table_0xd).type); break; - case 0xe: (*g_table_0xe).func(thr, (*g_table_0xe).type); break; - case 0xf: (*g_table_0xf).func(thr, (*g_table_0xf).type); break; - - default: LOG_ERROR(ARMv7, "ARMv7Decoder: unknown group 0x%x", (thr->code.code0 & 0xf000) >> 12); Emu.Pause(); break; - } -} - -#undef ARMv7_OP_2 -#undef ARMv7_OP_4 -#undef ARMv7_NULL_OP -#endif +#undef SKIP_IF +#undef BF +#undef BT diff --git a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp index a7cae52e4d..a240c216a3 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp @@ -1,25 +1,20 @@ #include "stdafx.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/state.h" -#include "Emu/IdManager.h" -#include "Emu/ARMv7/PSVFuncList.h" #include "ARMv7Thread.h" -#include "ARMv7Decoder.h" -#include "ARMv7DisAsm.h" +#include "ARMv7Opcodes.h" #include "ARMv7Interpreter.h" -void ARMv7Context::fast_call(u32 addr) -{ - return static_cast(this)->fast_call(addr); -} +namespace vm { using namespace psv; } + +const arm_decoder s_arm_interpreter; #define TLS_MAX 128 u32 g_armv7_tls_start; -std::array, TLS_MAX> g_armv7_tls_owners; +std::array, TLS_MAX> g_armv7_tls_owners; void armv7_init_tls() { @@ -48,8 +43,7 @@ u32 armv7_get_tls(u32 thread) for (u32 i = 0; i < TLS_MAX; i++) { - u32 old = 0; - if (g_armv7_tls_owners[i].compare_exchange_strong(old, thread)) + if (g_armv7_tls_owners[i].compare_and_swap_test(0, thread)) { const u32 addr = g_armv7_tls_start + i * Emu.GetTLSMemsz(); // get TLS address std::memcpy(vm::base(addr), vm::base(Emu.GetTLSAddr()), Emu.GetTLSFilesz()); // initialize from TLS image @@ -70,57 +64,38 @@ void armv7_free_tls(u32 thread) for (auto& v : g_armv7_tls_owners) { - u32 old = thread; - if (v.compare_exchange_strong(old, 0)) + if (v.compare_and_swap_test(thread, 0)) { return; } } } -ARMv7Thread::ARMv7Thread(const std::string& name) - : CPUThread(CPU_THREAD_ARMv7, name) - , ARMv7Context({}) -{ -} - -ARMv7Thread::~ARMv7Thread() -{ - close_stack(); - armv7_free_tls(m_id); -} - std::string ARMv7Thread::get_name() const { - return fmt::format("ARMv7 Thread[0x%x] (%s)[0x%08x]", m_id, CPUThread::get_name(), PC); + return fmt::format("ARMv7[0x%x] Thread (%s)", id, name); } -void ARMv7Thread::dump_info() const +std::string ARMv7Thread::dump() const { - if (hle_func) + std::string result = "Registers:\n=========\n"; + for(int i=0; i<15; ++i) { - const auto func = get_psv_func_by_nid(hle_func); - - LOG_SUCCESS(HLE, "Last function: %s (0x%x)", func ? func->name : "?????????", hle_func); + result += fmt::format("r%u\t= 0x%08x\n", i, GPR[i]); } - CPUThread::dump_info(); + result += fmt::format("APSR\t= 0x%08x [N: %d, Z: %d, C: %d, V: %d, Q: %d]\n", + APSR.APSR, + u32{ APSR.N }, + u32{ APSR.Z }, + u32{ APSR.C }, + u32{ APSR.V }, + u32{ APSR.Q }); + + return result; } -void ARMv7Thread::init_regs() -{ - memset(GPR, 0, sizeof(GPR)); - APSR.APSR = 0; - IPSR.IPSR = 0; - ISET = PC & 1 ? Thumb : ARM; // select instruction set - PC = PC & ~1; // and fix PC - ITSTATE.IT = 0; - SP = stack_addr + stack_size; - TLS = armv7_get_tls(m_id); - debug = DF_DISASM | DF_PRINT; -} - -void ARMv7Thread::init_stack() +void ARMv7Thread::cpu_init() { if (!stack_addr) { @@ -136,60 +111,15 @@ void ARMv7Thread::init_stack() throw EXCEPTION("Out of stack memory"); } } -} -void ARMv7Thread::close_stack() -{ - if (stack_addr) - { - vm::dealloc_verbose_nothrow(stack_addr, vm::main); - stack_addr = 0; - } -} - -std::string ARMv7Thread::RegsToString() const -{ - std::string result = "Registers:\n=========\n"; - for(int i=0; i<15; ++i) - { - result += fmt::format("%s\t= 0x%08x\n", g_arm_reg_name[i], GPR[i]); - } - - result += fmt::format("APSR\t= 0x%08x [N: %d, Z: %d, C: %d, V: %d, Q: %d]\n", - APSR.APSR, - u32{ APSR.N }, - u32{ APSR.Z }, - u32{ APSR.C }, - u32{ APSR.V }, - u32{ APSR.Q }); - - return result; -} - -std::string ARMv7Thread::ReadRegString(const std::string& reg) const -{ - return ""; -} - -bool ARMv7Thread::WriteRegString(const std::string& reg, std::string value) -{ - return true; -} - -void ARMv7Thread::do_run() -{ - m_dec.reset(); - - switch((int)rpcs3::state.config.core.ppu_decoder.value()) - { - case 0: - case 1: - m_dec.reset(new ARMv7Decoder(*this)); - break; - default: - LOG_ERROR(ARMv7, "Invalid CPU decoder mode: %d", (int)rpcs3::state.config.core.ppu_decoder.value()); - Emu.Pause(); - } + memset(GPR, 0, sizeof(GPR)); + APSR.APSR = 0; + IPSR.IPSR = 0; + ISET = PC & 1 ? Thumb : ARM; // select instruction set + PC = PC & ~1; // and fix PC + ITSTATE.IT = 0; + SP = stack_addr + stack_size; + TLS = armv7_get_tls(id); } void ARMv7Thread::cpu_task() @@ -201,10 +131,54 @@ void ARMv7Thread::cpu_task() return custom_task(*this); } - while (!m_state || !check_status()) + _log::g_tls_make_prefix = [](const auto&, auto, const auto&) { - // decode instruction using specified decoder - PC += m_dec->DecodeMemory(PC); + const auto cpu = static_cast(get_current_cpu_thread()); + + return fmt::format("%s [0x%08x]", cpu->get_name(), cpu->PC); + }; + + while (!state.load() || !check_status()) + { + if (ISET == Thumb) + { + const u16 op16 = vm::read16(PC); + const u32 cond = ITSTATE.advance(); + + if (const auto func16 = s_arm_interpreter.decode_thumb(op16)) + { + func16(*this, op16, cond); + PC += 2; + } + else + { + const u32 op32 = (op16 << 16) | vm::read16(PC + 2); + + s_arm_interpreter.decode_thumb(op32)(*this, op32, cond); + PC += 4; + } + } + else if (ISET == ARM) + { + const u32 op = vm::read32(PC); + + s_arm_interpreter.decode_arm(op)(*this, op, op >> 28); + PC += 4; + } + else + { + throw fmt::exception("Invalid instruction set" HERE); + } + } +} + +ARMv7Thread::~ARMv7Thread() +{ + armv7_free_tls(id); + + if (stack_addr) + { + vm::dealloc_verbose_nothrow(stack_addr, vm::main); } } @@ -228,11 +202,13 @@ void ARMv7Thread::fast_call(u32 addr) { cpu_task(); } - catch (CPUThreadReturn) + catch (cpu_state _s) { + state += _s; + if (_s != cpu_state::ret) throw; } - m_state &= ~CPU_STATE_RETURN; + state -= cpu_state::ret; PC = old_PC; @@ -244,67 +220,3 @@ void ARMv7Thread::fast_call(u32 addr) LR = old_LR; custom_task = std::move(old_task); } - -void ARMv7Thread::fast_stop() -{ - m_state |= CPU_STATE_RETURN; -} - -armv7_thread::armv7_thread(u32 entry, const std::string& name, u32 stack_size, s32 prio) -{ - std::shared_ptr armv7 = idm::make_ptr(name); - - armv7->PC = entry; - armv7->stack_size = stack_size; - armv7->prio = prio; - - thread = std::move(armv7); - - argc = 0; -} - -cpu_thread& armv7_thread::args(std::initializer_list values) -{ - assert(argc == 0); - - if (!values.size()) - { - return *this; - } - - std::vector argv_data; - u32 argv_size = 0; - - for (auto& arg : values) - { - const u32 arg_size = arg.size(); // get arg size - - for (char c : arg) - { - argv_data.push_back(c); // append characters - } - - argv_data.push_back('\0'); // append null terminator - - argv_size += arg_size + 1; - argc++; - } - - argv = vm::alloc(argv_size, vm::main); // allocate arg list - std::memcpy(vm::base(argv), argv_data.data(), argv_size); // copy arg list - - return *this; -} - -cpu_thread& armv7_thread::run() -{ - auto& armv7 = static_cast(*thread); - - armv7.run(); - - // set arguments - armv7.GPR[0] = argc; - armv7.GPR[1] = argv; - - return *this; -} diff --git a/rpcs3/Emu/ARMv7/ARMv7Thread.h b/rpcs3/Emu/ARMv7/ARMv7Thread.h index 878afb1aa6..1b6743c2da 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Thread.h +++ b/rpcs3/Emu/ARMv7/ARMv7Thread.h @@ -1,44 +1,271 @@ #pragma once -#include "Emu/CPU/CPUThread.h" -#include "ARMv7Context.h" -class ARMv7Thread final : public CPUThread, public ARMv7Context +#include "Emu/CPU/CPUThread.h" +#include "Emu/Memory/vm.h" + +enum ARMv7InstructionSet +{ + ARM, + Thumb, + Jazelle, + ThumbEE +}; + +class ARMv7Thread final : public cpu_thread { public: - std::function custom_task; - -public: - ARMv7Thread(const std::string& name); - virtual ~ARMv7Thread() override; - virtual std::string get_name() const override; - virtual void dump_info() const override; - virtual u32 get_pc() const override { return PC; } - virtual u32 get_offset() const override { return 0; } - virtual void do_run() override; + virtual std::string dump() const override; + virtual void cpu_init() override; virtual void cpu_task() override; - virtual void init_regs() override; - virtual void init_stack() override; - virtual void close_stack() override; - u32 get_stack_arg(u32 pos); + ARMv7Thread(const std::string& name) + : cpu_thread(cpu_type::arm, name) + { + } + + virtual ~ARMv7Thread() override; + + union + { + u32 GPR[15]; + + struct + { + u32 pad[13]; + + union + { + u32 SP; + + struct { u16 SP_main, SP_process; }; + }; + + u32 LR; + + union + { + struct + { + u32 reserved0 : 16; + u32 GE : 4; + u32 reserved1 : 4; + u32 dummy : 3; + u32 Q : 1; // Set to 1 if an SSAT or USAT instruction changes (saturates) the input value for the signed or unsigned range of the result + u32 V : 1; // Overflow condition code flag + u32 C : 1; // Carry condition code flag + u32 Z : 1; // Zero condition code flag + u32 N : 1; // Negative condition code flag + }; + + u32 APSR; + + } APSR; + }; + + struct + { + u64 GPR_D[8]; + }; + }; + + union + { + struct + { + u32 dummy : 24; + u32 exception : 8; + }; + + u32 IPSR; + + } IPSR; + + ARMv7InstructionSet ISET; + + union + { + struct + { + u8 shift_state : 5; + u8 cond_base : 3; + }; + + struct + { + u8 check_state : 4; + u8 condition : 4; + }; + + u8 IT; + + u32 advance() + { + // 0xf is "always true" and indicates that this instruction was not in IT block. + // 0xe is "always true" too and represents the AL condition of IT block. + // This makes a significant difference in some instructions. + const u32 res = check_state ? condition : 0xf; + + shift_state <<= 1; + if (!check_state) + { + IT = 0; // clear + } + + return res; + } + + operator bool() const + { + return check_state != 0; + } + + } ITSTATE; + + u32 TLS = 0; + + struct perf_counter + { + u32 event; + u32 value; + }; + + std::array counters{}; + + u32 PC = 0; + s32 prio = 0; + u32 stack_addr = 0; + u32 stack_size = 0; + + std::function custom_task; + + const char* last_function = nullptr; + + void write_pc(u32 value, u32 size) + { + ISET = value & 1 ? Thumb : ARM; + PC = (value & ~1) - size; + } + + u32 read_pc() + { + return ISET == ARM ? PC + 8 : PC + 4; + } + + u32 get_stack_arg(u32 pos) + { + return vm::psv::read32(SP + sizeof(u32) * (pos - 5)); + } + + void write_gpr(u32 n, u32 value, u32 size) + { + Expects(n < 16); + + if (n < 15) + { + GPR[n] = value; + } + else + { + write_pc(value, size); + } + } + + u32 read_gpr(u32 n) + { + Expects(n < 16); + + if (n < 15) + { + return GPR[n]; + } + + return read_pc(); + } + + // function for processing va_args in printf-like functions + u32 get_next_gpr_arg(u32& g_count) + { + if (g_count < 4) + { + return GPR[g_count++]; + } + else + { + return get_stack_arg(g_count++); + } + } + void fast_call(u32 addr); - void fast_stop(); - - virtual std::string RegsToString() const override; - virtual std::string ReadRegString(const std::string& reg) const override; - virtual bool WriteRegString(const std::string& reg, std::string value) override; }; -class armv7_thread : cpu_thread +template +struct arm_gpr_cast_impl { - u32 argv; - u32 argc; - -public: - armv7_thread(u32 entry, const std::string& name, u32 stack_size, s32 prio); - - cpu_thread& args(std::initializer_list values) override; - - cpu_thread& run() override; + static_assert(!sizeof(T), "Invalid type for arm_gpr_cast<>"); }; + +template +struct arm_gpr_cast_impl::value || std::is_enum::value>> +{ + static_assert(sizeof(T) <= 4, "Too big integral type for arm_gpr_cast<>()"); + static_assert(std::is_same::value == false, "bool type is deprecated in arm_gpr_cast<>(), use b8 instead"); + + static inline u32 to(const T& value) + { + return static_cast(value); + } + + static inline T from(const u32 reg) + { + return static_cast(reg); + } +}; + +template<> +struct arm_gpr_cast_impl +{ + static inline u32 to(const b8& value) + { + return value; + } + + static inline b8 from(const u32 reg) + { + return reg != 0; + } +}; + +template +struct arm_gpr_cast_impl, void> +{ + static inline u32 to(const vm::_ptr_base& value) + { + return arm_gpr_cast_impl::to(value.addr()); + } + + static inline vm::_ptr_base from(const u32 reg) + { + return{ arm_gpr_cast_impl::from(reg), vm::addr }; + } +}; + +template +struct arm_gpr_cast_impl, void> +{ + static inline u32 to(const vm::_ref_base& value) + { + return arm_gpr_cast_impl::to(value.addr()); + } + + static inline vm::_ref_base from(const u32 reg) + { + return{ arm_gpr_cast_impl::from(reg), vm::addr }; + } +}; + +template +inline To arm_gpr_cast(const From& value) +{ + return arm_gpr_cast_impl::from(arm_gpr_cast_impl::to(value)); +} diff --git a/rpcs3/Emu/ARMv7/ErrorCodes.h b/rpcs3/Emu/ARMv7/ErrorCodes.h new file mode 100644 index 0000000000..7cba3359e8 --- /dev/null +++ b/rpcs3/Emu/ARMv7/ErrorCodes.h @@ -0,0 +1,350 @@ +#pragma once + +#define ERROR_CODE(code) static_cast(code) + +enum SceOk : s32 +{ + SCE_OK = 0, +}; + +enum SceError : s32 +{ + SCE_ERROR_ERRNO_EPERM = ERROR_CODE(0x80010001), + SCE_ERROR_ERRNO_ENOENT = ERROR_CODE(0x80010002), + SCE_ERROR_ERRNO_ESRCH = ERROR_CODE(0x80010003), + SCE_ERROR_ERRNO_EINTR = ERROR_CODE(0x80010004), + SCE_ERROR_ERRNO_EIO = ERROR_CODE(0x80010005), + SCE_ERROR_ERRNO_ENXIO = ERROR_CODE(0x80010006), + SCE_ERROR_ERRNO_E2BIG = ERROR_CODE(0x80010007), + SCE_ERROR_ERRNO_ENOEXEC = ERROR_CODE(0x80010008), + SCE_ERROR_ERRNO_EBADF = ERROR_CODE(0x80010009), + SCE_ERROR_ERRNO_ECHILD = ERROR_CODE(0x8001000A), + SCE_ERROR_ERRNO_EAGAIN = ERROR_CODE(0x8001000B), + SCE_ERROR_ERRNO_ENOMEM = ERROR_CODE(0x8001000C), + SCE_ERROR_ERRNO_EACCES = ERROR_CODE(0x8001000D), + SCE_ERROR_ERRNO_EFAULT = ERROR_CODE(0x8001000E), + SCE_ERROR_ERRNO_ENOTBLK = ERROR_CODE(0x8001000F), + SCE_ERROR_ERRNO_EBUSY = ERROR_CODE(0x80010010), + SCE_ERROR_ERRNO_EEXIST = ERROR_CODE(0x80010011), + SCE_ERROR_ERRNO_EXDEV = ERROR_CODE(0x80010012), + SCE_ERROR_ERRNO_ENODEV = ERROR_CODE(0x80010013), + SCE_ERROR_ERRNO_ENOTDIR = ERROR_CODE(0x80010014), + SCE_ERROR_ERRNO_EISDIR = ERROR_CODE(0x80010015), + SCE_ERROR_ERRNO_EINVAL = ERROR_CODE(0x80010016), + SCE_ERROR_ERRNO_ENFILE = ERROR_CODE(0x80010017), + SCE_ERROR_ERRNO_EMFILE = ERROR_CODE(0x80010018), + SCE_ERROR_ERRNO_ENOTTY = ERROR_CODE(0x80010019), + SCE_ERROR_ERRNO_ETXTBSY = ERROR_CODE(0x8001001A), + SCE_ERROR_ERRNO_EFBIG = ERROR_CODE(0x8001001B), + SCE_ERROR_ERRNO_ENOSPC = ERROR_CODE(0x8001001C), + SCE_ERROR_ERRNO_ESPIPE = ERROR_CODE(0x8001001D), + SCE_ERROR_ERRNO_EROFS = ERROR_CODE(0x8001001E), + SCE_ERROR_ERRNO_EMLINK = ERROR_CODE(0x8001001F), + SCE_ERROR_ERRNO_EPIPE = ERROR_CODE(0x80010020), + SCE_ERROR_ERRNO_EDOM = ERROR_CODE(0x80010021), + SCE_ERROR_ERRNO_ERANGE = ERROR_CODE(0x80010022), + SCE_ERROR_ERRNO_ENOMSG = ERROR_CODE(0x80010023), + SCE_ERROR_ERRNO_EIDRM = ERROR_CODE(0x80010024), + SCE_ERROR_ERRNO_ECHRNG = ERROR_CODE(0x80010025), + SCE_ERROR_ERRNO_EL2NSYNC = ERROR_CODE(0x80010026), + SCE_ERROR_ERRNO_EL3HLT = ERROR_CODE(0x80010027), + SCE_ERROR_ERRNO_EL3RST = ERROR_CODE(0x80010028), + SCE_ERROR_ERRNO_ELNRNG = ERROR_CODE(0x80010029), + SCE_ERROR_ERRNO_EUNATCH = ERROR_CODE(0x8001002A), + SCE_ERROR_ERRNO_ENOCSI = ERROR_CODE(0x8001002B), + SCE_ERROR_ERRNO_EL2HLT = ERROR_CODE(0x8001002C), + SCE_ERROR_ERRNO_EDEADLK = ERROR_CODE(0x8001002D), + SCE_ERROR_ERRNO_ENOLCK = ERROR_CODE(0x8001002E), + SCE_ERROR_ERRNO_EFORMAT = ERROR_CODE(0x8001002F), + SCE_ERROR_ERRNO_EUNSUP = ERROR_CODE(0x80010030), + SCE_ERROR_ERRNO_EBADE = ERROR_CODE(0x80010032), + SCE_ERROR_ERRNO_EBADR = ERROR_CODE(0x80010033), + SCE_ERROR_ERRNO_EXFULL = ERROR_CODE(0x80010034), + SCE_ERROR_ERRNO_ENOANO = ERROR_CODE(0x80010035), + SCE_ERROR_ERRNO_EBADRQC = ERROR_CODE(0x80010036), + SCE_ERROR_ERRNO_EBADSLT = ERROR_CODE(0x80010037), + SCE_ERROR_ERRNO_EDEADLOCK = ERROR_CODE(0x80010038), + SCE_ERROR_ERRNO_EBFONT = ERROR_CODE(0x80010039), + SCE_ERROR_ERRNO_ENOSTR = ERROR_CODE(0x8001003C), + SCE_ERROR_ERRNO_ENODATA = ERROR_CODE(0x8001003D), + SCE_ERROR_ERRNO_ETIME = ERROR_CODE(0x8001003E), + SCE_ERROR_ERRNO_ENOSR = ERROR_CODE(0x8001003F), + SCE_ERROR_ERRNO_ENONET = ERROR_CODE(0x80010040), + SCE_ERROR_ERRNO_ENOPKG = ERROR_CODE(0x80010041), + SCE_ERROR_ERRNO_EREMOTE = ERROR_CODE(0x80010042), + SCE_ERROR_ERRNO_ENOLINK = ERROR_CODE(0x80010043), + SCE_ERROR_ERRNO_EADV = ERROR_CODE(0x80010044), + SCE_ERROR_ERRNO_ESRMNT = ERROR_CODE(0x80010045), + SCE_ERROR_ERRNO_ECOMM = ERROR_CODE(0x80010046), + SCE_ERROR_ERRNO_EPROTO = ERROR_CODE(0x80010047), + SCE_ERROR_ERRNO_EMULTIHOP = ERROR_CODE(0x8001004A), + SCE_ERROR_ERRNO_ELBIN = ERROR_CODE(0x8001004B), + SCE_ERROR_ERRNO_EDOTDOT = ERROR_CODE(0x8001004C), + SCE_ERROR_ERRNO_EBADMSG = ERROR_CODE(0x8001004D), + SCE_ERROR_ERRNO_EFTYPE = ERROR_CODE(0x8001004F), + SCE_ERROR_ERRNO_ENOTUNIQ = ERROR_CODE(0x80010050), + SCE_ERROR_ERRNO_EBADFD = ERROR_CODE(0x80010051), + SCE_ERROR_ERRNO_EREMCHG = ERROR_CODE(0x80010052), + SCE_ERROR_ERRNO_ELIBACC = ERROR_CODE(0x80010053), + SCE_ERROR_ERRNO_ELIBBAD = ERROR_CODE(0x80010054), + SCE_ERROR_ERRNO_ELIBSCN = ERROR_CODE(0x80010055), + SCE_ERROR_ERRNO_ELIBMAX = ERROR_CODE(0x80010056), + SCE_ERROR_ERRNO_ELIBEXEC = ERROR_CODE(0x80010057), + SCE_ERROR_ERRNO_ENOSYS = ERROR_CODE(0x80010058), + SCE_ERROR_ERRNO_ENMFILE = ERROR_CODE(0x80010059), + SCE_ERROR_ERRNO_ENOTEMPTY = ERROR_CODE(0x8001005A), + SCE_ERROR_ERRNO_ENAMETOOLONG = ERROR_CODE(0x8001005B), + SCE_ERROR_ERRNO_ELOOP = ERROR_CODE(0x8001005C), + SCE_ERROR_ERRNO_EOPNOTSUPP = ERROR_CODE(0x8001005F), + SCE_ERROR_ERRNO_EPFNOSUPPORT = ERROR_CODE(0x80010060), + SCE_ERROR_ERRNO_ECONNRESET = ERROR_CODE(0x80010068), + SCE_ERROR_ERRNO_ENOBUFS = ERROR_CODE(0x80010069), + SCE_ERROR_ERRNO_EAFNOSUPPORT = ERROR_CODE(0x8001006A), + SCE_ERROR_ERRNO_EPROTOTYPE = ERROR_CODE(0x8001006B), + SCE_ERROR_ERRNO_ENOTSOCK = ERROR_CODE(0x8001006C), + SCE_ERROR_ERRNO_ENOPROTOOPT = ERROR_CODE(0x8001006D), + SCE_ERROR_ERRNO_ESHUTDOWN = ERROR_CODE(0x8001006E), + SCE_ERROR_ERRNO_ECONNREFUSED = ERROR_CODE(0x8001006F), + SCE_ERROR_ERRNO_EADDRINUSE = ERROR_CODE(0x80010070), + SCE_ERROR_ERRNO_ECONNABORTED = ERROR_CODE(0x80010071), + SCE_ERROR_ERRNO_ENETUNREACH = ERROR_CODE(0x80010072), + SCE_ERROR_ERRNO_ENETDOWN = ERROR_CODE(0x80010073), + SCE_ERROR_ERRNO_ETIMEDOUT = ERROR_CODE(0x80010074), + SCE_ERROR_ERRNO_EHOSTDOWN = ERROR_CODE(0x80010075), + SCE_ERROR_ERRNO_EHOSTUNREACH = ERROR_CODE(0x80010076), + SCE_ERROR_ERRNO_EINPROGRESS = ERROR_CODE(0x80010077), + SCE_ERROR_ERRNO_EALREADY = ERROR_CODE(0x80010078), + SCE_ERROR_ERRNO_EDESTADDRREQ = ERROR_CODE(0x80010079), + SCE_ERROR_ERRNO_EMSGSIZE = ERROR_CODE(0x8001007A), + SCE_ERROR_ERRNO_EPROTONOSUPPORT = ERROR_CODE(0x8001007B), + SCE_ERROR_ERRNO_ESOCKTNOSUPPORT = ERROR_CODE(0x8001007C), + SCE_ERROR_ERRNO_EADDRNOTAVAIL = ERROR_CODE(0x8001007D), + SCE_ERROR_ERRNO_ENETRESET = ERROR_CODE(0x8001007E), + SCE_ERROR_ERRNO_EISCONN = ERROR_CODE(0x8001007F), + SCE_ERROR_ERRNO_ENOTCONN = ERROR_CODE(0x80010080), + SCE_ERROR_ERRNO_ETOOMANYREFS = ERROR_CODE(0x80010081), + SCE_ERROR_ERRNO_EPROCLIM = ERROR_CODE(0x80010082), + SCE_ERROR_ERRNO_EUSERS = ERROR_CODE(0x80010083), + SCE_ERROR_ERRNO_EDQUOT = ERROR_CODE(0x80010084), + SCE_ERROR_ERRNO_ESTALE = ERROR_CODE(0x80010085), + SCE_ERROR_ERRNO_ENOTSUP = ERROR_CODE(0x80010086), + SCE_ERROR_ERRNO_ENOMEDIUM = ERROR_CODE(0x80010087), + SCE_ERROR_ERRNO_ENOSHARE = ERROR_CODE(0x80010088), + SCE_ERROR_ERRNO_ECASECLASH = ERROR_CODE(0x80010089), + SCE_ERROR_ERRNO_EILSEQ = ERROR_CODE(0x8001008A), + SCE_ERROR_ERRNO_EOVERFLOW = ERROR_CODE(0x8001008B), + SCE_ERROR_ERRNO_ECANCELED = ERROR_CODE(0x8001008C), + SCE_ERROR_ERRNO_ENOTRECOVERABLE = ERROR_CODE(0x8001008D), + SCE_ERROR_ERRNO_EOWNERDEAD = ERROR_CODE(0x8001008E), +}; + +// Special return type signaling on errors +struct arm_error_code +{ + s32 value; + + // Print error message, error code is returned + static s32 report(s32 error, const char* text); + + // Must be specialized for specific tag type T + template + static const char* print(T code) + { + return nullptr; + } + + template + s32 error_check(T code) + { + if (const auto text = print(code)) + { + return report(code, text); + } + + return code; + } + + arm_error_code() = default; + + // General error check + template::value>> + arm_error_code(T value) + : value(error_check(value)) + { + } + + // Force error reporting with a message specified + arm_error_code(s32 value, const char* text) + : value(report(value, text)) + { + } + + // Silence any error + constexpr arm_error_code(s32 value, const std::nothrow_t&) + : value(value) + { + } + + // Conversion + constexpr operator s32() const + { + return value; + } +}; + +// Helper macro for silencing possible error checks on returning arm_error_code values +#define NOT_AN_ERROR(value) { static_cast(value), std::nothrow } + +template +struct arm_gpr_cast_impl; + +template<> +struct arm_gpr_cast_impl +{ + static inline u32 to(const arm_error_code& code) + { + return code; + } + + static inline arm_error_code from(const u32 reg) + { + return NOT_AN_ERROR(reg); + } +}; + +template<> +inline const char* arm_error_code::print(SceError error) +{ + switch (error) + { + STR_CASE(SCE_ERROR_ERRNO_EPERM); + STR_CASE(SCE_ERROR_ERRNO_ENOENT); + STR_CASE(SCE_ERROR_ERRNO_ESRCH); + STR_CASE(SCE_ERROR_ERRNO_EINTR); + STR_CASE(SCE_ERROR_ERRNO_EIO); + STR_CASE(SCE_ERROR_ERRNO_ENXIO); + STR_CASE(SCE_ERROR_ERRNO_E2BIG); + STR_CASE(SCE_ERROR_ERRNO_ENOEXEC); + STR_CASE(SCE_ERROR_ERRNO_EBADF); + STR_CASE(SCE_ERROR_ERRNO_ECHILD); + STR_CASE(SCE_ERROR_ERRNO_EAGAIN); + STR_CASE(SCE_ERROR_ERRNO_ENOMEM); + STR_CASE(SCE_ERROR_ERRNO_EACCES); + STR_CASE(SCE_ERROR_ERRNO_EFAULT); + STR_CASE(SCE_ERROR_ERRNO_ENOTBLK); + STR_CASE(SCE_ERROR_ERRNO_EBUSY); + STR_CASE(SCE_ERROR_ERRNO_EEXIST); + STR_CASE(SCE_ERROR_ERRNO_EXDEV); + STR_CASE(SCE_ERROR_ERRNO_ENODEV); + STR_CASE(SCE_ERROR_ERRNO_ENOTDIR); + STR_CASE(SCE_ERROR_ERRNO_EISDIR); + STR_CASE(SCE_ERROR_ERRNO_EINVAL); + STR_CASE(SCE_ERROR_ERRNO_ENFILE); + STR_CASE(SCE_ERROR_ERRNO_EMFILE); + STR_CASE(SCE_ERROR_ERRNO_ENOTTY); + STR_CASE(SCE_ERROR_ERRNO_ETXTBSY); + STR_CASE(SCE_ERROR_ERRNO_EFBIG); + STR_CASE(SCE_ERROR_ERRNO_ENOSPC); + STR_CASE(SCE_ERROR_ERRNO_ESPIPE); + STR_CASE(SCE_ERROR_ERRNO_EROFS); + STR_CASE(SCE_ERROR_ERRNO_EMLINK); + STR_CASE(SCE_ERROR_ERRNO_EPIPE); + STR_CASE(SCE_ERROR_ERRNO_EDOM); + STR_CASE(SCE_ERROR_ERRNO_ERANGE); + STR_CASE(SCE_ERROR_ERRNO_ENOMSG); + STR_CASE(SCE_ERROR_ERRNO_EIDRM); + STR_CASE(SCE_ERROR_ERRNO_ECHRNG); + STR_CASE(SCE_ERROR_ERRNO_EL2NSYNC); + STR_CASE(SCE_ERROR_ERRNO_EL3HLT); + STR_CASE(SCE_ERROR_ERRNO_EL3RST); + STR_CASE(SCE_ERROR_ERRNO_ELNRNG); + STR_CASE(SCE_ERROR_ERRNO_EUNATCH); + STR_CASE(SCE_ERROR_ERRNO_ENOCSI); + STR_CASE(SCE_ERROR_ERRNO_EL2HLT); + STR_CASE(SCE_ERROR_ERRNO_EDEADLK); + STR_CASE(SCE_ERROR_ERRNO_ENOLCK); + STR_CASE(SCE_ERROR_ERRNO_EFORMAT); + STR_CASE(SCE_ERROR_ERRNO_EUNSUP); + STR_CASE(SCE_ERROR_ERRNO_EBADE); + STR_CASE(SCE_ERROR_ERRNO_EBADR); + STR_CASE(SCE_ERROR_ERRNO_EXFULL); + STR_CASE(SCE_ERROR_ERRNO_ENOANO); + STR_CASE(SCE_ERROR_ERRNO_EBADRQC); + STR_CASE(SCE_ERROR_ERRNO_EBADSLT); + STR_CASE(SCE_ERROR_ERRNO_EDEADLOCK); + STR_CASE(SCE_ERROR_ERRNO_EBFONT); + STR_CASE(SCE_ERROR_ERRNO_ENOSTR); + STR_CASE(SCE_ERROR_ERRNO_ENODATA); + STR_CASE(SCE_ERROR_ERRNO_ETIME); + STR_CASE(SCE_ERROR_ERRNO_ENOSR); + STR_CASE(SCE_ERROR_ERRNO_ENONET); + STR_CASE(SCE_ERROR_ERRNO_ENOPKG); + STR_CASE(SCE_ERROR_ERRNO_EREMOTE); + STR_CASE(SCE_ERROR_ERRNO_ENOLINK); + STR_CASE(SCE_ERROR_ERRNO_EADV); + STR_CASE(SCE_ERROR_ERRNO_ESRMNT); + STR_CASE(SCE_ERROR_ERRNO_ECOMM); + STR_CASE(SCE_ERROR_ERRNO_EPROTO); + STR_CASE(SCE_ERROR_ERRNO_EMULTIHOP); + STR_CASE(SCE_ERROR_ERRNO_ELBIN); + STR_CASE(SCE_ERROR_ERRNO_EDOTDOT); + STR_CASE(SCE_ERROR_ERRNO_EBADMSG); + STR_CASE(SCE_ERROR_ERRNO_EFTYPE); + STR_CASE(SCE_ERROR_ERRNO_ENOTUNIQ); + STR_CASE(SCE_ERROR_ERRNO_EBADFD); + STR_CASE(SCE_ERROR_ERRNO_EREMCHG); + STR_CASE(SCE_ERROR_ERRNO_ELIBACC); + STR_CASE(SCE_ERROR_ERRNO_ELIBBAD); + STR_CASE(SCE_ERROR_ERRNO_ELIBSCN); + STR_CASE(SCE_ERROR_ERRNO_ELIBMAX); + STR_CASE(SCE_ERROR_ERRNO_ELIBEXEC); + STR_CASE(SCE_ERROR_ERRNO_ENOSYS); + STR_CASE(SCE_ERROR_ERRNO_ENMFILE); + STR_CASE(SCE_ERROR_ERRNO_ENOTEMPTY); + STR_CASE(SCE_ERROR_ERRNO_ENAMETOOLONG); + STR_CASE(SCE_ERROR_ERRNO_ELOOP); + STR_CASE(SCE_ERROR_ERRNO_EOPNOTSUPP); + STR_CASE(SCE_ERROR_ERRNO_EPFNOSUPPORT); + STR_CASE(SCE_ERROR_ERRNO_ECONNRESET); + STR_CASE(SCE_ERROR_ERRNO_ENOBUFS); + STR_CASE(SCE_ERROR_ERRNO_EAFNOSUPPORT); + STR_CASE(SCE_ERROR_ERRNO_EPROTOTYPE); + STR_CASE(SCE_ERROR_ERRNO_ENOTSOCK); + STR_CASE(SCE_ERROR_ERRNO_ENOPROTOOPT); + STR_CASE(SCE_ERROR_ERRNO_ESHUTDOWN); + STR_CASE(SCE_ERROR_ERRNO_ECONNREFUSED); + STR_CASE(SCE_ERROR_ERRNO_EADDRINUSE); + STR_CASE(SCE_ERROR_ERRNO_ECONNABORTED); + STR_CASE(SCE_ERROR_ERRNO_ENETUNREACH); + STR_CASE(SCE_ERROR_ERRNO_ENETDOWN); + STR_CASE(SCE_ERROR_ERRNO_ETIMEDOUT); + STR_CASE(SCE_ERROR_ERRNO_EHOSTDOWN); + STR_CASE(SCE_ERROR_ERRNO_EHOSTUNREACH); + STR_CASE(SCE_ERROR_ERRNO_EINPROGRESS); + STR_CASE(SCE_ERROR_ERRNO_EALREADY); + STR_CASE(SCE_ERROR_ERRNO_EDESTADDRREQ); + STR_CASE(SCE_ERROR_ERRNO_EMSGSIZE); + STR_CASE(SCE_ERROR_ERRNO_EPROTONOSUPPORT); + STR_CASE(SCE_ERROR_ERRNO_ESOCKTNOSUPPORT); + STR_CASE(SCE_ERROR_ERRNO_EADDRNOTAVAIL); + STR_CASE(SCE_ERROR_ERRNO_ENETRESET); + STR_CASE(SCE_ERROR_ERRNO_EISCONN); + STR_CASE(SCE_ERROR_ERRNO_ENOTCONN); + STR_CASE(SCE_ERROR_ERRNO_ETOOMANYREFS); + STR_CASE(SCE_ERROR_ERRNO_EPROCLIM); + STR_CASE(SCE_ERROR_ERRNO_EUSERS); + STR_CASE(SCE_ERROR_ERRNO_EDQUOT); + STR_CASE(SCE_ERROR_ERRNO_ESTALE); + STR_CASE(SCE_ERROR_ERRNO_ENOTSUP); + STR_CASE(SCE_ERROR_ERRNO_ENOMEDIUM); + STR_CASE(SCE_ERROR_ERRNO_ENOSHARE); + STR_CASE(SCE_ERROR_ERRNO_ECASECLASH); + STR_CASE(SCE_ERROR_ERRNO_EILSEQ); + STR_CASE(SCE_ERROR_ERRNO_EOVERFLOW); + STR_CASE(SCE_ERROR_ERRNO_ECANCELED); + STR_CASE(SCE_ERROR_ERRNO_ENOTRECOVERABLE); + STR_CASE(SCE_ERROR_ERRNO_EOWNERDEAD); + } + + return nullptr; +} diff --git a/rpcs3/Emu/ARMv7/Modules/sceAppMgr.cpp b/rpcs3/Emu/ARMv7/Modules/sceAppMgr.cpp index bc0d63c2b0..1dee409ee3 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceAppMgr.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceAppMgr.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceAppMgr.h" +LOG_CHANNEL(sceAppMgr); + s32 sceAppMgrReceiveEventNum(vm::ptr eventNum) { throw EXCEPTION(""); @@ -25,15 +27,10 @@ s32 sceAppMgrReleaseBgmPort() } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceAppMgr, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceAppMgrUser, nid, name) -psv_log_base sceAppMgr("SceAppMgr", []() +DECLARE(arm_module_manager::SceAppMgr)("SceAppMgrUser", []() { - sceAppMgr.on_load = nullptr; - sceAppMgr.on_unload = nullptr; - sceAppMgr.on_stop = nullptr; - sceAppMgr.on_error = nullptr; - REG_FUNC(0x47E5DD7D, sceAppMgrReceiveEventNum); REG_FUNC(0xCFAD5A3A, sceAppMgrReceiveEvent); REG_FUNC(0xF3D65520, sceAppMgrAcquireBgmPort); diff --git a/rpcs3/Emu/ARMv7/Modules/sceAppMgr.h b/rpcs3/Emu/ARMv7/Modules/sceAppMgr.h index 8329b62e14..8768ba0c2a 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceAppMgr.h +++ b/rpcs3/Emu/ARMv7/Modules/sceAppMgr.h @@ -6,5 +6,3 @@ struct SceAppMgrEvent le_t appId; char param[56]; }; - -extern psv_log_base sceAppMgr; diff --git a/rpcs3/Emu/ARMv7/Modules/sceAppUtil.cpp b/rpcs3/Emu/ARMv7/Modules/sceAppUtil.cpp index f05c91b0ec..6d63c2bf94 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceAppUtil.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceAppUtil.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceAppUtil.h" +LOG_CHANNEL(sceAppUtil); + s32 sceAppUtilInit(vm::cptr initParam, vm::ptr bootParam) { throw EXCEPTION(""); @@ -70,15 +72,10 @@ s32 sceAppUtilLoadSafeMemory(vm::ptr buf, u32 bufSize, s64 offset) } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceAppUtil, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceAppUtil, nid, name) -psv_log_base sceAppUtil("SceAppUtil", []() +DECLARE(arm_module_manager::SceAppUtil)("SceAppUtil", []() { - sceAppUtil.on_load = nullptr; - sceAppUtil.on_unload = nullptr; - sceAppUtil.on_stop = nullptr; - sceAppUtil.on_error = nullptr; - REG_FUNC(0xDAFFE671, sceAppUtilInit); REG_FUNC(0xB220B00B, sceAppUtilShutdown); REG_FUNC(0x7E8FE96A, sceAppUtilSaveDataSlotCreate); diff --git a/rpcs3/Emu/ARMv7/Modules/sceAppUtil.h b/rpcs3/Emu/ARMv7/Modules/sceAppUtil.h index b3e9fc4448..3e3ef55694 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceAppUtil.h +++ b/rpcs3/Emu/ARMv7/Modules/sceAppUtil.h @@ -65,5 +65,3 @@ struct SceAppUtilSaveDataFileSlot vm::lptr slotParam; char reserved[32]; }; - -extern psv_log_base sceAppUtil; diff --git a/rpcs3/Emu/ARMv7/Modules/sceAudio.cpp b/rpcs3/Emu/ARMv7/Modules/sceAudio.cpp index c4107eef55..0261c2e89b 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceAudio.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceAudio.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceAudio.h" +LOG_CHANNEL(sceAudio); + s32 sceAudioOutOpenPort(s32 portType, s32 len, s32 freq, s32 param) { throw EXCEPTION(""); @@ -45,15 +47,10 @@ s32 sceAudioOutGetAdopt(s32 portType) } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceAudio, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceAudio, nid, name) -psv_log_base sceAudio("SceAudio", []() +DECLARE(arm_module_manager::SceAudio)("SceAudio", []() { - sceAudio.on_load = nullptr; - sceAudio.on_unload = nullptr; - sceAudio.on_stop = nullptr; - sceAudio.on_error = nullptr; - REG_FUNC(0x5BC341E4, sceAudioOutOpenPort); REG_FUNC(0x69E2E6B5, sceAudioOutReleasePort); REG_FUNC(0x02DB3F5F, sceAudioOutOutput); diff --git a/rpcs3/Emu/ARMv7/Modules/sceAudio.h b/rpcs3/Emu/ARMv7/Modules/sceAudio.h index f6c654b5d0..6f70f09bee 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceAudio.h +++ b/rpcs3/Emu/ARMv7/Modules/sceAudio.h @@ -1,3 +1 @@ #pragma once - -extern psv_log_base sceAudio; diff --git a/rpcs3/Emu/ARMv7/Modules/sceAudioIn.cpp b/rpcs3/Emu/ARMv7/Modules/sceAudioIn.cpp index 03523adbd2..b97a8c6988 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceAudioIn.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceAudioIn.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceAudioIn.h" +LOG_CHANNEL(sceAudioIn); + s32 sceAudioInOpenPort(s32 portType, s32 grain, s32 freq, s32 param) { throw EXCEPTION(""); @@ -20,15 +22,10 @@ s32 sceAudioInInput(s32 port, vm::ptr destPtr) } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceAudioIn, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceAudioIn, nid, name) -psv_log_base sceAudioIn("SceAudioIn", []() +DECLARE(arm_module_manager::SceAudioIn)("SceAudioIn", []() { - sceAudioIn.on_load = nullptr; - sceAudioIn.on_unload = nullptr; - sceAudioIn.on_stop = nullptr; - sceAudioIn.on_error = nullptr; - REG_FUNC(0x638ADD2D, sceAudioInInput); REG_FUNC(0x39B50DC1, sceAudioInOpenPort); REG_FUNC(0x3A61B8C4, sceAudioInReleasePort); diff --git a/rpcs3/Emu/ARMv7/Modules/sceAudioIn.h b/rpcs3/Emu/ARMv7/Modules/sceAudioIn.h index ff85239855..6f70f09bee 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceAudioIn.h +++ b/rpcs3/Emu/ARMv7/Modules/sceAudioIn.h @@ -1,3 +1 @@ #pragma once - -extern psv_log_base sceAudioIn; diff --git a/rpcs3/Emu/ARMv7/Modules/sceAudiodec.cpp b/rpcs3/Emu/ARMv7/Modules/sceAudiodec.cpp index abb147a619..bce2640203 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceAudiodec.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceAudiodec.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceAudiodec.h" +LOG_CHANNEL(sceAudiodec); + s32 sceAudiodecInitLibrary(u32 codecType, vm::ptr pInitParam) { throw EXCEPTION(""); @@ -40,15 +42,10 @@ s32 sceAudiodecGetInternalError(vm::ptr pCtrl, vm::ptr pIn } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceAudiodec, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceAudiodecUser, nid, name) -psv_log_base sceAudiodec("SceAudiodec", []() +DECLARE(arm_module_manager::SceAudiodec)("SceAudiodecUser", []() { - sceAudiodec.on_load = nullptr; - sceAudiodec.on_unload = nullptr; - sceAudiodec.on_stop = nullptr; - sceAudiodec.on_error = nullptr; - REG_FUNC(0x445C2CEF, sceAudiodecInitLibrary); REG_FUNC(0x45719B9D, sceAudiodecTermLibrary); REG_FUNC(0x4DFD3AAA, sceAudiodecCreateDecoder); diff --git a/rpcs3/Emu/ARMv7/Modules/sceAudiodec.h b/rpcs3/Emu/ARMv7/Modules/sceAudiodec.h index cfa6c12b80..eb8c29bd3c 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceAudiodec.h +++ b/rpcs3/Emu/ARMv7/Modules/sceAudiodec.h @@ -79,5 +79,3 @@ struct SceAudiodecCtrl le_t wordLength; vm::lptr pInfo; }; - -extern psv_log_base sceAudiodec; diff --git a/rpcs3/Emu/ARMv7/Modules/sceAudioenc.cpp b/rpcs3/Emu/ARMv7/Modules/sceAudioenc.cpp index 73cdfe8b5a..ca7bc17aec 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceAudioenc.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceAudioenc.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceAudioenc.h" +LOG_CHANNEL(sceAudioenc); + s32 sceAudioencInitLibrary(u32 codecType, vm::ptr pInitParam) { throw EXCEPTION(""); @@ -45,15 +47,10 @@ s32 sceAudioencGetInternalError(vm::ptr pCtrl, vm::ptr pIn } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceAudioenc, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceAudioencUser, nid, name) -psv_log_base sceAudioenc("SceAudioenc", []() +DECLARE(arm_module_manager::SceAudioenc)("SceAudioencUser", []() { - sceAudioenc.on_load = nullptr; - sceAudioenc.on_unload = nullptr; - sceAudioenc.on_stop = nullptr; - sceAudioenc.on_error = nullptr; - REG_FUNC(0x76EE4DC6, sceAudioencInitLibrary); REG_FUNC(0xAB32D022, sceAudioencTermLibrary); REG_FUNC(0x64C04AE8, sceAudioencCreateEncoder); diff --git a/rpcs3/Emu/ARMv7/Modules/sceAudioenc.h b/rpcs3/Emu/ARMv7/Modules/sceAudioenc.h index 9b361005e0..b67cf8eb24 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceAudioenc.h +++ b/rpcs3/Emu/ARMv7/Modules/sceAudioenc.h @@ -55,5 +55,3 @@ struct SceAudioencCtrl vm::lptr pInfo; vm::lptr pOptInfo; }; - -extern psv_log_base sceAudioenc; diff --git a/rpcs3/Emu/ARMv7/Modules/sceCamera.cpp b/rpcs3/Emu/ARMv7/Modules/sceCamera.cpp index d5ff9d996d..766b450b4f 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceCamera.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceCamera.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceCamera.h" +LOG_CHANNEL(sceCamera); + s32 sceCameraOpen(s32 devnum, vm::ptr pInfo) { throw EXCEPTION(""); @@ -210,15 +212,10 @@ void sceCameraUseCacheMemoryForTrial(s32 isCache) } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceCamera, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceCamera, nid, name) -psv_log_base sceCamera("SceCamera", []() +DECLARE(arm_module_manager::SceCamera)("SceCamera", []() { - sceCamera.on_load = nullptr; - sceCamera.on_unload = nullptr; - sceCamera.on_stop = nullptr; - sceCamera.on_error = nullptr; - REG_FUNC(0xA462F801, sceCameraOpen); REG_FUNC(0xCD6E1CFC, sceCameraClose); REG_FUNC(0xA8FEAE35, sceCameraStart); diff --git a/rpcs3/Emu/ARMv7/Modules/sceCamera.h b/rpcs3/Emu/ARMv7/Modules/sceCamera.h index b0edcf3b77..20a735db31 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceCamera.h +++ b/rpcs3/Emu/ARMv7/Modules/sceCamera.h @@ -36,5 +36,3 @@ struct SceCameraRead vm::lptr pvUBase; vm::lptr pvVBase; }; - -extern psv_log_base sceCamera; diff --git a/rpcs3/Emu/ARMv7/Modules/sceCodecEngine.cpp b/rpcs3/Emu/ARMv7/Modules/sceCodecEngine.cpp index cfb84e9cfe..0fb17012d2 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceCodecEngine.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceCodecEngine.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceCodecEngine.h" +LOG_CHANNEL(sceCodecEngine); + s32 sceCodecEnginePmonStart() { throw EXCEPTION(""); @@ -25,15 +27,10 @@ s32 sceCodecEnginePmonReset() } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceCodecEngine, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceCodecEngine, nid, name) -psv_log_base sceCodecEngine("SceCodecEngine", []() +DECLARE(arm_module_manager::SceCodecEngine)("SceCodecEngine", []() { - sceCodecEngine.on_load = nullptr; - sceCodecEngine.on_unload = nullptr; - sceCodecEngine.on_stop = nullptr; - sceCodecEngine.on_error = nullptr; - REG_FUNC(0x3E718890, sceCodecEnginePmonStart); REG_FUNC(0x268B1EF5, sceCodecEnginePmonStop); REG_FUNC(0x859E4A68, sceCodecEnginePmonGetProcessorLoad); diff --git a/rpcs3/Emu/ARMv7/Modules/sceCodecEngine.h b/rpcs3/Emu/ARMv7/Modules/sceCodecEngine.h index 9cd72d5598..95cb73031a 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceCodecEngine.h +++ b/rpcs3/Emu/ARMv7/Modules/sceCodecEngine.h @@ -5,5 +5,3 @@ struct SceCodecEnginePmonProcessorLoad le_t size; le_t average; }; - -extern psv_log_base sceCodecEngine; diff --git a/rpcs3/Emu/ARMv7/Modules/sceCommonDialog.cpp b/rpcs3/Emu/ARMv7/Modules/sceCommonDialog.cpp index b63dd9d202..c3c290dc53 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceCommonDialog.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceCommonDialog.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceCommonDialog.h" +LOG_CHANNEL(sceCommonDialog); + s32 sceCommonDialogUpdate(vm::cptr updateParam) { throw EXCEPTION(""); @@ -205,15 +207,10 @@ s32 scePhotoReviewDialogAbort() } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceCommonDialog, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceCommonDialog, nid, name) -psv_log_base sceCommonDialog("SceCommonDialog", []() +DECLARE(arm_module_manager::SceCommonDialog)("SceCommonDialog", []() { - sceCommonDialog.on_load = nullptr; - sceCommonDialog.on_unload = nullptr; - sceCommonDialog.on_stop = nullptr; - sceCommonDialog.on_error = nullptr; - REG_FUNC(0x90530F2F, sceCommonDialogUpdate); REG_FUNC(0x755FF270, sceMsgDialogInit); REG_FUNC(0x4107019E, sceMsgDialogGetStatus); diff --git a/rpcs3/Emu/ARMv7/Modules/sceCommonDialog.h b/rpcs3/Emu/ARMv7/Modules/sceCommonDialog.h index 564c9eabea..1fcbcdb578 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceCommonDialog.h +++ b/rpcs3/Emu/ARMv7/Modules/sceCommonDialog.h @@ -298,5 +298,3 @@ struct ScePhotoReviewDialogResult le_t result; char reserved[32]; }; - -extern psv_log_base sceCommonDialog; diff --git a/rpcs3/Emu/ARMv7/Modules/sceCtrl.cpp b/rpcs3/Emu/ARMv7/Modules/sceCtrl.cpp index 3dc74100c4..1351e97738 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceCtrl.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceCtrl.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceCtrl.h" +LOG_CHANNEL(sceCtrl); + s32 sceCtrlSetSamplingMode(u32 uiMode) { throw EXCEPTION(""); @@ -45,15 +47,10 @@ s32 sceCtrlClearRapidFire(s32 port, s32 idx) } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceCtrl, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceCtrl, nid, name) -psv_log_base sceCtrl("SceCtrl", []() +DECLARE(arm_module_manager::SceCtrl)("SceCtrl", []() { - sceCtrl.on_load = nullptr; - sceCtrl.on_unload = nullptr; - sceCtrl.on_stop = nullptr; - sceCtrl.on_error = nullptr; - REG_FUNC(0xA497B150, sceCtrlSetSamplingMode); REG_FUNC(0xEC752AAF, sceCtrlGetSamplingMode); REG_FUNC(0xA9C3CED6, sceCtrlPeekBufferPositive); diff --git a/rpcs3/Emu/ARMv7/Modules/sceCtrl.h b/rpcs3/Emu/ARMv7/Modules/sceCtrl.h index 278e478b78..3039299611 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceCtrl.h +++ b/rpcs3/Emu/ARMv7/Modules/sceCtrl.h @@ -20,5 +20,3 @@ struct SceCtrlRapidFireRule le_t uiMake; le_t uiBreak; }; - -extern psv_log_base sceCtrl; diff --git a/rpcs3/Emu/ARMv7/Modules/sceDbg.cpp b/rpcs3/Emu/ARMv7/Modules/sceDbg.cpp index 262b0ea7d9..3617d18e07 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceDbg.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceDbg.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceDbg.h" +LOG_CHANNEL(sceDbg); + s32 sceDbgSetMinimumLogLevel(s32 minimumLogLevel) { throw EXCEPTION(""); @@ -14,26 +16,21 @@ s32 sceDbgSetBreakOnErrorState(SceDbgBreakOnErrorState state) throw EXCEPTION(""); } -s32 sceDbgAssertionHandler(vm::cptr pFile, s32 line, b8 stop, vm::cptr pComponent, vm::cptr pMessage, armv7_va_args_t va_args) +s32 sceDbgAssertionHandler(vm::cptr pFile, s32 line, b8 stop, vm::cptr pComponent, vm::cptr pMessage, arm_va_args_t va_args) { throw EXCEPTION(""); } -s32 sceDbgLoggingHandler(vm::cptr pFile, s32 line, s32 severity, vm::cptr pComponent, vm::cptr pMessage, armv7_va_args_t va_args) +s32 sceDbgLoggingHandler(vm::cptr pFile, s32 line, s32 severity, vm::cptr pComponent, vm::cptr pMessage, arm_va_args_t va_args) { throw EXCEPTION(""); } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceDbg, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceDbg, nid, name) -psv_log_base sceDbg("SceDbg", []() +DECLARE(arm_module_manager::SceDbg)("SceDbg", []() { - sceDbg.on_load = nullptr; - sceDbg.on_unload = nullptr; - sceDbg.on_stop = nullptr; - sceDbg.on_error = nullptr; - REG_FUNC(0x941622FA, sceDbgSetMinimumLogLevel); REG_FUNC(0x1AF3678B, sceDbgAssertionHandler); REG_FUNC(0x6605AB19, sceDbgLoggingHandler); diff --git a/rpcs3/Emu/ARMv7/Modules/sceDbg.h b/rpcs3/Emu/ARMv7/Modules/sceDbg.h index c9136a4c0f..dbc556af2c 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceDbg.h +++ b/rpcs3/Emu/ARMv7/Modules/sceDbg.h @@ -5,5 +5,3 @@ enum SceDbgBreakOnErrorState : s32 SCE_DBG_DISABLE_BREAK_ON_ERROR = 0, SCE_DBG_ENABLE_BREAK_ON_ERROR }; - -extern psv_log_base sceDbg; diff --git a/rpcs3/Emu/ARMv7/Modules/sceDeci4p.cpp b/rpcs3/Emu/ARMv7/Modules/sceDeci4p.cpp index 1553aa4bf3..abacc1199e 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceDeci4p.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceDeci4p.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceDeci4p.h" +LOG_CHANNEL(sceDeci4p); + s32 sceKernelDeci4pOpen(vm::cptr protoname, u32 protonum, u32 bufsize) { throw EXCEPTION(""); @@ -30,15 +32,10 @@ s32 sceKernelDeci4pRegisterCallback(s32 socketid, s32 cbid) } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceDeci4p, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceDeci4pUserp, nid, name) -psv_log_base sceDeci4p("SceDeci4pUserp", []() +DECLARE(arm_module_manager::SceDeci4p)("SceDeci4pUserp", []() { - sceDeci4p.on_load = nullptr; - sceDeci4p.on_unload = nullptr; - sceDeci4p.on_stop = nullptr; - sceDeci4p.on_error = nullptr; - REG_FUNC(0x28578FE8, sceKernelDeci4pOpen); REG_FUNC(0x63B0C50F, sceKernelDeci4pClose); REG_FUNC(0x971E1C66, sceKernelDeci4pRead); diff --git a/rpcs3/Emu/ARMv7/Modules/sceDeci4p.h b/rpcs3/Emu/ARMv7/Modules/sceDeci4p.h index 98f9e59faa..4393fdcf88 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceDeci4p.h +++ b/rpcs3/Emu/ARMv7/Modules/sceDeci4p.h @@ -1,5 +1,3 @@ #pragma once using SceKernelDeci4pCallback = s32(s32 notifyId, s32 notifyCount, s32 notifyArg, vm::ptr pCommon); - -extern psv_log_base sceDeci4p; diff --git a/rpcs3/Emu/ARMv7/Modules/sceDeflt.cpp b/rpcs3/Emu/ARMv7/Modules/sceDeflt.cpp index 2aa496213c..dc70310c59 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceDeflt.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceDeflt.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceDeflt.h" +LOG_CHANNEL(sceDeflt); + s32 sceGzipIsValid(vm::cptr pSrcGzip) { throw EXCEPTION(""); @@ -70,15 +72,10 @@ s32 sceZipGetInfo(vm::cptr pSrc, vm::cpptr ppvExtra, vm::ptr pu } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceDeflt, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceDeflt, nid, name) -psv_log_base sceDeflt("SceDeflt", []() +DECLARE(arm_module_manager::SceDeflt)("SceDeflt", []() { - sceDeflt.on_load = nullptr; - sceDeflt.on_unload = nullptr; - sceDeflt.on_stop = nullptr; - sceDeflt.on_error = nullptr; - REG_FUNC(0xCD83A464, sceZlibAdler32); REG_FUNC(0x110D5050, sceDeflateDecompress); REG_FUNC(0xE3CB51A3, sceGzipDecompress); diff --git a/rpcs3/Emu/ARMv7/Modules/sceDeflt.h b/rpcs3/Emu/ARMv7/Modules/sceDeflt.h index 1d61e9f7b1..6f70f09bee 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceDeflt.h +++ b/rpcs3/Emu/ARMv7/Modules/sceDeflt.h @@ -1,3 +1 @@ #pragma once - -extern psv_log_base sceDeflt; diff --git a/rpcs3/Emu/ARMv7/Modules/sceDisplay.cpp b/rpcs3/Emu/ARMv7/Modules/sceDisplay.cpp index 48e1eed48a..b9f978e3b0 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceDisplay.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceDisplay.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceDisplay.h" +LOG_CHANNEL(sceDisplay); + s32 sceDisplayGetRefreshRate(vm::ptr pFps) { throw EXCEPTION(""); @@ -75,20 +77,16 @@ s32 sceDisplayUnregisterVblankStartCallback(s32 uid) } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceDisplay, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceDisplay, nid, name) -psv_log_base sceDisplay("SceDisplay", []() +DECLARE(arm_module_manager::SceDisplayUser)("SceDisplayUser", []() { - sceDisplay.on_load = nullptr; - sceDisplay.on_unload = nullptr; - sceDisplay.on_stop = nullptr; - sceDisplay.on_error = nullptr; + REG_FNID(SceDisplayUser, 0x7A410B64, sceDisplaySetFrameBuf); + REG_FNID(SceDisplayUser, 0x42AE6BBC, sceDisplayGetFrameBuf); +}); - // SceDisplayUser - REG_FUNC(0x7A410B64, sceDisplaySetFrameBuf); - REG_FUNC(0x42AE6BBC, sceDisplayGetFrameBuf); - - // SceDisplay +DECLARE(arm_module_manager::SceDisplay)("SceDisplay", []() +{ REG_FUNC(0xA08CA60D, sceDisplayGetRefreshRate); REG_FUNC(0xB6FDE0BA, sceDisplayGetVcount); REG_FUNC(0x5795E898, sceDisplayWaitVblankStart); diff --git a/rpcs3/Emu/ARMv7/Modules/sceDisplay.h b/rpcs3/Emu/ARMv7/Modules/sceDisplay.h index cce29c9e38..9835022740 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceDisplay.h +++ b/rpcs3/Emu/ARMv7/Modules/sceDisplay.h @@ -9,5 +9,3 @@ struct SceDisplayFrameBuf le_t width; le_t height; }; - -extern psv_log_base sceDisplay; diff --git a/rpcs3/Emu/ARMv7/Modules/sceFiber.cpp b/rpcs3/Emu/ARMv7/Modules/sceFiber.cpp index 44fab30de3..bc769383df 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceFiber.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceFiber.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceFiber.h" +LOG_CHANNEL(sceFiber); + s32 _sceFiberInitializeImpl(vm::ptr fiber, vm::cptr name, vm::ptr entry, u32 argOnInitialize, vm::ptr addrContext, u32 sizeContext, vm::cptr optParam, u32 buildVersion) { throw EXCEPTION(""); @@ -45,15 +47,10 @@ s32 sceFiberGetInfo(vm::ptr fiber, vm::ptr fiberInfo) } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceFiber, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceFiber, nid, name) -psv_log_base sceFiber("SceFiber", []() +DECLARE(arm_module_manager::SceFiber)("SceFiber", []() { - sceFiber.on_load = nullptr; - sceFiber.on_unload = nullptr; - sceFiber.on_stop = nullptr; - sceFiber.on_error = nullptr; - REG_FUNC(0xF24A298C, _sceFiberInitializeImpl); //REG_FUNC(0xC6A3F9BB, _sceFiberInitializeWithInternalOptionImpl); //REG_FUNC(0x7D0C7DDB, _sceFiberAttachContextAndRun); diff --git a/rpcs3/Emu/ARMv7/Modules/sceFiber.h b/rpcs3/Emu/ARMv7/Modules/sceFiber.h index 11e40b0476..cbc65d6547 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceFiber.h +++ b/rpcs3/Emu/ARMv7/Modules/sceFiber.h @@ -27,5 +27,3 @@ struct alignas(8) SceFiberInfo }; CHECK_SIZE_ALIGN(SceFiberInfo, 128, 8); - -extern psv_log_base sceFiber; diff --git a/rpcs3/Emu/ARMv7/Modules/sceFios.cpp b/rpcs3/Emu/ARMv7/Modules/sceFios.cpp index 1ee3a319aa..67420d112f 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceFios.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceFios.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceFios.h" +LOG_CHANNEL(sceFios); + s32 sceFiosInitialize(vm::cptr pParameters) { throw EXCEPTION(""); @@ -119,7 +121,7 @@ s32 sceFiosPathncmp(vm::cptr pA, vm::cptr pB, u32 n) throw EXCEPTION(""); } -s32 sceFiosPrintf(vm::cptr pFormat, armv7_va_args_t va_args) +s32 sceFiosPrintf(vm::cptr pFormat, arm_va_args_t va_args) { throw EXCEPTION(""); } @@ -684,15 +686,10 @@ void sceFiosIOFilterPsarcDearchiver() throw EXCEPTION(""); } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceFios, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceFios2, nid, name) -psv_log_base sceFios("SceFios2", []() +DECLARE(arm_module_manager::SceFios)("SceFios2", []() { - sceFios.on_load = nullptr; - sceFios.on_unload = nullptr; - sceFios.on_stop = nullptr; - sceFios.on_error = nullptr; - REG_FUNC(0x15857180, sceFiosArchiveGetMountBufferSize); REG_FUNC(0xDF3352FC, sceFiosArchiveGetMountBufferSizeSync); //REG_FUNC(0x92E76BBD, sceFiosArchiveMount); diff --git a/rpcs3/Emu/ARMv7/Modules/sceFios.h b/rpcs3/Emu/ARMv7/Modules/sceFios.h index 0babf0ac0f..569c663893 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceFios.h +++ b/rpcs3/Emu/ARMv7/Modules/sceFios.h @@ -1,7 +1,7 @@ #pragma once using SceFiosOpCallback = s32(vm::ptr pContext, s32 op, u8 event, s32 err); -using SceFiosVprintfCallback = s32(vm::cptr fmt, armv7_va_args_t ap /* va_list */); +using SceFiosVprintfCallback = s32(vm::cptr fmt, arm_va_args_t ap /* va_list */); using SceFiosMemcpyCallback = vm::ptr(vm::ptr dst, vm::cptr src, u32 len); enum SceFiosWhence : s32 @@ -109,5 +109,3 @@ struct SceFiosPsarcDearchiverContext vm::lptr pWorkBuffer; le_t reserved[4]; }; - -extern psv_log_base sceFios; diff --git a/rpcs3/Emu/ARMv7/Modules/sceFpu.cpp b/rpcs3/Emu/ARMv7/Modules/sceFpu.cpp index 27b7c6e5c7..9dda61cf8e 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceFpu.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceFpu.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceFpu.h" +LOG_CHANNEL(sceFpu); + float sceFpuSinf(float x) { throw EXCEPTION(""); @@ -76,15 +78,10 @@ float sceFpuPowf(float x, float y) } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceFpu, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceFpu, nid, name) -psv_log_base sceFpu("SceFpu", []() +DECLARE(arm_module_manager::SceFpu)("SceFpu", []() { - sceFpu.on_load = nullptr; - sceFpu.on_unload = nullptr; - sceFpu.on_stop = nullptr; - sceFpu.on_error = nullptr; - //REG_FUNC(0x33E1AC14, sceFpuSinf); //REG_FUNC(0xDB66BA89, sceFpuCosf); //REG_FUNC(0x6FBDA1C9, sceFpuTanf); diff --git a/rpcs3/Emu/ARMv7/Modules/sceFpu.h b/rpcs3/Emu/ARMv7/Modules/sceFpu.h index 2df62880d4..6f70f09bee 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceFpu.h +++ b/rpcs3/Emu/ARMv7/Modules/sceFpu.h @@ -1,3 +1 @@ #pragma once - -extern psv_log_base sceFpu; diff --git a/rpcs3/Emu/ARMv7/Modules/sceGxm.cpp b/rpcs3/Emu/ARMv7/Modules/sceGxm.cpp index ae0f51a416..22fb6d3a92 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceGxm.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceGxm.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceGxm.h" +LOG_CHANNEL(sceGxm); + s32 sceGxmInitialize(vm::cptr params) { throw EXCEPTION(""); @@ -1067,15 +1069,10 @@ s32 sceGxmSetUniformDataF(vm::ptr uniformBuffer, vm::cptr hostMemSize; le_t driverMemBlock; }; - -extern psv_log_base sceGxm; diff --git a/rpcs3/Emu/ARMv7/Modules/sceHttp.cpp b/rpcs3/Emu/ARMv7/Modules/sceHttp.cpp index 6d7417ffea..1889742d60 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceHttp.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceHttp.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceHttp.h" +LOG_CHANNEL(sceHttp); + s32 sceHttpInit(u32 poolSize) { throw EXCEPTION(""); @@ -280,15 +282,10 @@ s32 sceHttpsFreeCaList(vm::ptr caList) } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceHttp, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceHttp, nid, name) -psv_log_base sceHttp("SceHttp", []() +DECLARE(arm_module_manager::SceHttp)("SceHttp", []() { - sceHttp.on_load = nullptr; - sceHttp.on_unload = nullptr; - sceHttp.on_stop = nullptr; - sceHttp.on_error = nullptr; - REG_FUNC(0x214926D9, sceHttpInit); REG_FUNC(0xC9076666, sceHttpTerm); REG_FUNC(0xF98CDFA9, sceHttpGetMemoryPoolStats); diff --git a/rpcs3/Emu/ARMv7/Modules/sceHttp.h b/rpcs3/Emu/ARMv7/Modules/sceHttp.h index 69e027bb06..1736330349 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceHttp.h +++ b/rpcs3/Emu/ARMv7/Modules/sceHttp.h @@ -70,5 +70,3 @@ struct SceHttpsCaList }; using SceHttpsCallback = s32(u32 verifyEsrr, vm::cptr> sslCert, s32 certNum, vm::ptr userArg); - -extern psv_log_base sceHttp; diff --git a/rpcs3/Emu/ARMv7/Modules/sceIme.cpp b/rpcs3/Emu/ARMv7/Modules/sceIme.cpp index c903c58309..7404b7d5d5 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceIme.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceIme.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceIme.h" +LOG_CHANNEL(sceIme); + s32 sceImeOpen(vm::ptr param) { throw EXCEPTION(""); @@ -30,15 +32,10 @@ s32 sceImeClose() } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceIme, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceIme, nid, name) -psv_log_base sceIme("SceIme", []() +DECLARE(arm_module_manager::SceIme)("SceIme", []() { - sceIme.on_load = nullptr; - sceIme.on_unload = nullptr; - sceIme.on_stop = nullptr; - sceIme.on_error = nullptr; - REG_FUNC(0x0E050613, sceImeOpen); REG_FUNC(0x71D6898A, sceImeUpdate); REG_FUNC(0x889A8421, sceImeClose); diff --git a/rpcs3/Emu/ARMv7/Modules/sceIme.h b/rpcs3/Emu/ARMv7/Modules/sceIme.h index 27aaf63987..40b98c9e3e 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceIme.h +++ b/rpcs3/Emu/ARMv7/Modules/sceIme.h @@ -66,5 +66,3 @@ struct SceImeParam le_t reserved0; le_t reserved1; }; - -extern psv_log_base sceIme; diff --git a/rpcs3/Emu/ARMv7/Modules/sceJpeg.cpp b/rpcs3/Emu/ARMv7/Modules/sceJpeg.cpp index c09b1a15ad..cc003a075a 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceJpeg.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceJpeg.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceJpeg.h" +LOG_CHANNEL(sceJpeg); + s32 sceJpegInitMJpeg(s32 maxSplitDecoder) { throw EXCEPTION(""); @@ -77,15 +79,10 @@ s32 sceJpegSplitDecodeMJpeg(vm::ptr pCtrl) } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceJpeg, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceJpegUser, nid, name) -psv_log_base sceJpeg("SceJpeg", []() +DECLARE(arm_module_manager::SceJpeg)("SceJpegUser", []() { - sceJpeg.on_load = nullptr; - sceJpeg.on_unload = nullptr; - sceJpeg.on_stop = nullptr; - sceJpeg.on_error = nullptr; - REG_FUNC(0xB030773B, sceJpegInitMJpeg); REG_FUNC(0x62842598, sceJpegFinishMJpeg); REG_FUNC(0x6215B095, sceJpegDecodeMJpeg); diff --git a/rpcs3/Emu/ARMv7/Modules/sceJpeg.h b/rpcs3/Emu/ARMv7/Modules/sceJpeg.h index 9b24acff5b..fcb273e9d4 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceJpeg.h +++ b/rpcs3/Emu/ARMv7/Modules/sceJpeg.h @@ -34,5 +34,3 @@ struct SceJpegSplitDecodeCtrl le_t internalData[3]; }; - -extern psv_log_base sceJpeg; diff --git a/rpcs3/Emu/ARMv7/Modules/sceJpegEnc.cpp b/rpcs3/Emu/ARMv7/Modules/sceJpegEnc.cpp index ef6bd1bccc..6146d926ba 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceJpegEnc.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceJpegEnc.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceJpegEnc.h" +LOG_CHANNEL(sceJpegEnc); + s32 sceJpegEncoderGetContextSize() { throw EXCEPTION(""); @@ -73,15 +75,10 @@ s32 sceJpegEncoderCsc( } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceJpegEnc, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceJpegEncUser, nid, name) -psv_log_base sceJpegEnc("SceJpegEnc", []() +DECLARE(arm_module_manager::SceJpegEnc)("SceJpegEncUser", []() { - sceJpegEnc.on_load = nullptr; - sceJpegEnc.on_unload = nullptr; - sceJpegEnc.on_stop = nullptr; - sceJpegEnc.on_error = nullptr; - REG_FUNC(0x2B55844D, sceJpegEncoderGetContextSize); REG_FUNC(0x88DA92B4, sceJpegEncoderInit); REG_FUNC(0xC60DE94C, sceJpegEncoderEncode); diff --git a/rpcs3/Emu/ARMv7/Modules/sceJpegEnc.h b/rpcs3/Emu/ARMv7/Modules/sceJpegEnc.h index 4a046f6f52..513ea5a222 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceJpegEnc.h +++ b/rpcs3/Emu/ARMv7/Modules/sceJpegEnc.h @@ -1,5 +1,3 @@ #pragma once using SceJpegEncoderContext = vm::ptr; - -extern psv_log_base sceJpegEnc; diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp index 4d2f8f1bd1..2a00e9c5c1 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp @@ -1,14 +1,12 @@ #include "stdafx.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/ARMv7/PSVFuncList.h" -#include "Emu/ARMv7/PSVObjectList.h" - -#include "Emu/SysCalls/Callback.h" -#include "Emu/ARMv7/ARMv7Thread.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceLibKernel.h" +LOG_CHANNEL(sceLibKernel); + extern u64 get_system_time(); s32 sceKernelAllocMemBlock(vm::cptr name, s32 type, u32 vsize, vm::ptr pOpt) @@ -31,22 +29,22 @@ s32 sceKernelGetMemBlockInfoByAddr(vm::ptr vbase, vm::ptr pName, vm::ptr entry, s32 initPriority, u32 stackSize, u32 attr, s32 cpuAffinityMask, vm::cptr pOptParam) +arm_error_code sceKernelCreateThread(vm::cptr pName, vm::ptr entry, s32 initPriority, u32 stackSize, u32 attr, s32 cpuAffinityMask, vm::cptr pOptParam) { sceLibKernel.warning("sceKernelCreateThread(pName=*0x%x, entry=*0x%x, initPriority=%d, stackSize=0x%x, attr=0x%x, cpuAffinityMask=0x%x, pOptParam=*0x%x)", pName, entry, initPriority, stackSize, attr, cpuAffinityMask, pOptParam); - auto armv7 = idm::make_ptr(pName.get_ptr()); + const auto thread = idm::make_ptr(pName.get_ptr()); - armv7->PC = entry.addr(); - armv7->prio = initPriority; - armv7->stack_size = stackSize; - armv7->run(); + thread->PC = entry.addr(); + thread->prio = initPriority; + thread->stack_size = stackSize; + thread->cpu_init(); - return armv7->get_id(); + return NOT_AN_ERROR(thread->id); } -s32 sceKernelStartThread(s32 threadId, u32 argSize, vm::cptr pArgBlock) +arm_error_code sceKernelStartThread(s32 threadId, u32 argSize, vm::cptr pArgBlock) { sceLibKernel.warning("sceKernelStartThread(threadId=0x%x, argSize=0x%x, pArgBlock=*0x%x)", threadId, argSize, pArgBlock); @@ -72,21 +70,22 @@ s32 sceKernelStartThread(s32 threadId, u32 argSize, vm::cptr pArgBlock) thread->GPR[0] = argSize; thread->GPR[1] = pos; - thread->exec(); + thread->state -= cpu_state::stop; + thread->safe_notify(); return SCE_OK; } -s32 sceKernelExitThread(ARMv7Thread& context, s32 exitStatus) +arm_error_code sceKernelExitThread(ARMv7Thread& cpu, s32 exitStatus) { sceLibKernel.warning("sceKernelExitThread(exitStatus=0x%x)", exitStatus); - // exit status is stored in r0 - context.exit(); + // Exit status is stored in r0 + cpu.state += cpu_state::exit; return SCE_OK; } -s32 sceKernelDeleteThread(s32 threadId) +arm_error_code sceKernelDeleteThread(s32 threadId) { sceLibKernel.warning("sceKernelDeleteThread(threadId=0x%x)", threadId); @@ -108,15 +107,14 @@ s32 sceKernelDeleteThread(s32 threadId) return SCE_OK; } -s32 sceKernelExitDeleteThread(ARMv7Thread& context, s32 exitStatus) +arm_error_code sceKernelExitDeleteThread(ARMv7Thread& cpu, s32 exitStatus) { sceLibKernel.warning("sceKernelExitDeleteThread(exitStatus=0x%x)", exitStatus); - // exit status is stored in r0 - context.stop(); + //cpu.state += cpu_state::stop; - // current thread should be deleted - idm::remove(context.get_id()); + // Delete current thread; exit status is stored in r0 + idm::remove(cpu.id); return SCE_OK; } @@ -149,11 +147,11 @@ s32 sceKernelGetThreadCurrentPriority() throw EXCEPTION(""); } -u32 sceKernelGetThreadId(ARMv7Thread& context) +u32 sceKernelGetThreadId(ARMv7Thread& cpu) { sceLibKernel.trace("sceKernelGetThreadId()"); - return context.get_id(); + return cpu.id; } s32 sceKernelChangeCurrentThreadAttr(u32 clearAttr, u32 setAttr) @@ -205,24 +203,17 @@ s32 sceKernelGetSystemInfo(vm::ptr pInfo) throw EXCEPTION(""); } -s32 sceKernelGetThreadmgrUIDClass(s32 uid) +arm_error_code sceKernelGetThreadmgrUIDClass(s32 uid) { sceLibKernel.error("sceKernelGetThreadmgrUIDClass(uid=0x%x)", uid); - const auto type = idm::get_type(uid); - - if (!type) - { - return SCE_KERNEL_ERROR_INVALID_UID; - } - - if (*type == typeid(ARMv7Thread)) return SCE_KERNEL_THREADMGR_UID_CLASS_THREAD; - if (*type == typeid(psv_semaphore_t)) return SCE_KERNEL_THREADMGR_UID_CLASS_SEMA; - if (*type == typeid(psv_event_flag_t)) return SCE_KERNEL_THREADMGR_UID_CLASS_EVENT_FLAG; - if (*type == typeid(psv_mutex_t)) return SCE_KERNEL_THREADMGR_UID_CLASS_MUTEX; - if (*type == typeid(psv_cond_t)) return SCE_KERNEL_THREADMGR_UID_CLASS_COND; + if (idm::check(uid)) return SCE_KERNEL_THREADMGR_UID_CLASS_THREAD; + if (idm::check(uid)) return SCE_KERNEL_THREADMGR_UID_CLASS_SEMA; + if (idm::check(uid)) return SCE_KERNEL_THREADMGR_UID_CLASS_EVENT_FLAG; + if (idm::check(uid)) return SCE_KERNEL_THREADMGR_UID_CLASS_MUTEX; + if (idm::check(uid)) return SCE_KERNEL_THREADMGR_UID_CLASS_COND; - throw EXCEPTION("Unknown UID class (type='%s')", type->name()); + return SCE_KERNEL_ERROR_INVALID_UID; } s32 sceKernelChangeThreadVfpException(s32 clearMask, s32 setMask) @@ -253,7 +244,7 @@ s32 sceKernelDelayThreadCB(u32 usec) throw EXCEPTION(""); } -s32 sceKernelWaitThreadEnd(s32 threadId, vm::ptr pExitStatus, vm::ptr pTimeout) +arm_error_code sceKernelWaitThreadEnd(s32 threadId, vm::ptr pExitStatus, vm::ptr pTimeout) { sceLibKernel.warning("sceKernelWaitThreadEnd(threadId=0x%x, pExitStatus=*0x%x, pTimeout=*0x%x)", threadId, pExitStatus, pTimeout); @@ -268,7 +259,7 @@ s32 sceKernelWaitThreadEnd(s32 threadId, vm::ptr pExitStatus, vm::ptr { } - while (thread->is_alive()) + while (!(thread->state & cpu_state::exit)) { CHECK_EMU_STATUS; @@ -381,14 +372,14 @@ s32 sceKernelWaitMultipleEventsCB(vm::ptr pWaitEventList, s3 // Event flag functions -s32 sceKernelCreateEventFlag(vm::cptr pName, u32 attr, u32 initPattern, vm::cptr pOptParam) +arm_error_code sceKernelCreateEventFlag(vm::cptr pName, u32 attr, u32 initPattern, vm::cptr pOptParam) { sceLibKernel.error("sceKernelCreateEventFlag(pName=*0x%x, attr=0x%x, initPattern=0x%x, pOptParam=*0x%x)", pName, attr, initPattern, pOptParam); - return idm::make(pName.get_ptr(), attr, initPattern); + return NOT_AN_ERROR(idm::make(pName.get_ptr(), attr, initPattern)); } -s32 sceKernelDeleteEventFlag(s32 evfId) +arm_error_code sceKernelDeleteEventFlag(s32 evfId) { sceLibKernel.error("sceKernelDeleteEventFlag(evfId=0x%x)", evfId); @@ -408,7 +399,7 @@ s32 sceKernelDeleteEventFlag(s32 evfId) return SCE_OK; } -s32 sceKernelOpenEventFlag(vm::cptr pName) +arm_error_code sceKernelOpenEventFlag(vm::cptr pName) { sceLibKernel.error("sceKernelOpenEventFlag(pName=*0x%x)", pName); @@ -419,14 +410,14 @@ s32 sceKernelOpenEventFlag(vm::cptr pName) if (evf->name == pName.get_ptr() && evf->ref.atomic_op(ipc_ref_try_inc)) { - return idm::import(evf); + return NOT_AN_ERROR(idm::import_existing(evf)); } } return SCE_KERNEL_ERROR_UID_CANNOT_FIND_BY_NAME; } -s32 sceKernelCloseEventFlag(s32 evfId) +arm_error_code sceKernelCloseEventFlag(s32 evfId) { sceLibKernel.error("sceKernelCloseEventFlag(evfId=0x%x)", evfId); @@ -446,7 +437,7 @@ s32 sceKernelCloseEventFlag(s32 evfId) return SCE_OK; } -s32 sceKernelWaitEventFlag(ARMv7Thread& context, s32 evfId, u32 bitPattern, u32 waitMode, vm::ptr pResultPat, vm::ptr pTimeout) +arm_error_code sceKernelWaitEventFlag(ARMv7Thread& cpu, s32 evfId, u32 bitPattern, u32 waitMode, vm::ptr pResultPat, vm::ptr pTimeout) { sceLibKernel.error("sceKernelWaitEventFlag(evfId=0x%x, bitPattern=0x%x, waitMode=0x%x, pResultPat=*0x%x, pTimeout=*0x%x)", evfId, bitPattern, waitMode, pResultPat, pTimeout); @@ -462,7 +453,7 @@ s32 sceKernelWaitEventFlag(ARMv7Thread& context, s32 evfId, u32 bitPattern, u32 std::unique_lock lock(evf->mutex); - const u32 result = evf->pattern.atomic_op(event_flag_try_poll, bitPattern, waitMode); + const u32 result = evf->pattern.fetch_op(event_flag_try_poll, bitPattern, waitMode); if (event_flag_test(result, bitPattern, waitMode)) { @@ -472,13 +463,13 @@ s32 sceKernelWaitEventFlag(ARMv7Thread& context, s32 evfId, u32 bitPattern, u32 } // fixup register values for external use - context.GPR[1] = bitPattern; - context.GPR[2] = waitMode; + cpu.GPR[1] = bitPattern; + cpu.GPR[2] = waitMode; // add waiter; attributes are ignored in current implementation - sleep_queue_entry_t waiter(context, evf->sq); + sleep_entry waiter(evf->sq, cpu); - while (!context.unsignal()) + while (!cpu.state.test_and_reset(cpu_state::signal)) { CHECK_EMU_STATUS; @@ -488,33 +479,33 @@ s32 sceKernelWaitEventFlag(ARMv7Thread& context, s32 evfId, u32 bitPattern, u32 if (passed >= timeout) { - context.GPR[0] = SCE_KERNEL_ERROR_WAIT_TIMEOUT; - context.GPR[1] = evf->pattern; + cpu.GPR[0] = SCE_KERNEL_ERROR_WAIT_TIMEOUT; + cpu.GPR[1] = evf->pattern; break; } - context.cv.wait_for(lock, std::chrono::microseconds(timeout - passed)); + cpu.cv.wait_for(lock, std::chrono::microseconds(timeout - passed)); } else { - context.cv.wait(lock); + cpu.cv.wait(lock); } } - if (pResultPat) *pResultPat = context.GPR[1]; + if (pResultPat) *pResultPat = cpu.GPR[1]; if (pTimeout) *pTimeout = static_cast(std::max(0, timeout - (get_system_time() - start_time))); - return context.GPR[0]; + return NOT_AN_ERROR(cpu.GPR[0]); } -s32 sceKernelWaitEventFlagCB(ARMv7Thread& context, s32 evfId, u32 bitPattern, u32 waitMode, vm::ptr pResultPat, vm::ptr pTimeout) +arm_error_code sceKernelWaitEventFlagCB(ARMv7Thread& cpu, s32 evfId, u32 bitPattern, u32 waitMode, vm::ptr pResultPat, vm::ptr pTimeout) { sceLibKernel.todo("sceKernelWaitEventFlagCB(evfId=0x%x, bitPattern=0x%x, waitMode=0x%x, pResultPat=*0x%x, pTimeout=*0x%x)", evfId, bitPattern, waitMode, pResultPat, pTimeout); - return sceKernelWaitEventFlag(context, evfId, bitPattern, waitMode, pResultPat, pTimeout); + return sceKernelWaitEventFlag(cpu, evfId, bitPattern, waitMode, pResultPat, pTimeout); } -s32 sceKernelPollEventFlag(s32 evfId, u32 bitPattern, u32 waitMode, vm::ptr pResultPat) +arm_error_code sceKernelPollEventFlag(s32 evfId, u32 bitPattern, u32 waitMode, vm::ptr pResultPat) { sceLibKernel.error("sceKernelPollEventFlag(evfId=0x%x, bitPattern=0x%x, waitMode=0x%x, pResultPat=*0x%x)", evfId, bitPattern, waitMode, pResultPat); @@ -527,7 +518,7 @@ s32 sceKernelPollEventFlag(s32 evfId, u32 bitPattern, u32 waitMode, vm::ptr std::lock_guard lock(evf->mutex); - const u32 result = evf->pattern.atomic_op(event_flag_try_poll, bitPattern, waitMode); + const u32 result = evf->pattern.fetch_op(event_flag_try_poll, bitPattern, waitMode); if (!event_flag_test(result, bitPattern, waitMode)) { @@ -539,7 +530,7 @@ s32 sceKernelPollEventFlag(s32 evfId, u32 bitPattern, u32 waitMode, vm::ptr return SCE_OK; } -s32 sceKernelSetEventFlag(s32 evfId, u32 bitPattern) +arm_error_code sceKernelSetEventFlag(s32 evfId, u32 bitPattern) { sceLibKernel.error("sceKernelSetEventFlag(evfId=0x%x, bitPattern=0x%x)", evfId, bitPattern); @@ -554,24 +545,25 @@ s32 sceKernelSetEventFlag(s32 evfId, u32 bitPattern) evf->pattern |= bitPattern; - auto pred = [&](sleep_queue_t::value_type& thread) -> bool + auto pred = [&](cpu_thread* thread) -> bool { - auto& context = static_cast(*thread); + auto& cpu = static_cast(*thread); // load pattern and mode from registers - const u32 pattern = context.GPR[1]; - const u32 mode = context.GPR[2]; + const u32 pattern = cpu.GPR[1]; + const u32 mode = cpu.GPR[2]; // check specific pattern - const u32 result = evf->pattern.atomic_op(event_flag_try_poll, pattern, mode); + const u32 result = evf->pattern.fetch_op(event_flag_try_poll, pattern, mode); if (event_flag_test(result, pattern, mode)) { // save pattern - context.GPR[0] = SCE_OK; - context.GPR[1] = result; + cpu.GPR[0] = SCE_OK; + cpu.GPR[1] = result; - context.signal(); + thread->state += cpu_state::signal; + thread->cv.notify_one(); return true; } @@ -584,7 +576,7 @@ s32 sceKernelSetEventFlag(s32 evfId, u32 bitPattern) return SCE_OK; } -s32 sceKernelClearEventFlag(s32 evfId, u32 bitPattern) +arm_error_code sceKernelClearEventFlag(s32 evfId, u32 bitPattern) { sceLibKernel.error("sceKernelClearEventFlag(evfId=0x%x, bitPattern=0x%x)", evfId, bitPattern); @@ -602,7 +594,7 @@ s32 sceKernelClearEventFlag(s32 evfId, u32 bitPattern) return SCE_OK; } -s32 sceKernelCancelEventFlag(s32 evfId, u32 setPattern, vm::ptr pNumWaitThreads) +arm_error_code sceKernelCancelEventFlag(s32 evfId, u32 setPattern, vm::ptr pNumWaitThreads) { sceLibKernel.error("sceKernelCancelEventFlag(evfId=0x%x, setPattern=0x%x, pNumWaitThreads=*0x%x)", evfId, setPattern, pNumWaitThreads); @@ -619,7 +611,8 @@ s32 sceKernelCancelEventFlag(s32 evfId, u32 setPattern, vm::ptr pNumWaitThr { static_cast(*thread).GPR[0] = SCE_KERNEL_ERROR_WAIT_CANCEL; static_cast(*thread).GPR[1] = setPattern; - thread->signal(); + thread->state += cpu_state::signal; + thread->cv.notify_one(); } *pNumWaitThreads = static_cast(evf->sq.size()); @@ -630,7 +623,7 @@ s32 sceKernelCancelEventFlag(s32 evfId, u32 setPattern, vm::ptr pNumWaitThr return SCE_OK; } -s32 sceKernelGetEventFlagInfo(s32 evfId, vm::ptr pInfo) +arm_error_code sceKernelGetEventFlagInfo(s32 evfId, vm::ptr pInfo) { sceLibKernel.error("sceKernelGetEventFlagInfo(evfId=0x%x, pInfo=*0x%x)", evfId, pInfo); @@ -658,14 +651,14 @@ s32 sceKernelGetEventFlagInfo(s32 evfId, vm::ptr pInfo) // Semaphore functions -s32 sceKernelCreateSema(vm::cptr pName, u32 attr, s32 initCount, s32 maxCount, vm::cptr pOptParam) +arm_error_code sceKernelCreateSema(vm::cptr pName, u32 attr, s32 initCount, s32 maxCount, vm::cptr pOptParam) { sceLibKernel.error("sceKernelCreateSema(pName=*0x%x, attr=0x%x, initCount=%d, maxCount=%d, pOptParam=*0x%x)", pName, attr, initCount, maxCount, pOptParam); - return idm::make(pName.get_ptr(), attr, initCount, maxCount); + return NOT_AN_ERROR(idm::make(pName.get_ptr(), attr, initCount, maxCount)); } -s32 sceKernelDeleteSema(s32 semaId) +arm_error_code sceKernelDeleteSema(s32 semaId) { sceLibKernel.error("sceKernelDeleteSema(semaId=0x%x)", semaId); @@ -691,7 +684,7 @@ s32 sceKernelCloseSema(s32 semaId) throw EXCEPTION(""); } -s32 sceKernelWaitSema(s32 semaId, s32 needCount, vm::ptr pTimeout) +arm_error_code sceKernelWaitSema(s32 semaId, s32 needCount, vm::ptr pTimeout) { sceLibKernel.error("sceKernelWaitSema(semaId=0x%x, needCount=%d, pTimeout=*0x%x)", semaId, needCount, pTimeout); @@ -734,14 +727,14 @@ s32 sceKernelGetSemaInfo(s32 semaId, vm::ptr pInfo) // Mutex functions -s32 sceKernelCreateMutex(vm::cptr pName, u32 attr, s32 initCount, vm::cptr pOptParam) +arm_error_code sceKernelCreateMutex(vm::cptr pName, u32 attr, s32 initCount, vm::cptr pOptParam) { sceLibKernel.error("sceKernelCreateMutex(pName=*0x%x, attr=0x%x, initCount=%d, pOptParam=*0x%x)", pName, attr, initCount, pOptParam); - return idm::make(pName.get_ptr(), attr, initCount); + return NOT_AN_ERROR(idm::make(pName.get_ptr(), attr, initCount)); } -s32 sceKernelDeleteMutex(s32 mutexId) +arm_error_code sceKernelDeleteMutex(s32 mutexId) { sceLibKernel.error("sceKernelDeleteMutex(mutexId=0x%x)", mutexId); @@ -841,7 +834,7 @@ s32 sceKernelGetLwMutexInfoById(s32 lwMutexId, vm::ptr pIn // Condition variable functions -s32 sceKernelCreateCond(vm::cptr pName, u32 attr, s32 mutexId, vm::cptr pOptParam) +arm_error_code sceKernelCreateCond(vm::cptr pName, u32 attr, s32 mutexId, vm::cptr pOptParam) { sceLibKernel.error("sceKernelCreateCond(pName=*0x%x, attr=0x%x, mutexId=0x%x, pOptParam=*0x%x)", pName, attr, mutexId, pOptParam); @@ -852,10 +845,10 @@ s32 sceKernelCreateCond(vm::cptr pName, u32 attr, s32 mutexId, vm::cptr(pName.get_ptr(), attr, mutex); + return NOT_AN_ERROR(idm::make(pName.get_ptr(), attr, mutex)); } -s32 sceKernelDeleteCond(s32 condId) +arm_error_code sceKernelDeleteCond(s32 condId) { sceLibKernel.error("sceKernelDeleteCond(condId=0x%x)", condId); @@ -1227,15 +1220,10 @@ s32 sceIoGetstat(vm::cptr name, vm::ptr buf) } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceLibKernel, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceLibKernel, nid, name) -psv_log_base sceLibKernel("sceLibKernel", []() +DECLARE(arm_module_manager::SceLibKernel)("SceLibKernel", []() { - sceLibKernel.on_load = nullptr; - sceLibKernel.on_unload = nullptr; - sceLibKernel.on_stop = nullptr; - //sceLibKernel.on_error = nullptr; // keep default error handler - // REG_FUNC(???, sceKernelGetEventInfo); //REG_FUNC(0x023EAA62, sceKernelPuts); @@ -1544,62 +1532,91 @@ psv_log_base sceLibKernel("sceLibKernel", []() //REG_FUNC(0x963F4A99, sceSblACMgrIsGameProgram); //REG_FUNC(0x261E2C34, sceKernelGetOpenPsId); - /* SceModulemgr */ - //REG_FUNC(0x36585DAF, sceKernelGetModuleInfo); - //REG_FUNC(0x2EF2581F, sceKernelGetModuleList); - //REG_FUNC(0xF5798C7C, sceKernelGetModuleIdByAddr); - - /* SceProcessmgr */ - //REG_FUNC(0xCD248267, sceKernelGetCurrentProcess); - //REG_FUNC(0x2252890C, sceKernelPowerTick); - //REG_FUNC(0x9E45DA09, sceKernelLibcClock); - //REG_FUNC(0x0039BE45, sceKernelLibcTime); - //REG_FUNC(0x4B879059, sceKernelLibcGettimeofday); - //REG_FUNC(0xC1727F59, sceKernelGetStdin); - //REG_FUNC(0xE5AA625C, sceKernelGetStdout); - //REG_FUNC(0xFA5E3ADA, sceKernelGetStderr); - //REG_FUNC(0xE6E9FCA3, sceKernelGetRemoteProcessTime); - //REG_FUNC(0xD37A8437, sceKernelGetProcessTime); - //REG_FUNC(0xF5D0D4C6, sceKernelGetProcessTimeLow); - //REG_FUNC(0x89DA0967, sceKernelGetProcessTimeWide); - //REG_FUNC(0x2BE3E066, sceKernelGetProcessParam); - - /* SceStdio */ - //REG_FUNC(0x54237407, sceKernelStdin); - //REG_FUNC(0x9033E9BD, sceKernelStdout); - //REG_FUNC(0x35EE7CF5, sceKernelStderr); - - /* SceSysmem */ - REG_FUNC(0xB9D5EBDE, sceKernelAllocMemBlock); - REG_FUNC(0xA91E15EE, sceKernelFreeMemBlock); - REG_FUNC(0xB8EF5818, sceKernelGetMemBlockBase); - //REG_FUNC(0x3B29E0F5, sceKernelRemapMemBlock); - //REG_FUNC(0xA33B99D1, sceKernelFindMemBlockByAddr); - REG_FUNC(0x4010AD65, sceKernelGetMemBlockInfoByAddr); - - /* SceCpu */ - //REG_FUNC(0x2704CFEE, sceKernelCpuId); - - /* SceDipsw */ - //REG_FUNC(0x1C783FB2, sceKernelCheckDipsw); - //REG_FUNC(0x817053D4, sceKernelSetDipsw); - //REG_FUNC(0x800EDCC1, sceKernelClearDipsw); - - /* SceThreadmgr */ - REG_FUNC(0x0C8A38E1, sceKernelExitThread); - REG_FUNC(0x1D17DECF, sceKernelExitDeleteThread); - REG_FUNC(0x4B675D05, sceKernelDelayThread); - REG_FUNC(0x9C0180E1, sceKernelDelayThreadCB); - //REG_FUNC(0x001173F8, sceKernelChangeActiveCpuMask); - REG_FUNC(0x01414F0B, sceKernelGetThreadCurrentPriority); - REG_FUNC(0x751C9B7A, sceKernelChangeCurrentThreadAttr); - REG_FUNC(0xD9BD74EB, sceKernelCheckWaitableStatus); - REG_FUNC(0x9DCB4B7A, sceKernelGetProcessId); - REG_FUNC(0xE53E41F6, sceKernelCheckCallback); - REG_FUNC(0xF4EE4FA9, sceKernelGetSystemTimeWide); - REG_FUNC(0x47F6DE49, sceKernelGetSystemTimeLow); - //REG_FUNC(0xC0FAF6A3, sceKernelCreateThreadForUser); - - /* SceDebugLed */ - //REG_FUNC(0x78E702D3, sceKernelSetGPO); + //REG_FUNC(0x4C4672BF, sceKernelGetProcessTime); // !!! +}); + +DECLARE(arm_module_manager::SceIofilemgr)("SceIofilemgr", []() +{ + REG_FNID(SceIofilemgr, 0x34EFD876, sceIoWrite); // !!! + REG_FNID(SceIofilemgr, 0xC70B8886, sceIoClose); // !!! + REG_FNID(SceIofilemgr, 0xFDB32293, sceIoRead); // !!! +}); + +DECLARE(arm_module_manager::SceModulemgr)("SceModulemgr", []() +{ + //REG_FNID(SceModulemgr, 0x36585DAF, sceKernelGetModuleInfo); + //REG_FNID(SceModulemgr, 0x2EF2581F, sceKernelGetModuleList); + //REG_FNID(SceModulemgr, 0xF5798C7C, sceKernelGetModuleIdByAddr); +}); + +DECLARE(arm_module_manager::SceProcessmgr)("SceProcessmgr", []() +{ + //REG_FNID(SceProcessmgr, 0xCD248267, sceKernelGetCurrentProcess); + //REG_FNID(SceProcessmgr, 0x2252890C, sceKernelPowerTick); + //REG_FNID(SceProcessmgr, 0x9E45DA09, sceKernelLibcClock); + //REG_FNID(SceProcessmgr, 0x0039BE45, sceKernelLibcTime); + //REG_FNID(SceProcessmgr, 0x4B879059, sceKernelLibcGettimeofday); + //REG_FNID(SceProcessmgr, 0xC1727F59, sceKernelGetStdin); + //REG_FNID(SceProcessmgr, 0xE5AA625C, sceKernelGetStdout); + //REG_FNID(SceProcessmgr, 0xFA5E3ADA, sceKernelGetStderr); + //REG_FNID(SceProcessmgr, 0xE6E9FCA3, sceKernelGetRemoteProcessTime); + //REG_FNID(SceProcessmgr, 0xD37A8437, sceKernelGetProcessTime); + //REG_FNID(SceProcessmgr, 0xF5D0D4C6, sceKernelGetProcessTimeLow); + //REG_FNID(SceProcessmgr, 0x89DA0967, sceKernelGetProcessTimeWide); + //REG_FNID(SceProcessmgr, 0x2BE3E066, sceKernelGetProcessParam); +}); + +DECLARE(arm_module_manager::SceStdio)("SceStdio", []() +{ + //REG_FNID(SceStdio, 0x54237407, sceKernelStdin); + //REG_FNID(SceStdio, 0x9033E9BD, sceKernelStdout); + //REG_FNID(SceStdio, 0x35EE7CF5, sceKernelStderr); +}); + +DECLARE(arm_module_manager::SceSysmem)("SceSysmem", []() +{ + REG_FNID(SceSysmem, 0xB9D5EBDE, sceKernelAllocMemBlock); + REG_FNID(SceSysmem, 0xA91E15EE, sceKernelFreeMemBlock); + REG_FNID(SceSysmem, 0xB8EF5818, sceKernelGetMemBlockBase); + //REG_FNID(SceSysmem, 0x3B29E0F5, sceKernelRemapMemBlock); + //REG_FNID(SceSysmem, 0xA33B99D1, sceKernelFindMemBlockByAddr); + REG_FNID(SceSysmem, 0x4010AD65, sceKernelGetMemBlockInfoByAddr); +}); + +DECLARE(arm_module_manager::SceCpu)("SceCpu", []() +{ + //REG_FNID(SceCpu, 0x2704CFEE, sceKernelCpuId); +}); + +DECLARE(arm_module_manager::SceDipsw)("SceDipsw", []() +{ + //REG_FNID(SceDipsw, 0x1C783FB2, sceKernelCheckDipsw); + //REG_FNID(SceDipsw, 0x817053D4, sceKernelSetDipsw); + //REG_FNID(SceDipsw, 0x800EDCC1, sceKernelClearDipsw); +}); + +DECLARE(arm_module_manager::SceThreadmgr)("SceThreadmgr", []() +{ + REG_FNID(SceThreadmgr, 0x0C8A38E1, sceKernelExitThread); + REG_FNID(SceThreadmgr, 0x1D17DECF, sceKernelExitDeleteThread); + REG_FNID(SceThreadmgr, 0x4B675D05, sceKernelDelayThread); + REG_FNID(SceThreadmgr, 0x9C0180E1, sceKernelDelayThreadCB); + REG_FNID(SceThreadmgr, 0x1BBDE3D9, sceKernelDeleteThread); // !!! + //REG_FNID(SceThreadmgr, 0x001173F8, sceKernelChangeActiveCpuMask); + REG_FNID(SceThreadmgr, 0x01414F0B, sceKernelGetThreadCurrentPriority); + REG_FNID(SceThreadmgr, 0x751C9B7A, sceKernelChangeCurrentThreadAttr); + REG_FNID(SceThreadmgr, 0xD9BD74EB, sceKernelCheckWaitableStatus); + REG_FNID(SceThreadmgr, 0x9DCB4B7A, sceKernelGetProcessId); + REG_FNID(SceThreadmgr, 0xB19CF7E9, sceKernelCreateCallback); // !!! + REG_FNID(SceThreadmgr, 0xD469676B, sceKernelDeleteCallback); // !!! + REG_FNID(SceThreadmgr, 0xE53E41F6, sceKernelCheckCallback); + REG_FNID(SceThreadmgr, 0xF4EE4FA9, sceKernelGetSystemTimeWide); + REG_FNID(SceThreadmgr, 0x47F6DE49, sceKernelGetSystemTimeLow); + //REG_FNID(SceThreadmgr, 0xC0FAF6A3, sceKernelCreateThreadForUser); + REG_FNID(SceThreadmgr, 0xF1AE5654, sceKernelGetThreadCpuAffinityMask); // !!! +}); + +DECLARE(arm_module_manager::SceDebugLed)("SceDebugLed", []() +{ + //REG_FNID(SceDebugLed, 0x78E702D3, sceKernelSetGPO); }); diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.h b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.h index 1ba6f3a4ca..a94a7ba760 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.h +++ b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.h @@ -1,258 +1,540 @@ #pragma once #include "Utilities/SleepQueue.h" +#include "Emu/ARMv7/ErrorCodes.h" // Error Codes -enum +enum SceLibKernelError : s32 { - SCE_KERNEL_ERROR_ERROR = 0x80020001, - SCE_KERNEL_ERROR_NOT_IMPLEMENTED = 0x80020002, - SCE_KERNEL_ERROR_INVALID_ARGUMENT = 0x80020003, - SCE_KERNEL_ERROR_INVALID_ARGUMENT_SIZE = 0x80020004, - SCE_KERNEL_ERROR_INVALID_FLAGS = 0x80020005, - SCE_KERNEL_ERROR_ILLEGAL_SIZE = 0x80020006, - SCE_KERNEL_ERROR_ILLEGAL_ADDR = 0x80020007, - SCE_KERNEL_ERROR_UNSUP = 0x80020008, - SCE_KERNEL_ERROR_ILLEGAL_MODE = 0x80020009, - SCE_KERNEL_ERROR_ILLEGAL_ALIGNMENT = 0x8002000A, - SCE_KERNEL_ERROR_NOSYS = 0x8002000B, - SCE_KERNEL_ERROR_DEBUG_ERROR = 0x80021000, - SCE_KERNEL_ERROR_ILLEGAL_DIPSW_NUMBER = 0x80021001, - SCE_KERNEL_ERROR_CPU_ERROR = 0x80022000, - SCE_KERNEL_ERROR_MMU_ILLEGAL_L1_TYPE = 0x80022001, - SCE_KERNEL_ERROR_MMU_L2_INDEX_OVERFLOW = 0x80022002, - SCE_KERNEL_ERROR_MMU_L2_SIZE_OVERFLOW = 0x80022003, - SCE_KERNEL_ERROR_INVALID_CPU_AFFINITY = 0x80022004, - SCE_KERNEL_ERROR_INVALID_MEMORY_ACCESS = 0x80022005, - SCE_KERNEL_ERROR_INVALID_MEMORY_ACCESS_PERMISSION = 0x80022006, - SCE_KERNEL_ERROR_VA2PA_FAULT = 0x80022007, - SCE_KERNEL_ERROR_VA2PA_MAPPED = 0x80022008, - SCE_KERNEL_ERROR_VALIDATION_CHECK_FAILED = 0x80022009, - SCE_KERNEL_ERROR_SYSMEM_ERROR = 0x80024000, - SCE_KERNEL_ERROR_INVALID_PROCESS_CONTEXT = 0x80024001, - SCE_KERNEL_ERROR_UID_NAME_TOO_LONG = 0x80024002, - SCE_KERNEL_ERROR_VARANGE_IS_NOT_PHYSICAL_CONTINUOUS = 0x80024003, - SCE_KERNEL_ERROR_PHYADDR_ERROR = 0x80024100, - SCE_KERNEL_ERROR_NO_PHYADDR = 0x80024101, - SCE_KERNEL_ERROR_PHYADDR_USED = 0x80024102, - SCE_KERNEL_ERROR_PHYADDR_NOT_USED = 0x80024103, - SCE_KERNEL_ERROR_NO_IOADDR = 0x80024104, - SCE_KERNEL_ERROR_PHYMEM_ERROR = 0x80024300, - SCE_KERNEL_ERROR_ILLEGAL_PHYPAGE_STATUS = 0x80024301, - SCE_KERNEL_ERROR_NO_FREE_PHYSICAL_PAGE = 0x80024302, - SCE_KERNEL_ERROR_NO_FREE_PHYSICAL_PAGE_UNIT = 0x80024303, - SCE_KERNEL_ERROR_PHYMEMPART_NOT_EMPTY = 0x80024304, - SCE_KERNEL_ERROR_NO_PHYMEMPART_LPDDR2 = 0x80024305, - SCE_KERNEL_ERROR_NO_PHYMEMPART_CDRAM = 0x80024306, - SCE_KERNEL_ERROR_FIXEDHEAP_ERROR = 0x80024400, - SCE_KERNEL_ERROR_FIXEDHEAP_ILLEGAL_SIZE = 0x80024401, - SCE_KERNEL_ERROR_FIXEDHEAP_ILLEGAL_INDEX = 0x80024402, - SCE_KERNEL_ERROR_FIXEDHEAP_INDEX_OVERFLOW = 0x80024403, - SCE_KERNEL_ERROR_FIXEDHEAP_NO_CHUNK = 0x80024404, - SCE_KERNEL_ERROR_UID_ERROR = 0x80024500, - SCE_KERNEL_ERROR_INVALID_UID = 0x80024501, - SCE_KERNEL_ERROR_SYSMEM_UID_INVALID_ARGUMENT = 0x80024502, - SCE_KERNEL_ERROR_SYSMEM_INVALID_UID_RANGE = 0x80024503, - SCE_KERNEL_ERROR_SYSMEM_NO_VALID_UID = 0x80024504, - SCE_KERNEL_ERROR_SYSMEM_CANNOT_ALLOCATE_UIDENTRY = 0x80024505, - SCE_KERNEL_ERROR_NOT_PROCESS_UID = 0x80024506, - SCE_KERNEL_ERROR_NOT_KERNEL_UID = 0x80024507, - SCE_KERNEL_ERROR_INVALID_UID_CLASS = 0x80024508, - SCE_KERNEL_ERROR_INVALID_UID_SUBCLASS = 0x80024509, - SCE_KERNEL_ERROR_UID_CANNOT_FIND_BY_NAME = 0x8002450A, - SCE_KERNEL_ERROR_VIRPAGE_ERROR = 0x80024600, - SCE_KERNEL_ERROR_ILLEGAL_VIRPAGE_TYPE = 0x80024601, - SCE_KERNEL_ERROR_BLOCK_ERROR = 0x80024700, - SCE_KERNEL_ERROR_ILLEGAL_BLOCK_ID = 0x80024701, - SCE_KERNEL_ERROR_ILLEGAL_BLOCK_TYPE = 0x80024702, - SCE_KERNEL_ERROR_BLOCK_IN_USE = 0x80024703, - SCE_KERNEL_ERROR_PARTITION_ERROR = 0x80024800, - SCE_KERNEL_ERROR_ILLEGAL_PARTITION_ID = 0x80024801, - SCE_KERNEL_ERROR_ILLEGAL_PARTITION_INDEX = 0x80024802, - SCE_KERNEL_ERROR_NO_L2PAGETABLE = 0x80024803, - SCE_KERNEL_ERROR_HEAPLIB_ERROR = 0x80024900, - SCE_KERNEL_ERROR_ILLEGAL_HEAP_ID = 0x80024901, - SCE_KERNEL_ERROR_OUT_OF_RANG = 0x80024902, - SCE_KERNEL_ERROR_HEAPLIB_NOMEM = 0x80024903, - SCE_KERNEL_ERROR_SYSMEM_ADDRESS_SPACE_ERROR = 0x80024A00, - SCE_KERNEL_ERROR_INVALID_ADDRESS_SPACE_ID = 0x80024A01, - SCE_KERNEL_ERROR_INVALID_PARTITION_INDEX = 0x80024A02, - SCE_KERNEL_ERROR_ADDRESS_SPACE_CANNOT_FIND_PARTITION_BY_ADDR = 0x80024A03, - SCE_KERNEL_ERROR_SYSMEM_MEMBLOCK_ERROR = 0x80024B00, - SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK_TYPE = 0x80024B01, - SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK_REMAP_TYPE = 0x80024B02, - SCE_KERNEL_ERROR_NOT_PHY_CONT_MEMBLOCK = 0x80024B03, - SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK_CODE = 0x80024B04, - SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK_SIZE = 0x80024B05, - SCE_KERNEL_ERROR_ILLEGAL_USERMAP_SIZE = 0x80024B06, - SCE_KERNEL_ERROR_MEMBLOCK_TYPE_FOR_KERNEL_PROCESS = 0x80024B07, - SCE_KERNEL_ERROR_PROCESS_CANNOT_REMAP_MEMBLOCK = 0x80024B08, - SCE_KERNEL_ERROR_SYSMEM_PHYMEMLOW_ERROR = 0x80024C00, - SCE_KERNEL_ERROR_CANNOT_ALLOC_PHYMEMLOW = 0x80024C01, - SCE_KERNEL_ERROR_UNKNOWN_PHYMEMLOW_TYPE = 0x80024C02, - SCE_KERNEL_ERROR_SYSMEM_BITHEAP_ERROR = 0x80024D00, - SCE_KERNEL_ERROR_CANNOT_ALLOC_BITHEAP = 0x80024D01, - SCE_KERNEL_ERROR_LOADCORE_ERROR = 0x80025000, - SCE_KERNEL_ERROR_ILLEGAL_ELF_HEADER = 0x80025001, - SCE_KERNEL_ERROR_ILLEGAL_SELF_HEADER = 0x80025002, - SCE_KERNEL_ERROR_EXCPMGR_ERROR = 0x80027000, - SCE_KERNEL_ERROR_ILLEGAL_EXCPCODE = 0x80027001, - SCE_KERNEL_ERROR_ILLEGAL_EXCPHANDLER = 0x80027002, - SCE_KERNEL_ERROR_NOTFOUND_EXCPHANDLER = 0x80027003, - SCE_KERNEL_ERROR_CANNOT_RELEASE_EXCPHANDLER = 0x80027004, - SCE_KERNEL_ERROR_INTRMGR_ERROR = 0x80027100, - SCE_KERNEL_ERROR_ILLEGAL_CONTEXT = 0x80027101, - SCE_KERNEL_ERROR_ILLEGAL_INTRCODE = 0x80027102, - SCE_KERNEL_ERROR_ILLEGAL_INTRPARAM = 0x80027103, - SCE_KERNEL_ERROR_ILLEGAL_INTRPRIORITY = 0x80027104, - SCE_KERNEL_ERROR_ILLEGAL_TARGET_CPU = 0x80027105, - SCE_KERNEL_ERROR_ILLEGAL_INTRFILTER = 0x80027106, - SCE_KERNEL_ERROR_ILLEGAL_INTRTYPE = 0x80027107, - SCE_KERNEL_ERROR_ILLEGAL_HANDLER = 0x80027108, - SCE_KERNEL_ERROR_FOUND_HANDLER = 0x80027109, - SCE_KERNEL_ERROR_NOTFOUND_HANDLER = 0x8002710A, - SCE_KERNEL_ERROR_NO_MEMORY = 0x8002710B, - SCE_KERNEL_ERROR_DMACMGR_ERROR = 0x80027200, - SCE_KERNEL_ERROR_ALREADY_QUEUED = 0x80027201, - SCE_KERNEL_ERROR_NOT_QUEUED = 0x80027202, - SCE_KERNEL_ERROR_NOT_SETUP = 0x80027203, - SCE_KERNEL_ERROR_ON_TRANSFERRING = 0x80027204, - SCE_KERNEL_ERROR_NOT_INITIALIZED = 0x80027205, - SCE_KERNEL_ERROR_TRANSFERRED = 0x80027206, - SCE_KERNEL_ERROR_NOT_UNDER_CONTROL = 0x80027207, - SCE_KERNEL_ERROR_SYSTIMER_ERROR = 0x80027300, - SCE_KERNEL_ERROR_NO_FREE_TIMER = 0x80027301, - SCE_KERNEL_ERROR_TIMER_NOT_ALLOCATED = 0x80027302, - SCE_KERNEL_ERROR_TIMER_COUNTING = 0x80027303, - SCE_KERNEL_ERROR_TIMER_STOPPED = 0x80027304, - SCE_KERNEL_ERROR_THREADMGR_ERROR = 0x80028000, - SCE_KERNEL_ERROR_DORMANT = 0x80028001, - SCE_KERNEL_ERROR_NOT_DORMANT = 0x80028002, - SCE_KERNEL_ERROR_UNKNOWN_THID = 0x80028003, - SCE_KERNEL_ERROR_CAN_NOT_WAIT = 0x80028004, - SCE_KERNEL_ERROR_ILLEGAL_THID = 0x80028005, - SCE_KERNEL_ERROR_THREAD_TERMINATED = 0x80028006, - SCE_KERNEL_ERROR_DELETED = 0x80028007, - SCE_KERNEL_ERROR_WAIT_TIMEOUT = 0x80028008, - SCE_KERNEL_ERROR_NOTIFY_CALLBACK = 0x80028009, - SCE_KERNEL_ERROR_WAIT_DELETE = 0x8002800A, - SCE_KERNEL_ERROR_ILLEGAL_ATTR = 0x8002800B, - SCE_KERNEL_ERROR_EVF_MULTI = 0x8002800C, - SCE_KERNEL_ERROR_WAIT_CANCEL = 0x8002800D, - SCE_KERNEL_ERROR_EVF_COND = 0x8002800E, - SCE_KERNEL_ERROR_ILLEGAL_COUNT = 0x8002800F, - SCE_KERNEL_ERROR_ILLEGAL_PRIORITY = 0x80028010, - SCE_KERNEL_ERROR_MUTEX_RECURSIVE = 0x80028011, - SCE_KERNEL_ERROR_MUTEX_LOCK_OVF = 0x80028012, - SCE_KERNEL_ERROR_MUTEX_NOT_OWNED = 0x80028013, - SCE_KERNEL_ERROR_MUTEX_UNLOCK_UDF = 0x80028014, - SCE_KERNEL_ERROR_MUTEX_FAILED_TO_OWN = 0x80028015, - SCE_KERNEL_ERROR_FAST_MUTEX_RECURSIVE = 0x80028016, - SCE_KERNEL_ERROR_FAST_MUTEX_LOCK_OVF = 0x80028017, - SCE_KERNEL_ERROR_FAST_MUTEX_FAILED_TO_OWN = 0x80028018, - SCE_KERNEL_ERROR_FAST_MUTEX_NOT_OWNED = 0x80028019, - SCE_KERNEL_ERROR_FAST_MUTEX_OWNED = 0x8002801A, - SCE_KERNEL_ERROR_ALARM_CAN_NOT_CANCEL = 0x8002801B, - SCE_KERNEL_ERROR_INVALID_OBJECT_TYPE = 0x8002801C, - SCE_KERNEL_ERROR_KERNEL_TLS_FULL = 0x8002801D, - SCE_KERNEL_ERROR_ILLEGAL_KERNEL_TLS_INDEX = 0x8002801E, - SCE_KERNEL_ERROR_KERNEL_TLS_BUSY = 0x8002801F, - SCE_KERNEL_ERROR_DIFFERENT_UID_CLASS = 0x80028020, - SCE_KERNEL_ERROR_UNKNOWN_UID = 0x80028021, - SCE_KERNEL_ERROR_SEMA_ZERO = 0x80028022, - SCE_KERNEL_ERROR_SEMA_OVF = 0x80028023, - SCE_KERNEL_ERROR_PMON_NOT_THREAD_MODE = 0x80028024, - SCE_KERNEL_ERROR_PMON_NOT_CPU_MODE = 0x80028025, - SCE_KERNEL_ERROR_ALREADY_REGISTERED = 0x80028026, - SCE_KERNEL_ERROR_INVALID_THREAD_ID = 0x80028027, - SCE_KERNEL_ERROR_ALREADY_DEBUG_SUSPENDED = 0x80028028, - SCE_KERNEL_ERROR_NOT_DEBUG_SUSPENDED = 0x80028029, - SCE_KERNEL_ERROR_CAN_NOT_USE_VFP = 0x8002802A, - SCE_KERNEL_ERROR_RUNNING = 0x8002802B, - SCE_KERNEL_ERROR_EVENT_COND = 0x8002802C, - SCE_KERNEL_ERROR_MSG_PIPE_FULL = 0x8002802D, - SCE_KERNEL_ERROR_MSG_PIPE_EMPTY = 0x8002802E, - SCE_KERNEL_ERROR_ALREADY_SENT = 0x8002802F, - SCE_KERNEL_ERROR_CAN_NOT_SUSPEND = 0x80028030, - SCE_KERNEL_ERROR_FAST_MUTEX_ALREADY_INITIALIZED = 0x80028031, - SCE_KERNEL_ERROR_FAST_MUTEX_NOT_INITIALIZED = 0x80028032, - SCE_KERNEL_ERROR_THREAD_STOPPED = 0x80028033, - SCE_KERNEL_ERROR_THREAD_SUSPENDED = 0x80028034, - SCE_KERNEL_ERROR_NOT_SUSPENDED = 0x80028035, - SCE_KERNEL_ERROR_WAIT_DELETE_MUTEX = 0x80028036, - SCE_KERNEL_ERROR_WAIT_CANCEL_MUTEX = 0x80028037, - SCE_KERNEL_ERROR_WAIT_DELETE_COND = 0x80028038, - SCE_KERNEL_ERROR_WAIT_CANCEL_COND = 0x80028039, - SCE_KERNEL_ERROR_LW_MUTEX_NOT_OWNED = 0x8002803A, - SCE_KERNEL_ERROR_LW_MUTEX_LOCK_OVF = 0x8002803B, - SCE_KERNEL_ERROR_LW_MUTEX_UNLOCK_UDF = 0x8002803C, - SCE_KERNEL_ERROR_LW_MUTEX_RECURSIVE = 0x8002803D, - SCE_KERNEL_ERROR_LW_MUTEX_FAILED_TO_OWN = 0x8002803E, - SCE_KERNEL_ERROR_WAIT_DELETE_LW_MUTEX = 0x8002803F, - SCE_KERNEL_ERROR_ILLEGAL_STACK_SIZE = 0x80028040, - SCE_KERNEL_ERROR_RW_LOCK_RECURSIVE = 0x80028041, - SCE_KERNEL_ERROR_RW_LOCK_LOCK_OVF = 0x80028042, - SCE_KERNEL_ERROR_RW_LOCK_NOT_OWNED = 0x80028043, - SCE_KERNEL_ERROR_RW_LOCK_UNLOCK_UDF = 0x80028044, - SCE_KERNEL_ERROR_RW_LOCK_FAILED_TO_LOCK = 0x80028045, - SCE_KERNEL_ERROR_RW_LOCK_FAILED_TO_UNLOCK = 0x80028046, - - SCE_KERNEL_ERROR_PROCESSMGR_ERROR = 0x80029000, - SCE_KERNEL_ERROR_INVALID_PID = 0x80029001, - SCE_KERNEL_ERROR_INVALID_PROCESS_TYPE = 0x80029002, - SCE_KERNEL_ERROR_PLS_FULL = 0x80029003, - SCE_KERNEL_ERROR_INVALID_PROCESS_STATUS = 0x80029004, - SCE_KERNEL_ERROR_INVALID_BUDGET_ID = 0x80029005, - SCE_KERNEL_ERROR_INVALID_BUDGET_SIZE = 0x80029006, - SCE_KERNEL_ERROR_CP14_DISABLED = 0x80029007, - SCE_KERNEL_ERROR_EXCEEDED_MAX_PROCESSES = 0x80029008, - SCE_KERNEL_ERROR_PROCESS_REMAINING = 0x80029009, - SCE_KERNEL_ERROR_IOFILEMGR_ERROR = 0x8002A000, - SCE_KERNEL_ERROR_IO_NAME_TOO_LONG = 0x8002A001, - SCE_KERNEL_ERROR_IO_REG_DEV = 0x8002A002, - SCE_KERNEL_ERROR_IO_ALIAS_USED = 0x8002A003, - SCE_KERNEL_ERROR_IO_DEL_DEV = 0x8002A004, - SCE_KERNEL_ERROR_IO_WOULD_BLOCK = 0x8002A005, - SCE_KERNEL_ERROR_MODULEMGR_START_FAILED = 0x8002D000, - SCE_KERNEL_ERROR_MODULEMGR_STOP_FAIL = 0x8002D001, - SCE_KERNEL_ERROR_MODULEMGR_IN_USE = 0x8002D002, - SCE_KERNEL_ERROR_MODULEMGR_NO_LIB = 0x8002D003, - SCE_KERNEL_ERROR_MODULEMGR_SYSCALL_REG = 0x8002D004, - SCE_KERNEL_ERROR_MODULEMGR_NOMEM_LIB = 0x8002D005, - SCE_KERNEL_ERROR_MODULEMGR_NOMEM_STUB = 0x8002D006, - SCE_KERNEL_ERROR_MODULEMGR_NOMEM_SELF = 0x8002D007, - SCE_KERNEL_ERROR_MODULEMGR_NOMEM = 0x8002D008, - SCE_KERNEL_ERROR_MODULEMGR_INVALID_LIB = 0x8002D009, - SCE_KERNEL_ERROR_MODULEMGR_INVALID_STUB = 0x8002D00A, - SCE_KERNEL_ERROR_MODULEMGR_NO_FUNC_NID = 0x8002D00B, - SCE_KERNEL_ERROR_MODULEMGR_NO_VAR_NID = 0x8002D00C, - SCE_KERNEL_ERROR_MODULEMGR_INVALID_TYPE = 0x8002D00D, - SCE_KERNEL_ERROR_MODULEMGR_NO_MOD_ENTRY = 0x8002D00E, - SCE_KERNEL_ERROR_MODULEMGR_INVALID_PROC_PARAM = 0x8002D00F, - SCE_KERNEL_ERROR_MODULEMGR_NO_MODOBJ = 0x8002D010, - SCE_KERNEL_ERROR_MODULEMGR_NO_MOD = 0x8002D011, - SCE_KERNEL_ERROR_MODULEMGR_NO_PROCESS = 0x8002D012, - SCE_KERNEL_ERROR_MODULEMGR_OLD_LIB = 0x8002D013, - SCE_KERNEL_ERROR_MODULEMGR_STARTED = 0x8002D014, - SCE_KERNEL_ERROR_MODULEMGR_NOT_STARTED = 0x8002D015, - SCE_KERNEL_ERROR_MODULEMGR_NOT_STOPPED = 0x8002D016, - SCE_KERNEL_ERROR_MODULEMGR_INVALID_PROCESS_UID = 0x8002D017, - SCE_KERNEL_ERROR_MODULEMGR_CANNOT_EXPORT_LIB_TO_SHARED = 0x8002D018, - SCE_KERNEL_ERROR_MODULEMGR_INVALID_REL_INFO = 0x8002D019, - SCE_KERNEL_ERROR_MODULEMGR_INVALID_REF_INFO = 0x8002D01A, - SCE_KERNEL_ERROR_MODULEMGR_ELINK = 0x8002D01B, - SCE_KERNEL_ERROR_MODULEMGR_NOENT = 0x8002D01C, - SCE_KERNEL_ERROR_MODULEMGR_BUSY = 0x8002D01D, - SCE_KERNEL_ERROR_MODULEMGR_NOEXEC = 0x8002D01E, - SCE_KERNEL_ERROR_MODULEMGR_NAMETOOLONG = 0x8002D01F, - SCE_KERNEL_ERROR_LIBRARYDB_NOENT = 0x8002D080, - SCE_KERNEL_ERROR_LIBRARYDB_NO_LIB = 0x8002D081, - SCE_KERNEL_ERROR_LIBRARYDB_NO_MOD = 0x8002D082, - SCE_KERNEL_ERROR_AUTHFAIL = 0x8002F000, - SCE_KERNEL_ERROR_NO_AUTH = 0x8002F001, + SCE_KERNEL_ERROR_ERROR = ERROR_CODE(0x80020001), + SCE_KERNEL_ERROR_NOT_IMPLEMENTED = ERROR_CODE(0x80020002), + SCE_KERNEL_ERROR_INVALID_ARGUMENT = ERROR_CODE(0x80020003), + SCE_KERNEL_ERROR_INVALID_ARGUMENT_SIZE = ERROR_CODE(0x80020004), + SCE_KERNEL_ERROR_INVALID_FLAGS = ERROR_CODE(0x80020005), + SCE_KERNEL_ERROR_ILLEGAL_SIZE = ERROR_CODE(0x80020006), + SCE_KERNEL_ERROR_ILLEGAL_ADDR = ERROR_CODE(0x80020007), + SCE_KERNEL_ERROR_UNSUP = ERROR_CODE(0x80020008), + SCE_KERNEL_ERROR_ILLEGAL_MODE = ERROR_CODE(0x80020009), + SCE_KERNEL_ERROR_ILLEGAL_ALIGNMENT = ERROR_CODE(0x8002000A), + SCE_KERNEL_ERROR_NOSYS = ERROR_CODE(0x8002000B), + SCE_KERNEL_ERROR_DEBUG_ERROR = ERROR_CODE(0x80021000), + SCE_KERNEL_ERROR_ILLEGAL_DIPSW_NUMBER = ERROR_CODE(0x80021001), + SCE_KERNEL_ERROR_CPU_ERROR = ERROR_CODE(0x80022000), + SCE_KERNEL_ERROR_MMU_ILLEGAL_L1_TYPE = ERROR_CODE(0x80022001), + SCE_KERNEL_ERROR_MMU_L2_INDEX_OVERFLOW = ERROR_CODE(0x80022002), + SCE_KERNEL_ERROR_MMU_L2_SIZE_OVERFLOW = ERROR_CODE(0x80022003), + SCE_KERNEL_ERROR_INVALID_CPU_AFFINITY = ERROR_CODE(0x80022004), + SCE_KERNEL_ERROR_INVALID_MEMORY_ACCESS = ERROR_CODE(0x80022005), + SCE_KERNEL_ERROR_INVALID_MEMORY_ACCESS_PERMISSION = ERROR_CODE(0x80022006), + SCE_KERNEL_ERROR_VA2PA_FAULT = ERROR_CODE(0x80022007), + SCE_KERNEL_ERROR_VA2PA_MAPPED = ERROR_CODE(0x80022008), + SCE_KERNEL_ERROR_VALIDATION_CHECK_FAILED = ERROR_CODE(0x80022009), + SCE_KERNEL_ERROR_SYSMEM_ERROR = ERROR_CODE(0x80024000), + SCE_KERNEL_ERROR_INVALID_PROCESS_CONTEXT = ERROR_CODE(0x80024001), + SCE_KERNEL_ERROR_UID_NAME_TOO_LONG = ERROR_CODE(0x80024002), + SCE_KERNEL_ERROR_VARANGE_IS_NOT_PHYSICAL_CONTINUOUS = ERROR_CODE(0x80024003), + SCE_KERNEL_ERROR_PHYADDR_ERROR = ERROR_CODE(0x80024100), + SCE_KERNEL_ERROR_NO_PHYADDR = ERROR_CODE(0x80024101), + SCE_KERNEL_ERROR_PHYADDR_USED = ERROR_CODE(0x80024102), + SCE_KERNEL_ERROR_PHYADDR_NOT_USED = ERROR_CODE(0x80024103), + SCE_KERNEL_ERROR_NO_IOADDR = ERROR_CODE(0x80024104), + SCE_KERNEL_ERROR_PHYMEM_ERROR = ERROR_CODE(0x80024300), + SCE_KERNEL_ERROR_ILLEGAL_PHYPAGE_STATUS = ERROR_CODE(0x80024301), + SCE_KERNEL_ERROR_NO_FREE_PHYSICAL_PAGE = ERROR_CODE(0x80024302), + SCE_KERNEL_ERROR_NO_FREE_PHYSICAL_PAGE_UNIT = ERROR_CODE(0x80024303), + SCE_KERNEL_ERROR_PHYMEMPART_NOT_EMPTY = ERROR_CODE(0x80024304), + SCE_KERNEL_ERROR_NO_PHYMEMPART_LPDDR2 = ERROR_CODE(0x80024305), + SCE_KERNEL_ERROR_NO_PHYMEMPART_CDRAM = ERROR_CODE(0x80024306), + SCE_KERNEL_ERROR_FIXEDHEAP_ERROR = ERROR_CODE(0x80024400), + SCE_KERNEL_ERROR_FIXEDHEAP_ILLEGAL_SIZE = ERROR_CODE(0x80024401), + SCE_KERNEL_ERROR_FIXEDHEAP_ILLEGAL_INDEX = ERROR_CODE(0x80024402), + SCE_KERNEL_ERROR_FIXEDHEAP_INDEX_OVERFLOW = ERROR_CODE(0x80024403), + SCE_KERNEL_ERROR_FIXEDHEAP_NO_CHUNK = ERROR_CODE(0x80024404), + SCE_KERNEL_ERROR_UID_ERROR = ERROR_CODE(0x80024500), + SCE_KERNEL_ERROR_INVALID_UID = ERROR_CODE(0x80024501), + SCE_KERNEL_ERROR_SYSMEM_UID_INVALID_ARGUMENT = ERROR_CODE(0x80024502), + SCE_KERNEL_ERROR_SYSMEM_INVALID_UID_RANGE = ERROR_CODE(0x80024503), + SCE_KERNEL_ERROR_SYSMEM_NO_VALID_UID = ERROR_CODE(0x80024504), + SCE_KERNEL_ERROR_SYSMEM_CANNOT_ALLOCATE_UIDENTRY = ERROR_CODE(0x80024505), + SCE_KERNEL_ERROR_NOT_PROCESS_UID = ERROR_CODE(0x80024506), + SCE_KERNEL_ERROR_NOT_KERNEL_UID = ERROR_CODE(0x80024507), + SCE_KERNEL_ERROR_INVALID_UID_CLASS = ERROR_CODE(0x80024508), + SCE_KERNEL_ERROR_INVALID_UID_SUBCLASS = ERROR_CODE(0x80024509), + SCE_KERNEL_ERROR_UID_CANNOT_FIND_BY_NAME = ERROR_CODE(0x8002450A), + SCE_KERNEL_ERROR_VIRPAGE_ERROR = ERROR_CODE(0x80024600), + SCE_KERNEL_ERROR_ILLEGAL_VIRPAGE_TYPE = ERROR_CODE(0x80024601), + SCE_KERNEL_ERROR_BLOCK_ERROR = ERROR_CODE(0x80024700), + SCE_KERNEL_ERROR_ILLEGAL_BLOCK_ID = ERROR_CODE(0x80024701), + SCE_KERNEL_ERROR_ILLEGAL_BLOCK_TYPE = ERROR_CODE(0x80024702), + SCE_KERNEL_ERROR_BLOCK_IN_USE = ERROR_CODE(0x80024703), + SCE_KERNEL_ERROR_PARTITION_ERROR = ERROR_CODE(0x80024800), + SCE_KERNEL_ERROR_ILLEGAL_PARTITION_ID = ERROR_CODE(0x80024801), + SCE_KERNEL_ERROR_ILLEGAL_PARTITION_INDEX = ERROR_CODE(0x80024802), + SCE_KERNEL_ERROR_NO_L2PAGETABLE = ERROR_CODE(0x80024803), + SCE_KERNEL_ERROR_HEAPLIB_ERROR = ERROR_CODE(0x80024900), + SCE_KERNEL_ERROR_ILLEGAL_HEAP_ID = ERROR_CODE(0x80024901), + SCE_KERNEL_ERROR_OUT_OF_RANG = ERROR_CODE(0x80024902), + SCE_KERNEL_ERROR_HEAPLIB_NOMEM = ERROR_CODE(0x80024903), + SCE_KERNEL_ERROR_SYSMEM_ADDRESS_SPACE_ERROR = ERROR_CODE(0x80024A00), + SCE_KERNEL_ERROR_INVALID_ADDRESS_SPACE_ID = ERROR_CODE(0x80024A01), + SCE_KERNEL_ERROR_INVALID_PARTITION_INDEX = ERROR_CODE(0x80024A02), + SCE_KERNEL_ERROR_ADDRESS_SPACE_CANNOT_FIND_PARTITION_BY_ADDR = ERROR_CODE(0x80024A03), + SCE_KERNEL_ERROR_SYSMEM_MEMBLOCK_ERROR = ERROR_CODE(0x80024B00), + SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK_TYPE = ERROR_CODE(0x80024B01), + SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK_REMAP_TYPE = ERROR_CODE(0x80024B02), + SCE_KERNEL_ERROR_NOT_PHY_CONT_MEMBLOCK = ERROR_CODE(0x80024B03), + SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK_CODE = ERROR_CODE(0x80024B04), + SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK_SIZE = ERROR_CODE(0x80024B05), + SCE_KERNEL_ERROR_ILLEGAL_USERMAP_SIZE = ERROR_CODE(0x80024B06), + SCE_KERNEL_ERROR_MEMBLOCK_TYPE_FOR_KERNEL_PROCESS = ERROR_CODE(0x80024B07), + SCE_KERNEL_ERROR_PROCESS_CANNOT_REMAP_MEMBLOCK = ERROR_CODE(0x80024B08), + SCE_KERNEL_ERROR_SYSMEM_PHYMEMLOW_ERROR = ERROR_CODE(0x80024C00), + SCE_KERNEL_ERROR_CANNOT_ALLOC_PHYMEMLOW = ERROR_CODE(0x80024C01), + SCE_KERNEL_ERROR_UNKNOWN_PHYMEMLOW_TYPE = ERROR_CODE(0x80024C02), + SCE_KERNEL_ERROR_SYSMEM_BITHEAP_ERROR = ERROR_CODE(0x80024D00), + SCE_KERNEL_ERROR_CANNOT_ALLOC_BITHEAP = ERROR_CODE(0x80024D01), + SCE_KERNEL_ERROR_LOADCORE_ERROR = ERROR_CODE(0x80025000), + SCE_KERNEL_ERROR_ILLEGAL_ELF_HEADER = ERROR_CODE(0x80025001), + SCE_KERNEL_ERROR_ILLEGAL_SELF_HEADER = ERROR_CODE(0x80025002), }; +enum SceLibKernelError0 : s32 +{ + SCE_KERNEL_ERROR_EXCPMGR_ERROR = ERROR_CODE(0x80027000), + SCE_KERNEL_ERROR_ILLEGAL_EXCPCODE = ERROR_CODE(0x80027001), + SCE_KERNEL_ERROR_ILLEGAL_EXCPHANDLER = ERROR_CODE(0x80027002), + SCE_KERNEL_ERROR_NOTFOUND_EXCPHANDLER = ERROR_CODE(0x80027003), + SCE_KERNEL_ERROR_CANNOT_RELEASE_EXCPHANDLER = ERROR_CODE(0x80027004), + SCE_KERNEL_ERROR_INTRMGR_ERROR = ERROR_CODE(0x80027100), + SCE_KERNEL_ERROR_ILLEGAL_CONTEXT = ERROR_CODE(0x80027101), + SCE_KERNEL_ERROR_ILLEGAL_INTRCODE = ERROR_CODE(0x80027102), + SCE_KERNEL_ERROR_ILLEGAL_INTRPARAM = ERROR_CODE(0x80027103), + SCE_KERNEL_ERROR_ILLEGAL_INTRPRIORITY = ERROR_CODE(0x80027104), + SCE_KERNEL_ERROR_ILLEGAL_TARGET_CPU = ERROR_CODE(0x80027105), + SCE_KERNEL_ERROR_ILLEGAL_INTRFILTER = ERROR_CODE(0x80027106), + SCE_KERNEL_ERROR_ILLEGAL_INTRTYPE = ERROR_CODE(0x80027107), + SCE_KERNEL_ERROR_ILLEGAL_HANDLER = ERROR_CODE(0x80027108), + SCE_KERNEL_ERROR_FOUND_HANDLER = ERROR_CODE(0x80027109), + SCE_KERNEL_ERROR_NOTFOUND_HANDLER = ERROR_CODE(0x8002710A), + SCE_KERNEL_ERROR_NO_MEMORY = ERROR_CODE(0x8002710B), + SCE_KERNEL_ERROR_DMACMGR_ERROR = ERROR_CODE(0x80027200), + SCE_KERNEL_ERROR_ALREADY_QUEUED = ERROR_CODE(0x80027201), + SCE_KERNEL_ERROR_NOT_QUEUED = ERROR_CODE(0x80027202), + SCE_KERNEL_ERROR_NOT_SETUP = ERROR_CODE(0x80027203), + SCE_KERNEL_ERROR_ON_TRANSFERRING = ERROR_CODE(0x80027204), + SCE_KERNEL_ERROR_NOT_INITIALIZED = ERROR_CODE(0x80027205), + SCE_KERNEL_ERROR_TRANSFERRED = ERROR_CODE(0x80027206), + SCE_KERNEL_ERROR_NOT_UNDER_CONTROL = ERROR_CODE(0x80027207), + SCE_KERNEL_ERROR_SYSTIMER_ERROR = ERROR_CODE(0x80027300), + SCE_KERNEL_ERROR_NO_FREE_TIMER = ERROR_CODE(0x80027301), + SCE_KERNEL_ERROR_TIMER_NOT_ALLOCATED = ERROR_CODE(0x80027302), + SCE_KERNEL_ERROR_TIMER_COUNTING = ERROR_CODE(0x80027303), + SCE_KERNEL_ERROR_TIMER_STOPPED = ERROR_CODE(0x80027304), + SCE_KERNEL_ERROR_THREADMGR_ERROR = ERROR_CODE(0x80028000), + SCE_KERNEL_ERROR_DORMANT = ERROR_CODE(0x80028001), + SCE_KERNEL_ERROR_NOT_DORMANT = ERROR_CODE(0x80028002), + SCE_KERNEL_ERROR_UNKNOWN_THID = ERROR_CODE(0x80028003), + SCE_KERNEL_ERROR_CAN_NOT_WAIT = ERROR_CODE(0x80028004), + SCE_KERNEL_ERROR_ILLEGAL_THID = ERROR_CODE(0x80028005), + SCE_KERNEL_ERROR_THREAD_TERMINATED = ERROR_CODE(0x80028006), + SCE_KERNEL_ERROR_DELETED = ERROR_CODE(0x80028007), + SCE_KERNEL_ERROR_WAIT_TIMEOUT = ERROR_CODE(0x80028008), + SCE_KERNEL_ERROR_NOTIFY_CALLBACK = ERROR_CODE(0x80028009), + SCE_KERNEL_ERROR_WAIT_DELETE = ERROR_CODE(0x8002800A), + SCE_KERNEL_ERROR_ILLEGAL_ATTR = ERROR_CODE(0x8002800B), + SCE_KERNEL_ERROR_EVF_MULTI = ERROR_CODE(0x8002800C), + SCE_KERNEL_ERROR_WAIT_CANCEL = ERROR_CODE(0x8002800D), + SCE_KERNEL_ERROR_EVF_COND = ERROR_CODE(0x8002800E), + SCE_KERNEL_ERROR_ILLEGAL_COUNT = ERROR_CODE(0x8002800F), + SCE_KERNEL_ERROR_ILLEGAL_PRIORITY = ERROR_CODE(0x80028010), + SCE_KERNEL_ERROR_MUTEX_RECURSIVE = ERROR_CODE(0x80028011), + SCE_KERNEL_ERROR_MUTEX_LOCK_OVF = ERROR_CODE(0x80028012), + SCE_KERNEL_ERROR_MUTEX_NOT_OWNED = ERROR_CODE(0x80028013), + SCE_KERNEL_ERROR_MUTEX_UNLOCK_UDF = ERROR_CODE(0x80028014), + SCE_KERNEL_ERROR_MUTEX_FAILED_TO_OWN = ERROR_CODE(0x80028015), + SCE_KERNEL_ERROR_FAST_MUTEX_RECURSIVE = ERROR_CODE(0x80028016), + SCE_KERNEL_ERROR_FAST_MUTEX_LOCK_OVF = ERROR_CODE(0x80028017), + SCE_KERNEL_ERROR_FAST_MUTEX_FAILED_TO_OWN = ERROR_CODE(0x80028018), + SCE_KERNEL_ERROR_FAST_MUTEX_NOT_OWNED = ERROR_CODE(0x80028019), + SCE_KERNEL_ERROR_FAST_MUTEX_OWNED = ERROR_CODE(0x8002801A), + SCE_KERNEL_ERROR_ALARM_CAN_NOT_CANCEL = ERROR_CODE(0x8002801B), + SCE_KERNEL_ERROR_INVALID_OBJECT_TYPE = ERROR_CODE(0x8002801C), + SCE_KERNEL_ERROR_KERNEL_TLS_FULL = ERROR_CODE(0x8002801D), + SCE_KERNEL_ERROR_ILLEGAL_KERNEL_TLS_INDEX = ERROR_CODE(0x8002801E), + SCE_KERNEL_ERROR_KERNEL_TLS_BUSY = ERROR_CODE(0x8002801F), + SCE_KERNEL_ERROR_DIFFERENT_UID_CLASS = ERROR_CODE(0x80028020), + SCE_KERNEL_ERROR_UNKNOWN_UID = ERROR_CODE(0x80028021), + SCE_KERNEL_ERROR_SEMA_ZERO = ERROR_CODE(0x80028022), + SCE_KERNEL_ERROR_SEMA_OVF = ERROR_CODE(0x80028023), + SCE_KERNEL_ERROR_PMON_NOT_THREAD_MODE = ERROR_CODE(0x80028024), + SCE_KERNEL_ERROR_PMON_NOT_CPU_MODE = ERROR_CODE(0x80028025), + SCE_KERNEL_ERROR_ALREADY_REGISTERED = ERROR_CODE(0x80028026), + SCE_KERNEL_ERROR_INVALID_THREAD_ID = ERROR_CODE(0x80028027), + SCE_KERNEL_ERROR_ALREADY_DEBUG_SUSPENDED = ERROR_CODE(0x80028028), + SCE_KERNEL_ERROR_NOT_DEBUG_SUSPENDED = ERROR_CODE(0x80028029), + SCE_KERNEL_ERROR_CAN_NOT_USE_VFP = ERROR_CODE(0x8002802A), + SCE_KERNEL_ERROR_RUNNING = ERROR_CODE(0x8002802B), + SCE_KERNEL_ERROR_EVENT_COND = ERROR_CODE(0x8002802C), + SCE_KERNEL_ERROR_MSG_PIPE_FULL = ERROR_CODE(0x8002802D), + SCE_KERNEL_ERROR_MSG_PIPE_EMPTY = ERROR_CODE(0x8002802E), + SCE_KERNEL_ERROR_ALREADY_SENT = ERROR_CODE(0x8002802F), + SCE_KERNEL_ERROR_CAN_NOT_SUSPEND = ERROR_CODE(0x80028030), + SCE_KERNEL_ERROR_FAST_MUTEX_ALREADY_INITIALIZED = ERROR_CODE(0x80028031), + SCE_KERNEL_ERROR_FAST_MUTEX_NOT_INITIALIZED = ERROR_CODE(0x80028032), + SCE_KERNEL_ERROR_THREAD_STOPPED = ERROR_CODE(0x80028033), + SCE_KERNEL_ERROR_THREAD_SUSPENDED = ERROR_CODE(0x80028034), + SCE_KERNEL_ERROR_NOT_SUSPENDED = ERROR_CODE(0x80028035), + SCE_KERNEL_ERROR_WAIT_DELETE_MUTEX = ERROR_CODE(0x80028036), + SCE_KERNEL_ERROR_WAIT_CANCEL_MUTEX = ERROR_CODE(0x80028037), + SCE_KERNEL_ERROR_WAIT_DELETE_COND = ERROR_CODE(0x80028038), + SCE_KERNEL_ERROR_WAIT_CANCEL_COND = ERROR_CODE(0x80028039), + SCE_KERNEL_ERROR_LW_MUTEX_NOT_OWNED = ERROR_CODE(0x8002803A), + SCE_KERNEL_ERROR_LW_MUTEX_LOCK_OVF = ERROR_CODE(0x8002803B), + SCE_KERNEL_ERROR_LW_MUTEX_UNLOCK_UDF = ERROR_CODE(0x8002803C), + SCE_KERNEL_ERROR_LW_MUTEX_RECURSIVE = ERROR_CODE(0x8002803D), + SCE_KERNEL_ERROR_LW_MUTEX_FAILED_TO_OWN = ERROR_CODE(0x8002803E), + SCE_KERNEL_ERROR_WAIT_DELETE_LW_MUTEX = ERROR_CODE(0x8002803F), + SCE_KERNEL_ERROR_ILLEGAL_STACK_SIZE = ERROR_CODE(0x80028040), + SCE_KERNEL_ERROR_RW_LOCK_RECURSIVE = ERROR_CODE(0x80028041), + SCE_KERNEL_ERROR_RW_LOCK_LOCK_OVF = ERROR_CODE(0x80028042), + SCE_KERNEL_ERROR_RW_LOCK_NOT_OWNED = ERROR_CODE(0x80028043), + SCE_KERNEL_ERROR_RW_LOCK_UNLOCK_UDF = ERROR_CODE(0x80028044), + SCE_KERNEL_ERROR_RW_LOCK_FAILED_TO_LOCK = ERROR_CODE(0x80028045), + SCE_KERNEL_ERROR_RW_LOCK_FAILED_TO_UNLOCK = ERROR_CODE(0x80028046), +}; + +enum SceLibKernelError1 : s32 +{ + SCE_KERNEL_ERROR_PROCESSMGR_ERROR = ERROR_CODE(0x80029000), + SCE_KERNEL_ERROR_INVALID_PID = ERROR_CODE(0x80029001), + SCE_KERNEL_ERROR_INVALID_PROCESS_TYPE = ERROR_CODE(0x80029002), + SCE_KERNEL_ERROR_PLS_FULL = ERROR_CODE(0x80029003), + SCE_KERNEL_ERROR_INVALID_PROCESS_STATUS = ERROR_CODE(0x80029004), + SCE_KERNEL_ERROR_INVALID_BUDGET_ID = ERROR_CODE(0x80029005), + SCE_KERNEL_ERROR_INVALID_BUDGET_SIZE = ERROR_CODE(0x80029006), + SCE_KERNEL_ERROR_CP14_DISABLED = ERROR_CODE(0x80029007), + SCE_KERNEL_ERROR_EXCEEDED_MAX_PROCESSES = ERROR_CODE(0x80029008), + SCE_KERNEL_ERROR_PROCESS_REMAINING = ERROR_CODE(0x80029009), + SCE_KERNEL_ERROR_IOFILEMGR_ERROR = ERROR_CODE(0x8002A000), + SCE_KERNEL_ERROR_IO_NAME_TOO_LONG = ERROR_CODE(0x8002A001), + SCE_KERNEL_ERROR_IO_REG_DEV = ERROR_CODE(0x8002A002), + SCE_KERNEL_ERROR_IO_ALIAS_USED = ERROR_CODE(0x8002A003), + SCE_KERNEL_ERROR_IO_DEL_DEV = ERROR_CODE(0x8002A004), + SCE_KERNEL_ERROR_IO_WOULD_BLOCK = ERROR_CODE(0x8002A005), + SCE_KERNEL_ERROR_MODULEMGR_START_FAILED = ERROR_CODE(0x8002D000), + SCE_KERNEL_ERROR_MODULEMGR_STOP_FAIL = ERROR_CODE(0x8002D001), + SCE_KERNEL_ERROR_MODULEMGR_IN_USE = ERROR_CODE(0x8002D002), + SCE_KERNEL_ERROR_MODULEMGR_NO_LIB = ERROR_CODE(0x8002D003), + SCE_KERNEL_ERROR_MODULEMGR_SYSCALL_REG = ERROR_CODE(0x8002D004), + SCE_KERNEL_ERROR_MODULEMGR_NOMEM_LIB = ERROR_CODE(0x8002D005), + SCE_KERNEL_ERROR_MODULEMGR_NOMEM_STUB = ERROR_CODE(0x8002D006), + SCE_KERNEL_ERROR_MODULEMGR_NOMEM_SELF = ERROR_CODE(0x8002D007), + SCE_KERNEL_ERROR_MODULEMGR_NOMEM = ERROR_CODE(0x8002D008), + SCE_KERNEL_ERROR_MODULEMGR_INVALID_LIB = ERROR_CODE(0x8002D009), + SCE_KERNEL_ERROR_MODULEMGR_INVALID_STUB = ERROR_CODE(0x8002D00A), + SCE_KERNEL_ERROR_MODULEMGR_NO_FUNC_NID = ERROR_CODE(0x8002D00B), + SCE_KERNEL_ERROR_MODULEMGR_NO_VAR_NID = ERROR_CODE(0x8002D00C), + SCE_KERNEL_ERROR_MODULEMGR_INVALID_TYPE = ERROR_CODE(0x8002D00D), + SCE_KERNEL_ERROR_MODULEMGR_NO_MOD_ENTRY = ERROR_CODE(0x8002D00E), + SCE_KERNEL_ERROR_MODULEMGR_INVALID_PROC_PARAM = ERROR_CODE(0x8002D00F), + SCE_KERNEL_ERROR_MODULEMGR_NO_MODOBJ = ERROR_CODE(0x8002D010), + SCE_KERNEL_ERROR_MODULEMGR_NO_MOD = ERROR_CODE(0x8002D011), + SCE_KERNEL_ERROR_MODULEMGR_NO_PROCESS = ERROR_CODE(0x8002D012), + SCE_KERNEL_ERROR_MODULEMGR_OLD_LIB = ERROR_CODE(0x8002D013), + SCE_KERNEL_ERROR_MODULEMGR_STARTED = ERROR_CODE(0x8002D014), + SCE_KERNEL_ERROR_MODULEMGR_NOT_STARTED = ERROR_CODE(0x8002D015), + SCE_KERNEL_ERROR_MODULEMGR_NOT_STOPPED = ERROR_CODE(0x8002D016), + SCE_KERNEL_ERROR_MODULEMGR_INVALID_PROCESS_UID = ERROR_CODE(0x8002D017), + SCE_KERNEL_ERROR_MODULEMGR_CANNOT_EXPORT_LIB_TO_SHARED = ERROR_CODE(0x8002D018), + SCE_KERNEL_ERROR_MODULEMGR_INVALID_REL_INFO = ERROR_CODE(0x8002D019), + SCE_KERNEL_ERROR_MODULEMGR_INVALID_REF_INFO = ERROR_CODE(0x8002D01A), + SCE_KERNEL_ERROR_MODULEMGR_ELINK = ERROR_CODE(0x8002D01B), + SCE_KERNEL_ERROR_MODULEMGR_NOENT = ERROR_CODE(0x8002D01C), + SCE_KERNEL_ERROR_MODULEMGR_BUSY = ERROR_CODE(0x8002D01D), + SCE_KERNEL_ERROR_MODULEMGR_NOEXEC = ERROR_CODE(0x8002D01E), + SCE_KERNEL_ERROR_MODULEMGR_NAMETOOLONG = ERROR_CODE(0x8002D01F), + SCE_KERNEL_ERROR_LIBRARYDB_NOENT = ERROR_CODE(0x8002D080), + SCE_KERNEL_ERROR_LIBRARYDB_NO_LIB = ERROR_CODE(0x8002D081), + SCE_KERNEL_ERROR_LIBRARYDB_NO_MOD = ERROR_CODE(0x8002D082), + SCE_KERNEL_ERROR_AUTHFAIL = ERROR_CODE(0x8002F000), + SCE_KERNEL_ERROR_NO_AUTH = ERROR_CODE(0x8002F001), +}; + +template<> +inline const char* arm_error_code::print(SceLibKernelError error) +{ + switch (error) + { + STR_CASE(SCE_KERNEL_ERROR_ERROR); + STR_CASE(SCE_KERNEL_ERROR_NOT_IMPLEMENTED); + STR_CASE(SCE_KERNEL_ERROR_INVALID_ARGUMENT); + STR_CASE(SCE_KERNEL_ERROR_INVALID_ARGUMENT_SIZE); + STR_CASE(SCE_KERNEL_ERROR_INVALID_FLAGS); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_SIZE); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_ADDR); + STR_CASE(SCE_KERNEL_ERROR_UNSUP); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_MODE); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_ALIGNMENT); + STR_CASE(SCE_KERNEL_ERROR_NOSYS); + STR_CASE(SCE_KERNEL_ERROR_DEBUG_ERROR); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_DIPSW_NUMBER); + STR_CASE(SCE_KERNEL_ERROR_CPU_ERROR); + STR_CASE(SCE_KERNEL_ERROR_MMU_ILLEGAL_L1_TYPE); + STR_CASE(SCE_KERNEL_ERROR_MMU_L2_INDEX_OVERFLOW); + STR_CASE(SCE_KERNEL_ERROR_MMU_L2_SIZE_OVERFLOW); + STR_CASE(SCE_KERNEL_ERROR_INVALID_CPU_AFFINITY); + STR_CASE(SCE_KERNEL_ERROR_INVALID_MEMORY_ACCESS); + STR_CASE(SCE_KERNEL_ERROR_INVALID_MEMORY_ACCESS_PERMISSION); + STR_CASE(SCE_KERNEL_ERROR_VA2PA_FAULT); + STR_CASE(SCE_KERNEL_ERROR_VA2PA_MAPPED); + STR_CASE(SCE_KERNEL_ERROR_VALIDATION_CHECK_FAILED); + STR_CASE(SCE_KERNEL_ERROR_SYSMEM_ERROR); + STR_CASE(SCE_KERNEL_ERROR_INVALID_PROCESS_CONTEXT); + STR_CASE(SCE_KERNEL_ERROR_UID_NAME_TOO_LONG); + STR_CASE(SCE_KERNEL_ERROR_VARANGE_IS_NOT_PHYSICAL_CONTINUOUS); + STR_CASE(SCE_KERNEL_ERROR_PHYADDR_ERROR); + STR_CASE(SCE_KERNEL_ERROR_NO_PHYADDR); + STR_CASE(SCE_KERNEL_ERROR_PHYADDR_USED); + STR_CASE(SCE_KERNEL_ERROR_PHYADDR_NOT_USED); + STR_CASE(SCE_KERNEL_ERROR_NO_IOADDR); + STR_CASE(SCE_KERNEL_ERROR_PHYMEM_ERROR); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_PHYPAGE_STATUS); + STR_CASE(SCE_KERNEL_ERROR_NO_FREE_PHYSICAL_PAGE); + STR_CASE(SCE_KERNEL_ERROR_NO_FREE_PHYSICAL_PAGE_UNIT); + STR_CASE(SCE_KERNEL_ERROR_PHYMEMPART_NOT_EMPTY); + STR_CASE(SCE_KERNEL_ERROR_NO_PHYMEMPART_LPDDR2); + STR_CASE(SCE_KERNEL_ERROR_NO_PHYMEMPART_CDRAM); + STR_CASE(SCE_KERNEL_ERROR_FIXEDHEAP_ERROR); + STR_CASE(SCE_KERNEL_ERROR_FIXEDHEAP_ILLEGAL_SIZE); + STR_CASE(SCE_KERNEL_ERROR_FIXEDHEAP_ILLEGAL_INDEX); + STR_CASE(SCE_KERNEL_ERROR_FIXEDHEAP_INDEX_OVERFLOW); + STR_CASE(SCE_KERNEL_ERROR_FIXEDHEAP_NO_CHUNK); + STR_CASE(SCE_KERNEL_ERROR_UID_ERROR); + STR_CASE(SCE_KERNEL_ERROR_INVALID_UID); + STR_CASE(SCE_KERNEL_ERROR_SYSMEM_UID_INVALID_ARGUMENT); + STR_CASE(SCE_KERNEL_ERROR_SYSMEM_INVALID_UID_RANGE); + STR_CASE(SCE_KERNEL_ERROR_SYSMEM_NO_VALID_UID); + STR_CASE(SCE_KERNEL_ERROR_SYSMEM_CANNOT_ALLOCATE_UIDENTRY); + STR_CASE(SCE_KERNEL_ERROR_NOT_PROCESS_UID); + STR_CASE(SCE_KERNEL_ERROR_NOT_KERNEL_UID); + STR_CASE(SCE_KERNEL_ERROR_INVALID_UID_CLASS); + STR_CASE(SCE_KERNEL_ERROR_INVALID_UID_SUBCLASS); + STR_CASE(SCE_KERNEL_ERROR_UID_CANNOT_FIND_BY_NAME); + STR_CASE(SCE_KERNEL_ERROR_VIRPAGE_ERROR); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_VIRPAGE_TYPE); + STR_CASE(SCE_KERNEL_ERROR_BLOCK_ERROR); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_BLOCK_ID); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_BLOCK_TYPE); + STR_CASE(SCE_KERNEL_ERROR_BLOCK_IN_USE); + STR_CASE(SCE_KERNEL_ERROR_PARTITION_ERROR); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_PARTITION_ID); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_PARTITION_INDEX); + STR_CASE(SCE_KERNEL_ERROR_NO_L2PAGETABLE); + STR_CASE(SCE_KERNEL_ERROR_HEAPLIB_ERROR); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_HEAP_ID); + STR_CASE(SCE_KERNEL_ERROR_OUT_OF_RANG); + STR_CASE(SCE_KERNEL_ERROR_HEAPLIB_NOMEM); + STR_CASE(SCE_KERNEL_ERROR_SYSMEM_ADDRESS_SPACE_ERROR); + STR_CASE(SCE_KERNEL_ERROR_INVALID_ADDRESS_SPACE_ID); + STR_CASE(SCE_KERNEL_ERROR_INVALID_PARTITION_INDEX); + STR_CASE(SCE_KERNEL_ERROR_ADDRESS_SPACE_CANNOT_FIND_PARTITION_BY_ADDR); + STR_CASE(SCE_KERNEL_ERROR_SYSMEM_MEMBLOCK_ERROR); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK_TYPE); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK_REMAP_TYPE); + STR_CASE(SCE_KERNEL_ERROR_NOT_PHY_CONT_MEMBLOCK); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK_CODE); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_MEMBLOCK_SIZE); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_USERMAP_SIZE); + STR_CASE(SCE_KERNEL_ERROR_MEMBLOCK_TYPE_FOR_KERNEL_PROCESS); + STR_CASE(SCE_KERNEL_ERROR_PROCESS_CANNOT_REMAP_MEMBLOCK); + STR_CASE(SCE_KERNEL_ERROR_SYSMEM_PHYMEMLOW_ERROR); + STR_CASE(SCE_KERNEL_ERROR_CANNOT_ALLOC_PHYMEMLOW); + STR_CASE(SCE_KERNEL_ERROR_UNKNOWN_PHYMEMLOW_TYPE); + STR_CASE(SCE_KERNEL_ERROR_SYSMEM_BITHEAP_ERROR); + STR_CASE(SCE_KERNEL_ERROR_CANNOT_ALLOC_BITHEAP); + STR_CASE(SCE_KERNEL_ERROR_LOADCORE_ERROR); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_ELF_HEADER); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_SELF_HEADER); + } + + return nullptr; +} + +template<> +inline const char* arm_error_code::print(SceLibKernelError0 error) +{ + switch (error) + { + STR_CASE(SCE_KERNEL_ERROR_EXCPMGR_ERROR); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_EXCPCODE); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_EXCPHANDLER); + STR_CASE(SCE_KERNEL_ERROR_NOTFOUND_EXCPHANDLER); + STR_CASE(SCE_KERNEL_ERROR_CANNOT_RELEASE_EXCPHANDLER); + STR_CASE(SCE_KERNEL_ERROR_INTRMGR_ERROR); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_CONTEXT); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_INTRCODE); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_INTRPARAM); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_INTRPRIORITY); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_TARGET_CPU); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_INTRFILTER); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_INTRTYPE); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_HANDLER); + STR_CASE(SCE_KERNEL_ERROR_FOUND_HANDLER); + STR_CASE(SCE_KERNEL_ERROR_NOTFOUND_HANDLER); + STR_CASE(SCE_KERNEL_ERROR_NO_MEMORY); + STR_CASE(SCE_KERNEL_ERROR_DMACMGR_ERROR); + STR_CASE(SCE_KERNEL_ERROR_ALREADY_QUEUED); + STR_CASE(SCE_KERNEL_ERROR_NOT_QUEUED); + STR_CASE(SCE_KERNEL_ERROR_NOT_SETUP); + STR_CASE(SCE_KERNEL_ERROR_ON_TRANSFERRING); + STR_CASE(SCE_KERNEL_ERROR_NOT_INITIALIZED); + STR_CASE(SCE_KERNEL_ERROR_TRANSFERRED); + STR_CASE(SCE_KERNEL_ERROR_NOT_UNDER_CONTROL); + STR_CASE(SCE_KERNEL_ERROR_SYSTIMER_ERROR); + STR_CASE(SCE_KERNEL_ERROR_NO_FREE_TIMER); + STR_CASE(SCE_KERNEL_ERROR_TIMER_NOT_ALLOCATED); + STR_CASE(SCE_KERNEL_ERROR_TIMER_COUNTING); + STR_CASE(SCE_KERNEL_ERROR_TIMER_STOPPED); + STR_CASE(SCE_KERNEL_ERROR_THREADMGR_ERROR); + STR_CASE(SCE_KERNEL_ERROR_DORMANT); + STR_CASE(SCE_KERNEL_ERROR_NOT_DORMANT); + STR_CASE(SCE_KERNEL_ERROR_UNKNOWN_THID); + STR_CASE(SCE_KERNEL_ERROR_CAN_NOT_WAIT); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_THID); + STR_CASE(SCE_KERNEL_ERROR_THREAD_TERMINATED); + STR_CASE(SCE_KERNEL_ERROR_DELETED); + STR_CASE(SCE_KERNEL_ERROR_WAIT_TIMEOUT); + STR_CASE(SCE_KERNEL_ERROR_NOTIFY_CALLBACK); + STR_CASE(SCE_KERNEL_ERROR_WAIT_DELETE); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_ATTR); + STR_CASE(SCE_KERNEL_ERROR_EVF_MULTI); + STR_CASE(SCE_KERNEL_ERROR_WAIT_CANCEL); + STR_CASE(SCE_KERNEL_ERROR_EVF_COND); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_COUNT); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_PRIORITY); + STR_CASE(SCE_KERNEL_ERROR_MUTEX_RECURSIVE); + STR_CASE(SCE_KERNEL_ERROR_MUTEX_LOCK_OVF); + STR_CASE(SCE_KERNEL_ERROR_MUTEX_NOT_OWNED); + STR_CASE(SCE_KERNEL_ERROR_MUTEX_UNLOCK_UDF); + STR_CASE(SCE_KERNEL_ERROR_MUTEX_FAILED_TO_OWN); + STR_CASE(SCE_KERNEL_ERROR_FAST_MUTEX_RECURSIVE); + STR_CASE(SCE_KERNEL_ERROR_FAST_MUTEX_LOCK_OVF); + STR_CASE(SCE_KERNEL_ERROR_FAST_MUTEX_FAILED_TO_OWN); + STR_CASE(SCE_KERNEL_ERROR_FAST_MUTEX_NOT_OWNED); + STR_CASE(SCE_KERNEL_ERROR_FAST_MUTEX_OWNED); + STR_CASE(SCE_KERNEL_ERROR_ALARM_CAN_NOT_CANCEL); + STR_CASE(SCE_KERNEL_ERROR_INVALID_OBJECT_TYPE); + STR_CASE(SCE_KERNEL_ERROR_KERNEL_TLS_FULL); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_KERNEL_TLS_INDEX); + STR_CASE(SCE_KERNEL_ERROR_KERNEL_TLS_BUSY); + STR_CASE(SCE_KERNEL_ERROR_DIFFERENT_UID_CLASS); + STR_CASE(SCE_KERNEL_ERROR_UNKNOWN_UID); + STR_CASE(SCE_KERNEL_ERROR_SEMA_ZERO); + STR_CASE(SCE_KERNEL_ERROR_SEMA_OVF); + STR_CASE(SCE_KERNEL_ERROR_PMON_NOT_THREAD_MODE); + STR_CASE(SCE_KERNEL_ERROR_PMON_NOT_CPU_MODE); + STR_CASE(SCE_KERNEL_ERROR_ALREADY_REGISTERED); + STR_CASE(SCE_KERNEL_ERROR_INVALID_THREAD_ID); + STR_CASE(SCE_KERNEL_ERROR_ALREADY_DEBUG_SUSPENDED); + STR_CASE(SCE_KERNEL_ERROR_NOT_DEBUG_SUSPENDED); + STR_CASE(SCE_KERNEL_ERROR_CAN_NOT_USE_VFP); + STR_CASE(SCE_KERNEL_ERROR_RUNNING); + STR_CASE(SCE_KERNEL_ERROR_EVENT_COND); + STR_CASE(SCE_KERNEL_ERROR_MSG_PIPE_FULL); + STR_CASE(SCE_KERNEL_ERROR_MSG_PIPE_EMPTY); + STR_CASE(SCE_KERNEL_ERROR_ALREADY_SENT); + STR_CASE(SCE_KERNEL_ERROR_CAN_NOT_SUSPEND); + STR_CASE(SCE_KERNEL_ERROR_FAST_MUTEX_ALREADY_INITIALIZED); + STR_CASE(SCE_KERNEL_ERROR_FAST_MUTEX_NOT_INITIALIZED); + STR_CASE(SCE_KERNEL_ERROR_THREAD_STOPPED); + STR_CASE(SCE_KERNEL_ERROR_THREAD_SUSPENDED); + STR_CASE(SCE_KERNEL_ERROR_NOT_SUSPENDED); + STR_CASE(SCE_KERNEL_ERROR_WAIT_DELETE_MUTEX); + STR_CASE(SCE_KERNEL_ERROR_WAIT_CANCEL_MUTEX); + STR_CASE(SCE_KERNEL_ERROR_WAIT_DELETE_COND); + STR_CASE(SCE_KERNEL_ERROR_WAIT_CANCEL_COND); + STR_CASE(SCE_KERNEL_ERROR_LW_MUTEX_NOT_OWNED); + STR_CASE(SCE_KERNEL_ERROR_LW_MUTEX_LOCK_OVF); + STR_CASE(SCE_KERNEL_ERROR_LW_MUTEX_UNLOCK_UDF); + STR_CASE(SCE_KERNEL_ERROR_LW_MUTEX_RECURSIVE); + STR_CASE(SCE_KERNEL_ERROR_LW_MUTEX_FAILED_TO_OWN); + STR_CASE(SCE_KERNEL_ERROR_WAIT_DELETE_LW_MUTEX); + STR_CASE(SCE_KERNEL_ERROR_ILLEGAL_STACK_SIZE); + STR_CASE(SCE_KERNEL_ERROR_RW_LOCK_RECURSIVE); + STR_CASE(SCE_KERNEL_ERROR_RW_LOCK_LOCK_OVF); + STR_CASE(SCE_KERNEL_ERROR_RW_LOCK_NOT_OWNED); + STR_CASE(SCE_KERNEL_ERROR_RW_LOCK_UNLOCK_UDF); + STR_CASE(SCE_KERNEL_ERROR_RW_LOCK_FAILED_TO_LOCK); + STR_CASE(SCE_KERNEL_ERROR_RW_LOCK_FAILED_TO_UNLOCK); + } + + return nullptr; +} + +template<> +inline const char* arm_error_code::print(SceLibKernelError1 error) +{ + switch (error) + { + STR_CASE(SCE_KERNEL_ERROR_PROCESSMGR_ERROR); + STR_CASE(SCE_KERNEL_ERROR_INVALID_PID); + STR_CASE(SCE_KERNEL_ERROR_INVALID_PROCESS_TYPE); + STR_CASE(SCE_KERNEL_ERROR_PLS_FULL); + STR_CASE(SCE_KERNEL_ERROR_INVALID_PROCESS_STATUS); + STR_CASE(SCE_KERNEL_ERROR_INVALID_BUDGET_ID); + STR_CASE(SCE_KERNEL_ERROR_INVALID_BUDGET_SIZE); + STR_CASE(SCE_KERNEL_ERROR_CP14_DISABLED); + STR_CASE(SCE_KERNEL_ERROR_EXCEEDED_MAX_PROCESSES); + STR_CASE(SCE_KERNEL_ERROR_PROCESS_REMAINING); + STR_CASE(SCE_KERNEL_ERROR_IOFILEMGR_ERROR); + STR_CASE(SCE_KERNEL_ERROR_IO_NAME_TOO_LONG); + STR_CASE(SCE_KERNEL_ERROR_IO_REG_DEV); + STR_CASE(SCE_KERNEL_ERROR_IO_ALIAS_USED); + STR_CASE(SCE_KERNEL_ERROR_IO_DEL_DEV); + STR_CASE(SCE_KERNEL_ERROR_IO_WOULD_BLOCK); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_START_FAILED); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_STOP_FAIL); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_IN_USE); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_NO_LIB); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_SYSCALL_REG); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_NOMEM_LIB); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_NOMEM_STUB); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_NOMEM_SELF); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_NOMEM); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_INVALID_LIB); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_INVALID_STUB); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_NO_FUNC_NID); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_NO_VAR_NID); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_INVALID_TYPE); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_NO_MOD_ENTRY); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_INVALID_PROC_PARAM); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_NO_MODOBJ); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_NO_MOD); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_NO_PROCESS); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_OLD_LIB); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_STARTED); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_NOT_STARTED); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_NOT_STOPPED); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_INVALID_PROCESS_UID); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_CANNOT_EXPORT_LIB_TO_SHARED); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_INVALID_REL_INFO); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_INVALID_REF_INFO); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_ELINK); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_NOENT); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_BUSY); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_NOEXEC); + STR_CASE(SCE_KERNEL_ERROR_MODULEMGR_NAMETOOLONG); + STR_CASE(SCE_KERNEL_ERROR_LIBRARYDB_NOENT); + STR_CASE(SCE_KERNEL_ERROR_LIBRARYDB_NO_LIB); + STR_CASE(SCE_KERNEL_ERROR_LIBRARYDB_NO_MOD); + STR_CASE(SCE_KERNEL_ERROR_AUTHFAIL); + STR_CASE(SCE_KERNEL_ERROR_NO_AUTH); + } + + return nullptr; +} + enum psv_object_class_t : u32 { SCE_KERNEL_UID_CLASS_PROCESS = 0, @@ -458,7 +740,7 @@ struct psv_event_flag_t std::mutex mutex; - sleep_queue_t sq; + sleep_queue sq; psv_event_flag_t(const char* name, u32 attr, u32 pattern) : name(name) @@ -479,7 +761,8 @@ struct psv_event_flag_t { static_cast(*thread).GPR[0] = SCE_KERNEL_ERROR_WAIT_DELETE; static_cast(*thread).GPR[1] = pattern; - thread->signal(); + thread->state += cpu_state::signal; + thread->cv.notify_one(); } } }; @@ -741,8 +1024,6 @@ struct SceIoDirent }; // Module -extern psv_log_base sceLibKernel; - // Aux inline bool ipc_ref_try_dec(u32& ref) diff --git a/rpcs3/Emu/ARMv7/Modules/sceXml.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibXml.cpp similarity index 97% rename from rpcs3/Emu/ARMv7/Modules/sceXml.cpp rename to rpcs3/Emu/ARMv7/Modules/sceLibXml.cpp index f07d94665b..789a45e8d7 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceXml.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibXml.cpp @@ -1,18 +1,15 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" -#include "sceXml.h" +#include "sceLibXml.h" -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceXml, #name, name) +LOG_CHANNEL(sceLibXml); -psv_log_base sceXml("SceXml", []() +#define REG_FUNC(nid, name) REG_FNID(SceLibXml, nid, name) + +DECLARE(arm_module_manager::SceLibXml)("SceLibXml", []() { - sceXml.on_load = nullptr; - sceXml.on_unload = nullptr; - sceXml.on_stop = nullptr; - sceXml.on_error = nullptr; - //REG_FUNC(0x57400A1A, _ZN3sce3Xml10SimpleDataC1EPKcj); //REG_FUNC(0x7E582075, _ZN3sce3Xml10SimpleDataC1Ev); //REG_FUNC(0x4CF0656B, _ZN3sce3Xml10SimpleDataC2EPKcj); diff --git a/rpcs3/Emu/SysCalls/Modules/sceNpUtil.h b/rpcs3/Emu/ARMv7/Modules/sceLibXml.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/sceNpUtil.h rename to rpcs3/Emu/ARMv7/Modules/sceLibXml.h diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp index d3a3f08c47..0e23fc0e3e 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp @@ -1,18 +1,21 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "Emu/ARMv7/ARMv7Thread.h" #include "Emu/ARMv7/ARMv7Callback.h" #include "sceLibc.h" +LOG_CHANNEL(sceLibc); + +// TODO vm::ptr g_dso; std::vector> g_atexit; std::mutex g_atexit_mutex; -std::string armv7_fmt(ARMv7Context& context, vm::cptr fmt, u32 g_count, u32 f_count, u32 v_count) +std::string arm_fmt(ARMv7Thread& cpu, vm::cptr fmt, u32 g_count) { std::string result; @@ -40,7 +43,7 @@ std::string armv7_fmt(ARMv7Context& context, vm::cptr fmt, u32 g_count, u3 if (*fmt == '*') { fmt++; - return context.get_next_gpr_arg(g_count, f_count, v_count); + return cpu.get_next_gpr_arg(g_count); } while (*fmt - '0' < 10) @@ -64,7 +67,7 @@ std::string armv7_fmt(ARMv7Context& context, vm::cptr fmt, u32 g_count, u3 if (*++fmt == '*') { fmt++; - return context.get_next_gpr_arg(g_count, f_count, v_count); + return cpu.get_next_gpr_arg(g_count); } while (*fmt - '0' < 10) @@ -88,7 +91,7 @@ std::string armv7_fmt(ARMv7Context& context, vm::cptr fmt, u32 g_count, u3 case 'i': { // signed decimal - const s64 value = context.get_next_gpr_arg(g_count, f_count, v_count); + const s64 value = cpu.get_next_gpr_arg(g_count); if (plus_sign || minus_sign || space_sign || number_sign || zero_padding || width || prec) break; @@ -99,7 +102,7 @@ std::string armv7_fmt(ARMv7Context& context, vm::cptr fmt, u32 g_count, u3 case 'X': { // hexadecimal - const u64 value = context.get_next_gpr_arg(g_count, f_count, v_count); + const u64 value = cpu.get_next_gpr_arg(g_count); if (plus_sign || minus_sign || space_sign || prec) break; @@ -108,7 +111,7 @@ std::string armv7_fmt(ARMv7Context& context, vm::cptr fmt, u32 g_count, u3 result += cf == 'x' ? "0x" : "0X"; } - const std::string& hex = cf == 'x' ? fmt::to_hex(value) : fmt::toupper(fmt::to_hex(value)); + const std::string& hex = cf == 'x' ? fmt::to_hex(value) : fmt::to_upper(fmt::to_hex(value)); if (hex.length() >= width) { @@ -127,7 +130,7 @@ std::string armv7_fmt(ARMv7Context& context, vm::cptr fmt, u32 g_count, u3 case 's': { // string - const vm::cptr string{ context.get_next_gpr_arg(g_count, f_count, v_count), vm::addr }; + const vm::cptr string{ cpu.get_next_gpr_arg(g_count), vm::addr }; if (plus_sign || minus_sign || space_sign || number_sign || zero_padding || width || prec) break; @@ -154,9 +157,9 @@ namespace sce_libc_func std::lock_guard lock(g_atexit_mutex); - g_atexit.insert(g_atexit.begin(), [func, arg, dso](ARMv7Thread& context) + g_atexit.insert(g_atexit.begin(), [func, arg, dso](ARMv7Thread& cpu) { - func(context, arg); + func(cpu, arg); }); } @@ -166,13 +169,13 @@ namespace sce_libc_func std::lock_guard lock(g_atexit_mutex); - g_atexit.insert(g_atexit.begin(), [func, arg, dso](ARMv7Thread& context) + g_atexit.insert(g_atexit.begin(), [func, arg, dso](ARMv7Thread& cpu) { - func(context, arg); + func(cpu, arg); }); } - void exit(ARMv7Thread& context) + void exit(ARMv7Thread& cpu) { sceLibc.warning("exit()"); @@ -182,7 +185,7 @@ namespace sce_libc_func for (auto& func : decltype(g_atexit)(std::move(g_atexit))) { - func(context); + func(cpu); } sceLibc.success("Process finished"); @@ -196,27 +199,27 @@ namespace sce_libc_func { CHECK_EMU_STATUS; - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(1ms); } } - void printf(ARMv7Thread& context, vm::cptr fmt, armv7_va_args_t va_args) + void printf(ARMv7Thread& cpu, vm::cptr fmt, arm_va_args_t va_args) { sceLibc.warning("printf(fmt=*0x%x)", fmt); sceLibc.trace("*** *fmt = '%s'", fmt.get_ptr()); - const std::string& result = armv7_fmt(context, fmt, va_args.g_count, va_args.f_count, va_args.v_count); + const std::string& result = arm_fmt(cpu, fmt, va_args.count); sceLibc.trace("*** -> '%s'", result); _log::g_tty_file.log(result); } - void sprintf(ARMv7Thread& context, vm::ptr str, vm::cptr fmt, armv7_va_args_t va_args) + void sprintf(ARMv7Thread& cpu, vm::ptr str, vm::cptr fmt, arm_va_args_t va_args) { sceLibc.warning("sprintf(str=*0x%x, fmt=*0x%x)", str, fmt); sceLibc.trace("*** *fmt = '%s'", fmt.get_ptr()); - const std::string& result = armv7_fmt(context, fmt, va_args.g_count, va_args.f_count, va_args.v_count); + const std::string& result = arm_fmt(cpu, fmt, va_args.count); sceLibc.trace("*** -> '%s'", result); ::memcpy(str.get_ptr(), result.c_str(), result.size() + 1); @@ -225,8 +228,9 @@ namespace sce_libc_func void __cxa_set_dso_handle_main(vm::ptr dso) { sceLibc.warning("__cxa_set_dso_handle_main(dso=*0x%x)", dso); - + g_dso = dso; + g_atexit.clear(); } void memcpy(vm::ptr dst, vm::cptr src, u32 size) @@ -252,18 +256,10 @@ namespace sce_libc_func } } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceLibc, #name, sce_libc_func::name) +#define REG_FUNC(nid, name) REG_FNID(SceLibc, nid, sce_libc_func::name) -psv_log_base sceLibc("SceLibc", []() +DECLARE(arm_module_manager::SceLibc)("SceLibc", []() { - g_dso = vm::null; - g_atexit.clear(); - - sceLibc.on_load = nullptr; - sceLibc.on_unload = nullptr; - sceLibc.on_stop = nullptr; - sceLibc.on_error = nullptr; - REG_FUNC(0xE4531F85, _Assert); //REG_FUNC(0xE71C5CDE, _Stoul); //REG_FUNC(0x7A5CA6A3, _Stoulx); diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibc.h b/rpcs3/Emu/ARMv7/Modules/sceLibc.h index 2766711aea..05cc11c1b4 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibc.h +++ b/rpcs3/Emu/ARMv7/Modules/sceLibc.h @@ -1,5 +1,3 @@ #pragma once using atexit_func_t = void(vm::ptr); - -extern psv_log_base sceLibc; diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibm.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibm.cpp index 6bf914f617..cdadc4e103 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibm.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibm.cpp @@ -1,23 +1,20 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceLibm.h" +LOG_CHANNEL(sceLibm); + namespace sce_libm_func { } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceLibm, #name, sce_libm_func::name) +#define REG_FUNC(nid, name) REG_FNID(SceLibm, nid, sce_libm_func::name) -psv_log_base sceLibm("SceLibm", []() +DECLARE(arm_module_manager::SceLibm)("SceLibm", []() { - sceLibm.on_load = nullptr; - sceLibm.on_unload = nullptr; - sceLibm.on_stop = nullptr; - sceLibm.on_error = nullptr; - //REG_FUNC(0xC73FE76D, _Exp); //REG_FUNC(0xFF4EAE04, _FExp); //REG_FUNC(0xB363D7D4, _LExp); diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibm.h b/rpcs3/Emu/ARMv7/Modules/sceLibm.h index 1b0a58e4f6..6f70f09bee 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibm.h +++ b/rpcs3/Emu/ARMv7/Modules/sceLibm.h @@ -1,3 +1 @@ #pragma once - -extern psv_log_base sceLibm; diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibstdcxx.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibstdcxx.cpp index 82dd811e25..53fd57dcec 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibstdcxx.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibstdcxx.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceLibstdcxx.h" +LOG_CHANNEL(sceLibstdcxx); + namespace sce_libstdcxx_func { void __aeabi_unwind_cpp_pr0() @@ -22,16 +24,12 @@ namespace sce_libstdcxx_func } } -// Attention: find and set correct original mangled name in third parameter, for example: REG_FUNC(0xAE71DC3, operator_new_nothrow, "_ZnwjRKSt9nothrow_t"); -#define REG_FUNC(nid, name, orig_name) reg_psv_func(nid, &sceLibstdcxx, orig_name, sce_libstdcxx_func::name) +// TODO: find and set correct original mangled name. Currently ignored. +// Example of correct usage: REG_FUNC(0xAE71DC3, operator_new_nothrow, "_ZnwjRKSt9nothrow_t"); +#define REG_FUNC(nid, name, orig_name) REG_FNID(SceLibstdcxx, nid, sce_libstdcxx_func::name) -psv_log_base sceLibstdcxx("SceLibstdcxx", []() +DECLARE(arm_module_manager::SceLibstdcxx)("SceLibstdcxx", []() { - sceLibstdcxx.on_load = nullptr; - sceLibstdcxx.on_unload = nullptr; - sceLibstdcxx.on_stop = nullptr; - sceLibstdcxx.on_error = nullptr; - //REG_FUNC(0x52B0C625, std::bad_typeid::what() const); //REG_FUNC(0x64D7D074, std::bad_typeid::_Doraise() const); //REG_FUNC(0x15FB88E2, std::logic_error::what() const); diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibstdcxx.h b/rpcs3/Emu/ARMv7/Modules/sceLibstdcxx.h index 5ddc0e48f4..6f70f09bee 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibstdcxx.h +++ b/rpcs3/Emu/ARMv7/Modules/sceLibstdcxx.h @@ -1,3 +1 @@ #pragma once - -extern psv_log_base sceLibstdcxx; diff --git a/rpcs3/Emu/ARMv7/Modules/sceLiveArea.cpp b/rpcs3/Emu/ARMv7/Modules/sceLiveArea.cpp index 05ef8948e6..f93fe7479e 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLiveArea.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLiveArea.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceLiveArea.h" +LOG_CHANNEL(sceLiveArea); + s32 sceLiveAreaResourceReplaceAll(vm::cptr dirpath) { throw EXCEPTION(""); @@ -14,15 +16,10 @@ s32 sceLiveAreaResourceGetStatus() throw EXCEPTION(""); } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceLiveArea, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceLiveArea, nid, name) -psv_log_base sceLiveArea("SceLiveArea", []() +DECLARE(arm_module_manager::SceLiveArea)("SceLiveArea", []() { - sceLiveArea.on_load = nullptr; - sceLiveArea.on_unload = nullptr; - sceLiveArea.on_stop = nullptr; - sceLiveArea.on_error = nullptr; - REG_FUNC(0xA4B506F9, sceLiveAreaResourceReplaceAll); REG_FUNC(0x54A395FB, sceLiveAreaResourceGetStatus); }); diff --git a/rpcs3/Emu/ARMv7/Modules/sceLiveArea.h b/rpcs3/Emu/ARMv7/Modules/sceLiveArea.h index fab4f795c2..6f70f09bee 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLiveArea.h +++ b/rpcs3/Emu/ARMv7/Modules/sceLiveArea.h @@ -1,3 +1 @@ #pragma once - -extern psv_log_base sceLiveArea; diff --git a/rpcs3/Emu/ARMv7/Modules/sceLocation.cpp b/rpcs3/Emu/ARMv7/Modules/sceLocation.cpp index 007a4e742e..c180e99c52 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLocation.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLocation.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceLocation.h" +LOG_CHANNEL(sceLocation); + s32 sceLocationOpen(vm::ptr handle, SceLocationLocationMethod lmethod, SceLocationHeadingMethod hmethod) { throw EXCEPTION(""); @@ -90,15 +92,10 @@ s32 sceLocationSetGpsEmulationFile(vm::ptr filename) } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceLocation, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceLibLocation, nid, name) -psv_log_base sceLocation("SceLibLocation", []() +DECLARE(arm_module_manager::SceLocation)("SceLibLocation", []() { - sceLocation.on_load = nullptr; - sceLocation.on_unload = nullptr; - sceLocation.on_stop = nullptr; - sceLocation.on_error = nullptr; - REG_FUNC(0xDD271661, sceLocationOpen); REG_FUNC(0x14FE76E8, sceLocationClose); REG_FUNC(0xB1F55065, sceLocationReopen); diff --git a/rpcs3/Emu/ARMv7/Modules/sceLocation.h b/rpcs3/Emu/ARMv7/Modules/sceLocation.h index 95d809797c..f6eccc0fac 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLocation.h +++ b/rpcs3/Emu/ARMv7/Modules/sceLocation.h @@ -79,5 +79,3 @@ struct SceLocationPermissionInfo SceLocationPermissionStatus mainstatus; SceLocationPermissionApplicationStatus applicationstatus; }; - -extern psv_log_base sceLocation; diff --git a/rpcs3/Emu/ARMv7/Modules/sceMd5.cpp b/rpcs3/Emu/ARMv7/Modules/sceMd5.cpp index 8b8172ebf8..e7f1412a5e 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceMd5.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceMd5.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceMd5.h" +LOG_CHANNEL(sceMd5); + s32 sceMd5Digest(vm::cptr plain, u32 len, vm::ptr digest) { throw EXCEPTION(""); @@ -24,15 +26,10 @@ s32 sceMd5BlockResult(vm::ptr pContext, vm::ptr digest) throw EXCEPTION(""); } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceMd5, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceMd5, nid, name) -psv_log_base sceMd5("SceMd5", []() +DECLARE(arm_module_manager::SceMd5)("SceMd5", []() { - sceMd5.on_load = nullptr; - sceMd5.on_unload = nullptr; - sceMd5.on_stop = nullptr; - sceMd5.on_error = nullptr; - REG_FUNC(0xB845BCCB, sceMd5Digest); REG_FUNC(0x4D6436F9, sceMd5BlockInit); REG_FUNC(0x094A4902, sceMd5BlockUpdate); diff --git a/rpcs3/Emu/ARMv7/Modules/sceMd5.h b/rpcs3/Emu/ARMv7/Modules/sceMd5.h index 27b1ba9879..14d1d630ef 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceMd5.h +++ b/rpcs3/Emu/ARMv7/Modules/sceMd5.h @@ -10,5 +10,3 @@ struct SceMd5Context u8 buf[64]; u8 result[64]; }; - -extern psv_log_base sceMd5; diff --git a/rpcs3/Emu/ARMv7/Modules/sceMotion.cpp b/rpcs3/Emu/ARMv7/Modules/sceMotion.cpp index 2b11a2c932..10d1729ecd 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceMotion.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceMotion.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceMotion.h" +LOG_CHANNEL(sceMotion); + s32 sceMotionGetState(vm::ptr motionState) { throw EXCEPTION(""); @@ -84,15 +86,10 @@ s32 sceMotionStopSampling() throw EXCEPTION(""); } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceMotion, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceMotion, nid, name) -psv_log_base sceMotion("SceMotion", []() +DECLARE(arm_module_manager::SceMotion)("SceMotion", []() { - sceMotion.on_load = nullptr; - sceMotion.on_unload = nullptr; - sceMotion.on_stop = nullptr; - sceMotion.on_error = nullptr; - REG_FUNC(0xBDB32767, sceMotionGetState); REG_FUNC(0x47D679EA, sceMotionGetSensorState); REG_FUNC(0xC1652201, sceMotionGetTiltCorrection); diff --git a/rpcs3/Emu/ARMv7/Modules/sceMotion.h b/rpcs3/Emu/ARMv7/Modules/sceMotion.h index 7f1b986758..102108b336 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceMotion.h +++ b/rpcs3/Emu/ARMv7/Modules/sceMotion.h @@ -26,5 +26,3 @@ struct SceMotionSensorState le_t hostTimestamp; u8 reserve3[8]; }; - -extern psv_log_base sceMotion; diff --git a/rpcs3/Emu/ARMv7/Modules/sceMt19937.cpp b/rpcs3/Emu/ARMv7/Modules/sceMt19937.cpp index 885b9c9088..5acabc9c25 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceMt19937.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceMt19937.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceMt19937.h" +LOG_CHANNEL(sceMt19937); + s32 sceMt19937Init(vm::ptr pCtx, u32 seed) { throw EXCEPTION(""); @@ -15,15 +17,10 @@ u32 sceMt19937UInt(vm::ptr pCtx) } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceMt19937, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceMt19937, nid, name) -psv_log_base sceMt19937("SceMt19937", []() +DECLARE(arm_module_manager::SceMt19937)("SceMt19937", []() { - sceMt19937.on_load = nullptr; - sceMt19937.on_unload = nullptr; - sceMt19937.on_stop = nullptr; - sceMt19937.on_error = nullptr; - REG_FUNC(0xEE5BA27C, sceMt19937Init); REG_FUNC(0x29E43BB5, sceMt19937UInt); }); diff --git a/rpcs3/Emu/ARMv7/Modules/sceMt19937.h b/rpcs3/Emu/ARMv7/Modules/sceMt19937.h index b647a670a8..65981e30bc 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceMt19937.h +++ b/rpcs3/Emu/ARMv7/Modules/sceMt19937.h @@ -5,5 +5,3 @@ struct SceMt19937Context le_t count; le_t state[624]; }; - -extern psv_log_base sceMt19937; diff --git a/rpcs3/Emu/ARMv7/Modules/sceNet.cpp b/rpcs3/Emu/ARMv7/Modules/sceNet.cpp index e873854dae..1775cb22a4 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceNet.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceNet.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceNet.h" +LOG_CHANNEL(sceNet); + s32 sceNetSetDnsInfo(vm::ptr info, s32 flags) { throw EXCEPTION(""); @@ -295,15 +297,10 @@ s32 sceNetGetStatisticsInfo(vm::ptr info, s32 flags) } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceNet, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceNet, nid, name) -psv_log_base sceNet("SceNet", []() +DECLARE(arm_module_manager::SceNet)("SceNet", []() { - sceNet.on_load = nullptr; - sceNet.on_unload = nullptr; - sceNet.on_stop = nullptr; - sceNet.on_error = nullptr; - REG_FUNC(0xD62EF218, sceNetSetDnsInfo); REG_FUNC(0xFEC1166D, sceNetClearDnsCache); REG_FUNC(0xAFF9FA4D, sceNetDumpCreate); diff --git a/rpcs3/Emu/ARMv7/Modules/sceNet.h b/rpcs3/Emu/ARMv7/Modules/sceNet.h index 816f31541a..8173c492f5 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceNet.h +++ b/rpcs3/Emu/ARMv7/Modules/sceNet.h @@ -178,5 +178,3 @@ struct SceNetStatisticsInfo le_t libnet_mem_free_size; le_t libnet_mem_free_min; }; - -extern psv_log_base sceNet; diff --git a/rpcs3/Emu/ARMv7/Modules/sceNetCtl.cpp b/rpcs3/Emu/ARMv7/Modules/sceNetCtl.cpp index 46f3880b59..6a19caba05 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceNetCtl.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceNetCtl.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceNetCtl.h" +LOG_CHANNEL(sceNetCtl); + s32 sceNetCtlInit() { throw EXCEPTION(""); @@ -84,15 +86,10 @@ s32 sceNetCtlAdhocGetInAddr(vm::ptr inaddr) throw EXCEPTION(""); } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceNetCtl, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceNetCtl, nid, name) -psv_log_base sceNetCtl("SceNetCtl", []() +DECLARE(arm_module_manager::SceNetCtl)("SceNetCtl", []() { - sceNetCtl.on_load = nullptr; - sceNetCtl.on_unload = nullptr; - sceNetCtl.on_stop = nullptr; - sceNetCtl.on_error = nullptr; - REG_FUNC(0x495CA1DB, sceNetCtlInit); REG_FUNC(0xCD188648, sceNetCtlTerm); REG_FUNC(0xDFFC3ED4, sceNetCtlCheckCallback); diff --git a/rpcs3/Emu/ARMv7/Modules/sceNetCtl.h b/rpcs3/Emu/ARMv7/Modules/sceNetCtl.h index 212ed9bd4b..219486777c 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceNetCtl.h +++ b/rpcs3/Emu/ARMv7/Modules/sceNetCtl.h @@ -43,5 +43,3 @@ struct SceNetCtlAdhocPeerInfo }; using SceNetCtlCallback = void(s32 event_type, vm::ptr arg); - -extern psv_log_base sceNetCtl; diff --git a/rpcs3/Emu/ARMv7/Modules/sceNgs.cpp b/rpcs3/Emu/ARMv7/Modules/sceNgs.cpp index 6f38a0aff6..7b8005c8f0 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceNgs.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceNgs.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceNgs.h" +LOG_CHANNEL(sceNgs); + s32 sceNgsSystemGetRequiredMemorySize(vm::cptr pSynthParams, vm::ptr pnSize) { throw EXCEPTION(""); @@ -320,15 +322,10 @@ s32 sceSulphaNgsTrace(vm::cptr message) } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceNgs, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceNgs, nid, name) -psv_log_base sceNgs("SceNgs", []() +DECLARE(arm_module_manager::SceNgs)("SceNgs", []() { - sceNgs.on_load = nullptr; - sceNgs.on_unload = nullptr; - sceNgs.on_stop = nullptr; - sceNgs.on_error = nullptr; - REG_FUNC(0x6CE8B36F, sceNgsSystemGetRequiredMemorySize); REG_FUNC(0xED14CF4A, sceNgsSystemInit); REG_FUNC(0x684F080C, sceNgsSystemUpdate); diff --git a/rpcs3/Emu/ARMv7/Modules/sceNgs.h b/rpcs3/Emu/ARMv7/Modules/sceNgs.h index ce2d70751a..3c0c34a9f6 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceNgs.h +++ b/rpcs3/Emu/ARMv7/Modules/sceNgs.h @@ -102,5 +102,3 @@ struct SceSulphaNgsConfig le_t maxNamedObjects; le_t maxTraceBufferBytes; }; - -extern psv_log_base sceNgs; diff --git a/rpcs3/Emu/ARMv7/Modules/sceNpBasic.cpp b/rpcs3/Emu/ARMv7/Modules/sceNpBasic.cpp index a081254608..c09a8002c4 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceNpBasic.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceNpBasic.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceNpBasic.h" +LOG_CHANNEL(sceNpBasic); + s32 sceNpBasicInit(vm::ptr opt) { throw EXCEPTION(""); @@ -94,15 +96,10 @@ s32 sceNpBasicGetPlaySessionLog(SceNpBasicPlaySessionLogType type, u32 index, vm throw EXCEPTION(""); } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceNpBasic, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceNpBasic, nid, name) -psv_log_base sceNpBasic("SceNpBasic", []() +DECLARE(arm_module_manager::SceNpBasic)("SceNpBasic", []() { - sceNpBasic.on_load = nullptr; - sceNpBasic.on_unload = nullptr; - sceNpBasic.on_stop = nullptr; - sceNpBasic.on_error = nullptr; - REG_FUNC(0xEFB91A99, sceNpBasicInit); REG_FUNC(0x389BCB3B, sceNpBasicTerm); REG_FUNC(0x26E6E048, sceNpBasicRegisterHandler); diff --git a/rpcs3/Emu/ARMv7/Modules/sceNpBasic.h b/rpcs3/Emu/ARMv7/Modules/sceNpBasic.h index 02c6f4b19e..4079e6c26e 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceNpBasic.h +++ b/rpcs3/Emu/ARMv7/Modules/sceNpBasic.h @@ -113,5 +113,3 @@ enum SceNpBasicPlaySessionLogType : s32 SCE_NP_BASIC_PLAY_SESSION_LOG_TYPE_BY_NP_COMM_ID = 1, SCE_NP_BASIC_PLAY_SESSION_LOG_TYPE_MAX = 2 }; - -extern psv_log_base sceNpBasic; diff --git a/rpcs3/Emu/ARMv7/Modules/sceNpCommon.cpp b/rpcs3/Emu/ARMv7/Modules/sceNpCommon.cpp index 477cab5523..f052347148 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceNpCommon.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceNpCommon.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceNpCommon.h" +LOG_CHANNEL(sceNpCommon); + s32 sceNpAuthInit() { throw EXCEPTION(""); @@ -59,15 +61,10 @@ s32 sceNpCmpNpIdInOrder(vm::cptr npid1, vm::cptr npid2, vm::pt throw EXCEPTION(""); } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceNpCommon, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceNpCommon, nid, name) -psv_log_base sceNpCommon("SceNpCommon", []() +DECLARE(arm_module_manager::SceNpCommon)("SceNpCommon", []() { - sceNpCommon.on_load = nullptr; - sceNpCommon.on_unload = nullptr; - sceNpCommon.on_stop = nullptr; - sceNpCommon.on_error = nullptr; - REG_FUNC(0x441D8B4E, sceNpAuthInit); REG_FUNC(0x6093B689, sceNpAuthTerm); REG_FUNC(0xED42079F, sceNpAuthCreateStartRequest); diff --git a/rpcs3/Emu/ARMv7/Modules/sceNpCommon.h b/rpcs3/Emu/ARMv7/Modules/sceNpCommon.h index 31c2ff9937..f1395ae5dc 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceNpCommon.h +++ b/rpcs3/Emu/ARMv7/Modules/sceNpCommon.h @@ -147,5 +147,3 @@ struct SceNpEntitlement le_t consumedCount; char padding[4]; }; - -extern psv_log_base sceNpCommon; diff --git a/rpcs3/Emu/ARMv7/Modules/sceNpManager.cpp b/rpcs3/Emu/ARMv7/Modules/sceNpManager.cpp index b2dcb72816..e964eaccd2 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceNpManager.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceNpManager.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceNpManager.h" +LOG_CHANNEL(sceNpManager); + s32 sceNpInit(vm::cptr commConf, vm::ptr opt) { throw EXCEPTION(""); @@ -54,15 +56,10 @@ s32 sceNpManagerGetChatRestrictionFlag(vm::ptr isRestricted) throw EXCEPTION(""); } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceNpManager, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceNpManager, nid, name) -psv_log_base sceNpManager("SceNpManager", []() +DECLARE(arm_module_manager::SceNpManager)("SceNpManager", []() { - sceNpManager.on_load = nullptr; - sceNpManager.on_unload = nullptr; - sceNpManager.on_stop = nullptr; - sceNpManager.on_error = nullptr; - REG_FUNC(0x04D9F484, sceNpInit); REG_FUNC(0x19E40AE1, sceNpTerm); REG_FUNC(0x3C94B4B4, sceNpManagerGetNpId); diff --git a/rpcs3/Emu/ARMv7/Modules/sceNpManager.h b/rpcs3/Emu/ARMv7/Modules/sceNpManager.h index 5753bf421d..6feb11b954 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceNpManager.h +++ b/rpcs3/Emu/ARMv7/Modules/sceNpManager.h @@ -8,5 +8,3 @@ struct SceNpOptParam }; using SceNpServiceStateCallback = void(SceNpServiceState state, vm::ptr userdata); - -extern psv_log_base sceNpManager; diff --git a/rpcs3/Emu/ARMv7/Modules/sceNpMatching.cpp b/rpcs3/Emu/ARMv7/Modules/sceNpMatching.cpp index d267f98bb4..0d19c7d717 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceNpMatching.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceNpMatching.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceNpMatching.h" +LOG_CHANNEL(sceNpMatching); + // Functions s32 sceNpMatching2Init(u32 poolSize, s32 threadPriority, s32 cpuAffinityMask, u32 threadStackSize) @@ -224,15 +226,10 @@ s32 sceNpMatching2SignalingGetPeerNetInfoResult( throw EXCEPTION(""); } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceNpMatching, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceNpMatching2, nid, name) -psv_log_base sceNpMatching("SceNpMatching2", []() +DECLARE(arm_module_manager::SceNpMatching)("SceNpMatching2", []() { - sceNpMatching.on_load = nullptr; - sceNpMatching.on_unload = nullptr; - sceNpMatching.on_stop = nullptr; - sceNpMatching.on_error = nullptr; - REG_FUNC(0xEBB1FE74, sceNpMatching2Init); REG_FUNC(0x0124641C, sceNpMatching2Term); REG_FUNC(0xADF578E1, sceNpMatching2CreateContext); diff --git a/rpcs3/Emu/ARMv7/Modules/sceNpMatching.h b/rpcs3/Emu/ARMv7/Modules/sceNpMatching.h index e438c38655..4385720830 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceNpMatching.h +++ b/rpcs3/Emu/ARMv7/Modules/sceNpMatching.h @@ -985,5 +985,3 @@ struct SceNpMatching2SignalingNetInfo SceNetInAddr mappedAddr; le_t natStatus; }; - -extern psv_log_base sceNpMatching; diff --git a/rpcs3/Emu/ARMv7/Modules/sceNpScore.cpp b/rpcs3/Emu/ARMv7/Modules/sceNpScore.cpp index ba7f686505..c9557fdc41 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceNpScore.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceNpScore.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceNpScore.h" +LOG_CHANNEL(sceNpScore); + s32 sceNpScoreInit(s32 threadPriority, s32 cpuAffinityMask, vm::ptr option) { throw EXCEPTION(""); @@ -276,15 +278,10 @@ s32 sceNpScoreSanitizeCommentAsync(s32 reqId, vm::cptr comment, vm::ptr pcId; u8 pad[4]; }; - -extern psv_log_base sceNpScore; diff --git a/rpcs3/Emu/ARMv7/Modules/sceNpUtility.cpp b/rpcs3/Emu/ARMv7/Modules/sceNpUtility.cpp index 1c76fffba6..561bd9d7a2 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceNpUtility.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceNpUtility.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceNpUtility.h" +LOG_CHANNEL(sceNpUtility); + s32 sceNpLookupInit(s32 usesAsync, s32 threadPriority, s32 cpuAffinityMask, vm::ptr option) { throw EXCEPTION(""); @@ -126,15 +128,10 @@ s32 sceNpBandwidthTestAbort() throw EXCEPTION(""); } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceNpUtility, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceNpUtility, nid, name) -psv_log_base sceNpUtility("SceNpUtility", []() +DECLARE(arm_module_manager::SceNpUtility)("SceNpUtility", []() { - sceNpUtility.on_load = nullptr; - sceNpUtility.on_unload = nullptr; - sceNpUtility.on_stop = nullptr; - sceNpUtility.on_error = nullptr; - REG_FUNC(0x9246A673, sceNpLookupInit); REG_FUNC(0x0158B61B, sceNpLookupTerm); REG_FUNC(0x5110E17E, sceNpLookupCreateTitleCtx); diff --git a/rpcs3/Emu/ARMv7/Modules/sceNpUtility.h b/rpcs3/Emu/ARMv7/Modules/sceNpUtility.h index dd2adec373..a66a429a5b 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceNpUtility.h +++ b/rpcs3/Emu/ARMv7/Modules/sceNpUtility.h @@ -9,5 +9,3 @@ struct SceNpBandwidthTestResult le_t result; char padding[4]; }; - -extern psv_log_base sceNpUtility; diff --git a/rpcs3/Emu/ARMv7/Modules/scePerf.cpp b/rpcs3/Emu/ARMv7/Modules/scePerf.cpp index 844c1e79bf..bb04f5b6ad 100644 --- a/rpcs3/Emu/ARMv7/Modules/scePerf.cpp +++ b/rpcs3/Emu/ARMv7/Modules/scePerf.cpp @@ -1,33 +1,29 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "scePerf.h" +LOG_CHANNEL(scePerf); + extern u64 get_system_time(); -s32 scePerfArmPmonReset(ARMv7Thread& context, s32 threadId) +arm_error_code scePerfArmPmonReset(ARMv7Thread& cpu, s32 threadId) { scePerf.warning("scePerfArmPmonReset(threadId=0x%x)", threadId); - if (threadId != SCE_PERF_ARM_PMON_THREAD_ID_SELF) - { - throw EXCEPTION("Unexpected thread"); - } + ASSERT(threadId == SCE_PERF_ARM_PMON_THREAD_ID_SELF); - context.counters = {}; + cpu.counters = {}; return SCE_OK; } -s32 scePerfArmPmonSelectEvent(ARMv7Thread& context, s32 threadId, u32 counter, u8 eventCode) +arm_error_code scePerfArmPmonSelectEvent(ARMv7Thread& cpu, s32 threadId, u32 counter, u8 eventCode) { scePerf.warning("scePerfArmPmonSelectEvent(threadId=0x%x, counter=0x%x, eventCode=0x%x)", threadId, counter, eventCode); - if (threadId != SCE_PERF_ARM_PMON_THREAD_ID_SELF) - { - throw EXCEPTION("Unexpected thread"); - } + ASSERT(threadId == SCE_PERF_ARM_PMON_THREAD_ID_SELF); if (counter >= 6) { @@ -66,44 +62,35 @@ s32 scePerfArmPmonSelectEvent(ARMv7Thread& context, s32 threadId, u32 counter, u } } - context.counters[counter].event = eventCode; - context.counters[counter].value = value; + cpu.counters[counter].event = eventCode; + cpu.counters[counter].value = value; return SCE_OK; } -s32 scePerfArmPmonStart(ARMv7Thread& context, s32 threadId) +arm_error_code scePerfArmPmonStart(ARMv7Thread& cpu, s32 threadId) { scePerf.warning("scePerfArmPmonStart(threadId=0x%x)", threadId); - if (threadId != SCE_PERF_ARM_PMON_THREAD_ID_SELF) - { - throw EXCEPTION("Unexpected thread"); - } + ASSERT(threadId == SCE_PERF_ARM_PMON_THREAD_ID_SELF); return SCE_OK; } -s32 scePerfArmPmonStop(ARMv7Thread& context, s32 threadId) +arm_error_code scePerfArmPmonStop(ARMv7Thread& cpu, s32 threadId) { scePerf.warning("scePerfArmPmonStop(threadId=0x%x)"); - if (threadId != SCE_PERF_ARM_PMON_THREAD_ID_SELF) - { - throw EXCEPTION("Unexpected thread"); - } + ASSERT(threadId == SCE_PERF_ARM_PMON_THREAD_ID_SELF); return SCE_OK; } -s32 scePerfArmPmonGetCounterValue(ARMv7Thread& context, s32 threadId, u32 counter, vm::ptr pValue) +arm_error_code scePerfArmPmonGetCounterValue(ARMv7Thread& cpu, s32 threadId, u32 counter, vm::ptr pValue) { scePerf.warning("scePerfArmPmonGetCounterValue(threadId=0x%x, counter=%d, pValue=*0x%x)", threadId, counter, pValue); - if (threadId != SCE_PERF_ARM_PMON_THREAD_ID_SELF) - { - throw EXCEPTION("Unexpected thread"); - } + ASSERT(threadId == SCE_PERF_ARM_PMON_THREAD_ID_SELF); if (counter >= 6 && counter != SCE_PERF_ARM_PMON_CYCLE_COUNTER) { @@ -112,7 +99,7 @@ s32 scePerfArmPmonGetCounterValue(ARMv7Thread& context, s32 threadId, u32 counte if (counter < 6) { - *pValue = context.counters[counter].value; + *pValue = cpu.counters[counter].value; } else { @@ -122,7 +109,7 @@ s32 scePerfArmPmonGetCounterValue(ARMv7Thread& context, s32 threadId, u32 counte return SCE_OK; } -s32 scePerfArmPmonSoftwareIncrement(ARMv7Thread& context, u32 mask) +arm_error_code scePerfArmPmonSoftwareIncrement(ARMv7Thread& cpu, u32 mask) { scePerf.warning("scePerfArmPmonSoftwareIncrement(mask=0x%x)", mask); @@ -135,7 +122,7 @@ s32 scePerfArmPmonSoftwareIncrement(ARMv7Thread& context, u32 mask) { if (mask & 1) { - context.counters[i].value++; + cpu.counters[i].value++; } } @@ -176,15 +163,10 @@ s32 sceRazorCpuSync() throw EXCEPTION(""); } -#define REG_FUNC(nid, name) reg_psv_func(nid, &scePerf, #name, name) +#define REG_FUNC(nid, name) REG_FNID(ScePerf, nid, name) -psv_log_base scePerf("ScePerf", []() +DECLARE(arm_module_manager::ScePerf)("ScePerf", []() { - scePerf.on_load = nullptr; - scePerf.on_unload = nullptr; - scePerf.on_stop = nullptr; - //scePerf.on_error = nullptr; // keep default error handler - REG_FUNC(0x35151735, scePerfArmPmonReset); REG_FUNC(0x63CBEA8B, scePerfArmPmonSelectEvent); REG_FUNC(0xC9D969D5, scePerfArmPmonStart); diff --git a/rpcs3/Emu/ARMv7/Modules/scePerf.h b/rpcs3/Emu/ARMv7/Modules/scePerf.h index cf8b27c891..81d4833320 100644 --- a/rpcs3/Emu/ARMv7/Modules/scePerf.h +++ b/rpcs3/Emu/ARMv7/Modules/scePerf.h @@ -1,11 +1,24 @@ #pragma once -enum +#include "Emu/ARMv7/ErrorCodes.h" + +enum ScePerfError : s32 { // Error Codes - SCE_PERF_ERROR_INVALID_ARGUMENT = 0x80580000, + SCE_PERF_ERROR_INVALID_ARGUMENT = ERROR_CODE(0x80580000), }; +template<> +inline const char* arm_error_code::print(ScePerfError error) +{ + switch (error) + { + STR_CASE(SCE_PERF_ERROR_INVALID_ARGUMENT); + } + + return nullptr; +} + enum : s32 { // Thread IDs @@ -89,5 +102,3 @@ enum : u8 SCE_PERF_ARM_PMON_PLE_FIFO_OVERFLOW = 0xA4, SCE_PERF_ARM_PMON_PLE_REQ_PROGRAMMED = 0xA5, }; - -extern psv_log_base scePerf; diff --git a/rpcs3/Emu/ARMv7/Modules/scePgf.cpp b/rpcs3/Emu/ARMv7/Modules/scePgf.cpp index ec4fb307bf..550c08def8 100644 --- a/rpcs3/Emu/ARMv7/Modules/scePgf.cpp +++ b/rpcs3/Emu/ARMv7/Modules/scePgf.cpp @@ -1,18 +1,15 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "scePgf.h" -#define REG_FUNC(nid, name) reg_psv_func(nid, &scePgf, #name, name) +LOG_CHANNEL(scePgf); -psv_log_base scePgf("ScePgf", []() +#define REG_FUNC(nid, name) REG_FNID(ScePgf, nid, name) + +DECLARE(arm_module_manager::ScePgf)("ScePgf", []() { - scePgf.on_load = nullptr; - scePgf.on_unload = nullptr; - scePgf.on_stop = nullptr; - scePgf.on_error = nullptr; - //REG_FUNC(0x1055ABA3, sceFontNewLib); //REG_FUNC(0x07EE1733, sceFontDoneLib); //REG_FUNC(0xDE47674C, sceFontSetResolution); diff --git a/rpcs3/Emu/ARMv7/Modules/scePgf.h b/rpcs3/Emu/ARMv7/Modules/scePgf.h index 0b299c6785..6f70f09bee 100644 --- a/rpcs3/Emu/ARMv7/Modules/scePgf.h +++ b/rpcs3/Emu/ARMv7/Modules/scePgf.h @@ -1,3 +1 @@ #pragma once - -extern psv_log_base scePgf; diff --git a/rpcs3/Emu/ARMv7/Modules/scePhotoExport.cpp b/rpcs3/Emu/ARMv7/Modules/scePhotoExport.cpp index a3bb019b95..d2caa21947 100644 --- a/rpcs3/Emu/ARMv7/Modules/scePhotoExport.cpp +++ b/rpcs3/Emu/ARMv7/Modules/scePhotoExport.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "scePhotoExport.h" +LOG_CHANNEL(scePhotoExport); + s32 scePhotoExportFromData( vm::cptr photodata, s32 photodataSize, @@ -29,15 +31,10 @@ s32 scePhotoExportFromFile( throw EXCEPTION(""); } -#define REG_FUNC(nid, name) reg_psv_func(nid, &scePhotoExport, #name, name) +#define REG_FUNC(nid, name) REG_FNID(libScePhotoExport, nid, name) -psv_log_base scePhotoExport("ScePhotoExport", []() +DECLARE(arm_module_manager::ScePhotoExport)("libScePhotoExport", []() { - scePhotoExport.on_load = nullptr; - scePhotoExport.on_unload = nullptr; - scePhotoExport.on_stop = nullptr; - scePhotoExport.on_error = nullptr; - REG_FUNC(0x70512321, scePhotoExportFromData); REG_FUNC(0x84FD9FC5, scePhotoExportFromFile); }); diff --git a/rpcs3/Emu/ARMv7/Modules/scePhotoExport.h b/rpcs3/Emu/ARMv7/Modules/scePhotoExport.h index 23b25755b8..bff84f9810 100644 --- a/rpcs3/Emu/ARMv7/Modules/scePhotoExport.h +++ b/rpcs3/Emu/ARMv7/Modules/scePhotoExport.h @@ -10,5 +10,3 @@ struct ScePhotoExportParam }; using ScePhotoExportCancelFunc = s32(vm::ptr); - -extern psv_log_base scePhotoExport; diff --git a/rpcs3/Emu/ARMv7/Modules/sceRazorCapture.cpp b/rpcs3/Emu/ARMv7/Modules/sceRazorCapture.cpp index 9107db2660..5fa33f4102 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceRazorCapture.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceRazorCapture.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceRazorCapture.h" +LOG_CHANNEL(sceRazorCapture); + void sceRazorCaptureSetTrigger(u32 frameIndex, vm::cptr captureFilename) { throw EXCEPTION(""); @@ -19,15 +21,10 @@ b8 sceRazorCaptureIsInProgress() throw EXCEPTION(""); } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceRazorCapture, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceRazorCapture, nid, name) -psv_log_base sceRazorCapture("SceRazorCapture", []() +DECLARE(arm_module_manager::SceRazorCapture)("SceRazorCapture", []() { - sceRazorCapture.on_load = nullptr; - sceRazorCapture.on_unload = nullptr; - sceRazorCapture.on_stop = nullptr; - sceRazorCapture.on_error = nullptr; - REG_FUNC(0x911E0AA0, sceRazorCaptureIsInProgress); REG_FUNC(0xE916B538, sceRazorCaptureSetTrigger); REG_FUNC(0x3D4B7E68, sceRazorCaptureSetTriggerNextFrame); diff --git a/rpcs3/Emu/ARMv7/Modules/sceRazorCapture.h b/rpcs3/Emu/ARMv7/Modules/sceRazorCapture.h index 25a64f6465..6f70f09bee 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceRazorCapture.h +++ b/rpcs3/Emu/ARMv7/Modules/sceRazorCapture.h @@ -1,3 +1 @@ #pragma once - -extern psv_log_base sceRazorCapture; diff --git a/rpcs3/Emu/ARMv7/Modules/sceRtc.cpp b/rpcs3/Emu/ARMv7/Modules/sceRtc.cpp index 2464327af3..b0c8836dc6 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceRtc.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceRtc.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceRtc.h" +LOG_CHANNEL(sceRtc); + u32 sceRtcGetTickResolution() { throw EXCEPTION(""); @@ -190,15 +192,10 @@ s32 sceRtcParseRFC3339(vm::ptr pUtc, vm::cptr pszDateTime) } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceRtc, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceRtcUser, nid, name) -psv_log_base sceRtc("SceRtc", []() +DECLARE(arm_module_manager::SceRtc)("SceRtcUser", []() { - sceRtc.on_load = nullptr; - sceRtc.on_unload = nullptr; - sceRtc.on_stop = nullptr; - sceRtc.on_error = nullptr; - REG_FUNC(0x23F79274, sceRtcGetCurrentTick); REG_FUNC(0xCDDD25FE, sceRtcGetCurrentNetworkTick); REG_FUNC(0x70FDE8F1, sceRtcGetCurrentClock); diff --git a/rpcs3/Emu/ARMv7/Modules/sceRtc.h b/rpcs3/Emu/ARMv7/Modules/sceRtc.h index 2c60084b05..6f70f09bee 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceRtc.h +++ b/rpcs3/Emu/ARMv7/Modules/sceRtc.h @@ -1,3 +1 @@ #pragma once - -extern psv_log_base sceRtc; diff --git a/rpcs3/Emu/ARMv7/Modules/sceSas.cpp b/rpcs3/Emu/ARMv7/Modules/sceSas.cpp index 40ee51bfaf..52088d1e00 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceSas.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceSas.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceSas.h" +LOG_CHANNEL(sceSas); + s32 sceSasGetNeededMemorySize(vm::cptr config, vm::ptr outSize) { throw EXCEPTION(""); @@ -150,15 +152,10 @@ s32 sceSasSetEffectParam(u32 delayTime, u32 feedback) } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceSas, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceSas, nid, name) -psv_log_base sceSas("SceSas", []() +DECLARE(arm_module_manager::SceSas)("SceSas", []() { - sceSas.on_load = nullptr; - sceSas.on_unload = nullptr; - sceSas.on_stop = nullptr; - sceSas.on_error = nullptr; - //REG_FUNC(0xA2209C58, sceAsSetRegisterReportHandler); //REG_FUNC(0xBB635544, sceAsSetUnregisterReportHandler); //REG_FUNC(0xF578F0EF, sceAsGetSystemNeededMemory); diff --git a/rpcs3/Emu/ARMv7/Modules/sceSas.h b/rpcs3/Emu/ARMv7/Modules/sceSas.h index d60bd26155..6f70f09bee 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceSas.h +++ b/rpcs3/Emu/ARMv7/Modules/sceSas.h @@ -1,3 +1 @@ #pragma once - -extern psv_log_base sceSas; diff --git a/rpcs3/Emu/ARMv7/Modules/sceScreenShot.cpp b/rpcs3/Emu/ARMv7/Modules/sceScreenShot.cpp index 62e4c88e00..a1d4385b02 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceScreenShot.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceScreenShot.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceScreenShot.h" +LOG_CHANNEL(sceScreenShot); + s32 sceScreenShotSetParam(vm::cptr param) { throw EXCEPTION(""); @@ -25,15 +27,10 @@ s32 sceScreenShotEnable() } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceScreenShot, #name, name) +#define REG_FUNC(nid, name) REG_FNID(libSceScreenShot, nid, name) -psv_log_base sceScreenShot("SceScreenShot", []() +DECLARE(arm_module_manager::SceScreenShot)("libSceScreenShot", []() { - sceScreenShot.on_load = nullptr; - sceScreenShot.on_unload = nullptr; - sceScreenShot.on_stop = nullptr; - sceScreenShot.on_error = nullptr; - REG_FUNC(0x05DB59C7, sceScreenShotSetParam); REG_FUNC(0x7061665B, sceScreenShotSetOverlayImage); REG_FUNC(0x50AE9FF9, sceScreenShotDisable); diff --git a/rpcs3/Emu/ARMv7/Modules/sceScreenShot.h b/rpcs3/Emu/ARMv7/Modules/sceScreenShot.h index 9aab6bef39..98d79a5b27 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceScreenShot.h +++ b/rpcs3/Emu/ARMv7/Modules/sceScreenShot.h @@ -7,5 +7,3 @@ struct SceScreenShotParam vm::lcptr gameComment; vm::lptr reserved; }; - -extern psv_log_base sceScreenShot; diff --git a/rpcs3/Emu/ARMv7/Modules/sceSfmt.cpp b/rpcs3/Emu/ARMv7/Modules/sceSfmt.cpp index 57931d32be..601c7d02de 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceSfmt.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceSfmt.cpp @@ -1,18 +1,13 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" -extern psv_log_base sceSfmt; +LOG_CHANNEL(sceSfmt); -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceSfmt, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceSfmt, nid, name) -psv_log_base sceSfmt("SceSfmt", []() +DECLARE(arm_module_manager::SceSfmt)("SceSfmt", []() { - sceSfmt.on_load = nullptr; - sceSfmt.on_unload = nullptr; - sceSfmt.on_stop = nullptr; - sceSfmt.on_error = nullptr; - //REG_FUNC(0x8FF464C9, sceSfmt11213InitGenRand); //REG_FUNC(0xBAF5F058, sceSfmt11213InitByArray); //REG_FUNC(0xFB281CD7, sceSfmt11213GenRand32); diff --git a/rpcs3/Emu/ARMv7/Modules/sceSha.cpp b/rpcs3/Emu/ARMv7/Modules/sceSha.cpp index 2fb134841e..a5322de9f6 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceSha.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceSha.cpp @@ -1,18 +1,13 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" -extern psv_log_base sceSha; +LOG_CHANNEL(sceSha); -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceSha, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceSha, nid, name) -psv_log_base sceSha("SceSha", []() +DECLARE(arm_module_manager::SceSha)("SceSha", []() { - sceSha.on_load = nullptr; - sceSha.on_unload = nullptr; - sceSha.on_stop = nullptr; - sceSha.on_error = nullptr; - //REG_FUNC(0xD19A9AA8, sceSha0Digest); //REG_FUNC(0xBCF6DB3A, sceSha0BlockInit); //REG_FUNC(0x37EF2AFC, sceSha0BlockUpdate); diff --git a/rpcs3/Emu/ARMv7/Modules/sceSqlite.cpp b/rpcs3/Emu/ARMv7/Modules/sceSqlite.cpp index 2acaffae9d..8d50081196 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceSqlite.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceSqlite.cpp @@ -1,18 +1,15 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceSqlite.h" -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceSqlite, #name, name) +LOG_CHANNEL(sceSqlite); -psv_log_base sceSqlite("SceSqlite", []() +#define REG_FUNC(nid, name) REG_FNID(SceSqlite, nid, name) + +DECLARE(arm_module_manager::SceSqlite)("SceSqlite", []() { - sceSqlite.on_load = nullptr; - sceSqlite.on_unload = nullptr; - sceSqlite.on_stop = nullptr; - sceSqlite.on_error = nullptr; - //REG_FUNC(0x26E46324, sqlite3_libversion); //REG_FUNC(0x4CCB58A2, sqlite3_sourceid); //REG_FUNC(0x5982F404, sqlite3_libversion_number); diff --git a/rpcs3/Emu/ARMv7/Modules/sceSqlite.h b/rpcs3/Emu/ARMv7/Modules/sceSqlite.h index be4fc046b7..6f70f09bee 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceSqlite.h +++ b/rpcs3/Emu/ARMv7/Modules/sceSqlite.h @@ -1,3 +1 @@ #pragma once - -extern psv_log_base sceSqlite; diff --git a/rpcs3/Emu/ARMv7/Modules/sceSsl.cpp b/rpcs3/Emu/ARMv7/Modules/sceSsl.cpp index 75e72e4717..1a9979517f 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceSsl.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceSsl.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceSsl.h" +LOG_CHANNEL(sceSsl); + s32 sceSslInit(u32 poolSize) { throw EXCEPTION(""); @@ -60,15 +62,10 @@ s32 sceSslFreeSslCertName(vm::ptr certName) } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceSsl, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceSsl, nid, name) -psv_log_base sceSsl("SceSsl", []() +DECLARE(arm_module_manager::SceSsl)("SceSsl", []() { - sceSsl.on_load = nullptr; - sceSsl.on_unload = nullptr; - sceSsl.on_stop = nullptr; - sceSsl.on_error = nullptr; - REG_FUNC(0x3C733316, sceSslInit); REG_FUNC(0x03CE6E3A, sceSslTerm); REG_FUNC(0xBD203262, sceSslGetMemoryPoolStats); diff --git a/rpcs3/Emu/ARMv7/Modules/sceSsl.h b/rpcs3/Emu/ARMv7/Modules/sceSsl.h index 4d9f7a9bb3..ef70e48946 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceSsl.h +++ b/rpcs3/Emu/ARMv7/Modules/sceSsl.h @@ -10,5 +10,3 @@ struct SceSslMemoryPoolStats le_t currentInuseSize; le_t reserved; }; - -extern psv_log_base sceSsl; diff --git a/rpcs3/Emu/ARMv7/Modules/sceSulpha.cpp b/rpcs3/Emu/ARMv7/Modules/sceSulpha.cpp index eabbe2c065..3210e04906 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceSulpha.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceSulpha.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceSulpha.h" +LOG_CHANNEL(sceSulpha); + s32 sceSulphaNetworkInit() { throw EXCEPTION(""); @@ -70,15 +72,10 @@ s32 sceSulphaAgentsUnregister(vm::cptr handles, u32 agentCount) } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceSulpha, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceSulpha, nid, name) -psv_log_base sceSulpha("SceSulpha", []() +DECLARE(arm_module_manager::SceSulpha)("SceSulpha", []() { - sceSulpha.on_load = nullptr; - sceSulpha.on_unload = nullptr; - sceSulpha.on_stop = nullptr; - sceSulpha.on_error = nullptr; - REG_FUNC(0xB4668AEA, sceSulphaNetworkInit); REG_FUNC(0x0FC71B72, sceSulphaNetworkShutdown); REG_FUNC(0xA6A05C50, sceSulphaGetDefaultConfig); diff --git a/rpcs3/Emu/ARMv7/Modules/sceSulpha.h b/rpcs3/Emu/ARMv7/Modules/sceSulpha.h index e373c37e8e..a513d22bfd 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceSulpha.h +++ b/rpcs3/Emu/ARMv7/Modules/sceSulpha.h @@ -12,5 +12,3 @@ struct SceSulphaConfig struct SceSulphaAgentsRegister; using SceSulphaHandle = void; - -extern psv_log_base sceSulpha; diff --git a/rpcs3/Emu/ARMv7/Modules/sceSysmodule.cpp b/rpcs3/Emu/ARMv7/Modules/sceSysmodule.cpp index 7637ba5aa8..6906f2cf3a 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceSysmodule.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceSysmodule.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceSysmodule.h" +LOG_CHANNEL(sceSysmodule); + s32 sceSysmoduleLoadModule(u16 id) { sceSysmodule.warning("sceSysmoduleLoadModule(id=0x%04x) -> SCE_OK", id); @@ -25,15 +27,10 @@ s32 sceSysmoduleIsLoaded(u16 id) return SCE_OK; // module is loaded } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceSysmodule, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceSysmodule, nid, name) -psv_log_base sceSysmodule("SceSysmodule", []() +DECLARE(arm_module_manager::SceSysmodule)("SceSysmodule", []() { - sceSysmodule.on_load = nullptr; - sceSysmodule.on_unload = nullptr; - sceSysmodule.on_stop = nullptr; - sceSysmodule.on_error = nullptr; - REG_FUNC(0x79A0160A, sceSysmoduleLoadModule); REG_FUNC(0x31D87805, sceSysmoduleUnloadModule); REG_FUNC(0x53099B7A, sceSysmoduleIsLoaded); diff --git a/rpcs3/Emu/ARMv7/Modules/sceSysmodule.h b/rpcs3/Emu/ARMv7/Modules/sceSysmodule.h index 0153c8725d..6f70f09bee 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceSysmodule.h +++ b/rpcs3/Emu/ARMv7/Modules/sceSysmodule.h @@ -1,3 +1 @@ #pragma once - -extern psv_log_base sceSysmodule; diff --git a/rpcs3/Emu/ARMv7/Modules/sceSystemGesture.cpp b/rpcs3/Emu/ARMv7/Modules/sceSystemGesture.cpp index f9e9c0f318..6d6dedf763 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceSystemGesture.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceSystemGesture.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceSystemGesture.h" +LOG_CHANNEL(sceSystemGesture); + s32 sceSystemGestureInitializePrimitiveTouchRecognizer(vm::ptr parameter) { throw EXCEPTION(""); @@ -90,15 +92,10 @@ s32 sceSystemGestureGetTouchEventByEventID(vm::cptr pPanelInfo) { throw EXCEPTION(""); @@ -30,15 +32,10 @@ s32 sceTouchGetSamplingState(u32 port, vm::ptr pState) } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceTouch, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceTouch, nid, name) -psv_log_base sceTouch("SceTouch", []() +DECLARE(arm_module_manager::SceTouch)("SceTouch", []() { - sceTouch.on_load = nullptr; - sceTouch.on_unload = nullptr; - sceTouch.on_stop = nullptr; - sceTouch.on_error = nullptr; - REG_FUNC(0x169A1D58, sceTouchRead); REG_FUNC(0xFF082DF0, sceTouchPeek); REG_FUNC(0x1B9C5D14, sceTouchSetSamplingState); diff --git a/rpcs3/Emu/ARMv7/Modules/sceTouch.h b/rpcs3/Emu/ARMv7/Modules/sceTouch.h index 021f6a86c6..0905fad0b0 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceTouch.h +++ b/rpcs3/Emu/ARMv7/Modules/sceTouch.h @@ -32,5 +32,3 @@ struct SceTouchData le_t reportNum; SceTouchReport report[8]; }; - -extern psv_log_base sceTouch; diff --git a/rpcs3/Emu/ARMv7/Modules/sceUlt.cpp b/rpcs3/Emu/ARMv7/Modules/sceUlt.cpp index 4b47e74181..445cf18212 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceUlt.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceUlt.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceUlt.h" +LOG_CHANNEL(sceUlt); + // Functions s32 _sceUltWaitingQueueResourcePoolOptParamInitialize(vm::ptr optParam, u32 buildVersion) @@ -384,15 +386,10 @@ s32 sceUltUlthreadGetSelf(vm::pptr ulthread) throw EXCEPTION(""); } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceUlt, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceUlt, nid, name) -psv_log_base sceUlt("SceUlt", []() +DECLARE(arm_module_manager::SceUlt)("SceUlt", []() { - sceUlt.on_load = nullptr; - sceUlt.on_unload = nullptr; - sceUlt.on_stop = nullptr; - sceUlt.on_error = nullptr; - REG_FUNC(0xEF094E35, _sceUltWaitingQueueResourcePoolOptParamInitialize); REG_FUNC(0x644DA029, sceUltWaitingQueueResourcePoolGetWorkAreaSize); REG_FUNC(0x62F9493E, _sceUltWaitingQueueResourcePoolCreate); diff --git a/rpcs3/Emu/ARMv7/Modules/sceUlt.h b/rpcs3/Emu/ARMv7/Modules/sceUlt.h index 42e741f2a7..0518badd7d 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceUlt.h +++ b/rpcs3/Emu/ARMv7/Modules/sceUlt.h @@ -154,5 +154,3 @@ struct SceUltUlthread CHECK_SIZE(SceUltUlthread, 256); using SceUltUlthreadEntry = s32(u32 arg); - -extern psv_log_base sceUlt; diff --git a/rpcs3/Emu/ARMv7/Modules/sceVideodec.cpp b/rpcs3/Emu/ARMv7/Modules/sceVideodec.cpp index 190645df00..9c57870236 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceVideodec.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceVideodec.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceVideodec.h" +LOG_CHANNEL(sceVideodec); + s32 sceVideodecInitLibrary(u32 codecType, vm::cptr pInitInfo) { throw EXCEPTION(""); @@ -50,15 +52,10 @@ s32 sceAvcdecDecodeFlush(vm::ptr pCtrl) } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceVideodec, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceVideodecUser, nid, name) -psv_log_base sceVideodec("SceVideodec", []() +DECLARE(arm_module_manager::SceVideodec)("SceVideodecUser", []() { - sceVideodec.on_load = nullptr; - sceVideodec.on_unload = nullptr; - sceVideodec.on_stop = nullptr; - sceVideodec.on_error = nullptr; - REG_FUNC(0xF1AF65A3, sceVideodecInitLibrary); REG_FUNC(0x3A5F4924, sceVideodecTermLibrary); REG_FUNC(0x97E95EDB, sceAvcdecQueryDecoderMemSize); diff --git a/rpcs3/Emu/ARMv7/Modules/sceVideodec.h b/rpcs3/Emu/ARMv7/Modules/sceVideodec.h index 825d4fc1b3..0ea43e1eea 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceVideodec.h +++ b/rpcs3/Emu/ARMv7/Modules/sceVideodec.h @@ -122,5 +122,3 @@ struct SceAvcdecArrayPicture le_t numOfElm; vm::lpptr pPicture; }; - -extern psv_log_base sceVideodec; diff --git a/rpcs3/Emu/ARMv7/Modules/sceVoice.cpp b/rpcs3/Emu/ARMv7/Modules/sceVoice.cpp index a76177503e..b0c1d53bca 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceVoice.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceVoice.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceVoice.h" +LOG_CHANNEL(sceVoice); + s32 sceVoiceInit(vm::ptr pArg, SceVoiceVersion version) { throw EXCEPTION(""); @@ -130,15 +132,10 @@ s32 sceVoiceGetResourceInfo(vm::ptr pInfo) } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceVoice, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceVoice, nid, name) -psv_log_base sceVoice("SceVoice", []() +DECLARE(arm_module_manager::SceVoice)("SceVoice", []() { - sceVoice.on_load = nullptr; - sceVoice.on_unload = nullptr; - sceVoice.on_stop = nullptr; - sceVoice.on_error = nullptr; - REG_FUNC(0xD02C00B4, sceVoiceGetBitRate); REG_FUNC(0xC913F7E9, sceVoiceGetMuteFlag); REG_FUNC(0x875CC80D, sceVoiceGetVolume); diff --git a/rpcs3/Emu/ARMv7/Modules/sceVoice.h b/rpcs3/Emu/ARMv7/Modules/sceVoice.h index a7986df9a6..4006e05f17 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceVoice.h +++ b/rpcs3/Emu/ARMv7/Modules/sceVoice.h @@ -128,5 +128,3 @@ struct SceVoiceStartParam le_t container; u8 reserved[28]; }; - -extern psv_log_base sceVoice; diff --git a/rpcs3/Emu/ARMv7/Modules/sceVoiceQoS.cpp b/rpcs3/Emu/ARMv7/Modules/sceVoiceQoS.cpp index 0adead3bfc..b584945713 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceVoiceQoS.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceVoiceQoS.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/ARMv7/PSVFuncList.h" +#include "Emu/ARMv7/ARMv7Module.h" #include "sceVoiceQoS.h" +LOG_CHANNEL(sceVoiceQoS); + s32 sceVoiceQoSInit() { throw EXCEPTION(""); @@ -90,15 +92,10 @@ s32 sceVoiceQoSReadPacket(s32 connectionId, vm::ptr pData, vm::ptr pS } -#define REG_FUNC(nid, name) reg_psv_func(nid, &sceVoiceQoS, #name, name) +#define REG_FUNC(nid, name) REG_FNID(SceVoiceQoS, nid, name) -psv_log_base sceVoiceQoS("SceVoiceQos", []() +DECLARE(arm_module_manager::SceVoiceQoS)("SceVoiceQoS", []() { - sceVoiceQoS.on_load = nullptr; - sceVoiceQoS.on_unload = nullptr; - sceVoiceQoS.on_stop = nullptr; - sceVoiceQoS.on_error = nullptr; - REG_FUNC(0x4B5FFF1C, sceVoiceQoSInit); REG_FUNC(0xFB0B747B, sceVoiceQoSEnd); REG_FUNC(0xAAB54BE4, sceVoiceQoSCreateLocalEndpoint); diff --git a/rpcs3/Emu/ARMv7/Modules/sceVoiceQoS.h b/rpcs3/Emu/ARMv7/Modules/sceVoiceQoS.h index c66b56b366..4dbb38f0c3 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceVoiceQoS.h +++ b/rpcs3/Emu/ARMv7/Modules/sceVoiceQoS.h @@ -17,5 +17,3 @@ enum SceVoiceQoSStatusId : s32 SCE_VOICE_QOS_IN_FRAME_RECEIVED_RATIO, SCE_VOICE_QOS_HEARTBEAT_FLAG }; - -extern psv_log_base sceVoiceQoS; diff --git a/rpcs3/Emu/ARMv7/Modules/sceXml.h b/rpcs3/Emu/ARMv7/Modules/sceXml.h deleted file mode 100644 index ea5d63ed71..0000000000 --- a/rpcs3/Emu/ARMv7/Modules/sceXml.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -extern psv_log_base sceXml; diff --git a/rpcs3/Emu/ARMv7/PSVFuncList.cpp b/rpcs3/Emu/ARMv7/PSVFuncList.cpp deleted file mode 100644 index d293d066b1..0000000000 --- a/rpcs3/Emu/ARMv7/PSVFuncList.cpp +++ /dev/null @@ -1,256 +0,0 @@ -#include "stdafx.h" -#include "Emu/System.h" -#include "ARMv7Thread.h" -#include "PSVFuncList.h" - -psv_log_base::psv_log_base(const std::string& name, init_func_t init) - : _log::channel(name) - , m_init(init) -{ - on_error = [this](s32 code, psv_func* func) - { - if (code < 0) - { - error("%s() failed: 0x%08X", func->name, code); - Emu.Pause(); - } - }; -} - -std::vector g_psv_func_list; -std::vector g_psv_modules; - -u32 add_psv_func(psv_func data) -{ - for (auto& f : g_psv_func_list) - { - assert(f.nid != data.nid || (&f - g_psv_func_list.data()) < SFI_MAX); - } - - g_psv_func_list.push_back(data); - return (u32)(g_psv_func_list.size() - 1); -} - -psv_func* get_psv_func_by_nid(u32 nid, u32* out_index) -{ - for (auto& f : g_psv_func_list) - { - if (f.nid == nid && &f - g_psv_func_list.data()) - { - const u32 index = (u32)(&f - g_psv_func_list.data()); - - if (index < SFI_MAX) - { - continue; - } - - if (out_index) - { - *out_index = index; - } - - return &f; - } - } - - return nullptr; -} - -psv_func* get_psv_func_by_index(u32 index) -{ - if (index >= g_psv_func_list.size()) - { - return nullptr; - } - - return &g_psv_func_list[index]; -} - -void execute_psv_func_by_index(ARMv7Thread& context, u32 index) -{ - if (auto func = get_psv_func_by_index(index)) - { - const u32 old_func = context.hle_func; - context.hle_func = func->nid; - - if (func->func) - { - func->func(context); - } - else - { - throw EXCEPTION("Unimplemented function"); - } - - // rough error code processing - if (context.GPR[0] && func->module && func->module->on_error) - { - func->module->on_error(context.GPR[0], func); - } - - context.hle_func = old_func; - } - else - { - throw EXCEPTION("Invalid function index"); - } -} - -extern psv_log_base sceAppMgr; -extern psv_log_base sceAppUtil; -extern psv_log_base sceAudio; -extern psv_log_base sceAudiodec; -extern psv_log_base sceAudioenc; -extern psv_log_base sceAudioIn; -extern psv_log_base sceCamera; -extern psv_log_base sceCodecEngine; -extern psv_log_base sceCommonDialog; -extern psv_log_base sceCtrl; -extern psv_log_base sceDbg; -extern psv_log_base sceDeci4p; -extern psv_log_base sceDeflt; -extern psv_log_base sceDisplay; -extern psv_log_base sceFiber; -extern psv_log_base sceFios; -extern psv_log_base sceFpu; -extern psv_log_base sceGxm; -extern psv_log_base sceHttp; -extern psv_log_base sceIme; -extern psv_log_base sceJpeg; -extern psv_log_base sceJpegEnc; -extern psv_log_base sceLibc; -extern psv_log_base sceLibKernel; -extern psv_log_base sceLibm; -extern psv_log_base sceLibstdcxx; -extern psv_log_base sceLiveArea; -extern psv_log_base sceLocation; -extern psv_log_base sceMd5; -extern psv_log_base sceMotion; -extern psv_log_base sceMt19937; -extern psv_log_base sceNet; -extern psv_log_base sceNetCtl; -extern psv_log_base sceNgs; -extern psv_log_base sceNpBasic; -extern psv_log_base sceNpCommon; -extern psv_log_base sceNpManager; -extern psv_log_base sceNpMatching; -extern psv_log_base sceNpScore; -extern psv_log_base sceNpUtility; -extern psv_log_base scePerf; -extern psv_log_base scePgf; -extern psv_log_base scePhotoExport; -extern psv_log_base sceRazorCapture; -extern psv_log_base sceRtc; -extern psv_log_base sceSas; -extern psv_log_base sceScreenShot; -extern psv_log_base sceSfmt; -extern psv_log_base sceSha; -extern psv_log_base sceSqlite; -extern psv_log_base sceSsl; -extern psv_log_base sceSulpha; -extern psv_log_base sceSysmodule; -extern psv_log_base sceSystemGesture; -extern psv_log_base sceTouch; -extern psv_log_base sceUlt; -extern psv_log_base sceVideodec; -extern psv_log_base sceVoice; -extern psv_log_base sceVoiceQoS; -extern psv_log_base sceXml; - -void initialize_psv_modules() -{ - assert(!g_psv_func_list.size() && !g_psv_modules.size()); - - // fill module list - g_psv_modules.push_back(&sceAppMgr); - g_psv_modules.push_back(&sceAppUtil); - g_psv_modules.push_back(&sceAudio); - g_psv_modules.push_back(&sceAudiodec); - g_psv_modules.push_back(&sceAudioenc); - g_psv_modules.push_back(&sceAudioIn); - g_psv_modules.push_back(&sceCamera); - g_psv_modules.push_back(&sceCodecEngine); - g_psv_modules.push_back(&sceCommonDialog); - g_psv_modules.push_back(&sceCtrl); - g_psv_modules.push_back(&sceDbg); - g_psv_modules.push_back(&sceDeci4p); - g_psv_modules.push_back(&sceDeflt); - g_psv_modules.push_back(&sceDisplay); - g_psv_modules.push_back(&sceFiber); - g_psv_modules.push_back(&sceFios); - g_psv_modules.push_back(&sceFpu); - g_psv_modules.push_back(&sceGxm); - g_psv_modules.push_back(&sceHttp); - g_psv_modules.push_back(&sceIme); - g_psv_modules.push_back(&sceJpeg); - g_psv_modules.push_back(&sceJpegEnc); - g_psv_modules.push_back(&sceLibc); - g_psv_modules.push_back(&sceLibKernel); - g_psv_modules.push_back(&sceLibm); - g_psv_modules.push_back(&sceLibstdcxx); - g_psv_modules.push_back(&sceLiveArea); - g_psv_modules.push_back(&sceLocation); - g_psv_modules.push_back(&sceMd5); - g_psv_modules.push_back(&sceMotion); - g_psv_modules.push_back(&sceMt19937); - g_psv_modules.push_back(&sceNet); - g_psv_modules.push_back(&sceNetCtl); - g_psv_modules.push_back(&sceNgs); - g_psv_modules.push_back(&sceNpBasic); - g_psv_modules.push_back(&sceNpCommon); - g_psv_modules.push_back(&sceNpManager); - g_psv_modules.push_back(&sceNpMatching); - g_psv_modules.push_back(&sceNpScore); - g_psv_modules.push_back(&sceNpUtility); - g_psv_modules.push_back(&scePerf); - g_psv_modules.push_back(&scePgf); - g_psv_modules.push_back(&scePhotoExport); - g_psv_modules.push_back(&sceRazorCapture); - g_psv_modules.push_back(&sceRtc); - g_psv_modules.push_back(&sceSas); - g_psv_modules.push_back(&sceScreenShot); - g_psv_modules.push_back(&sceSfmt); - g_psv_modules.push_back(&sceSha); - g_psv_modules.push_back(&sceSqlite); - g_psv_modules.push_back(&sceSsl); - g_psv_modules.push_back(&sceSulpha); - g_psv_modules.push_back(&sceSysmodule); - g_psv_modules.push_back(&sceSystemGesture); - g_psv_modules.push_back(&sceTouch); - g_psv_modules.push_back(&sceUlt); - g_psv_modules.push_back(&sceVideodec); - g_psv_modules.push_back(&sceVoice); - g_psv_modules.push_back(&sceVoiceQoS); - g_psv_modules.push_back(&sceXml); - - // setup special functions (without NIDs) - g_psv_func_list.resize(SFI_MAX); - - psv_func& hle_return = g_psv_func_list[SFI_HLE_RETURN]; - hle_return.nid = 0; - hle_return.name = "HLE_RETURN"; - hle_return.func = [](ARMv7Thread& context) - { - context.fast_stop(); - }; - - // load functions - for (auto module : g_psv_modules) - { - module->Init(); - } -} - -void finalize_psv_modules() -{ - for (auto module : g_psv_modules) - { - if (module->on_stop) - { - module->on_stop(); - } - } - - g_psv_func_list.clear(); - g_psv_modules.clear(); -} diff --git a/rpcs3/Emu/ARMv7/PSVFuncList.h b/rpcs3/Emu/ARMv7/PSVFuncList.h deleted file mode 100644 index f9a4977953..0000000000 --- a/rpcs3/Emu/ARMv7/PSVFuncList.h +++ /dev/null @@ -1,676 +0,0 @@ -#pragma once - -#include "Emu/Memory/Memory.h" -#include "ARMv7Thread.h" - -namespace vm { using namespace psv; } - -// PSV module class -class psv_log_base : public _log::channel -{ - using init_func_t = void(*)(); - - init_func_t m_init; - -public: - std::function on_load; - std::function on_unload; - std::function on_stop; - std::function on_error; - -public: - psv_log_base(const std::string& name, init_func_t init); - - void Init() - { - on_load = nullptr; - on_unload = nullptr; - on_stop = nullptr; - on_error = nullptr; - - m_init(); - } -}; - -using armv7_func_caller = void(*)(ARMv7Thread&); - -struct armv7_va_args_t -{ - u32 g_count; - u32 f_count; - u32 v_count; -}; - -// Utilities for binding ARMv7Context to C++ function arguments received by HLE functions or sent to callbacks -namespace psv_func_detail -{ - enum arg_class : u32 - { - ARG_GENERAL, - ARG_FLOAT, - ARG_VECTOR, - ARG_STACK, - ARG_CONTEXT, - ARG_VARIADIC, - ARG_UNKNOWN, - }; - - static const auto FIXED_STACK_FRAME_SIZE = 0x80; // described in CB_FUNC.h - - template - struct bind_arg - { - static_assert(type == ARG_GENERAL, "Unknown function argument type"); - static_assert(!std::is_pointer::value, "Invalid function argument type (pointer)"); - static_assert(!std::is_reference::value, "Invalid function argument type (reference)"); - static_assert(sizeof(T) <= 4, "Invalid function argument type for ARG_GENERAL"); - - force_inline static T get_arg(ARMv7Thread& context) - { - return cast_from_armv7_gpr(context.GPR[g_count - 1]); - } - - force_inline static void put_arg(ARMv7Thread& context, const T& arg) - { - context.GPR[g_count - 1] = cast_to_armv7_gpr(arg); - } - }; - - template - struct bind_arg - { - // first u64 argument is passed in r0-r1, second one is passed in r2-r3 (if g_count = 3) - static_assert(g_count == 2 || g_count == 4, "Wrong u64 argument position"); - - force_inline static u64 get_arg(ARMv7Thread& context) - { - return context.GPR_D[(g_count - 1) >> 1]; - } - - force_inline static void put_arg(ARMv7Thread& context, u64 arg) - { - context.GPR_D[(g_count - 1) >> 1] = arg; - } - }; - - template - struct bind_arg - { - static_assert(g_count == 2 || g_count == 4, "Wrong s64 argument position"); - - force_inline static s64 get_arg(ARMv7Thread& context) - { - return context.GPR_D[(g_count - 1) >> 1]; - } - - force_inline static void put_arg(ARMv7Thread& context, s64 arg) - { - context.GPR_D[(g_count - 1) >> 1] = arg; - } - }; - - template - struct bind_arg - { - static_assert(f_count <= 0, "TODO: Unsupported argument type (float)"); - static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_FLOAT"); - - force_inline static T get_arg(ARMv7Thread& context) - { - } - - force_inline static void put_arg(ARMv7Thread& context, const T& arg) - { - } - }; - - template - struct bind_arg - { - static_assert(v_count <= 0, "TODO: Unsupported argument type (vector)"); - static_assert(std::is_same, v128>::value, "Invalid function argument type for ARG_VECTOR"); - - force_inline static T get_arg(ARMv7Thread& context) - { - } - - force_inline static void put_arg(ARMv7Thread& context, const T& arg) - { - } - }; - - template - struct bind_arg - { - static_assert(f_count <= 0, "TODO: Unsupported stack argument type (float)"); - static_assert(v_count <= 0, "TODO: Unsupported stack argument type (vector)"); - static_assert(sizeof(T) <= 4, "Invalid function argument type for ARG_STACK"); - - force_inline static T get_arg(ARMv7Thread& context) - { - // TODO: check - return cast_from_armv7_gpr(vm::read32(context.SP + sizeof(u32) * (g_count - 5))); - } - - force_inline static void put_arg(ARMv7Thread& context, const T& arg) - { - // TODO: check - const int stack_pos = (g_count - 5) * 4 - FIXED_STACK_FRAME_SIZE; - static_assert(stack_pos < 0, "TODO: Increase fixed stack frame size (arg count limit broken)"); - - vm::write32(context.SP + stack_pos, cast_to_armv7_gpr(arg)); - } - }; - - template - struct bind_arg - { - force_inline static u64 get_arg(ARMv7Thread& context) - { - // TODO: check - return vm::read64(context.SP + sizeof(u32) * (g_count - 6)); - } - - force_inline static void put_arg(ARMv7Thread& context, u64 arg) - { - // TODO: check - const int stack_pos = (g_count - 6) * 4 - FIXED_STACK_FRAME_SIZE; - static_assert(stack_pos < -4, "TODO: Increase fixed stack frame size (arg count limit broken)"); - - vm::write64(context.SP + stack_pos, arg); - } - }; - - template - struct bind_arg - { - force_inline static s64 get_arg(ARMv7Thread& context) - { - // TODO: check - return vm::read64(context.SP + sizeof(u32) * (g_count - 6)); - } - - force_inline static void put_arg(ARMv7Thread& context, s64 arg) - { - // TODO: check - const int stack_pos = (g_count - 6) * 4 - FIXED_STACK_FRAME_SIZE; - static_assert(stack_pos < -4, "TODO: Increase fixed stack frame size (arg count limit broken)"); - - vm::write64(context.SP + stack_pos, arg); - } - }; - - template - struct bind_arg - { - static_assert(std::is_same::value, "Invalid function argument type for ARG_CONTEXT"); - - force_inline static ARMv7Thread& get_arg(ARMv7Thread& context) - { - return context; - } - - force_inline static void put_arg(ARMv7Thread& context, ARMv7Thread& arg) - { - } - }; - - template - struct bind_arg - { - static_assert(std::is_same, armv7_va_args_t>::value, "Invalid function argument type for ARG_VARIADIC"); - - force_inline static armv7_va_args_t get_arg(ARMv7Thread& context) - { - return{ g_count, f_count, v_count }; - } - }; - - template - struct bind_result - { - static_assert(type != ARG_FLOAT, "TODO: Unsupported funcion result type (float)"); - static_assert(type != ARG_VECTOR, "TODO: Unsupported funcion result type (vector)"); - static_assert(type == ARG_GENERAL, "Wrong use of bind_result template"); - static_assert(sizeof(T) <= 4, "Invalid function result type for ARG_GENERAL"); - - force_inline static T get_result(ARMv7Thread& context) - { - return cast_from_armv7_gpr(context.GPR[0]); - } - - force_inline static void put_result(ARMv7Thread& context, const T& result) - { - context.GPR[0] = cast_to_armv7_gpr(result); - } - }; - - template<> - struct bind_result - { - force_inline static u64 get_result(ARMv7Thread& context) - { - return context.GPR_D[0]; - } - - force_inline static void put_result(ARMv7Thread& context, u64 result) - { - context.GPR_D[0] = result; - } - }; - - template<> - struct bind_result - { - force_inline static s64 get_result(ARMv7Thread& context) - { - return context.GPR_D[0]; - } - - force_inline static void put_result(ARMv7Thread& context, s64 result) - { - context.GPR_D[0] = result; - } - }; - - //template - //struct bind_result - //{ - // static_assert(sizeof(T) <= 8, "Invalid function result type for ARG_FLOAT"); - - // static force_inline void put_result(ARMv7Thread& context, const T& result) - // { - // } - //}; - - //template - //struct bind_result - //{ - // static_assert(std::is_same, v128>::value, "Invalid function result type for ARG_VECTOR"); - - // static force_inline void put_result(ARMv7Thread& context, const T& result) - // { - // } - //}; - - template - struct result_type - { - static_assert(!std::is_pointer::value, "Invalid function result type (pointer)"); - static_assert(!std::is_reference::value, "Invalid function result type (reference)"); - static const bool is_float = std::is_floating_point::value; - static const bool is_vector = std::is_same, v128>::value; - static const arg_class value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); - }; - - template - struct arg_type - { - // TODO: check calculations - static const bool is_float = std::is_floating_point::value; - static const bool is_vector = std::is_same, v128>::value; - static const bool is_context = std::is_same::value; - static const bool is_variadic = std::is_same, armv7_va_args_t>::value; - static const bool is_general = !is_float && !is_vector && !is_context && !is_variadic; - - static const u32 g_align = ALIGN_32(T) > 4 ? ALIGN_32(T) >> 2 : 1; - static const u32 g_value = is_general ? ((g_count + (g_align - 1)) & ~(g_align - 1)) + (g_align) : g_count; - static const u32 f_value = f_count + is_float; - static const u32 v_value = v_count + is_vector; - - static const arg_class value = - is_general ? (g_value > 4 ? ARG_STACK : ARG_GENERAL) : - is_float ? (f_value > 9000 ? ARG_STACK : ARG_FLOAT) : - is_vector ? (v_value > 9000 ? ARG_STACK : ARG_VECTOR) : - is_context ? ARG_CONTEXT : - is_variadic ? ARG_VARIADIC : - ARG_UNKNOWN; - }; - - // wrapper for variadic argument info list, each value contains packed argument type and counts of GENERAL, FLOAT and VECTOR arguments - template struct arg_info_pack_t; - - template struct arg_info_pack_t - { - static const u32 last_value = arg_info_pack_t::last_value; - }; - - template struct arg_info_pack_t - { - static const u32 last_value = First; - }; - - template<> struct arg_info_pack_t<> - { - static const u32 last_value = 0; - }; - - // argument type + g/f/v_count unpacker - template struct bind_arg_packed - { - force_inline static T get_arg(ARMv7Thread& context) - { - return bind_arg(type_pack & 0xff), (type_pack >> 8) & 0xff, (type_pack >> 16) & 0xff, (type_pack >> 24)>::get_arg(context); - } - }; - - template - force_inline RT call(ARMv7Thread& context, RT(*func)(Args...), arg_info_pack_t info) - { - // do the actual function call when all arguments are prepared (simultaneous unpacking of Args... and Info...) - return func(bind_arg_packed::get_arg(context)...); - } - - template - force_inline RT call(ARMv7Thread& context, RT(*func)(Args...), arg_info_pack_t info) - { - // unpack previous type counts (0/0/0 for the first time) - const u32 g_count = (info.last_value >> 8) & 0xff; - const u32 f_count = (info.last_value >> 16) & 0xff; - const u32 v_count = (info.last_value >> 24); - - using type = arg_type; - const arg_class t = type::value; - const u32 g = type::g_value; - const u32 f = type::f_value; - const u32 v = type::v_value; - - return call(context, func, arg_info_pack_t{}); - } - - template - force_inline static bool put_func_args(ARMv7Thread& context) - { - // terminator - return false; - } - - template - force_inline static bool put_func_args(ARMv7Thread& context, T1 arg, T... args) - { - using type = arg_type; - const arg_class t = type::value; - const u32 g = type::g_value; - const u32 f = type::f_value; - const u32 v = type::v_value; - - bind_arg::put_arg(context, arg); - - // return true if stack was used - return put_func_args(context, args...) || (t == ARG_STACK); - } - - template - struct func_binder; - - template - struct func_binder - { - using func_t = void(*)(T...); - - static void do_call(ARMv7Thread& context, func_t func) - { - call(context, func, arg_info_pack_t<>{}); - } - }; - - template - struct func_binder - { - using func_t = RT(*)(T...); - - static void do_call(ARMv7Thread& context, func_t func) - { - bind_result::value>::put_result(context, call(context, func, arg_info_pack_t<>{})); - } - }; - - template - struct func_caller - { - force_inline static RT call(ARMv7Thread& context, u32 addr, T... args) - { - func_caller::call(context, addr, args...); - - return bind_result::value>::get_result(context); - } - }; - - template - struct func_caller - { - force_inline static void call(ARMv7Thread& context, u32 addr, T... args) - { - if (put_func_args<0, 0, 0, T...>(context, args...)) - { - context.SP -= FIXED_STACK_FRAME_SIZE; - context.fast_call(addr); - context.SP += FIXED_STACK_FRAME_SIZE; - } - else - { - context.fast_call(addr); - } - } - }; -} - -// Basic information about the HLE function -struct psv_func -{ - u32 nid; // Unique function ID (should be generated individually for each elf loaded) - u32 flags; - const char* name; // Function name for information - armv7_func_caller func; // Function caller - psv_log_base* module; // Module for information - - psv_func() - { - } - - psv_func(u32 nid, u32 flags, psv_log_base* module, const char* name, armv7_func_caller func) - : nid(nid) - , flags(flags) - , name(name) - , func(func) - , module(module) - { - } -}; - -enum psv_special_function_index : u16 -{ - SFI_HLE_RETURN, - - SFI_MAX -}; - -// Do not call directly -u32 add_psv_func(psv_func data); -// Do not call directly -template force_inline void call_psv_func(ARMv7Thread& context, RT(*func)(T...)) -{ - psv_func_detail::func_binder::do_call(context, func); -} - -#define reg_psv_func(nid, module, name, func) add_psv_func(psv_func(nid, 0, module, name, [](ARMv7Thread& context){ call_psv_func(context, func); })) - -// Find registered HLE function by NID -psv_func* get_psv_func_by_nid(u32 nid, u32* out_index = nullptr); -// Find registered HLE function by its index -psv_func* get_psv_func_by_index(u32 index); -// Execute registered HLE function by its index -void execute_psv_func_by_index(ARMv7Thread& context, u32 index); -// Register all HLE functions -void initialize_psv_modules(); -// Unregister all HLE functions -void finalize_psv_modules(); - -// General definitions - -enum psv_error_codes -{ - SCE_OK = 0, - - SCE_ERROR_ERRNO_EPERM = 0x80010001, - SCE_ERROR_ERRNO_ENOENT = 0x80010002, - SCE_ERROR_ERRNO_ESRCH = 0x80010003, - SCE_ERROR_ERRNO_EINTR = 0x80010004, - SCE_ERROR_ERRNO_EIO = 0x80010005, - SCE_ERROR_ERRNO_ENXIO = 0x80010006, - SCE_ERROR_ERRNO_E2BIG = 0x80010007, - SCE_ERROR_ERRNO_ENOEXEC = 0x80010008, - SCE_ERROR_ERRNO_EBADF = 0x80010009, - SCE_ERROR_ERRNO_ECHILD = 0x8001000A, - SCE_ERROR_ERRNO_EAGAIN = 0x8001000B, - SCE_ERROR_ERRNO_ENOMEM = 0x8001000C, - SCE_ERROR_ERRNO_EACCES = 0x8001000D, - SCE_ERROR_ERRNO_EFAULT = 0x8001000E, - SCE_ERROR_ERRNO_ENOTBLK = 0x8001000F, - SCE_ERROR_ERRNO_EBUSY = 0x80010010, - SCE_ERROR_ERRNO_EEXIST = 0x80010011, - SCE_ERROR_ERRNO_EXDEV = 0x80010012, - SCE_ERROR_ERRNO_ENODEV = 0x80010013, - SCE_ERROR_ERRNO_ENOTDIR = 0x80010014, - SCE_ERROR_ERRNO_EISDIR = 0x80010015, - SCE_ERROR_ERRNO_EINVAL = 0x80010016, - SCE_ERROR_ERRNO_ENFILE = 0x80010017, - SCE_ERROR_ERRNO_EMFILE = 0x80010018, - SCE_ERROR_ERRNO_ENOTTY = 0x80010019, - SCE_ERROR_ERRNO_ETXTBSY = 0x8001001A, - SCE_ERROR_ERRNO_EFBIG = 0x8001001B, - SCE_ERROR_ERRNO_ENOSPC = 0x8001001C, - SCE_ERROR_ERRNO_ESPIPE = 0x8001001D, - SCE_ERROR_ERRNO_EROFS = 0x8001001E, - SCE_ERROR_ERRNO_EMLINK = 0x8001001F, - SCE_ERROR_ERRNO_EPIPE = 0x80010020, - SCE_ERROR_ERRNO_EDOM = 0x80010021, - SCE_ERROR_ERRNO_ERANGE = 0x80010022, - SCE_ERROR_ERRNO_ENOMSG = 0x80010023, - SCE_ERROR_ERRNO_EIDRM = 0x80010024, - SCE_ERROR_ERRNO_ECHRNG = 0x80010025, - SCE_ERROR_ERRNO_EL2NSYNC = 0x80010026, - SCE_ERROR_ERRNO_EL3HLT = 0x80010027, - SCE_ERROR_ERRNO_EL3RST = 0x80010028, - SCE_ERROR_ERRNO_ELNRNG = 0x80010029, - SCE_ERROR_ERRNO_EUNATCH = 0x8001002A, - SCE_ERROR_ERRNO_ENOCSI = 0x8001002B, - SCE_ERROR_ERRNO_EL2HLT = 0x8001002C, - SCE_ERROR_ERRNO_EDEADLK = 0x8001002D, - SCE_ERROR_ERRNO_ENOLCK = 0x8001002E, - SCE_ERROR_ERRNO_EFORMAT = 0x8001002F, - SCE_ERROR_ERRNO_EUNSUP = 0x80010030, - SCE_ERROR_ERRNO_EBADE = 0x80010032, - SCE_ERROR_ERRNO_EBADR = 0x80010033, - SCE_ERROR_ERRNO_EXFULL = 0x80010034, - SCE_ERROR_ERRNO_ENOANO = 0x80010035, - SCE_ERROR_ERRNO_EBADRQC = 0x80010036, - SCE_ERROR_ERRNO_EBADSLT = 0x80010037, - SCE_ERROR_ERRNO_EDEADLOCK = 0x80010038, - SCE_ERROR_ERRNO_EBFONT = 0x80010039, - SCE_ERROR_ERRNO_ENOSTR = 0x8001003C, - SCE_ERROR_ERRNO_ENODATA = 0x8001003D, - SCE_ERROR_ERRNO_ETIME = 0x8001003E, - SCE_ERROR_ERRNO_ENOSR = 0x8001003F, - SCE_ERROR_ERRNO_ENONET = 0x80010040, - SCE_ERROR_ERRNO_ENOPKG = 0x80010041, - SCE_ERROR_ERRNO_EREMOTE = 0x80010042, - SCE_ERROR_ERRNO_ENOLINK = 0x80010043, - SCE_ERROR_ERRNO_EADV = 0x80010044, - SCE_ERROR_ERRNO_ESRMNT = 0x80010045, - SCE_ERROR_ERRNO_ECOMM = 0x80010046, - SCE_ERROR_ERRNO_EPROTO = 0x80010047, - SCE_ERROR_ERRNO_EMULTIHOP = 0x8001004A, - SCE_ERROR_ERRNO_ELBIN = 0x8001004B, - SCE_ERROR_ERRNO_EDOTDOT = 0x8001004C, - SCE_ERROR_ERRNO_EBADMSG = 0x8001004D, - SCE_ERROR_ERRNO_EFTYPE = 0x8001004F, - SCE_ERROR_ERRNO_ENOTUNIQ = 0x80010050, - SCE_ERROR_ERRNO_EBADFD = 0x80010051, - SCE_ERROR_ERRNO_EREMCHG = 0x80010052, - SCE_ERROR_ERRNO_ELIBACC = 0x80010053, - SCE_ERROR_ERRNO_ELIBBAD = 0x80010054, - SCE_ERROR_ERRNO_ELIBSCN = 0x80010055, - SCE_ERROR_ERRNO_ELIBMAX = 0x80010056, - SCE_ERROR_ERRNO_ELIBEXEC = 0x80010057, - SCE_ERROR_ERRNO_ENOSYS = 0x80010058, - SCE_ERROR_ERRNO_ENMFILE = 0x80010059, - SCE_ERROR_ERRNO_ENOTEMPTY = 0x8001005A, - SCE_ERROR_ERRNO_ENAMETOOLONG = 0x8001005B, - SCE_ERROR_ERRNO_ELOOP = 0x8001005C, - SCE_ERROR_ERRNO_EOPNOTSUPP = 0x8001005F, - SCE_ERROR_ERRNO_EPFNOSUPPORT = 0x80010060, - SCE_ERROR_ERRNO_ECONNRESET = 0x80010068, - SCE_ERROR_ERRNO_ENOBUFS = 0x80010069, - SCE_ERROR_ERRNO_EAFNOSUPPORT = 0x8001006A, - SCE_ERROR_ERRNO_EPROTOTYPE = 0x8001006B, - SCE_ERROR_ERRNO_ENOTSOCK = 0x8001006C, - SCE_ERROR_ERRNO_ENOPROTOOPT = 0x8001006D, - SCE_ERROR_ERRNO_ESHUTDOWN = 0x8001006E, - SCE_ERROR_ERRNO_ECONNREFUSED = 0x8001006F, - SCE_ERROR_ERRNO_EADDRINUSE = 0x80010070, - SCE_ERROR_ERRNO_ECONNABORTED = 0x80010071, - SCE_ERROR_ERRNO_ENETUNREACH = 0x80010072, - SCE_ERROR_ERRNO_ENETDOWN = 0x80010073, - SCE_ERROR_ERRNO_ETIMEDOUT = 0x80010074, - SCE_ERROR_ERRNO_EHOSTDOWN = 0x80010075, - SCE_ERROR_ERRNO_EHOSTUNREACH = 0x80010076, - SCE_ERROR_ERRNO_EINPROGRESS = 0x80010077, - SCE_ERROR_ERRNO_EALREADY = 0x80010078, - SCE_ERROR_ERRNO_EDESTADDRREQ = 0x80010079, - SCE_ERROR_ERRNO_EMSGSIZE = 0x8001007A, - SCE_ERROR_ERRNO_EPROTONOSUPPORT = 0x8001007B, - SCE_ERROR_ERRNO_ESOCKTNOSUPPORT = 0x8001007C, - SCE_ERROR_ERRNO_EADDRNOTAVAIL = 0x8001007D, - SCE_ERROR_ERRNO_ENETRESET = 0x8001007E, - SCE_ERROR_ERRNO_EISCONN = 0x8001007F, - SCE_ERROR_ERRNO_ENOTCONN = 0x80010080, - SCE_ERROR_ERRNO_ETOOMANYREFS = 0x80010081, - SCE_ERROR_ERRNO_EPROCLIM = 0x80010082, - SCE_ERROR_ERRNO_EUSERS = 0x80010083, - SCE_ERROR_ERRNO_EDQUOT = 0x80010084, - SCE_ERROR_ERRNO_ESTALE = 0x80010085, - SCE_ERROR_ERRNO_ENOTSUP = 0x80010086, - SCE_ERROR_ERRNO_ENOMEDIUM = 0x80010087, - SCE_ERROR_ERRNO_ENOSHARE = 0x80010088, - SCE_ERROR_ERRNO_ECASECLASH = 0x80010089, - SCE_ERROR_ERRNO_EILSEQ = 0x8001008A, - SCE_ERROR_ERRNO_EOVERFLOW = 0x8001008B, - SCE_ERROR_ERRNO_ECANCELED = 0x8001008C, - SCE_ERROR_ERRNO_ENOTRECOVERABLE = 0x8001008D, - SCE_ERROR_ERRNO_EOWNERDEAD = 0x8001008E, -}; - -struct SceDateTime -{ - le_t year; - le_t month; - le_t day; - le_t hour; - le_t minute; - le_t second; - le_t microsecond; -}; - -struct SceFVector3 -{ - le_t x, y, z; -}; - -struct SceFQuaternion -{ - le_t x, y, z, w; -}; - -union SceUMatrix4 -{ - struct - { - le_t f[4][4]; - }; - - struct - { - le_t i[4][4]; - }; -}; diff --git a/rpcs3/Emu/ARMv7/PSVObjectList.h b/rpcs3/Emu/ARMv7/PSVObjectList.h deleted file mode 100644 index 97e98ffd75..0000000000 --- a/rpcs3/Emu/ARMv7/PSVObjectList.h +++ /dev/null @@ -1,124 +0,0 @@ -#pragma once - -union psv_uid_t -{ - // true UID format is partially unknown - s32 uid; - - struct - { - u32 oddness : 1; // always 1 for UIDs (to not mess it up with addresses) - u32 number : 15; // ID from 0 to 2^15-1 - u32 type : 15; // UID class (psv_object_class_t) - u32 sign : 1; // UIDs are positive, error codes are negative - }; - - static psv_uid_t make(s32 uid) - { - psv_uid_t result; - result.uid = uid; - return result; - } -}; - -template -class psv_object_list_t // Class for managing object data -{ - std::array, 0x8000> m_data; - std::atomic m_hint; // guessing next free position - std::mutex m_mutex; - -public: - psv_object_list_t() - : m_hint(0) - { - } - - // check if UID is potentially valid (will return true even if the object doesn't exist) - static inline bool check(s32 uid) - { - const psv_uid_t id = psv_uid_t::make(uid); - - // check sign bit, uid class and ensure that value is odd - return !id.sign && id.type == uid_class && id.oddness == 1; - } - - // share object with UID specified - std::shared_ptr get(s32 uid) - { - if (!check(uid)) - { - return nullptr; - } - - std::lock_guard lock(m_mutex); - - return m_data[psv_uid_t::make(uid).number]; - } - - std::shared_ptr operator [](s32 uid) - { - return this->get(uid); - } - - // create new object and generate UID for it, or do nothing and return zero (if limit reached) - template s32 create(Args&&... args) - { - std::lock_guard lock(m_mutex); - - for (u32 i = 0, j = m_hint; i < m_data.size(); i++, j = (j + 1) % m_data.size()) - { - // find an empty position and copy the pointer - if (!m_data[j]) - { - m_data[j] = std::make_shared(args...); // construct object with specified arguments - - m_hint = (j + 1) % m_data.size(); // guess next position - - psv_uid_t id = psv_uid_t::make(1); // make UID - id.type = uid_class; - id.number = j; - - return id.uid; // return UID - } - } - - return 0; - } - - // remove object with specified UID - bool remove(s32 uid) - { - if (!check(uid)) - { - return false; - } - - std::lock_guard lock(m_mutex); - - const u32 pos = psv_uid_t::make(uid).number; - - m_hint = std::min(pos, m_hint); - - if (!m_data[pos]) - { - return false; - } - - m_data[pos].reset(); - return true; - } - - // remove all objects - void clear() - { - std::lock_guard lock(m_mutex); - - for (auto& v : m_data) - { - v.reset(); - } - - m_hint = 0; - } -}; diff --git a/rpcs3/Emu/Audio/AL/OpenALThread.cpp b/rpcs3/Emu/Audio/AL/OpenALThread.cpp index 5569b6df05..a81f612911 100644 --- a/rpcs3/Emu/Audio/AL/OpenALThread.cpp +++ b/rpcs3/Emu/Audio/AL/OpenALThread.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/System.h" -#include "Emu/state.h" #include "OpenALThread.h" +extern cfg::bool_entry g_cfg_audio_convert_to_u16; + #ifdef _MSC_VER #pragma comment(lib, "OpenAL32.lib") #endif @@ -32,30 +34,27 @@ void printAlcError(ALCenum err, const char* situation) } } -OpenALThread::~OpenALThread() +OpenALThread::OpenALThread() { - Quit(); -} - -void OpenALThread::Init() -{ - m_device = alcOpenDevice(nullptr); + ALCdevice* m_device = alcOpenDevice(nullptr); checkForAlcError("alcOpenDevice"); - m_context = alcCreateContext(m_device, nullptr); + ALCcontext* m_context = alcCreateContext(m_device, nullptr); checkForAlcError("alcCreateContext"); alcMakeContextCurrent(m_context); checkForAlcError("alcMakeContextCurrent"); } -void OpenALThread::Quit() +OpenALThread::~OpenALThread() { - m_context = alcGetCurrentContext(); - m_device = alcGetContextsDevice(m_context); - alcMakeContextCurrent(nullptr); - alcDestroyContext(m_context); - alcCloseDevice(m_device); + if (ALCcontext* m_context = alcGetCurrentContext()) + { + ALCdevice* m_device = alcGetContextsDevice(m_context); + alcMakeContextCurrent(nullptr); + alcDestroyContext(m_context); + alcCloseDevice(m_device); + } } void OpenALThread::Play() @@ -103,7 +102,7 @@ void OpenALThread::Open(const void* src, int size) for (uint i = 0; i m_audio_out; - -public: - void Init(); - void Close(); - - AudioThread& GetAudioOut() { return *m_audio_out; } -}; diff --git a/rpcs3/Emu/Audio/AudioThread.h b/rpcs3/Emu/Audio/AudioThread.h index 6932294bb3..fc01b25d7c 100644 --- a/rpcs3/Emu/Audio/AudioThread.h +++ b/rpcs3/Emu/Audio/AudioThread.h @@ -3,10 +3,8 @@ class AudioThread { public: - virtual ~AudioThread() {} + virtual ~AudioThread() = default; - virtual void Init() = 0; - virtual void Quit() = 0; virtual void Play() = 0; virtual void Open(const void* src, int size) = 0; virtual void Close() = 0; diff --git a/rpcs3/Emu/Audio/XAudio2/XAudio2Thread.cpp b/rpcs3/Emu/Audio/XAudio2/XAudio2Thread.cpp index 80483b6c35..3611783d2e 100644 --- a/rpcs3/Emu/Audio/XAudio2/XAudio2Thread.cpp +++ b/rpcs3/Emu/Audio/XAudio2/XAudio2Thread.cpp @@ -1,20 +1,16 @@ #include "stdafx.h" #ifdef _MSC_VER +#include "Utilities/Config.h" #include "Emu/System.h" -#include "Emu/state.h" #include "XAudio2Thread.h" -XAudio2Thread::~XAudio2Thread() -{ - Quit(); -} +extern cfg::bool_entry g_cfg_audio_convert_to_u16; -XAudio2Thread::XAudio2Thread() : m_xaudio2_instance(nullptr), m_master_voice(nullptr), m_source_voice(nullptr) -{ -} - -void XAudio2Thread::Init() +XAudio2Thread::XAudio2Thread() + : m_xaudio2_instance(nullptr) + , m_master_voice(nullptr) + , m_source_voice(nullptr) { HRESULT hr = S_OK; @@ -43,24 +39,23 @@ void XAudio2Thread::Init() } } -void XAudio2Thread::Quit() +XAudio2Thread::~XAudio2Thread() { - if (m_source_voice != nullptr) + if (m_source_voice != nullptr) { - Stop(); + m_source_voice->Stop(); m_source_voice->DestroyVoice(); - m_source_voice = nullptr; } + if (m_master_voice != nullptr) { m_master_voice->DestroyVoice(); - m_master_voice = nullptr; } + if (m_xaudio2_instance != nullptr) { m_xaudio2_instance->StopEngine(); m_xaudio2_instance->Release(); - m_xaudio2_instance = nullptr; } CoUninitialize(); @@ -101,11 +96,11 @@ void XAudio2Thread::Open(const void* src, int size) { HRESULT hr; - WORD sample_size = rpcs3::config.audio.convert_to_u16.value() ? sizeof(u16) : sizeof(float); + WORD sample_size = g_cfg_audio_convert_to_u16 ? sizeof(u16) : sizeof(float); WORD channels = 8; WAVEFORMATEX waveformatex; - waveformatex.wFormatTag = rpcs3::config.audio.convert_to_u16.value() ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT; + waveformatex.wFormatTag = g_cfg_audio_convert_to_u16 ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT; waveformatex.nChannels = channels; waveformatex.nSamplesPerSec = 48000; waveformatex.nAvgBytesPerSec = 48000 * (DWORD)channels * (DWORD)sample_size; @@ -121,6 +116,8 @@ void XAudio2Thread::Open(const void* src, int size) return; } + m_source_voice->SetVolume(4.0); + AddData(src, size); Play(); } diff --git a/rpcs3/Emu/Audio/XAudio2/XAudio2Thread.h b/rpcs3/Emu/Audio/XAudio2/XAudio2Thread.h index 3f149bea57..25729c450e 100644 --- a/rpcs3/Emu/Audio/XAudio2/XAudio2Thread.h +++ b/rpcs3/Emu/Audio/XAudio2/XAudio2Thread.h @@ -11,21 +11,18 @@ class XAudio2Thread : public AudioThread { -private: IXAudio2* m_xaudio2_instance; IXAudio2MasteringVoice* m_master_voice; IXAudio2SourceVoice* m_source_voice; public: - virtual ~XAudio2Thread(); XAudio2Thread(); + virtual ~XAudio2Thread() override; - virtual void Init(); - virtual void Quit(); - virtual void Play(); - virtual void Open(const void* src, int size); - virtual void Close(); - virtual void Stop(); - virtual void AddData(const void* src, int size); + virtual void Play() override; + virtual void Open(const void* src, int size) override; + virtual void Close() override; + virtual void Stop() override; + virtual void AddData(const void* src, int size) override; }; #endif diff --git a/rpcs3/Emu/CPU/CPUDecoder.h b/rpcs3/Emu/CPU/CPUDecoder.h deleted file mode 100644 index 4a6d0021b0..0000000000 --- a/rpcs3/Emu/CPU/CPUDecoder.h +++ /dev/null @@ -1,951 +0,0 @@ -#pragma once -#include "CPUInstrTable.h" - -class CPUDecoder -{ -public: - virtual u32 DecodeMemory(const u32 address) = 0; - - virtual ~CPUDecoder() = default; -}; - -template -class InstrCaller -{ -public: - virtual ~InstrCaller() = default; - - virtual void operator ()(TO* op, u32 code) const = 0; - - virtual u32 operator [](u32) const - { - return 0; - } -}; - -template -class InstrBinder_0 : public InstrCaller -{ - typedef void (TO::*func_t)(); - func_t m_func; - -public: - InstrBinder_0(func_t func) - : InstrCaller() - , m_func(func) - { - } - - virtual void operator ()(TO* op, u32 code) const - { - (op->*m_func)(); - } -}; - -template -class InstrBinder_1 : public InstrCaller -{ - typedef void (TO::*func_t)(T1); - func_t m_func; - const CodeFieldBase& m_arg_func_1; - -public: - InstrBinder_1(func_t func, const CodeFieldBase& arg_func_1) - : InstrCaller() - , m_func(func) - , m_arg_func_1(arg_func_1) - { - } - - virtual void operator ()(TO* op, u32 code) const - { - (op->*m_func)(static_cast(m_arg_func_1(code))); - } -}; - -template -class InstrBinder_2 : public InstrCaller -{ - typedef void (TO::*func_t)(T1, T2); - func_t m_func; - const CodeFieldBase& m_arg_func_1; - const CodeFieldBase& m_arg_func_2; - -public: - InstrBinder_2(func_t func, const CodeFieldBase& arg_func_1, const CodeFieldBase& arg_func_2) - : InstrCaller() - , m_func(func) - , m_arg_func_1(arg_func_1) - , m_arg_func_2(arg_func_2) - { - } - - virtual void operator ()(TO* op, u32 code) const - { - (op->*m_func)( - static_cast(m_arg_func_1(code)), - static_cast(m_arg_func_2(code)) - ); - } -}; - -template -class InstrBinder_3 : public InstrCaller -{ - typedef void (TO::*func_t)(T1, T2, T3); - func_t m_func; - const CodeFieldBase& m_arg_func_1; - const CodeFieldBase& m_arg_func_2; - const CodeFieldBase& m_arg_func_3; - -public: - InstrBinder_3(func_t func, - const CodeFieldBase& arg_func_1, - const CodeFieldBase& arg_func_2, - const CodeFieldBase& arg_func_3) - : InstrCaller() - , m_func(func) - , m_arg_func_1(arg_func_1) - , m_arg_func_2(arg_func_2) - , m_arg_func_3(arg_func_3) - { - } - - virtual void operator ()(TO* op, u32 code) const - { - (op->*m_func)( - static_cast(m_arg_func_1(code)), - static_cast(m_arg_func_2(code)), - static_cast(m_arg_func_3(code)) - ); - } -}; - -template -class InstrBinder_4 : public InstrCaller -{ - typedef void (TO::*func_t)(T1, T2, T3, T4); - func_t m_func; - const CodeFieldBase& m_arg_func_1; - const CodeFieldBase& m_arg_func_2; - const CodeFieldBase& m_arg_func_3; - const CodeFieldBase& m_arg_func_4; - -public: - InstrBinder_4(func_t func, - const CodeFieldBase& arg_func_1, - const CodeFieldBase& arg_func_2, - const CodeFieldBase& arg_func_3, - const CodeFieldBase& arg_func_4) - : InstrCaller() - , m_func(func) - , m_arg_func_1(arg_func_1) - , m_arg_func_2(arg_func_2) - , m_arg_func_3(arg_func_3) - , m_arg_func_4(arg_func_4) - { - } - - virtual void operator ()(TO* op, u32 code) const - { - (op->*m_func)( - static_cast(m_arg_func_1(code)), - static_cast(m_arg_func_2(code)), - static_cast(m_arg_func_3(code)), - static_cast(m_arg_func_4(code)) - ); - } -}; - -template -class InstrBinder_5 : public InstrCaller -{ - typedef void (TO::*func_t)(T1, T2, T3, T4, T5); - func_t m_func; - const CodeFieldBase& m_arg_func_1; - const CodeFieldBase& m_arg_func_2; - const CodeFieldBase& m_arg_func_3; - const CodeFieldBase& m_arg_func_4; - const CodeFieldBase& m_arg_func_5; - -public: - InstrBinder_5(func_t func, - const CodeFieldBase& arg_func_1, - const CodeFieldBase& arg_func_2, - const CodeFieldBase& arg_func_3, - const CodeFieldBase& arg_func_4, - const CodeFieldBase& arg_func_5) - : InstrCaller() - , m_func(func) - , m_arg_func_1(arg_func_1) - , m_arg_func_2(arg_func_2) - , m_arg_func_3(arg_func_3) - , m_arg_func_4(arg_func_4) - , m_arg_func_5(arg_func_5) - { - } - - virtual void operator ()(TO* op, u32 code) const - { - (op->*m_func)( - static_cast(m_arg_func_1(code)), - static_cast(m_arg_func_2(code)), - static_cast(m_arg_func_3(code)), - static_cast(m_arg_func_4(code)), - static_cast(m_arg_func_5(code)) - ); - } -}; - -template -class InstrBinder_6 : public InstrCaller -{ - typedef void (TO::*func_t)(T1, T2, T3, T4, T5, T6); - func_t m_func; - const CodeFieldBase& m_arg_func_1; - const CodeFieldBase& m_arg_func_2; - const CodeFieldBase& m_arg_func_3; - const CodeFieldBase& m_arg_func_4; - const CodeFieldBase& m_arg_func_5; - const CodeFieldBase& m_arg_func_6; - -public: - InstrBinder_6(func_t func, - const CodeFieldBase& arg_func_1, - const CodeFieldBase& arg_func_2, - const CodeFieldBase& arg_func_3, - const CodeFieldBase& arg_func_4, - const CodeFieldBase& arg_func_5, - const CodeFieldBase& arg_func_6) - : InstrCaller() - , m_func(func) - , m_arg_func_1(arg_func_1) - , m_arg_func_2(arg_func_2) - , m_arg_func_3(arg_func_3) - , m_arg_func_4(arg_func_4) - , m_arg_func_5(arg_func_5) - , m_arg_func_6(arg_func_6) - { - } - - virtual void operator ()(TO* op, u32 code) const - { - (op->*m_func)( - static_cast(m_arg_func_1(code)), - static_cast(m_arg_func_2(code)), - static_cast(m_arg_func_3(code)), - static_cast(m_arg_func_4(code)), - static_cast(m_arg_func_5(code)), - static_cast(m_arg_func_6(code)) - ); - } -}; - -template -InstrCaller* instr_bind(void (TO::*func)()) -{ - return new InstrBinder_0(func); -} - -template -InstrCaller* instr_bind(void (TO::*func)(T1), const CodeFieldBase& arg_func_1) -{ - return new InstrBinder_1(func, arg_func_1); -} - -template -InstrCaller* instr_bind(void (TO::*func)(T1, T2), - const CodeFieldBase& arg_func_1, - const CodeFieldBase& arg_func_2) -{ - return new InstrBinder_2(func, arg_func_1, arg_func_2); -} - -template -InstrCaller* instr_bind(void (TO::*func)(T1, T2, T3), - const CodeFieldBase& arg_func_1, - const CodeFieldBase& arg_func_2, - const CodeFieldBase& arg_func_3) -{ - return new InstrBinder_3(func, arg_func_1, arg_func_2, arg_func_3); -} - -template -InstrCaller* instr_bind(void (TO::*func)(T1, T2, T3, T4), - const CodeFieldBase& arg_func_1, - const CodeFieldBase& arg_func_2, - const CodeFieldBase& arg_func_3, - const CodeFieldBase& arg_func_4) -{ - return new InstrBinder_4(func, arg_func_1, arg_func_2, arg_func_3, arg_func_4); -} - -template -InstrCaller* instr_bind(void (TO::*func)(T1, T2, T3, T4, T5), - const CodeFieldBase& arg_func_1, - const CodeFieldBase& arg_func_2, - const CodeFieldBase& arg_func_3, - const CodeFieldBase& arg_func_4, - const CodeFieldBase& arg_func_5) -{ - return new InstrBinder_5(func, arg_func_1, arg_func_2, arg_func_3, arg_func_4, arg_func_5); -} - -template -InstrCaller* instr_bind(void (TO::*func)(T1, T2, T3, T4, T5, T6), - const CodeFieldBase& arg_func_1, - const CodeFieldBase& arg_func_2, - const CodeFieldBase& arg_func_3, - const CodeFieldBase& arg_func_4, - const CodeFieldBase& arg_func_5, - const CodeFieldBase& arg_func_6) -{ - return new InstrBinder_6(func, arg_func_1, arg_func_2, arg_func_3, arg_func_4, arg_func_5, arg_func_6); -} - -template -class InstrBase : public InstrCaller -{ -protected: - std::string m_name; - const u32 m_opcode; - CodeFieldBase** m_args; - const uint m_args_count; - -public: - InstrBase(const std::string& name, int opcode, uint args_count) - : InstrCaller() - , m_name(name) - , m_opcode(opcode) - , m_args_count(args_count) - , m_args(args_count ? new CodeFieldBase*[args_count] : nullptr) - { - std::transform( - name.begin(), - name.end(), - m_name.begin(), - [](const char &a) - { - char b = tolower(a); - if (b == '_') b = '.'; - return b; - }); - } - - InstrBase(const InstrBase &source) - : InstrCaller(source) - , m_name(source.m_name) - , m_opcode(source.m_opcode) - , m_args_count(source.m_args_count) - , m_args(source.m_args_count ? new CodeFieldBase*[source.m_args_count] : nullptr) - { - for(uint i = 0; i < source.m_args_count; ++i) - m_args[i] = source.m_args[i]; - } - - virtual ~InstrBase() - { - if (m_args) { - // m_args contains pointers to statically allocated CodeFieldBase objects - // We shouldn't call delete on these, they aren't allocated with new - - // The m_args array itself, however, should be deleted - delete[] m_args; - } - } - - force_inline const std::string& GetName() const - { - return m_name; - } - - force_inline const uint GetArgCount() const - { - return m_args_count; - } - - force_inline const CodeFieldBase& GetArg(uint index) const - { - assert(index < m_args_count); - return *m_args[index]; - } - - void operator ()(TO* op, u32 code) const - { - decode(op, code); - } - - u32 operator()(const std::vector& args) const - { - return encode(args); - } - - virtual void decode(TO* op, u32 code) const=0; - virtual u32 encode(const std::vector& args) const=0; -}; - -template -class InstrList : public InstrCaller -{ -public: - static const int count = _count; - -protected: - const CodeFieldBase& m_func; - InstrCaller* m_instrs[count]; - InstrBase* m_instrs_info[count]; - InstrCaller* m_error_func; - InstrCaller* m_parent; - int m_opcode; - -public: - InstrList(const CodeFieldBase& func, InstrCaller* error_func) - : InstrCaller() - , m_func(func) - , m_error_func(error_func) - , m_parent(nullptr) - , m_opcode(-1) - { - for(int i=0; i*) * count); - } - - virtual ~InstrList() - { - bool deletedErrorFunc = false; - - // Clean up m_instrs - for(int i = 0; i < count; ++i) - { - InstrCaller* deleteMe = m_instrs[i]; - - if (deleteMe) { // deleteMe will be a nullptr if we've already deleted it through another reference - // Remove any instances of pointers to this instruction caller from our m_instrs list - m_instrs[i] = nullptr; - for (int j = i + 1; j < count; j++) { - if (m_instrs[j] == deleteMe) { - m_instrs[j] = nullptr; - } - } - - // If we're deleting the error handler here, remember it so we don't try to delete it again later - if (deleteMe == m_error_func) { - deletedErrorFunc = true; - } - - // Delete the instruction caller - delete deleteMe; - } - } - - // Clean up m_instrs_info - for (int i = 0; i < count; ++i) - { - InstrBase* deleteMe = m_instrs_info[i]; - - if (deleteMe) { - m_instrs_info[i] = nullptr; - for (int j = i + 1; j < count; j++) { - if (m_instrs_info[j] == deleteMe) { - m_instrs[j] = nullptr; - } - } - - delete deleteMe; - } - } - - // If we haven't already deleted our error handler, and we have one, then delete it now - if (!deletedErrorFunc && m_error_func) - { - delete m_error_func; - } - } - - void set_parent(InstrCaller* parent, int opcode) - { - m_opcode = opcode; - m_parent = parent; - } - - InstrCaller* get_parent() const - { - return m_parent; - } - - u32 get_opcode() const - { - return m_opcode; - } - - void set_error_func(InstrCaller* error_func) - { - for(int i=0; i* func, InstrBase* info = nullptr) - { - assert(pos < count); - m_instrs[pos] = func; - m_instrs_info[pos] = info; - } - - InstrCaller* get_instr(int pos) const - { - assert(pos < count); - return m_instrs[pos]; - } - - InstrBase* get_instr_info(int pos) const - { - assert(pos < count); - return m_instrs_info[pos]; - } - - u32 encode(u32 entry) const - { - return m_func[entry] | (m_parent ? (*m_parent)[m_opcode] : 0); - } - - void decode(TO* op, u32 entry, u32 code) const - { - (*m_instrs[entry])(op, code); - } - - virtual void operator ()(TO* op, u32 code) const - { - decode(op, m_func(code) & (count - 1), code); - } - - virtual u32 operator [](u32 entry) const - { - return encode(entry); - } -}; - -template -static InstrList* connect_list(InstrList* parent, InstrList* child, int opcode) -{ - parent->set_instr(opcode, child); - child->set_parent(parent, opcode); - return child; -} - -template -static InstrList* connect_list(InstrList* parent, InstrList* child) -{ - parent->set_error_func(child); - child->set_parent(parent->get_parent(), parent->get_opcode()); - return child; -} - -template -class Instr0 : public InstrBase -{ - InstrList& m_list; - -public: - Instr0(InstrList* list, const std::string& name, - void (TO::*func)()) - : InstrBase(name, opcode, 0) - , m_list(*list) - { - m_list.set_instr(opcode, instr_bind(func), this); - } - - virtual void decode(TO* op, u32 code) const - { - m_list.decode(op, opcode, code); - } - - virtual u32 encode(const std::vector& args) const - { - assert(args.size() == InstrBase::m_args_count); - return m_list.encode(opcode); - } - - u32 encode() const - { - return m_list.encode(opcode); - } - - u32 operator()() const - { - return encode(); - } -}; - -template -class Instr1 : public InstrBase -{ - InstrList& m_list; - -public: - Instr1(InstrList* list, const std::string& name, - void (TO::*func)(T1), - CodeFieldBase& arg_1) - : InstrBase(name, opcode, 1) - , m_list(*list) - { - InstrBase::m_args[0] = &arg_1; - - m_list.set_instr(opcode, instr_bind(func, arg_1), this); - } - - virtual void decode(TO* op, u32 code) const - { - m_list.decode(op, opcode, code); - } - - virtual u32 encode(const std::vector& args) const - { - assert(args.size() == InstrBase::m_args_count); - return m_list.encode(opcode) | (*InstrBase::m_args[0])[args[0]]; - } - - u32 encode(T1 a1) const - { - return m_list.encode(opcode) | (*InstrBase::m_args[0])[a1]; - } - - u32 operator()(T1 a1) const - { - return encode(a1); - } -}; - -template -class Instr2 : public InstrBase -{ - InstrList& m_list; - -public: - Instr2(InstrList* list, const std::string& name, - void (TO::*func)(T1, T2), - CodeFieldBase& arg_1, - CodeFieldBase& arg_2) - : InstrBase(name, opcode, 2) - , m_list(*list) - { - InstrBase::m_args[0] = &arg_1; - InstrBase::m_args[1] = &arg_2; - - m_list.set_instr(opcode, instr_bind(func, arg_1, arg_2), this); - } - - virtual void decode(TO* op, u32 code) const - { - m_list.decode(op, opcode, code); - } - - virtual u32 encode(const std::vector& args) const - { - assert(args.size() == InstrBase::m_args_count); - return m_list.encode(opcode) | (*InstrBase::m_args[0])[args[0]] | (*InstrBase::m_args[1])[args[1]]; - } - - u32 encode(T1 a1, T2 a2) const - { - return m_list.encode(opcode) | (*InstrBase::m_args[0])[a1] | (*InstrBase::m_args[1])[a2]; - } - - u32 operator()(T1 a1, T2 a2) const - { - return encode(a1, a2); - } -}; - -template -class Instr3 : public InstrBase -{ - InstrList& m_list; - -public: - Instr3(InstrList* list, const std::string& name, - void (TO::*func)(T1, T2, T3), - CodeFieldBase& arg_1, - CodeFieldBase& arg_2, - CodeFieldBase& arg_3) - : InstrBase(name, opcode, 3) - , m_list(*list) - { - InstrBase::m_args[0] = &arg_1; - InstrBase::m_args[1] = &arg_2; - InstrBase::m_args[2] = &arg_3; - - m_list.set_instr(opcode, instr_bind(func, arg_1, arg_2, arg_3), this); - } - - virtual void decode(TO* op, u32 code) const - { - m_list.decode(op, opcode, code); - } - - virtual u32 encode(const std::vector& args) const - { - assert(args.size() == InstrBase::m_args_count); - return m_list.encode(opcode) | (*InstrBase::m_args[0])[args[0]] | (*InstrBase::m_args[1])[args[1]] | (*InstrBase::m_args[2])[args[2]]; - } - - u32 encode(T1 a1, T2 a2, T3 a3) const - { - return m_list.encode(opcode) | (*InstrBase::m_args[0])[a1] | (*InstrBase::m_args[1])[a2] | (*InstrBase::m_args[2])[a3]; - } - - u32 operator()(T1 a1, T2 a2, T3 a3) const - { - return encode(a1, a2, a3); - } -}; - -template -class Instr4 : public InstrBase -{ - InstrList& m_list; - -public: - Instr4(InstrList* list, const std::string& name, - void (TO::*func)(T1, T2, T3, T4), - CodeFieldBase& arg_1, - CodeFieldBase& arg_2, - CodeFieldBase& arg_3, - CodeFieldBase& arg_4) - : InstrBase(name, opcode, 4) - , m_list(*list) - { - InstrBase::m_args[0] = &arg_1; - InstrBase::m_args[1] = &arg_2; - InstrBase::m_args[2] = &arg_3; - InstrBase::m_args[3] = &arg_4; - - m_list.set_instr(opcode, instr_bind(func, arg_1, arg_2, arg_3, arg_4), this); - } - - virtual void decode(TO* op, u32 code) const - { - m_list.decode(op, opcode, code); - } - - virtual u32 encode(const std::vector& args) const - { - assert(args.size() == InstrBase::m_args_count); - return m_list.encode(opcode) | - (*InstrBase::m_args[0])[args[0]] | - (*InstrBase::m_args[1])[args[1]] | - (*InstrBase::m_args[2])[args[2]] | - (*InstrBase::m_args[3])[args[3]]; - } - - u32 encode(T1 a1, T2 a2, T3 a3, T4 a4) const - { - return m_list.encode(opcode) | - (*InstrBase::m_args[0])[a1] | - (*InstrBase::m_args[1])[a2] | - (*InstrBase::m_args[2])[a3] | - (*InstrBase::m_args[3])[a4]; - } - - u32 operator()(T1 a1, T2 a2, T3 a3, T4 a4) const - { - return encode(a1, a2, a3, a4); - } -}; - -template -class Instr5 : public InstrBase -{ - InstrList& m_list; - -public: - Instr5(InstrList* list, const std::string& name, - void (TO::*func)(T1, T2, T3, T4, T5), - CodeFieldBase& arg_1, - CodeFieldBase& arg_2, - CodeFieldBase& arg_3, - CodeFieldBase& arg_4, - CodeFieldBase& arg_5) - : InstrBase(name, opcode, 5) - , m_list(*list) - { - InstrBase::m_args[0] = &arg_1; - InstrBase::m_args[1] = &arg_2; - InstrBase::m_args[2] = &arg_3; - InstrBase::m_args[3] = &arg_4; - InstrBase::m_args[4] = &arg_5; - - m_list.set_instr(opcode, instr_bind(func, arg_1, arg_2, arg_3, arg_4, arg_5), this); - } - - virtual void decode(TO* op, u32 code) const - { - m_list.decode(op, opcode, code); - } - - virtual u32 encode(const std::vector& args) const - { - assert(args.size() == InstrBase::m_args_count); - return m_list.encode(opcode) | - (*InstrBase::m_args[0])[args[0]] | - (*InstrBase::m_args[1])[args[1]] | - (*InstrBase::m_args[2])[args[2]] | - (*InstrBase::m_args[3])[args[3]] | - (*InstrBase::m_args[4])[args[4]]; - } - - u32 encode(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) const - { - return m_list.encode(opcode) | - (*InstrBase::m_args[0])[a1] | - (*InstrBase::m_args[1])[a2] | - (*InstrBase::m_args[2])[a3] | - (*InstrBase::m_args[3])[a4] | - (*InstrBase::m_args[4])[a5]; - } - - u32 operator()(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) const - { - return encode(a1, a2, a3, a4, a5); - } -}; - -template -class Instr6 : public InstrBase -{ - InstrList& m_list; - -public: - Instr6(InstrList* list, const std::string& name, - void (TO::*func)(T1, T2, T3, T4, T5, T6), - CodeFieldBase& arg_1, - CodeFieldBase& arg_2, - CodeFieldBase& arg_3, - CodeFieldBase& arg_4, - CodeFieldBase& arg_5, - CodeFieldBase& arg_6) - : InstrBase(name, opcode, 6) - , m_list(*list) - { - InstrBase::m_args[0] = &arg_1; - InstrBase::m_args[1] = &arg_2; - InstrBase::m_args[2] = &arg_3; - InstrBase::m_args[3] = &arg_4; - InstrBase::m_args[4] = &arg_5; - InstrBase::m_args[5] = &arg_6; - - m_list.set_instr(opcode, instr_bind(func, arg_1, arg_2, arg_3, arg_4, arg_5, arg_6), this); - } - - virtual void decode(TO* op, u32 code) const - { - m_list.decode(op, opcode, code); - } - - virtual u32 encode(const std::vector& args) const - { - assert(args.size() == InstrBase::m_args_count); - return m_list.encode(opcode) | - (*InstrBase::m_args[0])[args[0]] | - (*InstrBase::m_args[1])[args[1]] | - (*InstrBase::m_args[2])[args[2]] | - (*InstrBase::m_args[3])[args[3]] | - (*InstrBase::m_args[4])[args[4]] | - (*InstrBase::m_args[5])[args[5]]; - } - - u32 encode(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T5 a6) const - { - return m_list.encode(opcode) | - (*InstrBase::m_args[0])[a1] | - (*InstrBase::m_args[1])[a2] | - (*InstrBase::m_args[2])[a3] | - (*InstrBase::m_args[3])[a4] | - (*InstrBase::m_args[4])[a5] | - (*InstrBase::m_args[5])[a6]; - } - - u32 operator()(T1 a1, T2 a2, T3 a3, T4 a4, T4 a5, T4 a6) const - { - return encode(a1, a2, a3, a4, a5, a6); - } -}; - -template -static Instr0& make_instr(InstrList* list, const std::string& name, void (TO::*func)()) -{ - return *new Instr0(list, name, func); -} - -template -static Instr1& make_instr(InstrList* list, const std::string& name, - void (TO::*func)(T1), - CodeFieldBase& arg_1) -{ - return *new Instr1(list, name, func, arg_1); -} - -template -static Instr2& make_instr(InstrList* list, const std::string& name, - void (TO::*func)(T1, T2), - CodeFieldBase& arg_1, - CodeFieldBase& arg_2) -{ - return *new Instr2(list, name, func, arg_1, arg_2); -} - -template -static Instr3& make_instr(InstrList* list, const std::string& name, - void (TO::*func)(T1, T2, T3), - CodeFieldBase& arg_1, - CodeFieldBase& arg_2, - CodeFieldBase& arg_3) -{ - return *new Instr3(list, name, func, arg_1, arg_2, arg_3); -} - -template -static Instr4& make_instr(InstrList* list, const std::string& name, - void (TO::*func)(T1, T2, T3, T4), - CodeFieldBase& arg_1, - CodeFieldBase& arg_2, - CodeFieldBase& arg_3, - CodeFieldBase& arg_4) -{ - return *new Instr4(list, name, func, arg_1, arg_2, arg_3, arg_4); -} - -template -static Instr5& make_instr(InstrList* list, const std::string& name, - void (TO::*func)(T1, T2, T3, T4, T5), - CodeFieldBase& arg_1, - CodeFieldBase& arg_2, - CodeFieldBase& arg_3, - CodeFieldBase& arg_4, - CodeFieldBase& arg_5) -{ - return *new Instr5(list, name, func, arg_1, arg_2, arg_3, arg_4, arg_5); -} - -template -static Instr6& make_instr(InstrList* list, const std::string& name, - void (TO::*func)(T1, T2, T3, T4, T5, T6), - CodeFieldBase& arg_1, - CodeFieldBase& arg_2, - CodeFieldBase& arg_3, - CodeFieldBase& arg_4, - CodeFieldBase& arg_5, - CodeFieldBase& arg_6) -{ - return *new Instr6(list, name, func, arg_1, arg_2, arg_3, arg_4, arg_5, arg_6); -} diff --git a/rpcs3/Emu/CPU/CPUDisAsm.h b/rpcs3/Emu/CPU/CPUDisAsm.h index 7c4d9badb0..8991f55c84 100644 --- a/rpcs3/Emu/CPU/CPUDisAsm.h +++ b/rpcs3/Emu/CPU/CPUDisAsm.h @@ -51,11 +51,14 @@ protected: { } - virtual u32 DisAsmBranchTarget(const s32 imm)=0; + virtual u32 DisAsmBranchTarget(const s32 imm) = 0; std::string FixOp(std::string op) { - op.append(std::max(10 - (int)op.length(), 0),' '); + op.resize(std::max(op.length(), 10), ' '); return op; } + +public: + virtual u32 disasm(u32 pc) = 0; }; diff --git a/rpcs3/Emu/CPU/CPUInstrTable.h b/rpcs3/Emu/CPU/CPUInstrTable.h deleted file mode 100644 index 1402a94cf5..0000000000 --- a/rpcs3/Emu/CPU/CPUInstrTable.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -template force_inline static T sign(const T value) -{ - static_assert(size > 0 && size < sizeof(T) * 8, "Bad sign size"); - - if(value & (T(1) << (size - 1))) - { - return value - (T(1) << size); - } - - return value; -} - -class CodeFieldBase -{ -public: - u32 m_type; - -public: - CodeFieldBase(u32 type) : m_type(type) - { - } - - virtual u32 operator ()(u32 data) const=0; - virtual void operator()(u32& data, u32 value) const=0; - - virtual u32 operator[](u32 value) const - { - u32 result = 0; - (*this)(result, value); - return result; - } -}; diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index 23959d5070..b80cc30c93 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -1,14 +1,16 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "CPUDecoder.h" +#include "Emu/Cell/PPUThread.h" +#include "Emu/Cell/SPUThread.h" +#include "Emu/Cell/RawSPUThread.h" +#include "Emu/ARMv7/ARMv7Thread.h" #include "CPUThread.h" -thread_local CPUThread* g_tls_current_cpu_thread = nullptr; +thread_local cpu_thread* g_tls_current_cpu_thread = nullptr; -void CPUThread::on_task() +void cpu_thread::on_task() { g_tls_current_cpu_thread = this; @@ -16,13 +18,13 @@ void CPUThread::on_task() std::unique_lock lock(mutex); - // check thread status - while (is_alive()) + // Check thread status + while (!(state & cpu_state::exit)) { CHECK_EMU_STATUS; // check stop status - if (!is_stopped()) + if (!(state & cpu_state::stop)) { if (lock) lock.unlock(); @@ -30,26 +32,17 @@ void CPUThread::on_task() { cpu_task(); } - catch (CPUThreadReturn) + catch (cpu_state _s) { - ; + state += _s; } - catch (CPUThreadStop) + catch (const std::exception&) { - m_state |= CPU_STATE_STOPPED; - } - catch (CPUThreadExit) - { - m_state |= CPU_STATE_DEAD; - break; - } - catch (...) - { - dump_info(); + LOG_NOTICE(GENERAL, "\n%s", dump()); throw; } - m_state &= ~CPU_STATE_RETURN; + state -= cpu_state::ret; continue; } @@ -63,201 +56,7 @@ void CPUThread::on_task() } } -CPUThread::CPUThread(CPUThreadType type, const std::string& name) - : m_id(idm::get_last_id()) - , m_type(type) - , m_name(name) -{ -} - -CPUThread::~CPUThread() -{ - Emu.SendDbgCommand(DID_REMOVE_THREAD, this); -} - -std::string CPUThread::get_name() const -{ - return m_name; -} - -bool CPUThread::is_paused() const -{ - return (m_state & CPU_STATE_PAUSED) != 0 || Emu.IsPaused(); -} - -void CPUThread::dump_info() const -{ - if (!Emu.IsStopped()) - { - LOG_NOTICE(GENERAL, "%s", RegsToString()); - } -} - -void CPUThread::run() -{ - Emu.SendDbgCommand(DID_START_THREAD, this); - - init_stack(); - init_regs(); - do_run(); - - Emu.SendDbgCommand(DID_STARTED_THREAD, this); -} - -void CPUThread::pause() -{ - Emu.SendDbgCommand(DID_PAUSE_THREAD, this); - - m_state |= CPU_STATE_PAUSED; - - Emu.SendDbgCommand(DID_PAUSED_THREAD, this); -} - -void CPUThread::resume() -{ - Emu.SendDbgCommand(DID_RESUME_THREAD, this); - - { - // lock for reliable notification - std::lock_guard lock(mutex); - - m_state &= ~CPU_STATE_PAUSED; - - cv.notify_one(); - } - - Emu.SendDbgCommand(DID_RESUMED_THREAD, this); -} - -void CPUThread::stop() -{ - Emu.SendDbgCommand(DID_STOP_THREAD, this); - - if (is_current()) - { - throw CPUThreadStop{}; - } - else - { - // lock for reliable notification - std::lock_guard lock(mutex); - - m_state |= CPU_STATE_STOPPED; - - cv.notify_one(); - } - - Emu.SendDbgCommand(DID_STOPED_THREAD, this); -} - -void CPUThread::exec() -{ - Emu.SendDbgCommand(DID_EXEC_THREAD, this); - - m_state &= ~CPU_STATE_STOPPED; - - { - // lock for reliable notification - std::lock_guard lock(mutex); - - cv.notify_one(); - } -} - -void CPUThread::exit() -{ - m_state |= CPU_STATE_DEAD; - - if (!is_current()) - { - // lock for reliable notification - std::lock_guard lock(mutex); - - cv.notify_one(); - } -} - -void CPUThread::step() -{ - if (m_state.atomic_op([](u64& state) -> bool - { - const bool was_paused = (state & CPU_STATE_PAUSED) != 0; - - state |= CPU_STATE_STEP; - state &= ~CPU_STATE_PAUSED; - - return was_paused; - })) - { - if (is_current()) return; - - // lock for reliable notification (only if PAUSE was removed) - std::lock_guard lock(mutex); - - cv.notify_one(); - } -} - -void CPUThread::sleep() -{ - m_state += CPU_STATE_MAX; - m_state |= CPU_STATE_SLEEP; -} - -void CPUThread::awake() -{ - // 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"); - } - - if ((state -= CPU_STATE_MAX) < CPU_STATE_MAX) - { - state &= ~CPU_STATE_SLEEP; - - // notify the condition variable as well - return true; - } - - return false; - })) - { - if (is_current()) return; - - // lock for reliable notification; the condition being checked is probably externally set - std::lock_guard lock(mutex); - - cv.notify_one(); - } -} - -bool CPUThread::signal() -{ - // try to set SIGNAL - if (m_state._or(CPU_STATE_SIGNAL) & CPU_STATE_SIGNAL) - { - return false; - } - else - { - // not truly responsible for signal delivery, requires additional measures like LV2_LOCK - cv.notify_one(); - - return true; - } -} - -bool CPUThread::unsignal() -{ - // remove SIGNAL and return its old value - return (m_state._and_not(CPU_STATE_SIGNAL) & CPU_STATE_SIGNAL) != 0; -} - -bool CPUThread::check_status() +bool cpu_thread::check_status() { std::unique_lock lock(mutex, std::defer_lock); @@ -265,12 +64,12 @@ bool CPUThread::check_status() { CHECK_EMU_STATUS; // check at least once - if (!is_alive()) + if (state & cpu_state::exit) { return true; } - if (!is_paused() && (m_state & CPU_STATE_INTR) == 0) + if (!state.test(cpu_state_pause) && !state.test(cpu_state::interrupt)) { break; } @@ -281,7 +80,7 @@ bool CPUThread::check_status() continue; } - if (!is_paused() && (m_state & CPU_STATE_INTR) != 0 && handle_interrupt()) + if (!state.test(cpu_state_pause) && state & cpu_state::interrupt && handle_interrupt()) { continue; } @@ -289,17 +88,45 @@ bool CPUThread::check_status() cv.wait(lock); } - if (m_state & CPU_STATE_RETURN || is_stopped()) + const auto state_ = state.load(); + + if (state_ & to_mset(cpu_state::ret, cpu_state::stop)) { return true; } - if (m_state & CPU_STATE_STEP) + if (state_ & cpu_state::dbg_step) { - // set PAUSE, but allow to execute once - m_state |= CPU_STATE_PAUSED; - m_state &= ~CPU_STATE_STEP; + state += cpu_state::dbg_pause; + state -= cpu_state::dbg_step; } return false; } + +std::vector> get_all_cpu_threads() +{ + std::vector> result; + + for (auto& t : idm::get_all()) + { + result.emplace_back(t); + } + + for (auto& t : idm::get_all()) + { + result.emplace_back(t); + } + + for (auto& t : idm::get_all()) + { + result.emplace_back(t); + } + + for (auto& t : idm::get_all()) + { + result.emplace_back(t); + } + + return result; +} diff --git a/rpcs3/Emu/CPU/CPUThread.h b/rpcs3/Emu/CPU/CPUThread.h index 1cfdd0e793..8baa65b03e 100644 --- a/rpcs3/Emu/CPU/CPUThread.h +++ b/rpcs3/Emu/CPU/CPUThread.h @@ -2,174 +2,97 @@ #include "Utilities/Thread.h" -enum CPUThreadType +// CPU Thread Type +enum class cpu_type : u32 { - CPU_THREAD_PPU, - CPU_THREAD_SPU, - CPU_THREAD_RAW_SPU, - CPU_THREAD_ARMv7, + ppu, // PPU Thread + spu, // SPU Thread + arm, // ARMv7 Thread }; -// CPU Thread State Flags -enum : u64 +// CPU Thread State flags +enum struct cpu_state : u32 { - CPU_STATE_STOPPED = (1ull << 0), // basic execution state (stopped by default), removed by Exec() - CPU_STATE_PAUSED = (1ull << 1), // pauses thread execution, set by the debugger (manually or after step execution) - CPU_STATE_SLEEP = (1ull << 2), // shouldn't affect thread execution, set by sleep(), removed by the latest awake(), may possibly indicate waiting state of the thread - CPU_STATE_STEP = (1ull << 3), // forces the thread to pause after executing just one instruction or something appropriate, set by the debugger - CPU_STATE_DEAD = (1ull << 4), // indicates irreversible exit of the thread - CPU_STATE_RETURN = (1ull << 5), // used for callback return - CPU_STATE_SIGNAL = (1ull << 6), // used for HLE signaling - CPU_STATE_INTR = (1ull << 7), // thread interrupted + stop, // Thread not running (HLE, initial state) + exit, // Irreversible exit + suspend, // Thread paused + ret, // Callback return requested + signal, // Thread received a signal (HLE) + interrupt, // Thread interrupted - CPU_STATE_MAX = (1ull << 8), // added to (subtracted from) m_state by sleep()/awake() calls to trigger status check + dbg_global_pause, // Emulation paused + dbg_global_stop, // Emulation stopped + dbg_pause, // Thread paused + dbg_step, // Thread forced to pause after one step (one instruction, etc) }; -class CPUThreadReturn {}; // "HLE return" exception event -class CPUThreadStop {}; // CPUThread::Stop exception event -class CPUThreadExit {}; // CPUThread::Exit exception event +// CPU Thread State flags: pause state union +constexpr mset cpu_state_pause = to_mset(cpu_state::suspend, cpu_state::dbg_global_pause, cpu_state::dbg_pause); -class CPUDecoder; - -class CPUThread : public named_thread_t +class cpu_thread : public named_thread { void on_task() override; - void on_id_aux_finalize() override { exit(); } // call exit() instead of join() - -protected: - atomic_t m_state{ CPU_STATE_STOPPED }; // thread state flags - - std::unique_ptr m_dec; - - const u32 m_id; - const CPUThreadType m_type; - const std::string m_name; // changing m_name is unsafe because it can be read at any moment - - CPUThread(CPUThreadType type, const std::string& name); public: - virtual ~CPUThread() override; + virtual void on_init() override + { + named_thread::on_init(); + } - virtual std::string get_name() const override; - u32 get_id() const { return m_id; } - CPUThreadType get_type() const { return m_type; } + virtual void on_stop() override + { + state += cpu_state::exit; + safe_notify(); + } - bool is_alive() const { return (m_state & CPU_STATE_DEAD) == 0; } - bool is_stopped() const { return (m_state & CPU_STATE_STOPPED) != 0; } - virtual bool is_paused() const; + const std::string name; + const u32 id{}; + const cpu_type type; - virtual void dump_info() const; - virtual u32 get_pc() const = 0; - virtual u32 get_offset() const = 0; - virtual void do_run() = 0; - virtual void cpu_task() = 0; + cpu_thread(cpu_type type, const std::string& name) + : type(type) + , name(name) + { + } - virtual void init_regs() = 0; - virtual void init_stack() = 0; - virtual void close_stack() = 0; + // Public thread state + atomic_t> state{ cpu_state::stop }; - // initialize thread - void run(); + // Recursively enter sleep state + void sleep() + { + if (!++m_sleep) xsleep(); + } - // called by the debugger, don't use - void pause(); + // Leave sleep state + void awake() + { + if (!m_sleep--) xsleep(); + } - // called by the debugger, don't use - void resume(); - - // stop thread execution - void stop(); - - // start thread execution (removing STOP status) - void exec(); - - // exit thread execution - void exit(); - - // called by the debugger, don't use - void step(); - - // trigger thread status check - void sleep(); - - // untrigger thread status check - void awake(); - - // set SIGNAL and notify (returns true if set) - bool signal(); - - // test SIGNAL and reset - bool unsignal(); - - // process m_state flags, returns true if the checker must return + // Process thread state, return true if the checker must return bool check_status(); + virtual std::string dump() const = 0; // Print CPU state + virtual void cpu_init() {} + virtual void cpu_task() = 0; virtual bool handle_interrupt() { return false; } - std::string GetFName() const +private: + [[noreturn]] void xsleep() { - return fmt::format("%s[0x%x] Thread (%s)", GetTypeString(), m_id, m_name); + throw std::runtime_error("cpu_thread: sleep()/awake() inconsistency"); } - static const char* CPUThreadTypeToString(CPUThreadType type) - { - switch (type) - { - case CPU_THREAD_PPU: return "PPU"; - case CPU_THREAD_SPU: return "SPU"; - case CPU_THREAD_RAW_SPU: return "RawSPU"; - case CPU_THREAD_ARMv7: return "ARMv7"; - } - - return "Unknown"; - } - - const char* ThreadStatusToString() const - { - // TODO - - //switch (ThreadStatus()) - //{ - //case CPUThread_Ready: return "Ready"; - //case CPUThread_Running: return "Running"; - //case CPUThread_Paused: return "Paused"; - //case CPUThread_Stopped: return "Stopped"; - //case CPUThread_Sleeping: return "Sleeping"; - //case CPUThread_Break: return "Break"; - //case CPUThread_Step: return "Step"; - //} - - return "Unknown"; - } - - const char* GetTypeString() const - { - return CPUThreadTypeToString(m_type); - } - - CPUDecoder* GetDecoder() - { - return m_dec.get(); - }; - - virtual std::string RegsToString() const = 0; - virtual std::string ReadRegString(const std::string& reg) const = 0; - virtual bool WriteRegString(const std::string& reg, std::string value) = 0; + // Sleep/Awake counter + atomic_t m_sleep{}; }; -inline CPUThread* get_current_cpu_thread() +inline cpu_thread* get_current_cpu_thread() noexcept { - extern thread_local CPUThread* g_tls_current_cpu_thread; + extern thread_local cpu_thread* g_tls_current_cpu_thread; return g_tls_current_cpu_thread; } -class cpu_thread -{ -protected: - std::shared_ptr thread; - -public: - virtual cpu_thread& args(std::initializer_list values) = 0; - virtual cpu_thread& run() = 0; -}; +extern std::vector> get_all_cpu_threads(); diff --git a/rpcs3/Emu/CPU/CPUThreadManager.cpp b/rpcs3/Emu/CPU/CPUThreadManager.cpp deleted file mode 100644 index e02f653c0e..0000000000 --- a/rpcs3/Emu/CPU/CPUThreadManager.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/System.h" -#include "Emu/IdManager.h" - -#include "Emu/Cell/PPUThread.h" -#include "Emu/Cell/SPUThread.h" -#include "Emu/Cell/RawSPUThread.h" -#include "Emu/ARMv7/ARMv7Thread.h" -#include "CPUThreadManager.h" - -CPUThreadManager::CPUThreadManager() -{ -} - -CPUThreadManager::~CPUThreadManager() -{ -} - -void CPUThreadManager::Close() -{ - std::lock_guard lock(m_mutex); - - for (auto& x : m_raw_spu) - { - x.reset(); - } -} - -std::vector> CPUThreadManager::GetAllThreads() -{ - std::vector> result; - - for (auto& t : idm::get_all()) - { - result.emplace_back(t); - } - - for (auto& t : idm::get_all()) - { - result.emplace_back(t); - } - - for (auto& t : idm::get_all()) - { - result.emplace_back(t); - } - - for (auto& t : idm::get_all()) - { - result.emplace_back(t); - } - - return result; -} - -void CPUThreadManager::Exec() -{ - for (auto& t : idm::get_all()) - { - t->exec(); - } - - for (auto& t : idm::get_all()) - { - t->exec(); - } -} - -std::shared_ptr CPUThreadManager::NewRawSPUThread() -{ - std::lock_guard lock(m_mutex); - - std::shared_ptr result; - - for (u32 i = 0; i < m_raw_spu.size(); i++) - { - if (m_raw_spu[i].expired()) - { - m_raw_spu[i] = result = idm::make_ptr(std::to_string(i), i); - break; - } - } - - return result; -} - -std::shared_ptr CPUThreadManager::GetRawSPUThread(u32 index) -{ - if (index >= m_raw_spu.size()) - { - return nullptr; - } - - std::lock_guard lock(m_mutex); - - return m_raw_spu[index].lock(); -} diff --git a/rpcs3/Emu/CPU/CPUThreadManager.h b/rpcs3/Emu/CPU/CPUThreadManager.h deleted file mode 100644 index 5fa772e971..0000000000 --- a/rpcs3/Emu/CPU/CPUThreadManager.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -class CPUThread; -class RawSPUThread; - -class CPUThreadManager final -{ - std::mutex m_mutex; - - std::array, 5> m_raw_spu; - -public: - CPUThreadManager(); - ~CPUThreadManager(); - - void Close(); - - static std::vector> GetAllThreads(); - - static void Exec(); - - std::shared_ptr NewRawSPUThread(); - - std::shared_ptr GetRawSPUThread(u32 index); -}; diff --git a/rpcs3/Emu/Cell/Common.h b/rpcs3/Emu/Cell/Common.h index b24396f854..214af66bce 100644 --- a/rpcs3/Emu/Cell/Common.h +++ b/rpcs3/Emu/Cell/Common.h @@ -8,16 +8,3 @@ enum FPSCR_RN FPSCR_RN_PINF = 2, FPSCR_RN_MINF = 3, }; - -using ppu_inter_func_t = void(*)(class PPUThread& CPU, union ppu_opcode_t opcode); - -struct ppu_decoder_cache_t -{ - ppu_inter_func_t* const pointer; - - ppu_decoder_cache_t(); - - ~ppu_decoder_cache_t(); - - void initialize(u32 addr, u32 size); -}; diff --git a/rpcs3/Emu/SysCalls/ErrorCodes.h b/rpcs3/Emu/Cell/ErrorCodes.h similarity index 53% rename from rpcs3/Emu/SysCalls/ErrorCodes.h rename to rpcs3/Emu/Cell/ErrorCodes.h index 373c806539..05445a6aa0 100644 --- a/rpcs3/Emu/SysCalls/ErrorCodes.h +++ b/rpcs3/Emu/Cell/ErrorCodes.h @@ -2,10 +2,13 @@ #define ERROR_CODE(code) static_cast(code) -enum : s32 +enum CellOk : s32 { - CELL_OK = 0, + CELL_OK = 0, +}; +enum CellError : s32 +{ CELL_EAGAIN = ERROR_CODE(0x80010001), // The resource is temporarily unavailable CELL_EINVAL = ERROR_CODE(0x80010002), // An invalid argument value is specified CELL_ENOSYS = ERROR_CODE(0x80010003), // The feature is not yet implemented @@ -64,6 +67,146 @@ enum : s32 CELL_EOVERFLOW = ERROR_CODE(0x80010039), CELL_ENOTMOUNTED = ERROR_CODE(0x8001003A), CELL_ENOTSDATA = ERROR_CODE(0x8001003B), - - CELL_UNKNOWN_ERROR = -1, }; + +// Special return type signaling on errors +struct ppu_error_code +{ + s32 value; + + // Print error message, error code is returned + static s32 report(s32 error, const char* text); + + // Must be specialized for specific tag type T + template + static const char* print(T code) + { + return nullptr; + } + + template + s32 error_check(T code) + { + if (const auto text = print(code)) + { + return report(code, text); + } + + return code; + } + + ppu_error_code() = default; + + // General error check + template::value>> + ppu_error_code(T value) + : value(error_check(value)) + { + } + + // Force error reporting with a message specified + ppu_error_code(s32 value, const char* text) + : value(report(value, text)) + { + } + + // Silence any error + constexpr ppu_error_code(s32 value, const std::nothrow_t&) + : value(value) + { + } + + // Conversion + constexpr operator s32() const + { + return value; + } +}; + +// Helper macro for silencing possible error checks on returning ppu_error_code values +#define NOT_AN_ERROR(value) { static_cast(value), std::nothrow } + +template +struct ppu_gpr_cast_impl; + +template<> +struct ppu_gpr_cast_impl +{ + static inline u64 to(const ppu_error_code& code) + { + return code; + } + + static inline ppu_error_code from(const u64 reg) + { + return NOT_AN_ERROR(reg); + } +}; + +template<> +inline const char* ppu_error_code::print(CellError error) +{ + switch (error) + { + STR_CASE(CELL_EAGAIN); + STR_CASE(CELL_EINVAL); + STR_CASE(CELL_ENOSYS); + STR_CASE(CELL_ENOMEM); + STR_CASE(CELL_ESRCH); + STR_CASE(CELL_ENOENT); + STR_CASE(CELL_ENOEXEC); + STR_CASE(CELL_EDEADLK); + STR_CASE(CELL_EPERM); + STR_CASE(CELL_EBUSY); + STR_CASE(CELL_ETIMEDOUT); + STR_CASE(CELL_EABORT); + STR_CASE(CELL_EFAULT); + STR_CASE(CELL_ESTAT); + STR_CASE(CELL_EALIGN); + STR_CASE(CELL_EKRESOURCE); + STR_CASE(CELL_EISDIR); + STR_CASE(CELL_ECANCELED); + STR_CASE(CELL_EEXIST); + STR_CASE(CELL_EISCONN); + STR_CASE(CELL_ENOTCONN); + STR_CASE(CELL_EAUTHFAIL); + STR_CASE(CELL_ENOTMSELF); + STR_CASE(CELL_ESYSVER); + STR_CASE(CELL_EAUTHFATAL); + STR_CASE(CELL_EDOM); + STR_CASE(CELL_ERANGE); + STR_CASE(CELL_EILSEQ); + STR_CASE(CELL_EFPOS); + STR_CASE(CELL_EINTR); + STR_CASE(CELL_EFBIG); + STR_CASE(CELL_EMLINK); + STR_CASE(CELL_ENFILE); + STR_CASE(CELL_ENOSPC); + STR_CASE(CELL_ENOTTY); + STR_CASE(CELL_EPIPE); + STR_CASE(CELL_EROFS); + STR_CASE(CELL_ESPIPE); + STR_CASE(CELL_E2BIG); + STR_CASE(CELL_EACCES); + STR_CASE(CELL_EBADF); + STR_CASE(CELL_EIO); + STR_CASE(CELL_EMFILE); + STR_CASE(CELL_ENODEV); + STR_CASE(CELL_ENOTDIR); + STR_CASE(CELL_ENXIO); + STR_CASE(CELL_EXDEV); + STR_CASE(CELL_EBADMSG); + STR_CASE(CELL_EINPROGRESS); + STR_CASE(CELL_EMSGSIZE); + STR_CASE(CELL_ENAMETOOLONG); + STR_CASE(CELL_ENOLCK); + STR_CASE(CELL_ENOTEMPTY); + STR_CASE(CELL_ENOTSUP); + STR_CASE(CELL_EFSSPECIFIC); + STR_CASE(CELL_EOVERFLOW); + STR_CASE(CELL_ENOTMOUNTED); + STR_CASE(CELL_ENOTSDATA); + } + + return nullptr; +} diff --git a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp b/rpcs3/Emu/Cell/Modules/cellAdec.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/cellAdec.cpp rename to rpcs3/Emu/Cell/Modules/cellAdec.cpp index 3a1234f6ae..ba9b76fe19 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAdec.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" extern std::mutex g_mutex_avcodec_open2; @@ -16,7 +15,7 @@ extern "C" #include "cellPamf.h" #include "cellAdec.h" -extern Module<> cellAdec; +LOG_CHANNEL(cellAdec); AudioDecoder::AudioDecoder(s32 type, u32 addr, u32 size, vm::ptr func, u32 arg) : type(type) @@ -467,8 +466,9 @@ void adecOpen(u32 adec_id) // TODO: call from the constructor }; - adec.adecCb->run(); - adec.adecCb->exec(); + adec.adecCb->cpu_init(); + adec.adecCb->state -= cpu_state::stop; + adec.adecCb->safe_notify(); } bool adecCheckType(s32 type) @@ -572,7 +572,7 @@ s32 cellAdecClose(u32 handle) std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } - idm::remove(adec->adecCb->get_id()); + idm::remove(adec->adecCb->id); idm::remove(handle); return CELL_OK; } @@ -863,7 +863,7 @@ s32 cellAdecGetPcmItem(u32 handle, vm::pptr pcmItem) return CELL_OK; } -Module<> cellAdec("cellAdec", []() +DECLARE(ppu_module_manager::cellAdec)("cellAdec", []() { REG_FUNC(cellAdec, cellAdecQueryAttr); REG_FUNC(cellAdec, cellAdecOpen); diff --git a/rpcs3/Emu/SysCalls/Modules/cellAdec.h b/rpcs3/Emu/Cell/Modules/cellAdec.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellAdec.h rename to rpcs3/Emu/Cell/Modules/cellAdec.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellAtrac.cpp b/rpcs3/Emu/Cell/Modules/cellAtrac.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/cellAtrac.cpp rename to rpcs3/Emu/Cell/Modules/cellAtrac.cpp index 977aa05480..d251fe9bcb 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAtrac.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAtrac.cpp @@ -1,10 +1,11 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellAtrac.h" +LOG_CHANNEL(cellAtrac); + s32 cellAtracSetDataAndGetMemSize(vm::ptr pHandle, vm::ptr pucBufferAddr, u32 uiReadByte, u32 uiBufferByte, vm::ptr puiWorkMemByte) { cellAtrac.warning("cellAtracSetDataAndGetMemSize(pHandle=*0x%x, pucBufferAddr=*0x%x, uiReadByte=0x%x, uiBufferByte=0x%x, puiWorkMemByte=*0x%x)", pHandle, pucBufferAddr, uiReadByte, uiBufferByte, puiWorkMemByte); @@ -194,7 +195,7 @@ s32 cellAtracGetInternalErrorInfo(vm::ptr pHandle, vm::ptr return CELL_OK; } -Module<> cellAtrac("cellAtrac", []() +DECLARE(ppu_module_manager::cellAtrac)("cellAtrac", []() { REG_FUNC(cellAtrac, cellAtracSetDataAndGetMemSize); diff --git a/rpcs3/Emu/SysCalls/Modules/cellAtrac.h b/rpcs3/Emu/Cell/Modules/cellAtrac.h similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/cellAtrac.h rename to rpcs3/Emu/Cell/Modules/cellAtrac.h index 391c838959..e9cca6f3bf 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAtrac.h +++ b/rpcs3/Emu/Cell/Modules/cellAtrac.h @@ -57,5 +57,3 @@ struct CellAtracExtRes vm::ptr pSpurs; u8 priority[8]; }; - -extern Module<> cellAtrac; diff --git a/rpcs3/Emu/SysCalls/Modules/cellAtracMulti.cpp b/rpcs3/Emu/Cell/Modules/cellAtracMulti.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/cellAtracMulti.cpp rename to rpcs3/Emu/Cell/Modules/cellAtracMulti.cpp index 5e8c78596d..75e1263f62 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAtracMulti.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAtracMulti.cpp @@ -1,10 +1,11 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellAtracMulti.h" +LOG_CHANNEL(cellAtracMulti); + s32 cellAtracMultiSetDataAndGetMemSize(vm::ptr pHandle, vm::ptr pucBufferAddr, u32 uiReadByte, u32 uiBufferByte, u32 uiOutputChNum, vm::ptr piTrackArray, vm::ptr puiWorkMemByte) { cellAtracMulti.warning("cellAtracMultiSetDataAndGetMemSize(pHandle=*0x%x, pucBufferAddr=*0x%x, uiReadByte=0x%x, uiBufferByte=0x%x, uiOutputChNum=%d, piTrackArray=*0x%x, puiWorkMemByte=*0x%x)", @@ -202,7 +203,7 @@ s32 cellAtracMultiGetInternalErrorInfo(vm::ptr pHandle, vm return CELL_OK; } -Module<> cellAtracMulti("cellAtrac", []() +DECLARE(ppu_module_manager::cellAtracMulti)("cellAtracMulti", []() { REG_FUNC(cellAtracMulti, cellAtracMultiSetDataAndGetMemSize); diff --git a/rpcs3/Emu/SysCalls/Modules/cellAtracMulti.h b/rpcs3/Emu/Cell/Modules/cellAtracMulti.h similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/cellAtracMulti.h rename to rpcs3/Emu/Cell/Modules/cellAtracMulti.h index d2807ae34c..51d5b7d889 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAtracMulti.h +++ b/rpcs3/Emu/Cell/Modules/cellAtracMulti.h @@ -58,5 +58,3 @@ struct CellAtracMultiExtRes vm::ptr pSpurs; u8 priority[8]; }; - -extern Module<> cellAtracMulti; diff --git a/rpcs3/Emu/Cell/Modules/cellAudio.cpp b/rpcs3/Emu/Cell/Modules/cellAudio.cpp new file mode 100644 index 0000000000..d5239f2557 --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/cellAudio.cpp @@ -0,0 +1,956 @@ +#include "stdafx.h" +#include "Emu/System.h" +#include "Emu/IdManager.h" +#include "Emu/Cell/PPUModule.h" + +#include "Emu/Cell/lv2/sys_event.h" +#include "Emu/Audio/AudioDumper.h" +#include "Emu/Audio/AudioThread.h" +#include "cellAudio.h" + +LOG_CHANNEL(cellAudio); + +cfg::bool_entry g_cfg_audio_dump_to_file(cfg::root.audio, "Dump to file"); +cfg::bool_entry g_cfg_audio_convert_to_u16(cfg::root.audio, "Convert to 16 bit"); + +void audio_config::on_task() +{ + for (u32 i = 0; i < AUDIO_PORT_COUNT; i++) + { + ports[i].number = i; + ports[i].addr = m_buffer + AUDIO_PORT_OFFSET * i; + ports[i].index = m_indexes + i; + } + + AudioDumper m_dump(g_cfg_audio_dump_to_file ? 2 : 0); // Init AudioDumper for 2 channels if enabled + + float buf2ch[2 * BUFFER_SIZE]{}; // intermediate buffer for 2 channels + float buf8ch[8 * BUFFER_SIZE]{}; // intermediate buffer for 8 channels + + static const size_t out_buffer_size = 8 * BUFFER_SIZE; // output buffer for 8 channels + + std::unique_ptr out_buffer[BUFFER_NUM]; + + for (u32 i = 0; i < BUFFER_NUM; i++) + { + out_buffer[i].reset(new float[out_buffer_size] {}); + } + + const auto audio = Emu.GetCallbacks().get_audio(); + audio->Open(buf8ch, out_buffer_size * (g_cfg_audio_convert_to_u16 ? 2 : 4)); + + while (fxm::check() && !Emu.IsStopped()) + { + if (Emu.IsPaused()) + { + std::this_thread::sleep_for(1ms); // hack + continue; + } + + const u64 stamp0 = get_system_time(); + + const u64 time_pos = stamp0 - start_time - Emu.GetPauseTime(); + + // TODO: send beforemix event (in ~2,6 ms before mixing) + + // precise time of sleeping: 5,(3) ms (or 256/48000 sec) + const u64 expected_time = m_counter * AUDIO_SAMPLES * 1000000 / 48000; + if (expected_time >= time_pos) + { + std::this_thread::sleep_for(1ms); // hack + continue; + } + + m_counter++; + + const u32 out_pos = m_counter % BUFFER_NUM; + + bool first_mix = true; + + // mixing: + for (auto& port : ports) + { + if (port.state != audio_port_state::started) continue; + + const u32 block_size = port.channel * AUDIO_SAMPLES; + const u32 position = port.tag % port.block; // old value + const u32 buf_addr = port.addr.addr() + position * block_size * sizeof(float); + + auto buf = vm::_ptr(buf_addr); + + static const float k = 1.0f; // may be 1.0f + const float& m = port.level; + + auto step_volume = [](audio_port& port) // part of cellAudioSetPortLevel functionality + { + const auto param = port.level_set.load(); + + if (param.inc != 0.0f) + { + port.level += param.inc; + const bool dec = param.inc < 0.0f; + + if ((!dec && param.value - port.level <= 0.0f) || (dec && param.value - port.level >= 0.0f)) + { + port.level = param.value; + port.level_set.compare_and_swap(param, { param.value, 0.0f }); + } + } + }; + + if (port.channel == 2) + { + if (first_mix) + { + for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) + { + step_volume(port); + + // reverse byte order + const float left = buf[i + 0] * m; + const float right = buf[i + 1] * m; + + buf2ch[i + 0] = left; + buf2ch[i + 1] = right; + + buf8ch[i * 4 + 0] = left; + buf8ch[i * 4 + 1] = right; + buf8ch[i * 4 + 2] = 0.0f; + buf8ch[i * 4 + 3] = 0.0f; + buf8ch[i * 4 + 4] = 0.0f; + buf8ch[i * 4 + 5] = 0.0f; + buf8ch[i * 4 + 6] = 0.0f; + buf8ch[i * 4 + 7] = 0.0f; + } + first_mix = false; + } + else + { + for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) + { + step_volume(port); + + const float left = buf[i + 0] * m; + const float right = buf[i + 1] * m; + + buf2ch[i + 0] += left; + buf2ch[i + 1] += right; + + buf8ch[i * 4 + 0] += left; + buf8ch[i * 4 + 1] += right; + } + } + } + else if (port.channel == 8) + { + if (first_mix) + { + for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) + { + step_volume(port); + + const float left = buf[i * 4 + 0] * m; + const float right = buf[i * 4 + 1] * m; + const float center = buf[i * 4 + 2] * m; + const float low_freq = buf[i * 4 + 3] * m; + const float rear_left = buf[i * 4 + 4] * m; + const float rear_right = buf[i * 4 + 5] * m; + const float side_left = buf[i * 4 + 6] * m; + const float side_right = buf[i * 4 + 7] * m; + + const float mid = (center + low_freq) * 0.708f; + buf2ch[i + 0] = (left + rear_left + side_left + mid) * k; + buf2ch[i + 1] = (right + rear_right + side_right + mid) * k; + + buf8ch[i * 4 + 0] = left; + buf8ch[i * 4 + 1] = right; + buf8ch[i * 4 + 2] = center; + buf8ch[i * 4 + 3] = low_freq; + buf8ch[i * 4 + 4] = rear_left; + buf8ch[i * 4 + 5] = rear_right; + buf8ch[i * 4 + 6] = side_left; + buf8ch[i * 4 + 7] = side_right; + } + first_mix = false; + } + else + { + for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) + { + step_volume(port); + + const float left = buf[i * 4 + 0] * m; + const float right = buf[i * 4 + 1] * m; + const float center = buf[i * 4 + 2] * m; + const float low_freq = buf[i * 4 + 3] * m; + const float rear_left = buf[i * 4 + 4] * m; + const float rear_right = buf[i * 4 + 5] * m; + const float side_left = buf[i * 4 + 6] * m; + const float side_right = buf[i * 4 + 7] * m; + + const float mid = (center + low_freq) * 0.708f; + buf2ch[i + 0] += (left + rear_left + side_left + mid) * k; + buf2ch[i + 1] += (right + rear_right + side_right + mid) * k; + + buf8ch[i * 4 + 0] += left; + buf8ch[i * 4 + 1] += right; + buf8ch[i * 4 + 2] += center; + buf8ch[i * 4 + 3] += low_freq; + buf8ch[i * 4 + 4] += rear_left; + buf8ch[i * 4 + 5] += rear_right; + buf8ch[i * 4 + 6] += side_left; + buf8ch[i * 4 + 7] += side_right; + } + } + } + else + { + throw EXCEPTION("Unknown channel count (port=%u, channel=%d)", port.number, port.channel); + } + + memset(buf, 0, block_size * sizeof(float)); + } + + + if (!first_mix) + { + // copy output data (2 ch) + //for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i++) + //{ + // out_buffer[out_pos][i] = buf2ch[i]; + //} + + // copy output data (8 ch) + for (u32 i = 0; i < (sizeof(buf8ch) / sizeof(float)); i++) + { + out_buffer[out_pos][i] = buf8ch[i]; + } + } + + const u64 stamp1 = get_system_time(); + + if (first_mix) + { + memset(out_buffer[out_pos].get(), 0, out_buffer_size * sizeof(float)); + } + + if (g_cfg_audio_convert_to_u16) + { + // convert the data from float to u16 with clipping: + // 2x MULPS + // 2x MAXPS (optional) + // 2x MINPS (optional) + // 2x CVTPS2DQ (converts float to s32) + // PACKSSDW (converts s32 to s16 with signed saturation) + + u16 buf_u16[out_buffer_size]; + for (size_t i = 0; i < out_buffer_size; i += 8) + { + const auto scale = _mm_set1_ps(0x8000); + (__m128i&)(buf_u16[i]) = _mm_packs_epi32( + _mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(out_buffer[out_pos].get() + i), scale)), + _mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(out_buffer[out_pos].get() + i + 4), scale))); + } + + audio->AddData(buf_u16, out_buffer_size * sizeof(u16)); + } + else + { + audio->AddData(out_buffer[out_pos].get(), out_buffer_size * sizeof(float)); + } + + const u64 stamp2 = get_system_time(); + + { + // update indices: + + for (u32 i = 0; i < AUDIO_PORT_COUNT; i++) + { + audio_port& port = ports[i]; + + if (port.state != audio_port_state::started) continue; + + u32 position = port.tag % port.block; // old value + port.counter = m_counter; + port.tag++; // absolute index of block that will be read + m_indexes[i] = (position + 1) % port.block; // write new value + } + + // send aftermix event (normal audio event) + + LV2_LOCK; + + std::lock_guard lock(mutex); + + for (u64 key : keys) + { + if (auto&& queue = lv2_event_queue_t::find(key)) + { + if (queue->events() < queue->size) + queue->push(lv2_lock, 0, 0, 0, 0); // TODO: check arguments + } + } + } + + const u64 stamp3 = get_system_time(); + + switch (m_dump.GetCh()) + { + case 2: m_dump.WriteData(&buf2ch, sizeof(buf2ch)); break; // write file data (2 ch) + case 8: m_dump.WriteData(&buf8ch, sizeof(buf8ch)); break; // write file data (8 ch) + } + + cellAudio.trace("Audio perf: start=%d (access=%d, AddData=%d, events=%d, dump=%d)", + time_pos, stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2, get_system_time() - stamp3); + } +} + +s32 cellAudioInit() +{ + cellAudio.warning("cellAudioInit()"); + + // Start audio thread + const auto g_audio = fxm::make(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_ALREADY_INIT; + } + + return CELL_OK; +} + +s32 cellAudioQuit() +{ + cellAudio.warning("cellAudioQuit()"); + + // Stop audio thread + const auto g_audio = fxm::withdraw(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + return CELL_OK; +} + +s32 cellAudioPortOpen(vm::ptr audioParam, vm::ptr portNum) +{ + cellAudio.warning("cellAudioPortOpen(audioParam=*0x%x, portNum=*0x%x)", audioParam, portNum); + + const auto g_audio = fxm::get(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (!audioParam || !portNum) + { + return CELL_AUDIO_ERROR_PARAM; + } + + const u64 channel = audioParam->nChannel; + const u64 block = audioParam->nBlock; + const u64 attr = audioParam->attr; + + // check attributes + if (channel != CELL_AUDIO_PORT_2CH && + channel != CELL_AUDIO_PORT_8CH && + channel) + { + return CELL_AUDIO_ERROR_PARAM; + } + + if (block != CELL_AUDIO_BLOCK_8 && + block != CELL_AUDIO_BLOCK_16 && + block != 2 && + block != 4 && + block != 32) + { + return CELL_AUDIO_ERROR_PARAM; + } + + // list unsupported flags + if (attr & CELL_AUDIO_PORTATTR_BGM) + { + cellAudio.todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_BGM"); + } + if (attr & CELL_AUDIO_PORTATTR_OUT_SECONDARY) + { + cellAudio.todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_SECONDARY"); + } + if (attr & CELL_AUDIO_PORTATTR_OUT_PERSONAL_0) + { + cellAudio.todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_PERSONAL_0"); + } + if (attr & CELL_AUDIO_PORTATTR_OUT_PERSONAL_1) + { + cellAudio.todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_PERSONAL_1"); + } + if (attr & CELL_AUDIO_PORTATTR_OUT_PERSONAL_2) + { + cellAudio.todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_PERSONAL_2"); + } + if (attr & CELL_AUDIO_PORTATTR_OUT_PERSONAL_3) + { + cellAudio.todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_PERSONAL_3"); + } + if (attr & CELL_AUDIO_PORTATTR_OUT_NO_ROUTE) + { + cellAudio.todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_NO_ROUTE"); + } + if (attr & 0xFFFFFFFFF0EFEFEEULL) + { + cellAudio.todo("cellAudioPortOpen(): unknown attributes (0x%llx)", attr); + } + + // Open audio port + const auto port = g_audio->open_port(); + + if (!port) + { + return CELL_AUDIO_ERROR_PORT_FULL; + } + + port->channel = ::narrow(channel); + port->block = ::narrow(block); + port->attr = attr; + port->size = ::narrow(channel * block * AUDIO_SAMPLES * sizeof(f32)); + port->tag = 0; + + if (attr & CELL_AUDIO_PORTATTR_INITLEVEL) + { + port->level = audioParam->level; + } + else + { + port->level = 1.0f; + } + + port->level_set.store({ port->level, 0.0f }); + + *portNum = port->number; + return CELL_OK; +} + +s32 cellAudioGetPortConfig(u32 portNum, vm::ptr portConfig) +{ + cellAudio.warning("cellAudioGetPortConfig(portNum=%d, portConfig=*0x%x)", portNum, portConfig); + + const auto g_audio = fxm::get(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (!portConfig || portNum >= AUDIO_PORT_COUNT) + { + return CELL_AUDIO_ERROR_PARAM; + } + + audio_port& port = g_audio->ports[portNum]; + + portConfig->readIndexAddr = port.index; + + switch (auto state = port.state.load()) + { + case audio_port_state::closed: portConfig->status = CELL_AUDIO_STATUS_CLOSE; break; + case audio_port_state::opened: portConfig->status = CELL_AUDIO_STATUS_READY; break; + case audio_port_state::started: portConfig->status = CELL_AUDIO_STATUS_RUN; break; + default: throw fmt::exception("Invalid port state (%d: %d)", portNum, state); + } + + portConfig->nChannel = port.channel; + portConfig->nBlock = port.block; + portConfig->portSize = port.size; + portConfig->portAddr = port.addr.addr(); + return CELL_OK; +} + +s32 cellAudioPortStart(u32 portNum) +{ + cellAudio.warning("cellAudioPortStart(portNum=%d)", portNum); + + const auto g_audio = fxm::get(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (portNum >= AUDIO_PORT_COUNT) + { + return CELL_AUDIO_ERROR_PARAM; + } + + switch (auto state = g_audio->ports[portNum].state.compare_and_swap(audio_port_state::opened, audio_port_state::started)) + { + case audio_port_state::closed: return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + case audio_port_state::started: return CELL_AUDIO_ERROR_PORT_ALREADY_RUN; + case audio_port_state::opened: return CELL_OK; + default: throw fmt::exception("Invalid port state (%d: %d)", portNum, state); + } +} + +s32 cellAudioPortClose(u32 portNum) +{ + cellAudio.warning("cellAudioPortClose(portNum=%d)", portNum); + + const auto g_audio = fxm::get(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (portNum >= AUDIO_PORT_COUNT) + { + return CELL_AUDIO_ERROR_PARAM; + } + + switch (auto state = g_audio->ports[portNum].state.exchange(audio_port_state::closed)) + { + case audio_port_state::closed: return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + case audio_port_state::started: return CELL_OK; + case audio_port_state::opened: return CELL_OK; + default: throw fmt::exception("Invalid port state (%d: %d)", portNum, state); + } +} + +s32 cellAudioPortStop(u32 portNum) +{ + cellAudio.warning("cellAudioPortStop(portNum=%d)", portNum); + + const auto g_audio = fxm::get(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (portNum >= AUDIO_PORT_COUNT) + { + return CELL_AUDIO_ERROR_PARAM; + } + + switch (auto state = g_audio->ports[portNum].state.compare_and_swap(audio_port_state::started, audio_port_state::opened)) + { + case audio_port_state::closed: return CELL_AUDIO_ERROR_PORT_NOT_RUN; + case audio_port_state::started: return CELL_OK; + case audio_port_state::opened: return CELL_AUDIO_ERROR_PORT_NOT_RUN; + default: throw fmt::exception("Invalid port state (%d: %d)", portNum, state); + } +} + +s32 cellAudioGetPortTimestamp(u32 portNum, u64 tag, vm::ptr stamp) +{ + cellAudio.trace("cellAudioGetPortTimestamp(portNum=%d, tag=0x%llx, stamp=*0x%x)", portNum, tag, stamp); + + const auto g_audio = fxm::get(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (portNum >= AUDIO_PORT_COUNT) + { + return CELL_AUDIO_ERROR_PARAM; + } + + audio_port& port = g_audio->ports[portNum]; + + if (port.state == audio_port_state::closed) + { + return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + } + + // TODO: check tag (CELL_AUDIO_ERROR_TAG_NOT_FOUND error) + + *stamp = g_audio->start_time + Emu.GetPauseTime() + (port.counter + (tag - port.tag)) * 256000000 / 48000; + + return CELL_OK; +} + +s32 cellAudioGetPortBlockTag(u32 portNum, u64 blockNo, vm::ptr tag) +{ + cellAudio.trace("cellAudioGetPortBlockTag(portNum=%d, blockNo=0x%llx, tag=*0x%x)", portNum, blockNo, tag); + + const auto g_audio = fxm::get(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (portNum >= AUDIO_PORT_COUNT) + { + return CELL_AUDIO_ERROR_PARAM; + } + + audio_port& port = g_audio->ports[portNum]; + + if (port.state == audio_port_state::closed) + { + return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + } + + if (blockNo >= port.block) + { + return CELL_AUDIO_ERROR_PARAM; + } + + u64 tag_base = port.tag; + if (tag_base % port.block > blockNo) + { + tag_base &= ~(port.block - 1); + tag_base += port.block; + } + else + { + tag_base &= ~(port.block - 1); + } + *tag = tag_base + blockNo; + + return CELL_OK; +} + +s32 cellAudioSetPortLevel(u32 portNum, float level) +{ + cellAudio.trace("cellAudioSetPortLevel(portNum=%d, level=%f)", portNum, level); + + const auto g_audio = fxm::get(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (portNum >= AUDIO_PORT_COUNT) + { + return CELL_AUDIO_ERROR_PARAM; + } + + audio_port& port = g_audio->ports[portNum]; + + if (port.state == audio_port_state::closed) + { + return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + } + + if (level >= 0.0f) + { + port.level_set.exchange({ level, (port.level - level) / 624.0f }); + } + else + { + cellAudio.todo("cellAudioSetPortLevel(%d): negative level value (%f)", portNum, level); + } + + return CELL_OK; +} + +s32 cellAudioCreateNotifyEventQueue(vm::ptr id, vm::ptr key) +{ + cellAudio.warning("cellAudioCreateNotifyEventQueue(id=*0x%x, key=*0x%x)", id, key); + + for (u64 k = 0; k < 100; k++) + { + const u64 key_value = 0x80004d494f323221ull + k; + + // Create an event queue "bruteforcing" an available key + if (auto&& queue = lv2_event_queue_t::make(SYS_SYNC_FIFO, SYS_PPU_QUEUE, 0, key_value, 32)) + { + *id = queue->id; + *key = key_value; + + return CELL_OK; + } + } + + return CELL_AUDIO_ERROR_EVENT_QUEUE; +} + +s32 cellAudioCreateNotifyEventQueueEx(vm::ptr id, vm::ptr key, u32 iFlags) +{ + cellAudio.todo("cellAudioCreateNotifyEventQueueEx(id=*0x%x, key=*0x%x, iFlags=0x%x)", id, key, iFlags); + + if (iFlags & ~CELL_AUDIO_CREATEEVENTFLAG_SPU) + { + return CELL_AUDIO_ERROR_PARAM; + } + + // TODO + + return CELL_AUDIO_ERROR_EVENT_QUEUE; +} + +s32 cellAudioSetNotifyEventQueue(u64 key) +{ + cellAudio.warning("cellAudioSetNotifyEventQueue(key=0x%llx)", key); + + const auto g_audio = fxm::get(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + std::lock_guard lock(g_audio->mutex); + + for (auto k : g_audio->keys) // check for duplicates + { + if (k == key) + { + return CELL_AUDIO_ERROR_TRANS_EVENT; + } + } + + g_audio->keys.emplace_back(key); + + return CELL_OK; +} + +s32 cellAudioSetNotifyEventQueueEx(u64 key, u32 iFlags) +{ + cellAudio.todo("cellAudioSetNotifyEventQueueEx(key=0x%llx, iFlags=0x%x)", key, iFlags); + + // TODO + + return CELL_OK; +} + +s32 cellAudioRemoveNotifyEventQueue(u64 key) +{ + cellAudio.warning("cellAudioRemoveNotifyEventQueue(key=0x%llx)", key); + + const auto g_audio = fxm::get(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + std::lock_guard lock(g_audio->mutex); + + for (auto i = g_audio->keys.begin(); i != g_audio->keys.end(); i++) + { + if (*i == key) + { + g_audio->keys.erase(i); + + return CELL_OK; + } + } + + return CELL_AUDIO_ERROR_TRANS_EVENT; +} + +s32 cellAudioRemoveNotifyEventQueueEx(u64 key, u32 iFlags) +{ + cellAudio.todo("cellAudioRemoveNotifyEventQueueEx(key=0x%llx, iFlags=0x%x)", key, iFlags); + + // TODO + + return CELL_OK; +} + +s32 cellAudioAddData(u32 portNum, vm::ptr src, u32 samples, float volume) +{ + cellAudio.trace("cellAudioAddData(portNum=%d, src=*0x%x, samples=%d, volume=%f)", portNum, src, samples, volume); + + const auto g_audio = fxm::get(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (portNum >= AUDIO_PORT_COUNT || !src || !src.aligned()) + { + return CELL_AUDIO_ERROR_PARAM; + } + + if (samples != 256) + { + // despite the docs, seems that only fixed value is supported + cellAudio.error("cellAudioAddData(): invalid samples value (%d)", samples); + return CELL_AUDIO_ERROR_PARAM; + } + + const audio_port& port = g_audio->ports[portNum]; + + const auto dst = vm::ptr::make(port.addr.addr() + u32(port.tag % port.block) * port.channel * 256 * SIZE_32(float)); + + for (u32 i = 0; i < samples * port.channel; i++) + { + dst[i] += src[i] * volume; // mix all channels + } + + return CELL_OK; +} + +s32 cellAudioAdd2chData(u32 portNum, vm::ptr src, u32 samples, float volume) +{ + cellAudio.trace("cellAudioAdd2chData(portNum=%d, src=*0x%x, samples=%d, volume=%f)", portNum, src, samples, volume); + + const auto g_audio = fxm::get(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (portNum >= AUDIO_PORT_COUNT || !src || !src.aligned()) + { + return CELL_AUDIO_ERROR_PARAM; + } + + if (samples != 256) + { + // despite the docs, seems that only fixed value is supported + cellAudio.error("cellAudioAdd2chData(): invalid samples value (%d)", samples); + return CELL_AUDIO_ERROR_PARAM; + } + + const audio_port& port = g_audio->ports[portNum]; + + const auto dst = vm::ptr::make(port.addr.addr() + s32(port.tag % port.block) * port.channel * 256 * SIZE_32(float)); + + if (port.channel == 2) + { + cellAudio.error("cellAudioAdd2chData(portNum=%d): port.channel = 2", portNum); + } + else if (port.channel == 6) + { + for (u32 i = 0; i < samples; i++) + { + dst[i * 6 + 0] += src[i * 2 + 0] * volume; // mix L ch + dst[i * 6 + 1] += src[i * 2 + 1] * volume; // mix R ch + //dst[i * 6 + 2] += 0.0f; // center + //dst[i * 6 + 3] += 0.0f; // LFE + //dst[i * 6 + 4] += 0.0f; // rear L + //dst[i * 6 + 5] += 0.0f; // rear R + } + } + else if (port.channel == 8) + { + for (u32 i = 0; i < samples; i++) + { + dst[i * 8 + 0] += src[i * 2 + 0] * volume; // mix L ch + dst[i * 8 + 1] += src[i * 2 + 1] * volume; // mix R ch + //dst[i * 8 + 2] += 0.0f; // center + //dst[i * 8 + 3] += 0.0f; // LFE + //dst[i * 8 + 4] += 0.0f; // rear L + //dst[i * 8 + 5] += 0.0f; // rear R + //dst[i * 8 + 6] += 0.0f; // side L + //dst[i * 8 + 7] += 0.0f; // side R + } + } + else + { + cellAudio.error("cellAudioAdd2chData(portNum=%d): invalid port.channel value (%d)", portNum, port.channel); + } + + return CELL_OK; +} + +s32 cellAudioAdd6chData(u32 portNum, vm::ptr src, float volume) +{ + cellAudio.trace("cellAudioAdd6chData(portNum=%d, src=*0x%x, volume=%f)", portNum, src, volume); + + const auto g_audio = fxm::get(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (portNum >= AUDIO_PORT_COUNT || !src || !src.aligned()) + { + return CELL_AUDIO_ERROR_PARAM; + } + + const audio_port& port = g_audio->ports[portNum]; + + const auto dst = vm::ptr::make(port.addr.addr() + s32(port.tag % port.block) * port.channel * 256 * SIZE_32(float)); + + if (port.channel == 2 || port.channel == 6) + { + cellAudio.error("cellAudioAdd2chData(portNum=%d): port.channel = %d", portNum, port.channel); + } + else if (port.channel == 8) + { + for (u32 i = 0; i < 256; i++) + { + dst[i * 8 + 0] += src[i * 6 + 0] * volume; // mix L ch + dst[i * 8 + 1] += src[i * 6 + 1] * volume; // mix R ch + dst[i * 8 + 2] += src[i * 6 + 2] * volume; // mix center + dst[i * 8 + 3] += src[i * 6 + 3] * volume; // mix LFE + dst[i * 8 + 4] += src[i * 6 + 4] * volume; // mix rear L + dst[i * 8 + 5] += src[i * 6 + 5] * volume; // mix rear R + //dst[i * 8 + 6] += 0.0f; // side L + //dst[i * 8 + 7] += 0.0f; // side R + } + } + else + { + cellAudio.error("cellAudioAdd6chData(portNum=%d): invalid port.channel value (%d)", portNum, port.channel); + } + + return CELL_OK; +} + +s32 cellAudioMiscSetAccessoryVolume(u32 devNum, float volume) +{ + cellAudio.todo("cellAudioMiscSetAccessoryVolume(devNum=%d, volume=%f)", devNum, volume); + return CELL_OK; +} + +s32 cellAudioSendAck(u64 data3) +{ + cellAudio.todo("cellAudioSendAck(data3=0x%llx)", data3); + return CELL_OK; +} + +s32 cellAudioSetPersonalDevice(s32 iPersonalStream, s32 iDevice) +{ + cellAudio.todo("cellAudioSetPersonalDevice(iPersonalStream=%d, iDevice=%d)", iPersonalStream, iDevice); + return CELL_OK; +} + +s32 cellAudioUnsetPersonalDevice(s32 iPersonalStream) +{ + cellAudio.todo("cellAudioUnsetPersonalDevice(iPersonalStream=%d)", iPersonalStream); + return CELL_OK; +} + +DECLARE(ppu_module_manager::cellAudio)("cellAudio", []() +{ + REG_FUNC(cellAudio, cellAudioInit); + REG_FUNC(cellAudio, cellAudioPortClose); + REG_FUNC(cellAudio, cellAudioPortStop); + REG_FUNC(cellAudio, cellAudioGetPortConfig); + REG_FUNC(cellAudio, cellAudioPortStart); + REG_FUNC(cellAudio, cellAudioQuit); + REG_FUNC(cellAudio, cellAudioPortOpen); + REG_FUNC(cellAudio, cellAudioSetPortLevel); + REG_FUNC(cellAudio, cellAudioCreateNotifyEventQueue); + REG_FUNC(cellAudio, cellAudioCreateNotifyEventQueueEx); + REG_FUNC(cellAudio, cellAudioMiscSetAccessoryVolume); + REG_FUNC(cellAudio, cellAudioSetNotifyEventQueue); + REG_FUNC(cellAudio, cellAudioSetNotifyEventQueueEx); + REG_FUNC(cellAudio, cellAudioGetPortTimestamp); + REG_FUNC(cellAudio, cellAudioAdd2chData); + REG_FUNC(cellAudio, cellAudioAdd6chData); + REG_FUNC(cellAudio, cellAudioAddData); + REG_FUNC(cellAudio, cellAudioGetPortBlockTag); + REG_FUNC(cellAudio, cellAudioRemoveNotifyEventQueue); + REG_FUNC(cellAudio, cellAudioRemoveNotifyEventQueueEx); + REG_FUNC(cellAudio, cellAudioSendAck); + REG_FUNC(cellAudio, cellAudioSetPersonalDevice); + REG_FUNC(cellAudio, cellAudioUnsetPersonalDevice); +}); diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudio.h b/rpcs3/Emu/Cell/Modules/cellAudio.h similarity index 76% rename from rpcs3/Emu/SysCalls/Modules/cellAudio.h rename to rpcs3/Emu/Cell/Modules/cellAudio.h index dd184d6e2a..e64a65f9ca 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAudio.h +++ b/rpcs3/Emu/Cell/Modules/cellAudio.h @@ -1,5 +1,7 @@ #pragma once +#include "Utilities/Thread.h" + namespace vm { using namespace ps3; } // Error codes @@ -66,7 +68,7 @@ struct CellAudioPortParam struct CellAudioPortConfig { - be_t readIndexAddr; + vm::bptr readIndexAddr; be_t status; be_t nChannel; be_t nBlock; @@ -83,36 +85,31 @@ enum : u32 AUDIO_SAMPLES = CELL_AUDIO_BLOCK_SAMPLES, }; -enum AudioState : u32 +extern u64 get_system_time(); + +enum class audio_port_state : u32 { - AUDIO_STATE_NOT_INITIALIZED, - AUDIO_STATE_INITIALIZED, - AUDIO_STATE_FINALIZED, + closed, + opened, + started, }; -enum AudioPortState : u32 +struct audio_port { - AUDIO_PORT_STATE_CLOSED, - AUDIO_PORT_STATE_OPENED, - AUDIO_PORT_STATE_STARTED, -}; + atomic_t state{ audio_port_state::closed }; -struct AudioPortConfig -{ - atomic_t state; - - std::mutex mutex; + u32 number; + vm::ptr addr{}; + vm::ptr index{}; u32 channel; u32 block; u64 attr; u64 tag; u64 counter; // copy of global counter - u32 addr; - u32 read_index_addr; u32 size; - struct level_set_t + struct alignas(8) level_set_t { float value; float inc; @@ -122,31 +119,36 @@ struct AudioPortConfig atomic_t level_set; }; -struct AudioConfig final // custom structure +class audio_config final : public named_thread { - atomic_t state; + void on_task() override; - std::mutex mutex; + std::string get_name() const override { return "Audio Thread"; } + + vm::var> m_buffer{ AUDIO_PORT_OFFSET * AUDIO_PORT_COUNT }; + vm::var> m_indexes{ AUDIO_PORT_COUNT }; + + u64 m_counter{}; + +public: + const u64 start_time = get_system_time(); + + std::array ports; - AudioPortConfig ports[AUDIO_PORT_COUNT]; - u32 buffer; // 1 MB memory for audio ports - u32 indexes; // current block indexes and other info - u64 counter; - u64 start_time; std::vector keys; - u32 open_port() + ~audio_config() noexcept = default; + + audio_port* open_port() { for (u32 i = 0; i < AUDIO_PORT_COUNT; i++) { - if (ports[i].state.compare_and_swap_test(AUDIO_PORT_STATE_CLOSED, AUDIO_PORT_STATE_OPENED)) + if (ports[i].state.compare_and_swap_test(audio_port_state::closed, audio_port_state::opened)) { - return i; + return &ports[i]; } } - return ~0; + return nullptr; } }; - -extern AudioConfig g_audio; diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudioIn.h b/rpcs3/Emu/Cell/Modules/cellAudioIn.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellAudioIn.h rename to rpcs3/Emu/Cell/Modules/cellAudioIn.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudioOut.cpp b/rpcs3/Emu/Cell/Modules/cellAudioOut.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/cellAudioOut.cpp rename to rpcs3/Emu/Cell/Modules/cellAudioOut.cpp index 0734bee4b8..d294bbd776 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAudioOut.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAudioOut.cpp @@ -1,10 +1,9 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellAudioOut.h" -extern Module<> cellSysutil; +extern _log::channel cellSysutil; s32 cellAudioOutGetSoundAvailability(u32 audioOut, u32 type, u32 fs, u32 option) { diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudioOut.h b/rpcs3/Emu/Cell/Modules/cellAudioOut.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellAudioOut.h rename to rpcs3/Emu/Cell/Modules/cellAudioOut.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellAvconfExt.cpp b/rpcs3/Emu/Cell/Modules/cellAvconfExt.cpp similarity index 63% rename from rpcs3/Emu/SysCalls/Modules/cellAvconfExt.cpp rename to rpcs3/Emu/Cell/Modules/cellAvconfExt.cpp index c34df3052d..7a005dc34a 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAvconfExt.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAvconfExt.cpp @@ -1,15 +1,14 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/state.h" +#include "Emu/System.h" +#include "Emu/Cell/PPUModule.h" #include "cellAudioIn.h" #include "cellAudioOut.h" #include "cellVideoOut.h" -extern Module<> cellAvconfExt; +LOG_CHANNEL(cellAvconfExt); -f32 g_gamma; +vm::gvar g_gamma; // TODO s32 cellAudioOutUnregisterDevice() { @@ -50,7 +49,7 @@ s32 cellVideoOutGetGamma(u32 videoOut, vm::ptr gamma) return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT; } - *gamma = g_gamma; + *gamma = *g_gamma; return CELL_OK; } @@ -79,7 +78,7 @@ s32 cellVideoOutSetGamma(u32 videoOut, f32 gamma) return CELL_VIDEO_OUT_ERROR_ILLEGAL_PARAMETER; } - g_gamma = gamma; + *g_gamma = gamma; return CELL_OK; } @@ -127,34 +126,32 @@ s32 cellVideoOutGetScreenSize(u32 videoOut, vm::ptr screenSize) // float diagonal = roundf(sqrtf((powf(wxGetDisplaySizeMM().GetWidth(), 2) + powf(wxGetDisplaySizeMM().GetHeight(), 2))) * 0.0393f); #endif - if (rpcs3::config.rsx._3dtv.value()) - { - *screenSize = 24.0f; - return CELL_OK; - } - return CELL_VIDEO_OUT_ERROR_VALUE_IS_NOT_SET; } -Module<> cellAvconfExt("cellAvconfExt", []() +DECLARE(ppu_module_manager::cellAvconfExt)("cellSysutilAvconfExt", []() { - g_gamma = 1.0f; + REG_VNID(cellSysutilAvconfExt, 0x00000000, g_gamma, [] + { + // Test + *g_gamma = 1.0f; + }); - REG_FUNC(cellAvconfExt, cellAudioOutUnregisterDevice); - REG_FUNC(cellAvconfExt, cellAudioOutGetDeviceInfo2); - REG_FUNC(cellAvconfExt, cellVideoOutSetXVColor); - REG_FUNC(cellAvconfExt, cellVideoOutSetupDisplay); - REG_FUNC(cellAvconfExt, cellAudioInGetDeviceInfo); - REG_FUNC(cellAvconfExt, cellVideoOutConvertCursorColor); - REG_FUNC(cellAvconfExt, cellVideoOutGetGamma); - REG_FUNC(cellAvconfExt, cellAudioInGetAvailableDeviceInfo); - REG_FUNC(cellAvconfExt, cellAudioOutGetAvailableDeviceInfo); - REG_FUNC(cellAvconfExt, cellVideoOutSetGamma); - REG_FUNC(cellAvconfExt, cellAudioOutRegisterDevice); - REG_FUNC(cellAvconfExt, cellAudioOutSetDeviceMode); - REG_FUNC(cellAvconfExt, cellAudioInSetDeviceMode); - REG_FUNC(cellAvconfExt, cellAudioInRegisterDevice); - REG_FUNC(cellAvconfExt, cellAudioInUnregisterDevice); - REG_FUNC(cellAvconfExt, cellVideoOutGetScreenSize); + REG_FUNC(cellSysutilAvconfExt, cellAudioOutUnregisterDevice); + REG_FUNC(cellSysutilAvconfExt, cellAudioOutGetDeviceInfo2); + REG_FUNC(cellSysutilAvconfExt, cellVideoOutSetXVColor); + REG_FUNC(cellSysutilAvconfExt, cellVideoOutSetupDisplay); + REG_FUNC(cellSysutilAvconfExt, cellAudioInGetDeviceInfo); + REG_FUNC(cellSysutilAvconfExt, cellVideoOutConvertCursorColor); + REG_FUNC(cellSysutilAvconfExt, cellVideoOutGetGamma); + REG_FUNC(cellSysutilAvconfExt, cellAudioInGetAvailableDeviceInfo); + REG_FUNC(cellSysutilAvconfExt, cellAudioOutGetAvailableDeviceInfo); + REG_FUNC(cellSysutilAvconfExt, cellVideoOutSetGamma); + REG_FUNC(cellSysutilAvconfExt, cellAudioOutRegisterDevice); + REG_FUNC(cellSysutilAvconfExt, cellAudioOutSetDeviceMode); + REG_FUNC(cellSysutilAvconfExt, cellAudioInSetDeviceMode); + REG_FUNC(cellSysutilAvconfExt, cellAudioInRegisterDevice); + REG_FUNC(cellSysutilAvconfExt, cellAudioInUnregisterDevice); + REG_FUNC(cellSysutilAvconfExt, cellVideoOutGetScreenSize); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellBgdl.cpp b/rpcs3/Emu/Cell/Modules/cellBgdl.cpp similarity index 69% rename from rpcs3/Emu/SysCalls/Modules/cellBgdl.cpp rename to rpcs3/Emu/Cell/Modules/cellBgdl.cpp index b57d7befa1..b83c0fa791 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellBgdl.cpp +++ b/rpcs3/Emu/Cell/Modules/cellBgdl.cpp @@ -1,9 +1,8 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellBGDL; +LOG_CHANNEL(cellBGDL); // Return Codes enum @@ -40,10 +39,10 @@ s32 cellBGDLGetMode() return CELL_OK; } -Module<> cellBGDL("cellBGDL", []() +DECLARE(ppu_module_manager::cellBGDL)("cellBGDLUtility", []() { - REG_FUNC(cellBGDL, cellBGDLGetInfo); - REG_FUNC(cellBGDL, cellBGDLGetInfo2); - REG_FUNC(cellBGDL, cellBGDLSetMode); - REG_FUNC(cellBGDL, cellBGDLGetMode); + REG_FUNC(cellBGDLUtility, cellBGDLGetInfo); + REG_FUNC(cellBGDLUtility, cellBGDLGetInfo2); + REG_FUNC(cellBGDLUtility, cellBGDLSetMode); + REG_FUNC(cellBGDLUtility, cellBGDLGetMode); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellCamera.cpp b/rpcs3/Emu/Cell/Modules/cellCamera.cpp similarity index 92% rename from rpcs3/Emu/SysCalls/Modules/cellCamera.cpp rename to rpcs3/Emu/Cell/Modules/cellCamera.cpp index e0c194ebac..6a2c491a43 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellCamera.cpp +++ b/rpcs3/Emu/Cell/Modules/cellCamera.cpp @@ -1,13 +1,25 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/IdManager.h" #include "Emu/System.h" -#include "Emu/state.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellCamera.h" -extern Module<> cellCamera; +LOG_CHANNEL(cellCamera); + +cfg::map_entry g_cfg_camera(cfg::root.io, "Camera", +{ + { "Null", false }, + { "Fake", true }, +}); + +cfg::map_entry g_cfg_camera_type(cfg::root.io, "Camera type", +{ + { "Unknown", CELL_CAMERA_TYPE_UNKNOWN }, + { "EyeToy", CELL_CAMERA_EYETOY }, + { "PS Eye", CELL_CAMERA_EYETOY2 }, + { "UVC 1.1", CELL_CAMERA_USBVIDEOCLASS }, +}); static const char* get_camera_attr_name(s32 value) { @@ -82,7 +94,7 @@ s32 cellCameraInit() { cellCamera.warning("cellCameraInit()"); - if (rpcs3::config.io.camera.value() == io_camera_state::null) + if (!g_cfg_camera.get()) { return CELL_CAMERA_ERROR_DEVICE_NOT_FOUND; } @@ -94,9 +106,9 @@ s32 cellCameraInit() return CELL_CAMERA_ERROR_ALREADY_INIT; } - switch (rpcs3::config.io.camera_type.value()) + switch (g_cfg_camera_type.get()) { - case io_camera_type::eye_toy: + case CELL_CAMERA_EYETOY: { camera->attr[CELL_CAMERA_SATURATION] = { 164 }; camera->attr[CELL_CAMERA_BRIGHTNESS] = { 96 }; @@ -115,7 +127,7 @@ s32 cellCameraInit() } break; - case io_camera_type::play_station_eye: + case CELL_CAMERA_EYETOY2: { camera->attr[CELL_CAMERA_SATURATION] = { 64 }; camera->attr[CELL_CAMERA_BRIGHTNESS] = { 8 }; @@ -191,14 +203,7 @@ s32 cellCameraGetType(s32 dev_num, vm::ptr type) return CELL_CAMERA_ERROR_NOT_INIT; } - switch (rpcs3::config.io.camera_type.value()) - { - case io_camera_type::eye_toy: *type = CELL_CAMERA_EYETOY; break; - case io_camera_type::play_station_eye: *type = CELL_CAMERA_EYETOY2; break; - case io_camera_type::usb_video_class_1_1: *type = CELL_CAMERA_USBVIDEOCLASS; break; - default: *type = CELL_CAMERA_TYPE_UNKNOWN; break; - } - + *type = g_cfg_camera_type.get(); return CELL_OK; } @@ -212,12 +217,12 @@ s32 cellCameraIsAttached(s32 dev_num) { cellCamera.warning("cellCameraIsAttached(dev_num=%d)", dev_num); - if (rpcs3::config.io.camera.value() == io_camera_state::connected) + if (g_cfg_camera.get()) { return 1; } - return CELL_OK; // CELL_OK means that no camera is attached + return 0; // It's not CELL_OK lol } s32 cellCameraIsOpen(s32 dev_num) @@ -381,7 +386,7 @@ s32 cellCameraRemoveNotifyEventQueue2(u64 key) return CELL_OK; } -Module<> cellCamera("cellCamera", []() +DECLARE(ppu_module_manager::cellCamera)("cellCamera", []() { REG_FUNC(cellCamera, cellCameraInit); REG_FUNC(cellCamera, cellCameraEnd); diff --git a/rpcs3/Emu/SysCalls/Modules/cellCamera.h b/rpcs3/Emu/Cell/Modules/cellCamera.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellCamera.h rename to rpcs3/Emu/Cell/Modules/cellCamera.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellCelp8Enc.cpp b/rpcs3/Emu/Cell/Modules/cellCelp8Enc.cpp similarity index 91% rename from rpcs3/Emu/SysCalls/Modules/cellCelp8Enc.cpp rename to rpcs3/Emu/Cell/Modules/cellCelp8Enc.cpp index b5e29f813a..bb0b24b9ef 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellCelp8Enc.cpp +++ b/rpcs3/Emu/Cell/Modules/cellCelp8Enc.cpp @@ -1,9 +1,8 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellCelp8Enc; +LOG_CHANNEL(cellCelp8Enc); // Return Codes enum @@ -70,7 +69,7 @@ s32 cellCelp8EncGetAu() return CELL_OK; } -Module<> cellCelp8Enc("cellCelp8Enc", []() +DECLARE(ppu_module_manager::cellCelp8Enc)("cellCelp8Enc", []() { REG_FUNC(cellCelp8Enc, cellCelp8EncQueryAttr); REG_FUNC(cellCelp8Enc, cellCelp8EncOpen); diff --git a/rpcs3/Emu/SysCalls/Modules/cellCelpEnc.cpp b/rpcs3/Emu/Cell/Modules/cellCelpEnc.cpp similarity index 91% rename from rpcs3/Emu/SysCalls/Modules/cellCelpEnc.cpp rename to rpcs3/Emu/Cell/Modules/cellCelpEnc.cpp index 2f2dd2c9ef..bb551877bb 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellCelpEnc.cpp +++ b/rpcs3/Emu/Cell/Modules/cellCelpEnc.cpp @@ -1,9 +1,8 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellCelpEnc; +LOG_CHANNEL(cellCelpEnc); // Return Codes enum @@ -70,7 +69,7 @@ s32 cellCelpEncGetAu() return CELL_OK; } -Module<> cellCelpEnc("cellCelpEnc", []() +DECLARE(ppu_module_manager::cellCelpEnc)("cellCelpEnc", []() { REG_FUNC(cellCelpEnc, cellCelpEncQueryAttr); REG_FUNC(cellCelpEnc, cellCelpEncOpen); diff --git a/rpcs3/Emu/SysCalls/Modules/cellDaisy.cpp b/rpcs3/Emu/Cell/Modules/cellDaisy.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/cellDaisy.cpp rename to rpcs3/Emu/Cell/Modules/cellDaisy.cpp index 8556089ea2..bd82c4d31b 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDaisy.cpp +++ b/rpcs3/Emu/Cell/Modules/cellDaisy.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellDaisy; +LOG_CHANNEL(cellDaisy); s32 _ZN4cell5Daisy17LFQueue2PushCloseEPNS0_8LFQueue2EPFiPvjE() { @@ -265,7 +264,7 @@ s32 _QN4cell5Daisy22ScatterGatherInterlock7releaseEv() } -Module<> cellDaisy("cellDaisy", []() +DECLARE(ppu_module_manager::cellDaisy)("cellDaisy", []() { REG_FUNC(cellDaisy, _ZN4cell5Daisy17LFQueue2PushCloseEPNS0_8LFQueue2EPFiPvjE); REG_FUNC(cellDaisy, _ZN4cell5Daisy21LFQueue2GetPopPointerEPNS0_8LFQueue2EPij); diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp b/rpcs3/Emu/Cell/Modules/cellDmux.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/cellDmux.cpp rename to rpcs3/Emu/Cell/Modules/cellDmux.cpp index 5a2cbf2135..0c755b197d 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp +++ b/rpcs3/Emu/Cell/Modules/cellDmux.cpp @@ -1,13 +1,12 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellPamf.h" #include "cellDmux.h" -extern Module<> cellDmux; +LOG_CHANNEL(cellDmux); PesHeader::PesHeader(DemuxerStream& stream) : pts(CODEC_TS_INVALID) @@ -80,7 +79,6 @@ PesHeader::PesHeader(DemuxerStream& stream) ElementaryStream::ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr cbFunc, u32 cbArg, u32 spec) : dmux(dmux) - , id(idm::get_last_id()) , memAddr(align(addr, 128)) , memSize(size - (addr - memAddr)) , fidMajor(fidMajor) @@ -112,8 +110,7 @@ bool ElementaryStream::is_full(u32 space) u32 first = 0; if (!entries.peek(first, 0, &dmux->is_closed) || !first) { - assert(!"es::is_full() error: entries.Peek() failed"); - return false; + throw std::runtime_error("entries.peek() failed" HERE); } else if (first >= put) { @@ -145,7 +142,7 @@ void ElementaryStream::push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool ra u32 addr; { std::lock_guard lock(m_mutex); - assert(!is_full(size)); + ASSERT(!is_full(size)); if (put + size + 128 > memAddr + memSize) { @@ -185,10 +182,8 @@ void ElementaryStream::push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool ra put_count++; } - if (!entries.push(addr, &dmux->is_closed)) - { - assert(!"es::push_au() error: entries.Push() failed"); - } + + ASSERT(entries.push(addr, &dmux->is_closed)); } void ElementaryStream::push(DemuxerStream& stream, u32 size) @@ -762,8 +757,9 @@ void dmuxOpen(u32 dmux_id) // TODO: call from the constructor dmux.is_finished = true; }; - dmux.dmuxCb->run(); - dmux.dmuxCb->exec(); + dmux.dmuxCb->cpu_init(); + dmux.dmuxCb->state -= cpu_state::stop; + dmux.dmuxCb->safe_notify(); } s32 cellDmuxQueryAttr(vm::cptr type, vm::ptr attr) @@ -872,7 +868,7 @@ s32 cellDmuxClose(u32 handle) std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } - idm::remove(dmux->dmuxCb->get_id()); + idm::remove(dmux->dmuxCb->id); idm::remove(handle); return CELL_OK; } @@ -1178,7 +1174,7 @@ s32 cellDmuxFlushEs(u32 esHandle) return CELL_OK; } -Module<> cellDmux("cellDmux", []() +DECLARE(ppu_module_manager::cellDmux)("cellDmux", []() { REG_FUNC(cellDmux, cellDmuxQueryAttr); REG_FUNC(cellDmux, cellDmuxQueryAttr2); diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.h b/rpcs3/Emu/Cell/Modules/cellDmux.h similarity index 99% rename from rpcs3/Emu/SysCalls/Modules/cellDmux.h rename to rpcs3/Emu/Cell/Modules/cellDmux.h index 407cdad56e..3341718e61 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.h +++ b/rpcs3/Emu/Cell/Modules/cellDmux.h @@ -405,8 +405,8 @@ public: u32 id; volatile bool is_finished; volatile bool is_closed; - std::atomic is_running; - std::atomic is_working; + atomic_t is_running; + atomic_t is_working; std::shared_ptr dmuxCb; @@ -440,7 +440,7 @@ public: ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr cbFunc, u32 cbArg, u32 spec); Demuxer* dmux; - const u32 id; + const u32 id{}; const u32 memAddr; const u32 memSize; const u32 fidMajor; diff --git a/rpcs3/Emu/SysCalls/Modules/cellFiber.cpp b/rpcs3/Emu/Cell/Modules/cellFiber.cpp similarity index 61% rename from rpcs3/Emu/SysCalls/Modules/cellFiber.cpp rename to rpcs3/Emu/Cell/Modules/cellFiber.cpp index 906b8d5184..ba744dc37a 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellFiber.cpp +++ b/rpcs3/Emu/Cell/Modules/cellFiber.cpp @@ -1,11 +1,10 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellFiber.h" -extern Module<> cellFiber; +LOG_CHANNEL(cellFiber); s32 _cellFiberPpuInitialize() { @@ -291,59 +290,59 @@ s32 cellFiberPpuUtilWorkerControlInitializeWithAttribute() return CELL_OK; } -Module<> cellFiber("cellFiber", []() +DECLARE(ppu_module_manager::cellFiber)("cellFiber", []() { - REG_FUNC(cellFiber, _cellFiberPpuInitialize, MFF_NO_RETURN); + REG_FUNC(cellFiber, _cellFiberPpuInitialize); - REG_FUNC(cellFiber, _cellFiberPpuSchedulerAttributeInitialize, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuInitializeScheduler, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuFinalizeScheduler, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuRunFibers, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuCheckFlags, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuHasRunnableFiber, MFF_NO_RETURN); + REG_FUNC(cellFiber, _cellFiberPpuSchedulerAttributeInitialize); + REG_FUNC(cellFiber, cellFiberPpuInitializeScheduler); + REG_FUNC(cellFiber, cellFiberPpuFinalizeScheduler); + REG_FUNC(cellFiber, cellFiberPpuRunFibers); + REG_FUNC(cellFiber, cellFiberPpuCheckFlags); + REG_FUNC(cellFiber, cellFiberPpuHasRunnableFiber); - REG_FUNC(cellFiber, _cellFiberPpuAttributeInitialize, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuCreateFiber, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuExit, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuYield, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuJoinFiber, MFF_NO_RETURN); + REG_FUNC(cellFiber, _cellFiberPpuAttributeInitialize); + REG_FUNC(cellFiber, cellFiberPpuCreateFiber); + REG_FUNC(cellFiber, cellFiberPpuExit); + REG_FUNC(cellFiber, cellFiberPpuYield); + REG_FUNC(cellFiber, cellFiberPpuJoinFiber); REG_FUNC(cellFiber, cellFiberPpuSelf); - REG_FUNC(cellFiber, cellFiberPpuSendSignal, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuWaitSignal, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuWaitFlag, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuGetScheduler, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuSetPriority, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuCheckStackLimit, MFF_NO_RETURN); + REG_FUNC(cellFiber, cellFiberPpuSendSignal); + REG_FUNC(cellFiber, cellFiberPpuWaitSignal); + REG_FUNC(cellFiber, cellFiberPpuWaitFlag); + REG_FUNC(cellFiber, cellFiberPpuGetScheduler); + REG_FUNC(cellFiber, cellFiberPpuSetPriority); + REG_FUNC(cellFiber, cellFiberPpuCheckStackLimit); - REG_FUNC(cellFiber, _cellFiberPpuContextAttributeInitialize, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuContextInitialize, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuContextFinalize, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuContextRun, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuContextSwitch, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuContextSelf, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuContextReturnToThread, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuContextCheckStackLimit, MFF_NO_RETURN); + REG_FUNC(cellFiber, _cellFiberPpuContextAttributeInitialize); + REG_FUNC(cellFiber, cellFiberPpuContextInitialize); + REG_FUNC(cellFiber, cellFiberPpuContextFinalize); + REG_FUNC(cellFiber, cellFiberPpuContextRun); + REG_FUNC(cellFiber, cellFiberPpuContextSwitch); + REG_FUNC(cellFiber, cellFiberPpuContextSelf); + REG_FUNC(cellFiber, cellFiberPpuContextReturnToThread); + REG_FUNC(cellFiber, cellFiberPpuContextCheckStackLimit); - REG_FUNC(cellFiber, cellFiberPpuContextRunScheduler, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuContextEnterScheduler, MFF_NO_RETURN); + REG_FUNC(cellFiber, cellFiberPpuContextRunScheduler); + REG_FUNC(cellFiber, cellFiberPpuContextEnterScheduler); - REG_FUNC(cellFiber, cellFiberPpuSchedulerTraceInitialize, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuSchedulerTraceFinalize, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuSchedulerTraceStart, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuSchedulerTraceStop, MFF_NO_RETURN); + REG_FUNC(cellFiber, cellFiberPpuSchedulerTraceInitialize); + REG_FUNC(cellFiber, cellFiberPpuSchedulerTraceFinalize); + REG_FUNC(cellFiber, cellFiberPpuSchedulerTraceStart); + REG_FUNC(cellFiber, cellFiberPpuSchedulerTraceStop); - REG_FUNC(cellFiber, _cellFiberPpuUtilWorkerControlAttributeInitialize, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlRunFibers, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlInitialize, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlSetPollingMode, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlJoinFiber, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlDisconnectEventQueue, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlSendSignal, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlConnectEventQueueToSpurs, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlFinalize, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlWakeup, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlCreateFiber, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlShutdown, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlCheckFlags, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlInitializeWithAttribute, MFF_NO_RETURN); + REG_FUNC(cellFiber, _cellFiberPpuUtilWorkerControlAttributeInitialize); + REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlRunFibers); + REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlInitialize); + REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlSetPollingMode); + REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlJoinFiber); + REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlDisconnectEventQueue); + REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlSendSignal); + REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlConnectEventQueueToSpurs); + REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlFinalize); + REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlWakeup); + REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlCreateFiber); + REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlShutdown); + REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlCheckFlags); + REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlInitializeWithAttribute); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellFiber.h b/rpcs3/Emu/Cell/Modules/cellFiber.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellFiber.h rename to rpcs3/Emu/Cell/Modules/cellFiber.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellFont.cpp b/rpcs3/Emu/Cell/Modules/cellFont.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/cellFont.cpp rename to rpcs3/Emu/Cell/Modules/cellFont.cpp index adae60dc89..0d3f10c2a5 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellFont.cpp +++ b/rpcs3/Emu/Cell/Modules/cellFont.cpp @@ -1,15 +1,14 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/System.h" +#include "Emu/Cell/PPUModule.h" // Defines STB_TRUETYPE_IMPLEMENTATION *once* before including stb_truetype.h (as noted in stb_truetype.h's comments) #define STB_TRUETYPE_IMPLEMENTATION #include -#include "Emu/FS/vfsFile.h" #include "cellFont.h" -extern Module<> cellFont; +LOG_CHANNEL(cellFont); // Functions s32 cellFontInitializeWithRevision(u64 revisionFlags, vm::ptr config) @@ -68,15 +67,15 @@ s32 cellFontOpenFontFile(vm::ptr library, vm::cptr fontPa { cellFont.warning("cellFontOpenFontFile(library=*0x%x, fontPath=*0x%x, subNum=%d, uniqueId=%d, font=*0x%x)", library, fontPath, subNum, uniqueId, font); - vfsFile f(fontPath.get_ptr()); - if (!f.IsOpened()) + fs::file f(vfs::get(fontPath.get_ptr())); + if (!f) { return CELL_FONT_ERROR_FONT_OPEN_FAILED; } - u32 fileSize = (u32)f.GetSize(); + u32 fileSize = ::size32(f); u32 bufferAddr = vm::alloc(fileSize, vm::main); // Freed in cellFontCloseFont - f.Read(vm::base(bufferAddr), fileSize); + f.read(vm::base(bufferAddr), fileSize); s32 ret = cellFontOpenFontMemory(library, bufferAddr, fileSize, subNum, uniqueId, font); font->origin = CELL_FONT_OPEN_FONT_FILE; @@ -742,7 +741,7 @@ s32 cellFontGraphicsGetLineRGBA() } -Module<> cellFont("cellFont", []() +DECLARE(ppu_module_manager::cellFont)("cellFont", []() { REG_FUNC(cellFont, cellFontSetFontsetOpenMode); REG_FUNC(cellFont, cellFontSetFontOpenMode); diff --git a/rpcs3/Emu/SysCalls/Modules/cellFont.h b/rpcs3/Emu/Cell/Modules/cellFont.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellFont.h rename to rpcs3/Emu/Cell/Modules/cellFont.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellFontFT.cpp b/rpcs3/Emu/Cell/Modules/cellFontFT.cpp similarity index 85% rename from rpcs3/Emu/SysCalls/Modules/cellFontFT.cpp rename to rpcs3/Emu/Cell/Modules/cellFontFT.cpp index 5afe132d5e..5821d440c6 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellFontFT.cpp +++ b/rpcs3/Emu/Cell/Modules/cellFontFT.cpp @@ -1,10 +1,9 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellFontFT.h" -extern Module<> cellFontFT; +LOG_CHANNEL(cellFontFT); s32 cellFontInitLibraryFreeTypeWithRevision(u64 revisionFlags, vm::ptr config, vm::pptr lib) { @@ -27,7 +26,7 @@ s32 cellFontFTGetInitializedRevisionFlags() return CELL_OK; } -Module<> cellFontFT("cellFontFT", []() +DECLARE(ppu_module_manager::cellFontFT)("cellFontFT", []() { REG_FUNC(cellFontFT, cellFontInitLibraryFreeTypeWithRevision); REG_FUNC(cellFontFT, cellFontFTGetRevisionFlags); diff --git a/rpcs3/Emu/SysCalls/Modules/cellFontFT.h b/rpcs3/Emu/Cell/Modules/cellFontFT.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellFontFT.h rename to rpcs3/Emu/Cell/Modules/cellFontFT.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellFs.cpp b/rpcs3/Emu/Cell/Modules/cellFs.cpp similarity index 79% rename from rpcs3/Emu/SysCalls/Modules/cellFs.cpp rename to rpcs3/Emu/Cell/Modules/cellFs.cpp index 37154ae03b..ee85879eff 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellFs.cpp +++ b/rpcs3/Emu/Cell/Modules/cellFs.cpp @@ -1,18 +1,12 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/SysCalls/Callback.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsFile.h" -#include "Emu/FS/vfsDir.h" - -#include "Emu/SysCalls/lv2/sys_fs.h" +#include "Emu/Cell/lv2/sys_fs.h" #include "cellFs.h" -extern Module<> cellFs; +LOG_CHANNEL(cellFs); s32 cellFsOpen(vm::cptr path, s32 flags, vm::ptr fd, vm::cptr arg, u64 size) { @@ -222,20 +216,22 @@ s32 cellFsGetDirectoryEntries(u32 fd, vm::ptr entries, u32 for (; count < entries_size; count++) { - if (const auto info = directory->dir->Read()) + fs::dir_entry info; + + if (directory->dir.read(info)) { - entries[count].attribute.mode = info->flags & DirEntry_TypeDir ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666; + entries[count].attribute.mode = info.is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666; entries[count].attribute.uid = 1; // ??? entries[count].attribute.gid = 1; // ??? - entries[count].attribute.atime = info->access_time; - entries[count].attribute.mtime = info->modify_time; - entries[count].attribute.ctime = info->create_time; - entries[count].attribute.size = info->size; + entries[count].attribute.atime = info.atime; + entries[count].attribute.mtime = info.mtime; + entries[count].attribute.ctime = info.ctime; + entries[count].attribute.size = info.size; entries[count].attribute.blksize = 4096; // ??? - entries[count].entry_name.d_type = info->flags & DirEntry_TypeFile ? CELL_FS_TYPE_REGULAR : CELL_FS_TYPE_DIRECTORY; - entries[count].entry_name.d_namlen = u8(std::min(info->name.length(), CELL_FS_MAX_FS_FILE_NAME_LENGTH)); - strcpy_trunc(entries[count].entry_name.d_name, info->name); + entries[count].entry_name.d_type = info.is_directory ? CELL_FS_TYPE_DIRECTORY : CELL_FS_TYPE_REGULAR; + entries[count].entry_name.d_namlen = u8(std::min(info.name.size(), CELL_FS_MAX_FS_FILE_NAME_LENGTH)); + strcpy_trunc(entries[count].entry_name.d_name, info.name); } else { @@ -263,13 +259,11 @@ s32 cellFsReadWithOffset(u32 fd, u64 offset, vm::ptr buf, u64 buffer_size, std::lock_guard lock(file->mutex); - const auto old_position = file->file->Tell(); + const auto old_pos = file->file.pos(); file->file.seek(offset); - CHECK_ASSERTION(file->file->Seek(offset) != -1); + const auto read = file->file.read(buf.get_ptr(), buffer_size); - const auto read = file->file->Read(buf.get_ptr(), buffer_size); - - CHECK_ASSERTION(file->file->Seek(old_position) != -1); + ASSERT(file->file.seek(old_pos) == old_pos); if (nread) { @@ -294,13 +288,11 @@ s32 cellFsWriteWithOffset(u32 fd, u64 offset, vm::cptr buf, u64 data_size, std::lock_guard lock(file->mutex); - const auto old_position = file->file->Tell(); + const auto old_pos = file->file.pos(); file->file.seek(offset); - CHECK_ASSERTION(file->file->Seek(offset) != -1); + const auto written = file->file.write(buf.get_ptr(), data_size); - const auto written = file->file->Write(buf.get_ptr(), data_size); - - CHECK_ASSERTION(file->file->Seek(old_position) != -1); + ASSERT(file->file.seek(old_pos) == old_pos); if (nwrite) { @@ -489,12 +481,12 @@ s32 cellFsStReadStart(u32 fd, u64 offset, u64 size) } } - offset = std::min(file->file->GetSize(), offset); - size = std::min(file->file->GetSize() - offset, size); + offset = std::min(file->file.size(), offset); + size = std::min(file->file.size() - offset, size); file->st_read_size = size; - file->st_thread = thread_ctrl::spawn(PURE_EXPR("FS ST Thread"s), [=]() + file->st_thread = thread_ctrl::spawn("FS ST Thread", [=]() { std::unique_lock lock(file->mutex); @@ -504,13 +496,13 @@ s32 cellFsStReadStart(u32 fd, u64 offset, u64 size) if (file->st_total_read - file->st_copied <= file->st_ringbuf_size - file->st_block_size && file->st_total_read < file->st_read_size) { // get buffer position - const u32 position = VM_CAST(file->st_buffer + file->st_total_read % file->st_ringbuf_size); + const u32 position = vm::cast(file->st_buffer + file->st_total_read % file->st_ringbuf_size, HERE); // read data - auto old = file->file->Tell(); - CHECK_ASSERTION(file->file->Seek(offset + file->st_total_read) != -1); - auto res = file->file->Read(vm::base(position), file->st_block_size); - CHECK_ASSERTION(file->file->Seek(old) != -1); + auto old = file->file.pos(); + file->file.seek(offset + file->st_total_read); + auto res = file->file.read(vm::base(position), file->st_block_size); + ASSERT(file->file.seek(old) == old); // notify file->st_total_read += res; @@ -594,7 +586,7 @@ s32 cellFsStRead(u32 fd, vm::ptr buf, u64 size, vm::ptr rsize) } const u64 copied = file->st_copied; - const u32 position = VM_CAST(file->st_buffer + copied % file->st_ringbuf_size); + const u32 position = vm::cast(file->st_buffer + copied % file->st_ringbuf_size, HERE); const u64 total_read = file->st_total_read; const u64 copy_size = (*rsize = std::min(size, total_read - copied)); // write rsize @@ -628,7 +620,7 @@ s32 cellFsStReadGetCurrentAddr(u32 fd, vm::ptr addr, vm::ptr size) } const u64 copied = file->st_copied; - const u32 position = VM_CAST(file->st_buffer + copied % file->st_ringbuf_size); + const u32 position = vm::cast(file->st_buffer + copied % file->st_ringbuf_size, HERE); const u64 total_read = file->st_total_read; if ((*size = std::min(file->st_ringbuf_size - (position - file->st_buffer), total_read - copied))) @@ -752,23 +744,23 @@ bool sdata_check(u32 version, u32 flags, u64 filesizeInput, u64 filesizeTmp) s32 sdata_unpack(const std::string& packed_file, const std::string& unpacked_file) { - std::shared_ptr packed_stream(Emu.GetVFS().OpenFile(packed_file, fom::read)); - std::shared_ptr unpacked_stream(Emu.GetVFS().OpenFile(unpacked_file, fom::rewrite)); + fs::file packed_stream(vfs::get(packed_file)); + fs::file unpacked_stream(vfs::get(unpacked_file), fs::rewrite); - if (!packed_stream || !packed_stream->IsOpened()) + if (!packed_stream) { - cellFs.error("File '%s' not found!", packed_file.c_str()); + cellFs.error("File '%s' not found!", packed_file); return CELL_ENOENT; } - if (!unpacked_stream || !unpacked_stream->IsOpened()) + if (!unpacked_stream) { - cellFs.error("File '%s' couldn't be created!", unpacked_file.c_str()); + cellFs.error("File '%s' couldn't be created!", unpacked_file); return CELL_ENOENT; } char buffer[10200]; - packed_stream->Read(buffer, 256); + packed_stream.read(buffer, 256); u32 format = *(be_t*)&buffer[0]; if (format != 0x4E504400) // "NPD\x00" { @@ -780,7 +772,7 @@ s32 sdata_unpack(const std::string& packed_file, const std::string& unpacked_fil u32 flags = *(be_t*)&buffer[0x80]; u32 blockSize = *(be_t*)&buffer[0x84]; u64 filesizeOutput = *(be_t*)&buffer[0x88]; - u64 filesizeInput = packed_stream->GetSize(); + u64 filesizeInput = packed_stream.size(); u32 blockCount = (u32)((filesizeOutput + blockSize - 1) / blockSize); // SDATA file is compressed @@ -804,20 +796,18 @@ s32 sdata_unpack(const std::string& packed_file, const std::string& unpacked_fil if (flags & 0x20) { - CHECK_ASSERTION(packed_stream->Seek(0x100) != -1); + ASSERT(packed_stream.seek(0x100) == 0x100); } else { - CHECK_ASSERTION(packed_stream->Seek(startOffset) != -1); + ASSERT(packed_stream.seek(startOffset) == startOffset); } for (u32 i = 0; i < blockCount; i++) { if (flags & 0x20) { - s64 cur; - CHECK_ASSERTION((cur = packed_stream->Tell()) != -1); - CHECK_ASSERTION(packed_stream->Seek(cur + t1) != -1); + packed_stream.seek(t1, fs::seek_cur); } if (!(blockCount - i - 1)) @@ -825,8 +815,8 @@ s32 sdata_unpack(const std::string& packed_file, const std::string& unpacked_fil blockSize = (u32)(filesizeOutput - i * blockSize); } - packed_stream->Read(buffer + 256, blockSize); - unpacked_stream->Write(buffer + 256, blockSize); + packed_stream.read(buffer + 256, blockSize); + unpacked_stream.write(buffer + 256, blockSize); } } @@ -891,13 +881,13 @@ void fsAio(vm::ptr aio, bool write, s32 xid, fs_aio_cb_t func) { std::lock_guard lock(file->mutex); - const auto old_position = file->file->Tell(); + const auto old_pos = file->file.pos(); file->file.seek(aio->offset); - CHECK_ASSERTION(file->file->Seek(aio->offset) != -1); + result = write + ? file->file.write(aio->buf.get_ptr(), aio->size) + : file->file.read(aio->buf.get_ptr(), aio->size); - result = write ? file->file->Write(aio->buf.get_ptr(), aio->size) : file->file->Read(aio->buf.get_ptr(), aio->size); - - CHECK_ASSERTION(file->file->Seek(old_position) != -1); + ASSERT(file->file.seek(old_pos) == old_pos); } // should be executed directly by FS AIO thread @@ -927,7 +917,7 @@ s32 cellFsAioFinish(vm::cptr mount_point) return CELL_OK; } -std::atomic g_fs_aio_id; +atomic_t g_fs_aio_id; s32 cellFsAioRead(vm::ptr aio, vm::ptr id, fs_aio_cb_t func) { @@ -937,7 +927,7 @@ s32 cellFsAioRead(vm::ptr aio, vm::ptr id, fs_aio_cb_t func) const s32 xid = (*id = ++g_fs_aio_id); - thread_ctrl::spawn(PURE_EXPR("FS AIO Read Thread"s), COPY_EXPR(fsAio(aio, false, xid, func))); + thread_ctrl::spawn("FS AIO Read Thread", COPY_EXPR(fsAio(aio, false, xid, func))); return CELL_OK; } @@ -950,7 +940,7 @@ s32 cellFsAioWrite(vm::ptr aio, vm::ptr id, fs_aio_cb_t func) const s32 xid = (*id = ++g_fs_aio_id); - thread_ctrl::spawn(PURE_EXPR("FS AIO Write Thread"s), COPY_EXPR(fsAio(aio, true, xid, func))); + thread_ctrl::spawn("FS AIO Write Thread", COPY_EXPR(fsAio(aio, true, xid, func))); return CELL_OK; } @@ -1051,66 +1041,64 @@ s32 cellFsUnregisterL10nCallbacks() } -Module<> cellFs("cellFs", []() +DECLARE(ppu_module_manager::cellFs)("sys_fs", []() { - g_fs_aio_id = 1; - - REG_FUNC(cellFs, cellFsOpen); - REG_FUNC(cellFs, cellFsSdataOpen); - REG_FUNC(cellFs, cellFsSdataOpenByFd); - REG_FUNC(cellFs, cellFsRead, MFF_PERFECT); - REG_FUNC(cellFs, cellFsWrite, MFF_PERFECT); - REG_FUNC(cellFs, cellFsClose, MFF_PERFECT); - REG_FUNC(cellFs, cellFsOpendir); - REG_FUNC(cellFs, cellFsReaddir, MFF_PERFECT); - REG_FUNC(cellFs, cellFsClosedir, MFF_PERFECT); - REG_FUNC(cellFs, cellFsStat); - REG_FUNC(cellFs, cellFsFstat, MFF_PERFECT); - REG_FUNC(cellFs, cellFsMkdir); - REG_FUNC(cellFs, cellFsRename); - REG_FUNC(cellFs, cellFsChmod); - REG_FUNC(cellFs, cellFsFsync); - REG_FUNC(cellFs, cellFsRmdir); - REG_FUNC(cellFs, cellFsUnlink); - REG_FUNC(cellFs, cellFsLseek, MFF_PERFECT); - REG_FUNC(cellFs, cellFsFtruncate, MFF_PERFECT); - REG_FUNC(cellFs, cellFsTruncate); - REG_FUNC(cellFs, cellFsFGetBlockSize, MFF_PERFECT); - REG_FUNC(cellFs, cellFsAioInit); - REG_FUNC(cellFs, cellFsAioFinish); - REG_FUNC(cellFs, cellFsAioRead); - REG_FUNC(cellFs, cellFsAioWrite); - REG_FUNC(cellFs, cellFsAioCancel); - REG_FUNC(cellFs, cellFsGetBlockSize); - REG_FUNC(cellFs, cellFsGetFreeSize); - REG_FUNC(cellFs, cellFsReadWithOffset); - REG_FUNC(cellFs, cellFsWriteWithOffset); - REG_FUNC(cellFs, cellFsGetDirectoryEntries); - REG_FUNC(cellFs, cellFsStReadInit); - REG_FUNC(cellFs, cellFsStReadFinish); - REG_FUNC(cellFs, cellFsStReadGetRingBuf); - REG_FUNC(cellFs, cellFsStReadGetStatus); - REG_FUNC(cellFs, cellFsStReadGetRegid); - REG_FUNC(cellFs, cellFsStReadStart); - REG_FUNC(cellFs, cellFsStReadStop); - REG_FUNC(cellFs, cellFsStRead); - REG_FUNC(cellFs, cellFsStReadGetCurrentAddr); - REG_FUNC(cellFs, cellFsStReadPutCurrentAddr); - REG_FUNC(cellFs, cellFsStReadWait); - REG_FUNC(cellFs, cellFsStReadWaitCallback); - REG_FUNC(cellFs, cellFsSetDefaultContainer); - REG_FUNC(cellFs, cellFsSetIoBufferFromDefaultContainer); - REG_FUNC(cellFs, cellFsUtime); - REG_FUNC(cellFs, cellFsArcadeHddSerialNumber); - REG_FUNC(cellFs, cellFsAllocateFileAreaWithInitialData); - REG_FUNC(cellFs, cellFsAllocateFileAreaByFdWithoutZeroFill); - REG_FUNC(cellFs, cellFsSetIoBuffer); - REG_FUNC(cellFs, cellFsAllocateFileAreaByFdWithInitialData); - REG_FUNC(cellFs, cellFsTruncate2); - REG_FUNC(cellFs, cellFsChangeFileSizeWithoutAllocation); - REG_FUNC(cellFs, cellFsAllocateFileAreaWithoutZeroFill); - REG_FUNC(cellFs, cellFsChangeFileSizeByFdWithoutAllocation); - REG_FUNC(cellFs, cellFsSetDiscReadRetrySetting); - REG_FUNC(cellFs, cellFsRegisterConversionCallback); - REG_FUNC(cellFs, cellFsUnregisterL10nCallbacks); + REG_FUNC(sys_fs, cellFsOpen); + REG_FUNC(sys_fs, cellFsSdataOpen); + REG_FUNC(sys_fs, cellFsSdataOpenByFd); + REG_FUNC(sys_fs, cellFsRead, MFF_PERFECT); + REG_FUNC(sys_fs, cellFsWrite, MFF_PERFECT); + REG_FUNC(sys_fs, cellFsClose, MFF_PERFECT); + REG_FUNC(sys_fs, cellFsOpendir); + REG_FUNC(sys_fs, cellFsReaddir, MFF_PERFECT); + REG_FUNC(sys_fs, cellFsClosedir, MFF_PERFECT); + REG_FUNC(sys_fs, cellFsStat); + REG_FUNC(sys_fs, cellFsFstat, MFF_PERFECT); + REG_FUNC(sys_fs, cellFsMkdir); + REG_FUNC(sys_fs, cellFsRename); + REG_FUNC(sys_fs, cellFsChmod); + REG_FUNC(sys_fs, cellFsFsync); + REG_FUNC(sys_fs, cellFsRmdir); + REG_FUNC(sys_fs, cellFsUnlink); + REG_FUNC(sys_fs, cellFsLseek, MFF_PERFECT); + REG_FUNC(sys_fs, cellFsFtruncate, MFF_PERFECT); + REG_FUNC(sys_fs, cellFsTruncate); + REG_FUNC(sys_fs, cellFsFGetBlockSize, MFF_PERFECT); + REG_FUNC(sys_fs, cellFsAioInit); + REG_FUNC(sys_fs, cellFsAioFinish); + REG_FUNC(sys_fs, cellFsAioRead); + REG_FUNC(sys_fs, cellFsAioWrite); + REG_FUNC(sys_fs, cellFsAioCancel); + REG_FUNC(sys_fs, cellFsGetBlockSize); + REG_FUNC(sys_fs, cellFsGetFreeSize); + REG_FUNC(sys_fs, cellFsReadWithOffset); + REG_FUNC(sys_fs, cellFsWriteWithOffset); + REG_FUNC(sys_fs, cellFsGetDirectoryEntries); + REG_FUNC(sys_fs, cellFsStReadInit); + REG_FUNC(sys_fs, cellFsStReadFinish); + REG_FUNC(sys_fs, cellFsStReadGetRingBuf); + REG_FUNC(sys_fs, cellFsStReadGetStatus); + REG_FUNC(sys_fs, cellFsStReadGetRegid); + REG_FUNC(sys_fs, cellFsStReadStart); + REG_FUNC(sys_fs, cellFsStReadStop); + REG_FUNC(sys_fs, cellFsStRead); + REG_FUNC(sys_fs, cellFsStReadGetCurrentAddr); + REG_FUNC(sys_fs, cellFsStReadPutCurrentAddr); + REG_FUNC(sys_fs, cellFsStReadWait); + REG_FUNC(sys_fs, cellFsStReadWaitCallback); + REG_FUNC(sys_fs, cellFsSetDefaultContainer); + REG_FUNC(sys_fs, cellFsSetIoBufferFromDefaultContainer); + REG_FUNC(sys_fs, cellFsUtime); + REG_FUNC(sys_fs, cellFsArcadeHddSerialNumber); + REG_FUNC(sys_fs, cellFsAllocateFileAreaWithInitialData); + REG_FUNC(sys_fs, cellFsAllocateFileAreaByFdWithoutZeroFill); + REG_FUNC(sys_fs, cellFsSetIoBuffer); + REG_FUNC(sys_fs, cellFsAllocateFileAreaByFdWithInitialData); + REG_FUNC(sys_fs, cellFsTruncate2); + REG_FUNC(sys_fs, cellFsChangeFileSizeWithoutAllocation); + REG_FUNC(sys_fs, cellFsAllocateFileAreaWithoutZeroFill); + REG_FUNC(sys_fs, cellFsChangeFileSizeByFdWithoutAllocation); + REG_FUNC(sys_fs, cellFsSetDiscReadRetrySetting); + REG_FUNC(sys_fs, cellFsRegisterConversionCallback); + REG_FUNC(sys_fs, cellFsUnregisterL10nCallbacks); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellFs.h b/rpcs3/Emu/Cell/Modules/cellFs.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellFs.h rename to rpcs3/Emu/Cell/Modules/cellFs.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellGame.cpp b/rpcs3/Emu/Cell/Modules/cellGame.cpp similarity index 83% rename from rpcs3/Emu/SysCalls/Modules/cellGame.cpp rename to rpcs3/Emu/Cell/Modules/cellGame.cpp index 08a535e449..0230547d47 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGame.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGame.cpp @@ -1,17 +1,15 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsFile.h" -#include "Loader/PSF.h" #include "cellSysutil.h" #include "cellMsgDialog.h" #include "cellGame.h" -extern Module<> cellGame; +#include + +LOG_CHANNEL(cellGame); // Normal content directory (if is_temporary is not involved): // contentInfo = dir @@ -40,7 +38,7 @@ struct content_permission_t final { if (is_temporary) { - Emu.GetVFS().DeleteAll("/dev_hdd1/game/" + dir); + fs::remove_all(vfs::get("/dev_hdd1/game/" + dir)); } } }; @@ -56,7 +54,6 @@ s32 cellHddGameCheck(PPUThread& ppu, u32 version, vm::cptr dirName, u32 er return CELL_HDDGAME_ERROR_PARAM; } - vm::var param; vm::var result; vm::var get; vm::var set; @@ -71,14 +68,17 @@ s32 cellHddGameCheck(PPUThread& ppu, u32 version, vm::cptr dirName, u32 er strcpy_trunc(get->contentInfoPath, "/dev_hdd0/game/" + dir); strcpy_trunc(get->hddGamePath, "/dev_hdd0/game/" + dir + "/USRDIR"); - if (!Emu.GetVFS().ExistsDir("/dev_hdd0/game/" + dir)) + const std::string& local_dir = vfs::get("/dev_hdd0/game/" + dir); + + if (!fs::is_dir(local_dir)) { get->isNewData = CELL_HDDGAME_ISNEWDATA_NODIR; + get->getParam = {}; } else { // TODO: Is cellHddGameCheck really responsible for writing the information in get->getParam ? (If not, delete this else) - const auto& psf = psf::load(vfsFile("/dev_hdd0/game/" + dir + "/PARAM.SFO").VRead()); + const auto& psf = psf::load_object(fs::file(local_dir +"/PARAM.SFO")); get->getParam.parentalLevel = psf.at("PARENTAL_LEVEL").as_integer(); get->getParam.attribute = psf.at("ATTRIBUTE").as_integer(); @@ -159,16 +159,9 @@ s32 cellGameBootCheck(vm::ptr type, vm::ptr attributes, vm::ptrsysSizeKB = 0; } - const auto& psf = psf::load(vfsFile("/app_home/../PARAM.SFO").VRead()); + // According to testing (in debug mode) cellGameBootCheck doesn't return an error code, when PARAM.SFO doesn't exist. + const std::string& category = psf::get_string(Emu.GetPSF(), "CATEGORY"); - if (psf.empty()) - { - // According to testing (in debug mode) cellGameBootCheck doesn't return an error code, when PARAM.SFO doesn't exist. - cellGame.error("cellGameBootCheck(): Cannot read PARAM.SFO."); - return CELL_GAME_RET_OK; - } - - const std::string& category = psf.at("CATEGORY").as_string(); if (category == "DG") { *type = CELL_GAME_GAMETYPE_DISC; @@ -182,22 +175,20 @@ s32 cellGameBootCheck(vm::ptr type, vm::ptr attributes, vm::ptr("/dev_hdd0/game/" + titleId, false)) + if (!fxm::make("/dev_hdd0/game/" + Emu.GetTitleID(), false)) { return CELL_GAME_ERROR_BUSY; } } else if (category == "GD") { - const std::string& titleId = psf.at("TITLE_ID").as_string(); *type = CELL_GAME_GAMETYPE_DISC; *attributes = CELL_GAME_ATTRIBUTE_PATCH; // TODO - if (dirName) strcpy_trunc(*dirName, titleId); // ??? + if (dirName) strcpy_trunc(*dirName, Emu.GetTitleID()); // ??? if (!fxm::make("/dev_bdvd/PS3_GAME", false)) { @@ -206,7 +197,7 @@ s32 cellGameBootCheck(vm::ptr type, vm::ptr attributes, vm::ptr size, vm::ptr reserved size->sysSizeKB = 0; } - const auto& psf = psf::load(vfsFile("/app_home/../PARAM.SFO").VRead()); - - if (psf.empty() || psf.at("CATEGORY").as_string() != "GD") + if (psf::get_string(Emu.GetPSF(), "CATEGORY") != "GD") { cellGame.error("cellGamePatchCheck(): CELL_GAME_ERROR_NOTPATCH"); return CELL_GAME_ERROR_NOTPATCH; } - if (!fxm::make("/dev_hdd0/game/" + psf.at("TITLE_ID").as_string(), false)) + if (!fxm::make("/dev_hdd0/game/" + Emu.GetTitleID(), false)) { return CELL_GAME_ERROR_BUSY; } @@ -262,35 +251,18 @@ s32 cellGameDataCheck(u32 type, vm::cptr dirName, vm::ptrsysSizeKB = 0; } - if (type == CELL_GAME_GAMETYPE_DISC) + // TODO: not sure what should be checked there + const std::string& dir = type == CELL_GAME_GAMETYPE_DISC ? "/dev_bdvd/PS3_GAME"s : "/dev_hdd0/game/"s + dirName.get_ptr(); + + if (!fs::is_dir(vfs::get(dir))) { - // TODO: not sure what should be checked there - - if (!Emu.GetVFS().ExistsDir("/dev_bdvd/PS3_GAME")) - { - cellGame.warning("cellGameDataCheck(): /dev_bdvd/PS3_GAME not found"); - return CELL_GAME_RET_NONE; - } - - if (!fxm::make("/dev_bdvd/PS3_GAME", false)) - { - return CELL_GAME_ERROR_BUSY; - } + cellGame.warning("cellGameDataCheck(): '%s' directory not found", dir.c_str()); + return CELL_GAME_RET_NONE; } - else + + if (!fxm::make(dir, false)) { - const std::string dir = "/dev_hdd0/game/"s + dirName.get_ptr(); - - if (!Emu.GetVFS().ExistsDir(dir)) - { - cellGame.warning("cellGameDataCheck(): '%s' directory not found", dir.c_str()); - return CELL_GAME_RET_NONE; - } - - if (!fxm::make(dir, false)) - { - return CELL_GAME_ERROR_BUSY; - } + return CELL_GAME_ERROR_BUSY; } return CELL_GAME_RET_OK; @@ -314,19 +286,21 @@ s32 cellGameContentPermit(vm::ptr contentInfoPath, vm: if (path_set->is_temporary) { - const std::string dir = "/dev_hdd0/game/" + path_set->dir; + const std::string& dir = "/dev_hdd0/game/" + path_set->dir; - // make temporary directory persistent - if (Emu.GetVFS().Rename("/dev_hdd1/game/" + path_set->dir, dir)) + // Make temporary directory persistent + fs::remove_all(vfs::get(dir)); + + if (fs::rename(vfs::get("/dev_hdd1/game/" + path_set->dir), vfs::get(dir))) { - cellGame.success("cellGameContentPermit(): '%s' directory created", dir); + cellGame.success("cellGameContentPermit(): created directory %s", dir); } else { - throw EXCEPTION("Cannot create gamedata directory"); + throw fmt::exception("cellGameContentPermit(): failed to rename to %s", dir); } - // prevent deleting directory + // Disable deletion path_set->is_temporary = false; strcpy_trunc(*contentInfoPath, dir); @@ -353,17 +327,15 @@ s32 cellGameDataCheckCreate2(PPUThread& ppu, u32 version, vm::cptr dirName // TODO: output errors (errDialog) - const std::string dir = "/dev_hdd0/game/"s + dirName.get_ptr(); + const std::string& dir = "/dev_hdd0/game/"s + dirName.get_ptr(); - if (!Emu.GetVFS().ExistsDir(dir)) + if (!fs::is_dir(vfs::get(dir))) { - cellGame.todo("cellGameDataCheckCreate2(): creating directory '%s'", dir.c_str()); + cellGame.todo("cellGameDataCheckCreate2(): should create directory %s", dir); // TODO: create data return CELL_GAMEDATA_RET_OK; } - const auto& psf = psf::load(vfsFile("/app_home/../PARAM.SFO").VRead()); - vm::var cbResult; vm::var cbGet; vm::var cbSet; @@ -385,10 +357,10 @@ s32 cellGameDataCheckCreate2(PPUThread& ppu, u32 version, vm::cptr dirName cbGet->sysSizeKB = 0; cbGet->getParam.attribute = CELL_GAMEDATA_ATTR_NORMAL; - cbGet->getParam.parentalLevel = psf.at("PARENTAL_LEVEL").as_integer(); - strcpy_trunc(cbGet->getParam.dataVersion, psf.at("APP_VER").as_string()); - strcpy_trunc(cbGet->getParam.titleId, psf.at("TITLE_ID").as_string()); - strcpy_trunc(cbGet->getParam.title, psf.at("TITLE").as_string()); + cbGet->getParam.parentalLevel = Emu.GetPSF().at("PARENTAL_LEVEL").as_integer(); + strcpy_trunc(cbGet->getParam.dataVersion, Emu.GetPSF().at("APP_VER").as_string()); + strcpy_trunc(cbGet->getParam.titleId, Emu.GetPSF().at("TITLE_ID").as_string()); + strcpy_trunc(cbGet->getParam.title, Emu.GetPSF().at("TITLE").as_string()); // TODO: write lang titles funcStat(ppu, cbResult, cbGet, cbSet); @@ -446,15 +418,15 @@ s32 cellGameCreateGameData(vm::ptr init, vm::ptr value) { cellGame.warning("cellGameGetParamInt(id=%d, value=*0x%x)", id, value); - const auto& psf = psf::load(vfsFile("/app_home/../PARAM.SFO").VRead()); - std::string key; switch(id) @@ -498,7 +468,7 @@ s32 cellGameGetParamInt(u32 id, vm::ptr value) return CELL_GAME_ERROR_INVALID_ID; } - *value = psf.at(key).as_integer(); + *value = Emu.GetPSF().at(key).as_integer(); return CELL_OK; } @@ -506,9 +476,8 @@ s32 cellGameGetParamString(u32 id, vm::ptr buf, u32 bufsize) { cellGame.warning("cellGameGetParamString(id=%d, buf=*0x%x, bufsize=%d)", id, buf, bufsize); - const auto& psf = psf::load(vfsFile("/app_home/../PARAM.SFO").VRead()); - std::string key; + switch(id) { case CELL_GAME_PARAMID_TITLE: key = "TITLE"; break; // TODO: Is this value correct? @@ -542,7 +511,7 @@ s32 cellGameGetParamString(u32 id, vm::ptr buf, u32 bufsize) return CELL_GAME_ERROR_INVALID_ID; } - const std::string& value = psf.at(key).as_string().substr(0, bufsize - 1); + const std::string& value = Emu.GetPSF().at(key).as_string().substr(0, bufsize - 1); std::copy_n(value.c_str(), value.size() + 1, buf.get_ptr()); @@ -666,8 +635,6 @@ s32 cellGameUnregisterDiscChangeCallback() void cellSysutil_GameData_init() { - extern Module<> cellSysutil; - REG_FUNC(cellSysutil, cellHddGameCheck); REG_FUNC(cellSysutil, cellHddGameCheck2); REG_FUNC(cellSysutil, cellHddGameGetSizeKB); @@ -688,7 +655,7 @@ void cellSysutil_GameData_init() REG_FUNC(cellSysutil, cellGameUnregisterDiscChangeCallback); } -Module<> cellGame("cellGame", []() +DECLARE(ppu_module_manager::cellGame)("cellGame", []() { REG_FUNC(cellGame, cellGameBootCheck); REG_FUNC(cellGame, cellGamePatchCheck); diff --git a/rpcs3/Emu/SysCalls/Modules/cellGame.h b/rpcs3/Emu/Cell/Modules/cellGame.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellGame.h rename to rpcs3/Emu/Cell/Modules/cellGame.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellGameExec.cpp b/rpcs3/Emu/Cell/Modules/cellGameExec.cpp similarity index 89% rename from rpcs3/Emu/SysCalls/Modules/cellGameExec.cpp rename to rpcs3/Emu/Cell/Modules/cellGameExec.cpp index 01f08d5e30..9367db8796 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGameExec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGameExec.cpp @@ -1,10 +1,9 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellGame.h" -extern Module<> cellGameExec; +LOG_CHANNEL(cellGameExec); s32 cellGameSetExitParam() { @@ -45,7 +44,7 @@ s32 cellGameGetBootGameInfo(vm::ptr type, vm::ptr dirName, vm::ptr cellGameExec("cellGameExec", []() +DECLARE(ppu_module_manager::cellGameExec)("cellGameExec", []() { REG_FUNC(cellGameExec, cellGameSetExitParam); REG_FUNC(cellGameExec, cellGameGetHomeDataExportPath); diff --git a/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp b/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp similarity index 89% rename from rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp rename to rpcs3/Emu/Cell/Modules/cellGcmSys.cpp index 3f14986a60..f1e856df33 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp @@ -1,17 +1,16 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/IdManager.h" +#include "Emu/Cell/PPUModule.h" -#include "sysPrxForUser.h" - -//#include "Emu/RSX/GCM.h" -#include "Emu/RSX/GSManager.h" +#include "Emu/Cell/PPUOpcodes.h" +#include "Emu/Memory/Memory.h" #include "Emu/RSX/GSRender.h" -//#include "Emu/SysCalls/lv2/sys_process.h" #include "cellGcmSys.h" -extern Module<> cellGcmSys; +LOG_CHANNEL(cellGcmSys); + +extern s32 cellGcmCallback(vm::ptr context, u32 count); const u32 tiled_pitches[] = { 0x00000000, 0x00000200, 0x00000300, 0x00000400, @@ -101,8 +100,7 @@ vm::ptr cellGcmGetReportDataAddressLocation(u32 index, u32 lo cellGcmSys.error("cellGcmGetReportDataAddressLocation: Wrong main index (%d)", index); return vm::null; } - // TODO: It seems m_report_main_addr is not initialized - return vm::ptr::make(Emu.GetGSManager().GetRender().report_main_addr + index * 0x10); + return vm::ptr::make(RSXIOMem.RealAddr(index * 0x10)); } cellGcmSys.error("cellGcmGetReportDataAddressLocation: Wrong location (%d)", location); @@ -200,8 +198,7 @@ u64 cellGcmGetTimeStampLocation(u32 index, u32 location) cellGcmSys.error("cellGcmGetTimeStampLocation: Wrong main index (%d)", index); return 0; } - // TODO: It seems m_report_main_addr is not initialized - return vm::read64(Emu.GetGSManager().GetRender().report_main_addr + index * 0x10); + return vm::read64(RSXIOMem.RealAddr(index * 0x10)); } cellGcmSys.error("cellGcmGetTimeStampLocation: Wrong location (%d)", location); @@ -257,8 +254,7 @@ s32 cellGcmBindTile(u8 index) return CELL_GCM_ERROR_INVALID_VALUE; } - auto& tile = Emu.GetGSManager().GetRender().tiles[index]; - tile.binded = true; + fxm::get()->tiles[index].binded = true; return CELL_OK; } @@ -273,8 +269,7 @@ s32 cellGcmBindZcull(u8 index) return CELL_GCM_ERROR_INVALID_VALUE; } - auto& zcull = Emu.GetGSManager().GetRender().zculls[index]; - zcull.binded = true; + fxm::get()->zculls[index].binded = true; return CELL_OK; } @@ -290,7 +285,7 @@ s32 cellGcmGetConfiguration(vm::ptr config) s32 cellGcmGetFlipStatus() { - s32 status = Emu.GetGSManager().GetRender().flip_status; + s32 status = fxm::get()->flip_status; cellGcmSys.trace("cellGcmGetFlipStatus() -> %d", status); @@ -328,6 +323,11 @@ s32 _cellGcmInitBody(vm::pptr context, u32 cmdSize, u32 ioSi { cellGcmSys.warning("_cellGcmInitBody(context=**0x%x, cmdSize=0x%x, ioSize=0x%x, ioAddress=0x%x)", context, cmdSize, ioSize, ioAddress); + current_config.ioAddress = 0; + current_config.localAddress = 0; + local_size = 0; + local_addr = 0; + if (!local_size && !local_addr) { local_size = 0xf900000; // TODO: Get sdk_version in _cellGcmFunc15 and pass it to gcmGetLocalMemorySize @@ -369,15 +369,19 @@ s32 _cellGcmInitBody(vm::pptr context, u32 cmdSize, u32 ioSi g_defaultCommandBufferBegin = ioAddress; g_defaultCommandBufferFragmentCount = cmdSize / (32 * 1024); + gcm_info.context_addr = vm::alloc(0x1000, vm::main); + gcm_info.control_addr = vm::alloc(0x1000, vm::main); + gcm_info.label_addr = vm::alloc(0x1000, vm::main); // ??? + current_context.begin.set(g_defaultCommandBufferBegin + 4096); // 4 kb reserved at the beginning current_context.end.set(g_defaultCommandBufferBegin + 32 * 1024 - 4); // 4b at the end for jump current_context.current = current_context.begin; - current_context.callback.set(Emu.GetRSXCallback() - 4); + current_context.callback.set(gcm_info.context_addr + 0x40); - gcm_info.context_addr = vm::alloc(0x1000, vm::main); - gcm_info.control_addr = gcm_info.context_addr + 0x40; - - gcm_info.label_addr = vm::alloc(0x1000, vm::main); // ??? + vm::write32(gcm_info.context_addr + 0x40, gcm_info.context_addr + 0x48); + vm::write32(gcm_info.context_addr + 0x44, 0xabadcafe); + vm::write32(gcm_info.context_addr + 0x48, ppu_instructions::HACK(FIND_FUNC(cellGcmCallback))); + vm::write32(gcm_info.context_addr + 0x4c, ppu_instructions::BLR()); vm::_ref(gcm_info.context_addr) = current_context; context->set(gcm_info.context_addr); @@ -387,16 +391,16 @@ s32 _cellGcmInitBody(vm::pptr context, u32 cmdSize, u32 ioSi ctrl.get = 0; ctrl.ref = -1; - auto& render = Emu.GetGSManager().GetRender(); - render.ctxt_addr = context.addr(); - 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; - render.gcm_current_buffer = 0; - render.main_mem_addr = 0; - render.label_addr = gcm_info.label_addr; - render.init(g_defaultCommandBufferBegin, cmdSize, gcm_info.control_addr, local_addr); + const auto render = fxm::get(); + render->ctxt_addr = context.addr(); + 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; + render->gcm_current_buffer = 0; + render->main_mem_addr = 0; + render->label_addr = gcm_info.label_addr; + render->init(g_defaultCommandBufferBegin, cmdSize, gcm_info.control_addr, local_addr); return CELL_OK; } @@ -405,7 +409,7 @@ s32 cellGcmResetFlipStatus() { cellGcmSys.trace("cellGcmResetFlipStatus()"); - Emu.GetGSManager().GetRender().flip_status = CELL_GCM_DISPLAY_FLIP_STATUS_WAITING; + fxm::get()->flip_status = CELL_GCM_DISPLAY_FLIP_STATUS_WAITING; return CELL_OK; } @@ -419,7 +423,7 @@ s32 cellGcmSetDebugOutputLevel(s32 level) case CELL_GCM_DEBUG_LEVEL0: case CELL_GCM_DEBUG_LEVEL1: case CELL_GCM_DEBUG_LEVEL2: - Emu.GetGSManager().GetRender().debug_level = level; + fxm::get()->debug_level = level; break; default: return CELL_EINVAL; @@ -438,16 +442,18 @@ s32 cellGcmSetDisplayBuffer(u32 id, u32 offset, u32 pitch, u32 width, u32 height return CELL_EINVAL; } - auto buffers = Emu.GetGSManager().GetRender().gcm_buffers; + const auto render = fxm::get(); + + auto buffers = render->gcm_buffers; buffers[id].offset = offset; buffers[id].pitch = pitch; buffers[id].width = width; buffers[id].height = height; - if (id + 1 > Emu.GetGSManager().GetRender().gcm_buffers_count) + if (id + 1 > render->gcm_buffers_count) { - Emu.GetGSManager().GetRender().gcm_buffers_count = id + 1; + render->gcm_buffers_count = id + 1; } return CELL_OK; @@ -457,7 +463,7 @@ void cellGcmSetFlipHandler(vm::ptr handler) { cellGcmSys.warning("cellGcmSetFlipHandler(handler=*0x%x)", handler); - Emu.GetGSManager().GetRender().flip_handler = handler; + fxm::get()->flip_handler = handler; } s32 cellGcmSetFlipMode(u32 mode) @@ -469,7 +475,7 @@ s32 cellGcmSetFlipMode(u32 mode) case CELL_GCM_DISPLAY_HSYNC: case CELL_GCM_DISPLAY_VSYNC: case CELL_GCM_DISPLAY_HSYNC_WITH_NOISE: - Emu.GetGSManager().GetRender().flip_mode = mode; + fxm::get()->flip_mode = mode; break; default: @@ -483,7 +489,7 @@ void cellGcmSetFlipStatus() { cellGcmSys.warning("cellGcmSetFlipStatus()"); - Emu.GetGSManager().GetRender().flip_status = 0; + fxm::get()->flip_status = 0; } s32 cellGcmSetPrepareFlip(PPUThread& ppu, vm::ptr ctxt, u32 id) @@ -541,14 +547,22 @@ s32 cellGcmSetSecondVFrequency(u32 freq) { cellGcmSys.warning("cellGcmSetSecondVFrequency(level=%d)", freq); + const auto render = fxm::get(); + switch (freq) { case CELL_GCM_DISPLAY_FREQUENCY_59_94HZ: - Emu.GetGSManager().GetRender().frequency_mode = freq; Emu.GetGSManager().GetRender().fps_limit = 59.94; break; + render->frequency_mode = freq; + render->fps_limit = 59.94; + break; case CELL_GCM_DISPLAY_FREQUENCY_SCANOUT: - Emu.GetGSManager().GetRender().frequency_mode = freq; cellGcmSys.todo("Unimplemented display frequency: Scanout"); break; + render->frequency_mode = freq; + cellGcmSys.todo("Unimplemented display frequency: Scanout"); + break; case CELL_GCM_DISPLAY_FREQUENCY_DISABLE: - Emu.GetGSManager().GetRender().frequency_mode = freq; cellGcmSys.todo("Unimplemented display frequency: Disabled"); break; + render->frequency_mode = freq; + cellGcmSys.todo("Unimplemented display frequency: Disabled"); + break; default: cellGcmSys.error("Improper display frequency specified!"); return CELL_OK; } @@ -583,7 +597,9 @@ s32 cellGcmSetTileInfo(u8 index, u8 location, u32 offset, u32 size, u32 pitch, u cellGcmSys.error("cellGcmSetTileInfo: bad compression mode! (%d)", comp); } - auto& tile = Emu.GetGSManager().GetRender().tiles[index]; + const auto render = fxm::get(); + + auto& tile = render->tiles[index]; tile.location = location; tile.offset = offset; tile.size = size; @@ -592,7 +608,7 @@ s32 cellGcmSetTileInfo(u8 index, u8 location, u32 offset, u32 size, u32 pitch, u tile.base = base; tile.bank = bank; - vm::_ptr(Emu.GetGSManager().GetRender().tiles_addr)[index] = tile.pack(); + vm::_ptr(render->tiles_addr)[index] = tile.pack(); return CELL_OK; } @@ -600,7 +616,7 @@ void cellGcmSetUserHandler(vm::ptr handler) { cellGcmSys.warning("cellGcmSetUserHandler(handler=*0x%x)", handler); - Emu.GetGSManager().GetRender().user_handler = handler; + fxm::get()->user_handler = handler; } s32 cellGcmSetUserCommand() @@ -612,7 +628,7 @@ void cellGcmSetVBlankHandler(vm::ptr handler) { cellGcmSys.warning("cellGcmSetVBlankHandler(handler=*0x%x)", handler); - Emu.GetGSManager().GetRender().vblank_handler = handler; + fxm::get()->vblank_handler = handler; } s32 cellGcmSetWaitFlip(vm::ptr ctxt) @@ -640,7 +656,9 @@ s32 cellGcmSetZcull(u8 index, u32 offset, u32 width, u32 height, u32 cullStart, return CELL_GCM_ERROR_INVALID_VALUE; } - auto& zcull = Emu.GetGSManager().GetRender().zculls[index]; + const auto render = fxm::get(); + + auto& zcull = render->zculls[index]; zcull.offset = offset; zcull.width = width; zcull.height = height; @@ -653,7 +671,7 @@ s32 cellGcmSetZcull(u8 index, u32 offset, u32 width, u32 height, u32 cullStart, zcull.sRef = sRef; zcull.sMask = sMask; - vm::_ptr(Emu.GetGSManager().GetRender().zculls_addr)[index] = zcull.pack(); + vm::_ptr(render->zculls_addr)[index] = zcull.pack(); return CELL_OK; } @@ -667,8 +685,7 @@ s32 cellGcmUnbindTile(u8 index) return CELL_GCM_ERROR_INVALID_VALUE; } - auto& tile = Emu.GetGSManager().GetRender().tiles[index]; - tile.binded = false; + fxm::get()->tiles[index].binded = false; return CELL_OK; } @@ -683,8 +700,7 @@ s32 cellGcmUnbindZcull(u8 index) return CELL_EINVAL; } - auto& zcull = Emu.GetGSManager().GetRender().zculls[index]; - zcull.binded = false; + fxm::get()->zculls[index].binded = false; return CELL_OK; } @@ -692,32 +708,30 @@ s32 cellGcmUnbindZcull(u8 index) u32 cellGcmGetTileInfo() { cellGcmSys.warning("cellGcmGetTileInfo()"); - return Emu.GetGSManager().GetRender().tiles_addr; + return fxm::get()->tiles_addr; } u32 cellGcmGetZcullInfo() { cellGcmSys.warning("cellGcmGetZcullInfo()"); - return Emu.GetGSManager().GetRender().zculls_addr; + return fxm::get()->zculls_addr; } u32 cellGcmGetDisplayInfo() { - cellGcmSys.warning("cellGcmGetDisplayInfo() = 0x%x", Emu.GetGSManager().GetRender().gcm_buffers.addr()); - return Emu.GetGSManager().GetRender().gcm_buffers.addr(); + cellGcmSys.warning("cellGcmGetDisplayInfo()"); + return fxm::get()->gcm_buffers.addr(); } s32 cellGcmGetCurrentDisplayBufferId(vm::ptr id) { cellGcmSys.warning("cellGcmGetCurrentDisplayBufferId(id=*0x%x)", id); - if (Emu.GetGSManager().GetRender().gcm_current_buffer > UINT8_MAX) + if ((*id = fxm::get()->gcm_current_buffer) > UINT8_MAX) { throw EXCEPTION("Unexpected"); } - *id = Emu.GetGSManager().GetRender().gcm_current_buffer; - return CELL_OK; } @@ -748,7 +762,7 @@ u64 cellGcmGetLastFlipTime() { cellGcmSys.trace("cellGcmGetLastFlipTime()"); - return Emu.GetGSManager().GetRender().last_flip_time; + return fxm::get()->last_flip_time; } u64 cellGcmGetLastSecondVTime() @@ -761,7 +775,7 @@ u64 cellGcmGetVBlankCount() { cellGcmSys.trace("cellGcmGetVBlankCount()"); - return Emu.GetGSManager().GetRender().vblank_count; + return fxm::get()->vblank_count; } s32 cellGcmSysGetLastVBlankTime() @@ -896,6 +910,8 @@ s32 gcmMapEaIoAddress(u32 ea, u32 io, u32 size, bool is_strict) { if ((ea & 0xFFFFF) || (io & 0xFFFFF) || (size & 0xFFFFF)) return CELL_GCM_ERROR_FAILURE; + const auto render = fxm::get(); + // Check if the mapping was successfull if (RSXIOMem.Map(ea, size, io)) { @@ -904,7 +920,7 @@ s32 gcmMapEaIoAddress(u32 ea, u32 io, u32 size, bool is_strict) { offsetTable.ioAddress[(ea >> 20) + i] = (io >> 20) + i; offsetTable.eaAddress[(io >> 20) + i] = (ea >> 20) + i; - Emu.GetGSManager().GetRender().strict_ordering[(io >> 20) + i] = is_strict; + render->strict_ordering[(io >> 20) + i] = is_strict; } } else @@ -927,7 +943,7 @@ s32 cellGcmMapEaIoAddressWithFlags(u32 ea, u32 io, u32 size, u32 flags) { cellGcmSys.warning("cellGcmMapEaIoAddressWithFlags(ea=0x%x, io=0x%x, size=0x%x, flags=0x%x)", ea, io, size, flags); - assert(flags == 2 /*CELL_GCM_IOMAP_FLAG_STRICT_ORDERING*/); + ASSERT(flags == 2 /*CELL_GCM_IOMAP_FLAG_STRICT_ORDERING*/); return gcmMapEaIoAddress(ea, io, size, true); } @@ -958,6 +974,8 @@ s32 cellGcmMapMainMemory(u32 ea, u32 size, vm::ptr offset) u32 io = RSXIOMem.Map(ea, size); + const auto render = fxm::get(); + //check if the mapping was successfull if (RSXIOMem.RealAddr(io) == ea) { @@ -966,7 +984,7 @@ s32 cellGcmMapMainMemory(u32 ea, u32 size, vm::ptr offset) { offsetTable.ioAddress[(ea >> 20) + i] = (u16)((io >> 20) + i); offsetTable.eaAddress[(io >> 20) + i] = (u16)((ea >> 20) + i); - Emu.GetGSManager().GetRender().strict_ordering[(io >> 20) + i] = false; + render->strict_ordering[(io >> 20) + i] = false; } *offset = io; @@ -977,7 +995,7 @@ s32 cellGcmMapMainMemory(u32 ea, u32 size, vm::ptr offset) return CELL_GCM_ERROR_NO_IO_PAGE_TABLE; } - Emu.GetGSManager().GetRender().main_mem_addr = Emu.GetGSManager().GetRender().ioAddress; + render->main_mem_addr = render->ioAddress; return CELL_OK; } @@ -1117,7 +1135,7 @@ s32 cellGcmSetCursorImageOffset(u32 offset) void cellGcmSetDefaultCommandBuffer() { cellGcmSys.warning("cellGcmSetDefaultCommandBuffer()"); - vm::write32(Emu.GetGSManager().GetRender().ctxt_addr, gcm_info.context_addr); + vm::write32(fxm::get()->ctxt_addr, gcm_info.context_addr); } s32 cellGcmSetDefaultCommandBufferAndSegmentWordSize() @@ -1174,7 +1192,9 @@ s32 cellGcmSetTile(u8 index, u8 location, u32 offset, u32 size, u32 pitch, u8 co cellGcmSys.error("cellGcmSetTile: bad compression mode! (%d)", comp); } - auto& tile = Emu.GetGSManager().GetRender().tiles[index]; + const auto render = fxm::get(); + + auto& tile = render->tiles[index]; tile.location = location; tile.offset = offset; tile.size = size; @@ -1183,7 +1203,7 @@ s32 cellGcmSetTile(u8 index, u8 location, u32 offset, u32 size, u32 pitch, u8 co tile.base = base; tile.bank = bank; - vm::_ptr(Emu.GetGSManager().GetRender().tiles_addr)[index] = tile.pack(); + vm::_ptr(render->tiles_addr)[index] = tile.pack(); return CELL_OK; } @@ -1247,7 +1267,7 @@ static std::pair getNextCommandBufferBeginEnd(u32 current) static u32 getOffsetFromAddress(u32 address) { const u32 upper = offsetTable.ioAddress[address >> 20]; // 12 bits - assert(upper != 0xFFFF); + Expects(upper != 0xFFFF); return (upper << 20) | (address & 0xFFFFF); } @@ -1269,7 +1289,6 @@ static bool isInCommandBufferExcept(u32 getPos, u32 bufferBegin, u32 bufferEnd) return true; } -// TODO: Avoid using syscall 1023 for calling this function s32 cellGcmCallback(vm::ptr context, u32 count) { cellGcmSys.trace("cellGcmCallback(context=*0x%x, count=0x%x)", context, count); @@ -1306,13 +1325,8 @@ s32 cellGcmCallback(vm::ptr context, u32 count) //---------------------------------------------------------------------------- -Module<> cellGcmSys("cellGcmSys", []() +DECLARE(ppu_module_manager::cellGcmSys)("cellGcmSys", []() { - current_config.ioAddress = 0; - current_config.localAddress = 0; - local_size = 0; - local_addr = 0; - // Data Retrieval REG_FUNC(cellGcmSys, cellGcmGetCurrentField); REG_FUNC(cellGcmSys, cellGcmGetLabelAddress); @@ -1419,4 +1433,7 @@ Module<> cellGcmSys("cellGcmSys", []() REG_FUNC(cellGcmSys, cellGcmGpadGetStatus); REG_FUNC(cellGcmSys, cellGcmGpadNotifyCaptureSurface); REG_FUNC(cellGcmSys, cellGcmGpadCaptureSnapshot); + + // Special + REG_FNID(cellGcmSys, 0x00000000, cellGcmCallback); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellGcmSys.h b/rpcs3/Emu/Cell/Modules/cellGcmSys.h similarity index 87% rename from rpcs3/Emu/SysCalls/Modules/cellGcmSys.h rename to rpcs3/Emu/Cell/Modules/cellGcmSys.h index 58f7a7dc1a..1c4109cbcb 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGcmSys.h +++ b/rpcs3/Emu/Cell/Modules/cellGcmSys.h @@ -22,6 +22,3 @@ struct CellGcmOffsetTable // Auxiliary functions s32 gcmMapEaIoAddress(u32 ea, u32 io, u32 size, bool is_strict); - -// Syscall -s32 cellGcmCallback(vm::ptr context, u32 count); diff --git a/rpcs3/Emu/SysCalls/Modules/cellGem.cpp b/rpcs3/Emu/Cell/Modules/cellGem.cpp similarity index 69% rename from rpcs3/Emu/SysCalls/Modules/cellGem.cpp rename to rpcs3/Emu/Cell/Modules/cellGem.cpp index a2e3910fad..f10e41ea58 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGem.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGem.cpp @@ -1,11 +1,10 @@ #include "stdafx.h" #include "Emu/IdManager.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellGem.h" -extern Module<> cellGem; +LOG_CHANNEL(cellGem); struct gem_t { @@ -273,43 +272,43 @@ s32 cellGemWriteExternalPort() return CELL_OK; } -Module<> cellGem("cellGem", []() +DECLARE(ppu_module_manager::cellGem)("libgem", []() { - REG_FUNC(cellGem, cellGemCalibrate); - REG_FUNC(cellGem, cellGemClearStatusFlags); - REG_FUNC(cellGem, cellGemConvertVideoFinish); - REG_FUNC(cellGem, cellGemConvertVideoStart); - REG_FUNC(cellGem, cellGemEnableCameraPitchAngleCorrection); - REG_FUNC(cellGem, cellGemEnableMagnetometer); - REG_FUNC(cellGem, cellGemEnd); - REG_FUNC(cellGem, cellGemFilterState); - REG_FUNC(cellGem, cellGemForceRGB); - REG_FUNC(cellGem, cellGemGetAccelerometerPositionInDevice); - REG_FUNC(cellGem, cellGemGetAllTrackableHues); - REG_FUNC(cellGem, cellGemGetCameraState); - REG_FUNC(cellGem, cellGemGetEnvironmentLightingColor); - REG_FUNC(cellGem, cellGemGetHuePixels); - REG_FUNC(cellGem, cellGemGetImageState); - REG_FUNC(cellGem, cellGemGetInertialState); - REG_FUNC(cellGem, cellGemGetInfo); - REG_FUNC(cellGem, cellGemGetMemorySize); - REG_FUNC(cellGem, cellGemGetRGB); - REG_FUNC(cellGem, cellGemGetRumble); - REG_FUNC(cellGem, cellGemGetState); - REG_FUNC(cellGem, cellGemGetStatusFlags); - REG_FUNC(cellGem, cellGemGetTrackerHue); - REG_FUNC(cellGem, cellGemHSVtoRGB); - REG_FUNC(cellGem, cellGemInit); - REG_FUNC(cellGem, cellGemInvalidateCalibration); - REG_FUNC(cellGem, cellGemIsTrackableHue); - REG_FUNC(cellGem, cellGemPrepareCamera); - REG_FUNC(cellGem, cellGemPrepareVideoConvert); - REG_FUNC(cellGem, cellGemReadExternalPortDeviceInfo); - REG_FUNC(cellGem, cellGemReset); - REG_FUNC(cellGem, cellGemSetRumble); - REG_FUNC(cellGem, cellGemSetYaw); - REG_FUNC(cellGem, cellGemTrackHues); - REG_FUNC(cellGem, cellGemUpdateFinish); - REG_FUNC(cellGem, cellGemUpdateStart); - REG_FUNC(cellGem, cellGemWriteExternalPort); + REG_FUNC(libgem, cellGemCalibrate); + REG_FUNC(libgem, cellGemClearStatusFlags); + REG_FUNC(libgem, cellGemConvertVideoFinish); + REG_FUNC(libgem, cellGemConvertVideoStart); + REG_FUNC(libgem, cellGemEnableCameraPitchAngleCorrection); + REG_FUNC(libgem, cellGemEnableMagnetometer); + REG_FUNC(libgem, cellGemEnd); + REG_FUNC(libgem, cellGemFilterState); + REG_FUNC(libgem, cellGemForceRGB); + REG_FUNC(libgem, cellGemGetAccelerometerPositionInDevice); + REG_FUNC(libgem, cellGemGetAllTrackableHues); + REG_FUNC(libgem, cellGemGetCameraState); + REG_FUNC(libgem, cellGemGetEnvironmentLightingColor); + REG_FUNC(libgem, cellGemGetHuePixels); + REG_FUNC(libgem, cellGemGetImageState); + REG_FUNC(libgem, cellGemGetInertialState); + REG_FUNC(libgem, cellGemGetInfo); + REG_FUNC(libgem, cellGemGetMemorySize); + REG_FUNC(libgem, cellGemGetRGB); + REG_FUNC(libgem, cellGemGetRumble); + REG_FUNC(libgem, cellGemGetState); + REG_FUNC(libgem, cellGemGetStatusFlags); + REG_FUNC(libgem, cellGemGetTrackerHue); + REG_FUNC(libgem, cellGemHSVtoRGB); + REG_FUNC(libgem, cellGemInit); + REG_FUNC(libgem, cellGemInvalidateCalibration); + REG_FUNC(libgem, cellGemIsTrackableHue); + REG_FUNC(libgem, cellGemPrepareCamera); + REG_FUNC(libgem, cellGemPrepareVideoConvert); + REG_FUNC(libgem, cellGemReadExternalPortDeviceInfo); + REG_FUNC(libgem, cellGemReset); + REG_FUNC(libgem, cellGemSetRumble); + REG_FUNC(libgem, cellGemSetYaw); + REG_FUNC(libgem, cellGemTrackHues); + REG_FUNC(libgem, cellGemUpdateFinish); + REG_FUNC(libgem, cellGemUpdateStart); + REG_FUNC(libgem, cellGemWriteExternalPort); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellGem.h b/rpcs3/Emu/Cell/Modules/cellGem.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellGem.h rename to rpcs3/Emu/Cell/Modules/cellGem.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp b/rpcs3/Emu/Cell/Modules/cellGifDec.cpp similarity index 94% rename from rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp rename to rpcs3/Emu/Cell/Modules/cellGifDec.cpp index 4cef65232d..64c10ca7cf 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGifDec.cpp @@ -1,19 +1,15 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" // STB_IMAGE_IMPLEMENTATION is already defined in stb_image.cpp #include -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsFileBase.h" -#include "Emu/SysCalls/lv2/sys_fs.h" - +#include "Emu/Cell/lv2/sys_fs.h" #include "cellGifDec.h" -extern Module<> cellGifDec; +LOG_CHANNEL(cellGifDec); // cellGifDec aliases (only for cellGifDec.cpp) using PPMainHandle = vm::pptr; @@ -61,11 +57,11 @@ s32 cellGifDecOpen(PMainHandle mainHandle, PPSubHandle subHandle, PSrc src, POpe case CELL_GIFDEC_FILE: { // Get file descriptor and size - std::shared_ptr file_s(Emu.GetVFS().OpenFile(src->fileName.get_ptr(), fom::read)); + fs::file file_s(vfs::get(src->fileName.get_ptr())); if (!file_s) return CELL_GIFDEC_ERROR_OPEN_FILE; - current_subHandle.fd = idm::make(file_s, 0, 0); - current_subHandle.fileSize = file_s->GetSize(); + current_subHandle.fileSize = file_s.size(); + current_subHandle.fd = idm::make(std::move(file_s), 0, 0); break; } } @@ -102,8 +98,8 @@ s32 cellGifDecReadHeader(PMainHandle mainHandle, PSubHandle subHandle, PInfo inf case CELL_GIFDEC_FILE: { auto file = idm::get(fd); - file->file->Seek(0); - file->file->Read(buffer, sizeof(buffer)); + file->file.seek(0); + file->file.read(buffer, sizeof(buffer)); break; } } @@ -186,8 +182,8 @@ s32 cellGifDecDecodeData(PMainHandle mainHandle, PSubHandle subHandle, vm::ptr(fd); - file->file->Seek(0); - file->file->Read(gif.get(), fileSize); + file->file.seek(0); + file->file.read(gif.get(), fileSize); break; } } @@ -300,7 +296,7 @@ s32 cellGifDecDestroy(PMainHandle mainHandle) return CELL_OK; } -Module<> cellGifDec("cellGifDec", []() +DECLARE(ppu_module_manager::cellGifDec)("cellGifDec", []() { REG_FUNC(cellGifDec, cellGifDecCreate); REG_FUNC(cellGifDec, cellGifDecExtCreate); diff --git a/rpcs3/Emu/SysCalls/Modules/cellGifDec.h b/rpcs3/Emu/Cell/Modules/cellGifDec.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellGifDec.h rename to rpcs3/Emu/Cell/Modules/cellGifDec.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellHttp.cpp b/rpcs3/Emu/Cell/Modules/cellHttp.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/cellHttp.cpp rename to rpcs3/Emu/Cell/Modules/cellHttp.cpp index ee6a48fcbc..46328b1cf7 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellHttp.cpp +++ b/rpcs3/Emu/Cell/Modules/cellHttp.cpp @@ -1,9 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellHttp; -extern Module<> cellHttps; +LOG_CHANNEL(cellHttp); s32 cellHttpInit() { @@ -599,7 +597,7 @@ s32 cellHttpClientSetSslIdDestroyCallback() return CELL_OK; } -Module<> cellHttp("cellHttp", []() +DECLARE(ppu_module_manager::cellHttp)("cellHttp", []() { REG_FUNC(cellHttp, cellHttpInit); REG_FUNC(cellHttp, cellHttpEnd); @@ -713,7 +711,7 @@ Module<> cellHttp("cellHttp", []() REG_FUNC(cellHttp, cellHttpClientSetSslIdDestroyCallback); }); -Module<> cellHttps("cellHttps", []() +DECLARE(ppu_module_manager::cellHttps)("cellHttps", []() { // cellHttps doesn't have functions (cellHttpsInit belongs to cellHttp, for example) }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellHttpUtil.cpp b/rpcs3/Emu/Cell/Modules/cellHttpUtil.cpp similarity index 95% rename from rpcs3/Emu/SysCalls/Modules/cellHttpUtil.cpp rename to rpcs3/Emu/Cell/Modules/cellHttpUtil.cpp index 4625593b15..35c7c5328c 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellHttpUtil.cpp +++ b/rpcs3/Emu/Cell/Modules/cellHttpUtil.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellHttpUtil; +LOG_CHANNEL(cellHttpUtil); s32 cellHttpUtilParseUri() { @@ -124,7 +123,7 @@ s32 cellHttpUtilBase64Decoder() return CELL_OK; } -Module<> cellHttpUtil("cellHttpUtil", []() +DECLARE(ppu_module_manager::cellHttpUtil)("cellHttpUtil", []() { REG_FUNC(cellHttpUtil, cellHttpUtilParseUri); REG_FUNC(cellHttpUtil, cellHttpUtilParseUriPath); diff --git a/rpcs3/Emu/SysCalls/Modules/cellImejp.cpp b/rpcs3/Emu/Cell/Modules/cellImejp.cpp similarity index 62% rename from rpcs3/Emu/SysCalls/Modules/cellImejp.cpp rename to rpcs3/Emu/Cell/Modules/cellImejp.cpp index d1959b36c9..278103fd3f 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellImejp.cpp +++ b/rpcs3/Emu/Cell/Modules/cellImejp.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellImeJp; +LOG_CHANNEL(cellImeJp); // Return Codes enum @@ -262,50 +261,50 @@ s32 cellImeJpConfirmPrediction() return CELL_OK; } -Module<> cellImeJp("cellImeJp", []() +DECLARE(ppu_module_manager::cellImeJp)("cellImeJpUtility", []() { - REG_FUNC(cellImeJp, cellImeJpOpen); - REG_FUNC(cellImeJp, cellImeJpOpen2); - REG_FUNC(cellImeJp, cellImeJpOpen3); - REG_FUNC(cellImeJp, cellImeJpClose); + REG_FUNC(cellImeJpUtility, cellImeJpOpen); + REG_FUNC(cellImeJpUtility, cellImeJpOpen2); + REG_FUNC(cellImeJpUtility, cellImeJpOpen3); + REG_FUNC(cellImeJpUtility, cellImeJpClose); - REG_FUNC(cellImeJp, cellImeJpSetKanaInputMode); - REG_FUNC(cellImeJp, cellImeJpSetInputCharType); - REG_FUNC(cellImeJp, cellImeJpSetFixInputMode); - REG_FUNC(cellImeJp, cellImeJpAllowExtensionCharacters); - REG_FUNC(cellImeJp, cellImeJpReset); + REG_FUNC(cellImeJpUtility, cellImeJpSetKanaInputMode); + REG_FUNC(cellImeJpUtility, cellImeJpSetInputCharType); + REG_FUNC(cellImeJpUtility, cellImeJpSetFixInputMode); + REG_FUNC(cellImeJpUtility, cellImeJpAllowExtensionCharacters); + REG_FUNC(cellImeJpUtility, cellImeJpReset); - REG_FUNC(cellImeJp, cellImeJpGetStatus); + REG_FUNC(cellImeJpUtility, cellImeJpGetStatus); - REG_FUNC(cellImeJp, cellImeJpEnterChar); - REG_FUNC(cellImeJp, cellImeJpEnterCharExt); - REG_FUNC(cellImeJp, cellImeJpEnterString); - REG_FUNC(cellImeJp, cellImeJpEnterStringExt); - REG_FUNC(cellImeJp, cellImeJpModeCaretRight); - REG_FUNC(cellImeJp, cellImeJpModeCaretLeft); - REG_FUNC(cellImeJp, cellImeJpBackspaceWord); - REG_FUNC(cellImeJp, cellImeJpDeleteWord); - REG_FUNC(cellImeJp, cellImeJpAllDeleteConvertString); - REG_FUNC(cellImeJp, cellImeJpConvertForward); - REG_FUNC(cellImeJp, cellImeJpConvertBackward); - REG_FUNC(cellImeJp, cellImeJpCurrentPartConfirm); - REG_FUNC(cellImeJp, cellImeJpAllConfirm); - REG_FUNC(cellImeJp, cellImeJpConvertCancel); - REG_FUNC(cellImeJp, cellImeJpAllConvertCancel); - REG_FUNC(cellImeJp, cellImeJpExtendConvertArea); - REG_FUNC(cellImeJp, cellImeJpShortenConvertArea); - REG_FUNC(cellImeJp, cellImeJpTemporalConfirm); - REG_FUNC(cellImeJp, cellImeJpPostConvert); - REG_FUNC(cellImeJp, cellImeJpMoveFocusClause); - REG_FUNC(cellImeJp, cellImeJpGetFocusTop); - REG_FUNC(cellImeJp, cellImeJpGetFocusLength); - REG_FUNC(cellImeJp, cellImeJpGetConfirmYomiString); - REG_FUNC(cellImeJp, cellImeJpGetConfirmString); - REG_FUNC(cellImeJp, cellImeJpGetConvertYomiString); - REG_FUNC(cellImeJp, cellImeJpGetConvertString); - REG_FUNC(cellImeJp, cellImeJpGetCandidateListSize); - REG_FUNC(cellImeJp, cellImeJpGetCandidateList); - REG_FUNC(cellImeJp, cellImeJpGetCandidateSelect); - REG_FUNC(cellImeJp, cellImeJpGetPredictList); - REG_FUNC(cellImeJp, cellImeJpConfirmPrediction); + REG_FUNC(cellImeJpUtility, cellImeJpEnterChar); + REG_FUNC(cellImeJpUtility, cellImeJpEnterCharExt); + REG_FUNC(cellImeJpUtility, cellImeJpEnterString); + REG_FUNC(cellImeJpUtility, cellImeJpEnterStringExt); + REG_FUNC(cellImeJpUtility, cellImeJpModeCaretRight); + REG_FUNC(cellImeJpUtility, cellImeJpModeCaretLeft); + REG_FUNC(cellImeJpUtility, cellImeJpBackspaceWord); + REG_FUNC(cellImeJpUtility, cellImeJpDeleteWord); + REG_FUNC(cellImeJpUtility, cellImeJpAllDeleteConvertString); + REG_FUNC(cellImeJpUtility, cellImeJpConvertForward); + REG_FUNC(cellImeJpUtility, cellImeJpConvertBackward); + REG_FUNC(cellImeJpUtility, cellImeJpCurrentPartConfirm); + REG_FUNC(cellImeJpUtility, cellImeJpAllConfirm); + REG_FUNC(cellImeJpUtility, cellImeJpConvertCancel); + REG_FUNC(cellImeJpUtility, cellImeJpAllConvertCancel); + REG_FUNC(cellImeJpUtility, cellImeJpExtendConvertArea); + REG_FUNC(cellImeJpUtility, cellImeJpShortenConvertArea); + REG_FUNC(cellImeJpUtility, cellImeJpTemporalConfirm); + REG_FUNC(cellImeJpUtility, cellImeJpPostConvert); + REG_FUNC(cellImeJpUtility, cellImeJpMoveFocusClause); + REG_FUNC(cellImeJpUtility, cellImeJpGetFocusTop); + REG_FUNC(cellImeJpUtility, cellImeJpGetFocusLength); + REG_FUNC(cellImeJpUtility, cellImeJpGetConfirmYomiString); + REG_FUNC(cellImeJpUtility, cellImeJpGetConfirmString); + REG_FUNC(cellImeJpUtility, cellImeJpGetConvertYomiString); + REG_FUNC(cellImeJpUtility, cellImeJpGetConvertString); + REG_FUNC(cellImeJpUtility, cellImeJpGetCandidateListSize); + REG_FUNC(cellImeJpUtility, cellImeJpGetCandidateList); + REG_FUNC(cellImeJpUtility, cellImeJpGetCandidateSelect); + REG_FUNC(cellImeJpUtility, cellImeJpGetPredictList); + REG_FUNC(cellImeJpUtility, cellImeJpConfirmPrediction); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp b/rpcs3/Emu/Cell/Modules/cellJpgDec.cpp similarity index 94% rename from rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp rename to rpcs3/Emu/Cell/Modules/cellJpgDec.cpp index 0c5ded73b9..3fcb2a967e 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellJpgDec.cpp @@ -1,19 +1,15 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" // STB_IMAGE_IMPLEMENTATION is already defined in stb_image.cpp #include -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsFileBase.h" -#include "Emu/SysCalls/lv2/sys_fs.h" - +#include "Emu/Cell/lv2/sys_fs.h" #include "cellJpgDec.h" -extern Module<> cellJpgDec; +LOG_CHANNEL(cellJpgDec); s32 cellJpgDecCreate(u32 mainHandle, u32 threadInParam, u32 threadOutParam) { @@ -51,11 +47,11 @@ s32 cellJpgDecOpen(u32 mainHandle, vm::ptr subHandle, vm::ptr file_s(Emu.GetVFS().OpenFile(src->fileName.get_ptr(), fom::read)); + fs::file file_s(vfs::get(src->fileName.get_ptr())); if (!file_s) return CELL_JPGDEC_ERROR_OPEN_FILE; - current_subHandle.fd = idm::make(file_s, 0, 0); - current_subHandle.fileSize = file_s->GetSize(); + current_subHandle.fileSize = file_s.size(); + current_subHandle.fd = idm::make(std::move(file_s), 0, 0); break; } } @@ -115,8 +111,8 @@ s32 cellJpgDecReadHeader(u32 mainHandle, u32 subHandle, vm::ptr case CELL_JPGDEC_FILE: { auto file = idm::get(fd); - file->file->Seek(0); - file->file->Read(buffer.get(), fileSize); + file->file.seek(0); + file->file.read(buffer.get(), fileSize); break; } } @@ -194,8 +190,8 @@ s32 cellJpgDecDecodeData(u32 mainHandle, u32 subHandle, vm::ptr data, vm::cp case CELL_JPGDEC_FILE: { auto file = idm::get(fd); - file->file->Seek(0); - file->file->Read(jpg.get(), fileSize); + file->file.seek(0); + file->file.read(jpg.get(), fileSize); break; } } @@ -357,7 +353,7 @@ s32 cellJpgDecExtSetParameter() } -Module<> cellJpgDec("cellJpgDec", []() +DECLARE(ppu_module_manager::cellJpgDec)("cellJpgDec", []() { REG_FUNC(cellJpgDec, cellJpgDecCreate); REG_FUNC(cellJpgDec, cellJpgDecExtCreate); diff --git a/rpcs3/Emu/SysCalls/Modules/cellJpgDec.h b/rpcs3/Emu/Cell/Modules/cellJpgDec.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellJpgDec.h rename to rpcs3/Emu/Cell/Modules/cellJpgDec.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellJpgEnc.cpp b/rpcs3/Emu/Cell/Modules/cellJpgEnc.cpp similarity index 92% rename from rpcs3/Emu/SysCalls/Modules/cellJpgEnc.cpp rename to rpcs3/Emu/Cell/Modules/cellJpgEnc.cpp index 2b91af18b4..605a04e930 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellJpgEnc.cpp +++ b/rpcs3/Emu/Cell/Modules/cellJpgEnc.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellJpgEnc; +LOG_CHANNEL(cellJpgEnc); // Error Codes enum @@ -75,7 +74,7 @@ s32 cellJpgEncReset() return CELL_OK; } -Module<> cellJpgEnc("cellJpgEnc", []() +DECLARE(ppu_module_manager::cellJpgEnc)("cellJpgEnc", []() { REG_FUNC(cellJpgEnc, cellJpgEncQueryAttr); REG_FUNC(cellJpgEnc, cellJpgEncOpen); diff --git a/rpcs3/Emu/SysCalls/Modules/cellKb.cpp b/rpcs3/Emu/Cell/Modules/cellKb.cpp similarity index 81% rename from rpcs3/Emu/SysCalls/Modules/cellKb.cpp rename to rpcs3/Emu/Cell/Modules/cellKb.cpp index bab63108c2..a4647993b1 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellKb.cpp +++ b/rpcs3/Emu/Cell/Modules/cellKb.cpp @@ -1,35 +1,37 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/IdManager.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/Io/Keyboard.h" +#include "Emu/Io/KeyboardHandler.h" #include "cellKb.h" -extern Module<> sys_io; +extern _log::channel sys_io; s32 cellKbInit(u32 max_connect) { sys_io.warning("cellKbInit(max_connect=%d)", max_connect); - if (Emu.GetKeyboardManager().IsInited()) - return CELL_KB_ERROR_ALREADY_INITIALIZED; if (max_connect > 7) return CELL_KB_ERROR_INVALID_PARAMETER; - Emu.GetKeyboardManager().Init(max_connect); + const auto handler = fxm::import(PURE_EXPR(Emu.GetCallbacks().get_kb_handler())); + + if (!handler) + return CELL_KB_ERROR_ALREADY_INITIALIZED; + + handler->Init(max_connect); return CELL_OK; } s32 cellKbEnd() { - sys_io.trace("cellKbEnd()"); + sys_io.notice("cellKbEnd()"); - if (!Emu.GetKeyboardManager().IsInited()) + if (!fxm::remove()) return CELL_KB_ERROR_UNINITIALIZED; - Emu.GetKeyboardManager().Close(); return CELL_OK; } @@ -37,10 +39,12 @@ s32 cellKbClearBuf(u32 port_no) { sys_io.trace("cellKbClearBuf(port_no=%d)", port_no); - if (!Emu.GetKeyboardManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_KB_ERROR_UNINITIALIZED; - if (port_no >= Emu.GetKeyboardManager().GetKeyboards().size()) + if (port_no >= handler->GetKeyboards().size()) return CELL_KB_ERROR_INVALID_PARAMETER; //? @@ -98,10 +102,12 @@ s32 cellKbGetInfo(vm::ptr info) { sys_io.trace("cellKbGetInfo(info=*0x%x)", info); - if (!Emu.GetKeyboardManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_KB_ERROR_UNINITIALIZED; - const KbInfo& current_info = Emu.GetKeyboardManager().GetInfo(); + const KbInfo& current_info = handler->GetInfo(); info->max_connect = current_info.max_connect; info->now_connect = current_info.now_connect; info->info = current_info.info; @@ -118,14 +124,17 @@ s32 cellKbRead(u32 port_no, vm::ptr data) { sys_io.trace("cellKbRead(port_no=%d, data=*0x%x)", port_no, data); - const std::vector& keyboards = Emu.GetKeyboardManager().GetKeyboards(); - if (!Emu.GetKeyboardManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_KB_ERROR_UNINITIALIZED; + const std::vector& keyboards = handler->GetKeyboards(); + if (port_no >= keyboards.size()) return CELL_KB_ERROR_INVALID_PARAMETER; - KbData& current_data = Emu.GetKeyboardManager().GetData(port_no); + KbData& current_data = handler->GetData(port_no); data->led = current_data.led; data->mkey = current_data.mkey; data->len = std::min((u32)current_data.len, CELL_KB_MAX_KEYCODES); @@ -144,10 +153,12 @@ s32 cellKbSetCodeType(u32 port_no, u32 type) { sys_io.trace("cellKbSetCodeType(port_no=%d,type=%d)", port_no, type); - if (!Emu.GetKeyboardManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_KB_ERROR_UNINITIALIZED; - KbConfig& current_config = Emu.GetKeyboardManager().GetConfig(port_no); + KbConfig& current_config = handler->GetConfig(port_no); current_config.code_type = type; return CELL_OK; } @@ -162,10 +173,12 @@ s32 cellKbSetReadMode(u32 port_no, u32 rmode) { sys_io.trace("cellKbSetReadMode(port_no=%d,rmode=%d)", port_no, rmode); - if (!Emu.GetKeyboardManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_KB_ERROR_UNINITIALIZED; - KbConfig& current_config = Emu.GetKeyboardManager().GetConfig(port_no); + KbConfig& current_config = handler->GetConfig(port_no); current_config.read_mode = rmode; return CELL_OK; @@ -175,10 +188,12 @@ s32 cellKbGetConfiguration(u32 port_no, vm::ptr config) { sys_io.trace("cellKbGetConfiguration(port_no=%d, config=*0x%x)", port_no, config); - if (!Emu.GetKeyboardManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_KB_ERROR_UNINITIALIZED; - const KbConfig& current_config = Emu.GetKeyboardManager().GetConfig(port_no); + const KbConfig& current_config = handler->GetConfig(port_no); config->arrange = current_config.arrange; config->read_mode = current_config.read_mode; config->code_type = current_config.code_type; diff --git a/rpcs3/Emu/SysCalls/Modules/cellKb.h b/rpcs3/Emu/Cell/Modules/cellKb.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellKb.h rename to rpcs3/Emu/Cell/Modules/cellKb.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellKey2char.cpp b/rpcs3/Emu/Cell/Modules/cellKey2char.cpp similarity index 88% rename from rpcs3/Emu/SysCalls/Modules/cellKey2char.cpp rename to rpcs3/Emu/Cell/Modules/cellKey2char.cpp index 72979257f6..3a51a3c347 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellKey2char.cpp +++ b/rpcs3/Emu/Cell/Modules/cellKey2char.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellKey2char; +LOG_CHANNEL(cellKey2char); // Return Codes enum @@ -46,7 +45,7 @@ s32 cellKey2CharSetArrangement() return CELL_OK; } -Module<> cellKey2char("cellKey2char", []() +DECLARE(ppu_module_manager::cellKey2char)("cellKey2char", []() { REG_FUNC(cellKey2char, cellKey2CharOpen); REG_FUNC(cellKey2char, cellKey2CharClose); diff --git a/rpcs3/Emu/SysCalls/Modules/cellL10n.cpp b/rpcs3/Emu/Cell/Modules/cellL10n.cpp similarity index 99% rename from rpcs3/Emu/SysCalls/Modules/cellL10n.cpp rename to rpcs3/Emu/Cell/Modules/cellL10n.cpp index ad209aecfc..73ec6cad6c 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellL10n.cpp +++ b/rpcs3/Emu/Cell/Modules/cellL10n.cpp @@ -1,9 +1,8 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #ifdef _WIN32 -#include +#include #endif #ifdef _MSC_VER @@ -15,7 +14,7 @@ typedef const char *HostCode; #include "cellL10n.h" -extern Module<> cellL10n; +LOG_CHANNEL(cellL10n); // Translate code id to code name. some codepage may has another name. // If this makes your compilation fail, try replace the string code with one in "iconv -l" @@ -1061,7 +1060,7 @@ s32 UTF8toBIG5() s32 UTF16stoUTF8s(vm::cptr utf16, vm::ref utf16_len, vm::ptr utf8, vm::ref 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); + cellL10n.error("UTF16stoUTF8s(utf16=*0x%x, utf16_len=*0x%x, utf8=*0x%x, utf8_len=*0x%x)", utf16, utf16_len.addr(), utf8, utf8_len.addr()); const u32 max_len = utf8_len; utf8_len = 0; @@ -1170,7 +1169,7 @@ s32 UTF8stoUCS2s() } -Module<> cellL10n("cellL10n", []() +DECLARE(ppu_module_manager::cellL10n)("cellL10n", []() { REG_FUNC(cellL10n, UCS2toEUCJP); REG_FUNC(cellL10n, l10n_convert); diff --git a/rpcs3/Emu/SysCalls/Modules/cellL10n.h b/rpcs3/Emu/Cell/Modules/cellL10n.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellL10n.h rename to rpcs3/Emu/Cell/Modules/cellL10n.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellMic.cpp b/rpcs3/Emu/Cell/Modules/cellMic.cpp similarity index 97% rename from rpcs3/Emu/SysCalls/Modules/cellMic.cpp rename to rpcs3/Emu/Cell/Modules/cellMic.cpp index e5e3a9bce5..b0cd2b8ba7 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellMic.cpp +++ b/rpcs3/Emu/Cell/Modules/cellMic.cpp @@ -1,11 +1,10 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellMic.h" -extern Module<> cellMic; +LOG_CHANNEL(cellMic); s32 cellMicInit() { @@ -260,13 +259,12 @@ s32 cellMicGetDeviceIdentifier() return CELL_OK; } -Module<> cellMic("cellMic", []() +DECLARE(ppu_module_manager::cellMic)("cellMic", []() { REG_FUNC(cellMic, cellMicInit); REG_FUNC(cellMic, cellMicEnd); REG_FUNC(cellMic, cellMicOpen); REG_FUNC(cellMic, cellMicClose); - REG_FUNC(cellMic, cellMicGetDeviceGUID); REG_FUNC(cellMic, cellMicGetType); REG_FUNC(cellMic, cellMicIsAttached); @@ -276,16 +274,13 @@ Module<> cellMic("cellMic", []() REG_FUNC(cellMic, cellMicGetSignalAttr); REG_FUNC(cellMic, cellMicSetSignalAttr); REG_FUNC(cellMic, cellMicGetSignalState); - REG_FUNC(cellMic, cellMicStart); REG_FUNC(cellMic, cellMicRead); REG_FUNC(cellMic, cellMicStop); REG_FUNC(cellMic, cellMicReset); - REG_FUNC(cellMic, cellMicSetNotifyEventQueue); REG_FUNC(cellMic, cellMicSetNotifyEventQueue2); REG_FUNC(cellMic, cellMicRemoveNotifyEventQueue); - REG_FUNC(cellMic, cellMicOpenEx); REG_FUNC(cellMic, cellMicStartEx); REG_FUNC(cellMic, cellMicGetFormatRaw); @@ -295,7 +290,6 @@ Module<> cellMic("cellMic", []() REG_FUNC(cellMic, cellMicReadRaw); REG_FUNC(cellMic, cellMicReadAux); REG_FUNC(cellMic, cellMicReadDsp); - REG_FUNC(cellMic, cellMicGetStatus); REG_FUNC(cellMic, cellMicStopEx); // this function shouldn't exist REG_FUNC(cellMic, cellMicSysShareClose); diff --git a/rpcs3/Emu/SysCalls/Modules/cellMic.h b/rpcs3/Emu/Cell/Modules/cellMic.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellMic.h rename to rpcs3/Emu/Cell/Modules/cellMic.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellMouse.cpp b/rpcs3/Emu/Cell/Modules/cellMouse.cpp similarity index 71% rename from rpcs3/Emu/SysCalls/Modules/cellMouse.cpp rename to rpcs3/Emu/Cell/Modules/cellMouse.cpp index e4aae28a40..e9cea73dc8 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellMouse.cpp +++ b/rpcs3/Emu/Cell/Modules/cellMouse.cpp @@ -1,42 +1,45 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/IdManager.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/Io/Mouse.h" +#include "Emu/Io/MouseHandler.h" #include "cellMouse.h" -extern Module<> sys_io; +extern _log::channel sys_io; s32 cellMouseInit(u32 max_connect) { sys_io.warning("cellMouseInit(max_connect=%d)", max_connect); - if (Emu.GetMouseManager().IsInited()) - { - return CELL_MOUSE_ERROR_ALREADY_INITIALIZED; - } - if (max_connect > 7) { return CELL_MOUSE_ERROR_INVALID_PARAMETER; } - Emu.GetMouseManager().Init(max_connect); + const auto handler = fxm::import(PURE_EXPR(Emu.GetCallbacks().get_mouse_handler())); + + if (!handler) + { + return CELL_MOUSE_ERROR_ALREADY_INITIALIZED; + } + + handler->Init(max_connect); return CELL_OK; } - s32 cellMouseClearBuf(u32 port_no) { sys_io.trace("cellMouseClearBuf(port_no=%d)", port_no); - if (!Emu.GetMouseManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) { return CELL_MOUSE_ERROR_UNINITIALIZED; } - if (port_no >= Emu.GetMouseManager().GetMice().size()) + if (port_no >= handler->GetMice().size()) { return CELL_MOUSE_ERROR_INVALID_PARAMETER; } @@ -48,14 +51,13 @@ s32 cellMouseClearBuf(u32 port_no) s32 cellMouseEnd() { - sys_io.trace("cellMouseEnd()"); + sys_io.notice("cellMouseEnd()"); - if (!Emu.GetMouseManager().IsInited()) + if (!fxm::remove()) { return CELL_MOUSE_ERROR_UNINITIALIZED; } - Emu.GetMouseManager().Close(); return CELL_OK; } @@ -63,12 +65,14 @@ s32 cellMouseGetInfo(vm::ptr info) { sys_io.trace("cellMouseGetInfo(info=*0x%x)", info); - if (!Emu.GetMouseManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) { return CELL_MOUSE_ERROR_UNINITIALIZED; } - const MouseInfo& current_info = Emu.GetMouseManager().GetInfo(); + const MouseInfo& current_info = handler->GetInfo(); info->max_connect = current_info.max_connect; info->now_connect = current_info.now_connect; info->info = current_info.info; @@ -82,12 +86,15 @@ s32 cellMouseGetInfo(vm::ptr info) s32 cellMouseInfoTabletMode(u32 port_no, vm::ptr info) { sys_io.trace("cellMouseInfoTabletMode(port_no=%d, info=*0x%x)", port_no, info); - if (!Emu.GetMouseManager().IsInited()) + + const auto handler = fxm::get(); + + if (!handler) { return CELL_MOUSE_ERROR_UNINITIALIZED; } - if (port_no >= Emu.GetMouseManager().GetMice().size()) + if (port_no >= handler->GetMice().size()) { return CELL_MOUSE_ERROR_INVALID_PARAMETER; } @@ -101,16 +108,20 @@ s32 cellMouseInfoTabletMode(u32 port_no, vm::ptr info) s32 cellMouseGetData(u32 port_no, vm::ptr data) { sys_io.trace("cellMouseGetData(port_no=%d, data=*0x%x)", port_no, data); - if (!Emu.GetMouseManager().IsInited()) + + const auto handler = fxm::get(); + + if (!handler) { return CELL_MOUSE_ERROR_UNINITIALIZED; } - if (port_no >= Emu.GetMouseManager().GetMice().size()) + + if (port_no >= handler->GetMice().size()) { return CELL_MOUSE_ERROR_NO_DEVICE; } - MouseData& current_data = Emu.GetMouseManager().GetData(port_no); + MouseData& current_data = handler->GetData(port_no); data->update = current_data.update; data->buttons = current_data.buttons; data->x_axis = current_data.x_axis; @@ -147,20 +158,21 @@ s32 cellMouseGetTabletDataList(u32 port_no, u32 data_addr) return CELL_OK; } -s32 cellMouseGetRawData(u32 port_no, vm::ptr data) +s32 cellMouseGetRawData(u32 port_no, vm::ptr data) { sys_io.todo("cellMouseGetRawData(port_no=%d, data=*0x%x)", port_no, data); - /*if (!Emu.GetMouseManager().IsInited()) return CELL_MOUSE_ERROR_UNINITIALIZED; - if (port_no >= Emu.GetMouseManager().GetMice().size()) return CELL_MOUSE_ERROR_NO_DEVICE; - CellMouseRawData& current_rawdata = Emu.GetMouseManager().GetRawData(port_no); - data += current_rawdata.len; - for(s32 i=0; i(); + + if (!handler) { - data += current_rawdata.data[i]; + return CELL_MOUSE_ERROR_UNINITIALIZED; } - current_rawdata.len = 0;*/ + if (port_no >= handler->GetMice().size()) + { + return CELL_MOUSE_ERROR_NO_DEVICE; + } return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellMouse.h b/rpcs3/Emu/Cell/Modules/cellMouse.h similarity index 93% rename from rpcs3/Emu/SysCalls/Modules/cellMouse.h rename to rpcs3/Emu/Cell/Modules/cellMouse.h index 3831a6bea3..61b384f18e 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellMouse.h +++ b/rpcs3/Emu/Cell/Modules/cellMouse.h @@ -51,3 +51,9 @@ struct CellMouseDataList }; static const u32 CELL_MOUSE_MAX_CODES = 64; + +struct CellMouseRawData +{ + be_t len; + u8 data[CELL_MOUSE_MAX_CODES]; +}; diff --git a/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp b/rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp similarity index 94% rename from rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp rename to rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp index bbba03473d..9718fa9a95 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp +++ b/rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp @@ -1,14 +1,14 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/SysCalls/Callback.h" +#include "Emu/Cell/PPUModule.h" #include "cellSysutil.h" #include "cellMsgDialog.h" -extern Module<> cellSysutil; +#include + +extern _log::channel cellSysutil; s32 cellMsgDialogOpen() { @@ -61,7 +61,7 @@ s32 cellMsgDialogOpen2(u32 type, vm::cptr msgString, vm::ptr(WRAP_EXPR(Emu.GetCallbacks().get_msg_dialog())); + const auto dlg = fxm::import(PURE_EXPR(Emu.GetCallbacks().get_msg_dialog())); if (!dlg) { @@ -103,8 +103,21 @@ s32 cellMsgDialogOpen2(u32 type, vm::cptr msgString, vm::ptrCreate(msgString.get_ptr()))).get(); + // Make "shared" promise to workaround std::function limitation + auto spr = std::make_shared>(); + + // Get future + std::future future = spr->get_future(); + + // Run asynchronously in GUI thread + Emu.CallAfter([&, spr = std::move(spr)]() + { + dlg->Create(msgString.get_ptr()); + spr->set_value(); + }); + + // Wait for the "result" + future.get(); return CELL_OK; } @@ -206,7 +219,7 @@ s32 cellMsgDialogClose(f32 delay) const u64 wait_until = get_system_time() + static_cast(std::max(delay, 0.0f) * 1000); - thread_ctrl::spawn(PURE_EXPR("MsgDialog Thread"s), [=]() + thread_ctrl::spawn("MsgDialog Thread", [=]() { while (dlg->state == MsgDialogState::Open && get_system_time() < wait_until) { diff --git a/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.h b/rpcs3/Emu/Cell/Modules/cellMsgDialog.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellMsgDialog.h rename to rpcs3/Emu/Cell/Modules/cellMsgDialog.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellMusic.cpp b/rpcs3/Emu/Cell/Modules/cellMusic.cpp similarity index 61% rename from rpcs3/Emu/SysCalls/Modules/cellMusic.cpp rename to rpcs3/Emu/Cell/Modules/cellMusic.cpp index 38525e4f7d..6fe8cd4146 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellMusic.cpp +++ b/rpcs3/Emu/Cell/Modules/cellMusic.cpp @@ -1,13 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Callback.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellMusic.h" -extern Module<> cellMusic; +LOG_CHANNEL(cellMusic); struct music2_t { @@ -144,28 +142,28 @@ s32 cellMusicGetVolume2() } -Module<> cellMusic("cellMusic", []() +DECLARE(ppu_module_manager::cellMusic)("cellMusicUtility", []() { - REG_FUNC(cellMusic, cellMusicGetSelectionContext); - REG_FUNC(cellMusic, cellMusicSetSelectionContext2); - REG_FUNC(cellMusic, cellMusicSetVolume2); - REG_FUNC(cellMusic, cellMusicGetContentsId); - REG_FUNC(cellMusic, cellMusicSetSelectionContext); - REG_FUNC(cellMusic, cellMusicInitialize2SystemWorkload); - REG_FUNC(cellMusic, cellMusicGetPlaybackStatus2); - REG_FUNC(cellMusic, cellMusicGetContentsId2); - REG_FUNC(cellMusic, cellMusicFinalize); - REG_FUNC(cellMusic, cellMusicInitializeSystemWorkload); - REG_FUNC(cellMusic, cellMusicInitialize); - REG_FUNC(cellMusic, cellMusicFinalize2); - REG_FUNC(cellMusic, cellMusicGetSelectionContext2); - REG_FUNC(cellMusic, cellMusicGetVolume); - REG_FUNC(cellMusic, cellMusicGetPlaybackStatus); - REG_FUNC(cellMusic, cellMusicSetPlaybackCommand2); - REG_FUNC(cellMusic, cellMusicSetPlaybackCommand); - REG_FUNC(cellMusic, cellMusicSelectContents2); - REG_FUNC(cellMusic, cellMusicSelectContents); - REG_FUNC(cellMusic, cellMusicInitialize2); - REG_FUNC(cellMusic, cellMusicSetVolume); - REG_FUNC(cellMusic, cellMusicGetVolume2); + REG_FUNC(cellMusicUtility, cellMusicGetSelectionContext); + REG_FUNC(cellMusicUtility, cellMusicSetSelectionContext2); + REG_FUNC(cellMusicUtility, cellMusicSetVolume2); + REG_FUNC(cellMusicUtility, cellMusicGetContentsId); + REG_FUNC(cellMusicUtility, cellMusicSetSelectionContext); + REG_FUNC(cellMusicUtility, cellMusicInitialize2SystemWorkload); + REG_FUNC(cellMusicUtility, cellMusicGetPlaybackStatus2); + REG_FUNC(cellMusicUtility, cellMusicGetContentsId2); + REG_FUNC(cellMusicUtility, cellMusicFinalize); + REG_FUNC(cellMusicUtility, cellMusicInitializeSystemWorkload); + REG_FUNC(cellMusicUtility, cellMusicInitialize); + REG_FUNC(cellMusicUtility, cellMusicFinalize2); + REG_FUNC(cellMusicUtility, cellMusicGetSelectionContext2); + REG_FUNC(cellMusicUtility, cellMusicGetVolume); + REG_FUNC(cellMusicUtility, cellMusicGetPlaybackStatus); + REG_FUNC(cellMusicUtility, cellMusicSetPlaybackCommand2); + REG_FUNC(cellMusicUtility, cellMusicSetPlaybackCommand); + REG_FUNC(cellMusicUtility, cellMusicSelectContents2); + REG_FUNC(cellMusicUtility, cellMusicSelectContents); + REG_FUNC(cellMusicUtility, cellMusicInitialize2); + REG_FUNC(cellMusicUtility, cellMusicSetVolume); + REG_FUNC(cellMusicUtility, cellMusicGetVolume2); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellMusic.h b/rpcs3/Emu/Cell/Modules/cellMusic.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellMusic.h rename to rpcs3/Emu/Cell/Modules/cellMusic.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellMusicDecode.cpp b/rpcs3/Emu/Cell/Modules/cellMusicDecode.cpp similarity index 65% rename from rpcs3/Emu/SysCalls/Modules/cellMusicDecode.cpp rename to rpcs3/Emu/Cell/Modules/cellMusicDecode.cpp index 0d86d8c1d5..dcb43e75a8 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellMusicDecode.cpp +++ b/rpcs3/Emu/Cell/Modules/cellMusicDecode.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellMusicDecode; +LOG_CHANNEL(cellMusicDecode); // Return Codes enum @@ -145,27 +144,27 @@ s32 cellMusicDecodeGetContentsId2() } -Module<> cellMusicDecode("cellMusicDecode", []() +DECLARE(ppu_module_manager::cellMusicDecode)("cellMusicDecodeUtility", []() { - REG_FUNC(cellMusicDecode, cellMusicDecodeInitialize); - REG_FUNC(cellMusicDecode, cellMusicDecodeInitializeSystemWorkload); - REG_FUNC(cellMusicDecode, cellMusicDecodeFinalize); - REG_FUNC(cellMusicDecode, cellMusicDecodeSelectContents); - REG_FUNC(cellMusicDecode, cellMusicDecodeSetDecodeCommand); - REG_FUNC(cellMusicDecode, cellMusicDecodeGetDecodeStatus); - REG_FUNC(cellMusicDecode, cellMusicDecodeRead); - REG_FUNC(cellMusicDecode, cellMusicDecodeGetSelectionContext); - REG_FUNC(cellMusicDecode, cellMusicDecodeSetSelectionContext); - REG_FUNC(cellMusicDecode, cellMusicDecodeGetContentsId); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeInitialize); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeInitializeSystemWorkload); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeFinalize); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeSelectContents); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeSetDecodeCommand); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeGetDecodeStatus); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeRead); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeGetSelectionContext); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeSetSelectionContext); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeGetContentsId); - REG_FUNC(cellMusicDecode, cellMusicDecodeInitialize2); - REG_FUNC(cellMusicDecode, cellMusicDecodeInitialize2SystemWorkload); - REG_FUNC(cellMusicDecode, cellMusicDecodeFinalize2); - REG_FUNC(cellMusicDecode, cellMusicDecodeSelectContents2); - REG_FUNC(cellMusicDecode, cellMusicDecodeSetDecodeCommand2); - REG_FUNC(cellMusicDecode, cellMusicDecodeGetDecodeStatus2); - REG_FUNC(cellMusicDecode, cellMusicDecodeRead2); - REG_FUNC(cellMusicDecode, cellMusicDecodeGetSelectionContext2); - REG_FUNC(cellMusicDecode, cellMusicDecodeSetSelectionContext2); - REG_FUNC(cellMusicDecode, cellMusicDecodeGetContentsId2); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeInitialize2); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeInitialize2SystemWorkload); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeFinalize2); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeSelectContents2); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeSetDecodeCommand2); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeGetDecodeStatus2); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeRead2); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeGetSelectionContext2); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeSetSelectionContext2); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeGetContentsId2); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellMusicExport.cpp b/rpcs3/Emu/Cell/Modules/cellMusicExport.cpp similarity index 72% rename from rpcs3/Emu/SysCalls/Modules/cellMusicExport.cpp rename to rpcs3/Emu/Cell/Modules/cellMusicExport.cpp index 690188e000..0c614e907e 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellMusicExport.cpp +++ b/rpcs3/Emu/Cell/Modules/cellMusicExport.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellMusicExport; +LOG_CHANNEL(cellMusicExport); // Return Codes enum @@ -51,11 +50,11 @@ s32 cellMusicExportProgress() return CELL_OK; } -Module<> cellMusicExport("cellMusicExport", []() +DECLARE(ppu_module_manager::cellMusicExport)("cellMusicExportUtility", []() { - REG_FUNC(cellMusicExport, cellMusicExportInitialize); - REG_FUNC(cellMusicExport, cellMusicExportInitialize2); - REG_FUNC(cellMusicExport, cellMusicExportFinalize); - REG_FUNC(cellMusicExport, cellMusicExportFromFile); - REG_FUNC(cellMusicExport, cellMusicExportProgress); + REG_FUNC(cellMusicExportUtility, cellMusicExportInitialize); + REG_FUNC(cellMusicExportUtility, cellMusicExportInitialize2); + REG_FUNC(cellMusicExportUtility, cellMusicExportFinalize); + REG_FUNC(cellMusicExportUtility, cellMusicExportFromFile); + REG_FUNC(cellMusicExportUtility, cellMusicExportProgress); }); diff --git a/rpcs3/Emu/Cell/Modules/cellNetCtl.cpp b/rpcs3/Emu/Cell/Modules/cellNetCtl.cpp new file mode 100644 index 0000000000..361daa9849 --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/cellNetCtl.cpp @@ -0,0 +1,211 @@ +#include "stdafx.h" +#include "Emu/System.h" +#include "Emu/Cell/PPUModule.h" + +#include "cellSysutil.h" +#include "cellNetCtl.h" + +LOG_CHANNEL(cellNetCtl); + +cfg::map_entry g_cfg_net_status(cfg::root.net, "Connection status", +{ + { "Disconnected", CELL_NET_CTL_STATE_Disconnected }, + { "Connecting", CELL_NET_CTL_STATE_Connecting }, + { "Obtaining IP", CELL_NET_CTL_STATE_IPObtaining }, + { "IP Obtained", CELL_NET_CTL_STATE_IPObtained }, +}); + +cfg::string_entry g_cfg_net_ip_address(cfg::root.net, "IP address", "192.168.1.1"); + +s32 cellNetCtlInit() +{ + cellNetCtl.warning("cellNetCtlInit()"); + + return CELL_OK; +} + +s32 cellNetCtlTerm() +{ + cellNetCtl.warning("cellNetCtlTerm()"); + + return CELL_OK; +} + +s32 cellNetCtlGetState(vm::ptr state) +{ + cellNetCtl.trace("cellNetCtlGetState(state=*0x%x)", state); + + *state = g_cfg_net_status.get(); + return CELL_OK; +} + +s32 cellNetCtlAddHandler(vm::ptr handler, vm::ptr arg, vm::ptr hid) +{ + cellNetCtl.todo("cellNetCtlAddHandler(handler=*0x%x, arg=*0x%x, hid=*0x%x)", handler, arg, hid); + + return CELL_OK; +} + +s32 cellNetCtlDelHandler(s32 hid) +{ + cellNetCtl.todo("cellNetCtlDelHandler(hid=0x%x)", hid); + + return CELL_OK; +} + +s32 cellNetCtlGetInfo(s32 code, vm::ptr info) +{ + cellNetCtl.todo("cellNetCtlGetInfo(code=0x%x (%s), info=*0x%x)", code, InfoCodeToName(code), info); + + if (code == CELL_NET_CTL_INFO_MTU) + { + info->mtu = 1500; + } + else if (code == CELL_NET_CTL_INFO_LINK) + { + if (g_cfg_net_status.get() != CELL_NET_CTL_STATE_Disconnected) + { + info->link = CELL_NET_CTL_LINK_CONNECTED; + } + else + { + info->link = CELL_NET_CTL_LINK_DISCONNECTED; + } + } + else if (code == CELL_NET_CTL_INFO_IP_ADDRESS) + { + if (g_cfg_net_status.get() != CELL_NET_CTL_STATE_IPObtained) + { + // 0.0.0.0 seems to be the default address when no ethernet cables are connected to the PS3 + strcpy_trunc(info->ip_address, "0.0.0.0"); + } + else + { + strcpy_trunc(info->ip_address, g_cfg_net_ip_address); + } + } + else if (code == CELL_NET_CTL_INFO_NETMASK) + { + strcpy_trunc(info->netmask, "255.255.255.255"); + } + + return CELL_OK; +} + +s32 cellNetCtlNetStartDialogLoadAsync(vm::ptr param) +{ + cellNetCtl.error("cellNetCtlNetStartDialogLoadAsync(param=*0x%x)", param); + + // TODO: Actually sign into PSN or an emulated network similar to PSN (ESN) + // TODO: Properly open the dialog prompt for sign in + sysutilSendSystemCommand(CELL_SYSUTIL_NET_CTL_NETSTART_LOADED, 0); + sysutilSendSystemCommand(CELL_SYSUTIL_NET_CTL_NETSTART_FINISHED, 0); + + return CELL_OK; +} + +s32 cellNetCtlNetStartDialogAbortAsync() +{ + cellNetCtl.error("cellNetCtlNetStartDialogAbortAsync()"); + + return CELL_OK; +} + +s32 cellNetCtlNetStartDialogUnloadAsync(vm::ptr result) +{ + cellNetCtl.warning("cellNetCtlNetStartDialogUnloadAsync(result=*0x%x)", result); + + result->result = CELL_NET_CTL_ERROR_DIALOG_CANCELED; + sysutilSendSystemCommand(CELL_SYSUTIL_NET_CTL_NETSTART_UNLOADED, 0); + + return CELL_OK; +} + +s32 cellNetCtlGetNatInfo(vm::ptr natInfo) +{ + cellNetCtl.todo("cellNetCtlGetNatInfo(natInfo=*0x%x)", natInfo); + + if (natInfo->size == 0) + { + cellNetCtl.error("cellNetCtlGetNatInfo : CELL_NET_CTL_ERROR_INVALID_SIZE"); + return CELL_NET_CTL_ERROR_INVALID_SIZE; + } + + return CELL_OK; +} + +s32 cellGameUpdateInit() +{ + throw EXCEPTION(""); +} + +s32 cellGameUpdateTerm() +{ + throw EXCEPTION(""); +} + + +s32 cellGameUpdateCheckStartAsync() +{ + throw EXCEPTION(""); +} + +s32 cellGameUpdateCheckFinishAsync() +{ + throw EXCEPTION(""); +} + +s32 cellGameUpdateCheckStartWithoutDialogAsync() +{ + throw EXCEPTION(""); +} + +s32 cellGameUpdateCheckAbort() +{ + throw EXCEPTION(""); +} + +s32 cellGameUpdateCheckStartAsyncEx() +{ + throw EXCEPTION(""); +} + +s32 cellGameUpdateCheckFinishAsyncEx() +{ + throw EXCEPTION(""); +} + +s32 cellGameUpdateCheckStartWithoutDialogAsyncEx() +{ + throw EXCEPTION(""); +} + + +DECLARE(ppu_module_manager::cellNetCtl)("cellNetCtl", []() +{ + REG_FUNC(cellNetCtl, cellNetCtlInit); + REG_FUNC(cellNetCtl, cellNetCtlTerm); + + REG_FUNC(cellNetCtl, cellNetCtlGetState); + REG_FUNC(cellNetCtl, cellNetCtlAddHandler); + REG_FUNC(cellNetCtl, cellNetCtlDelHandler); + + REG_FUNC(cellNetCtl, cellNetCtlGetInfo); + + REG_FUNC(cellNetCtl, cellNetCtlNetStartDialogLoadAsync); + REG_FUNC(cellNetCtl, cellNetCtlNetStartDialogAbortAsync); + REG_FUNC(cellNetCtl, cellNetCtlNetStartDialogUnloadAsync); + + REG_FUNC(cellNetCtl, cellNetCtlGetNatInfo); + + REG_FUNC(cellNetCtl, cellGameUpdateInit); + REG_FUNC(cellNetCtl, cellGameUpdateTerm); + + REG_FUNC(cellNetCtl, cellGameUpdateCheckStartAsync); + REG_FUNC(cellNetCtl, cellGameUpdateCheckFinishAsync); + REG_FUNC(cellNetCtl, cellGameUpdateCheckStartWithoutDialogAsync); + REG_FUNC(cellNetCtl, cellGameUpdateCheckAbort); + REG_FUNC(cellNetCtl, cellGameUpdateCheckStartAsyncEx); + REG_FUNC(cellNetCtl, cellGameUpdateCheckFinishAsyncEx); + REG_FUNC(cellNetCtl, cellGameUpdateCheckStartWithoutDialogAsyncEx); +}); diff --git a/rpcs3/Emu/SysCalls/Modules/cellNetCtl.h b/rpcs3/Emu/Cell/Modules/cellNetCtl.h similarity index 97% rename from rpcs3/Emu/SysCalls/Modules/cellNetCtl.h rename to rpcs3/Emu/Cell/Modules/cellNetCtl.h index 4e08262927..28900f7a56 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellNetCtl.h +++ b/rpcs3/Emu/Cell/Modules/cellNetCtl.h @@ -220,19 +220,19 @@ union CellNetCtlInfo CellNetCtlSSID ssid; be_t wlan_security; be_t auth_8021x_type; - s8 auth_8021x_auth_name[128]; + char auth_8021x_auth_name[128]; u8 rssi; u8 channel; be_t ip_config; - s8 dhcp_hostname[256]; - s8 pppoe_auth_name[128]; + char dhcp_hostname[256]; + char pppoe_auth_name[128]; char ip_address[16]; - s8 netmask[16]; - s8 default_route[16]; - s8 primary_dns[16]; - s8 secondary_dns[16]; + char netmask[16]; + char default_route[16]; + char primary_dns[16]; + char secondary_dns[16]; be_t http_proxy_config; - s8 http_proxy_server[256]; + char http_proxy_server[256]; be_t http_proxy_port; be_t upnp_config; }; diff --git a/rpcs3/Emu/SysCalls/Modules/cellOskDialog.cpp b/rpcs3/Emu/Cell/Modules/cellOskDialog.cpp similarity index 68% rename from rpcs3/Emu/SysCalls/Modules/cellOskDialog.cpp rename to rpcs3/Emu/Cell/Modules/cellOskDialog.cpp index 6a83bd544e..ccc0c51f7f 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellOskDialog.cpp +++ b/rpcs3/Emu/Cell/Modules/cellOskDialog.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellOskDialog; +LOG_CHANNEL(cellOskDialog); s32 cellOskDialogLoadAsync() { @@ -153,9 +152,6 @@ s32 cellOskDialogExtRegisterForceFinishCallback() void cellSysutil_OskDialog_init() { - extern Module<> cellSysutil; - - // cellOskDialog functions: REG_FUNC(cellSysutil, cellOskDialogLoadAsync); REG_FUNC(cellSysutil, cellOskDialogUnloadAsync); REG_FUNC(cellSysutil, cellOskDialogGetSize); @@ -171,23 +167,22 @@ void cellSysutil_OskDialog_init() REG_FUNC(cellSysutil, cellOskDialogGetInputText); } -Module<> cellOskDialog("cellOskDialog", []() +DECLARE(ppu_module_manager::cellOskDialog)("cellOskExtUtility", []() { - // cellOskDialogExt functions: - REG_FUNC(cellOskDialog, cellOskDialogExtInputDeviceUnlock); - REG_FUNC(cellOskDialog, cellOskDialogExtRegisterKeyboardEventHookCallback); - REG_FUNC(cellOskDialog, cellOskDialogExtAddJapaneseOptionDictionary); - REG_FUNC(cellOskDialog, cellOskDialogExtEnableClipboard); - REG_FUNC(cellOskDialog, cellOskDialogExtSendFinishMessage); - REG_FUNC(cellOskDialog, cellOskDialogExtAddOptionDictionary); - REG_FUNC(cellOskDialog, cellOskDialogExtSetInitialScale); - REG_FUNC(cellOskDialog, cellOskDialogExtInputDeviceLock); - REG_FUNC(cellOskDialog, cellOskDialogExtSetBaseColor); - REG_FUNC(cellOskDialog, cellOskDialogExtRegisterConfirmWordFilterCallback); - REG_FUNC(cellOskDialog, cellOskDialogExtUpdateInputText); - REG_FUNC(cellOskDialog, cellOskDialogExtDisableHalfByteKana); - REG_FUNC(cellOskDialog, cellOskDialogExtSetPointerEnable); - REG_FUNC(cellOskDialog, cellOskDialogExtUpdatePointerDisplayPos); - REG_FUNC(cellOskDialog, cellOskDialogExtEnableHalfByteKana); - REG_FUNC(cellOskDialog, cellOskDialogExtRegisterForceFinishCallback); + REG_FUNC(cellOskExtUtility, cellOskDialogExtInputDeviceUnlock); + REG_FUNC(cellOskExtUtility, cellOskDialogExtRegisterKeyboardEventHookCallback); + REG_FUNC(cellOskExtUtility, cellOskDialogExtAddJapaneseOptionDictionary); + REG_FUNC(cellOskExtUtility, cellOskDialogExtEnableClipboard); + REG_FUNC(cellOskExtUtility, cellOskDialogExtSendFinishMessage); + REG_FUNC(cellOskExtUtility, cellOskDialogExtAddOptionDictionary); + REG_FUNC(cellOskExtUtility, cellOskDialogExtSetInitialScale); + REG_FUNC(cellOskExtUtility, cellOskDialogExtInputDeviceLock); + REG_FUNC(cellOskExtUtility, cellOskDialogExtSetBaseColor); + REG_FUNC(cellOskExtUtility, cellOskDialogExtRegisterConfirmWordFilterCallback); + REG_FUNC(cellOskExtUtility, cellOskDialogExtUpdateInputText); + REG_FUNC(cellOskExtUtility, cellOskDialogExtDisableHalfByteKana); + REG_FUNC(cellOskExtUtility, cellOskDialogExtSetPointerEnable); + REG_FUNC(cellOskExtUtility, cellOskDialogExtUpdatePointerDisplayPos); + REG_FUNC(cellOskExtUtility, cellOskDialogExtEnableHalfByteKana); + REG_FUNC(cellOskExtUtility, cellOskDialogExtRegisterForceFinishCallback); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellOvis.cpp b/rpcs3/Emu/Cell/Modules/cellOvis.cpp similarity index 82% rename from rpcs3/Emu/SysCalls/Modules/cellOvis.cpp rename to rpcs3/Emu/Cell/Modules/cellOvis.cpp index ce14d263d5..49e22da87f 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellOvis.cpp +++ b/rpcs3/Emu/Cell/Modules/cellOvis.cpp @@ -1,10 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -namespace vm { using namespace ps3; } - -extern Module<> cellOvis; +LOG_CHANNEL(cellOvis); // Return Codes enum @@ -38,7 +35,7 @@ s32 cellOvisInvalidateOverlappedSegments() return CELL_OK; } -Module<> cellOvis("cellOvis", []() +DECLARE(ppu_module_manager::cellOvis)("cellOvis", []() { REG_FUNC(cellOvis, cellOvisGetOverlayTableSize); REG_FUNC(cellOvis, cellOvisInitializeOverlayTable); diff --git a/rpcs3/Emu/SysCalls/Modules/cellPad.cpp b/rpcs3/Emu/Cell/Modules/cellPad.cpp similarity index 85% rename from rpcs3/Emu/SysCalls/Modules/cellPad.cpp rename to rpcs3/Emu/Cell/Modules/cellPad.cpp index d691ff3023..f0441cc739 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPad.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPad.cpp @@ -1,37 +1,37 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/IdManager.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/Io/Pad.h" +#include "Emu/Io/PadHandler.h" #include "cellPad.h" -extern Module<> sys_io; +extern _log::channel sys_io; s32 cellPadInit(u32 max_connect) { sys_io.warning("cellPadInit(max_connect=%d)", max_connect); - if (Emu.GetPadManager().IsInited()) - return CELL_PAD_ERROR_ALREADY_INITIALIZED; - if (max_connect > CELL_PAD_MAX_PORT_NUM) return CELL_PAD_ERROR_INVALID_PARAMETER; - Emu.GetPadManager().Init(max_connect); + const auto handler = fxm::import(PURE_EXPR(Emu.GetCallbacks().get_pad_handler())); + + if (!handler) + return CELL_PAD_ERROR_ALREADY_INITIALIZED; + + handler->Init(max_connect); return CELL_OK; } s32 cellPadEnd() { - sys_io.trace("cellPadEnd()"); + sys_io.notice("cellPadEnd()"); - if (!Emu.GetPadManager().IsInited()) + if (!fxm::remove()) return CELL_PAD_ERROR_UNINITIALIZED; - Emu.GetPadManager().Close(); - return CELL_OK; } @@ -39,10 +39,12 @@ s32 cellPadClearBuf(u32 port_no) { sys_io.trace("cellPadClearBuf(port_no=%d)", port_no); - if (!Emu.GetPadManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; - const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); + const PadInfo& rinfo = handler->GetInfo(); if (port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER; @@ -52,7 +54,7 @@ s32 cellPadClearBuf(u32 port_no) //Set 'm_buffer_cleared' to force a resend of everything //might as well also reset everything in our pad 'buffer' to nothing as well - std::vector& pads = Emu.GetPadManager().GetPads(); + std::vector& pads = handler->GetPads(); Pad& pad = pads[port_no]; pad.m_buffer_cleared = true; @@ -74,18 +76,18 @@ s32 cellPadPeriphGetInfo(vm::ptr info) { sys_io.todo("cellPadPeriphGetInfo(info=*0x%x)", info); - if (!Emu.GetPadManager().IsInited()) - { - return CELL_PAD_ERROR_UNINITIALIZED; - } + const auto handler = fxm::get(); - const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); + if (!handler) + return CELL_PAD_ERROR_UNINITIALIZED; + + const PadInfo& rinfo = handler->GetInfo(); info->max_connect = rinfo.max_connect; info->now_connect = rinfo.now_connect; info->system_info = rinfo.system_info; - std::vector& pads = Emu.GetPadManager().GetPads(); + std::vector& pads = handler->GetPads(); // TODO: Support other types of controllers for (u32 i = 0; i < CELL_PAD_MAX_PORT_NUM; ++i) @@ -113,12 +115,14 @@ s32 cellPadGetData(u32 port_no, vm::ptr data) { sys_io.trace("cellPadGetData(port_no=%d, data=*0x%x)", port_no, data); - std::vector& pads = Emu.GetPadManager().GetPads(); + const auto handler = fxm::get(); - if (!Emu.GetPadManager().IsInited()) + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; - const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); + std::vector& pads = handler->GetPads(); + + const PadInfo& rinfo = handler->GetInfo(); if (port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER; @@ -297,10 +301,12 @@ s32 cellPadGetDataExtra(u32 port_no, vm::ptr device_type, vm::ptr(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; - const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); + const PadInfo& rinfo = handler->GetInfo(); if (port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER; @@ -314,10 +320,12 @@ s32 cellPadSetActDirect(u32 port_no, vm::ptr param) { sys_io.trace("cellPadSetActDirect(port_no=%d, param=*0x%x)", port_no, param); - if (!Emu.GetPadManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; - const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); + const PadInfo& rinfo = handler->GetInfo(); if (port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER; @@ -331,16 +339,18 @@ s32 cellPadGetInfo(vm::ptr info) { sys_io.trace("cellPadGetInfo(info=*0x%x)", info); - if (!Emu.GetPadManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; - const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); + const PadInfo& rinfo = handler->GetInfo(); info->max_connect = rinfo.max_connect; info->now_connect = rinfo.now_connect; info->system_info = rinfo.system_info; //Can't have this as const, we need to reset Assign Changes Flag here - std::vector& pads = Emu.GetPadManager().GetPads(); + std::vector& pads = handler->GetPads(); for (u32 i=0; i info) { sys_io.trace("cellPadGetInfo2(info=*0x%x)", info); - if (!Emu.GetPadManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; - const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); + const PadInfo& rinfo = handler->GetInfo(); info->max_connect = rinfo.max_connect; info->now_connect = rinfo.now_connect; info->system_info = rinfo.system_info; - std::vector& pads = Emu.GetPadManager().GetPads(); + std::vector& pads = handler->GetPads(); for (u32 i=0; i info) { sys_io.trace("cellPadGetCapabilityInfo(port_no=%d, data_addr:=0x%x)", port_no, info.addr()); - if (!Emu.GetPadManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; - const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); + const PadInfo& rinfo = handler->GetInfo(); if (port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER; if (port_no >= rinfo.now_connect) return CELL_PAD_ERROR_NO_DEVICE; - const std::vector& pads = Emu.GetPadManager().GetPads(); + const std::vector& pads = handler->GetPads(); //Should return the same as device capability mask, psl1ght has it backwards in pad.h info->info[0] = pads[port_no].m_device_capability; @@ -411,17 +425,19 @@ s32 cellPadSetPortSetting(u32 port_no, u32 port_setting) { sys_io.trace("cellPadSetPortSetting(port_no=%d, port_setting=0x%x)", port_no, port_setting); - if (!Emu.GetPadManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; - const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); + const PadInfo& rinfo = handler->GetInfo(); if (port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER; if (port_no >= rinfo.now_connect) return CELL_PAD_ERROR_NO_DEVICE; - std::vector& pads = Emu.GetPadManager().GetPads(); + std::vector& pads = handler->GetPads(); pads[port_no].m_port_setting = port_setting; return CELL_OK; @@ -431,17 +447,19 @@ s32 cellPadInfoPressMode(u32 port_no) { sys_io.trace("cellPadInfoPressMode(port_no=%d)", port_no); - if (!Emu.GetPadManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; - const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); + const PadInfo& rinfo = handler->GetInfo(); if (port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER; if (port_no >= rinfo.now_connect) return CELL_PAD_ERROR_NO_DEVICE; - const std::vector& pads = Emu.GetPadManager().GetPads(); + const std::vector& pads = handler->GetPads(); return (pads[port_no].m_device_capability & CELL_PAD_CAPABILITY_PRESS_MODE) > 0; } @@ -450,17 +468,19 @@ s32 cellPadInfoSensorMode(u32 port_no) { sys_io.trace("cellPadInfoSensorMode(port_no=%d)", port_no); - if (!Emu.GetPadManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; - const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); + const PadInfo& rinfo = handler->GetInfo(); if (port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER; if (port_no >= rinfo.now_connect) return CELL_PAD_ERROR_NO_DEVICE; - const std::vector& pads = Emu.GetPadManager().GetPads(); + const std::vector& pads = handler->GetPads(); return (pads[port_no].m_device_capability & CELL_PAD_CAPABILITY_SENSOR_MODE) > 0; } @@ -469,19 +489,22 @@ s32 cellPadSetPressMode(u32 port_no, u32 mode) { sys_io.trace("cellPadSetPressMode(port_no=%d, mode=%d)", port_no, mode); - if (!Emu.GetPadManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; + if (mode != 0 && mode != 1) return CELL_PAD_ERROR_INVALID_PARAMETER; - const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); + const PadInfo& rinfo = handler->GetInfo(); if (port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER; if (port_no >= rinfo.now_connect) return CELL_PAD_ERROR_NO_DEVICE; - std::vector& pads = Emu.GetPadManager().GetPads(); + std::vector& pads = handler->GetPads(); if (mode) pads[port_no].m_port_setting |= CELL_PAD_SETTING_PRESS_ON; @@ -495,19 +518,22 @@ s32 cellPadSetSensorMode(u32 port_no, u32 mode) { sys_io.trace("cellPadSetSensorMode(port_no=%d, mode=%d)", port_no, mode); - if (!Emu.GetPadManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; + if (mode != 0 && mode != 1) return CELL_PAD_ERROR_INVALID_PARAMETER; - const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); + const PadInfo& rinfo = handler->GetInfo(); if (port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER; if (port_no >= rinfo.now_connect) return CELL_PAD_ERROR_NO_DEVICE; - std::vector& pads = Emu.GetPadManager().GetPads(); + std::vector& pads = handler->GetPads(); if (mode) pads[port_no].m_port_setting |= CELL_PAD_SETTING_SENSOR_ON; @@ -521,7 +547,9 @@ s32 cellPadLddRegisterController() { sys_io.todo("cellPadLddRegisterController()"); - if (!Emu.GetPadManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; return CELL_OK; @@ -531,7 +559,9 @@ s32 cellPadLddDataInsert(s32 handle, vm::ptr data) { sys_io.todo("cellPadLddDataInsert(handle=%d, data=*0x%x)", handle, data); - if (!Emu.GetPadManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; return CELL_OK; @@ -541,7 +571,9 @@ s32 cellPadLddGetPortNo(s32 handle) { sys_io.todo("cellPadLddGetPortNo(handle=%d)", handle); - if (!Emu.GetPadManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; return CELL_OK; @@ -551,7 +583,9 @@ s32 cellPadLddUnregisterController(s32 handle) { sys_io.todo("cellPadLddUnregisterController(handle=%d)", handle); - if (!Emu.GetPadManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; return CELL_OK; diff --git a/rpcs3/Emu/SysCalls/Modules/cellPad.h b/rpcs3/Emu/Cell/Modules/cellPad.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellPad.h rename to rpcs3/Emu/Cell/Modules/cellPad.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellPamf.cpp b/rpcs3/Emu/Cell/Modules/cellPamf.cpp similarity index 95% rename from rpcs3/Emu/SysCalls/Modules/cellPamf.cpp rename to rpcs3/Emu/Cell/Modules/cellPamf.cpp index 36f26bcea9..fcd64720b6 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPamf.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPamf.cpp @@ -1,16 +1,23 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellPamf.h" -extern Module<> cellPamf; +const std::function SQUEUE_ALWAYS_EXIT = []() { return true; }; +const std::function SQUEUE_NEVER_EXIT = []() { return false; }; + +bool squeue_test_exit() +{ + return Emu.IsStopped(); +} + +LOG_CHANNEL(cellPamf); s32 pamfStreamTypeToEsFilterId(u8 type, u8 ch, CellCodecEsFilterId& pEsFilterId) { // convert type and ch to EsFilterId - assert(ch < 16); + Expects(ch < 16); pEsFilterId.supplementalInfo1 = type == CELL_PAMF_STREAM_TYPE_AVC; pEsFilterId.supplementalInfo2 = 0; @@ -110,7 +117,7 @@ s32 pamfStreamTypeToEsFilterId(u8 type, u8 ch, CellCodecEsFilterId& pEsFilterId) u8 pamfGetStreamType(vm::ptr pSelf, u32 stream) { // TODO: get stream type correctly - assert(stream < (u32)pSelf->pAddr->stream_count); + Expects(stream < (u32)pSelf->pAddr->stream_count); auto& header = pSelf->pAddr->stream_headers[stream]; switch (header.type) @@ -131,7 +138,7 @@ u8 pamfGetStreamType(vm::ptr pSelf, u32 stream) u8 pamfGetStreamChannel(vm::ptr pSelf, u32 stream) { // TODO: get stream channel correctly - assert(stream < (u32)pSelf->pAddr->stream_count); + Expects(stream < (u32)pSelf->pAddr->stream_count); auto& header = pSelf->pAddr->stream_headers[stream]; switch (header.type) @@ -139,29 +146,29 @@ u8 pamfGetStreamChannel(vm::ptr pSelf, u32 stream) case 0x1b: // AVC case 0x02: // M2V { - assert((header.fid_major & 0xf0) == 0xe0 && header.fid_minor == 0); + Expects((header.fid_major & 0xf0) == 0xe0 && header.fid_minor == 0); return header.fid_major % 16; } case 0xdc: // ATRAC3PLUS { - assert(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0); + Expects(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0); return header.fid_minor % 16; } case 0x80: // LPCM { - assert(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x40); + Expects(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x40); return header.fid_minor % 16; } case 0x81: // AC3 { - assert(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x30); + Expects(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x30); return header.fid_minor % 16; } case 0xdd: { - assert(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x20); + Expects(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x20); return header.fid_minor % 16; } } @@ -447,7 +454,7 @@ s32 cellPamfReaderGetEsFilterId(vm::ptr pSelf, vm::ptrstream < (u32)pSelf->pAddr->stream_count); + Expects((u32)pSelf->stream < (u32)pSelf->pAddr->stream_count); auto& header = pSelf->pAddr->stream_headers[pSelf->stream]; pEsFilterId->filterIdMajor = header.fid_major; pEsFilterId->filterIdMinor = header.fid_minor; @@ -460,7 +467,7 @@ s32 cellPamfReaderGetStreamInfo(vm::ptr pSelf, vm::ptr pIn { cellPamf.warning("cellPamfReaderGetStreamInfo(pSelf=*0x%x, pInfo=*0x%x, size=%d)", pSelf, pInfo, size); - assert((u32)pSelf->stream < (u32)pSelf->pAddr->stream_count); + Expects((u32)pSelf->stream < (u32)pSelf->pAddr->stream_count); auto& header = pSelf->pAddr->stream_headers[pSelf->stream]; const u8 type = pamfGetStreamType(pSelf, pSelf->stream); const u8 ch = pamfGetStreamChannel(pSelf, pSelf->stream); @@ -733,7 +740,7 @@ s32 cellPamfEpIteratorMove(vm::ptr pIt, s32 steps, vm::ptr cellPamf("cellPamf", []() +DECLARE(ppu_module_manager::cellPamf)("cellPamf", []() { REG_FUNC(cellPamf, cellPamfGetHeaderSize); REG_FUNC(cellPamf, cellPamfGetHeaderSize2); diff --git a/rpcs3/Emu/SysCalls/Modules/cellPamf.h b/rpcs3/Emu/Cell/Modules/cellPamf.h similarity index 59% rename from rpcs3/Emu/SysCalls/Modules/cellPamf.h rename to rpcs3/Emu/Cell/Modules/cellPamf.h index 823a1b564f..4dd45b3256 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPamf.h +++ b/rpcs3/Emu/Cell/Modules/cellPamf.h @@ -399,3 +399,342 @@ struct CellPamfReader CHECK_SIZE(CellPamfReader, 128); s32 cellPamfReaderInitialize(vm::ptr pSelf, vm::cptr pAddr, u64 fileSize, u32 attribute); + + +extern const std::function SQUEUE_ALWAYS_EXIT; +extern const std::function SQUEUE_NEVER_EXIT; + +bool squeue_test_exit(); + +// TODO: eliminate this boolshit +template +class squeue_t +{ + struct alignas(8) squeue_sync_var_t + { + struct + { + u32 position : 31; + u32 pop_lock : 1; + }; + struct + { + u32 count : 31; + u32 push_lock : 1; + }; + }; + + atomic_t m_sync; + + mutable std::mutex m_rcv_mutex; + mutable std::mutex m_wcv_mutex; + mutable std::condition_variable m_rcv; + mutable std::condition_variable m_wcv; + + T m_data[sq_size]; + + enum squeue_sync_var_result : u32 + { + SQSVR_OK = 0, + SQSVR_LOCKED = 1, + SQSVR_FAILED = 2, + }; + +public: + squeue_t() + : m_sync(squeue_sync_var_t{}) + { + } + + u32 get_max_size() const + { + return sq_size; + } + + bool is_full() const + { + return m_sync.load().count == sq_size; + } + + bool push(const T& data, const std::function& test_exit) + { + u32 pos = 0; + + while (u32 res = m_sync.atomic_op([&pos](squeue_sync_var_t& sync) -> u32 + { + Expects(sync.count <= sq_size); + Expects(sync.position < sq_size); + + if (sync.push_lock) + { + return SQSVR_LOCKED; + } + if (sync.count == sq_size) + { + return SQSVR_FAILED; + } + + sync.push_lock = 1; + pos = sync.position + sync.count; + return SQSVR_OK; + })) + { + if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit())) + { + return false; + } + + std::unique_lock wcv_lock(m_wcv_mutex); + m_wcv.wait_for(wcv_lock, std::chrono::milliseconds(1)); + } + + m_data[pos >= sq_size ? pos - sq_size : pos] = data; + + m_sync.atomic_op([](squeue_sync_var_t& sync) + { + Expects(sync.count <= sq_size); + Expects(sync.position < sq_size); + Expects(sync.push_lock); + sync.push_lock = 0; + sync.count++; + }); + + m_rcv.notify_one(); + m_wcv.notify_one(); + return true; + } + + bool push(const T& data, const volatile bool* do_exit) + { + return push(data, [do_exit]() { return do_exit && *do_exit; }); + } + + force_inline bool push(const T& data) + { + return push(data, SQUEUE_NEVER_EXIT); + } + + force_inline bool try_push(const T& data) + { + return push(data, SQUEUE_ALWAYS_EXIT); + } + + bool pop(T& data, const std::function& test_exit) + { + u32 pos = 0; + + while (u32 res = m_sync.atomic_op([&pos](squeue_sync_var_t& sync) -> u32 + { + Expects(sync.count <= sq_size); + Expects(sync.position < sq_size); + + if (!sync.count) + { + return SQSVR_FAILED; + } + if (sync.pop_lock) + { + return SQSVR_LOCKED; + } + + sync.pop_lock = 1; + pos = sync.position; + return SQSVR_OK; + })) + { + if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit())) + { + return false; + } + + std::unique_lock rcv_lock(m_rcv_mutex); + m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1)); + } + + data = m_data[pos]; + + m_sync.atomic_op([](squeue_sync_var_t& sync) + { + Expects(sync.count <= sq_size); + Expects(sync.position < sq_size); + Expects(sync.pop_lock); + sync.pop_lock = 0; + sync.position++; + sync.count--; + if (sync.position == sq_size) + { + sync.position = 0; + } + }); + + m_rcv.notify_one(); + m_wcv.notify_one(); + return true; + } + + bool pop(T& data, const volatile bool* do_exit) + { + return pop(data, [do_exit]() { return do_exit && *do_exit; }); + } + + force_inline bool pop(T& data) + { + return pop(data, SQUEUE_NEVER_EXIT); + } + + force_inline bool try_pop(T& data) + { + return pop(data, SQUEUE_ALWAYS_EXIT); + } + + bool peek(T& data, u32 start_pos, const std::function& test_exit) + { + Expects(start_pos < sq_size); + u32 pos = 0; + + while (u32 res = m_sync.atomic_op([&pos, start_pos](squeue_sync_var_t& sync) -> u32 + { + Expects(sync.count <= sq_size); + Expects(sync.position < sq_size); + + if (sync.count <= start_pos) + { + return SQSVR_FAILED; + } + if (sync.pop_lock) + { + return SQSVR_LOCKED; + } + + sync.pop_lock = 1; + pos = sync.position + start_pos; + return SQSVR_OK; + })) + { + if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit())) + { + return false; + } + + std::unique_lock rcv_lock(m_rcv_mutex); + m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1)); + } + + data = m_data[pos >= sq_size ? pos - sq_size : pos]; + + m_sync.atomic_op([](squeue_sync_var_t& sync) + { + Expects(sync.count <= sq_size); + Expects(sync.position < sq_size); + Expects(sync.pop_lock); + sync.pop_lock = 0; + }); + + m_rcv.notify_one(); + return true; + } + + bool peek(T& data, u32 start_pos, const volatile bool* do_exit) + { + return peek(data, start_pos, [do_exit]() { return do_exit && *do_exit; }); + } + + force_inline bool peek(T& data, u32 start_pos = 0) + { + return peek(data, start_pos, SQUEUE_NEVER_EXIT); + } + + force_inline bool try_peek(T& data, u32 start_pos = 0) + { + return peek(data, start_pos, SQUEUE_ALWAYS_EXIT); + } + + class squeue_data_t + { + T* const m_data; + const u32 m_pos; + const u32 m_count; + + squeue_data_t(T* data, u32 pos, u32 count) + : m_data(data) + , m_pos(pos) + , m_count(count) + { + } + + public: + T& operator [] (u32 index) + { + Expects(index < m_count); + index += m_pos; + index = index < sq_size ? index : index - sq_size; + return m_data[index]; + } + }; + + void process(void(*proc)(squeue_data_t data)) + { + u32 pos, count; + + while (m_sync.atomic_op([&pos, &count](squeue_sync_var_t& sync) -> u32 + { + Expects(sync.count <= sq_size); + Expects(sync.position < sq_size); + + if (sync.pop_lock || sync.push_lock) + { + return SQSVR_LOCKED; + } + + pos = sync.position; + count = sync.count; + sync.pop_lock = 1; + sync.push_lock = 1; + return SQSVR_OK; + })) + { + std::unique_lock rcv_lock(m_rcv_mutex); + m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1)); + } + + proc(squeue_data_t(m_data, pos, count)); + + m_sync.atomic_op([](squeue_sync_var_t& sync) + { + Expects(sync.count <= sq_size); + Expects(sync.position < sq_size); + Expects(sync.pop_lock && sync.push_lock); + sync.pop_lock = 0; + sync.push_lock = 0; + }); + + m_wcv.notify_one(); + m_rcv.notify_one(); + } + + void clear() + { + while (m_sync.atomic_op([](squeue_sync_var_t& sync) -> u32 + { + Expects(sync.count <= sq_size); + Expects(sync.position < sq_size); + + if (sync.pop_lock || sync.push_lock) + { + return SQSVR_LOCKED; + } + + sync.pop_lock = 1; + sync.push_lock = 1; + return SQSVR_OK; + })) + { + std::unique_lock rcv_lock(m_rcv_mutex); + m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1)); + } + + m_sync.exchange({}); + m_wcv.notify_one(); + m_rcv.notify_one(); + } +}; diff --git a/rpcs3/Emu/SysCalls/Modules/cellPhotoDecode.cpp b/rpcs3/Emu/Cell/Modules/cellPhotoDecode.cpp similarity index 72% rename from rpcs3/Emu/SysCalls/Modules/cellPhotoDecode.cpp rename to rpcs3/Emu/Cell/Modules/cellPhotoDecode.cpp index 8ede8c8388..90f759f1e4 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPhotoDecode.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPhotoDecode.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellPhotoDecode; +LOG_CHANNEL(cellPhotoDecode); // Return Codes enum @@ -56,10 +55,10 @@ s32 cellPhotoDecodeFromFile() return CELL_OK; } -Module<> cellPhotoDecode("cellPhotoDecode", []() +DECLARE(ppu_module_manager::cellPhotoDecode)("cellPhotoDecodeUtil", []() { - REG_FUNC(cellPhotoDecode, cellPhotoDecodeInitialize); - REG_FUNC(cellPhotoDecode, cellPhotoDecodeInitialize2); - REG_FUNC(cellPhotoDecode, cellPhotoDecodeFinalize); - REG_FUNC(cellPhotoDecode, cellPhotoDecodeFromFile); + REG_FUNC(cellPhotoDecodeUtil, cellPhotoDecodeInitialize); + REG_FUNC(cellPhotoDecodeUtil, cellPhotoDecodeInitialize2); + REG_FUNC(cellPhotoDecodeUtil, cellPhotoDecodeFinalize); + REG_FUNC(cellPhotoDecodeUtil, cellPhotoDecodeFromFile); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellPhotoExport.cpp b/rpcs3/Emu/Cell/Modules/cellPhotoExport.cpp similarity index 70% rename from rpcs3/Emu/SysCalls/Modules/cellPhotoExport.cpp rename to rpcs3/Emu/Cell/Modules/cellPhotoExport.cpp index 00b88fabc3..3b9f4a6381 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPhotoExport.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPhotoExport.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellPhotoExport; +LOG_CHANNEL(cellPhotoExport); // Return Codes enum @@ -75,15 +74,15 @@ s32 cellPhotoExportProgress() return CELL_OK; } -Module<> cellPhotoExport("cellPhotoExport", []() +DECLARE(ppu_module_manager::cellPhotoExport)("cellPhotoUtility", []() { - REG_FUNC(cellPhotoExport, cellPhotoInitialize); - REG_FUNC(cellPhotoExport, cellPhotoFinalize); - REG_FUNC(cellPhotoExport, cellPhotoRegistFromFile); - REG_FUNC(cellPhotoExport, cellPhotoExportInitialize); - REG_FUNC(cellPhotoExport, cellPhotoExportInitialize2); - REG_FUNC(cellPhotoExport, cellPhotoExportFinalize); - REG_FUNC(cellPhotoExport, cellPhotoExportFromFile); - REG_FUNC(cellPhotoExport, cellPhotoExportFromFileWithCopy); - REG_FUNC(cellPhotoExport, cellPhotoExportProgress); + REG_FUNC(cellPhotoUtility, cellPhotoInitialize); + REG_FUNC(cellPhotoUtility, cellPhotoFinalize); + REG_FUNC(cellPhotoUtility, cellPhotoRegistFromFile); + REG_FUNC(cellPhotoUtility, cellPhotoExportInitialize); + REG_FUNC(cellPhotoUtility, cellPhotoExportInitialize2); + REG_FUNC(cellPhotoUtility, cellPhotoExportFinalize); + REG_FUNC(cellPhotoUtility, cellPhotoExportFromFile); + REG_FUNC(cellPhotoUtility, cellPhotoExportFromFileWithCopy); + REG_FUNC(cellPhotoUtility, cellPhotoExportProgress); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellPhotoImport.cpp b/rpcs3/Emu/Cell/Modules/cellPhotoImport.cpp similarity index 89% rename from rpcs3/Emu/SysCalls/Modules/cellPhotoImport.cpp rename to rpcs3/Emu/Cell/Modules/cellPhotoImport.cpp index cb4bddb8fb..4bb17ce497 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPhotoImport.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPhotoImport.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellPhotoImportUtil; +LOG_CHANNEL(cellPhotoImportUtil); // Return Codes enum @@ -53,7 +52,7 @@ s32 cellPhotoImport2() return CELL_OK; } -Module<> cellPhotoImportUtil("cellPhotoImport", []() +DECLARE(ppu_module_manager::cellPhotoImportUtil)("cellPhotoImportUtil", []() { REG_FUNC(cellPhotoImportUtil, cellPhotoImport); REG_FUNC(cellPhotoImportUtil, cellPhotoImport2); diff --git a/rpcs3/Emu/SysCalls/Modules/cellPng.h b/rpcs3/Emu/Cell/Modules/cellPng.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellPng.h rename to rpcs3/Emu/Cell/Modules/cellPng.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellPngDec.cpp b/rpcs3/Emu/Cell/Modules/cellPngDec.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/cellPngDec.cpp rename to rpcs3/Emu/Cell/Modules/cellPngDec.cpp index 44ad101ed3..431170548e 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPngDec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPngDec.cpp @@ -1,16 +1,13 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsFileBase.h" -#include "Emu/SysCalls/lv2/sys_fs.h" +#include "Emu/Cell/PPUModule.h" +#include "Emu/Cell/lv2/sys_fs.h" #include "png.h" #include "cellPngDec.h" -extern Module<> cellPngDec; +LOG_CHANNEL(cellPngDec); // cellPngDec aliases to improve readability using PPHandle = vm::pptr; @@ -59,7 +56,7 @@ void pngDecReadBuffer(png_structp png_ptr, png_bytep out, png_size_t length) auto file = idm::get(buffer.fd); // Read the data - file->file->Read(out, length); + file->file.read(out, length); } else { @@ -338,7 +335,7 @@ s32 pngDecOpen(PPUThread& ppu, PHandle handle, PPStream png_stream, PSrc source, if (source->srcSelect == CELL_PNGDEC_FILE) { // Open a file stream - std::shared_ptr file_stream(Emu.GetVFS().OpenFile(stream->source.fileName.get_ptr(), fom::read)); + fs::file file_stream(vfs::get(stream->source.fileName.get_ptr())); // Check if opening of the PNG file failed if (!file_stream) @@ -348,14 +345,14 @@ s32 pngDecOpen(PPUThread& ppu, PHandle handle, PPStream png_stream, PSrc source, } // Read the header - if (file_stream->Read(header, 8) != 8) + if (file_stream.read(header, 8) != 8) { cellPngDec.error("PNG header is too small."); return CELL_PNGDEC_ERROR_HEADER; } // Get the file descriptor - buffer->fd = idm::make(file_stream, 0, 0); + buffer->fd = idm::make(std::move(file_stream), 0, 0); // Indicate that we need to read from a file stream buffer->file = true; @@ -852,7 +849,7 @@ s32 cellPngDecGetTextChunk(PHandle handle, PStream stream, vm::ptr textInfo throw EXCEPTION(""); } -Module<> cellPngDec("cellPngDec", []() +DECLARE(ppu_module_manager::cellPngDec)("cellPngDec", []() { REG_FUNC(cellPngDec, cellPngDecGetUnknownChunks); REG_FUNC(cellPngDec, cellPngDecClose); diff --git a/rpcs3/Emu/SysCalls/Modules/cellPngDec.h b/rpcs3/Emu/Cell/Modules/cellPngDec.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellPngDec.h rename to rpcs3/Emu/Cell/Modules/cellPngDec.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellPngEnc.cpp b/rpcs3/Emu/Cell/Modules/cellPngEnc.cpp similarity index 91% rename from rpcs3/Emu/SysCalls/Modules/cellPngEnc.cpp rename to rpcs3/Emu/Cell/Modules/cellPngEnc.cpp index 5317ed0143..a1efb70795 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPngEnc.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPngEnc.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellPngEnc; +LOG_CHANNEL(cellPngEnc); // Error Codes enum @@ -69,7 +68,7 @@ s32 cellPngEncReset() return CELL_OK; } -Module<> cellPngEnc("cellPngEnc", []() +DECLARE(ppu_module_manager::cellPngEnc)("cellPngEnc", []() { REG_FUNC(cellPngEnc, cellPngEncQueryAttr); REG_FUNC(cellPngEnc, cellPngEncOpen); diff --git a/rpcs3/Emu/SysCalls/Modules/cellPrint.cpp b/rpcs3/Emu/Cell/Modules/cellPrint.cpp similarity index 66% rename from rpcs3/Emu/SysCalls/Modules/cellPrint.cpp rename to rpcs3/Emu/Cell/Modules/cellPrint.cpp index c64f0ea728..b0a37969cd 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPrint.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPrint.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellPrint; +LOG_CHANNEL(cellPrint); // Error Codes enum @@ -101,21 +100,21 @@ s32 cellPrintSendBand() return CELL_OK; } -Module<> cellPrint("cellPrint", []() +DECLARE(ppu_module_manager::cellPrint)("cellPrintUtility", []() { - REG_FUNC(cellPrint, cellSysutilPrintInit); - REG_FUNC(cellPrint, cellSysutilPrintShutdown); + REG_FUNC(cellPrintUtility, cellSysutilPrintInit); + REG_FUNC(cellPrintUtility, cellSysutilPrintShutdown); - REG_FUNC(cellPrint, cellPrintLoadAsync); - REG_FUNC(cellPrint, cellPrintLoadAsync2); - REG_FUNC(cellPrint, cellPrintUnloadAsync); - REG_FUNC(cellPrint, cellPrintGetStatus); - REG_FUNC(cellPrint, cellPrintOpenConfig); - REG_FUNC(cellPrint, cellPrintGetPrintableArea); - REG_FUNC(cellPrint, cellPrintStartJob); - REG_FUNC(cellPrint, cellPrintEndJob); - REG_FUNC(cellPrint, cellPrintCancelJob); - REG_FUNC(cellPrint, cellPrintStartPage); - REG_FUNC(cellPrint, cellPrintEndPage); - REG_FUNC(cellPrint, cellPrintSendBand); + REG_FUNC(cellPrintUtility, cellPrintLoadAsync); + REG_FUNC(cellPrintUtility, cellPrintLoadAsync2); + REG_FUNC(cellPrintUtility, cellPrintUnloadAsync); + REG_FUNC(cellPrintUtility, cellPrintGetStatus); + REG_FUNC(cellPrintUtility, cellPrintOpenConfig); + REG_FUNC(cellPrintUtility, cellPrintGetPrintableArea); + REG_FUNC(cellPrintUtility, cellPrintStartJob); + REG_FUNC(cellPrintUtility, cellPrintEndJob); + REG_FUNC(cellPrintUtility, cellPrintCancelJob); + REG_FUNC(cellPrintUtility, cellPrintStartPage); + REG_FUNC(cellPrintUtility, cellPrintEndPage); + REG_FUNC(cellPrintUtility, cellPrintSendBand); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellRec.cpp b/rpcs3/Emu/Cell/Modules/cellRec.cpp similarity index 83% rename from rpcs3/Emu/SysCalls/Modules/cellRec.cpp rename to rpcs3/Emu/Cell/Modules/cellRec.cpp index 4a53e6f145..ce3aa50e99 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellRec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellRec.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellRec; +LOG_CHANNEL(cellRec); s32 cellRecOpen() { @@ -40,7 +39,7 @@ s32 cellRecSetInfo() } -Module<> cellRec("cellRec", []() +DECLARE(ppu_module_manager::cellRec)("cellRec", []() { REG_FUNC(cellRec, cellRecOpen); REG_FUNC(cellRec, cellRecClose); diff --git a/rpcs3/Emu/SysCalls/Modules/cellRemotePlay.cpp b/rpcs3/Emu/Cell/Modules/cellRemotePlay.cpp similarity index 87% rename from rpcs3/Emu/SysCalls/Modules/cellRemotePlay.cpp rename to rpcs3/Emu/Cell/Modules/cellRemotePlay.cpp index ffc5abb825..0c7983bb12 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellRemotePlay.cpp +++ b/rpcs3/Emu/Cell/Modules/cellRemotePlay.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellRemotePlay; +LOG_CHANNEL(cellRemotePlay); s32 cellRemotePlayGetStatus() { @@ -45,7 +44,7 @@ s32 cellRemotePlayBreak() } -Module<> cellRemotePlay("cellRemotePlay", []() +DECLARE(ppu_module_manager::cellRemotePlay)("cellRemotePlay", []() { REG_FUNC(cellRemotePlay, cellRemotePlayGetStatus); REG_FUNC(cellRemotePlay, cellRemotePlaySetComparativeVolume); diff --git a/rpcs3/Emu/Cell/Modules/cellResc.cpp b/rpcs3/Emu/Cell/Modules/cellResc.cpp new file mode 100644 index 0000000000..00e1a5f8f9 --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/cellResc.cpp @@ -0,0 +1,180 @@ +#include "stdafx.h" +#include "Emu/System.h" +#include "Emu/IdManager.h" +#include "Emu/Cell/PPUModule.h" + +#include "Emu/RSX/GCM.h" +#include "cellResc.h" + +LOG_CHANNEL(cellResc); + +s32 cellRescInit(vm::ptr initConfig) +{ + cellResc.todo("cellRescInit(initConfig=*0x%x)", initConfig); + + return CELL_OK; +} + +void cellRescExit() +{ + cellResc.todo("cellRescExit()"); +} + +s32 cellRescVideoOutResolutionId2RescBufferMode(u32 resolutionId, vm::ptr bufferMode) +{ + cellResc.todo("cellRescVideoOutResolutionId2RescBufferMode(resolutionId=%d, bufferMode=*0x%x)", resolutionId, bufferMode); + + return CELL_OK; +} + +s32 cellRescSetDsts(u32 dstsMode, vm::ptr dsts) +{ + cellResc.todo("cellRescSetDsts(dstsMode=%d, dsts=*0x%x)", dstsMode, dsts); + + return CELL_OK; +} + +s32 cellRescSetDisplayMode(u32 displayMode) +{ + cellResc.todo("cellRescSetDisplayMode(displayMode=%d)", displayMode); + + return CELL_OK; +} + +s32 cellRescAdjustAspectRatio(f32 horizontal, f32 vertical) +{ + cellResc.todo("cellRescAdjustAspectRatio(horizontal=%f, vertical=%f)", horizontal, vertical); + + return CELL_OK; +} + +s32 cellRescSetPalInterpolateDropFlexRatio(f32 ratio) +{ + cellResc.todo("cellRescSetPalInterpolateDropFlexRatio(ratio=%f)", ratio); + + return CELL_OK; +} + +s32 cellRescGetBufferSize(vm::ptr colorBuffers, vm::ptr vertexArray, vm::ptr fragmentShader) +{ + cellResc.todo("cellRescGetBufferSize(colorBuffers=*0x%x, vertexArray=*0x%x, fragmentShader=*0x%x)", colorBuffers, vertexArray, fragmentShader); + + return CELL_OK; +} + +s32 cellRescGetNumColorBuffers(u32 dstMode, u32 palTemporalMode, u32 reserved) +{ + cellResc.todo("cellRescGetNumColorBuffers(dstMode=%d, palTemporalMode=%d, reserved=%d)", dstMode, palTemporalMode, reserved); + + return 2; +} + +s32 cellRescGcmSurface2RescSrc(vm::ptr gcmSurface, vm::ptr rescSrc) +{ + cellResc.todo("cellRescGcmSurface2RescSrc(gcmSurface=*0x%x, rescSrc=*0x%x)", gcmSurface, rescSrc); + + return CELL_OK; +} + +s32 cellRescSetSrc(s32 idx, vm::ptr src) +{ + cellResc.todo("cellRescSetSrc(idx=0x%x, src=*0x%x)", idx, src); + + return CELL_OK; +} + +s32 cellRescSetConvertAndFlip(PPUThread& ppu, vm::ptr cntxt, s32 idx) +{ + cellResc.todo("cellRescSetConvertAndFlip(cntxt=*0x%x, idx=0x%x)", cntxt, idx); + + return CELL_OK; +} + +s32 cellRescSetWaitFlip() +{ + cellResc.todo("cellRescSetWaitFlip()"); + + return CELL_OK; +} + +s32 cellRescSetBufferAddress(vm::ptr colorBuffers, vm::ptr vertexArray, vm::ptr fragmentShader) +{ + cellResc.todo("cellRescSetBufferAddress(colorBuffers=*0x%x, vertexArray=*0x%x, fragmentShader=*0x%x)", colorBuffers, vertexArray, fragmentShader); + + return CELL_OK; +} + +void cellRescSetFlipHandler(vm::ptr handler) +{ + cellResc.todo("cellRescSetFlipHandler(handler=*0x%x)", handler); +} + +void cellRescResetFlipStatus() +{ + cellResc.todo("cellRescResetFlipStatus()"); +} + +s32 cellRescGetFlipStatus() +{ + cellResc.todo("cellRescGetFlipStatus()"); + + return 0; +} + +s32 cellRescGetRegisterCount() +{ + UNIMPLEMENTED_FUNC(cellResc); + return CELL_OK; +} + +u64 cellRescGetLastFlipTime() +{ + cellResc.todo("cellRescGetLastFlipTime()"); + + return 0; +} + +s32 cellRescSetRegisterCount() +{ + UNIMPLEMENTED_FUNC(cellResc); + return CELL_OK; +} + +void cellRescSetVBlankHandler(vm::ptr handler) +{ + cellResc.todo("cellRescSetVBlankHandler(handler=*0x%x)", handler); +} + +s32 cellRescCreateInterlaceTable(u32 ea_addr, f32 srcH, CellRescTableElement depth, s32 length) +{ + cellResc.todo("cellRescCreateInterlaceTable(ea_addr=0x%x, srcH=%f, depth=%d, length=%d)", ea_addr, srcH, depth, length); + + return CELL_OK; +} + + +DECLARE(ppu_module_manager::cellResc)("cellResc", []() +{ + REG_FUNC(cellResc, cellRescSetConvertAndFlip); + REG_FUNC(cellResc, cellRescSetWaitFlip); + REG_FUNC(cellResc, cellRescSetFlipHandler); + REG_FUNC(cellResc, cellRescGcmSurface2RescSrc); + REG_FUNC(cellResc, cellRescGetNumColorBuffers); + REG_FUNC(cellResc, cellRescSetDsts); + REG_FUNC(cellResc, cellRescResetFlipStatus); + REG_FUNC(cellResc, cellRescSetPalInterpolateDropFlexRatio); + REG_FUNC(cellResc, cellRescGetRegisterCount); + REG_FUNC(cellResc, cellRescAdjustAspectRatio); + REG_FUNC(cellResc, cellRescSetDisplayMode); + REG_FUNC(cellResc, cellRescExit); + REG_FUNC(cellResc, cellRescInit); + REG_FUNC(cellResc, cellRescGetBufferSize); + REG_FUNC(cellResc, cellRescGetLastFlipTime); + REG_FUNC(cellResc, cellRescSetSrc); + REG_FUNC(cellResc, cellRescSetRegisterCount); + REG_FUNC(cellResc, cellRescSetBufferAddress); + REG_FUNC(cellResc, cellRescGetFlipStatus); + REG_FUNC(cellResc, cellRescVideoOutResolutionId2RescBufferMode); + REG_FUNC(cellResc, cellRescSetVBlankHandler); + REG_FUNC(cellResc, cellRescCreateInterlaceTable); +}); diff --git a/rpcs3/Emu/SysCalls/Modules/cellResc.h b/rpcs3/Emu/Cell/Modules/cellResc.h similarity index 68% rename from rpcs3/Emu/SysCalls/Modules/cellResc.h rename to rpcs3/Emu/Cell/Modules/cellResc.h index 6fcb438ec8..a4b135d5ac 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellResc.h +++ b/rpcs3/Emu/Cell/Modules/cellResc.h @@ -1,12 +1,7 @@ #pragma once -#define roundup(x,a) (((x)+(a)-1)&(~((a)-1))) -#define SEVIRITY 80.f - namespace vm { using namespace ps3; } -#include "Emu/RSX/GCM.h" - enum { CELL_RESC_ERROR_NOT_INITIALIZED = 0x80210301, @@ -109,41 +104,3 @@ struct CellRescSrc be_t height; be_t offset; }; - -struct RescVertex_t -{ - be_t Px, Py; - be_t u, v; - be_t u2, v2; -}; - -struct CCellRescInternal -{ - CellRescInitConfig m_initConfig; - CellRescSrc m_rescSrc[SRC_BUFFER_NUM]; - u32 m_dstMode; - CellRescDsts m_rescDsts[4], *m_pRescDsts; - CellRescTableElement m_interlaceElement; - - u32 m_colorBuffersEA, m_vertexArrayEA, m_fragmentUcodeEA; - u32 m_bufIdFront; - s32 m_dstWidth, m_dstHeight, m_dstPitch; - u16 m_srcWidthInterlace, m_srcHeightInterlace; - u32 m_dstBufInterval, m_dstOffsets[MAX_DST_BUFFER_NUM]; - s32 m_nVertex; - u32 m_bufIdFrontPrevDrop, m_bufIdPalMidPrev, m_bufIdPalMidNow; - u32 m_interlaceTableEA; - int m_interlaceTableLength; - float m_ratioAdjX, m_ratioAdjY, m_flexRatio; - bool m_bInitialized, m_bNewlyAdjustRatio; - bool m_isDummyFlipped; - u8 m_cgParamIndex[RESC_PARAM_NUM]; - u64 m_commandIdxCaF, m_rcvdCmdIdx; - vm::ptr s_applicationFlipHandler; - vm::ptr s_applicationVBlankHandler; - - CCellRescInternal() - : m_bInitialized(false) - { - } -}; diff --git a/rpcs3/Emu/Cell/Modules/cellRtc.cpp b/rpcs3/Emu/Cell/Modules/cellRtc.cpp new file mode 100644 index 0000000000..8648da34ee --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/cellRtc.cpp @@ -0,0 +1,295 @@ +#include "stdafx.h" +#include "Emu/Cell/PPUModule.h" + +#include "cellRtc.h" + +LOG_CHANNEL(cellRtc); + +s64 convertToUNIXTime(u16 seconds, u16 minutes, u16 hours, u16 days, s32 years) +{ + return (s64)seconds + (s64)minutes * 60 + (s64)hours * 3600 + (s64)days * 86400 + + (s64)(years - 70) * 31536000 + (s64)((years - 69) / 4) * 86400 - + (s64)((years - 1) / 100) * 86400 + (s64)((years + 299) / 400) * 86400; +} + +u64 convertToWin32FILETIME(u16 seconds, u16 minutes, u16 hours, u16 days, s32 years) +{ + s64 unixtime = convertToUNIXTime(seconds, minutes, hours, days, years); + u64 win32time = u64(unixtime) * u64(10000000) + u64(116444736000000000); + u64 win32filetime = win32time | win32time >> 32; + return win32filetime; +} + +s32 cellRtcGetCurrentTick(vm::ptr pTick) +{ + cellRtc.todo("cellRtcGetCurrentTick(pTick=*0x%x)", pTick); + + return CELL_OK; +} + +s32 cellRtcGetCurrentClock(vm::ptr pClock, s32 iTimeZone) +{ + cellRtc.todo("cellRtcGetCurrentClock(pClock=*0x%x, time_zone=%d)", pClock, iTimeZone); + + return CELL_OK; +} + +s32 cellRtcGetCurrentClockLocalTime(vm::ptr pClock) +{ + cellRtc.todo("cellRtcGetCurrentClockLocalTime(pClock=*0x%x)", pClock); + + return CELL_OK; +} + +s32 cellRtcFormatRfc2822(vm::ptr pszDateTime, vm::ptr pUtc, s32 iTimeZone) +{ + cellRtc.todo("cellRtcFormatRfc2822(pszDateTime=*0x%x, pUtc=*0x%x, time_zone=%d)", pszDateTime, pUtc, iTimeZone); + + return CELL_OK; +} + +s32 cellRtcFormatRfc2822LocalTime(vm::ptr pszDateTime, vm::ptr pUtc) +{ + cellRtc.todo("cellRtcFormatRfc2822LocalTime(pszDateTime=*0x%x, pUtc=*0x%x)", pszDateTime, pUtc); + + return CELL_OK; +} + +s32 cellRtcFormatRfc3339(vm::ptr pszDateTime, vm::ptr pUtc, s32 iTimeZone) +{ + cellRtc.todo("cellRtcFormatRfc3339(pszDateTime=*0x%x, pUtc=*0x%x, iTimeZone=%d)", pszDateTime, pUtc, iTimeZone); + + return CELL_OK; +} + +s32 cellRtcFormatRfc3339LocalTime(vm::ptr pszDateTime, vm::ptr pUtc) +{ + cellRtc.todo("cellRtcFormatRfc3339LocalTime(pszDateTime=*0x%x, pUtc=*0x%x)", pszDateTime, pUtc); + + return CELL_OK; +} + +s32 cellRtcParseDateTime(vm::ptr pUtc, vm::cptr pszDateTime) +{ + cellRtc.todo("cellRtcParseDateTime(pUtc=*0x%x, pszDateTime=*0x%x)", pUtc, pszDateTime); + + return CELL_OK; +} + +s32 cellRtcParseRfc3339(vm::ptr pUtc, vm::cptr pszDateTime) +{ + cellRtc.todo("cellRtcParseRfc3339(pUtc=*0x%x, pszDateTime=*0x%x)", pUtc, pszDateTime); + + return CELL_OK; +} + +s32 cellRtcGetTick(vm::ptr pTime, vm::ptr pTick) +{ + cellRtc.todo("cellRtcGetTick(pTime=*0x%x, pTick=*0x%x)", pTime, pTick); + + + return CELL_OK; +} + +s32 cellRtcSetTick(vm::ptr pTime, vm::ptr pTick) +{ + cellRtc.todo("cellRtcSetTick(pTime=*0x%x, pTick=*0x%x)", pTime, pTick); + + return CELL_OK; +} + +s32 cellRtcTickAddTicks(vm::ptr pTick0, vm::ptr pTick1, s64 lAdd) +{ + cellRtc.todo("cellRtcTickAddTicks(pTick0=*0x%x, pTick1=*0x%x, lAdd=%lld)", pTick0, pTick1, lAdd); + + return CELL_OK; +} + +s32 cellRtcTickAddMicroseconds(vm::ptr pTick0, vm::ptr pTick1, s64 lAdd) +{ + cellRtc.todo("cellRtcTickAddMicroseconds(pTick0=*0x%x, pTick1=*0x%x, lAdd=%lld)", pTick0, pTick1, lAdd); + + return CELL_OK; +} + +s32 cellRtcTickAddSeconds(vm::ptr pTick0, vm::ptr pTick1, s64 lAdd) +{ + cellRtc.todo("cellRtcTickAddSeconds(pTick0=*0x%x, pTick1=*0x%x, lAdd=%lld)", pTick0, pTick1, lAdd); + + return CELL_OK; +} + +s32 cellRtcTickAddMinutes(vm::ptr pTick0, vm::ptr pTick1, s64 lAdd) +{ + cellRtc.todo("cellRtcTickAddMinutes(pTick0=*0x%x, pTick1=*0x%x, lAdd=%lld)", pTick0, pTick1, lAdd); + + return CELL_OK; +} + +s32 cellRtcTickAddHours(vm::ptr pTick0, vm::ptr pTick1, s32 iAdd) +{ + cellRtc.todo("cellRtcTickAddHours(pTick0=*0x%x, pTick1=*0x%x, iAdd=%d)", pTick0, pTick1, iAdd); + + return CELL_OK; +} + +s32 cellRtcTickAddDays(vm::ptr pTick0, vm::ptr pTick1, s32 iAdd) +{ + cellRtc.todo("cellRtcTickAddDays(pTick0=*0x%x, pTick1=*0x%x, iAdd=%d)", pTick0, pTick1, iAdd); + + return CELL_OK; +} + +s32 cellRtcTickAddWeeks(vm::ptr pTick0, vm::ptr pTick1, s32 iAdd) +{ + cellRtc.todo("cellRtcTickAddWeeks(pTick0=*0x%x, pTick1=*0x%x, iAdd=%d)", pTick0, pTick1, iAdd); + + return CELL_OK; +} + +s32 cellRtcTickAddMonths(vm::ptr pTick0, vm::ptr pTick1, s32 iAdd) +{ + cellRtc.todo("cellRtcTickAddMonths(pTick0=*0x%x, pTick1=*0x%x, iAdd=%d)", pTick0, pTick1, iAdd); + + return CELL_OK; +} + +s32 cellRtcTickAddYears(vm::ptr pTick0, vm::ptr pTick1, s32 iAdd) +{ + cellRtc.todo("cellRtcTickAddYears(pTick0=*0x%x, pTick1=*0x%x, iAdd=%d)", pTick0, pTick1, iAdd); + + return CELL_OK; +} + +s32 cellRtcConvertUtcToLocalTime(vm::ptr pUtc, vm::ptr pLocalTime) +{ + cellRtc.todo("cellRtcConvertUtcToLocalTime(pUtc=*0x%x, pLocalTime=*0x%x)", pUtc, pLocalTime); + + return CELL_OK; +} + +s32 cellRtcConvertLocalTimeToUtc(vm::ptr pLocalTime, vm::ptr pUtc) +{ + cellRtc.todo("cellRtcConvertLocalTimeToUtc(pLocalTime=*0x%x, pUtc=*0x%x)", pLocalTime, pUtc); + + return CELL_OK; +} + +s32 cellRtcGetDosTime(vm::ptr pDateTime, vm::ptr puiDosTime) +{ + cellRtc.todo("cellRtcGetDosTime(pDateTime=*0x%x, puiDosTime=*0x%x)", pDateTime, puiDosTime); + + return CELL_OK; +} + +s32 cellRtcGetTime_t(vm::ptr pDateTime, vm::ptr piTime) +{ + cellRtc.todo("cellRtcGetTime_t(pDateTime=*0x%x, piTime=*0x%x)", pDateTime, piTime); + + return CELL_OK; +} + +s32 cellRtcGetWin32FileTime(vm::ptr pDateTime, vm::ptr pulWin32FileTime) +{ + cellRtc.todo("cellRtcGetWin32FileTime(pDateTime=*0x%x, pulWin32FileTime=*0x%x)", pDateTime, pulWin32FileTime); + + return CELL_OK; +} + +s32 cellRtcSetDosTime(vm::ptr pDateTime, u32 uiDosTime) +{ + cellRtc.todo("cellRtcSetDosTime(pDateTime=*0x%x, uiDosTime=0x%x)", pDateTime, uiDosTime); + + return CELL_OK; +} + +s32 cellRtcSetTime_t(vm::ptr pDateTime, u64 iTime) +{ + cellRtc.todo("cellRtcSetTime_t(pDateTime=*0x%x, iTime=0x%llx)", pDateTime, iTime); + + return CELL_OK; +} + +s32 cellRtcSetWin32FileTime(vm::ptr pDateTime, u64 ulWin32FileTime) +{ + cellRtc.todo("cellRtcSetWin32FileTime(pDateTime=*0x%x, ulWin32FileTime=0x%llx)", pDateTime, ulWin32FileTime); + + return CELL_OK; +} + +s32 cellRtcIsLeapYear(s32 year) +{ + cellRtc.todo("cellRtcIsLeapYear(year=%d)", year); + + return 0; +} + +s32 cellRtcGetDaysInMonth(s32 year, s32 month) +{ + cellRtc.todo("cellRtcGetDaysInMonth(year=%d, month=%d)", year, month); + + return 0; +} + +s32 cellRtcGetDayOfWeek(s32 year, s32 month, s32 day) +{ + cellRtc.todo("cellRtcGetDayOfWeek(year=%d, month=%d, day=%d)", year, month, day); + + return 0; +} + +s32 cellRtcCheckValid(vm::ptr pTime) +{ + cellRtc.todo("cellRtcCheckValid(pTime=*0x%x)", pTime); + + return CELL_OK; +} + +s32 cellRtcCompareTick(vm::ptr pTick0, vm::ptr pTick1) +{ + cellRtc.todo("cellRtcCompareTick(pTick0=*0x%x, pTick1=*0x%x)", pTick0, pTick1); + + return CELL_OK; +} + +DECLARE(ppu_module_manager::cellRtc)("cellRtc", []() +{ + REG_FUNC(cellRtc, cellRtcGetCurrentTick); + REG_FUNC(cellRtc, cellRtcGetCurrentClock); + REG_FUNC(cellRtc, cellRtcGetCurrentClockLocalTime); + + REG_FUNC(cellRtc, cellRtcFormatRfc2822); + REG_FUNC(cellRtc, cellRtcFormatRfc2822LocalTime); + REG_FUNC(cellRtc, cellRtcFormatRfc3339); + REG_FUNC(cellRtc, cellRtcFormatRfc3339LocalTime); + REG_FUNC(cellRtc, cellRtcParseDateTime); + REG_FUNC(cellRtc, cellRtcParseRfc3339); + + REG_FUNC(cellRtc, cellRtcGetTick); + REG_FUNC(cellRtc, cellRtcSetTick); + REG_FUNC(cellRtc, cellRtcTickAddTicks); + REG_FUNC(cellRtc, cellRtcTickAddMicroseconds); + REG_FUNC(cellRtc, cellRtcTickAddSeconds); + REG_FUNC(cellRtc, cellRtcTickAddMinutes); + REG_FUNC(cellRtc, cellRtcTickAddHours); + REG_FUNC(cellRtc, cellRtcTickAddDays); + REG_FUNC(cellRtc, cellRtcTickAddWeeks); + REG_FUNC(cellRtc, cellRtcTickAddMonths); + REG_FUNC(cellRtc, cellRtcTickAddYears); + REG_FUNC(cellRtc, cellRtcConvertUtcToLocalTime); + REG_FUNC(cellRtc, cellRtcConvertLocalTimeToUtc); + + REG_FUNC(cellRtc, cellRtcGetDosTime); + REG_FUNC(cellRtc, cellRtcGetTime_t); + REG_FUNC(cellRtc, cellRtcGetWin32FileTime); + REG_FUNC(cellRtc, cellRtcSetDosTime); + REG_FUNC(cellRtc, cellRtcSetTime_t); + REG_FUNC(cellRtc, cellRtcSetWin32FileTime); + + REG_FUNC(cellRtc, cellRtcIsLeapYear); + REG_FUNC(cellRtc, cellRtcGetDaysInMonth); + REG_FUNC(cellRtc, cellRtcGetDayOfWeek); + REG_FUNC(cellRtc, cellRtcCheckValid); + + REG_FUNC(cellRtc, cellRtcCompareTick); +}); diff --git a/rpcs3/Emu/SysCalls/Modules/cellRtc.h b/rpcs3/Emu/Cell/Modules/cellRtc.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellRtc.h rename to rpcs3/Emu/Cell/Modules/cellRtc.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellRudp.cpp b/rpcs3/Emu/Cell/Modules/cellRudp.cpp similarity index 97% rename from rpcs3/Emu/SysCalls/Modules/cellRudp.cpp rename to rpcs3/Emu/Cell/Modules/cellRudp.cpp index f9f22f9710..f72f07fa01 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellRudp.cpp +++ b/rpcs3/Emu/Cell/Modules/cellRudp.cpp @@ -1,12 +1,11 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/IdManager.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/IdManager.h" +#include "Emu/Cell/PPUModule.h" #include "cellRudp.h" -extern Module<> cellRudp; +LOG_CHANNEL(cellRudp); struct rudp_t { @@ -239,7 +238,7 @@ s32 cellRudpProcessEvents() return CELL_OK; } -Module<> cellRudp("cellRudp", []() +DECLARE(ppu_module_manager::cellRudp)("cellRudp", []() { REG_FUNC(cellRudp, cellRudpInit); REG_FUNC(cellRudp, cellRudpEnd); diff --git a/rpcs3/Emu/SysCalls/Modules/cellRudp.h b/rpcs3/Emu/Cell/Modules/cellRudp.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellRudp.h rename to rpcs3/Emu/Cell/Modules/cellRudp.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellSail.cpp b/rpcs3/Emu/Cell/Modules/cellSail.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/cellSail.cpp rename to rpcs3/Emu/Cell/Modules/cellSail.cpp index bce818099c..8193c663ff 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSail.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSail.cpp @@ -1,14 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Callback.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/FS/vfsFile.h" +#include "Emu/Cell/PPUModule.h" #include "cellSail.h" #include "cellPamf.h" -extern Module<> cellSail; +LOG_CHANNEL(cellSail); void playerBoot(vm::ptr pSelf, u64 userParam) { @@ -815,15 +812,13 @@ s32 cellSailPlayerCreateDescriptor(vm::ptr pSelf, s32 streamType std::string uri = pUri.get_ptr(); if (uri.substr(0, 12) == "x-cell-fs://") { - std::string path = uri.substr(12); - vfsFile f; - if (f.Open(path)) + if (fs::file f{ vfs::get(uri.substr(12)) }) { - u64 size = f.GetSize(); + u64 size = f.size(); u32 buffer = vm::alloc(size, vm::main); auto bufPtr = vm::cptr::make(buffer); PamfHeader *buf = const_cast(bufPtr.get_ptr()); - assert(f.Read(buf, size) == size); + ASSERT(f.read(buf, size) == size); u32 sp_ = vm::alloc(sizeof(CellPamfReader), vm::main); auto sp = vm::ptr::make(sp_); u32 reader = cellPamfReaderInitialize(sp, bufPtr, size, 0); @@ -1043,7 +1038,7 @@ s32 cellSailPlayerUnregisterSource() return CELL_OK; } -Module<> cellSail("cellSail", []() +DECLARE(ppu_module_manager::cellSail)("cellSail", []() { REG_FUNC(cellSail, cellSailMemAllocatorInitialize); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSail.h b/rpcs3/Emu/Cell/Modules/cellSail.h similarity index 99% rename from rpcs3/Emu/SysCalls/Modules/cellSail.h rename to rpcs3/Emu/Cell/Modules/cellSail.h index 9bfd158f74..2ba84d26ae 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSail.h +++ b/rpcs3/Emu/Cell/Modules/cellSail.h @@ -674,11 +674,13 @@ union CellSailEvent be_t value; }; -template struct cast_ppu_gpr; +template +struct ppu_gpr_cast_impl; -template<> struct cast_ppu_gpr +template<> +struct ppu_gpr_cast_impl { - static inline u64 to_gpr(const CellSailEvent& event) + static inline u64 to(const CellSailEvent& event) { return event.value; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellSailRec.cpp b/rpcs3/Emu/Cell/Modules/cellSailRec.cpp similarity index 97% rename from rpcs3/Emu/SysCalls/Modules/cellSailRec.cpp rename to rpcs3/Emu/Cell/Modules/cellSailRec.cpp index 2777d8d0c9..7840bc8461 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSailRec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSailRec.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellSailRec; +LOG_CHANNEL(cellSailRec); // Error Codes enum @@ -255,7 +254,7 @@ s32 cellSailRecorderDumpImage() return CELL_OK; } -Module<> cellSailRec("cellSailRec", []() +DECLARE(ppu_module_manager::cellSailRec)("cellSailRec", []() { REG_FUNC(cellSailRec, cellSailProfileSetEsAudioParameter); REG_FUNC(cellSailRec, cellSailProfileSetEsVideoParameter); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp similarity index 80% rename from rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp rename to rpcs3/Emu/Cell/Modules/cellSaveData.cpp index 677097c3a3..333b4e86c6 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp @@ -1,17 +1,10 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsFile.h" -#include "Emu/FS/vfsDir.h" -#include "Loader/PSF.h" #include "cellSaveData.h" -extern Module<> cellSysutil; -extern Module<> cellSaveData; -extern Module<> cellMinisSaveData; +LOG_CHANNEL(cellSaveData); // cellSaveData aliases (only for cellSaveData.cpp) using PSetList = vm::ptr; @@ -38,7 +31,7 @@ enum : u32 std::mutex g_savedata_mutex; -never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cptr dirName, +static never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cptr dirName, u32 errDialog, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, u32 unknown, vm::ptr userdata, u32 userId, PFuncDone funcDone) { @@ -61,7 +54,7 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt vm::var fileSet; // path of the specified user (00000001 by default) - const std::string base_dir = fmt::format("/dev_hdd0/home/%08u/savedata/", userId ? userId : 1u); + const std::string& base_dir = vfs::get(fmt::format("/dev_hdd0/home/%08u/savedata/", userId ? userId : 1u)); result->userdata = userdata; // probably should be assigned only once (allows the callback to change it) @@ -78,16 +71,16 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt const auto prefix_list = fmt::split(setList->dirNamePrefix.get_ptr(), { "|" }); - for (const auto entry : vfsDir(base_dir)) + for (const auto& entry : fs::dir(base_dir)) { - if (entry->flags & DirEntry_TypeFile) + if (entry.is_directory) { continue; } for (const auto& prefix : prefix_list) { - if (entry->name.substr(0, prefix.size()) == prefix) + if (entry.name.substr(0, prefix.size()) == prefix) { // Count the amount of matches and the amount of listed directories if (listGet->dirListNum++ < setBuf->dirListMax) @@ -95,7 +88,7 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt listGet->dirNum++; // PSF parameters - const auto& psf = psf::load(vfsFile(base_dir + entry->name + "/PARAM.SFO").VRead()); + const auto& psf = psf::load_object(fs::file(base_dir + entry.name + "/PARAM.SFO")); if (psf.empty()) { @@ -111,14 +104,14 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt save_entry2.size = 0; - for (const auto entry2 : vfsDir(base_dir + entry->name)) + for (const auto entry2 : fs::dir(base_dir + entry.name)) { - save_entry2.size += entry2->size; + save_entry2.size += entry2.size; } - save_entry2.atime = entry->access_time; - save_entry2.mtime = entry->modify_time; - save_entry2.ctime = entry->create_time; + save_entry2.atime = entry.atime; + save_entry2.mtime = entry.mtime; + save_entry2.ctime = entry.ctime; //save_entry2.iconBuf = NULL; // TODO: Here should be the PNG buffer //save_entry2.iconBufSize = 0; // TODO: Size of the PNG file save_entry2.isNew = false; @@ -184,7 +177,7 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt if (result->result < 0) { - cellSysutil.warning("savedata_op(): funcList returned < 0."); + cellSaveData.warning("savedata_op(): funcList returned < 0."); return CELL_SAVEDATA_ERROR_CBRESULT; } @@ -266,7 +259,7 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt } default: { - cellSysutil.error("savedata_op(): unknown listSet->focusPosition (0x%x)", pos_type); + cellSaveData.error("savedata_op(): unknown listSet->focusPosition (0x%x)", pos_type); return CELL_SAVEDATA_ERROR_PARAM; } } @@ -294,7 +287,7 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt if (result->result < 0) { - cellSysutil.warning("savedata_op(): funcFixed returned < 0."); + cellSaveData.warning("savedata_op(): funcFixed returned < 0."); return CELL_SAVEDATA_ERROR_CBRESULT; } @@ -339,16 +332,12 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt std::string dir_path = base_dir + save_entry.dirName + "/"; std::string sfo_path = dir_path + "PARAM.SFO"; - auto&& psf = psf::load(vfsFile(sfo_path).VRead()); + auto&& psf = psf::load_object(fs::file(sfo_path)); // Get save stats { - std::string dir_local_path; - - Emu.GetVFS().GetDevice(dir_path, dir_local_path); - - fs::stat_t dir_info; - if (!fs::stat(dir_local_path, dir_info)) + fs::stat_t dir_info{}; + if (!fs::stat(dir_path, dir_info)) { // error } @@ -381,32 +370,32 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt auto file_list = statGet->fileList.get_ptr(); - for (const auto entry : vfsDir(dir_path)) + for (const auto& entry : fs::dir(dir_path)) { // only files, system files ignored, fileNum is limited by setBuf->fileListMax - if (entry->flags & DirEntry_TypeFile && entry->name != "PARAM.SFO" && statGet->fileListNum++ < setBuf->fileListMax) + if (!entry.is_directory && entry.name != "PARAM.SFO" && statGet->fileListNum++ < setBuf->fileListMax) { statGet->fileNum++; auto& file = *file_list++; - if (entry->name == "ICON0.PNG") + if (entry.name == "ICON0.PNG") { file.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_ICON0; } - else if (entry->name == "ICON1.PAM") + else if (entry.name == "ICON1.PAM") { file.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_ICON1; } - else if (entry->name == "PIC1.PNG") + else if (entry.name == "PIC1.PNG") { file.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_PIC1; } - else if (entry->name == "SND0.AT3") + else if (entry.name == "SND0.AT3") { file.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_SND0; } - else if (psf::get_integer(psf, "*" + entry->name)) // let's put the list of protected files in PARAM.SFO (int param = 1 if protected) + else if (psf::get_integer(psf, "*" + entry.name)) // let's put the list of protected files in PARAM.SFO (int param = 1 if protected) { file.fileType = CELL_SAVEDATA_FILETYPE_SECUREFILE; } @@ -415,11 +404,11 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt file.fileType = CELL_SAVEDATA_FILETYPE_NORMALFILE; } - file.size = entry->size; - file.atime = entry->access_time; - file.mtime = entry->modify_time; - file.ctime = entry->create_time; - strcpy_trunc(file.fileName, entry->name); + file.size = entry.size; + file.atime = entry.atime; + file.mtime = entry.mtime; + file.ctime = entry.ctime; + strcpy_trunc(file.fileName, entry.name); } } @@ -428,7 +417,7 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt if (result->result < 0) { - cellSysutil.warning("savedata_op(): funcStat returned < 0."); + cellSaveData.warning("savedata_op(): funcStat returned 0x%x", result->result); return CELL_SAVEDATA_ERROR_CBRESULT; } @@ -473,19 +462,19 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt case CELL_SAVEDATA_RECREATE_YES: case CELL_SAVEDATA_RECREATE_YES_RESET_OWNER: { - // kill it with fire - for (const auto entry : vfsDir(dir_path)) + // TODO? + for (const auto& entry : fs::dir(dir_path)) { - if (entry->flags & DirEntry_TypeFile) + if (!entry.is_directory) { - Emu.GetVFS().RemoveFile(dir_path + entry->name); + fs::remove_file(dir_path + entry.name); } } if (!statSet->setParam) { // Savedata deleted and setParam is NULL: delete directory and abort operation - if (Emu.GetVFS().RemoveDir(dir_path)) cellSysutil.error("savedata_op(): savedata directory %s deleted", save_entry.dirName); + if (fs::remove_dir(dir_path)) cellSaveData.error("savedata_op(): savedata directory %s deleted", save_entry.dirName); return CELL_OK; } @@ -495,16 +484,17 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt default: { - cellSysutil.error("savedata_op(): unknown statSet->reCreateMode (0x%x)", statSet->reCreateMode); + cellSaveData.error("savedata_op(): unknown statSet->reCreateMode (0x%x)", statSet->reCreateMode); return CELL_SAVEDATA_ERROR_PARAM; } } } // Create save directory if necessary - if (psf.size() && save_entry.isNew && !Emu.GetVFS().CreateDir(dir_path)) + if (psf.size() && save_entry.isNew && !fs::create_dir(dir_path)) { // Let's ignore this error for now + cellSaveData.warning("savedata_op(): failed to create %s", dir_path); } // Enter the loop where the save files are read/created/deleted @@ -518,7 +508,7 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt if (result->result < 0) { - cellSysutil.warning("savedata_op(): funcFile returned < 0."); + cellSaveData.warning("savedata_op(): funcFile returned < 0."); return CELL_SAVEDATA_ERROR_CBRESULT; } @@ -564,22 +554,18 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt default: { - cellSysutil.error("savedata_op(): unknown fileSet->fileType (0x%x)", type); + cellSaveData.error("savedata_op(): unknown fileSet->fileType (0x%x)", type); return CELL_SAVEDATA_ERROR_PARAM; } } psf.emplace("*" + file_path, fileSet->fileType == CELL_SAVEDATA_FILETYPE_SECUREFILE); - std::string local_path; - - Emu.GetVFS().GetDevice(dir_path + file_path, local_path); - switch (const u32 op = fileSet->fileOperation) { case CELL_SAVEDATA_FILEOP_READ: { - fs::file file(local_path, fom::read); + fs::file file(dir_path + file_path, fs::read); file.seek(fileSet->fileOffset); fileGet->excSize = static_cast(file.read(fileSet->fileBuf.get_ptr(), std::min(fileSet->fileSize, fileSet->fileBufSize))); break; @@ -587,23 +573,23 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt case CELL_SAVEDATA_FILEOP_WRITE: { - fs::file file(local_path, fom::write | fom::create); + fs::file file(dir_path + file_path, fs::write + fs::create); file.seek(fileSet->fileOffset); fileGet->excSize = static_cast(file.write(fileSet->fileBuf.get_ptr(), std::min(fileSet->fileSize, fileSet->fileBufSize))); - file.trunc(file.seek(0, fs::seek_cur)); // truncate + file.trunc(file.pos()); // truncate break; } case CELL_SAVEDATA_FILEOP_DELETE: { - fs::remove_file(local_path); + fs::remove_file(dir_path + file_path); fileGet->excSize = 0; break; } case CELL_SAVEDATA_FILEOP_WRITE_NOTRUNC: { - fs::file file(local_path, fom::write | fom::create); + fs::file file(dir_path + file_path, fs::write + fs::create); file.seek(fileSet->fileOffset); fileGet->excSize = static_cast(file.write(fileSet->fileBuf.get_ptr(), std::min(fileSet->fileSize, fileSet->fileBufSize))); break; @@ -611,7 +597,7 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt default: { - cellSysutil.error("savedata_op(): unknown fileSet->fileOperation (0x%x)", op); + cellSaveData.error("savedata_op(): unknown fileSet->fileOperation (0x%x)", op); return CELL_SAVEDATA_ERROR_PARAM; } } @@ -620,7 +606,7 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt // Write PARAM.SFO if (psf.size()) { - vfsFile(sfo_path, fom::rewrite).VWrite(psf::save(psf)); + fs::file(sfo_path, fs::rewrite).write(psf::save_object(psf)); } return CELL_OK; @@ -630,7 +616,7 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt s32 cellSaveDataListSave2(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.warning("cellSaveDataListSave2(version=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.warning("cellSaveDataListSave2(version=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, setList, setBuf, funcList, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_LIST_SAVE, version, vm::null, 1, setList, setBuf, funcList, vm::null, funcStat, funcFile, container, 2, userdata, 0, vm::null); @@ -639,7 +625,7 @@ s32 cellSaveDataListSave2(PPUThread& ppu, u32 version, PSetList setList, PSetBuf s32 cellSaveDataListLoad2(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.warning("cellSaveDataListLoad2(version=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.warning("cellSaveDataListLoad2(version=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, setList, setBuf, funcList, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_LIST_LOAD, version, vm::null, 1, setList, setBuf, funcList, vm::null, funcStat, funcFile, container, 2, userdata, 0, vm::null); @@ -648,7 +634,7 @@ s32 cellSaveDataListLoad2(PPUThread& ppu, u32 version, PSetList setList, PSetBuf s32 cellSaveDataListSave(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncStat funcStat, PFuncFile funcFile, u32 container) { - cellSysutil.warning("cellSaveDataListSave(version=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", + cellSaveData.warning("cellSaveDataListSave(version=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", version, setList, setBuf, funcList, funcStat, funcFile, container); return savedata_op(ppu, SAVEDATA_OP_LIST_SAVE, version, vm::null, 1, setList, setBuf, funcList, vm::null, funcStat, funcFile, container, 2, vm::null, 0, vm::null); @@ -657,7 +643,7 @@ s32 cellSaveDataListSave(PPUThread& ppu, u32 version, PSetList setList, PSetBuf s32 cellSaveDataListLoad(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncStat funcStat, PFuncFile funcFile, u32 container) { - cellSysutil.warning("cellSaveDataListLoad(version=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", + cellSaveData.warning("cellSaveDataListLoad(version=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", version, setList, setBuf, funcList, funcStat, funcFile, container); return savedata_op(ppu, SAVEDATA_OP_LIST_LOAD, version, vm::null, 1, setList, setBuf, funcList, vm::null, funcStat, funcFile, container, 2, vm::null, 0, vm::null); @@ -667,7 +653,7 @@ s32 cellSaveDataListLoad(PPUThread& ppu, u32 version, PSetList setList, PSetBuf s32 cellSaveDataFixedSave2(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.warning("cellSaveDataFixedSave2(version=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.warning("cellSaveDataFixedSave2(version=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, setList, setBuf, funcFixed, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_FIXED_SAVE, version, vm::null, 1, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 2, userdata, 0, vm::null); @@ -676,7 +662,7 @@ s32 cellSaveDataFixedSave2(PPUThread& ppu, u32 version, PSetList setList, PSetBu s32 cellSaveDataFixedLoad2(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.warning("cellSaveDataFixedLoad2(version=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.warning("cellSaveDataFixedLoad2(version=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, setList, setBuf, funcFixed, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_FIXED_LOAD, version, vm::null, 1, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 2, userdata, 0, vm::null); @@ -685,7 +671,7 @@ s32 cellSaveDataFixedLoad2(PPUThread& ppu, u32 version, PSetList setList, PSetBu s32 cellSaveDataFixedSave(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container) { - cellSysutil.warning("cellSaveDataFixedSave(version=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", + cellSaveData.warning("cellSaveDataFixedSave(version=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", version, setList, setBuf, funcFixed, funcStat, funcFile, container); return savedata_op(ppu, SAVEDATA_OP_FIXED_SAVE, version, vm::null, 1, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 2, vm::null, 0, vm::null); @@ -695,7 +681,7 @@ s32 cellSaveDataFixedSave(PPUThread& ppu, u32 version, PSetList setList, PSetBuf s32 cellSaveDataFixedLoad(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container) { - cellSysutil.warning("cellSaveDataFixedLoad(version=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", + cellSaveData.warning("cellSaveDataFixedLoad(version=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", version, setList, setBuf, funcFixed, funcStat, funcFile, container); return savedata_op(ppu, SAVEDATA_OP_FIXED_LOAD, version, vm::null, 1, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 2, vm::null, 0, vm::null); @@ -704,7 +690,7 @@ s32 cellSaveDataFixedLoad(PPUThread& ppu, u32 version, PSetList setList, PSetBuf s32 cellSaveDataAutoSave2(PPUThread& ppu, u32 version, vm::cptr dirName, u32 errDialog, PSetBuf setBuf, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.warning("cellSaveDataAutoSave2(version=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.warning("cellSaveDataAutoSave2(version=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, dirName, errDialog, setBuf, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_AUTO_SAVE, version, dirName, errDialog, vm::null, setBuf, vm::null, vm::null, funcStat, funcFile, container, 2, userdata, 0, vm::null); @@ -713,7 +699,7 @@ s32 cellSaveDataAutoSave2(PPUThread& ppu, u32 version, vm::cptr dirName, u s32 cellSaveDataAutoLoad2(PPUThread& ppu, u32 version, vm::cptr dirName, u32 errDialog, PSetBuf setBuf, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.warning("cellSaveDataAutoLoad2(version=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.warning("cellSaveDataAutoLoad2(version=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, dirName, errDialog, setBuf, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_AUTO_LOAD, version, dirName, errDialog, vm::null, setBuf, vm::null, vm::null, funcStat, funcFile, container, 2, userdata, 0, vm::null); @@ -722,7 +708,7 @@ s32 cellSaveDataAutoLoad2(PPUThread& ppu, u32 version, vm::cptr dirName, u s32 cellSaveDataAutoSave(PPUThread& ppu, u32 version, vm::cptr dirName, u32 errDialog, PSetBuf setBuf, PFuncStat funcStat, PFuncFile funcFile, u32 container) { - cellSysutil.warning("cellSaveDataAutoSave(version=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", + cellSaveData.warning("cellSaveDataAutoSave(version=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", version, dirName, errDialog, setBuf, funcStat, funcFile, container); return savedata_op(ppu, SAVEDATA_OP_AUTO_SAVE, version, dirName, errDialog, vm::null, setBuf, vm::null, vm::null, funcStat, funcFile, container, 2, vm::null, 0, vm::null); @@ -731,7 +717,7 @@ s32 cellSaveDataAutoSave(PPUThread& ppu, u32 version, vm::cptr dirName, u3 s32 cellSaveDataAutoLoad(PPUThread& ppu, u32 version, vm::cptr dirName, u32 errDialog, PSetBuf setBuf, PFuncStat funcStat, PFuncFile funcFile, u32 container) { - cellSysutil.warning("cellSaveDataAutoLoad(version=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", + cellSaveData.warning("cellSaveDataAutoLoad(version=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", version, dirName, errDialog, setBuf, funcStat, funcFile, container); return savedata_op(ppu, SAVEDATA_OP_AUTO_LOAD, version, dirName, errDialog, vm::null, setBuf, vm::null, vm::null, funcStat, funcFile, container, 2, vm::null, 0, vm::null); @@ -739,7 +725,7 @@ s32 cellSaveDataAutoLoad(PPUThread& ppu, u32 version, vm::cptr dirName, u3 s32 cellSaveDataListAutoSave(PPUThread& ppu, u32 version, u32 errDialog, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.warning("cellSaveDataListAutoSave(version=%d, errDialog=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.warning("cellSaveDataListAutoSave(version=%d, errDialog=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, errDialog, setList, setBuf, funcFixed, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_LIST_AUTO_SAVE, version, vm::null, errDialog, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 0, userdata, 0, vm::null); @@ -747,7 +733,7 @@ s32 cellSaveDataListAutoSave(PPUThread& ppu, u32 version, u32 errDialog, PSetLis s32 cellSaveDataListAutoLoad(PPUThread& ppu, u32 version, u32 errDialog, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.warning("cellSaveDataListAutoLoad(version=%d, errDialog=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.warning("cellSaveDataListAutoLoad(version=%d, errDialog=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, errDialog, setList, setBuf, funcFixed, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_LIST_AUTO_LOAD, version, vm::null, errDialog, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 0, userdata, 0, vm::null); @@ -755,21 +741,21 @@ s32 cellSaveDataListAutoLoad(PPUThread& ppu, u32 version, u32 errDialog, PSetLis s32 cellSaveDataDelete2(u32 container) { - cellSysutil.todo("cellSaveDataDelete2(container=0x%x)", container); + cellSaveData.todo("cellSaveDataDelete2(container=0x%x)", container); return CELL_SAVEDATA_RET_CANCEL; } s32 cellSaveDataDelete(u32 container) { - cellSysutil.todo("cellSaveDataDelete(container=0x%x)", container); + cellSaveData.todo("cellSaveDataDelete(container=0x%x)", container); return CELL_SAVEDATA_RET_CANCEL; } s32 cellSaveDataFixedDelete(PPUThread& ppu, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncDone funcDone, u32 container, vm::ptr userdata) { - cellSysutil.todo("cellSaveDataFixedDelete(setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcDone=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.todo("cellSaveDataFixedDelete(setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcDone=*0x%x, container=0x%x, userdata=*0x%x)", setList, setBuf, funcFixed, funcDone, container, userdata); return CELL_OK; @@ -777,7 +763,7 @@ s32 cellSaveDataFixedDelete(PPUThread& ppu, PSetList setList, PSetBuf setBuf, PF s32 cellSaveDataUserListSave(PPUThread& ppu, u32 version, u32 userId, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.error("cellSaveDataUserListSave(version=%d, userId=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.error("cellSaveDataUserListSave(version=%d, userId=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, userId, setList, setBuf, funcList, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_LIST_SAVE, version, vm::null, 0, setList, setBuf, funcList, vm::null, funcStat, funcFile, container, 6, userdata, userId, vm::null); @@ -785,7 +771,7 @@ s32 cellSaveDataUserListSave(PPUThread& ppu, u32 version, u32 userId, PSetList s s32 cellSaveDataUserListLoad(PPUThread& ppu, u32 version, u32 userId, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.error("cellSaveDataUserListLoad(version=%d, userId=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.error("cellSaveDataUserListLoad(version=%d, userId=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, userId, setList, setBuf, funcList, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_LIST_LOAD, version, vm::null, 0, setList, setBuf, funcList, vm::null, funcStat, funcFile, container, 6, userdata, userId, vm::null); @@ -793,7 +779,7 @@ s32 cellSaveDataUserListLoad(PPUThread& ppu, u32 version, u32 userId, PSetList s s32 cellSaveDataUserFixedSave(PPUThread& ppu, u32 version, u32 userId, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.error("cellSaveDataUserFixedSave(version=%d, userId=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.error("cellSaveDataUserFixedSave(version=%d, userId=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, userId, setList, setBuf, funcFixed, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_FIXED_SAVE, version, vm::null, 0, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 6, userdata, userId, vm::null); @@ -801,7 +787,7 @@ s32 cellSaveDataUserFixedSave(PPUThread& ppu, u32 version, u32 userId, PSetList s32 cellSaveDataUserFixedLoad(PPUThread& ppu, u32 version, u32 userId, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.error("cellSaveDataUserFixedLoad(version=%d, userId=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.error("cellSaveDataUserFixedLoad(version=%d, userId=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, userId, setList, setBuf, funcFixed, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_FIXED_LOAD, version, vm::null, 0, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 6, userdata, userId, vm::null); @@ -809,7 +795,7 @@ s32 cellSaveDataUserFixedLoad(PPUThread& ppu, u32 version, u32 userId, PSetList s32 cellSaveDataUserAutoSave(PPUThread& ppu, u32 version, u32 userId, vm::cptr dirName, u32 errDialog, PSetBuf setBuf, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.error("cellSaveDataUserAutoSave(version=%d, userId=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.error("cellSaveDataUserAutoSave(version=%d, userId=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, userId, dirName, errDialog, setBuf, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_AUTO_SAVE, version, dirName, errDialog, vm::null, setBuf, vm::null, vm::null, funcStat, funcFile, container, 6, userdata, userId, vm::null); @@ -817,7 +803,7 @@ s32 cellSaveDataUserAutoSave(PPUThread& ppu, u32 version, u32 userId, vm::cptr dirName, u32 errDialog, PSetBuf setBuf, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.error("cellSaveDataUserAutoLoad(version=%d, userId=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.error("cellSaveDataUserAutoLoad(version=%d, userId=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, userId, dirName, errDialog, setBuf, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_AUTO_LOAD, version, dirName, errDialog, vm::null, setBuf, vm::null, vm::null, funcStat, funcFile, container, 6, userdata, userId, vm::null); @@ -825,7 +811,7 @@ s32 cellSaveDataUserAutoLoad(PPUThread& ppu, u32 version, u32 userId, vm::cptr userdata) { - cellSysutil.error("cellSaveDataUserListAutoSave(version=%d, userId=%d, errDialog=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.error("cellSaveDataUserListAutoSave(version=%d, userId=%d, errDialog=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, userId, errDialog, setList, setBuf, funcFixed, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_LIST_AUTO_SAVE, version, vm::null, errDialog, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 6, userdata, userId, vm::null); @@ -833,7 +819,7 @@ s32 cellSaveDataUserListAutoSave(PPUThread& ppu, u32 version, u32 userId, u32 er s32 cellSaveDataUserListAutoLoad(PPUThread& ppu, u32 version, u32 userId, u32 errDialog, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.error("cellSaveDataUserListAutoLoad(version=%d, userId=%d, errDialog=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.error("cellSaveDataUserListAutoLoad(version=%d, userId=%d, errDialog=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, userId, errDialog, setList, setBuf, funcFixed, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_LIST_AUTO_LOAD, version, vm::null, errDialog, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 6, userdata, userId, vm::null); @@ -841,7 +827,7 @@ s32 cellSaveDataUserListAutoLoad(PPUThread& ppu, u32 version, u32 userId, u32 er s32 cellSaveDataUserFixedDelete(PPUThread& ppu, u32 userId, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncDone funcDone, u32 container, vm::ptr userdata) { - cellSysutil.todo("cellSaveDataUserFixedDelete(userId=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcDone=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.todo("cellSaveDataUserFixedDelete(userId=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcDone=*0x%x, container=0x%x, userdata=*0x%x)", userId, setList, setBuf, funcFixed, funcDone, container, userdata); return CELL_OK; @@ -849,7 +835,7 @@ s32 cellSaveDataUserFixedDelete(PPUThread& ppu, u32 userId, PSetList setList, PS void cellSaveDataEnableOverlay(s32 enable) { - cellSysutil.error("cellSaveDataEnableOverlay(enable=%d)", enable); + cellSaveData.error("cellSaveDataEnableOverlay(enable=%d)", enable); return; } @@ -977,7 +963,7 @@ void cellSysutil_SaveData_init() REG_FUNC(cellSysutil, cellSaveDataAutoSave); } -Module<> cellSaveData("cellSaveData", []() +DECLARE(ppu_module_manager::cellSaveData)("cellSaveData", []() { // libsysutil_savedata functions: REG_FUNC(cellSaveData, cellSaveDataUserGetListItem); @@ -994,7 +980,7 @@ Module<> cellSaveData("cellSaveData", []() REG_FUNC(cellSaveData, cellSaveDataListImport); }); -Module<> cellMinisSaveData("cellMinisSaveData", []() +DECLARE(ppu_module_manager::cellMinisSaveData)("cellMinisSaveData", []() { // libsysutil_savedata_psp functions: //REG_FUNC(cellMinisSaveData, cellMinisSaveDataDelete); // 0x6eb168b3 diff --git a/rpcs3/Emu/SysCalls/Modules/cellSaveData.h b/rpcs3/Emu/Cell/Modules/cellSaveData.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellSaveData.h rename to rpcs3/Emu/Cell/Modules/cellSaveData.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellScreenshot.cpp b/rpcs3/Emu/Cell/Modules/cellScreenshot.cpp similarity index 59% rename from rpcs3/Emu/SysCalls/Modules/cellScreenshot.cpp rename to rpcs3/Emu/Cell/Modules/cellScreenshot.cpp index 95b8e15a40..b062a1d5e8 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellScreenshot.cpp +++ b/rpcs3/Emu/Cell/Modules/cellScreenshot.cpp @@ -1,10 +1,10 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" + #include "cellScreenshot.h" -extern Module<> cellScreenshot; +LOG_CHANNEL(cellScreenshot); s32 cellScreenShotSetParameter() //const CellScreenShotSetParam *param { @@ -30,10 +30,10 @@ s32 cellScreenShotDisable() return CELL_OK; } -Module<> cellScreenshot("cellScreenshot", []() +DECLARE(ppu_module_manager::cellScreenShot)("cellScreenShotUtility", []() { - REG_FUNC(cellScreenshot, cellScreenShotSetParameter); - REG_FUNC(cellScreenshot, cellScreenShotSetOverlayImage); - REG_FUNC(cellScreenshot, cellScreenShotEnable); - REG_FUNC(cellScreenshot, cellScreenShotDisable); + REG_FUNC(cellScreenShotUtility, cellScreenShotSetParameter); + REG_FUNC(cellScreenShotUtility, cellScreenShotSetOverlayImage); + REG_FUNC(cellScreenShotUtility, cellScreenShotEnable); + REG_FUNC(cellScreenShotUtility, cellScreenShotDisable); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellScreenshot.h b/rpcs3/Emu/Cell/Modules/cellScreenshot.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellScreenshot.h rename to rpcs3/Emu/Cell/Modules/cellScreenshot.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellSearch.cpp b/rpcs3/Emu/Cell/Modules/cellSearch.cpp similarity index 60% rename from rpcs3/Emu/SysCalls/Modules/cellSearch.cpp rename to rpcs3/Emu/Cell/Modules/cellSearch.cpp index 90f264f3f6..6c9e43fc6c 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSearch.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSearch.cpp @@ -1,10 +1,10 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" + #include "cellSearch.h" -extern Module<> cellSearch; +LOG_CHANNEL(cellSearch); s32 cellSearchInitialize(CellSearchMode mode, u32 container, vm::ptr func, vm::ptr userData) { @@ -130,26 +130,26 @@ s32 cellSearchEnd() return CELL_OK; } -Module<> cellSearch("cellSearch", []() +DECLARE(ppu_module_manager::cellSearch)("cellSearchUtility", []() { - REG_FUNC(cellSearch, cellSearchInitialize); - REG_FUNC(cellSearch, cellSearchFinalize); - REG_FUNC(cellSearch, cellSearchStartListSearch); - REG_FUNC(cellSearch, cellSearchStartContentSearchInList); - REG_FUNC(cellSearch, cellSearchStartContentSearch); - REG_FUNC(cellSearch, cellSearchStartSceneSearchInVideo); - REG_FUNC(cellSearch, cellSearchStartSceneSearch); - REG_FUNC(cellSearch, cellSearchGetContentInfoByOffset); - REG_FUNC(cellSearch, cellSearchGetContentInfoByContentId); - REG_FUNC(cellSearch, cellSearchGetOffsetByContentId); - REG_FUNC(cellSearch, cellSearchGetContentIdByOffset); - REG_FUNC(cellSearch, cellSearchGetContentInfoGameComment); - REG_FUNC(cellSearch, cellSearchGetMusicSelectionContext); - REG_FUNC(cellSearch, cellSearchGetMusicSelectionContextOfSingleTrack); - REG_FUNC(cellSearch, cellSearchGetContentInfoPath); - REG_FUNC(cellSearch, cellSearchGetContentInfoPathMovieThumb); - REG_FUNC(cellSearch, cellSearchPrepareFile); - REG_FUNC(cellSearch, cellSearchGetContentInfoDeveloperData); - REG_FUNC(cellSearch, cellSearchCancel); - REG_FUNC(cellSearch, cellSearchEnd); + REG_FUNC(cellSearchUtility, cellSearchInitialize); + REG_FUNC(cellSearchUtility, cellSearchFinalize); + REG_FUNC(cellSearchUtility, cellSearchStartListSearch); + REG_FUNC(cellSearchUtility, cellSearchStartContentSearchInList); + REG_FUNC(cellSearchUtility, cellSearchStartContentSearch); + REG_FUNC(cellSearchUtility, cellSearchStartSceneSearchInVideo); + REG_FUNC(cellSearchUtility, cellSearchStartSceneSearch); + REG_FUNC(cellSearchUtility, cellSearchGetContentInfoByOffset); + REG_FUNC(cellSearchUtility, cellSearchGetContentInfoByContentId); + REG_FUNC(cellSearchUtility, cellSearchGetOffsetByContentId); + REG_FUNC(cellSearchUtility, cellSearchGetContentIdByOffset); + REG_FUNC(cellSearchUtility, cellSearchGetContentInfoGameComment); + REG_FUNC(cellSearchUtility, cellSearchGetMusicSelectionContext); + REG_FUNC(cellSearchUtility, cellSearchGetMusicSelectionContextOfSingleTrack); + REG_FUNC(cellSearchUtility, cellSearchGetContentInfoPath); + REG_FUNC(cellSearchUtility, cellSearchGetContentInfoPathMovieThumb); + REG_FUNC(cellSearchUtility, cellSearchPrepareFile); + REG_FUNC(cellSearchUtility, cellSearchGetContentInfoDeveloperData); + REG_FUNC(cellSearchUtility, cellSearchCancel); + REG_FUNC(cellSearchUtility, cellSearchEnd); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSearch.h b/rpcs3/Emu/Cell/Modules/cellSearch.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellSearch.h rename to rpcs3/Emu/Cell/Modules/cellSearch.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellSheap.cpp b/rpcs3/Emu/Cell/Modules/cellSheap.cpp similarity index 95% rename from rpcs3/Emu/SysCalls/Modules/cellSheap.cpp rename to rpcs3/Emu/Cell/Modules/cellSheap.cpp index b8bd086ac8..fe8ac83558 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSheap.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSheap.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellSheap; +LOG_CHANNEL(cellSheap); // Return Codes enum @@ -121,7 +120,7 @@ s32 cellKeySheapQueueDelete() return CELL_OK; } -Module<> cellSheap("cellSheap", []() +DECLARE(ppu_module_manager::cellSheap)("cellSheap", []() { REG_FUNC(cellSheap, cellSheapInitialize); REG_FUNC(cellSheap, cellSheapAllocate); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpudll.cpp b/rpcs3/Emu/Cell/Modules/cellSpudll.cpp similarity index 75% rename from rpcs3/Emu/SysCalls/Modules/cellSpudll.cpp rename to rpcs3/Emu/Cell/Modules/cellSpudll.cpp index 026b5be393..5aeaa9ae77 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpudll.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSpudll.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellSpudll; +LOG_CHANNEL(cellSpudll); s32 cellSpudllGetImageSize(vm::ptr psize, vm::cptr so_elf, vm::cptr config) { @@ -14,7 +13,7 @@ s32 cellSpudllHandleConfigSetDefaultValues(vm::ptr cellSpudll("cellSpudll", []() +DECLARE(ppu_module_manager::cellSpudll)("cellSpudll", []() { REG_FUNC(cellSpudll, cellSpudllGetImageSize); REG_FUNC(cellSpudll, cellSpudllHandleConfigSetDefaultValues); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp b/rpcs3/Emu/Cell/Modules/cellSpurs.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp rename to rpcs3/Emu/Cell/Modules/cellSpurs.cpp index d94ffa27c0..d20b448ce4 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSpurs.cpp @@ -1,28 +1,34 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" #include "Emu/IdManager.h" -#include "Emu/Event.h" +#include "Emu/Cell/PPUModule.h" #include "Emu/Cell/SPUThread.h" -#include "Emu/SysCalls/lv2/sys_sync.h" -#include "Emu/SysCalls/lv2/sys_lwmutex.h" -#include "Emu/SysCalls/lv2/sys_lwcond.h" -#include "Emu/SysCalls/lv2/sys_spu.h" -#include "Emu/SysCalls/lv2/sys_ppu_thread.h" -#include "Emu/SysCalls/lv2/sys_memory.h" -#include "Emu/SysCalls/lv2/sys_process.h" -#include "Emu/SysCalls/lv2/sys_semaphore.h" -#include "Emu/SysCalls/lv2/sys_event.h" +#include "Emu/Cell/lv2/sys_lwmutex.h" +#include "Emu/Cell/lv2/sys_lwcond.h" +#include "Emu/Cell/lv2/sys_spu.h" +#include "Emu/Cell/lv2/sys_ppu_thread.h" +#include "Emu/Cell/lv2/sys_memory.h" +#include "Emu/Cell/lv2/sys_process.h" +#include "Emu/Cell/lv2/sys_semaphore.h" +#include "Emu/Cell/lv2/sys_event.h" #include "sysPrxForUser.h" #include "cellSpurs.h" -//---------------------------------------------------------------------------- -// Externs -//---------------------------------------------------------------------------- +LOG_CHANNEL(cellSpurs); -extern Module<> cellSpurs; +// TODO +struct cell_error_t +{ + s32 value; + + explicit operator bool() const + { + return (value < 0); + } +}; + +#define CHECK_SUCCESS(expr) if (cell_error_t error{expr}) throw fmt::exception("Failure: %s -> 0x%x" HERE, #expr, error.value) //---------------------------------------------------------------------------- // Function prototypes @@ -582,7 +588,7 @@ void _spurs::handler_entry(PPUThread& ppu, vm::ptr spurs) if ((spurs->flags1 & SF1_EXIT_IF_NO_WORK) == 0) { - CHECK_ASSERTION(spurs->handlerExiting == 1); + ASSERT(spurs->handlerExiting == 1); return sys_ppu_thread_exit(ppu, 0); } @@ -645,16 +651,16 @@ s32 _spurs::wakeup_shutdown_completion_waiter(PPUThread& ppu, vm::ptr { wklF->hook(ppu, spurs, wid, wklF->hookArg); - CHECK_ASSERTION(wklEvent->load() & 0x01); - CHECK_ASSERTION(wklEvent->load() & 0x02); - CHECK_ASSERTION((wklEvent->load() & 0x20) == 0); - *wklEvent |= 0x20; + ASSERT(wklEvent->load() & 0x01); + ASSERT(wklEvent->load() & 0x02); + ASSERT((wklEvent->load() & 0x20) == 0); + wklEvent->fetch_or(0x20); } s32 rc = CELL_OK; if (!wklF->hook || wklEvent->load() & 0x10) { - CHECK_ASSERTION(wklF->x28 == 2); + ASSERT(wklF->x28 == 2); rc = sys_semaphore_post((u32)wklF->sem, 1); } @@ -665,8 +671,8 @@ void _spurs::event_helper_entry(PPUThread& ppu, vm::ptr spurs) { bool terminate = false; - vm::var events; - vm::var count; + vm::var events(8); + vm::var count; while (!terminate) { @@ -738,7 +744,7 @@ void _spurs::event_helper_entry(PPUThread& ppu, vm::ptr spurs) } else { - CHECK_SUCCESS(data0); + throw fmt::exception("data0=0x%x" HERE, data0); } } } @@ -1021,7 +1027,7 @@ s32 _spurs::initialize(PPUThread& ppu, vm::ptr spurs, u32 revision, u // Import SPURS kernel spurs->spuImg.type = SYS_SPU_IMAGE_TYPE_USER; - spurs->spuImg.addr = vm::alloc(0x40000, vm::main); + spurs->spuImg.segs = { vm::alloc(0x40000, vm::main), vm::addr }; spurs->spuImg.entry_point = isSecond ? CELL_SPURS_KERNEL2_ENTRY_ADDR : CELL_SPURS_KERNEL1_ENTRY_ADDR; spurs->spuImg.nsegs = 1; @@ -2111,8 +2117,8 @@ s32 _spurs::add_workload(vm::ptr spurs, vm::ptr wid, vm::cptrwklCurrentContention[wnum] & 0xf) == 0); - CHECK_ASSERTION((spurs->wklPendingContention[wnum] & 0xf) == 0); + ASSERT((spurs->wklCurrentContention[wnum] & 0xf) == 0); + ASSERT((spurs->wklPendingContention[wnum] & 0xf) == 0); spurs->wklState1[wnum] = 1; spurs->wklStatus1[wnum] = 0; spurs->wklEvent1[wnum] = 0; @@ -2147,8 +2153,8 @@ s32 _spurs::add_workload(vm::ptr spurs, vm::ptr wid, vm::cptrwklCurrentContention[index] & 0xf0) == 0); - CHECK_ASSERTION((spurs->wklPendingContention[index] & 0xf0) == 0); + ASSERT((spurs->wklCurrentContention[index] & 0xf0) == 0); + ASSERT((spurs->wklPendingContention[index] & 0xf0) == 0); spurs->wklState2[index] = 1; spurs->wklStatus2[index] = 0; spurs->wklEvent2[index] = 0; @@ -2183,7 +2189,7 @@ s32 _spurs::add_workload(vm::ptr spurs, vm::ptr wid, vm::cptr 8 ? 8 : maxContention); }); - spurs->wklSignal1._and_not(0x8000 >> index); // clear bit in wklFlag1 + spurs->wklSignal1.fetch_and(~(0x8000 >> index)); // clear bit in wklFlag1 } else { @@ -2192,7 +2198,7 @@ s32 _spurs::add_workload(vm::ptr spurs, vm::ptr wid, vm::cptr 8 ? 8 : maxContention) << 4; }); - spurs->wklSignal2._and_not(0x8000 >> index); // clear bit in wklFlag2 + spurs->wklSignal2.fetch_and(~(0x8000 >> index)); // clear bit in wklFlag2 } spurs->wklFlagReceiver.compare_and_swap(wnum, 0xff); @@ -2227,7 +2233,7 @@ s32 _spurs::add_workload(vm::ptr spurs, vm::ptr wid, vm::cptr> wnum); }); - CHECK_ASSERTION(res_wkl <= 31); + ASSERT(res_wkl <= 31); spurs->wklState(wnum).exchange(2); spurs->sysSrvMsgUpdateWorkload.exchange(0xff); spurs->sysSrvMessage.exchange(0xff); @@ -3160,10 +3166,15 @@ s32 cellSpursEventFlagGetTasksetAddress(vm::ptr eventFlag, v return CELL_SPURS_TASK_ERROR_ALIGN; } - taskset->set(eventFlag->isIwl ? 0u : VM_CAST(eventFlag->addr)); + taskset->set(eventFlag->isIwl ? 0u : vm::cast(eventFlag->addr, HERE)); return CELL_OK; } +static inline s32 SyncErrorToSpursError(const ppu_error_code& res) +{ + return res.value < 0 ? 0x80410900 | (res.value & 0xff) : res.value; +} + s32 _cellSpursLFQueueInitialize(vm::ptr pTasksetOrSpurs, vm::ptr pQueue, vm::cptr buffer, u32 size, u32 depth, u32 direction) { cellSpurs.todo("_cellSpursLFQueueInitialize(pTasksetOrSpurs=*0x%x, pQueue=*0x%x, buffer=*0x%x, size=0x%x, depth=0x%x, direction=%d)", pTasksetOrSpurs, pQueue, buffer, size, depth, direction); @@ -4094,7 +4105,7 @@ s32 cellSpursSemaphoreGetTasksetAddress() return CELL_OK; } -Module<> cellSpurs("cellSpurs", []() +DECLARE(ppu_module_manager::cellSpurs)("cellSpurs", []() { // Core REG_FUNC(cellSpurs, cellSpursInitialize); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.h b/rpcs3/Emu/Cell/Modules/cellSpurs.h similarity index 96% rename from rpcs3/Emu/SysCalls/Modules/cellSpurs.h rename to rpcs3/Emu/Cell/Modules/cellSpurs.h index e7698fa9fa..b82f239201 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.h +++ b/rpcs3/Emu/Cell/Modules/cellSpurs.h @@ -1,921 +1,916 @@ -#pragma once - -#include "cellSync.h" - -namespace vm { using namespace ps3; } - -struct CellSpurs; -struct CellSpursTaskset; - -// Core return codes. -enum -{ - CELL_SPURS_CORE_ERROR_AGAIN = 0x80410701, - CELL_SPURS_CORE_ERROR_INVAL = 0x80410702, - CELL_SPURS_CORE_ERROR_NOMEM = 0x80410704, - CELL_SPURS_CORE_ERROR_SRCH = 0x80410705, - CELL_SPURS_CORE_ERROR_PERM = 0x80410709, - CELL_SPURS_CORE_ERROR_BUSY = 0x8041070A, - CELL_SPURS_CORE_ERROR_STAT = 0x8041070F, - CELL_SPURS_CORE_ERROR_ALIGN = 0x80410710, - CELL_SPURS_CORE_ERROR_NULL_POINTER = 0x80410711, -}; - -// -enum -{ - CELL_SPURS_POLICY_MODULE_ERROR_AGAIN = 0x80410801, - CELL_SPURS_POLICY_MODULE_ERROR_INVAL = 0x80410802, - CELL_SPURS_POLICY_MODULE_ERROR_NOSYS = 0x80410803, - CELL_SPURS_POLICY_MODULE_ERROR_NOMEM = 0x80410804, - CELL_SPURS_POLICY_MODULE_ERROR_SRCH = 0x80410805, - CELL_SPURS_POLICY_MODULE_ERROR_NOENT = 0x80410806, - CELL_SPURS_POLICY_MODULE_ERROR_NOEXEC = 0x80410807, - CELL_SPURS_POLICY_MODULE_ERROR_DEADLK = 0x80410808, - CELL_SPURS_POLICY_MODULE_ERROR_PERM = 0x80410809, - CELL_SPURS_POLICY_MODULE_ERROR_BUSY = 0x8041080A, - CELL_SPURS_POLICY_MODULE_ERROR_ABORT = 0x8041080C, - CELL_SPURS_POLICY_MODULE_ERROR_FAULT = 0x8041080D, - CELL_SPURS_POLICY_MODULE_ERROR_CHILD = 0x8041080E, - CELL_SPURS_POLICY_MODULE_ERROR_STAT = 0x8041080F, - CELL_SPURS_POLICY_MODULE_ERROR_ALIGN = 0x80410810, - CELL_SPURS_POLICY_MODULE_ERROR_NULL_POINTER = 0x80410811, -}; - -// Task return codes. -enum -{ - CELL_SPURS_TASK_ERROR_AGAIN = 0x80410901, - CELL_SPURS_TASK_ERROR_INVAL = 0x80410902, - CELL_SPURS_TASK_ERROR_NOSYS = 0x80410903, - CELL_SPURS_TASK_ERROR_NOMEM = 0x80410904, - CELL_SPURS_TASK_ERROR_SRCH = 0x80410905, - CELL_SPURS_TASK_ERROR_NOEXEC = 0x80410907, - CELL_SPURS_TASK_ERROR_PERM = 0x80410909, - CELL_SPURS_TASK_ERROR_BUSY = 0x8041090A, - CELL_SPURS_TASK_ERROR_FAULT = 0x8041090D, - CELL_SPURS_TASK_ERROR_ALIGN = 0x80410910, - CELL_SPURS_TASK_ERROR_STAT = 0x8041090F, - CELL_SPURS_TASK_ERROR_NULL_POINTER = 0x80410911, - CELL_SPURS_TASK_ERROR_FATAL = 0x80410914, - CELL_SPURS_TASK_ERROR_SHUTDOWN = 0x80410920, -}; - -enum -{ - CELL_SPURS_JOB_ERROR_AGAIN = 0x80410A01, - CELL_SPURS_JOB_ERROR_INVAL = 0x80410A02, - CELL_SPURS_JOB_ERROR_NOSYS = 0x80410A03, - CELL_SPURS_JOB_ERROR_NOMEM = 0x80410A04, - CELL_SPURS_JOB_ERROR_SRCH = 0x80410A05, - CELL_SPURS_JOB_ERROR_NOENT = 0x80410A06, - CELL_SPURS_JOB_ERROR_NOEXEC = 0x80410A07, - CELL_SPURS_JOB_ERROR_DEADLK = 0x80410A08, - CELL_SPURS_JOB_ERROR_PERM = 0x80410A09, - CELL_SPURS_JOB_ERROR_BUSY = 0x80410A0A, - CELL_SPURS_JOB_ERROR_JOB_DESCRIPTOR = 0x80410A0B, - CELL_SPURS_JOB_ERROR_JOB_DESCRIPTOR_SIZE = 0x80410A0C, - CELL_SPURS_JOB_ERROR_FAULT = 0x80410A0D, - CELL_SPURS_JOB_ERROR_CHILD = 0x80410A0E, - CELL_SPURS_JOB_ERROR_STAT = 0x80410A0F, - CELL_SPURS_JOB_ERROR_ALIGN = 0x80410A10, - CELL_SPURS_JOB_ERROR_NULL_POINTER = 0x80410A11, - CELL_SPURS_JOB_ERROR_MEMORY_CORRUPTED = 0x80410A12, - - CELL_SPURS_JOB_ERROR_MEMORY_SIZE = 0x80410A17, - CELL_SPURS_JOB_ERROR_UNKNOWN_COMMAND = 0x80410A18, - CELL_SPURS_JOB_ERROR_JOBLIST_ALIGNMENT = 0x80410A19, - CELL_SPURS_JOB_ERROR_JOB_ALIGNMENT = 0x80410A1a, - CELL_SPURS_JOB_ERROR_CALL_OVERFLOW = 0x80410A1b, - CELL_SPURS_JOB_ERROR_ABORT = 0x80410A1c, - CELL_SPURS_JOB_ERROR_DMALIST_ELEMENT = 0x80410A1d, - CELL_SPURS_JOB_ERROR_NUM_CACHE = 0x80410A1e, - CELL_SPURS_JOB_ERROR_INVALID_BINARY = 0x80410A1f, -}; - -// SPURS defines. -enum SPURSKernelInterfaces : u32 -{ - CELL_SPURS_MAX_SPU = 8, - CELL_SPURS_MAX_WORKLOAD = 16, - CELL_SPURS_MAX_WORKLOAD2 = 32, - CELL_SPURS_SYS_SERVICE_WORKLOAD_ID = 32, - CELL_SPURS_MAX_PRIORITY = 16, - CELL_SPURS_NAME_MAX_LENGTH = 15, - CELL_SPURS_SIZE = 4096, - CELL_SPURS_SIZE2 = 8192, - CELL_SPURS_INTERRUPT_VECTOR = 0x0, - CELL_SPURS_LOCK_LINE = 0x80, - CELL_SPURS_KERNEL_DMA_TAG_ID = 31, - CELL_SPURS_KERNEL1_ENTRY_ADDR = 0x818, - CELL_SPURS_KERNEL2_ENTRY_ADDR = 0x848, - CELL_SPURS_KERNEL1_EXIT_ADDR = 0x808, - CELL_SPURS_KERNEL2_EXIT_ADDR = 0x838, - CELL_SPURS_KERNEL1_SELECT_WORKLOAD_ADDR = 0x290, - CELL_SPURS_KERNEL2_SELECT_WORKLOAD_ADDR = 0x290, -}; - -enum RangeofEventQueuePortNumbers -{ - CELL_SPURS_STATIC_PORT_RANGE_BOTTOM = 15, - CELL_SPURS_DYNAMIC_PORT_RANGE_TOP = 16, - CELL_SPURS_DYNAMIC_PORT_RANGE_BOTTOM = 63, -}; - -enum SpursAttrFlags : u32 -{ - SAF_NONE = 0x00000000, - SAF_EXIT_IF_NO_WORK = 0x00000001, - SAF_UNKNOWN_FLAG_30 = 0x00000002, - SAF_SECOND_VERSION = 0x00000004, - SAF_UNKNOWN_FLAG_9 = 0x00400000, - SAF_UNKNOWN_FLAG_8 = 0x00800000, - SAF_UNKNOWN_FLAG_7 = 0x01000000, - SAF_SYSTEM_WORKLOAD_ENABLED = 0x02000000, - SAF_SPU_PRINTF_ENABLED = 0x10000000, - SAF_SPU_TGT_EXCLUSIVE_NON_CONTEXT = 0x20000000, - SAF_SPU_MEMORY_CONTAINER_SET = 0x40000000, - SAF_UNKNOWN_FLAG_0 = 0x80000000, -}; - -enum SpursFlags1 : u8 -{ - SF1_NONE = 0x00, - SF1_32_WORKLOADS = 0x40, - SF1_EXIT_IF_NO_WORK = 0x80, -}; - -enum SpursWorkloadConstants : u32 -{ - // Workload states - SPURS_WKL_STATE_NON_EXISTENT = 0, - SPURS_WKL_STATE_PREPARING = 1, - SPURS_WKL_STATE_RUNNABLE = 2, - SPURS_WKL_STATE_SHUTTING_DOWN = 3, - SPURS_WKL_STATE_REMOVABLE = 4, - SPURS_WKL_STATE_INVALID = 5, - - // Image addresses - SPURS_IMG_ADDR_SYS_SRV_WORKLOAD = 0x100, - SPURS_IMG_ADDR_TASKSET_PM = 0x200, -}; - -enum SpursWorkloadGUIDs : u64 -{ - // GUID - SPURS_GUID_SYS_WKL = 0x1BB841BF38F89D33ull, - SPURS_GUID_TASKSET_PM = 0x836E915B2E654143ull, -}; - -enum CellSpursModulePollStatus -{ - CELL_SPURS_MODULE_POLL_STATUS_READYCOUNT = 1, - CELL_SPURS_MODULE_POLL_STATUS_SIGNAL = 2, - CELL_SPURS_MODULE_POLL_STATUS_FLAG = 4 -}; - -enum SpursTraceConstants -{ - // Trace tag types - CELL_SPURS_TRACE_TAG_KERNEL = 0x20, - CELL_SPURS_TRACE_TAG_SERVICE = 0x21, - CELL_SPURS_TRACE_TAG_TASK = 0x22, - CELL_SPURS_TRACE_TAG_JOB = 0x23, - CELL_SPURS_TRACE_TAG_OVIS = 0x24, - CELL_SPURS_TRACE_TAG_LOAD = 0x2a, - CELL_SPURS_TRACE_TAG_MAP = 0x2b, - CELL_SPURS_TRACE_TAG_START = 0x2c, - CELL_SPURS_TRACE_TAG_STOP = 0x2d, - CELL_SPURS_TRACE_TAG_USER = 0x2e, - CELL_SPURS_TRACE_TAG_GUID = 0x2f, - - // Service incident - CELL_SPURS_TRACE_SERVICE_INIT = 0x01, - CELL_SPURS_TRACE_SERVICE_WAIT = 0x02, - CELL_SPURS_TRACE_SERVICE_EXIT = 0x03, - - // Task incident - CELL_SPURS_TRACE_TASK_DISPATCH = 0x01, - CELL_SPURS_TRACE_TASK_YIELD = 0x03, - CELL_SPURS_TRACE_TASK_WAIT = 0x04, - CELL_SPURS_TRACE_TASK_EXIT = 0x05, - - // Trace mode flags - CELL_SPURS_TRACE_MODE_FLAG_WRAP_BUFFER = 0x1, - CELL_SPURS_TRACE_MODE_FLAG_SYNCHRONOUS_START_STOP = 0x2, - CELL_SPURS_TRACE_MODE_FLAG_MASK = 0x3, -}; - -// SPURS task constants -enum SpursTaskConstants -{ - CELL_SPURS_MAX_TASK = 128, - CELL_SPURS_TASK_TOP = 0x3000, - CELL_SPURS_TASK_BOTTOM = 0x40000, - CELL_SPURS_MAX_TASK_NAME_LENGTH = 32, - CELL_SPURS_TASK_ATTRIBUTE_REVISION = 1, - CELL_SPURS_TASKSET_ATTRIBUTE_REVISION = 1, - CELL_SPURS_TASK_EXECUTION_CONTEXT_SIZE = 1024, - CELL_SPURS_TASKSET_PM_ENTRY_ADDR = 0xA00, - CELL_SPURS_TASKSET_PM_SYSCALL_ADDR = 0xA70, - - // Task syscall numbers - CELL_SPURS_TASK_SYSCALL_EXIT = 0, - CELL_SPURS_TASK_SYSCALL_YIELD = 1, - CELL_SPURS_TASK_SYSCALL_WAIT_SIGNAL = 2, - CELL_SPURS_TASK_SYSCALL_POLL = 3, - CELL_SPURS_TASK_SYSCALL_RECV_WKL_FLAG = 4, - - // Task poll status - CELL_SPURS_TASK_POLL_FOUND_TASK = 1, - CELL_SPURS_TASK_POLL_FOUND_WORKLOAD = 2, -}; - -enum CellSpursEventFlagWaitMode -{ - CELL_SPURS_EVENT_FLAG_OR = 0, - CELL_SPURS_EVENT_FLAG_AND = 1, - CELL_SPURS_EVENT_FLAG_WAIT_MODE_LAST = CELL_SPURS_EVENT_FLAG_AND, -}; - -enum CellSpursEventFlagClearMode -{ - CELL_SPURS_EVENT_FLAG_CLEAR_AUTO = 0, - CELL_SPURS_EVENT_FLAG_CLEAR_MANUAL = 1, - CELL_SPURS_EVENT_FLAG_CLEAR_LAST = CELL_SPURS_EVENT_FLAG_CLEAR_MANUAL, -}; - -enum CellSpursEventFlagDirection -{ - CELL_SPURS_EVENT_FLAG_SPU2SPU, - CELL_SPURS_EVENT_FLAG_SPU2PPU, - CELL_SPURS_EVENT_FLAG_PPU2SPU, - CELL_SPURS_EVENT_FLAG_ANY2ANY, - CELL_SPURS_EVENT_FLAG_LAST = CELL_SPURS_EVENT_FLAG_ANY2ANY, -}; - -// Event flag constants -enum SpursEventFlagConstants -{ - CELL_SPURS_EVENT_FLAG_MAX_WAIT_SLOTS = 16, - CELL_SPURS_EVENT_FLAG_INVALID_SPU_PORT = 0xFF, -}; - -struct alignas(16) CellSpursWorkloadFlag -{ - be_t unused0; - be_t unused1; - atomic_be_t flag; -}; - -CHECK_SIZE_ALIGN(CellSpursWorkloadFlag, 16, 16); - -struct CellSpursInfo -{ - be_t nSpus; - be_t spuThreadGroupPriority; - be_t ppuThreadPriority; - bool exitIfNoWork; - bool spurs2; - u8 padding24[2]; - vm::bptr traceBuffer; - be_t padding32; - be_t traceBufferSize; - be_t traceMode; - be_t spuThreadGroup; - be_t spuThreads[8]; - be_t spursHandlerThread0; - be_t spursHandlerThread1; - char namePrefix[16]; - be_t namePrefixLength; - be_t deadlineMissCounter; - be_t deadlineMeetCounter; - u8 padding[164]; -}; - -CHECK_SIZE(CellSpursInfo, 280); - -struct alignas(8) CellSpursAttribute -{ - be_t revision; // 0x0 - be_t sdkVersion; // 0x4 - be_t nSpus; // 0x8 - be_t spuPriority; // 0xC - be_t ppuPriority; // 0x10 - bool exitIfNoWork; // 0x14 - char prefix[15]; // 0x15 (not a NTS) - be_t prefixSize; // 0x24 - be_t flags; // 0x28 (SpursAttrFlags) - be_t container; // 0x2C - be_t unk0; // 0x30 - be_t unk1; // 0x34 - u8 swlPriority[8]; // 0x38 - be_t swlMaxSpu; // 0x40 - be_t swlIsPreem; // 0x44 - u8 padding[440]; -}; - -CHECK_SIZE_ALIGN(CellSpursAttribute, 512, 8); - -using CellSpursShutdownCompletionEventHook = void(vm::ptr spurs, u32 wid, vm::ptr arg); - -struct alignas(16) CellSpursTraceInfo -{ - be_t spuThread[8]; // 0x00 - be_t count[8]; // 0x20 - be_t spuThreadGroup; // 0x40 - be_t numSpus; // 0x44 - u8 padding[56]; -}; - -CHECK_SIZE_ALIGN(CellSpursTraceInfo, 128, 16); - -struct CellSpursTraceHeader -{ - u8 tag; - u8 length; - u8 spu; - u8 workload; - be_t time; -}; - -struct CellSpursTraceControlData -{ - be_t incident; - be_t reserved; -}; - -struct CellSpursTraceServiceData -{ - be_t incident; - be_t reserved; -}; - -struct CellSpursTraceTaskData -{ - be_t incident; - be_t taskId; -}; - -struct CellSpursTraceJobData -{ - u8 reserved[3]; - u8 binLSAhigh8; - be_t jobDescriptor; -}; - -struct CellSpursTraceLoadData -{ - be_t ea; - be_t ls; - be_t size; -}; - -struct CellSpursTraceMapData -{ - be_t offset; - be_t ls; - be_t size; -}; - -struct CellSpursTraceStartData -{ - char module[4]; - be_t level; - be_t ls; -}; - -struct alignas(16) CellSpursTracePacket -{ - CellSpursTraceHeader header; - - union - { - CellSpursTraceControlData control; - CellSpursTraceServiceData service; - CellSpursTraceTaskData task; - CellSpursTraceJobData job; - - CellSpursTraceLoadData load; - CellSpursTraceMapData map; - CellSpursTraceStartData start; - - be_t stop; - be_t user; - be_t guid; - be_t raw; - } - data; -}; - -CHECK_SIZE_ALIGN(CellSpursTracePacket, 16, 16); - -// Core CellSpurs structures -struct alignas(128) CellSpurs -{ - struct _sub_str1 - { - u8 unk0[0x20]; // 0x00 - SPU exception handler 0x08 - SPU exception handler args - be_t sem; // 0x20 - be_t x28; // 0x28 - be_t x2C; // 0x2C - vm::bptr hook; // 0x30 - vm::bptr hookArg; // 0x38 - u8 unk2[0x40]; - }; - - CHECK_SIZE(_sub_str1, 128); - - struct EventPortMux; - - using EventHandlerCallback = void(vm::ptr, u64 data); - - struct EventHandlerListNode - { - vm::bptr next; - be_t data; - vm::bptr handler; - }; - - struct EventPortMux - { - atomic_be_t reqPending; // 0x00 - be_t spuPort; // 0x04 - be_t x08; // 0x08 - be_t x0C; // 0x0C - be_t eventPort; // 0x10 - atomic_t> handlerList; // 0x18 - u8 x20[0x80 - 0x20]; // 0x20 - }; - - CHECK_SIZE(EventPortMux, 128); - - struct WorkloadInfo - { - vm::bcptr addr; // 0x00 Address of the executable - be_t arg; // 0x08 Argument - be_t size; // 0x10 Size of the executable - atomic_t uniqueId; // 0x14 Unique id of the workload. It is the same for all workloads with the same addr. - u8 pad[3]; - u8 priority[8]; // 0x18 Priority of the workload on each SPU - }; - - CHECK_SIZE(WorkloadInfo, 32); - - struct _sub_str4 - { - vm::bcptr nameClass; - vm::bcptr nameInstance; - }; - - atomic_t wklReadyCount1[0x10]; // 0x00 Number of SPUs requested by each workload (0..15 wids). - atomic_t wklIdleSpuCountOrReadyCount2[0x10]; // 0x10 SPURS1: Number of idle SPUs requested by each workload (0..15 wids). SPURS2: Number of SPUs requested by each workload (16..31 wids). - u8 wklCurrentContention[0x10]; // 0x20 Number of SPUs used by each workload. SPURS1: index = wid. SPURS2: packed 4-bit data, index = wid % 16, internal index = wid / 16. - u8 wklPendingContention[0x10]; // 0x30 Number of SPUs that are pending to context switch to the workload. SPURS1: index = wid. SPURS2: packed 4-bit data, index = wid % 16, internal index = wid / 16. - u8 wklMinContention[0x10]; // 0x40 Min SPUs required for each workload. SPURS1: index = wid. SPURS2: Unused. - atomic_t wklMaxContention[0x10]; // 0x50 Max SPUs that may be allocated to each workload. SPURS1: index = wid. SPURS2: packed 4-bit data, index = wid % 16, internal index = wid / 16. - CellSpursWorkloadFlag wklFlag; // 0x60 - atomic_be_t wklSignal1; // 0x70 Bitset for 0..15 wids - atomic_t sysSrvMessage; // 0x72 - u8 spuIdling; // 0x73 - u8 flags1; // 0x74 Type is SpursFlags1 - u8 sysSrvTraceControl; // 0x75 - u8 nSpus; // 0x76 - atomic_t wklFlagReceiver; // 0x77 - atomic_be_t wklSignal2; // 0x78 Bitset for 16..32 wids - u8 x7A[6]; // 0x7A - atomic_t wklState1[0x10]; // 0x80 SPURS_WKL_STATE_* - u8 wklStatus1[0x10]; // 0x90 - atomic_t wklEvent1[0x10]; // 0xA0 - atomic_be_t wklEnabled; // 0xB0 - atomic_be_t wklMskB; // 0xB4 - System service - Available module id - u32 xB8; // 0xB8 - u8 sysSrvExitBarrier; // 0xBC - atomic_t sysSrvMsgUpdateWorkload; // 0xBD - u8 xBE; // 0xBE - u8 sysSrvMsgTerminate; // 0xBF - u8 sysSrvPreemptWklId[8]; // 0xC0 Id of the workload that was preempted by the system workload on each SPU - u8 sysSrvOnSpu; // 0xC8 - u8 spuPort; // 0xC9 - u8 xCA; // 0xCA - u8 xCB; // 0xCB - - struct SrvTraceSyncVar - { - u8 sysSrvTraceInitialised; // 0xCC - u8 sysSrvNotifyUpdateTraceComplete; // 0xCD - u8 sysSrvMsgUpdateTrace; // 0xCE - u8 xCF; - }; - - atomic_t sysSrvTrace; // 0xCC - - atomic_t wklState2[0x10]; // 0xD0 SPURS_WKL_STATE_* - u8 wklStatus2[0x10]; // 0xE0 - atomic_t wklEvent2[0x10]; // 0xF0 - _sub_str1 wklF1[0x10]; // 0x100 - vm::bptr traceBuffer; // 0x900 - be_t traceStartIndex[6]; // 0x908 - u8 unknown7[0x948 - 0x920]; // 0x920 - be_t traceDataSize; // 0x948 - be_t traceMode; // 0x950 - u8 unknown8[0x980 - 0x954]; // 0x954 - be_t semPrv; // 0x980 - be_t unk11; // 0x988 - be_t unk12; // 0x98C - be_t unk13; // 0x990 - u8 unknown4[0xB00 - 0x998]; - WorkloadInfo wklInfo1[0x10]; // 0xB00 - WorkloadInfo wklInfoSysSrv; // 0xD00 - be_t ppu0; // 0xD20 Handler thread - be_t ppu1; // 0xD28 - be_t spuTG; // 0xD30 SPU thread group - be_t spus[8]; // 0xD34 - u8 unknown3[0xD5C - 0xD54]; - be_t eventQueue; // 0xD5C - be_t eventPort; // 0xD60 - atomic_t handlerDirty; // 0xD64 - atomic_t handlerWaiting; // 0xD65 - atomic_t handlerExiting; // 0xD66 - atomic_be_t enableEH; // 0xD68 - be_t exception; // 0xD6C - sys_spu_image spuImg; // 0xD70 - be_t flags; // 0xD80 - be_t spuPriority; // 0xD84 - be_t ppuPriority; // 0xD88 - char prefix[0x0f]; // 0xD8C - u8 prefixSize; // 0xD9B - be_t unk5; // 0xD9C - be_t revision; // 0xDA0 - be_t sdkVersion; // 0xDA4 - atomic_be_t spuPortBits; // 0xDA8 - sys_lwmutex_t mutex; // 0xDB0 - sys_lwcond_t cond; // 0xDC8 - u8 unknown9[0xE00 - 0xDD0]; - _sub_str4 wklH1[0x10]; // 0xE00 - EventPortMux eventPortMux; // 0xF00 - atomic_be_t globalSpuExceptionHandler; // 0xF80 - be_t globalSpuExceptionHandlerArgs; // 0xF88 - u8 unknown6[0x1000 - 0xF90]; - WorkloadInfo wklInfo2[0x10]; // 0x1000 - _sub_str1 wklF2[0x10]; // 0x1200 - _sub_str4 wklH2[0x10]; // 0x1A00 - u8 unknown_[0x2000 - 0x1B00]; - - force_inline atomic_t& wklState(const u32 wid) - { - if (wid & 0x10) - { - return wklState2[wid & 0xf]; - } - else - { - return wklState1[wid & 0xf]; - } - } -}; - -CHECK_SIZE_ALIGN(CellSpurs, 0x2000, 128); - -using CellSpurs2 = CellSpurs; - -struct CellSpursExceptionInfo -{ - be_t spu_thread; - be_t spu_npc; - be_t cause; - be_t option; -}; - -// Exception handler -using CellSpursGlobalExceptionEventHandler = void(vm::ptr spurs, vm::cptr info, u32 id, vm::ptr arg); - -struct CellSpursWorkloadAttribute -{ - be_t revision; - be_t sdkVersion; - vm::bcptr pm; - be_t size; - be_t data; - u8 priority[8]; - be_t minContention; - be_t maxContention; - vm::bcptr nameClass; - vm::bcptr nameInstance; - vm::bptr hook; - vm::bptr hookArg; - u8 padding[456]; -}; - -CHECK_SIZE_ALIGN(CellSpursWorkloadAttribute, 512, 8); - -struct alignas(128) CellSpursEventFlag -{ - struct ControlSyncVar - { - be_t events; // 0x00 Event bits - be_t spuTaskPendingRecv; // 0x02 A bit is set to 1 when the condition of the SPU task using the slot are met and back to 0 when the SPU task unblocks - be_t ppuWaitMask; // 0x04 Wait mask for blocked PPU thread - u8 ppuWaitSlotAndMode; // 0x06 Top 4 bits: Wait slot number of the blocked PPU threa, Bottom 4 bits: Wait mode of the blocked PPU thread - u8 ppuPendingRecv; // 0x07 Set to 1 when the blocked PPU thread's conditions are met and back to 0 when the PPU thread is unblocked - }; - - union - { - atomic_t ctrl; // 0x00 - atomic_be_t events; // 0x00 - }; - - be_t spuTaskUsedWaitSlots; // 0x08 A bit is set to 1 if the wait slot corresponding to the bit is used by an SPU task and 0 otherwise - be_t spuTaskWaitMode; // 0x0A A bit is set to 1 if the wait mode for the SPU task corresponding to the bit is AND and 0 otherwise - u8 spuPort; // 0x0C - u8 isIwl; // 0x0D - u8 direction; // 0x0E - u8 clearMode; // 0x0F - be_t spuTaskWaitMask[16]; // 0x10 Wait mask for blocked SPU tasks - be_t pendingRecvTaskEvents[16]; // 0x30 The value of event flag when the wait condition for the thread/task was met - u8 waitingTaskId[16]; // 0x50 Task id of waiting SPU threads - u8 waitingTaskWklId[16]; // 0x60 Workload id of waiting SPU threads - be_t addr; // 0x70 - be_t eventPortId; // 0x78 - be_t eventQueueId; // 0x7C -}; - -CHECK_SIZE_ALIGN(CellSpursEventFlag, 128, 128); - -using CellSpursLFQueue = CellSyncLFQueue; - -union CellSpursTaskArgument -{ - be_t _u32[4]; - be_t _u64[2]; -}; - -union CellSpursTaskLsPattern -{ - be_t _u32[4]; - be_t _u64[2]; -}; - -struct alignas(16) CellSpursTaskAttribute -{ - u8 reserved[256]; -}; - -CHECK_SIZE_ALIGN(CellSpursTaskAttribute, 256, 16); - -struct alignas(16) CellSpursTaskAttribute2 -{ - be_t revision; - be_t sizeContext; - be_t eaContext; - CellSpursTaskLsPattern lsPattern; - vm::bcptr name; - - u8 reserved[220]; -}; - -CHECK_SIZE_ALIGN(CellSpursTaskAttribute2, 256, 16); - -// Exception handler -using CellSpursTasksetExceptionEventHandler = void(vm::ptr spurs, vm::ptr taskset, u32 idTask, vm::cptr info, vm::ptr arg); - -struct alignas(128) CellSpursTaskExitCode -{ - u8 skip[128]; -}; - -CHECK_SIZE_ALIGN(CellSpursTaskExitCode, 128, 128); - -struct CellSpursTaskInfo -{ - CellSpursTaskLsPattern lsPattern; - CellSpursTaskArgument argument; - vm::bptr eaElf; - vm::bptr eaContext; - be_t sizeContext; - u8 state; - u8 hasSignal; - u8 padding[2]; - vm::bcptr eaTaskExitCode; - u8 guid[8]; - u8 reserved[12]; -}; - -CHECK_SIZE(CellSpursTaskInfo, 72); - -struct CellSpursTasksetInfo -{ - CellSpursTaskInfo taskInfo[CELL_SPURS_MAX_TASK]; - be_t argument; - be_t idWorkload; - be_t idLastScheduledTask; - vm::bcptr name; - vm::bptr exceptionEventHandler; - vm::bptr exceptionEventHandlerArgument; - be_t sizeTaskset; - u8 reserved[112]; -}; - -CHECK_SIZE(CellSpursTasksetInfo, 9360); - -struct alignas(8) CellSpursTasksetAttribute -{ - be_t revision; // 0x00 - be_t sdk_version; // 0x04 - be_t args; // 0x08 - u8 priority[8]; // 0x10 - be_t max_contention; // 0x18 - vm::bcptr name; // 0x1C - be_t taskset_size; // 0x20 - be_t enable_clear_ls; // 0x24 - u8 reserved[472]; -}; - -CHECK_SIZE_ALIGN(CellSpursTasksetAttribute, 512, 8); - -struct alignas(128) CellSpursTaskset -{ - struct TaskInfo - { - CellSpursTaskArgument args; // 0x00 - vm::bcptr elf; // 0x10 - be_t context_save_storage_and_alloc_ls_blocks; // 0x18 This is (context_save_storage_addr | allocated_ls_blocks) - CellSpursTaskLsPattern ls_pattern; // 0x20 - }; - - CHECK_SIZE(TaskInfo, 48); - - be_t running; // 0x00 - be_t ready; // 0x10 - be_t pending_ready; // 0x20 - be_t enabled; // 0x30 - be_t signalled; // 0x40 - be_t waiting; // 0x50 - vm::bptr spurs; // 0x60 - be_t args; // 0x68 - u8 enable_clear_ls; // 0x70 - u8 x71; // 0x71 - u8 wkl_flag_wait_task; // 0x72 - u8 last_scheduled_task; // 0x73 - be_t wid; // 0x74 - be_t x78; // 0x78 - TaskInfo task_info[128]; // 0x80 - vm::bptr exception_handler; // 0x1880 - vm::bptr exception_handler_arg; // 0x1888 - be_t size; // 0x1890 - u32 unk2; // 0x1894 - u32 event_flag_id1; // 0x1898 - u32 event_flag_id2; // 0x189C - u8 unk3[0x60]; // 0x18A0 -}; - -CHECK_SIZE_ALIGN(CellSpursTaskset, 128 * 50, 128); - -struct alignas(128) CellSpursTaskset2 -{ - struct TaskInfo - { - CellSpursTaskArgument args; - vm::bptr elf_addr; - vm::bptr context_save_storage; // This is (context_save_storage_addr | allocated_ls_blocks) - CellSpursTaskLsPattern ls_pattern; - }; - - CHECK_SIZE(TaskInfo, 48); - - be_t running_set[4]; // 0x00 - be_t ready_set[4]; // 0x10 - be_t ready2_set[4]; // 0x20 - TODO: Find out what this is - be_t enabled_set[4]; // 0x30 - be_t signal_received_set[4]; // 0x40 - be_t waiting_set[4]; // 0x50 - vm::bptr spurs; // 0x60 - be_t args; // 0x68 - u8 enable_clear_ls; // 0x70 - u8 x71; // 0x71 - u8 x72; // 0x72 - u8 last_scheduled_task; // 0x73 - be_t wid; // 0x74 - be_t x78; // 0x78 - TaskInfo task_info[128]; // 0x80 - vm::bptr exception_handler; // 0x1880 - vm::bptr exception_handler_arg; // 0x1888 - be_t size; // 0x1890 - u32 unk2; // 0x1894 - u32 event_flag_id1; // 0x1898 - u32 event_flag_id2; // 0x189C - u8 unk3[0x1980 - 0x18A0]; // 0x18A0 - be_t task_exit_code[128]; // 0x1980 - u8 unk4[0x2900 - 0x2180]; // 0x2180 -}; - -CHECK_SIZE_ALIGN(CellSpursTaskset2, 128 * 82, 128); - -struct alignas(16) CellSpursTaskNameBuffer -{ - char taskName[CELL_SPURS_MAX_TASK][CELL_SPURS_MAX_TASK_NAME_LENGTH]; -}; - -struct alignas(8) CellSpursTasksetAttribute2 -{ - be_t revision; // 0x00 - vm::bcptr name; // 0x04 - be_t args; // 0x08 - u8 priority[8]; // 0x10 - be_t max_contention; // 0x18 - be_t enable_clear_ls; // 0x1C - vm::bptr task_name_buffer; // 0x20 - u8 reserved[472]; -}; - -CHECK_SIZE_ALIGN(CellSpursTasksetAttribute2, 512, 8); - -struct alignas(16) CellSpursTaskBinInfo -{ - be_t eaElf; - be_t sizeContext; - be_t reserved; - CellSpursTaskLsPattern lsPattern; -}; - -// The SPURS kernel context. This resides at 0x100 of the LS. -struct SpursKernelContext -{ - u8 tempArea[0x80]; // 0x100 - u8 wklLocContention[0x10]; // 0x180 - u8 wklLocPendingContention[0x10]; // 0x190 - u8 priority[0x10]; // 0x1A0 - u8 x1B0[0x10]; // 0x1B0 - vm::bptr spurs; // 0x1C0 - be_t spuNum; // 0x1C8 - be_t dmaTagId; // 0x1CC - vm::bcptr wklCurrentAddr; // 0x1D0 - be_t wklCurrentUniqueId; // 0x1D8 - be_t wklCurrentId; // 0x1DC - be_t exitToKernelAddr; // 0x1E0 - be_t selectWorkloadAddr; // 0x1E4 - u8 moduleId[2]; // 0x1E8 - u8 sysSrvInitialised; // 0x1EA - u8 spuIdling; // 0x1EB - be_t wklRunnable1; // 0x1EC - be_t wklRunnable2; // 0x1EE - be_t x1F0; // 0x1F0 - be_t x1F4; // 0x1F4 - be_t x1F8; // 0x1F8 - be_t x1FC; // 0x1FC - be_t x200; // 0x200 - be_t x204; // 0x204 - be_t x208; // 0x208 - be_t x20C; // 0x20C - be_t traceBuffer; // 0x210 - be_t traceMsgCount; // 0x218 - be_t traceMaxCount; // 0x21C - u8 wklUniqueId[0x10]; // 0x220 - u8 x230[0x280 - 0x230]; // 0x230 - be_t guid[4]; // 0x280 -}; - -CHECK_SIZE(SpursKernelContext, 0x190); - -// The SPURS taskset policy module context. This resides at 0x2700 of the LS. -struct SpursTasksetContext -{ - u8 tempAreaTaskset[0x80]; // 0x2700 - u8 tempAreaTaskInfo[0x30]; // 0x2780 - be_t x27B0; // 0x27B0 - vm::bptr taskset; // 0x27B8 - be_t kernelMgmtAddr; // 0x27C0 - be_t syscallAddr; // 0x27C4 - be_t x27C8; // 0x27C8 - be_t spuNum; // 0x27CC - be_t dmaTagId; // 0x27D0 - be_t taskId; // 0x27D4 - u8 x27D8[0x2840 - 0x27D8]; // 0x27D8 - u8 moduleId[16]; // 0x2840 - u8 stackArea[0x2C80 - 0x2850]; // 0x2850 - be_t savedContextLr; // 0x2C80 - be_t savedContextSp; // 0x2C90 - be_t savedContextR80ToR127[48]; // 0x2CA0 - be_t savedContextFpscr; // 0x2FA0 - be_t savedWriteTagGroupQueryMask; // 0x2FB0 - be_t savedSpuWriteEventMask; // 0x2FB4 - be_t tasksetMgmtAddr; // 0x2FB8 - be_t guidAddr; // 0x2FBC - be_t x2FC0; // 0x2FC0 - be_t x2FC8; // 0x2FC8 - be_t taskExitCode; // 0x2FD0 - be_t x2FD4; // 0x2FD4 - u8 x2FD8[0x3000 - 0x2FD8]; // 0x2FD8 -}; - -CHECK_SIZE(SpursTasksetContext, 0x900); - -class SpursModuleExit -{ -}; - -inline static s32 SyncErrorToSpursError(s32 res) -{ - return res < 0 ? 0x80410900 | (res & 0xff) : res; -} +#pragma once + +#include "cellSync.h" + +namespace vm { using namespace ps3; } + +struct CellSpurs; +struct CellSpursTaskset; + +// Core return codes. +enum +{ + CELL_SPURS_CORE_ERROR_AGAIN = 0x80410701, + CELL_SPURS_CORE_ERROR_INVAL = 0x80410702, + CELL_SPURS_CORE_ERROR_NOMEM = 0x80410704, + CELL_SPURS_CORE_ERROR_SRCH = 0x80410705, + CELL_SPURS_CORE_ERROR_PERM = 0x80410709, + CELL_SPURS_CORE_ERROR_BUSY = 0x8041070A, + CELL_SPURS_CORE_ERROR_STAT = 0x8041070F, + CELL_SPURS_CORE_ERROR_ALIGN = 0x80410710, + CELL_SPURS_CORE_ERROR_NULL_POINTER = 0x80410711, +}; + +// +enum +{ + CELL_SPURS_POLICY_MODULE_ERROR_AGAIN = 0x80410801, + CELL_SPURS_POLICY_MODULE_ERROR_INVAL = 0x80410802, + CELL_SPURS_POLICY_MODULE_ERROR_NOSYS = 0x80410803, + CELL_SPURS_POLICY_MODULE_ERROR_NOMEM = 0x80410804, + CELL_SPURS_POLICY_MODULE_ERROR_SRCH = 0x80410805, + CELL_SPURS_POLICY_MODULE_ERROR_NOENT = 0x80410806, + CELL_SPURS_POLICY_MODULE_ERROR_NOEXEC = 0x80410807, + CELL_SPURS_POLICY_MODULE_ERROR_DEADLK = 0x80410808, + CELL_SPURS_POLICY_MODULE_ERROR_PERM = 0x80410809, + CELL_SPURS_POLICY_MODULE_ERROR_BUSY = 0x8041080A, + CELL_SPURS_POLICY_MODULE_ERROR_ABORT = 0x8041080C, + CELL_SPURS_POLICY_MODULE_ERROR_FAULT = 0x8041080D, + CELL_SPURS_POLICY_MODULE_ERROR_CHILD = 0x8041080E, + CELL_SPURS_POLICY_MODULE_ERROR_STAT = 0x8041080F, + CELL_SPURS_POLICY_MODULE_ERROR_ALIGN = 0x80410810, + CELL_SPURS_POLICY_MODULE_ERROR_NULL_POINTER = 0x80410811, +}; + +// Task return codes. +enum +{ + CELL_SPURS_TASK_ERROR_AGAIN = 0x80410901, + CELL_SPURS_TASK_ERROR_INVAL = 0x80410902, + CELL_SPURS_TASK_ERROR_NOSYS = 0x80410903, + CELL_SPURS_TASK_ERROR_NOMEM = 0x80410904, + CELL_SPURS_TASK_ERROR_SRCH = 0x80410905, + CELL_SPURS_TASK_ERROR_NOEXEC = 0x80410907, + CELL_SPURS_TASK_ERROR_PERM = 0x80410909, + CELL_SPURS_TASK_ERROR_BUSY = 0x8041090A, + CELL_SPURS_TASK_ERROR_FAULT = 0x8041090D, + CELL_SPURS_TASK_ERROR_ALIGN = 0x80410910, + CELL_SPURS_TASK_ERROR_STAT = 0x8041090F, + CELL_SPURS_TASK_ERROR_NULL_POINTER = 0x80410911, + CELL_SPURS_TASK_ERROR_FATAL = 0x80410914, + CELL_SPURS_TASK_ERROR_SHUTDOWN = 0x80410920, +}; + +enum +{ + CELL_SPURS_JOB_ERROR_AGAIN = 0x80410A01, + CELL_SPURS_JOB_ERROR_INVAL = 0x80410A02, + CELL_SPURS_JOB_ERROR_NOSYS = 0x80410A03, + CELL_SPURS_JOB_ERROR_NOMEM = 0x80410A04, + CELL_SPURS_JOB_ERROR_SRCH = 0x80410A05, + CELL_SPURS_JOB_ERROR_NOENT = 0x80410A06, + CELL_SPURS_JOB_ERROR_NOEXEC = 0x80410A07, + CELL_SPURS_JOB_ERROR_DEADLK = 0x80410A08, + CELL_SPURS_JOB_ERROR_PERM = 0x80410A09, + CELL_SPURS_JOB_ERROR_BUSY = 0x80410A0A, + CELL_SPURS_JOB_ERROR_JOB_DESCRIPTOR = 0x80410A0B, + CELL_SPURS_JOB_ERROR_JOB_DESCRIPTOR_SIZE = 0x80410A0C, + CELL_SPURS_JOB_ERROR_FAULT = 0x80410A0D, + CELL_SPURS_JOB_ERROR_CHILD = 0x80410A0E, + CELL_SPURS_JOB_ERROR_STAT = 0x80410A0F, + CELL_SPURS_JOB_ERROR_ALIGN = 0x80410A10, + CELL_SPURS_JOB_ERROR_NULL_POINTER = 0x80410A11, + CELL_SPURS_JOB_ERROR_MEMORY_CORRUPTED = 0x80410A12, + + CELL_SPURS_JOB_ERROR_MEMORY_SIZE = 0x80410A17, + CELL_SPURS_JOB_ERROR_UNKNOWN_COMMAND = 0x80410A18, + CELL_SPURS_JOB_ERROR_JOBLIST_ALIGNMENT = 0x80410A19, + CELL_SPURS_JOB_ERROR_JOB_ALIGNMENT = 0x80410A1a, + CELL_SPURS_JOB_ERROR_CALL_OVERFLOW = 0x80410A1b, + CELL_SPURS_JOB_ERROR_ABORT = 0x80410A1c, + CELL_SPURS_JOB_ERROR_DMALIST_ELEMENT = 0x80410A1d, + CELL_SPURS_JOB_ERROR_NUM_CACHE = 0x80410A1e, + CELL_SPURS_JOB_ERROR_INVALID_BINARY = 0x80410A1f, +}; + +// SPURS defines. +enum SPURSKernelInterfaces : u32 +{ + CELL_SPURS_MAX_SPU = 8, + CELL_SPURS_MAX_WORKLOAD = 16, + CELL_SPURS_MAX_WORKLOAD2 = 32, + CELL_SPURS_SYS_SERVICE_WORKLOAD_ID = 32, + CELL_SPURS_MAX_PRIORITY = 16, + CELL_SPURS_NAME_MAX_LENGTH = 15, + CELL_SPURS_SIZE = 4096, + CELL_SPURS_SIZE2 = 8192, + CELL_SPURS_INTERRUPT_VECTOR = 0x0, + CELL_SPURS_LOCK_LINE = 0x80, + CELL_SPURS_KERNEL_DMA_TAG_ID = 31, + CELL_SPURS_KERNEL1_ENTRY_ADDR = 0x818, + CELL_SPURS_KERNEL2_ENTRY_ADDR = 0x848, + CELL_SPURS_KERNEL1_EXIT_ADDR = 0x808, + CELL_SPURS_KERNEL2_EXIT_ADDR = 0x838, + CELL_SPURS_KERNEL1_SELECT_WORKLOAD_ADDR = 0x290, + CELL_SPURS_KERNEL2_SELECT_WORKLOAD_ADDR = 0x290, +}; + +enum RangeofEventQueuePortNumbers +{ + CELL_SPURS_STATIC_PORT_RANGE_BOTTOM = 15, + CELL_SPURS_DYNAMIC_PORT_RANGE_TOP = 16, + CELL_SPURS_DYNAMIC_PORT_RANGE_BOTTOM = 63, +}; + +enum SpursAttrFlags : u32 +{ + SAF_NONE = 0x00000000, + SAF_EXIT_IF_NO_WORK = 0x00000001, + SAF_UNKNOWN_FLAG_30 = 0x00000002, + SAF_SECOND_VERSION = 0x00000004, + SAF_UNKNOWN_FLAG_9 = 0x00400000, + SAF_UNKNOWN_FLAG_8 = 0x00800000, + SAF_UNKNOWN_FLAG_7 = 0x01000000, + SAF_SYSTEM_WORKLOAD_ENABLED = 0x02000000, + SAF_SPU_PRINTF_ENABLED = 0x10000000, + SAF_SPU_TGT_EXCLUSIVE_NON_CONTEXT = 0x20000000, + SAF_SPU_MEMORY_CONTAINER_SET = 0x40000000, + SAF_UNKNOWN_FLAG_0 = 0x80000000, +}; + +enum SpursFlags1 : u8 +{ + SF1_NONE = 0x00, + SF1_32_WORKLOADS = 0x40, + SF1_EXIT_IF_NO_WORK = 0x80, +}; + +enum SpursWorkloadConstants : u32 +{ + // Workload states + SPURS_WKL_STATE_NON_EXISTENT = 0, + SPURS_WKL_STATE_PREPARING = 1, + SPURS_WKL_STATE_RUNNABLE = 2, + SPURS_WKL_STATE_SHUTTING_DOWN = 3, + SPURS_WKL_STATE_REMOVABLE = 4, + SPURS_WKL_STATE_INVALID = 5, + + // Image addresses + SPURS_IMG_ADDR_SYS_SRV_WORKLOAD = 0x100, + SPURS_IMG_ADDR_TASKSET_PM = 0x200, +}; + +enum SpursWorkloadGUIDs : u64 +{ + // GUID + SPURS_GUID_SYS_WKL = 0x1BB841BF38F89D33ull, + SPURS_GUID_TASKSET_PM = 0x836E915B2E654143ull, +}; + +enum CellSpursModulePollStatus +{ + CELL_SPURS_MODULE_POLL_STATUS_READYCOUNT = 1, + CELL_SPURS_MODULE_POLL_STATUS_SIGNAL = 2, + CELL_SPURS_MODULE_POLL_STATUS_FLAG = 4 +}; + +enum SpursTraceConstants +{ + // Trace tag types + CELL_SPURS_TRACE_TAG_KERNEL = 0x20, + CELL_SPURS_TRACE_TAG_SERVICE = 0x21, + CELL_SPURS_TRACE_TAG_TASK = 0x22, + CELL_SPURS_TRACE_TAG_JOB = 0x23, + CELL_SPURS_TRACE_TAG_OVIS = 0x24, + CELL_SPURS_TRACE_TAG_LOAD = 0x2a, + CELL_SPURS_TRACE_TAG_MAP = 0x2b, + CELL_SPURS_TRACE_TAG_START = 0x2c, + CELL_SPURS_TRACE_TAG_STOP = 0x2d, + CELL_SPURS_TRACE_TAG_USER = 0x2e, + CELL_SPURS_TRACE_TAG_GUID = 0x2f, + + // Service incident + CELL_SPURS_TRACE_SERVICE_INIT = 0x01, + CELL_SPURS_TRACE_SERVICE_WAIT = 0x02, + CELL_SPURS_TRACE_SERVICE_EXIT = 0x03, + + // Task incident + CELL_SPURS_TRACE_TASK_DISPATCH = 0x01, + CELL_SPURS_TRACE_TASK_YIELD = 0x03, + CELL_SPURS_TRACE_TASK_WAIT = 0x04, + CELL_SPURS_TRACE_TASK_EXIT = 0x05, + + // Trace mode flags + CELL_SPURS_TRACE_MODE_FLAG_WRAP_BUFFER = 0x1, + CELL_SPURS_TRACE_MODE_FLAG_SYNCHRONOUS_START_STOP = 0x2, + CELL_SPURS_TRACE_MODE_FLAG_MASK = 0x3, +}; + +// SPURS task constants +enum SpursTaskConstants +{ + CELL_SPURS_MAX_TASK = 128, + CELL_SPURS_TASK_TOP = 0x3000, + CELL_SPURS_TASK_BOTTOM = 0x40000, + CELL_SPURS_MAX_TASK_NAME_LENGTH = 32, + CELL_SPURS_TASK_ATTRIBUTE_REVISION = 1, + CELL_SPURS_TASKSET_ATTRIBUTE_REVISION = 1, + CELL_SPURS_TASK_EXECUTION_CONTEXT_SIZE = 1024, + CELL_SPURS_TASKSET_PM_ENTRY_ADDR = 0xA00, + CELL_SPURS_TASKSET_PM_SYSCALL_ADDR = 0xA70, + + // Task syscall numbers + CELL_SPURS_TASK_SYSCALL_EXIT = 0, + CELL_SPURS_TASK_SYSCALL_YIELD = 1, + CELL_SPURS_TASK_SYSCALL_WAIT_SIGNAL = 2, + CELL_SPURS_TASK_SYSCALL_POLL = 3, + CELL_SPURS_TASK_SYSCALL_RECV_WKL_FLAG = 4, + + // Task poll status + CELL_SPURS_TASK_POLL_FOUND_TASK = 1, + CELL_SPURS_TASK_POLL_FOUND_WORKLOAD = 2, +}; + +enum CellSpursEventFlagWaitMode +{ + CELL_SPURS_EVENT_FLAG_OR = 0, + CELL_SPURS_EVENT_FLAG_AND = 1, + CELL_SPURS_EVENT_FLAG_WAIT_MODE_LAST = CELL_SPURS_EVENT_FLAG_AND, +}; + +enum CellSpursEventFlagClearMode +{ + CELL_SPURS_EVENT_FLAG_CLEAR_AUTO = 0, + CELL_SPURS_EVENT_FLAG_CLEAR_MANUAL = 1, + CELL_SPURS_EVENT_FLAG_CLEAR_LAST = CELL_SPURS_EVENT_FLAG_CLEAR_MANUAL, +}; + +enum CellSpursEventFlagDirection +{ + CELL_SPURS_EVENT_FLAG_SPU2SPU, + CELL_SPURS_EVENT_FLAG_SPU2PPU, + CELL_SPURS_EVENT_FLAG_PPU2SPU, + CELL_SPURS_EVENT_FLAG_ANY2ANY, + CELL_SPURS_EVENT_FLAG_LAST = CELL_SPURS_EVENT_FLAG_ANY2ANY, +}; + +// Event flag constants +enum SpursEventFlagConstants +{ + CELL_SPURS_EVENT_FLAG_MAX_WAIT_SLOTS = 16, + CELL_SPURS_EVENT_FLAG_INVALID_SPU_PORT = 0xFF, +}; + +struct alignas(16) CellSpursWorkloadFlag +{ + be_t unused0; + be_t unused1; + atomic_be_t flag; +}; + +CHECK_SIZE_ALIGN(CellSpursWorkloadFlag, 16, 16); + +struct CellSpursInfo +{ + be_t nSpus; + be_t spuThreadGroupPriority; + be_t ppuThreadPriority; + bool exitIfNoWork; + bool spurs2; + u8 padding24[2]; + vm::bptr traceBuffer; + be_t padding32; + be_t traceBufferSize; + be_t traceMode; + be_t spuThreadGroup; + be_t spuThreads[8]; + be_t spursHandlerThread0; + be_t spursHandlerThread1; + char namePrefix[16]; + be_t namePrefixLength; + be_t deadlineMissCounter; + be_t deadlineMeetCounter; + u8 padding[164]; +}; + +CHECK_SIZE(CellSpursInfo, 280); + +struct alignas(8) CellSpursAttribute +{ + be_t revision; // 0x0 + be_t sdkVersion; // 0x4 + be_t nSpus; // 0x8 + be_t spuPriority; // 0xC + be_t ppuPriority; // 0x10 + bool exitIfNoWork; // 0x14 + char prefix[15]; // 0x15 (not a NTS) + be_t prefixSize; // 0x24 + be_t flags; // 0x28 (SpursAttrFlags) + be_t container; // 0x2C + be_t unk0; // 0x30 + be_t unk1; // 0x34 + u8 swlPriority[8]; // 0x38 + be_t swlMaxSpu; // 0x40 + be_t swlIsPreem; // 0x44 + u8 padding[440]; +}; + +CHECK_SIZE_ALIGN(CellSpursAttribute, 512, 8); + +using CellSpursShutdownCompletionEventHook = void(vm::ptr spurs, u32 wid, vm::ptr arg); + +struct alignas(16) CellSpursTraceInfo +{ + be_t spuThread[8]; // 0x00 + be_t count[8]; // 0x20 + be_t spuThreadGroup; // 0x40 + be_t numSpus; // 0x44 + u8 padding[56]; +}; + +CHECK_SIZE_ALIGN(CellSpursTraceInfo, 128, 16); + +struct CellSpursTraceHeader +{ + u8 tag; + u8 length; + u8 spu; + u8 workload; + be_t time; +}; + +struct CellSpursTraceControlData +{ + be_t incident; + be_t reserved; +}; + +struct CellSpursTraceServiceData +{ + be_t incident; + be_t reserved; +}; + +struct CellSpursTraceTaskData +{ + be_t incident; + be_t taskId; +}; + +struct CellSpursTraceJobData +{ + u8 reserved[3]; + u8 binLSAhigh8; + be_t jobDescriptor; +}; + +struct CellSpursTraceLoadData +{ + be_t ea; + be_t ls; + be_t size; +}; + +struct CellSpursTraceMapData +{ + be_t offset; + be_t ls; + be_t size; +}; + +struct CellSpursTraceStartData +{ + char module[4]; + be_t level; + be_t ls; +}; + +struct alignas(16) CellSpursTracePacket +{ + CellSpursTraceHeader header; + + union + { + CellSpursTraceControlData control; + CellSpursTraceServiceData service; + CellSpursTraceTaskData task; + CellSpursTraceJobData job; + + CellSpursTraceLoadData load; + CellSpursTraceMapData map; + CellSpursTraceStartData start; + + be_t stop; + be_t user; + be_t guid; + be_t raw; + } + data; +}; + +CHECK_SIZE_ALIGN(CellSpursTracePacket, 16, 16); + +// Core CellSpurs structures +struct alignas(128) CellSpurs +{ + struct _sub_str1 + { + u8 unk0[0x20]; // 0x00 - SPU exception handler 0x08 - SPU exception handler args + be_t sem; // 0x20 + be_t x28; // 0x28 + be_t x2C; // 0x2C + vm::bptr hook; // 0x30 + vm::bptr hookArg; // 0x38 + u8 unk2[0x40]; + }; + + CHECK_SIZE(_sub_str1, 128); + + struct EventPortMux; + + using EventHandlerCallback = void(vm::ptr, u64 data); + + struct EventHandlerListNode + { + vm::bptr next; + be_t data; + vm::bptr handler; + }; + + struct EventPortMux + { + atomic_be_t reqPending; // 0x00 + be_t spuPort; // 0x04 + be_t x08; // 0x08 + be_t x0C; // 0x0C + be_t eventPort; // 0x10 + atomic_t> handlerList; // 0x18 + u8 x20[0x80 - 0x20]; // 0x20 + }; + + CHECK_SIZE(EventPortMux, 128); + + struct WorkloadInfo + { + vm::bcptr addr; // 0x00 Address of the executable + be_t arg; // 0x08 Argument + be_t size; // 0x10 Size of the executable + atomic_t uniqueId; // 0x14 Unique id of the workload. It is the same for all workloads with the same addr. + u8 pad[3]; + u8 priority[8]; // 0x18 Priority of the workload on each SPU + }; + + CHECK_SIZE(WorkloadInfo, 32); + + struct _sub_str4 + { + vm::bcptr nameClass; + vm::bcptr nameInstance; + }; + + atomic_t wklReadyCount1[0x10]; // 0x00 Number of SPUs requested by each workload (0..15 wids). + atomic_t wklIdleSpuCountOrReadyCount2[0x10]; // 0x10 SPURS1: Number of idle SPUs requested by each workload (0..15 wids). SPURS2: Number of SPUs requested by each workload (16..31 wids). + u8 wklCurrentContention[0x10]; // 0x20 Number of SPUs used by each workload. SPURS1: index = wid. SPURS2: packed 4-bit data, index = wid % 16, internal index = wid / 16. + u8 wklPendingContention[0x10]; // 0x30 Number of SPUs that are pending to context switch to the workload. SPURS1: index = wid. SPURS2: packed 4-bit data, index = wid % 16, internal index = wid / 16. + u8 wklMinContention[0x10]; // 0x40 Min SPUs required for each workload. SPURS1: index = wid. SPURS2: Unused. + atomic_t wklMaxContention[0x10]; // 0x50 Max SPUs that may be allocated to each workload. SPURS1: index = wid. SPURS2: packed 4-bit data, index = wid % 16, internal index = wid / 16. + CellSpursWorkloadFlag wklFlag; // 0x60 + atomic_be_t wklSignal1; // 0x70 Bitset for 0..15 wids + atomic_t sysSrvMessage; // 0x72 + u8 spuIdling; // 0x73 + u8 flags1; // 0x74 Type is SpursFlags1 + u8 sysSrvTraceControl; // 0x75 + u8 nSpus; // 0x76 + atomic_t wklFlagReceiver; // 0x77 + atomic_be_t wklSignal2; // 0x78 Bitset for 16..32 wids + u8 x7A[6]; // 0x7A + atomic_t wklState1[0x10]; // 0x80 SPURS_WKL_STATE_* + u8 wklStatus1[0x10]; // 0x90 + atomic_t wklEvent1[0x10]; // 0xA0 + atomic_be_t wklEnabled; // 0xB0 + atomic_be_t wklMskB; // 0xB4 - System service - Available module id + u32 xB8; // 0xB8 + u8 sysSrvExitBarrier; // 0xBC + atomic_t sysSrvMsgUpdateWorkload; // 0xBD + u8 xBE; // 0xBE + u8 sysSrvMsgTerminate; // 0xBF + u8 sysSrvPreemptWklId[8]; // 0xC0 Id of the workload that was preempted by the system workload on each SPU + u8 sysSrvOnSpu; // 0xC8 + u8 spuPort; // 0xC9 + u8 xCA; // 0xCA + u8 xCB; // 0xCB + + struct alignas(4) SrvTraceSyncVar + { + u8 sysSrvTraceInitialised; // 0xCC + u8 sysSrvNotifyUpdateTraceComplete; // 0xCD + u8 sysSrvMsgUpdateTrace; // 0xCE + u8 xCF; + }; + + atomic_t sysSrvTrace; // 0xCC + + atomic_t wklState2[0x10]; // 0xD0 SPURS_WKL_STATE_* + u8 wklStatus2[0x10]; // 0xE0 + atomic_t wklEvent2[0x10]; // 0xF0 + _sub_str1 wklF1[0x10]; // 0x100 + vm::bptr traceBuffer; // 0x900 + be_t traceStartIndex[6]; // 0x908 + u8 unknown7[0x948 - 0x920]; // 0x920 + be_t traceDataSize; // 0x948 + be_t traceMode; // 0x950 + u8 unknown8[0x980 - 0x954]; // 0x954 + be_t semPrv; // 0x980 + be_t unk11; // 0x988 + be_t unk12; // 0x98C + be_t unk13; // 0x990 + u8 unknown4[0xB00 - 0x998]; + WorkloadInfo wklInfo1[0x10]; // 0xB00 + WorkloadInfo wklInfoSysSrv; // 0xD00 + be_t ppu0; // 0xD20 Handler thread + be_t ppu1; // 0xD28 + be_t spuTG; // 0xD30 SPU thread group + be_t spus[8]; // 0xD34 + u8 unknown3[0xD5C - 0xD54]; + be_t eventQueue; // 0xD5C + be_t eventPort; // 0xD60 + atomic_t handlerDirty; // 0xD64 + atomic_t handlerWaiting; // 0xD65 + atomic_t handlerExiting; // 0xD66 + atomic_be_t enableEH; // 0xD68 + be_t exception; // 0xD6C + sys_spu_image_t spuImg; // 0xD70 + be_t flags; // 0xD80 + be_t spuPriority; // 0xD84 + be_t ppuPriority; // 0xD88 + char prefix[0x0f]; // 0xD8C + u8 prefixSize; // 0xD9B + be_t unk5; // 0xD9C + be_t revision; // 0xDA0 + be_t sdkVersion; // 0xDA4 + atomic_be_t spuPortBits; // 0xDA8 + sys_lwmutex_t mutex; // 0xDB0 + sys_lwcond_t cond; // 0xDC8 + u8 unknown9[0xE00 - 0xDD0]; + _sub_str4 wklH1[0x10]; // 0xE00 + EventPortMux eventPortMux; // 0xF00 + atomic_be_t globalSpuExceptionHandler; // 0xF80 + be_t globalSpuExceptionHandlerArgs; // 0xF88 + u8 unknown6[0x1000 - 0xF90]; + WorkloadInfo wklInfo2[0x10]; // 0x1000 + _sub_str1 wklF2[0x10]; // 0x1200 + _sub_str4 wklH2[0x10]; // 0x1A00 + u8 unknown_[0x2000 - 0x1B00]; + + force_inline atomic_t& wklState(const u32 wid) + { + if (wid & 0x10) + { + return wklState2[wid & 0xf]; + } + else + { + return wklState1[wid & 0xf]; + } + } +}; + +CHECK_SIZE_ALIGN(CellSpurs, 0x2000, 128); + +using CellSpurs2 = CellSpurs; + +struct CellSpursExceptionInfo +{ + be_t spu_thread; + be_t spu_npc; + be_t cause; + be_t option; +}; + +// Exception handler +using CellSpursGlobalExceptionEventHandler = void(vm::ptr spurs, vm::cptr info, u32 id, vm::ptr arg); + +struct CellSpursWorkloadAttribute +{ + be_t revision; + be_t sdkVersion; + vm::bcptr pm; + be_t size; + be_t data; + u8 priority[8]; + be_t minContention; + be_t maxContention; + vm::bcptr nameClass; + vm::bcptr nameInstance; + vm::bptr hook; + vm::bptr hookArg; + u8 padding[456]; +}; + +CHECK_SIZE_ALIGN(CellSpursWorkloadAttribute, 512, 8); + +struct alignas(128) CellSpursEventFlag +{ + struct alignas(8) ControlSyncVar + { + be_t events; // 0x00 Event bits + be_t spuTaskPendingRecv; // 0x02 A bit is set to 1 when the condition of the SPU task using the slot are met and back to 0 when the SPU task unblocks + be_t ppuWaitMask; // 0x04 Wait mask for blocked PPU thread + u8 ppuWaitSlotAndMode; // 0x06 Top 4 bits: Wait slot number of the blocked PPU threa, Bottom 4 bits: Wait mode of the blocked PPU thread + u8 ppuPendingRecv; // 0x07 Set to 1 when the blocked PPU thread's conditions are met and back to 0 when the PPU thread is unblocked + }; + + union + { + atomic_t ctrl; // 0x00 + atomic_be_t events; // 0x00 + }; + + be_t spuTaskUsedWaitSlots; // 0x08 A bit is set to 1 if the wait slot corresponding to the bit is used by an SPU task and 0 otherwise + be_t spuTaskWaitMode; // 0x0A A bit is set to 1 if the wait mode for the SPU task corresponding to the bit is AND and 0 otherwise + u8 spuPort; // 0x0C + u8 isIwl; // 0x0D + u8 direction; // 0x0E + u8 clearMode; // 0x0F + be_t spuTaskWaitMask[16]; // 0x10 Wait mask for blocked SPU tasks + be_t pendingRecvTaskEvents[16]; // 0x30 The value of event flag when the wait condition for the thread/task was met + u8 waitingTaskId[16]; // 0x50 Task id of waiting SPU threads + u8 waitingTaskWklId[16]; // 0x60 Workload id of waiting SPU threads + be_t addr; // 0x70 + be_t eventPortId; // 0x78 + be_t eventQueueId; // 0x7C +}; + +CHECK_SIZE_ALIGN(CellSpursEventFlag, 128, 128); + +using CellSpursLFQueue = CellSyncLFQueue; + +union CellSpursTaskArgument +{ + be_t _u32[4]; + be_t _u64[2]; +}; + +union CellSpursTaskLsPattern +{ + be_t _u32[4]; + be_t _u64[2]; +}; + +struct alignas(16) CellSpursTaskAttribute +{ + u8 reserved[256]; +}; + +CHECK_SIZE_ALIGN(CellSpursTaskAttribute, 256, 16); + +struct alignas(16) CellSpursTaskAttribute2 +{ + be_t revision; + be_t sizeContext; + be_t eaContext; + CellSpursTaskLsPattern lsPattern; + vm::bcptr name; + + u8 reserved[220]; +}; + +CHECK_SIZE_ALIGN(CellSpursTaskAttribute2, 256, 16); + +// Exception handler +using CellSpursTasksetExceptionEventHandler = void(vm::ptr spurs, vm::ptr taskset, u32 idTask, vm::cptr info, vm::ptr arg); + +struct alignas(128) CellSpursTaskExitCode +{ + u8 skip[128]; +}; + +CHECK_SIZE_ALIGN(CellSpursTaskExitCode, 128, 128); + +struct CellSpursTaskInfo +{ + CellSpursTaskLsPattern lsPattern; + CellSpursTaskArgument argument; + vm::bptr eaElf; + vm::bptr eaContext; + be_t sizeContext; + u8 state; + u8 hasSignal; + u8 padding[2]; + vm::bcptr eaTaskExitCode; + u8 guid[8]; + u8 reserved[12]; +}; + +CHECK_SIZE(CellSpursTaskInfo, 72); + +struct CellSpursTasksetInfo +{ + CellSpursTaskInfo taskInfo[CELL_SPURS_MAX_TASK]; + be_t argument; + be_t idWorkload; + be_t idLastScheduledTask; + vm::bcptr name; + vm::bptr exceptionEventHandler; + vm::bptr exceptionEventHandlerArgument; + be_t sizeTaskset; + u8 reserved[112]; +}; + +CHECK_SIZE(CellSpursTasksetInfo, 9360); + +struct alignas(8) CellSpursTasksetAttribute +{ + be_t revision; // 0x00 + be_t sdk_version; // 0x04 + be_t args; // 0x08 + u8 priority[8]; // 0x10 + be_t max_contention; // 0x18 + vm::bcptr name; // 0x1C + be_t taskset_size; // 0x20 + be_t enable_clear_ls; // 0x24 + u8 reserved[472]; +}; + +CHECK_SIZE_ALIGN(CellSpursTasksetAttribute, 512, 8); + +struct alignas(128) CellSpursTaskset +{ + struct TaskInfo + { + CellSpursTaskArgument args; // 0x00 + vm::bcptr elf; // 0x10 + be_t context_save_storage_and_alloc_ls_blocks; // 0x18 This is (context_save_storage_addr | allocated_ls_blocks) + CellSpursTaskLsPattern ls_pattern; // 0x20 + }; + + CHECK_SIZE(TaskInfo, 48); + + be_t running; // 0x00 + be_t ready; // 0x10 + be_t pending_ready; // 0x20 + be_t enabled; // 0x30 + be_t signalled; // 0x40 + be_t waiting; // 0x50 + vm::bptr spurs; // 0x60 + be_t args; // 0x68 + u8 enable_clear_ls; // 0x70 + u8 x71; // 0x71 + u8 wkl_flag_wait_task; // 0x72 + u8 last_scheduled_task; // 0x73 + be_t wid; // 0x74 + be_t x78; // 0x78 + TaskInfo task_info[128]; // 0x80 + vm::bptr exception_handler; // 0x1880 + vm::bptr exception_handler_arg; // 0x1888 + be_t size; // 0x1890 + u32 unk2; // 0x1894 + u32 event_flag_id1; // 0x1898 + u32 event_flag_id2; // 0x189C + u8 unk3[0x60]; // 0x18A0 +}; + +CHECK_SIZE_ALIGN(CellSpursTaskset, 128 * 50, 128); + +struct alignas(128) CellSpursTaskset2 +{ + struct TaskInfo + { + CellSpursTaskArgument args; + vm::bptr elf_addr; + vm::bptr context_save_storage; // This is (context_save_storage_addr | allocated_ls_blocks) + CellSpursTaskLsPattern ls_pattern; + }; + + CHECK_SIZE(TaskInfo, 48); + + be_t running_set[4]; // 0x00 + be_t ready_set[4]; // 0x10 + be_t ready2_set[4]; // 0x20 - TODO: Find out what this is + be_t enabled_set[4]; // 0x30 + be_t signal_received_set[4]; // 0x40 + be_t waiting_set[4]; // 0x50 + vm::bptr spurs; // 0x60 + be_t args; // 0x68 + u8 enable_clear_ls; // 0x70 + u8 x71; // 0x71 + u8 x72; // 0x72 + u8 last_scheduled_task; // 0x73 + be_t wid; // 0x74 + be_t x78; // 0x78 + TaskInfo task_info[128]; // 0x80 + vm::bptr exception_handler; // 0x1880 + vm::bptr exception_handler_arg; // 0x1888 + be_t size; // 0x1890 + u32 unk2; // 0x1894 + u32 event_flag_id1; // 0x1898 + u32 event_flag_id2; // 0x189C + u8 unk3[0x1980 - 0x18A0]; // 0x18A0 + be_t task_exit_code[128]; // 0x1980 + u8 unk4[0x2900 - 0x2180]; // 0x2180 +}; + +CHECK_SIZE_ALIGN(CellSpursTaskset2, 128 * 82, 128); + +struct alignas(16) CellSpursTaskNameBuffer +{ + char taskName[CELL_SPURS_MAX_TASK][CELL_SPURS_MAX_TASK_NAME_LENGTH]; +}; + +struct alignas(8) CellSpursTasksetAttribute2 +{ + be_t revision; // 0x00 + vm::bcptr name; // 0x04 + be_t args; // 0x08 + u8 priority[8]; // 0x10 + be_t max_contention; // 0x18 + be_t enable_clear_ls; // 0x1C + vm::bptr task_name_buffer; // 0x20 + u8 reserved[472]; +}; + +CHECK_SIZE_ALIGN(CellSpursTasksetAttribute2, 512, 8); + +struct alignas(16) CellSpursTaskBinInfo +{ + be_t eaElf; + be_t sizeContext; + be_t reserved; + CellSpursTaskLsPattern lsPattern; +}; + +// The SPURS kernel context. This resides at 0x100 of the LS. +struct SpursKernelContext +{ + u8 tempArea[0x80]; // 0x100 + u8 wklLocContention[0x10]; // 0x180 + u8 wklLocPendingContention[0x10]; // 0x190 + u8 priority[0x10]; // 0x1A0 + u8 x1B0[0x10]; // 0x1B0 + vm::bptr spurs; // 0x1C0 + be_t spuNum; // 0x1C8 + be_t dmaTagId; // 0x1CC + vm::bcptr wklCurrentAddr; // 0x1D0 + be_t wklCurrentUniqueId; // 0x1D8 + be_t wklCurrentId; // 0x1DC + be_t exitToKernelAddr; // 0x1E0 + be_t selectWorkloadAddr; // 0x1E4 + u8 moduleId[2]; // 0x1E8 + u8 sysSrvInitialised; // 0x1EA + u8 spuIdling; // 0x1EB + be_t wklRunnable1; // 0x1EC + be_t wklRunnable2; // 0x1EE + be_t x1F0; // 0x1F0 + be_t x1F4; // 0x1F4 + be_t x1F8; // 0x1F8 + be_t x1FC; // 0x1FC + be_t x200; // 0x200 + be_t x204; // 0x204 + be_t x208; // 0x208 + be_t x20C; // 0x20C + be_t traceBuffer; // 0x210 + be_t traceMsgCount; // 0x218 + be_t traceMaxCount; // 0x21C + u8 wklUniqueId[0x10]; // 0x220 + u8 x230[0x280 - 0x230]; // 0x230 + be_t guid[4]; // 0x280 +}; + +CHECK_SIZE(SpursKernelContext, 0x190); + +// The SPURS taskset policy module context. This resides at 0x2700 of the LS. +struct SpursTasksetContext +{ + u8 tempAreaTaskset[0x80]; // 0x2700 + u8 tempAreaTaskInfo[0x30]; // 0x2780 + be_t x27B0; // 0x27B0 + vm::bptr taskset; // 0x27B8 + be_t kernelMgmtAddr; // 0x27C0 + be_t syscallAddr; // 0x27C4 + be_t x27C8; // 0x27C8 + be_t spuNum; // 0x27CC + be_t dmaTagId; // 0x27D0 + be_t taskId; // 0x27D4 + u8 x27D8[0x2840 - 0x27D8]; // 0x27D8 + u8 moduleId[16]; // 0x2840 + u8 stackArea[0x2C80 - 0x2850]; // 0x2850 + be_t savedContextLr; // 0x2C80 + be_t savedContextSp; // 0x2C90 + be_t savedContextR80ToR127[48]; // 0x2CA0 + be_t savedContextFpscr; // 0x2FA0 + be_t savedWriteTagGroupQueryMask; // 0x2FB0 + be_t savedSpuWriteEventMask; // 0x2FB4 + be_t tasksetMgmtAddr; // 0x2FB8 + be_t guidAddr; // 0x2FBC + be_t x2FC0; // 0x2FC0 + be_t x2FC8; // 0x2FC8 + be_t taskExitCode; // 0x2FD0 + be_t x2FD4; // 0x2FD4 + u8 x2FD8[0x3000 - 0x2FD8]; // 0x2FD8 +}; + +CHECK_SIZE(SpursTasksetContext, 0x900); + +class SpursModuleExit +{ +}; diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpursJq.cpp b/rpcs3/Emu/Cell/Modules/cellSpursJq.cpp similarity index 97% rename from rpcs3/Emu/SysCalls/Modules/cellSpursJq.cpp rename to rpcs3/Emu/Cell/Modules/cellSpursJq.cpp index 1a943ebccc..b5d85f2d5c 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpursJq.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSpursJq.cpp @@ -1,16 +1,14 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/SysCalls/lv2/sys_sync.h" -#include "Emu/SysCalls/lv2/sys_lwmutex.h" -#include "Emu/SysCalls/lv2/sys_lwcond.h" -#include "Emu/SysCalls/lv2/sys_spu.h" +#include "Emu/Cell/lv2/sys_lwmutex.h" +#include "Emu/Cell/lv2/sys_lwcond.h" +#include "Emu/Cell/lv2/sys_spu.h" #include "cellSpurs.h" #include "cellSpursJq.h" -extern Module<> cellSpursJq; +LOG_CHANNEL(cellSpursJq); s32 cellSpursJobQueueAttributeInitialize() { @@ -390,7 +388,7 @@ s32 cellSpursJobQueueUnsetExceptionEventHandler() return CELL_OK; } -Module<> cellSpursJq("cellSpursJq", []() +DECLARE(ppu_module_manager::cellSpursJq)("cellSpursJq", []() { REG_FUNC(cellSpursJq, cellSpursJobQueueAttributeInitialize); REG_FUNC(cellSpursJq, cellSpursJobQueueAttributeSetMaxGrab); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpursJq.h b/rpcs3/Emu/Cell/Modules/cellSpursJq.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellSpursJq.h rename to rpcs3/Emu/Cell/Modules/cellSpursJq.h diff --git a/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp b/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp new file mode 100644 index 0000000000..eb56cdd302 --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp @@ -0,0 +1,1986 @@ +#include "stdafx.h" +#include "Loader/ELF.h" +#include "Emu/System.h" +#include "Emu/Cell/PPUModule.h" + +#include "Emu/Cell/SPUThread.h" +#include "Emu/Cell/lv2/sys_lwmutex.h" +#include "Emu/Cell/lv2/sys_lwcond.h" +#include "Emu/Cell/lv2/sys_spu.h" +#include "cellSpurs.h" + +//---------------------------------------------------------------------------- +// Externs +//---------------------------------------------------------------------------- + +extern _log::channel cellSpurs; + +//---------------------------------------------------------------------------- +// Function prototypes +//---------------------------------------------------------------------------- + +// +// SPURS utility functions +// +static void cellSpursModulePutTrace(CellSpursTracePacket* packet, u32 dmaTagId); +static u32 cellSpursModulePollStatus(SPUThread& spu, u32* status); +static void cellSpursModuleExit(SPUThread& spu); + +static bool spursDma(SPUThread& spu, u32 cmd, u64 ea, u32 lsa, u32 size, u32 tag); +static u32 spursDmaGetCompletionStatus(SPUThread& spu, u32 tagMask); +static u32 spursDmaWaitForCompletion(SPUThread& spu, u32 tagMask, bool waitForAll = true); +static void spursHalt(SPUThread& spu); + +// +// SPURS kernel functions +// +static bool spursKernel1SelectWorkload(SPUThread& spu); +static bool spursKernel2SelectWorkload(SPUThread& spu); +static void spursKernelDispatchWorkload(SPUThread& spu, u64 widAndPollStatus); +static bool spursKernelWorkloadExit(SPUThread& spu); +bool spursKernelEntry(SPUThread& spu); + +// +// SPURS system workload functions +// +static bool spursSysServiceEntry(SPUThread& spu); +// TODO: Exit +static void spursSysServiceIdleHandler(SPUThread& spu, SpursKernelContext* ctxt); +static void spursSysServiceMain(SPUThread& spu, u32 pollStatus); +static void spursSysServiceProcessRequests(SPUThread& spu, SpursKernelContext* ctxt); +static void spursSysServiceActivateWorkload(SPUThread& spu, SpursKernelContext* ctxt); +// TODO: Deactivate workload +static void spursSysServiceUpdateShutdownCompletionEvents(SPUThread& spu, SpursKernelContext* ctxt, u32 wklShutdownBitSet); +static void spursSysServiceTraceSaveCount(SPUThread& spu, SpursKernelContext* ctxt); +static void spursSysServiceTraceUpdate(SPUThread& spu, SpursKernelContext* ctxt, u32 arg2, u32 arg3, u32 forceNotify); +// TODO: Deactivate trace +// TODO: System workload entry +static void spursSysServiceCleanupAfterSystemWorkload(SPUThread& spu, SpursKernelContext* ctxt); + +// +// SPURS taskset policy module functions +// +static bool spursTasksetEntry(SPUThread& spu); +static bool spursTasksetSyscallEntry(SPUThread& spu); +static void spursTasksetResumeTask(SPUThread& spu); +static void spursTasksetStartTask(SPUThread& spu, CellSpursTaskArgument& taskArgs); +static s32 spursTasksetProcessRequest(SPUThread& spu, s32 request, u32* taskId, u32* isWaiting); +static void spursTasksetProcessPollStatus(SPUThread& spu, u32 pollStatus); +static bool spursTasksetPollStatus(SPUThread& spu); +static void spursTasksetExit(SPUThread& spu); +static void spursTasksetOnTaskExit(SPUThread& spu, u64 addr, u32 taskId, s32 exitCode, u64 args); +static s32 spursTasketSaveTaskContext(SPUThread& spu); +static void spursTasksetDispatch(SPUThread& spu); +static s32 spursTasksetProcessSyscall(SPUThread& spu, u32 syscallNum, u32 args); +static void spursTasksetInit(SPUThread& spu, u32 pollStatus); +static s32 spursTasksetLoadElf(SPUThread& spu, u32* entryPoint, u32* lowestLoadAddr, u64 elfAddr, bool skipWriteableSegments); + +//---------------------------------------------------------------------------- +// SPURS utility functions +//---------------------------------------------------------------------------- + +// Output trace information +void cellSpursModulePutTrace(CellSpursTracePacket* packet, u32 dmaTagId) +{ + // TODO: Implement this +} + +// Check for execution right requests +u32 cellSpursModulePollStatus(SPUThread& spu, u32* status) +{ + auto ctxt = vm::_ptr(spu.offset + 0x100); + + spu.gpr[3]._u32[3] = 1; + if (ctxt->spurs->flags1 & SF1_32_WORKLOADS) + { + spursKernel2SelectWorkload(spu); + } + else + { + spursKernel1SelectWorkload(spu); + } + + auto result = spu.gpr[3]._u64[1]; + if (status) + { + *status = (u32)result; + } + + u32 wklId = result >> 32; + return wklId == ctxt->wklCurrentId ? 0 : 1; +} + +// Exit current workload +void cellSpursModuleExit(SPUThread& spu) +{ + auto ctxt = vm::_ptr(spu.offset + 0x100); + spu.pc = ctxt->exitToKernelAddr - 4; + throw SpursModuleExit(); +} + +// Execute a DMA operation +bool spursDma(SPUThread& spu, u32 cmd, u64 ea, u32 lsa, u32 size, u32 tag) +{ + spu.set_ch_value(MFC_LSA, lsa); + spu.set_ch_value(MFC_EAH, (u32)(ea >> 32)); + spu.set_ch_value(MFC_EAL, (u32)(ea)); + spu.set_ch_value(MFC_Size, size); + spu.set_ch_value(MFC_TagID, tag); + spu.set_ch_value(MFC_Cmd, cmd); + + if (cmd == MFC_GETLLAR_CMD || cmd == MFC_PUTLLC_CMD || cmd == MFC_PUTLLUC_CMD) + { + u32 rv; + + rv = spu.get_ch_value(MFC_RdAtomicStat); + auto success = rv ? true : false; + success = cmd == MFC_PUTLLC_CMD ? !success : success; + return success; + } + + return true; +} + +// Get the status of DMA operations +u32 spursDmaGetCompletionStatus(SPUThread& spu, u32 tagMask) +{ + spu.set_ch_value(MFC_WrTagMask, tagMask); + spu.set_ch_value(MFC_WrTagUpdate, MFC_TAG_UPDATE_IMMEDIATE); + return spu.get_ch_value(MFC_RdTagStat); +} + +// Wait for DMA operations to complete +u32 spursDmaWaitForCompletion(SPUThread& spu, u32 tagMask, bool waitForAll) +{ + spu.set_ch_value(MFC_WrTagMask, tagMask); + spu.set_ch_value(MFC_WrTagUpdate, waitForAll ? MFC_TAG_UPDATE_ALL : MFC_TAG_UPDATE_ANY); + return spu.get_ch_value(MFC_RdTagStat); +} + +// Halt the SPU +void spursHalt(SPUThread& spu) +{ + spu.halt(); +} + +//---------------------------------------------------------------------------- +// SPURS kernel functions +//---------------------------------------------------------------------------- + +// Select a workload to run +bool spursKernel1SelectWorkload(SPUThread& spu) +{ + auto ctxt = vm::_ptr(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. + // If the first argument is true then the shared data is not updated with the result. + const auto isPoll = spu.gpr[3]._u32[3]; + + u32 wklSelectedId; + u32 pollStatus; + + vm::reservation_op(vm::cast(ctxt->spurs.addr(), HERE), 128, [&]() + { + // lock the first 0x80 bytes of spurs + auto spurs = ctxt->spurs.get_ptr_priv(); + + // Calculate the contention (number of SPUs used) for each workload + u8 contention[CELL_SPURS_MAX_WORKLOAD]; + u8 pendingContention[CELL_SPURS_MAX_WORKLOAD]; + for (auto i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) + { + contention[i] = spurs->wklCurrentContention[i] - ctxt->wklLocContention[i]; + + // If this is a poll request then the number of SPUs pending to context switch is also added to the contention presumably + // to prevent unnecessary jumps to the kernel + if (isPoll) + { + pendingContention[i] = spurs->wklPendingContention[i] - ctxt->wklLocPendingContention[i]; + if (i != ctxt->wklCurrentId) + { + contention[i] += pendingContention[i]; + } + } + } + + wklSelectedId = CELL_SPURS_SYS_SERVICE_WORKLOAD_ID; + pollStatus = 0; + + // The system service has the highest priority. Select the system service if + // the system service message bit for this SPU is set. + if (spurs->sysSrvMessage & (1 << ctxt->spuNum)) + { + ctxt->spuIdling = 0; + if (!isPoll || ctxt->wklCurrentId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) + { + // Clear the message bit + spurs->sysSrvMessage.raw() &= ~(1 << ctxt->spuNum); + } + } + else + { + // Caclulate the scheduling weight for each workload + u16 maxWeight = 0; + for (auto i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) + { + u16 runnable = ctxt->wklRunnable1 & (0x8000 >> i); + u16 wklSignal = spurs->wklSignal1.load() & (0x8000 >> i); + u8 wklFlag = spurs->wklFlag.flag.load() == 0 ? spurs->wklFlagReceiver == i ? 1 : 0 : 0; + u8 readyCount = spurs->wklReadyCount1[i] > CELL_SPURS_MAX_SPU ? CELL_SPURS_MAX_SPU : spurs->wklReadyCount1[i].load(); + u8 idleSpuCount = spurs->wklIdleSpuCountOrReadyCount2[i] > CELL_SPURS_MAX_SPU ? CELL_SPURS_MAX_SPU : spurs->wklIdleSpuCountOrReadyCount2[i].load(); + u8 requestCount = readyCount + idleSpuCount; + + // For a workload to be considered for scheduling: + // 1. Its priority must not be 0 + // 2. The number of SPUs used by it must be less than the max contention for that workload + // 3. The workload should be in runnable state + // 4. The number of SPUs allocated to it must be less than the number of SPUs requested (i.e. readyCount) + // OR the workload must be signalled + // OR the workload flag is 0 and the workload is configured as the wokload flag receiver + if (runnable && ctxt->priority[i] != 0 && spurs->wklMaxContention[i] > contention[i]) + { + if (wklFlag || wklSignal || (readyCount != 0 && requestCount > contention[i])) + { + // The scheduling weight of the workload is formed from the following parameters in decreasing order of priority: + // 1. Wokload signal set or workload flag or ready count > contention + // 2. Priority of the workload on the SPU + // 3. Is the workload the last selected workload + // 4. Minimum contention of the workload + // 5. Number of SPUs that are being used by the workload (lesser the number, more the weight) + // 6. Is the workload executable same as the currently loaded executable + // 7. The workload id (lesser the number, more the weight) + u16 weight = (wklFlag || wklSignal || (readyCount > contention[i])) ? 0x8000 : 0; + weight |= (u16)(ctxt->priority[i] & 0x7F) << 16; + weight |= i == ctxt->wklCurrentId ? 0x80 : 0x00; + weight |= (contention[i] > 0 && spurs->wklMinContention[i] > contention[i]) ? 0x40 : 0x00; + weight |= ((CELL_SPURS_MAX_SPU - contention[i]) & 0x0F) << 2; + weight |= ctxt->wklUniqueId[i] == ctxt->wklCurrentId ? 0x02 : 0x00; + weight |= 0x01; + + // In case of a tie the lower numbered workload is chosen + if (weight > maxWeight) + { + wklSelectedId = i; + maxWeight = weight; + pollStatus = readyCount > contention[i] ? CELL_SPURS_MODULE_POLL_STATUS_READYCOUNT : 0; + pollStatus |= wklSignal ? CELL_SPURS_MODULE_POLL_STATUS_SIGNAL : 0; + pollStatus |= wklFlag ? CELL_SPURS_MODULE_POLL_STATUS_FLAG : 0; + } + } + } + } + + // Not sure what this does. Possibly mark the SPU as idle/in use. + ctxt->spuIdling = wklSelectedId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID ? 1 : 0; + + if (!isPoll || wklSelectedId == ctxt->wklCurrentId) + { + // Clear workload signal for the selected workload + spurs->wklSignal1.raw() &= ~(0x8000 >> wklSelectedId); + spurs->wklSignal2.raw() &= ~(0x80000000u >> wklSelectedId); + + // If the selected workload is the wklFlag workload then pull the wklFlag to all 1s + if (wklSelectedId == spurs->wklFlagReceiver) + { + spurs->wklFlag.flag = -1; + } + } + } + + if (!isPoll) + { + // Called by kernel + // Increment the contention for the selected workload + if (wklSelectedId != CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) + { + contention[wklSelectedId]++; + } + + for (auto i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) + { + spurs->wklCurrentContention[i] = contention[i]; + spurs->wklPendingContention[i] = spurs->wklPendingContention[i] - ctxt->wklLocPendingContention[i]; + ctxt->wklLocContention[i] = 0; + ctxt->wklLocPendingContention[i] = 0; + } + + if (wklSelectedId != CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) + { + ctxt->wklLocContention[wklSelectedId] = 1; + } + + ctxt->wklCurrentId = wklSelectedId; + } + else if (wklSelectedId != ctxt->wklCurrentId) + { + // Not called by kernel but a context switch is required + // Increment the pending contention for the selected workload + if (wklSelectedId != CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) + { + pendingContention[wklSelectedId]++; + } + + for (auto i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) + { + spurs->wklPendingContention[i] = pendingContention[i]; + ctxt->wklLocPendingContention[i] = 0; + } + + if (wklSelectedId != CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) + { + ctxt->wklLocPendingContention[wklSelectedId] = 1; + } + } + else + { + // Not called by kernel and no context switch is required + for (auto i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) + { + spurs->wklPendingContention[i] = spurs->wklPendingContention[i] - ctxt->wklLocPendingContention[i]; + ctxt->wklLocPendingContention[i] = 0; + } + } + + std::memcpy(vm::base(spu.offset + 0x100), spurs, 128); + }); + + u64 result = (u64)wklSelectedId << 32; + result |= pollStatus; + spu.gpr[3]._u64[1] = result; + return true; +} + +// Select a workload to run +bool spursKernel2SelectWorkload(SPUThread& spu) +{ + auto ctxt = vm::_ptr(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. + // If the first argument is true then the shared data is not updated with the result. + const auto isPoll = spu.gpr[3]._u32[3]; + + u32 wklSelectedId; + u32 pollStatus; + + vm::reservation_op(vm::cast(ctxt->spurs.addr(), HERE), 128, [&]() + { + // lock the first 0x80 bytes of spurs + auto spurs = ctxt->spurs.get_ptr_priv(); + + // Calculate the contention (number of SPUs used) for each workload + u8 contention[CELL_SPURS_MAX_WORKLOAD2]; + u8 pendingContention[CELL_SPURS_MAX_WORKLOAD2]; + for (auto i = 0; i < CELL_SPURS_MAX_WORKLOAD2; i++) + { + contention[i] = spurs->wklCurrentContention[i & 0x0F] - ctxt->wklLocContention[i & 0x0F]; + contention[i] = i < CELL_SPURS_MAX_WORKLOAD ? contention[i] & 0x0F : contention[i] >> 4; + + // If this is a poll request then the number of SPUs pending to context switch is also added to the contention presumably + // to prevent unnecessary jumps to the kernel + if (isPoll) + { + pendingContention[i] = spurs->wklPendingContention[i & 0x0F] - ctxt->wklLocPendingContention[i & 0x0F]; + pendingContention[i] = i < CELL_SPURS_MAX_WORKLOAD ? pendingContention[i] & 0x0F : pendingContention[i] >> 4; + if (i != ctxt->wklCurrentId) + { + contention[i] += pendingContention[i]; + } + } + } + + wklSelectedId = CELL_SPURS_SYS_SERVICE_WORKLOAD_ID; + pollStatus = 0; + + // The system service has the highest priority. Select the system service if + // the system service message bit for this SPU is set. + if (spurs->sysSrvMessage & (1 << ctxt->spuNum)) + { + // Not sure what this does. Possibly Mark the SPU as in use. + ctxt->spuIdling = 0; + if (!isPoll || ctxt->wklCurrentId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) + { + // Clear the message bit + spurs->sysSrvMessage.raw() &= ~(1 << ctxt->spuNum); + } + } + else + { + // Caclulate the scheduling weight for each workload + u8 maxWeight = 0; + for (auto i = 0; i < CELL_SPURS_MAX_WORKLOAD2; i++) + { + auto j = i & 0x0F; + u16 runnable = i < CELL_SPURS_MAX_WORKLOAD ? ctxt->wklRunnable1 & (0x8000 >> j) : ctxt->wklRunnable2 & (0x8000 >> j); + u8 priority = i < CELL_SPURS_MAX_WORKLOAD ? ctxt->priority[j] & 0x0F : ctxt->priority[j] >> 4; + u8 maxContention = i < CELL_SPURS_MAX_WORKLOAD ? spurs->wklMaxContention[j] & 0x0F : spurs->wklMaxContention[j] >> 4; + u16 wklSignal = i < CELL_SPURS_MAX_WORKLOAD ? spurs->wklSignal1.load() & (0x8000 >> j) : spurs->wklSignal2.load() & (0x8000 >> j); + u8 wklFlag = spurs->wklFlag.flag.load() == 0 ? spurs->wklFlagReceiver == i ? 1 : 0 : 0; + u8 readyCount = i < CELL_SPURS_MAX_WORKLOAD ? spurs->wklReadyCount1[j] : spurs->wklIdleSpuCountOrReadyCount2[j]; + + // For a workload to be considered for scheduling: + // 1. Its priority must be greater than 0 + // 2. The number of SPUs used by it must be less than the max contention for that workload + // 3. The workload should be in runnable state + // 4. The number of SPUs allocated to it must be less than the number of SPUs requested (i.e. readyCount) + // OR the workload must be signalled + // OR the workload flag is 0 and the workload is configured as the wokload receiver + if (runnable && priority > 0 && maxContention > contention[i]) + { + if (wklFlag || wklSignal || readyCount > contention[i]) + { + // The scheduling weight of the workload is equal to the priority of the workload for the SPU. + // The current workload is given a sligtly higher weight presumably to reduce the number of context switches. + // In case of a tie the lower numbered workload is chosen. + u8 weight = priority << 4; + if (ctxt->wklCurrentId == i) + { + weight |= 0x04; + } + + if (weight > maxWeight) + { + wklSelectedId = i; + maxWeight = weight; + pollStatus = readyCount > contention[i] ? CELL_SPURS_MODULE_POLL_STATUS_READYCOUNT : 0; + pollStatus |= wklSignal ? CELL_SPURS_MODULE_POLL_STATUS_SIGNAL : 0; + pollStatus |= wklFlag ? CELL_SPURS_MODULE_POLL_STATUS_FLAG : 0; + } + } + } + } + + // Not sure what this does. Possibly mark the SPU as idle/in use. + ctxt->spuIdling = wklSelectedId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID ? 1 : 0; + + if (!isPoll || wklSelectedId == ctxt->wklCurrentId) + { + // Clear workload signal for the selected workload + spurs->wklSignal1.raw() &= ~(0x8000 >> wklSelectedId); + spurs->wklSignal2.raw() &= ~(0x80000000u >> wklSelectedId); + + // If the selected workload is the wklFlag workload then pull the wklFlag to all 1s + if (wklSelectedId == spurs->wklFlagReceiver) + { + spurs->wklFlag.flag = -1; + } + } + } + + if (!isPoll) + { + // Called by kernel + // Increment the contention for the selected workload + if (wklSelectedId != CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) + { + contention[wklSelectedId]++; + } + + for (auto i = 0; i < (CELL_SPURS_MAX_WORKLOAD2 >> 1); i++) + { + spurs->wklCurrentContention[i] = contention[i] | (contention[i + 0x10] << 4); + spurs->wklPendingContention[i] = spurs->wklPendingContention[i] - ctxt->wklLocPendingContention[i]; + ctxt->wklLocContention[i] = 0; + ctxt->wklLocPendingContention[i] = 0; + } + + ctxt->wklLocContention[wklSelectedId & 0x0F] = wklSelectedId < CELL_SPURS_MAX_WORKLOAD ? 0x01 : wklSelectedId < CELL_SPURS_MAX_WORKLOAD2 ? 0x10 : 0; + ctxt->wklCurrentId = wklSelectedId; + } + else if (wklSelectedId != ctxt->wklCurrentId) + { + // Not called by kernel but a context switch is required + // Increment the pending contention for the selected workload + if (wklSelectedId != CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) + { + pendingContention[wklSelectedId]++; + } + + for (auto i = 0; i < (CELL_SPURS_MAX_WORKLOAD2 >> 1); i++) + { + spurs->wklPendingContention[i] = pendingContention[i] | (pendingContention[i + 0x10] << 4); + ctxt->wklLocPendingContention[i] = 0; + } + + ctxt->wklLocPendingContention[wklSelectedId & 0x0F] = wklSelectedId < CELL_SPURS_MAX_WORKLOAD ? 0x01 : wklSelectedId < CELL_SPURS_MAX_WORKLOAD2 ? 0x10 : 0; + } + else + { + // Not called by kernel and no context switch is required + for (auto i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) + { + spurs->wklPendingContention[i] = spurs->wklPendingContention[i] - ctxt->wklLocPendingContention[i]; + ctxt->wklLocPendingContention[i] = 0; + } + } + + std::memcpy(vm::base(spu.offset + 0x100), spurs, 128); + }); + + u64 result = (u64)wklSelectedId << 32; + result |= pollStatus; + spu.gpr[3]._u64[1] = result; + return true; +} + +// SPURS kernel dispatch workload +void spursKernelDispatchWorkload(SPUThread& spu, u64 widAndPollStatus) +{ + auto ctxt = vm::_ptr(spu.offset + 0x100); + auto isKernel2 = ctxt->spurs->flags1 & SF1_32_WORKLOADS ? true : false; + + auto pollStatus = (u32)widAndPollStatus; + auto wid = (u32)(widAndPollStatus >> 32); + + // DMA in the workload info for the selected workload + auto wklInfoOffset = wid < CELL_SPURS_MAX_WORKLOAD ? &ctxt->spurs->wklInfo1[wid] : + wid < CELL_SPURS_MAX_WORKLOAD2 && isKernel2 ? &ctxt->spurs->wklInfo2[wid & 0xf] : + &ctxt->spurs->wklInfoSysSrv; + + std::memcpy(vm::base(spu.offset + 0x3FFE0), wklInfoOffset, 0x20); + + // Load the workload to LS + auto wklInfo = vm::_ptr(spu.offset + 0x3FFE0); + if (ctxt->wklCurrentAddr != wklInfo->addr) + { + switch (wklInfo->addr.addr()) + { + case SPURS_IMG_ADDR_SYS_SRV_WORKLOAD: + spu.RegisterHleFunction(0xA00, spursSysServiceEntry); + break; + case SPURS_IMG_ADDR_TASKSET_PM: + spu.RegisterHleFunction(0xA00, spursTasksetEntry); + break; + default: + std::memcpy(vm::base(spu.offset + 0xA00), wklInfo->addr.get_ptr(), wklInfo->size); + break; + } + + ctxt->wklCurrentAddr = wklInfo->addr; + ctxt->wklCurrentUniqueId = wklInfo->uniqueId; + } + + if (!isKernel2) + { + ctxt->moduleId[0] = 0; + ctxt->moduleId[1] = 0; + } + + // Run workload + spu.gpr[0]._u32[3] = ctxt->exitToKernelAddr; + spu.gpr[1]._u32[3] = 0x3FFB0; + spu.gpr[3]._u32[3] = 0x100; + spu.gpr[4]._u64[1] = wklInfo->arg; + spu.gpr[5]._u32[3] = pollStatus; + spu.pc = 0xA00 - 4; +} + +// SPURS kernel workload exit +bool spursKernelWorkloadExit(SPUThread& spu) +{ + auto ctxt = vm::_ptr(spu.offset + 0x100); + auto isKernel2 = ctxt->spurs->flags1 & SF1_32_WORKLOADS ? true : false; + + // Select next workload to run + spu.gpr[3].clear(); + if (isKernel2) + { + spursKernel2SelectWorkload(spu); + } + else + { + spursKernel1SelectWorkload(spu); + } + + spursKernelDispatchWorkload(spu, spu.gpr[3]._u64[1]); + return false; +} + +// SPURS kernel entry point +bool spursKernelEntry(SPUThread& spu) +{ + while (true) + { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + CHECK_EMU_STATUS; + } + + auto ctxt = vm::_ptr(spu.offset + 0x100); + memset(ctxt, 0, sizeof(SpursKernelContext)); + + // Save arguments + ctxt->spuNum = spu.gpr[3]._u32[3]; + ctxt->spurs.set(spu.gpr[4]._u64[1]); + + auto isKernel2 = ctxt->spurs->flags1 & SF1_32_WORKLOADS ? true : false; + + // Initialise the SPURS context to its initial values + ctxt->dmaTagId = CELL_SPURS_KERNEL_DMA_TAG_ID; + ctxt->wklCurrentUniqueId = 0x20; + ctxt->wklCurrentId = CELL_SPURS_SYS_SERVICE_WORKLOAD_ID; + ctxt->exitToKernelAddr = isKernel2 ? CELL_SPURS_KERNEL2_EXIT_ADDR : CELL_SPURS_KERNEL1_EXIT_ADDR; + ctxt->selectWorkloadAddr = isKernel2 ? CELL_SPURS_KERNEL2_SELECT_WORKLOAD_ADDR : CELL_SPURS_KERNEL1_SELECT_WORKLOAD_ADDR; + if (!isKernel2) + { + ctxt->x1F0 = 0xF0020000; + ctxt->x200 = 0x20000; + ctxt->guid[0] = 0x423A3A02; + ctxt->guid[1] = 0x43F43A82; + ctxt->guid[2] = 0x43F26502; + ctxt->guid[3] = 0x420EB382; + } + else + { + ctxt->guid[0] = 0x43A08402; + ctxt->guid[1] = 0x43FB0A82; + ctxt->guid[2] = 0x435E9302; + ctxt->guid[3] = 0x43A3C982; + } + + // Register SPURS kernel HLE functions + spu.UnregisterHleFunctions(0, 0x40000/*LS_BOTTOM*/); + spu.RegisterHleFunction(isKernel2 ? CELL_SPURS_KERNEL2_ENTRY_ADDR : CELL_SPURS_KERNEL1_ENTRY_ADDR, spursKernelEntry); + spu.RegisterHleFunction(ctxt->exitToKernelAddr, spursKernelWorkloadExit); + spu.RegisterHleFunction(ctxt->selectWorkloadAddr, isKernel2 ? spursKernel2SelectWorkload : spursKernel1SelectWorkload); + + // Start the system service + spursKernelDispatchWorkload(spu, ((u64)CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) << 32); + return false; +} + +//---------------------------------------------------------------------------- +// SPURS system workload functions +//---------------------------------------------------------------------------- + +// Entry point of the system service +bool spursSysServiceEntry(SPUThread& spu) +{ + auto ctxt = vm::_ptr(spu.offset + spu.gpr[3]._u32[3]); + auto arg = spu.gpr[4]._u64[1]; + auto pollStatus = spu.gpr[5]._u32[3]; + + try + { + if (ctxt->wklCurrentId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) + { + spursSysServiceMain(spu, pollStatus); + } + else + { + // TODO: If we reach here it means the current workload was preempted to start the + // system workload. Need to implement this. + } + + cellSpursModuleExit(spu); + } + + catch (SpursModuleExit) + { + } + + return false; +} + +// Wait for an external event or exit the SPURS thread group if no workloads can be scheduled +void spursSysServiceIdleHandler(SPUThread& spu, SpursKernelContext* ctxt) +{ + bool shouldExit; + + std::unique_lock lock(spu.mutex, std::defer_lock); + + while (true) + { + vm::reservation_acquire(vm::base(spu.offset + 0x100), vm::cast(ctxt->spurs.addr(), HERE), 128); + auto spurs = vm::_ptr(spu.offset + 0x100); + + // Find the number of SPUs that are idling in this SPURS instance + u32 nIdlingSpus = 0; + for (u32 i = 0; i < 8; i++) + { + if (spurs->spuIdling & (1 << i)) + { + nIdlingSpus++; + } + } + + bool allSpusIdle = nIdlingSpus == spurs->nSpus ? true : false; + bool exitIfNoWork = spurs->flags1 & SF1_EXIT_IF_NO_WORK ? true : false; + shouldExit = allSpusIdle && exitIfNoWork; + + // Check if any workloads can be scheduled + bool foundReadyWorkload = false; + if (spurs->sysSrvMessage & (1 << ctxt->spuNum)) + { + foundReadyWorkload = true; + } + else + { + if (spurs->flags1 & SF1_32_WORKLOADS) + { + for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD2; i++) + { + u32 j = i & 0x0F; + u16 runnable = i < CELL_SPURS_MAX_WORKLOAD ? ctxt->wklRunnable1 & (0x8000 >> j) : ctxt->wklRunnable2 & (0x8000 >> j); + u8 priority = i < CELL_SPURS_MAX_WORKLOAD ? ctxt->priority[j] & 0x0F : ctxt->priority[j] >> 4; + u8 maxContention = i < CELL_SPURS_MAX_WORKLOAD ? spurs->wklMaxContention[j] & 0x0F : spurs->wklMaxContention[j] >> 4; + u8 contention = i < CELL_SPURS_MAX_WORKLOAD ? spurs->wklCurrentContention[j] & 0x0F : spurs->wklCurrentContention[j] >> 4; + u16 wklSignal = i < CELL_SPURS_MAX_WORKLOAD ? spurs->wklSignal1.load() & (0x8000 >> j) : spurs->wklSignal2.load() & (0x8000 >> j); + u8 wklFlag = spurs->wklFlag.flag.load() == 0 ? spurs->wklFlagReceiver == i ? 1 : 0 : 0; + u8 readyCount = i < CELL_SPURS_MAX_WORKLOAD ? spurs->wklReadyCount1[j] : spurs->wklIdleSpuCountOrReadyCount2[j]; + + if (runnable && priority > 0 && maxContention > contention) + { + if (wklFlag || wklSignal || readyCount > contention) + { + foundReadyWorkload = true; + break; + } + } + } + } + else + { + for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) + { + u16 runnable = ctxt->wklRunnable1 & (0x8000 >> i); + u16 wklSignal = spurs->wklSignal1.load() & (0x8000 >> i); + u8 wklFlag = spurs->wklFlag.flag.load() == 0 ? spurs->wklFlagReceiver == i ? 1 : 0 : 0; + u8 readyCount = spurs->wklReadyCount1[i] > CELL_SPURS_MAX_SPU ? CELL_SPURS_MAX_SPU : spurs->wklReadyCount1[i].load(); + u8 idleSpuCount = spurs->wklIdleSpuCountOrReadyCount2[i] > CELL_SPURS_MAX_SPU ? CELL_SPURS_MAX_SPU : spurs->wklIdleSpuCountOrReadyCount2[i].load(); + u8 requestCount = readyCount + idleSpuCount; + + if (runnable && ctxt->priority[i] != 0 && spurs->wklMaxContention[i] > spurs->wklCurrentContention[i]) + { + if (wklFlag || wklSignal || (readyCount != 0 && requestCount > spurs->wklCurrentContention[i])) + { + foundReadyWorkload = true; + break; + } + } + } + } + } + + bool spuIdling = spurs->spuIdling & (1 << ctxt->spuNum) ? true : false; + if (foundReadyWorkload && shouldExit == false) + { + spurs->spuIdling &= ~(1 << ctxt->spuNum); + } + else + { + spurs->spuIdling |= 1 << ctxt->spuNum; + } + + // If all SPUs are idling and the exit_if_no_work flag is set then the SPU thread group must exit. Otherwise wait for external events. + if (spuIdling && shouldExit == false && foundReadyWorkload == false) + { + // The system service blocks by making a reservation and waiting on the lock line reservation lost event. + CHECK_EMU_STATUS; + if (!lock) lock.lock(); + spu.cv.wait_for(lock, std::chrono::milliseconds(1)); + continue; + } + + if (vm::reservation_update(vm::cast(ctxt->spurs.addr(), HERE), vm::base(spu.offset + 0x100), 128) && (shouldExit || foundReadyWorkload)) + { + break; + } + } + + if (shouldExit) + { + // TODO: exit spu thread group + } +} + +// Main function for the system service +void spursSysServiceMain(SPUThread& spu, u32 pollStatus) +{ + auto ctxt = vm::_ptr(spu.offset + 0x100); + + if (!ctxt->spurs.aligned()) + { + LOG_ERROR(SPU, "spursSysServiceMain(): invalid spurs alignment"); + spursHalt(spu); + } + + // Initialise the system service if this is the first time its being started on this SPU + if (ctxt->sysSrvInitialised == 0) + { + ctxt->sysSrvInitialised = 1; + + vm::reservation_acquire(vm::base(spu.offset + 0x100), vm::cast(ctxt->spurs.addr(), HERE), 128); + + vm::reservation_op(ctxt->spurs.ptr(&CellSpurs::wklState1).addr(), 128, [&]() + { + auto spurs = ctxt->spurs.get_ptr_priv(); + + // Halt if already initialised + if (spurs->sysSrvOnSpu & (1 << ctxt->spuNum)) + { + LOG_ERROR(SPU, "spursSysServiceMain(): already initialized"); + spursHalt(spu); + } + + spurs->sysSrvOnSpu |= 1 << ctxt->spuNum; + + std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128); + }); + + ctxt->traceBuffer = 0; + ctxt->traceMsgCount = -1; + spursSysServiceTraceUpdate(spu, ctxt, 1, 1, 0); + spursSysServiceCleanupAfterSystemWorkload(spu, ctxt); + + // Trace - SERVICE: INIT + CellSpursTracePacket pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = CELL_SPURS_TRACE_TAG_SERVICE; + pkt.data.service.incident = CELL_SPURS_TRACE_SERVICE_INIT; + cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); + } + + // Trace - START: Module='SYS ' + CellSpursTracePacket pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = CELL_SPURS_TRACE_TAG_START; + memcpy(pkt.data.start.module, "SYS ", 4); + pkt.data.start.level = 1; // Policy module + pkt.data.start.ls = 0xA00 >> 2; + cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); + + while (true) + { + CHECK_EMU_STATUS; + // Process requests for the system service + spursSysServiceProcessRequests(spu, ctxt); + + poll: + if (cellSpursModulePollStatus(spu, nullptr)) + { + // Trace - SERVICE: EXIT + CellSpursTracePacket pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = CELL_SPURS_TRACE_TAG_SERVICE; + pkt.data.service.incident = CELL_SPURS_TRACE_SERVICE_EXIT; + cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); + + // Trace - STOP: GUID + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = CELL_SPURS_TRACE_TAG_STOP; + pkt.data.stop = SPURS_GUID_SYS_WKL; + cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); + + //spursDmaWaitForCompletion(spu, 1 << ctxt->dmaTagId); + break; + } + + // If we reach here it means that either there are more system service messages to be processed + // or there are no workloads that can be scheduled. + + // If the SPU is not idling then process the remaining system service messages + if (ctxt->spuIdling == 0) + { + continue; + } + + // If we reach here it means that the SPU is idling + + // Trace - SERVICE: WAIT + CellSpursTracePacket pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = CELL_SPURS_TRACE_TAG_SERVICE; + pkt.data.service.incident = CELL_SPURS_TRACE_SERVICE_WAIT; + cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); + + spursSysServiceIdleHandler(spu, ctxt); + CHECK_EMU_STATUS; + + goto poll; + } +} + +// Process any requests +void spursSysServiceProcessRequests(SPUThread& spu, SpursKernelContext* ctxt) +{ + bool updateTrace = false; + bool updateWorkload = false; + bool terminate = false; + + vm::reservation_op(vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, wklState1), HERE), 128, [&]() + { + auto spurs = ctxt->spurs.get_ptr_priv(); + + // Terminate request + if (spurs->sysSrvMsgTerminate & (1 << ctxt->spuNum)) + { + spurs->sysSrvOnSpu &= ~(1 << ctxt->spuNum); + terminate = true; + } + + // Update workload message + if (spurs->sysSrvMsgUpdateWorkload & (1 << ctxt->spuNum)) + { + spurs->sysSrvMsgUpdateWorkload &= ~(1 << ctxt->spuNum); + updateWorkload = true; + } + + // Update trace message + if (spurs->sysSrvTrace.load().sysSrvMsgUpdateTrace & (1 << ctxt->spuNum)) + { + updateTrace = true; + } + + std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128); + }); + + // Process update workload message + if (updateWorkload) + { + spursSysServiceActivateWorkload(spu, ctxt); + } + + // Process update trace message + if (updateTrace) + { + spursSysServiceTraceUpdate(spu, ctxt, 1, 0, 0); + } + + // Process terminate request + if (terminate) + { + // TODO: Rest of the terminate processing + } +} + +// Activate a workload +void spursSysServiceActivateWorkload(SPUThread& spu, SpursKernelContext* ctxt) +{ + auto spurs = vm::_ptr(spu.offset + 0x100); + std::memcpy(vm::base(spu.offset + 0x30000), ctxt->spurs->wklInfo1, 0x200); + if (spurs->flags1 & SF1_32_WORKLOADS) + { + 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::_ptr(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::_ptr(spu.offset + 0x30200); + + // Copy the priority of the workload for this SPU to the LS + if (wklInfo2[i].priority[ctxt->spuNum]) + { + ctxt->priority[i] |= (0x10 - wklInfo2[i].priority[ctxt->spuNum]) << 4; + } + } + } + + vm::reservation_op(ctxt->spurs.ptr(&CellSpurs::wklState1).addr(), 128, [&]() + { + 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 + auto wklStatus = spurs->wklStatus1[i]; + if (spurs->wklState1[i] == SPURS_WKL_STATE_RUNNABLE) + { + spurs->wklStatus1[i] |= 1 << ctxt->spuNum; + ctxt->wklRunnable1 |= 0x8000 >> i; + } + else + { + spurs->wklStatus1[i] &= ~(1 << ctxt->spuNum); + } + + // If the workload is shutting down and if this is the last SPU from which it is being removed then + // add it to the shutdown bit set + if (spurs->wklState1[i] == SPURS_WKL_STATE_SHUTTING_DOWN) + { + if (((wklStatus & (1 << ctxt->spuNum)) != 0) && (spurs->wklStatus1[i] == 0)) + { + spurs->wklState1[i] = SPURS_WKL_STATE_REMOVABLE; + wklShutdownBitSet |= 0x80000000u >> i; + } + } + + if (spurs->flags1 & SF1_32_WORKLOADS) + { + // Update workload status and runnable flag based on the workload state + wklStatus = spurs->wklStatus2[i]; + if (spurs->wklState2[i] == SPURS_WKL_STATE_RUNNABLE) + { + spurs->wklStatus2[i] |= 1 << ctxt->spuNum; + ctxt->wklRunnable2 |= 0x8000 >> i; + } + else + { + spurs->wklStatus2[i] &= ~(1 << ctxt->spuNum); + } + + // If the workload is shutting down and if this is the last SPU from which it is being removed then + // add it to the shutdown bit set + if (spurs->wklState2[i] == SPURS_WKL_STATE_SHUTTING_DOWN) + { + if (((wklStatus & (1 << ctxt->spuNum)) != 0) && (spurs->wklStatus2[i] == 0)) + { + spurs->wklState2[i] = SPURS_WKL_STATE_REMOVABLE; + wklShutdownBitSet |= 0x8000 >> i; + } + } + } + } + + std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128); + }); + + if (wklShutdownBitSet) + { + spursSysServiceUpdateShutdownCompletionEvents(spu, ctxt, wklShutdownBitSet); + } +} + +// Update shutdown completion events +void spursSysServiceUpdateShutdownCompletionEvents(SPUThread& spu, SpursKernelContext* ctxt, u32 wklShutdownBitSet) +{ + // Mark the workloads in wklShutdownBitSet as completed and also generate a bit set of the completed + // workloads that have a shutdown completion hook registered + u32 wklNotifyBitSet; + u8 spuPort; + vm::reservation_op(ctxt->spurs.ptr(&CellSpurs::wklState1).addr(), 128, [&]() + { + auto spurs = ctxt->spurs.get_ptr_priv(); + + wklNotifyBitSet = 0; + spuPort = spurs->spuPort;; + for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) + { + if (wklShutdownBitSet & (0x80000000u >> i)) + { + spurs->wklEvent1[i] |= 0x01; + if (spurs->wklEvent1[i] & 0x02 || spurs->wklEvent1[i] & 0x10) + { + wklNotifyBitSet |= 0x80000000u >> i; + } + } + + if (wklShutdownBitSet & (0x8000 >> i)) + { + spurs->wklEvent2[i] |= 0x01; + if (spurs->wklEvent2[i] & 0x02 || spurs->wklEvent2[i] & 0x10) + { + wklNotifyBitSet |= 0x8000 >> i; + } + } + } + + std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128); + }); + + if (wklNotifyBitSet) + { + // TODO: sys_spu_thread_send_event(spuPort, 0, wklNotifyMask); + } +} + +// Update the trace count for this SPU +void spursSysServiceTraceSaveCount(SPUThread& spu, SpursKernelContext* ctxt) +{ + if (ctxt->traceBuffer) + { + auto traceInfo = vm::ptr::make((u32)(ctxt->traceBuffer - (ctxt->spurs->traceStartIndex[ctxt->spuNum] << 4))); + traceInfo->count[ctxt->spuNum] = ctxt->traceMsgCount; + } +} + +// Update trace control +void spursSysServiceTraceUpdate(SPUThread& spu, SpursKernelContext* ctxt, u32 arg2, u32 arg3, u32 forceNotify) +{ + bool notify; + + u8 sysSrvMsgUpdateTrace; + vm::reservation_op(ctxt->spurs.ptr(&CellSpurs::wklState1).addr(), 128, [&]() + { + auto spurs = ctxt->spurs.get_ptr_priv(); + auto& trace = spurs->sysSrvTrace.raw(); + + sysSrvMsgUpdateTrace = trace.sysSrvMsgUpdateTrace; + trace.sysSrvMsgUpdateTrace &= ~(1 << ctxt->spuNum); + trace.sysSrvTraceInitialised &= ~(1 << ctxt->spuNum); + trace.sysSrvTraceInitialised |= arg2 << ctxt->spuNum; + + notify = false; + if (((sysSrvMsgUpdateTrace & (1 << ctxt->spuNum)) != 0) && (spurs->sysSrvTrace.load().sysSrvMsgUpdateTrace == 0) && (spurs->sysSrvTrace.load().sysSrvNotifyUpdateTraceComplete != 0)) + { + trace.sysSrvNotifyUpdateTraceComplete = 0; + notify = true; + } + + if (forceNotify && spurs->sysSrvTrace.load().sysSrvNotifyUpdateTraceComplete != 0) + { + trace.sysSrvNotifyUpdateTraceComplete = 0; + notify = true; + } + + 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::base(spu.offset + 0x80), ctxt->spurs.ptr(&CellSpurs::traceBuffer).addr(), 128); + auto spurs = vm::_ptr(spu.offset + 0x80 - OFFSET_32(CellSpurs, traceBuffer)); + + if (ctxt->traceMsgCount != 0xFF || spurs->traceBuffer.addr() == 0) + { + spursSysServiceTraceSaveCount(spu, ctxt); + } + else + { + std::memcpy(vm::base(spu.offset + 0x2C00), vm::base(spurs->traceBuffer.addr() & -0x4), 0x80); + auto traceBuffer = vm::_ptr(spu.offset + 0x2C00); + ctxt->traceMsgCount = traceBuffer->count[ctxt->spuNum]; + } + + ctxt->traceBuffer = spurs->traceBuffer.addr() + (spurs->traceStartIndex[ctxt->spuNum] << 4); + ctxt->traceMaxCount = spurs->traceStartIndex[1] - spurs->traceStartIndex[0]; + if (ctxt->traceBuffer == 0) + { + ctxt->traceMsgCount = 0; + } + } + + if (notify) + { + auto spurs = vm::_ptr(spu.offset + 0x2D80 - OFFSET_32(CellSpurs, wklState1)); + sys_spu_thread_send_event(spu, spurs->spuPort, 2, 0); + } +} + +// Restore state after executing the system workload +void spursSysServiceCleanupAfterSystemWorkload(SPUThread& spu, SpursKernelContext* ctxt) +{ + u8 wklId; + + bool do_return = false; + + vm::reservation_op(ctxt->spurs.ptr(&CellSpurs::wklState1).addr(), 128, [&]() + { + auto spurs = ctxt->spurs.get_ptr_priv(); + + if (spurs->sysSrvPreemptWklId[ctxt->spuNum] == 0xFF) + { + do_return = true; + return; + } + + wklId = spurs->sysSrvPreemptWklId[ctxt->spuNum]; + spurs->sysSrvPreemptWklId[ctxt->spuNum] = 0xFF; + + std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128); + }); + + if (do_return) return; + + spursSysServiceActivateWorkload(spu, ctxt); + + vm::reservation_op(vm::cast(ctxt->spurs.addr(), HERE), 128, [&]() + { + auto spurs = ctxt->spurs.get_ptr_priv(); + + if (wklId >= CELL_SPURS_MAX_WORKLOAD) + { + spurs->wklCurrentContention[wklId & 0x0F] -= 0x10; + spurs->wklReadyCount1[wklId & 0x0F].raw() -= 1; + } + else + { + spurs->wklCurrentContention[wklId & 0x0F] -= 0x01; + spurs->wklIdleSpuCountOrReadyCount2[wklId & 0x0F].raw() -= 1; + } + + std::memcpy(vm::base(spu.offset + 0x100), spurs, 128); + }); + + // Set the current workload id to the id of the pre-empted workload since cellSpursModulePutTrace + // uses the current worload id to determine the workload to which the trace belongs + auto wklIdSaved = ctxt->wklCurrentId; + ctxt->wklCurrentId = wklId; + + // Trace - STOP: GUID + CellSpursTracePacket pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = CELL_SPURS_TRACE_TAG_STOP; + pkt.data.stop = SPURS_GUID_SYS_WKL; + cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); + + ctxt->wklCurrentId = wklIdSaved; +} + +//---------------------------------------------------------------------------- +// SPURS taskset policy module functions +//---------------------------------------------------------------------------- + +enum SpursTasksetRequest +{ + SPURS_TASKSET_REQUEST_POLL_SIGNAL = -1, + SPURS_TASKSET_REQUEST_DESTROY_TASK = 0, + SPURS_TASKSET_REQUEST_YIELD_TASK = 1, + SPURS_TASKSET_REQUEST_WAIT_SIGNAL = 2, + SPURS_TASKSET_REQUEST_POLL = 3, + SPURS_TASKSET_REQUEST_WAIT_WKL_FLAG = 4, + SPURS_TASKSET_REQUEST_SELECT_TASK = 5, + SPURS_TASKSET_REQUEST_RECV_WKL_FLAG = 6, +}; + +// Taskset PM entry point +bool spursTasksetEntry(SPUThread& spu) +{ + auto ctxt = vm::_ptr(spu.offset + 0x2700); + auto kernelCtxt = vm::_ptr(spu.offset + spu.gpr[3]._u32[3]); + + auto arg = spu.gpr[4]._u64[1]; + auto pollStatus = spu.gpr[5]._u32[3]; + + // Initialise memory and save args + memset(ctxt, 0, sizeof(*ctxt)); + ctxt->taskset.set(arg); + memcpy(ctxt->moduleId, "SPURSTASK MODULE", sizeof(ctxt->moduleId)); + ctxt->kernelMgmtAddr = spu.gpr[3]._u32[3]; + ctxt->syscallAddr = CELL_SPURS_TASKSET_PM_SYSCALL_ADDR; + ctxt->spuNum = kernelCtxt->spuNum; + ctxt->dmaTagId = kernelCtxt->dmaTagId; + ctxt->taskId = 0xFFFFFFFF; + + // Register SPURS takset policy module HLE functions + spu.UnregisterHleFunctions(CELL_SPURS_TASKSET_PM_ENTRY_ADDR, 0x40000/*LS_BOTTOM*/); + spu.RegisterHleFunction(CELL_SPURS_TASKSET_PM_ENTRY_ADDR, spursTasksetEntry); + spu.RegisterHleFunction(ctxt->syscallAddr, spursTasksetSyscallEntry); + + try + { + // Initialise the taskset policy module + spursTasksetInit(spu, pollStatus); + + // Dispatch + spursTasksetDispatch(spu); + } + catch (SpursModuleExit) + { + } + + return false; +} + +// Entry point into the Taskset PM for task syscalls +bool spursTasksetSyscallEntry(SPUThread& spu) +{ + auto ctxt = vm::_ptr(spu.offset + 0x2700); + + try + { + // Save task context + ctxt->savedContextLr = spu.gpr[0]; + ctxt->savedContextSp = spu.gpr[1]; + for (auto i = 0; i < 48; i++) + { + ctxt->savedContextR80ToR127[i] = spu.gpr[80 + i]; + } + + // Handle the syscall + spu.gpr[3]._u32[3] = spursTasksetProcessSyscall(spu, spu.gpr[3]._u32[3], spu.gpr[4]._u32[3]); + + // Resume the previously executing task if the syscall did not cause a context switch + throw EXCEPTION("Broken (TODO)"); + //if (spu.m_is_branch == false) { + // spursTasksetResumeTask(spu); + //} + } + catch (SpursModuleExit) + { + } + + return false; +} + +// Resume a task +void spursTasksetResumeTask(SPUThread& spu) +{ + auto ctxt = vm::_ptr(spu.offset + 0x2700); + + // Restore task context + spu.gpr[0] = ctxt->savedContextLr; + spu.gpr[1] = ctxt->savedContextSp; + for (auto i = 0; i < 48; i++) + { + spu.gpr[80 + i] = ctxt->savedContextR80ToR127[i]; + } + + spu.pc = spu.gpr[0]._u32[3] - 4; +} + +// Start a task +void spursTasksetStartTask(SPUThread& spu, CellSpursTaskArgument& taskArgs) +{ + auto ctxt = vm::_ptr(spu.offset + 0x2700); + auto taskset = vm::_ptr(spu.offset + 0x2700); + + spu.gpr[2].clear(); + spu.gpr[3] = v128::from64r(taskArgs._u64[0], taskArgs._u64[1]); + spu.gpr[4]._u64[1] = taskset->args; + spu.gpr[4]._u64[0] = taskset->spurs.addr(); + for (auto i = 5; i < 128; i++) + { + spu.gpr[i].clear(); + } + + spu.pc = ctxt->savedContextLr.value()._u32[3] - 4; +} + +// Process a request and update the state of the taskset +s32 spursTasksetProcessRequest(SPUThread& spu, s32 request, u32* taskId, u32* isWaiting) +{ + auto kernelCtxt = vm::_ptr(spu.offset + 0x100); + auto ctxt = vm::_ptr(spu.offset + 0x2700); + + s32 rc = CELL_OK; + s32 numNewlyReadyTasks; + vm::reservation_op(vm::cast(ctxt->taskset.addr(), HERE), 128, [&]() + { + auto taskset = ctxt->taskset.get_ptr_priv(); + + // Verify taskset state is valid + be_t _0(v128::from32(0)); + if ((taskset->waiting & taskset->running) != _0 || (taskset->ready & taskset->pending_ready) != _0 || + ((taskset->running | taskset->ready | taskset->pending_ready | taskset->signalled | taskset->waiting) & ~taskset->enabled) != _0) + { + LOG_ERROR(SPU, "Invalid taskset state"); + spursHalt(spu); + } + + // Find the number of tasks that have become ready since the last iteration + auto newlyReadyTasks = (taskset->signalled | taskset->pending_ready) & ~taskset->ready.value(); + numNewlyReadyTasks = 0; + for (auto i = 0; i < 128; i++) + { + if (newlyReadyTasks._bit[i]) + { + numNewlyReadyTasks++; + } + } + + v128 readyButNotRunning; + u8 selectedTaskId; + v128 running = taskset->running.value(); + v128 waiting = taskset->waiting.value(); + v128 enabled = taskset->enabled.value(); + v128 signalled = (taskset->signalled & (taskset->ready | taskset->pending_ready)); + v128 ready = (taskset->signalled | taskset->ready | taskset->pending_ready); + + switch (request) + { + case SPURS_TASKSET_REQUEST_POLL_SIGNAL: + rc = signalled._bit[ctxt->taskId] ? 1 : 0; + signalled._bit[ctxt->taskId] = false; + break; + case SPURS_TASKSET_REQUEST_DESTROY_TASK: + numNewlyReadyTasks--; + running._bit[ctxt->taskId] = false; + enabled._bit[ctxt->taskId] = false; + signalled._bit[ctxt->taskId] = false; + ready._bit[ctxt->taskId] = false; + break; + case SPURS_TASKSET_REQUEST_YIELD_TASK: + running._bit[ctxt->taskId] = false; + waiting._bit[ctxt->taskId] = true; + break; + case SPURS_TASKSET_REQUEST_WAIT_SIGNAL: + if (signalled._bit[ctxt->taskId] == false) + { + numNewlyReadyTasks--; + running._bit[ctxt->taskId] = false; + waiting._bit[ctxt->taskId] = true; + signalled._bit[ctxt->taskId] = false; + ready._bit[ctxt->taskId] = false; + } + break; + case SPURS_TASKSET_REQUEST_POLL: + readyButNotRunning = ready & ~running; + if (taskset->wkl_flag_wait_task < CELL_SPURS_MAX_TASK) + { + readyButNotRunning = readyButNotRunning & ~(v128::fromBit(taskset->wkl_flag_wait_task)); + } + + rc = readyButNotRunning != _0 ? 1 : 0; + break; + case SPURS_TASKSET_REQUEST_WAIT_WKL_FLAG: + if (taskset->wkl_flag_wait_task == 0x81) + { + // A workload flag is already pending so consume it + taskset->wkl_flag_wait_task = 0x80; + rc = 0; + } + else if (taskset->wkl_flag_wait_task == 0x80) + { + // No tasks are waiting for the workload flag. Mark this task as waiting for the workload flag. + taskset->wkl_flag_wait_task = ctxt->taskId; + running._bit[ctxt->taskId] = false; + waiting._bit[ctxt->taskId] = true; + rc = 1; + numNewlyReadyTasks--; + } + else + { + // Another task is already waiting for the workload signal + rc = CELL_SPURS_TASK_ERROR_BUSY; + } + break; + case SPURS_TASKSET_REQUEST_SELECT_TASK: + readyButNotRunning = ready & ~running; + if (taskset->wkl_flag_wait_task < CELL_SPURS_MAX_TASK) + { + readyButNotRunning = readyButNotRunning & ~(v128::fromBit(taskset->wkl_flag_wait_task)); + } + + // Select a task from the readyButNotRunning set to run. Start from the task after the last scheduled task to ensure fairness. + for (selectedTaskId = taskset->last_scheduled_task + 1; selectedTaskId < 128; selectedTaskId++) + { + if (readyButNotRunning._bit[selectedTaskId]) + { + break; + } + } + + if (selectedTaskId == 128) + { + for (selectedTaskId = 0; selectedTaskId < taskset->last_scheduled_task + 1; selectedTaskId++) + { + if (readyButNotRunning._bit[selectedTaskId]) + { + break; + } + } + + if (selectedTaskId == taskset->last_scheduled_task + 1) + { + selectedTaskId = CELL_SPURS_MAX_TASK; + } + } + + *taskId = selectedTaskId; + *isWaiting = waiting._bit[selectedTaskId < CELL_SPURS_MAX_TASK ? selectedTaskId : 0] ? 1 : 0; + if (selectedTaskId != CELL_SPURS_MAX_TASK) + { + taskset->last_scheduled_task = selectedTaskId; + running._bit[selectedTaskId] = true; + waiting._bit[selectedTaskId] = false; + } + break; + case SPURS_TASKSET_REQUEST_RECV_WKL_FLAG: + if (taskset->wkl_flag_wait_task < CELL_SPURS_MAX_TASK) + { + // There is a task waiting for the workload flag + taskset->wkl_flag_wait_task = 0x80; + rc = 1; + numNewlyReadyTasks++; + } + else + { + // No tasks are waiting for the workload flag + taskset->wkl_flag_wait_task = 0x81; + rc = 0; + } + break; + default: + LOG_ERROR(SPU, "Unknown taskset request"); + spursHalt(spu); + } + + taskset->pending_ready = _0; + taskset->running = running; + taskset->waiting = waiting; + taskset->enabled = enabled; + taskset->signalled = signalled; + taskset->ready = ready; + + 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(), HERE), 128, [&]() + { + 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; + readyCount = readyCount < 0 ? 0 : readyCount > 0xFF ? 0xFF : readyCount; + + if (kernelCtxt->wklCurrentId < CELL_SPURS_MAX_WORKLOAD) + { + spurs->wklReadyCount1[kernelCtxt->wklCurrentId] = readyCount; + } + else + { + spurs->wklIdleSpuCountOrReadyCount2[kernelCtxt->wklCurrentId & 0x0F] = readyCount; + } + + std::memcpy(vm::base(spu.offset + 0x100), spurs, 128); + }); + + return rc; +} + +// Process pollStatus received from the SPURS kernel +void spursTasksetProcessPollStatus(SPUThread& spu, u32 pollStatus) +{ + if (pollStatus & CELL_SPURS_MODULE_POLL_STATUS_FLAG) + { + spursTasksetProcessRequest(spu, SPURS_TASKSET_REQUEST_RECV_WKL_FLAG, nullptr, nullptr); + } +} + +// Check execution rights +bool spursTasksetPollStatus(SPUThread& spu) +{ + u32 pollStatus; + + if (cellSpursModulePollStatus(spu, &pollStatus)) + { + return true; + } + + spursTasksetProcessPollStatus(spu, pollStatus); + return false; +} + +// Exit the Taskset PM +void spursTasksetExit(SPUThread& spu) +{ + auto ctxt = vm::_ptr(spu.offset + 0x2700); + + // Trace - STOP + CellSpursTracePacket pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = 0x54; // Its not clear what this tag means exactly but it seems similar to CELL_SPURS_TRACE_TAG_STOP + pkt.data.stop = SPURS_GUID_TASKSET_PM; + cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); + + // Not sure why this check exists. Perhaps to check for memory corruption. + if (memcmp(ctxt->moduleId, "SPURSTASK MODULE", 16) != 0) + { + LOG_ERROR(SPU, "spursTasksetExit(): memory corruption"); + spursHalt(spu); + } + + cellSpursModuleExit(spu); +} + +// Invoked when a task exits +void spursTasksetOnTaskExit(SPUThread& spu, u64 addr, u32 taskId, s32 exitCode, u64 args) +{ + auto ctxt = vm::_ptr(spu.offset + 0x2700); + + 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; + spu.gpr[5]._u32[3] = exitCode; + spu.gpr[6]._u64[1] = args; + spu.fast_call(0x10000); +} + +// Save the context of a task +s32 spursTasketSaveTaskContext(SPUThread& spu) +{ + auto ctxt = vm::_ptr(spu.offset + 0x2700); + auto taskInfo = vm::_ptr(spu.offset + 0x2780); + + //spursDmaWaitForCompletion(spu, 0xFFFFFFFF); + + if (taskInfo->context_save_storage_and_alloc_ls_blocks == 0) + { + return CELL_SPURS_TASK_ERROR_STAT; + } + + u32 allocLsBlocks = taskInfo->context_save_storage_and_alloc_ls_blocks & 0x7F; + u32 lsBlocks = 0; + v128 ls_pattern = v128::from64r(taskInfo->ls_pattern._u64[0], taskInfo->ls_pattern._u64[1]); + for (auto i = 0; i < 128; i++) + { + if (ls_pattern._bit[i]) + { + lsBlocks++; + } + } + + if (lsBlocks > allocLsBlocks) + { + return CELL_SPURS_TASK_ERROR_STAT; + } + + // Make sure the stack is area is specified in the ls pattern + for (auto i = (ctxt->savedContextSp.value()._u32[3]) >> 11; i < 128; i++) + { + if (ls_pattern._bit[i] == false) + { + return CELL_SPURS_TASK_ERROR_STAT; + } + } + + // Get the processor context + v128 r; + spu.fpscr.Read(r); + ctxt->savedContextFpscr = r; + ctxt->savedSpuWriteEventMask = spu.get_ch_value(SPU_RdEventMask); + ctxt->savedWriteTagGroupQueryMask = spu.get_ch_value(MFC_RdTagMask); + + // Store the processor context + const u32 contextSaveStorage = vm::cast(taskInfo->context_save_storage_and_alloc_ls_blocks & -0x80, HERE); + 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 + std::memcpy(vm::base(contextSaveStorage + 0x400 + ((i - 6) << 11)), vm::base(spu.offset + CELL_SPURS_TASK_TOP + ((i - 6) << 11)), 0x800); + } + } + + //spursDmaWaitForCompletion(spu, 1 << ctxt->dmaTagId); + return CELL_OK; +} + +// Taskset dispatcher +void spursTasksetDispatch(SPUThread& spu) +{ + auto ctxt = vm::_ptr(spu.offset + 0x2700); + auto taskset = vm::_ptr(spu.offset + 0x2700); + + u32 taskId; + u32 isWaiting; + spursTasksetProcessRequest(spu, SPURS_TASKSET_REQUEST_SELECT_TASK, &taskId, &isWaiting); + if (taskId >= CELL_SPURS_MAX_TASK) + { + spursTasksetExit(spu); + return; + } + + ctxt->taskId = taskId; + + // DMA in the task info for the selected task + std::memcpy(vm::base(spu.offset + 0x2780), &ctxt->taskset->task_info[taskId], sizeof(CellSpursTaskset::TaskInfo)); + auto taskInfo = vm::_ptr(spu.offset + 0x2780); + auto elfAddr = taskInfo->elf.addr().value(); + taskInfo->elf.set(taskInfo->elf.addr() & 0xFFFFFFFFFFFFFFF8); + + // Trace - Task: Incident=dispatch + CellSpursTracePacket pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = CELL_SPURS_TRACE_TAG_TASK; + pkt.data.task.incident = CELL_SPURS_TRACE_TASK_DISPATCH; + pkt.data.task.taskId = taskId; + cellSpursModulePutTrace(&pkt, CELL_SPURS_KERNEL_DMA_TAG_ID); + + if (isWaiting == 0) + { + // If we reach here it means that the task is being started and not being resumed + 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; + u32 lowestLoadAddr; + if (spursTasksetLoadElf(spu, &entryPoint, &lowestLoadAddr, taskInfo->elf.addr(), false) != CELL_OK) + { + LOG_ERROR(SPU, "spursTaskLoadElf() failed"); + spursHalt(spu); + } + + //spursDmaWaitForCompletion(spu, 1 << ctxt->dmaTagId); + + ctxt->savedContextLr = v128::from32r(entryPoint); + ctxt->guidAddr = lowestLoadAddr; + ctxt->tasksetMgmtAddr = 0x2700; + ctxt->x2FC0 = 0; + ctxt->taskExitCode = isWaiting; + ctxt->x2FD4 = elfAddr & 5; // TODO: Figure this out + + if ((elfAddr & 5) == 1) + { + std::memcpy(vm::base(spu.offset + 0x2FC0), &((CellSpursTaskset2*)(ctxt->taskset.get_ptr()))->task_exit_code[taskId], 0x10); + } + + // Trace - GUID + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = CELL_SPURS_TRACE_TAG_GUID; + pkt.data.guid = 0; // TODO: Put GUID of taskId here + cellSpursModulePutTrace(&pkt, 0x1F); + + if (elfAddr & 2) + { + // TODO: Figure this out + spu.status |= SPU_STATUS_STOPPED_BY_STOP; + throw cpu_state::stop; + } + + spursTasksetStartTask(spu, taskInfo->args); + } + else + { + if (taskset->enable_clear_ls) + { + 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 + v128 ls_pattern = v128::from64r(taskInfo->ls_pattern._u64[0], taskInfo->ls_pattern._u64[1]); + if (ls_pattern != v128::from64r(0x03FFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull)) + { + // Load the ELF + u32 entryPoint; + if (spursTasksetLoadElf(spu, &entryPoint, nullptr, taskInfo->elf.addr(), true) != CELL_OK) + { + LOG_ERROR(SPU, "spursTasksetLoadElf() failed"); + spursHalt(spu); + } + } + + // Load saved context from main memory to LS + const u32 contextSaveStorage = vm::cast(taskInfo->context_save_storage_and_alloc_ls_blocks & -0x80, HERE); + 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 + std::memcpy(vm::base(spu.offset + CELL_SPURS_TASK_TOP + ((i - 6) << 11)), vm::base(contextSaveStorage + 0x400 + ((i - 6) << 11)), 0x800); + } + } + + //spursDmaWaitForCompletion(spu, 1 << ctxt->dmaTagId); + + // Restore saved registers + spu.fpscr.Write(ctxt->savedContextFpscr.value()); + spu.set_ch_value(MFC_WrTagMask, ctxt->savedWriteTagGroupQueryMask); + spu.set_ch_value(SPU_WrEventMask, ctxt->savedSpuWriteEventMask); + + // Trace - GUID + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = CELL_SPURS_TRACE_TAG_GUID; + pkt.data.guid = 0; // TODO: Put GUID of taskId here + cellSpursModulePutTrace(&pkt, 0x1F); + + if (elfAddr & 2) + { + // TODO: Figure this out + spu.status |= SPU_STATUS_STOPPED_BY_STOP; + throw cpu_state::stop; + } + + spu.gpr[3].clear(); + spursTasksetResumeTask(spu); + } +} + +// Process a syscall request +s32 spursTasksetProcessSyscall(SPUThread& spu, u32 syscallNum, u32 args) +{ + auto ctxt = vm::_ptr(spu.offset + 0x2700); + auto taskset = vm::_ptr(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 + // for DMA completion + if ((syscallNum & 0x10) == 0) + { + //spursDmaWaitForCompletion(spu, 0xFFFFFFFF); + } + + s32 rc = 0; + u32 incident = 0; + switch (syscallNum & 0x0F) + { + case CELL_SPURS_TASK_SYSCALL_EXIT: + if (ctxt->x2FD4 == 4 || (ctxt->x2FC0 & 0xFFFFFFFF) != 0) + { // TODO: Figure this out + if (ctxt->x2FD4 != 4) + { + spursTasksetProcessRequest(spu, SPURS_TASKSET_REQUEST_DESTROY_TASK, nullptr, nullptr); + } + + const u64 addr = ctxt->x2FD4 == 4 ? taskset->x78 : ctxt->x2FC0; + const u64 args = ctxt->x2FD4 == 4 ? 0 : ctxt->x2FC8.value(); + spursTasksetOnTaskExit(spu, addr, ctxt->taskId, ctxt->taskExitCode, args); + } + + incident = CELL_SPURS_TRACE_TASK_EXIT; + break; + case CELL_SPURS_TASK_SYSCALL_YIELD: + if (spursTasksetPollStatus(spu) || spursTasksetProcessRequest(spu, SPURS_TASKSET_REQUEST_POLL, nullptr, nullptr)) + { + // If we reach here then it means that either another task can be scheduled or another workload can be scheduled + // Save the context of the current task + rc = spursTasketSaveTaskContext(spu); + if (rc == CELL_OK) + { + spursTasksetProcessRequest(spu, SPURS_TASKSET_REQUEST_YIELD_TASK, nullptr, nullptr); + incident = CELL_SPURS_TRACE_TASK_YIELD; + } + } + break; + case CELL_SPURS_TASK_SYSCALL_WAIT_SIGNAL: + if (spursTasksetProcessRequest(spu, SPURS_TASKSET_REQUEST_POLL_SIGNAL, nullptr, nullptr) == 0) + { + rc = spursTasketSaveTaskContext(spu); + if (rc == CELL_OK) + { + if (spursTasksetProcessRequest(spu, SPURS_TASKSET_REQUEST_WAIT_SIGNAL, nullptr, nullptr) == 0) + { + incident = CELL_SPURS_TRACE_TASK_WAIT; + } + } + } + break; + case CELL_SPURS_TASK_SYSCALL_POLL: + rc = spursTasksetPollStatus(spu) ? CELL_SPURS_TASK_POLL_FOUND_WORKLOAD : 0; + rc |= spursTasksetProcessRequest(spu, SPURS_TASKSET_REQUEST_POLL, nullptr, nullptr) ? CELL_SPURS_TASK_POLL_FOUND_TASK : 0; + break; + case CELL_SPURS_TASK_SYSCALL_RECV_WKL_FLAG: + if (args == 0) + { // TODO: Figure this out + LOG_ERROR(SPU, "args == 0"); + //spursHalt(spu); + } + + if (spursTasksetPollStatus(spu) || spursTasksetProcessRequest(spu, SPURS_TASKSET_REQUEST_WAIT_WKL_FLAG, nullptr, nullptr) != 1) + { + rc = spursTasketSaveTaskContext(spu); + if (rc == CELL_OK) + { + incident = CELL_SPURS_TRACE_TASK_WAIT; + } + } + break; + default: + rc = CELL_SPURS_TASK_ERROR_NOSYS; + break; + } + + if (incident) + { + // Trace - TASK + CellSpursTracePacket pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = CELL_SPURS_TRACE_TAG_TASK; + pkt.data.task.incident = incident; + pkt.data.task.taskId = ctxt->taskId; + cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); + + // Clear the GUID of the task + std::memset(vm::base(spu.offset + ctxt->guidAddr), 0, 0x10); + + if (spursTasksetPollStatus(spu)) + { + spursTasksetExit(spu); + } + else + { + spursTasksetDispatch(spu); + } + } + + return rc; +} + +// Initialise the Taskset PM +void spursTasksetInit(SPUThread& spu, u32 pollStatus) +{ + auto ctxt = vm::_ptr(spu.offset + 0x2700); + auto kernelCtxt = vm::_ptr(spu.offset + 0x100); + + kernelCtxt->moduleId[0] = 'T'; + kernelCtxt->moduleId[1] = 'K'; + + // Trace - START: Module='TKST' + CellSpursTracePacket pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = 0x52; // Its not clear what this tag means exactly but it seems similar to CELL_SPURS_TRACE_TAG_START + memcpy(pkt.data.start.module, "TKST", 4); + pkt.data.start.level = 2; + pkt.data.start.ls = 0xA00 >> 2; + cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); + + spursTasksetProcessPollStatus(spu, pollStatus); +} + +// Load an ELF +s32 spursTasksetLoadElf(SPUThread& spu, u32* entryPoint, u32* lowestLoadAddr, u64 elfAddr, bool skipWriteableSegments) +{ + if (elfAddr == 0 || (elfAddr & 0x0F) != 0) + { + return CELL_SPURS_TASK_ERROR_INVAL; + } + + const spu_exec_loader loader(fs::file(vm::base(vm::cast(elfAddr, HERE)), u32(0 - elfAddr))); + + if (loader != elf_error::ok) + { + return CELL_SPURS_TASK_ERROR_NOEXEC; + } + + u32 _lowestLoadAddr = CELL_SPURS_TASK_BOTTOM; + for (const auto& prog : loader.progs) + { + if (prog.p_paddr >= CELL_SPURS_TASK_BOTTOM) + { + break; + } + + if (prog.p_type == 1 /* PT_LOAD */) + { + if (skipWriteableSegments == false || (prog.p_flags & 2 /*PF_W*/ ) == 0) + { + if (prog.p_vaddr < CELL_SPURS_TASK_TOP || prog.p_vaddr + prog.p_memsz > CELL_SPURS_TASK_BOTTOM) + { + return CELL_SPURS_TASK_ERROR_FAULT; + } + + _lowestLoadAddr > prog.p_vaddr ? _lowestLoadAddr = prog.p_vaddr : _lowestLoadAddr; + } + } + } + + for (const auto& prog : loader.progs) + { + if (prog.p_paddr >= CELL_SPURS_TASK_BOTTOM) // ??? + { + break; + } + + if (prog.p_type == 1) + { + if (skipWriteableSegments == false || (prog.p_flags & 2) == 0) + { + std::memcpy(vm::base(spu.offset + prog.p_vaddr), prog.bin.data(), prog.p_filesz); + } + } + } + + *entryPoint = loader.header.e_entry; + if (lowestLoadAddr) *lowestLoadAddr = _lowestLoadAddr; + + return CELL_OK; +} diff --git a/rpcs3/Emu/SysCalls/Modules/cellSsl.cpp b/rpcs3/Emu/Cell/Modules/cellSsl.cpp similarity index 93% rename from rpcs3/Emu/SysCalls/Modules/cellSsl.cpp rename to rpcs3/Emu/Cell/Modules/cellSsl.cpp index eaac5d7760..ab14c7fedd 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSsl.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSsl.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellSsl; +LOG_CHANNEL(cellSsl); s32 cellSslInit() { @@ -88,7 +87,7 @@ s32 cellSslCertGetMd5Fingerprint() return CELL_OK; } -Module<> cellSsl("cellSsl", []() +DECLARE(ppu_module_manager::cellSsl)("cellSsl", []() { REG_FUNC(cellSsl, cellSslInit); REG_FUNC(cellSsl, cellSslEnd); diff --git a/rpcs3/Emu/SysCalls/Modules/cellStorage.cpp b/rpcs3/Emu/Cell/Modules/cellStorage.cpp similarity index 79% rename from rpcs3/Emu/SysCalls/Modules/cellStorage.cpp rename to rpcs3/Emu/Cell/Modules/cellStorage.cpp index 07ce05e6a5..894f33cf4a 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellStorage.cpp +++ b/rpcs3/Emu/Cell/Modules/cellStorage.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellSysutil; +extern _log::channel cellSysutil; s32 cellStorageDataImportMove() { diff --git a/rpcs3/Emu/SysCalls/Modules/cellSubdisplay.cpp b/rpcs3/Emu/Cell/Modules/cellSubdisplay.cpp similarity index 92% rename from rpcs3/Emu/SysCalls/Modules/cellSubdisplay.cpp rename to rpcs3/Emu/Cell/Modules/cellSubdisplay.cpp index 230adbc86f..6f971a4923 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSubdisplay.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSubdisplay.cpp @@ -1,10 +1,9 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellSubdisplay.h" -extern Module<> cellSubdisplay; +LOG_CHANNEL(cellSubdisplay); s32 cellSubDisplayInit() { @@ -74,7 +73,7 @@ s32 cellSubDisplayGetPeerList() return CELL_OK; } -Module<> cellSubdisplay("cellSubdisplay", []() +DECLARE(ppu_module_manager::cellSubdisplay)("cellSubdisplay", []() { REG_FUNC(cellSubdisplay, cellSubDisplayInit); REG_FUNC(cellSubdisplay, cellSubDisplayEnd); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSubdisplay.h b/rpcs3/Emu/Cell/Modules/cellSubdisplay.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellSubdisplay.h rename to rpcs3/Emu/Cell/Modules/cellSubdisplay.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellSync.cpp b/rpcs3/Emu/Cell/Modules/cellSync.cpp similarity index 79% rename from rpcs3/Emu/SysCalls/Modules/cellSync.cpp rename to rpcs3/Emu/Cell/Modules/cellSync.cpp index c01f8d4ddf..83ada37380 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSync.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSync.cpp @@ -1,17 +1,32 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/SysCalls/lv2/sys_sync.h" -#include "Emu/SysCalls/lv2/sys_event.h" -#include "Emu/SysCalls/lv2/sys_process.h" -#include "Emu/Event.h" +#include "Emu/Cell/lv2/sys_event.h" +#include "Emu/Cell/lv2/sys_process.h" #include "cellSync.h" -extern Module<> cellSync; +LOG_CHANNEL(cellSync); -s32 cellSyncMutexInitialize(vm::ptr mutex) +namespace _sync +{ + static inline be_t mutex_acquire(mutex& ctrl) + { + return ctrl.acq++; + } + + static inline bool mutex_try_lock(mutex& ctrl) + { + return ctrl.acq++ == ctrl.rel; + } + + static inline void mutex_unlock(mutex& ctrl) + { + ctrl.rel++; + } +} + +ppu_error_code cellSyncMutexInitialize(vm::ptr mutex) { cellSync.trace("cellSyncMutexInitialize(mutex=*0x%x)", mutex); @@ -30,7 +45,7 @@ s32 cellSyncMutexInitialize(vm::ptr mutex) return CELL_OK; } -s32 cellSyncMutexLock(PPUThread& ppu, vm::ptr mutex) +ppu_error_code cellSyncMutexLock(PPUThread& ppu, vm::ptr mutex) { cellSync.trace("cellSyncMutexLock(mutex=*0x%x)", mutex); @@ -45,7 +60,7 @@ s32 cellSyncMutexLock(PPUThread& ppu, vm::ptr mutex) } // increase acq value and remember its old value - const auto order = mutex->ctrl.atomic_op(_sync::mutex::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->ctrl.load().rel == order)); @@ -55,7 +70,7 @@ s32 cellSyncMutexLock(PPUThread& ppu, vm::ptr mutex) return CELL_OK; } -s32 cellSyncMutexTryLock(vm::ptr mutex) +ppu_error_code cellSyncMutexTryLock(vm::ptr mutex) { cellSync.trace("cellSyncMutexTryLock(mutex=*0x%x)", mutex); @@ -69,15 +84,15 @@ s32 cellSyncMutexTryLock(vm::ptr mutex) return CELL_SYNC_ERROR_ALIGN; } - if (!mutex->ctrl.atomic_op(_sync::mutex::try_lock)) + if (!mutex->ctrl.atomic_op(_sync::mutex_try_lock)) { - return CELL_SYNC_ERROR_BUSY; + return NOT_AN_ERROR(CELL_SYNC_ERROR_BUSY); } return CELL_OK; } -s32 cellSyncMutexUnlock(vm::ptr mutex) +ppu_error_code cellSyncMutexUnlock(vm::ptr mutex) { cellSync.trace("cellSyncMutexUnlock(mutex=*0x%x)", mutex); @@ -91,14 +106,14 @@ s32 cellSyncMutexUnlock(vm::ptr mutex) return CELL_SYNC_ERROR_ALIGN; } - mutex->ctrl.atomic_op(_sync::mutex::unlock); + mutex->ctrl.atomic_op(_sync::mutex_unlock); vm::notify_at(mutex); return CELL_OK; } -s32 cellSyncBarrierInitialize(vm::ptr barrier, u16 total_count) +ppu_error_code cellSyncBarrierInitialize(vm::ptr barrier, u16 total_count) { cellSync.trace("cellSyncBarrierInitialize(barrier=*0x%x, total_count=%d)", barrier, total_count); @@ -123,7 +138,7 @@ s32 cellSyncBarrierInitialize(vm::ptr barrier, u16 total_count) return CELL_OK; } -s32 cellSyncBarrierNotify(PPUThread& ppu, vm::ptr barrier) +ppu_error_code cellSyncBarrierNotify(PPUThread& ppu, vm::ptr barrier) { cellSync.trace("cellSyncBarrierNotify(barrier=*0x%x)", barrier); @@ -144,7 +159,7 @@ s32 cellSyncBarrierNotify(PPUThread& ppu, vm::ptr barrier) return CELL_OK; } -s32 cellSyncBarrierTryNotify(vm::ptr barrier) +ppu_error_code cellSyncBarrierTryNotify(vm::ptr barrier) { cellSync.trace("cellSyncBarrierTryNotify(barrier=*0x%x)", barrier); @@ -162,7 +177,7 @@ s32 cellSyncBarrierTryNotify(vm::ptr barrier) if (!barrier->ctrl.atomic_op(_sync::barrier::try_notify)) { - return CELL_SYNC_ERROR_BUSY; + return NOT_AN_ERROR(CELL_SYNC_ERROR_BUSY); } vm::notify_at(barrier); @@ -170,7 +185,7 @@ s32 cellSyncBarrierTryNotify(vm::ptr barrier) return CELL_OK; } -s32 cellSyncBarrierWait(PPUThread& ppu, vm::ptr barrier) +ppu_error_code cellSyncBarrierWait(PPUThread& ppu, vm::ptr barrier) { cellSync.trace("cellSyncBarrierWait(barrier=*0x%x)", barrier); @@ -193,7 +208,7 @@ s32 cellSyncBarrierWait(PPUThread& ppu, vm::ptr barrier) return CELL_OK; } -s32 cellSyncBarrierTryWait(vm::ptr barrier) +ppu_error_code cellSyncBarrierTryWait(vm::ptr barrier) { cellSync.trace("cellSyncBarrierTryWait(barrier=*0x%x)", barrier); @@ -211,7 +226,7 @@ s32 cellSyncBarrierTryWait(vm::ptr barrier) if (!barrier->ctrl.atomic_op(_sync::barrier::try_wait)) { - return CELL_SYNC_ERROR_BUSY; + return NOT_AN_ERROR(CELL_SYNC_ERROR_BUSY); } vm::notify_at(barrier); @@ -219,7 +234,7 @@ s32 cellSyncBarrierTryWait(vm::ptr barrier) return CELL_OK; } -s32 cellSyncRwmInitialize(vm::ptr rwm, vm::ptr buffer, u32 buffer_size) +ppu_error_code cellSyncRwmInitialize(vm::ptr rwm, vm::ptr buffer, u32 buffer_size) { cellSync.trace("cellSyncRwmInitialize(rwm=*0x%x, buffer=*0x%x, buffer_size=0x%x)", rwm, buffer, buffer_size); @@ -248,7 +263,7 @@ s32 cellSyncRwmInitialize(vm::ptr rwm, vm::ptr buffer, u32 bu return CELL_OK; } -s32 cellSyncRwmRead(PPUThread& ppu, vm::ptr rwm, vm::ptr buffer) +ppu_error_code cellSyncRwmRead(PPUThread& ppu, vm::ptr rwm, vm::ptr buffer) { cellSync.trace("cellSyncRwmRead(rwm=*0x%x, buffer=*0x%x)", rwm, buffer); @@ -279,7 +294,7 @@ s32 cellSyncRwmRead(PPUThread& ppu, vm::ptr rwm, vm::ptr buff return CELL_OK; } -s32 cellSyncRwmTryRead(vm::ptr rwm, vm::ptr buffer) +ppu_error_code cellSyncRwmTryRead(vm::ptr rwm, vm::ptr buffer) { cellSync.trace("cellSyncRwmTryRead(rwm=*0x%x, buffer=*0x%x)", rwm, buffer); @@ -296,7 +311,7 @@ s32 cellSyncRwmTryRead(vm::ptr rwm, vm::ptr buffer) // increase `readers` if `writers` is zero if (!rwm->ctrl.atomic_op(_sync::rwlock::try_read_begin)) { - return CELL_SYNC_ERROR_BUSY; + return NOT_AN_ERROR(CELL_SYNC_ERROR_BUSY); } // copy data to buffer @@ -313,7 +328,7 @@ s32 cellSyncRwmTryRead(vm::ptr rwm, vm::ptr buffer) return CELL_OK; } -s32 cellSyncRwmWrite(PPUThread& ppu, vm::ptr rwm, vm::cptr buffer) +ppu_error_code cellSyncRwmWrite(PPUThread& ppu, vm::ptr rwm, vm::cptr buffer) { cellSync.trace("cellSyncRwmWrite(rwm=*0x%x, buffer=*0x%x)", rwm, buffer); @@ -344,7 +359,7 @@ s32 cellSyncRwmWrite(PPUThread& ppu, vm::ptr rwm, vm::cptr bu return CELL_OK; } -s32 cellSyncRwmTryWrite(vm::ptr rwm, vm::cptr buffer) +ppu_error_code cellSyncRwmTryWrite(vm::ptr rwm, vm::cptr buffer) { cellSync.trace("cellSyncRwmTryWrite(rwm=*0x%x, buffer=*0x%x)", rwm, buffer); @@ -361,7 +376,7 @@ s32 cellSyncRwmTryWrite(vm::ptr rwm, vm::cptr buffer) // set `writers` to 1 if `readers` and `writers` are zero if (!rwm->ctrl.compare_and_swap_test({ 0, 0 }, { 0, 1 })) { - return CELL_SYNC_ERROR_BUSY; + return NOT_AN_ERROR(CELL_SYNC_ERROR_BUSY); } // copy data from buffer @@ -375,7 +390,7 @@ s32 cellSyncRwmTryWrite(vm::ptr rwm, vm::cptr buffer) return CELL_OK; } -s32 cellSyncQueueInitialize(vm::ptr queue, vm::ptr buffer, u32 size, u32 depth) +ppu_error_code cellSyncQueueInitialize(vm::ptr queue, vm::ptr buffer, u32 size, u32 depth) { cellSync.trace("cellSyncQueueInitialize(queue=*0x%x, buffer=*0x%x, size=0x%x, depth=0x%x)", queue, buffer, size, depth); @@ -410,7 +425,7 @@ s32 cellSyncQueueInitialize(vm::ptr queue, vm::ptr buffer, u3 return CELL_OK; } -s32 cellSyncQueuePush(PPUThread& ppu, vm::ptr queue, vm::cptr buffer) +ppu_error_code cellSyncQueuePush(PPUThread& ppu, vm::ptr queue, vm::cptr buffer) { cellSync.trace("cellSyncQueuePush(queue=*0x%x, buffer=*0x%x)", queue, buffer); @@ -428,20 +443,20 @@ s32 cellSyncQueuePush(PPUThread& ppu, vm::ptr queue, vm::cptrctrl.atomic_op(_sync::queue::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); // ...push_end - queue->ctrl._and_not({ 0, 0xff000000 }); + queue->ctrl.atomic_op([](_sync::queue& ctrl) { ctrl._push = 0; }); vm::notify_at(queue.ptr(&CellSyncQueue::ctrl)); return CELL_OK; } -s32 cellSyncQueueTryPush(vm::ptr queue, vm::cptr buffer) +ppu_error_code cellSyncQueueTryPush(vm::ptr queue, vm::cptr buffer) { cellSync.trace("cellSyncQueueTryPush(queue=*0x%x, buffer=*0x%x)", queue, buffer); @@ -459,23 +474,23 @@ s32 cellSyncQueueTryPush(vm::ptr queue, vm::cptr buffer) u32 position; - if (!queue->ctrl.atomic_op(_sync::queue::try_push_begin, depth, position)) + if (!queue->ctrl.atomic_op(_sync::queue::try_push_begin, depth, &position)) { - return CELL_SYNC_ERROR_BUSY; + return NOT_AN_ERROR(CELL_SYNC_ERROR_BUSY); } // copy data from the buffer at the position std::memcpy(&queue->buffer[position * queue->size], buffer.get_ptr(), queue->size); // ...push_end - queue->ctrl._and_not({ 0, 0xff000000 }); + queue->ctrl.atomic_op([](_sync::queue& ctrl) { ctrl._push = 0; }); vm::notify_at(queue.ptr(&CellSyncQueue::ctrl)); return CELL_OK; } -s32 cellSyncQueuePop(PPUThread& ppu, vm::ptr queue, vm::ptr buffer) +ppu_error_code cellSyncQueuePop(PPUThread& ppu, vm::ptr queue, vm::ptr buffer) { cellSync.trace("cellSyncQueuePop(queue=*0x%x, buffer=*0x%x)", queue, buffer); @@ -493,20 +508,20 @@ s32 cellSyncQueuePop(PPUThread& ppu, vm::ptr queue, vm::ptr u32 position; - vm::wait_op(ppu, queue.addr(), 8, WRAP_EXPR(queue->ctrl.atomic_op(_sync::queue::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 % depth * queue->size], queue->size); // ...pop_end - queue->ctrl._and_not({ 0xff000000, 0 }); + queue->ctrl.atomic_op([](_sync::queue& ctrl) { ctrl._pop = 0; }); vm::notify_at(queue.ptr(&CellSyncQueue::ctrl)); return CELL_OK; } -s32 cellSyncQueueTryPop(vm::ptr queue, vm::ptr buffer) +ppu_error_code cellSyncQueueTryPop(vm::ptr queue, vm::ptr buffer) { cellSync.trace("cellSyncQueueTryPop(queue=*0x%x, buffer=*0x%x)", queue, buffer); @@ -524,23 +539,23 @@ s32 cellSyncQueueTryPop(vm::ptr queue, vm::ptr buffer) u32 position; - if (!queue->ctrl.atomic_op(_sync::queue::try_pop_begin, depth, position)) + if (!queue->ctrl.atomic_op(_sync::queue::try_pop_begin, depth, &position)) { - return CELL_SYNC_ERROR_BUSY; + return NOT_AN_ERROR(CELL_SYNC_ERROR_BUSY); } // copy data at the position to the buffer std::memcpy(buffer.get_ptr(), &queue->buffer[position % depth * queue->size], queue->size); // ...pop_end - queue->ctrl._and_not({ 0xff000000, 0 }); + queue->ctrl.atomic_op([](_sync::queue& ctrl) { ctrl._pop = 0; }); vm::notify_at(queue.ptr(&CellSyncQueue::ctrl)); return CELL_OK; } -s32 cellSyncQueuePeek(PPUThread& ppu, vm::ptr queue, vm::ptr buffer) +ppu_error_code cellSyncQueuePeek(PPUThread& ppu, vm::ptr queue, vm::ptr buffer) { cellSync.trace("cellSyncQueuePeek(queue=*0x%x, buffer=*0x%x)", queue, buffer); @@ -558,20 +573,20 @@ s32 cellSyncQueuePeek(PPUThread& ppu, vm::ptr queue, vm::ptrctrl.atomic_op(_sync::queue::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 % depth * queue->size], queue->size); // ...peek_end - queue->ctrl._and_not({ 0xff000000, 0 }); + queue->ctrl.atomic_op([](_sync::queue& ctrl) { ctrl._pop = 0; }); vm::notify_at(queue.ptr(&CellSyncQueue::ctrl)); return CELL_OK; } -s32 cellSyncQueueTryPeek(vm::ptr queue, vm::ptr buffer) +ppu_error_code cellSyncQueueTryPeek(vm::ptr queue, vm::ptr buffer) { cellSync.trace("cellSyncQueueTryPeek(queue=*0x%x, buffer=*0x%x)", queue, buffer); @@ -589,23 +604,23 @@ s32 cellSyncQueueTryPeek(vm::ptr queue, vm::ptr buffer) u32 position; - if (!queue->ctrl.atomic_op(_sync::queue::try_peek_begin, depth, position)) + if (!queue->ctrl.atomic_op(_sync::queue::try_peek_begin, depth, &position)) { - return CELL_SYNC_ERROR_BUSY; + return NOT_AN_ERROR(CELL_SYNC_ERROR_BUSY); } // copy data at the position to the buffer std::memcpy(buffer.get_ptr(), &queue->buffer[position % depth * queue->size], queue->size); // ...peek_end - queue->ctrl._and_not({ 0xff000000, 0 }); + queue->ctrl.atomic_op([](_sync::queue& ctrl) { ctrl._pop = 0; }); vm::notify_at(queue.ptr(&CellSyncQueue::ctrl)); return CELL_OK; } -s32 cellSyncQueueSize(vm::ptr queue) +ppu_error_code cellSyncQueueSize(vm::ptr queue) { cellSync.trace("cellSyncQueueSize(queue=*0x%x)", queue); @@ -621,10 +636,10 @@ s32 cellSyncQueueSize(vm::ptr queue) const u32 depth = queue->check_depth(); - return queue->ctrl.load().count & 0xffffff; + return NOT_AN_ERROR(queue->ctrl.load().count & 0xffffff); } -s32 cellSyncQueueClear(PPUThread& ppu, vm::ptr queue) +ppu_error_code cellSyncQueueClear(PPUThread& ppu, vm::ptr queue) { cellSync.trace("cellSyncQueueClear(queue=*0x%x)", queue); @@ -692,7 +707,7 @@ void syncLFQueueInitialize(vm::ptr queue, vm::cptr buffer queue->m_eq_id = 0; } -s32 cellSyncLFQueueInitialize(vm::ptr queue, vm::cptr buffer, u32 size, u32 depth, u32 direction, vm::ptr eaSignal) +ppu_error_code cellSyncLFQueueInitialize(vm::ptr queue, vm::cptr buffer, u32 size, u32 depth, u32 direction, vm::ptr eaSignal) { cellSync.warning("cellSyncLFQueueInitialize(queue=*0x%x, buffer=*0x%x, size=0x%x, depth=0x%x, direction=%d, eaSignal=*0x%x)", queue, buffer, size, depth, direction, eaSignal); @@ -729,7 +744,7 @@ s32 cellSyncLFQueueInitialize(vm::ptr queue, vm::cptr buf if (s32 ret = process_get_sdk_version(process_getpid(), sdk_ver)) { - return ret; + return NOT_AN_ERROR(ret); } if (sdk_ver == -1) @@ -801,7 +816,7 @@ s32 cellSyncLFQueueInitialize(vm::ptr queue, vm::cptr buf return CELL_OK; } -s32 _cellSyncLFQueueGetPushPointer(PPUThread& ppu, vm::ptr queue, vm::ptr pointer, u32 isBlocking, u32 useEventQueue) +ppu_error_code _cellSyncLFQueueGetPushPointer(PPUThread& ppu, vm::ptr queue, vm::ptr pointer, u32 isBlocking, u32 useEventQueue) { cellSync.warning("_cellSyncLFQueueGetPushPointer(queue=*0x%x, pointer=*0x%x, isBlocking=%d, useEventQueue=%d)", queue, pointer, isBlocking, useEventQueue); @@ -883,21 +898,18 @@ s32 _cellSyncLFQueueGetPushPointer(PPUThread& ppu, vm::ptr queu { if (!push.m_h7 || res) { - return res; + return NOT_AN_ERROR(res); } break; } } - if (s32 res = sys_event_queue_receive(ppu, queue->m_eq_id, vm::null, 0)) - { - throw EXCEPTION(""); - } + ASSERT(sys_event_queue_receive(ppu, queue->m_eq_id, vm::null, 0) == CELL_OK); var1 = 1; } } -s32 _cellSyncLFQueueGetPushPointer2(PPUThread& ppu, vm::ptr queue, vm::ptr pointer, u32 isBlocking, u32 useEventQueue) +ppu_error_code _cellSyncLFQueueGetPushPointer2(PPUThread& ppu, vm::ptr queue, vm::ptr pointer, u32 isBlocking, u32 useEventQueue) { // arguments copied from _cellSyncLFQueueGetPushPointer cellSync.todo("_cellSyncLFQueueGetPushPointer2(queue=*0x%x, pointer=*0x%x, isBlocking=%d, useEventQueue=%d)", queue, pointer, isBlocking, useEventQueue); @@ -905,7 +917,7 @@ s32 _cellSyncLFQueueGetPushPointer2(PPUThread& ppu, vm::ptr que throw EXCEPTION(""); } -s32 _cellSyncLFQueueCompletePushPointer(PPUThread& ppu, vm::ptr queue, s32 pointer, vm::ptr fpSendSignal) +ppu_error_code _cellSyncLFQueueCompletePushPointer(PPUThread& ppu, vm::ptr queue, s32 pointer, vm::ptr fpSendSignal) { cellSync.warning("_cellSyncLFQueueCompletePushPointer(queue=*0x%x, pointer=%d, fpSendSignal=*0x%x)", queue, pointer, fpSendSignal); @@ -983,7 +995,7 @@ s32 _cellSyncLFQueueCompletePushPointer(PPUThread& ppu, vm::ptr if (var9 > 1 && (u32)var8 > 1) { - assert(16 - var2 <= 1); + ASSERT(16 - var2 <= 1); } s32 var11 = (pack >> 10) & 0x1f; @@ -1015,16 +1027,12 @@ s32 _cellSyncLFQueueCompletePushPointer(PPUThread& ppu, vm::ptr if (queue->push2.compare_and_swap_test(old, push2)) { - assert(var2 + var4 < 16); + ASSERT(var2 + var4 < 16); if (var6 != -1) { - bool exch = queue->push3.compare_and_swap_test(old2, push3); - assert(exch); - if (exch) - { - assert(fpSendSignal); - return fpSendSignal(ppu, (u32)queue->m_eaSignal.addr(), var6); - } + ASSERT(queue->push3.compare_and_swap_test(old2, push3)); + ASSERT(fpSendSignal); + return NOT_AN_ERROR(fpSendSignal(ppu, (u32)queue->m_eaSignal.addr(), var6)); } else { @@ -1041,7 +1049,7 @@ s32 _cellSyncLFQueueCompletePushPointer(PPUThread& ppu, vm::ptr } } -s32 _cellSyncLFQueueCompletePushPointer2(PPUThread& ppu, vm::ptr queue, s32 pointer, vm::ptr fpSendSignal) +ppu_error_code _cellSyncLFQueueCompletePushPointer2(PPUThread& ppu, vm::ptr queue, s32 pointer, vm::ptr fpSendSignal) { // arguments copied from _cellSyncLFQueueCompletePushPointer cellSync.todo("_cellSyncLFQueueCompletePushPointer2(queue=*0x%x, pointer=%d, fpSendSignal=*0x%x)", queue, pointer, fpSendSignal); @@ -1049,7 +1057,7 @@ s32 _cellSyncLFQueueCompletePushPointer2(PPUThread& ppu, vm::ptr queue, vm::cptr buffer, u32 isBlocking) +ppu_error_code _cellSyncLFQueuePushBody(PPUThread& ppu, vm::ptr queue, vm::cptr buffer, u32 isBlocking) { // cellSyncLFQueuePush has 1 in isBlocking param, cellSyncLFQueueTryPush has 0 cellSync.warning("_cellSyncLFQueuePushBody(queue=*0x%x, buffer=*0x%x, isBlocking=%d)", queue, buffer, isBlocking); @@ -1083,7 +1091,7 @@ s32 _cellSyncLFQueuePushBody(PPUThread& ppu, vm::ptr queue, vm: if (!isBlocking || res != CELL_SYNC_ERROR_AGAIN) { - if (res) return res; + if (res) return NOT_AN_ERROR(res); break; } @@ -1094,7 +1102,7 @@ s32 _cellSyncLFQueuePushBody(PPUThread& ppu, vm::ptr queue, vm: const s32 depth = queue->m_depth; 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))); + const u32 addr = vm::cast((u64)((queue->m_buffer.addr() & ~1ull) + size * (pos >= depth ? pos - depth : pos)), HERE); std::memcpy(vm::base(addr), buffer.get_ptr(), size); if (queue->m_direction != CELL_SYNC_QUEUE_ANY2ANY) @@ -1107,7 +1115,7 @@ s32 _cellSyncLFQueuePushBody(PPUThread& ppu, vm::ptr queue, vm: } } -s32 _cellSyncLFQueueGetPopPointer(PPUThread& ppu, vm::ptr queue, vm::ptr pointer, u32 isBlocking, u32 arg4, u32 useEventQueue) +ppu_error_code _cellSyncLFQueueGetPopPointer(PPUThread& ppu, vm::ptr queue, vm::ptr pointer, u32 isBlocking, u32 arg4, u32 useEventQueue) { cellSync.warning("_cellSyncLFQueueGetPopPointer(queue=*0x%x, pointer=*0x%x, isBlocking=%d, arg4=%d, useEventQueue=%d)", queue, pointer, isBlocking, arg4, useEventQueue); @@ -1189,21 +1197,18 @@ s32 _cellSyncLFQueueGetPopPointer(PPUThread& ppu, vm::ptr queue { if (!pop.m_h3 || res) { - return res; + return NOT_AN_ERROR(res); } break; } } - if (s32 res = sys_event_queue_receive(ppu, queue->m_eq_id, vm::null, 0)) - { - throw EXCEPTION(""); - } + ASSERT(sys_event_queue_receive(ppu, queue->m_eq_id, vm::null, 0) == CELL_OK); var1 = 1; } } -s32 _cellSyncLFQueueGetPopPointer2(PPUThread& ppu, vm::ptr queue, vm::ptr pointer, u32 isBlocking, u32 useEventQueue) +ppu_error_code _cellSyncLFQueueGetPopPointer2(PPUThread& ppu, vm::ptr queue, vm::ptr pointer, u32 isBlocking, u32 useEventQueue) { // arguments copied from _cellSyncLFQueueGetPopPointer cellSync.todo("_cellSyncLFQueueGetPopPointer2(queue=*0x%x, pointer=*0x%x, isBlocking=%d, useEventQueue=%d)", queue, pointer, isBlocking, useEventQueue); @@ -1211,7 +1216,7 @@ s32 _cellSyncLFQueueGetPopPointer2(PPUThread& ppu, vm::ptr queu throw EXCEPTION(""); } -s32 _cellSyncLFQueueCompletePopPointer(PPUThread& ppu, vm::ptr queue, s32 pointer, vm::ptr fpSendSignal, u32 noQueueFull) +ppu_error_code _cellSyncLFQueueCompletePopPointer(PPUThread& ppu, vm::ptr queue, s32 pointer, vm::ptr fpSendSignal, u32 noQueueFull) { // arguments copied from _cellSyncLFQueueCompletePushPointer + unknown argument (noQueueFull taken from LFQueue2CompletePopPointer) cellSync.warning("_cellSyncLFQueueCompletePopPointer(queue=*0x%x, pointer=%d, fpSendSignal=*0x%x, noQueueFull=%d)", queue, pointer, fpSendSignal, noQueueFull); @@ -1294,7 +1299,7 @@ s32 _cellSyncLFQueueCompletePopPointer(PPUThread& ppu, vm::ptr if (var9 > 1 && (u32)var8 > 1) { - assert(16 - var2 <= 1); + ASSERT(16 - var2 <= 1); } s32 var11 = (pack >> 10) & 0x1f; @@ -1324,13 +1329,9 @@ s32 _cellSyncLFQueueCompletePopPointer(PPUThread& ppu, vm::ptr { if (var6 != -1) { - bool exch = queue->pop3.compare_and_swap_test(old2, pop3); - assert(exch); - if (exch) - { - assert(fpSendSignal); - return fpSendSignal(ppu, (u32)queue->m_eaSignal.addr(), var6); - } + ASSERT(queue->pop3.compare_and_swap_test(old2, pop3)); + ASSERT(fpSendSignal); + return NOT_AN_ERROR(fpSendSignal(ppu, (u32)queue->m_eaSignal.addr(), var6)); } else { @@ -1347,7 +1348,7 @@ s32 _cellSyncLFQueueCompletePopPointer(PPUThread& ppu, vm::ptr } } -s32 _cellSyncLFQueueCompletePopPointer2(PPUThread& ppu, vm::ptr queue, s32 pointer, vm::ptr fpSendSignal, u32 noQueueFull) +ppu_error_code _cellSyncLFQueueCompletePopPointer2(PPUThread& ppu, vm::ptr queue, s32 pointer, vm::ptr fpSendSignal, u32 noQueueFull) { // arguments copied from _cellSyncLFQueueCompletePopPointer cellSync.todo("_cellSyncLFQueueCompletePopPointer2(queue=*0x%x, pointer=%d, fpSendSignal=*0x%x, noQueueFull=%d)", queue, pointer, fpSendSignal, noQueueFull); @@ -1355,7 +1356,7 @@ s32 _cellSyncLFQueueCompletePopPointer2(PPUThread& ppu, vm::ptr throw EXCEPTION(""); } -s32 _cellSyncLFQueuePopBody(PPUThread& ppu, vm::ptr queue, vm::ptr buffer, u32 isBlocking) +ppu_error_code _cellSyncLFQueuePopBody(PPUThread& ppu, vm::ptr queue, vm::ptr buffer, u32 isBlocking) { // cellSyncLFQueuePop has 1 in isBlocking param, cellSyncLFQueueTryPop has 0 cellSync.warning("_cellSyncLFQueuePopBody(queue=*0x%x, buffer=*0x%x, isBlocking=%d)", queue, buffer, isBlocking); @@ -1389,7 +1390,7 @@ s32 _cellSyncLFQueuePopBody(PPUThread& ppu, vm::ptr queue, vm:: if (!isBlocking || res != CELL_SYNC_ERROR_AGAIN) { - if (res) return res; + if (res) return NOT_AN_ERROR(res); break; } @@ -1400,7 +1401,7 @@ s32 _cellSyncLFQueuePopBody(PPUThread& ppu, vm::ptr queue, vm:: const s32 depth = queue->m_depth; 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))); + const u32 addr = vm::cast((u64)((queue->m_buffer.addr() & ~1) + size * (pos >= depth ? pos - depth : pos)), HERE); std::memcpy(buffer.get_ptr(), vm::base(addr), size); if (queue->m_direction != CELL_SYNC_QUEUE_ANY2ANY) @@ -1413,7 +1414,7 @@ s32 _cellSyncLFQueuePopBody(PPUThread& ppu, vm::ptr queue, vm:: } } -s32 cellSyncLFQueueClear(vm::ptr queue) +ppu_error_code cellSyncLFQueueClear(vm::ptr queue) { cellSync.warning("cellSyncLFQueueClear(queue=*0x%x)", queue); @@ -1464,7 +1465,7 @@ s32 cellSyncLFQueueClear(vm::ptr queue) return CELL_OK; } -s32 cellSyncLFQueueSize(vm::ptr queue, vm::ptr size) +ppu_error_code cellSyncLFQueueSize(vm::ptr queue, vm::ptr size) { cellSync.warning("cellSyncLFQueueSize(queue=*0x%x, size=*0x%x)", queue, size); @@ -1501,7 +1502,7 @@ s32 cellSyncLFQueueSize(vm::ptr queue, vm::ptr size) } } -s32 cellSyncLFQueueDepth(vm::ptr queue, vm::ptr depth) +ppu_error_code cellSyncLFQueueDepth(vm::ptr queue, vm::ptr depth) { cellSync.trace("cellSyncLFQueueDepth(queue=*0x%x, depth=*0x%x)", queue, depth); @@ -1520,7 +1521,7 @@ s32 cellSyncLFQueueDepth(vm::ptr queue, vm::ptr depth) return CELL_OK; } -s32 _cellSyncLFQueueGetSignalAddress(vm::cptr queue, vm::pptr ppSignal) +ppu_error_code _cellSyncLFQueueGetSignalAddress(vm::cptr queue, vm::pptr ppSignal) { cellSync.trace("_cellSyncLFQueueGetSignalAddress(queue=*0x%x, ppSignal=**0x%x)", queue, ppSignal); @@ -1539,7 +1540,7 @@ s32 _cellSyncLFQueueGetSignalAddress(vm::cptr queue, vm::pptr queue, vm::ptr direction) +ppu_error_code cellSyncLFQueueGetDirection(vm::cptr queue, vm::ptr direction) { cellSync.trace("cellSyncLFQueueGetDirection(queue=*0x%x, direction=*0x%x)", queue, direction); @@ -1558,7 +1559,7 @@ s32 cellSyncLFQueueGetDirection(vm::cptr queue, vm::ptr di return CELL_OK; } -s32 cellSyncLFQueueGetEntrySize(vm::cptr queue, vm::ptr entry_size) +ppu_error_code cellSyncLFQueueGetEntrySize(vm::cptr queue, vm::ptr entry_size) { cellSync.trace("cellSyncLFQueueGetEntrySize(queue=*0x%x, entry_size=*0x%x)", queue, entry_size); @@ -1577,57 +1578,22 @@ s32 cellSyncLFQueueGetEntrySize(vm::cptr queue, vm::ptr en return CELL_OK; } -s32 _cellSyncLFQueueAttachLv2EventQueue(vm::ptr spus, u32 num, vm::ptr queue) +ppu_error_code _cellSyncLFQueueAttachLv2EventQueue(vm::ptr spus, u32 num, vm::ptr queue) { cellSync.todo("_cellSyncLFQueueAttachLv2EventQueue(spus=*0x%x, num=%d, queue=*0x%x)", spus, num, queue); throw EXCEPTION(""); } -s32 _cellSyncLFQueueDetachLv2EventQueue(vm::ptr spus, u32 num, vm::ptr queue) +ppu_error_code _cellSyncLFQueueDetachLv2EventQueue(vm::ptr spus, u32 num, vm::ptr queue) { cellSync.todo("_cellSyncLFQueueDetachLv2EventQueue(spus=*0x%x, num=%d, queue=*0x%x)", spus, num, queue); throw EXCEPTION(""); } -Module<> cellSync("cellSync", []() +DECLARE(ppu_module_manager::cellSync)("cellSync", []() { - // setup error handler - cellSync.on_error = [](s64 value, ModuleFunc* func) - { - // get error name for CELL_SYNC errors - auto get_error = [](u32 code) -> const char* - { - switch (code) - { - case CELL_SYNC_ERROR_AGAIN: return "CELL_SYNC_ERROR_AGAIN"; - case CELL_SYNC_ERROR_INVAL: return "CELL_SYNC_ERROR_INVAL"; - case CELL_SYNC_ERROR_NOSYS: return "CELL_SYNC_ERROR_NOSYS"; - case CELL_SYNC_ERROR_NOMEM: return "CELL_SYNC_ERROR_NOMEM"; - case CELL_SYNC_ERROR_SRCH: return "CELL_SYNC_ERROR_SRCH"; - case CELL_SYNC_ERROR_NOENT: return "CELL_SYNC_ERROR_NOENT"; - case CELL_SYNC_ERROR_NOEXEC: return "CELL_SYNC_ERROR_NOEXEC"; - case CELL_SYNC_ERROR_DEADLK: return "CELL_SYNC_ERROR_DEADLK"; - case CELL_SYNC_ERROR_PERM: return "CELL_SYNC_ERROR_PERM"; - case CELL_SYNC_ERROR_BUSY: return "CELL_SYNC_ERROR_BUSY"; - case CELL_SYNC_ERROR_ABORT: return "CELL_SYNC_ERROR_ABORT"; - case CELL_SYNC_ERROR_FAULT: return "CELL_SYNC_ERROR_FAULT"; - case CELL_SYNC_ERROR_CHILD: return "CELL_SYNC_ERROR_CHILD"; - case CELL_SYNC_ERROR_STAT: return "CELL_SYNC_ERROR_STAT"; - case CELL_SYNC_ERROR_ALIGN: return "CELL_SYNC_ERROR_ALIGN"; - } - - return "???"; - }; - - // analyse error code - if (u32 code = (value & 0xffffff00) == 0x80410100 ? static_cast(value) : 0) - { - cellSync.error("%s() -> %s (0x%x)", func->name, get_error(code), code); - } - }; - REG_FUNC(cellSync, cellSyncMutexInitialize); REG_FUNC(cellSync, cellSyncMutexLock); REG_FUNC(cellSync, cellSyncMutexTryLock); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSync.h b/rpcs3/Emu/Cell/Modules/cellSync.h similarity index 58% rename from rpcs3/Emu/SysCalls/Modules/cellSync.h rename to rpcs3/Emu/Cell/Modules/cellSync.h index fbf1e7464b..831ce776d1 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSync.h +++ b/rpcs3/Emu/Cell/Modules/cellSync.h @@ -3,53 +3,82 @@ namespace vm { using namespace ps3; } // Return Codes -enum +enum CellSyncError : s32 { - CELL_SYNC_ERROR_AGAIN = 0x80410101, - CELL_SYNC_ERROR_INVAL = 0x80410102, - CELL_SYNC_ERROR_NOSYS = 0x80410103, - CELL_SYNC_ERROR_NOMEM = 0x80410104, - CELL_SYNC_ERROR_SRCH = 0x80410105, - CELL_SYNC_ERROR_NOENT = 0x80410106, - CELL_SYNC_ERROR_NOEXEC = 0x80410107, - CELL_SYNC_ERROR_DEADLK = 0x80410108, - CELL_SYNC_ERROR_PERM = 0x80410109, - CELL_SYNC_ERROR_BUSY = 0x8041010A, - CELL_SYNC_ERROR_ABORT = 0x8041010C, - CELL_SYNC_ERROR_FAULT = 0x8041010D, - CELL_SYNC_ERROR_CHILD = 0x8041010E, - CELL_SYNC_ERROR_STAT = 0x8041010F, - CELL_SYNC_ERROR_ALIGN = 0x80410110, - - CELL_SYNC_ERROR_NULL_POINTER = 0x80410111, - CELL_SYNC_ERROR_NOT_SUPPORTED_THREAD = 0x80410112, - CELL_SYNC_ERROR_SHOTAGE = 0x80410112, - CELL_SYNC_ERROR_NO_NOTIFIER = 0x80410113, - CELL_SYNC_ERROR_UNKNOWNKEY = 0x80410113, - CELL_SYNC_ERROR_NO_SPU_CONTEXT_STORAGE = 0x80410114, + CELL_SYNC_ERROR_AGAIN = ERROR_CODE(0x80410101), + CELL_SYNC_ERROR_INVAL = ERROR_CODE(0x80410102), + CELL_SYNC_ERROR_NOSYS = ERROR_CODE(0x80410103), + CELL_SYNC_ERROR_NOMEM = ERROR_CODE(0x80410104), + CELL_SYNC_ERROR_SRCH = ERROR_CODE(0x80410105), + CELL_SYNC_ERROR_NOENT = ERROR_CODE(0x80410106), + CELL_SYNC_ERROR_NOEXEC = ERROR_CODE(0x80410107), + CELL_SYNC_ERROR_DEADLK = ERROR_CODE(0x80410108), + CELL_SYNC_ERROR_PERM = ERROR_CODE(0x80410109), + CELL_SYNC_ERROR_BUSY = ERROR_CODE(0x8041010A), + CELL_SYNC_ERROR_ABORT = ERROR_CODE(0x8041010C), + CELL_SYNC_ERROR_FAULT = ERROR_CODE(0x8041010D), + CELL_SYNC_ERROR_CHILD = ERROR_CODE(0x8041010E), + CELL_SYNC_ERROR_STAT = ERROR_CODE(0x8041010F), + CELL_SYNC_ERROR_ALIGN = ERROR_CODE(0x80410110), + CELL_SYNC_ERROR_NULL_POINTER = ERROR_CODE(0x80410111), + CELL_SYNC_ERROR_NOT_SUPPORTED_THREAD = ERROR_CODE(0x80410112), + CELL_SYNC_ERROR_NO_NOTIFIER = ERROR_CODE(0x80410113), + CELL_SYNC_ERROR_NO_SPU_CONTEXT_STORAGE = ERROR_CODE(0x80410114), }; +enum CellSyncError1 : s32 +{ + CELL_SYNC_ERROR_SHOTAGE = ERROR_CODE(0x80410112), + CELL_SYNC_ERROR_UNKNOWNKEY = ERROR_CODE(0x80410113), +}; + +template<> +inline const char* ppu_error_code::print(CellSyncError error) +{ + switch (error) + { + STR_CASE(CELL_SYNC_ERROR_AGAIN); + STR_CASE(CELL_SYNC_ERROR_INVAL); + STR_CASE(CELL_SYNC_ERROR_NOSYS); + STR_CASE(CELL_SYNC_ERROR_NOMEM); + STR_CASE(CELL_SYNC_ERROR_SRCH); + STR_CASE(CELL_SYNC_ERROR_NOENT); + STR_CASE(CELL_SYNC_ERROR_NOEXEC); + STR_CASE(CELL_SYNC_ERROR_DEADLK); + STR_CASE(CELL_SYNC_ERROR_PERM); + STR_CASE(CELL_SYNC_ERROR_BUSY); + STR_CASE(CELL_SYNC_ERROR_ABORT); + STR_CASE(CELL_SYNC_ERROR_FAULT); + STR_CASE(CELL_SYNC_ERROR_CHILD); + STR_CASE(CELL_SYNC_ERROR_STAT); + STR_CASE(CELL_SYNC_ERROR_ALIGN); + STR_CASE(CELL_SYNC_ERROR_NULL_POINTER); + STR_CASE(CELL_SYNC_ERROR_NOT_SUPPORTED_THREAD); + STR_CASE(CELL_SYNC_ERROR_NO_NOTIFIER); + STR_CASE(CELL_SYNC_ERROR_NO_SPU_CONTEXT_STORAGE); + } + + return nullptr; +} + +template<> +inline const char* ppu_error_code::print(CellSyncError1 error) +{ + switch (error) + { + STR_CASE(CELL_SYNC_ERROR_SHOTAGE); + STR_CASE(CELL_SYNC_ERROR_UNKNOWNKEY); + } + + return nullptr; +} + namespace _sync { struct alignas(4) mutex // CellSyncMutex control variable { be_t rel; be_t acq; - - static inline be_t acquire(mutex& ctrl) - { - return ctrl.acq++; - } - - static inline bool try_lock(mutex& ctrl) - { - return ctrl.acq++ == ctrl.rel; - } - - static inline void unlock(mutex& ctrl) - { - ctrl.rel++; - } }; } @@ -108,7 +137,7 @@ CHECK_SIZE_ALIGN(CellSyncBarrier, 4, 4); namespace _sync { - struct rwlock // CellSyncRwm control variable + struct alignas(4) rwlock // CellSyncRwm control variable { be_t readers; be_t writers; @@ -160,25 +189,25 @@ CHECK_SIZE_ALIGN(CellSyncRwm, 16, 16); namespace _sync { - struct queue // CellSyncQueue control variable + struct alignas(8) queue // CellSyncQueue control variable { union { be_t x0; - bf_be_t next; - bf_be_t _pop; + bf_t, 0, 24> next; + bf_t, 24, 8> _pop; }; union { be_t x4; - bf_be_t count; - bf_be_t _push; + bf_t, 0, 24> count; + bf_t, 24, 8> _push; }; - static inline bool try_push_begin(queue& ctrl, u32 depth, u32& position) + static inline bool try_push_begin(queue& ctrl, u32 depth, u32* position) { const u32 count = ctrl.count; @@ -187,14 +216,14 @@ namespace _sync return false; } - position = ctrl.next; - ctrl.next = position + 1 != depth ? position + 1 : 0; + *position = ctrl.next; + ctrl.next = *position + 1 != depth ? *position + 1 : 0; ctrl.count = count + 1; ctrl._push = 1; return true; } - static inline bool try_pop_begin(queue& ctrl, u32 depth, u32& position) + static inline bool try_pop_begin(queue& ctrl, u32 depth, u32* position) { const u32 count = ctrl.count; @@ -204,12 +233,12 @@ namespace _sync } ctrl._pop = 1; - position = ctrl.next + depth - count; + *position = ctrl.next + depth - count; ctrl.count = count - 1; return true; } - static inline bool try_peek_begin(queue& ctrl, u32 depth, u32& position) + static inline bool try_peek_begin(queue& ctrl, u32 depth, u32* position) { const u32 count = ctrl.count; @@ -219,7 +248,7 @@ namespace _sync } ctrl._pop = 1; - position = ctrl.next + depth - count; + *position = ctrl.next + depth - count; return true; } @@ -281,7 +310,7 @@ enum CellSyncQueueDirection : u32 // CellSyncLFQueueDirection struct alignas(128) CellSyncLFQueue { - struct pop1_t + struct alignas(8) pop1_t { be_t m_h1; be_t m_h2; @@ -294,13 +323,13 @@ struct alignas(128) CellSyncLFQueue be_t pack; }; - struct pop3_t + struct alignas(4) pop3_t { be_t m_h1; be_t m_h2; }; - struct push1_t + struct alignas(8) push1_t { be_t m_h5; be_t m_h6; @@ -313,7 +342,7 @@ struct alignas(128) CellSyncLFQueue be_t pack; }; - struct push3_t + struct alignas(4) push3_t { be_t m_h5; be_t m_h6; @@ -367,4 +396,4 @@ struct alignas(128) CellSyncLFQueue CHECK_SIZE_ALIGN(CellSyncLFQueue, 128, 128); // Prototypes -s32 cellSyncLFQueueInitialize(vm::ptr queue, vm::cptr buffer, u32 size, u32 depth, u32 direction, vm::ptr eaSignal); +ppu_error_code cellSyncLFQueueInitialize(vm::ptr queue, vm::cptr buffer, u32 size, u32 depth, u32 direction, vm::ptr eaSignal); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSync2.cpp b/rpcs3/Emu/Cell/Modules/cellSync2.cpp similarity index 89% rename from rpcs3/Emu/SysCalls/Modules/cellSync2.cpp rename to rpcs3/Emu/Cell/Modules/cellSync2.cpp index b875e2f7ec..145d51ba98 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSync2.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSync2.cpp @@ -1,21 +1,17 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellSync2.h" -struct Sync2Instance -{ - CellSync2CallerThreadType gCellSync2CallerThreadTypePpuThread; - CellSync2Notifier gCellSync2NotifierPpuThread; - CellSync2CallerThreadType gCellSync2CallerThreadTypePpuFiber; - CellSync2Notifier gCellSync2NotifierPpuFiber; - CellSync2Notifier gCellSync2NotifierSpursTask; - CellSync2Notifier gCellSync2NotifierSpursJobQueueJob; -}; +LOG_CHANNEL(cellSync2); -extern Module cellSync2; +vm::gvar gCellSync2CallerThreadTypePpuThread; +vm::gvar gCellSync2NotifierPpuThread; +vm::gvar gCellSync2CallerThreadTypePpuFiber; +vm::gvar gCellSync2NotifierPpuFiber; +vm::gvar gCellSync2NotifierSpursTask; +vm::gvar gCellSync2NotifierSpursJobQueueJob; s32 _cellSync2MutexAttributeInitialize(vm::ptr attr, u32 sdkVersion) { @@ -259,14 +255,14 @@ s32 cellSync2QueueGetDepth() return CELL_OK; } -Module cellSync2("cellSync2", []() +DECLARE(ppu_module_manager::cellSync2)("cellSync2", []() { - REG_VARIABLE(cellSync2, gCellSync2CallerThreadTypePpuThread); - REG_VARIABLE(cellSync2, gCellSync2NotifierPpuThread); - REG_VARIABLE(cellSync2, gCellSync2CallerThreadTypePpuFiber); - REG_VARIABLE(cellSync2, gCellSync2NotifierPpuFiber); - REG_VARIABLE(cellSync2, gCellSync2NotifierSpursTask); - REG_VARIABLE(cellSync2, gCellSync2NotifierSpursJobQueueJob); + REG_VAR(cellSync2, gCellSync2CallerThreadTypePpuThread); + REG_VAR(cellSync2, gCellSync2NotifierPpuThread); + REG_VAR(cellSync2, gCellSync2CallerThreadTypePpuFiber); + REG_VAR(cellSync2, gCellSync2NotifierPpuFiber); + REG_VAR(cellSync2, gCellSync2NotifierSpursTask); + REG_VAR(cellSync2, gCellSync2NotifierSpursJobQueueJob); REG_FUNC(cellSync2, _cellSync2MutexAttributeInitialize); REG_FUNC(cellSync2, cellSync2MutexEstimateBufferSize); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSync2.h b/rpcs3/Emu/Cell/Modules/cellSync2.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellSync2.h rename to rpcs3/Emu/Cell/Modules/cellSync2.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellSysconf.cpp b/rpcs3/Emu/Cell/Modules/cellSysconf.cpp similarity index 58% rename from rpcs3/Emu/SysCalls/Modules/cellSysconf.cpp rename to rpcs3/Emu/Cell/Modules/cellSysconf.cpp index 9a3a55f788..3685f8f1ef 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSysconf.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSysconf.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellSysconf; +LOG_CHANNEL(cellSysconf); s32 cellSysconfAbort() { @@ -21,13 +20,11 @@ s32 cellSysconfBtGetDeviceList() void cellSysutil_Sysconf_init() { - extern Module<> cellSysutil; - REG_FUNC(cellSysutil, cellSysconfAbort); REG_FUNC(cellSysutil, cellSysconfOpen); } -Module<> cellSysconf("cellSysconf", []() +DECLARE(ppu_module_manager::cellSysconf)("cellSysconfExtUtility", []() { - REG_FUNC(cellSysconf, cellSysconfBtGetDeviceList); + REG_FUNC(cellSysconfExtUtility, cellSysconfBtGetDeviceList); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSysmodule.cpp b/rpcs3/Emu/Cell/Modules/cellSysmodule.cpp similarity index 53% rename from rpcs3/Emu/SysCalls/Modules/cellSysmodule.cpp rename to rpcs3/Emu/Cell/Modules/cellSysmodule.cpp index f5fe1b2230..c8ffe495d0 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSysmodule.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSysmodule.cpp @@ -1,221 +1,357 @@ -#include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/System.h" -#include "Emu/SysCalls/ModuleManager.h" -#include "Emu/SysCalls/Modules.h" - -extern Module<> cellSysmodule; - -enum -{ - CELL_SYSMODULE_LOADED = CELL_OK, - CELL_SYSMODULE_ERROR_DUPLICATED = 0x80012001, - CELL_SYSMODULE_ERROR_UNKNOWN = 0x80012002, - CELL_SYSMODULE_ERROR_UNLOADED = 0x80012003, - CELL_SYSMODULE_ERROR_INVALID_MEMCONTAINER = 0x80012004, - CELL_SYSMODULE_ERROR_FATAL = 0x800120ff, -}; - -const char* get_module_id(u16 id) -{ - switch (id) - { - case 0x0000: return "CELL_SYSMODULE_NET"; - case 0x0001: return "CELL_SYSMODULE_HTTP"; - case 0x0002: return "CELL_SYSMODULE_HTTP_UTIL"; - case 0x0003: return "CELL_SYSMODULE_SSL"; - case 0x0004: return "CELL_SYSMODULE_HTTPS"; - case 0x0005: return "CELL_SYSMODULE_VDEC"; - case 0x0006: return "CELL_SYSMODULE_ADEC"; - case 0x0007: return "CELL_SYSMODULE_DMUX"; - case 0x0008: return "CELL_SYSMODULE_VPOST"; - case 0x0009: return "CELL_SYSMODULE_RTC"; - case 0x000a: return "CELL_SYSMODULE_SPURS"; - case 0x000b: return "CELL_SYSMODULE_OVIS"; - case 0x000c: return "CELL_SYSMODULE_SHEAP"; - case 0x000d: return "CELL_SYSMODULE_SYNC"; - case 0x000e: return "CELL_SYSMODULE_FS"; - case 0x000f: return "CELL_SYSMODULE_JPGDEC"; - case 0x0010: return "CELL_SYSMODULE_GCM_SYS"; - case 0x0011: return "CELL_SYSMODULE_AUDIO"; - case 0x0012: return "CELL_SYSMODULE_PAMF"; - case 0x0013: return "CELL_SYSMODULE_ATRAC3PLUS"; - case 0x0014: return "CELL_SYSMODULE_NETCTL"; - case 0x0015: return "CELL_SYSMODULE_SYSUTIL"; - case 0x0016: return "CELL_SYSMODULE_SYSUTIL_NP"; - case 0x0017: return "CELL_SYSMODULE_IO"; - case 0x0018: return "CELL_SYSMODULE_PNGDEC"; - case 0x0019: return "CELL_SYSMODULE_FONT"; - case 0x001a: return "CELL_SYSMODULE_FONTFT"; - case 0x001b: return "CELL_SYSMODULE_FREETYPE"; - case 0x001c: return "CELL_SYSMODULE_USBD"; - case 0x001d: return "CELL_SYSMODULE_SAIL"; - case 0x001e: return "CELL_SYSMODULE_L10N"; - case 0x001f: return "CELL_SYSMODULE_RESC"; - case 0x0020: return "CELL_SYSMODULE_DAISY"; - case 0x0021: return "CELL_SYSMODULE_KEY2CHAR"; - case 0x0022: return "CELL_SYSMODULE_MIC"; - case 0x0023: return "CELL_SYSMODULE_CAMERA"; - case 0x0024: return "CELL_SYSMODULE_VDEC_MPEG2"; - case 0x0025: return "CELL_SYSMODULE_VDEC_AVC"; - case 0x0026: return "CELL_SYSMODULE_ADEC_LPCM"; - case 0x0027: return "CELL_SYSMODULE_ADEC_AC3"; - case 0x0028: return "CELL_SYSMODULE_ADEC_ATX"; - case 0x0029: return "CELL_SYSMODULE_ADEC_AT3"; - case 0x002a: return "CELL_SYSMODULE_DMUX_PAMF"; - case 0x002b: return "CELL_SYSMODULE_VDEC_AL"; - case 0x002c: return "CELL_SYSMODULE_ADEC_AL"; - case 0x002d: return "CELL_SYSMODULE_DMUX_AL"; - case 0x002e: return "CELL_SYSMODULE_LV2DBG"; - case 0x002f: return "CELL_SYSMODULE_SYSUTIL_AVCHAT"; - case 0x0030: return "CELL_SYSMODULE_USBPSPCM"; - case 0x0031: return "CELL_SYSMODULE_AVCONF_EXT"; - case 0x0032: return "CELL_SYSMODULE_SYSUTIL_USERINFO"; - case 0x0033: return "CELL_SYSMODULE_SYSUTIL_SAVEDATA"; - case 0x0034: return "CELL_SYSMODULE_SUBDISPLAY"; - case 0x0035: return "CELL_SYSMODULE_SYSUTIL_REC"; - case 0x0036: return "CELL_SYSMODULE_VIDEO_EXPORT"; - case 0x0037: return "CELL_SYSMODULE_SYSUTIL_GAME_EXEC"; - case 0x0038: return "CELL_SYSMODULE_SYSUTIL_NP2"; - case 0x0039: return "CELL_SYSMODULE_SYSUTIL_AP"; - case 0x003a: return "CELL_SYSMODULE_SYSUTIL_NP_CLANS"; - case 0x003b: return "CELL_SYSMODULE_SYSUTIL_OSK_EXT"; - case 0x003c: return "CELL_SYSMODULE_VDEC_DIVX"; - case 0x003d: return "CELL_SYSMODULE_JPGENC"; - case 0x003e: return "CELL_SYSMODULE_SYSUTIL_GAME"; - case 0x003f: return "CELL_SYSMODULE_BGDL"; - case 0x0040: return "CELL_SYSMODULE_FREETYPE_TT"; - case 0x0041: return "CELL_SYSMODULE_SYSUTIL_VIDEO_UPLOAD"; - case 0x0042: return "CELL_SYSMODULE_SYSUTIL_SYSCONF_EXT"; - case 0x0043: return "CELL_SYSMODULE_FIBER"; - case 0x0044: return "CELL_SYSMODULE_SYSUTIL_NP_COMMERCE2"; - case 0x0045: return "CELL_SYSMODULE_SYSUTIL_NP_TUS"; - case 0x0046: return "CELL_SYSMODULE_VOICE"; - case 0x0047: return "CELL_SYSMODULE_ADEC_CELP8"; - case 0x0048: return "CELL_SYSMODULE_CELP8ENC"; - case 0x0049: return "CELL_SYSMODULE_SYSUTIL_LICENSEAREA"; - case 0x004a: return "CELL_SYSMODULE_SYSUTIL_MUSIC2"; - case 0x004e: return "CELL_SYSMODULE_SYSUTIL_SCREENSHOT"; - case 0x004f: return "CELL_SYSMODULE_SYSUTIL_MUSIC_DECODE"; - case 0x0050: return "CELL_SYSMODULE_SPURS_JQ"; - case 0x0052: return "CELL_SYSMODULE_PNGENC"; - case 0x0053: return "CELL_SYSMODULE_SYSUTIL_MUSIC_DECODE2"; - case 0x0055: return "CELL_SYSMODULE_SYNC2"; - case 0x0056: return "CELL_SYSMODULE_SYSUTIL_NP_UTIL"; - case 0x0057: return "CELL_SYSMODULE_RUDP"; - case 0x0059: return "CELL_SYSMODULE_SYSUTIL_NP_SNS"; - case 0x005a: return "CELL_SYSMODULE_GEM"; - case 0xf00a: return "CELL_SYSMODULE_CELPENC"; - case 0xf010: return "CELL_SYSMODULE_GIFDEC"; - case 0xf019: return "CELL_SYSMODULE_ADEC_CELP"; - case 0xf01b: return "CELL_SYSMODULE_ADEC_M2BC"; - case 0xf01d: return "CELL_SYSMODULE_ADEC_M4AAC"; - case 0xf01e: return "CELL_SYSMODULE_ADEC_MP3"; - case 0xf023: return "CELL_SYSMODULE_IMEJP"; - case 0xf028: return "CELL_SYSMODULE_SYSUTIL_MUSIC"; - case 0xf029: return "CELL_SYSMODULE_PHOTO_EXPORT"; - case 0xf02a: return "CELL_SYSMODULE_PRINT"; - case 0xf02b: return "CELL_SYSMODULE_PHOTO_IMPORT"; - case 0xf02c: return "CELL_SYSMODULE_MUSIC_EXPORT"; - case 0xf02e: return "CELL_SYSMODULE_PHOTO_DECODE"; - case 0xf02f: return "CELL_SYSMODULE_SYSUTIL_SEARCH"; - case 0xf030: return "CELL_SYSMODULE_SYSUTIL_AVCHAT2"; - case 0xf034: return "CELL_SYSMODULE_SAIL_REC"; - case 0xf035: return "CELL_SYSMODULE_SYSUTIL_NP_TROPHY"; - case 0xf054: return "CELL_SYSMODULE_LIBATRAC3MULTI"; - case 0xffff: return "CELL_SYSMODULE_INVALID"; - } - - return "UNKNOWN MODULE"; -} - -s32 cellSysmoduleInitialize() -{ - cellSysmodule.warning("cellSysmoduleInitialize()"); - return CELL_OK; -} - -s32 cellSysmoduleFinalize() -{ - cellSysmodule.warning("cellSysmoduleFinalize()"); - return CELL_OK; -} - -s32 cellSysmoduleSetMemcontainer(u32 ct_id) -{ - cellSysmodule.todo("cellSysmoduleSetMemcontainer(ct_id=0x%x)", ct_id); - return CELL_OK; -} - -s32 cellSysmoduleLoadModule(u16 id) -{ - cellSysmodule.warning("cellSysmoduleLoadModule(id=0x%04x: %s)", id, get_module_id(id)); - - if (!Emu.GetModuleManager().CheckModuleId(id)) - { - return CELL_SYSMODULE_ERROR_UNKNOWN; - } - - if (Module<>* m = Emu.GetModuleManager().GetModuleById(id)) - { - // CELL_SYSMODULE_ERROR_DUPLICATED shouldn't be returned - m->Load(); - } - - return CELL_OK; -} - -s32 cellSysmoduleUnloadModule(u16 id) -{ - cellSysmodule.warning("cellSysmoduleUnloadModule(id=0x%04x: %s)", id, get_module_id(id)); - - if (!Emu.GetModuleManager().CheckModuleId(id)) - { - return CELL_SYSMODULE_ERROR_UNKNOWN; - } - - if (Module<>* m = Emu.GetModuleManager().GetModuleById(id)) - { - if (!m->IsLoaded()) - { - cellSysmodule.error("cellSysmoduleUnloadModule() failed: module not loaded (id=0x%04x)", id); - return CELL_SYSMODULE_ERROR_FATAL; - } - - m->Unload(); - } - - return CELL_OK; -} - -s32 cellSysmoduleIsLoaded(u16 id) -{ - cellSysmodule.warning("cellSysmoduleIsLoaded(id=0x%04x: %s)", id, get_module_id(id)); - - if (!Emu.GetModuleManager().CheckModuleId(id)) - { - cellSysmodule.error("cellSysmoduleIsLoaded(): unknown module (id=0x%04x)", id); - return CELL_SYSMODULE_ERROR_UNKNOWN; - } - - if (Module<>* m = Emu.GetModuleManager().GetModuleById(id)) - { - if (!m->IsLoaded()) - { - cellSysmodule.warning("cellSysmoduleIsLoaded(): module not loaded (id=0x%04x)", id); - return CELL_SYSMODULE_ERROR_UNLOADED; - } - } - - return CELL_SYSMODULE_LOADED; -} - -Module<> cellSysmodule("cellSysmodule", []() -{ - REG_FUNC(cellSysmodule, cellSysmoduleInitialize); - REG_FUNC(cellSysmodule, cellSysmoduleFinalize); - REG_FUNC(cellSysmodule, cellSysmoduleSetMemcontainer); - REG_FUNC(cellSysmodule, cellSysmoduleLoadModule); - REG_FUNC(cellSysmodule, cellSysmoduleUnloadModule); - REG_FUNC(cellSysmodule, cellSysmoduleIsLoaded); -}); +#include "stdafx.h" +#include "Emu/System.h" +#include "Emu/Cell/PPUModule.h" + +LOG_CHANNEL(cellSysmodule); + +enum +{ + CELL_SYSMODULE_LOADED = CELL_OK, + CELL_SYSMODULE_ERROR_DUPLICATED = 0x80012001, + CELL_SYSMODULE_ERROR_UNKNOWN = 0x80012002, + CELL_SYSMODULE_ERROR_UNLOADED = 0x80012003, + CELL_SYSMODULE_ERROR_INVALID_MEMCONTAINER = 0x80012004, + CELL_SYSMODULE_ERROR_FATAL = 0x800120ff, +}; + +static const char* get_module_name(u16 id) +{ + switch (id) + { + case 0x0000: return "sys_net"; + case 0x0001: return "cellHttp"; + case 0x0002: return "cellHttpUtil"; + case 0x0003: return "cellSsl"; + case 0x0004: return "cellHttps"; + case 0x0005: return "libvdec"; + case 0x0006: return "cellAdec"; + case 0x0007: return "cellDmux"; + case 0x0008: return "cellVpost"; + case 0x0009: return "cellRtc"; + case 0x000a: return "cellSpurs"; + case 0x000b: return "cellOvis"; + case 0x000c: return "cellSheap"; + case 0x000d: return "cellSync"; + case 0x000e: return "sys_fs"; + case 0x000f: return "cellJpgDec"; + case 0x0010: return "cellGcmSys"; + case 0x0011: return "cellAudio"; + case 0x0012: return "cellPamf"; + case 0x0013: return "cellAtrac"; + case 0x0014: return "cellNetCtl"; + case 0x0015: return "cellSysutil"; + case 0x0016: return "sceNp"; + case 0x0017: return "sys_io"; + case 0x0018: return "cellPngDec"; + case 0x0019: return "cellFont"; + case 0x001a: return "cellFontFT"; + case 0x001b: return "cell_FreeType2"; + case 0x001c: return "cellUsbd"; + case 0x001d: return "cellSail"; + case 0x001e: return "cellL10n"; + case 0x001f: return "cellResc"; + case 0x0020: return "cellDaisy"; + case 0x0021: return "cellKey2char"; + case 0x0022: return "cellMic"; + case 0x0023: return "cellCamera"; + case 0x0024: return "cellVdecMpeg2"; + case 0x0025: return "cellVdecAvc"; + case 0x0026: return "cellAdecLpcm"; + case 0x0027: return "cellAdecAc3"; + case 0x0028: return "cellAdecAtx"; + case 0x0029: return "cellAdecAt3"; + case 0x002a: return "cellDmuxPamf"; + case 0x002b: return nullptr; + case 0x002c: return nullptr; + case 0x002d: return nullptr; + case 0x002e: return "sys_lv2dbg"; + case 0x002f: return "cellSysutilAvcExt"; + case 0x0030: return "cellUsbPspcm"; + case 0x0031: return "cellSysutilAvconfExt"; + case 0x0032: return "cellUserInfo"; + case 0x0033: return "cellSaveData"; + case 0x0034: return "cellSubDisplay"; + case 0x0035: return "cellRec"; + case 0x0036: return "cellVideoExportUtility"; + case 0x0037: return "cellGameExec"; + case 0x0038: return "sceNp2"; + case 0x0039: return "cellSysutilAp"; + case 0x003a: return "sceNpClans"; + case 0x003b: return "cellOskExtUtility"; + case 0x003c: return "cellVdecDivx"; + case 0x003d: return "cellJpgEnc"; + case 0x003e: return "cellGame"; + case 0x003f: return "cellBGDLUtility"; + case 0x0040: return "cell_FreeType2"; + case 0x0041: return "cellVideoUpload"; + case 0x0042: return "cellSysconfExtUtility"; + case 0x0043: return "cellFiber"; + case 0x0044: return "sceNpCommerce2"; + case 0x0045: return "sceNpTus"; + case 0x0046: return "cellVoice"; + case 0x0047: return "cellAdecCelp8"; + case 0x0048: return "cellCelp8Enc"; + case 0x0049: return "cellSysutilMisc"; + case 0x004a: return "cellMusicUtility"; + case 0x004e: return "cellScreenShotUtility"; + case 0x004f: return "cellMusicDecodeUtility"; + case 0x0050: return "cellSpursJq"; + case 0x0052: return "cellPngEnc"; + case 0x0053: return "cellMusicDecodeUtility"; + case 0x0055: return "cellSync2"; + case 0x0056: return "sceNpUtil"; + case 0x0057: return "cellRudp"; + case 0x0059: return "sceNpSns"; + case 0x005a: return "libgem"; + case 0xf00a: return "cellCelpEnc"; + case 0xf010: return "cellGifDec"; + case 0xf019: return "cellAdecCelp"; + case 0xf01b: return "cellAdecM2bc"; + case 0xf01d: return "cellAdecM4aac"; + case 0xf01e: return "cellAdecMp3"; + case 0xf023: return "cellImeJpUtility"; + case 0xf028: return "cellMusicUtility"; + case 0xf029: return "cellPhotoUtility"; + case 0xf02a: return "cellPrintUtility"; + case 0xf02b: return "cellPhotoImportUtil"; + case 0xf02c: return "cellMusicExportUtility"; + case 0xf02e: return "cellPhotoDecodeUtil"; + case 0xf02f: return "cellSearchUtility"; + case 0xf030: return "cellSysutilAvc2"; + case 0xf034: return "cellSailRec"; + case 0xf035: return "sceNpTrophy"; + case 0xf053: return "cellAdecAt3multi"; + case 0xf054: return "cellAtracMulti"; + } + + return nullptr; +} + +static const char* get_module_id(u16 id) +{ + thread_local static char tls_id_name[8]; // for test + + switch (id) + { + case 0x0000: return "CELL_SYSMODULE_NET"; + case 0x0001: return "CELL_SYSMODULE_HTTP"; + case 0x0002: return "CELL_SYSMODULE_HTTP_UTIL"; + case 0x0003: return "CELL_SYSMODULE_SSL"; + case 0x0004: return "CELL_SYSMODULE_HTTPS"; + case 0x0005: return "CELL_SYSMODULE_VDEC"; + case 0x0006: return "CELL_SYSMODULE_ADEC"; + case 0x0007: return "CELL_SYSMODULE_DMUX"; + case 0x0008: return "CELL_SYSMODULE_VPOST"; + case 0x0009: return "CELL_SYSMODULE_RTC"; + case 0x000a: return "CELL_SYSMODULE_SPURS"; + case 0x000b: return "CELL_SYSMODULE_OVIS"; + case 0x000c: return "CELL_SYSMODULE_SHEAP"; + case 0x000d: return "CELL_SYSMODULE_SYNC"; + case 0x000e: return "CELL_SYSMODULE_FS"; + case 0x000f: return "CELL_SYSMODULE_JPGDEC"; + case 0x0010: return "CELL_SYSMODULE_GCM_SYS"; + case 0x0011: return "CELL_SYSMODULE_AUDIO"; + case 0x0012: return "CELL_SYSMODULE_PAMF"; + case 0x0013: return "CELL_SYSMODULE_ATRAC3PLUS"; + case 0x0014: return "CELL_SYSMODULE_NETCTL"; + case 0x0015: return "CELL_SYSMODULE_SYSUTIL"; + case 0x0016: return "CELL_SYSMODULE_SYSUTIL_NP"; + case 0x0017: return "CELL_SYSMODULE_IO"; + case 0x0018: return "CELL_SYSMODULE_PNGDEC"; + case 0x0019: return "CELL_SYSMODULE_FONT"; + case 0x001a: return "CELL_SYSMODULE_FONTFT"; + case 0x001b: return "CELL_SYSMODULE_FREETYPE"; + case 0x001c: return "CELL_SYSMODULE_USBD"; + case 0x001d: return "CELL_SYSMODULE_SAIL"; + case 0x001e: return "CELL_SYSMODULE_L10N"; + case 0x001f: return "CELL_SYSMODULE_RESC"; + case 0x0020: return "CELL_SYSMODULE_DAISY"; + case 0x0021: return "CELL_SYSMODULE_KEY2CHAR"; + case 0x0022: return "CELL_SYSMODULE_MIC"; + case 0x0023: return "CELL_SYSMODULE_CAMERA"; + case 0x0024: return "CELL_SYSMODULE_VDEC_MPEG2"; + case 0x0025: return "CELL_SYSMODULE_VDEC_AVC"; + case 0x0026: return "CELL_SYSMODULE_ADEC_LPCM"; + case 0x0027: return "CELL_SYSMODULE_ADEC_AC3"; + case 0x0028: return "CELL_SYSMODULE_ADEC_ATX"; + case 0x0029: return "CELL_SYSMODULE_ADEC_AT3"; + case 0x002a: return "CELL_SYSMODULE_DMUX_PAMF"; + case 0x002b: return "CELL_SYSMODULE_VDEC_AL"; + case 0x002c: return "CELL_SYSMODULE_ADEC_AL"; + case 0x002d: return "CELL_SYSMODULE_DMUX_AL"; + case 0x002e: return "CELL_SYSMODULE_LV2DBG"; + case 0x002f: return "CELL_SYSMODULE_SYSUTIL_AVCHAT"; + case 0x0030: return "CELL_SYSMODULE_USBPSPCM"; + case 0x0031: return "CELL_SYSMODULE_AVCONF_EXT"; + case 0x0032: return "CELL_SYSMODULE_SYSUTIL_USERINFO"; + case 0x0033: return "CELL_SYSMODULE_SYSUTIL_SAVEDATA"; + case 0x0034: return "CELL_SYSMODULE_SUBDISPLAY"; + case 0x0035: return "CELL_SYSMODULE_SYSUTIL_REC"; + case 0x0036: return "CELL_SYSMODULE_VIDEO_EXPORT"; + case 0x0037: return "CELL_SYSMODULE_SYSUTIL_GAME_EXEC"; + case 0x0038: return "CELL_SYSMODULE_SYSUTIL_NP2"; + case 0x0039: return "CELL_SYSMODULE_SYSUTIL_AP"; + case 0x003a: return "CELL_SYSMODULE_SYSUTIL_NP_CLANS"; + case 0x003b: return "CELL_SYSMODULE_SYSUTIL_OSK_EXT"; + case 0x003c: return "CELL_SYSMODULE_VDEC_DIVX"; + case 0x003d: return "CELL_SYSMODULE_JPGENC"; + case 0x003e: return "CELL_SYSMODULE_SYSUTIL_GAME"; + case 0x003f: return "CELL_SYSMODULE_BGDL"; + case 0x0040: return "CELL_SYSMODULE_FREETYPE_TT"; + case 0x0041: return "CELL_SYSMODULE_SYSUTIL_VIDEO_UPLOAD"; + case 0x0042: return "CELL_SYSMODULE_SYSUTIL_SYSCONF_EXT"; + case 0x0043: return "CELL_SYSMODULE_FIBER"; + case 0x0044: return "CELL_SYSMODULE_SYSUTIL_NP_COMMERCE2"; + case 0x0045: return "CELL_SYSMODULE_SYSUTIL_NP_TUS"; + case 0x0046: return "CELL_SYSMODULE_VOICE"; + case 0x0047: return "CELL_SYSMODULE_ADEC_CELP8"; + case 0x0048: return "CELL_SYSMODULE_CELP8ENC"; + case 0x0049: return "CELL_SYSMODULE_SYSUTIL_LICENSEAREA"; + case 0x004a: return "CELL_SYSMODULE_SYSUTIL_MUSIC2"; + case 0x004e: return "CELL_SYSMODULE_SYSUTIL_SCREENSHOT"; + case 0x004f: return "CELL_SYSMODULE_SYSUTIL_MUSIC_DECODE"; + case 0x0050: return "CELL_SYSMODULE_SPURS_JQ"; + case 0x0052: return "CELL_SYSMODULE_PNGENC"; + case 0x0053: return "CELL_SYSMODULE_SYSUTIL_MUSIC_DECODE2"; + case 0x0055: return "CELL_SYSMODULE_SYNC2"; + case 0x0056: return "CELL_SYSMODULE_SYSUTIL_NP_UTIL"; + case 0x0057: return "CELL_SYSMODULE_RUDP"; + case 0x0059: return "CELL_SYSMODULE_SYSUTIL_NP_SNS"; + case 0x005a: return "CELL_SYSMODULE_GEM"; + case 0xf00a: return "CELL_SYSMODULE_CELPENC"; + case 0xf010: return "CELL_SYSMODULE_GIFDEC"; + case 0xf019: return "CELL_SYSMODULE_ADEC_CELP"; + case 0xf01b: return "CELL_SYSMODULE_ADEC_M2BC"; + case 0xf01d: return "CELL_SYSMODULE_ADEC_M4AAC"; + case 0xf01e: return "CELL_SYSMODULE_ADEC_MP3"; + case 0xf023: return "CELL_SYSMODULE_IMEJP"; + case 0xf028: return "CELL_SYSMODULE_SYSUTIL_MUSIC"; + case 0xf029: return "CELL_SYSMODULE_PHOTO_EXPORT"; + case 0xf02a: return "CELL_SYSMODULE_PRINT"; + case 0xf02b: return "CELL_SYSMODULE_PHOTO_IMPORT"; + case 0xf02c: return "CELL_SYSMODULE_MUSIC_EXPORT"; + case 0xf02e: return "CELL_SYSMODULE_PHOTO_DECODE"; + case 0xf02f: return "CELL_SYSMODULE_SYSUTIL_SEARCH"; + case 0xf030: return "CELL_SYSMODULE_SYSUTIL_AVCHAT2"; + case 0xf034: return "CELL_SYSMODULE_SAIL_REC"; + case 0xf035: return "CELL_SYSMODULE_SYSUTIL_NP_TROPHY"; + case 0xf054: return "CELL_SYSMODULE_LIBATRAC3MULTI"; + case 0xffff: return "CELL_SYSMODULE_INVALID"; + } + + std::snprintf(tls_id_name, sizeof(tls_id_name), "0x%04X", id); + return tls_id_name; +} + +s32 cellSysmoduleInitialize() +{ + cellSysmodule.warning("cellSysmoduleInitialize()"); + return CELL_OK; +} + +s32 cellSysmoduleFinalize() +{ + cellSysmodule.warning("cellSysmoduleFinalize()"); + return CELL_OK; +} + +s32 cellSysmoduleSetMemcontainer(u32 ct_id) +{ + cellSysmodule.todo("cellSysmoduleSetMemcontainer(ct_id=0x%x)", ct_id); + return CELL_OK; +} + +s32 cellSysmoduleLoadModule(u16 id) +{ + cellSysmodule.warning("cellSysmoduleLoadModule(id=%s)", get_module_id(id)); + + const auto name = get_module_name(id); + + if (!name) + { + cellSysmodule.error("cellSysmoduleLoadModule() failed: unknown module 0x%04X", id); + return CELL_SYSMODULE_ERROR_UNKNOWN; + } + + //if (Module<>* m = Emu.GetModuleManager().GetModuleById(id)) + //{ + // // CELL_SYSMODULE_ERROR_DUPLICATED shouldn't be returned + // m->Load(); + //} + + return CELL_OK; +} + +s32 cellSysmoduleUnloadModule(u16 id) +{ + cellSysmodule.warning("cellSysmoduleUnloadModule(id=%s)", get_module_id(id)); + + const auto name = get_module_name(id); + + if (!name) + { + cellSysmodule.error("cellSysmoduleUnloadModule() failed: unknown module 0x%04X", id); + return CELL_SYSMODULE_ERROR_UNKNOWN; + } + + //if (Module<>* m = Emu.GetModuleManager().GetModuleById(id)) + //{ + // if (!m->IsLoaded()) + // { + // cellSysmodule.error("cellSysmoduleUnloadModule() failed: module not loaded (id=0x%04x)", id); + // return CELL_SYSMODULE_ERROR_FATAL; + // } + + // m->Unload(); + //} + + return CELL_OK; +} + +s32 cellSysmoduleIsLoaded(u16 id) +{ + cellSysmodule.warning("cellSysmoduleIsLoaded(id=%s)", get_module_id(id)); + + const auto name = get_module_name(id); + + if (!name) + { + cellSysmodule.error("cellSysmoduleIsLoaded() failed: unknown module 0x%04X", id); + return CELL_SYSMODULE_ERROR_UNKNOWN; + } + + //if (Module<>* m = Emu.GetModuleManager().GetModuleById(id)) + //{ + // if (!m->IsLoaded()) + // { + // cellSysmodule.warning("cellSysmoduleIsLoaded(): module not loaded (id=0x%04x)", id); + // return CELL_SYSMODULE_ERROR_UNLOADED; + // } + //} + + return CELL_SYSMODULE_LOADED; +} + +s32 cellSysmoduleGetImagesize() +{ + UNIMPLEMENTED_FUNC(cellSysmodule); + return CELL_OK; +} + +s32 cellSysmoduleFetchImage() +{ + UNIMPLEMENTED_FUNC(cellSysmodule); + return CELL_OK; +} + +DECLARE(ppu_module_manager::cellSysmodule)("cellSysmodule", []() +{ + REG_FUNC(cellSysmodule, cellSysmoduleInitialize); + REG_FUNC(cellSysmodule, cellSysmoduleFinalize); + REG_FUNC(cellSysmodule, cellSysmoduleSetMemcontainer); + REG_FUNC(cellSysmodule, cellSysmoduleLoadModule); + REG_FUNC(cellSysmodule, cellSysmoduleUnloadModule); + REG_FUNC(cellSysmodule, cellSysmoduleIsLoaded); + REG_FUNC(cellSysmodule, cellSysmoduleGetImagesize); + REG_FUNC(cellSysmodule, cellSysmoduleFetchImage); +}); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp b/rpcs3/Emu/Cell/Modules/cellSysutil.cpp similarity index 76% rename from rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp rename to rpcs3/Emu/Cell/Modules/cellSysutil.cpp index 048dd4625c..ecf5c77899 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSysutil.cpp @@ -1,19 +1,60 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/state.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/SysCalls/Callback.h" +#include "Emu/IdManager.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/FS/VFS.h" #include "cellSysutil.h" -extern Module<> cellSysutil; +LOG_CHANNEL(cellSysutil); -std::unique_ptr g_sysutil; +// Temporarily +using sys_callbacks_t = std::array, vm::ptr>, 4>; -const char* get_systemparam_id_name(s32 id) +void sysutilSendSystemCommand(u64 status, u64 param) { + if (const auto g_sys_callback = fxm::get()) + { + for (auto& cb : *g_sys_callback) + { + if (cb.first) + { + Emu.GetCallbackManager().Register([=](PPUThread& ppu) -> s32 + { + // TODO: check it and find the source of the return value (void isn't equal to CELL_OK) + cb.first(ppu, status, param, cb.second); + return CELL_OK; + }); + } + } + } +} + +cfg::map_entry g_cfg_sys_language(cfg::root.sys, "Language", +{ + { "Japanese", CELL_SYSUTIL_LANG_JAPANESE }, + { "English (US)", CELL_SYSUTIL_LANG_ENGLISH_US }, + { "French", CELL_SYSUTIL_LANG_FRENCH }, + { "Spanish", CELL_SYSUTIL_LANG_SPANISH }, + { "German", CELL_SYSUTIL_LANG_GERMAN }, + { "Italian", CELL_SYSUTIL_LANG_ITALIAN }, + { "Dutch", CELL_SYSUTIL_LANG_DUTCH }, + { "Portuguese (PT)", CELL_SYSUTIL_LANG_PORTUGUESE_PT }, + { "Russian", CELL_SYSUTIL_LANG_RUSSIAN }, + { "Korean", CELL_SYSUTIL_LANG_KOREAN }, + { "Chinese (Trad.)", CELL_SYSUTIL_LANG_CHINESE_T }, + { "Chinese (Simp.)", CELL_SYSUTIL_LANG_CHINESE_S }, + { "Finnish", CELL_SYSUTIL_LANG_FINNISH }, + { "Swedish", CELL_SYSUTIL_LANG_SWEDISH }, + { "Danish", CELL_SYSUTIL_LANG_DANISH }, + { "Norwegian", CELL_SYSUTIL_LANG_NORWEGIAN }, + { "Polish", CELL_SYSUTIL_LANG_POLISH }, + { "English (UK)", CELL_SYSUTIL_LANG_ENGLISH_GB }, +}); + +static const char* get_systemparam_id_name(s32 id) +{ + thread_local static char tls_id_name[16]; // for test + switch (id) { case CELL_SYSUTIL_SYSTEMPARAM_ID_LANG: return "ID_LANG"; @@ -33,18 +74,22 @@ const char* get_systemparam_id_name(s32 id) case CELL_SYSUTIL_SYSTEMPARAM_ID_PAD_AUTOOFF: return "ID_PAD_AUTOOFF"; case CELL_SYSUTIL_SYSTEMPARAM_ID_NICKNAME: return "ID_NICKNAME"; case CELL_SYSUTIL_SYSTEMPARAM_ID_CURRENT_USERNAME: return "ID_CURRENT_USERNAME"; - default: return "???"; } + + std::snprintf(tls_id_name, sizeof(tls_id_name), "0x%04X", id); + return tls_id_name; } s32 cellSysutilGetSystemParamInt(s32 id, vm::ptr value) { - cellSysutil.warning("cellSysutilGetSystemParamInt(id=0x%x(%s), value=*0x%x)", id, get_systemparam_id_name(id), value); + cellSysutil.warning("cellSysutilGetSystemParamInt(id=%s, value=*0x%x)", get_systemparam_id_name(id), value); + + // TODO: load this information from config (preferably "sys/" group) switch(id) { case CELL_SYSUTIL_SYSTEMPARAM_ID_LANG: - *value = rpcs3::config.system.language.value(); + *value = g_cfg_sys_language.get(); break; case CELL_SYSUTIL_SYSTEMPARAM_ID_ENTER_BUTTON_ASSIGN: @@ -133,29 +178,6 @@ s32 cellSysutilGetSystemParamString(s32 id, vm::ptr buf, u32 bufsize) return CELL_OK; } -struct sys_callback -{ - vm::ptr func; - vm::ptr arg; -} -g_sys_callback[4]; - -void sysutilSendSystemCommand(u64 status, u64 param) -{ - // TODO: check it and find the source of the return value (void isn't equal to CELL_OK) - for (auto& cb : g_sys_callback) - { - if (cb.func) - { - Emu.GetCallbackManager().Register([=](PPUThread& ppu) -> s32 - { - cb.func(ppu, status, param, cb.arg); - return CELL_OK; - }); - } - } -} - s32 cellSysutilCheckCallback(PPUThread& CPU) { cellSysutil.trace("cellSysutilCheckCallback()"); @@ -177,27 +199,25 @@ s32 cellSysutilRegisterCallback(s32 slot, vm::ptr func, vm: { cellSysutil.warning("cellSysutilRegisterCallback(slot=%d, func=*0x%x, userdata=*0x%x)", slot, func, userdata); - if ((u32)slot > 3) + if (slot >= sys_callbacks_t{}.size()) { return CELL_SYSUTIL_ERROR_VALUE; } - g_sys_callback[slot].func = func; - g_sys_callback[slot].arg = userdata; + fxm::get_always()->at(slot) = std::make_pair(func, userdata); return CELL_OK; } -s32 cellSysutilUnregisterCallback(s32 slot) +s32 cellSysutilUnregisterCallback(u32 slot) { cellSysutil.warning("cellSysutilUnregisterCallback(slot=%d)", slot); - if ((u32)slot > 3) + if (slot >= sys_callbacks_t{}.size()) { return CELL_SYSUTIL_ERROR_VALUE; } - g_sys_callback[slot].func.set(0); - g_sys_callback[slot].arg.set(0); + fxm::get_always()->at(slot) = std::make_pair(vm::null, vm::null); return CELL_OK; } @@ -205,13 +225,12 @@ s32 cellSysCacheClear(void) { cellSysutil.todo("cellSysCacheClear()"); - if (!g_sysutil->cacheMounted) + if (!fxm::check()) { return CELL_SYSCACHE_ERROR_NOTMOUNTED; } - std::string localPath; - Emu.GetVFS().GetDevice("/dev_hdd1/cache/", localPath); + const std::string& local_path = vfs::get("/dev_hdd1/cache/"); // TODO: Write tests to figure out, what is deleted. @@ -222,13 +241,15 @@ s32 cellSysCacheMount(vm::ptr param) { cellSysutil.warning("cellSysCacheMount(param=*0x%x)", param); - // TODO: implement - char id[CELL_SYSCACHE_ID_SIZE] = { '\0' }; - strncpy(id, param->cacheId, CELL_SYSCACHE_ID_SIZE - 1); - strncpy(param->getCachePath, ("/dev_hdd1/cache/"s + id + "/").c_str(), CELL_SYSCACHE_PATH_MAX); - param->getCachePath[CELL_SYSCACHE_PATH_MAX - 1] = '\0'; - Emu.GetVFS().CreateDir(param->getCachePath); - g_sysutil->cacheMounted.exchange(true); + const std::string& cache_id = param->cacheId; + ASSERT(cache_id.size() < sizeof(param->cacheId)); + + const std::string& cache_path = "/dev_hdd1/cache/" + cache_id + '/'; + strcpy_trunc(param->getCachePath, cache_path); + + // TODO: implement (what?) + fs::create_dir(vfs::get(cache_path)); + fxm::make_always(*param); return CELL_SYSCACHE_RET_OK_RELAYED; } @@ -302,7 +323,8 @@ s32 cellSysutilGetBgmPlaybackStatus2(vm::ptr stat s32 cellSysutilSetBgmPlaybackExtraParam() { - throw EXCEPTION(""); + cellSysutil.todo("cellSysutilSetBgmPlaybackExtraParam()"); + return CELL_OK; } s32 cellSysutilRegisterCallbackDispatcher() @@ -351,16 +373,8 @@ extern void cellSysutil_WebBrowser_init(); extern void cellSysutil_AudioOut_init(); extern void cellSysutil_VideoOut_init(); -Module<> cellSysutil("cellSysutil", []() +DECLARE(ppu_module_manager::cellSysutil)("cellSysutil", []() { - g_sysutil = std::make_unique(); - - for (auto& v : g_sys_callback) - { - v.func.set(0); - v.arg.set(0); - } - cellSysutil_SaveData_init(); // cellSaveData functions cellSysutil_GameData_init(); // cellGameData, cellHddGame functions cellSysutil_MsgDialog_init(); // cellMsgDialog functions diff --git a/rpcs3/Emu/SysCalls/Modules/cellSysutil.h b/rpcs3/Emu/Cell/Modules/cellSysutil.h similarity index 97% rename from rpcs3/Emu/SysCalls/Modules/cellSysutil.h rename to rpcs3/Emu/Cell/Modules/cellSysutil.h index 1018ba4d89..69d9c2917d 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSysutil.h +++ b/rpcs3/Emu/Cell/Modules/cellSysutil.h @@ -82,8 +82,6 @@ enum using CellSysutilCallback = void(u64 status, u64 param, vm::ptr userdata); -void sysutilSendSystemCommand(u64 status, u64 param); - enum { CELL_SYSUTIL_ENTER_BUTTON_ASSIGN_CIRCLE = 0, @@ -197,7 +195,4 @@ struct CellSysCacheParam vm::ptr reserved; }; -struct sysutil_t -{ - std::atomic cacheMounted{ false }; -}; +extern void sysutilSendSystemCommand(u64 status, u64 param); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSysutilAp.cpp b/rpcs3/Emu/Cell/Modules/cellSysutilAp.cpp similarity index 87% rename from rpcs3/Emu/SysCalls/Modules/cellSysutilAp.cpp rename to rpcs3/Emu/Cell/Modules/cellSysutilAp.cpp index b2d3947b8d..f8c6d1668f 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSysutilAp.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSysutilAp.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellSysutilAp; +LOG_CHANNEL(cellSysutilAp); // Return Codes enum @@ -35,7 +34,7 @@ s32 cellSysutilApOff() return CELL_OK; } -Module<> cellSysutilAp("cellSysutilAp", []() +DECLARE(ppu_module_manager::cellSysutilAp)("cellSysutilAp", []() { REG_FUNC(cellSysutilAp, cellSysutilApGetRequiredMemSize); REG_FUNC(cellSysutilAp, cellSysutilApOn); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSysutilAvc.cpp b/rpcs3/Emu/Cell/Modules/cellSysutilAvc.cpp similarity index 96% rename from rpcs3/Emu/SysCalls/Modules/cellSysutilAvc.cpp rename to rpcs3/Emu/Cell/Modules/cellSysutilAvc.cpp index b6d132419b..24b78da7b4 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSysutilAvc.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSysutilAvc.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellSysutilAvc; +LOG_CHANNEL(cellSysutilAvc); s32 cellSysutilAvcByeRequest() { @@ -218,8 +217,6 @@ s32 cellSysutilAvcExtGetWindowShowStatus() void cellSysutil_SysutilAvc_init() { - extern Module<> cellSysutil; - REG_FUNC(cellSysutil, cellSysutilAvcByeRequest); REG_FUNC(cellSysutil, cellSysutilAvcCancelByeRequest); REG_FUNC(cellSysutil, cellSysutilAvcCancelJoinRequest); @@ -242,7 +239,7 @@ void cellSysutil_SysutilAvc_init() REG_FUNC(cellSysutil, cellSysutilAvcUnloadAsync); } -Module<> cellSysutilAvc("cellSysutilAvc", []() +DECLARE(ppu_module_manager::cellSysutilAvc)("cellSysutilAvc", []() { REG_FUNC(cellSysutilAvc, cellSysutilAvcExtInitOptionParam); REG_FUNC(cellSysutilAvc, cellSysutilAvcExtSetHideNamePlate); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSysutilAvc2.cpp b/rpcs3/Emu/Cell/Modules/cellSysutilAvc2.cpp similarity index 94% rename from rpcs3/Emu/SysCalls/Modules/cellSysutilAvc2.cpp rename to rpcs3/Emu/Cell/Modules/cellSysutilAvc2.cpp index 97cfb7cb29..c88ffd32d5 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSysutilAvc2.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSysutilAvc2.cpp @@ -1,13 +1,11 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/state.h" +#include "Emu/Cell/PPUModule.h" #include "sceNp.h" #include "sceNp2.h" #include "cellSysutilAvc2.h" -extern Module<> cellSysutilAvc2; +LOG_CHANNEL(cellSysutilAvc2); s32 cellSysutilAvc2GetPlayerInfo() { @@ -133,16 +131,7 @@ s32 cellSysutilAvc2IsCameraAttached(vm::ptr status) { cellSysutilAvc2.todo("cellSysutilAvc2IsCameraAttached()"); - if (rpcs3::config.io.camera.value() == io_camera_state::null) - { - *status = CELL_AVC2_CAMERA_STATUS_DETACHED; - } - else - { - // TODO: We need to check if the camera has been turned on, but this requires further implementation of cellGem/cellCamera. - *status = CELL_AVC2_CAMERA_STATUS_ATTACHED_OFF; - } - + *status = CELL_AVC2_CAMERA_STATUS_DETACHED; return CELL_OK; } @@ -334,7 +323,7 @@ s32 cellSysutilAvc2GetWindowPosition() } -Module<> cellSysutilAvc2("cellSysutilAvc2", []() +DECLARE(ppu_module_manager::cellSysutilAvc2)("cellSysutilAvc2", []() { REG_FUNC(cellSysutilAvc2, cellSysutilAvc2GetPlayerInfo); REG_FUNC(cellSysutilAvc2, cellSysutilAvc2JoinChat); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSysutilAvc2.h b/rpcs3/Emu/Cell/Modules/cellSysutilAvc2.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellSysutilAvc2.h rename to rpcs3/Emu/Cell/Modules/cellSysutilAvc2.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellSysutilMisc.cpp b/rpcs3/Emu/Cell/Modules/cellSysutilMisc.cpp similarity index 86% rename from rpcs3/Emu/SysCalls/Modules/cellSysutilMisc.cpp rename to rpcs3/Emu/Cell/Modules/cellSysutilMisc.cpp index d93bba7751..e009f8e0bc 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSysutilMisc.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSysutilMisc.cpp @@ -1,9 +1,8 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellSysutilMisc; +LOG_CHANNEL(cellSysutilMisc); // License areas enum @@ -33,7 +32,7 @@ s32 cellSysutilGetLicenseArea() } } -Module<> cellSysutilMisc("cellSysutilMisc", []() +DECLARE(ppu_module_manager::cellSysutilMisc)("cellSysutilMisc", []() { REG_FUNC(cellSysutilMisc, cellSysutilGetLicenseArea); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellUsbd.cpp b/rpcs3/Emu/Cell/Modules/cellUsbd.cpp similarity index 96% rename from rpcs3/Emu/SysCalls/Modules/cellUsbd.cpp rename to rpcs3/Emu/Cell/Modules/cellUsbd.cpp index bcd3476fc4..607277c74e 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellUsbd.cpp +++ b/rpcs3/Emu/Cell/Modules/cellUsbd.cpp @@ -1,10 +1,9 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellUsbd.h" -extern Module<> cellUsbd; +LOG_CHANNEL(cellUsbd); s32 cellUsbdInit() { @@ -152,7 +151,7 @@ s32 cellUsbdFreeMemory() return CELL_OK; } -Module<> cellUsbd("cellUsbd", []() +DECLARE(ppu_module_manager::cellUsbd)("cellUsbd", []() { REG_FUNC(cellUsbd, cellUsbdInit); REG_FUNC(cellUsbd, cellUsbdEnd); diff --git a/rpcs3/Emu/SysCalls/Modules/cellUsbd.h b/rpcs3/Emu/Cell/Modules/cellUsbd.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellUsbd.h rename to rpcs3/Emu/Cell/Modules/cellUsbd.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellUsbpspcm.cpp b/rpcs3/Emu/Cell/Modules/cellUsbpspcm.cpp similarity index 96% rename from rpcs3/Emu/SysCalls/Modules/cellUsbpspcm.cpp rename to rpcs3/Emu/Cell/Modules/cellUsbpspcm.cpp index 30a9fe71d1..ccd4cae8bb 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellUsbpspcm.cpp +++ b/rpcs3/Emu/Cell/Modules/cellUsbpspcm.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellUsbPspcm; +LOG_CHANNEL(cellUsbPspcm); // Return Codes enum @@ -183,7 +182,7 @@ s32 cellUsbPspcmCancelWaitData() return CELL_OK; } -Module<> cellUsbPspcm("cellUsbPspcm", []() +DECLARE(ppu_module_manager::cellUsbPspcm)("cellUsbPspcm", []() { REG_FUNC(cellUsbPspcm, cellUsbPspcmInit); REG_FUNC(cellUsbPspcm, cellUsbPspcmEnd); diff --git a/rpcs3/Emu/SysCalls/Modules/cellUserInfo.cpp b/rpcs3/Emu/Cell/Modules/cellUserInfo.cpp similarity index 69% rename from rpcs3/Emu/SysCalls/Modules/cellUserInfo.cpp rename to rpcs3/Emu/Cell/Modules/cellUserInfo.cpp index a868720f4e..facf4365aa 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellUserInfo.cpp +++ b/rpcs3/Emu/Cell/Modules/cellUserInfo.cpp @@ -1,13 +1,10 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsFileBase.h" #include "cellUserInfo.h" -extern Module<> cellUserInfo; +LOG_CHANNEL(cellUserInfo); s32 cellUserInfoGetStat(u32 id, vm::ptr stat) { @@ -22,24 +19,16 @@ s32 cellUserInfoGetStat(u32 id, vm::ptr stat) id = 1; } - char path[256]; - sprintf(path, "/dev_hdd0/home/%08d", id); - if (!Emu.GetVFS().ExistsDir(path)) + const std::string& path = vfs::get(fmt::format("/dev_hdd0/home/%08d/", id)); + if (!fs::is_dir(path)) return CELL_USERINFO_ERROR_NOUSER; - sprintf(path, "/dev_hdd0/home/%08d/localusername", id); - vfsStream* stream = Emu.GetVFS().OpenFile(path, fom::read); - if (!stream || !(stream->IsOpened())) + const fs::file f(path + "localusername"); + if (!f) return CELL_USERINFO_ERROR_INTERNAL; - char name [CELL_USERINFO_USERNAME_SIZE]; - memset(name, 0, CELL_USERINFO_USERNAME_SIZE); - stream->Read(name, CELL_USERINFO_USERNAME_SIZE); - stream->Close(); - delete stream; - stat->id = id; - memcpy(stat->name, name, CELL_USERINFO_USERNAME_SIZE); + strcpy_trunc(stat->name, f.to_string()); return CELL_OK; } @@ -79,7 +68,7 @@ s32 cellUserInfoGetList(vm::ptr listNum, vm::ptr list return CELL_OK; } -Module<> cellUserInfo("cellUserInfo", []() +DECLARE(ppu_module_manager::cellUserInfo)("cellUserInfo", []() { REG_FUNC(cellUserInfo, cellUserInfoGetStat); REG_FUNC(cellUserInfo, cellUserInfoSelectUser_ListType); diff --git a/rpcs3/Emu/SysCalls/Modules/cellUserInfo.h b/rpcs3/Emu/Cell/Modules/cellUserInfo.h similarity index 73% rename from rpcs3/Emu/SysCalls/Modules/cellUserInfo.h rename to rpcs3/Emu/Cell/Modules/cellUserInfo.h index a06391519c..a9a77159c0 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellUserInfo.h +++ b/rpcs3/Emu/Cell/Modules/cellUserInfo.h @@ -21,7 +21,7 @@ enum CellUserInfoParamSize CELL_USERINFO_USERNAME_SIZE = 64, }; -enum CellUserInfoListType +enum CellUserInfoListType { CELL_USERINFO_LISTTYPE_ALL = 0, CELL_USERINFO_LISTTYPE_NOCURRENT = 1, @@ -37,7 +37,7 @@ enum struct CellUserInfoUserStat { be_t id; - u8 name[CELL_USERINFO_USERNAME_SIZE]; + char name[CELL_USERINFO_USERNAME_SIZE]; }; struct CellUserInfoUserList @@ -47,17 +47,17 @@ struct CellUserInfoUserList struct CellUserInfoListSet { - be_t title_addr; // (char*) - be_t focus; + vm::bptr title; + be_t focus; // id be_t fixedListNum; - vm::ptr fixedList; - be_t reserved_addr; // (void*) + vm::bptr fixedList; + vm::bptr reserved; }; struct CellUserInfoTypeSet { - be_t title_addr; // (char*) - be_t focus; - CellUserInfoListType type; - be_t reserved_addr; // (void*) + vm::bptr title; + be_t focus; // id + be_t type; // CellUserInfoListType + vm::bptr reserved; }; diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp b/rpcs3/Emu/Cell/Modules/cellVdec.cpp similarity index 96% rename from rpcs3/Emu/SysCalls/Modules/cellVdec.cpp rename to rpcs3/Emu/Cell/Modules/cellVdec.cpp index 34e06c726f..92f33a2d66 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellVdec.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" std::mutex g_mutex_avcodec_open2; @@ -17,7 +16,9 @@ extern "C" #include "cellPamf.h" #include "cellVdec.h" -extern Module<> cellVdec; +LOG_CHANNEL(cellVdec); + +vm::gvar _cell_vdec_prx_ver; // ??? VideoDecoder::VideoDecoder(s32 type, u32 profile, u32 addr, u32 size, vm::ptr func, u32 arg) : type(type) @@ -538,8 +539,9 @@ void vdecOpen(u32 vdec_id) // TODO: call from the constructor vdec.is_finished = true; }; - vdec.vdecCb->run(); - vdec.vdecCb->exec(); + vdec.vdecCb->cpu_init(); + vdec.vdecCb->state -= cpu_state::stop; + vdec.vdecCb->safe_notify(); } s32 cellVdecQueryAttr(vm::cptr type, vm::ptr attr) @@ -595,7 +597,7 @@ s32 cellVdecClose(u32 handle) std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } - idm::remove(vdec->vdecCb->get_id()); + idm::remove(vdec->vdecCb->id); idm::remove(handle); return CELL_OK; } @@ -948,24 +950,24 @@ s32 cellVdecSetFrameRate(u32 handle, CellVdecFrameRate frc) return CELL_OK; } -Module<> cellVdec("cellVdec", []() +DECLARE(ppu_module_manager::cellVdec)("libvdec", []() { - //REG_VARIABLE(cellVdec, _cell_vdec_prx_ver); // 0x085a7ecb + REG_VAR(libvdec, _cell_vdec_prx_ver); // 0x085a7ecb - REG_FUNC(cellVdec, cellVdecQueryAttr); - REG_FUNC(cellVdec, cellVdecQueryAttrEx); - REG_FUNC(cellVdec, cellVdecOpen); - REG_FUNC(cellVdec, cellVdecOpenEx); - //REG_FUNC(cellVdec, cellVdecOpenExt); // 0xef4d8ad7 - REG_FUNC(cellVdec, cellVdecClose); - REG_FUNC(cellVdec, cellVdecStartSeq); - //REG_FUNC(cellVdec, cellVdecStartSeqExt); // 0xebb8e70a - REG_FUNC(cellVdec, cellVdecEndSeq); - REG_FUNC(cellVdec, cellVdecDecodeAu); - REG_FUNC(cellVdec, cellVdecGetPicture); - REG_FUNC(cellVdec, cellVdecGetPictureExt); // 0xa21aa896 - REG_FUNC(cellVdec, cellVdecGetPicItem); - //REG_FUNC(cellVdec, cellVdecGetPicItemExt); // 0x2cbd9806 - REG_FUNC(cellVdec, cellVdecSetFrameRate); - //REG_FUNC(cellVdec, cellVdecSetFrameRateExt); // 0xcffc42a5 + REG_FUNC(libvdec, cellVdecQueryAttr); + REG_FUNC(libvdec, cellVdecQueryAttrEx); + REG_FUNC(libvdec, cellVdecOpen); + REG_FUNC(libvdec, cellVdecOpenEx); + //REG_FUNC(libvdec, cellVdecOpenExt); // 0xef4d8ad7 + REG_FUNC(libvdec, cellVdecClose); + REG_FUNC(libvdec, cellVdecStartSeq); + //REG_FUNC(libvdec, cellVdecStartSeqExt); // 0xebb8e70a + REG_FUNC(libvdec, cellVdecEndSeq); + REG_FUNC(libvdec, cellVdecDecodeAu); + REG_FUNC(libvdec, cellVdecGetPicture); + REG_FUNC(libvdec, cellVdecGetPictureExt); // 0xa21aa896 + REG_FUNC(libvdec, cellVdecGetPicItem); + //REG_FUNC(libvdec, cellVdecGetPicItemExt); // 0x2cbd9806 + REG_FUNC(libvdec, cellVdecSetFrameRate); + //REG_FUNC(libvdec, cellVdecSetFrameRateExt); // 0xcffc42a5 }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.h b/rpcs3/Emu/Cell/Modules/cellVdec.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellVdec.h rename to rpcs3/Emu/Cell/Modules/cellVdec.h diff --git a/rpcs3/Emu/Cell/Modules/cellVideoExport.cpp b/rpcs3/Emu/Cell/Modules/cellVideoExport.cpp new file mode 100644 index 0000000000..266d8abc45 --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/cellVideoExport.cpp @@ -0,0 +1,45 @@ +#include "stdafx.h" +#include "Emu/Cell/PPUModule.h" + +LOG_CHANNEL(cellVideoExport); + +s32 cellVideoExportProgress() +{ + throw EXCEPTION(""); +} + +s32 cellVideoExportInitialize2() +{ + throw EXCEPTION(""); +} + +s32 cellVideoExportInitialize() +{ + throw EXCEPTION(""); +} + +s32 cellVideoExportFromFileWithCopy() +{ + throw EXCEPTION(""); +} + +s32 cellVideoExportFromFile() +{ + throw EXCEPTION(""); +} + +s32 cellVideoExportFinalize() +{ + throw EXCEPTION(""); +} + + +DECLARE(ppu_module_manager::cellVideoExport)("cellVideoExportUtility", []() +{ + REG_FUNC(cellVideoExportUtility, cellVideoExportProgress); + REG_FUNC(cellVideoExportUtility, cellVideoExportInitialize2); + REG_FUNC(cellVideoExportUtility, cellVideoExportInitialize); + REG_FUNC(cellVideoExportUtility, cellVideoExportFromFileWithCopy); + REG_FUNC(cellVideoExportUtility, cellVideoExportFromFile); + REG_FUNC(cellVideoExportUtility, cellVideoExportFinalize); +}); diff --git a/rpcs3/Emu/Cell/Modules/cellVideoOut.cpp b/rpcs3/Emu/Cell/Modules/cellVideoOut.cpp new file mode 100644 index 0000000000..c3fd404652 --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/cellVideoOut.cpp @@ -0,0 +1,239 @@ +#include "stdafx.h" +#include "Emu/System.h" +#include "Emu/Cell/PPUModule.h" + +#include "cellVideoOut.h" + +extern _log::channel cellSysutil; + +cfg::map_entry g_cfg_video_out_resolution(cfg::root.video, "Resolution", "1280x720", +{ + { "1920x1080", CELL_VIDEO_OUT_RESOLUTION_1080 }, + { "1280x720", CELL_VIDEO_OUT_RESOLUTION_720 }, + { "720x480", CELL_VIDEO_OUT_RESOLUTION_480 }, + { "720x576", CELL_VIDEO_OUT_RESOLUTION_576 }, + { "1600x1080", CELL_VIDEO_OUT_RESOLUTION_1600x1080 }, + { "1440x1080", CELL_VIDEO_OUT_RESOLUTION_1440x1080 }, + { "1280x1080", CELL_VIDEO_OUT_RESOLUTION_1280x1080 }, + { "960x1080", CELL_VIDEO_OUT_RESOLUTION_960x1080 }, +}); + +cfg::map_entry g_cfg_video_out_aspect_ratio(cfg::root.video, "Aspect ratio", "16x9", +{ + { "4x3", CELL_VIDEO_OUT_ASPECT_4_3 }, + { "16x9", CELL_VIDEO_OUT_ASPECT_16_9 }, +}); + +const extern std::unordered_map g_video_out_resolution_map +{ + { CELL_VIDEO_OUT_RESOLUTION_1080, { 1920, 1080 } }, + { CELL_VIDEO_OUT_RESOLUTION_720, { 1280, 720 } }, + { CELL_VIDEO_OUT_RESOLUTION_480, { 720, 480 } }, + { CELL_VIDEO_OUT_RESOLUTION_576, { 720, 576 } }, + { CELL_VIDEO_OUT_RESOLUTION_1600x1080, { 1600, 1080 } }, + { CELL_VIDEO_OUT_RESOLUTION_1440x1080, { 1440, 1080 } }, + { CELL_VIDEO_OUT_RESOLUTION_1280x1080, { 1280, 1080 } }, + { CELL_VIDEO_OUT_RESOLUTION_960x1080, { 960, 1080 } }, +}; + +ppu_error_code cellVideoOutGetState(u32 videoOut, u32 deviceIndex, vm::ptr state) +{ + cellSysutil.trace("cellVideoOutGetState(videoOut=%d, deviceIndex=%d, state=*0x%x)", videoOut, deviceIndex, state); + + if (deviceIndex) return CELL_VIDEO_OUT_ERROR_DEVICE_NOT_FOUND; + + switch (videoOut) + { + case CELL_VIDEO_OUT_PRIMARY: + state->state = CELL_VIDEO_OUT_OUTPUT_STATE_ENABLED; + state->colorSpace = CELL_VIDEO_OUT_COLOR_SPACE_RGB; + state->displayMode.resolutionId = g_cfg_video_out_resolution.get(); // TODO + state->displayMode.scanMode = CELL_VIDEO_OUT_SCAN_MODE_PROGRESSIVE; + state->displayMode.conversion = CELL_VIDEO_OUT_DISPLAY_CONVERSION_NONE; + state->displayMode.aspect = g_cfg_video_out_aspect_ratio.get(); // TODO + state->displayMode.refreshRates = CELL_VIDEO_OUT_REFRESH_RATE_59_94HZ; + return CELL_OK; + + case CELL_VIDEO_OUT_SECONDARY: + *state = { CELL_VIDEO_OUT_OUTPUT_STATE_DISABLED }; // ??? + return CELL_OK; + } + + return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT; +} + +ppu_error_code cellVideoOutGetResolution(u32 resolutionId, vm::ptr resolution) +{ + cellSysutil.trace("cellVideoOutGetResolution(resolutionId=0x%x, resolution=*0x%x)", resolutionId, resolution); + + if (!resolution) + { + return CELL_VIDEO_OUT_ERROR_ILLEGAL_PARAMETER; + } + + switch (resolutionId) + { + case 0x01: *resolution = { 0x780, 0x438 }; break; + case 0x02: *resolution = { 0x500, 0x2d0 }; break; + case 0x04: *resolution = { 0x2d0, 0x1e0 }; break; + case 0x05: *resolution = { 0x2d0, 0x240 }; break; + case 0x0a: *resolution = { 0x640, 0x438 }; break; + case 0x0b: *resolution = { 0x5a0, 0x438 }; break; + case 0x0c: *resolution = { 0x500, 0x438 }; break; + case 0x0d: *resolution = { 0x3c0, 0x438 }; break; + case 0x64: *resolution = { 0x550, 0x300 }; break; + case 0x81: *resolution = { 0x500, 0x5be }; break; + case 0x82: *resolution = { 0x780, 0x438 }; break; + case 0x83: *resolution = { 0x780, 0x89d }; break; + case 0x8b: *resolution = { 0x280, 0x5be }; break; + case 0x8a: *resolution = { 0x320, 0x5be }; break; + case 0x89: *resolution = { 0x3c0, 0x5be }; break; + case 0x88: *resolution = { 0x400, 0x5be }; break; + case 0x91: *resolution = { 0x500, 0x5be }; break; + case 0x92: *resolution = { 0x780, 0x438 }; break; + case 0x9b: *resolution = { 0x280, 0x5be }; break; + case 0x9a: *resolution = { 0x320, 0x5be }; break; + case 0x99: *resolution = { 0x3c0, 0x5be }; break; + case 0x98: *resolution = { 0x400, 0x5be }; break; + case 0xa1: *resolution = { 0x780, 0x438 }; break; + + default: return CELL_VIDEO_OUT_ERROR_ILLEGAL_PARAMETER; + } + + return CELL_OK; +} + +ppu_error_code cellVideoOutConfigure(u32 videoOut, vm::ptr config, vm::ptr option, u32 waitForEvent) +{ + cellSysutil.warning("cellVideoOutConfigure(videoOut=%d, config=*0x%x, option=*0x%x, waitForEvent=%d)", videoOut, config, option, waitForEvent); + + switch (videoOut) + { + case CELL_VIDEO_OUT_PRIMARY: + // TODO + return CELL_OK; + + case CELL_VIDEO_OUT_SECONDARY: + return CELL_OK; + } + + return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT; +} + +ppu_error_code cellVideoOutGetConfiguration(u32 videoOut, vm::ptr config, vm::ptr option) +{ + cellSysutil.warning("cellVideoOutGetConfiguration(videoOut=%d, config=*0x%x, option=*0x%x)", videoOut, config, option); + + if (option) *option = {}; + *config = {}; + + switch (videoOut) + { + case CELL_VIDEO_OUT_PRIMARY: + config->resolutionId = g_cfg_video_out_resolution.get(); + config->format = CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8; + config->aspect = g_cfg_video_out_aspect_ratio.get(); + config->pitch = 4 * g_video_out_resolution_map.at(g_cfg_video_out_resolution.get()).width; + + return CELL_OK; + + case CELL_VIDEO_OUT_SECONDARY: + + return CELL_OK; + } + + return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT; +} + +ppu_error_code cellVideoOutGetDeviceInfo(u32 videoOut, u32 deviceIndex, vm::ptr info) +{ + cellSysutil.warning("cellVideoOutGetDeviceInfo(videoOut=%d, deviceIndex=%d, info=*0x%x)", videoOut, deviceIndex, info); + + if (deviceIndex) return CELL_VIDEO_OUT_ERROR_DEVICE_NOT_FOUND; + + // Use standard dummy values for now. + info->portType = CELL_VIDEO_OUT_PORT_HDMI; + info->colorSpace = CELL_VIDEO_OUT_COLOR_SPACE_RGB; + info->latency = 1000; + info->availableModeCount = 1; + info->state = CELL_VIDEO_OUT_DEVICE_STATE_AVAILABLE; + info->rgbOutputRange = 1; + info->colorInfo.blueX = 0xFFFF; + info->colorInfo.blueY = 0xFFFF; + info->colorInfo.greenX = 0xFFFF; + info->colorInfo.greenY = 0xFFFF; + info->colorInfo.redX = 0xFFFF; + info->colorInfo.redY = 0xFFFF; + info->colorInfo.whiteX = 0xFFFF; + info->colorInfo.whiteY = 0xFFFF; + info->colorInfo.gamma = 100; + info->availableModes[0].aspect = 0; + info->availableModes[0].conversion = 0; + info->availableModes[0].refreshRates = 0xF; + info->availableModes[0].resolutionId = 1; + info->availableModes[0].scanMode = 0; + + return CELL_OK; +} + +ppu_error_code cellVideoOutGetNumberOfDevice(u32 videoOut) +{ + cellSysutil.warning("cellVideoOutGetNumberOfDevice(videoOut=%d)", videoOut); + + switch (videoOut) + { + case CELL_VIDEO_OUT_PRIMARY: return NOT_AN_ERROR(1); + case CELL_VIDEO_OUT_SECONDARY: return NOT_AN_ERROR(0); + } + + return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT; +} + +ppu_error_code cellVideoOutGetResolutionAvailability(u32 videoOut, u32 resolutionId, u32 aspect, u32 option) +{ + cellSysutil.warning("cellVideoOutGetResolutionAvailability(videoOut=%d, resolutionId=0x%x, aspect=%d, option=%d)", videoOut, resolutionId, aspect, option); + + switch (videoOut) + { + case CELL_VIDEO_OUT_PRIMARY: return NOT_AN_ERROR(1); + case CELL_VIDEO_OUT_SECONDARY: return NOT_AN_ERROR(0); + } + + return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT; +} + +s32 cellVideoOutGetConvertCursorColorInfo(vm::ptr rgbOutputRange) +{ + throw EXCEPTION(""); +} + +s32 cellVideoOutDebugSetMonitorType(u32 videoOut, u32 monitorType) +{ + throw EXCEPTION(""); +} + +s32 cellVideoOutRegisterCallback(u32 slot, vm::ptr function, vm::ptr userData) +{ + throw EXCEPTION(""); +} + +s32 cellVideoOutUnregisterCallback(u32 slot) +{ + throw EXCEPTION(""); +} + + +void cellSysutil_VideoOut_init() +{ + REG_FUNC(cellSysutil, cellVideoOutGetState); + REG_FUNC(cellSysutil, cellVideoOutGetResolution, MFF_PERFECT); + REG_FUNC(cellSysutil, cellVideoOutConfigure); + REG_FUNC(cellSysutil, cellVideoOutGetConfiguration); + REG_FUNC(cellSysutil, cellVideoOutGetDeviceInfo); + REG_FUNC(cellSysutil, cellVideoOutGetNumberOfDevice); + REG_FUNC(cellSysutil, cellVideoOutGetResolutionAvailability); + REG_FUNC(cellSysutil, cellVideoOutGetConvertCursorColorInfo); + REG_FUNC(cellSysutil, cellVideoOutDebugSetMonitorType); + REG_FUNC(cellSysutil, cellVideoOutRegisterCallback); + REG_FUNC(cellSysutil, cellVideoOutUnregisterCallback); +} diff --git a/rpcs3/Emu/Cell/Modules/cellVideoOut.h b/rpcs3/Emu/Cell/Modules/cellVideoOut.h new file mode 100644 index 0000000000..988c36335c --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/cellVideoOut.h @@ -0,0 +1,262 @@ +#pragma once + +namespace vm { using namespace ps3; } + +#include "Emu/Cell/ErrorCodes.h" + +// Video Out Error Codes +enum CellVideoOutError : s32 +{ + CELL_VIDEO_OUT_ERROR_NOT_IMPLEMENTED = ERROR_CODE(0x8002b220), + CELL_VIDEO_OUT_ERROR_ILLEGAL_CONFIGURATION = ERROR_CODE(0x8002b221), + CELL_VIDEO_OUT_ERROR_ILLEGAL_PARAMETER = ERROR_CODE(0x8002b222), + CELL_VIDEO_OUT_ERROR_PARAMETER_OUT_OF_RANGE = ERROR_CODE(0x8002b223), + CELL_VIDEO_OUT_ERROR_DEVICE_NOT_FOUND = ERROR_CODE(0x8002b224), + CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT = ERROR_CODE(0x8002b225), + CELL_VIDEO_OUT_ERROR_UNSUPPORTED_DISPLAY_MODE = ERROR_CODE(0x8002b226), + CELL_VIDEO_OUT_ERROR_CONDITION_BUSY = ERROR_CODE(0x8002b227), + CELL_VIDEO_OUT_ERROR_VALUE_IS_NOT_SET = ERROR_CODE(0x8002b228), +}; + +template<> +inline const char* ppu_error_code::print(CellVideoOutError error) +{ + switch (error) + { + STR_CASE(CELL_VIDEO_OUT_ERROR_NOT_IMPLEMENTED); + STR_CASE(CELL_VIDEO_OUT_ERROR_ILLEGAL_CONFIGURATION); + STR_CASE(CELL_VIDEO_OUT_ERROR_ILLEGAL_PARAMETER); + STR_CASE(CELL_VIDEO_OUT_ERROR_PARAMETER_OUT_OF_RANGE); + STR_CASE(CELL_VIDEO_OUT_ERROR_DEVICE_NOT_FOUND); + STR_CASE(CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT); + STR_CASE(CELL_VIDEO_OUT_ERROR_UNSUPPORTED_DISPLAY_MODE); + STR_CASE(CELL_VIDEO_OUT_ERROR_CONDITION_BUSY); + STR_CASE(CELL_VIDEO_OUT_ERROR_VALUE_IS_NOT_SET); + } + + return nullptr; +} + +enum CellVideoOut : s32 +{ + CELL_VIDEO_OUT_PRIMARY = 0, + CELL_VIDEO_OUT_SECONDARY = 1, +}; + +enum CellVideoOutResolutionId : s32 +{ + CELL_VIDEO_OUT_RESOLUTION_UNDEFINED = 0, + CELL_VIDEO_OUT_RESOLUTION_1080 = 1, + CELL_VIDEO_OUT_RESOLUTION_720 = 2, + CELL_VIDEO_OUT_RESOLUTION_480 = 4, + CELL_VIDEO_OUT_RESOLUTION_576 = 5, + CELL_VIDEO_OUT_RESOLUTION_1600x1080 = 0xa, + CELL_VIDEO_OUT_RESOLUTION_1440x1080 = 0xb, + CELL_VIDEO_OUT_RESOLUTION_1280x1080 = 0xc, + CELL_VIDEO_OUT_RESOLUTION_960x1080 = 0xd, + CELL_VIDEO_OUT_RESOLUTION_720_3D_FRAME_PACKING = 0x81, + CELL_VIDEO_OUT_RESOLUTION_1024x720_3D_FRAME_PACKING = 0x88, + CELL_VIDEO_OUT_RESOLUTION_960x720_3D_FRAME_PACKING = 0x89, + CELL_VIDEO_OUT_RESOLUTION_800x720_3D_FRAME_PACKING = 0x8a, + CELL_VIDEO_OUT_RESOLUTION_640x720_3D_FRAME_PACKING = 0x8b, + CELL_VIDEO_OUT_RESOLUTION_720_DUALVIEW_FRAME_PACKING = 0x91, + CELL_VIDEO_OUT_RESOLUTION_720_SIMULVIEW_FRAME_PACKING = 0x91, + CELL_VIDEO_OUT_RESOLUTION_1024x720_DUALVIEW_FRAME_PACKING = 0x98, + CELL_VIDEO_OUT_RESOLUTION_1024x720_SIMULVIEW_FRAME_PACKING = 0x98, + CELL_VIDEO_OUT_RESOLUTION_960x720_DUALVIEW_FRAME_PACKING = 0x99, + CELL_VIDEO_OUT_RESOLUTION_960x720_SIMULVIEW_FRAME_PACKING = 0x99, + CELL_VIDEO_OUT_RESOLUTION_800x720_DUALVIEW_FRAME_PACKING = 0x9a, + CELL_VIDEO_OUT_RESOLUTION_800x720_SIMULVIEW_FRAME_PACKING = 0x9a, + CELL_VIDEO_OUT_RESOLUTION_640x720_DUALVIEW_FRAME_PACKING = 0x9b, + CELL_VIDEO_OUT_RESOLUTION_640x720_SIMULVIEW_FRAME_PACKING = 0x9b, +}; + +enum CellVideoOutScanMode : s32 +{ + CELL_VIDEO_OUT_SCAN_MODE_INTERLACE, + CELL_VIDEO_OUT_SCAN_MODE_PROGRESSIVE, +}; + +enum CellVideoOutScanMode2 : s32 +{ + CELL_VIDEO_OUT_SCAN_MODE2_AUTO, + CELL_VIDEO_OUT_SCAN_MODE2_INTERLACE, + CELL_VIDEO_OUT_SCAN_MODE2_PROGRESSIVE, +}; + +enum CellVideoOutRefreshRate : s32 +{ + CELL_VIDEO_OUT_REFRESH_RATE_AUTO = 0x0000, + CELL_VIDEO_OUT_REFRESH_RATE_59_94HZ = 0x0001, + CELL_VIDEO_OUT_REFRESH_RATE_50HZ = 0x0002, + CELL_VIDEO_OUT_REFRESH_RATE_60HZ = 0x0004, + CELL_VIDEO_OUT_REFRESH_RATE_30HZ = 0x0008, +}; + +enum CellVideoOutPortType : s32 +{ + CELL_VIDEO_OUT_PORT_NONE = 0x00, + CELL_VIDEO_OUT_PORT_HDMI = 0x01, + CELL_VIDEO_OUT_PORT_NETWORK = 0x41, + CELL_VIDEO_OUT_PORT_COMPOSITE_S = 0x81, + CELL_VIDEO_OUT_PORT_D = 0x82, + CELL_VIDEO_OUT_PORT_COMPONENT = 0x83, + CELL_VIDEO_OUT_PORT_RGB = 0x84, + CELL_VIDEO_OUT_PORT_AVMULTI_SCART = 0x85, + CELL_VIDEO_OUT_PORT_DSUB = 0x86, +}; + +enum CellVideoOutDisplayAspect : s32 +{ + CELL_VIDEO_OUT_ASPECT_AUTO, + CELL_VIDEO_OUT_ASPECT_4_3, + CELL_VIDEO_OUT_ASPECT_16_9, +}; + +enum CellVideoOutBufferColorFormat : s32 +{ + CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8, + CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8B8G8R8, + CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_R16G16B16X16_FLOAT, +}; + +enum CellVideoOutOutputState : s32 +{ + CELL_VIDEO_OUT_OUTPUT_STATE_ENABLED, + CELL_VIDEO_OUT_OUTPUT_STATE_DISABLED, + CELL_VIDEO_OUT_OUTPUT_STATE_PREPARING, +}; + +enum CellVideoOutDeviceState : s32 +{ + CELL_VIDEO_OUT_DEVICE_STATE_UNAVAILABLE, + CELL_VIDEO_OUT_DEVICE_STATE_AVAILABLE, +}; + +enum CellVideoOutColorSpace : s32 +{ + CELL_VIDEO_OUT_COLOR_SPACE_RGB = 0x01, + CELL_VIDEO_OUT_COLOR_SPACE_YUV = 0x02, + CELL_VIDEO_OUT_COLOR_SPACE_XVYCC = 0x04, +}; + +enum CellVideoOutDebugMonitorType : s32 +{ + CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_UNDEFINED = 0, + CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_480I_59_94HZ = 1, + CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_576I_50HZ = 2, + CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_480P_59_94HZ = 3, + CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_576P_50HZ = 4, + CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_1080I_59_94HZ = 5, + CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_720P_59_94HZ = 7, + CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_1080P_59_94HZ = 9, + CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_WXGA_60HZ = 11, + CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_SXGA_60HZ = 12, + CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_WUXGA_60HZ = 13, +}; + +struct CellVideoOutColorInfo +{ + be_t redX; + be_t redY; + be_t greenX; + be_t greenY; + be_t blueX; + be_t blueY; + be_t whiteX; + be_t whiteY; + be_t gamma; +}; + +struct CellVideoOutKSVList +{ + u8 ksv[32*5]; + u8 reserved[4]; + be_t count; +}; + +enum CellVideoOutDisplayConversion : s32 +{ + CELL_VIDEO_OUT_DISPLAY_CONVERSION_NONE = 0x00, + CELL_VIDEO_OUT_DISPLAY_CONVERSION_TO_WXGA = 0x01, + CELL_VIDEO_OUT_DISPLAY_CONVERSION_TO_SXGA = 0x02, + CELL_VIDEO_OUT_DISPLAY_CONVERSION_TO_WUXGA = 0x03, + CELL_VIDEO_OUT_DISPLAY_CONVERSION_TO_1080 = 0x05, + CELL_VIDEO_OUT_DISPLAY_CONVERSION_TO_REMOTEPLAY = 0x10, + CELL_VIDEO_OUT_DISPLAY_CONVERSION_TO_720_3D_FRAME_PACKING = 0x80, +}; + +struct CellVideoOutDisplayMode +{ + u8 resolutionId; + u8 scanMode; + u8 conversion; + u8 aspect; + u8 reserved[2]; + be_t refreshRates; +}; + +struct CellVideoOutResolution +{ + be_t width; + be_t height; +}; + +struct CellVideoOutDeviceInfo +{ + u8 portType; + u8 colorSpace; + be_t latency; + u8 availableModeCount; + u8 state; + u8 rgbOutputRange; + u8 reserved[5]; + CellVideoOutColorInfo colorInfo; + CellVideoOutDisplayMode availableModes[32]; + CellVideoOutKSVList ksvList; +}; + +struct CellVideoOutState +{ + u8 state; + u8 colorSpace; + u8 reserved[6]; + CellVideoOutDisplayMode displayMode; +}; + +struct CellVideoOutConfiguration +{ + u8 resolutionId; + u8 format; + u8 aspect; + u8 reserved[9]; + be_t pitch; +}; + +struct CellVideoOutOption +{ + be_t reserved; +}; + +enum CellVideoOutEvent : s32 +{ + CELL_VIDEO_OUT_EVENT_DEVICE_CHANGED, + CELL_VIDEO_OUT_EVENT_OUTPUT_DISABLED, + CELL_VIDEO_OUT_EVENT_DEVICE_AUTHENTICATED, + CELL_VIDEO_OUT_EVENT_OUTPUT_ENABLED, +}; + +enum CellVideoOutCopyControl : s32 +{ + CELL_VIDEO_OUT_COPY_CONTROL_COPY_FREE, + CELL_VIDEO_OUT_COPY_CONTROL_COPY_ONCE, + CELL_VIDEO_OUT_COPY_CONTROL_COPY_NEVER, +}; + +enum CellVideoOutRGBOutputRange : s32 +{ + CELL_VIDEO_OUT_RGB_OUTPUT_RANGE_LIMITED, + CELL_VIDEO_OUT_RGB_OUTPUT_RANGE_FULL, +}; + +using CellVideoOutCallback = s32(u32 slot, u32 videoOut, u32 deviceIndex, u32 event, vm::ptr info, vm::ptr userData); diff --git a/rpcs3/Emu/Cell/Modules/cellVideoUpload.cpp b/rpcs3/Emu/Cell/Modules/cellVideoUpload.cpp new file mode 100644 index 0000000000..f41f52a573 --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/cellVideoUpload.cpp @@ -0,0 +1,14 @@ +#include "stdafx.h" +#include "Emu/Cell/PPUModule.h" + +LOG_CHANNEL(cellVideoUpload); + +s32 cellVideoUploadInitialize() +{ + throw EXCEPTION(""); +} + +DECLARE(ppu_module_manager::cellVideoUpload)("cellVideoUpload", []() +{ + REG_FUNC(cellVideoUpload, cellVideoUploadInitialize); +}); diff --git a/rpcs3/Emu/SysCalls/Modules/cellVoice.cpp b/rpcs3/Emu/Cell/Modules/cellVoice.cpp similarity index 97% rename from rpcs3/Emu/SysCalls/Modules/cellVoice.cpp rename to rpcs3/Emu/Cell/Modules/cellVoice.cpp index 5083aa6823..83c227faa9 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVoice.cpp +++ b/rpcs3/Emu/Cell/Modules/cellVoice.cpp @@ -1,9 +1,8 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellVoice; +LOG_CHANNEL(cellVoice); // Error Codes enum @@ -237,7 +236,7 @@ s32 cellVoiceDebugTopology() return CELL_OK; } -Module<> cellVoice("cellVoice", []() +DECLARE(ppu_module_manager::cellVoice)("cellVoice", []() { REG_FUNC(cellVoice, cellVoiceConnectIPortToOPort); REG_FUNC(cellVoice, cellVoiceCreateNotifyEventQueue); diff --git a/rpcs3/Emu/SysCalls/Modules/cellVpost.cpp b/rpcs3/Emu/Cell/Modules/cellVpost.cpp similarity index 97% rename from rpcs3/Emu/SysCalls/Modules/cellVpost.cpp rename to rpcs3/Emu/Cell/Modules/cellVpost.cpp index 1f466e12db..d42d4febbc 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVpost.cpp +++ b/rpcs3/Emu/Cell/Modules/cellVpost.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" extern "C" { @@ -11,7 +10,7 @@ extern "C" #include "cellVpost.h" -extern Module<> cellVpost; +LOG_CHANNEL(cellVpost); s32 cellVpostQueryAttr(vm::cptr cfgParam, vm::ptr attr) { @@ -137,7 +136,7 @@ s32 cellVpostExec(u32 handle, vm::cptr inPicBuff, vm::cptr cellVpost("cellVpost", []() +DECLARE(ppu_module_manager::cellVpost)("cellVpost", []() { REG_FUNC(cellVpost, cellVpostQueryAttr); REG_FUNC(cellVpost, cellVpostOpen); diff --git a/rpcs3/Emu/SysCalls/Modules/cellVpost.h b/rpcs3/Emu/Cell/Modules/cellVpost.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellVpost.h rename to rpcs3/Emu/Cell/Modules/cellVpost.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellWebBrowser.cpp b/rpcs3/Emu/Cell/Modules/cellWebBrowser.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/cellWebBrowser.cpp rename to rpcs3/Emu/Cell/Modules/cellWebBrowser.cpp index 1929045f4a..4f0877a095 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellWebBrowser.cpp +++ b/rpcs3/Emu/Cell/Modules/cellWebBrowser.cpp @@ -1,10 +1,9 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellWebBrowser.h" -extern Module<> cellSysutil; +extern _log::channel cellSysutil; s32 cellWebBrowserActivate() { diff --git a/rpcs3/Emu/SysCalls/Modules/cellWebBrowser.h b/rpcs3/Emu/Cell/Modules/cellWebBrowser.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellWebBrowser.h rename to rpcs3/Emu/Cell/Modules/cellWebBrowser.h diff --git a/rpcs3/Emu/Cell/Modules/libmixer.cpp b/rpcs3/Emu/Cell/Modules/libmixer.cpp new file mode 100644 index 0000000000..ac5b0ed831 --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/libmixer.cpp @@ -0,0 +1,654 @@ +#include "stdafx.h" +#include "Emu/System.h" +#include "Emu/IdManager.h" +#include "Emu/Cell/PPUModule.h" + +#include "cellAudio.h" +#include "libmixer.h" + +LOG_CHANNEL(libmixer); + +// TODO: use fxm +SurMixerConfig g_surmx; + +std::vector g_ssp; + +s32 cellAANAddData(u32 aan_handle, u32 aan_port, u32 offset, vm::ptr addr, u32 samples) +{ + libmixer.trace("cellAANAddData(aan_handle=0x%x, aan_port=0x%x, offset=0x%x, addr=*0x%x, samples=%d)", aan_handle, aan_port, offset, addr, samples); + + u32 type = aan_port >> 16; + u32 port = aan_port & 0xffff; + + switch (type) + { + case CELL_SURMIXER_CHSTRIP_TYPE1A: + if (port >= g_surmx.ch_strips_1) type = 0; break; + case CELL_SURMIXER_CHSTRIP_TYPE2A: + if (port >= g_surmx.ch_strips_2) type = 0; break; + case CELL_SURMIXER_CHSTRIP_TYPE6A: + if (port >= g_surmx.ch_strips_6) type = 0; break; + case CELL_SURMIXER_CHSTRIP_TYPE8A: + if (port >= g_surmx.ch_strips_8) type = 0; break; + default: + type = 0; break; + } + + if (aan_handle != 0x11111111 || samples != 256 || !type || offset != 0) + { + libmixer.error("cellAANAddData(aan_handle=0x%x, aan_port=0x%x, offset=0x%x, addr=*0x%x, samples=%d): invalid parameters", aan_handle, aan_port, offset, addr, samples); + return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; + } + + std::lock_guard lock(g_surmx.mutex); + + if (type == CELL_SURMIXER_CHSTRIP_TYPE1A) + { + // mono upmixing + for (u32 i = 0; i < samples; i++) + { + const float center = addr[i]; + g_surmx.mixdata[i * 8 + 0] += center; + g_surmx.mixdata[i * 8 + 1] += center; + } + } + else if (type == CELL_SURMIXER_CHSTRIP_TYPE2A) + { + // stereo upmixing + for (u32 i = 0; i < samples; i++) + { + const float left = addr[i * 2 + 0]; + const float right = addr[i * 2 + 1]; + g_surmx.mixdata[i * 8 + 0] += left; + g_surmx.mixdata[i * 8 + 1] += right; + } + } + else if (type == CELL_SURMIXER_CHSTRIP_TYPE6A) + { + // 5.1 upmixing + for (u32 i = 0; i < samples; i++) + { + const float left = addr[i * 6 + 0]; + const float right = addr[i * 6 + 1]; + const float center = addr[i * 6 + 2]; + const float low_freq = addr[i * 6 + 3]; + const float rear_left = addr[i * 6 + 4]; + const float rear_right = addr[i * 6 + 5]; + g_surmx.mixdata[i * 8 + 0] += left; + g_surmx.mixdata[i * 8 + 1] += right; + g_surmx.mixdata[i * 8 + 2] += center; + g_surmx.mixdata[i * 8 + 3] += low_freq; + g_surmx.mixdata[i * 8 + 4] += rear_left; + g_surmx.mixdata[i * 8 + 5] += rear_right; + } + } + else if (type == CELL_SURMIXER_CHSTRIP_TYPE8A) + { + // 7.1 + for (u32 i = 0; i < samples * 8; i++) + { + g_surmx.mixdata[i] += addr[i]; + } + } + + return CELL_OK; +} + +s32 cellAANConnect(u32 receive, u32 receivePortNo, u32 source, u32 sourcePortNo) +{ + libmixer.warning("cellAANConnect(receive=0x%x, receivePortNo=0x%x, source=0x%x, sourcePortNo=0x%x)", + receive, receivePortNo, source, sourcePortNo); + + std::lock_guard lock(g_surmx.mutex); + + if (source >= g_ssp.size() || !g_ssp[source].m_created) + { + libmixer.error("cellAANConnect(): invalid source (%d)", source); + return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; + } + + g_ssp[source].m_connected = true; + + return CELL_OK; +} + +s32 cellAANDisconnect(u32 receive, u32 receivePortNo, u32 source, u32 sourcePortNo) +{ + libmixer.warning("cellAANDisconnect(receive=0x%x, receivePortNo=0x%x, source=0x%x, sourcePortNo=0x%x)", + receive, receivePortNo, source, sourcePortNo); + + std::lock_guard lock(g_surmx.mutex); + + if (source >= g_ssp.size() || !g_ssp[source].m_created) + { + libmixer.error("cellAANDisconnect(): invalid source (%d)", source); + return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; + } + + g_ssp[source].m_connected = false; + + return CELL_OK; +} + +s32 cellSSPlayerCreate(vm::ptr handle, vm::ptr config) +{ + libmixer.warning("cellSSPlayerCreate(handle=*0x%x, config=*0x%x)", handle, config); + + if (config->outputMode != 0 || config->channels - 1 >= 2) + { + libmixer.error("cellSSPlayerCreate(config.outputMode=%d, config.channels=%d): invalid parameters", config->outputMode, config->channels); + return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; + } + + std::lock_guard lock(g_surmx.mutex); + + SSPlayer p; + p.m_created = true; + p.m_connected = false; + p.m_active = false; + p.m_channels = config->channels; + + g_ssp.push_back(p); + *handle = (u32)g_ssp.size() - 1; + return CELL_OK; +} + +s32 cellSSPlayerRemove(u32 handle) +{ + libmixer.warning("cellSSPlayerRemove(handle=0x%x)", handle); + + std::lock_guard lock(g_surmx.mutex); + + if (handle >= g_ssp.size() || !g_ssp[handle].m_created) + { + libmixer.error("cellSSPlayerRemove(): SSPlayer not found (%d)", handle); + return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; + } + + g_ssp[handle].m_active = false; + g_ssp[handle].m_created = false; + g_ssp[handle].m_connected = false; + + return CELL_OK; +} + +s32 cellSSPlayerSetWave(u32 handle, vm::ptr waveInfo, vm::ptr commonInfo) +{ + libmixer.warning("cellSSPlayerSetWave(handle=0x%x, waveInfo=*0x%x, commonInfo=*0x%x)", handle, waveInfo, commonInfo); + + std::lock_guard lock(g_surmx.mutex); + + if (handle >= g_ssp.size() || !g_ssp[handle].m_created) + { + libmixer.error("cellSSPlayerSetWave(): SSPlayer not found (%d)", handle); + return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; + } + + // TODO: check parameters + + g_ssp[handle].m_addr = waveInfo->addr; + g_ssp[handle].m_samples = waveInfo->samples; + g_ssp[handle].m_loop_start = waveInfo->loopStartOffset - 1; + g_ssp[handle].m_loop_mode = commonInfo ? (u32)commonInfo->loopMode : CELL_SSPLAYER_ONESHOT; + g_ssp[handle].m_position = waveInfo->startOffset - 1; + + return CELL_OK; +} + +s32 cellSSPlayerPlay(u32 handle, vm::ptr info) +{ + libmixer.warning("cellSSPlayerPlay(handle=0x%x, info=*0x%x)", handle, info); + + std::lock_guard lock(g_surmx.mutex); + + if (handle >= g_ssp.size() || !g_ssp[handle].m_created) + { + libmixer.error("cellSSPlayerPlay(): SSPlayer not found (%d)", handle); + return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; + } + + // TODO: check parameters + + g_ssp[handle].m_active = true; + g_ssp[handle].m_level = info->level; + g_ssp[handle].m_speed = info->speed; + g_ssp[handle].m_x = info->position.x; + g_ssp[handle].m_y = info->position.y; + g_ssp[handle].m_z = info->position.z; + + return CELL_OK; +} + +s32 cellSSPlayerStop(u32 handle, u32 mode) +{ + libmixer.warning("cellSSPlayerStop(handle=0x%x, mode=0x%x)", handle, mode); + + std::lock_guard lock(g_surmx.mutex); + + if (handle >= g_ssp.size() || !g_ssp[handle].m_created) + { + libmixer.error("cellSSPlayerStop(): SSPlayer not found (%d)", handle); + return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; + } + + // TODO: transition to stop state + + g_ssp[handle].m_active = false; + + return CELL_OK; +} + +s32 cellSSPlayerSetParam(u32 handle, vm::ptr info) +{ + libmixer.warning("cellSSPlayerSetParam(handle=0x%x, info=*0x%x)", handle, info); + + std::lock_guard lock(g_surmx.mutex); + + if (handle >= g_ssp.size() || !g_ssp[handle].m_created) + { + libmixer.error("cellSSPlayerSetParam(): SSPlayer not found (%d)", handle); + return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; + } + + // TODO: check parameters + + g_ssp[handle].m_level = info->level; + g_ssp[handle].m_speed = info->speed; + g_ssp[handle].m_x = info->position.x; + g_ssp[handle].m_y = info->position.y; + g_ssp[handle].m_z = info->position.z; + + return CELL_OK; +} + +s32 cellSSPlayerGetState(u32 handle) +{ + libmixer.warning("cellSSPlayerGetState(handle=0x%x)", handle); + + std::lock_guard lock(g_surmx.mutex); + + if (handle >= g_ssp.size() || !g_ssp[handle].m_created) + { + libmixer.warning("cellSSPlayerGetState(): SSPlayer not found (%d)", handle); + return CELL_SSPLAYER_STATE_ERROR; + } + + if (g_ssp[handle].m_active) + { + return CELL_SSPLAYER_STATE_ON; + } + + return CELL_SSPLAYER_STATE_OFF; +} + +s32 cellSurMixerCreate(vm::cptr config) +{ + libmixer.warning("cellSurMixerCreate(config=*0x%x)", config); + + const auto g_audio = fxm::get(); + + const auto port = g_audio->open_port(); + + if (!port) + { + return CELL_LIBMIXER_ERROR_FULL; + } + + g_surmx.audio_port = port->number; + g_surmx.priority = config->priority; + g_surmx.ch_strips_1 = config->chStrips1; + g_surmx.ch_strips_2 = config->chStrips2; + g_surmx.ch_strips_6 = config->chStrips6; + g_surmx.ch_strips_8 = config->chStrips8; + + port->channel = 8; + port->block = 16; + port->attr = 0; + port->size = port->channel * port->block * AUDIO_SAMPLES * sizeof(float); + port->tag = 0; + port->level = 1.0f; + port->level_set.store({ 1.0f, 0.0f }); + + libmixer.warning("*** audio port opened (port=%d)", g_surmx.audio_port); + + g_surmx.mixcount = 0; + g_surmx.cb = vm::null; + + g_ssp.clear(); + + libmixer.warning("*** surMixer created (ch1=%d, ch2=%d, ch6=%d, ch8=%d)", config->chStrips1, config->chStrips2, config->chStrips6, config->chStrips8); + + const auto ppu = idm::make_ptr("Surmixer Thread"); + ppu->prio = 1001; + ppu->stack_size = 0x10000; + ppu->custom_task = [g_audio](PPUThread& ppu) + { + audio_port& port = g_audio->ports[g_surmx.audio_port]; + + while (port.state != audio_port_state::closed) + { + CHECK_EMU_STATUS; + + if (g_surmx.mixcount > (port.tag + 0)) // adding positive value (1-15): preemptive buffer filling (hack) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + continue; + } + + if (port.state == audio_port_state::started) + { + //u64 stamp0 = get_system_time(); + + memset(g_surmx.mixdata, 0, sizeof(g_surmx.mixdata)); + if (g_surmx.cb) + { + g_surmx.cb(ppu, g_surmx.cb_arg, (u32)g_surmx.mixcount, 256); + } + + //u64 stamp1 = get_system_time(); + + { + std::lock_guard lock(g_surmx.mutex); + + for (auto& p : g_ssp) if (p.m_active && p.m_created) + { + auto v = vm::ptrl::make(p.m_addr); // 16-bit LE audio data + float left = 0.0f; + float right = 0.0f; + float speed = fabs(p.m_speed); + float fpos = 0.0f; + for (s32 i = 0; i < 256; i++) if (p.m_active) + { + u32 pos = p.m_position; + s32 pos_inc = 0; + if (p.m_speed > 0.0f) // select direction + { + pos_inc = 1; + } + else if (p.m_speed < 0.0f) + { + pos_inc = -1; + } + s32 shift = i - (int)fpos; // change playback speed (simple and rough) + if (shift > 0) + { + // slow playback + pos_inc = 0; // duplicate one sample at this time + fpos += 1.0f; + fpos += speed; + } + else if (shift < 0) + { + // fast playback + i--; // mix two sample into one at this time + fpos -= 1.0f; + } + else + { + fpos += speed; + } + p.m_position += (u32)pos_inc; + if (p.m_channels == 1) // get mono data + { + left = right = (float)v[pos] / 0x8000 * p.m_level; + } + else if (p.m_channels == 2) // get stereo data + { + left = (float)v[pos * 2 + 0] / 0x8000 * p.m_level; + right = (float)v[pos * 2 + 1] / 0x8000 * p.m_level; + } + if (p.m_connected) // mix + { + // TODO: m_x, m_y, m_z ignored + g_surmx.mixdata[i * 8 + 0] += left; + g_surmx.mixdata[i * 8 + 1] += right; + } + if ((p.m_position == p.m_samples && p.m_speed > 0.0f) || + (p.m_position == ~0 && p.m_speed < 0.0f)) // loop or stop + { + if (p.m_loop_mode == CELL_SSPLAYER_LOOP_ON) + { + p.m_position = p.m_loop_start; + } + else if (p.m_loop_mode == CELL_SSPLAYER_ONESHOT_CONT) + { + p.m_position -= (u32)pos_inc; // restore position + } + else // oneshot + { + p.m_active = false; + p.m_position = p.m_loop_start; // TODO: check value + } + } + } + } + } + + //u64 stamp2 = get_system_time(); + + auto buf = vm::_ptr(port.addr.addr() + (g_surmx.mixcount % port.block) * port.channel * AUDIO_SAMPLES * sizeof(float)); + + for (auto& mixdata : g_surmx.mixdata) + { + // reverse byte order + *buf++ = mixdata; + } + + //u64 stamp3 = get_system_time(); + + //ConLog.Write("Libmixer perf: start=%lld (cb=%lld, ssp=%lld, finalize=%lld)", stamp0 - m_config.start_time, stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2); + } + + g_surmx.mixcount++; + } + + idm::remove(ppu.id); + }; + + ppu->cpu_init(); + ppu->state -= cpu_state::stop; + ppu->safe_notify(); + + return CELL_OK; +} + +s32 cellSurMixerGetAANHandle(vm::ptr handle) +{ + libmixer.warning("cellSurMixerGetAANHandle(handle=*0x%x) -> %d", handle, 0x11111111); + *handle = 0x11111111; + return CELL_OK; +} + +s32 cellSurMixerChStripGetAANPortNo(vm::ptr port, u32 type, u32 index) +{ + libmixer.warning("cellSurMixerChStripGetAANPortNo(port=*0x%x, type=0x%x, index=0x%x) -> 0x%x", port, type, index, (type << 16) | index); + *port = (type << 16) | index; + return CELL_OK; +} + +s32 cellSurMixerSetNotifyCallback(vm::ptr func, vm::ptr arg) +{ + libmixer.warning("cellSurMixerSetNotifyCallback(func=*0x%x, arg=*0x%x)", func, arg); + + if (g_surmx.cb) + { + throw EXCEPTION("Callback already set"); + } + + g_surmx.cb = func; + g_surmx.cb_arg = arg; + + return CELL_OK; +} + +s32 cellSurMixerRemoveNotifyCallback(vm::ptr func) +{ + libmixer.warning("cellSurMixerRemoveNotifyCallback(func=*0x%x)", func); + + if (g_surmx.cb != func) + { + throw EXCEPTION("Callback not set"); + } + + g_surmx.cb = vm::null; + + return CELL_OK; +} + +s32 cellSurMixerStart() +{ + libmixer.warning("cellSurMixerStart()"); + + const auto g_audio = fxm::get(); + + if (g_surmx.audio_port >= AUDIO_PORT_COUNT) + { + return CELL_LIBMIXER_ERROR_NOT_INITIALIZED; + } + + g_audio->ports[g_surmx.audio_port].state.compare_and_swap(audio_port_state::opened, audio_port_state::started); + + return CELL_OK; +} + +s32 cellSurMixerSetParameter(u32 param, float value) +{ + libmixer.todo("cellSurMixerSetParameter(param=0x%x, value=%f)", param, value); + return CELL_OK; +} + +s32 cellSurMixerFinalize() +{ + libmixer.warning("cellSurMixerFinalize()"); + + const auto g_audio = fxm::get(); + + if (g_surmx.audio_port >= AUDIO_PORT_COUNT) + { + return CELL_LIBMIXER_ERROR_NOT_INITIALIZED; + } + + g_audio->ports[g_surmx.audio_port].state.compare_and_swap(audio_port_state::opened, audio_port_state::closed); + + return CELL_OK; +} + +s32 cellSurMixerSurBusAddData(u32 busNo, u32 offset, vm::ptr addr, u32 samples) +{ + if (busNo < 8 && samples == 256 && offset == 0) + { + libmixer.trace("cellSurMixerSurBusAddData(busNo=%d, offset=0x%x, addr=0x%x, samples=%d)", busNo, offset, addr, samples); + } + else + { + libmixer.todo("cellSurMixerSurBusAddData(busNo=%d, offset=0x%x, addr=0x%x, samples=%d)", busNo, offset, addr, samples); + return CELL_OK; + } + + std::lock_guard lock(g_surmx.mutex); + + for (u32 i = 0; i < samples; i++) + { + // reverse byte order and mix + g_surmx.mixdata[i * 8 + busNo] += addr[i]; + } + + return CELL_OK; +} + +s32 cellSurMixerChStripSetParameter(u32 type, u32 index, vm::ptr param) +{ + libmixer.todo("cellSurMixerChStripSetParameter(type=%d, index=%d, param=*0x%x)", type, index, param); + return CELL_OK; +} + +s32 cellSurMixerPause(u32 type) +{ + libmixer.warning("cellSurMixerPause(type=%d)", type); + + const auto g_audio = fxm::get(); + + if (g_surmx.audio_port >= AUDIO_PORT_COUNT) + { + return CELL_LIBMIXER_ERROR_NOT_INITIALIZED; + } + + g_audio->ports[g_surmx.audio_port].state.compare_and_swap(audio_port_state::started, audio_port_state::opened); + + return CELL_OK; +} + +s32 cellSurMixerGetCurrentBlockTag(vm::ptr tag) +{ + libmixer.trace("cellSurMixerGetCurrentBlockTag(tag=*0x%x)", tag); + + *tag = g_surmx.mixcount; + return CELL_OK; +} + +s32 cellSurMixerGetTimestamp(u64 tag, vm::ptr stamp) +{ + libmixer.trace("cellSurMixerGetTimestamp(tag=0x%llx, stamp=*0x%x)", tag, stamp); + + const auto g_audio = fxm::get(); + *stamp = g_audio->start_time + (tag) * 256000000 / 48000; // ??? + return CELL_OK; +} + +void cellSurMixerBeep(u32 arg) +{ + libmixer.todo("cellSurMixerBeep(arg=%d)", arg); + return; +} + +f32 cellSurMixerUtilGetLevelFromDB(f32 dB) +{ + libmixer.todo("cellSurMixerUtilGetLevelFromDB(dB=%f)", dB); + throw EXCEPTION("TODO"); +} + +f32 cellSurMixerUtilGetLevelFromDBIndex(s32 index) +{ + libmixer.todo("cellSurMixerUtilGetLevelFromDBIndex(index=%d)", index); + throw EXCEPTION("TODO"); +} + +f32 cellSurMixerUtilNoteToRatio(u8 refNote, u8 note) +{ + libmixer.todo("cellSurMixerUtilNoteToRatio(refNote=%d, note=%d)", refNote, note); + throw EXCEPTION("TODO"); +} + +DECLARE(ppu_module_manager::libmixer)("libmixer", []() +{ + REG_FUNC(libmixer, cellAANAddData); + REG_FUNC(libmixer, cellAANConnect); + REG_FUNC(libmixer, cellAANDisconnect); + + REG_FUNC(libmixer, cellSurMixerCreate); + REG_FUNC(libmixer, cellSurMixerGetAANHandle); + REG_FUNC(libmixer, cellSurMixerChStripGetAANPortNo); + REG_FUNC(libmixer, cellSurMixerSetNotifyCallback); + REG_FUNC(libmixer, cellSurMixerRemoveNotifyCallback); + REG_FUNC(libmixer, cellSurMixerStart); + REG_FUNC(libmixer, cellSurMixerSetParameter); + REG_FUNC(libmixer, cellSurMixerFinalize); + REG_FUNC(libmixer, cellSurMixerSurBusAddData); + REG_FUNC(libmixer, cellSurMixerChStripSetParameter); + REG_FUNC(libmixer, cellSurMixerPause); + REG_FUNC(libmixer, cellSurMixerGetCurrentBlockTag); + REG_FUNC(libmixer, cellSurMixerGetTimestamp); + REG_FUNC(libmixer, cellSurMixerBeep); + + REG_FUNC(libmixer, cellSSPlayerCreate); + REG_FUNC(libmixer, cellSSPlayerRemove); + REG_FUNC(libmixer, cellSSPlayerSetWave); + REG_FUNC(libmixer, cellSSPlayerPlay); + REG_FUNC(libmixer, cellSSPlayerStop); + REG_FUNC(libmixer, cellSSPlayerSetParam); + REG_FUNC(libmixer, cellSSPlayerGetState); + + REG_FUNC(libmixer, cellSurMixerUtilGetLevelFromDB); + REG_FUNC(libmixer, cellSurMixerUtilGetLevelFromDBIndex); + REG_FUNC(libmixer, cellSurMixerUtilNoteToRatio); +}); diff --git a/rpcs3/Emu/SysCalls/Modules/libmixer.h b/rpcs3/Emu/Cell/Modules/libmixer.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/libmixer.h rename to rpcs3/Emu/Cell/Modules/libmixer.h diff --git a/rpcs3/Emu/SysCalls/Modules/libsnd3.cpp b/rpcs3/Emu/Cell/Modules/libsnd3.cpp similarity index 71% rename from rpcs3/Emu/SysCalls/Modules/libsnd3.cpp rename to rpcs3/Emu/Cell/Modules/libsnd3.cpp index 74e5f84fbe..861039754d 100644 --- a/rpcs3/Emu/SysCalls/Modules/libsnd3.cpp +++ b/rpcs3/Emu/Cell/Modules/libsnd3.cpp @@ -1,9 +1,10 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "libsnd3.h" +LOG_CHANNEL(libsnd3); + s32 cellSnd3Init(u32 maxVoice, u32 samples, vm::ptr queue) { UNIMPLEMENTED_FUNC(libsnd3); @@ -290,56 +291,56 @@ s32 cellSnd3SMFGetKeyOnID(u32 smfID, u32 midiChannel, vm::ptr keyOnID) } -Module<> libsnd3("libsnd3", []() +DECLARE(ppu_module_manager::libsnd3)("libsnd3", []() { - REG_SUB(libsnd3,, cellSnd3Init); - REG_SUB(libsnd3,, cellSnd3Exit); - REG_SUB(libsnd3,, cellSnd3Note2Pitch); - REG_SUB(libsnd3,, cellSnd3Pitch2Note); - REG_SUB(libsnd3,, cellSnd3SetOutputMode); - REG_SUB(libsnd3,, cellSnd3Synthesis); - REG_SUB(libsnd3,, cellSnd3SynthesisEx); - REG_SUB(libsnd3,, cellSnd3BindSoundData); - REG_SUB(libsnd3,, cellSnd3UnbindSoundData); - REG_SUB(libsnd3,, cellSnd3NoteOnByTone); - REG_SUB(libsnd3,, cellSnd3KeyOnByTone); - REG_SUB(libsnd3,, cellSnd3VoiceNoteOnByTone); - REG_SUB(libsnd3,, cellSnd3VoiceKeyOnByTone); - REG_SUB(libsnd3,, cellSnd3VoiceSetReserveMode); - REG_SUB(libsnd3,, cellSnd3VoiceSetSustainHold); - REG_SUB(libsnd3,, cellSnd3VoiceKeyOff); - REG_SUB(libsnd3,, cellSnd3VoiceSetPitch); - REG_SUB(libsnd3,, cellSnd3VoiceSetVelocity); - REG_SUB(libsnd3,, cellSnd3VoiceSetPanpot); - REG_SUB(libsnd3,, cellSnd3VoiceSetPanpotEx); - REG_SUB(libsnd3,, cellSnd3VoiceSetPitchBend); - REG_SUB(libsnd3,, cellSnd3VoiceAllKeyOff); - REG_SUB(libsnd3,, cellSnd3VoiceGetEnvelope); - REG_SUB(libsnd3,, cellSnd3VoiceGetStatus); - REG_SUB(libsnd3,, cellSnd3KeyOffByID); - REG_SUB(libsnd3,, cellSnd3GetVoice); - REG_SUB(libsnd3,, cellSnd3GetVoiceByID); - REG_SUB(libsnd3,, cellSnd3NoteOn); - REG_SUB(libsnd3,, cellSnd3NoteOff); - REG_SUB(libsnd3,, cellSnd3SetSustainHold); - REG_SUB(libsnd3,, cellSnd3SetEffectType); - REG_SUB(libsnd3,, cellSnd3SMFBind); - REG_SUB(libsnd3,, cellSnd3SMFUnbind); - REG_SUB(libsnd3,, cellSnd3SMFPlay); - REG_SUB(libsnd3,, cellSnd3SMFPlayEx); - REG_SUB(libsnd3,, cellSnd3SMFPause); - REG_SUB(libsnd3,, cellSnd3SMFResume); - REG_SUB(libsnd3,, cellSnd3SMFStop); - REG_SUB(libsnd3,, cellSnd3SMFAddTempo); - REG_SUB(libsnd3,, cellSnd3SMFGetTempo); - REG_SUB(libsnd3,, cellSnd3SMFSetPlayVelocity); - REG_SUB(libsnd3,, cellSnd3SMFGetPlayVelocity); - REG_SUB(libsnd3,, cellSnd3SMFSetPlayPanpot); - REG_SUB(libsnd3,, cellSnd3SMFSetPlayPanpotEx); - REG_SUB(libsnd3,, cellSnd3SMFGetPlayPanpot); - REG_SUB(libsnd3,, cellSnd3SMFGetPlayPanpotEx); - REG_SUB(libsnd3,, cellSnd3SMFGetPlayStatus); - REG_SUB(libsnd3,, cellSnd3SMFSetPlayChannel); - REG_SUB(libsnd3,, cellSnd3SMFGetPlayChannel); - REG_SUB(libsnd3,, cellSnd3SMFGetKeyOnID); + REG_FUNC(libsnd3, cellSnd3Init); + REG_FUNC(libsnd3, cellSnd3Exit); + REG_FUNC(libsnd3, cellSnd3Note2Pitch); + REG_FUNC(libsnd3, cellSnd3Pitch2Note); + REG_FUNC(libsnd3, cellSnd3SetOutputMode); + REG_FUNC(libsnd3, cellSnd3Synthesis); + REG_FUNC(libsnd3, cellSnd3SynthesisEx); + REG_FUNC(libsnd3, cellSnd3BindSoundData); + REG_FUNC(libsnd3, cellSnd3UnbindSoundData); + REG_FUNC(libsnd3, cellSnd3NoteOnByTone); + REG_FUNC(libsnd3, cellSnd3KeyOnByTone); + REG_FUNC(libsnd3, cellSnd3VoiceNoteOnByTone); + REG_FUNC(libsnd3, cellSnd3VoiceKeyOnByTone); + REG_FUNC(libsnd3, cellSnd3VoiceSetReserveMode); + REG_FUNC(libsnd3, cellSnd3VoiceSetSustainHold); + REG_FUNC(libsnd3, cellSnd3VoiceKeyOff); + REG_FUNC(libsnd3, cellSnd3VoiceSetPitch); + REG_FUNC(libsnd3, cellSnd3VoiceSetVelocity); + REG_FUNC(libsnd3, cellSnd3VoiceSetPanpot); + REG_FUNC(libsnd3, cellSnd3VoiceSetPanpotEx); + REG_FUNC(libsnd3, cellSnd3VoiceSetPitchBend); + REG_FUNC(libsnd3, cellSnd3VoiceAllKeyOff); + REG_FUNC(libsnd3, cellSnd3VoiceGetEnvelope); + REG_FUNC(libsnd3, cellSnd3VoiceGetStatus); + REG_FUNC(libsnd3, cellSnd3KeyOffByID); + REG_FUNC(libsnd3, cellSnd3GetVoice); + REG_FUNC(libsnd3, cellSnd3GetVoiceByID); + REG_FUNC(libsnd3, cellSnd3NoteOn); + REG_FUNC(libsnd3, cellSnd3NoteOff); + REG_FUNC(libsnd3, cellSnd3SetSustainHold); + REG_FUNC(libsnd3, cellSnd3SetEffectType); + REG_FUNC(libsnd3, cellSnd3SMFBind); + REG_FUNC(libsnd3, cellSnd3SMFUnbind); + REG_FUNC(libsnd3, cellSnd3SMFPlay); + REG_FUNC(libsnd3, cellSnd3SMFPlayEx); + REG_FUNC(libsnd3, cellSnd3SMFPause); + REG_FUNC(libsnd3, cellSnd3SMFResume); + REG_FUNC(libsnd3, cellSnd3SMFStop); + REG_FUNC(libsnd3, cellSnd3SMFAddTempo); + REG_FUNC(libsnd3, cellSnd3SMFGetTempo); + REG_FUNC(libsnd3, cellSnd3SMFSetPlayVelocity); + REG_FUNC(libsnd3, cellSnd3SMFGetPlayVelocity); + REG_FUNC(libsnd3, cellSnd3SMFSetPlayPanpot); + REG_FUNC(libsnd3, cellSnd3SMFSetPlayPanpotEx); + REG_FUNC(libsnd3, cellSnd3SMFGetPlayPanpot); + REG_FUNC(libsnd3, cellSnd3SMFGetPlayPanpotEx); + REG_FUNC(libsnd3, cellSnd3SMFGetPlayStatus); + REG_FUNC(libsnd3, cellSnd3SMFSetPlayChannel); + REG_FUNC(libsnd3, cellSnd3SMFGetPlayChannel); + REG_FUNC(libsnd3, cellSnd3SMFGetKeyOnID); }); diff --git a/rpcs3/Emu/SysCalls/Modules/libsnd3.h b/rpcs3/Emu/Cell/Modules/libsnd3.h similarity index 97% rename from rpcs3/Emu/SysCalls/Modules/libsnd3.h rename to rpcs3/Emu/Cell/Modules/libsnd3.h index 978d8b9a77..5afd3024b4 100644 --- a/rpcs3/Emu/SysCalls/Modules/libsnd3.h +++ b/rpcs3/Emu/Cell/Modules/libsnd3.h @@ -51,5 +51,3 @@ struct CellSnd3RequestQueueCtx vm::bptr rearQueue; be_t rearQueueSize; }; - -extern Module<> libsnd3; diff --git a/rpcs3/Emu/SysCalls/Modules/libsynth2.cpp b/rpcs3/Emu/Cell/Modules/libsynth2.cpp similarity index 75% rename from rpcs3/Emu/SysCalls/Modules/libsynth2.cpp rename to rpcs3/Emu/Cell/Modules/libsynth2.cpp index ad341c25c9..532932a2d7 100644 --- a/rpcs3/Emu/SysCalls/Modules/libsynth2.cpp +++ b/rpcs3/Emu/Cell/Modules/libsynth2.cpp @@ -1,9 +1,10 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "libsynth2.h" +LOG_CHANNEL(libsynth2); + s32 cellSoundSynth2Config(s16 param, s32 value) { libsynth2.todo("cellSoundSynth2Config(param=%d, value=%d)", param, value); @@ -104,23 +105,23 @@ u16 cellSoundSynth2Pitch2Note(u16 center_note, u16 center_fine, u16 pitch) } -Module<> libsynth2("libsynth2", []() +DECLARE(ppu_module_manager::libsynth2)("libsynth2", []() { - REG_SUB(libsynth2,, cellSoundSynth2Config); - REG_SUB(libsynth2,, cellSoundSynth2Init); - REG_SUB(libsynth2,, cellSoundSynth2Exit); - REG_SUB(libsynth2,, cellSoundSynth2SetParam); - REG_SUB(libsynth2,, cellSoundSynth2GetParam); - REG_SUB(libsynth2,, cellSoundSynth2SetSwitch); - REG_SUB(libsynth2,, cellSoundSynth2GetSwitch); - REG_SUB(libsynth2,, cellSoundSynth2SetAddr); - REG_SUB(libsynth2,, cellSoundSynth2GetAddr); - REG_SUB(libsynth2,, cellSoundSynth2SetEffectAttr); - REG_SUB(libsynth2,, cellSoundSynth2SetEffectMode); - REG_SUB(libsynth2,, cellSoundSynth2SetCoreAttr); - REG_SUB(libsynth2,, cellSoundSynth2Generate); - REG_SUB(libsynth2,, cellSoundSynth2VoiceTrans); - REG_SUB(libsynth2,, cellSoundSynth2VoiceTransStatus); - REG_SUB(libsynth2,, cellSoundSynth2Note2Pitch); - REG_SUB(libsynth2,, cellSoundSynth2Pitch2Note); + REG_FUNC(libsynth2, cellSoundSynth2Config); + REG_FUNC(libsynth2, cellSoundSynth2Init); + REG_FUNC(libsynth2, cellSoundSynth2Exit); + REG_FUNC(libsynth2, cellSoundSynth2SetParam); + REG_FUNC(libsynth2, cellSoundSynth2GetParam); + REG_FUNC(libsynth2, cellSoundSynth2SetSwitch); + REG_FUNC(libsynth2, cellSoundSynth2GetSwitch); + REG_FUNC(libsynth2, cellSoundSynth2SetAddr); + REG_FUNC(libsynth2, cellSoundSynth2GetAddr); + REG_FUNC(libsynth2, cellSoundSynth2SetEffectAttr); + REG_FUNC(libsynth2, cellSoundSynth2SetEffectMode); + REG_FUNC(libsynth2, cellSoundSynth2SetCoreAttr); + REG_FUNC(libsynth2, cellSoundSynth2Generate); + REG_FUNC(libsynth2, cellSoundSynth2VoiceTrans); + REG_FUNC(libsynth2, cellSoundSynth2VoiceTransStatus); + REG_FUNC(libsynth2, cellSoundSynth2Note2Pitch); + REG_FUNC(libsynth2, cellSoundSynth2Pitch2Note); }); diff --git a/rpcs3/Emu/SysCalls/Modules/libsynth2.h b/rpcs3/Emu/Cell/Modules/libsynth2.h similarity index 92% rename from rpcs3/Emu/SysCalls/Modules/libsynth2.h rename to rpcs3/Emu/Cell/Modules/libsynth2.h index 6b972ad7cf..cd2ce07f89 100644 --- a/rpcs3/Emu/SysCalls/Modules/libsynth2.h +++ b/rpcs3/Emu/Cell/Modules/libsynth2.h @@ -17,5 +17,3 @@ struct CellSoundSynth2EffectAttr be_t delay; be_t feedback; }; - -extern Module<> libsynth2; diff --git a/rpcs3/Emu/SysCalls/Modules/sceNp.cpp b/rpcs3/Emu/Cell/Modules/sceNp.cpp similarity index 95% rename from rpcs3/Emu/SysCalls/Modules/sceNp.cpp rename to rpcs3/Emu/Cell/Modules/sceNp.cpp index d3204c22f3..80c682eeed 100644 --- a/rpcs3/Emu/SysCalls/Modules/sceNp.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNp.cpp @@ -1,16 +1,12 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/state.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/SysCalls/lv2/sys_process.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsDir.h" +#include "Emu/Cell/lv2/sys_process.h" #include "Crypto/unedat.h" #include "sceNp.h" -extern Module<> sceNp; +LOG_CHANNEL(sceNp); s32 sceNpInit(u32 poolsize, vm::ptr poolptr) { @@ -42,9 +38,11 @@ s32 sceNpTerm() s32 npDrmIsAvailable(u32 k_licensee_addr, vm::cptr drm_path) { - if (!Emu.GetVFS().ExistsFile(drm_path.get_ptr())) + const std::string& enc_drm_path = drm_path.get_ptr(); + + if (!fs::is_file(vfs::get(enc_drm_path))) { - sceNp.warning("npDrmIsAvailable(): '%s' not found", drm_path.get_ptr()); + sceNp.warning("npDrmIsAvailable(): '%s' not found", enc_drm_path); return CELL_ENOENT; } @@ -60,49 +58,40 @@ s32 npDrmIsAvailable(u32 k_licensee_addr, vm::cptr drm_path) } } - sceNp.warning("npDrmIsAvailable(): Found DRM license file at %s", drm_path.get_ptr()); - sceNp.warning("npDrmIsAvailable(): Using k_licensee 0x%s", k_licensee_str.c_str()); + sceNp.warning("npDrmIsAvailable(): Found DRM license file at %s", enc_drm_path); + sceNp.warning("npDrmIsAvailable(): Using k_licensee 0x%s", k_licensee_str); // Set the necessary file paths. - std::string drm_file_name = fmt::AfterLast(drm_path.get_ptr(), '/'); + const std::string& drm_file_name = enc_drm_path.substr(enc_drm_path.find_last_of('/') + 1); // TODO: Make more explicit what this actually does (currently it copies "XXXXXXXX" from drm_path (== "/dev_hdd0/game/XXXXXXXXX/*" assumed) - std::string titleID(&drm_path[15], 9); + const std::string& drm_file_dir = enc_drm_path.substr(15); + const std::string& title_id = drm_file_dir.substr(0, drm_file_dir.find_first_of('/')); - // TODO: These shouldn't use current dir - std::string enc_drm_path = drm_path.get_ptr(); - std::string dec_drm_path = "/dev_hdd1/cache/" + drm_file_name; - std::string pf_str("00000001"); // TODO: Allow multiple profiles. Use default for now. - std::string rap_path("/dev_hdd0/home/" + pf_str + "/exdata/"); + const std::string& dec_drm_path = "/dev_hdd1/cache/" + drm_file_name; + + std::string rap_lpath = vfs::get("/dev_hdd0/home/00000001/exdata/"); // TODO: Allow multiple profiles. Use default for now. // Search for a compatible RAP file. - for (const auto entry : vfsDir(rap_path)) + for (const auto& entry : fs::dir(rap_lpath)) { - if (entry->name.find(titleID) != std::string::npos) + if (entry.name.find(title_id) != -1) { - rap_path += entry->name; + rap_lpath += entry.name; break; } } - if (rap_path.back() == '/') + if (rap_lpath.back() == '/') { - sceNp.warning("npDrmIsAvailable(): Can't find RAP file for '%s' (titleID='%s')", drm_path.get_ptr(), titleID); - rap_path.clear(); + sceNp.warning("npDrmIsAvailable(): Can't find RAP file for %s", enc_drm_path); + rap_lpath.clear(); } - // Decrypt this EDAT using the supplied k_licensee and matching RAP file. - std::string enc_drm_path_local, dec_drm_path_local, rap_path_local; + const std::string& enc_drm_path_local = vfs::get(enc_drm_path); + const std::string& dec_drm_path_local = vfs::get(dec_drm_path); - Emu.GetVFS().GetDevice(enc_drm_path, enc_drm_path_local); - Emu.GetVFS().GetDevice(dec_drm_path, dec_drm_path_local); - - if (rap_path.size()) - { - Emu.GetVFS().GetDevice(rap_path, rap_path_local); - } - - if (DecryptEDAT(enc_drm_path_local, dec_drm_path_local, 8, rap_path_local, k_licensee, false) >= 0) + if (DecryptEDAT(enc_drm_path_local, dec_drm_path_local, 8, rap_lpath, k_licensee, false) >= 0) { // If decryption succeeds, replace the encrypted file with it. fs::remove_file(enc_drm_path_local); @@ -1526,7 +1515,7 @@ s32 _Z32_sce_np_sysutil_cxml_prepare_docPN16sysutil_cxmlutil11FixedMemoryERN4cxm } -Module<> sceNp("sceNp", []() +DECLARE(ppu_module_manager::sceNp)("sceNp", []() { REG_FUNC(sceNp, sceNpInit); REG_FUNC(sceNp, sceNpTerm); diff --git a/rpcs3/Emu/SysCalls/Modules/sceNp.h b/rpcs3/Emu/Cell/Modules/sceNp.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/sceNp.h rename to rpcs3/Emu/Cell/Modules/sceNp.h diff --git a/rpcs3/Emu/SysCalls/Modules/sceNp2.cpp b/rpcs3/Emu/Cell/Modules/sceNp2.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/sceNp2.cpp rename to rpcs3/Emu/Cell/Modules/sceNp2.cpp index 0c6cf5260b..c424aaf877 100644 --- a/rpcs3/Emu/SysCalls/Modules/sceNp2.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNp2.cpp @@ -1,11 +1,10 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "sceNp.h" #include "sceNp2.h" -extern Module<> sceNp2; +LOG_CHANNEL(sceNp2); s32 sceNp2Init(u32 poolsize, vm::ptr poolptr) { @@ -384,7 +383,7 @@ s32 sceNpMatching2RegisterRoomMessageCallback() } -Module<> sceNp2("sceNp2", []() +DECLARE(ppu_module_manager::sceNp2)("sceNp2", []() { REG_FUNC(sceNp2, sceNpMatching2DestroyContext); REG_FUNC(sceNp2, sceNpMatching2LeaveLobby); diff --git a/rpcs3/Emu/SysCalls/Modules/sceNp2.h b/rpcs3/Emu/Cell/Modules/sceNp2.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/sceNp2.h rename to rpcs3/Emu/Cell/Modules/sceNp2.h diff --git a/rpcs3/Emu/SysCalls/Modules/sceNpClans.cpp b/rpcs3/Emu/Cell/Modules/sceNpClans.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/sceNpClans.cpp rename to rpcs3/Emu/Cell/Modules/sceNpClans.cpp index 2bf714ad12..e3d7daca27 100644 --- a/rpcs3/Emu/SysCalls/Modules/sceNpClans.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNpClans.cpp @@ -1,12 +1,11 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "sceNp.h" #include "sceNpClans.h" -extern Module<> sceNpClans; +LOG_CHANNEL(sceNpClans); s32 sceNpClansInit(vm::ptr commId, vm::ptr passphrase, vm::ptr pool, vm::ptr poolSize, u32 flags) { @@ -255,7 +254,7 @@ s32 sceNpClansRemoveChallenge() return CELL_OK; } -Module<> sceNpClans("sceNpClans", []() +DECLARE(ppu_module_manager::sceNpClans)("sceNpClans", []() { REG_FUNC(sceNpClans, sceNpClansInit); REG_FUNC(sceNpClans, sceNpClansTerm); diff --git a/rpcs3/Emu/SysCalls/Modules/sceNpClans.h b/rpcs3/Emu/Cell/Modules/sceNpClans.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/sceNpClans.h rename to rpcs3/Emu/Cell/Modules/sceNpClans.h diff --git a/rpcs3/Emu/SysCalls/Modules/sceNpCommerce2.cpp b/rpcs3/Emu/Cell/Modules/sceNpCommerce2.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/sceNpCommerce2.cpp rename to rpcs3/Emu/Cell/Modules/sceNpCommerce2.cpp index c1bdbf23d9..ba8f47ce7e 100644 --- a/rpcs3/Emu/SysCalls/Modules/sceNpCommerce2.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNpCommerce2.cpp @@ -1,10 +1,9 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "sceNpCommerce2.h" -extern Module<> sceNpCommerce2; +LOG_CHANNEL(sceNpCommerce2); s32 sceNpCommerce2ExecuteStoreBrowse() { @@ -315,7 +314,7 @@ s32 sceNpCommerce2DoServiceListFinishAsync() throw EXCEPTION(""); } -Module<> sceNpCommerce2("sceNpCommerce2", []() +DECLARE(ppu_module_manager::sceNpCommerce2)("sceNpCommerce2", []() { REG_FUNC(sceNpCommerce2, sceNpCommerce2ExecuteStoreBrowse); REG_FUNC(sceNpCommerce2, sceNpCommerce2GetStoreBrowseUserdata); diff --git a/rpcs3/Emu/SysCalls/Modules/sceNpCommerce2.h b/rpcs3/Emu/Cell/Modules/sceNpCommerce2.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/sceNpCommerce2.h rename to rpcs3/Emu/Cell/Modules/sceNpCommerce2.h diff --git a/rpcs3/Emu/SysCalls/Modules/sceNpSns.cpp b/rpcs3/Emu/Cell/Modules/sceNpSns.cpp similarity index 92% rename from rpcs3/Emu/SysCalls/Modules/sceNpSns.cpp rename to rpcs3/Emu/Cell/Modules/sceNpSns.cpp index 26b61aed15..15dc2c7153 100644 --- a/rpcs3/Emu/SysCalls/Modules/sceNpSns.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNpSns.cpp @@ -1,9 +1,9 @@ #include "stdafx.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "sceNpSns.h" -extern Module<> sceNpSns; +LOG_CHANNEL(sceNpSns); s32 sceNpSnsFbInit(vm::ptr params) { @@ -66,7 +66,7 @@ s32 sceNpSnsFbLoadThrottle() } -Module<> sceNpSns("sceNpSns", []() +DECLARE(ppu_module_manager::sceNpSns)("sceNpSns", []() { REG_FUNC(sceNpSns, sceNpSnsFbInit); REG_FUNC(sceNpSns, sceNpSnsFbTerm); diff --git a/rpcs3/Emu/SysCalls/Modules/sceNpSns.h b/rpcs3/Emu/Cell/Modules/sceNpSns.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/sceNpSns.h rename to rpcs3/Emu/Cell/Modules/sceNpSns.h diff --git a/rpcs3/Emu/SysCalls/Modules/sceNpTrophy.cpp b/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp similarity index 92% rename from rpcs3/Emu/SysCalls/Modules/sceNpTrophy.cpp rename to rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp index 98756e976c..a0848e2621 100644 --- a/rpcs3/Emu/SysCalls/Modules/sceNpTrophy.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp @@ -1,33 +1,29 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/IdManager.h" #include "Emu/System.h" -#include "Emu/state.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/IdManager.h" +#include "Emu/Cell/PPUModule.h" #include "Utilities/rXml.h" #include "Loader/TRP.h" #include "Loader/TROPUSR.h" -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsDir.h" -#include "Emu/FS/vfsFileBase.h" + #include "sceNp.h" #include "sceNpTrophy.h" -extern Module<> sceNpTrophy; +LOG_CHANNEL(sceNpTrophy); struct trophy_context_t { - const u32 id = idm::get_last_id(); + const u32 id{}; std::string trp_name; - std::unique_ptr trp_stream; + fs::file trp_stream; std::unique_ptr tropusr; }; struct trophy_handle_t { - const u32 id = idm::get_last_id(); + const u32 id{}; }; // Functions @@ -103,10 +99,10 @@ s32 sceNpTrophyCreateContext(vm::ptr context, vm::cptrdata, commId->num); // open trophy pack file - std::unique_ptr stream(Emu.GetVFS().OpenFile("/app_home/../TROPDIR/" + name + "/TROPHY.TRP", fom::read)); + fs::file stream(vfs::get("/app_home/../TROPDIR/" + name + "/TROPHY.TRP")); // check if exists and opened - if (!stream || !stream->IsOpened()) + if (!stream) { return SCE_NP_TROPHY_ERROR_CONF_DOES_NOT_EXIST; } @@ -158,7 +154,7 @@ s32 sceNpTrophyRegisterContext(PPUThread& CPU, u32 context, u32 handle, vm::ptr< return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE; } - TRPLoader trp(*ctxt->trp_stream); + TRPLoader trp(ctxt->trp_stream); if (!trp.LoadHeader()) { sceNpTrophy.error("sceNpTrophyRegisterContext(): SCE_NP_TROPHY_ERROR_ILLEGAL_UPDATE"); @@ -169,7 +165,7 @@ s32 sceNpTrophyRegisterContext(PPUThread& CPU, u32 context, u32 handle, vm::ptr< const size_t kTargetBufferLength = 31; char target[kTargetBufferLength + 1]; target[kTargetBufferLength] = 0; - strcpy_trunc(target, fmt::format("TROP_%02d.SFM", rpcs3::config.system.language.value())); + strcpy_trunc(target, fmt::format("TROP_%02d.SFM", /*rpcs3::config.system.language.value()*/0)); if (trp.ContainsEntry(target)) { @@ -191,7 +187,7 @@ s32 sceNpTrophyRegisterContext(PPUThread& CPU, u32 context, u32 handle, vm::ptr< for (s32 i = 0; i <= 18; i++) { strcpy_trunc(target, fmt::format("TROP_%02d.SFM", i)); - if (i != rpcs3::config.system.language.value()) + if (i != /*rpcs3::config.system.language.value()*/0) { trp.RemoveEntry(target); } @@ -237,7 +233,7 @@ s32 sceNpTrophyGetRequiredDiskSpace(u32 context, u32 handle, vm::ptr reqspa } // TODO: This is not accurate. It's just an approximation of the real value - *reqspace = ctxt->trp_stream->GetSize(); + *reqspace = ctxt->trp_stream.size(); return CELL_OK; } @@ -267,9 +263,12 @@ s32 sceNpTrophyGetGameInfo(u32 context, u32 handle, vm::ptrtrp_name + "/TROPCONF.SFM"); + + // TODO: rXmlDocument can open only real file + ASSERT(!fs::get_virtual_device(path)); rXmlDocument doc; - Emu.GetVFS().GetDevice("/dev_hdd0/home/00000001/trophy/" + ctxt->trp_name + "/TROPCONF.SFM", path); // TODO: Get the path of the current user doc.Load(path); std::string titleName; @@ -394,9 +393,12 @@ s32 sceNpTrophyGetTrophyInfo(u32 context, u32 handle, s32 trophyId, vm::ptrtrp_name + "/TROPCONF.SFM", path); // TODO: Get the path of the current user + // TODO: Get the path of the current user + const std::string& path = vfs::get("/dev_hdd0/home/00000001/trophy/" + ctxt->trp_name + "/TROPCONF.SFM"); + + // TODO: rXmlDocument can open only real file + ASSERT(!fs::get_virtual_device(path)); + rXmlDocument doc; doc.Load(path); std::string name; @@ -455,7 +457,7 @@ s32 sceNpTrophyGetTrophyIcon(u32 context, u32 handle, s32 trophyId, vm::ptr sceNpTrophy("sceNpTrophy", []() +DECLARE(ppu_module_manager::sceNpTrophy)("sceNpTrophy", []() { REG_FUNC(sceNpTrophy, sceNpTrophyGetGameProgress); REG_FUNC(sceNpTrophy, sceNpTrophyRegisterContext); diff --git a/rpcs3/Emu/SysCalls/Modules/sceNpTrophy.h b/rpcs3/Emu/Cell/Modules/sceNpTrophy.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/sceNpTrophy.h rename to rpcs3/Emu/Cell/Modules/sceNpTrophy.h diff --git a/rpcs3/Emu/SysCalls/Modules/sceNpTus.cpp b/rpcs3/Emu/Cell/Modules/sceNpTus.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/sceNpTus.cpp rename to rpcs3/Emu/Cell/Modules/sceNpTus.cpp index 4eb33b0cee..1ee55bf9f6 100644 --- a/rpcs3/Emu/SysCalls/Modules/sceNpTus.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNpTus.cpp @@ -1,11 +1,10 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "sceNp.h" #include "sceNpTus.h" -extern Module<> sceNpTus; +LOG_CHANNEL(sceNpTus); s32 sceNpTusInit() { @@ -333,7 +332,7 @@ s32 sceNpTusDeleteMultiSlotDataVUserAsync() return CELL_OK; } -Module<> sceNpTus("sceNpTus", []() +DECLARE(ppu_module_manager::sceNpTus)("sceNpTus", []() { REG_FUNC(sceNpTus, sceNpTusInit); REG_FUNC(sceNpTus, sceNpTusTerm); diff --git a/rpcs3/Emu/SysCalls/Modules/sceNpTus.h b/rpcs3/Emu/Cell/Modules/sceNpTus.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/sceNpTus.h rename to rpcs3/Emu/Cell/Modules/sceNpTus.h diff --git a/rpcs3/Emu/SysCalls/Modules/sceNpUtil.cpp b/rpcs3/Emu/Cell/Modules/sceNpUtil.cpp similarity index 83% rename from rpcs3/Emu/SysCalls/Modules/sceNpUtil.cpp rename to rpcs3/Emu/Cell/Modules/sceNpUtil.cpp index a0ad31b011..0dc924f80a 100644 --- a/rpcs3/Emu/SysCalls/Modules/sceNpUtil.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNpUtil.cpp @@ -1,11 +1,10 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "sceNp.h" #include "sceNpUtil.h" -extern Module<> sceNpUtil; +LOG_CHANNEL(sceNpUtil); s32 sceNpUtilBandwidthTestInitStart(u32 prio, size_t stack) { @@ -31,7 +30,7 @@ s32 sceNpUtilBandwidthTestAbort() return CELL_OK; } -Module<> sceNpUtil("sceNpUtil", []() +DECLARE(ppu_module_manager::sceNpUtil)("sceNpUtil", []() { REG_FUNC(sceNpUtil, sceNpUtilBandwidthTestInitStart); REG_FUNC(sceNpUtil, sceNpUtilBandwidthTestShutdown); diff --git a/rpcs3/Emu/Cell/Modules/sceNpUtil.h b/rpcs3/Emu/Cell/Modules/sceNpUtil.h new file mode 100644 index 0000000000..6f70f09bee --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/sceNpUtil.h @@ -0,0 +1 @@ +#pragma once diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp b/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp similarity index 51% rename from rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp rename to rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp index ca24e0bd8a..7140e8b37e 100644 --- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp @@ -1,80 +1,84 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/SysCalls/lv2/sys_interrupt.h" -#include "Emu/SysCalls/lv2/sys_process.h" +#include "Emu/Cell/lv2/sys_interrupt.h" +#include "Emu/Cell/lv2/sys_process.h" #include "sysPrxForUser.h" -extern Module<> sysPrxForUser; +LOG_CHANNEL(sysPrxForUser); extern u64 get_system_time(); -#define TLS_MAX 128 +vm::gvar sys_prx_version; // ??? + #define TLS_SYS 0x30 -u32 g_tls_start; // start of TLS memory area -u32 g_tls_size; +u32 g_tls_size = 0; // Size of TLS area per thread +u32 g_tls_addr = 0; // Start of TLS memory area +u32 g_tls_max = 0; // Max number of threads -std::array, TLS_MAX> g_tls_owners; +std::unique_ptr[]> g_tls_map; // I'd like to make it std::vector but it won't work -void sys_initialize_tls() +u32 ppu_alloc_tls() { - sysPrxForUser.trace("sys_initialize_tls()"); -} - -u32 ppu_get_tls(u32 thread) -{ - if (!g_tls_start) + for (u32 i = 0; i < g_tls_max; i++) { - g_tls_size = Emu.GetTLSMemsz() + TLS_SYS; - g_tls_start = vm::alloc(g_tls_size * TLS_MAX, vm::main); // memory for up to TLS_MAX threads - LOG_NOTICE(MEMORY, "Thread Local Storage initialized (g_tls_start=0x%x, user_size=0x%x)\n*** TLS segment addr: 0x%08x\n*** TLS segment size: 0x%08x", - g_tls_start, Emu.GetTLSMemsz(), Emu.GetTLSAddr(), Emu.GetTLSFilesz()); - } - - if (!thread) - { - return 0; - } - - for (u32 i = 0; i < TLS_MAX; i++) - { - if (g_tls_owners[i] == thread) + if (g_tls_map[i].exchange(true) == false) { - return g_tls_start + i * g_tls_size + TLS_SYS; // if already initialized, return TLS address - } - } - - for (u32 i = 0; i < TLS_MAX; i++) - { - u32 old = 0; - 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 - 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 + const u32 addr = g_tls_addr + i * g_tls_size; // Calculate TLS address + std::memset(vm::base(addr), 0, TLS_SYS); // Clear system area (TODO) + std::memcpy(vm::base(addr + TLS_SYS), vm::base(Emu.GetTLSAddr()), Emu.GetTLSFilesz()); // Copy TLS image + std::memset(vm::base(addr + TLS_SYS + Emu.GetTLSFilesz()), 0, Emu.GetTLSMemsz() - Emu.GetTLSFilesz()); // Clear the rest return addr; } } - throw EXCEPTION("Out of TLS memory"); + sysPrxForUser.error("ppu_alloc_tls(): out of TLS memory (max=%zu)", g_tls_max); + return 0; } -void ppu_free_tls(u32 thread) +void ppu_free_tls(u32 addr) { - for (auto& v : g_tls_owners) + // Calculate TLS position + const u32 i = (addr - g_tls_addr) / g_tls_size; + + if (addr < g_tls_addr || i >= g_tls_max || (addr - g_tls_addr) % g_tls_size) { - u32 old = thread; - if (v.compare_exchange_strong(old, 0)) - { - return; - } + sysPrxForUser.error("ppu_free_tls(0x%x): invalid address", addr); + return; } - LOG_ERROR(MEMORY, "TLS deallocation failed (thread=0x%x)", thread); + if (g_tls_map[i].exchange(false) == false) + { + sysPrxForUser.error("ppu_free_tls(0x%x): deallocation failed", addr); + return; + } +} + +void sys_initialize_tls(PPUThread& ppu, u64 main_thread_id, u32 tls_seg_addr, u32 tls_seg_size, u32 tls_mem_size) +{ + sysPrxForUser.notice("sys_initialize_tls(thread_id=0x%llx, addr=*0x%x, size=0x%x, mem_size=0x%x)", main_thread_id, tls_seg_addr, tls_seg_size, tls_mem_size); + + // Uninitialized TLS expected. + if (ppu.GPR[13] != 0) return; + + // Initialize TLS memory + g_tls_size = Emu.GetTLSMemsz() + TLS_SYS; + g_tls_addr = vm::alloc(0x20000, vm::main) + 0x30; + g_tls_max = (0xffd0 / g_tls_size) + (0x10000 / g_tls_size); + g_tls_map = std::make_unique[]>(g_tls_max); + + // Allocate TLS for main thread + ppu.GPR[13] = ppu_alloc_tls() + 0x7000 + TLS_SYS; + + sysPrxForUser.notice("TLS initialized (addr=0x%x, size=0x%x, max=0x%zu)", g_tls_addr - 0x30, g_tls_size, g_tls_max); + + // TODO + g_spu_printf_agcb = vm::null; + g_spu_printf_dgcb = vm::null; + g_spu_printf_atcb = vm::null; + g_spu_printf_dtcb = vm::null; } s64 sys_time_get_system_time() @@ -86,21 +90,32 @@ s64 sys_time_get_system_time() s64 _sys_process_atexitspawn() { - sysPrxForUser.trace("_sys_process_atexitspawn()"); + sysPrxForUser.todo("_sys_process_atexitspawn()"); return CELL_OK; } s64 _sys_process_at_Exitspawn() { - sysPrxForUser.trace("_sys_process_at_Exitspawn"); + sysPrxForUser.todo("_sys_process_at_Exitspawn"); return CELL_OK; } s32 sys_interrupt_thread_disestablish(PPUThread& ppu, u32 ih) { - sysPrxForUser.todo("sys_interrupt_thread_disestablish(ih=0x%x)", ih); + sysPrxForUser.notice("sys_interrupt_thread_disestablish(ih=0x%x)", ih); - return _sys_interrupt_thread_disestablish(ppu, ih, vm::var{}); + vm::var r13; + + // Call the syscall + if (s32 res = _sys_interrupt_thread_disestablish(ppu, ih, r13)) + { + return res; + } + + // Deallocate TLS + ppu_free_tls(vm::cast(*r13, HERE) - 0x7030); + + return CELL_OK; } s32 sys_process_is_stack(u32 p) @@ -166,20 +181,8 @@ extern void sysPrxForUser_sys_spu_init(); extern void sysPrxForUser_sys_game_init(); extern void sysPrxForUser_sys_libc_init(); -Module<> sysPrxForUser("sysPrxForUser", []() +DECLARE(ppu_module_manager::sysPrxForUser)("sysPrxForUser", []() { - g_tls_start = 0; - - for (auto& v : g_tls_owners) - { - v = 0; - } - - // Setup random number generator - srand(time(NULL)); - - //REG_VARIABLE(sysPrxForUser, sys_prx_version); // 0x7df066cf - sysPrxForUser_sys_lwmutex_init(); sysPrxForUser_sys_lwcond_init(); sysPrxForUser_sys_ppu_thread_init(); @@ -192,6 +195,8 @@ Module<> sysPrxForUser("sysPrxForUser", []() sysPrxForUser_sys_game_init(); sysPrxForUser_sys_libc_init(); + REG_VAR(sysPrxForUser, sys_prx_version); // 0x7df066cf + REG_FUNC(sysPrxForUser, sys_initialize_tls); REG_FUNC(sysPrxForUser, sys_time_get_system_time); diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.h b/rpcs3/Emu/Cell/Modules/sysPrxForUser.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/sysPrxForUser.h rename to rpcs3/Emu/Cell/Modules/sysPrxForUser.h diff --git a/rpcs3/Emu/SysCalls/Modules/sys_game.cpp b/rpcs3/Emu/Cell/Modules/sys_game.cpp similarity index 91% rename from rpcs3/Emu/SysCalls/Modules/sys_game.cpp rename to rpcs3/Emu/Cell/Modules/sys_game.cpp index 413cd98b5c..1c2d47b368 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_game.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_game.cpp @@ -1,12 +1,10 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/FS/VFS.h" #include "sysPrxForUser.h" -extern Module<> sysPrxForUser; +extern _log::channel sysPrxForUser; void sys_game_process_exitspawn(vm::cptr path, u32 argv_addr, u32 envp_addr, u32 data_addr, u32 data_size, u32 prio, u64 flags) { @@ -70,18 +68,11 @@ void sys_game_process_exitspawn(vm::cptr path, u32 argv_addr, u32 envp_add Emu.Pause(); sysPrxForUser.success("Process finished"); - Emu.CallAfter([=]() + Emu.CallAfter([=, path = vfs::get(_path)]() { Emu.Stop(); - - std::string real_path; - - Emu.GetVFS().GetDevice(_path.c_str(), real_path); - - Emu.BootGame(real_path, true); + Emu.BootGame(path, true); }); - - return; } void sys_game_process_exitspawn2(vm::cptr path, u32 argv_addr, u32 envp_addr, u32 data_addr, u32 data_size, u32 prio, u64 flags) @@ -146,15 +137,10 @@ void sys_game_process_exitspawn2(vm::cptr path, u32 argv_addr, u32 envp_ad Emu.Pause(); sysPrxForUser.success("Process finished"); - Emu.CallAfter([=]() + Emu.CallAfter([=, path = vfs::get(_path)]() { Emu.Stop(); - - std::string real_path; - - Emu.GetVFS().GetDevice(_path.c_str(), real_path); - - Emu.BootGame(real_path, true); + Emu.BootGame(path, true); }); return; diff --git a/rpcs3/Emu/SysCalls/Modules/sys_heap.cpp b/rpcs3/Emu/Cell/Modules/sys_heap.cpp similarity index 95% rename from rpcs3/Emu/SysCalls/Modules/sys_heap.cpp rename to rpcs3/Emu/Cell/Modules/sys_heap.cpp index cec953fdf1..13b344fd2f 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_heap.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_heap.cpp @@ -1,12 +1,11 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/IdManager.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/IdManager.h" +#include "Emu/Cell/PPUModule.h" #include "sysPrxForUser.h" -extern Module<> sysPrxForUser; +extern _log::channel sysPrxForUser; struct HeapInfo { diff --git a/rpcs3/Emu/SysCalls/Modules/sys_io.cpp b/rpcs3/Emu/Cell/Modules/sys_io.cpp similarity index 88% rename from rpcs3/Emu/SysCalls/Modules/sys_io.cpp rename to rpcs3/Emu/Cell/Modules/sys_io.cpp index eb7888f151..11d2202e5d 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_io.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_io.cpp @@ -1,7 +1,7 @@ #include "stdafx.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> sys_io; +LOG_CHANNEL(sys_io); extern void cellPad_init(); extern void cellKb_init(); @@ -39,7 +39,7 @@ s32 sys_config_unregister_service() } -Module<> sys_io("sys_io", []() +DECLARE(ppu_module_manager::sys_io)("sys_io", []() { cellPad_init(); cellKb_init(); diff --git a/rpcs3/Emu/Cell/Modules/sys_libc.cpp b/rpcs3/Emu/Cell/Modules/sys_libc.cpp new file mode 100644 index 0000000000..74fabd32b0 --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/sys_libc.cpp @@ -0,0 +1,24 @@ +#include "stdafx.h" +#include "Emu/System.h" +#include "Emu/Cell/PPUModule.h" +#include "Emu/Cell/PPUOpcodes.h" + +LOG_CHANNEL(sys_libc); + +namespace sys_libc_func +{ + void memcpy(vm::ptr dst, vm::cptr src, u32 size) + { + sys_libc.trace("memcpy(dst=*0x%x, src=*0x%x, size=0x%x)", dst, src, size); + + ::memcpy(dst.get_ptr(), src.get_ptr(), size); + } +} + +// Define macro for namespace +#define REG_FUNC_(name) REG_FNID(sys_libc, ppu_generate_id(#name), sys_libc_func::name) + +DECLARE(ppu_module_manager::sys_libc)("sys_libc", []() +{ + REG_FUNC_(memcpy); +}); diff --git a/rpcs3/Emu/SysCalls/Modules/sys_libc.cpp b/rpcs3/Emu/Cell/Modules/sys_libc_.cpp similarity index 83% rename from rpcs3/Emu/SysCalls/Modules/sys_libc.cpp rename to rpcs3/Emu/Cell/Modules/sys_libc_.cpp index 0045cdf423..61f91faee2 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_libc.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_libc_.cpp @@ -1,12 +1,10 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/Cell/PPUInstrTable.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> sys_libc; +extern _log::channel sysPrxForUser; -std::string ps3_fmt(PPUThread& context, vm::cptr fmt, u32 g_count, u32 f_count, u32 v_count) +// TODO +static std::string ps3_fmt(PPUThread& context, vm::cptr fmt, u32 g_count) { std::string result; @@ -33,7 +31,7 @@ std::string ps3_fmt(PPUThread& context, vm::cptr fmt, u32 g_count, u32 f_c if (*fmt == '*') { fmt++; - return context.get_next_gpr_arg(g_count, f_count, v_count); + return context.get_next_arg(g_count); } while (*fmt - '0' < 10) @@ -57,7 +55,7 @@ std::string ps3_fmt(PPUThread& context, vm::cptr fmt, u32 g_count, u32 f_c if (*++fmt == '*') { fmt++; - return context.get_next_gpr_arg(g_count, f_count, v_count); + return context.get_next_arg(g_count); } while (*fmt - '0' < 10) @@ -81,7 +79,7 @@ std::string ps3_fmt(PPUThread& context, vm::cptr fmt, u32 g_count, u32 f_c case 'i': { // signed decimal - const s64 value = context.get_next_gpr_arg(g_count, f_count, v_count); + const s64 value = context.get_next_arg(g_count); if (plus_sign || minus_sign || space_sign || number_sign || zero_padding || width || prec) break; @@ -92,7 +90,7 @@ std::string ps3_fmt(PPUThread& context, vm::cptr fmt, u32 g_count, u32 f_c case 'X': { // hexadecimal - const u64 value = context.get_next_gpr_arg(g_count, f_count, v_count); + const u64 value = context.get_next_arg(g_count); if (plus_sign || minus_sign || space_sign || prec) break; @@ -101,7 +99,7 @@ std::string ps3_fmt(PPUThread& context, vm::cptr fmt, u32 g_count, u32 f_c result += cf == 'x' ? "0x" : "0X"; } - const std::string& hex = cf == 'x' ? fmt::to_hex(value) : fmt::toupper(fmt::to_hex(value)); + const std::string& hex = cf == 'x' ? fmt::to_hex(value) : fmt::to_upper(fmt::to_hex(value)); if (hex.length() >= width) { @@ -120,7 +118,7 @@ std::string ps3_fmt(PPUThread& context, vm::cptr fmt, u32 g_count, u32 f_c case 's': { // string - auto string = vm::cptr::make(context.get_next_gpr_arg(g_count, f_count, v_count)); + auto string = vm::cptr::make(context.get_next_arg(g_count)); if (plus_sign || minus_sign || space_sign || number_sign || zero_padding || width || prec) break; @@ -130,7 +128,7 @@ std::string ps3_fmt(PPUThread& context, vm::cptr fmt, u32 g_count, u32 f_c case 'u': { // unsigned decimal - const u64 value = context.get_next_gpr_arg(g_count, f_count, v_count); + const u64 value = context.get_next_arg(g_count); if (plus_sign || minus_sign || space_sign || number_sign || zero_padding || width || prec) break; @@ -149,18 +147,6 @@ std::string ps3_fmt(PPUThread& context, vm::cptr fmt, u32 g_count, u32 f_c return result; } -namespace sys_libc_func -{ - void memcpy(vm::ptr dst, vm::cptr src, u32 size) - { - sys_libc.trace("memcpy(dst=*0x%x, src=*0x%x, size=0x%x)", dst, src, size); - - ::memcpy(dst.get_ptr(), src.get_ptr(), size); - } -} - -extern Module<> sysPrxForUser; - vm::ptr _sys_memset(vm::ptr dst, s32 value, u32 size) { sysPrxForUser.trace("_sys_memset(dst=*0x%x, value=%d, size=0x%x)", dst, value, size); @@ -328,7 +314,7 @@ s32 _sys_snprintf(PPUThread& ppu, vm::ptr dst, u32 count, vm::cptr f { sysPrxForUser.warning("_sys_snprintf(dst=*0x%x, count=%d, fmt=*0x%x, ...)", dst, count, fmt); - std::string result = ps3_fmt(ppu, fmt, va_args.g_count, va_args.f_count, va_args.v_count); + std::string result = ps3_fmt(ppu, fmt, va_args.count); sysPrxForUser.warning("*** '%s' -> '%s'", fmt.get_ptr(), result); @@ -350,7 +336,7 @@ s32 _sys_printf(PPUThread& ppu, vm::cptr fmt, ppu_va_args_t va_args) { sysPrxForUser.warning("_sys_printf(fmt=*0x%x, ...)", fmt); - _log::g_tty_file.log(ps3_fmt(ppu, fmt, va_args.g_count, va_args.f_count, va_args.v_count)); + _log::g_tty_file.log(ps3_fmt(ppu, fmt, va_args.count)); return CELL_OK; } @@ -414,19 +400,3 @@ void sysPrxForUser_sys_libc_init() REG_FUNC(sysPrxForUser, _sys_qsort); } - -Module<> sys_libc("sys_libc", []() -{ - using namespace PPU_instr; - - REG_SUB(sys_libc, sys_libc_func, memcpy, - SP_I(CMPLDI(cr7, r5, 7)), - SP_I(CLRLDI(r3, r3, 32)), - SP_I(CLRLDI(r4, r4, 32)), - SP_I(MR(r11, r3)), - SP_I(BGT(cr7, XXX & 0xff)), - SP_I(CMPDI(r5, 0)), - OPT_SP_I(MR(r9, r3)), - { SPET_MASKED_OPCODE, 0x4d820020, 0xffffffff }, - ); -}); diff --git a/rpcs3/Emu/SysCalls/Modules/sys_lv2dbg.cpp b/rpcs3/Emu/Cell/Modules/sys_lv2dbg.cpp similarity index 97% rename from rpcs3/Emu/SysCalls/Modules/sys_lv2dbg.cpp rename to rpcs3/Emu/Cell/Modules/sys_lv2dbg.cpp index c2c0fbf4bf..791e29ceed 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_lv2dbg.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_lv2dbg.cpp @@ -1,12 +1,11 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "sys_lv2dbg.h" -extern Module<> sys_lv2dbg; +LOG_CHANNEL(sys_lv2dbg); s32 sys_dbg_read_ppu_thread_context(u64 id, vm::ptr ppu_context) { @@ -190,7 +189,7 @@ s32 sys_dbg_set_mask_to_ppu_exception_handler(u64 mask, u64 flags) throw EXCEPTION(""); } -Module<> sys_lv2dbg("sys_lv2dbg", [] +DECLARE(ppu_module_manager::sys_lv2dbg)("sys_lv2dbg", [] { REG_FUNC(sys_lv2dbg, sys_dbg_read_ppu_thread_context); REG_FUNC(sys_lv2dbg, sys_dbg_read_spu_thread_context); diff --git a/rpcs3/Emu/SysCalls/Modules/sys_lv2dbg.h b/rpcs3/Emu/Cell/Modules/sys_lv2dbg.h similarity index 95% rename from rpcs3/Emu/SysCalls/Modules/sys_lv2dbg.h rename to rpcs3/Emu/Cell/Modules/sys_lv2dbg.h index 5661690945..e9a30c19fd 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_lv2dbg.h +++ b/rpcs3/Emu/Cell/Modules/sys_lv2dbg.h @@ -1,13 +1,13 @@ #pragma once -#include "Emu/SysCalls/lv2/sys_mutex.h" -#include "Emu/SysCalls/lv2/sys_cond.h" -#include "Emu/SysCalls/lv2/sys_rwlock.h" -#include "Emu/SysCalls/lv2/sys_event.h" -#include "Emu/SysCalls/lv2/sys_semaphore.h" -#include "Emu/SysCalls/lv2/sys_lwmutex.h" -#include "Emu/SysCalls/lv2/sys_lwcond.h" -#include "Emu/SysCalls/lv2/sys_event_flag.h" +#include "Emu/Cell/lv2/sys_mutex.h" +#include "Emu/Cell/lv2/sys_cond.h" +#include "Emu/Cell/lv2/sys_rwlock.h" +#include "Emu/Cell/lv2/sys_event.h" +#include "Emu/Cell/lv2/sys_semaphore.h" +#include "Emu/Cell/lv2/sys_lwmutex.h" +#include "Emu/Cell/lv2/sys_lwcond.h" +#include "Emu/Cell/lv2/sys_event_flag.h" namespace vm { using namespace ps3; } diff --git a/rpcs3/Emu/SysCalls/Modules/sys_lwcond_.cpp b/rpcs3/Emu/Cell/Modules/sys_lwcond_.cpp similarity index 94% rename from rpcs3/Emu/SysCalls/Modules/sys_lwcond_.cpp rename to rpcs3/Emu/Cell/Modules/sys_lwcond_.cpp index 8f6577dec7..d3bf78062c 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_lwcond_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_lwcond_.cpp @@ -1,15 +1,13 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/IdManager.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/SysCalls/lv2/sys_sync.h" -#include "Emu/SysCalls/lv2/sys_lwmutex.h" -#include "Emu/SysCalls/lv2/sys_lwcond.h" +#include "Emu/Cell/lv2/sys_lwmutex.h" +#include "Emu/Cell/lv2/sys_lwcond.h" #include "sysPrxForUser.h" -extern Module<> sysPrxForUser; +extern _log::channel sysPrxForUser; s32 sys_lwcond_create(vm::ptr lwcond, vm::ptr lwmutex, vm::ptr attr) { @@ -47,7 +45,7 @@ s32 sys_lwcond_signal(PPUThread& ppu, vm::ptr lwcond) //return _sys_lwcond_signal(lwcond->lwcond_queue, 0, -1, 2); } - if (lwmutex->vars.owner.load() == ppu.get_id()) + if (lwmutex->vars.owner.load() == ppu.id) { // if owns the mutex lwmutex->all_info++; @@ -105,7 +103,7 @@ s32 sys_lwcond_signal_all(PPUThread& ppu, vm::ptr lwcond) //return _sys_lwcond_signal_all(lwcond->lwcond_queue, lwmutex->sleep_queue, 2); } - if (lwmutex->vars.owner.load() == ppu.get_id()) + if (lwmutex->vars.owner.load() == ppu.id) { // if owns the mutex, call the syscall const s32 res = _sys_lwcond_signal_all(lwcond->lwcond_queue, lwmutex->sleep_queue, 1); @@ -162,7 +160,7 @@ s32 sys_lwcond_signal_to(PPUThread& ppu, vm::ptr lwcond, u32 ppu_t //return _sys_lwcond_signal(lwcond->lwcond_queue, 0, ppu_thread_id, 2); } - if (lwmutex->vars.owner.load() == ppu.get_id()) + if (lwmutex->vars.owner.load() == ppu.id) { // if owns the mutex lwmutex->all_info++; @@ -212,7 +210,7 @@ s32 sys_lwcond_wait(PPUThread& ppu, vm::ptr lwcond, u64 timeout) { sysPrxForUser.trace("sys_lwcond_wait(lwcond=*0x%x, timeout=0x%llx)", lwcond, timeout); - const be_t tid = ppu.get_id(); + const be_t tid = ppu.id; const vm::ptr lwmutex = lwcond->lwmutex; diff --git a/rpcs3/Emu/SysCalls/Modules/sys_lwmutex_.cpp b/rpcs3/Emu/Cell/Modules/sys_lwmutex_.cpp similarity index 94% rename from rpcs3/Emu/SysCalls/Modules/sys_lwmutex_.cpp rename to rpcs3/Emu/Cell/Modules/sys_lwmutex_.cpp index 347c180077..7e2e9fad4c 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_lwmutex_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_lwmutex_.cpp @@ -2,13 +2,12 @@ #include "Emu/Memory/Memory.h" #include "Emu/IdManager.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/SysCalls/lv2/sys_sync.h" -#include "Emu/SysCalls/lv2/sys_lwmutex.h" +#include "Emu/Cell/lv2/sys_lwmutex.h" #include "sysPrxForUser.h" -extern Module<> sysPrxForUser; +extern _log::channel sysPrxForUser; s32 sys_lwmutex_create(vm::ptr lwmutex, vm::ptr attr) { @@ -45,7 +44,7 @@ s32 sys_lwmutex_destroy(PPUThread& ppu, vm::ptr lwmutex) sysPrxForUser.trace("sys_lwmutex_destroy(lwmutex=*0x%x)", lwmutex); // check to prevent recursive locking in the next call - if (lwmutex->vars.owner.load() == ppu.get_id()) + if (lwmutex->vars.owner.load() == ppu.id) { return CELL_EBUSY; } @@ -75,7 +74,7 @@ s32 sys_lwmutex_lock(PPUThread& ppu, vm::ptr lwmutex, u64 timeout { sysPrxForUser.trace("sys_lwmutex_lock(lwmutex=*0x%x, timeout=0x%llx)", lwmutex, timeout); - const be_t tid = ppu.get_id(); + const be_t tid = ppu.id; // try to lock lightweight mutex const be_t old_owner = lwmutex->vars.owner.compare_and_swap(lwmutex_free, tid); @@ -169,7 +168,7 @@ s32 sys_lwmutex_trylock(PPUThread& ppu, vm::ptr lwmutex) { sysPrxForUser.trace("sys_lwmutex_trylock(lwmutex=*0x%x)", lwmutex); - const be_t tid = ppu.get_id(); + const be_t tid = ppu.id; // try to lock lightweight mutex const be_t old_owner = lwmutex->vars.owner.compare_and_swap(lwmutex_free, tid); @@ -236,7 +235,7 @@ s32 sys_lwmutex_unlock(PPUThread& ppu, vm::ptr lwmutex) { sysPrxForUser.trace("sys_lwmutex_unlock(lwmutex=*0x%x)", lwmutex); - const be_t tid = ppu.get_id(); + const be_t tid = ppu.id; // check owner if (lwmutex->vars.owner.load() != tid) diff --git a/rpcs3/Emu/SysCalls/Modules/sys_mempool.cpp b/rpcs3/Emu/Cell/Modules/sys_mempool.cpp similarity index 97% rename from rpcs3/Emu/SysCalls/Modules/sys_mempool.cpp rename to rpcs3/Emu/Cell/Modules/sys_mempool.cpp index 60851eacb8..99763b4b1f 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_mempool.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_mempool.cpp @@ -1,12 +1,11 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "sysPrxForUser.h" -extern Module<> sysPrxForUser; +extern _log::channel sysPrxForUser; using sys_mempool_t = u32; diff --git a/rpcs3/Emu/SysCalls/Modules/sys_mmapper_.cpp b/rpcs3/Emu/Cell/Modules/sys_mmapper_.cpp similarity index 76% rename from rpcs3/Emu/SysCalls/Modules/sys_mmapper_.cpp rename to rpcs3/Emu/Cell/Modules/sys_mmapper_.cpp index 5a2c59c300..37830aea71 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_mmapper_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_mmapper_.cpp @@ -1,12 +1,11 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/SysCalls/lv2/sys_mmapper.h" +#include "Emu/Cell/lv2/sys_mmapper.h" #include "sysPrxForUser.h" -extern Module<> sysPrxForUser; +extern _log::channel sysPrxForUser; void sysPrxForUser_sys_mmapper_init() { diff --git a/rpcs3/Emu/SysCalls/Modules/sys_net.cpp b/rpcs3/Emu/Cell/Modules/sys_net.cpp similarity index 97% rename from rpcs3/Emu/SysCalls/Modules/sys_net.cpp rename to rpcs3/Emu/Cell/Modules/sys_net.cpp index 35456c6a65..9ebd8d7e4b 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_net.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_net.cpp @@ -1,6 +1,5 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "sys_net.h" @@ -9,7 +8,6 @@ #define _WIN32_WINNT 0x0601 #include #include -#pragma comment(lib, "ws2_32.lib") #else #include #include @@ -18,7 +16,7 @@ #include #endif -extern Module<> libnet; +LOG_CHANNEL(libnet); // We map host sockets to sequential IDs to return as FDs because syscalls using // socketselect(), etc. expect socket FDs to be under 1024. @@ -622,10 +620,10 @@ namespace sys_net } } -// define additional macro for specific namespace -#define REG_FUNC_(name) add_ppu_func(ModuleFunc(get_function_id(#name), 0, &libnet, #name, BIND_FUNC(sys_net::name))) +// Define macro for namespace +#define REG_FUNC_(name) REG_FNID(sys_net, ppu_generate_id(#name), sys_net::name) -Module<> libnet("sys_net", []() +DECLARE(ppu_module_manager::libnet)("sys_net", []() { REG_FUNC_(accept); REG_FUNC_(bind); diff --git a/rpcs3/Emu/SysCalls/Modules/sys_net.h b/rpcs3/Emu/Cell/Modules/sys_net.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/sys_net.h rename to rpcs3/Emu/Cell/Modules/sys_net.h diff --git a/rpcs3/Emu/SysCalls/Modules/sys_ppu_thread_.cpp b/rpcs3/Emu/Cell/Modules/sys_ppu_thread_.cpp similarity index 72% rename from rpcs3/Emu/SysCalls/Modules/sys_ppu_thread_.cpp rename to rpcs3/Emu/Cell/Modules/sys_ppu_thread_.cpp index a22edcc521..f339fa8407 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_ppu_thread_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_ppu_thread_.cpp @@ -1,28 +1,35 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/SysCalls/lv2/sys_ppu_thread.h" +#include "Emu/Cell/lv2/sys_ppu_thread.h" #include "sysPrxForUser.h" -extern Module<> sysPrxForUser; +extern _log::channel sysPrxForUser; + +extern u32 ppu_alloc_tls(); +extern void ppu_free_tls(u32 addr); s32 sys_ppu_thread_create(vm::ptr thread_id, u32 entry, u64 arg, s32 prio, u32 stacksize, u64 flags, vm::cptr 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); + 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); - // (allocate TLS) - // (return CELL_ENOMEM if failed) - // ... + // Allocate TLS + const u32 tls_addr = ppu_alloc_tls(); - // call the syscall - if (s32 res = _sys_ppu_thread_create(thread_id, vm::make_var(ppu_thread_param_t{ entry, 0 }), arg, 0, prio, stacksize, flags, threadname)) + if (!tls_addr) + { + return CELL_ENOMEM; + } + + // Call the syscall + if (s32 res = _sys_ppu_thread_create(thread_id, vm::make_var(ppu_thread_param_t{ entry, tls_addr + 0x7030 }), arg, 0, prio, stacksize, flags, threadname)) { return res; } - // run the thread + // Run the thread return flags & SYS_PPU_THREAD_CREATE_INTERRUPT ? CELL_OK : sys_ppu_thread_start(static_cast(*thread_id)); } @@ -30,7 +37,7 @@ s32 sys_ppu_thread_get_id(PPUThread& ppu, vm::ptr thread_id) { sysPrxForUser.trace("sys_ppu_thread_get_id(thread_id=*0x%x)", thread_id); - *thread_id = ppu.get_id(); + *thread_id = ppu.id; return CELL_OK; } @@ -40,13 +47,15 @@ void sys_ppu_thread_exit(PPUThread& ppu, u64 val) sysPrxForUser.trace("sys_ppu_thread_exit(val=0x%llx)", val); // (call registered atexit functions) - // (deallocate TLS) // ... + + // Deallocate TLS + ppu_free_tls(vm::cast(ppu.GPR[13], HERE) - 0x7030); - if (ppu.hle_code == 0xaff080a4) + if (ppu.GPR[3] == val && !ppu.custom_task) { - // Change sys_ppu_thread_exit code to the syscall code - ppu.hle_code = ~41; + // Change sys_ppu_thread_exit code to the syscall code (hack) + ppu.GPR[11] = 41; } // Call the syscall diff --git a/rpcs3/Emu/SysCalls/Modules/sys_prx_.cpp b/rpcs3/Emu/Cell/Modules/sys_prx_.cpp similarity index 90% rename from rpcs3/Emu/SysCalls/Modules/sys_prx_.cpp rename to rpcs3/Emu/Cell/Modules/sys_prx_.cpp index 0ad64dc4ad..1b2fac8523 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_prx_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_prx_.cpp @@ -1,12 +1,11 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/SysCalls/lv2/sys_prx.h" +#include "Emu/Cell/lv2/sys_prx.h" #include "sysPrxForUser.h" -extern Module<> sysPrxForUser; +extern _log::channel sysPrxForUser; s64 sys_prx_exitspawn_with_level() { diff --git a/rpcs3/Emu/SysCalls/Modules/sys_spinlock.cpp b/rpcs3/Emu/Cell/Modules/sys_spinlock.cpp similarity index 92% rename from rpcs3/Emu/SysCalls/Modules/sys_spinlock.cpp rename to rpcs3/Emu/Cell/Modules/sys_spinlock.cpp index 50bc095695..42397477b7 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_spinlock.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_spinlock.cpp @@ -1,11 +1,10 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "sysPrxForUser.h" -extern Module<> sysPrxForUser; +extern _log::channel sysPrxForUser; void sys_spinlock_initialize(vm::ptr> lock) { diff --git a/rpcs3/Emu/SysCalls/Modules/sys_spu_.cpp b/rpcs3/Emu/Cell/Modules/sys_spu_.cpp similarity index 78% rename from rpcs3/Emu/SysCalls/Modules/sys_spu_.cpp rename to rpcs3/Emu/Cell/Modules/sys_spu_.cpp index 4d859a9739..3d2c0e6863 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_spu_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_spu_.cpp @@ -1,15 +1,13 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "Emu/Cell/RawSPUThread.h" -#include "Emu/SysCalls/lv2/sys_spu.h" -#include "Emu/FS/vfsFile.h" +#include "Emu/Cell/lv2/sys_spu.h" #include "Crypto/unself.h" #include "sysPrxForUser.h" -extern Module<> sysPrxForUser; +extern _log::channel sysPrxForUser; extern u64 get_system_time(); @@ -30,17 +28,38 @@ s32 sys_spu_elf_get_segments(u32 elf_img, vm::ptr segments, s32 return CELL_OK; } -s32 sys_spu_image_import(vm::ptr img, u32 src, u32 type) +s32 sys_spu_image_import(vm::ptr img, u32 src, u32 type) { sysPrxForUser.warning("sys_spu_image_import(img=*0x%x, src=0x%x, type=%d)", img, src, type); - return spu_image_import(*img, src, type); + u32 entry, offset = LoadSpuImage(fs::file(vm::base(src), 0 - src), entry); + + img->type = SYS_SPU_IMAGE_TYPE_USER; + img->entry_point = entry; + img->segs.set(offset); // TODO: writing actual segment info + img->nsegs = 1; // wrong value + + return CELL_OK; } -s32 sys_spu_image_close(vm::ptr img) +s32 sys_spu_image_close(vm::ptr img) { - sysPrxForUser.todo("sys_spu_image_close(img=*0x%x)", img); + sysPrxForUser.warning("sys_spu_image_close(img=*0x%x)", img); + if (img->type == SYS_SPU_IMAGE_TYPE_USER) + { + //_sys_free(img->segs.addr()); + } + else if (img->type == SYS_SPU_IMAGE_TYPE_KERNEL) + { + //return syscall_158(img); + } + else + { + return CELL_EINVAL; + } + + ASSERT(vm::dealloc(img->segs.addr(), vm::main)); // Current rough implementation return CELL_OK; } @@ -49,10 +68,10 @@ s32 sys_raw_spu_load(s32 id, vm::cptr path, vm::ptr entry) sysPrxForUser.warning("sys_raw_spu_load(id=%d, path=*0x%x, entry=*0x%x)", id, path, entry); sysPrxForUser.warning("*** path = '%s'", path.get_ptr()); - vfsFile f(path.get_ptr()); - if (!f.IsOpened()) + const fs::file f(vfs::get(path.get_ptr())); + if (!f) { - sysPrxForUser.error("sys_raw_spu_load error: '%s' not found!", path.get_ptr()); + sysPrxForUser.error("sys_raw_spu_load() error: '%s' not found!", path.get_ptr()); return CELL_ENOENT; } @@ -61,12 +80,10 @@ s32 sys_raw_spu_load(s32 id, vm::cptr path, vm::ptr entry) if (hdr.CheckMagic()) { - sysPrxForUser.error("sys_raw_spu_load error: '%s' is encrypted! Decrypt SELF and try again.", path.get_ptr()); - Emu.Pause(); - return CELL_ENOENT; + throw fmt::exception("sys_raw_spu_load() error: '%s' is encrypted! Try to decrypt it manually and try again.", path.get_ptr()); } - f.Seek(0); + f.seek(0); u32 _entry; LoadSpuImage(f, _entry, RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id); @@ -76,7 +93,7 @@ s32 sys_raw_spu_load(s32 id, vm::cptr path, vm::ptr entry) return CELL_OK; } -s32 sys_raw_spu_image_load(PPUThread& ppu, s32 id, vm::ptr img) +s32 sys_raw_spu_image_load(PPUThread& ppu, s32 id, vm::ptr img) { sysPrxForUser.warning("sys_raw_spu_image_load(id=%d, img=*0x%x)", id, img); @@ -84,7 +101,7 @@ s32 sys_raw_spu_image_load(PPUThread& ppu, s32 id, vm::ptr img) const auto stamp0 = get_system_time(); - std::memcpy(vm::base(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id), vm::base(img->addr), 256 * 1024); + std::memcpy(vm::base(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id), img->segs.get_ptr(), 256 * 1024); const auto stamp1 = get_system_time(); @@ -173,11 +190,6 @@ s32 _sys_spu_printf_detach_thread(PPUThread& ppu, u32 thread) void sysPrxForUser_sys_spu_init() { - g_spu_printf_agcb = vm::null; - g_spu_printf_dgcb = vm::null; - g_spu_printf_atcb = vm::null; - g_spu_printf_dtcb = vm::null; - REG_FUNC(sysPrxForUser, sys_spu_elf_get_information); REG_FUNC(sysPrxForUser, sys_spu_elf_get_segments); REG_FUNC(sysPrxForUser, sys_spu_image_import); diff --git a/rpcs3/Emu/Cell/PPCDecoder.cpp b/rpcs3/Emu/Cell/PPCDecoder.cpp deleted file mode 100644 index 7cbb50565f..0000000000 --- a/rpcs3/Emu/Cell/PPCDecoder.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "PPCDecoder.h" - -u32 PPCDecoder::DecodeMemory(const u32 address) -{ - u32 instr = vm::ps3::read32(address); - Decode(instr); - - return sizeof(u32); -} diff --git a/rpcs3/Emu/Cell/PPCDecoder.h b/rpcs3/Emu/Cell/PPCDecoder.h deleted file mode 100644 index 0a602f562a..0000000000 --- a/rpcs3/Emu/Cell/PPCDecoder.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once -#include "Emu/CPU/CPUDecoder.h" -#include "PPCInstrTable.h" - -class PPCDecoder : public CPUDecoder -{ -public: - virtual void Decode(const u32 code) = 0; - - virtual u32 DecodeMemory(const u32 address); - - virtual ~PPCDecoder() = default; -}; - - -template -static InstrList<(1 << (CodeField::size)), TO>* new_list(const CodeField& func, InstrCaller* error_func = nullptr) -{ - return new InstrList<(1 << (CodeField::size)), TO>(func, error_func); -} - -template -static InstrList<(1 << (CodeField::size)), TO>* new_list(InstrList* parent, int opcode, const CodeField& func, InstrCaller* error_func = nullptr) -{ - return connect_list(parent, new InstrList<(1 << (CodeField::size)), TO>(func, error_func), opcode); -} - -template -static InstrList<(1 << (CodeField::size)), TO>* new_list(InstrList* parent, const CodeField& func, InstrCaller* error_func = nullptr) -{ - return connect_list(parent, new InstrList<(1 << (CodeField::size)), TO>(func, error_func)); -} diff --git a/rpcs3/Emu/Cell/PPCInstrTable.h b/rpcs3/Emu/Cell/PPCInstrTable.h deleted file mode 100644 index 2eac8f73a7..0000000000 --- a/rpcs3/Emu/Cell/PPCInstrTable.h +++ /dev/null @@ -1,172 +0,0 @@ -#pragma once -#include "Emu/CPU/CPUInstrTable.h" - -enum CodeFieldType -{ - FIELD_IMM, - FIELD_R_GPR, - FIELD_R_FPR, - FIELD_R_VPR, - FIELD_R_CR, - FIELD_BRANCH, -}; - -template -class CodeField : public CodeFieldBase -{ - static_assert(from <= to, "too big 'from' value"); - static_assert(to <= 31, "too big 'to' value"); - -public: - CodeField(CodeFieldType type = FIELD_IMM) : CodeFieldBase(type) - { - } - - static const u32 size = to - from + 1; - static const u32 shift = 31 - to; - static const u32 mask = ((1ULL << ((to - from) + 1)) - 1) << shift; - - static force_inline void encode(u32& data, u32 value) - { - data &= ~mask; - data |= (value << shift) & mask; - } - - static force_inline u32 decode(u32 data) - { - return (data & mask) >> shift; - } - - virtual u32 operator ()(u32 data) const - { - return decode(data); - } - - virtual void operator()(u32& data, u32 value) const - { - encode(data, value); - } -}; - -static CodeField<0, 31> GetCode; - -template -class DoubleCodeField : public CodeField -{ - static_assert(from2 <= to2, "too big from2 value"); - static_assert(to2 <= 31, "too big to2 value"); - -public: - DoubleCodeField(CodeFieldType type = FIELD_IMM) : CodeField(type) - { - } - - static const u32 shift2 = 31 - to2; - static const u32 mask2 = ((1 << ((to2 - from2) + 1)) - 1) << shift2; - - static force_inline void encode(u32& data, u32 value) - { - data &= ~(CodeField::mask | mask2); - data |= ((value << CodeField::shift) & CodeField::mask) | (((value >> offset) << shift2) & mask2); - } - - static force_inline u32 decode(u32 data) - { - return ((data & CodeField::mask) >> CodeField::shift) | (((data & mask2) >> shift2) << offset); - } - - virtual u32 operator ()(u32 data) const - { - return decode(data); - } - - virtual void operator()(u32& data, u32 value) const - { - encode(data, value); - } -}; - -template -class CodeFieldSigned : public CodeField -{ -public: - CodeFieldSigned(CodeFieldType type = FIELD_IMM) : CodeField(type) - { - } - - static const int size = _size; - - static force_inline u32 decode(u32 data) - { - return sign((data & CodeField::mask) >> CodeField::shift); - } - - virtual u32 operator ()(u32 data) const - { - return decode(data); - } -}; - -template -class CodeFieldOffset : public CodeField -{ - static const int offset = _offset; - -public: - CodeFieldOffset(CodeFieldType type = FIELD_IMM) : CodeField(type) - { - } - - static force_inline u32 decode(u32 data) - { - return ((data & CodeField::mask) >> CodeField::shift) << offset; - } - - static force_inline void encode(u32& data, u32 value) - { - data &= ~CodeField::mask; - data |= ((value >> offset) << CodeField::shift) & CodeField::mask; - } - - virtual u32 operator ()(u32 data) const - { - return decode(data); - } - - virtual void operator ()(u32& data, u32 value) const - { - return encode(data, value); - } -}; - -template -class CodeFieldSignedOffset : public CodeFieldSigned -{ - static const int offset = _offset; - -public: - CodeFieldSignedOffset(CodeFieldType type = FIELD_IMM) : CodeFieldSigned(type) - { - } - - static force_inline u32 decode(u32 data) - { - return sign((data & CodeField::mask) >> CodeField::shift) << offset; - } - - static force_inline void encode(u32& data, u32 value) - { - data &= ~CodeField::mask; - data |= ((value >> offset) << CodeField::shift) & CodeField::mask; - } - - virtual u32 operator ()(u32 data) const - { - return decode(data); - } - - virtual void operator ()(u32& data, u32 value) const - { - return encode(data, value); - } -}; diff --git a/rpcs3/Emu/Cell/PPCThreadManager.cpp b/rpcs3/Emu/Cell/PPCThreadManager.cpp deleted file mode 100644 index b829ef72e5..0000000000 --- a/rpcs3/Emu/Cell/PPCThreadManager.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#if 0 -#include "stdafx.h" -#include "PPCThreadManager.h" -#include "PPUThread.h" -#include "SPUThread.h" -#include "RawSPUThread.h" - -PPCThreadManager::PPCThreadManager() : -m_raw_spu_num(0) -{ -} - -PPCThreadManager::~PPCThreadManager() -{ - Close(); -} - -void PPCThreadManager::Close() -{ - while(m_threads.size()) RemoveThread(m_threads[0]->GetId()); -} - -PPCThread& PPCThreadManager::AddThread(PPCThreadType type) -{ - std::lock_guard lock(m_mtx_thread); - - PPCThread* new_thread; - char* name; - switch(type) - { - case PPC_THREAD_PPU: new_thread = new PPUThread(); name = "PPU"; break; - case PPC_THREAD_SPU: new_thread = new SPUThread(); name = "SPU"; break; - case PPC_THREAD_RAW_SPU: new_thread = new RawSPUThread(m_raw_spu_num++); name = "RawSPU"; break; - default: assert(0); - } - - new_thread->SetId(Emu.GetIdManager().GetNewID(fmt::Format("%s Thread", name), new_thread)); - - m_threads.push_back(new_thread); - wxGetApp().SendDbgCommand(DID_CREATE_THREAD, new_thread); - - return *new_thread; -} - -void PPCThreadManager::RemoveThread(const u32 id) -{ - std::lock_guard lock(m_mtx_thread); - - for(u32 i=0; im_wait_thread_id == id) - { - m_threads[i]->Wait(false); - m_threads[i]->m_wait_thread_id = -1; - } - - if(m_threads[i]->GetId() != id) continue; - - PPCThread* thr = m_threads[i]; - wxGetApp().SendDbgCommand(DID_REMOVE_THREAD, thr); - if(thr->IsAlive()) - { - thr->Close(); - } - else - { - thr->Close(); - delete thr; - } - - - m_threads.erase(m_threads.begin() + i); - i--; - } - - Emu.GetIdManager().RemoveID(id, false); - Emu.CheckStatus(); -} - -s32 PPCThreadManager::GetThreadNumById(PPCThreadType type, u32 id) -{ - s32 num = 0; - - for(u32 i=0; iGetId() == id) return num; - if(m_threads[i]->GetType() == type) num++; - } - - return -1; -} - -PPCThread* PPCThreadManager::GetThread(u32 id) -{ - for(u32 i=0; iGetId() == id) return m_threads[i]; - } - - return nullptr; -} - -void PPCThreadManager::Exec() -{ - for(u32 i=0; iExec(); - } -} -#endif diff --git a/rpcs3/Emu/Cell/PPCThreadManager.h b/rpcs3/Emu/Cell/PPCThreadManager.h deleted file mode 100644 index 9bb650304c..0000000000 --- a/rpcs3/Emu/Cell/PPCThreadManager.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once -#include "PPCThread.h" - -enum PPCThreadType -{ - PPC_THREAD_PPU, - PPC_THREAD_SPU, - PPC_THREAD_RAW_SPU -}; - -class PPCThreadManager -{ - //IdManager m_threads_id; - //ArrayF m_ppu_threads; - //ArrayF m_spu_threads; - std::vector m_threads; - std::mutex m_mtx_thread; - wxSemaphore m_sem_task; - u32 m_raw_spu_num; - -public: - PPCThreadManager(); - ~PPCThreadManager(); - - void Close(); - - PPCThread& AddThread(PPCThreadType type); - void RemoveThread(const u32 id); - - std::vector& GetThreads() { return m_threads; } - s32 GetThreadNumById(PPCThreadType type, u32 id); - PPCThread* GetThread(u32 id); - //IdManager& GetIDs() {return m_threads_id;} - - void Exec(); - void Task(); -}; diff --git a/rpcs3/Emu/SysCalls/Callback.cpp b/rpcs3/Emu/Cell/PPUCallback.cpp similarity index 80% rename from rpcs3/Emu/SysCalls/Callback.cpp rename to rpcs3/Emu/Cell/PPUCallback.cpp index d2146c161f..8ca6a675e0 100644 --- a/rpcs3/Emu/SysCalls/Callback.cpp +++ b/rpcs3/Emu/Cell/PPUCallback.cpp @@ -3,9 +3,8 @@ #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/Cell/PPUThread.h" -#include "Emu/ARMv7/ARMv7Thread.h" -#include "Callback.h" +#include "PPUThread.h" +#include "PPUCallback.h" void CallbackManager::Register(check_cb_t func) { @@ -79,17 +78,14 @@ void CallbackManager::Init() } }; - if (vm::get(vm::main)->addr == 0x10000) - { - auto thread = idm::make_ptr("Callback Thread"); + auto thread = idm::make_ptr("Callback Thread"); - thread->prio = 1001; - thread->stack_size = 0x10000; - thread->custom_task = task; - thread->run(); + thread->prio = 1001; + thread->stack_size = 0x10000; + thread->custom_task = task; + thread->cpu_init(); - m_cb_thread = thread; - } + m_cb_thread = thread; } void CallbackManager::Clear() diff --git a/rpcs3/Emu/SysCalls/CB_FUNC.h b/rpcs3/Emu/Cell/PPUCallback.h similarity index 61% rename from rpcs3/Emu/SysCalls/CB_FUNC.h rename to rpcs3/Emu/Cell/PPUCallback.h index 2d621439f2..66b3ce2449 100644 --- a/rpcs3/Emu/SysCalls/CB_FUNC.h +++ b/rpcs3/Emu/Cell/PPUCallback.h @@ -2,7 +2,7 @@ #include "Emu/Cell/PPUThread.h" -namespace cb_detail +namespace ppu_cb_detail { enum _func_arg_type { @@ -10,7 +10,7 @@ namespace cb_detail ARG_FLOAT, ARG_VECTOR, ARG_STACK, - ARG_CONTEXT, // for compatibility with SC_FUNC and CALL_FUNC + ARG_CONTEXT, ARG_UNKNOWN, }; @@ -19,7 +19,7 @@ namespace cb_detail // It's possible to calculate suitable stack frame size in template, but too complicated. static const auto FIXED_STACK_FRAME_SIZE = 0x90; - template + template struct _func_arg { static_assert(type == ARG_GENERAL, "Unknown callback argument type"); @@ -27,50 +27,48 @@ namespace cb_detail static_assert(!std::is_reference::value, "Invalid callback argument type (reference)"); static_assert(sizeof(T) <= 8, "Invalid callback argument type for ARG_GENERAL"); - force_inline static void set_value(PPUThread& CPU, const T& arg) + static inline void set_value(PPUThread& CPU, const T& arg) { - CPU.GPR[g_count + 2] = cast_to_ppu_gpr(arg); + CPU.GPR[g_count + 2] = ppu_gpr_cast(arg); } }; - template + template struct _func_arg { static_assert(sizeof(T) <= 8, "Invalid callback argument type for ARG_FLOAT"); - force_inline static void set_value(PPUThread& CPU, const T& arg) + static inline void set_value(PPUThread& CPU, const T& arg) { CPU.FPR[f_count] = static_cast(arg); } }; - template + template struct _func_arg { - static_assert(std::is_same, v128>::value, "Invalid callback argument type for ARG_VECTOR"); + static_assert(std::is_same::value, "Invalid callback argument type for ARG_VECTOR"); - force_inline static void set_value(PPUThread& CPU, const T& arg) + static inline void set_value(PPUThread& CPU, const T& arg) { - CPU.VPR[v_count + 1] = arg; + CPU.VR[v_count + 1] = arg; } }; - template + template struct _func_arg { - static_assert(f_count <= 13, "TODO: Unsupported stack argument type (float)"); - static_assert(v_count <= 12, "TODO: Unsupported stack argument type (vector)"); - static_assert(sizeof(T) <= 8, "Invalid callback argument type for ARG_STACK"); + static_assert(alignof(T) <= 16, "Unsupported callback argument type alignment for ARG_STACK"); - force_inline static void set_value(PPUThread& CPU, const T& arg) + static inline void set_value(PPUThread& CPU, const T& arg) { - const int stack_pos = (g_count - 9) * 8 - FIXED_STACK_FRAME_SIZE; - static_assert(stack_pos < 0, "TODO: Increase fixed stack frame size (arg count limit broken)"); - vm::ps3::write64(CPU.GPR[1] + stack_pos, cast_to_ppu_gpr(arg)); + const s64 stack_pos = (g_count - 1) * 0x8 + 0x30 - FIXED_STACK_FRAME_SIZE; + static_assert(stack_pos < 0, "TODO: Increase FIXED_STACK_FRAME_SIZE (arg count limit broken)"); + vm::ps3::write64(CPU.GPR[1] + stack_pos, ppu_gpr_cast(arg)); // TODO } }; - template + template struct _func_arg { static_assert(std::is_same::value, "Invalid callback argument type for ARG_CONTEXT"); @@ -80,18 +78,18 @@ namespace cb_detail } }; - template + template force_inline static bool _bind_func_args(PPUThread& CPU) { // terminator return false; } - template + template force_inline static bool _bind_func_args(PPUThread& CPU, T1 arg1, T... args) { const bool is_float = std::is_floating_point::value; - const bool is_vector = std::is_same, v128>::value; + const bool is_vector = std::is_same::value; const bool is_context = std::is_same::value; const bool is_general = !is_float && !is_vector && !is_context; @@ -102,9 +100,9 @@ namespace cb_detail is_context ? ARG_CONTEXT : ARG_UNKNOWN; - const int g = g_count + is_general; - const int f = f_count + is_float; - const int v = v_count + is_vector; + const u32 g = g_count + (is_general || is_float ? 1 : is_vector ? ::align(g_count, 2) + 2 : 0); + const u32 f = f_count + is_float; + const u32 v = v_count + is_vector; _func_arg::set_value(CPU, arg1); @@ -120,7 +118,7 @@ namespace cb_detail force_inline static T get_value(const PPUThread& CPU) { - return cast_from_ppu_gpr(CPU.GPR[3]); + return ppu_gpr_cast(CPU.GPR[3]); } }; @@ -138,11 +136,11 @@ namespace cb_detail template struct _func_res { - static_assert(std::is_same, v128>::value, "Invalid callback result type for ARG_VECTOR"); + static_assert(std::is_same::value, "Invalid callback result type for ARG_VECTOR"); force_inline static T get_value(const PPUThread& CPU) { - return CPU.VPR[2]; + return CPU.VR[2]; } }; @@ -169,11 +167,9 @@ namespace cb_detail force_inline static void call(PPUThread& CPU, u32 pc, u32 rtoc, T... args) { const bool stack = _bind_func_args<0, 0, 0, T...>(CPU, args...); - if (stack) CPU.GPR[1] -= FIXED_STACK_FRAME_SIZE; - CPU.GPR[1] -= 0x70; // create reserved area + CPU.GPR[1] -= stack ? FIXED_STACK_FRAME_SIZE : 0x30; // create reserved area CPU.fast_call(pc, rtoc); - CPU.GPR[1] += 0x70; - if (stack) CPU.GPR[1] += FIXED_STACK_FRAME_SIZE; + CPU.GPR[1] += stack ? FIXED_STACK_FRAME_SIZE : 0x30; } }; } @@ -183,15 +179,44 @@ namespace vm template force_inline RT _ptr_base::operator()(PPUThread& CPU, T... args) const { - const auto data = vm::ps3::_ptr(VM_CAST(m_addr)); + const auto data = vm::ps3::_ptr(vm::cast(m_addr, HERE)); const u32 pc = data[0]; const u32 rtoc = data[1]; - return cb_detail::_func_caller::call(CPU, pc, rtoc, args...); + return ppu_cb_detail::_func_caller::call(CPU, pc, rtoc, args...); } } template inline RT cb_call(PPUThread& CPU, u32 pc, u32 rtoc, T... args) { - return cb_detail::_func_caller::call(CPU, pc, rtoc, args...); + return ppu_cb_detail::_func_caller::call(CPU, pc, rtoc, args...); } + +#include + +class CallbackManager +{ + using check_cb_t = std::function; + using async_cb_t = std::function; + + std::mutex m_mutex; + + std::queue m_check_cb; + std::queue m_async_cb; + + std::shared_ptr m_cb_thread; + +public: + // Register checked callback + void Register(check_cb_t func); + + // Register async callback, called in callback thread + void Async(async_cb_t func); + + // Get one registered callback + check_cb_t Check(); + + void Init(); + + void Clear(); +}; diff --git a/rpcs3/Emu/Cell/PPUDecoder.h b/rpcs3/Emu/Cell/PPUDecoder.h deleted file mode 100644 index 97132b07e9..0000000000 --- a/rpcs3/Emu/Cell/PPUDecoder.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "Emu/Cell/PPUOpcodes.h" -#include "Emu/Cell/PPCDecoder.h" -#include "PPUInstrTable.h" - -class PPUDecoder : public PPCDecoder -{ - PPUOpcodes* m_op; - -public: - PPUDecoder(PPUOpcodes* op) : m_op(op) - { - } - - virtual ~PPUDecoder() - { - delete m_op; - } - - virtual void Decode(const u32 code) - { - (*PPU_instr::main_list)(m_op, code); - } -}; \ No newline at end of file diff --git a/rpcs3/Emu/Cell/PPUDisAsm.cpp b/rpcs3/Emu/Cell/PPUDisAsm.cpp new file mode 100644 index 0000000000..31a1cfa48d --- /dev/null +++ b/rpcs3/Emu/Cell/PPUDisAsm.cpp @@ -0,0 +1,2160 @@ +#include "stdafx.h" +#include "PPUDisAsm.h" + +const ppu_decoder s_ppu_disasm; + +u32 PPUDisAsm::disasm(u32 pc) +{ + const u32 op = *(be_t*)(offset + pc); + (this->*(s_ppu_disasm.decode(op)))({ op }); + return 4; +} + +void PPUDisAsm::TDI(ppu_opcode_t op) +{ + DisAsm_INT1_R1_IMM("tdi", op.bo, op.ra, op.simm16); +} + +void PPUDisAsm::TWI(ppu_opcode_t op) +{ + DisAsm_INT1_R1_IMM("twi", op.bo, op.ra, op.simm16); +} + +void PPUDisAsm::MFVSCR(ppu_opcode_t op) +{ + DisAsm_V1("mfvscr", op.vd); +} + +void PPUDisAsm::MTVSCR(ppu_opcode_t op) +{ + DisAsm_V1("mtvscr", op.vb); +} + +void PPUDisAsm::VADDCUW(ppu_opcode_t op) +{ + DisAsm_V3("vaddcuw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDFP(ppu_opcode_t op) +{ + DisAsm_V3("vaddfp", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDSBS(ppu_opcode_t op) +{ + DisAsm_V3("vaddsbs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDSHS(ppu_opcode_t op) +{ + DisAsm_V3("vaddshs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDSWS(ppu_opcode_t op) +{ + DisAsm_V3("vaddsws", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDUBM(ppu_opcode_t op) +{ + DisAsm_V3("vaddubm", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDUBS(ppu_opcode_t op) +{ + DisAsm_V3("vaddubs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDUHM(ppu_opcode_t op) +{ + DisAsm_V3("vadduhm", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDUHS(ppu_opcode_t op) +{ + DisAsm_V3("vadduhs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDUWM(ppu_opcode_t op) +{ + DisAsm_V3("vadduwm", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDUWS(ppu_opcode_t op) +{ + DisAsm_V3("vadduws", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VAND(ppu_opcode_t op) +{ + DisAsm_V3("vand", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VANDC(ppu_opcode_t op) +{ + DisAsm_V3("vandc", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VAVGSB(ppu_opcode_t op) +{ + DisAsm_V3("vavgsb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VAVGSH(ppu_opcode_t op) +{ + DisAsm_V3("vavgsh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VAVGSW(ppu_opcode_t op) +{ + DisAsm_V3("vavgsw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VAVGUB(ppu_opcode_t op) +{ + DisAsm_V3("vavgub", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VAVGUH(ppu_opcode_t op) +{ + DisAsm_V3("vavguh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VAVGUW(ppu_opcode_t op) +{ + DisAsm_V3("vavguw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCFSX(ppu_opcode_t op) +{ + DisAsm_V2_UIMM("vcfsx", op.vd, op.vb, op.vuimm); +} + +void PPUDisAsm::VCFUX(ppu_opcode_t op) +{ + DisAsm_V2_UIMM("vcfux", op.vd, op.vb, op.vuimm); +} + +void PPUDisAsm::VCMPBFP(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpbfp." : "vcmpbfp", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPEQFP(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpeqfp." : "vcmpeqfp", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPEQUB(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpequb." : "vcmpequb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPEQUH(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpequh." : "vcmpequh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPEQUW(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpequw." : "vcmpequw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPGEFP(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpgefp." : "vcmpgefp", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPGTFP(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpgtfp." : "vcmpgtfp", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPGTSB(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpgtsb." : "vcmpgtsb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPGTSH(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpgtsh." : "vcmpgtsh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPGTSW(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpgtsw." : "vcmpgtsw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPGTUB(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpgtub." : "vcmpgtub", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPGTUH(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpgtuh." : "vcmpgtuh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPGTUW(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpgtuw." : "vcmpgtuw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCTSXS(ppu_opcode_t op) +{ + DisAsm_V2_UIMM("vctsxs", op.vd, op.vb, op.vuimm); +} + +void PPUDisAsm::VCTUXS(ppu_opcode_t op) +{ + DisAsm_V2_UIMM("vctuxs", op.vd, op.vb, op.vuimm); +} + +void PPUDisAsm::VEXPTEFP(ppu_opcode_t op) +{ + DisAsm_V2("vexptefp", op.vd, op.vb); +} + +void PPUDisAsm::VLOGEFP(ppu_opcode_t op) +{ + DisAsm_V2("vlogefp", op.vd, op.vb); +} + +void PPUDisAsm::VMADDFP(ppu_opcode_t op) +{ + DisAsm_V4("vmaddfp", op.vd, op.va, op.vc, op.vb); +} + +void PPUDisAsm::VMAXFP(ppu_opcode_t op) +{ + DisAsm_V3("vmaxfp", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMAXSB(ppu_opcode_t op) +{ + DisAsm_V3("vmaxsb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMAXSH(ppu_opcode_t op) +{ + DisAsm_V3("vmaxsh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMAXSW(ppu_opcode_t op) +{ + DisAsm_V3("vmaxsw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMAXUB(ppu_opcode_t op) +{ + DisAsm_V3("vmaxub", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMAXUH(ppu_opcode_t op) +{ + DisAsm_V3("vmaxuh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMAXUW(ppu_opcode_t op) +{ + DisAsm_V3("vmaxuw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMHADDSHS(ppu_opcode_t op) +{ + DisAsm_V4("vmhaddshs", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VMHRADDSHS(ppu_opcode_t op) +{ + DisAsm_V4("vmhraddshs", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VMINFP(ppu_opcode_t op) +{ + DisAsm_V3("vminfp", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMINSB(ppu_opcode_t op) +{ + DisAsm_V3("vminsb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMINSH(ppu_opcode_t op) +{ + DisAsm_V3("vminsh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMINSW(ppu_opcode_t op) +{ + DisAsm_V3("vminsw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMINUB(ppu_opcode_t op) +{ + DisAsm_V3("vminub", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMINUH(ppu_opcode_t op) +{ + DisAsm_V3("vminuh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMINUW(ppu_opcode_t op) +{ + DisAsm_V3("vminuw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMLADDUHM(ppu_opcode_t op) +{ + DisAsm_V4("vmladduhm", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VMRGHB(ppu_opcode_t op) +{ + DisAsm_V3("vmrghb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMRGHH(ppu_opcode_t op) +{ + DisAsm_V3("vmrghh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMRGHW(ppu_opcode_t op) +{ + DisAsm_V3("vmrghw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMRGLB(ppu_opcode_t op) +{ + DisAsm_V3("vmrglb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMRGLH(ppu_opcode_t op) +{ + DisAsm_V3("vmrglh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMRGLW(ppu_opcode_t op) +{ + DisAsm_V3("vmrglw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMSUMMBM(ppu_opcode_t op) +{ + DisAsm_V4("vmsummbm", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VMSUMSHM(ppu_opcode_t op) +{ + DisAsm_V4("vmsumshm", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VMSUMSHS(ppu_opcode_t op) +{ + DisAsm_V4("vmsumshs", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VMSUMUBM(ppu_opcode_t op) +{ + DisAsm_V4("vmsumubm", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VMSUMUHM(ppu_opcode_t op) +{ + DisAsm_V4("vmsumuhm", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VMSUMUHS(ppu_opcode_t op) +{ + DisAsm_V4("vmsumuhs", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VMULESB(ppu_opcode_t op) +{ + DisAsm_V3("vmulesb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMULESH(ppu_opcode_t op) +{ + DisAsm_V3("vmulesh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMULEUB(ppu_opcode_t op) +{ + DisAsm_V3("vmuleub", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMULEUH(ppu_opcode_t op) +{ + DisAsm_V3("vmuleuh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMULOSB(ppu_opcode_t op) +{ + DisAsm_V3("vmulosb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMULOSH(ppu_opcode_t op) +{ + DisAsm_V3("vmulosh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMULOUB(ppu_opcode_t op) +{ + DisAsm_V3("vmuloub", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMULOUH(ppu_opcode_t op) +{ + DisAsm_V3("vmulouh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VNMSUBFP(ppu_opcode_t op) +{ + DisAsm_V4("vnmsubfp", op.vd, op.va, op.vc, op.vb); +} + +void PPUDisAsm::VNOR(ppu_opcode_t op) +{ + DisAsm_V3("vnor", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VOR(ppu_opcode_t op) +{ + DisAsm_V3("vor", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VPERM(ppu_opcode_t op) +{ + DisAsm_V4("vperm", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VPKPX(ppu_opcode_t op) +{ + DisAsm_V3("vpkpx", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VPKSHSS(ppu_opcode_t op) +{ + DisAsm_V3("vpkshss", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VPKSHUS(ppu_opcode_t op) +{ + DisAsm_V3("vpkshus", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VPKSWSS(ppu_opcode_t op) +{ + DisAsm_V3("vpkswss", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VPKSWUS(ppu_opcode_t op) +{ + DisAsm_V3("vpkswus", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VPKUHUM(ppu_opcode_t op) +{ + DisAsm_V3("vpkuhum", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VPKUHUS(ppu_opcode_t op) +{ + DisAsm_V3("vpkuhus", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VPKUWUM(ppu_opcode_t op) +{ + DisAsm_V3("vpkuwum", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VPKUWUS(ppu_opcode_t op) +{ + DisAsm_V3("vpkuwus", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VREFP(ppu_opcode_t op) +{ + DisAsm_V2("vrefp", op.vd, op.vb); +} + +void PPUDisAsm::VRFIM(ppu_opcode_t op) +{ + DisAsm_V2("vrfim", op.vd, op.vb); +} + +void PPUDisAsm::VRFIN(ppu_opcode_t op) +{ + DisAsm_V2("vrfin", op.vd, op.vb); +} + +void PPUDisAsm::VRFIP(ppu_opcode_t op) +{ + DisAsm_V2("vrfip", op.vd, op.vb); +} + +void PPUDisAsm::VRFIZ(ppu_opcode_t op) +{ + DisAsm_V2("vrfiz", op.vd, op.vb); +} + +void PPUDisAsm::VRLB(ppu_opcode_t op) +{ + DisAsm_V3("vrlb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VRLH(ppu_opcode_t op) +{ + DisAsm_V3("vrlh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VRLW(ppu_opcode_t op) +{ + DisAsm_V3("vrlw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VRSQRTEFP(ppu_opcode_t op) +{ + DisAsm_V2("vrsqrtefp", op.vd, op.vb); +} + +void PPUDisAsm::VSEL(ppu_opcode_t op) +{ + DisAsm_V4("vsel", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VSL(ppu_opcode_t op) +{ + DisAsm_V3("vsl", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSLB(ppu_opcode_t op) +{ + DisAsm_V3("vslb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSLDOI(ppu_opcode_t op) +{ + DisAsm_V3_UIMM("vsldoi", op.vd, op.va, op.vb, op.vsh); +} + +void PPUDisAsm::VSLH(ppu_opcode_t op) +{ + DisAsm_V3("vslh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSLO(ppu_opcode_t op) +{ + DisAsm_V3("vslo", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSLW(ppu_opcode_t op) +{ + DisAsm_V3("vslw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSPLTB(ppu_opcode_t op) +{ + DisAsm_V2_UIMM("vspltb", op.vd, op.vb, op.vuimm & 0xf); +} + +void PPUDisAsm::VSPLTH(ppu_opcode_t op) +{ + DisAsm_V2_UIMM("vsplth", op.vd, op.vb, op.vuimm & 0x7); +} + +void PPUDisAsm::VSPLTISB(ppu_opcode_t op) +{ + DisAsm_V1_SIMM("vspltisb", op.vd, op.vsimm); +} + +void PPUDisAsm::VSPLTISH(ppu_opcode_t op) +{ + DisAsm_V1_SIMM("vspltish", op.vd, op.vsimm); +} + +void PPUDisAsm::VSPLTISW(ppu_opcode_t op) +{ + DisAsm_V1_SIMM("vspltisw", op.vd, op.vsimm); +} + +void PPUDisAsm::VSPLTW(ppu_opcode_t op) +{ + DisAsm_V2_UIMM("vspltw", op.vd, op.vb, op.vuimm & 0x3); +} + +void PPUDisAsm::VSR(ppu_opcode_t op) +{ + DisAsm_V3("vsr", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSRAB(ppu_opcode_t op) +{ + DisAsm_V3("vsrab", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSRAH(ppu_opcode_t op) +{ + DisAsm_V3("vsrah", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSRAW(ppu_opcode_t op) +{ + DisAsm_V3("vsraw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSRB(ppu_opcode_t op) +{ + DisAsm_V3("vsrb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSRH(ppu_opcode_t op) +{ + DisAsm_V3("vsrh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSRO(ppu_opcode_t op) +{ + DisAsm_V3("vsro", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSRW(ppu_opcode_t op) +{ + DisAsm_V3("vsrw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBCUW(ppu_opcode_t op) +{ + DisAsm_V3("vsubcuw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBFP(ppu_opcode_t op) +{ + DisAsm_V3("vsubfp", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBSBS(ppu_opcode_t op) +{ + DisAsm_V3("vsubsbs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBSHS(ppu_opcode_t op) +{ + DisAsm_V3("vsubshs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBSWS(ppu_opcode_t op) +{ + DisAsm_V3("vsubsws", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBUBM(ppu_opcode_t op) +{ + DisAsm_V3("vsububm", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBUBS(ppu_opcode_t op) +{ + DisAsm_V3("vsububs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBUHM(ppu_opcode_t op) +{ + DisAsm_V3("vsubuhm", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBUHS(ppu_opcode_t op) +{ + DisAsm_V3("vsubuhs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBUWM(ppu_opcode_t op) +{ + DisAsm_V3("vsubuwm", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBUWS(ppu_opcode_t op) +{ + DisAsm_V3("vsubuws", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUMSWS(ppu_opcode_t op) +{ + DisAsm_V3("vsumsws", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUM2SWS(ppu_opcode_t op) +{ + DisAsm_V3("vsum2sws", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUM4SBS(ppu_opcode_t op) +{ + DisAsm_V3("vsum4sbs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUM4SHS(ppu_opcode_t op) +{ + DisAsm_V3("vsum4shs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUM4UBS(ppu_opcode_t op) +{ + DisAsm_V3("vsum4ubs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VUPKHPX(ppu_opcode_t op) +{ + DisAsm_V2("vupkhpx", op.vd, op.vb); +} + +void PPUDisAsm::VUPKHSB(ppu_opcode_t op) +{ + DisAsm_V2("vupkhsb", op.vd, op.vb); +} + +void PPUDisAsm::VUPKHSH(ppu_opcode_t op) +{ + DisAsm_V2("vupkhsh", op.vd, op.vb); +} + +void PPUDisAsm::VUPKLPX(ppu_opcode_t op) +{ + DisAsm_V2("vupklpx", op.vd, op.vb); +} + +void PPUDisAsm::VUPKLSB(ppu_opcode_t op) +{ + DisAsm_V2("vupklsb", op.vd, op.vb); +} + +void PPUDisAsm::VUPKLSH(ppu_opcode_t op) +{ + DisAsm_V2("vupklsh", op.vd, op.vb); +} + +void PPUDisAsm::VXOR(ppu_opcode_t op) +{ + DisAsm_V3("vxor", op.vd, op.va, op.vb); +} + +void PPUDisAsm::MULLI(ppu_opcode_t op) +{ + DisAsm_R2_IMM("mulli", op.rd, op.ra, op.simm16); +} + +void PPUDisAsm::SUBFIC(ppu_opcode_t op) +{ + DisAsm_R2_IMM("subfic", op.rd, op.ra, op.simm16); +} + +void PPUDisAsm::CMPLI(ppu_opcode_t op) +{ + DisAsm_CR1_R1_IMM(op.l10 ? "cmpdi" : "cmpwi", op.crfd, op.ra, op.uimm16); +} + +void PPUDisAsm::CMPI(ppu_opcode_t op) +{ + DisAsm_CR1_R1_IMM(op.l10 ? "cmpdi" : "cmpwi", op.crfd, op.ra, op.simm16); +} + +void PPUDisAsm::ADDIC(ppu_opcode_t op) +{ + DisAsm_R2_IMM(op.main & 1 ? "addic." : "addic", op.rd, op.ra, op.simm16); +} + +void PPUDisAsm::ADDI(ppu_opcode_t op) +{ + if (op.ra == 0) + { + DisAsm_R1_IMM("li", op.rd, op.simm16); + } + else + { + DisAsm_R2_IMM("addi", op.rd, op.ra, op.simm16); + } +} + +void PPUDisAsm::ADDIS(ppu_opcode_t op) +{ + if (op.ra == 0) + { + DisAsm_R1_IMM("lis", op.rd, op.simm16); + } + else + { + DisAsm_R2_IMM("addis", op.rd, op.ra, op.simm16); + } +} + +void PPUDisAsm::BC(ppu_opcode_t op) +{ + const u32 bo = op.bo; + const u32 bi = op.bi; + const s32 bd = op.ds * 4; + const u32 aa = op.aa; + const u32 lk = op.lk; + + if (m_mode == CPUDisAsm_CompilerElfMode) + { + Write(fmt::format("bc 0x%x, 0x%x, 0x%x, %d, %d", bo, bi, bd, aa, lk)); + return; + } + + //TODO: aa lk + const u8 bo0 = (bo & 0x10) ? 1 : 0; + const u8 bo1 = (bo & 0x08) ? 1 : 0; + const u8 bo2 = (bo & 0x04) ? 1 : 0; + const u8 bo3 = (bo & 0x02) ? 1 : 0; + const u8 bo4 = (bo & 0x01) ? 1 : 0; + + if (bo0 && !bo1 && !bo2 && bo3 && !bo4) + { + DisAsm_CR_BRANCH("bdz", bi / 4, bd); return; + } + else if (bo0 && bo1 && !bo2 && bo3 && !bo4) + { + DisAsm_CR_BRANCH("bdz-", bi / 4, bd); return; + } + else if (bo0 && bo1 && !bo2 && bo3 && bo4) + { + DisAsm_CR_BRANCH("bdz+", bi / 4, bd); return; + } + else if (bo0 && !bo1 && !bo2 && !bo3 && !bo4) + { + DisAsm_CR_BRANCH("bdnz", bi / 4, bd); return; + } + else if (bo0 && bo1 && !bo2 && !bo3 && !bo4) + { + DisAsm_CR_BRANCH("bdnz-", bi / 4, bd); return; + } + else if (bo0 && bo1 && !bo2 && !bo3 && bo4) + { + DisAsm_CR_BRANCH("bdnz+", bi / 4, bd); return; + } + else if (!bo0 && !bo1 && bo2 && !bo3 && !bo4) + { + switch (bi % 4) + { + case 0x0: DisAsm_CR_BRANCH("bge", bi / 4, bd); return; + case 0x1: DisAsm_CR_BRANCH("ble", bi / 4, bd); return; + case 0x2: DisAsm_CR_BRANCH("bne", bi / 4, bd); return; + } + } + else if (!bo0 && !bo1 && bo2 && bo3 && !bo4) + { + switch (bi % 4) + { + case 0x0: DisAsm_CR_BRANCH("bge-", bi / 4, bd); return; + case 0x1: DisAsm_CR_BRANCH("ble-", bi / 4, bd); return; + case 0x2: DisAsm_CR_BRANCH("bne-", bi / 4, bd); return; + } + } + else if (!bo0 && !bo1 && bo2 && bo3 && bo4) + { + switch (bi % 4) + { + case 0x0: DisAsm_CR_BRANCH("bge+", bi / 4, bd); return; + case 0x1: DisAsm_CR_BRANCH("ble+", bi / 4, bd); return; + case 0x2: DisAsm_CR_BRANCH("bne+", bi / 4, bd); return; + } + } + else if (!bo0 && bo1 && bo2 && !bo3 && !bo4) + { + switch (bi % 4) + { + case 0x0: DisAsm_CR_BRANCH("blt", bi / 4, bd); return; + case 0x1: DisAsm_CR_BRANCH("bgt", bi / 4, bd); return; + case 0x2: DisAsm_CR_BRANCH("beq", bi / 4, bd); return; + } + } + else if (!bo0 && bo1 && bo2 && bo3 && !bo4) + { + switch (bi % 4) + { + case 0x0: DisAsm_CR_BRANCH("blt-", bi / 4, bd); return; + case 0x1: DisAsm_CR_BRANCH("bgt-", bi / 4, bd); return; + case 0x2: DisAsm_CR_BRANCH("beq-", bi / 4, bd); return; + } + } + else if (!bo0 && bo1 && bo2 && bo3 && bo4) + { + switch (bi % 4) + { + case 0x0: DisAsm_CR_BRANCH("blt+", bi / 4, bd); return; + case 0x1: DisAsm_CR_BRANCH("bgt+", bi / 4, bd); return; + case 0x2: DisAsm_CR_BRANCH("beq+", bi / 4, bd); return; + } + } + + Write(fmt::format("bc [%x:%x:%x:%x:%x], cr%d[%x], 0x%x, %d, %d", bo0, bo1, bo2, bo3, bo4, bi / 4, bi % 4, bd, aa, lk)); +} + +void PPUDisAsm::HACK(ppu_opcode_t op) +{ + Write(fmt::format("hack %d", op.opcode & 0x3ffffff)); +} + +void PPUDisAsm::SC(ppu_opcode_t op) +{ + switch (op.lev) + { + case 0x0: Write("sc"); break; + case 0x1: Write("HyperCall LV1"); break; + case 0x3: Write("fast_stop()"); break; // hack + default: Write(fmt::format("Unknown sc: 0x%x", op.lev)); + } +} + +void PPUDisAsm::B(ppu_opcode_t op) +{ + const u32 ll = op.ll; + const u32 aa = op.aa; + const u32 lk = op.lk; + + if (m_mode == CPUDisAsm_CompilerElfMode) + { + Write(fmt::format("b 0x%x, %d, %d", ll, aa, lk)); + return; + } + + switch (lk) + { + case 0: + switch (aa) + { + case 0: DisAsm_BRANCH("b", ll); break; + case 1: DisAsm_BRANCH_A("ba", ll); break; + } + break; + + case 1: + switch (aa) + { + case 0: DisAsm_BRANCH("bl", ll); break; + case 1: DisAsm_BRANCH_A("bla", ll); break; + } + break; + } +} + +void PPUDisAsm::MCRF(ppu_opcode_t op) +{ + DisAsm_CR2("mcrf", op.crfd, op.crfs); +} + +void PPUDisAsm::BCLR(ppu_opcode_t op) +{ + const u32 bo = op.bo; + const u32 bi = op.bi; + + const u8 bo0 = (bo & 0x10) ? 1 : 0; + const u8 bo1 = (bo & 0x08) ? 1 : 0; + const u8 bo2 = (bo & 0x04) ? 1 : 0; + const u8 bo3 = (bo & 0x02) ? 1 : 0; + + if (bo0 && !bo1 && bo2 && !bo3) { Write("blr"); return; } + Write(fmt::format("bclr [%x:%x:%x:%x], cr%d[%x], %d, %d", bo0, bo1, bo2, bo3, bi / 4, bi % 4, op.bh, op.lk)); +} + +void PPUDisAsm::CRNOR(ppu_opcode_t op) +{ + DisAsm_INT3("crnor", op.crbd, op.crba, op.crbb); +} + +void PPUDisAsm::CRANDC(ppu_opcode_t op) +{ + DisAsm_INT3("crandc", op.crbd, op.crba, op.crbb); +} + +void PPUDisAsm::ISYNC(ppu_opcode_t op) +{ + Write("isync"); +} + +void PPUDisAsm::CRXOR(ppu_opcode_t op) +{ + DisAsm_INT3("crxor", op.crbd, op.crba, op.crbb); +} + +void PPUDisAsm::CRNAND(ppu_opcode_t op) +{ + DisAsm_INT3("crnand", op.crbd, op.crba, op.crbb); +} + +void PPUDisAsm::CRAND(ppu_opcode_t op) +{ + DisAsm_INT3("crand", op.crbd, op.crba, op.crbb); +} + +void PPUDisAsm::CREQV(ppu_opcode_t op) +{ + DisAsm_INT3("creqv", op.crbd, op.crba, op.crbb); +} + +void PPUDisAsm::CRORC(ppu_opcode_t op) +{ + DisAsm_INT3("crorc", op.crbd, op.crba, op.crbb); +} + +void PPUDisAsm::CROR(ppu_opcode_t op) +{ + DisAsm_INT3("cror", op.crbd, op.crba, op.crbb); +} + +void PPUDisAsm::BCCTR(ppu_opcode_t op) +{ + const u32 bo = op.bo; + const u32 bi = op.bi; + const u32 bh = op.bh; + + switch (op.lk) + { + case 0: DisAsm_INT3("bcctr", bo, bi, bh); break; + case 1: DisAsm_INT3("bcctrl", bo, bi, bh); break; + } +} + +void PPUDisAsm::RLWIMI(ppu_opcode_t op) +{ + DisAsm_R2_INT3_RC("rlwimi", op.ra, op.rs, op.sh32, op.mb32, op.me32, op.rc); +} + +void PPUDisAsm::RLWINM(ppu_opcode_t op) +{ + DisAsm_R2_INT3_RC("rlwinm", op.ra, op.rs, op.sh32, op.mb32, op.me32, op.rc); +} + +void PPUDisAsm::RLWNM(ppu_opcode_t op) +{ + DisAsm_R3_INT2_RC("rlwnm", op.ra, op.rs, op.rb, op.mb32, op.me32, op.rc); +} + +void PPUDisAsm::ORI(ppu_opcode_t op) +{ + if (op.rs == 0 && op.ra == 0 && op.uimm16 == 0) return Write("nop"); + DisAsm_R2_IMM("ori", op.rs, op.ra, op.uimm16); +} + +void PPUDisAsm::ORIS(ppu_opcode_t op) +{ + if (op.rs == 0 && op.ra == 0 && op.uimm16 == 0) return Write("nop"); + DisAsm_R2_IMM("oris", op.rs, op.ra, op.uimm16); +} + +void PPUDisAsm::XORI(ppu_opcode_t op) +{ + DisAsm_R2_IMM("xori", op.ra, op.rs, op.uimm16); +} + +void PPUDisAsm::XORIS(ppu_opcode_t op) +{ + DisAsm_R2_IMM("xoris", op.ra, op.rs, op.uimm16); +} + +void PPUDisAsm::ANDI(ppu_opcode_t op) +{ + DisAsm_R2_IMM("andi.", op.ra, op.rs, op.uimm16); +} + +void PPUDisAsm::ANDIS(ppu_opcode_t op) +{ + DisAsm_R2_IMM("andis.", op.ra, op.rs, op.uimm16); +} + +void PPUDisAsm::RLDICL(ppu_opcode_t op) +{ + const u32 sh = op.sh64; + const u32 mb = op.mbe64; + + if (sh == 0) + { + DisAsm_R2_INT1_RC("clrldi", op.ra, op.rs, mb, op.rc); + } + else if (mb == 0) + { + DisAsm_R2_INT1_RC("rotldi", op.ra, op.rs, sh, op.rc); + } + else if (mb == 64 - sh) + { + DisAsm_R2_INT1_RC("srdi", op.ra, op.rs, mb, op.rc); + } + else + { + DisAsm_R2_INT2_RC("rldicl", op.ra, op.rs, sh, mb, op.rc); + } +} + +void PPUDisAsm::RLDICR(ppu_opcode_t op) +{ + const u32 sh = op.sh64; + const u32 me = op.mbe64; + + DisAsm_R2_INT2_RC("rldicr", op.ra, op.rs, sh, me, op.rc); +} + +void PPUDisAsm::RLDIC(ppu_opcode_t op) +{ + const u32 sh = op.sh64; + const u32 mb = op.mbe64; + + DisAsm_R2_INT2_RC("rldic", op.ra, op.rs, sh, mb, op.rc); +} + +void PPUDisAsm::RLDIMI(ppu_opcode_t op) +{ + const u32 sh = op.sh64; + const u32 mb = op.mbe64; + + DisAsm_R2_INT2_RC("rldimi", op.ra, op.rs, sh, mb, op.rc); +} + +void PPUDisAsm::RLDCL(ppu_opcode_t op) +{ + const u32 mb = op.mbe64; + + DisAsm_R3_INT2_RC("rldcl", op.ra, op.rs, op.rb, mb, 0, op.rc); +} + +void PPUDisAsm::RLDCR(ppu_opcode_t op) +{ + const u32 me = op.mbe64; + + DisAsm_R3_INT2_RC("rldcr", op.ra, op.rs, op.rb, me, 0, op.rc); +} + +void PPUDisAsm::CMP(ppu_opcode_t op) +{ + DisAsm_CR1_R2(op.l10 ? "cmpd" : "cmpw", op.crfd, op.ra, op.rb); +} + +void PPUDisAsm::TW(ppu_opcode_t op) +{ + DisAsm_INT1_R2("tw", op.bo, op.ra, op.rb); +} + +void PPUDisAsm::LVSL(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvsl", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::LVEBX(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvebx", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::SUBFC(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("subfc", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::ADDC(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("addc", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::MULHDU(ppu_opcode_t op) +{ + DisAsm_R3_RC("mulhdu", op.rd, op.ra, op.rb, op.rc); +} + +void PPUDisAsm::MULHWU(ppu_opcode_t op) +{ + DisAsm_R3_RC("mulhwu", op.rd, op.ra, op.rb, op.rc); +} + +void PPUDisAsm::MFOCRF(ppu_opcode_t op) +{ + if (op.l11) + { + DisAsm_R1_IMM("mfocrf", op.rd, op.crm); + } + else + { + DisAsm_R1("mfcr", op.rd); + } +} + +void PPUDisAsm::LWARX(ppu_opcode_t op) +{ + DisAsm_R3("lwarx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::LDX(ppu_opcode_t op) +{ + DisAsm_R3("ldx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::LWZX(ppu_opcode_t op) +{ + DisAsm_R3("lwzx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::SLW(ppu_opcode_t op) +{ + DisAsm_R3_RC("slw", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::CNTLZW(ppu_opcode_t op) +{ + DisAsm_R2_RC("cntlzw", op.ra, op.rs, op.rc); +} + +void PPUDisAsm::SLD(ppu_opcode_t op) +{ + DisAsm_R3_RC("sld", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::AND(ppu_opcode_t op) +{ + DisAsm_R3_RC("and", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::CMPL(ppu_opcode_t op) +{ + DisAsm_CR1_R2(op.l10 ? "cmpld" : "cmplw", op.crfd, op.ra, op.rb); +} + +void PPUDisAsm::LVSR(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvsr", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::LVEHX(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvehx", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::SUBF(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("subf", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::LDUX(ppu_opcode_t op) +{ + DisAsm_R3("ldux", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::DCBST(ppu_opcode_t op) +{ + DisAsm_R2("dcbst", op.ra, op.rb); +} + +void PPUDisAsm::LWZUX(ppu_opcode_t op) +{ + DisAsm_R3("lwzux", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::CNTLZD(ppu_opcode_t op) +{ + DisAsm_R2_RC("cntlzd", op.ra, op.rs, op.rc); +} + +void PPUDisAsm::ANDC(ppu_opcode_t op) +{ + DisAsm_R3_RC("andc", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::TD(ppu_opcode_t op) +{ + DisAsm_INT1_R2("td", op.bo, op.ra, op.rb); +} + +void PPUDisAsm::LVEWX(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvewx", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::MULHD(ppu_opcode_t op) +{ + DisAsm_R3_RC("mulhd", op.rd, op.ra, op.rb, op.rc); +} + +void PPUDisAsm::MULHW(ppu_opcode_t op) +{ + DisAsm_R3_RC("mulhw", op.rd, op.ra, op.rb, op.rc); +} + +void PPUDisAsm::LDARX(ppu_opcode_t op) +{ + DisAsm_R3("ldarx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::DCBF(ppu_opcode_t op) +{ + DisAsm_R2("dcbf", op.ra, op.rb); +} + +void PPUDisAsm::LBZX(ppu_opcode_t op) +{ + DisAsm_R3("lbzx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::LVX(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvx", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::NEG(ppu_opcode_t op) +{ + DisAsm_R2_OE_RC("neg", op.rd, op.ra, op.oe, op.rc); +} + +void PPUDisAsm::LBZUX(ppu_opcode_t op) +{ + DisAsm_R3("lbzux", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::NOR(ppu_opcode_t op) +{ + if (op.rs == op.rb) + { + DisAsm_R2_RC("not", op.ra, op.rs, op.rc); + } + else + { + DisAsm_R3_RC("nor", op.ra, op.rs, op.rb, op.rc); + } +} + +void PPUDisAsm::STVEBX(ppu_opcode_t op) +{ + DisAsm_V1_R2("stvebx", op.vs, op.ra, op.rb); +} + +void PPUDisAsm::SUBFE(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("subfe", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::ADDE(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("adde", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::MTOCRF(ppu_opcode_t op) +{ + if (op.l11) + { + DisAsm_INT1_R1("mtocrf", op.crm, op.rs); + } + else + { + DisAsm_INT1_R1("mtcrf", op.crm, op.rs); + } +} + +void PPUDisAsm::STDX(ppu_opcode_t op) +{ + DisAsm_R3("stdx.", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STWCX(ppu_opcode_t op) +{ + DisAsm_R3("stwcx.", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STWX(ppu_opcode_t op) +{ + DisAsm_R3("stwx", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STVEHX(ppu_opcode_t op) +{ + DisAsm_V1_R2("stvehx", op.vs, op.ra, op.rb); +} + +void PPUDisAsm::STDUX(ppu_opcode_t op) +{ + DisAsm_R3("stdux", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STWUX(ppu_opcode_t op) +{ + DisAsm_R3("stwux", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STVEWX(ppu_opcode_t op) +{ + DisAsm_V1_R2("stvewx", op.vs, op.ra, op.rb); +} + +void PPUDisAsm::SUBFZE(ppu_opcode_t op) +{ + DisAsm_R2_OE_RC("subfze", op.rd, op.ra, op.oe, op.rc); +} + +void PPUDisAsm::ADDZE(ppu_opcode_t op) +{ + DisAsm_R2_OE_RC("addze", op.rd, op.ra, op.oe, op.rc); +} + +void PPUDisAsm::STDCX(ppu_opcode_t op) +{ + DisAsm_R3("stdcx.", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STBX(ppu_opcode_t op) +{ + DisAsm_R3("stbx", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STVX(ppu_opcode_t op) +{ + DisAsm_V1_R2("stvx", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::SUBFME(ppu_opcode_t op) +{ + DisAsm_R2_OE_RC("subfme", op.rd, op.ra, op.oe, op.rc); +} + +void PPUDisAsm::MULLD(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("mulld", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::ADDME(ppu_opcode_t op) +{ + DisAsm_R2_OE_RC("addme", op.rd, op.ra, op.oe, op.rc); +} + +void PPUDisAsm::MULLW(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("mullw", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::DCBTST(ppu_opcode_t op) +{ + DisAsm_R3("dcbtst", op.ra, op.rb, op.bo); +} + +void PPUDisAsm::STBUX(ppu_opcode_t op) +{ + DisAsm_R3("stbux", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::ADD(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("add", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::DCBT(ppu_opcode_t op) +{ + DisAsm_R2("dcbt", op.ra, op.rb); +} + +void PPUDisAsm::LHZX(ppu_opcode_t op) +{ + DisAsm_R3("lhzx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::EQV(ppu_opcode_t op) +{ + DisAsm_R3_RC("eqv", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::ECIWX(ppu_opcode_t op) +{ + DisAsm_R3("eciwx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::LHZUX(ppu_opcode_t op) +{ + DisAsm_R3("lhzux", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::XOR(ppu_opcode_t op) +{ + DisAsm_R3_RC("xor", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::MFSPR(ppu_opcode_t op) +{ + const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5); + switch (n) + { + case 0x001: DisAsm_R1("mfxer", op.rd); break; + case 0x008: DisAsm_R1("mflr", op.rd); break; + case 0x009: DisAsm_R1("mfctr", op.rd); break; + default: DisAsm_R1_IMM("mfspr", op.rd, op.spr); break; + } +} + +void PPUDisAsm::LWAX(ppu_opcode_t op) +{ + DisAsm_R3("lwax", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::DST(ppu_opcode_t op) +{ + DisAsm_R2("dst(t)", op.ra, op.rb); +} + +void PPUDisAsm::LHAX(ppu_opcode_t op) +{ + DisAsm_R3("lhax", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::LVXL(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvxl", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::MFTB(ppu_opcode_t op) +{ + const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5); + switch (n) + { + case 268: DisAsm_R1("mftb", op.rd); break; + case 269: DisAsm_R1("mftbu", op.rd); break; + default: DisAsm_R1_IMM("mftb", op.rd, op.spr); break; + } +} + +void PPUDisAsm::LWAUX(ppu_opcode_t op) +{ + DisAsm_R3("lwaux", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::DSTST(ppu_opcode_t op) +{ + DisAsm_R2("dstst(t)", op.ra, op.rb); +} + +void PPUDisAsm::LHAUX(ppu_opcode_t op) +{ + DisAsm_R3("lhaux", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::STHX(ppu_opcode_t op) +{ + DisAsm_R3("sthx", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::ORC(ppu_opcode_t op) +{ + DisAsm_R3_RC("orc", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::ECOWX(ppu_opcode_t op) +{ + DisAsm_R3("ecowx", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STHUX(ppu_opcode_t op) +{ + DisAsm_R3("sthux", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::OR(ppu_opcode_t op) +{ + if (op.rs == op.rb) + { + DisAsm_R2_RC("mr", op.ra, op.rb, op.rc); + } + else + { + DisAsm_R3_RC("or", op.ra, op.rs, op.rb, op.rc); + } +} + +void PPUDisAsm::DIVDU(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("divdu", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::DIVWU(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("divwu", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::MTSPR(ppu_opcode_t op) +{ + const u32 n = (op.spr & 0x1f) + ((op.spr >> 5) & 0x1f); + + switch (n) + { + case 0x001: DisAsm_R1("mtxer", op.rs); break; + case 0x008: DisAsm_R1("mtlr", op.rs); break; + case 0x009: DisAsm_R1("mtctr", op.rs); break; + default: DisAsm_IMM_R1("mtspr", op.spr, op.rs); break; + } +} + +void PPUDisAsm::DCBI(ppu_opcode_t op) +{ + DisAsm_R2("dcbi", op.ra, op.rb); +} + +void PPUDisAsm::NAND(ppu_opcode_t op) +{ + DisAsm_R3_RC("nand", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::STVXL(ppu_opcode_t op) +{ + DisAsm_V1_R2("stvxl", op.vs, op.ra, op.rb); +} + +void PPUDisAsm::DIVD(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("divd", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::DIVW(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("divw", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::LVLX(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvlx", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::LDBRX(ppu_opcode_t op) +{ + DisAsm_R3("ldbrx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::LSWX(ppu_opcode_t op) +{ + DisAsm_R3("lswx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::LWBRX(ppu_opcode_t op) +{ + DisAsm_R3("lwbrx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::LFSX(ppu_opcode_t op) +{ + DisAsm_F1_R2("lfsx", op.frd, op.ra, op.rb); +} + +void PPUDisAsm::SRW(ppu_opcode_t op) +{ + DisAsm_R3_RC("srw", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::SRD(ppu_opcode_t op) +{ + DisAsm_R3_RC("srd", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::LVRX(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvrx", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::LSWI(ppu_opcode_t op) +{ + DisAsm_R2_INT1("lswi", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::LFSUX(ppu_opcode_t op) +{ + DisAsm_F1_R2("lfsux", op.frd, op.ra, op.rb); +} + +void PPUDisAsm::SYNC(ppu_opcode_t op) +{ + Write("sync"); +} + +void PPUDisAsm::LFDX(ppu_opcode_t op) +{ + DisAsm_F1_R2("lfdx", op.frd, op.ra, op.rb); +} + +void PPUDisAsm::LFDUX(ppu_opcode_t op) +{ + DisAsm_F1_R2("lfdux", op.frd, op.ra, op.rb); +} + +void PPUDisAsm::STVLX(ppu_opcode_t op) +{ + DisAsm_V1_R2("stvlx", op.vs, op.ra, op.rb); +} + +void PPUDisAsm::STDBRX(ppu_opcode_t op) +{ + DisAsm_R3("stdbrx", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STSWX(ppu_opcode_t op) +{ + DisAsm_R3("swswx", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STWBRX(ppu_opcode_t op) +{ + DisAsm_R3("stwbrx", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STFSX(ppu_opcode_t op) +{ + DisAsm_F1_R2("stfsx", op.frs, op.ra, op.rb); +} + +void PPUDisAsm::STVRX(ppu_opcode_t op) +{ + DisAsm_V1_R2("stvrx", op.vs, op.ra, op.rb); +} + +void PPUDisAsm::STFSUX(ppu_opcode_t op) +{ + DisAsm_F1_R2("stfsux", op.frs, op.ra, op.rb); +} + +void PPUDisAsm::STSWI(ppu_opcode_t op) +{ + DisAsm_R2_INT1("stswi", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::STFDX(ppu_opcode_t op) +{ + DisAsm_F1_R2("stfdx", op.frs, op.ra, op.rb); +} + +void PPUDisAsm::STFDUX(ppu_opcode_t op) +{ + DisAsm_F1_R2("stfdux", op.frs, op.ra, op.rb); +} + +void PPUDisAsm::LVLXL(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvlxl", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::LHBRX(ppu_opcode_t op) +{ + DisAsm_R3("lhbrx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::SRAW(ppu_opcode_t op) +{ + DisAsm_R3_RC("sraw", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::SRAD(ppu_opcode_t op) +{ + DisAsm_R3_RC("srad", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::LVRXL(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvrxl", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::DSS(ppu_opcode_t op) +{ + Write("dss()"); +} + +void PPUDisAsm::SRAWI(ppu_opcode_t op) +{ + DisAsm_R2_INT1_RC("srawi", op.ra, op.rs, op.sh32, op.rc); +} + +void PPUDisAsm::SRADI(ppu_opcode_t op) +{ + DisAsm_R2_INT1_RC("sradi", op.ra, op.rs, op.sh64, op.rc); +} + +void PPUDisAsm::EIEIO(ppu_opcode_t op) +{ + Write("eieio"); +} + +void PPUDisAsm::STVLXL(ppu_opcode_t op) +{ + DisAsm_V1_R2("stvlxl", op.vs, op.ra, op.rb); +} + +void PPUDisAsm::STHBRX(ppu_opcode_t op) +{ + DisAsm_R3("sthbrx", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::EXTSH(ppu_opcode_t op) +{ + DisAsm_R2_RC("extsh", op.ra, op.rs, op.rc); +} + +void PPUDisAsm::STVRXL(ppu_opcode_t op) +{ + DisAsm_V1_R2("stvrxl", op.vs, op.ra, op.rb); +} + +void PPUDisAsm::EXTSB(ppu_opcode_t op) +{ + DisAsm_R2_RC("extsb", op.ra, op.rs, op.rc); +} + +void PPUDisAsm::STFIWX(ppu_opcode_t op) +{ + DisAsm_F1_R2("stfiwx", op.frs, op.ra, op.rb); +} + +void PPUDisAsm::EXTSW(ppu_opcode_t op) +{ + DisAsm_R2_RC("extsw", op.ra, op.rs, op.rc); +} + +void PPUDisAsm::ICBI(ppu_opcode_t op) +{ + DisAsm_R2("icbi", op.ra, op.rb); +} + +void PPUDisAsm::DCBZ(ppu_opcode_t op) +{ + DisAsm_R2("dcbz", op.ra, op.rb); +} + +void PPUDisAsm::LWZ(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lwz", op.rd, op.ra, op.simm16); +} + +void PPUDisAsm::LWZU(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lwzu", op.rd, op.ra, op.simm16); +} + +void PPUDisAsm::LBZ(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lbz", op.rd, op.ra, op.simm16); +} + +void PPUDisAsm::LBZU(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lbzu", op.rd, op.ra, op.simm16); +} + +void PPUDisAsm::STW(ppu_opcode_t op) +{ + DisAsm_R2_IMM("stw", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::STWU(ppu_opcode_t op) +{ + DisAsm_R2_IMM("stwu", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::STB(ppu_opcode_t op) +{ + DisAsm_R2_IMM("stb", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::STBU(ppu_opcode_t op) +{ + DisAsm_R2_IMM("stbu", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::LHZ(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lhz", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::LHZU(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lhzu", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::LHA(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lha", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::LHAU(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lhau", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::STH(ppu_opcode_t op) +{ + DisAsm_R2_IMM("sth", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::STHU(ppu_opcode_t op) +{ + DisAsm_R2_IMM("sthu", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::LMW(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lmw", op.rd, op.ra, op.simm16); +} + +void PPUDisAsm::STMW(ppu_opcode_t op) +{ + DisAsm_R2_IMM("stmw", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::LFS(ppu_opcode_t op) +{ + DisAsm_F1_IMM_R1("lfs", op.frd, op.simm16, op.ra); +} + +void PPUDisAsm::LFSU(ppu_opcode_t op) +{ + DisAsm_F1_IMM_R1("lfsu", op.frd, op.simm16, op.ra); +} + +void PPUDisAsm::LFD(ppu_opcode_t op) +{ + DisAsm_F1_IMM_R1("lfd", op.frd, op.simm16, op.ra); +} + +void PPUDisAsm::LFDU(ppu_opcode_t op) +{ + DisAsm_F1_IMM_R1("lfdu", op.frd, op.simm16, op.ra); +} + +void PPUDisAsm::STFS(ppu_opcode_t op) +{ + DisAsm_F1_IMM_R1("stfs", op.frs, op.simm16, op.ra); +} + +void PPUDisAsm::STFSU(ppu_opcode_t op) +{ + DisAsm_F1_IMM_R1("stfsu", op.frs, op.simm16, op.ra); +} + +void PPUDisAsm::STFD(ppu_opcode_t op) +{ + DisAsm_F1_IMM_R1("stfd", op.frs, op.simm16, op.ra); +} + +void PPUDisAsm::STFDU(ppu_opcode_t op) +{ + DisAsm_F1_IMM_R1("stfdu", op.frs, op.simm16, op.ra); +} + +void PPUDisAsm::LD(ppu_opcode_t op) +{ + DisAsm_R2_IMM("ld", op.rd, op.ra, op.ds * 4); +} + +void PPUDisAsm::LDU(ppu_opcode_t op) +{ + DisAsm_R2_IMM("ldu", op.rd, op.ra, op.ds * 4); +} + +void PPUDisAsm::LWA(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lwa", op.rd, op.ra, op.ds * 4); +} + +void PPUDisAsm::FDIVS(ppu_opcode_t op) +{ + DisAsm_F3_RC("fdivs", op.frd, op.fra, op.frb, op.rc); +} + +void PPUDisAsm::FSUBS(ppu_opcode_t op) +{ + DisAsm_F3_RC("fsubs", op.frd, op.fra, op.frb, op.rc); +} + +void PPUDisAsm::FADDS(ppu_opcode_t op) +{ + DisAsm_F3_RC("fadds", op.frd, op.fra, op.frb, op.rc); +} + +void PPUDisAsm::FSQRTS(ppu_opcode_t op) +{ + DisAsm_F2_RC("fsqrts", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FRES(ppu_opcode_t op) +{ + DisAsm_F2_RC("fres", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FMULS(ppu_opcode_t op) +{ + DisAsm_F3_RC("fmuls", op.frd, op.fra, op.frc, op.rc); +} + +void PPUDisAsm::FMADDS(ppu_opcode_t op) +{ + DisAsm_F4_RC("fmadds", op.frd, op.fra, op.frc, op.frb, op.rc); +} + +void PPUDisAsm::FMSUBS(ppu_opcode_t op) +{ + DisAsm_F4_RC("fmsubs", op.frd, op.fra, op.frc, op.frb, op.rc); +} + +void PPUDisAsm::FNMSUBS(ppu_opcode_t op) +{ + DisAsm_F4_RC("fnmsubs", op.frd, op.fra, op.frc, op.frb, op.rc); +} + +void PPUDisAsm::FNMADDS(ppu_opcode_t op) +{ + DisAsm_F4_RC("fnmadds", op.frd, op.fra, op.frc, op.frb, op.rc); +} + +void PPUDisAsm::STD(ppu_opcode_t op) +{ + DisAsm_R2_IMM("std", op.rs, op.ra, op.ds * 4); +} + +void PPUDisAsm::STDU(ppu_opcode_t op) +{ + DisAsm_R2_IMM("stdu", op.rs, op.ra, op.ds * 4); +} + +void PPUDisAsm::MTFSB1(ppu_opcode_t op) +{ + Write(fmt::format("mtfsb1%s %d", op.rc ? "." : "", op.crbd)); +} + +void PPUDisAsm::MCRFS(ppu_opcode_t op) +{ + DisAsm_CR2("mcrfs", op.crfd, op.crfs); +} + +void PPUDisAsm::MTFSB0(ppu_opcode_t op) +{ + Write(fmt::format("mtfsb0%s %d", op.rc ? "." : "", op.crbd)); +} + +void PPUDisAsm::MTFSFI(ppu_opcode_t op) +{ + Write(fmt::format("mtfsfi%s cr%d,%d,%d", op.rc ? "." : "", op.crfd, op.i, op.l15)); +} + +void PPUDisAsm::MFFS(ppu_opcode_t op) +{ + DisAsm_F1_RC("mffs", op.frd, op.rc); +} + +void PPUDisAsm::MTFSF(ppu_opcode_t op) +{ + Write(fmt::format("mtfsf%s %d,f%d,%d,%d", op.rc ? "." : "", op.rc, op.flm, op.frb, op.l6, op.l15)); +} + +void PPUDisAsm::FCMPU(ppu_opcode_t op) +{ + DisAsm_CR1_F2("fcmpu", op.crfd, op.fra, op.frb); +} + +void PPUDisAsm::FRSP(ppu_opcode_t op) +{ + DisAsm_F2_RC("frsp", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FCTIW(ppu_opcode_t op) +{ + DisAsm_F2_RC("fctiw", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FCTIWZ(ppu_opcode_t op) +{ + DisAsm_F2_RC("fctiwz", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FDIV(ppu_opcode_t op) +{ + DisAsm_F3_RC("fdiv", op.frd, op.fra, op.frb, op.rc); +} + +void PPUDisAsm::FSUB(ppu_opcode_t op) +{ + DisAsm_F3_RC("fsub", op.frd, op.fra, op.frb, op.rc); +} + +void PPUDisAsm::FADD(ppu_opcode_t op) +{ + DisAsm_F3_RC("fadd", op.frd, op.fra, op.frb, op.rc); +} + +void PPUDisAsm::FSQRT(ppu_opcode_t op) +{ + DisAsm_F2_RC("fsqrt", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FSEL(ppu_opcode_t op) +{ + DisAsm_F4_RC("fsel", op.frd, op.fra, op.frc, op.frb, op.rc); +} + +void PPUDisAsm::FMUL(ppu_opcode_t op) +{ + DisAsm_F3_RC("fmul", op.frd, op.fra, op.frc, op.rc); +} + +void PPUDisAsm::FRSQRTE(ppu_opcode_t op) +{ + DisAsm_F2_RC("frsqrte", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FMSUB(ppu_opcode_t op) +{ + DisAsm_F4_RC("fmsub", op.frd, op.fra, op.frc, op.frb, op.rc); +} + +void PPUDisAsm::FMADD(ppu_opcode_t op) +{ + DisAsm_F4_RC("fmadd", op.frd, op.fra, op.frc, op.frb, op.rc); +} + +void PPUDisAsm::FNMSUB(ppu_opcode_t op) +{ + DisAsm_F4_RC("fnmsub", op.frd, op.fra, op.frc, op.frb, op.rc); +} + +void PPUDisAsm::FNMADD(ppu_opcode_t op) +{ + DisAsm_F4_RC("fnmadd", op.frd, op.fra, op.frc, op.frb, op.rc); +} + +void PPUDisAsm::FCMPO(ppu_opcode_t op) +{ + DisAsm_F3("fcmpo", op.crfd, op.fra, op.frb); +} + +void PPUDisAsm::FNEG(ppu_opcode_t op) +{ + DisAsm_F2_RC("fneg", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FMR(ppu_opcode_t op) +{ + DisAsm_F2_RC("fmr", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FNABS(ppu_opcode_t op) +{ + DisAsm_F2_RC("fnabs", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FABS(ppu_opcode_t op) +{ + DisAsm_F2_RC("fabs", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FCTID(ppu_opcode_t op) +{ + DisAsm_F2_RC("fctid", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FCTIDZ(ppu_opcode_t op) +{ + DisAsm_F2_RC("fctidz", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FCFID(ppu_opcode_t op) +{ + DisAsm_F2_RC("fcfid", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::UNK(ppu_opcode_t op) +{ + Write(fmt::format("Unknown/Illegal opcode! (0x%08x)", op.opcode)); +} diff --git a/rpcs3/Emu/Cell/PPUDisAsm.h b/rpcs3/Emu/Cell/PPUDisAsm.h index 53478560ac..7138bfe519 100644 --- a/rpcs3/Emu/Cell/PPUDisAsm.h +++ b/rpcs3/Emu/Cell/PPUDisAsm.h @@ -3,9 +3,7 @@ #include "Emu/Cell/PPCDisAsm.h" #include "Emu/Cell/PPUOpcodes.h" -class PPUDisAsm - : public PPUOpcodes - , public PPCDisAsm +class PPUDisAsm final : public PPCDisAsm { public: PPUDisAsm(CPUDisAsmMode mode) : PPCDisAsm(mode) @@ -15,7 +13,7 @@ public: private: u32 DisAsmBranchTarget(const s32 imm) { - return branchTarget(dump_pc, imm); + return ppu_branch_target(dump_pc, imm); } private: @@ -131,9 +129,9 @@ private: { DisAsm_R1_RC(op, r0, false); } - void DisAsm_R2_OE_RC(const std::string& op, u32 r0, u32 r1, u32 oe, u32 rc) + void DisAsm_R2_OE_RC(const std::string& op, u32 r0, u32 r1, u32 _oe, u32 rc) { - Write(fmt::format("%s%s%s r%d,r%d", FixOp(op).c_str(), (oe ? "o" : ""), (rc ? "." : ""), r0, r1)); + Write(fmt::format("%s%s%s r%d,r%d", FixOp(op).c_str(), (_oe ? "o" : ""), (rc ? "." : ""), r0, r1)); } void DisAsm_R2_RC(const std::string& op, u32 r0, u32 r1, u32 rc) { @@ -143,9 +141,9 @@ private: { DisAsm_R2_RC(op, r0, r1, false); } - void DisAsm_R3_OE_RC(const std::string& op, u32 r0, u32 r1, u32 r2, u32 oe, u32 rc) + void DisAsm_R3_OE_RC(const std::string& op, u32 r0, u32 r1, u32 r2, u32 _oe, u32 rc) { - Write(fmt::format("%s%s%s r%d,r%d,r%d", FixOp(op).c_str(), (oe ? "o" : ""), (rc ? "." : ""), r0, r1, r2)); + Write(fmt::format("%s%s%s r%d,r%d,r%d", FixOp(op).c_str(), (_oe ? "o" : ""), (rc ? "." : ""), r0, r1, r2)); } void DisAsm_R3_INT2_RC(const std::string& op, u32 r0, u32 r1, u32 r2, s32 i0, s32 i1, u32 rc) { @@ -242,1841 +240,389 @@ private: Write(fmt::format("%s cr%d,0x%x ", FixOp(op).c_str(), cr, DisAsmBranchTarget(pc))); } -private: - void NULL_OP() - { - Write( "null" ); - } +public: + u32 disasm(u32 pc) override; - void NOP() - { - Write( "nop" ); - } + void TDI(ppu_opcode_t op); + void TWI(ppu_opcode_t op); + void MFVSCR(ppu_opcode_t op); + void MTVSCR(ppu_opcode_t op); + void VADDCUW(ppu_opcode_t op); + void VADDFP(ppu_opcode_t op); + void VADDSBS(ppu_opcode_t op); + void VADDSHS(ppu_opcode_t op); + void VADDSWS(ppu_opcode_t op); + void VADDUBM(ppu_opcode_t op); + void VADDUBS(ppu_opcode_t op); + void VADDUHM(ppu_opcode_t op); + void VADDUHS(ppu_opcode_t op); + void VADDUWM(ppu_opcode_t op); + void VADDUWS(ppu_opcode_t op); + void VAND(ppu_opcode_t op); + void VANDC(ppu_opcode_t op); + void VAVGSB(ppu_opcode_t op); + void VAVGSH(ppu_opcode_t op); + void VAVGSW(ppu_opcode_t op); + void VAVGUB(ppu_opcode_t op); + void VAVGUH(ppu_opcode_t op); + void VAVGUW(ppu_opcode_t op); + void VCFSX(ppu_opcode_t op); + void VCFUX(ppu_opcode_t op); + void VCMPBFP(ppu_opcode_t op); + void VCMPEQFP(ppu_opcode_t op); + void VCMPEQUB(ppu_opcode_t op); + void VCMPEQUH(ppu_opcode_t op); + void VCMPEQUW(ppu_opcode_t op); + void VCMPGEFP(ppu_opcode_t op); + void VCMPGTFP(ppu_opcode_t op); + void VCMPGTSB(ppu_opcode_t op); + void VCMPGTSH(ppu_opcode_t op); + void VCMPGTSW(ppu_opcode_t op); + void VCMPGTUB(ppu_opcode_t op); + void VCMPGTUH(ppu_opcode_t op); + void VCMPGTUW(ppu_opcode_t op); + void VCTSXS(ppu_opcode_t op); + void VCTUXS(ppu_opcode_t op); + void VEXPTEFP(ppu_opcode_t op); + void VLOGEFP(ppu_opcode_t op); + void VMADDFP(ppu_opcode_t op); + void VMAXFP(ppu_opcode_t op); + void VMAXSB(ppu_opcode_t op); + void VMAXSH(ppu_opcode_t op); + void VMAXSW(ppu_opcode_t op); + void VMAXUB(ppu_opcode_t op); + void VMAXUH(ppu_opcode_t op); + void VMAXUW(ppu_opcode_t op); + void VMHADDSHS(ppu_opcode_t op); + void VMHRADDSHS(ppu_opcode_t op); + void VMINFP(ppu_opcode_t op); + void VMINSB(ppu_opcode_t op); + void VMINSH(ppu_opcode_t op); + void VMINSW(ppu_opcode_t op); + void VMINUB(ppu_opcode_t op); + void VMINUH(ppu_opcode_t op); + void VMINUW(ppu_opcode_t op); + void VMLADDUHM(ppu_opcode_t op); + void VMRGHB(ppu_opcode_t op); + void VMRGHH(ppu_opcode_t op); + void VMRGHW(ppu_opcode_t op); + void VMRGLB(ppu_opcode_t op); + void VMRGLH(ppu_opcode_t op); + void VMRGLW(ppu_opcode_t op); + void VMSUMMBM(ppu_opcode_t op); + void VMSUMSHM(ppu_opcode_t op); + void VMSUMSHS(ppu_opcode_t op); + void VMSUMUBM(ppu_opcode_t op); + void VMSUMUHM(ppu_opcode_t op); + void VMSUMUHS(ppu_opcode_t op); + void VMULESB(ppu_opcode_t op); + void VMULESH(ppu_opcode_t op); + void VMULEUB(ppu_opcode_t op); + void VMULEUH(ppu_opcode_t op); + void VMULOSB(ppu_opcode_t op); + void VMULOSH(ppu_opcode_t op); + void VMULOUB(ppu_opcode_t op); + void VMULOUH(ppu_opcode_t op); + void VNMSUBFP(ppu_opcode_t op); + void VNOR(ppu_opcode_t op); + void VOR(ppu_opcode_t op); + void VPERM(ppu_opcode_t op); + void VPKPX(ppu_opcode_t op); + void VPKSHSS(ppu_opcode_t op); + void VPKSHUS(ppu_opcode_t op); + void VPKSWSS(ppu_opcode_t op); + void VPKSWUS(ppu_opcode_t op); + void VPKUHUM(ppu_opcode_t op); + void VPKUHUS(ppu_opcode_t op); + void VPKUWUM(ppu_opcode_t op); + void VPKUWUS(ppu_opcode_t op); + void VREFP(ppu_opcode_t op); + void VRFIM(ppu_opcode_t op); + void VRFIN(ppu_opcode_t op); + void VRFIP(ppu_opcode_t op); + void VRFIZ(ppu_opcode_t op); + void VRLB(ppu_opcode_t op); + void VRLH(ppu_opcode_t op); + void VRLW(ppu_opcode_t op); + void VRSQRTEFP(ppu_opcode_t op); + void VSEL(ppu_opcode_t op); + void VSL(ppu_opcode_t op); + void VSLB(ppu_opcode_t op); + void VSLDOI(ppu_opcode_t op); + void VSLH(ppu_opcode_t op); + void VSLO(ppu_opcode_t op); + void VSLW(ppu_opcode_t op); + void VSPLTB(ppu_opcode_t op); + void VSPLTH(ppu_opcode_t op); + void VSPLTISB(ppu_opcode_t op); + void VSPLTISH(ppu_opcode_t op); + void VSPLTISW(ppu_opcode_t op); + void VSPLTW(ppu_opcode_t op); + void VSR(ppu_opcode_t op); + void VSRAB(ppu_opcode_t op); + void VSRAH(ppu_opcode_t op); + void VSRAW(ppu_opcode_t op); + void VSRB(ppu_opcode_t op); + void VSRH(ppu_opcode_t op); + void VSRO(ppu_opcode_t op); + void VSRW(ppu_opcode_t op); + void VSUBCUW(ppu_opcode_t op); + void VSUBFP(ppu_opcode_t op); + void VSUBSBS(ppu_opcode_t op); + void VSUBSHS(ppu_opcode_t op); + void VSUBSWS(ppu_opcode_t op); + void VSUBUBM(ppu_opcode_t op); + void VSUBUBS(ppu_opcode_t op); + void VSUBUHM(ppu_opcode_t op); + void VSUBUHS(ppu_opcode_t op); + void VSUBUWM(ppu_opcode_t op); + void VSUBUWS(ppu_opcode_t op); + void VSUMSWS(ppu_opcode_t op); + void VSUM2SWS(ppu_opcode_t op); + void VSUM4SBS(ppu_opcode_t op); + void VSUM4SHS(ppu_opcode_t op); + void VSUM4UBS(ppu_opcode_t op); + void VUPKHPX(ppu_opcode_t op); + void VUPKHSB(ppu_opcode_t op); + void VUPKHSH(ppu_opcode_t op); + void VUPKLPX(ppu_opcode_t op); + void VUPKLSB(ppu_opcode_t op); + void VUPKLSH(ppu_opcode_t op); + void VXOR(ppu_opcode_t op); + void MULLI(ppu_opcode_t op); + void SUBFIC(ppu_opcode_t op); + void CMPLI(ppu_opcode_t op); + void CMPI(ppu_opcode_t op); + void ADDIC(ppu_opcode_t op); + void ADDI(ppu_opcode_t op); + void ADDIS(ppu_opcode_t op); + void BC(ppu_opcode_t op); + void HACK(ppu_opcode_t op); + void SC(ppu_opcode_t op); + void B(ppu_opcode_t op); + void MCRF(ppu_opcode_t op); + void BCLR(ppu_opcode_t op); + void CRNOR(ppu_opcode_t op); + void CRANDC(ppu_opcode_t op); + void ISYNC(ppu_opcode_t op); + void CRXOR(ppu_opcode_t op); + void CRNAND(ppu_opcode_t op); + void CRAND(ppu_opcode_t op); + void CREQV(ppu_opcode_t op); + void CRORC(ppu_opcode_t op); + void CROR(ppu_opcode_t op); + void BCCTR(ppu_opcode_t op); + void RLWIMI(ppu_opcode_t op); + void RLWINM(ppu_opcode_t op); + void RLWNM(ppu_opcode_t op); + void ORI(ppu_opcode_t op); + void ORIS(ppu_opcode_t op); + void XORI(ppu_opcode_t op); + void XORIS(ppu_opcode_t op); + void ANDI(ppu_opcode_t op); + void ANDIS(ppu_opcode_t op); + void RLDICL(ppu_opcode_t op); + void RLDICR(ppu_opcode_t op); + void RLDIC(ppu_opcode_t op); + void RLDIMI(ppu_opcode_t op); + void RLDCL(ppu_opcode_t op); + void RLDCR(ppu_opcode_t op); + void CMP(ppu_opcode_t op); + void TW(ppu_opcode_t op); + void LVSL(ppu_opcode_t op); + void LVEBX(ppu_opcode_t op); + void SUBFC(ppu_opcode_t op); + void ADDC(ppu_opcode_t op); + void MULHDU(ppu_opcode_t op); + void MULHWU(ppu_opcode_t op); + void MFOCRF(ppu_opcode_t op); + void LWARX(ppu_opcode_t op); + void LDX(ppu_opcode_t op); + void LWZX(ppu_opcode_t op); + void SLW(ppu_opcode_t op); + void CNTLZW(ppu_opcode_t op); + void SLD(ppu_opcode_t op); + void AND(ppu_opcode_t op); + void CMPL(ppu_opcode_t op); + void LVSR(ppu_opcode_t op); + void LVEHX(ppu_opcode_t op); + void SUBF(ppu_opcode_t op); + void LDUX(ppu_opcode_t op); + void DCBST(ppu_opcode_t op); + void LWZUX(ppu_opcode_t op); + void CNTLZD(ppu_opcode_t op); + void ANDC(ppu_opcode_t op); + void TD(ppu_opcode_t op); + void LVEWX(ppu_opcode_t op); + void MULHD(ppu_opcode_t op); + void MULHW(ppu_opcode_t op); + void LDARX(ppu_opcode_t op); + void DCBF(ppu_opcode_t op); + void LBZX(ppu_opcode_t op); + void LVX(ppu_opcode_t op); + void NEG(ppu_opcode_t op); + void LBZUX(ppu_opcode_t op); + void NOR(ppu_opcode_t op); + void STVEBX(ppu_opcode_t op); + void SUBFE(ppu_opcode_t op); + void ADDE(ppu_opcode_t op); + void MTOCRF(ppu_opcode_t op); + void STDX(ppu_opcode_t op); + void STWCX(ppu_opcode_t op); + void STWX(ppu_opcode_t op); + void STVEHX(ppu_opcode_t op); + void STDUX(ppu_opcode_t op); + void STWUX(ppu_opcode_t op); + void STVEWX(ppu_opcode_t op); + void SUBFZE(ppu_opcode_t op); + void ADDZE(ppu_opcode_t op); + void STDCX(ppu_opcode_t op); + void STBX(ppu_opcode_t op); + void STVX(ppu_opcode_t op); + void SUBFME(ppu_opcode_t op); + void MULLD(ppu_opcode_t op); + void ADDME(ppu_opcode_t op); + void MULLW(ppu_opcode_t op); + void DCBTST(ppu_opcode_t op); + void STBUX(ppu_opcode_t op); + void ADD(ppu_opcode_t op); + void DCBT(ppu_opcode_t op); + void LHZX(ppu_opcode_t op); + void EQV(ppu_opcode_t op); + void ECIWX(ppu_opcode_t op); + void LHZUX(ppu_opcode_t op); + void XOR(ppu_opcode_t op); + void MFSPR(ppu_opcode_t op); + void LWAX(ppu_opcode_t op); + void DST(ppu_opcode_t op); + void LHAX(ppu_opcode_t op); + void LVXL(ppu_opcode_t op); + void MFTB(ppu_opcode_t op); + void LWAUX(ppu_opcode_t op); + void DSTST(ppu_opcode_t op); + void LHAUX(ppu_opcode_t op); + void STHX(ppu_opcode_t op); + void ORC(ppu_opcode_t op); + void ECOWX(ppu_opcode_t op); + void STHUX(ppu_opcode_t op); + void OR(ppu_opcode_t op); + void DIVDU(ppu_opcode_t op); + void DIVWU(ppu_opcode_t op); + void MTSPR(ppu_opcode_t op); + void DCBI(ppu_opcode_t op); + void NAND(ppu_opcode_t op); + void STVXL(ppu_opcode_t op); + void DIVD(ppu_opcode_t op); + void DIVW(ppu_opcode_t op); + void LVLX(ppu_opcode_t op); + void LDBRX(ppu_opcode_t op); + void LSWX(ppu_opcode_t op); + void LWBRX(ppu_opcode_t op); + void LFSX(ppu_opcode_t op); + void SRW(ppu_opcode_t op); + void SRD(ppu_opcode_t op); + void LVRX(ppu_opcode_t op); + void LSWI(ppu_opcode_t op); + void LFSUX(ppu_opcode_t op); + void SYNC(ppu_opcode_t op); + void LFDX(ppu_opcode_t op); + void LFDUX(ppu_opcode_t op); + void STVLX(ppu_opcode_t op); + void STDBRX(ppu_opcode_t op); + void STSWX(ppu_opcode_t op); + void STWBRX(ppu_opcode_t op); + void STFSX(ppu_opcode_t op); + void STVRX(ppu_opcode_t op); + void STFSUX(ppu_opcode_t op); + void STSWI(ppu_opcode_t op); + void STFDX(ppu_opcode_t op); + void STFDUX(ppu_opcode_t op); + void LVLXL(ppu_opcode_t op); + void LHBRX(ppu_opcode_t op); + void SRAW(ppu_opcode_t op); + void SRAD(ppu_opcode_t op); + void LVRXL(ppu_opcode_t op); + void DSS(ppu_opcode_t op); + void SRAWI(ppu_opcode_t op); + void SRADI(ppu_opcode_t op); + void EIEIO(ppu_opcode_t op); + void STVLXL(ppu_opcode_t op); + void STHBRX(ppu_opcode_t op); + void EXTSH(ppu_opcode_t op); + void STVRXL(ppu_opcode_t op); + void EXTSB(ppu_opcode_t op); + void STFIWX(ppu_opcode_t op); + void EXTSW(ppu_opcode_t op); + void ICBI(ppu_opcode_t op); + void DCBZ(ppu_opcode_t op); + void LWZ(ppu_opcode_t op); + void LWZU(ppu_opcode_t op); + void LBZ(ppu_opcode_t op); + void LBZU(ppu_opcode_t op); + void STW(ppu_opcode_t op); + void STWU(ppu_opcode_t op); + void STB(ppu_opcode_t op); + void STBU(ppu_opcode_t op); + void LHZ(ppu_opcode_t op); + void LHZU(ppu_opcode_t op); + void LHA(ppu_opcode_t op); + void LHAU(ppu_opcode_t op); + void STH(ppu_opcode_t op); + void STHU(ppu_opcode_t op); + void LMW(ppu_opcode_t op); + void STMW(ppu_opcode_t op); + void LFS(ppu_opcode_t op); + void LFSU(ppu_opcode_t op); + void LFD(ppu_opcode_t op); + void LFDU(ppu_opcode_t op); + void STFS(ppu_opcode_t op); + void STFSU(ppu_opcode_t op); + void STFD(ppu_opcode_t op); + void STFDU(ppu_opcode_t op); + void LD(ppu_opcode_t op); + void LDU(ppu_opcode_t op); + void LWA(ppu_opcode_t op); + void FDIVS(ppu_opcode_t op); + void FSUBS(ppu_opcode_t op); + void FADDS(ppu_opcode_t op); + void FSQRTS(ppu_opcode_t op); + void FRES(ppu_opcode_t op); + void FMULS(ppu_opcode_t op); + void FMADDS(ppu_opcode_t op); + void FMSUBS(ppu_opcode_t op); + void FNMSUBS(ppu_opcode_t op); + void FNMADDS(ppu_opcode_t op); + void STD(ppu_opcode_t op); + void STDU(ppu_opcode_t op); + void MTFSB1(ppu_opcode_t op); + void MCRFS(ppu_opcode_t op); + void MTFSB0(ppu_opcode_t op); + void MTFSFI(ppu_opcode_t op); + void MFFS(ppu_opcode_t op); + void MTFSF(ppu_opcode_t op); + void FCMPU(ppu_opcode_t op); + void FRSP(ppu_opcode_t op); + void FCTIW(ppu_opcode_t op); + void FCTIWZ(ppu_opcode_t op); + void FDIV(ppu_opcode_t op); + void FSUB(ppu_opcode_t op); + void FADD(ppu_opcode_t op); + void FSQRT(ppu_opcode_t op); + void FSEL(ppu_opcode_t op); + void FMUL(ppu_opcode_t op); + void FRSQRTE(ppu_opcode_t op); + void FMSUB(ppu_opcode_t op); + void FMADD(ppu_opcode_t op); + void FNMSUB(ppu_opcode_t op); + void FNMADD(ppu_opcode_t op); + void FCMPO(ppu_opcode_t op); + void FNEG(ppu_opcode_t op); + void FMR(ppu_opcode_t op); + void FNABS(ppu_opcode_t op); + void FABS(ppu_opcode_t op); + void FCTID(ppu_opcode_t op); + void FCTIDZ(ppu_opcode_t op); + void FCFID(ppu_opcode_t op); - void TDI(u32 to, u32 ra, s32 simm16) - { - DisAsm_INT1_R1_IMM("tdi", to, ra, simm16); - } - void TWI(u32 to, u32 ra, s32 simm16) - { - DisAsm_INT1_R1_IMM("twi", to, ra, simm16); - } - void MFVSCR(u32 vd) - { - DisAsm_V1("mfvscr", vd); - } - void MTVSCR(u32 vb) - { - DisAsm_V1("mtvscr", vb); - } - void VADDCUW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vaddcuw", vd, va, vb); - } - void VADDFP(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vaddfp", vd, va, vb); - } - void VADDSBS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vaddsbs", vd, va, vb); - } - void VADDSHS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vaddshs", vd, va, vb); - } - void VADDSWS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vaddsws", vd, va, vb); - } - void VADDUBM(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vaddubm", vd, va, vb); - } - void VADDUBS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vaddubs", vd, va, vb); - } - void VADDUHM(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vadduhm", vd, va, vb); - } - void VADDUHS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vadduhs", vd, va, vb); - } - void VADDUWM(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vadduwm", vd, va, vb); - } - void VADDUWS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vadduws", vd, va, vb); - } - void VAND(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vand", vd, va, vb); - } - void VANDC(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vandc", vd, va, vb); - } - void VAVGSB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vavgsb", vd, va, vb); - } - void VAVGSH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vavgsh", vd, va, vb); - } - void VAVGSW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vavgsw", vd, va, vb); - } - void VAVGUB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vavgub", vd, va, vb); - } - void VAVGUH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vavguh", vd, va, vb); - } - void VAVGUW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vavguw", vd, va, vb); - } - void VCFSX(u32 vd, u32 uimm5, u32 vb) - { - DisAsm_V2_UIMM("vcfsx", vd, vb, uimm5); - } - void VCFUX(u32 vd, u32 uimm5, u32 vb) - { - DisAsm_V2_UIMM("vcfux", vd, vb, uimm5); - } - void VCMPBFP(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpbfp", vd, va, vb); - } - void VCMPBFP_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpbfp.", vd, va, vb); - } - void VCMPEQFP(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpeqfp", vd, va, vb); - } - void VCMPEQFP_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpeqfp.", vd, va, vb); - } - void VCMPEQUB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpequb", vd, va, vb); - } - void VCMPEQUB_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpequb.", vd, va, vb); - } - void VCMPEQUH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpequh", vd, va, vb); - } - void VCMPEQUH_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpequh.", vd, va, vb); - } - void VCMPEQUW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpequw", vd, va, vb); - } - void VCMPEQUW_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpequw.", vd, va, vb); - } - void VCMPGEFP(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgefp", vd, va, vb); - } - void VCMPGEFP_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgefp.", vd, va, vb); - } - void VCMPGTFP(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtfp", vd, va, vb); - } - void VCMPGTFP_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtfp.", vd, va, vb); - } - void VCMPGTSB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtsb", vd, va, vb); - } - void VCMPGTSB_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtsb.", vd, va, vb); - } - void VCMPGTSH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtsh", vd, va, vb); - } - void VCMPGTSH_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtsh.", vd, va, vb); - } - void VCMPGTSW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtsw", vd, va, vb); - } - void VCMPGTSW_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtsw.", vd, va, vb); - } - void VCMPGTUB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtub", vd, va, vb); - } - void VCMPGTUB_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtub.", vd, va, vb); - } - void VCMPGTUH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtuh", vd, va, vb); - } - void VCMPGTUH_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtuh.", vd, va, vb); - } - void VCMPGTUW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtuw", vd, va, vb); - } - void VCMPGTUW_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtuw.", vd, va, vb); - } - void VCTSXS(u32 vd, u32 uimm5, u32 vb) - { - DisAsm_V2_UIMM("vctsxs", vd, vb, uimm5); - } - void VCTUXS(u32 vd, u32 uimm5, u32 vb) - { - DisAsm_V2_UIMM("vctuxs", vd, vb, uimm5); - } - void VEXPTEFP(u32 vd, u32 vb) - { - DisAsm_V2("vexptefp", vd, vb); - } - void VLOGEFP(u32 vd, u32 vb) - { - DisAsm_V2("vlogefp", vd, vb); - } - void VMADDFP(u32 vd, u32 va, u32 vc, u32 vb) - { - DisAsm_V4("vmaddfp", vd, va, vc, vb); - } - void VMAXFP(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmaxfp", vd, va, vb); - } - void VMAXSB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmaxsb", vd, va, vb); - } - void VMAXSH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmaxsh", vd, va, vb); - } - void VMAXSW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmaxsw", vd, va, vb); - } - void VMAXUB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmaxub", vd, va, vb); - } - void VMAXUH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmaxuh", vd, va, vb); - } - void VMAXUW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmaxuw", vd, va, vb); - } - void VMHADDSHS(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vmhaddshs", vd, va, vb, vc); - } - void VMHRADDSHS(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vmhraddshs", vd, va, vb, vc); - } - void VMINFP(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vminfp", vd, va, vb); - } - void VMINSB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vminsb", vd, va, vb); - } - void VMINSH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vminsh", vd, va, vb); - } - void VMINSW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vminsw", vd, va, vb); - } - void VMINUB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vminub", vd, va, vb); - } - void VMINUH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vminuh", vd, va, vb); - } - void VMINUW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vminuw", vd, va, vb); - } - void VMLADDUHM(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vmladduhm", vd, va, vb, vc); - } - void VMRGHB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmrghb", vd, va, vb); - } - void VMRGHH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmrghh", vd, va, vb); - } - void VMRGHW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmrghw", vd, va, vb); - } - void VMRGLB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmrglb", vd, va, vb); - } - void VMRGLH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmrglh", vd, va, vb); - } - void VMRGLW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmrglw", vd, va, vb); - } - void VMSUMMBM(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vmsummbm", vd, va, vb, vc); - } - void VMSUMSHM(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vmsumshm", vd, va, vb, vc); - } - void VMSUMSHS(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vmsumshs", vd, va, vb, vc); - } - void VMSUMUBM(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vmsumubm", vd, va, vb, vc); - } - void VMSUMUHM(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vmsumuhm", vd, va, vb, vc); - } - void VMSUMUHS(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vmsumuhs", vd, va, vb, vc); - } - void VMULESB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmulesb", vd, va, vb); - } - void VMULESH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmulesh", vd, va, vb); - } - void VMULEUB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmuleub", vd, va, vb); - } - void VMULEUH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmuleuh", vd, va, vb); - } - void VMULOSB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmulosb", vd, va, vb); - } - void VMULOSH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmulosh", vd, va, vb); - } - void VMULOUB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmuloub", vd, va, vb); - } - void VMULOUH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmulouh", vd, va, vb); - } - void VNMSUBFP(u32 vd, u32 va, u32 vc, u32 vb) - { - DisAsm_V4("vnmsubfp", vd, va, vc, vb); - } - void VNOR(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vnor", vd, va, vb); - } - void VOR(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vor", vd, va, vb); - } - void VPERM(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vperm", vd, va, vb, vc); - } - void VPKPX(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vpkpx", vd, va, vb); - } - void VPKSHSS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vpkshss", vd, va, vb); - } - void VPKSHUS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vpkshus", vd, va, vb); - } - void VPKSWSS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vpkswss", vd, va, vb); - } - void VPKSWUS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vpkswus", vd, va, vb); - } - void VPKUHUM(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vpkuhum", vd, va, vb); - } - void VPKUHUS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vpkuhus", vd, va, vb); - } - void VPKUWUM(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vpkuwum", vd, va, vb); - } - void VPKUWUS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vpkuwus", vd, va, vb); - } - void VREFP(u32 vd, u32 vb) - { - DisAsm_V2("vrefp", vd, vb); - } - void VRFIM(u32 vd, u32 vb) - { - DisAsm_V2("vrfim", vd, vb); - } - void VRFIN(u32 vd, u32 vb) - { - DisAsm_V2("vrfin", vd, vb); - } - void VRFIP(u32 vd, u32 vb) - { - DisAsm_V2("vrfip", vd, vb); - } - void VRFIZ(u32 vd, u32 vb) - { - DisAsm_V2("vrfiz", vd, vb); - } - void VRLB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vrlb", vd, va, vb); - } - void VRLH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vrlh", vd, va, vb); - } - void VRLW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vrlw", vd, va, vb); - } - void VRSQRTEFP(u32 vd, u32 vb) - { - DisAsm_V2("vrsqrtefp", vd, vb); - } - void VSEL(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vsel", vd, va, vb, vc); - } - void VSL(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsl", vd, va, vb); - } - void VSLB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vslb", vd, va, vb); - } - void VSLDOI(u32 vd, u32 va, u32 vb, u32 sh) - { - DisAsm_V3_UIMM("vsldoi", vd, va, vb, sh); - } - void VSLH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vslh", vd, va, vb); - } - void VSLO(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vslo", vd, va, vb); - } - void VSLW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vslw", vd, va, vb); - } - void VSPLTB(u32 vd, u32 uimm5, u32 vb) - { - DisAsm_V2_UIMM("vspltb", vd, vb, uimm5); - } - void VSPLTH(u32 vd, u32 uimm5, u32 vb) - { - DisAsm_V2_UIMM("vsplth", vd, vb, uimm5); - } - void VSPLTISB(u32 vd, s32 simm5) - { - DisAsm_V1_SIMM("vspltisb", vd, simm5); - } - void VSPLTISH(u32 vd, s32 simm5) - { - DisAsm_V1_SIMM("vspltish", vd, simm5); - } - void VSPLTISW(u32 vd, s32 simm5) - { - DisAsm_V1_SIMM("vspltisw", vd, simm5); - } - void VSPLTW(u32 vd, u32 uimm5, u32 vb) - { - DisAsm_V2_UIMM("vspltw", vd, vb, uimm5); - } - void VSR(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsr", vd, va, vb); - } - void VSRAB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsrab", vd, va, vb); - } - void VSRAH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsrah", vd, va, vb); - } - void VSRAW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsraw", vd, va, vb); - } - void VSRB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsrb", vd, va, vb); - } - void VSRH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsrh", vd, va, vb); - } - void VSRO(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsro", vd, va, vb); - } - void VSRW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsrw", vd, va, vb); - } - void VSUBCUW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsubcuw", vd, va, vb); - } - void VSUBFP(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsubfp", vd, va, vb); - } - void VSUBSBS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsubsbs", vd, va, vb); - } - void VSUBSHS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsubshs", vd, va, vb); - } - void VSUBSWS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsubsws", vd, va, vb); - } - void VSUBUBM(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsububm", vd, va, vb); - } - void VSUBUBS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsububs", vd, va, vb); - } - void VSUBUHM(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsubuhm", vd, va, vb); - } - void VSUBUHS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsubuhs", vd, va, vb); - } - void VSUBUWM(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsubuwm", vd, va, vb); - } - void VSUBUWS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsubuws", vd, va, vb); - } - void VSUMSWS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsumsws", vd, va, vb); - } - void VSUM2SWS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsum2sws", vd, va, vb); - } - void VSUM4SBS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsum4sbs", vd, va, vb); - } - void VSUM4SHS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsum4shs", vd, va, vb); - } - void VSUM4UBS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsum4ubs", vd, va, vb); - } - void VUPKHPX(u32 vd, u32 vb) - { - DisAsm_V2("vupkhpx", vd, vb); - } - void VUPKHSB(u32 vd, u32 vb) - { - DisAsm_V2("vupkhsb", vd, vb); - } - void VUPKHSH(u32 vd, u32 vb) - { - DisAsm_V2("vupkhsh", vd, vb); - } - void VUPKLPX(u32 vd, u32 vb) - { - DisAsm_V2("vupklpx", vd, vb); - } - void VUPKLSB(u32 vd, u32 vb) - { - DisAsm_V2("vupklsb", vd, vb); - } - void VUPKLSH(u32 vd, u32 vb) - { - DisAsm_V2("vupklsh", vd, vb); - } - void VXOR(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vxor", vd, va, vb); - } - void MULLI(u32 rd, u32 ra, s32 simm16) - { - DisAsm_R2_IMM("mulli", rd, ra, simm16); - } - void SUBFIC(u32 rd, u32 ra, s32 simm16) - { - DisAsm_R2_IMM("subfic", rd, ra, simm16); - } - void CMPLI(u32 crfd, u32 l, u32 ra, u32 uimm16) - { - DisAsm_CR1_R1_IMM(fmt::format("cmpl%si", (l ? "d" : "w")), crfd, ra, uimm16); - } - void CMPI(u32 crfd, u32 l, u32 ra, s32 simm16) - { - DisAsm_CR1_R1_IMM(fmt::format("cmp%si", (l ? "d" : "w")), crfd, ra, simm16); - } - void ADDIC(u32 rd, u32 ra, s32 simm16) - { - DisAsm_R2_IMM("addic", rd, ra, simm16); - } - void ADDIC_(u32 rd, u32 ra, s32 simm16) - { - DisAsm_R2_IMM("addic.", rd, ra, simm16); - } - void ADDI(u32 rd, u32 ra, s32 simm16) - { - if(ra == 0) - { - DisAsm_R1_IMM("li", rd, simm16); - } - else - { - DisAsm_R2_IMM("addi", rd, ra, simm16); - } - } - void ADDIS(u32 rd, u32 ra, s32 simm16) - { - if(ra == 0) - { - DisAsm_R1_IMM("lis", rd, simm16); - } - else - { - DisAsm_R2_IMM("addis", rd, ra, simm16); - } - } - void BC(u32 bo, u32 bi, s32 bd, u32 aa, u32 lk) - { - if(m_mode == CPUDisAsm_CompilerElfMode) - { - Write(fmt::format("bc 0x%x, 0x%x, 0x%x, %d, %d", bo, bi, bd, aa, lk)); - return; - } - - //TODO: aa lk - const u8 bo0 = (bo & 0x10) ? 1 : 0; - const u8 bo1 = (bo & 0x08) ? 1 : 0; - const u8 bo2 = (bo & 0x04) ? 1 : 0; - const u8 bo3 = (bo & 0x02) ? 1 : 0; - const u8 bo4 = (bo & 0x01) ? 1 : 0; - - if(bo0 && !bo1 && !bo2 && bo3 && !bo4) - { - DisAsm_CR_BRANCH("bdz", bi/4, bd); return; - } - else if(bo0 && bo1 && !bo2 && bo3 && !bo4) - { - DisAsm_CR_BRANCH("bdz-", bi/4, bd); return; - } - else if(bo0 && bo1 && !bo2 && bo3 && bo4) - { - DisAsm_CR_BRANCH("bdz+", bi/4, bd); return; - } - else if(bo0 && !bo1 && !bo2 && !bo3 && !bo4) - { - DisAsm_CR_BRANCH("bdnz", bi/4, bd); return; - } - else if(bo0 && bo1 && !bo2 && !bo3 && !bo4) - { - DisAsm_CR_BRANCH("bdnz-", bi/4, bd); return; - } - else if(bo0 && bo1 && !bo2 && !bo3 && bo4) - { - DisAsm_CR_BRANCH("bdnz+", bi/4, bd); return; - } - else if(!bo0 && !bo1 && bo2 && !bo3 && !bo4) - { - switch(bi % 4) - { - case 0x0: DisAsm_CR_BRANCH("bge", bi/4, bd); return; - case 0x1: DisAsm_CR_BRANCH("ble", bi/4, bd); return; - case 0x2: DisAsm_CR_BRANCH("bne", bi/4, bd); return; - } - } - else if(!bo0 && !bo1 && bo2 && bo3 && !bo4) - { - switch(bi % 4) - { - case 0x0: DisAsm_CR_BRANCH("bge-", bi/4, bd); return; - case 0x1: DisAsm_CR_BRANCH("ble-", bi/4, bd); return; - case 0x2: DisAsm_CR_BRANCH("bne-", bi/4, bd); return; - } - } - else if(!bo0 && !bo1 && bo2 && bo3 && bo4) - { - switch(bi % 4) - { - case 0x0: DisAsm_CR_BRANCH("bge+", bi/4, bd); return; - case 0x1: DisAsm_CR_BRANCH("ble+", bi/4, bd); return; - case 0x2: DisAsm_CR_BRANCH("bne+", bi/4, bd); return; - } - } - else if(!bo0 && bo1 && bo2 && !bo3 && !bo4) - { - switch(bi % 4) - { - case 0x0: DisAsm_CR_BRANCH("blt", bi/4, bd); return; - case 0x1: DisAsm_CR_BRANCH("bgt", bi/4, bd); return; - case 0x2: DisAsm_CR_BRANCH("beq", bi/4, bd); return; - } - } - else if(!bo0 && bo1 && bo2 && bo3 && !bo4) - { - switch(bi % 4) - { - case 0x0: DisAsm_CR_BRANCH("blt-", bi/4, bd); return; - case 0x1: DisAsm_CR_BRANCH("bgt-", bi/4, bd); return; - case 0x2: DisAsm_CR_BRANCH("beq-", bi/4, bd); return; - } - } - else if(!bo0 && bo1 && bo2 && bo3 && bo4) - { - switch(bi % 4) - { - case 0x0: DisAsm_CR_BRANCH("blt+", bi/4, bd); return; - case 0x1: DisAsm_CR_BRANCH("bgt+", bi/4, bd); return; - case 0x2: DisAsm_CR_BRANCH("beq+", bi/4, bd); return; - } - } - - Write(fmt::format("bc [%x:%x:%x:%x:%x], cr%d[%x], 0x%x, %d, %d", bo0, bo1, bo2, bo3, bo4, bi/4, bi%4, bd, aa, lk)); - } - void HACK(u32 index) - { - Write(fmt::format("hack %d", index)); - } - void SC(u32 lev) - { - switch (lev) - { - case 0x0: Write("sc"); break; - case 0x1: Write("HyperCall LV1"); break; - default: Write(fmt::format("Unknown sc: 0x%x", lev)); - } - } - void B(s32 ll, u32 aa, u32 lk) - { - if(m_mode == CPUDisAsm_CompilerElfMode) - { - Write(fmt::format("b 0x%x, %d, %d", ll, aa, lk)); - return; - } - - switch(lk) - { - case 0: - switch(aa) - { - case 0: DisAsm_BRANCH("b", ll); break; - case 1: DisAsm_BRANCH_A("ba", ll); break; - } - break; - - case 1: - switch(aa) - { - case 0: DisAsm_BRANCH("bl", ll); break; - case 1: DisAsm_BRANCH_A("bla", ll); break; - } - break; - } - } - void MCRF(u32 crfd, u32 crfs) - { - DisAsm_CR2("mcrf", crfd, crfs); - } - void BCLR(u32 bo, u32 bi, u32 bh, u32 lk) - { - const u8 bo0 = (bo & 0x10) ? 1 : 0; - const u8 bo1 = (bo & 0x08) ? 1 : 0; - const u8 bo2 = (bo & 0x04) ? 1 : 0; - const u8 bo3 = (bo & 0x02) ? 1 : 0; - - if(bo0 && !bo1 && bo2 && !bo3) {Write("blr"); return;} - Write(fmt::format("bclr [%x:%x:%x:%x], cr%d[%x], %d, %d", bo0, bo1, bo2, bo3, bi/4, bi%4, bh, lk)); - } - void CRNOR(u32 bt, u32 ba, u32 bb) - { - DisAsm_INT3("crnor", bt, ba, bb); - } - void CRANDC(u32 bt, u32 ba, u32 bb) - { - DisAsm_INT3("crandc", bt, ba, bb); - } - void ISYNC() - { - Write("isync"); - } - void CRXOR(u32 bt, u32 ba, u32 bb) - { - DisAsm_INT3("crxor", bt, ba, bb); - } - void CRNAND(u32 bt, u32 ba, u32 bb) - { - DisAsm_INT3("crnand", bt, ba, bb); - } - void CRAND(u32 bt, u32 ba, u32 bb) - { - DisAsm_INT3("crand", bt, ba, bb); - } - void CREQV(u32 bt, u32 ba, u32 bb) - { - DisAsm_INT3("creqv", bt, ba, bb); - } - void CRORC(u32 bt, u32 ba, u32 bb) - { - DisAsm_INT3("crorc", bt, ba, bb); - } - void CROR(u32 bt, u32 ba, u32 bb) - { - DisAsm_INT3("cror", bt, ba, bb); - } - void BCCTR(u32 bo, u32 bi, u32 bh, u32 lk) - { - switch(lk) - { - case 0: DisAsm_INT3("bcctr", bo, bi, bh); break; - case 1: DisAsm_INT3("bcctrl", bo, bi, bh); break; - } - } - void RLWIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) - { - DisAsm_R2_INT3_RC("rlwimi", ra, rs, sh, mb, me, rc); - } - void RLWINM(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) - { - DisAsm_R2_INT3_RC("rlwinm", ra, rs, sh, mb, me, rc); - } - void RLWNM(u32 ra, u32 rs, u32 rb, u32 MB, u32 ME, u32 rc) - { - DisAsm_R3_INT2_RC("rlwnm", ra, rs, rb, MB, ME, rc); - } - void ORI(u32 rs, u32 ra, u32 uimm16) - { - if(rs == 0 && ra == 0 && uimm16 == 0) - { - NOP(); - return; - } - DisAsm_R2_IMM("ori", rs, ra, uimm16); - } - void ORIS(u32 rs, u32 ra, u32 uimm16) - { - if(rs == 0 && ra == 0 && uimm16 == 0) - { - NOP(); - return; - } - DisAsm_R2_IMM("oris", rs, ra, uimm16); - } - void XORI(u32 ra, u32 rs, u32 uimm16) - { - DisAsm_R2_IMM("xori", ra, rs, uimm16); - } - void XORIS(u32 ra, u32 rs, u32 uimm16) - { - DisAsm_R2_IMM("xoris", ra, rs, uimm16); - } - void ANDI_(u32 ra, u32 rs, u32 uimm16) - { - DisAsm_R2_IMM("andi.", ra, rs, uimm16); - } - void ANDIS_(u32 ra, u32 rs, u32 uimm16) - { - DisAsm_R2_IMM("andis.", ra, rs, uimm16); - } - void RLDICL(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) - { - if(sh == 0) - { - DisAsm_R2_INT1_RC("clrldi", ra, rs, mb, rc); - } - else if(mb == 0) - { - DisAsm_R2_INT1_RC("rotldi", ra, rs, sh, rc); - } - else if(mb == 64 - sh) - { - DisAsm_R2_INT1_RC("srdi", ra, rs, mb, rc); - } - else - { - DisAsm_R2_INT2_RC("rldicl", ra, rs, sh, mb, rc); - } - } - void RLDICR(u32 ra, u32 rs, u32 sh, u32 me, u32 rc) - { - DisAsm_R2_INT2_RC("rldicr", ra, rs, sh, me, rc); - } - void RLDIC(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) - { - DisAsm_R2_INT2_RC("rldic", ra, rs, sh, mb, rc); - } - void RLDIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) - { - DisAsm_R2_INT2_RC("rldimi", ra, rs, sh, mb, rc); - } - void RLDC_LR(u32 ra, u32 rs, u32 rb, u32 m_eb, u32 is_r, u32 rc) - { - if (is_r) - DisAsm_R3_INT2_RC("rldcr", ra, rs, rb, m_eb, 0, rc); - else - DisAsm_R3_INT2_RC("rldcl", ra, rs, rb, m_eb, 0, rc); - } - void CMP(u32 crfd, u32 l, u32 ra, u32 rb) - { - DisAsm_CR1_R2(fmt::format("cmp%s", (l ? "d" : "w")), crfd, ra, rb); - } - void TW(u32 to, u32 ra, u32 rb) - { - DisAsm_INT1_R2("tw", to, ra, rb); - } - void LVSL(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvsl", vd, ra, rb); - } - void LVEBX(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvebx", vd, ra, rb); - } - void SUBFC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("subfc", rd, ra, rb, oe, rc); - } - void ADDC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("addc", rd, ra, rb, oe, rc); - } - void MULHDU(u32 rd, u32 ra, u32 rb, u32 rc) - { - DisAsm_R3_RC("mulhdu", rd, ra, rb, rc); - } - void MULHWU(u32 rd, u32 ra, u32 rb, u32 rc) - { - DisAsm_R3_RC("mulhwu", rd, ra, rb, rc); - } - void MFOCRF(u32 a, u32 rd, u32 crm) - { - if(a) - { - DisAsm_R1_IMM("mfocrf", rd, crm); - } - else - { - DisAsm_R1("mfcr", rd); - } - } - void LWARX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lwarx", rd, ra, rb); - } - void LDX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("ldx", rd, ra, rb); - } - void LWZX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lwzx", rd, ra, rb); - } - void SLW(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("slw", ra, rs, rb, rc); - } - void CNTLZW(u32 ra, u32 rs, u32 rc) - { - DisAsm_R2_RC("cntlzw", ra, rs, rc); - } - void SLD(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("sld", ra, rs, rb, rc); - } - void AND(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("and", ra, rs, rb, rc); - } - void CMPL(u32 crfd, u32 l, u32 ra, u32 rb) - { - DisAsm_CR1_R2(fmt::format("cmpl%s", (l ? "d" : "w")), crfd, ra, rb); - } - void LVSR(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvsr", vd, ra, rb); - } - void LVEHX(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvehx", vd, ra, rb); - } - void SUBF(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("subf", rd, ra, rb, oe, rc); - } - void LDUX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("ldux", rd, ra, rb); - } - void DCBST(u32 ra, u32 rb) - { - DisAsm_R2("dcbst", ra, rb); - } - void LWZUX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lwzux", rd, ra, rb); - } - void CNTLZD(u32 ra, u32 rs, u32 rc) - { - DisAsm_R2_RC("cntlzd", ra, rs, rc); - } - void ANDC(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("andc", ra, rs, rb, rc); - } - void TD(u32 to, u32 ra, u32 rb) - { - DisAsm_INT1_R2("td", to, ra, rb); - } - void LVEWX(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvewx", vd, ra, rb); - } - void MULHD(u32 rd, u32 ra, u32 rb, u32 rc) - { - DisAsm_R3_RC("mulhd", rd, ra, rb, rc); - } - void MULHW(u32 rd, u32 ra, u32 rb, u32 rc) - { - DisAsm_R3_RC("mulhw", rd, ra, rb, rc); - } - void LDARX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("ldarx", rd, ra, rb); - } - void DCBF(u32 ra, u32 rb) - { - DisAsm_R2("dcbf", ra, rb); - } - void LBZX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lbzx", rd, ra, rb); - } - void LVX(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvx", vd, ra, rb); - } - void NEG(u32 rd, u32 ra, u32 oe, u32 rc) - { - DisAsm_R2_OE_RC("neg", rd, ra, oe, rc); - } - void LBZUX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lbzux", rd, ra, rb); - } - void NOR(u32 ra, u32 rs, u32 rb, u32 rc) - { - if(rs == rb) - { - DisAsm_R2_RC("not", ra, rs, rc); - } - else - { - DisAsm_R3_RC("nor", ra, rs, rb, rc); - } - } - void STVEBX(u32 vs, u32 ra, u32 rb) - { - DisAsm_V1_R2("stvebx", vs, ra, rb); - } - void SUBFE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("subfe", rd, ra, rb, oe, rc); - } - void ADDE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("adde", rd, ra, rb, oe, rc); - } - void MTOCRF(u32 l, u32 crm, u32 rs) - { - if(l) - { - DisAsm_INT1_R1("mtocrf", crm, rs); - } - else - { - DisAsm_INT1_R1("mtcrf", crm, rs); - } - } - void STDX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stdx.", rs, ra, rb); - } - void STWCX_(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stwcx.", rs, ra, rb); - } - void STWX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stwx", rs, ra, rb); - } - void STVEHX(u32 vs, u32 ra, u32 rb) - { - DisAsm_V1_R2("stvehx", vs, ra, rb); - } - void STDUX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stdux", rs, ra, rb); - } - void STWUX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stwux", rs, ra, rb); - } - void STVEWX(u32 vs, u32 ra, u32 rb) - { - DisAsm_V1_R2("stvewx", vs, ra, rb); - } - void SUBFZE(u32 rd, u32 ra, u32 oe, u32 rc) - { - DisAsm_R2_OE_RC("subfze", rd, ra, oe, rc); - } - void ADDZE(u32 rd, u32 ra, u32 oe, u32 rc) - { - DisAsm_R2_OE_RC("addze", rd, ra, oe, rc); - } - void STDCX_(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stdcx.", rs, ra, rb); - } - void STBX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stbx", rs, ra, rb); - } - void STVX(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("stvx", vd, ra, rb); - } - void SUBFME(u32 rd, u32 ra, u32 oe, u32 rc) - { - DisAsm_R2_OE_RC("subfme", rd, ra, oe, rc); - } - void MULLD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("mulld", rd, ra, rb, oe, rc); - } - void ADDME(u32 rd, u32 ra, u32 oe, u32 rc) - { - DisAsm_R2_OE_RC("addme", rd, ra, oe, rc); - } - void MULLW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("mullw", rd, ra, rb, oe, rc); - } - void DCBTST(u32 ra, u32 rb, u32 th) - { - DisAsm_R3("dcbtst", ra, rb, th); - } - void STBUX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stbux", rs, ra, rb); - } - void ADD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("add", rd, ra, rb, oe, rc); - } - void DCBT(u32 ra, u32 rb, u32 th) - { - DisAsm_R2("dcbt", ra, rb); - } - void LHZX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lhzx", rd, ra, rb); - } - void EQV(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("eqv", ra, rs, rb, rc); - } - void ECIWX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("eciwx", rd, ra, rb); - } - void LHZUX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lhzux", rd, ra, rb); - } - void XOR(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("xor", ra, rs, rb, rc); - } - void MFSPR(u32 rd, u32 spr) - { - const u32 n = (spr >> 5) | ((spr & 0x1f) << 5); - switch(n) - { - case 0x001: DisAsm_R1("mfxer", rd); break; - case 0x008: DisAsm_R1("mflr", rd); break; - case 0x009: DisAsm_R1("mfctr", rd); break; - default: DisAsm_R1_IMM("mfspr", rd, spr); break; - } - } - void LWAX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lwax", rd, ra, rb); - } - void DST(u32 ra, u32 rb, u32 strm, u32 t) - { - if(t) - { - DisAsm_R2_INT1("dstt", ra, rb, strm); - } - else - { - DisAsm_R2_INT1("dst", ra, rb, strm); - } - } - void LHAX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lhax", rd, ra, rb); - } - void LVXL(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvxl", vd, ra, rb); - } - void MFTB(u32 rd, u32 spr) - { - const u32 n = (spr >> 5) | ((spr & 0x1f) << 5); - switch(n) - { - case 268: DisAsm_R1("mftb", rd); break; - case 269: DisAsm_R1("mftbu", rd); break; - default: DisAsm_R1_IMM("mftb", rd, spr); break; - } - } - void LWAUX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lwaux", rd, ra, rb); - } - void DSTST(u32 ra, u32 rb, u32 strm, u32 t) - { - if(t) - { - DisAsm_R2_INT1("dststt", ra, rb, strm); - } - else - { - DisAsm_R2_INT1("dstst", ra, rb, strm); - } - } - void LHAUX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lhaux", rd, ra, rb); - } - void STHX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("sthx", rs, ra, rb); - } - void ORC(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("orc", ra, rs, rb, rc); - } - void ECOWX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("ecowx", rs, ra, rb); - } - void STHUX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("sthux", rs, ra, rb); - } - void OR(u32 ra, u32 rs, u32 rb, u32 rc) - { - if(rs==rb) - { - DisAsm_R2_RC("mr", ra, rb, rc); - } - else - { - DisAsm_R3_RC("or", ra, rs, rb, rc); - } - } - void DIVDU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("divdu", rd, ra, rb, oe, rc); - } - void DIVWU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("divwu", rd, ra, rb, oe, rc); - } - void MTSPR(u32 spr, u32 rs) - { - const u32 n = (spr & 0x1f) + ((spr >> 5) & 0x1f); - - switch(n) - { - case 0x001: DisAsm_R1("mtxer", rs); break; - case 0x008: DisAsm_R1("mtlr", rs); break; - case 0x009: DisAsm_R1("mtctr", rs); break; - default: DisAsm_IMM_R1("mtspr", spr, rs); break; - } - } - void DCBI(u32 ra, u32 rb) - { - DisAsm_R2("dcbi", ra, rb); - } - void NAND(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("nand", ra, rs, rb, rc); - } - void STVXL(u32 vs, u32 ra, u32 rb) - { - DisAsm_V1_R2("stvxl", vs, ra, rb); - } - void DIVD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("divd", rd, ra, rb, oe, rc); - } - void DIVW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("divw", rd, ra, rb, oe, rc); - } - void LVLX(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvlx", vd, ra, rb); - } - void LDBRX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("ldbrx", rd, ra, rb); - } - void LSWX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lswx", rd, ra, rb); - } - void LWBRX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lwbrx", rd, ra, rb); - } - void LFSX(u32 frd, u32 ra, u32 rb) - { - DisAsm_F1_R2("lfsx", frd, ra, rb); - } - void SRW(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("srw", ra, rs, rb, rc); - } - void SRD(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("srd", ra, rs, rb, rc); - } - void LVRX(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvrx", vd, ra, rb); - } - void LSWI(u32 rd, u32 ra, u32 nb) - { - DisAsm_R2_INT1("lswi", rd, ra, nb); - } - void LFSUX(u32 frd, u32 ra, u32 rb) - { - DisAsm_F1_R2("lfsux", frd, ra, rb); - } - void SYNC(u32 l) - { - DisAsm_INT1("sync", l); - } - void LFDX(u32 frd, u32 ra, u32 rb) - { - DisAsm_F1_R2("lfdx", frd, ra, rb); - } - void LFDUX(u32 frd, u32 ra, u32 rb) - { - DisAsm_F1_R2("lfdux", frd, ra, rb); - } - void STVLX(u32 vs, u32 ra, u32 rb) - { - DisAsm_V1_R2("stvlx", vs, ra, rb); - } - void STDBRX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stdbrx", rs, ra, rb); - } - void STSWX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("swswx", rs, ra, rb); - } - void STWBRX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stwbrx", rs, ra, rb); - } - void STFSX(u32 frs, u32 ra, u32 rb) - { - DisAsm_F1_R2("stfsx", frs, ra, rb); - } - void STVRX(u32 sd, u32 ra, u32 rb) - { - DisAsm_V1_R2("stvrx", sd, ra, rb); - } - void STFSUX(u32 frs, u32 ra, u32 rb) - { - DisAsm_F1_R2("stfsux", frs, ra, rb); - } - void STSWI(u32 rd, u32 ra, u32 nb) - { - DisAsm_R2_INT1("stswi", rd, ra, nb); - } - void STFDX(u32 frs, u32 ra, u32 rb) - { - DisAsm_F1_R2("stfdx", frs, ra, rb); - } - void STFDUX(u32 frs, u32 ra, u32 rb) - { - DisAsm_F1_R2("stfdux", frs, ra, rb); - } - void LVLXL(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvlxl", vd, ra, rb); - } - void LHBRX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lhbrx", rd, ra, rb); - } - void SRAW(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("sraw", ra, rs, rb, rc); - } - void SRAD(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("srad", ra, rs, rb, rc); - } - void LVRXL(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvrxl", vd, ra, rb); - } - void DSS(u32 strm, u32 a) - { - if(a) - { - Write("dssall"); - } - else - { - DisAsm_INT1("dss", strm); - } - } - void SRAWI(u32 ra, u32 rs, u32 sh, u32 rc) - { - DisAsm_R2_INT1_RC("srawi", ra, rs, sh, rc); - } - void SRADI1(u32 ra, u32 rs, u32 sh, u32 rc) - { - DisAsm_R2_INT1_RC("sradi", ra, rs, sh, rc); - } - void SRADI2(u32 ra, u32 rs, u32 sh, u32 rc) - { - DisAsm_R2_INT1_RC("sradi", ra, rs, sh, rc); - } - void EIEIO() - { - Write("eieio"); - } - void STVLXL(u32 vs, u32 ra, u32 rb) - { - DisAsm_V1_R2("stvlxl", vs, ra, rb); - } - void STHBRX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("sthbrx", rs, ra, rb); - } - void EXTSH(u32 ra, u32 rs, u32 rc) - { - DisAsm_R2_RC("extsh", ra, rs, rc); - } - void STVRXL(u32 sd, u32 ra, u32 rb) - { - DisAsm_V1_R2("stvrxl", sd, ra, rb); - } - void EXTSB(u32 ra, u32 rs, u32 rc) - { - DisAsm_R2_RC("extsb", ra, rs, rc); - } - void STFIWX(u32 frs, u32 ra, u32 rb) - { - DisAsm_F1_R2("stfiwx", frs, ra, rb); - } - void EXTSW(u32 ra, u32 rs, u32 rc) - { - DisAsm_R2_RC("extsw", ra, rs, rc); - } - void ICBI(u32 ra, u32 rb) - { - DisAsm_R2("icbi", ra, rb); - } - void DCBZ(u32 ra, u32 rb) - { - DisAsm_R2("dcbz", ra, rb); - } - void LWZ(u32 rd, u32 ra, s32 d) - { - DisAsm_R2_IMM("lwz", rd, ra, d); - } - void LWZU(u32 rd, u32 ra, s32 d) - { - DisAsm_R2_IMM("lwzu", rd, ra, d); - } - void LBZ(u32 rd, u32 ra, s32 d) - { - DisAsm_R2_IMM("lbz", rd, ra, d); - } - void LBZU(u32 rd, u32 ra, s32 d) - { - DisAsm_R2_IMM("lbzu", rd, ra, d); - } - void STW(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("stw", rs, ra, d); - } - void STWU(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("stwu", rs, ra, d); - } - void STB(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("stb", rs, ra, d); - } - void STBU(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("stbu", rs, ra, d); - } - void LHZ(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("lhz", rs, ra, d); - } - void LHZU(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("lhzu", rs, ra, d); - } - void LHA(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("lha", rs, ra, d); - } - void LHAU(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("lhau", rs, ra, d); - } - void STH(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("sth", rs, ra, d); - } - void STHU(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("sthu", rs, ra, d); - } - void LMW(u32 rd, u32 ra, s32 d) - { - DisAsm_R2_IMM("lmw", rd, ra, d); - } - void STMW(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("stmw", rs, ra, d); - } - void LFS(u32 frd, u32 ra, s32 d) - { - DisAsm_F1_IMM_R1("lfs", frd, d, ra); - } - void LFSU(u32 frd, u32 ra, s32 ds) - { - DisAsm_F1_IMM_R1("lfsu", frd, ds, ra); - } - void LFD(u32 frd, u32 ra, s32 d) - { - DisAsm_F1_IMM_R1("lfd", frd, d, ra); - } - void LFDU(u32 frd, u32 ra, s32 ds) - { - DisAsm_F1_IMM_R1("lfdu", frd, ds, ra); - } - void STFS(u32 frs, u32 ra, s32 d) - { - DisAsm_F1_IMM_R1("stfs", frs, d, ra); - } - void STFSU(u32 frs, u32 ra, s32 d) - { - DisAsm_F1_IMM_R1("stfsu", frs, d, ra); - } - void STFD(u32 frs, u32 ra, s32 d) - { - DisAsm_F1_IMM_R1("stfd", frs, d, ra); - } - void STFDU(u32 frs, u32 ra, s32 d) - { - DisAsm_F1_IMM_R1("stfdu", frs, d, ra); - } - void LD(u32 rd, u32 ra, s32 ds) - { - DisAsm_R2_IMM("ld", rd, ra, ds); - } - void LDU(u32 rd, u32 ra, s32 ds) - { - DisAsm_R2_IMM("ldu", rd, ra, ds); - } - void LWA(u32 rd, u32 ra, s32 ds) - { - DisAsm_R2_IMM("lwa", rd, ra, ds); - } - void FDIVS(u32 frd, u32 fra, u32 frb, u32 rc) - { - DisAsm_F3_RC("fdivs", frd, fra, frb, rc); - } - void FSUBS(u32 frd, u32 fra, u32 frb, u32 rc) - { - DisAsm_F3_RC("fsubs", frd, fra, frb, rc); - } - void FADDS(u32 frd, u32 fra, u32 frb, u32 rc) - { - DisAsm_F3_RC("fadds", frd, fra, frb, rc); - } - void FSQRTS(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fsqrts", frd, frb, rc); - } - void FRES(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fres", frd, frb, rc); - } - void FMULS(u32 frd, u32 fra, u32 frc, u32 rc) - { - DisAsm_F3_RC("fmuls", frd, fra, frc, rc); - } - void FMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) - { - DisAsm_F4_RC("fmadds", frd, fra, frc, frb, rc); - } - void FMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) - { - DisAsm_F4_RC("fmsubs", frd, fra, frc, frb, rc); - } - void FNMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) - { - DisAsm_F4_RC("fnmsubs", frd, fra, frc, frb, rc); - } - void FNMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) - { - DisAsm_F4_RC("fnmadds", frd, fra, frc, frb, rc); - } - void STD(u32 rs, u32 ra, s32 ds) - { - DisAsm_R2_IMM("std", rs, ra, ds); - } - void STDU(u32 rs, u32 ra, s32 ds) - { - DisAsm_R2_IMM("stdu", rs, ra, ds); - } - void MTFSB1(u32 bt, u32 rc) - { - DisAsm_F1_RC("mtfsb1", bt, rc); - } - void MCRFS(u32 bf, u32 bfa) - { - DisAsm_F2("mcrfs", bf, bfa); - } - void MTFSB0(u32 bt, u32 rc) - { - DisAsm_F1_RC("mtfsb0", bt, rc); - } - void MTFSFI(u32 crfd, u32 i, u32 rc) - { - DisAsm_F2_RC("mtfsfi", crfd, i, rc); - } - void MFFS(u32 frd, u32 rc) - { - DisAsm_F1_RC("mffs", frd, rc); - } - void MTFSF(u32 flm, u32 frb, u32 rc) - { - DisAsm_F2_RC("mtfsf", flm, frb, rc); - } - void FCMPU(u32 crfd, u32 fra, u32 frb) - { - DisAsm_CR1_F2("fcmpu", crfd, fra, frb); - } - void FRSP(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("frsp", frd, frb, rc); - } - void FCTIW(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fctiw", frd, frb, rc); - } - void FCTIWZ(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fctiwz", frd, frb, rc); - } - void FDIV(u32 frd, u32 fra, u32 frb, u32 rc) - { - DisAsm_F3_RC("fdiv", frd, fra, frb, rc); - } - void FSUB(u32 frd, u32 fra, u32 frb, u32 rc) - { - DisAsm_F3_RC("fsub", frd, fra, frb, rc); - } - void FADD(u32 frd, u32 fra, u32 frb, u32 rc) - { - DisAsm_F3_RC("fadd", frd, fra, frb, rc); - } - void FSQRT(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fsqrt", frd, frb, rc); - } - void FSEL(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) - { - DisAsm_F4_RC("fsel", frd, fra, frc, frb, rc); - } - void FMUL(u32 frd, u32 fra, u32 frc, u32 rc) - { - DisAsm_F3_RC("fmul", frd, fra, frc, rc); - } - void FRSQRTE(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("frsqrte", frd, frb, rc); - } - void FMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) - { - DisAsm_F4_RC("fmsub", frd, fra, frc, frb, rc); - } - void FMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) - { - DisAsm_F4_RC("fmadd", frd, fra, frc, frb, rc); - } - void FNMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) - { - DisAsm_F4_RC("fnmsub", frd, fra, frc, frb, rc); - } - void FNMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) - { - DisAsm_F4_RC("fnmadd", frd, fra, frc, frb, rc); - } - void FCMPO(u32 crfd, u32 fra, u32 frb) - { - DisAsm_F3("fcmpo", crfd, fra, frb); - } - void FNEG(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fneg", frd, frb, rc); - } - void FMR(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fmr", frd, frb, rc); - } - void FNABS(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fnabs", frd, frb, rc); - } - void FABS(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fabs", frd, frb, rc); - } - void FCTID(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fctid", frd, frb, rc); - } - void FCTIDZ(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fctidz", frd, frb, rc); - } - void FCFID(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fcfid", frd, frb, rc); - } - - void UNK(const u32 code, const u32 opcode, const u32 gcode) - { - Write(fmt::format("Unknown/Illegal opcode! (0x%08x : 0x%x : 0x%x)", code, opcode, gcode)); - } + void UNK(ppu_opcode_t op); }; - -#undef START_OPCODES_GROUP -#undef END_OPCODES_GROUP diff --git a/rpcs3/Emu/Cell/PPUFunction.cpp b/rpcs3/Emu/Cell/PPUFunction.cpp new file mode 100644 index 0000000000..8ad14ff3db --- /dev/null +++ b/rpcs3/Emu/Cell/PPUFunction.cpp @@ -0,0 +1,2379 @@ +#include "stdafx.h" +#include "PPUModule.h" + +extern std::string ppu_get_syscall_name(u64 code) +{ + switch (code) + { + case 1: return "sys_process_getpid"; + case 2: return "sys_process_wait_for_child"; + case 3: return "sys_process_exit"; + case 4: return "sys_process_get_status"; + case 5: return "sys_process_detach_child"; + case 12: return "sys_process_get_number_of_object"; + case 13: return "sys_process_get_id"; + case 14: return "sys_process_is_spu_lock_line_reservation_address"; + case 18: return "sys_process_getppid"; + case 19: return "sys_process_kill"; + case 21: return "_sys_process_spawn"; + case 22: return "sys_process_exit"; + case 23: return "sys_process_wait_for_child2"; + case 25: return "sys_process_get_sdk_version"; + case 26: return "_sys_process_exit"; + case 28: return "_sys_process_get_number_of_object"; + case 29: return "sys_process_get_id"; + case 30: return "_sys_process_get_paramsfo"; + case 31: return "sys_process_get_ppu_guid"; + case 41: return "_sys_ppu_thread_exit"; + case 43: return "sys_ppu_thread_yield"; + case 44: return "sys_ppu_thread_join"; + case 45: return "sys_ppu_thread_detach"; + case 46: return "sys_ppu_thread_get_join_state"; + case 47: return "sys_ppu_thread_set_priority"; + case 48: return "sys_ppu_thread_get_priority"; + case 49: return "sys_ppu_thread_get_stack_information"; + case 50: return "sys_ppu_thread_stop"; + case 51: return "sys_ppu_thread_restart"; + case 52: return "_sys_ppu_thread_create"; + case 53: return "sys_ppu_thread_start"; + case 56: return "sys_ppu_thread_rename"; + case 57: return "sys_ppu_thread_recover_page_fault"; + case 58: return "sys_ppu_thread_get_page_fault_context"; + case 60: return "sys_trace_create"; + case 61: return "sys_trace_start"; + case 62: return "sys_trace_stop"; + case 63: return "sys_trace_update_top_index"; + case 64: return "sys_trace_destroy"; + case 65: return "sys_trace_drain"; + case 66: return "sys_trace_attach_process"; + case 67: return "sys_trace_allocate_buffer"; + case 68: return "sys_trace_free_buffer"; + case 69: return "sys_trace_create2"; + case 70: return "sys_timer_create"; + case 71: return "sys_timer_destroy"; + case 72: return "sys_timer_get_information"; + case 73: return "_sys_timer_start"; + case 74: return "sys_timer_stop"; + case 75: return "sys_timer_connect_event_queue"; + case 76: return "sys_timer_disconnect_event_queue"; + case 77: return "sys_trace_create2_in_cbepm"; + case 80: return "sys_interrupt_tag_create"; + case 81: return "sys_interrupt_tag_destroy"; + case 82: return "sys_event_flag_create"; + case 83: return "sys_event_flag_destroy"; + case 84: return "_sys_interrupt_thread_establish"; + case 85: return "sys_event_flag_wait"; + case 86: return "sys_event_flag_trywait"; + case 87: return "sys_event_flag_set"; + case 88: return "sys_interrupt_thread_eoi"; + case 89: return "_sys_interrupt_thread_disestablish"; + case 90: return "sys_semaphore_create"; + case 91: return "sys_semaphore_destroy"; + case 92: return "sys_semaphore_wait"; + case 93: return "sys_semaphore_trywait"; + case 94: return "sys_semaphore_post"; + case 95: return "_sys_lwmutex_create"; + case 96: return "_sys_lwmutex_destroy"; + case 97: return "_sys_lwmutex_lock"; + case 98: return "_sys_lwmutex_unlock"; + case 99: return "_sys_lwmutex_trylock"; + case 100: return "sys_mutex_create"; + case 101: return "sys_mutex_destroy"; + case 102: return "sys_mutex_lock"; + case 103: return "sys_mutex_trylock"; + case 104: return "sys_mutex_unlock"; + case 105: return "sys_cond_create"; + case 106: return "sys_cond_destroy"; + case 107: return "sys_cond_wait"; + case 108: return "sys_cond_signal"; + case 109: return "sys_cond_signal_all"; + case 110: return "sys_cond_signal_to"; + case 111: return "_sys_lwcond_create"; + case 112: return "_sys_lwcond_destroy"; + case 113: return "_sys_lwcond_queue_wait"; + case 114: return "sys_semaphore_get_value"; + case 115: return "_sys_lwcond_signal"; + case 116: return "_sys_lwcond_signal_all"; + case 118: return "sys_event_flag_clear"; + case 120: return "sys_rwlock_create"; + case 121: return "sys_rwlock_destroy"; + case 122: return "sys_rwlock_rlock"; + case 123: return "sys_rwlock_tryrlock"; + case 124: return "sys_rwlock_runlock"; + case 125: return "sys_rwlock_wlock"; + case 126: return "sys_rwlock_trywlock"; + case 127: return "sys_rwlock_wunlock"; + case 128: return "sys_event_queue_create"; + case 129: return "sys_event_queue_destroy"; + case 130: return "sys_event_queue_receive"; + case 131: return "sys_event_queue_tryreceive"; + case 132: return "sys_event_flag_cancel"; + case 133: return "sys_event_queue_drain"; + case 134: return "sys_event_port_create"; + case 135: return "sys_event_port_destroy"; + case 136: return "sys_event_port_connect_local"; + case 137: return "sys_event_port_disconnect"; + case 138: return "sys_event_port_send"; + case 139: return "sys_event_flag_get"; + case 140: return "sys_event_port_connect_ipc"; + case 141: return "sys_timer_usleep"; + case 142: return "sys_timer_sleep"; + case 143: return "sys_time_set_timezone"; + case 144: return "sys_time_get_timezone"; + case 145: return "sys_time_get_current_time"; + case 146: return "sys_time_get_system_time"; + case 147: return "sys_time_get_timebase_frequency"; + case 148: return "_sys_rwlock_trywlock"; + case 150: return "sys_raw_spu_create_interrupt_tag"; + case 151: return "sys_raw_spu_set_int_mask"; + case 152: return "sys_raw_spu_get_int_mask"; + case 153: return "sys_raw_spu_set_int_stat"; + case 154: return "sys_raw_spu_get_int_stat"; + case 155: return "sys_spu_image_get_information?"; + case 156: return "sys_spu_image_open"; + case 157: return "sys_spu_image_import"; + case 158: return "sys_spu_image_close"; + case 159: return "sys_raw_spu_load"; + case 160: return "sys_raw_spu_create"; + case 161: return "sys_raw_spu_destroy"; + case 163: return "sys_raw_spu_read_puint_mb"; + case 165: return "sys_spu_thread_get_exit_status"; + case 166: return "sys_spu_thread_set_argument"; + case 167: return "sys_spu_thread_group_start_on_exit"; + case 169: return "sys_spu_initialize"; + case 170: return "sys_spu_thread_group_create"; + case 171: return "sys_spu_thread_group_destroy"; + case 172: return "sys_spu_thread_initialize"; + case 173: return "sys_spu_thread_group_start"; + case 174: return "sys_spu_thread_group_suspend"; + case 175: return "sys_spu_thread_group_resume"; + case 176: return "sys_spu_thread_group_yield"; + case 177: return "sys_spu_thread_group_terminate"; + case 178: return "sys_spu_thread_group_join"; + case 179: return "sys_spu_thread_group_set_priority"; + case 180: return "sys_spu_thread_group_get_priority"; + case 181: return "sys_spu_thread_write_ls"; + case 182: return "sys_spu_thread_read_ls"; + case 184: return "sys_spu_thread_write_snr"; + case 185: return "sys_spu_thread_group_connect_event"; + case 186: return "sys_spu_thread_group_disconnect_event"; + case 187: return "sys_spu_thread_set_spu_cfg"; + case 188: return "sys_spu_thread_get_spu_cfg"; + case 190: return "sys_spu_thread_write_spu_mb"; + case 191: return "sys_spu_thread_connect_event"; + case 192: return "sys_spu_thread_disconnect_event"; + case 193: return "sys_spu_thread_bind_queue"; + case 194: return "sys_spu_thread_unbind_queue"; + case 196: return "sys_raw_spu_set_spu_cfg"; + case 197: return "sys_raw_spu_get_spu_cfg"; + case 198: return "sys_spu_thread_recover_page_fault"; + case 199: return "sys_raw_spu_recover_page_fault"; + case 215: return "sys_dbg_mat_set_condition"; + case 216: return "sys_dbg_mat_get_condition"; + case 230: return "sys_isolated_spu_create"; + case 231: return "sys_isolated_spu_destroy"; + case 232: return "sys_isolated_spu_start"; + case 233: return "sys_isolated_spu_create_interrupt_tag"; + case 234: return "sys_isolated_spu_set_int_mask"; + case 235: return "sys_isolated_spu_get_int_mask"; + case 236: return "sys_isolated_spu_set_int_stat"; + case 237: return "sys_isolated_spu_get_int_stat"; + case 238: return "sys_isolated_spu_set_spu_cfg"; + case 239: return "sys_isolated_spu_get_spu_cfg"; + case 240: return "sys_isolated_spu_read_puint_mb"; + case 244: return "sys_spu_thread_group_system_set_next_group"; + case 245: return "sys_spu_thread_group_system_unset_next_group"; + case 246: return "sys_spu_thread_group_system_set_switch_group"; + case 247: return "sys_spu_thread_group_system_unset_switch_group"; + case 250: return "sys_spu_thread_group_set_cooperative_victims"; + case 251: return "sys_spu_thread_group_connect_event_all_threads"; + case 252: return "sys_spu_thread_group_disconnect_event_all_threads"; + case 254: return "sys_spu_thread_group_log"; + case 260: return "sys_spu_image_open_by_fd"; + case 300: return "sys_vm_memory_map"; + case 301: return "sys_vm_unmap"; + case 302: return "sys_vm_append_memory"; + case 303: return "sys_vm_return_memory"; + case 304: return "sys_vm_lock"; + case 305: return "sys_vm_unlock"; + case 306: return "sys_vm_touch"; + case 307: return "sys_vm_flush"; + case 308: return "sys_vm_invalidate"; + case 309: return "sys_vm_store"; + case 310: return "sys_vm_sync"; + case 311: return "sys_vm_test"; + case 312: return "sys_vm_get_statistics"; + case 324: return "sys_memory_container_create"; + case 325: return "sys_memory_container_destroy"; + case 326: return "sys_mmapper_allocate_fixed_address"; + case 327: return "sys_mmapper_enable_page_fault_notification"; + case 329: return "sys_mmapper_free_shared_memory"; + case 330: return "sys_mmapper_allocate_address"; + case 331: return "sys_mmapper_free_address"; + case 332: return "sys_mmapper_allocate_shared_memory"; + case 333: return "sys_mmapper_set_shared_memory_flag"; + case 334: return "sys_mmapper_map_shared_memory"; + case 335: return "sys_mmapper_unmap_shared_memory"; + case 336: return "sys_mmapper_change_address_access_right"; + case 337: return "sys_mmapper_search_and_map"; + case 338: return "sys_mmapper_get_shared_memory_attribute"; + case 341: return "sys_memory_container_create"; + case 342: return "sys_memory_container_destroy"; + case 343: return "sys_memory_container_get_size"; + case 344: return "sys_memory_budget_set"; + case 348: return "sys_memory_allocate"; + case 349: return "sys_memory_free"; + case 350: return "sys_memory_allocate_from_container"; + case 351: return "sys_memory_get_page_attribute"; + case 352: return "sys_memory_get_user_memory_size"; + case 353: return "sys_memory_get_user_memory_stat"; + case 356: return "sys_memory_allocate_colored"; + case 361: return "sys_memory_allocate_from_container_colored"; + case 362: return "sys_mmapper_allocate_memory_from_container"; + case 367: return "sys_uart_initialize"; + case 368: return "sys_uart_receive"; + case 369: return "sys_uart_send"; + case 370: return "sys_uart_get_params"; + case 372: return "sys_game_watchdog_start"; + case 373: return "sys_game_watchdog_stop"; + case 374: return "sys_game_watchdog_clear"; + case 375: return "sys_game_set_system_sw_version"; + case 376: return "sys_game_get_system_sw_version"; + case 377: return "sys_sm_set_shop_mode"; + case 378: return "sys_sm_get_ext_event2"; + case 379: return "sys_sm_shutdown"; + case 380: return "sys_sm_get_params"; + case 381: return "sys_sm_get_inter_lpar_parameter"; + case 383: return "sys_game_get_temperature"; + case 384: return "sys_sm_get_tzpb"; + case 385: return "sys_sm_request_led"; + case 386: return "sys_sm_control_led"; + case 387: return "sys_sm_get_platform_info"; + case 388: return "sys_sm_ring_buzzer"; + case 389: return "sys_sm_set_fan_policy"; + case 390: return "sys_sm_request_error_log"; + case 391: return "sys_sm_request_be_count"; + case 392: return "sys_sm_ring_buzzer"; + case 393: return "sys_sm_get_hw_config"; + case 394: return "sys_sm_request_scversion"; + case 395: return "sys_sm_request_system_event_log"; + case 396: return "sys_sm_set_rtc_alarm"; + case 397: return "sys_sm_get_rtc_alarm"; + case 398: return "sys_console_write"; + case 402: return "sys_tty_read"; + case 403: return "sys_tty_write"; + case 408: return "sys_sm_get_tzpb"; + case 409: return "sys_sm_get_fan_policy"; + case 410: return "sys_game_board_storage_read"; + case 411: return "sys_game_board_storage_write"; + case 412: return "sys_game_get_rtc_status"; + case 450: return "sys_overlay_load_module"; + case 451: return "sys_overlay_unload_module"; + case 452: return "sys_overlay_get_module_list"; + case 453: return "sys_overlay_get_module_info"; + case 454: return "sys_overlay_load_module_by_fd"; + case 455: return "sys_overlay_get_module_info2"; + case 456: return "sys_overlay_get_sdk_version"; + case 457: return "sys_overlay_get_module_dbg_info"; + case 458: return "sys_overlay_get_module_dbg_info"; + case 460: return "sys_prx_dbg_get_module_id_list"; + case 461: return "sys_prx_get_module_id_by_address"; + case 463: return "sys_prx_load_module_by_fd"; + case 464: return "sys_prx_load_module_on_memcontainer_by_fd"; + case 465: return "sys_prx_load_module_list"; + case 466: return "sys_prx_load_module_list_on_memcontainer"; + case 467: return "sys_prx_get_ppu_guid"; + case 480: return "sys_prx_load_module"; + case 481: return "sys_prx_start_module"; + case 482: return "sys_prx_stop_module"; + case 483: return "sys_prx_unload_module"; + case 484: return "sys_prx_register_module"; + case 485: return "sys_prx_query_module"; + case 486: return "sys_prx_register_library"; + case 487: return "sys_prx_unregister_library"; + case 488: return "sys_prx_link_library"; + case 489: return "sys_prx_unlink_library"; + case 490: return "sys_prx_query_library"; + case 493: return "sys_prx_dbg_get_module_info"; + case 494: return "sys_prx_get_module_list"; + case 495: return "sys_prx_get_module_info"; + case 496: return "sys_prx_get_module_id_by_name"; + case 497: return "sys_prx_load_module_on_memcontainer"; + case 498: return "sys_prx_start"; + case 499: return "sys_prx_stop"; + case 500: return "sys_hid_manager_open"; + case 501: return "sys_hid_manager_close"; + case 502: return "sys_hid_manager_read"; + case 503: return "sys_hid_manager_ioctl"; + case 504: return "sys_hid_manager_map_logical_id_to_port_id"; + case 505: return "sys_hid_manager_unmap_logical_id_to_port_id"; + case 506: return "sys_hid_manager_add_hot_key_observer"; + case 507: return "sys_hid_manager_remove_hot_key_observer"; + case 508: return "sys_hid_manager_grab_focus"; + case 509: return "sys_hid_manager_release_focus"; + case 516: return "sys_config_open"; + case 517: return "sys_config_close"; + case 518: return "sys_config_get_service_event"; + case 519: return "sys_config_add_service_listener"; + case 520: return "sys_config_remove_service_listener"; + case 521: return "sys_config_register_service"; + case 522: return "sys_config_unregister_service"; + case 523: return "sys_config_io_event"; + case 530: return "sys_usbd_initialize"; + case 531: return "sys_usbd_finalize"; + case 532: return "sys_usbd_get_device_list"; + case 533: return "sys_usbd_get_descriptor_size"; + case 534: return "sys_usbd_get_descriptor"; + case 535: return "sys_usbd_register_ldd"; + case 536: return "sys_usbd_unregister_ldd"; + case 537: return "sys_usbd_open_pipe"; + case 538: return "sys_usbd_open_default_pipe"; + case 539: return "sys_usbd_close_pipe"; + case 540: return "sys_usbd_receive_event"; + case 541: return "sys_usbd_detect_event"; + case 542: return "sys_usbd_attach"; + case 543: return "sys_usbd_transfer_data"; + case 544: return "sys_usbd_isochronous_transfer_data"; + case 545: return "sys_usbd_get_transfer_status"; + case 546: return "sys_usbd_get_isochronous_transfer_status"; + case 547: return "sys_usbd_get_device_location"; + case 548: return "sys_usbd_send_event"; + case 550: return "sys_usbd_allocate_memory"; + case 551: return "sys_usbd_free_memory"; + case 556: return "sys_usbd_get_device_speed"; + case 559: return "sys_usbd_register_extra_ldd"; + case 571: return "sys_pad_ldd_unregister_controller"; + case 572: return "sys_pad_ldd_data_insert"; + case 573: return "sys_pad_dbg_ldd_set_data_insert_mode"; + case 574: return "sys_pad_ldd_register_controller"; + case 575: return "sys_pad_ldd_get_port_no"; + case 577: return "sys_pad_manager_..."; + case 600: return "sys_storage_open"; + case 601: return "sys_storage_close"; + case 602: return "sys_storage_read"; + case 603: return "sys_storage_write"; + case 604: return "sys_storage_send_device_command"; + case 605: return "sys_storage_async_configure"; + case 606: return "sys_storage_async_read"; + case 607: return "sys_storage_async_write"; + case 608: return "sys_storage_async_cancel"; + case 609: return "sys_storage_get_device_info"; + case 610: return "sys_storage_get_device_config"; + case 611: return "sys_storage_report_devices"; + case 612: return "sys_storage_configure_medium_event"; + case 613: return "sys_storage_set_medium_polling_interval"; + case 614: return "sys_storage_create_region"; + case 615: return "sys_storage_delete_region"; + case 616: return "sys_storage_execute_device_command"; + case 617: return "sys_storage_check_region_acl"; + case 618: return "sys_storage_set_region_acl"; + case 619: return "sys_storage_async_send_device_command"; + case 621: return "sys_gamepad_ycon_if"; + case 622: return "sys_storage_get_region_offset"; + case 623: return "sys_storage_set_emulated_speed"; + case 624: return "sys_io_buffer_create"; + case 625: return "sys_io_buffer_destroy"; + case 626: return "sys_io_buffer_allocate"; + case 627: return "sys_io_buffer_free"; + case 630: return "sys_gpio_set"; + case 631: return "sys_gpio_get"; + case 633: return "sys_fsw_connect_event"; + case 634: return "sys_fsw_disconnect_event"; + case 635: return "sys_btsetting_if"; + case 650: return "sys_rsxaudio_initialize"; + case 651: return "sys_rsxaudio_finalize"; + case 652: return "sys_rsxaudio_import_shared_memory"; + case 653: return "sys_rsxaudio_unimport_shared_memory"; + case 654: return "sys_rsxaudio_create_connection"; + case 655: return "sys_rsxaudio_close_connection"; + case 656: return "sys_rsxaudio_prepare_process"; + case 657: return "sys_rsxaudio_start_process"; + case 666: return "sys_rsx_device_open"; + case 667: return "sys_rsx_device_close"; + case 668: return "sys_rsx_memory_allocate"; + case 669: return "sys_rsx_memory_free"; + case 670: return "sys_rsx_context_allocate"; + case 671: return "sys_rsx_context_free"; + case 672: return "sys_rsx_context_iomap"; + case 673: return "sys_rsx_context_iounmap"; + case 674: return "sys_rsx_context_attribute"; + case 675: return "sys_rsx_device_map"; + case 676: return "sys_rsx_device_unmap"; + case 677: return "sys_rsx_attribute"; + case 699: return "sys_bdemu_send_command"; + case 700: return "sys_net_bnet_accept"; + case 701: return "sys_net_bnet_bind"; + case 702: return "sys_net_bnet_connect"; + case 703: return "sys_net_bnet_getpeername"; + case 704: return "sys_net_bnet_getsockname"; + case 705: return "sys_net_bnet_getsockopt"; + case 706: return "sys_net_bnet_listen"; + case 707: return "sys_net_bnet_recvfrom"; + case 708: return "sys_net_bnet_recvmsg"; + case 709: return "sys_net_bnet_sendmsg"; + case 710: return "sys_net_bnet_sendto"; + case 711: return "sys_net_bnet_setsockop"; + case 712: return "sys_net_bnet_shutdown"; + case 713: return "sys_net_bnet_socket"; + case 714: return "sys_net_bnet_close"; + case 715: return "sys_net_bnet_poll"; + case 716: return "sys_net_bnet_select"; + case 717: return "sys_net_open_dump"; + case 718: return "sys_net_read_dump"; + case 719: return "sys_net_close_dump"; + case 720: return "sys_net_write_dump"; + case 721: return "sys_net_abort"; + case 722: return "sys_net_infoctl"; + case 723: return "sys_net_control"; + case 724: return "sys_net_bnet_ioctl"; + case 725: return "sys_net_bnet_sysctl"; + case 726: return "sys_net_eurus_post_command"; + case 800: return "sys_fs_test"; + case 801: return "sys_fs_open"; + case 802: return "sys_fs_read"; + case 803: return "sys_fs_write"; + case 804: return "sys_fs_close"; + case 805: return "sys_fs_opendir"; + case 806: return "sys_fs_readdir"; + case 807: return "sys_fs_closedir"; + case 808: return "sys_fs_stat"; + case 809: return "sys_fs_fstat"; + case 810: return "sys_fs_link"; + case 811: return "sys_fs_mkdir"; + case 812: return "sys_fs_rename"; + case 813: return "sys_fs_rmdir"; + case 814: return "sys_fs_unlink"; + case 815: return "sys_fs_utime"; + case 816: return "sys_fs_access"; + case 817: return "sys_fs_fcntl"; + case 818: return "sys_fs_lseek"; + case 819: return "sys_fs_fdatasync"; + case 820: return "sys_fs_fsync"; + case 821: return "sys_fs_fget_block_size"; + case 822: return "sys_fs_get_block_size"; + case 823: return "sys_fs_acl_read"; + case 824: return "sys_fs_acl_write"; + case 825: return "sys_fs_lsn_get_cda_size"; + case 826: return "sys_fs_lsn_get_cda"; + case 827: return "sys_fs_lsn_lock"; + case 828: return "sys_fs_lsn_unlock"; + case 829: return "sys_fs_lsn_read"; + case 830: return "sys_fs_lsn_write"; + case 831: return "sys_fs_truncate"; + case 832: return "sys_fs_ftruncate"; + case 833: return "sys_fs_symbolic_link"; + case 834: return "sys_fs_chmod"; + case 835: return "sys_fs_chown"; + case 836: return "sys_fs_newfs"; + case 837: return "sys_fs_mount"; + case 838: return "sys_fs_unmount"; + case 839: return "sys_fs_sync"; + case 840: return "sys_fs_disk_free"; + case 841: return "sys_fs_get_mount_info_size"; + case 842: return "sys_fs_get_mount_info"; + case 843: return "sys_fs_get_fs_info_size"; + case 844: return "sys_fs_get_fs_info"; + case 845: return "sys_fs_mapped_allocate"; + case 846: return "sys_fs_mapped_free"; + case 847: return "sys_fs_truncate2"; + case 860: return "sys_ss_get_cache_of_analog_sunset_flag"; + case 865: return "sys_ss_random_number_generator"; + case 870: return "sys_ss_get_console_id"; + case 871: return "sys_ss_access_control_engine"; + case 872: return "sys_ss_get_open_psid"; + case 873: return "sys_ss_get_cache_of_product_mode"; + case 874: return "sys_ss_get_cache_of_flash_ext_flag"; + case 875: return "sys_ss_get_boot_device"; + case 876: return "sys_ss_disc_access_control"; + case 877: return "sys_ss_~utoken_if"; + case 878: return "sys_ss_ad_sign"; + case 879: return "sys_ss_media_id"; + case 880: return "sys_deci3_open"; + case 881: return "sys_deci3_create_event_path"; + case 882: return "sys_deci3_close"; + case 883: return "sys_deci3_send"; + case 884: return "sys_deci3_receive"; + case 885: return "sys_deci3_open2"; + case 890: return "sys_deci3_initialize"; + case 891: return "sys_deci3_terminate"; + case 892: return "sys_deci3_debug_mode"; + case 893: return "sys_deci3_show_status"; + case 894: return "sys_deci3_echo_test"; + case 895: return "sys_deci3_send_dcmp_packet"; + case 896: return "sys_deci3_dump_cp_register"; + case 897: return "sys_deci3_dump_cp_buffer"; + case 899: return "sys_deci3_test"; + case 900: return "sys_dbg_stop_processes"; + case 901: return "sys_dbg_continue_processes"; + case 902: return "sys_dbg_stop_threads"; + case 903: return "sys_dbg_continue_threads"; + case 904: return "sys_dbg_read_process_memory"; + case 905: return "sys_dbg_write_process_memory"; + case 906: return "sys_dbg_read_thread_register"; + case 907: return "sys_dbg_write_thread_register"; + case 908: return "sys_dbg_get_process_list"; + case 909: return "sys_dbg_get_thread_list"; + case 910: return "sys_dbg_get_thread_info"; + case 911: return "sys_dbg_spu_thread_read_from_ls"; + case 912: return "sys_dbg_spu_thread_write_to_ls"; + case 913: return "sys_dbg_kill_process"; + case 914: return "sys_dbg_get_process_info"; + case 915: return "sys_dbg_set_run_control_bit_to_spu"; + case 916: return "sys_dbg_spu_thread_get_exception_cause"; + case 917: return "sys_dbg_create_kernel_event_queue"; + case 918: return "sys_dbg_read_kernel_event_queue"; + case 919: return "sys_dbg_destroy_kernel_event_queue"; + case 920: return "sys_dbg_get_process_event_ctrl_flag"; + case 921: return "sys_dbg_set_process_event_cntl_flag"; + case 922: return "sys_dbg_get_spu_thread_group_event_cntl_flag"; + case 923: return "sys_dbg_set_spu_thread_group_event_cntl_flag"; + case 925: return "sys_dbg_get_raw_spu_list"; + case 932: return "sys_dbg_get_mutex_list"; + case 933: return "sys_dbg_get_mutex_information"; + case 934: return "sys_dbg_get_cond_list"; + case 935: return "sys_dbg_get_cond_information"; + case 936: return "sys_dbg_get_rwlock_list"; + case 937: return "sys_dbg_get_rwlock_information"; + case 938: return "sys_dbg_get_lwmutex_list"; + case 939: return "sys_dbg_get_address_from_dabr"; + case 940: return "sys_dbg_set_address_to_dabr"; + case 941: return "sys_dbg_get_lwmutex_information"; + case 942: return "sys_dbg_get_event_queue_list"; + case 943: return "sys_dbg_get_event_queue_information"; + case 944: return "sys_dbg_initialize_ppu_exception_handler"; + case 945: return "sys_dbg_finalize_ppu_exception_handler"; + case 946: return "sys_dbg_get_semaphore_list"; + case 947: return "sys_dbg_get_semaphore_information"; + case 948: return "sys_dbg_get_kernel_thread_list"; + case 949: return "sys_dbg_get_kernel_thread_info"; + case 950: return "sys_dbg_get_lwcond_list"; + case 951: return "sys_dbg_get_lwcond_information"; + case 952: return "sys_dbg_create_scratch_data_area_ext"; + case 953: return "sys_dbg_vm_get_page_information"; + case 954: return "sys_dbg_vm_get_info"; + case 955: return "sys_dbg_enable_floating_point_enabled_exception"; + case 956: return "sys_dbg_disable_floating_point_enabled_exception"; + case 960: return "sys_dbg_perfomance_monitor"; + case 970: return "sys_dbg_get_event_flag_list"; + case 971: return "sys_dbg_get_event_flag_information"; + case 975: return "sys_dbg_read_spu_thread_context2"; + case 985: return "sys_dbg_get_console_type"; + } + + return fmt::format("syscall_%llu", code); +} + +// Get function name by FNID +extern std::string ppu_get_function_name(const std::string& module, u32 fnid) +{ + // Check known FNIDs + if (module == "sys_libc" || module == "sys_libm") switch (fnid) + { + case 0x00acf0e5: return "spu_printf_finalize"; + case 0x00fb4a6b: return "spu_thread_sprintf"; + case 0x0125b2ca: return "_rand_int32_TT800"; + case 0x01508f24: return "raw_spu_write_float"; + case 0x0264f468: return "_Wctomb"; + case 0x02f4d325: return "spu_thread_read_double"; + case 0x02f52a3c: return "_filep_close_it"; + case 0x03becf3c: return "_Defloc"; + case 0x04a183fc: return "strcpy"; + case 0x04a1f19d: return "raw_spu_write_short"; + case 0x05d821c4: return "_Stoullx"; + case 0x077cdb23: return "btowc"; + case 0x07c7971d: return "_Stoldx"; + case 0x0871ffb0: return "mspace_malloc_usable_size"; + case 0x0891a3fa: return "_Tlsfree"; + case 0x09cbee1e: return "strxfrm"; + case 0x0a1d4b00: return "spu_thread_read_uint"; + case 0x0a4e2541: return "spu_thread_read_ldouble"; + case 0x0ae275a4: return "_Stolx"; + case 0x0b0d272f: return "_malloc_finalize"; + case 0x0b9d04d0: return "_Getnloc"; + case 0x0b9ecb98: return "toupper_ascii"; + case 0x0cae547f: return "raw_spu_write_double"; + case 0x0d2a593b: return "srand"; + case 0x0d8a2de0: return "_CStrxfrm"; + case 0x0df8809f: return "__call_functions_registered_with_atexit"; + case 0x0f60eb63: return "vfwscanf"; + case 0x0ff4722c: return "raw_spu_read_ushort"; + case 0x1096f8f1: return "ispunct_ascii"; + case 0x1098a99d: return "localeconv"; + case 0x112ea8ea: return "strspn"; + case 0x115e2f70: return "spu_thread_snprintf"; + case 0x116cda13: return "wcstol"; + case 0x118712ea: return "islower"; + case 0x11d270d2: return "exitspawn"; + case 0x126656b7: return "_Btowc"; + case 0x128b334f: return "raw_spu_read_mem"; + case 0x12a55fb7: return "mbrtowc"; + case 0x130d20a5: return "towlower"; + case 0x1365b52a: return "fcntl"; + case 0x13808972: return "wcstok"; + case 0x14052ae0: return "absi4"; + case 0x14348b57: return "divi4"; + case 0x145853cd: return "mspace_destroy"; + case 0x15362bc9: return "spu_thread_read_long"; + case 0x153b364a: return "mkdir"; + case 0x15bdcc00: return "rand"; + case 0x15c2e29d: return "isgraph_ascii"; + case 0x17752bab: return "wcsftime"; + case 0x17bc0136: return "_Lrv2d"; + case 0x17c031d7: return "spu_thread_read_ulong"; + case 0x1855b9b1: return "setlocale"; + case 0x1895908d: return "mspace_realloc"; + case 0x18e48b5d: return "wscanf"; + case 0x18f7b77d: return "_Dnorm"; + case 0x1970cd7e: return "getpid"; + case 0x19ccbb81: return "mktime"; + case 0x1ab01ea8: return "truncate"; + case 0x1abd0985: return "div"; + case 0x1ae06860: return "wcstoumax"; + case 0x1b4c3ff0: return "atexit"; + case 0x1c0e8ab6: return "vswscanf"; + case 0x1c2ef212: return "getwc"; + case 0x1cf4d80a: return "iswalpha"; + case 0x1dcd8609: return "_Strxfrmx"; + case 0x1dd0d4c5: return "spu_printf_attach_group"; + case 0x1df4732e: return "_Getptolower"; + case 0x1e9d2b4f: return "spu_thread_read_int"; + case 0x1ecae195: return "_Vacopy"; + case 0x1f913e8d: return "chmod"; + case 0x1f925c41: return "_allocate_mapped_pages"; + case 0x206612c4: return "spu_thread_read_ptr"; + case 0x216984ed: return "spu_thread_write_long"; + case 0x216fcd2a: return "_Atrealloc"; + case 0x21807b8e: return "towctrans"; + case 0x225702e1: return "_fs_initialize"; + case 0x22b0e566: return "_Stollx"; + case 0x23d3bca7: return "_Eadd"; + case 0x242c603e: return "_Frprep"; + case 0x243b52d8: return "_Mbtowcx"; + case 0x24802244: return "iswcntrl"; + case 0x24c9e021: return "abs"; + case 0x24e230d2: return "_Wctob"; + case 0x24f6cbdd: return "clock"; + case 0x253b7210: return "_rand_real2_TT800"; + case 0x25beee5a: return "__raw_spu_printf"; + case 0x25da8fbb: return "iscntrl"; + case 0x266311a0: return "localtime"; + case 0x2677568c: return "putchar"; + case 0x26f023d5: return "ftell"; + case 0x273b9711: return "sprintf"; + case 0x28b92ebf: return "raw_spu_read_uchar"; + case 0x296bc72f: return "_FDunscale"; + case 0x2b45cb34: return "wcsrtombs"; + case 0x2b7ba4ca: return "_Tlsset"; + case 0x2b81fb7f: return "readdir"; + case 0x2bc9dee6: return "raw_spu_read_short"; + case 0x2caea755: return "_Once"; + case 0x2d067448: return "ftruncate64"; + case 0x2d17ca7f: return "_Puttxt"; + case 0x2eea9f25: return "_Esub"; + case 0x2f45d39c: return "strlen"; + case 0x2fecec13: return "getwchar"; + case 0x30fb2899: return "_Getmem"; + case 0x312be3b3: return "_malloc_init_lv2"; + case 0x313f04ab: return "raw_spu_read_char"; + case 0x329a4540: return "_WPrintf"; + case 0x32e4a30a: return "_Mtxdst"; + case 0x336b4191: return "_Getint"; + case 0x33d6ae54: return "ferror"; + case 0x344eca7e: return "_WGetstr"; + case 0x34dd6650: return "_Getcloc"; + case 0x34e7c97e: return "_Unlocksyslock"; + case 0x3512ad38: return "tmpnam"; + case 0x355fd1fd: return "mbtowc"; + case 0x3574d37d: return "_Wcsxfrmx"; + case 0x36c067c1: return "_Stoll"; + case 0x36f2b4ed: return "strtoull"; + case 0x36feb965: return "raw_spu_write_llong"; + case 0x3704840e: return "_fs_finalize"; + case 0x38426d25: return "_Wctombx"; + case 0x3902363a: return "malloc_footprint"; + case 0x39bf419c: return "valloc"; + case 0x3a210c93: return "swscanf"; + case 0x3a840ae3: return "snprintf"; + case 0x3b22e88a: return "isxdigit"; + case 0x3b8097ac: return "_WScanf"; + case 0x3bce073b: return "putc"; + case 0x3bd9ce0a: return "fsync"; + case 0x3ca81c76: return "_Iswctype"; + case 0x3d1460e9: return "_Strerror"; + case 0x3d541975: return "atoi"; + case 0x3d5fdea7: return "vfwprintf"; + case 0x3d85d6f8: return "strcmp"; + case 0x3dbc3bee: return "opendir"; + case 0x3e57dfac: return "_Genld"; + case 0x3ec99a66: return "_Getptimes"; + case 0x3ee29d0b: return "_Stof"; + case 0x3f125e2e: return "spu_thread_write_short"; + case 0x3f4ccdc7: return "isdigit"; + case 0x3f650700: return "mspace_is_heap_empty"; + case 0x40a2599a: return "atol"; + case 0x40d04e4e: return "fwide"; + case 0x40e0ff25: return "_WGenld"; + case 0x41283333: return "isdigit_ascii"; + case 0x418bdfe1: return "_get_fd"; + case 0x4217b4cf: return "difftime"; + case 0x433fe2a9: return "fwscanf"; + case 0x44115dd0: return "_Geterrno"; + case 0x44796e5c: return "strerror"; + case 0x449317ed: return "_Fopen"; + case 0x44d7cae8: return "raw_spu_read_float"; + case 0x4544c2de: return "spu_thread_write_mem"; + case 0x4569518c: return "malloc_stats"; + case 0x459072c3: return "_init_TT800"; + case 0x4595c42b: return "wcsxfrm"; + case 0x468b45dc: return "mspace_calloc"; + case 0x4911ff9c: return "rand_int31_TT800"; + case 0x498a5036: return "raw_spu_write_mem"; + case 0x4a0049c6: return "_Getpctype"; + case 0x4ab5fbe2: return "_Printf"; + case 0x4b36c0e0: return "vfscanf"; + case 0x4b6a4010: return "vswprintf"; + case 0x4bb8e2b2: return "raw_spu_write_ushort"; + case 0x4c3f5f29: return "_Getgloballocale"; + case 0x4c7dc863: return "iswupper"; + case 0x4d348427: return "fputs"; + case 0x4e4be299: return "longjmp"; + case 0x4e72f810: return "wmemchr"; + case 0x4ffba189: return "feof"; + case 0x508196b4: return "raw_spu_printf"; + case 0x508e00c6: return "_Getloc"; + case 0x51b28904: return "_Stodx"; + case 0x526a496a: return "write"; + case 0x532b03be: return "raw_spu_read_uint"; + case 0x53eb43a1: return "_Getpmbstate"; + case 0x54b383bc: return "_Locvar"; + case 0x54c2844e: return "spu_raw_snprintf"; + case 0x54f57626: return "rewind"; + case 0x5516bbbf: return "iswctype"; + case 0x55d4866e: return "fgetws"; + case 0x5751acf9: return "_LDscale"; + case 0x575fb268: return "wctrans"; + case 0x57ff7dd7: return "_WStod"; + case 0x58320830: return "_WLitob"; + case 0x589b5314: return "strncat"; + case 0x5909e3c4: return "memset"; + case 0x59640bc6: return "raw_spu_read_ullong"; + case 0x59c1bb1f: return "_Getpwcstate"; + case 0x59e8dd58: return "strtoll"; + case 0x5a74f774: return "spu_thread_read_float"; + case 0x5b162b7f: return "memmove"; + case 0x5b4b6d6d: return "wcspbrk"; + case 0x5cc71eee: return "raw_spu_write_ldouble"; + case 0x5d43c1a3: return "_Mbtowc"; + case 0x5dbceee3: return "rand_int32_TT800"; + case 0x5e06c3fe: return "__getpid"; + case 0x5e7888f0: return "bsearch"; + case 0x5eb95641: return "_Stold"; + case 0x5f922a30: return "_Dscale"; + case 0x5f9a65c7: return "_WStold"; + case 0x5fa1e497: return "_Unlockfilelock"; + case 0x60627fb3: return "_LDunscale"; + case 0x6075a3c6: return "_Ld2rv"; + case 0x609080ec: return "isspace_ascii"; + case 0x6137d196: return "memalign"; + case 0x6287ac6a: return "iswdigit"; + case 0x62bf1d6c: return "swprintf"; + case 0x64aaf016: return "raw_spu_read_ldouble"; + case 0x6514dbe5: return "wcstold"; + case 0x6539ff6d: return "_Gentime"; + case 0x6545b7de: return "fgetpos"; + case 0x65e8d4d0: return "wcslen"; + case 0x6660fc8d: return "TlsGetValue"; + case 0x6687fba4: return "_Fgpos"; + case 0x66b71b17: return "wcsspn"; + case 0x67582370: return "spu_thread_write_double"; + case 0x676e3e7a: return "raw_spu_write_ptr"; + case 0x67d6334b: return "strtof"; + case 0x6823c180: return "iswprint"; + case 0x69106fd2: return "_init_by_array_TT800"; + case 0x692b497f: return "perror"; + case 0x6995f5e8: return "_Ldtob"; + case 0x69c27c12: return "fopen"; + case 0x69ff1b9b: return "fseek"; + case 0x6ba10474: return "_Tlsalloc"; + case 0x6cf78f3e: return "_Mtxunlock"; + case 0x6d5115b0: return "wcsncmp"; + case 0x6e988e5f: return "_rand_int31_TT800"; + case 0x7028dea9: return "_Locksyslock"; + case 0x703ec767: return "setvbuf"; + case 0x70b0e833: return "mblen"; + case 0x714c9618: return "__raw_spu_putfld"; + case 0x717b2502: return "stat"; + case 0x72236cbc: return "raw_spu_write_ullong"; + case 0x72b84004: return "spu_printf_attach_thread"; + case 0x73096858: return "wctob"; + case 0x7345b4be: return "_WStoll"; + case 0x73eae03d: return "strrchr"; + case 0x744d2505: return "ispunct"; + case 0x74fe4a7b: return "iswgraph"; + case 0x759e0635: return "malloc"; + case 0x75d4485c: return "rename"; + case 0x75f98579: return "wcscoll"; + case 0x76da0c84: return "ftruncate"; + case 0x76ed4243: return "_Wcsftime"; + case 0x770bfaee: return "wctype"; + case 0x77a602dd: return "free"; + case 0x77c15441: return "_WGetfloat"; + case 0x77e241bc: return "_Skip"; + case 0x7817edf0: return "raw_spu_write_uint"; + case 0x783636d1: return "spu_thread_read_char"; + case 0x78429d81: return "putwchar"; + case 0x79819dbf: return "fputc"; + case 0x7994c28d: return "_FDtentox"; + case 0x79eadf05: return "malloc_usable_size"; + case 0x7aaab95c: return "iswblank"; + case 0x7ae82e0f: return "vsprintf"; + case 0x7aee5acd: return "_Lockfilelock"; + case 0x7b5aac20: return "spu_thread_write_ptr"; + case 0x7b7a687a: return "_WPutfld"; + case 0x7b9c592e: return "spu_thread_read_ullong"; + case 0x7c1bcf37: return "isalnum_ascii"; + case 0x7c370679: return "_Foprep"; + case 0x7cec7b39: return "_Putfld"; + case 0x7d894764: return "_Readloc"; + case 0x7e7017b1: return "rmdir"; + case 0x7ea8d860: return "spu_printf_detach_group"; + case 0x7efd420a: return "_Daysto"; + case 0x7fd325c4: return "mspace_malloc_stats"; + case 0x7fdcf73e: return "wcscat"; + case 0x806fd281: return "isblank_ascii"; + case 0x809a143f: return "kill"; + case 0x813a9666: return "ungetwc"; + case 0x814d8cb0: return "fflush"; + case 0x81a0a858: return "_memset_int"; + case 0x82a3cc30: return "wcschr"; + case 0x82a4561a: return "_put_fd"; + case 0x831d70a5: return "memcpy"; + case 0x8342b757: return "utime"; + case 0x84378ddc: return "wcsncpy"; + case 0x86532174: return "imaxdiv"; + case 0x867275d7: return "_Stoul"; + case 0x86b4c669: return "tolower_ascii"; + case 0x8713c859: return "link"; + case 0x8725a1a7: return "_memset_vmx"; + case 0x87e8f748: return "memset_vmx"; + case 0x8809cdfd: return "_Getpwctytab"; + case 0x882689f2: return "_Makeloc"; + case 0x882e7760: return "raw_spu_write_uchar"; + case 0x889d5804: return "_Dunscale"; + case 0x88e009f5: return "vwprintf"; + case 0x896e1bfd: return "spu_thread_write_uchar"; + case 0x89b62f56: return "_Etentox"; + case 0x89f6f026: return "time"; + case 0x8a6830e7: return "abort"; + case 0x8a71132c: return "remove"; + case 0x8a847b51: return "tmpfile"; + case 0x8ab0abc6: return "strncpy"; + case 0x8b439438: return "clearerr"; + case 0x8b9d8dd2: return "iswpunct"; + case 0x8cb6bfdc: return "_Locsum"; + case 0x8d7ffaf1: return "_WStopfx"; + case 0x8e2484f1: return "_Emul"; + case 0x8ed71e8b: return "_WGetfld"; + case 0x8ef85e47: return "_WPuttxt"; + case 0x8f5dd179: return "_Nnl"; + case 0x90010029: return "gets"; + case 0x9027fd99: return "_WStoldx"; + case 0x90457fe3: return "raw_spu_read_long"; + case 0x90b27880: return "strtoumax"; + case 0x9234f738: return "raw_spu_read_int"; + case 0x93427cb9: return "setbuf"; + case 0x938bfcf7: return "spu_thread_write_char"; + case 0x93a3e3ac: return "tolower"; + case 0x9439e4cd: return "wcsncat"; + case 0x96b6baa6: return "spu_thread_read_mem"; + case 0x96e6303b: return "_WStoxflt"; + case 0x96ea4de6: return "wctomb"; + case 0x97896359: return "isspace"; + case 0x9800573c: return "_WLdtob"; + case 0x980d3ea7: return "_Getfld"; + case 0x9886810c: return "_FDnorm"; + case 0x98f0eeab: return "raw_spu_write_ulong"; + case 0x99782342: return "strncasecmp_ascii"; + case 0x99a72146: return "vsnprintf"; + case 0x99b38ce7: return "wmemmove"; + case 0x9a87bb3a: return "_Getmbcurmax"; + case 0x9abe8c74: return "wprintf"; + case 0x9c7028a5: return "spu_thread_write_uint"; + case 0x9c9d7b0d: return "strtold"; + case 0x9cab08d1: return "spu_thread_write_int"; + case 0x9d140351: return "_Destroytls"; + case 0x9eb25e00: return "strcoll"; + case 0x9eee5387: return "truncate64"; + case 0x9ff08d57: return "_Clearlocks"; + case 0xa0ab76d5: return "_absi4"; + case 0xa0bc0efb: return "mallinfo"; + case 0xa0ddba8e: return "_Stoulx"; + case 0xa1dbb466: return "_Gettime"; + case 0xa2945229: return "_WGetint"; + case 0xa30d4797: return "wcstoll"; + case 0xa3440924: return "closedir"; + case 0xa3da58f6: return "rand_real1_TT800"; + case 0xa45a0313: return "mspace_create"; + case 0xa483d50d: return "_rv2d"; + case 0xa53800c2: return "_malloc_finalize_lv2"; + case 0xa568db82: return "spu_thread_read_ushort"; + case 0xa57cc615: return "iswspace"; + case 0xa5bc0e19: return "getchar"; + case 0xa6463518: return "__rename"; + case 0xa650df19: return "toupper"; + case 0xa65886b8: return "_Findloc"; + case 0xa72a7595: return "calloc"; + case 0xa797790f: return "wcsstr"; + case 0xa82d70da: return "_Tlsget"; + case 0xa835be11: return "__cxa_atexit"; + case 0xa874036a: return "wcstof"; + case 0xa8a6f615: return "TlsSetValue"; + case 0xa8b07f1b: return "wmemcpy"; + case 0xa9f68eff: return "qsort"; + case 0xaa1e687d: return "isgraph"; + case 0xaa266d35: return "_malloc_init"; + case 0xaa9635d7: return "strcat"; + case 0xab4c7ca1: return "_CWcsxfrm"; + case 0xab77019f: return "fstat"; + case 0xabc27420: return "wcstoul"; + case 0xac758d20: return "wmemcmp"; + case 0xac893127: return "fgetc"; + case 0xace90be4: return "_Dtentox"; + case 0xad62a342: return "ldiv"; + case 0xad8e9ad0: return "_Initlocks"; + case 0xaec7c970: return "lseek"; + case 0xaf002043: return "independent_comalloc"; + case 0xaf44a615: return "fgets"; + case 0xaf6bdcb0: return "_Nonfatal_Assert"; + case 0xaf89fdbd: return "_Assert"; + case 0xafa39179: return "_WPutstr"; + case 0xb120f6ca: return "close"; + case 0xb17b79d0: return "isalpha"; + case 0xb18cc115: return "freopen"; + case 0xb1cc43e3: return "_CStrftime"; + case 0xb1f4779d: return "spu_thread_printf"; + case 0xb24cb8d6: return "_Locterm"; + case 0xb2702e15: return "wcrtomb"; + case 0xb2748a9f: return "_Freeloc"; + case 0xb30042ce: return "lldiv"; + case 0xb37982ea: return "_Getstr"; + case 0xb3c495bd: return "imaxabs"; + case 0xb3d98d59: return "_rand_real1_TT800"; + case 0xb400f226: return "isupper_ascii"; + case 0xb4225825: return "mbsinit"; + case 0xb43c25c7: return "wcstoull"; + case 0xb49eea74: return "_init_malloc_lock0"; + case 0xb4a54446: return "_Stofx"; + case 0xb4fc7078: return "_close_all_FILE"; + case 0xb529d259: return "isalnum"; + case 0xb569849d: return "reallocalign"; + case 0xb57bdf7b: return "iswxdigit"; + case 0xb5d353e8: return "_LDtentox"; + case 0xb6002508: return "_Putstr"; + case 0xb6257e3d: return "strncasecmp"; + case 0xb680e240: return "wcstombs"; + case 0xb6af290e: return "_WFrprep"; + case 0xb6d92ac3: return "strcasecmp"; + case 0xb738027a: return "strtok_r"; + case 0xb794631e: return "_WStofx"; + case 0xb7ab5127: return "wcsrchr"; + case 0xb7b793ed: return "get_state_TT800"; + case 0xb7ba4aeb: return "_WStoul"; + case 0xb7d3427f: return "iscntrl_ascii"; + case 0xb81cd66a: return "mbrlen"; + case 0xb9ed25d4: return "raw_spu_read_ulong"; + case 0xba62681f: return "mspace_memalign"; + case 0xbb605c96: return "pvalloc"; + case 0xbbd4582f: return "_Setloc"; + case 0xbc1d69c5: return "atoll"; + case 0xbc374779: return "_Getlname"; + case 0xbc5af0b5: return "fgetwc"; + case 0xbc7b4b8e: return "ctime"; + case 0xbe11beaa: return "_wremove"; + case 0xbe251a29: return "islower_ascii"; + case 0xbe6e5c58: return "spu_thread_read_uchar"; + case 0xbec43f86: return "raw_spu_read_ptr"; + case 0xbf5bf5ea: return "lseek64"; + case 0xbfcd1b3b: return "_Getdst"; + case 0xc01d9f97: return "printf"; + case 0xc08cc41d: return "wcstod"; + case 0xc0e27b2c: return "_Makestab"; + case 0xc155a73f: return "_WStoull"; + case 0xc15e657e: return "spu_raw_sprintf"; + case 0xc1a71972: return "_d2rv"; + case 0xc1b4bbb9: return "raw_spu_write_char"; + case 0xc1c8737c: return "_Getptoupper"; + case 0xc291e698: return "exit"; + case 0xc3c598e2: return "spu_printf_initialize"; + case 0xc3e14cbe: return "memcmp"; + case 0xc4178000: return "_rand_real3_TT800"; + case 0xc41c6e5d: return "_Scanf"; + case 0xc57337f8: return "_Fofind"; + case 0xc5c09834: return "strstr"; + case 0xc63c354f: return "_Exit"; + case 0xc69b2427: return "labs"; + case 0xc78df618: return "rand_real3_TT800"; + case 0xc7b62ab8: return "spu_thread_write_ullong"; + case 0xc9471fac: return "_Mtxinit"; + case 0xc94b27e3: return "_WStof"; + case 0xc95b20d3: return "fputwc"; + case 0xc9607d35: return "_Stopfx"; + case 0xc97a17d7: return "vsscanf"; + case 0xcab654bf: return "_Once_ctor"; + case 0xcb85ac70: return "mspace_malloc"; + case 0xcb9c535b: return "strftime"; + case 0xcbac7ad7: return "memchr"; + case 0xcbdc3a6d: return "raw_spu_write_int"; + case 0xcc5e0c72: return "_divi4"; + case 0xcca68e9c: return "putwc"; + case 0xce7a9e76: return "isprint_ascii"; + case 0xcecbcdc4: return "_Frv2d"; + case 0xcf863219: return "_Fwprep"; + case 0xcfbfb7a7: return "spu_printf_detach_thread"; + case 0xd14ece90: return "strtol"; + case 0xd1d69cb8: return "_Stod"; + case 0xd20f6601: return "independent_calloc"; + case 0xd2a99b1e: return "isprint"; + case 0xd2ac48d7: return "iswalnum"; + case 0xd360dcb4: return "fileno"; + case 0xd3964a09: return "__spu_thread_putfld"; + case 0xd40723d6: return "fread"; + case 0xd417eeb5: return "_Stoull"; + case 0xd4912ee3: return "_FDscale"; + case 0xd5c8cb55: return "spu_thread_write_ushort"; + case 0xd69c513d: return "_Wcscollx"; + case 0xd784459d: return "isupper"; + case 0xd7dc3a8f: return "strtod"; + case 0xd8b4eb20: return "__spu_thread_puttxt"; + case 0xd9674905: return "mspace_reallocalign"; + case 0xd9a4f812: return "atoff"; + case 0xda5a7eb8: return "strtoul"; + case 0xdaeada07: return "mallopt"; + case 0xddbac025: return "strcasecmp_ascii"; + case 0xddc71a75: return "_SCE_Assert"; + case 0xde1bb092: return "init_by_array_TT800"; + case 0xde32a334: return "_Exitspawn"; + case 0xde7aff7a: return "memcpy16"; + case 0xdebee2af: return "strchr"; + case 0xdef86a83: return "isxdigit_ascii"; + case 0xdfb52083: return "_Stoxflt"; + case 0xe03c7ab1: return "_Fspos"; + case 0xe1858899: return "_Getpwctrtab"; + case 0xe1bd3587: return "fclose"; + case 0xe1e83c65: return "strncmp"; + case 0xe2c5274a: return "_WStoflt"; + case 0xe3812672: return "fdopen"; + case 0xe3cc73f3: return "puts"; + case 0xe3d91db3: return "raw_spu_read_double"; + case 0xe40ba755: return "strtok"; + case 0xe44bf0bf: return "atof"; + case 0xe469fb20: return "_Atexit"; + case 0xe48348e9: return "vprintf"; + case 0xe4c51d4c: return "wcstoimax"; + case 0xe5ea9e2b: return "_Isdst"; + case 0xe5f09c80: return "llabs"; + case 0xe60ee9e5: return "fputws"; + case 0xe6a7de0a: return "ungetc"; + case 0xe7def231: return "_Getfloat"; + case 0xe89071ad: return "isalpha_ascii"; + case 0xe9137453: return "fwprintf"; + case 0xe9a2cc40: return "raw_spu_write_long"; + case 0xe9b560a5: return "sscanf"; + case 0xeb26298c: return "gmtime"; + case 0xeb40c9ec: return "rand_real2_TT800"; + case 0xeb8abe73: return "vwscanf"; + case 0xec9e7cb9: return "spu_thread_read_llong"; + case 0xecddba69: return "_WStodx"; + case 0xed6ec979: return "fsetpos"; + case 0xeda48c80: return "malloc_trim"; + case 0xeddcee2c: return "init_TT800"; + case 0xedec777d: return "_Ttotm"; + case 0xeeeb4f3e: return "_get_state_TT800"; + case 0xeeffc9a6: return "_wrename"; + case 0xef110b6b: return "unlink"; + case 0xf06eed36: return "wmemset"; + case 0xf0776a44: return "wcscmp"; + case 0xf0e022c6: return "getc"; + case 0xf2bbbee9: return "_Litob"; + case 0xf2fca4b2: return "spu_thread_write_llong"; + case 0xf356418c: return "open"; + case 0xf3ef3678: return "wcscspn"; + case 0xf41355f9: return "wcscpy"; + case 0xf418ee84: return "_WFwprep"; + case 0xf4207734: return "spu_thread_write_ulong"; + case 0xf5a32994: return "_Getpcostate"; + case 0xf5ef229c: return "_Getpwcostate"; + case 0xf5f7dda8: return "towupper"; + case 0xf68e2ac9: return "_init_malloc_lock"; + case 0xf7583d67: return "vscanf"; + case 0xf7908e27: return "strcspn"; + case 0xf7a14a22: return "realloc"; + case 0xf7d51596: return "scanf"; + case 0xf7ddb471: return "_Setgloballocale"; + case 0xf88f26c4: return "fwrite"; + case 0xf8935fe3: return "spu_thread_write_float"; + case 0xf89dc648: return "strpbrk"; + case 0xf9dae72c: return "setjmp"; + case 0xf9dba140: return "_Mtxlock"; + case 0xf9e26b72: return "_Once_dtor"; + case 0xfa00d211: return "read"; + case 0xfae4b063: return "_Strcollx"; + case 0xfaec8c60: return "fprintf"; + case 0xfb0f0018: return "_Makewct"; + case 0xfb2081fd: return "vfprintf"; + case 0xfb81426d: return "iswlower"; + case 0xfb8ea4d2: return "_Fd2rv"; + case 0xfc0428a6: return "strdup"; + case 0xfc60575c: return "__spu_thread_printf"; + case 0xfc606237: return "mbsrtowcs"; + case 0xfcac2e8e: return "mbstowcs"; + case 0xfd0cb96d: return "spu_thread_read_short"; + case 0xfd461e85: return "spu_thread_write_ldouble"; + case 0xfd6a1ddb: return "raw_spu_read_llong"; + case 0xfd81f6ca: return "_Stoflt"; + case 0xfe0261aa: return "mspace_free"; + case 0xfe630fd9: return "isblank"; + case 0xfe88e97e: return "fscanf"; + case 0xff689124: return "strtoimax"; + case 0xffbae95e: return "asctime"; + case 0xffbd876b: return "__raw_spu_puttxt"; + case 0x003395d9: return "_Feraise"; + case 0x00367be0: return "fminl"; + case 0x007854f4: return "_FDclass"; + case 0x00fde072: return "f_powf"; + case 0x010818fc: return "asinf4"; + case 0x012d0a91: return "_fminf4"; + case 0x016556df: return "_sinf4"; + case 0x01b84b27: return "llround"; + case 0x01ecef7d: return "_FCbuild"; + case 0x02e68d44: return "_f_fmodf"; + case 0x032cc709: return "csin"; + case 0x03593d2c: return "_f_expf"; + case 0x03aea906: return "divf4"; + case 0x0522d1af: return "_recipf4"; + case 0x054aae63: return "_fdimf4"; + case 0x05cb1718: return "f_fdimf"; + case 0x05e27a13: return "log10f4fast"; + case 0x05efc660: return "asin"; + case 0x05f1dc9e: return "_FExp"; + case 0x07274304: return "csinh"; + case 0x07daed62: return "log2f4"; + case 0x07f400e3: return "_LCbuild"; + case 0x080414bd: return "conjl"; + case 0x08139bd2: return "_fmaxf4"; + case 0x0829a21d: return "asinhl"; + case 0x0a242ed5: return "sinf4"; + case 0x0b3f4e90: return "catanhf"; + case 0x0bb036a6: return "_cosf4"; + case 0x0c14cfcc: return "fesetenv"; + case 0x0c9b8305: return "hypotf4"; + case 0x0cbdae68: return "sinf"; + case 0x0cf9b8bd: return "_Erfc"; + case 0x0d86295d: return "_LCaddcr"; + case 0x0e53319f: return "_asinf4"; + case 0x0e8573dc: return "expm1l"; + case 0x0f02f882: return "llrintl"; + case 0x0f428f0f: return "rint"; + case 0x0f721a9d: return "_LCsubcc"; + case 0x10627248: return "f_fmodf"; + case 0x11c51388: return "tgamma"; + case 0x1225dd31: return "casinf"; + case 0x12de4e46: return "_powf4"; + case 0x12e04cd7: return "cimagl"; + case 0x1313a420: return "acos"; + case 0x137f7e77: return "expf4"; + case 0x14208b00: return "_asinf4fast"; + case 0x1498a072: return "_Cmulcr"; + case 0x16bf208a: return "log10f"; + case 0x17316bee: return "log2"; + case 0x178d98dd: return "atanf4fast"; + case 0x17cd5d87: return "_recipf4fast"; + case 0x182cd542: return "tgammal"; + case 0x18668ce3: return "exp"; + case 0x18b26998: return "remainderl"; + case 0x18ec6099: return "rintl"; + case 0x1988732d: return "clog10"; + case 0x1a1adede: return "rsqrtf4fast"; + case 0x1acb2b16: return "acosf4"; + case 0x1bbdcd9f: return "expm1f4"; + case 0x1bcdeb47: return "_LSinh"; + case 0x1be996cc: return "_LCdivcc"; + case 0x1c11885d: return "_floorf4"; + case 0x1d35bfe4: return "_LLog"; + case 0x1d5bf5d0: return "_modff4"; + case 0x1e623f95: return "truncf4"; + case 0x1e85ef02: return "f_atanf"; + case 0x1e9fd6ba: return "_sinf4fast"; + case 0x2033eeb7: return "csqrt"; + case 0x2118fe46: return "cexpl"; + case 0x21a37b3e: return "log1pf"; + case 0x21e6d304: return "ceil"; + case 0x22c3e308: return "_exp2f4"; + case 0x238af59b: return "fegetenv"; + case 0x23b985f7: return "floorf"; + case 0x241f9337: return "_FCmulcr"; + case 0x24497c52: return "cosf"; + case 0x246ea8d0: return "f_sqrtf"; + case 0x2627d6b2: return "erfc"; + case 0x266d2473: return "_Caddcr"; + case 0x26deed0b: return "cosl"; + case 0x26ef50ed: return "asinh"; + case 0x28faaa5a: return "ilogbf4"; + case 0x29685118: return "_negatef4"; + case 0x2a138d2b: return "truncf"; + case 0x2a4dcbad: return "cacosl"; + case 0x2a89ce33: return "llrintf"; + case 0x2af4b73b: return "fmax"; + case 0x2b282ebb: return "sqrtl"; + case 0x2bb0f2c9: return "logb"; + case 0x2c45fe6a: return "fmaxl"; + case 0x2c601f3b: return "csinl"; + case 0x2cbb6f53: return "f_hypotf"; + case 0x2dcab6a4: return "nanl"; + case 0x2df339bc: return "_f_floorf"; + case 0x2e69bb2a: return "_FCosh"; + case 0x2ec867b4: return "exp2f4fast"; + case 0x30bc7a53: return "logf4"; + case 0x315673f6: return "_Csubcc"; + case 0x31be25c3: return "scalblnf"; + case 0x31db8c89: return "atan2"; + case 0x321c55de: return "nexttowardl"; + case 0x3261de11: return "fesetexceptflag"; + case 0x329ec019: return "rsqrtf4"; + case 0x32f994a1: return "cosf4fast"; + case 0x33e5929b: return "_LDsign"; + case 0x33f27f25: return "_FCdivcr"; + case 0x3436f008: return "csinhf"; + case 0x3459748b: return "log10f4"; + case 0x347c1ee1: return "atanf4"; + case 0x34c0371e: return "powl"; + case 0x358d7f93: return "_f_lrintf"; + case 0x3593a445: return "clog"; + case 0x35b6e70a: return "lrintl"; + case 0x35d3f688: return "creal"; + case 0x36778d1b: return "coshf"; + case 0x373054d1: return "cpow"; + case 0x37345541: return "log1pl"; + case 0x376fb27f: return "sinhl"; + case 0x3792b12d: return "lroundl"; + case 0x38ba5590: return "ccosl"; + case 0x38e69f09: return "pow"; + case 0x398483aa: return "_expm1f4fast"; + case 0x39ef81c9: return "f_fmaxf"; + case 0x3ad203fa: return "lrint"; + case 0x3adc01d7: return "f_frexpf"; + case 0x3b802524: return "ldexpf4"; + case 0x3c057fbd: return "atanf"; + case 0x3c616743: return "_LDtest"; + case 0x3cb818fa: return "_f_fdimf"; + case 0x3d4efafb: return "atan2l"; + case 0x3d549f2a: return "ctanhl"; + case 0x3d901a10: return "_ceilf4"; + case 0x3da55602: return "fabsf"; + case 0x3dfa060f: return "scalbnl"; + case 0x3e7eb58f: return "frexpf4"; + case 0x3e919cba: return "scalbnf"; + case 0x3ec9de23: return "_cbrtf4"; + case 0x3eeedb0e: return "_Dclass"; + case 0x3f6262b3: return "f_fminf"; + case 0x3f701e78: return "_Poly"; + case 0x4020f5ef: return "cbrt"; + case 0x405f9727: return "_log1pf4fast"; + case 0x40a2e212: return "_fabsf4"; + case 0x4111b546: return "_LExp"; + case 0x411434bb: return "asinf"; + case 0x414c5ecc: return "_f_hypotf"; + case 0x4152669c: return "scalbln"; + case 0x417851ce: return "feholdexcept"; + case 0x418036e3: return "_FTgamma"; + case 0x4189a367: return "remquo"; + case 0x41d1b236: return "_f_rintf"; + case 0x430309a1: return "ldexpf"; + case 0x434881a0: return "cacosf"; + case 0x43d522f4: return "cabsl"; + case 0x44cd6308: return "remainder"; + case 0x44cf744b: return "tanhl"; + case 0x45034943: return "nan"; + case 0x452ac4bb: return "floorf4"; + case 0x453f9e91: return "cbrtf"; + case 0x46b66f76: return "csqrtl"; + case 0x46cf72d9: return "fdimf"; + case 0x47433144: return "expm1f4fast"; + case 0x475d855b: return "trunc"; + case 0x476b5591: return "fmaf"; + case 0x48157605: return "_f_llrintf"; + case 0x4826db61: return "fma"; + case 0x4875601d: return "_exp2f4fast"; + case 0x487bbd1c: return "tanf4"; + case 0x488df791: return "cexp"; + case 0x48d462a9: return "_FDint"; + case 0x4930ac11: return "logbl"; + case 0x4a5ae27d: return "f_exp2f"; + case 0x4a6ca9a6: return "powf4"; + case 0x4ab22a63: return "_Caddcc"; + case 0x4add664c: return "feclearexcept"; + case 0x4ae52dd3: return "exp2"; + case 0x4b03d5b2: return "f_rintf"; + case 0x4b584841: return "f_asinf"; + case 0x4cb5fa99: return "nexttoward"; + case 0x4d878773: return "remainderf4"; + case 0x4ddb926b: return "powf"; + case 0x4e010403: return "copysign"; + case 0x4eb5eb51: return "sin"; + case 0x4fa4f5ec: return "nexttowardf"; + case 0x501c412f: return "cargf"; + case 0x519ebb77: return "floor"; + case 0x547fb4a7: return "sinf4fast"; + case 0x54d2fb8c: return "rintf"; + case 0x5516d621: return "acosl"; + case 0x55c8a549: return "truncl"; + case 0x56c573a8: return "log1p"; + case 0x575e9b6e: return "asinl"; + case 0x58eb9e57: return "fabs"; + case 0x596ab55c: return "atanh"; + case 0x5b18eded: return "clogl"; + case 0x5b474c22: return "casinhl"; + case 0x5bfd37be: return "_FCaddcc"; + case 0x5e48dede: return "exp2f4"; + case 0x5ee10a95: return "catanh"; + case 0x5ee37927: return "_LErfc"; + case 0x60e9ff3c: return "_expm1f4"; + case 0x61250988: return "catanl"; + case 0x6261c0b5: return "_log10f4"; + case 0x63bbdfa6: return "_FCmulcc"; + case 0x642e3d18: return "_frexpf4"; + case 0x642f7d6b: return "f_copysignf"; + case 0x645557bd: return "copysignl"; + case 0x64abdb4d: return "csinhl"; + case 0x657d0e83: return "divf4fast"; + case 0x65935877: return "ilogbf"; + case 0x659e011e: return "sqrt"; + case 0x6636c4a5: return "frexpf"; + case 0x664e04b9: return "negatef4"; + case 0x6764c707: return "f_log2f"; + case 0x683cacb3: return "sinh"; + case 0x68a8957f: return "casinhf"; + case 0x68f72416: return "nextafterl"; + case 0x69040b9b: return "logbf4"; + case 0x69725dce: return "lgamma"; + case 0x6ad1c42b: return "_sincosf4"; + case 0x6b660894: return "_acosf4fast"; + case 0x6b6ab2a9: return "_LDclass"; + case 0x6c009c56: return "f_log10f"; + case 0x6c6285c6: return "acoshf"; + case 0x6cc4bd13: return "casinh"; + case 0x6ddd31b2: return "hypot"; + case 0x6df35518: return "floorl"; + case 0x6e9eb0dc: return "sincosf4fast"; + case 0x6ef6b083: return "_FCsubcr"; + case 0x6f5dd7d2: return "cexpf"; + case 0x6f639afb: return "f_llroundf"; + case 0x6fcc1e27: return "_FPoly"; + case 0x70357b12: return "_atanf4fast"; + case 0x7048396e: return "carg"; + case 0x705d9e24: return "f_acosf"; + case 0x70f71871: return "_FCdivcc"; + case 0x71293b71: return "_FLog"; + case 0x714adce1: return "log"; + case 0x71f2bc56: return "_divf4fast"; + case 0x728149e5: return "f_ldexpf"; + case 0x729b7269: return "cproj"; + case 0x72a3ed28: return "fesettrapenable"; + case 0x72f1f64b: return "_logbf4"; + case 0x734ca589: return "_f_cosf"; + case 0x742f12b4: return "_Sin"; + case 0x74902d4b: return "expf4fast"; + case 0x749440f9: return "lgammal"; + case 0x752fa85e: return "fmaxf4"; + case 0x758f33dc: return "nearbyint"; + case 0x75e3e2e9: return "nearbyintl"; + case 0x76afaf04: return "_sqrtf4"; + case 0x76e639ec: return "_atanf4"; + case 0x772f1e4d: return "lround"; + case 0x7793a86b: return "ctanf"; + case 0x7831a2e0: return "hypotl"; + case 0x78e4590a: return "acosh"; + case 0x790c53bd: return "_Fpcomp"; + case 0x7919f414: return "_f_nearbyintf"; + case 0x79ba9b5c: return "expl"; + case 0x7a893af1: return "_rsqrtf4"; + case 0x7ab679da: return "f_cosf"; + case 0x7c2eaeb5: return "fminf"; + case 0x7d02a5ca: return "sqrtf4fast"; + case 0x7d6191d0: return "_Cosh"; + case 0x7f381837: return "frexp"; + case 0x7f579e03: return "atan"; + case 0x7f91cd41: return "tanf4fast"; + case 0x812ed488: return "cabsf"; + case 0x81daf880: return "_LCsubcr"; + case 0x8217e783: return "cosh"; + case 0x833e6b0e: return "cimag"; + case 0x834f5917: return "ccosh"; + case 0x842cb14d: return "_log1pf4"; + case 0x8451edf0: return "sqrtf"; + case 0x889cccb0: return "llroundl"; + case 0x88fb4a66: return "recipf4fast"; + case 0x892f2590: return "fegetround"; + case 0x895cdb49: return "fmaxf"; + case 0x89b507b3: return "catanhl"; + case 0x89d1d168: return "_LAtan"; + case 0x8b168769: return "fdiml"; + case 0x8bd1deb2: return "_LTgamma"; + case 0x8bd67efc: return "erf"; + case 0x8c85369b: return "_f_fminf"; + case 0x8d5858db: return "_f_exp2f"; + case 0x8e01379e: return "cacoshf"; + case 0x8e258fa0: return "cacos"; + case 0x8ecae294: return "nextafter"; + case 0x8f2bcdb5: return "_logf4"; + case 0x8f96319e: return "log10l"; + case 0x8fb7bac7: return "_sqrtf4fast"; + case 0x904e646b: return "cargl"; + case 0x90f0242f: return "_f_sinf"; + case 0x9110708a: return "modfl"; + case 0x91cdfdb0: return "asinf4fast"; + case 0x9232baea: return "_FDtest"; + case 0x9245e01b: return "_divf4"; + case 0x9379e36e: return "tanf"; + case 0x938fb946: return "_tanf4fast"; + case 0x947ae18e: return "_LHypot"; + case 0x9558ed08: return "lrintf"; + case 0x95dfecb1: return "_FCsubcc"; + case 0x961688d1: return "f_nearbyintf"; + case 0x9616e336: return "_FHypot"; + case 0x964ac044: return "creall"; + case 0x96d1b95e: return "log2f4fast"; + case 0x9700d9cd: return "clogf"; + case 0x970a3432: return "cacosh"; + case 0x99a6c261: return "catanf"; + case 0x99c228fc: return "roundl"; + case 0x9a81e583: return "fmodf"; + case 0x9af30eaf: return "casin"; + case 0x9e289062: return "_f_ceilf"; + case 0x9e3ada21: return "logl"; + case 0x9e8130b6: return "ccos"; + case 0x9f03dd3e: return "lgammaf"; + case 0x9f0efc6e: return "exp2l"; + case 0x9f46f5a4: return "tgammaf"; + case 0x9f65bd34: return "fdimf4"; + case 0x9f78f052: return "cos"; + case 0x9fded78a: return "_acosf4"; + case 0xa0160c30: return "_copysignf4"; + case 0xa20827a8: return "ctanl"; + case 0xa2c81938: return "_LSin"; + case 0xa4578433: return "fmin"; + case 0xa46a70a1: return "atanhl"; + case 0xa4ca5cf2: return "llroundf"; + case 0xa56557b6: return "catan"; + case 0xa5d0b260: return "acoshl"; + case 0xa713f8cf: return "modf"; + case 0xa7658186: return "log1pf4"; + case 0xa823836b: return "ilogb"; + case 0xa8c16038: return "_FDsign"; + case 0xa8d180e8: return "_Cbuild"; + case 0xa92bcc85: return "cabs"; + case 0xa9e039c4: return "erfcf"; + case 0xaaa270dc: return "_LCdivcr"; + case 0xab377381: return "log2f"; + case 0xabdccc7a: return "f_atan2f"; + case 0xacca2f83: return "copysignf"; + case 0xad17e787: return "_Dint"; + case 0xad3a093d: return "_LCosh"; + case 0xad5d3e57: return "_FLgamma"; + case 0xaddce673: return "erfcl"; + case 0xafa13040: return "f_llrintf"; + case 0xafcfdad7: return "_Lgamma"; + case 0xafd9a625: return "cimagf"; + case 0xb0fa1592: return "clog10l"; + case 0xb24bd2f8: return "logbf"; + case 0xb348c5c2: return "_LLgamma"; + case 0xb412a8dc: return "_LDint"; + case 0xb4ef29d5: return "f_floorf"; + case 0xb4f4513e: return "_Tgamma"; + case 0xb54cc9a1: return "f_sinf"; + case 0xb5961d4e: return "_sincosf4fast"; + case 0xb598a495: return "fmodl"; + case 0xb5e28191: return "_FSin"; + case 0xb7696143: return "nextafterf"; + case 0xb79012ba: return "modff"; + case 0xb89863bc: return "_rsqrtf4fast"; + case 0xb8aa984e: return "_expf4"; + case 0xb94b9d13: return "_Dtest"; + case 0xb9d2ad22: return "remquol"; + case 0xba136594: return "csinf"; + case 0xba84eab5: return "coshl"; + case 0xbaf11866: return "ceilf"; + case 0xbb165807: return "expm1f"; + case 0xbb208b20: return "cbrtf4fast"; + case 0xbb761c89: return "remquof"; + case 0xbbaa300b: return "f_log1pf"; + case 0xbbf7354e: return "fegetexceptflag"; + case 0xbd7410d9: return "recipf4"; + case 0xbd8bb75c: return "asinhf"; + case 0xbf23f2e7: return "cprojl"; + case 0xbfda6837: return "_f_log10f"; + case 0xc0609820: return "nearbyintf"; + case 0xc0bcf25e: return "_logf4fast"; + case 0xc357b33a: return "frexpl"; + case 0xc406dd09: return "cbrtf4"; + case 0xc41f01db: return "fminf4"; + case 0xc477c0f6: return "f_lroundf"; + case 0xc4cccd1f: return "modff4"; + case 0xc7369fce: return "_Atan"; + case 0xc78ac9d0: return "scalbn"; + case 0xc7b45a19: return "_LFpcomp"; + case 0xc7f1d407: return "fmal"; + case 0xc7fb73d6: return "f_lrintf"; + case 0xc8910002: return "ilogbl"; + case 0xc8dd9279: return "expm1"; + case 0xc90f4bbc: return "_atan2f4"; + case 0xc9481758: return "_tanf4"; + case 0xc94fcc63: return "cbrtl"; + case 0xc977e1ea: return "fetestexcept"; + case 0xc984bf53: return "roundf"; + case 0xc9c536ce: return "_ldexpf4"; + case 0xca239640: return "fmodf4"; + case 0xca463458: return "_Log"; + case 0xcaaf7ae7: return "cprojf"; + case 0xcac167a5: return "_Cmulcc"; + case 0xcb6599c0: return "exp2f"; + case 0xcb6a147e: return "_cosf4fast"; + case 0xcbdf9afb: return "_log10f4fast"; + case 0xccc66f11: return "_FSinh"; + case 0xce91ff18: return "nanf"; + case 0xcfee82d8: return "_remainderf4"; + case 0xd0fd3ca8: return "_hypotf4"; + case 0xd125b89e: return "conjf"; + case 0xd1a3574c: return "clog10f"; + case 0xd231e30a: return "ldexpl"; + case 0xd28ef6dd: return "_Hypot"; + case 0xd2a666c9: return "ctanh"; + case 0xd3a346a8: return "tanl"; + case 0xd40f3f2c: return "erff"; + case 0xd42904b7: return "fabsl"; + case 0xd477852d: return "logf"; + case 0xd48eaae1: return "scalblnl"; + case 0xd4f37b9d: return "tanhf"; + case 0xd50277ad: return "tan"; + case 0xd54039cb: return "fegettrapenable"; + case 0xd5adc4b2: return "cpowl"; + case 0xd5d38552: return "_LCaddcc"; + case 0xd612fa16: return "_Sinh"; + case 0xd70df92a: return "_FCaddcr"; + case 0xd7653782: return "sinhf"; + case 0xd76a16da: return "_fmaf4"; + case 0xd8270894: return "fdim"; + case 0xd8c4096d: return "atan2f4"; + case 0xd8d157f5: return "f_expf"; + case 0xd8f79f4c: return "log10"; + case 0xd97852b7: return "sinl"; + case 0xd97ce5d4: return "fesetround"; + case 0xda217d1f: return "atanl"; + case 0xda31fc5d: return "_FFpcomp"; + case 0xdc14974c: return "fmaf4"; + case 0xdc151707: return "_f_log2f"; + case 0xdd8660d2: return "atan2f4fast"; + case 0xdd92118e: return "ceill"; + case 0xdddabb32: return "remainderf"; + case 0xde7833f2: return "_log2f4fast"; + case 0xdece76a6: return "acosf"; + case 0xdfd41734: return "_Exp"; + case 0xdffb4e3c: return "casinl"; + case 0xe1288c47: return "atanhf"; + case 0xe1c71b05: return "ccoshl"; + case 0xe2b596ec: return "ccosf"; + case 0xe2de89e6: return "csqrtf"; + case 0xe2f1d4b2: return "tanh"; + case 0xe31cc0d3: return "_ilogbf4"; + case 0xe3e379b8: return "_expf4fast"; + case 0xe584836c: return "_LPoly"; + case 0xe58fc9b5: return "erfl"; + case 0xe5a0be9f: return "_powf4fast"; + case 0xe5d2293f: return "_Force_raise"; + case 0xe5ea65e8: return "feraiseexcept"; + case 0xe6c1ff41: return "llrint"; + case 0xe769e5cf: return "fmod"; + case 0xe8fcf1f8: return "acosf4fast"; + case 0xe913a166: return "logf4fast"; + case 0xe92f3fb8: return "_f_fmaf"; + case 0xe93abfca: return "ctan"; + case 0xe9ac8223: return "_LCmulcr"; + case 0xe9f501df: return "crealf"; + case 0xea1e83e3: return "f_logf"; + case 0xeac62795: return "_Cdivcc"; + case 0xeac7ca2c: return "ceilf4"; + case 0xebb4e08a: return "hypotf"; + case 0xec43b983: return "_f_sqrtf"; + case 0xec7da0c8: return "_atan2f4fast"; + case 0xed05c265: return "sqrtf4"; + case 0xed9d1ac5: return "f_tanf"; + case 0xeda86c48: return "copysignf4"; + case 0xee0db701: return "_Csubcr"; + case 0xee204ac6: return "f_ceilf"; + case 0xee303936: return "_Dsign"; + case 0xeed82401: return "_f_logf"; + case 0xf0947035: return "ctanhf"; + case 0xf0ab77c1: return "ccoshf"; + case 0xf16568af: return "_FAtan"; + case 0xf19c5e94: return "sincosf4"; + case 0xf1aaa2f8: return "conj"; + case 0xf3bd7d08: return "_cbrtf4fast"; + case 0xf3ec0258: return "round"; + case 0xf4ad6ea8: return "ldexp"; + case 0xf537d837: return "_truncf4"; + case 0xf5cd1e19: return "cosf4"; + case 0xf7844153: return "_f_fmaxf"; + case 0xf83a372f: return "f_fmaf"; + case 0xf95b7769: return "powf4fast"; + case 0xf99da2fc: return "fabsf4"; + case 0xfa28434b: return "log2l"; + case 0xfa765d42: return "_Cdivcr"; + case 0xfa97afbf: return "feupdateenv"; + case 0xfae9e727: return "_f_copysignf"; + case 0xfb6e6213: return "log1pf4fast"; + case 0xfb932a56: return "atan2f"; + case 0xfbb4047a: return "lroundf"; + case 0xfbe88922: return "_FErfc"; + case 0xfcedabc3: return "_fmodf4"; + case 0xfcf08193: return "expf"; + case 0xfdec16e1: return "cacoshl"; + case 0xfe23dbe9: return "_log2f4"; + case 0xff036800: return "cpowf"; + case 0xfffe79bf: return "_LCmulcc"; + } + + if (module == "sys_libstdcxx") switch (fnid) + { + case 0x002c338b: return "_ZNKSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE16do_get_monthnameES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0x002e18d8: return "_ZNSt6locale7_LocimpD0Ev"; + case 0x0091a3fd: return "_ZNKSt6locale9_GetfacetEj"; + case 0x00c3975e: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE5_LockEv"; + case 0x00cf44f7: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basecl"; + case 0x01409785: return "_ZNKSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE7_GetintERS3_S5_iiRi"; + case 0x01aa0cef: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERx"; + case 0x01c4ef01: return "_ZNSt6localeC2ERKS_S1_i"; + case 0x01d9b3f5: return "_ZNSt6localeC1EPKci"; + case 0x01f81190: return "_ZNSt12codecvt_baseD1Ev"; + case 0x020b22f3: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_RSt8ios_basewPKv"; + case 0x02e40598: return "_ZNSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE5_InitERKSt8_Locinfo"; + case 0x03217f6f: return "_ZNSt19istreambuf_iteratorIcSt11char_traitsIcEE5_PeekEv"; + case 0x0339259c: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basecPKv"; + case 0x033c18f4: return "_ZNSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEED1Ev"; + case 0x03cca12f: return "_ZNSt6localeC1ERKS_PKci"; + case 0x040c18ff: return "_ZNKSt7_MpunctIwE16do_decimal_pointEv"; + case 0x045e124a: return "_ZdaPv"; + case 0x0490855d: return "_ZNSt8numpunctIwE7_GetcatEPPKNSt6locale5facetE"; + case 0x055c1462: return "_ZNSt15basic_streambufIcSt11char_traitsIcEED1Ev"; + case 0x05903101: return "_ZNKSt7collateIcE7do_hashEPKcS2_"; + case 0x05a9cef6: return "_ZNSt7_MpunctIcE5_InitERKSt8_Locinfo"; + case 0x05ec37c8: return "_ZSt10_MaklocstrIwEPT_PKcS1_RKSt7_Cvtvec"; + case 0x06bc5b51: return "_ZNKSt7_MpunctIwE16do_positive_signEv"; + case 0x07a3bd16: return "_ZNSt6locale7_LocimpD1Ev"; + case 0x07b6c924: return "_ZTv0_n12_NSt13basic_ostreamIwSt11char_traitsIwEED1Ev"; + case 0x085bff4f: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE5_LockEv"; + case 0x08e1865c: return "_ZNKSt8numpunctIwE16do_thousands_sepEv"; + case 0x09e73a2a: return "_ZNKSt7codecvtIwcSt9_MbstatetE11do_encodingEv"; + case 0x0ba5483c: return "_ZNKSt12codecvt_base11do_encodingEv"; + case 0x0bc08c57: return "_ZNKSt7collateIwE7do_hashEPKwS2_"; + case 0x0bcc1910: return "_ZNSt10ostrstreamD2Ev"; + case 0x0d4290d2: return "_ZNSt12length_errorD0Ev"; + case 0x0d644dca: return "_ZNKSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE11do_get_dateES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0x0e147a9d: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE9pbackfailEi"; + case 0x0e744ef5: return "_ZNSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEED1Ev"; + case 0x0e9698af: return "_ZNSt7codecvtIwcSt9_MbstatetED1Ev"; + case 0x0e9a5554: return "_ZNSt13basic_istreamIwSt11char_traitsIwEED0Ev"; + case 0x0f930fdd: return "_ZNSt13messages_baseD2Ev"; + case 0x0ff264b9: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE4syncEv"; + case 0x10231873: return "_ZNSt13runtime_errorD1Ev"; + case 0x10dc3f6c: return "_ZNSbIwSt11char_traitsIwESaIwEE6appendEjw"; + case 0x113a515f: return "_ZNKSt8messagesIcE7do_openERKSsRKSt6locale"; + case 0x114e9178: return "_ZNSt11logic_errorD0Ev"; + case 0x128cd621: return "_ZNKSt5ctypeIwE10do_scan_isEsPKwS2_"; + case 0x12de5772: return "_ZNKSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_bRSt8ios_baseRNSt5_IosbIiE8_IostateERSs"; + case 0x1374b8c8: return "_ZNSt10moneypunctIcLb0EED1Ev"; + case 0x143048bf: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE7seekoffElNSt5_IosbIiE8_SeekdirENS4_9_OpenmodeE"; + case 0x1474ac53: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERt"; + case 0x14e3faa5: return "_ZNKSt5ctypeIwE9do_narrowEwc"; + case 0x1527fe95: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE4syncEv"; + case 0x1692ae0c: return "_ZNSt6localeD1Ev"; + case 0x16df5ecb: return "_ZNKSt12codecvt_base16do_always_noconvEv"; + case 0x17dd0a4e: return "_ZNKSt7_MpunctIwE16do_negative_signEv"; + case 0x18628537: return "_ZNKSt8numpunctIcE16do_decimal_pointEv"; + case 0x186bcc94: return "_ZNSt8ios_base4InitD1Ev"; + case 0x18a38254: return "_ZNSt10ctype_baseD1Ev"; + case 0x197fc348: return "_ZNSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEED1Ev"; + case 0x1989f59c: return "_ZNSt8ios_base17register_callbackEPFvNS_5eventERS_iEi"; + case 0x19c901ce: return "_ZTv0_n12_NSt9strstreamD0Ev"; + case 0x1a00f889: return "_ZNSt9exceptionD2Ev"; + case 0x1a4f2fa6: return "_ZNSt8ios_base7failureD0Ev"; + case 0x1a7f963c: return "_ZNKSt8numpunctIcE11do_truenameEv"; + case 0x1b266c3d: return "_ZNSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE7_GetcatEPPKNSt6locale5facetE"; + case 0x1b6a7482: return "_ZNKSt7_MpunctIwE13do_neg_formatEv"; + case 0x1b6ad260: return "_ZSt13resetiosflagsNSt5_IosbIiE9_FmtflagsE"; + case 0x1b9b3b5c: return "_ZNSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEED0Ev"; + case 0x1bccd2ca: return "_ZNKSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE7_GetintERS3_S5_iiRi"; + case 0x1c3f1c4f: return "_ZNSt6_MutexD1Ev"; + case 0x1c8083c5: return "_ZNSt12strstreambufD0Ev"; + case 0x1c8405dc: return "_ZNSt7_MpunctIcEC2Ejb"; + case 0x1cf6785d: return "_ZSt9use_facetISt5ctypeIwEERKT_RKSt6locale"; + case 0x1d43fb44: return "_ZSt9use_facetISt8numpunctIwEERKT_RKSt6locale"; + case 0x1ee13e83: return "_ZNSt6locale5facetD0Ev"; + case 0x1f2e9f4e: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE9underflowEv"; + case 0x1f3a9ada: return "_ZNSt12strstreambuf7seekposESt4fposISt9_MbstatetENSt5_IosbIiE9_OpenmodeE"; + case 0x2070a73d: return "_ZNSt6locale7_LocimpC1ERKS0_"; + case 0x207b56fa: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE8_GetffldEPcRS3_S6_RKSt6locale"; + case 0x20a02b6d: return "_ZNSt6locale2idcvjEv"; + case 0x20f7e066: return "_ZNSt10moneypunctIwLb0EED0Ev"; + case 0x21659e45: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE5_FputES3_RSt8ios_basecPKcjjjj"; + case 0x22777290: return "_ZNSs7replaceEjjPKcj"; + case 0x229a0963: return "_ZNKSt5ctypeIwE5do_isEsw"; + case 0x2354ec0a: return "_ZNKSt7codecvtIwcSt9_MbstatetE10do_unshiftERS0_PcS3_RS3_"; + case 0x2356ef16: return "_ZnajRKSt9nothrow_t"; + case 0x23a87483: return "_ZNKSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE11do_get_timeES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0x23ef7642: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE8_GetifldEPcRS3_S6_NSt5_IosbIiE9_FmtflagsERKSt6locale"; + case 0x258359df: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basece"; + case 0x2670b433: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE8_GetffldEPcRS3_S6_RKSt6locale"; + case 0x268c3ea5: return "_ZNKSt7_MpunctIwE13do_pos_formatEv"; + case 0x26e8e1cf: return "_ZNKSt5ctypeIwE5do_isEPKwS2_Ps"; + case 0x273be056: return "_ZNKSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE8_PutmfldES3_bRSt8ios_basecbSs"; + case 0x281f9107: return "_ZTv0_n12_NSiD1Ev"; + case 0x294779fb: return "_ZNSt8ios_base4InitD2Ev"; + case 0x2954d64d: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE9underflowEv"; + case 0x29c11f46: return "_ZNKSt7codecvtIccSt9_MbstatetE9do_lengthERKS0_PKcS5_j"; + case 0x29c90b94: return "_ZNKSt8numpunctIcE16do_thousands_sepEv"; + case 0x2a16469d: return "_ZNSt8ios_base5imbueERKSt6locale"; + case 0x2ac890f4: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERb"; + case 0x2adccb1a: return "_ZNKSt7_MpunctIcE14do_frac_digitsEv"; + case 0x2af79bd6: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE5_IputES3_RSt8ios_basecPcj"; + case 0x2b05b95a: return "_ZNKSt7_MpunctIcE11do_groupingEv"; + case 0x2b88f26e: return "_ZNSt15basic_streambufIwSt11char_traitsIwEED0Ev"; + case 0x2c241d13: return "_ZnajjRKSt9nothrow_t"; + case 0x2c6ce396: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERd"; + case 0x2cf8ea50: return "_ZNKSt7codecvtIwcSt9_MbstatetE16do_always_noconvEv"; + case 0x2d489b47: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE9underflowEv"; + case 0x2d50650f: return "_ZSt9use_facetISt10moneypunctIcLb1EEERKT_RKSt6locale"; + case 0x2d8be7e8: return "_ZNKSt9exception6_RaiseEv"; + case 0x2daa5a42: return "_ZTv0_n12_NSt9strstreamD1Ev"; + case 0x2e2b80c8: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERPv"; + case 0x2e84ebb3: return "_ZNSt8_LocinfoC1EiPKc"; + case 0x2eb5c13a: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE4syncEv"; + case 0x2f29da90: return "_ZNSt12strstreambuf5_TidyEv"; + case 0x2ff8d101: return "_ZNSt6localeC1ERKS_S1_i"; + case 0x30195cf5: return "_ZNKSt8numpunctIcE11do_groupingEv"; + case 0x30ce43d4: return "_ZNSt8numpunctIcED0Ev"; + case 0x30e297ea: return "_ZNSt7_MpunctIcEC2ERKSt8_Locinfojb"; + case 0x316b7a34: return "_ZNSt9exceptionD1Ev"; + case 0x31a81476: return "_ZdlPvj"; + case 0x31b3e5cc: return "_ZNSs5_TidyEbj"; + case 0x3286b855: return "_ZNSt8time_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE7_GetcatEPPKNSt6locale5facetE"; + case 0x332f8409: return "_ZNSt8time_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE7_GetcatEPPKNSt6locale5facetE"; + case 0x336e904e: return "_ZNSdD0Ev"; + case 0x33e04d8e: return "_ZNKSt7collateIwE12do_transformEPKwS2_"; + case 0x34b63588: return "_ZNKSt5ctypeIwE9_DonarrowEwc"; + case 0x34edd72b: return "_ZNSt10moneypunctIwLb0EED1Ev"; + case 0x360f8a4f: return "_ZNSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEED1Ev"; + case 0x3697bbd3: return "_ZNSt8ios_base5_InitEv"; + case 0x36e7826a: return "_ZNSt7collateIcED1Ev"; + case 0x3783acfa: return "_ZTv0_n12_NSt13basic_istreamIwSt11char_traitsIwEED1Ev"; + case 0x38783beb: return "_ZNKSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE11do_get_yearES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0x3933645f: return "_ZNKSt7_MpunctIwE14do_frac_digitsEv"; + case 0x3937f2f8: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basecm"; + case 0x39775ce9: return "_ZNSt11logic_errorD2Ev"; + case 0x3ad12959: return "_ZNSt9basic_iosIcSt11char_traitsIcEE4initEPSt15basic_streambufIcS1_Eb"; + case 0x3bac19dc: return "_ZThn8_NSdD0Ev"; + case 0x3bda45a7: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basecy"; + case 0x3d32a7f4: return "_ZNSt6localeC2EPKci"; + case 0x3da21a90: return "_ZNSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEED1Ev"; + case 0x3e18602a: return "_ZNKSt12codecvt_base13do_max_lengthEv"; + case 0x3eeb7167: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE7_UnlockEv"; + case 0x3f6a6e68: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE9_EndwriteEv"; + case 0x3f9cb259: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERl"; + case 0x3fc2324d: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basecd"; + case 0x409409af: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE6setbufEPci"; + case 0x411b923e: return "_ZSt9use_facetISt8numpunctIcEERKT_RKSt6locale"; + case 0x4148e091: return "_ZNKSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE8_GetmfldERS3_S5_bRSt8ios_base"; + case 0x417f47af: return "_ZSt9use_facetISt10moneypunctIcLb0EEERKT_RKSt6locale"; + case 0x42c40b2f: return "_ZNSt12out_of_rangeD0Ev"; + case 0x45010630: return "_ZNSt10moneypunctIcLb1EED0Ev"; + case 0x4520d6a2: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE5_LockEv"; + case 0x46034d2e: return "_ZNSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEED0Ev"; + case 0x460e5cb7: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE7seekposESt4fposISt9_MbstatetENSt5_IosbIiE9_OpenmodeE"; + case 0x4761783a: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE5imbueERKSt6locale"; + case 0x47aab531: return "_ZNSt7_MpunctIcED0Ev"; + case 0x47e5c318: return "_ZNSt8_LocinfoD2Ev"; + case 0x4827e6be: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERe"; + case 0x48d101ef: return "_ZNKSt8ios_base7failure8_DoraiseEv"; + case 0x493212da: return "_ZNSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEED0Ev"; + case 0x4952490e: return "_ZNSt8ios_base5clearENSt5_IosbIiE8_IostateEb"; + case 0x496c6f50: return "_Getctyptab"; + case 0x49d9ddaf: return "_ZNKSt8numpunctIwE12do_falsenameEv"; + case 0x49da8c5f: return "_ZNKSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_bRSt8ios_baseRNSt5_IosbIiE8_IostateERe"; + case 0x49f7d434: return "_ZNSt8numpunctIwED0Ev"; + case 0x4a40969d: return "_Fac_tidy"; + case 0x4a799510: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERl"; + case 0x4aec14d5: return "_ZNSt12length_errorD1Ev"; + case 0x4aff73cc: return "_ZSt14_Debug_messagePKcS0_"; + case 0x4b1ad744: return "_ZdaPvjRKSt9nothrow_t"; + case 0x4b5a8abc: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE6setbufEPwi"; + case 0x4bc193c7: return "_ZNSt10ostrstreamC2EPciNSt5_IosbIiE9_OpenmodeE"; + case 0x4bda379a: return "_ZNSt8ios_base4InitC1Ev"; + case 0x4bee7ba9: return "_ZNSt8ios_base7failureD1Ev"; + case 0x4cb35e7d: return "_ZNSt9time_baseD1Ev"; + case 0x4cdab0ba: return "_ZNSt7_MpunctIwED0Ev"; + case 0x4daf3fcf: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE6xsgetnEPci"; + case 0x4e34cf83: return "_ZNSbIwSt11char_traitsIwESaIwEE5_GrowEjb"; + case 0x4e5cd916: return "_ZNKSt8numpunctIwE11do_groupingEv"; + case 0x4ec89bf8: return "_ZNSt7collateIcE7_GetcatEPPKNSt6locale5facetE"; + case 0x4ef0eb8e: return "_ZNSt12strstreambuf7seekoffElNSt5_IosbIiE8_SeekdirENS1_9_OpenmodeE"; + case 0x4fde96de: return "_ZNSt15basic_streambufIwSt11char_traitsIwEED1Ev"; + case 0x5015b8d3: return "_ZSt7_FiopenPKwNSt5_IosbIiE9_OpenmodeEi"; + case 0x50b34c09: return "_ZNKSt9exception4whatEv"; + case 0x5102ac61: return "_ZNKSt7_MpunctIwE14do_curr_symbolEv"; + case 0x5119680b: return "_ZNSt8_LocinfoD1Ev"; + case 0x5127dcd1: return "_ZNSsC1Ev"; + case 0x522b0457: return "_ZNSt10istrstreamD0Ev"; + case 0x52330fbd: return "_ZNSt13runtime_errorD0Ev"; + case 0x5298ef8e: return "_ZdaPvRKSt9nothrow_t"; + case 0x5333bdc9: return "_ZNKSt13runtime_error4whatEv"; + case 0x53693d40: return "_ZSt11setiosflagsNSt5_IosbIiE9_FmtflagsE"; + case 0x5438d7d8: return "_ZdaPvS_"; + case 0x550255f7: return "_ZNKSt7codecvtIccSt9_MbstatetE10do_unshiftERS0_PcS3_RS3_"; + case 0x55481e6f: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE9showmanycEv"; + case 0x5560c79e: return "_ZNSdD1Ev"; + case 0x55b3ebf2: return "_ZNSt9strstreamC2EPciNSt5_IosbIiE9_OpenmodeE"; + case 0x563fd2be: return "_ZNSt6localeC2ERKS_PKci"; + case 0x5656ccff: return "_ZNKSt7collateIcE10do_compareEPKcS2_S2_S2_"; + case 0x56d3d4f0: return "_ZNSt9bad_allocD1Ev"; + case 0x56fac416: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERe"; + case 0x577c2695: return "_ZNSt6_Mutex5_LockEv"; + case 0x57ef52f0: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE7_UnlockEv"; + case 0x581fc95b: return "_ZNSt5ctypeIcED0Ev"; + case 0x58fad1c1: return "_ZNSt5ctypeIwE7_GetcatEPPKNSt6locale5facetE"; + case 0x5949408e: return "_ZNSt8ios_base5_TidyEv"; + case 0x59c77266: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERd"; + case 0x5a3ad4bd: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERf"; + case 0x5a5a9107: return "_ZNSt6localeC2Ev"; + case 0x5a6e4e50: return "_ZNSt6locale7_Locimp9_MakewlocERKSt8_LocinfoiPS0_PKS_"; + case 0x5a898327: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE7seekoffElNSt5_IosbIiE8_SeekdirENS4_9_OpenmodeE"; + case 0x5adf9060: return "_ZNKSt5ctypeIcE8do_widenEPKcS2_Pc"; + case 0x5b71b85d: return "_ZNSt19istreambuf_iteratorIwSt11char_traitsIwEE4_IncEv"; + case 0x5c15972f: return "_ZNSt13basic_ostreamIwSt11char_traitsIwEED1Ev"; + case 0x5ca98e4a: return "_ZNSt13basic_filebufIcSt11char_traitsIcEED0Ev"; + case 0x5e1f2d37: return "_ZNKSt9exception8_DoraiseEv"; + case 0x5e55ab8c: return "_ZSt10_GetloctxtIwSt19istreambuf_iteratorIwSt11char_traitsIwEEEiRT0_S5_jPKT_"; + case 0x5ed4fb7a: return "_ZTv0_n12_NSt13basic_istreamIwSt11char_traitsIwEED0Ev"; + case 0x604fec95: return "_ZNSt12out_of_rangeD1Ev"; + case 0x605131d5: return "_ZNSt8_LocinfoC1EPKc"; + case 0x6051c802: return "_ZNSt7codecvtIccSt9_MbstatetED0Ev"; + case 0x608abbb5: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE5uflowEv"; + case 0x61119152: return "_ZNSt6locale5_InitEv"; + case 0x61248c80: return "_ZNKSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE13do_date_orderEv"; + case 0x61a23009: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE5_FputES3_RSt8ios_basewPKcjjjj"; + case 0x61f55c30: return "_ZNKSt5ctypeIcE8do_widenEc"; + case 0x629b8531: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE5_IputES3_RSt8ios_basewPcj"; + case 0x62d6bf82: return "_ZNSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEED1Ev"; + case 0x62f52bb0: return "_ZNSt7_MpunctIwEC2ERKSt8_Locinfojb"; + case 0x635166c3: return "_ZNKSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_bRSt8ios_basewe"; + case 0x63a2b2cc: return "_ZNKSt8messagesIcE8do_closeEi"; + case 0x643235cf: return "_ZNSt9strstreamD1Ev"; + case 0x6437a975: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERt"; + case 0x643e67f4: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERPv"; + case 0x6463d9ea: return "_ZNKSt8messagesIwE6do_getEiiiRKSbIwSt11char_traitsIwESaIwEE"; + case 0x64ce0374: return "_ZNSbIwSt11char_traitsIwESaIwEE7replaceEjjPKwj"; + case 0x64ed868e: return "_ZSt9terminatev"; + case 0x6500d2d5: return "_ZNSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE7_GetcatEPPKNSt6locale5facetE"; + case 0x65f19631: return "_ZTv0_n12_NSiD0Ev"; + case 0x660882e8: return "_ZNSt6localeC1Ev"; + case 0x667d741b: return "_ZNSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEED0Ev"; + case 0x668b31c6: return "_ZNSs5_GrowEjb"; + case 0x66f39adb: return "_ZNSt8numpunctIwED1Ev"; + case 0x66fcc6f4: return "_ZNSt8messagesIwE7_GetcatEPPKNSt6locale5facetE"; + case 0x67948307: return "_ZNKSt7codecvtIwcSt9_MbstatetE9do_lengthERKS0_PKcS5_j"; + case 0x67c09257: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERx"; + case 0x67edde2f: return "_ZdlPvjRKSt9nothrow_t"; + case 0x67fbabf0: return "_ZNKSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE14do_get_weekdayES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0x683ca70a: return "_ZNKSt12_String_base5_XlenEv"; + case 0x6863452e: return "_ZNSt6locale5facetD1Ev"; + case 0x6929318d: return "_ZNSs6assignERKSsjj"; + case 0x696b47f2: return "_ZNKSt7_MpunctIcE13do_neg_formatEv"; + case 0x6a6b90c9: return "_ZSt15set_new_handlerPFvvE"; + case 0x6adc320a: return "_ZNSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEED0Ev"; + case 0x6b493669: return "_ZSt7setbasei"; + case 0x6b913d53: return "_ZNSs6insertEjjc"; + case 0x6c19db26: return "_ZNKSt7_MpunctIcE16do_thousands_sepEv"; + case 0x6c386f54: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE7seekposESt4fposISt9_MbstatetENSt5_IosbIiE9_OpenmodeE"; + case 0x6c8dc459: return "_ZNKSt8bad_cast4whatEv"; + case 0x6cb1a335: return "_ZNSt6locale5facet7_DecrefEv"; + case 0x6d483b7a: return "_ZNSt12strstreambuf9pbackfailEi"; + case 0x6daed882: return "_ZNSt8ios_baseD0Ev"; + case 0x6dbbb9de: return "_ZNKSt5ctypeIcE10do_toupperEc"; + case 0x6e0bf85d: return "_ZTv0_n12_NSt10istrstreamD1Ev"; + case 0x6e4a84c1: return "_ZNSt5ctypeIcED1Ev"; + case 0x6e61426d: return "_ZNSt13basic_filebufIwSt11char_traitsIwEED1Ev"; + case 0x6f1945fc: return "_ZNSoD1Ev"; + case 0x6fe060a0: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE7seekposESt4fposISt9_MbstatetENSt5_IosbIiE9_OpenmodeE"; + case 0x7008e209: return "_ZNKSt5ctypeIwE10do_toupperEw"; + case 0x708cf940: return "_ZNKSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE11do_get_dateES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0x709ab035: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE6setbufEPci"; + case 0x7142ad20: return "_ZNKSt7_MpunctIcE16do_decimal_pointEv"; + case 0x718977c5: return "_ZNSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE7_GetcatEPPKNSt6locale5facetE"; + case 0x736c5f22: return "_ZNSoD0Ev"; + case 0x74a39b4f: return "_ZThn8_NSt9strstreamD1Ev"; + case 0x753c71db: return "_ZNKSt7_MpunctIcE13do_pos_formatEv"; + case 0x75824de0: return "_ZNSt6_MutexC1Ev"; + case 0x75975eb4: return "_ZNSsC1EPKc"; + case 0x75a0617c: return "_ZNKSt7_MpunctIwE11do_groupingEv"; + case 0x764ceaa4: return "_ZNSt10ostrstreamD0Ev"; + case 0x767a4e70: return "_ZNSt6_WinitC2Ev"; + case 0x76db6974: return "_ZNSt7codecvtIwcSt9_MbstatetED0Ev"; + case 0x76de9b0f: return "_ZNSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEED1Ev"; + case 0x76e846b2: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE6xsputnEPKwi"; + case 0x77c1d3a9: return "_ZNKSt13runtime_error8_DoraiseEv"; + case 0x7882e64e: return "_ZNSt7collateIwED0Ev"; + case 0x78a142d0: return "_ZSt7_FiopenPKcNSt5_IosbIiE9_OpenmodeEi"; + case 0x79a415f8: return "_ZNSbIwSt11char_traitsIwESaIwEE6insertEjjw"; + case 0x79ad3575: return "_ZTv0_n12_NSoD1Ev"; + case 0x7a180518: return "_ZNSt10money_baseD0Ev"; + case 0x7b1db41e: return "_ZNSt6locale7_AddfacEPNS_5facetEjj"; + case 0x7b5fce95: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE6setbufEPwi"; + case 0x7c391411: return "_ZNSt10moneypunctIcLb0EED0Ev"; + case 0x7cdbda48: return "_ZNSt7collateIcED0Ev"; + case 0x7d23aa12: return "_ZNSt10moneypunctIwLb0EE7_GetcatEPPKNSt6locale5facetE"; + case 0x7da7fdb1: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_RSt8ios_basewy"; + case 0x7e7ac30e: return "_ZNSt6locale5emptyEv"; + case 0x7ebad3f0: return "_ZNKSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE8_PutmfldES3_bRSt8ios_basewbSbIwS2_SaIwEE"; + case 0x7fe08910: return "_ZNSt10moneypunctIcLb0EE7_GetcatEPPKNSt6locale5facetE"; + case 0x7ff35597: return "_ZNSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE7_GetcatEPPKNSt6locale5facetE"; + case 0x8006c4ec: return "_ZNSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEED0Ev"; + case 0x8044f596: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE5_LockEv"; + case 0x81027e75: return "_ZNSt7_MpunctIwE5_InitERKSt8_Locinfo"; + case 0x816aebc3: return "_ZNSt9bad_allocD0Ev"; + case 0x823759d3: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_RSt8ios_basewl"; + case 0x8341b529: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE8overflowEi"; + case 0x83b2cc6f: return "_Znwj"; + case 0x83bca135: return "_ZNKSt11logic_error4whatEv"; + case 0x83cba890: return "_ZNSt6locale5facetD2Ev"; + case 0x84023c03: return "_ZSt12setprecisioni"; + case 0x854bc7c7: return "_ZNSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEED0Ev"; + case 0x85b3c6da: return "_ZNKSt8_Locinfo7_GetcvtEv"; + case 0x85ba062f: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE7_UnlockEv"; + case 0x867956a4: return "_ZNSt9basic_iosIcSt11char_traitsIcEED1Ev"; + case 0x868531a3: return "_ZdaPvj"; + case 0x86c66cfc: return "_ZNSsD1Ev"; + case 0x871506ea: return "_ZNSbIwSt11char_traitsIwESaIwEE6assignERKS2_jj"; + case 0x8729f617: return "_ZNSt10ostrstreamC1EPciNSt5_IosbIiE9_OpenmodeE"; + case 0x87b1f5eb: return "_ZNSt9exceptionD0Ev"; + case 0x88052736: return "_ZTv0_n12_NSt10ostrstreamD0Ev"; + case 0x883e1f16: return "_ZNKSt11logic_error8_DoraiseEv"; + case 0x884b021b: return "_ZNKSt5ctypeIwE8_DowidenEc"; + case 0x8a665143: return "_ZNSt8_Locinfo8_AddcatsEiPKc"; + case 0x8a85d688: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_RSt8ios_basewx"; + case 0x8bfd4395: return "_ZNSt9basic_iosIwSt11char_traitsIwEE4initEPSt15basic_streambufIwS1_Eb"; + case 0x8c2e6d06: return "_ZNKSt8messagesIwE7do_openERKSsRKSt6locale"; + case 0x8c3afd4c: return "_ZSt10unexpectedv"; + case 0x8c6b8d39: return "_ZNSt13basic_filebufIcSt11char_traitsIcEED1Ev"; + case 0x8cda1f3b: return "_ZSt10_GetloctxtIcSt19istreambuf_iteratorIcSt11char_traitsIcEEEiRT0_S5_jPKT_"; + case 0x8d4e266b: return "_ZNKSt8_Locinfo9_GetctypeEv"; + case 0x8fa764f3: return "_ZNSt6_WinitC1Ev"; + case 0x900d1fa4: return "_ZNSt8time_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEED0Ev"; + case 0x903afa37: return "_ZTv0_n12_NSt13basic_ostreamIwSt11char_traitsIwEED0Ev"; + case 0x904dbd32: return "_ZNSt6locale7_LocimpC1Eb"; + case 0x9111ec36: return "_ZNSt13messages_baseD0Ev"; + case 0x91959ed6: return "_ZNKSt5ctypeIcE9do_narrowEcc"; + case 0x91b0e37e: return "_ZSt14set_unexpectedPFvvE"; + case 0x9268d6e7: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERj"; + case 0x928fbe36: return "_ZTv0_n12_NSdD1Ev"; + case 0x93c638e9: return "_ZNSt19istreambuf_iteratorIwSt11char_traitsIwEE5_PeekEv"; + case 0x94c49383: return "_ZdlPvS_"; + case 0x94fa1f5b: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE5uflowEv"; + case 0x95082493: return "_ZNKSt8messagesIcE6do_getEiiiRKSs"; + case 0x95b43c9d: return "_ZNSt6locale7_LocimpD2Ev"; + case 0x96634e42: return "_ZNKSt9bad_alloc4whatEv"; + case 0x96bc2578: return "_Znajj"; + case 0x97911f5f: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE5uflowEv"; + case 0x984ce3d7: return "_ZNSt8numpunctIcED1Ev"; + case 0x9891bf45: return "_ZNKSt7_MpunctIwE16do_thousands_sepEv"; + case 0x9a194306: return "_ZNSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE5_InitERKSt8_Locinfo"; + case 0x9a449047: return "_ZNSt7_MpunctIwEC2Ejb"; + case 0x9aa7a8b3: return "_ZNSt10istrstreamD2Ev"; + case 0x9afa5d71: return "_ZNSt10money_baseD2Ev"; + case 0x9b5358f9: return "_ZNKSt7_MpunctIcE16do_positive_signEv"; + case 0x9c40d1f9: return "_ZNKSt8numpunctIwE16do_decimal_pointEv"; + case 0x9c486668: return "_ZNSt6locale7_Locimp9_MakexlocERKSt8_LocinfoiPS0_PKS_"; + case 0x9cb73ee0: return "_ZSt6_ThrowRKSt9exception"; + case 0x9cfc0eaf: return "_ZNSiD1Ev"; + case 0x9d6a8167: return "_ZNSbIwSt11char_traitsIwESaIwEE5eraseEjj"; + case 0x9dbbe07d: return "_ZNKSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE8_GetmfldERS3_S5_bRSt8ios_base"; + case 0x9dc040e4: return "_Deletegloballocale"; + case 0x9dcb4bcb: return "_ZNKSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE14do_get_weekdayES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0x9e741d47: return "_ZNSsC1ERKSs"; + case 0x9ec88ae6: return "_ZNKSt5ctypeIwE10do_tolowerEPwPKw"; + case 0x9ef60bf3: return "_ZNKSt5ctypeIwE10do_tolowerEw"; + case 0x9f528cd3: return "_ZNKSt7codecvtIccSt9_MbstatetE6do_outERS0_PKcS4_RS4_PcS6_RS6_"; + case 0x9f959451: return "_ZNSt13basic_istreamIwSt11char_traitsIwEED1Ev"; + case 0x9facb533: return "_ZNSt13messages_baseD1Ev"; + case 0x9fd2eea9: return "_ZNSt8_LocinfoC2EiPKc"; + case 0xa1c6fc55: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE7_UnlockEv"; + case 0xa1de25c2: return "_ZTv0_n12_NSt10ostrstreamD1Ev"; + case 0xa22d5dda: return "_ZNSt8messagesIcED0Ev"; + case 0xa2fd0ec5: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE9pbackfailEi"; + case 0xa35033e8: return "_ZNKSt5ctypeIwE8do_widenEPKcS2_Pw"; + case 0xa37c3e51: return "_ZNKSt5ctypeIwE8do_widenEc"; + case 0xa3f5c3b2: return "_ZNSt9strstreamD2Ev"; + case 0xa433147a: return "_ZNSt8messagesIcE7_GetcatEPPKNSt6locale5facetE"; + case 0xa464c70a: return "_ZNKSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_bRSt8ios_basewRKSbIwS2_SaIwEE"; + case 0xa4f6a919: return "_ZThn8_NSdD1Ev"; + case 0xa5306edb: return "_ZNSt10moneypunctIwLb1EED1Ev"; + case 0xa562099c: return "_ZNSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEED1Ev"; + case 0xa700bc7d: return "_ZNKSt7codecvtIwcSt9_MbstatetE6do_outERS0_PKwS4_RS4_PcS6_RS6_"; + case 0xa74e5a27: return "_ZNKSt6localeeqERKS_"; + case 0xa79c4516: return "_ZNSt15basic_streambufIcSt11char_traitsIcEED0Ev"; + case 0xa8ece2e0: return "_ZSt9use_facetISt10moneypunctIwLb0EEERKT_RKSt6locale"; + case 0xa8f64fdb: return "_ZNKSt5ctypeIcE10do_tolowerEPcPKc"; + case 0xa90c4ff2: return "_ZNSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE7_GetcatEPPKNSt6locale5facetE"; + case 0xa9116516: return "_ZNSs6appendEjc"; + case 0xa94be0fa: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE9_EndwriteEv"; + case 0xa957adcc: return "_ZNKSt5ctypeIcE9do_narrowEPKcS2_cPc"; + case 0xa9e5bb16: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERm"; + case 0xaa520d9f: return "_ZNSt6locale7_Locimp7_AddfacEPNS_5facetEj"; + case 0xaae64804: return "_ZNSt8ios_base8_FindarrEi"; + case 0xab211d97: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basecb"; + case 0xab5832fd: return "_ZNSt10money_baseD1Ev"; + case 0xabd92bcc: return "_ZNSt7collateIwE7_GetcatEPPKNSt6locale5facetE"; + case 0xabdc2b49: return "_ZNSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE7_GetcatEPPKNSt6locale5facetE"; + case 0xac6c23c0: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERy"; + case 0xad3777a2: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE8overflowEi"; + case 0xad382a99: return "_ZdlPvRKSt9nothrow_t"; + case 0xad6d839f: return "_ZNSt12codecvt_baseD0Ev"; + case 0xad6dbac2: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERm"; + case 0xadc2263b: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE6xsputnEPKci"; + case 0xae7d042f: return "_ZNSt7codecvtIwcSt9_MbstatetE7_GetcatEPPKNSt6locale5facetE"; + case 0xaea59ceb: return "_ZNSt10ctype_baseD0Ev"; + case 0xb0c185b7: return "_ZNSt10moneypunctIcLb1EE7_GetcatEPPKNSt6locale5facetE"; + case 0xb0e7c2f3: return "_ZNSiD0Ev"; + case 0xb1550b3c: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basecx"; + case 0xb1ac1fa3: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE6xsgetnEPwi"; + case 0xb1d696f7: return "_ZNKSt8numpunctIcE12do_falsenameEv"; + case 0xb326f699: return "_ZNKSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_bRSt8ios_basece"; + case 0xb33ef042: return "_ZNSt8bad_castD0Ev"; + case 0xb3f05af3: return "_ZNKSt7collateIcE12do_transformEPKcS2_"; + case 0xb4352488: return "_ZNKSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_bRSt8ios_basecRKSs"; + case 0xb4a8791f: return "_ZNSt8time_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEED1Ev"; + case 0xb509ab64: return "_ZNSt10moneypunctIcLb1EED1Ev"; + case 0xb53fa02e: return "_ZnwjjRKSt9nothrow_t"; + case 0xb6a4d760: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE7seekposESt4fposISt9_MbstatetENSt5_IosbIiE9_OpenmodeE"; + case 0xb6a7ba7a: return "_ZNSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEED0Ev"; + case 0xb74f7b8f: return "_ZNSt6locale7_LocimpC2ERKS0_"; + case 0xb7dcbfdd: return "__Setgloballocale"; + case 0xb80ca215: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE5imbueERKSt6locale"; + case 0xb87c4b43: return "_ZNSt12strstreambuf6freezeEb"; + case 0xb8836b50: return "_ZNSt9exception18_Set_raise_handlerEPFvRKS_E"; + case 0xb8ec13a5: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_RSt8ios_basewb"; + case 0xb9a2282d: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE8overflowEi"; + case 0xba0b6300: return "_ZNSt9basic_iosIwSt11char_traitsIwEED1Ev"; + case 0xba85ce08: return "_ZNSt12strstreambufD2Ev"; + case 0xbaa15803: return "_ZSt4setwi"; + case 0xbb4599c5: return "_ZNSt11logic_errorD1Ev"; + case 0xbb712718: return "_ZnwjRKSt9nothrow_t"; + case 0xbc5ad91c: return "_ZNKSt7collateIwE10do_compareEPKwS2_S2_S2_"; + case 0xbd140e12: return "_ZNKSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE11do_get_timeES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0xbd316983: return "_ZNSt8numpunctIcE5_InitERKSt8_Locinfo"; + case 0xbd35830b: return "_ZdaPvjS_"; + case 0xbd58ea5a: return "_ZNSt19ostreambuf_iteratorIwSt11char_traitsIwEEaSEw"; + case 0xbda26024: return "_ZNSt9strstreamD0Ev"; + case 0xbf9c3609: return "_ZNKSt5ctypeIwE10do_toupperEPwPKw"; + case 0xc013acd8: return "_ZNSt8ios_base8_CallfnsENS_5eventE"; + case 0xc06a4cd8: return "_ZNSt7_MpunctIwED1Ev"; + case 0xc22cebd8: return "_ZNSt8messagesIwED1Ev"; + case 0xc3d24eb3: return "_ZNSt9basic_iosIwSt11char_traitsIwEED0Ev"; + case 0xc41d676d: return "_ZNSt9time_baseD2Ev"; + case 0xc4c7993b: return "_ZNSbIwSt11char_traitsIwESaIwEE5_TidyEbj"; + case 0xc53ab1c0: return "_ZNSt8numpunctIwE5_InitERKSt8_Locinfo"; + case 0xc5977986: return "_ZNSt8ios_base7_AddstdEv"; + case 0xc612a38e: return "_ZNSt6_WinitD1Ev"; + case 0xc6e09225: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE5_InitEPSt6_FiletNS2_7_InitflE"; + case 0xc6ea0fd0: return "_ZNSt6locale7classicEv"; + case 0xc6f18e84: return "_ZNKSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_bRSt8ios_baseRNSt5_IosbIiE8_IostateERSbIwS2_SaIwEE"; + case 0xc79278ec: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE5imbueERKSt6locale"; + case 0xc7931798: return "_ZNKSt12_String_base5_XranEv"; + case 0xc7d0ee0c: return "_ZNKSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE16do_get_monthnameES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0xc862f7c8: return "_ZNSt12strstreambuf8overflowEi"; + case 0xcac83a05: return "_ZNSt6locale7_LocimpC2Eb"; + case 0xcb7d00a4: return "_ZNSt6_WinitD2Ev"; + case 0xcb82e0dc: return "_ZSt13set_terminatePFvvE"; + case 0xcbe74ad3: return "_ZNKSt8messagesIwE8do_closeEi"; + case 0xcc79f55d: return "_ZNKSt7_MpunctIcE16do_negative_signEv"; + case 0xccf14bd5: return "_ZNSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE7_GetcatEPPKNSt6locale5facetE"; + case 0xcd33ed4f: return "_ZNSbIwSt11char_traitsIwESaIwEEC1Ev"; + case 0xcdafdf19: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE9showmanycEv"; + case 0xce653b6c: return "_ZNSt6_MutexC2Ev"; + case 0xce6705c3: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE8_GetifldEPcRS3_S6_NSt5_IosbIiE9_FmtflagsERKSt6locale"; + case 0xce8c6abc: return "_ZNSt8ios_base4InitC2Ev"; + case 0xcf9b4d80: return "_ZNSt10moneypunctIwLb1EED0Ev"; + case 0xd05ea37c: return "_ZNKSt19istreambuf_iteratorIwSt11char_traitsIwEEdeEv"; + case 0xd1b043b7: return "_ZSt10_MaklocchrIwET_cPS0_RKSt7_Cvtvec"; + case 0xd1ee6195: return "_ZNKSt8time_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basecPKSt2tmcc"; + case 0xd2f9d93d: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_RSt8ios_basewe"; + case 0xd356aefd: return "_ZNSt6_Mutex7_UnlockEv"; + case 0xd38f4018: return "_ZSt11_MaklocbyteIwEcT_RKSt7_Cvtvec"; + case 0xd4838fbd: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_RSt8ios_basewm"; + case 0xd4ba5b31: return "_ZNSt8_LocinfoC2EPKc"; + case 0xd5244a29: return "_ZNSt10moneypunctIwLb1EE7_GetcatEPPKNSt6locale5facetE"; + case 0xd5c5ee3d: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERj"; + case 0xd6ee1090: return "_ZNKSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_bRSt8ios_baseRNSt5_IosbIiE8_IostateERe"; + case 0xd73321ed: return "_ZNSt10ostrstreamD1Ev"; + case 0xd76b2e07: return "_ZNKSt7codecvtIwcSt9_MbstatetE13do_max_lengthEv"; + case 0xd78efcc3: return "_ZNSt12strstreambuf9underflowEv"; + case 0xd7bc220d: return "_ZNSt8time_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEED1Ev"; + case 0xd7d92e51: return "_ZNSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEED0Ev"; + case 0xd830252c: return "_ZNSt12strstreambuf5_InitEiPcS0_i"; + case 0xd84b3689: return "_ZdlPv"; + case 0xd8aeb94a: return "_ZNSt8messagesIcED1Ev"; + case 0xd8b23008: return "_ZNSt8ios_baseD2Ev"; + case 0xd93d52b1: return "_ZNSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEED1Ev"; + case 0xd9a12c5e: return "_ZNKSt5ctypeIcE10do_toupperEPcPKc"; + case 0xd9d8af82: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE8overflowEi"; + case 0xda1088ce: return "_ZNSt6locale5facet7_IncrefEv"; + case 0xda1b159a: return "_ZNSt6_MutexD2Ev"; + case 0xda5469b3: return "_ZNSt9time_baseD0Ev"; + case 0xdab0a910: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE9pbackfailEi"; + case 0xdaf3996f: return "_ZNSt6locale6globalERKS_"; + case 0xdb5eae26: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE5_InitEPSt6_FiletNS2_7_InitflE"; + case 0xdc0c889c: return "_ZNSt8ios_base7copyfmtERKS_"; + case 0xdc4d7540: return "_ZNSt5ctypeIwED1Ev"; + case 0xdc65ab00: return "_ZNSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEED1Ev"; + case 0xdc981b5f: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE9underflowEv"; + case 0xdd8b1d47: return "_ZNSs5eraseEjj"; + case 0xdefe3230: return "_ZNSt8ios_baseD1Ev"; + case 0xdf1e09e1: return "_ZNKSt5ctypeIwE9do_narrowEPKwS2_cPc"; + case 0xdf7edb4d: return "_ZSt9use_facetISt10moneypunctIwLb1EEERKT_RKSt6locale"; + case 0xe177fd02: return "_ZNSt7_MpunctIcED2Ev"; + case 0xe196beab: return "_ZNSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEED0Ev"; + case 0xe206c08f: return "_ZNSt13basic_filebufIwSt11char_traitsIwEED0Ev"; + case 0xe2b2ac5a: return "_ZNSt6locale5facet9_RegisterEv"; + case 0xe3edd790: return "_ZNSt8bad_castD1Ev"; + case 0xe528a368: return "_ZNKSt7_MpunctIcE14do_curr_symbolEv"; + case 0xe54f1fe0: return "_ZNKSt9bad_alloc8_DoraiseEv"; + case 0xe5e1dcbc: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE5imbueERKSt6locale"; + case 0xe6547e35: return "_ZNSt8messagesIwED0Ev"; + case 0xe667985a: return "_ZNSt8time_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEED0Ev"; + case 0xe75f6e21: return "_ZNKSt12length_error8_DoraiseEv"; + case 0xe7d8449e: return "_ZdlPvjS_"; + case 0xe82a422d: return "_ZNKSt8numpunctIwE11do_truenameEv"; + case 0xe8691be5: return "_ZNSt5ctypeIwED0Ev"; + case 0xe8c15f8a: return "_ZNSt7_MpunctIwED2Ev"; + case 0xe9d7a4ae: return "_ZNKSt8time_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_RSt8ios_basewPKSt2tmcc"; + case 0xeb76301c: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE9pbackfailEi"; + case 0xebd4b51d: return "_ZNKSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE11do_get_yearES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0xece969c0: return "_ZTv0_n12_NSt10istrstreamD0Ev"; + case 0xed3da02b: return "_Znwjj"; + case 0xee853baf: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE4syncEv"; + case 0xef62751c: return "_ZNKSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE13do_date_orderEv"; + case 0xef6f90d8: return "_ZNKSt5ctypeIwE11do_scan_notEsPKwS2_"; + case 0xef959a6d: return "_ZThn8_NSt9strstreamD0Ev"; + case 0xf001a741: return "_ZNSt12strstreambufD1Ev"; + case 0xf00401d2: return "_ZNSt9basic_iosIcSt11char_traitsIcEED0Ev"; + case 0xf01deff8: return "_ZNKSt7codecvtIwcSt9_MbstatetE5do_inERS0_PKcS4_RS4_PwS6_RS6_"; + case 0xf05df017: return "_ZNSt5ctypeIcE7_GetcatEPPKNSt6locale5facetE"; + case 0xf127e816: return "_ZNSt10istrstreamD1Ev"; + case 0xf1543f02: return "_ZNKSt8_Locinfo8_GetcollEv"; + case 0xf1c86c92: return "_ZNKSt12out_of_range8_DoraiseEv"; + case 0xf1cff87d: return "_ZNSt10ctype_baseD2Ev"; + case 0xf2b9ab86: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERf"; + case 0xf30d3407: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_RSt8ios_basewd"; + case 0xf51dc289: return "_ZNSt7codecvtIccSt9_MbstatetED1Ev"; + case 0xf53021e0: return "_ZNSt8bad_castC1Ev"; + case 0xf5825c7d: return "_ZNSt7collateIwED1Ev"; + case 0xf584de56: return "_ZNSt6locale7_Locimp8_MakelocERKSt8_LocinfoiPS0_PKS_"; + case 0xf58e83a5: return "_Znaj"; + case 0xf67a7e17: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE5uflowEv"; + case 0xf73f6afc: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE7seekoffElNSt5_IosbIiE8_SeekdirENS4_9_OpenmodeE"; + case 0xf7845d1c: return "_ZNSt7_MpunctIcED1Ev"; + case 0xf7ba51fd: return "_ZNSt13basic_ostreamIwSt11char_traitsIwEED0Ev"; + case 0xf83e8d95: return "_ZNKSt5ctypeIcE10do_tolowerEc"; + case 0xf9ff46a1: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE7seekoffElNSt5_IosbIiE8_SeekdirENS4_9_OpenmodeE"; + case 0xfb36c588: return "_ZNSt9strstreamC1EPciNSt5_IosbIiE9_OpenmodeE"; + case 0xfc563813: return "_ZNKSt7codecvtIccSt9_MbstatetE5do_inERS0_PKcS4_RS4_PcS6_RS6_"; + case 0xfc825dda: return "_ZNSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE7_GetcatEPPKNSt6locale5facetE"; + case 0xfe468b7a: return "_ZTv0_n12_NSdD0Ev"; + case 0xfeb4107c: return "_ZNSt12codecvt_baseD2Ev"; + case 0xfefd7d3a: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERy"; + case 0xffaf3218: return "_ZTv0_n12_NSoD0Ev"; + case 0xfff6ef55: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERb"; + } + + if (module == "sysPrxForUser") switch (fnid) + { + case 0x0341bb97: return "sys_prx_get_module_id_by_address"; + case 0x04e83d2c: return "_sys_strncmp"; + case 0x052d29a6: return "_sys_strcat"; + case 0x05c65656: return "sys_mempool_try_allocate_block"; + case 0x0618936b: return "_sys_vsnprintf"; + case 0x06574237: return "_sys_snprintf"; + case 0x1573dc3f: return "sys_lwmutex_lock"; + case 0x191f0c4a: return "_sys_strrchr"; + case 0x1ae10b92: return "_sys_spu_printf_attach_thread"; + case 0x1bc200f4: return "sys_lwmutex_unlock"; + case 0x1c9a942c: return "sys_lwcond_destroy"; + case 0x1ca525a2: return "_sys_strncasecmp"; + case 0x1ed454ce: return "sys_spu_elf_get_information"; + case 0x24a1ea07: return "sys_ppu_thread_create"; + case 0x25596f51: return "sys_mempool_get_count"; + case 0x26090058: return "sys_prx_load_module"; + case 0x27427742: return "_sys_memmove"; + case 0x2a6d9d51: return "sys_lwcond_wait"; + case 0x2c847572: return "_sys_process_atexitspawn"; + case 0x2d36462b: return "_sys_strlen"; + case 0x2f85c0ef: return "sys_lwmutex_create"; + case 0x3172759d: return "sys_game_get_temperature"; + case 0x318f17e1: return "_sys_memalign"; + case 0x350d454e: return "sys_ppu_thread_get_id"; + case 0x35168520: return "_sys_heap_malloc"; + case 0x3bd53c7b: return "_sys_memchr"; + case 0x3dd4a957: return "sys_ppu_thread_register_atexit"; + case 0x409ad939: return "sys_mmapper_free_memory"; + case 0x42b23552: return "sys_prx_register_library"; + case 0x44265c08: return "_sys_heap_memalign"; + case 0x459b4393: return "_sys_strcmp"; + case 0x45fe2fce: return "_sys_spu_printf_initialize"; + case 0x4643ba6e: return "sys_mmapper_unmap_memory"; + case 0x4a071d98: return "sys_interrupt_thread_disestablish"; + case 0x4b2f301a: return "_sys_tolower"; + case 0x5267cb35: return "sys_spinlock_unlock"; + case 0x52aadadf: return "sys_lwcond_signal_to"; + case 0x5fdfb2fe: return "_sys_spu_printf_detach_group"; + case 0x608212fc: return "sys_mempool_free_block"; + case 0x620e35a7: return "sys_game_get_system_sw_version"; + case 0x67f9fedb: return "sys_game_process_exitspawn2"; + case 0x68b9b011: return "_sys_memset"; + case 0x6bf66ea7: return "_sys_memcpy"; + case 0x6e05231d: return "sys_game_watchdog_stop"; + case 0x70258515: return "sys_mmapper_allocate_memory_from_container"; + case 0x71a8472a: return "sys_get_random_number"; + case 0x722a0254: return "sys_spinlock_trylock"; + case 0x74311398: return "sys_prx_get_my_module_id"; + case 0x744680a2: return "sys_initialize_tls"; + case 0x7498887b: return "_sys_strchr"; + case 0x791b9219: return "_sys_vsprintf"; + case 0x80fb0c19: return "sys_prx_stop_module"; + case 0x8461e528: return "sys_time_get_system_time"; + case 0x84bb6774: return "sys_prx_get_module_info"; + case 0x893305fa: return "sys_raw_spu_load"; + case 0x8985b5b6: return "_sys_heap_stats"; + case 0x8a2f159b: return "console_getc"; + case 0x8a561d92: return "_sys_heap_free"; + case 0x8bb03ab8: return "sys_game_board_storage_write"; + case 0x8c2bb498: return "sys_spinlock_initialize"; + case 0x96328741: return "_sys_process_at_Exitspawn"; + case 0x4f7172c9: return "sys_process_is_stack"; + case 0x996f7cf8: return "_sys_strncat"; + case 0x99c88692: return "_sys_strcpy"; + case 0x9d3c0f81: return "sys_mempool_destroy"; + case 0x9e0623b5: return "sys_game_watchdog_start"; + case 0x9f04f7af: return "_sys_printf"; + case 0x9f18429d: return "sys_prx_start_module"; + case 0x9f950780: return "sys_game_get_rtc_status"; + case 0xa146a143: return "sys_mempool_allocate_block"; + case 0xa1f9eafe: return "_sys_sprintf"; + case 0xa285139d: return "sys_spinlock_lock"; + case 0xa2c7ba64: return "sys_prx_exitspawn_with_level"; + case 0xa330ad84: return "sys_prx_load_module_on_memcontainer_by_fd"; + case 0xa3e3be68: return "sys_ppu_thread_once"; + case 0xa5d06bf0: return "sys_prx_get_module_list"; + case 0xaa6d9bff: return "sys_prx_load_module_on_memcontainer"; + case 0xac6fc404: return "sys_ppu_thread_unregister_atexit"; + case 0xacad8fb6: return "sys_game_watchdog_clear"; + case 0xaeb78725: return "sys_lwmutex_trylock"; + case 0xaede4b03: return "_sys_heap_delete_heap"; + case 0xaff080a4: return "sys_ppu_thread_exit"; + case 0xb257540b: return "sys_mmapper_allocate_memory"; + case 0xb27c8ae7: return "sys_prx_load_module_list"; + case 0xb2fcf2c8: return "_sys_heap_create_heap"; + case 0xb3bbcf2a: return "_sys_spu_printf_detach_thread"; + case 0xb6369393: return "_sys_heap_get_total_free_size"; + case 0xb995662e: return "sys_raw_spu_image_load"; + case 0xb9bf1078: return "_sys_heap_alloc_heap_memory"; + case 0xbdb18f83: return "_sys_malloc"; + case 0xc3476d0c: return "sys_lwmutex_destroy"; + case 0xc4fd6121: return "_sys_qsort"; + case 0xca9a60bf: return "sys_mempool_create"; + case 0xd0ea47a7: return "sys_prx_unregister_library"; + case 0xd1ad4570: return "_sys_heap_get_mallinfo"; + case 0xd3039d4d: return "_sys_strncpy"; + case 0xda0eb71a: return "sys_lwcond_create"; + case 0xdb6b3250: return "sys_spu_elf_get_segments"; + case 0xdc578057: return "sys_mmapper_map_memory"; + case 0xdd0c1e09: return "_sys_spu_printf_attach_group"; + case 0xdd3b27ac: return "_sys_spu_printf_finalize"; + case 0xe0998dbf: return "sys_prx_get_module_id_by_name"; + case 0xe0da8efd: return "sys_spu_image_close"; + case 0xe66bac36: return "console_putc"; + case 0xe6f2c1e7: return "sys_process_exit"; + case 0xe76964f5: return "sys_game_board_storage_read"; + case 0xe7ef3a80: return "sys_prx_load_module_list_on_memcontainer"; + case 0xe9a1bd84: return "sys_lwcond_signal_all"; + case 0xebe5f72f: return "sys_spu_image_import"; + case 0xeef75113: return "_sys_toupper"; + case 0xef68c17c: return "sys_prx_load_module_by_fd"; + case 0xef87a695: return "sys_lwcond_signal"; + case 0xf0aece0d: return "sys_prx_unload_module"; + case 0xf57e1d6f: return "console_write"; + case 0xf7f7fb20: return "_sys_free"; + case 0xfa7f693d: return "_sys_vprintf"; + case 0xfb5db080: return "_sys_memcmp"; + case 0xfc52a7a9: return "sys_game_process_exitspawn"; + } + + // Check registered functions + if (const auto sm = ppu_module_manager::get_module(module)) + { + const auto found = sm->functions.find(fnid); + + if (found != sm->functions.end()) + { + return found->second.name; + } + } + + return fmt::format("0x%08X", fnid); +} + +// Get variable name by VNID +extern std::string ppu_get_variable_name(const std::string& module, u32 vnid) +{ + // Check registered variables + if (const auto sm = ppu_module_manager::get_module(module)) + { + const auto found = sm->variables.find(vnid); + + if (found != sm->variables.end()) + { + return found->second.name; + } + } + + return fmt::format("0x%08X", vnid); +} + +s32 ppu_error_code::report(s32 error, const char* text) +{ + if (auto thread = get_current_cpu_thread()) + { + if (thread->type == cpu_type::ppu) + { + if (auto func = static_cast(thread)->last_function) + { + LOG_ERROR(PPU, "Function '%s' failed with 0x%08x : %s", func, error, text); + } + else + { + LOG_ERROR(PPU, "Unknown function failed with 0x%08x : %s", error, text); + } + + return error; + } + } + + LOG_ERROR(PPU, "Illegal call to ppu_report_error(0x%x, '%s')!"); + return error; +} diff --git a/rpcs3/Emu/SysCalls/SC_FUNC.h b/rpcs3/Emu/Cell/PPUFunction.h similarity index 68% rename from rpcs3/Emu/SysCalls/SC_FUNC.h rename to rpcs3/Emu/Cell/PPUFunction.h index 510c7fd0ff..184e8bba7b 100644 --- a/rpcs3/Emu/SysCalls/SC_FUNC.h +++ b/rpcs3/Emu/Cell/PPUFunction.h @@ -1,14 +1,14 @@ #pragma once -#include "Emu/Cell/PPUThread.h" +#include "PPUThread.h" -using ppu_func_caller = void(*)(PPUThread&); +using ppu_function_t = void(*)(PPUThread&); + +#define BIND_FUNC(func) [](PPUThread& ppu){ ppu.last_function = #func; ppu_func_detail::do_call(ppu, func); } struct ppu_va_args_t { - u32 g_count; - u32 f_count; - u32 v_count; + u32 count; // Number of 64-bit args passed }; namespace ppu_func_detail @@ -16,12 +16,12 @@ namespace ppu_func_detail // argument type classification enum arg_class : u32 { - ARG_GENERAL, // argument is stored in GPR registers (from r3 to r10) - ARG_FLOAT, // argument is stored in FPR registers (from f1 to f13) - ARG_VECTOR, // argument is stored in VPR registers (from v2 to v13) - ARG_STACK, // argument is stored on the stack + ARG_GENERAL, // argument stored in GPR (from r3 to r10) + ARG_FLOAT, // argument stored in FPR (from f1 to f13) + ARG_VECTOR, // argument stored in VR (from v2 to v13) + ARG_STACK, // argument stored on the stack ARG_CONTEXT, // PPUThread& passed, doesn't affect g/f/v_count - ARG_VARIADIC, // information about arg counts already passed, doesn't affect g/f/v_count + ARG_VARIADIC, // argument count at specific position, doesn't affect g/f/v_count ARG_UNKNOWN, }; @@ -33,9 +33,9 @@ namespace ppu_func_detail static_assert(!std::is_reference::value, "Invalid function argument type (reference)"); static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_GENERAL"); - static force_inline T get_arg(PPUThread& ppu) + static inline T get_arg(PPUThread& ppu) { - return cast_from_ppu_gpr(ppu.GPR[g_count + 2]); + return ppu_gpr_cast(ppu.GPR[g_count + 2]); } }; @@ -44,7 +44,7 @@ namespace ppu_func_detail { static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_FLOAT"); - static force_inline T get_arg(PPUThread& ppu) + static inline T get_arg(PPUThread& ppu) { return static_cast(ppu.FPR[f_count]); } @@ -53,26 +53,22 @@ namespace ppu_func_detail template struct bind_arg { - static_assert(std::is_same, v128>::value, "Invalid function argument type for ARG_VECTOR"); + static_assert(std::is_same::value, "Invalid function argument type for ARG_VECTOR"); static force_inline T get_arg(PPUThread& ppu) { - return ppu.VPR[v_count + 1]; + return ppu.VR[v_count + 1]; } }; template struct bind_arg { - static_assert(f_count <= 13, "TODO: Unsupported stack argument type (float)"); - static_assert(v_count <= 12, "TODO: Unsupported stack argument type (vector)"); - static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_STACK"); + static_assert(alignof(T) <= 16, "Unsupported type alignment for ARG_STACK"); static force_inline T get_arg(PPUThread& ppu) { - // TODO: check stack argument displacement - const u64 res = ppu.get_stack_arg(8 + std::max(g_count - 8, 0) + std::max(f_count - 13, 0) + std::max(v_count - 12, 0)); - return cast_from_ppu_gpr(res); + return ppu_gpr_cast(*ppu.get_stack_arg(g_count, alignof(T))); // TODO } }; @@ -94,7 +90,7 @@ namespace ppu_func_detail static force_inline ppu_va_args_t get_arg(PPUThread& ppu) { - return{ g_count, f_count, v_count }; + return{ g_count }; } }; @@ -106,7 +102,7 @@ namespace ppu_func_detail static force_inline void put_result(PPUThread& ppu, const T& result) { - ppu.GPR[3] = cast_to_ppu_gpr(result); + ppu.GPR[3] = ppu_gpr_cast(result); } }; @@ -124,11 +120,11 @@ namespace ppu_func_detail template struct bind_result { - static_assert(std::is_same, v128>::value, "Invalid function result type for ARG_VECTOR"); + static_assert(std::is_same::value, "Invalid function result type for ARG_VECTOR"); static force_inline void put_result(PPUThread& ppu, const T& result) { - ppu.VPR[2] = result; + ppu.VR[2] = result; } }; @@ -176,9 +172,9 @@ namespace ppu_func_detail // TODO: check calculations const bool is_float = std::is_floating_point::value; - const bool is_vector = std::is_same, v128>::value; + const bool is_vector = std::is_same::value; const bool is_context = std::is_same::value; - const bool is_variadic = std::is_same, ppu_va_args_t>::value; + const bool is_variadic = std::is_same::value; const bool is_general = !is_float && !is_vector && !is_context && !is_variadic; const arg_class t = @@ -189,19 +185,20 @@ namespace ppu_func_detail is_variadic ? ARG_VARIADIC : ARG_UNKNOWN; - const u32 g = g_count + is_general; + const u32 g = g_count + (is_general || is_float ? 1 : is_vector ? ::align(g_count, 2) + 2 : 0); const u32 f = f_count + is_float; const u32 v = v_count + is_vector; return call(ppu, func, arg_info_pack_t{}); } - template struct result_type + template + struct result_type { static_assert(!std::is_pointer::value, "Invalid function result type (pointer)"); static_assert(!std::is_reference::value, "Invalid function result type (reference)"); static const bool is_float = std::is_floating_point::value; - static const bool is_vector = std::is_same, v128>::value; + static const bool is_vector = std::is_same::value; static const arg_class value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); }; @@ -229,10 +226,66 @@ namespace ppu_func_detail } }; - template force_inline void do_call(PPUThread& ppu, RT(*func)(T...)) + template + force_inline void do_call(PPUThread& ppu, RT(*func)(T...)) { func_binder::do_call(ppu, func); } } -#define BIND_FUNC(func) [](PPUThread& ppu){ ppu_func_detail::do_call(ppu, func); } +class ppu_function_manager +{ + // Global variable for each registered function + template + struct registered + { + static u32 index; + }; + + // Access global function list + static never_inline auto& access() + { + static std::vector list + { + nullptr, + [](PPUThread& ppu) { ppu.state += cpu_state::ret; }, + }; + + return list; + } + + static never_inline u32 add_function(ppu_function_t function) + { + auto& list = access(); + + list.push_back(function); + + return ::size32(list) - 1; + } + +public: + // Register function (shall only be called during global initialization) + template + static inline u32 register_function(ppu_function_t func) + { + return registered::index = add_function(func); + } + + // Get function index + template + static inline u32 get_index() + { + return registered::index; + } + + // Read all registered functions + static inline const auto& get() + { + return access(); + } +}; + +template +u32 ppu_function_manager::registered::index = 0; + +#define FIND_FUNC(func) ppu_function_manager::get_index() diff --git a/rpcs3/Emu/Cell/PPUInstrTable.h b/rpcs3/Emu/Cell/PPUInstrTable.h deleted file mode 100644 index fbad298fbb..0000000000 --- a/rpcs3/Emu/Cell/PPUInstrTable.h +++ /dev/null @@ -1,704 +0,0 @@ -#pragma once -#include "PPCInstrTable.h" -#include "PPCDecoder.h" -#include "PPUOpcodes.h" - -namespace PPU_instr -{ - namespace fields - { - //This field is used in rotate instructions to specify the first 1 bit of a 64-bit mask - static DoubleCodeField<21, 25, 26, 26, 5> mb; - - //This field is used in rotate instructions to specify the last 1 bit of a 64-bit mask - static DoubleCodeField<21, 25, 26, 26, 5> me; - - //This field is used to specify a shift amount - static DoubleCodeField<16, 20, 30, 30, 5> sh; - - //This field is used to specify a special-purpose register for the mtspr and mfspr instructions - static CodeField<11, 20> SPR; - - // - static CodeField<6, 10> VS(FIELD_R_VPR); - - // - static CodeField<6, 10> VD(FIELD_R_VPR); - - // - static CodeField<11, 15> VA(FIELD_R_VPR); - - // - static CodeField<16, 20> VB(FIELD_R_VPR); - - // - static CodeField<21, 25> VC(FIELD_R_VPR); - - // - static CodeField<11, 15> VUIMM; - - // - static CodeFieldSigned<11, 15> VSIMM; - - // - static CodeField<22, 25> VSH; - - //This field is used to specify a GPR to be used as a destination - static CodeField<6, 10> RD(FIELD_R_GPR); - - //This field is used to specify a GPR to be used as a source - static CodeField<6, 10> RS(FIELD_R_GPR); - - //This field is used to specify a GPR to be used as a source or destination - static CodeField<11, 15> RA(FIELD_R_GPR); - - //This field is used to specify a GPR to be used as a source - static CodeField<16, 20> RB(FIELD_R_GPR); - - //This field is used to specify the number of bytes to move in an immediate string load or store - static CodeField<16, 20> NB; - - //This field is used to specify one of the CR fields, or one of the FPSCR fields, as a destination - static CodeField<6, 8> CRFD(FIELD_R_CR); - - //This field is used to specify one of the CR fields, or one of the FPSCR fields, as a source - static CodeField<11, 13> CRFS(FIELD_R_CR); - - //This field is used to specify a bit in the CR to be used as a source - static CodeField<11, 15> CRBA(FIELD_R_CR); - - //This field is used to specify a bit in the CR to be used as a source - static CodeField<16, 20> CRBB(FIELD_R_CR); - - //This field is used to specify a bit in the CR, or in the FPSCR, as the destination of the result of an instruction - static CodeField<6, 10> CRBD(FIELD_R_CR); - - //This field is used to specify options for the branch conditional instructions - static CodeField<6, 10> BO; - - //This field is used to specify a bit in the CR to be used as the condition of a branch conditional instruction - static CodeField<11, 15> BI; - - //Immediate field specifying a 14-bit signed two's complement branch displacement that is concatenated on the - //right with '00' and sign-extended to 64 bits. - static CodeFieldSigned<16, 31> BD(FIELD_BRANCH); - - // - static CodeField<19, 20> BH; - - // - static CodeField<11, 13> BFA; - - //Field used by the optional data stream variant of the dcbt instruction. - static CodeField<9, 10> TH; - - //This field is used to specify the conditions on which to trap - static CodeField<6, 10> TO; - - // - static CodeField<21, 25> MB; - - // - static CodeField<26, 30> ME; - - //This field is used to specify a shift amount - static CodeField<16, 20> SH; - - /* - Absolute address bit. - 0 The immediate field represents an address relative to the current instruction address (CIA). (For more - information on the CIA, see Table 8-3.) The effective (logical) address of the branch is either the sum - of the LI field sign-extended to 64 bits and the address of the branch instruction or the sum of the BD - field sign-extended to 64 bits and the address of the branch instruction. - 1 The immediate field represents an absolute address. The effective address (EA) of the branch is the - LI field sign-extended to 64 bits or the BD field sign-extended to 64 bits. - */ - static CodeField<30> AA; - - // - static CodeFieldSignedOffset<6, 29, 2> LL(FIELD_BRANCH); - /* - Link bit. - 0 Does not update the link register (LR). - 1 Updates the LR. If the instruction is a branch instruction, the address of the instruction following the - branch instruction is placed into the LR. - */ - static CodeField<31> LK; - - //This field is used for extended arithmetic to enable setting OV and SO in the XER - static CodeField<21> OE; - - //Field used to specify whether an integer compare instruction is to compare 64-bit numbers or 32-bit numbers - static CodeField<10> L_10; - static CodeField<6> L_6; - static CodeField<9, 10> L_9_10; - static CodeField<11> L_11; - // - static CodeField<16, 19> I; - - // - static CodeField<16, 27> DQ; - - //This field is used to specify an FPR as the destination - static CodeField<6, 10> FRD; - - //This field is used to specify an FPR as a source - static CodeField<6, 10> FRS; - - // - static CodeField<7, 14> FM; - - //This field is used to specify an FPR as a source - static CodeField<11, 15> FRA(FIELD_R_FPR); - - //This field is used to specify an FPR as a source - static CodeField<16, 20> FRB(FIELD_R_FPR); - - //This field is used to specify an FPR as a source - static CodeField<21, 25> FRC(FIELD_R_FPR); - - //This field mask is used to identify the CR fields that are to be updated by the mtcrf instruction. - static CodeField<12, 19> CRM; - - // This field is used to identify the system call level - static CodeField<20, 26> LEV; - - //Immediate field specifying a 16-bit signed two's complement integer that is sign-extended to 64 bits - static CodeFieldSigned<16, 31> D; - - // - static CodeFieldSignedOffset<16, 29, 2> DS; - - //This immediate field is used to specify a 16-bit signed integer - static CodeFieldSigned<16, 31> simm16; - - //This immediate field is used to specify a 16-bit unsigned integer - static CodeField<16, 31> uimm16; - - static CodeField<6, 31> uimm26; - - /* - Record bit. - 0 Does not update the condition register (CR). - 1 Updates the CR to reflect the result of the operation. - For integer instructions, CR bits [0-2] are set to reflect the result as a signed quantity and CR bit [3] - receives a copy of the summary overflow bit, XER[SO]. The result as an unsigned quantity or a bit - string can be deduced from the EQ bit. For floating-point instructions, CR bits [4-7] are set to reflect - floating-point exception, floating-point enabled exception, floating-point invalid operation exception, - and floating-point overflow exception. - */ - static CodeField<31> RC; - - //Primary opcode field - static CodeField<0, 5> OPCD; - - static CodeField<26, 31> GD_04; //0x3f - static CodeField<21, 31> GD_04_0;//0x7ff - static CodeField<21, 30> GD_13; //0x3ff - static CodeField<27, 29> GD_1e; //0x7 - static CodeField<21, 30> GD_1f; //0x3ff - static CodeField<30, 31> GD_3a; //0x3 - static CodeField<26, 30> GD_3b; //0x1f - static CodeField<30, 31> GD_3e; //0x3 - static CodeField<26, 30> GD_3f;//0x1f - static CodeField<21, 30> GD_3f_0; //0x3ff - - static CodeField<9, 10> STRM; - } - - namespace lists - { - using namespace fields; - - //static auto main_list = new_list(OPCD, instr_bind(&PPUOpcodes::UNK, GetCode, OPCD, OPCD)); - static InstrList<1 << CodeField<0, 5>::size, ::PPUOpcodes> main_list_obj(OPCD, instr_bind(&PPUOpcodes::UNK, GetCode, OPCD, OPCD)); - static auto main_list = &main_list_obj; - static auto g04_list = new_list(main_list, PPU_opcodes::G_04, GD_04); - static auto g04_0_list = new_list(g04_list, GD_04_0, instr_bind(&PPUOpcodes::UNK, GetCode, OPCD, GD_04_0)); - static auto g13_list = new_list(main_list, PPU_opcodes::G_13, GD_13, instr_bind(&PPUOpcodes::UNK, GetCode, OPCD, GD_13)); - static auto g1e_list = new_list(main_list, PPU_opcodes::G_1e, GD_1e, instr_bind(&PPUOpcodes::UNK, GetCode, OPCD, GD_1e)); - static auto g1f_list = new_list(main_list, PPU_opcodes::G_1f, GD_1f, instr_bind(&PPUOpcodes::UNK, GetCode, OPCD, GD_1f)); - static auto g3a_list = new_list(main_list, PPU_opcodes::G_3a, GD_3a, instr_bind(&PPUOpcodes::UNK, GetCode, OPCD, GD_3a)); - static auto g3b_list = new_list(main_list, PPU_opcodes::G_3b, GD_3b, instr_bind(&PPUOpcodes::UNK, GetCode, OPCD, GD_3b)); - static auto g3e_list = new_list(main_list, PPU_opcodes::G_3e, GD_3e, instr_bind(&PPUOpcodes::UNK, GetCode, OPCD, GD_3e)); - static auto g3f_list = new_list(main_list, PPU_opcodes::G_3f, GD_3f); - static auto g3f_0_list = new_list(g3f_list, GD_3f_0, instr_bind(&PPUOpcodes::UNK, GetCode, OPCD, GD_3f_0)); - -#define bind_instr(list, name, ...) \ - static const auto& name = make_instr(list, #name, &PPUOpcodes::name, ##__VA_ARGS__) -#define bind_instr_oe(list, name, ...) \ - bind_instr(list, name, ##__VA_ARGS__); \ - static const auto& name##O = make_instr(list, #name "O", &PPUOpcodes::name, ##__VA_ARGS__) - - bind_instr(main_list, TDI, TO, RA, simm16); - bind_instr(main_list, TWI, TO, RA, simm16); - bind_instr(main_list, MULLI, RD, RA, simm16); - bind_instr(main_list, SUBFIC, RD, RA, simm16); - bind_instr(main_list, CMPLI, CRFD, L_10, RA, uimm16); - bind_instr(main_list, CMPI, CRFD, L_10, RA, simm16); - bind_instr(main_list, ADDIC, RD, RA, simm16); - bind_instr(main_list, ADDIC_, RD, RA, simm16); - bind_instr(main_list, ADDI, RD, RA, simm16); - bind_instr(main_list, ADDIS, RD, RA, simm16); - bind_instr(main_list, BC, BO, BI, BD, AA, LK); - bind_instr(main_list, HACK, uimm26); - bind_instr(main_list, SC, LEV); - bind_instr(main_list, B, LL, AA, LK); - bind_instr(main_list, RLWIMI, RA, RS, SH, MB, ME, RC); - bind_instr(main_list, RLWINM, RA, RS, SH, MB, ME, RC); - bind_instr(main_list, RLWNM, RA, RS, RB, MB, ME, RC); - bind_instr(main_list, ORI, RA, RS, uimm16); - bind_instr(main_list, ORIS, RA, RS, uimm16); - bind_instr(main_list, XORI, RA, RS, uimm16); - bind_instr(main_list, XORIS, RA, RS, uimm16); - bind_instr(main_list, ANDI_, RA, RS, uimm16); - bind_instr(main_list, ANDIS_, RA, RS, uimm16); - bind_instr(main_list, LWZ, RD, RA, D); - bind_instr(main_list, LWZU, RD, RA, D); - bind_instr(main_list, LBZ, RD, RA, D); - bind_instr(main_list, LBZU, RD, RA, D); - bind_instr(main_list, STW, RS, RA, D); - bind_instr(main_list, STWU, RS, RA, D); - bind_instr(main_list, STB, RS, RA, D); - bind_instr(main_list, STBU, RS, RA, D); - bind_instr(main_list, LHZ, RD, RA, D); - bind_instr(main_list, LHZU, RD, RA, D); - bind_instr(main_list, LHA, RD, RA, D); - bind_instr(main_list, LHAU, RD, RA, D); - bind_instr(main_list, STH, RS, RA, D); - bind_instr(main_list, STHU, RS, RA, D); - bind_instr(main_list, LMW, RD, RA, D); - bind_instr(main_list, STMW, RS, RA, D); - bind_instr(main_list, LFS, FRD, RA, D); - bind_instr(main_list, LFSU, FRD, RA, D); - bind_instr(main_list, LFD, FRD, RA, D); - bind_instr(main_list, LFDU, FRD, RA, D); - bind_instr(main_list, STFS, FRS, RA, D); - bind_instr(main_list, STFSU, FRS, RA, D); - bind_instr(main_list, STFD, FRS, RA, D); - bind_instr(main_list, STFDU, FRS, RA, D); - - bind_instr(g04_list, VMADDFP, VD, VA, VC, VB); - bind_instr(g04_list, VMHADDSHS, VD, VA, VB, VC); - bind_instr(g04_list, VMHRADDSHS, VD, VA, VB, VC); - bind_instr(g04_list, VMLADDUHM, VD, VA, VB, VC); - bind_instr(g04_list, VMSUMMBM, VD, VA, VB, VC); - bind_instr(g04_list, VMSUMSHM, VD, VA, VB, VC); - bind_instr(g04_list, VMSUMSHS, VD, VA, VB, VC); - bind_instr(g04_list, VMSUMUBM, VD, VA, VB, VC); - bind_instr(g04_list, VMSUMUHM, VD, VA, VB, VC); - bind_instr(g04_list, VMSUMUHS, VD, VA, VB, VC); - bind_instr(g04_list, VNMSUBFP, VD, VA, VC, VB); - bind_instr(g04_list, VPERM, VD, VA, VB, VC); - bind_instr(g04_list, VSEL, VD, VA, VB, VC); - bind_instr(g04_list, VSLDOI, VD, VA, VB, VSH); - - bind_instr(g04_0_list, MFVSCR, VD); - bind_instr(g04_0_list, MTVSCR, VB); - bind_instr(g04_0_list, VADDCUW, VD, VA, VB); - bind_instr(g04_0_list, VADDFP, VD, VA, VB); - bind_instr(g04_0_list, VADDSBS, VD, VA, VB); - bind_instr(g04_0_list, VADDSHS, VD, VA, VB); - bind_instr(g04_0_list, VADDSWS, VD, VA, VB); - bind_instr(g04_0_list, VADDUBM, VD, VA, VB); - bind_instr(g04_0_list, VADDUBS, VD, VA, VB); - bind_instr(g04_0_list, VADDUHM, VD, VA, VB); - bind_instr(g04_0_list, VADDUHS, VD, VA, VB); - bind_instr(g04_0_list, VADDUWM, VD, VA, VB); - bind_instr(g04_0_list, VADDUWS, VD, VA, VB); - bind_instr(g04_0_list, VAND, VD, VA, VB); - bind_instr(g04_0_list, VANDC, VD, VA, VB); - bind_instr(g04_0_list, VAVGSB, VD, VA, VB); - bind_instr(g04_0_list, VAVGSH, VD, VA, VB); - bind_instr(g04_0_list, VAVGSW, VD, VA, VB); - bind_instr(g04_0_list, VAVGUB, VD, VA, VB); - bind_instr(g04_0_list, VAVGUH, VD, VA, VB); - bind_instr(g04_0_list, VAVGUW, VD, VA, VB); - bind_instr(g04_0_list, VCFSX, VD, VUIMM, VB); - bind_instr(g04_0_list, VCFUX, VD, VUIMM, VB); - bind_instr(g04_0_list, VCMPBFP, VD, VA, VB); - bind_instr(g04_0_list, VCMPBFP_, VD, VA, VB); - bind_instr(g04_0_list, VCMPEQFP, VD, VA, VB); - bind_instr(g04_0_list, VCMPEQFP_, VD, VA, VB); - bind_instr(g04_0_list, VCMPEQUB, VD, VA, VB); - bind_instr(g04_0_list, VCMPEQUB_, VD, VA, VB); - bind_instr(g04_0_list, VCMPEQUH, VD, VA, VB); - bind_instr(g04_0_list, VCMPEQUH_, VD, VA, VB); - bind_instr(g04_0_list, VCMPEQUW, VD, VA, VB); - bind_instr(g04_0_list, VCMPEQUW_, VD, VA, VB); - bind_instr(g04_0_list, VCMPGEFP, VD, VA, VB); - bind_instr(g04_0_list, VCMPGEFP_, VD, VA, VB); - bind_instr(g04_0_list, VCMPGTFP, VD, VA, VB); - bind_instr(g04_0_list, VCMPGTFP_, VD, VA, VB); - bind_instr(g04_0_list, VCMPGTSB, VD, VA, VB); - bind_instr(g04_0_list, VCMPGTSB_, VD, VA, VB); - bind_instr(g04_0_list, VCMPGTSH, VD, VA, VB); - bind_instr(g04_0_list, VCMPGTSH_, VD, VA, VB); - bind_instr(g04_0_list, VCMPGTSW, VD, VA, VB); - bind_instr(g04_0_list, VCMPGTSW_, VD, VA, VB); - bind_instr(g04_0_list, VCMPGTUB, VD, VA, VB); - bind_instr(g04_0_list, VCMPGTUB_, VD, VA, VB); - bind_instr(g04_0_list, VCMPGTUH, VD, VA, VB); - bind_instr(g04_0_list, VCMPGTUH_, VD, VA, VB); - bind_instr(g04_0_list, VCMPGTUW, VD, VA, VB); - bind_instr(g04_0_list, VCMPGTUW_, VD, VA, VB); - bind_instr(g04_0_list, VCTSXS, VD, VUIMM, VB); - bind_instr(g04_0_list, VCTUXS, VD, VUIMM, VB); - bind_instr(g04_0_list, VEXPTEFP, VD, VB); - bind_instr(g04_0_list, VLOGEFP, VD, VB); - bind_instr(g04_0_list, VMAXFP, VD, VA, VB); - bind_instr(g04_0_list, VMAXSB, VD, VA, VB); - bind_instr(g04_0_list, VMAXSH, VD, VA, VB); - bind_instr(g04_0_list, VMAXSW, VD, VA, VB); - bind_instr(g04_0_list, VMAXUB, VD, VA, VB); - bind_instr(g04_0_list, VMAXUH, VD, VA, VB); - bind_instr(g04_0_list, VMAXUW, VD, VA, VB); - bind_instr(g04_0_list, VMINFP, VD, VA, VB); - bind_instr(g04_0_list, VMINSB, VD, VA, VB); - bind_instr(g04_0_list, VMINSH, VD, VA, VB); - bind_instr(g04_0_list, VMINSW, VD, VA, VB); - bind_instr(g04_0_list, VMINUB, VD, VA, VB); - bind_instr(g04_0_list, VMINUH, VD, VA, VB); - bind_instr(g04_0_list, VMINUW, VD, VA, VB); - bind_instr(g04_0_list, VMRGHB, VD, VA, VB); - bind_instr(g04_0_list, VMRGHH, VD, VA, VB); - bind_instr(g04_0_list, VMRGHW, VD, VA, VB); - bind_instr(g04_0_list, VMRGLB, VD, VA, VB); - bind_instr(g04_0_list, VMRGLH, VD, VA, VB); - bind_instr(g04_0_list, VMRGLW, VD, VA, VB); - bind_instr(g04_0_list, VMULESB, VD, VA, VB); - bind_instr(g04_0_list, VMULESH, VD, VA, VB); - bind_instr(g04_0_list, VMULEUB, VD, VA, VB); - bind_instr(g04_0_list, VMULEUH, VD, VA, VB); - bind_instr(g04_0_list, VMULOSB, VD, VA, VB); - bind_instr(g04_0_list, VMULOSH, VD, VA, VB); - bind_instr(g04_0_list, VMULOUB, VD, VA, VB); - bind_instr(g04_0_list, VMULOUH, VD, VA, VB); - bind_instr(g04_0_list, VNOR, VD, VA, VB); - bind_instr(g04_0_list, VOR, VD, VA, VB); - bind_instr(g04_0_list, VPKPX, VD, VA, VB); - bind_instr(g04_0_list, VPKSHSS, VD, VA, VB); - bind_instr(g04_0_list, VPKSHUS, VD, VA, VB); - bind_instr(g04_0_list, VPKSWSS, VD, VA, VB); - bind_instr(g04_0_list, VPKSWUS, VD, VA, VB); - bind_instr(g04_0_list, VPKUHUM, VD, VA, VB); - bind_instr(g04_0_list, VPKUHUS, VD, VA, VB); - bind_instr(g04_0_list, VPKUWUM, VD, VA, VB); - bind_instr(g04_0_list, VPKUWUS, VD, VA, VB); - bind_instr(g04_0_list, VREFP, VD, VB); - bind_instr(g04_0_list, VRFIM, VD, VB); - bind_instr(g04_0_list, VRFIN, VD, VB); - bind_instr(g04_0_list, VRFIP, VD, VB); - bind_instr(g04_0_list, VRFIZ, VD, VB); - bind_instr(g04_0_list, VRLB, VD, VA, VB); - bind_instr(g04_0_list, VRLH, VD, VA, VB); - bind_instr(g04_0_list, VRLW, VD, VA, VB); - bind_instr(g04_0_list, VRSQRTEFP, VD, VB); - bind_instr(g04_0_list, VSL, VD, VA, VB); - bind_instr(g04_0_list, VSLB, VD, VA, VB); - bind_instr(g04_0_list, VSLH, VD, VA, VB); - bind_instr(g04_0_list, VSLO, VD, VA, VB); - bind_instr(g04_0_list, VSLW, VD, VA, VB); - bind_instr(g04_0_list, VSPLTB, VD, VUIMM, VB); - bind_instr(g04_0_list, VSPLTH, VD, VUIMM, VB); - bind_instr(g04_0_list, VSPLTISB, VD, VSIMM); - bind_instr(g04_0_list, VSPLTISH, VD, VSIMM); - bind_instr(g04_0_list, VSPLTISW, VD, VSIMM); - bind_instr(g04_0_list, VSPLTW, VD, VUIMM, VB); - bind_instr(g04_0_list, VSR, VD, VA, VB); - bind_instr(g04_0_list, VSRAB, VD, VA, VB); - bind_instr(g04_0_list, VSRAH, VD, VA, VB); - bind_instr(g04_0_list, VSRAW, VD, VA, VB); - bind_instr(g04_0_list, VSRB, VD, VA, VB); - bind_instr(g04_0_list, VSRH, VD, VA, VB); - bind_instr(g04_0_list, VSRO, VD, VA, VB); - bind_instr(g04_0_list, VSRW, VD, VA, VB); - bind_instr(g04_0_list, VSUBCUW, VD, VA, VB); - bind_instr(g04_0_list, VSUBFP, VD, VA, VB); - bind_instr(g04_0_list, VSUBSBS, VD, VA, VB); - bind_instr(g04_0_list, VSUBSHS, VD, VA, VB); - bind_instr(g04_0_list, VSUBSWS, VD, VA, VB); - bind_instr(g04_0_list, VSUBUBM, VD, VA, VB); - bind_instr(g04_0_list, VSUBUBS, VD, VA, VB); - bind_instr(g04_0_list, VSUBUHM, VD, VA, VB); - bind_instr(g04_0_list, VSUBUHS, VD, VA, VB); - bind_instr(g04_0_list, VSUBUWM, VD, VA, VB); - bind_instr(g04_0_list, VSUBUWS, VD, VA, VB); - bind_instr(g04_0_list, VSUMSWS, VD, VA, VB); - bind_instr(g04_0_list, VSUM2SWS, VD, VA, VB); - bind_instr(g04_0_list, VSUM4SBS, VD, VA, VB); - bind_instr(g04_0_list, VSUM4SHS, VD, VA, VB); - bind_instr(g04_0_list, VSUM4UBS, VD, VA, VB); - bind_instr(g04_0_list, VUPKHPX, VD, VB); - bind_instr(g04_0_list, VUPKHSB, VD, VB); - bind_instr(g04_0_list, VUPKHSH, VD, VB); - bind_instr(g04_0_list, VUPKLPX, VD, VB); - bind_instr(g04_0_list, VUPKLSB, VD, VB); - bind_instr(g04_0_list, VUPKLSH, VD, VB); - bind_instr(g04_0_list, VXOR, VD, VA, VB); - - bind_instr(g13_list, MCRF, CRFD, CRFS); - bind_instr(g13_list, BCLR, BO, BI, BH, LK); - bind_instr(g13_list, CRNOR, CRBD, CRBA, CRBB); - bind_instr(g13_list, CRANDC, CRBD, CRBA, CRBB); - bind_instr(g13_list, ISYNC); - bind_instr(g13_list, CRXOR, CRBD, CRBA, CRBB); - bind_instr(g13_list, CRNAND, CRBD, CRBA, CRBB); - bind_instr(g13_list, CRAND, CRBD, CRBA, CRBB); - bind_instr(g13_list, CREQV, CRBD, CRBA, CRBB); - bind_instr(g13_list, CRORC, CRBD, CRBA, CRBB); - bind_instr(g13_list, CROR, CRBD, CRBA, CRBB); - bind_instr(g13_list, BCCTR, BO, BI, BH, LK); - - bind_instr(g1e_list, RLDICL, RA, RS, sh, mb, RC); - bind_instr(g1e_list, RLDICR, RA, RS, sh, me, RC); - bind_instr(g1e_list, RLDIC, RA, RS, sh, mb, RC); - bind_instr(g1e_list, RLDIMI, RA, RS, sh, mb, RC); - bind_instr(g1e_list, RLDC_LR, RA, RS, RB, mb, AA, RC); - - /*0x000*/bind_instr(g1f_list, CMP, CRFD, L_10, RA, RB); - /*0x004*/bind_instr(g1f_list, TW, TO, RA, RB); - /*0x006*/bind_instr(g1f_list, LVSL, VD, RA, RB); - /*0x007*/bind_instr(g1f_list, LVEBX, VD, RA, RB); - /*0x008*/bind_instr_oe(g1f_list, SUBFC, RD, RA, RB, OE, RC); - /*0x009*/bind_instr(g1f_list, MULHDU, RD, RA, RB, RC); - /*0x00a*/bind_instr_oe(g1f_list, ADDC, RD, RA, RB, OE, RC); - /*0x00b*/bind_instr(g1f_list, MULHWU, RD, RA, RB, RC); - /*0x013*/bind_instr(g1f_list, MFOCRF, L_11, RD, CRM); - /*0x014*/bind_instr(g1f_list, LWARX, RD, RA, RB); - /*0x015*/bind_instr(g1f_list, LDX, RD, RA, RB); - /*0x017*/bind_instr(g1f_list, LWZX, RD, RA, RB); - /*0x018*/bind_instr(g1f_list, SLW, RA, RS, RB, RC); - /*0x01a*/bind_instr(g1f_list, CNTLZW, RA, RS, RC); - /*0x01b*/bind_instr(g1f_list, SLD, RA, RS, RB, RC); - /*0x01c*/bind_instr(g1f_list, AND, RA, RS, RB, RC); - /*0x020*/bind_instr(g1f_list, CMPL, CRFD, L_10, RA, RB); - /*0x026*/bind_instr(g1f_list, LVSR, VD, RA, RB); - /*0x027*/bind_instr(g1f_list, LVEHX, VD, RA, RB); - /*0x028*/bind_instr_oe(g1f_list, SUBF, RD, RA, RB, OE, RC); - /*0x035*/bind_instr(g1f_list, LDUX, RD, RA, RB); - /*0x036*/bind_instr(g1f_list, DCBST, RA, RB); - /*0x037*/bind_instr(g1f_list, LWZUX, RD, RA, RB); - /*0x03a*/bind_instr(g1f_list, CNTLZD, RA, RS, RC); - /*0x03c*/bind_instr(g1f_list, ANDC, RA, RS, RB, RC); - /*0x03c*/bind_instr(g1f_list, TD, TO, RA, RB); - /*0x047*/bind_instr(g1f_list, LVEWX, VD, RA, RB); - /*0x049*/bind_instr(g1f_list, MULHD, RD, RA, RB, RC); - /*0x04b*/bind_instr(g1f_list, MULHW, RD, RA, RB, RC); - /*0x054*/bind_instr(g1f_list, LDARX, RD, RA, RB); - /*0x056*/bind_instr(g1f_list, DCBF, RA, RB); - /*0x057*/bind_instr(g1f_list, LBZX, RD, RA, RB); - /*0x067*/bind_instr(g1f_list, LVX, VD, RA, RB); - /*0x068*/bind_instr_oe(g1f_list, NEG, RD, RA, OE, RC); - /*0x077*/bind_instr(g1f_list, LBZUX, RD, RA, RB); - /*0x07c*/bind_instr(g1f_list, NOR, RA, RS, RB, RC); - /*0x087*/bind_instr(g1f_list, STVEBX, VS, RA, RB); - /*0x088*/bind_instr_oe(g1f_list, SUBFE, RD, RA, RB, OE, RC); - /*0x08a*/bind_instr_oe(g1f_list, ADDE, RD, RA, RB, OE, RC); - /*0x090*/bind_instr(g1f_list, MTOCRF, L_11, CRM, RS); - /*0x095*/bind_instr(g1f_list, STDX, RS, RA, RB); - /*0x096*/bind_instr(g1f_list, STWCX_, RS, RA, RB); - /*0x097*/bind_instr(g1f_list, STWX, RS, RA, RB); - /*0x0a7*/bind_instr(g1f_list, STVEHX, VS, RA, RB); - /*0x0b5*/bind_instr(g1f_list, STDUX, RS, RA, RB); - /*0x0b7*/bind_instr(g1f_list, STWUX, RS, RA, RB); - /*0x0c7*/bind_instr(g1f_list, STVEWX, VS, RA, RB); - /*0x0c8*/bind_instr_oe(g1f_list, SUBFZE, RD, RA, OE, RC); - /*0x0ca*/bind_instr_oe(g1f_list, ADDZE, RD, RA, OE, RC); - /*0x0d6*/bind_instr(g1f_list, STDCX_, RS, RA, RB); - /*0x0d7*/bind_instr(g1f_list, STBX, RS, RA, RB); - /*0x0e7*/bind_instr(g1f_list, STVX, VS, RA, RB); - /*0x0e8*/bind_instr_oe(g1f_list, SUBFME, RD, RA, OE, RC); - /*0x0e9*/bind_instr_oe(g1f_list, MULLD, RD, RA, RB, OE, RC); - /*0x0ea*/bind_instr_oe(g1f_list, ADDME, RD, RA, OE, RC); - /*0x0eb*/bind_instr_oe(g1f_list, MULLW, RD, RA, RB, OE, RC); - /*0x0f6*/bind_instr(g1f_list, DCBTST, RA, RB, TH); - /*0x0f7*/bind_instr(g1f_list, STBUX, RS, RA, RB); - /*0x10a*/bind_instr_oe(g1f_list, ADD, RD, RA, RB, OE, RC); - /*0x116*/bind_instr(g1f_list, DCBT, RA, RB, TH); - /*0x117*/bind_instr(g1f_list, LHZX, RD, RA, RB); - /*0x11c*/bind_instr(g1f_list, EQV, RA, RS, RB, RC); - /*0x136*/bind_instr(g1f_list, ECIWX, RD, RA, RB); - /*0x137*/bind_instr(g1f_list, LHZUX, RD, RA, RB); - /*0x13c*/bind_instr(g1f_list, XOR, RA, RS, RB, RC); - /*0x153*/bind_instr(g1f_list, MFSPR, RD, SPR); - /*0x155*/bind_instr(g1f_list, LWAX, RD, RA, RB); - /*0x156*/bind_instr(g1f_list, DST, RA, RB, STRM, L_6); - /*0x157*/bind_instr(g1f_list, LHAX, RD, RA, RB); - /*0x167*/bind_instr(g1f_list, LVXL, VD, RA, RB); - /*0x173*/bind_instr(g1f_list, MFTB, RD, SPR); - /*0x175*/bind_instr(g1f_list, LWAUX, RD, RA, RB); - /*0x176*/bind_instr(g1f_list, DSTST, RA, RB, STRM, L_6); - /*0x177*/bind_instr(g1f_list, LHAUX, RD, RA, RB); - /*0x197*/bind_instr(g1f_list, STHX, RS, RA, RB); - /*0x19c*/bind_instr(g1f_list, ORC, RA, RS, RB, RC); - /*0x1b6*/bind_instr(g1f_list, ECOWX, RS, RA, RB); - /*0x1b7*/bind_instr(g1f_list, STHUX, RS, RA, RB); - /*0x1bc*/bind_instr(g1f_list, OR, RA, RS, RB, RC); - /*0x1c9*/bind_instr_oe(g1f_list, DIVDU, RD, RA, RB, OE, RC); - /*0x1cb*/bind_instr_oe(g1f_list, DIVWU, RD, RA, RB, OE, RC); - /*0x1d3*/bind_instr(g1f_list, MTSPR, SPR, RS); - /*0x1d6*///DCBI - /*0x1dc*/bind_instr(g1f_list, NAND, RA, RS, RB, RC); - /*0x1e7*/bind_instr(g1f_list, STVXL, VS, RA, RB); - /*0x1e9*/bind_instr_oe(g1f_list, DIVD, RD, RA, RB, OE, RC); - /*0x1eb*/bind_instr_oe(g1f_list, DIVW, RD, RA, RB, OE, RC); - /*0x207*/bind_instr(g1f_list, LVLX, VD, RA, RB); - // MULH{D|DU|W|WU} don't use OE, but a real Cell accepts - // opcodes with OE=1 and Rc=0, behaving as if OE was not set. - // OE=1 and Rc=1 causes an invalid instruction exception, but - // we don't worry about that. - static const auto& MULHDUO = make_instr<0x209>(g1f_list, "MULHDUO", &PPUOpcodes::MULHDU, RD, RA, RB, RC); - static const auto& MULHWUO = make_instr<0x20b>(g1f_list, "MULHWUO", &PPUOpcodes::MULHWU, RD, RA, RB, RC); - /*0x214*/bind_instr(g1f_list, LDBRX, RD, RA, RB); - /*0x215*/bind_instr(g1f_list, LSWX, RD, RA, RB); - /*0x216*/bind_instr(g1f_list, LWBRX, RD, RA, RB); - /*0x217*/bind_instr(g1f_list, LFSX, FRD, RA, RB); - /*0x218*/bind_instr(g1f_list, SRW, RA, RS, RB, RC); - /*0x21b*/bind_instr(g1f_list, SRD, RA, RS, RB, RC); - /*0x227*/bind_instr(g1f_list, LVRX, VD, RA, RB); - /*0x237*/bind_instr(g1f_list, LFSUX, FRD, RA, RB); - static const auto& MULHDO = make_instr<0x249>(g1f_list, "MULHDO", &PPUOpcodes::MULHD, RD, RA, RB, RC); - static const auto& MULHWO = make_instr<0x24b>(g1f_list, "MULHWO", &PPUOpcodes::MULHW, RD, RA, RB, RC); - /*0x255*/bind_instr(g1f_list, LSWI, RD, RA, NB); - /*0x256*/bind_instr(g1f_list, SYNC, L_9_10); - /*0x257*/bind_instr(g1f_list, LFDX, FRD, RA, RB); - /*0x277*/bind_instr(g1f_list, LFDUX, FRD, RA, RB); - /*0x287*/bind_instr(g1f_list, STVLX, VS, RA, RB); - /*0x294*/bind_instr(g1f_list, STDBRX, RD, RA, RB); - /*0x296*/bind_instr(g1f_list, STSWX, RS, RA, RB); - /*0x296*/bind_instr(g1f_list, STWBRX, RS, RA, RB); - /*0x297*/bind_instr(g1f_list, STFSX, FRS, RA, RB); - /*0x2a7*/bind_instr(g1f_list, STVRX, VS, RA, RB); - /*0x2b7*/bind_instr(g1f_list, STFSUX, FRS, RA, RB); - /*0x2d5*/bind_instr(g1f_list, STSWI, RS, RA, NB); - /*0x2d7*/bind_instr(g1f_list, STFDX, FRS, RA, RB); - /*0x2d7*/bind_instr(g1f_list, STFDUX, FRS, RA, RB); - /*0x307*/bind_instr(g1f_list, LVLXL, VD, RA, RB); - /*0x316*/bind_instr(g1f_list, LHBRX, RD, RA, RB); - /*0x318*/bind_instr(g1f_list, SRAW, RA, RS, RB, RC); - /*0x31a*/bind_instr(g1f_list, SRAD, RA, RS, RB, RC); - /*0x327*/bind_instr(g1f_list, LVRXL, VD, RA, RB); - /*0x336*/bind_instr(g1f_list, DSS, STRM, L_6); - /*0x338*/bind_instr(g1f_list, SRAWI, RA, RS, SH, RC); - /*0x33a*/bind_instr(g1f_list, SRADI1, RA, RS, sh, RC); - /*0x33b*/bind_instr(g1f_list, SRADI2, RA, RS, sh, RC); - /*0x356*/bind_instr(g1f_list, EIEIO); - /*0x387*/bind_instr(g1f_list, STVLXL, VS, RA, RB); - /*0x396*/bind_instr(g1f_list, STHBRX, RS, RA, RB); - /*0x39a*/bind_instr(g1f_list, EXTSH, RA, RS, RC); - /*0x387*/bind_instr(g1f_list, STVRXL, VS, RA, RB); - /*0x3ba*/bind_instr(g1f_list, EXTSB, RA, RS, RC); - /*0x3d7*/bind_instr(g1f_list, STFIWX, FRS, RA, RB); - /*0x3da*/bind_instr(g1f_list, EXTSW, RA, RS, RC); - /*0x3d6*/bind_instr(g1f_list, ICBI, RA, RB); - /*0x3f6*/bind_instr(g1f_list, DCBZ, RA, RB); - - bind_instr(g3a_list, LD, RD, RA, DS); - bind_instr(g3a_list, LDU, RD, RA, DS); - bind_instr(g3a_list, LWA, RD, RA, DS); - - bind_instr(g3b_list, FDIVS, FRD, FRA, FRB, RC); - bind_instr(g3b_list, FSUBS, FRD, FRA, FRB, RC); - bind_instr(g3b_list, FADDS, FRD, FRA, FRB, RC); - bind_instr(g3b_list, FSQRTS, FRD, FRB, RC); - bind_instr(g3b_list, FRES, FRD, FRB, RC); - bind_instr(g3b_list, FMULS, FRD, FRA, FRC, RC); - bind_instr(g3b_list, FMADDS, FRD, FRA, FRC, FRB, RC); - bind_instr(g3b_list, FMSUBS, FRD, FRA, FRC, FRB, RC); - bind_instr(g3b_list, FNMSUBS, FRD, FRA, FRC, FRB, RC); - bind_instr(g3b_list, FNMADDS, FRD, FRA, FRC, FRB, RC); - - bind_instr(g3e_list, STD, RS, RA, DS); - bind_instr(g3e_list, STDU, RS, RA, DS); - - bind_instr(g3f_list, FSEL, FRD, FRA, FRC, FRB, RC); - bind_instr(g3f_list, FMUL, FRD, FRA, FRC, RC); - bind_instr(g3f_list, FMSUB, FRD, FRA, FRC, FRB, RC); - bind_instr(g3f_list, FMADD, FRD, FRA, FRC, FRB, RC); - bind_instr(g3f_list, FNMSUB, FRD, FRA, FRC, FRB, RC); - bind_instr(g3f_list, FNMADD, FRD, FRA, FRC, FRB, RC); - - bind_instr(g3f_0_list, FDIV, FRD, FRA, FRB, RC); - bind_instr(g3f_0_list, FSUB, FRD, FRA, FRB, RC); - bind_instr(g3f_0_list, FADD, FRD, FRA, FRB, RC); - bind_instr(g3f_0_list, FSQRT, FRD, FRB, RC); - bind_instr(g3f_0_list, FRSQRTE, FRD, FRB, RC); - bind_instr(g3f_0_list, FCMPU, CRFD, FRA, FRB); - bind_instr(g3f_0_list, FRSP, FRD, FRB, RC); - bind_instr(g3f_0_list, FCTIW, FRD, FRB, RC); - bind_instr(g3f_0_list, FCTIWZ, FRD, FRB, RC); - bind_instr(g3f_0_list, FCMPO, CRFD, FRA, FRB); - bind_instr(g3f_0_list, FNEG, FRD, FRB, RC); - bind_instr(g3f_0_list, FMR, FRD, FRB, RC); - bind_instr(g3f_0_list, FNABS, FRD, FRB, RC); - bind_instr(g3f_0_list, FABS, FRD, FRB, RC); - bind_instr(g3f_0_list, FCFID, FRD, FRB, RC); - bind_instr(g3f_0_list, FCTID, FRD, FRB, RC); - bind_instr(g3f_0_list, FCTIDZ, FRD, FRB, RC); - - bind_instr(g3f_0_list, MTFSB1, CRBD, RC); - bind_instr(g3f_0_list, MCRFS, CRFD, CRFS); - bind_instr(g3f_0_list, MTFSB0, CRBD, RC); - bind_instr(g3f_0_list, MTFSFI, CRFD, I, RC); - bind_instr(g3f_0_list, MFFS, FRD, RC); - bind_instr(g3f_0_list, MTFSF, FM, FRB, RC); - - enum - { - r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, - r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, - r22, r23, r24, r25, r26, r27, r28, r29, r30, r31 - }; - - enum - { - cr0, cr1, cr2, cr3, cr4, cr5, cr6, cr7 - }; - } - - namespace implicts - { - using namespace lists; - - inline u32 LIS(u32 reg, u32 imm) { return ADDIS(reg, r0, imm); } - inline u32 LI_(u32 reg, u32 imm) { return ADDI(reg, r0, imm); } - inline u32 NOP() { return ORI(r0, r0, 0); } - inline u32 MR(u32 x, u32 y) { return OR(x, y, y, false); } - inline u32 BLR() { return BCLR(0x10 | 0x04, 0, 0, 0); } - inline u32 BCTR() { return BCCTR(0x10 | 0x04, 0, 0, 0); } - inline u32 BCTRL() { return BCCTR(0x10 | 0x04, 0, 0, 1); } - inline u32 MFCTR(u32 reg) { return MFSPR(reg, 9 << 5); } - inline u32 MTCTR(u32 reg) { return MTSPR(9 << 5, reg); } - inline u32 MFLR(u32 reg) { return MFSPR(reg, 8 << 5); } - inline u32 MTLR(u32 reg) { return MTSPR(8 << 5, reg); } - - inline u32 BNE(u32 cr, s32 imm) { return BC(4, 2 | cr << 2, imm, 0, 0); } - inline u32 BEQ(u32 cr, s32 imm) { return BC(12, 2 | cr << 2, imm, 0, 0); } - inline u32 BGT(u32 cr, s32 imm) { return BC(12, 1 | cr << 2, imm, 0, 0); } - - inline u32 BNE(s32 imm) { return BNE(cr0, imm); } - inline u32 BEQ(s32 imm) { return BEQ(cr0, imm); } - inline u32 BGT(s32 imm) { return BGT(cr0, imm); } - - inline u32 CMPDI(u32 cr, u32 reg, u32 imm) { return CMPI(cr, 1, reg, imm); } - inline u32 CMPDI(u32 reg, u32 imm) { return CMPDI(cr0, reg, imm); } - - inline u32 CMPWI(u32 cr, u32 reg, u32 imm) { return CMPI(cr, 0, reg, imm); } - inline u32 CMPWI(u32 reg, u32 imm) { return CMPWI(cr0, reg, imm); } - - inline u32 CMPLDI(u32 cr, u32 reg, u32 imm) { return CMPLI(cr, 1, reg, imm); } - inline u32 CMPLDI(u32 reg, u32 imm) { return CMPLDI(cr0, reg, imm); } - - inline u32 CMPLWI(u32 cr, u32 reg, u32 imm) { return CMPLI(cr, 0, reg, imm); } - inline u32 CMPLWI(u32 reg, u32 imm) { return CMPLWI(cr0, reg, imm); } - - inline u32 EXTRDI(u32 x, u32 y, u32 n, u32 b) { return RLDICL(x, y, b + n, 64 - b, false); } - inline u32 SRDI(u32 x, u32 y, u32 n) { return RLDICL(x, y, 64 - n, n, false); } - inline u32 CLRLDI(u32 x, u32 y, u32 n) { return RLDICL(x, y, 0, n, false); } - } - - using namespace lists; - using namespace implicts; - #undef bind_instr -}; diff --git a/rpcs3/Emu/Cell/PPUInterpreter.cpp b/rpcs3/Emu/Cell/PPUInterpreter.cpp index ec051c8ab1..1a33bad5a6 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.cpp +++ b/rpcs3/Emu/Cell/PPUInterpreter.cpp @@ -1,13 +1,40 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/Cell/PPUThread.h" -#include "Emu/SysCalls/SysCalls.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/Cell/PPUDecoder.h" -#include "PPUInstrTable.h" +#include "PPUThread.h" #include "PPUInterpreter.h" -#include "PPUInterpreter2.h" + +inline u8 rol8(const u8 x, const u8 n) { return x << n | x >> (8 - n); } +inline u16 rol16(const u16 x, const u16 n) { return x << n | x >> (16 - n); } +inline u32 rol32(const u32 x, const u32 n) { return x << n | x >> (32 - n); } +inline u64 rol64(const u64 x, const u64 n) { return x << n | x >> (64 - n); } +inline u64 dup32(const u32 x) { return x | static_cast(x) << 32; } + +#if defined(__GNUG__) +inline std::uint64_t UMULH64(std::uint64_t a, std::uint64_t b) +{ + std::uint64_t result; + __asm__("mulq %[b]" : "=d" (result) : [a] "a" (a), [b] "rm" (b)); + return result; +} + +inline std::int64_t MULH64(std::int64_t a, std::int64_t b) +{ + std::int64_t result; + __asm__("imulq %[b]" : "=d" (result) : [a] "a" (a), [b] "rm" (b)); + return result; +} +#endif + +#if defined(_MSC_VER) +#define UMULH64 __umulh +#define MULH64 __mulh +#endif + +extern u64 get_timebased_time(); +extern void ppu_execute_syscall(PPUThread& ppu, u64 code); +extern void ppu_execute_function(PPUThread& ppu, u32 index); + +namespace vm { using namespace ps3; } class ppu_scale_table_t { @@ -30,20 +57,10 @@ public: const g_ppu_scale_table; -void ppu_interpreter::NULL_OP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::TDI(PPUThread& ppu, ppu_opcode_t op) { - PPUInterpreter inter(CPU); (*PPU_instr::main_list)(&inter, op.opcode); -} - -void ppu_interpreter::NOP(PPUThread& CPU, ppu_opcode_t op) -{ -} - - -void ppu_interpreter::TDI(PPUThread& CPU, ppu_opcode_t op) -{ - const s64 a = CPU.GPR[op.ra], b = op.simm16; - const u64 a_ = a, b_ = b; // unsigned + const s64 a = ppu.GPR[op.ra], b = op.simm16; + const u64 a_ = a, b_ = b; if (((op.bo & 0x10) && a < b) || ((op.bo & 0x8) && a > b) || @@ -51,14 +68,14 @@ void ppu_interpreter::TDI(PPUThread& CPU, ppu_opcode_t op) ((op.bo & 0x2) && a_ < b_) || ((op.bo & 0x1) && a_ > b_)) { - throw EXCEPTION(""); + throw std::runtime_error("Trap!" HERE); } } -void ppu_interpreter::TWI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::TWI(PPUThread& ppu, ppu_opcode_t op) { - const s32 a = (s32)CPU.GPR[op.ra], b = op.simm16; - const u32 a_ = a, b_ = b; // unsigned + const s32 a = u32(ppu.GPR[op.ra]), b = op.simm16; + const u32 a_ = a, b_ = b; if (((op.bo & 0x10) && a < b) || ((op.bo & 0x8) && a > b) || @@ -66,511 +83,439 @@ void ppu_interpreter::TWI(PPUThread& CPU, ppu_opcode_t op) ((op.bo & 0x2) && a_ < b_) || ((op.bo & 0x1) && a_ > b_)) { - throw EXCEPTION(""); + throw std::runtime_error("Trap!" HERE); } } -void ppu_interpreter::MFVSCR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MFVSCR(PPUThread& ppu, ppu_opcode_t op) { - throw EXCEPTION(""); + throw std::runtime_error("MFVSCR" HERE); } -void ppu_interpreter::MTVSCR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MTVSCR(PPUThread& ppu, ppu_opcode_t op) { - // ignored (MFVSCR disabled) + LOG_WARNING(PPU, "MTVSCR"); } -void ppu_interpreter::VADDCUW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDCUW(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; - CPU.VPR[op.vd].vi = _mm_srli_epi32(_mm_cmpgt_epi32(_mm_xor_si128(b, _mm_set1_epi32(0x80000000)), _mm_xor_si128(a, _mm_set1_epi32(0x7fffffff))), 31); + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; + ppu.VR[op.vd].vi = _mm_srli_epi32(_mm_cmpgt_epi32(_mm_xor_si128(b, _mm_set1_epi32(0x80000000)), _mm_xor_si128(a, _mm_set1_epi32(0x7fffffff))), 31); } -void ppu_interpreter::VADDFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::addfs(CPU.VPR[op.va], CPU.VPR[op.vb]); + ppu.VR[op.vd] = v128::addfs(ppu.VR[op.va], ppu.VR[op.vb]); } -void ppu_interpreter::VADDSBS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDSBS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_adds_epi8(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_adds_epi8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VADDSHS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDSHS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_adds_epi16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_adds_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VADDSWS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDSWS(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va]; - const auto b = CPU.VPR[op.vb]; + const auto a = ppu.VR[op.va]; + const auto b = ppu.VR[op.vb]; const auto s = v128::add32(a, b); // a + b const auto m = (a ^ s) & (b ^ s); // overflow bit const auto x = _mm_srai_epi32(m.vi, 31); // saturation mask const auto y = _mm_srai_epi32(_mm_and_si128(s.vi, m.vi), 31); // positive saturation mask - CPU.VPR[op.vd].vi = _mm_xor_si128(_mm_xor_si128(_mm_srli_epi32(x, 1), y), _mm_or_si128(s.vi, x)); + ppu.VR[op.vd].vi = _mm_xor_si128(_mm_xor_si128(_mm_srli_epi32(x, 1), y), _mm_or_si128(s.vi, x)); } -void ppu_interpreter::VADDUBM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDUBM(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::add8(CPU.VPR[op.va], CPU.VPR[op.vb]); + ppu.VR[op.vd] = v128::add8(ppu.VR[op.va], ppu.VR[op.vb]); } -void ppu_interpreter::VADDUBS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDUBS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_adds_epu8(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_adds_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VADDUHM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDUHM(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::add16(CPU.VPR[op.va], CPU.VPR[op.vb]); + ppu.VR[op.vd] = v128::add16(ppu.VR[op.va], ppu.VR[op.vb]); } -void ppu_interpreter::VADDUHS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDUHS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_adds_epu16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_adds_epu16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VADDUWM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDUWM(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::add32(CPU.VPR[op.va], CPU.VPR[op.vb]); + ppu.VR[op.vd] = v128::add32(ppu.VR[op.va], ppu.VR[op.vb]); } -void ppu_interpreter::VADDUWS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDUWS(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_add_epi32(a, b), _mm_cmpgt_epi32(_mm_xor_si128(b, _mm_set1_epi32(0x80000000)), _mm_xor_si128(a, _mm_set1_epi32(0x7fffffff)))); + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; + ppu.VR[op.vd].vi = _mm_or_si128(_mm_add_epi32(a, b), _mm_cmpgt_epi32(_mm_xor_si128(b, _mm_set1_epi32(0x80000000)), _mm_xor_si128(a, _mm_set1_epi32(0x7fffffff)))); } -void ppu_interpreter::VAND(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VAND(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = CPU.VPR[op.va] & CPU.VPR[op.vb]; + ppu.VR[op.vd] = ppu.VR[op.va] & ppu.VR[op.vb]; } -void ppu_interpreter::VANDC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VANDC(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = CPU.VPR[op.va] & ~CPU.VPR[op.vb]; + ppu.VR[op.vd] = v128::andnot(ppu.VR[op.vb], ppu.VR[op.va]); } -void ppu_interpreter::VAVGSB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VAVGSB(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va]; - const auto b = v128::add8(CPU.VPR[op.vb], v128::from8p(1)); // add 1 + const auto a = ppu.VR[op.va]; + const auto b = v128::add8(ppu.VR[op.vb], v128::from8p(1)); // add 1 const auto summ = v128::add8(a, b) & v128::from8p(0xfe); const auto sign = v128::from8p(0x80); const auto overflow = (((a ^ summ) & (b ^ summ)) ^ summ ^ v128::eq8(b, sign)) & sign; // calculate msb - CPU.VPR[op.vd].vi = _mm_or_si128(overflow.vi, _mm_srli_epi64(summ.vi, 1)); + ppu.VR[op.vd].vi = _mm_or_si128(overflow.vi, _mm_srli_epi64(summ.vi, 1)); } -void ppu_interpreter::VAVGSH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VAVGSH(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va]; - const auto b = v128::add16(CPU.VPR[op.vb], v128::from16p(1)); // add 1 + const auto a = ppu.VR[op.va]; + const auto b = v128::add16(ppu.VR[op.vb], v128::from16p(1)); // add 1 const auto summ = v128::add16(a, b); const auto sign = v128::from16p(0x8000); const auto overflow = (((a ^ summ) & (b ^ summ)) ^ summ ^ v128::eq16(b, sign)) & sign; // calculate msb - CPU.VPR[op.vd].vi = _mm_or_si128(overflow.vi, _mm_srli_epi16(summ.vi, 1)); + ppu.VR[op.vd].vi = _mm_or_si128(overflow.vi, _mm_srli_epi16(summ.vi, 1)); } -void ppu_interpreter::VAVGSW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VAVGSW(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va]; - const auto b = v128::add32(CPU.VPR[op.vb], v128::from32p(1)); // add 1 + const auto a = ppu.VR[op.va]; + const auto b = v128::add32(ppu.VR[op.vb], v128::from32p(1)); // add 1 const auto summ = v128::add32(a, b); const auto sign = v128::from32p(0x80000000); const auto overflow = (((a ^ summ) & (b ^ summ)) ^ summ ^ v128::eq32(b, sign)) & sign; // calculate msb - CPU.VPR[op.vd].vi = _mm_or_si128(overflow.vi, _mm_srli_epi32(summ.vi, 1)); + ppu.VR[op.vd].vi = _mm_or_si128(overflow.vi, _mm_srli_epi32(summ.vi, 1)); } -void ppu_interpreter::VAVGUB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VAVGUB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_avg_epu8(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_avg_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VAVGUH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VAVGUH(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_avg_epu16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_avg_epu16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VAVGUW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VAVGUW(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va]; - const auto b = CPU.VPR[op.vb]; + const auto a = ppu.VR[op.va]; + const auto b = ppu.VR[op.vb]; const auto summ = v128::add32(v128::add32(a, b), v128::from32p(1)); const auto carry = _mm_xor_si128(_mm_slli_epi32(sse_cmpgt_epu32(summ.vi, a.vi), 31), _mm_set1_epi32(0x80000000)); - CPU.VPR[op.vd].vi = _mm_or_si128(carry, _mm_srli_epi32(summ.vi, 1)); + ppu.VR[op.vd].vi = _mm_or_si128(carry, _mm_srli_epi32(summ.vi, 1)); } -void ppu_interpreter::VCFSX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCFSX(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_mul_ps(_mm_cvtepi32_ps(CPU.VPR[op.vb].vi), g_ppu_scale_table[0 - op.vuimm]); + ppu.VR[op.vd].vf = _mm_mul_ps(_mm_cvtepi32_ps(ppu.VR[op.vb].vi), g_ppu_scale_table[0 - op.vuimm]); } -void ppu_interpreter::VCFUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCFUX(PPUThread& ppu, ppu_opcode_t op) { - const auto b = CPU.VPR[op.vb].vi; + const auto b = ppu.VR[op.vb].vi; const auto fix = _mm_and_ps(_mm_castsi128_ps(_mm_srai_epi32(b, 31)), _mm_set1_ps(0x80000000)); - CPU.VPR[op.vd].vf = _mm_mul_ps(_mm_add_ps(_mm_cvtepi32_ps(_mm_and_si128(b, _mm_set1_epi32(0x7fffffff))), fix), g_ppu_scale_table[0 - op.vuimm]); + ppu.VR[op.vd].vf = _mm_mul_ps(_mm_add_ps(_mm_cvtepi32_ps(_mm_and_si128(b, _mm_set1_epi32(0x7fffffff))), fix), g_ppu_scale_table[0 - op.vuimm]); } -void ppu_interpreter::VCMPBFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPBFP(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vf; - const auto b = CPU.VPR[op.vb].vf; + const auto a = ppu.VR[op.va].vf; + const auto b = ppu.VR[op.vb].vf; const auto sign = _mm_castsi128_ps(_mm_set1_epi32(0x80000000)); - const auto bneg = _mm_xor_ps(b, sign); - CPU.VPR[op.vd].vf = _mm_or_ps(_mm_and_ps(_mm_cmpnle_ps(a, b), sign), _mm_and_ps(_mm_cmpnge_ps(a, bneg), _mm_castsi128_ps(_mm_set1_epi32(0x40000000)))); + const auto cmp1 = _mm_cmpnle_ps(a, b); + const auto cmp2 = _mm_cmpnge_ps(a, _mm_xor_ps(b, sign)); + ppu.VR[op.vd].vf = _mm_or_ps(_mm_and_ps(cmp1, sign), _mm_and_ps(cmp2, _mm_castsi128_ps(_mm_set1_epi32(0x40000000)))); + if (op.oe) ppu.SetCR(6, false, false, _mm_movemask_ps(_mm_or_ps(cmp1, cmp2)) == 0, false); } -void ppu_interpreter::VCMPBFP_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPEQFP(PPUThread& ppu, ppu_opcode_t op) { - VCMPBFP(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? 0 : 2; // set 2 if all in bounds + const auto rmask = _mm_movemask_ps(ppu.VR[op.vd].vf = _mm_cmpeq_ps(ppu.VR[op.va].vf, ppu.VR[op.vb].vf)); + if (op.oe) ppu.SetCR(6, rmask == 0xf, false, rmask == 0, false); } -void ppu_interpreter::VCMPEQFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPEQUB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_cmpeq_ps(CPU.VPR[op.va].vf, CPU.VPR[op.vb].vf); + const auto rmask = _mm_movemask_epi8((ppu.VR[op.vd] = v128::eq8(ppu.VR[op.va], ppu.VR[op.vb])).vi); + if (op.oe) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); } -void ppu_interpreter::VCMPEQFP_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPEQUH(PPUThread& ppu, ppu_opcode_t op) { - VCMPEQFP(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; // set 2 if none equal, 8 if all equal + const auto rmask = _mm_movemask_epi8((ppu.VR[op.vd] = v128::eq16(ppu.VR[op.va], ppu.VR[op.vb])).vi); + if (op.oe) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); } -void ppu_interpreter::VCMPEQUB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPEQUW(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::eq8(CPU.VPR[op.va], CPU.VPR[op.vb]); + const auto rmask = _mm_movemask_epi8((ppu.VR[op.vd] = v128::eq32(ppu.VR[op.va], ppu.VR[op.vb])).vi); + if (op.oe) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); } -void ppu_interpreter::VCMPEQUB_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPGEFP(PPUThread& ppu, ppu_opcode_t op) { - VCMPEQUB(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; // set 2 if none equal, 8 if all equal + const auto rmask = _mm_movemask_ps(ppu.VR[op.vd].vf = _mm_cmpge_ps(ppu.VR[op.va].vf, ppu.VR[op.vb].vf)); + if (op.oe) ppu.SetCR(6, rmask == 0xf, false, rmask == 0, false); } -void ppu_interpreter::VCMPEQUH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPGTFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::eq16(CPU.VPR[op.va], CPU.VPR[op.vb]); + const auto rmask = _mm_movemask_ps(ppu.VR[op.vd].vf = _mm_cmpgt_ps(ppu.VR[op.va].vf, ppu.VR[op.vb].vf)); + if (op.oe) ppu.SetCR(6, rmask == 0xf, false, rmask == 0, false); } -void ppu_interpreter::VCMPEQUH_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPGTSB(PPUThread& ppu, ppu_opcode_t op) { - VCMPEQUH(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; // set 2 if none equal, 8 if all equal + const auto rmask = _mm_movemask_epi8(ppu.VR[op.vd].vi = _mm_cmpgt_epi8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi)); + if (op.oe) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); } -void ppu_interpreter::VCMPEQUW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPGTSH(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::eq32(CPU.VPR[op.va], CPU.VPR[op.vb]); + const auto rmask = _mm_movemask_epi8(ppu.VR[op.vd].vi = _mm_cmpgt_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi)); + if (op.oe) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); } -void ppu_interpreter::VCMPEQUW_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPGTSW(PPUThread& ppu, ppu_opcode_t op) { - VCMPEQUW(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; // set 2 if none equal, 8 if all equal + const auto rmask = _mm_movemask_epi8(ppu.VR[op.vd].vi = _mm_cmpgt_epi32(ppu.VR[op.va].vi, ppu.VR[op.vb].vi)); + if (op.oe) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); } -void ppu_interpreter::VCMPGEFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPGTUB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_cmpge_ps(CPU.VPR[op.va].vf, CPU.VPR[op.vb].vf); + const auto rmask = _mm_movemask_epi8(ppu.VR[op.vd].vi = sse_cmpgt_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi)); + if (op.oe) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); } -void ppu_interpreter::VCMPGEFP_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPGTUH(PPUThread& ppu, ppu_opcode_t op) { - VCMPGEFP(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; + const auto rmask = _mm_movemask_epi8(ppu.VR[op.vd].vi = sse_cmpgt_epu16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi)); + if (op.oe) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); } -void ppu_interpreter::VCMPGTFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPGTUW(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_cmpgt_ps(CPU.VPR[op.va].vf, CPU.VPR[op.vb].vf); + const auto rmask = _mm_movemask_epi8(ppu.VR[op.vd].vi = sse_cmpgt_epu32(ppu.VR[op.va].vi, ppu.VR[op.vb].vi)); + if (op.oe) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); } -void ppu_interpreter::VCMPGTFP_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCTSXS(PPUThread& ppu, ppu_opcode_t op) { - VCMPGTFP(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; + const auto scaled = _mm_mul_ps(ppu.VR[op.vb].vf, g_ppu_scale_table[op.vuimm]); + ppu.VR[op.vd].vi = _mm_xor_si128(_mm_cvttps_epi32(scaled), _mm_castps_si128(_mm_cmpge_ps(scaled, _mm_set1_ps(0x80000000)))); } -void ppu_interpreter::VCMPGTSB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCTUXS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_cmpgt_epi8(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); -} - -void ppu_interpreter::VCMPGTSB_(PPUThread& CPU, ppu_opcode_t op) -{ - VCMPGTSB(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; -} - -void ppu_interpreter::VCMPGTSH(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.VPR[op.vd].vi = _mm_cmpgt_epi16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); -} - -void ppu_interpreter::VCMPGTSH_(PPUThread& CPU, ppu_opcode_t op) -{ - VCMPGTSH(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; -} - -void ppu_interpreter::VCMPGTSW(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.VPR[op.vd].vi = _mm_cmpgt_epi32(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); -} - -void ppu_interpreter::VCMPGTSW_(PPUThread& CPU, ppu_opcode_t op) -{ - VCMPGTSW(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; -} - -void ppu_interpreter::VCMPGTUB(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.VPR[op.vd].vi = sse_cmpgt_epu8(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); -} - -void ppu_interpreter::VCMPGTUB_(PPUThread& CPU, ppu_opcode_t op) -{ - VCMPGTUB(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; -} - -void ppu_interpreter::VCMPGTUH(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.VPR[op.vd].vi = sse_cmpgt_epu16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); -} - -void ppu_interpreter::VCMPGTUH_(PPUThread& CPU, ppu_opcode_t op) -{ - VCMPGTUH(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; -} - -void ppu_interpreter::VCMPGTUW(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.VPR[op.vd].vi = sse_cmpgt_epu32(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); -} - -void ppu_interpreter::VCMPGTUW_(PPUThread& CPU, ppu_opcode_t op) -{ - VCMPGTUW(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; -} - -void ppu_interpreter::VCTSXS(PPUThread& CPU, ppu_opcode_t op) -{ - const auto scaled = _mm_mul_ps(CPU.VPR[op.vb].vf, g_ppu_scale_table[op.vuimm]); - CPU.VPR[op.vd].vi = _mm_xor_si128(_mm_cvttps_epi32(scaled), _mm_castps_si128(_mm_cmpge_ps(scaled, _mm_set1_ps(0x80000000)))); -} - -void ppu_interpreter::VCTUXS(PPUThread& CPU, ppu_opcode_t op) -{ - const auto scaled1 = _mm_max_ps(_mm_mul_ps(CPU.VPR[op.vb].vf, g_ppu_scale_table[op.vuimm]), _mm_set1_ps(0.0f)); + const auto scaled1 = _mm_max_ps(_mm_mul_ps(ppu.VR[op.vb].vf, g_ppu_scale_table[op.vuimm]), _mm_set1_ps(0.0f)); const auto scaled2 = _mm_and_ps(_mm_sub_ps(scaled1, _mm_set1_ps(0x80000000)), _mm_cmpge_ps(scaled1, _mm_set1_ps(0x80000000))); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_or_si128(_mm_cvttps_epi32(scaled1), _mm_cvttps_epi32(scaled2)), _mm_castps_si128(_mm_cmpge_ps(scaled1, _mm_set1_ps(0x100000000)))); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_or_si128(_mm_cvttps_epi32(scaled1), _mm_cvttps_epi32(scaled2)), _mm_castps_si128(_mm_cmpge_ps(scaled1, _mm_set1_ps(0x100000000)))); } -void ppu_interpreter::VEXPTEFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VEXPTEFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = sse_exp2_ps(CPU.VPR[op.vb].vf); + ppu.VR[op.vd].vf = sse_exp2_ps(ppu.VR[op.vb].vf); } -void ppu_interpreter::VLOGEFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VLOGEFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = sse_log2_ps(CPU.VPR[op.vb].vf); + ppu.VR[op.vd].vf = sse_log2_ps(ppu.VR[op.vb].vf); } -void ppu_interpreter::VMADDFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMADDFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_add_ps(_mm_mul_ps(CPU.VPR[op.va].vf, CPU.VPR[op.vc].vf), CPU.VPR[op.vb].vf); + ppu.VR[op.vd].vf = _mm_add_ps(_mm_mul_ps(ppu.VR[op.va].vf, ppu.VR[op.vc].vf), ppu.VR[op.vb].vf); } -void ppu_interpreter::VMAXFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMAXFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_max_ps(CPU.VPR[op.va].vf, CPU.VPR[op.vb].vf); + ppu.VR[op.vd].vf = _mm_max_ps(ppu.VR[op.va].vf, ppu.VR[op.vb].vf); } -void ppu_interpreter::VMAXSB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMAXSB(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; const auto m = _mm_cmpgt_epi8(a, b); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_and_si128(m, a), _mm_andnot_si128(m, b)); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_and_si128(m, a), _mm_andnot_si128(m, b)); } -void ppu_interpreter::VMAXSH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMAXSH(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_max_epi16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_max_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VMAXSW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMAXSW(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; const auto m = _mm_cmpgt_epi32(a, b); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_and_si128(m, a), _mm_andnot_si128(m, b)); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_and_si128(m, a), _mm_andnot_si128(m, b)); } -void ppu_interpreter::VMAXUB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMAXUB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_max_epu8(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_max_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VMAXUH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMAXUH(PPUThread& ppu, ppu_opcode_t op) { const auto mask = _mm_set1_epi32(0x80008000); - CPU.VPR[op.vd].vi = _mm_xor_si128(_mm_max_epi16(_mm_xor_si128(CPU.VPR[op.va].vi, mask), _mm_xor_si128(CPU.VPR[op.vb].vi, mask)), mask); + ppu.VR[op.vd].vi = _mm_xor_si128(_mm_max_epi16(_mm_xor_si128(ppu.VR[op.va].vi, mask), _mm_xor_si128(ppu.VR[op.vb].vi, mask)), mask); } -void ppu_interpreter::VMAXUW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMAXUW(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; const auto m = sse_cmpgt_epu32(a, b); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_and_si128(m, a), _mm_andnot_si128(m, b)); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_and_si128(m, a), _mm_andnot_si128(m, b)); } -void ppu_interpreter::VMHADDSHS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMHADDSHS(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; - const auto c = CPU.VPR[op.vc].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; + const auto c = ppu.VR[op.vc].vi; const auto m = _mm_or_si128(_mm_srli_epi16(_mm_mullo_epi16(a, b), 15), _mm_slli_epi16(_mm_mulhi_epi16(a, b), 1)); const auto s = _mm_cmpeq_epi16(m, _mm_set1_epi16(-0x8000)); // detect special case (positive 0x8000) - CPU.VPR[op.vd].vi = _mm_adds_epi16(_mm_adds_epi16(_mm_xor_si128(m, s), c), _mm_srli_epi16(s, 15)); + ppu.VR[op.vd].vi = _mm_adds_epi16(_mm_adds_epi16(_mm_xor_si128(m, s), c), _mm_srli_epi16(s, 15)); } -void ppu_interpreter::VMHRADDSHS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMHRADDSHS(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; - const auto c = CPU.VPR[op.vc].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; + const auto c = ppu.VR[op.vc].vi; const auto m = _mm_mulhrs_epi16(a, b); const auto s = _mm_cmpeq_epi16(m, _mm_set1_epi16(-0x8000)); // detect special case (positive 0x8000) - CPU.VPR[op.vd].vi = _mm_adds_epi16(_mm_adds_epi16(_mm_xor_si128(m, s), c), _mm_srli_epi16(s, 15)); + ppu.VR[op.vd].vi = _mm_adds_epi16(_mm_adds_epi16(_mm_xor_si128(m, s), c), _mm_srli_epi16(s, 15)); } -void ppu_interpreter::VMINFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMINFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_min_ps(CPU.VPR[op.va].vf, CPU.VPR[op.vb].vf); + ppu.VR[op.vd].vf = _mm_min_ps(ppu.VR[op.va].vf, ppu.VR[op.vb].vf); } -void ppu_interpreter::VMINSB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMINSB(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; const auto m = _mm_cmpgt_epi8(a, b); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_andnot_si128(m, a), _mm_and_si128(m, b)); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_andnot_si128(m, a), _mm_and_si128(m, b)); } -void ppu_interpreter::VMINSH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMINSH(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_min_epi16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_min_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VMINSW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMINSW(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; const auto m = _mm_cmpgt_epi32(a, b); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_andnot_si128(m, a), _mm_and_si128(m, b)); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_andnot_si128(m, a), _mm_and_si128(m, b)); } -void ppu_interpreter::VMINUB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMINUB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_min_epu8(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_min_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VMINUH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMINUH(PPUThread& ppu, ppu_opcode_t op) { const auto mask = _mm_set1_epi32(0x80008000); - CPU.VPR[op.vd].vi = _mm_xor_si128(_mm_min_epi16(_mm_xor_si128(CPU.VPR[op.va].vi, mask), _mm_xor_si128(CPU.VPR[op.vb].vi, mask)), mask); + ppu.VR[op.vd].vi = _mm_xor_si128(_mm_min_epi16(_mm_xor_si128(ppu.VR[op.va].vi, mask), _mm_xor_si128(ppu.VR[op.vb].vi, mask)), mask); } -void ppu_interpreter::VMINUW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMINUW(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; const auto m = sse_cmpgt_epu32(a, b); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_andnot_si128(m, a), _mm_and_si128(m, b)); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_andnot_si128(m, a), _mm_and_si128(m, b)); } -void ppu_interpreter::VMLADDUHM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMLADDUHM(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_add_epi16(_mm_mullo_epi16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi), CPU.VPR[op.vc].vi); + ppu.VR[op.vd].vi = _mm_add_epi16(_mm_mullo_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi), ppu.VR[op.vc].vi); } -void ppu_interpreter::VMRGHB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMRGHB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_unpackhi_epi8(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); + ppu.VR[op.vd].vi = _mm_unpackhi_epi8(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); } -void ppu_interpreter::VMRGHH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMRGHH(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_unpackhi_epi16(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); + ppu.VR[op.vd].vi = _mm_unpackhi_epi16(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); } -void ppu_interpreter::VMRGHW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMRGHW(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_unpackhi_epi32(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); + ppu.VR[op.vd].vi = _mm_unpackhi_epi32(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); } -void ppu_interpreter::VMRGLB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMRGLB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_unpacklo_epi8(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); + ppu.VR[op.vd].vi = _mm_unpacklo_epi8(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); } -void ppu_interpreter::VMRGLH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMRGLH(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_unpacklo_epi16(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); + ppu.VR[op.vd].vi = _mm_unpacklo_epi16(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); } -void ppu_interpreter::VMRGLW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMRGLW(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_unpacklo_epi32(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); + ppu.VR[op.vd].vi = _mm_unpacklo_epi32(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); } -void ppu_interpreter::VMSUMMBM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMSUMMBM(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; // signed bytes - const auto b = CPU.VPR[op.vb].vi; // unsigned bytes - const auto c = CPU.VPR[op.vc].vi; + const auto a = ppu.VR[op.va].vi; // signed bytes + const auto b = ppu.VR[op.vb].vi; // unsigned bytes + const auto c = ppu.VR[op.vc].vi; const auto ah = _mm_srai_epi16(a, 8); const auto bh = _mm_srli_epi16(b, 8); const auto al = _mm_srai_epi16(_mm_slli_epi16(a, 8), 8); const auto bl = _mm_and_si128(b, _mm_set1_epi16(0x00ff)); const auto sh = _mm_madd_epi16(ah, bh); const auto sl = _mm_madd_epi16(al, bl); - CPU.VPR[op.vd].vi = _mm_add_epi32(_mm_add_epi32(c, sh), sl); + ppu.VR[op.vd].vi = _mm_add_epi32(_mm_add_epi32(c, sh), sl); } -void ppu_interpreter::VMSUMSHM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMSUMSHM(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_add_epi32(_mm_madd_epi16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi), CPU.VPR[op.vc].vi); + ppu.VR[op.vd].vi = _mm_add_epi32(_mm_madd_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi), ppu.VR[op.vc].vi); } -void ppu_interpreter::VMSUMSHS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMSUMSHS(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + const auto& c = ppu.VR[op.vc]; + for (uint w = 0; w < 4; w++) { s64 result = 0; @@ -578,10 +523,10 @@ void ppu_interpreter::VMSUMSHS(PPUThread& CPU, ppu_opcode_t op) for (uint h = 0; h < 2; h++) { - result += CPU.VPR[op.va]._s16[w * 2 + h] * CPU.VPR[op.vb]._s16[w * 2 + h]; + result += a._s16[w * 2 + h] * b._s16[w * 2 + h]; } - result += CPU.VPR[op.vc]._s32[w]; + result += c._s32[w]; if (result > 0x7fffffff) { @@ -594,15 +539,15 @@ void ppu_interpreter::VMSUMSHS(PPUThread& CPU, ppu_opcode_t op) else saturated = (s32)result; - CPU.VPR[op.vd]._s32[w] = saturated; + d._s32[w] = saturated; } } -void ppu_interpreter::VMSUMUBM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMSUMUBM(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; - const auto c = CPU.VPR[op.vc].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; + const auto c = ppu.VR[op.vc].vi; const auto mask = _mm_set1_epi16(0x00ff); const auto ah = _mm_srli_epi16(a, 8); const auto al = _mm_and_si128(a, mask); @@ -610,23 +555,28 @@ void ppu_interpreter::VMSUMUBM(PPUThread& CPU, ppu_opcode_t op) const auto bl = _mm_and_si128(b, mask); const auto sh = _mm_madd_epi16(ah, bh); const auto sl = _mm_madd_epi16(al, bl); - CPU.VPR[op.vd].vi = _mm_add_epi32(_mm_add_epi32(c, sh), sl); + ppu.VR[op.vd].vi = _mm_add_epi32(_mm_add_epi32(c, sh), sl); } -void ppu_interpreter::VMSUMUHM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMSUMUHM(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; - const auto c = CPU.VPR[op.vc].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; + const auto c = ppu.VR[op.vc].vi; const auto ml = _mm_mullo_epi16(a, b); // low results const auto mh = _mm_mulhi_epu16(a, b); // high results const auto ls = _mm_add_epi32(_mm_srli_epi32(ml, 16), _mm_and_si128(ml, _mm_set1_epi32(0x0000ffff))); const auto hs = _mm_add_epi32(_mm_slli_epi32(mh, 16), _mm_and_si128(mh, _mm_set1_epi32(0xffff0000))); - CPU.VPR[op.vd].vi = _mm_add_epi32(_mm_add_epi32(c, ls), hs); + ppu.VR[op.vd].vi = _mm_add_epi32(_mm_add_epi32(c, ls), hs); } -void ppu_interpreter::VMSUMUHS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMSUMUHS(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + const auto& c = ppu.VR[op.vc]; + for (uint w = 0; w < 4; w++) { u64 result = 0; @@ -634,10 +584,10 @@ void ppu_interpreter::VMSUMUHS(PPUThread& CPU, ppu_opcode_t op) for (uint h = 0; h < 2; h++) { - result += (u64)CPU.VPR[op.va]._u16[w * 2 + h] * (u64)CPU.VPR[op.vb]._u16[w * 2 + h]; + result += (u64)a._u16[w * 2 + h] * (u64)b._u16[w * 2 + h]; } - result += CPU.VPR[op.vc]._u32[w]; + result += c._u32[w]; if (result > 0xffffffffu) { @@ -646,88 +596,89 @@ void ppu_interpreter::VMSUMUHS(PPUThread& CPU, ppu_opcode_t op) else saturated = (u32)result; - CPU.VPR[op.vd]._u32[w] = saturated; + d._u32[w] = saturated; } } -void ppu_interpreter::VMULESB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMULESB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_mullo_epi16(_mm_srai_epi16(CPU.VPR[op.va].vi, 8), _mm_srai_epi16(CPU.VPR[op.vb].vi, 8)); + ppu.VR[op.vd].vi = _mm_mullo_epi16(_mm_srai_epi16(ppu.VR[op.va].vi, 8), _mm_srai_epi16(ppu.VR[op.vb].vi, 8)); } -void ppu_interpreter::VMULESH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMULESH(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_madd_epi16(_mm_srli_epi32(CPU.VPR[op.va].vi, 16), _mm_srli_epi32(CPU.VPR[op.vb].vi, 16)); + ppu.VR[op.vd].vi = _mm_madd_epi16(_mm_srli_epi32(ppu.VR[op.va].vi, 16), _mm_srli_epi32(ppu.VR[op.vb].vi, 16)); } -void ppu_interpreter::VMULEUB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMULEUB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_mullo_epi16(_mm_srli_epi16(CPU.VPR[op.va].vi, 8), _mm_srli_epi16(CPU.VPR[op.vb].vi, 8)); + ppu.VR[op.vd].vi = _mm_mullo_epi16(_mm_srli_epi16(ppu.VR[op.va].vi, 8), _mm_srli_epi16(ppu.VR[op.vb].vi, 8)); } -void ppu_interpreter::VMULEUH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMULEUH(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; const auto ml = _mm_mullo_epi16(a, b); const auto mh = _mm_mulhi_epu16(a, b); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_srli_epi32(ml, 16), _mm_and_si128(mh, _mm_set1_epi32(0xffff0000))); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_srli_epi32(ml, 16), _mm_and_si128(mh, _mm_set1_epi32(0xffff0000))); } -void ppu_interpreter::VMULOSB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMULOSB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_mullo_epi16(_mm_srai_epi16(_mm_slli_epi16(CPU.VPR[op.va].vi, 8), 8), _mm_srai_epi16(_mm_slli_epi16(CPU.VPR[op.vb].vi, 8), 8)); + ppu.VR[op.vd].vi = _mm_mullo_epi16(_mm_srai_epi16(_mm_slli_epi16(ppu.VR[op.va].vi, 8), 8), _mm_srai_epi16(_mm_slli_epi16(ppu.VR[op.vb].vi, 8), 8)); } -void ppu_interpreter::VMULOSH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMULOSH(PPUThread& ppu, ppu_opcode_t op) { const auto mask = _mm_set1_epi32(0x0000ffff); - CPU.VPR[op.vd].vi = _mm_madd_epi16(_mm_and_si128(CPU.VPR[op.va].vi, mask), _mm_and_si128(CPU.VPR[op.vb].vi, mask)); + ppu.VR[op.vd].vi = _mm_madd_epi16(_mm_and_si128(ppu.VR[op.va].vi, mask), _mm_and_si128(ppu.VR[op.vb].vi, mask)); } -void ppu_interpreter::VMULOUB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMULOUB(PPUThread& ppu, ppu_opcode_t op) { const auto mask = _mm_set1_epi16(0x00ff); - CPU.VPR[op.vd].vi = _mm_mullo_epi16(_mm_and_si128(CPU.VPR[op.va].vi, mask), _mm_and_si128(CPU.VPR[op.vb].vi, mask)); + ppu.VR[op.vd].vi = _mm_mullo_epi16(_mm_and_si128(ppu.VR[op.va].vi, mask), _mm_and_si128(ppu.VR[op.vb].vi, mask)); } -void ppu_interpreter::VMULOUH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMULOUH(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; const auto ml = _mm_mullo_epi16(a, b); const auto mh = _mm_mulhi_epu16(a, b); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_slli_epi32(mh, 16), _mm_and_si128(ml, _mm_set1_epi32(0x0000ffff))); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_slli_epi32(mh, 16), _mm_and_si128(ml, _mm_set1_epi32(0x0000ffff))); } -void ppu_interpreter::VNMSUBFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VNMSUBFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_sub_ps(CPU.VPR[op.vb].vf, _mm_mul_ps(CPU.VPR[op.va].vf, CPU.VPR[op.vc].vf)); + ppu.VR[op.vd].vf = _mm_sub_ps(ppu.VR[op.vb].vf, _mm_mul_ps(ppu.VR[op.va].vf, ppu.VR[op.vc].vf)); } -void ppu_interpreter::VNOR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VNOR(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = ~(CPU.VPR[op.va] | CPU.VPR[op.vb]); + ppu.VR[op.vd] = ~(ppu.VR[op.va] | ppu.VR[op.vb]); } -void ppu_interpreter::VOR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VOR(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = CPU.VPR[op.va] | CPU.VPR[op.vb]; + ppu.VR[op.vd] = ppu.VR[op.va] | ppu.VR[op.vb]; } -void ppu_interpreter::VPERM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPERM(PPUThread& ppu, ppu_opcode_t op) { - const auto index = _mm_andnot_si128(CPU.VPR[op.vc].vi, _mm_set1_epi8(0x1f)); + const auto index = _mm_andnot_si128(ppu.VR[op.vc].vi, _mm_set1_epi8(0x1f)); const auto mask = _mm_cmpgt_epi8(index, _mm_set1_epi8(0xf)); - const auto sa = _mm_shuffle_epi8(CPU.VPR[op.va].vi, index); - const auto sb = _mm_shuffle_epi8(CPU.VPR[op.vb].vi, index); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_and_si128(mask, sa), _mm_andnot_si128(mask, sb)); + const auto sa = _mm_shuffle_epi8(ppu.VR[op.va].vi, index); + const auto sb = _mm_shuffle_epi8(ppu.VR[op.vb].vi, index); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_and_si128(mask, sa), _mm_andnot_si128(mask, sb)); } -void ppu_interpreter::VPKPX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPKPX(PPUThread& ppu, ppu_opcode_t op) { - v128 VA = CPU.VPR[op.va]; - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + v128 VB = ppu.VR[op.vb]; for (uint h = 0; h < 4; h++) { u16 bb7 = VB._u8[15 - (h * 4 + 0)] & 0x1; @@ -739,32 +690,32 @@ void ppu_interpreter::VPKPX(PPUThread& CPU, ppu_opcode_t op) u16 ab16 = VA._u8[15 - (h * 4 + 2)] >> 3; u16 ab24 = VA._u8[15 - (h * 4 + 3)] >> 3; - CPU.VPR[op.vd]._u16[3 - h] = (bb7 << 15) | (bb8 << 10) | (bb16 << 5) | bb24; - CPU.VPR[op.vd]._u16[4 + (3 - h)] = (ab7 << 15) | (ab8 << 10) | (ab16 << 5) | ab24; + d._u16[3 - h] = (bb7 << 15) | (bb8 << 10) | (bb16 << 5) | bb24; + d._u16[4 + (3 - h)] = (ab7 << 15) | (ab8 << 10) | (ab16 << 5) | ab24; } } -void ppu_interpreter::VPKSHSS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPKSHSS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_packs_epi16(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); + ppu.VR[op.vd].vi = _mm_packs_epi16(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); } -void ppu_interpreter::VPKSHUS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPKSHUS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_packus_epi16(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); + ppu.VR[op.vd].vi = _mm_packus_epi16(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); } -void ppu_interpreter::VPKSWSS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPKSWSS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_packs_epi32(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); + ppu.VR[op.vd].vi = _mm_packs_epi32(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); } -void ppu_interpreter::VPKSWUS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPKSWUS(PPUThread& ppu, ppu_opcode_t op) { - //CPU.VPR[op.vd].vi = _mm_packus_epi32(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); - - v128 VA = CPU.VPR[op.va]; - v128 VB = CPU.VPR[op.vb]; + //ppu.VR[op.vd].vi = _mm_packus_epi32(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + v128 VB = ppu.VR[op.vb]; for (uint h = 0; h < 4; h++) { s32 result = VA._s32[h]; @@ -778,7 +729,7 @@ void ppu_interpreter::VPKSWUS(PPUThread& CPU, ppu_opcode_t op) result = 0; } - CPU.VPR[op.vd]._u16[h + 4] = result; + d._u16[h + 4] = result; result = VB._s32[h]; @@ -791,25 +742,27 @@ void ppu_interpreter::VPKSWUS(PPUThread& CPU, ppu_opcode_t op) result = 0; } - CPU.VPR[op.vd]._u16[h] = result; + d._u16[h] = result; } } -void ppu_interpreter::VPKUHUM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPKUHUM(PPUThread& ppu, ppu_opcode_t op) { - v128 VA = CPU.VPR[op.va]; - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + v128 VB = ppu.VR[op.vb]; for (uint b = 0; b < 8; b++) { - CPU.VPR[op.vd]._u8[b + 8] = VA._u8[b * 2]; - CPU.VPR[op.vd]._u8[b] = VB._u8[b * 2]; + d._u8[b + 8] = VA._u8[b * 2]; + d._u8[b] = VB._u8[b * 2]; } } -void ppu_interpreter::VPKUHUS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPKUHUS(PPUThread& ppu, ppu_opcode_t op) { - v128 VA = CPU.VPR[op.va]; - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + v128 VB = ppu.VR[op.vb]; for (uint b = 0; b < 8; b++) { u16 result = VA._u16[b]; @@ -819,7 +772,7 @@ void ppu_interpreter::VPKUHUS(PPUThread& CPU, ppu_opcode_t op) result = UINT8_MAX; } - CPU.VPR[op.vd]._u8[b + 8] = (u8)result; + d._u8[b + 8] = (u8)result; result = VB._u16[b]; @@ -828,25 +781,27 @@ void ppu_interpreter::VPKUHUS(PPUThread& CPU, ppu_opcode_t op) result = UINT8_MAX; } - CPU.VPR[op.vd]._u8[b] = (u8)result; + d._u8[b] = (u8)result; } } -void ppu_interpreter::VPKUWUM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPKUWUM(PPUThread& ppu, ppu_opcode_t op) { - v128 VA = CPU.VPR[op.va]; - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + v128 VB = ppu.VR[op.vb]; for (uint h = 0; h < 4; h++) { - CPU.VPR[op.vd]._u16[h + 4] = VA._u16[h * 2]; - CPU.VPR[op.vd]._u16[h] = VB._u16[h * 2]; + d._u16[h + 4] = VA._u16[h * 2]; + d._u16[h] = VB._u16[h * 2]; } } -void ppu_interpreter::VPKUWUS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPKUWUS(PPUThread& ppu, ppu_opcode_t op) { - v128 VA = CPU.VPR[op.va]; - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + v128 VB = ppu.VR[op.vb]; for (uint h = 0; h < 4; h++) { u32 result = VA._u32[h]; @@ -856,7 +811,7 @@ void ppu_interpreter::VPKUWUS(PPUThread& CPU, ppu_opcode_t op) result = UINT16_MAX; } - CPU.VPR[op.vd]._u16[h + 4] = result; + d._u16[h + 4] = result; result = VB._u32[h]; @@ -865,830 +820,935 @@ void ppu_interpreter::VPKUWUS(PPUThread& CPU, ppu_opcode_t op) result = UINT16_MAX; } - CPU.VPR[op.vd]._u16[h] = result; + d._u16[h] = result; } } -void ppu_interpreter::VREFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VREFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_rcp_ps(CPU.VPR[op.vb].vf); + ppu.VR[op.vd].vf = _mm_rcp_ps(ppu.VR[op.vb].vf); } -void ppu_interpreter::VRFIM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VRFIM(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - const float b = CPU.VPR[op.vb]._f[w]; - CPU.VPR[op.vd]._f[w] = floorf(CPU.VPR[op.vb]._f[w]); + d._f[w] = floorf(b._f[w]); } } -void ppu_interpreter::VRFIN(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VRFIN(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - const float b = CPU.VPR[op.vb]._f[w]; - CPU.VPR[op.vd]._f[w] = nearbyintf(CPU.VPR[op.vb]._f[w]); + d._f[w] = nearbyintf(b._f[w]); } } -void ppu_interpreter::VRFIP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VRFIP(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - const float b = CPU.VPR[op.vb]._f[w]; - CPU.VPR[op.vd]._f[w] = ceilf(CPU.VPR[op.vb]._f[w]); + d._f[w] = ceilf(b._f[w]); } } -void ppu_interpreter::VRFIZ(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VRFIZ(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - const float b = CPU.VPR[op.vb]._f[w]; - CPU.VPR[op.vd]._f[w] = truncf(CPU.VPR[op.vb]._f[w]); + d._f[w] = truncf(b._f[w]); } } -void ppu_interpreter::VRLB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VRLB(PPUThread& ppu, ppu_opcode_t op) { - for (uint b = 0; b < 16; b++) + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + + for (uint i = 0; i < 16; i++) { - int nRot = CPU.VPR[op.vb]._u8[b] & 0x7; - - CPU.VPR[op.vd]._u8[b] = (CPU.VPR[op.va]._u8[b] << nRot) | (CPU.VPR[op.va]._u8[b] >> (8 - nRot)); + d._u8[i] = rol8(a._u8[i], b._u8[i] & 0x7); } } -void ppu_interpreter::VRLH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VRLH(PPUThread& ppu, ppu_opcode_t op) { - for (uint h = 0; h < 8; h++) + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + + for (uint i = 0; i < 8; i++) { - CPU.VPR[op.vd]._u16[h] = rotl16(CPU.VPR[op.va]._u16[h], CPU.VPR[op.vb]._u8[h * 2] & 0xf); + d._u16[i] = rol16(a._u16[i], b._u8[i * 2] & 0xf); } } -void ppu_interpreter::VRLW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VRLW(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._u32[w] = (u32)rotl32(CPU.VPR[op.va]._u32[w], CPU.VPR[op.vb]._u8[w * 4] & 0x1f); + d._u32[w] = rol32(a._u32[w], b._u8[w * 4] & 0x1f); } } -void ppu_interpreter::VRSQRTEFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VRSQRTEFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_rsqrt_ps(CPU.VPR[op.vb].vf); + ppu.VR[op.vd].vf = _mm_rsqrt_ps(ppu.VR[op.vb].vf); } -void ppu_interpreter::VSEL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSEL(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = (CPU.VPR[op.vb] & CPU.VPR[op.vc]) | (CPU.VPR[op.va] & ~CPU.VPR[op.vc]); + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + const auto& c = ppu.VR[op.vc]; + + d = (b & c) | v128::andnot(c, a); } -void ppu_interpreter::VSL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSL(PPUThread& ppu, ppu_opcode_t op) { - v128 VA = CPU.VPR[op.va]; - u8 sh = CPU.VPR[op.vb]._u8[0] & 0x7; + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + u8 sh = ppu.VR[op.vb]._u8[0] & 0x7; - CPU.VPR[op.vd]._u8[0] = VA._u8[0] << sh; + d._u8[0] = VA._u8[0] << sh; for (uint b = 1; b < 16; b++) { - CPU.VPR[op.vd]._u8[b] = (VA._u8[b] << sh) | (VA._u8[b - 1] >> (8 - sh)); + d._u8[b] = (VA._u8[b] << sh) | (VA._u8[b - 1] >> (8 - sh)); } } -void ppu_interpreter::VSLB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSLB(PPUThread& ppu, ppu_opcode_t op) { - for (uint b = 0; b < 16; b++) + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + + for (uint i = 0; i < 16; i++) { - CPU.VPR[op.vd]._u8[b] = CPU.VPR[op.va]._u8[b] << (CPU.VPR[op.vb]._u8[b] & 0x7); + d._u8[i] = a._u8[i] << (b._u8[i] & 0x7); } } -void ppu_interpreter::VSLDOI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSLDOI(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; u8 tmpSRC[32]; - std::memcpy(tmpSRC, CPU.VPR + op.vb, 16); - std::memcpy(tmpSRC + 16, CPU.VPR + op.va, 16); + std::memcpy(tmpSRC, &ppu.VR[op.vb], 16); + std::memcpy(tmpSRC + 16, &ppu.VR[op.va], 16); for (uint b = 0; b<16; b++) { - CPU.VPR[op.vd]._u8[15 - b] = tmpSRC[31 - (b + op.vsh)]; + d._u8[15 - b] = tmpSRC[31 - (b + op.vsh)]; } } -void ppu_interpreter::VSLH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSLH(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint h = 0; h < 8; h++) { - CPU.VPR[op.vd]._u16[h] = CPU.VPR[op.va]._u16[h] << (CPU.VPR[op.vb]._u16[h] & 0xf); + d._u16[h] = a._u16[h] << (b._u16[h] & 0xf); } } -void ppu_interpreter::VSLO(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSLO(PPUThread& ppu, ppu_opcode_t op) { - v128 VA = CPU.VPR[op.va]; - u8 nShift = (CPU.VPR[op.vb]._u8[0] >> 3) & 0xf; + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + u8 nShift = (ppu.VR[op.vb]._u8[0] >> 3) & 0xf; - CPU.VPR[op.vd].clear(); + d.clear(); for (u8 b = 0; b < 16 - nShift; b++) { - CPU.VPR[op.vd]._u8[15 - b] = VA._u8[15 - (b + nShift)]; + d._u8[15 - b] = VA._u8[15 - (b + nShift)]; } } -void ppu_interpreter::VSLW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSLW(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._u32[w] = CPU.VPR[op.va]._u32[w] << (CPU.VPR[op.vb]._u32[w] & 0x1f); + d._u32[w] = a._u32[w] << (b._u32[w] & 0x1f); } } -void ppu_interpreter::VSPLTB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSPLTB(PPUThread& ppu, ppu_opcode_t op) { - u8 byte = CPU.VPR[op.vb]._u8[15 - op.vuimm]; + auto& d = ppu.VR[op.vd]; + u8 byte = ppu.VR[op.vb]._u8[15 - op.vuimm]; for (uint b = 0; b < 16; b++) { - CPU.VPR[op.vd]._u8[b] = byte; + d._u8[b] = byte; } } -void ppu_interpreter::VSPLTH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSPLTH(PPUThread& ppu, ppu_opcode_t op) { - assert(op.vuimm < 8); + auto& d = ppu.VR[op.vd]; + Expects(op.vuimm < 8); - u16 hword = CPU.VPR[op.vb]._u16[7 - op.vuimm]; + u16 hword = ppu.VR[op.vb]._u16[7 - op.vuimm]; for (uint h = 0; h < 8; h++) { - CPU.VPR[op.vd]._u16[h] = hword; + d._u16[h] = hword; } } -void ppu_interpreter::VSPLTISB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSPLTISB(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const s8 imm = op.vsimm; + for (uint b = 0; b < 16; b++) { - CPU.VPR[op.vd]._u8[b] = op.vsimm; + d._u8[b] = imm; } } -void ppu_interpreter::VSPLTISH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSPLTISH(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const s16 imm = op.vsimm; + for (uint h = 0; h < 8; h++) { - CPU.VPR[op.vd]._u16[h] = (s16)op.vsimm; + d._u16[h] = imm; } } -void ppu_interpreter::VSPLTISW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSPLTISW(PPUThread& ppu, ppu_opcode_t op) { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[op.vd]._u32[w] = (s32)op.vsimm; - } -} - -void ppu_interpreter::VSPLTW(PPUThread& CPU, ppu_opcode_t op) -{ - assert(op.vuimm < 4); - - u32 word = CPU.VPR[op.vb]._u32[3 - op.vuimm]; + auto& d = ppu.VR[op.vd]; + const s32 imm = op.vsimm; for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._u32[w] = word; + d._u32[w] = imm; } } -void ppu_interpreter::VSR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSPLTW(PPUThread& ppu, ppu_opcode_t op) { - v128 VA = CPU.VPR[op.va]; - u8 sh = CPU.VPR[op.vb]._u8[0] & 0x7; + auto& d = ppu.VR[op.vd]; + Expects(op.vuimm < 4); - CPU.VPR[op.vd]._u8[15] = VA._u8[15] >> sh; + u32 word = ppu.VR[op.vb]._u32[3 - op.vuimm]; + + for (uint w = 0; w < 4; w++) + { + d._u32[w] = word; + } +} + +void ppu_interpreter::VSR(PPUThread& ppu, ppu_opcode_t op) +{ + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + u8 sh = ppu.VR[op.vb]._u8[0] & 0x7; + + d._u8[15] = VA._u8[15] >> sh; for (uint b = 14; ~b; b--) { - CPU.VPR[op.vd]._u8[b] = (VA._u8[b] >> sh) | (VA._u8[b + 1] << (8 - sh)); + d._u8[b] = (VA._u8[b] >> sh) | (VA._u8[b + 1] << (8 - sh)); } } -void ppu_interpreter::VSRAB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSRAB(PPUThread& ppu, ppu_opcode_t op) { - for (uint b = 0; b < 16; b++) + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + + for (uint i = 0; i < 16; i++) { - CPU.VPR[op.vd]._s8[b] = CPU.VPR[op.va]._s8[b] >> (CPU.VPR[op.vb]._u8[b] & 0x7); + d._s8[i] = a._s8[i] >> (b._u8[i] & 0x7); } } -void ppu_interpreter::VSRAH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSRAH(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint h = 0; h < 8; h++) { - CPU.VPR[op.vd]._s16[h] = CPU.VPR[op.va]._s16[h] >> (CPU.VPR[op.vb]._u16[h] & 0xf); + d._s16[h] = a._s16[h] >> (b._u16[h] & 0xf); } } -void ppu_interpreter::VSRAW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSRAW(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._s32[w] = CPU.VPR[op.va]._s32[w] >> (CPU.VPR[op.vb]._u32[w] & 0x1f); + d._s32[w] = a._s32[w] >> (b._u32[w] & 0x1f); } } -void ppu_interpreter::VSRB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSRB(PPUThread& ppu, ppu_opcode_t op) { - for (uint b = 0; b < 16; b++) + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + + for (uint i = 0; i < 16; i++) { - CPU.VPR[op.vd]._u8[b] = CPU.VPR[op.va]._u8[b] >> (CPU.VPR[op.vb]._u8[b] & 0x7); + d._u8[i] = a._u8[i] >> (b._u8[i] & 0x7); } } -void ppu_interpreter::VSRH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSRH(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint h = 0; h < 8; h++) { - CPU.VPR[op.vd]._u16[h] = CPU.VPR[op.va]._u16[h] >> (CPU.VPR[op.vb]._u16[h] & 0xf); + d._u16[h] = a._u16[h] >> (b._u16[h] & 0xf); } } -void ppu_interpreter::VSRO(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSRO(PPUThread& ppu, ppu_opcode_t op) { - v128 VA = CPU.VPR[op.va]; - u8 nShift = (CPU.VPR[op.vb]._u8[0] >> 3) & 0xf; + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + u8 nShift = (ppu.VR[op.vb]._u8[0] >> 3) & 0xf; - CPU.VPR[op.vd].clear(); + d.clear(); for (u8 b = 0; b < 16 - nShift; b++) { - CPU.VPR[op.vd]._u8[b] = VA._u8[b + nShift]; + d._u8[b] = VA._u8[b + nShift]; } } -void ppu_interpreter::VSRW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSRW(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._u32[w] = CPU.VPR[op.va]._u32[w] >> (CPU.VPR[op.vb]._u32[w] & 0x1f); + d._u32[w] = a._u32[w] >> (b._u32[w] & 0x1f); } } -void ppu_interpreter::VSUBCUW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBCUW(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._u32[w] = CPU.VPR[op.va]._u32[w] < CPU.VPR[op.vb]._u32[w] ? 0 : 1; + d._u32[w] = a._u32[w] < b._u32[w] ? 0 : 1; } } -void ppu_interpreter::VSUBFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::subfs(CPU.VPR[op.va], CPU.VPR[op.vb]); + ppu.VR[op.vd] = v128::subfs(ppu.VR[op.va], ppu.VR[op.vb]); } -void ppu_interpreter::VSUBSBS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBSBS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_subs_epi8(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_subs_epi8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VSUBSHS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBSHS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_subs_epi16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_subs_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VSUBSWS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBSWS(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - s64 result = (s64)CPU.VPR[op.va]._s32[w] - (s64)CPU.VPR[op.vb]._s32[w]; + s64 result = (s64)a._s32[w] - (s64)b._s32[w]; if (result < INT32_MIN) { - CPU.VPR[op.vd]._s32[w] = (s32)INT32_MIN; + d._s32[w] = (s32)INT32_MIN; } else if (result > INT32_MAX) { - CPU.VPR[op.vd]._s32[w] = (s32)INT32_MAX; + d._s32[w] = (s32)INT32_MAX; } else - CPU.VPR[op.vd]._s32[w] = (s32)result; + d._s32[w] = (s32)result; } } -void ppu_interpreter::VSUBUBM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBUBM(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::sub8(CPU.VPR[op.va], CPU.VPR[op.vb]); + ppu.VR[op.vd] = v128::sub8(ppu.VR[op.va], ppu.VR[op.vb]); } -void ppu_interpreter::VSUBUBS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBUBS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_subs_epu8(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_subs_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VSUBUHM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBUHM(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::sub16(CPU.VPR[op.va], CPU.VPR[op.vb]); + ppu.VR[op.vd] = v128::sub16(ppu.VR[op.va], ppu.VR[op.vb]); } -void ppu_interpreter::VSUBUHS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBUHS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_subs_epu16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_subs_epu16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VSUBUWM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBUWM(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::sub32(CPU.VPR[op.va], CPU.VPR[op.vb]); + ppu.VR[op.vd] = v128::sub32(ppu.VR[op.va], ppu.VR[op.vb]); } -void ppu_interpreter::VSUBUWS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBUWS(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - s64 result = (s64)CPU.VPR[op.va]._u32[w] - (s64)CPU.VPR[op.vb]._u32[w]; + s64 result = (s64)a._u32[w] - (s64)b._u32[w]; if (result < 0) { - CPU.VPR[op.vd]._u32[w] = 0; + d._u32[w] = 0; } else - CPU.VPR[op.vd]._u32[w] = (u32)result; + d._u32[w] = (u32)result; } } -void ppu_interpreter::VSUMSWS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUMSWS(PPUThread& ppu, ppu_opcode_t op) { - s64 sum = CPU.VPR[op.vb]._s32[0]; + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + + s64 sum = b._s32[0]; for (uint w = 0; w < 4; w++) { - sum += CPU.VPR[op.va]._s32[w]; + sum += a._s32[w]; } - CPU.VPR[op.vd].clear(); + d.clear(); if (sum > INT32_MAX) { - CPU.VPR[op.vd]._s32[0] = (s32)INT32_MAX; + d._s32[0] = (s32)INT32_MAX; } else if (sum < INT32_MIN) { - CPU.VPR[op.vd]._s32[0] = (s32)INT32_MIN; + d._s32[0] = (s32)INT32_MIN; } else - CPU.VPR[op.vd]._s32[0] = (s32)sum; + d._s32[0] = (s32)sum; } -void ppu_interpreter::VSUM2SWS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUM2SWS(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint n = 0; n < 2; n++) { - s64 sum = (s64)CPU.VPR[op.va]._s32[n * 2] + CPU.VPR[op.va]._s32[n * 2 + 1] + CPU.VPR[op.vb]._s32[n * 2]; + s64 sum = (s64)a._s32[n * 2] + a._s32[n * 2 + 1] + b._s32[n * 2]; if (sum > INT32_MAX) { - CPU.VPR[op.vd]._s32[n * 2] = (s32)INT32_MAX; + d._s32[n * 2] = (s32)INT32_MAX; } else if (sum < INT32_MIN) { - CPU.VPR[op.vd]._s32[n * 2] = (s32)INT32_MIN; + d._s32[n * 2] = (s32)INT32_MIN; } else - CPU.VPR[op.vd]._s32[n * 2] = (s32)sum; + d._s32[n * 2] = (s32)sum; } - CPU.VPR[op.vd]._s32[1] = 0; - CPU.VPR[op.vd]._s32[3] = 0; + d._s32[1] = 0; + d._s32[3] = 0; } -void ppu_interpreter::VSUM4SBS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUM4SBS(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - s64 sum = CPU.VPR[op.vb]._s32[w]; + s64 sum = b._s32[w]; for (uint b = 0; b < 4; b++) { - sum += CPU.VPR[op.va]._s8[w * 4 + b]; + sum += a._s8[w * 4 + b]; } if (sum > INT32_MAX) { - CPU.VPR[op.vd]._s32[w] = (s32)INT32_MAX; + d._s32[w] = (s32)INT32_MAX; } else if (sum < INT32_MIN) { - CPU.VPR[op.vd]._s32[w] = (s32)INT32_MIN; + d._s32[w] = (s32)INT32_MIN; } else - CPU.VPR[op.vd]._s32[w] = (s32)sum; + d._s32[w] = (s32)sum; } } -void ppu_interpreter::VSUM4SHS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUM4SHS(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - s64 sum = CPU.VPR[op.vb]._s32[w]; + s64 sum = b._s32[w]; for (uint h = 0; h < 2; h++) { - sum += CPU.VPR[op.va]._s16[w * 2 + h]; + sum += a._s16[w * 2 + h]; } if (sum > INT32_MAX) { - CPU.VPR[op.vd]._s32[w] = (s32)INT32_MAX; + d._s32[w] = (s32)INT32_MAX; } else if (sum < INT32_MIN) { - CPU.VPR[op.vd]._s32[w] = (s32)INT32_MIN; + d._s32[w] = (s32)INT32_MIN; } else - CPU.VPR[op.vd]._s32[w] = (s32)sum; + d._s32[w] = (s32)sum; } } -void ppu_interpreter::VSUM4UBS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUM4UBS(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - u64 sum = CPU.VPR[op.vb]._u32[w]; + u64 sum = b._u32[w]; for (uint b = 0; b < 4; b++) { - sum += CPU.VPR[op.va]._u8[w * 4 + b]; + sum += a._u8[w * 4 + b]; } if (sum > UINT32_MAX) { - CPU.VPR[op.vd]._u32[w] = (u32)UINT32_MAX; + d._u32[w] = (u32)UINT32_MAX; } else - CPU.VPR[op.vd]._u32[w] = (u32)sum; + d._u32[w] = (u32)sum; } } -void ppu_interpreter::VUPKHPX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VUPKHPX(PPUThread& ppu, ppu_opcode_t op) { - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VB = ppu.VR[op.vb]; for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._s8[w * 4 + 3] = VB._s8[8 + w * 2 + 1] >> 7; // signed shift sign extends - CPU.VPR[op.vd]._u8[w * 4 + 2] = (VB._u8[8 + w * 2 + 1] >> 2) & 0x1f; - CPU.VPR[op.vd]._u8[w * 4 + 1] = ((VB._u8[8 + w * 2 + 1] & 0x3) << 3) | ((VB._u8[8 + w * 2 + 0] >> 5) & 0x7); - CPU.VPR[op.vd]._u8[w * 4 + 0] = VB._u8[8 + w * 2 + 0] & 0x1f; + d._s8[w * 4 + 3] = VB._s8[8 + w * 2 + 1] >> 7; // signed shift sign extends + d._u8[w * 4 + 2] = (VB._u8[8 + w * 2 + 1] >> 2) & 0x1f; + d._u8[w * 4 + 1] = ((VB._u8[8 + w * 2 + 1] & 0x3) << 3) | ((VB._u8[8 + w * 2 + 0] >> 5) & 0x7); + d._u8[w * 4 + 0] = VB._u8[8 + w * 2 + 0] & 0x1f; } } -void ppu_interpreter::VUPKHSB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VUPKHSB(PPUThread& ppu, ppu_opcode_t op) { - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VB = ppu.VR[op.vb]; for (uint h = 0; h < 8; h++) { - CPU.VPR[op.vd]._s16[h] = VB._s8[8 + h]; + d._s16[h] = VB._s8[8 + h]; } } -void ppu_interpreter::VUPKHSH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VUPKHSH(PPUThread& ppu, ppu_opcode_t op) { - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VB = ppu.VR[op.vb]; for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._s32[w] = VB._s16[4 + w]; + d._s32[w] = VB._s16[4 + w]; } } -void ppu_interpreter::VUPKLPX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VUPKLPX(PPUThread& ppu, ppu_opcode_t op) { - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VB = ppu.VR[op.vb]; for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._s8[w * 4 + 3] = VB._s8[w * 2 + 1] >> 7; // signed shift sign extends - CPU.VPR[op.vd]._u8[w * 4 + 2] = (VB._u8[w * 2 + 1] >> 2) & 0x1f; - CPU.VPR[op.vd]._u8[w * 4 + 1] = ((VB._u8[w * 2 + 1] & 0x3) << 3) | ((VB._u8[w * 2 + 0] >> 5) & 0x7); - CPU.VPR[op.vd]._u8[w * 4 + 0] = VB._u8[w * 2 + 0] & 0x1f; + d._s8[w * 4 + 3] = VB._s8[w * 2 + 1] >> 7; // signed shift sign extends + d._u8[w * 4 + 2] = (VB._u8[w * 2 + 1] >> 2) & 0x1f; + d._u8[w * 4 + 1] = ((VB._u8[w * 2 + 1] & 0x3) << 3) | ((VB._u8[w * 2 + 0] >> 5) & 0x7); + d._u8[w * 4 + 0] = VB._u8[w * 2 + 0] & 0x1f; } } -void ppu_interpreter::VUPKLSB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VUPKLSB(PPUThread& ppu, ppu_opcode_t op) { - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VB = ppu.VR[op.vb]; for (uint h = 0; h < 8; h++) { - CPU.VPR[op.vd]._s16[h] = VB._s8[h]; + d._s16[h] = VB._s8[h]; } } -void ppu_interpreter::VUPKLSH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VUPKLSH(PPUThread& ppu, ppu_opcode_t op) { - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VB = ppu.VR[op.vb]; for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._s32[w] = VB._s16[w]; + d._s32[w] = VB._s16[w]; } } -void ppu_interpreter::VXOR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VXOR(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = CPU.VPR[op.va] ^ CPU.VPR[op.vb]; + ppu.VR[op.vd] = ppu.VR[op.va] ^ ppu.VR[op.vb]; } -void ppu_interpreter::MULLI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MULLI(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.rd] = (s64)CPU.GPR[op.ra] * op.simm16; + ppu.GPR[op.rd] = (s64)ppu.GPR[op.ra] * op.simm16; } -void ppu_interpreter::SUBFIC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SUBFIC(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - const u64 IMM = (s64)op.simm16; - CPU.GPR[op.rd] = ~RA + IMM + 1; - - CPU.XER.CA = CPU.IsCarry(~RA, IMM, 1); + const u64 a = ppu.GPR[op.ra]; + const s64 i = op.simm16; + const auto r = add64_flags(~a, i, 1); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; } -void ppu_interpreter::CMPLI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CMPLI(PPUThread& ppu, ppu_opcode_t op) { - CPU.UpdateCRnU(op.l10, op.crfd, CPU.GPR[op.ra], op.uimm16); + if (op.l10) + { + ppu.SetCR(op.crfd, ppu.GPR[op.ra], op.uimm16); + } + else + { + ppu.SetCR(op.crfd, u32(ppu.GPR[op.ra]), op.uimm16); + } } -void ppu_interpreter::CMPI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CMPI(PPUThread& ppu, ppu_opcode_t op) { - CPU.UpdateCRnS(op.l10, op.crfd, CPU.GPR[op.ra], op.simm16); + if (op.l10) + { + ppu.SetCR(op.crfd, ppu.GPR[op.ra], op.simm16); + } + else + { + ppu.SetCR(op.crfd, u32(ppu.GPR[op.ra]), op.simm16); + } } -void ppu_interpreter::ADDIC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ADDIC(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - CPU.GPR[op.rd] = RA + op.simm16; - CPU.XER.CA = CPU.IsCarry(RA, op.simm16); + const s64 a = ppu.GPR[op.ra]; + const s64 i = op.simm16; + const auto r = add64_flags(a, i); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; + if (op.main & 1) ppu.SetCR(0, r.result, 0); } -void ppu_interpreter::ADDIC_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ADDI(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - CPU.GPR[op.rd] = RA + op.simm16; - CPU.XER.CA = CPU.IsCarry(RA, op.simm16); - CPU.UpdateCR0(CPU.GPR[op.rd]); + ppu.GPR[op.rd] = op.ra ? ((s64)ppu.GPR[op.ra] + op.simm16) : op.simm16; } -void ppu_interpreter::ADDI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ADDIS(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.rd] = op.ra ? ((s64)CPU.GPR[op.ra] + op.simm16) : op.simm16; + ppu.GPR[op.rd] = op.ra ? ((s64)ppu.GPR[op.ra] + (op.simm16 << 16)) : (op.simm16 << 16); } -void ppu_interpreter::ADDIS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::BC(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.rd] = op.ra ? ((s64)CPU.GPR[op.ra] + (op.simm16 << 16)) : (op.simm16 << 16); -} + const bool bo0 = (op.bo & 0x10) != 0; + const bool bo1 = (op.bo & 0x08) != 0; + const bool bo2 = (op.bo & 0x04) != 0; + const bool bo3 = (op.bo & 0x02) != 0; -void ppu_interpreter::BC(PPUThread& CPU, ppu_opcode_t op) -{ - const u8 bo0 = (op.bo & 0x10) ? 1 : 0; - const u8 bo1 = (op.bo & 0x08) ? 1 : 0; - const u8 bo2 = (op.bo & 0x04) ? 1 : 0; - const u8 bo3 = (op.bo & 0x02) ? 1 : 0; + ppu.CTR -= (bo2 ^ true); - if (!bo2) --CPU.CTR; - - const u8 ctr_ok = bo2 | ((CPU.CTR != 0) ^ bo3); - const u8 cond_ok = bo0 | (CPU.IsCR(op.bi) ^ (~bo1 & 0x1)); + const bool ctr_ok = bo2 | ((ppu.CTR != 0) ^ bo3); + const bool cond_ok = bo0 | (ppu.CR[op.bi] ^ (bo1 ^ true)); if (ctr_ok && cond_ok) { - const u32 nextLR = CPU.PC + 4; - CPU.PC = PPUOpcodes::branchTarget((op.aa ? 0 : CPU.PC), op.simm16) - 4; - if (op.lk) CPU.LR = nextLR; + const u32 nextLR = ppu.PC + 4; + ppu.PC = ppu_branch_target((op.aa ? 0 : ppu.PC), op.simm16) - 4; + if (op.lk) ppu.LR = nextLR; } } -void ppu_interpreter::HACK(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::HACK(PPUThread& ppu, ppu_opcode_t op) { - execute_ppu_func_by_index(CPU, op.opcode & 0x3ffffff); + ppu_execute_function(ppu, op.opcode & 0x3ffffff); } -void ppu_interpreter::SC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SC(PPUThread& ppu, ppu_opcode_t op) { - switch (op.lev) + switch (u32 lv = op.lev) { - case 0x0: execute_syscall_by_index(CPU, CPU.GPR[11]); break; - case 0x3: CPU.fast_stop(); break; - default: throw EXCEPTION(""); + case 0x0: ppu_execute_syscall(ppu, ppu.GPR[11]); break; + default: throw fmt::exception("SC lv%u", lv); } } -void ppu_interpreter::B(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::B(PPUThread& ppu, ppu_opcode_t op) { - const u32 nextLR = CPU.PC + 4; - CPU.PC = PPUOpcodes::branchTarget(op.aa ? 0 : CPU.PC, op.ll) - 4; - if (op.lk) CPU.LR = nextLR; + const u32 nextLR = ppu.PC + 4; + ppu.PC = ppu_branch_target(op.aa ? 0 : ppu.PC, op.ll) - 4; + if (op.lk) ppu.LR = nextLR; } -void ppu_interpreter::MCRF(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MCRF(PPUThread& ppu, ppu_opcode_t op) { - CPU.SetCR(op.crfd, CPU.GetCR(op.crfs)); + CHECK_SIZE(PPUThread::CR, 32); + reinterpret_cast(ppu.CR)[op.crfd] = reinterpret_cast(ppu.CR)[op.crfs]; } -void ppu_interpreter::BCLR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::BCLR(PPUThread& ppu, ppu_opcode_t op) { - const u8 bo0 = (op.bo & 0x10) ? 1 : 0; - const u8 bo1 = (op.bo & 0x08) ? 1 : 0; - const u8 bo2 = (op.bo & 0x04) ? 1 : 0; - const u8 bo3 = (op.bo & 0x02) ? 1 : 0; + const bool bo0 = (op.bo & 0x10) != 0; + const bool bo1 = (op.bo & 0x08) != 0; + const bool bo2 = (op.bo & 0x04) != 0; + const bool bo3 = (op.bo & 0x02) != 0; - if (!bo2) --CPU.CTR; + ppu.CTR -= (bo2 ^ true); - const u8 ctr_ok = bo2 | ((CPU.CTR != 0) ^ bo3); - const u8 cond_ok = bo0 | (CPU.IsCR(op.bi) ^ (~bo1 & 0x1)); + const bool ctr_ok = bo2 | ((ppu.CTR != 0) ^ bo3); + const bool cond_ok = bo0 | (ppu.CR[op.bi] ^ (bo1 ^ true)); if (ctr_ok && cond_ok) { - const u32 nextLR = CPU.PC + 4; - CPU.PC = PPUOpcodes::branchTarget(0, (u32)CPU.LR) - 4; - if (op.lk) CPU.LR = nextLR; + const u32 nextLR = ppu.PC + 4; + ppu.PC = ppu_branch_target(0, (u32)ppu.LR) - 4; + if (op.lk) ppu.LR = nextLR; } } -void ppu_interpreter::CRNOR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CRNOR(PPUThread& ppu, ppu_opcode_t op) { - const u8 v = 1 ^ (CPU.IsCR(op.crba) | CPU.IsCR(op.crbb)); - CPU.SetCRBit2(op.crbd, v & 0x1); + ppu.CR[op.crbd] = (ppu.CR[op.crba] | ppu.CR[op.crbb]) ^ true; } -void ppu_interpreter::CRANDC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CRANDC(PPUThread& ppu, ppu_opcode_t op) { - const u8 v = CPU.IsCR(op.crba) & (1 ^ CPU.IsCR(op.crbb)); - CPU.SetCRBit2(op.crbd, v & 0x1); + ppu.CR[op.crbd] = ppu.CR[op.crba] & (ppu.CR[op.crbb] ^ true); } -void ppu_interpreter::ISYNC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ISYNC(PPUThread& ppu, ppu_opcode_t op) { _mm_mfence(); } -void ppu_interpreter::CRXOR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CRXOR(PPUThread& ppu, ppu_opcode_t op) { - const u8 v = CPU.IsCR(op.crba) ^ CPU.IsCR(op.crbb); - CPU.SetCRBit2(op.crbd, v & 0x1); + ppu.CR[op.crbd] = ppu.CR[op.crba] ^ ppu.CR[op.crbb]; } -void ppu_interpreter::CRNAND(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CRNAND(PPUThread& ppu, ppu_opcode_t op) { - const u8 v = 1 ^ (CPU.IsCR(op.crba) & CPU.IsCR(op.crbb)); - CPU.SetCRBit2(op.crbd, v & 0x1); + ppu.CR[op.crbd] = (ppu.CR[op.crba] & ppu.CR[op.crbb]) ^ true; } -void ppu_interpreter::CRAND(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CRAND(PPUThread& ppu, ppu_opcode_t op) { - const u8 v = CPU.IsCR(op.crba) & CPU.IsCR(op.crbb); - CPU.SetCRBit2(op.crbd, v & 0x1); + ppu.CR[op.crbd] = ppu.CR[op.crba] & ppu.CR[op.crbb]; } -void ppu_interpreter::CREQV(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CREQV(PPUThread& ppu, ppu_opcode_t op) { - const u8 v = 1 ^ (CPU.IsCR(op.crba) ^ CPU.IsCR(op.crbb)); - CPU.SetCRBit2(op.crbd, v & 0x1); + ppu.CR[op.crbd] = (ppu.CR[op.crba] ^ ppu.CR[op.crbb]) ^ true; } -void ppu_interpreter::CRORC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CRORC(PPUThread& ppu, ppu_opcode_t op) { - const u8 v = CPU.IsCR(op.crba) | (1 ^ CPU.IsCR(op.crbb)); - CPU.SetCRBit2(op.crbd, v & 0x1); + ppu.CR[op.crbd] = ppu.CR[op.crba] | (ppu.CR[op.crbb] ^ true); } -void ppu_interpreter::CROR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CROR(PPUThread& ppu, ppu_opcode_t op) { - const u8 v = CPU.IsCR(op.crba) | CPU.IsCR(op.crbb); - CPU.SetCRBit2(op.crbd, v & 0x1); + ppu.CR[op.crbd] = ppu.CR[op.crba] | ppu.CR[op.crbb]; } -void ppu_interpreter::BCCTR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::BCCTR(PPUThread& ppu, ppu_opcode_t op) { - if (op.bo & 0x10 || CPU.IsCR(op.bi) == ((op.bo & 0x8) != 0)) + if (op.bo & 0x10 || ppu.CR[op.bi] == ((op.bo & 0x8) != 0)) { - const u32 nextLR = CPU.PC + 4; - CPU.PC = PPUOpcodes::branchTarget(0, (u32)CPU.CTR) - 4; - if (op.lk) CPU.LR = nextLR; + const u32 nextLR = ppu.PC + 4; + ppu.PC = ppu_branch_target(0, (u32)ppu.CTR) - 4; + if (op.lk) ppu.LR = nextLR; } } -void ppu_interpreter::RLWIMI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::RLWIMI(PPUThread& ppu, ppu_opcode_t op) { - const u64 mask = rotate_mask[32 + op.mb][32 + op.me]; - CPU.GPR[op.ra] = (CPU.GPR[op.ra] & ~mask) | (rotl32(CPU.GPR[op.rs], op.sh) & mask); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + const u64 mask = ppu_rotate_mask(32 + op.mb32, 32 + op.me32); + ppu.GPR[op.ra] = (ppu.GPR[op.ra] & ~mask) | (dup32(rol32(u32(ppu.GPR[op.rs]), op.sh32)) & mask); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::RLWINM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::RLWINM(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = rotl32(CPU.GPR[op.rs], op.sh) & rotate_mask[32 + op.mb][32 + op.me]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = dup32(rol32(u32(ppu.GPR[op.rs]), op.sh32)) & ppu_rotate_mask(32 + op.mb32, 32 + op.me32); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::RLWNM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::RLWNM(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = rotl32(CPU.GPR[op.rs], CPU.GPR[op.rb] & 0x1f) & rotate_mask[32 + op.mb][32 + op.me]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = dup32(rol32(u32(ppu.GPR[op.rs]), ppu.GPR[op.rb] & 0x1f)) & ppu_rotate_mask(32 + op.mb32, 32 + op.me32); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::ORI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ORI(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = CPU.GPR[op.rs] | op.uimm16; + ppu.GPR[op.ra] = ppu.GPR[op.rs] | op.uimm16; } -void ppu_interpreter::ORIS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ORIS(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = CPU.GPR[op.rs] | ((u64)op.uimm16 << 16); + ppu.GPR[op.ra] = ppu.GPR[op.rs] | ((u64)op.uimm16 << 16); } -void ppu_interpreter::XORI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::XORI(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = CPU.GPR[op.rs] ^ op.uimm16; + ppu.GPR[op.ra] = ppu.GPR[op.rs] ^ op.uimm16; } -void ppu_interpreter::XORIS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::XORIS(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = CPU.GPR[op.rs] ^ ((u64)op.uimm16 << 16); + ppu.GPR[op.ra] = ppu.GPR[op.rs] ^ ((u64)op.uimm16 << 16); } -void ppu_interpreter::ANDI_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ANDI(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = CPU.GPR[op.rs] & op.uimm16; - CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = ppu.GPR[op.rs] & op.uimm16; + ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::ANDIS_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ANDIS(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = CPU.GPR[op.rs] & ((u64)op.uimm16 << 16); - CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = ppu.GPR[op.rs] & ((u64)op.uimm16 << 16); + ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::RLDICL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::RLDICL(PPUThread& ppu, ppu_opcode_t op) { - auto sh = (op.shh << 5) | op.shl; - auto mb = (op.mbmeh << 5) | op.mbmel; - - CPU.GPR[op.ra] = rotl64(CPU.GPR[op.rs], sh) & rotate_mask[mb][63]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = rol64(ppu.GPR[op.rs], op.sh64) & ppu_rotate_mask(op.mbe64, 63); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::RLDICR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::RLDICR(PPUThread& ppu, ppu_opcode_t op) { - auto sh = (op.shh << 5) | op.shl; - auto me = (op.mbmeh << 5) | op.mbmel; - - CPU.GPR[op.ra] = rotl64(CPU.GPR[op.rs], sh) & rotate_mask[0][me]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = rol64(ppu.GPR[op.rs], op.sh64) & ppu_rotate_mask(0, op.mbe64); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::RLDIC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::RLDIC(PPUThread& ppu, ppu_opcode_t op) { - auto sh = (op.shh << 5) | op.shl; - auto mb = (op.mbmeh << 5) | op.mbmel; - - CPU.GPR[op.ra] = rotl64(CPU.GPR[op.rs], sh) & rotate_mask[mb][63 - sh]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = rol64(ppu.GPR[op.rs], op.sh64) & ppu_rotate_mask(op.mbe64, op.sh64 ^ 63); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::RLDIMI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::RLDIMI(PPUThread& ppu, ppu_opcode_t op) { - auto sh = (op.shh << 5) | op.shl; - auto mb = (op.mbmeh << 5) | op.mbmel; - - const u64 mask = rotate_mask[mb][63 - sh]; - CPU.GPR[op.ra] = (CPU.GPR[op.ra] & ~mask) | (rotl64(CPU.GPR[op.rs], sh) & mask); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + const u64 mask = ppu_rotate_mask(op.mbe64, op.sh64 ^ 63); + ppu.GPR[op.ra] = (ppu.GPR[op.ra] & ~mask) | (rol64(ppu.GPR[op.rs], op.sh64) & mask); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::RLDC_LR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::RLDCL(PPUThread& ppu, ppu_opcode_t op) { - auto sh = (u32)(CPU.GPR[op.rb] & 0x3F); - auto mbme = (op.mbmeh << 5) | op.mbmel; + ppu.GPR[op.ra] = rol64(ppu.GPR[op.rs], ppu.GPR[op.rb] & 0x3f) & ppu_rotate_mask(op.mbe64, 63); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} - if (op.aa) // rldcr +void ppu_interpreter::RLDCR(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.GPR[op.ra] = rol64(ppu.GPR[op.rs], ppu.GPR[op.rb] & 0x3f) & ppu_rotate_mask(0, op.mbe64); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} + +void ppu_interpreter::CMP(PPUThread& ppu, ppu_opcode_t op) +{ + if (op.l10) { - CPU.GPR[op.ra] = rotl64(CPU.GPR[op.rs], sh) & rotate_mask[0][mbme]; + ppu.SetCR(op.crfd, ppu.GPR[op.ra], ppu.GPR[op.rb]); } - else // rldcl + else { - CPU.GPR[op.ra] = rotl64(CPU.GPR[op.rs], sh) & rotate_mask[mbme][63]; + ppu.SetCR(op.crfd, u32(ppu.GPR[op.ra]), u32(ppu.GPR[op.rb])); } - - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); } -void ppu_interpreter::CMP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::TW(PPUThread& ppu, ppu_opcode_t op) { - CPU.UpdateCRnS(op.l10, op.crfd, CPU.GPR[op.ra], CPU.GPR[op.rb]); -} - -void ppu_interpreter::TW(PPUThread& CPU, ppu_opcode_t op) -{ - s32 a = (s32)CPU.GPR[op.ra]; - s32 b = (s32)CPU.GPR[op.rb]; + s32 a = (s32)ppu.GPR[op.ra]; + s32 b = (s32)ppu.GPR[op.rb]; if ((a < b && (op.bo & 0x10)) || (a > b && (op.bo & 0x8)) || @@ -1696,13 +1756,13 @@ void ppu_interpreter::TW(PPUThread& CPU, ppu_opcode_t op) ((u32)a < (u32)b && (op.bo & 0x2)) || ((u32)a >(u32)b && (op.bo & 0x1))) { - throw EXCEPTION(""); + throw std::runtime_error("Trap!" HERE); } } -void ppu_interpreter::LVSL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVSL(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; static const u64 lvsl_values[0x10][2] = { @@ -1724,125 +1784,140 @@ void ppu_interpreter::LVSL(PPUThread& CPU, ppu_opcode_t op) { 0x1718191A1B1C1D1E, 0x0F10111213141516 }, }; - CPU.VPR[op.vd]._u64[0] = lvsl_values[addr & 0xf][0]; - CPU.VPR[op.vd]._u64[1] = lvsl_values[addr & 0xf][1]; + ppu.VR[op.vd]._u64[0] = lvsl_values[addr & 0xf][0]; + ppu.VR[op.vd]._u64[1] = lvsl_values[addr & 0xf][1]; } -void ppu_interpreter::LVEBX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVEBX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.VPR[op.vd]._u8[15 - (addr & 0xf)] = vm::read8(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.VR[op.vd]._u8[15 - (addr & 0xf)] = vm::read8(vm::cast(addr, HERE)); } -void ppu_interpreter::SUBFC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SUBFC(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - const u64 RB = CPU.GPR[op.rb]; - CPU.GPR[op.rd] = ~RA + RB + 1; - CPU.XER.CA = CPU.IsCarry(~RA, RB, 1); - if (op.oe) CPU.SetOV((~RA >> 63 == RB >> 63) && (~RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + const u64 RB = ppu.GPR[op.rb]; + const auto r = add64_flags(~RA, RB, 1); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; + if (op.oe) ppu.SetOV((~RA >> 63 == RB >> 63) && (~RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, r.result, 0); } -void ppu_interpreter::MULHDU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MULHDU(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.rd] = UMULH64(CPU.GPR[op.ra], CPU.GPR[op.rb]); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + ppu.GPR[op.rd] = UMULH64(ppu.GPR[op.ra], ppu.GPR[op.rb]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.rd], 0); } -void ppu_interpreter::ADDC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ADDC(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - const u64 RB = CPU.GPR[op.rb]; - CPU.GPR[op.rd] = RA + RB; - CPU.XER.CA = CPU.IsCarry(RA, RB); - if (op.oe) CPU.SetOV((RA >> 63 == RB >> 63) && (RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + const u64 RB = ppu.GPR[op.rb]; + const auto r = add64_flags(RA, RB); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; + if (op.oe) ppu.SetOV((RA >> 63 == RB >> 63) && (RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, r.result, 0); } -void ppu_interpreter::MULHWU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MULHWU(PPUThread& ppu, ppu_opcode_t op) { - u32 a = (u32)CPU.GPR[op.ra]; - u32 b = (u32)CPU.GPR[op.rb]; - CPU.GPR[op.rd] = ((u64)a * (u64)b) >> 32; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + u32 a = (u32)ppu.GPR[op.ra]; + u32 b = (u32)ppu.GPR[op.rb]; + ppu.GPR[op.rd] = ((u64)a * (u64)b) >> 32; + if (op.rc) ppu.SetCR(0, false, false, false, ppu.SO); } -void ppu_interpreter::MFOCRF(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MFOCRF(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.rd] = CPU.CR.CR; + if (op.l11) + { + // MFOCRF + const u32 n = cntlz32(op.crm) & 7; + const u32 p = n * 4; + const u32 v = ppu.CR[p + 0] << 3 | ppu.CR[p + 1] << 2 | ppu.CR[p + 2] << 1 | ppu.CR[p + 3] << 0; + + ppu.GPR[op.rd] = v << (p ^ 0x1c); + } + else + { + // MFCR + auto* lanes = reinterpret_cast*>(ppu.CR); + const u32 mh = _mm_movemask_epi8(_mm_slli_epi64(lanes[0].value().vi, 7)); + const u32 ml = _mm_movemask_epi8(_mm_slli_epi64(lanes[1].value().vi, 7)); + + ppu.GPR[op.rd] = (mh << 16) | ml; + } } -void ppu_interpreter::LWARX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LWARX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; be_t value; - vm::reservation_acquire(&value, VM_CAST(addr), SIZE_32(value)); + vm::reservation_acquire(&value, vm::cast(addr, HERE), SIZE_32(value)); - CPU.GPR[op.rd] = value; + ppu.GPR[op.rd] = value; } -void ppu_interpreter::LDX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LDX(PPUThread& ppu, 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::read64(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::read64(vm::cast(addr, HERE)); } -void ppu_interpreter::LWZX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LWZX(PPUThread& ppu, 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::read32(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::read32(vm::cast(addr, HERE)); } -void ppu_interpreter::SLW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SLW(PPUThread& ppu, ppu_opcode_t op) { - u32 n = CPU.GPR[op.rb] & 0x1f; - u32 r = (u32)rotl32((u32)CPU.GPR[op.rs], n); - u32 m = ((u32)CPU.GPR[op.rb] & 0x20) ? 0 : (u32)rotate_mask[32][63 - n]; - - CPU.GPR[op.ra] = r & m; - - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = u32(ppu.GPR[op.rs] << (ppu.GPR[op.rb] & 0x3f)); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::CNTLZW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CNTLZW(PPUThread& ppu, ppu_opcode_t op) { - u32 i; - for (i = 0; i < 32; i++) + ppu.GPR[op.ra] = cntlz32(u32(ppu.GPR[op.rs])); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} + +void ppu_interpreter::SLD(PPUThread& ppu, ppu_opcode_t op) +{ + u32 n = ppu.GPR[op.rb] & 0x3f; + u64 r = rol64(ppu.GPR[op.rs], n); + u64 m = (ppu.GPR[op.rb] & 0x40) ? 0 : ppu_rotate_mask(0, 63 - n); + + ppu.GPR[op.ra] = r & m; + + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} + +void ppu_interpreter::AND(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.GPR[op.ra] = ppu.GPR[op.rs] & ppu.GPR[op.rb]; + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} + +void ppu_interpreter::CMPL(PPUThread& ppu, ppu_opcode_t op) +{ + if (op.l10) { - if (CPU.GPR[op.rs] & (1ULL << (31 - i))) break; + ppu.SetCR(op.crfd, ppu.GPR[op.ra], ppu.GPR[op.rb]); + } + else + { + ppu.SetCR(op.crfd, u32(ppu.GPR[op.ra]), u32(ppu.GPR[op.rb])); } - - CPU.GPR[op.ra] = i; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); } -void ppu_interpreter::SLD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVSR(PPUThread& ppu, ppu_opcode_t op) { - u32 n = CPU.GPR[op.rb] & 0x3f; - u64 r = rotl64(CPU.GPR[op.rs], n); - u64 m = (CPU.GPR[op.rb] & 0x40) ? 0 : rotate_mask[0][63 - n]; - - CPU.GPR[op.ra] = r & m; - - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); -} - -void ppu_interpreter::AND(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.GPR[op.ra] = CPU.GPR[op.rs] & CPU.GPR[op.rb]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); -} - -void ppu_interpreter::CMPL(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.UpdateCRnU(op.l10, op.crfd, CPU.GPR[op.ra], CPU.GPR[op.rb]); -} - -void ppu_interpreter::LVSR(PPUThread& CPU, ppu_opcode_t op) -{ - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; static const u64 lvsr_values[0x10][2] = { @@ -1864,696 +1939,636 @@ void ppu_interpreter::LVSR(PPUThread& CPU, ppu_opcode_t op) { 0x090A0B0C0D0E0F10, 0x0102030405060708 }, }; - CPU.VPR[op.vd]._u64[0] = lvsr_values[addr & 0xf][0]; - CPU.VPR[op.vd]._u64[1] = lvsr_values[addr & 0xf][1]; + ppu.VR[op.vd]._u64[0] = lvsr_values[addr & 0xf][0]; + ppu.VR[op.vd]._u64[1] = lvsr_values[addr & 0xf][1]; } -void ppu_interpreter::LVEHX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVEHX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]) & ~1ULL; - CPU.VPR[op.vd]._u16[7 - ((addr >> 1) & 0x7)] = vm::read16(VM_CAST(addr)); + const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~1ULL; + ppu.VR[op.vd]._u16[7 - ((addr >> 1) & 0x7)] = vm::read16(vm::cast(addr, HERE)); } -void ppu_interpreter::SUBF(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SUBF(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - const u64 RB = CPU.GPR[op.rb]; - CPU.GPR[op.rd] = RB - RA; - if (op.oe) CPU.SetOV((~RA >> 63 == RB >> 63) && (~RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + const u64 RB = ppu.GPR[op.rb]; + ppu.GPR[op.rd] = RB - RA; + if (op.oe) ppu.SetOV((~RA >> 63 == RB >> 63) && (~RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.rd], 0); } -void ppu_interpreter::LDUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LDUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - CPU.GPR[op.rd] = vm::read64(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::read64(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::DCBST(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::DCBST(PPUThread& ppu, ppu_opcode_t op) { } -void ppu_interpreter::LWZUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LWZUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - CPU.GPR[op.rd] = vm::read32(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::read32(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::CNTLZD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CNTLZD(PPUThread& ppu, ppu_opcode_t op) { - u32 i; - for (i = 0; i < 64; i++) + ppu.GPR[op.ra] = cntlz64(ppu.GPR[op.rs]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} + +void ppu_interpreter::ANDC(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.GPR[op.ra] = ppu.GPR[op.rs] & ~ppu.GPR[op.rb]; + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} + +void ppu_interpreter::TD(PPUThread& ppu, ppu_opcode_t op) +{ + const s64 a = ppu.GPR[op.ra], b = ppu.GPR[op.rb]; + const u64 a_ = a, b_ = b; + + if (((op.bo & 0x10) && a < b) || + ((op.bo & 0x8) && a > b) || + ((op.bo & 0x4) && a == b) || + ((op.bo & 0x2) && a_ < b_) || + ((op.bo & 0x1) && a_ > b_)) { - if (CPU.GPR[op.rs] & (1ULL << (63 - i))) break; + throw std::runtime_error("Trap!" HERE); } - - CPU.GPR[op.ra] = i; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); } -void ppu_interpreter::ANDC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVEWX(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = CPU.GPR[op.rs] & ~CPU.GPR[op.rb]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~3ULL; + ppu.VR[op.vd]._u32[3 - ((addr >> 2) & 0x3)] = vm::read32(vm::cast(addr, HERE)); } -void ppu_interpreter::TD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MULHD(PPUThread& ppu, ppu_opcode_t op) { - throw EXCEPTION(""); + ppu.GPR[op.rd] = MULH64(ppu.GPR[op.ra], ppu.GPR[op.rb]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.rd], 0); } -void ppu_interpreter::LVEWX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MULHW(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]) & ~3ULL; - CPU.VPR[op.vd]._u32[3 - ((addr >> 2) & 0x3)] = vm::read32(VM_CAST(addr)); + s32 a = (s32)ppu.GPR[op.ra]; + s32 b = (s32)ppu.GPR[op.rb]; + ppu.GPR[op.rd] = ((s64)a * (s64)b) >> 32; + if (op.rc) ppu.SetCR(0, false, false, false, ppu.SO); } -void ppu_interpreter::MULHD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LDARX(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.rd] = MULH64(CPU.GPR[op.ra], CPU.GPR[op.rb]); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); -} - -void ppu_interpreter::MULHW(PPUThread& CPU, ppu_opcode_t op) -{ - s32 a = (s32)CPU.GPR[op.ra]; - s32 b = (s32)CPU.GPR[op.rb]; - CPU.GPR[op.rd] = ((s64)a * (s64)b) >> 32; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); -} - -void ppu_interpreter::LDARX(PPUThread& CPU, ppu_opcode_t op) -{ - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; be_t value; - vm::reservation_acquire(&value, VM_CAST(addr), SIZE_32(value)); + vm::reservation_acquire(&value, vm::cast(addr, HERE), SIZE_32(value)); - CPU.GPR[op.rd] = value; + ppu.GPR[op.rd] = value; } -void ppu_interpreter::DCBF(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::DCBF(PPUThread& ppu, ppu_opcode_t op) { } -void ppu_interpreter::LBZX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LBZX(PPUThread& ppu, 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::read8(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::read8(vm::cast(addr, HERE)); } -void ppu_interpreter::LVX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVX(PPUThread& ppu, 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::_ref(VM_CAST(addr)); + const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~0xfull; + ppu.VR[op.vd] = vm::_ref(vm::cast(addr, HERE)); } -void ppu_interpreter::NEG(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::NEG(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - CPU.GPR[op.rd] = 0 - RA; - if (op.oe) CPU.SetOV((~RA >> 63 == 0) && (~RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + ppu.GPR[op.rd] = 0 - RA; + if (op.oe) ppu.SetOV((~RA >> 63 == 0) && (~RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.rd], 0); } -void ppu_interpreter::LBZUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LBZUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - CPU.GPR[op.rd] = vm::read8(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::read8(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::NOR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::NOR(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = ~(CPU.GPR[op.rs] | CPU.GPR[op.rb]); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = ~(ppu.GPR[op.rs] | ppu.GPR[op.rb]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::STVEBX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STVEBX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; const u8 eb = addr & 0xf; - vm::write8(VM_CAST(addr), CPU.VPR[op.vs]._u8[15 - eb]); + vm::write8(vm::cast(addr, HERE), ppu.VR[op.vs]._u8[15 - eb]); } -void ppu_interpreter::SUBFE(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SUBFE(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - const u64 RB = CPU.GPR[op.rb]; - CPU.GPR[op.rd] = ~RA + RB + CPU.XER.CA; - CPU.XER.CA = CPU.IsCarry(~RA, RB, CPU.XER.CA); - if (op.oe) CPU.SetOV((~RA >> 63 == RB >> 63) && (~RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + const u64 RB = ppu.GPR[op.rb]; + const auto r = add64_flags(~RA, RB, ppu.CA); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; + if (op.oe) ppu.SetOV((~RA >> 63 == RB >> 63) && (~RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, r.result, 0); } -void ppu_interpreter::ADDE(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ADDE(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - const u64 RB = CPU.GPR[op.rb]; - if (CPU.XER.CA) - { - if (RA == ~0ULL) //-1 - { - CPU.GPR[op.rd] = RB; - CPU.XER.CA = 1; - } - else - { - CPU.GPR[op.rd] = RA + 1 + RB; - CPU.XER.CA = CPU.IsCarry(RA + 1, RB); - } - } - else - { - CPU.GPR[op.rd] = RA + RB; - CPU.XER.CA = CPU.IsCarry(RA, RB); - } - if (op.oe) CPU.SetOV((RA >> 63 == RB >> 63) && (RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + const u64 RB = ppu.GPR[op.rb]; + const auto r = add64_flags(RA, RB, ppu.CA); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; + if (op.oe) ppu.SetOV((RA >> 63 == RB >> 63) && (RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, r.result, 0); } -void ppu_interpreter::MTOCRF(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MTOCRF(PPUThread& ppu, ppu_opcode_t op) { + const u64 s = ppu.GPR[op.rs]; + if (op.l11) { - u32 n = 0, count = 0; - for (u32 i = 0; i<8; ++i) - { - if (op.crm & (1 << i)) - { - n = i; - count++; - } - } + // MTOCRF - if (count == 1) - { - //CR[4*n : 4*n+3] = RS[32+4*n : 32+4*n+3]; - CPU.SetCR(7 - n, (CPU.GPR[op.rs] >> (4 * n)) & 0xf); - } - else - CPU.CR.CR = 0; + const u32 n = cntlz32(op.crm) & 7; + const u32 p = n * 4; + const u64 v = s >> (p ^ 0x1c); + ppu.CR[p + 0] = (v & 8) != 0; + ppu.CR[p + 1] = (v & 4) != 0; + ppu.CR[p + 2] = (v & 2) != 0; + ppu.CR[p + 3] = (v & 1) != 0; } else { - for (u32 i = 0; i<8; ++i) + // MTCRF + + for (u32 i = 0; i < 8; i++) { - if (op.crm & (1 << i)) + const u32 p = i * 4; + const u64 v = s >> (p ^ 0x1c); + + if (op.crm & (128 >> i)) { - CPU.SetCR(7 - i, (CPU.GPR[op.rs] >> (i * 4)) & 0xf); + ppu.CR[p + 0] = (v & 8) != 0; + ppu.CR[p + 1] = (v & 4) != 0; + ppu.CR[p + 2] = (v & 2) != 0; + ppu.CR[p + 3] = (v & 1) != 0; } } } } -void ppu_interpreter::STDX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STDX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::write64(VM_CAST(addr), CPU.GPR[op.rs]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::write64(vm::cast(addr, HERE), ppu.GPR[op.rs]); } -void ppu_interpreter::STWCX_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STWCX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; - const be_t value = (u32)CPU.GPR[op.rs]; - CPU.SetCR_EQ(0, vm::reservation_update(VM_CAST(addr), &value, SIZE_32(value))); + const be_t value = (u32)ppu.GPR[op.rs]; + ppu.SetCR(0, false, false, vm::reservation_update(vm::cast(addr, HERE), &value, SIZE_32(value)), ppu.SO); } -void ppu_interpreter::STWX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STWX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::write32(VM_CAST(addr), (u32)CPU.GPR[op.rs]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::write32(vm::cast(addr, HERE), (u32)ppu.GPR[op.rs]); } -void ppu_interpreter::STVEHX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STVEHX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]) & ~1ULL; + const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~1ULL; const u8 eb = (addr & 0xf) >> 1; - vm::write16(VM_CAST(addr), CPU.VPR[op.vs]._u16[7 - eb]); + vm::write16(vm::cast(addr, HERE), ppu.VR[op.vs]._u16[7 - eb]); } -void ppu_interpreter::STDUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STDUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - vm::write64(VM_CAST(addr), CPU.GPR[op.rs]); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + vm::write64(vm::cast(addr, HERE), ppu.GPR[op.rs]); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STWUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STWUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - vm::write32(VM_CAST(addr), (u32)CPU.GPR[op.rs]); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + vm::write32(vm::cast(addr, HERE), (u32)ppu.GPR[op.rs]); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STVEWX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STVEWX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]) & ~3ULL; + const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~3ULL; const u8 eb = (addr & 0xf) >> 2; - vm::write32(VM_CAST(addr), CPU.VPR[op.vs]._u32[3 - eb]); + vm::write32(vm::cast(addr, HERE), ppu.VR[op.vs]._u32[3 - eb]); } -void ppu_interpreter::SUBFZE(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SUBFZE(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - CPU.GPR[op.rd] = ~RA + CPU.XER.CA; - CPU.XER.CA = CPU.IsCarry(~RA, CPU.XER.CA); - if (op.oe) CPU.SetOV((~RA >> 63 == 0) && (~RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + const auto r = add64_flags(~RA, 0, ppu.CA); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; + if (op.oe) ppu.SetOV((~RA >> 63 == 0) && (~RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, r.result, 0); } -void ppu_interpreter::ADDZE(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ADDZE(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - CPU.GPR[op.rd] = RA + CPU.XER.CA; - CPU.XER.CA = CPU.IsCarry(RA, CPU.XER.CA); - if (op.oe) CPU.SetOV((RA >> 63 == 0) && (RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + const auto r = add64_flags(RA, 0, ppu.CA); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; + if (op.oe) ppu.SetOV((RA >> 63 == 0) && (RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, r.result, 0); } -void ppu_interpreter::STDCX_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STDCX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; - const be_t value = CPU.GPR[op.rs]; - CPU.SetCR_EQ(0, vm::reservation_update(VM_CAST(addr), &value, SIZE_32(value))); + const be_t value = ppu.GPR[op.rs]; + ppu.SetCR(0, false, false, vm::reservation_update(vm::cast(addr, HERE), &value, SIZE_32(value)), ppu.SO); } -void ppu_interpreter::STBX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STBX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::write8(VM_CAST(addr), (u8)CPU.GPR[op.rs]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::write8(vm::cast(addr, HERE), (u8)ppu.GPR[op.rs]); } -void ppu_interpreter::STVX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STVX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]) & ~0xfull; - vm::_ref(VM_CAST(addr)) = CPU.VPR[op.vs]; + const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~0xfull; + vm::_ref(vm::cast(addr, HERE)) = ppu.VR[op.vs]; } -void ppu_interpreter::MULLD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MULLD(PPUThread& ppu, ppu_opcode_t op) { - const s64 RA = CPU.GPR[op.ra]; - const s64 RB = CPU.GPR[op.rb]; - CPU.GPR[op.rd] = (s64)(RA * RB); + const s64 RA = ppu.GPR[op.ra]; + const s64 RB = ppu.GPR[op.rb]; + ppu.GPR[op.rd] = (s64)(RA * RB); if (op.oe) { const s64 high = MULH64(RA, RB); - CPU.SetOV(high != s64(CPU.GPR[op.rd]) >> 63); + ppu.SetOV(high != s64(ppu.GPR[op.rd]) >> 63); } - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.rd], 0); } -void ppu_interpreter::SUBFME(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SUBFME(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - CPU.GPR[op.rd] = ~RA + CPU.XER.CA + ~0ULL; - CPU.XER.CA = CPU.IsCarry(~RA, CPU.XER.CA, ~0ULL); - if (op.oe) CPU.SetOV((~RA >> 63 == 1) && (~RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + const auto r = add64_flags(~RA, ~0ull, ppu.CA); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; + if (op.oe) ppu.SetOV((~RA >> 63 == 1) && (~RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, r.result, 0); } -void ppu_interpreter::ADDME(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ADDME(PPUThread& ppu, ppu_opcode_t op) { - const s64 RA = CPU.GPR[op.ra]; - CPU.GPR[op.rd] = RA + CPU.XER.CA - 1; - CPU.XER.CA |= RA != 0; - - if (op.oe) CPU.SetOV((u64(RA) >> 63 == 1) && (u64(RA) >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const s64 RA = ppu.GPR[op.ra]; + const auto r = add64_flags(RA, ~0ull, ppu.CA); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; + if (op.oe) ppu.SetOV((u64(RA) >> 63 == 1) && (u64(RA) >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, r.result, 0); } -void ppu_interpreter::MULLW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MULLW(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.rd] = (s64)((s64)(s32)CPU.GPR[op.ra] * (s64)(s32)CPU.GPR[op.rb]); - if (op.oe) CPU.SetOV(s64(CPU.GPR[op.rd]) < s64(-1) << 31 || s64(CPU.GPR[op.rd]) >= s64(1) << 31); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + ppu.GPR[op.rd] = (s64)((s64)(s32)ppu.GPR[op.ra] * (s64)(s32)ppu.GPR[op.rb]); + if (op.oe) ppu.SetOV(s64(ppu.GPR[op.rd]) < s64(-1) << 31 || s64(ppu.GPR[op.rd]) >= s64(1) << 31); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::DCBTST(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::DCBTST(PPUThread& ppu, ppu_opcode_t op) { } -void ppu_interpreter::STBUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STBUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - vm::write8(VM_CAST(addr), (u8)CPU.GPR[op.rs]); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + vm::write8(vm::cast(addr, HERE), (u8)ppu.GPR[op.rs]); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::ADD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ADD(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - const u64 RB = CPU.GPR[op.rb]; - CPU.GPR[op.rd] = RA + RB; - if (op.oe) CPU.SetOV((RA >> 63 == RB >> 63) && (RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + const u64 RB = ppu.GPR[op.rb]; + ppu.GPR[op.rd] = RA + RB; + if (op.oe) ppu.SetOV((RA >> 63 == RB >> 63) && (RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.rd], 0); } -void ppu_interpreter::DCBT(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::DCBT(PPUThread& ppu, ppu_opcode_t op) { } -void ppu_interpreter::LHZX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LHZX(PPUThread& ppu, 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::read16(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::read16(vm::cast(addr, HERE)); } -void ppu_interpreter::EQV(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::EQV(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = ~(CPU.GPR[op.rs] ^ CPU.GPR[op.rb]); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = ~(ppu.GPR[op.rs] ^ ppu.GPR[op.rb]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::ECIWX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ECIWX(PPUThread& ppu, ppu_opcode_t op) { - throw EXCEPTION(""); + throw std::runtime_error("ECIWX" HERE); } -void ppu_interpreter::LHZUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LHZUX(PPUThread& ppu, 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::read16(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::read16(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::XOR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::XOR(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = CPU.GPR[op.rs] ^ CPU.GPR[op.rb]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = ppu.GPR[op.rs] ^ ppu.GPR[op.rb]; + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::MFSPR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MFSPR(PPUThread& ppu, ppu_opcode_t op) { const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5); switch (n) { - case 0x001: CPU.GPR[op.rd] = CPU.XER.XER; return; - case 0x008: CPU.GPR[op.rd] = CPU.LR; return; - case 0x009: CPU.GPR[op.rd] = CPU.CTR; return; - case 0x100: CPU.GPR[op.rd] = CPU.VRSAVE; return; - case 0x103: CPU.GPR[op.rd] = CPU.SPRG[3]; return; + case 0x001: ppu.GPR[op.rd] = u32{ ppu.SO } << 31 | ppu.OV << 30 | ppu.CA << 29 | ppu.XCNT; return; + case 0x008: ppu.GPR[op.rd] = ppu.LR; return; + case 0x009: ppu.GPR[op.rd] = ppu.CTR; return; + case 0x100: ppu.GPR[op.rd] = ppu.VRSAVE; return; - case 0x10C: CPU.TB = get_timebased_time(); CPU.GPR[op.rd] = CPU.TB; return; - case 0x10D: CPU.TB = get_timebased_time(); CPU.GPR[op.rd] = CPU.TB >> 32; return; - - case 0x110: - case 0x111: - case 0x112: - case 0x113: - case 0x114: - case 0x115: - case 0x116: - case 0x117: CPU.GPR[op.rd] = CPU.SPRG[n - 0x110]; return; + case 0x10C: ppu.GPR[op.rd] = get_timebased_time() & 0xffffffff; return; + case 0x10D: ppu.GPR[op.rd] = get_timebased_time() >> 32; return; } - throw EXCEPTION(""); + throw fmt::exception("MFSPR 0x%x" HERE, n); } -void ppu_interpreter::LWAX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LWAX(PPUThread& ppu, 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] = (s64)(s32)vm::read32(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = (s64)(s32)vm::read32(vm::cast(addr, HERE)); } -void ppu_interpreter::DST(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::DST(PPUThread& ppu, ppu_opcode_t op) { } -void ppu_interpreter::LHAX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LHAX(PPUThread& ppu, 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] = (s64)(s16)vm::read16(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = (s64)(s16)vm::read16(vm::cast(addr, HERE)); } -void ppu_interpreter::LVXL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVXL(PPUThread& ppu, 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::_ref(VM_CAST(addr)); + const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~0xfull; + ppu.VR[op.vd] = vm::_ref(vm::cast(addr, HERE)); } -void ppu_interpreter::MFTB(PPUThread& CPU, ppu_opcode_t op) -{ - const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5); - - CPU.TB = get_timebased_time(); - switch (n) - { - case 0x10C: CPU.GPR[op.rd] = CPU.TB; break; - case 0x10D: CPU.GPR[op.rd] = CPU.TB >> 32; break; - default: throw EXCEPTION(""); - } -} - -void ppu_interpreter::LWAUX(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] = (s64)(s32)vm::read32(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; -} - -void ppu_interpreter::DSTST(PPUThread& CPU, ppu_opcode_t op) -{ -} - -void ppu_interpreter::LHAUX(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] = (s64)(s16)vm::read16(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; -} - -void ppu_interpreter::STHX(PPUThread& CPU, ppu_opcode_t op) -{ - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::write16(VM_CAST(addr), (u16)CPU.GPR[op.rs]); -} - -void ppu_interpreter::ORC(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.GPR[op.ra] = CPU.GPR[op.rs] | ~CPU.GPR[op.rb]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); -} - -void ppu_interpreter::ECOWX(PPUThread& CPU, ppu_opcode_t op) -{ - throw EXCEPTION(""); -} - -void ppu_interpreter::STHUX(PPUThread& CPU, ppu_opcode_t op) -{ - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - vm::write16(VM_CAST(addr), (u16)CPU.GPR[op.rs]); - CPU.GPR[op.ra] = addr; -} - -void ppu_interpreter::OR(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.GPR[op.ra] = CPU.GPR[op.rs] | CPU.GPR[op.rb]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); -} - -void ppu_interpreter::DIVDU(PPUThread& CPU, ppu_opcode_t op) -{ - const u64 RA = CPU.GPR[op.ra]; - const u64 RB = CPU.GPR[op.rb]; - - if (RB == 0) - { - if (op.oe) CPU.SetOV(true); - CPU.GPR[op.rd] = 0; - } - else - { - if (op.oe) CPU.SetOV(false); - CPU.GPR[op.rd] = RA / RB; - } - - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); -} - -void ppu_interpreter::DIVWU(PPUThread& CPU, ppu_opcode_t op) -{ - const u32 RA = (u32)CPU.GPR[op.ra]; - const u32 RB = (u32)CPU.GPR[op.rb]; - - if (RB == 0) - { - if (op.oe) CPU.SetOV(true); - CPU.GPR[op.rd] = 0; - } - else - { - if (op.oe) CPU.SetOV(false); - CPU.GPR[op.rd] = RA / RB; - } - - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); -} - -void ppu_interpreter::MTSPR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MFTB(PPUThread& ppu, ppu_opcode_t op) { const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5); switch (n) { - case 0x001: CPU.XER.XER = CPU.GPR[op.rs]; return; - case 0x008: CPU.LR = CPU.GPR[op.rs]; return; - case 0x009: CPU.CTR = CPU.GPR[op.rs]; return; - case 0x100: CPU.VRSAVE = (u32)CPU.GPR[op.rs]; return; - - case 0x110: - case 0x111: - case 0x112: - case 0x113: - case 0x114: - case 0x115: - case 0x116: - case 0x117: CPU.SPRG[n - 0x110] = CPU.GPR[op.rs]; return; + case 0x10C: ppu.GPR[op.rd] = get_timebased_time() & 0xffffffff; break; + case 0x10D: ppu.GPR[op.rd] = get_timebased_time() >> 32; break; + default: throw fmt::exception("MFSPR 0x%x" HERE, n); } - - throw EXCEPTION(""); } -void ppu_interpreter::DCBI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LWAUX(PPUThread& ppu, ppu_opcode_t op) +{ + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = (s64)(s32)vm::read32(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; +} + +void ppu_interpreter::DSTST(PPUThread& ppu, ppu_opcode_t op) { } -void ppu_interpreter::NAND(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LHAUX(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = ~(CPU.GPR[op.rs] & CPU.GPR[op.rb]); - - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = (s64)(s16)vm::read16(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STVXL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STHX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]) & ~0xfull; - vm::_ref(VM_CAST(addr)) = CPU.VPR[op.vs]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::write16(vm::cast(addr, HERE), (u16)ppu.GPR[op.rs]); } -void ppu_interpreter::DIVD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ORC(PPUThread& ppu, ppu_opcode_t op) { - const s64 RA = CPU.GPR[op.ra]; - const s64 RB = CPU.GPR[op.rb]; + ppu.GPR[op.ra] = ppu.GPR[op.rs] | ~ppu.GPR[op.rb]; + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} - if (RB == 0 || ((u64)RA == (1ULL << 63) && RB == -1)) +void ppu_interpreter::ECOWX(PPUThread& ppu, ppu_opcode_t op) +{ + throw std::runtime_error("ECOWX" HERE); +} + +void ppu_interpreter::STHUX(PPUThread& ppu, ppu_opcode_t op) +{ + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + vm::write16(vm::cast(addr, HERE), (u16)ppu.GPR[op.rs]); + ppu.GPR[op.ra] = addr; +} + +void ppu_interpreter::OR(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.GPR[op.ra] = ppu.GPR[op.rs] | ppu.GPR[op.rb]; + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} + +void ppu_interpreter::DIVDU(PPUThread& ppu, ppu_opcode_t op) +{ + const u64 RA = ppu.GPR[op.ra]; + const u64 RB = ppu.GPR[op.rb]; + ppu.GPR[op.rd] = RB == 0 ? 0 : RA / RB; + if (op.oe) ppu.SetOV(RB == 0); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.rd], 0); +} + +void ppu_interpreter::DIVWU(PPUThread& ppu, ppu_opcode_t op) +{ + const u32 RA = (u32)ppu.GPR[op.ra]; + const u32 RB = (u32)ppu.GPR[op.rb]; + ppu.GPR[op.rd] = RB == 0 ? 0 : RA / RB; + if (op.oe) ppu.SetOV(RB == 0); + if (op.rc) ppu.SetCR(0, false, false, false, ppu.SO); +} + +void ppu_interpreter::MTSPR(PPUThread& ppu, ppu_opcode_t op) +{ + const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5); + + switch (n) { - if (op.oe) CPU.SetOV(true); - CPU.GPR[op.rd] = /*(((u64)RA & (1ULL << 63)) && RB == 0) ? -1 :*/ 0; - } - else + case 0x001: { - if (op.oe) CPU.SetOV(false); - CPU.GPR[op.rd] = RA / RB; + const u64 value = ppu.GPR[op.rs]; + ppu.SO = (value & 0x80000000) != 0; + ppu.OV = (value & 0x40000000) != 0; + ppu.CA = (value & 0x20000000) != 0; + ppu.XCNT = value & 0x7f; + return; + } + case 0x008: ppu.LR = ppu.GPR[op.rs]; return; + case 0x009: ppu.CTR = ppu.GPR[op.rs]; return; + case 0x100: ppu.VRSAVE = (u32)ppu.GPR[op.rs]; return; } - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + throw fmt::exception("MTSPR 0x%x" HERE, n); } -void ppu_interpreter::DIVW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::DCBI(PPUThread& ppu, ppu_opcode_t op) { - const s32 RA = (s32)CPU.GPR[op.ra]; - const s32 RB = (s32)CPU.GPR[op.rb]; - - if (RB == 0 || ((u32)RA == (1 << 31) && RB == -1)) - { - if (op.oe) CPU.SetOV(true); - CPU.GPR[op.rd] = /*(((u32)RA & (1 << 31)) && RB == 0) ? -1 :*/ 0; - } - else - { - if (op.oe) CPU.SetOV(false); - CPU.GPR[op.rd] = (u32)(RA / RB); - } - - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); } -void ppu_interpreter::LVLX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::NAND(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + ppu.GPR[op.ra] = ~(ppu.GPR[op.rs] & ppu.GPR[op.rb]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} + +void ppu_interpreter::STVXL(PPUThread& ppu, ppu_opcode_t op) +{ + const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~0xfull; + vm::_ref(vm::cast(addr, HERE)) = ppu.VR[op.vs]; +} + +void ppu_interpreter::DIVD(PPUThread& ppu, ppu_opcode_t op) +{ + const s64 RA = ppu.GPR[op.ra]; + const s64 RB = ppu.GPR[op.rb]; + const bool o = RB == 0 || ((u64)RA == (1ULL << 63) && RB == -1); + ppu.GPR[op.rd] = o ? 0 : RA / RB; + if (op.oe) ppu.SetOV(o); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.rd], 0); +} + +void ppu_interpreter::DIVW(PPUThread& ppu, ppu_opcode_t op) +{ + const s32 RA = (s32)ppu.GPR[op.ra]; + const s32 RB = (s32)ppu.GPR[op.rb]; + const bool o = RB == 0 || ((u32)RA == (1 << 31) && RB == -1); + ppu.GPR[op.rd] = o ? 0 : u32(RA / RB); + if (op.oe) ppu.SetOV(o); + if (op.rc) ppu.SetCR(0, false, false, false, ppu.SO); +} + +void ppu_interpreter::LVLX(PPUThread& ppu, ppu_opcode_t op) +{ + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; const u32 eb = addr & 0xf; - CPU.VPR[op.vd].clear(); - for (u32 i = 0; i < 16u - eb; ++i) CPU.VPR[op.vd]._u8[15 - i] = vm::read8(VM_CAST(addr + i)); + ppu.VR[op.vd].clear(); + for (u32 i = 0; i < 16u - eb; ++i) ppu.VR[op.vd]._u8[15 - i] = vm::read8(vm::cast(addr + i, HERE)); } -void ppu_interpreter::LDBRX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LDBRX(PPUThread& ppu, 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::_ref>(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::_ref>(vm::cast(addr, HERE)); } -void ppu_interpreter::LSWX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LSWX(PPUThread& ppu, ppu_opcode_t op) { - u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - u32 count = CPU.XER.XER & 0x7F; + u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + u32 count = ppu.XCNT & 0x7f; for (; count >= 4; count -= 4, addr += 4, op.rd = (op.rd + 1) & 31) { - CPU.GPR[op.rd] = vm::_ref(VM_CAST(addr)); + ppu.GPR[op.rd] = vm::_ref(vm::cast(addr, HERE)); } if (count) { u32 value = 0; for (u32 byte = 0; byte < count; byte++) { - u32 byte_value = vm::_ref(VM_CAST(addr + byte)); + u32 byte_value = vm::_ref(vm::cast(addr + byte, HERE)); value |= byte_value << ((3 ^ byte) * 8); } - CPU.GPR[op.rd] = value; + ppu.GPR[op.rd] = value; } } -void ppu_interpreter::LWBRX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LWBRX(PPUThread& ppu, 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::_ref>(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::_ref>(vm::cast(addr, HERE)); } -void ppu_interpreter::LFSX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LFSX(PPUThread& ppu, 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::_ref(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.FPR[op.frd] = vm::_ref(vm::cast(addr, HERE)); } -void ppu_interpreter::SRW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SRW(PPUThread& ppu, ppu_opcode_t op) { - u32 n = CPU.GPR[op.rb] & 0x1f; - u32 r = (u32)rotl32((u32)CPU.GPR[op.rs], 64 - n); - u32 m = ((u32)CPU.GPR[op.rb] & 0x20) ? 0 : (u32)rotate_mask[32 + n][63]; - CPU.GPR[op.ra] = r & m; - - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = (ppu.GPR[op.rs] & 0xffffffff) >> (ppu.GPR[op.rb] & 0x3f); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::SRD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SRD(PPUThread& ppu, ppu_opcode_t op) { - u32 n = CPU.GPR[op.rb] & 0x3f; - u64 r = rotl64(CPU.GPR[op.rs], 64 - n); - u64 m = (CPU.GPR[op.rb] & 0x40) ? 0 : rotate_mask[n][63]; - CPU.GPR[op.ra] = r & m; + u32 n = ppu.GPR[op.rb] & 0x3f; + u64 r = rol64(ppu.GPR[op.rs], 64 - n); + u64 m = (ppu.GPR[op.rb] & 0x40) ? 0 : ppu_rotate_mask(n, 63); + ppu.GPR[op.ra] = r & m; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::LVRX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVRX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; const u8 eb = addr & 0xf; - CPU.VPR[op.vd].clear(); - for (u32 i = 16 - eb; i < 16; ++i) CPU.VPR[op.vd]._u8[15 - i] = vm::read8(VM_CAST(addr + i - 16)); + ppu.VR[op.vd].clear(); + for (u32 i = 16 - eb; i < 16; ++i) ppu.VR[op.vd]._u8[15 - i] = vm::read8(vm::cast(addr + i - 16, HERE)); } -void ppu_interpreter::LSWI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LSWI(PPUThread& ppu, ppu_opcode_t op) { - u64 addr = op.ra ? CPU.GPR[op.ra] : 0; + u64 addr = op.ra ? ppu.GPR[op.ra] : 0; u64 N = op.rb ? op.rb : 32; u8 reg = op.rd; @@ -2561,7 +2576,7 @@ void ppu_interpreter::LSWI(PPUThread& CPU, ppu_opcode_t op) { if (N > 3) { - CPU.GPR[reg] = vm::read32(VM_CAST(addr)); + ppu.GPR[reg] = vm::read32(vm::cast(addr, HERE)); addr += 4; N -= 4; } @@ -2572,104 +2587,104 @@ void ppu_interpreter::LSWI(PPUThread& CPU, ppu_opcode_t op) while (N > 0) { N = N - 1; - buf |= vm::read8(VM_CAST(addr)) << (i * 8); + buf |= vm::read8(vm::cast(addr, HERE)) << (i * 8); addr++; i--; } - CPU.GPR[reg] = buf; + ppu.GPR[reg] = buf; } reg = (reg + 1) % 32; } } -void ppu_interpreter::LFSUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LFSUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - CPU.FPR[op.frd]._double = vm::_ref(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + ppu.FPR[op.frd] = vm::_ref(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::SYNC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SYNC(PPUThread& ppu, ppu_opcode_t op) { _mm_mfence(); } -void ppu_interpreter::LFDX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LFDX(PPUThread& ppu, 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::_ref(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.FPR[op.frd] = vm::_ref(vm::cast(addr, HERE)); } -void ppu_interpreter::LFDUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LFDUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - CPU.FPR[op.frd]._double = vm::_ref(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + ppu.FPR[op.frd] = vm::_ref(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STVLX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STVLX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; const u32 eb = addr & 0xf; - for (u32 i = 0; i < 16u - eb; ++i) vm::write8(VM_CAST(addr + i), CPU.VPR[op.vs]._u8[15 - i]); + for (u32 i = 0; i < 16u - eb; ++i) vm::write8(vm::cast(addr + i, HERE), ppu.VR[op.vs]._u8[15 - i]); } -void ppu_interpreter::STDBRX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STDBRX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::_ref>(VM_CAST(addr)) = CPU.GPR[op.rs]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::_ref>(vm::cast(addr, HERE)) = ppu.GPR[op.rs]; } -void ppu_interpreter::STSWX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STSWX(PPUThread& ppu, ppu_opcode_t op) { - u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - u32 count = CPU.XER.XER & 0x7F; + u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + u32 count = ppu.XCNT & 0x7F; for (; count >= 4; count -= 4, addr += 4, op.rs = (op.rs + 1) & 31) { - vm::write32(VM_CAST(addr), (u32)CPU.GPR[op.rs]); + vm::write32(vm::cast(addr, HERE), (u32)ppu.GPR[op.rs]); } if (count) { - u32 value = (u32)CPU.GPR[op.rs]; + u32 value = (u32)ppu.GPR[op.rs]; for (u32 byte = 0; byte < count; byte++) { u32 byte_value = (u8)(value >> ((3 ^ byte) * 8)); - vm::write8(VM_CAST(addr + byte), byte_value); + vm::write8(vm::cast(addr + byte, HERE), byte_value); } } } -void ppu_interpreter::STWBRX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STWBRX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::_ref>(VM_CAST(addr)) = (u32)CPU.GPR[op.rs]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::_ref>(vm::cast(addr, HERE)) = (u32)ppu.GPR[op.rs]; } -void ppu_interpreter::STFSX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STFSX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::_ref(VM_CAST(addr)) = static_cast(CPU.FPR[op.frs]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::_ref(vm::cast(addr, HERE)) = static_cast(ppu.FPR[op.frs]); } -void ppu_interpreter::STVRX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STVRX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; const u8 eb = addr & 0xf; - for (u32 i = 16 - eb; i < 16; ++i) vm::write8(VM_CAST(addr + i - 16), CPU.VPR[op.vs]._u8[15 - i]); + for (u32 i = 16 - eb; i < 16; ++i) vm::write8(vm::cast(addr + i - 16, HERE), ppu.VR[op.vs]._u8[15 - i]); } -void ppu_interpreter::STFSUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STFSUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - vm::_ref(VM_CAST(addr)) = static_cast(CPU.FPR[op.frs]); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + vm::_ref(vm::cast(addr, HERE)) = static_cast(ppu.FPR[op.frs]); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STSWI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STSWI(PPUThread& ppu, ppu_opcode_t op) { - u64 addr = op.ra ? CPU.GPR[op.ra] : 0; + u64 addr = op.ra ? ppu.GPR[op.ra] : 0; u64 N = op.rb ? op.rb : 32; u8 reg = op.rd; @@ -2677,17 +2692,17 @@ void ppu_interpreter::STSWI(PPUThread& CPU, ppu_opcode_t op) { if (N > 3) { - vm::write32(VM_CAST(addr), (u32)CPU.GPR[reg]); + vm::write32(vm::cast(addr, HERE), (u32)ppu.GPR[reg]); addr += 4; N -= 4; } else { - u32 buf = (u32)CPU.GPR[reg]; + u32 buf = (u32)ppu.GPR[reg]; while (N > 0) { N = N - 1; - vm::write8(VM_CAST(addr), (0xFF000000 & buf) >> 24); + vm::write8(vm::cast(addr, HERE), (0xFF000000 & buf) >> 24); buf <<= 8; addr++; } @@ -2696,631 +2711,598 @@ void ppu_interpreter::STSWI(PPUThread& CPU, ppu_opcode_t op) } } -void ppu_interpreter::STFDX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STFDX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::_ref(VM_CAST(addr)) = CPU.FPR[op.frs]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::_ref(vm::cast(addr, HERE)) = ppu.FPR[op.frs]; } -void ppu_interpreter::STFDUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STFDUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - vm::_ref(VM_CAST(addr)) = CPU.FPR[op.frs]; - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + vm::_ref(vm::cast(addr, HERE)) = ppu.FPR[op.frs]; + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::LVLXL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVLXL(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; const u32 eb = addr & 0xf; - CPU.VPR[op.vd].clear(); - for (u32 i = 0; i < 16u - eb; ++i) CPU.VPR[op.vd]._u8[15 - i] = vm::read8(VM_CAST(addr + i)); + ppu.VR[op.vd].clear(); + for (u32 i = 0; i < 16u - eb; ++i) ppu.VR[op.vd]._u8[15 - i] = vm::read8(vm::cast(addr + i, HERE)); } -void ppu_interpreter::LHBRX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LHBRX(PPUThread& ppu, 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::_ref>(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::_ref>(vm::cast(addr, HERE)); } -void ppu_interpreter::SRAW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SRAW(PPUThread& ppu, ppu_opcode_t op) { - s32 RS = (s32)CPU.GPR[op.rs]; - u8 shift = CPU.GPR[op.rb] & 63; + s32 RS = (s32)ppu.GPR[op.rs]; + u8 shift = ppu.GPR[op.rb] & 63; if (shift > 31) { - CPU.GPR[op.ra] = 0 - (RS < 0); - CPU.XER.CA = (RS < 0); + ppu.GPR[op.ra] = 0 - (RS < 0); + ppu.CA = (RS < 0); } else { - CPU.GPR[op.ra] = RS >> shift; - CPU.XER.CA = (RS < 0) & ((CPU.GPR[op.ra] << shift) != RS); + ppu.GPR[op.ra] = RS >> shift; + ppu.CA = (RS < 0) && ((ppu.GPR[op.ra] << shift) != RS); } - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::SRAD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SRAD(PPUThread& ppu, ppu_opcode_t op) { - s64 RS = CPU.GPR[op.rs]; - u8 shift = CPU.GPR[op.rb] & 127; + s64 RS = ppu.GPR[op.rs]; + u8 shift = ppu.GPR[op.rb] & 127; if (shift > 63) { - CPU.GPR[op.ra] = 0 - (RS < 0); - CPU.XER.CA = (RS < 0); + ppu.GPR[op.ra] = 0 - (RS < 0); + ppu.CA = (RS < 0); } else { - CPU.GPR[op.ra] = RS >> shift; - CPU.XER.CA = (RS < 0) & ((CPU.GPR[op.ra] << shift) != RS); + ppu.GPR[op.ra] = RS >> shift; + ppu.CA = (RS < 0) && ((ppu.GPR[op.ra] << shift) != RS); } - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::LVRXL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVRXL(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; const u8 eb = addr & 0xf; - CPU.VPR[op.vd].clear(); - for (u32 i = 16 - eb; i < 16; ++i) CPU.VPR[op.vd]._u8[15 - i] = vm::read8(VM_CAST(addr + i - 16)); + ppu.VR[op.vd].clear(); + for (u32 i = 16 - eb; i < 16; ++i) ppu.VR[op.vd]._u8[15 - i] = vm::read8(vm::cast(addr + i - 16, HERE)); } -void ppu_interpreter::DSS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::DSS(PPUThread& ppu, ppu_opcode_t op) { } -void ppu_interpreter::SRAWI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SRAWI(PPUThread& ppu, ppu_opcode_t op) { - s32 RS = (u32)CPU.GPR[op.rs]; - CPU.GPR[op.ra] = RS >> op.sh; - CPU.XER.CA = (RS < 0) & ((u32)(CPU.GPR[op.ra] << op.sh) != RS); + s32 RS = (u32)ppu.GPR[op.rs]; + ppu.GPR[op.ra] = RS >> op.sh32; + ppu.CA = (RS < 0) && ((u32)(ppu.GPR[op.ra] << op.sh32) != RS); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::SRADI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SRADI(PPUThread& ppu, ppu_opcode_t op) { - auto sh = (op.shh << 5) | op.shl; - s64 RS = CPU.GPR[op.rs]; - CPU.GPR[op.ra] = RS >> sh; - CPU.XER.CA = (RS < 0) & ((CPU.GPR[op.ra] << sh) != RS); + auto sh = op.sh64; + s64 RS = ppu.GPR[op.rs]; + ppu.GPR[op.ra] = RS >> sh; + ppu.CA = (RS < 0) && ((ppu.GPR[op.ra] << sh) != RS); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::EIEIO(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::EIEIO(PPUThread& ppu, ppu_opcode_t op) { _mm_mfence(); } -void ppu_interpreter::STVLXL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STVLXL(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; const u32 eb = addr & 0xf; - for (u32 i = 0; i < 16u - eb; ++i) vm::write8(VM_CAST(addr + i), CPU.VPR[op.vs]._u8[15 - i]); + for (u32 i = 0; i < 16u - eb; ++i) vm::write8(vm::cast(addr + i, HERE), ppu.VR[op.vs]._u8[15 - i]); } -void ppu_interpreter::STHBRX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STHBRX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::_ref>(VM_CAST(addr)) = (u16)CPU.GPR[op.rs]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::_ref>(vm::cast(addr, HERE)) = (u16)ppu.GPR[op.rs]; } -void ppu_interpreter::EXTSH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::EXTSH(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = (s64)(s16)CPU.GPR[op.rs]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = (s64)(s16)ppu.GPR[op.rs]; + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::STVRXL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STVRXL(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; const u8 eb = addr & 0xf; - for (u32 i = 16 - eb; i < 16; ++i) vm::write8(VM_CAST(addr + i - 16), CPU.VPR[op.vs]._u8[15 - i]); + for (u32 i = 16 - eb; i < 16; ++i) vm::write8(vm::cast(addr + i - 16, HERE), ppu.VR[op.vs]._u8[15 - i]); } -void ppu_interpreter::EXTSB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::EXTSB(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = (s64)(s8)CPU.GPR[op.rs]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = (s64)(s8)ppu.GPR[op.rs]; + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::STFIWX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STFIWX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::write32(VM_CAST(addr), (u32&)CPU.FPR[op.frs]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::write32(vm::cast(addr, HERE), (u32&)ppu.FPR[op.frs]); } -void ppu_interpreter::EXTSW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::EXTSW(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = (s64)(s32)CPU.GPR[op.rs]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = (s64)(s32)ppu.GPR[op.rs]; + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::ICBI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ICBI(PPUThread& ppu, ppu_opcode_t op) { } -void ppu_interpreter::DCBZ(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::DCBZ(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; - std::memset(vm::base(VM_CAST(addr) & ~127), 0, 128); + std::memset(vm::base(vm::cast(addr, HERE) & ~127), 0, 128); } -void ppu_interpreter::LWZ(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LWZ(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - CPU.GPR[op.rd] = vm::read32(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + ppu.GPR[op.rd] = vm::read32(vm::cast(addr, HERE)); } -void ppu_interpreter::LWZU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LWZU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - CPU.GPR[op.rd] = vm::read32(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + ppu.GPR[op.rd] = vm::read32(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::LBZ(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LBZ(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - CPU.GPR[op.rd] = vm::read8(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + ppu.GPR[op.rd] = vm::read8(vm::cast(addr, HERE)); } -void ppu_interpreter::LBZU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LBZU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - CPU.GPR[op.rd] = vm::read8(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + ppu.GPR[op.rd] = vm::read8(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STW(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - vm::write32(VM_CAST(addr), (u32)CPU.GPR[op.rs]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + vm::write32(vm::cast(addr, HERE), (u32)ppu.GPR[op.rs]); } -void ppu_interpreter::STWU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STWU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - vm::write32(VM_CAST(addr), (u32)CPU.GPR[op.rs]); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + vm::write32(vm::cast(addr, HERE), (u32)ppu.GPR[op.rs]); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STB(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - vm::write8(VM_CAST(addr), (u8)CPU.GPR[op.rs]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + vm::write8(vm::cast(addr, HERE), (u8)ppu.GPR[op.rs]); } -void ppu_interpreter::STBU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STBU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - vm::write8(VM_CAST(addr), (u8)CPU.GPR[op.rs]); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + vm::write8(vm::cast(addr, HERE), (u8)ppu.GPR[op.rs]); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::LHZ(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LHZ(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - CPU.GPR[op.rd] = vm::read16(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + ppu.GPR[op.rd] = vm::read16(vm::cast(addr, HERE)); } -void ppu_interpreter::LHZU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LHZU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - CPU.GPR[op.rd] = vm::read16(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + ppu.GPR[op.rd] = vm::read16(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::LHA(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LHA(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - CPU.GPR[op.rd] = (s64)(s16)vm::read16(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + ppu.GPR[op.rd] = (s64)(s16)vm::read16(vm::cast(addr, HERE)); } -void ppu_interpreter::LHAU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LHAU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - CPU.GPR[op.rd] = (s64)(s16)vm::read16(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + ppu.GPR[op.rd] = (s64)(s16)vm::read16(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STH(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - vm::write16(VM_CAST(addr), (u16)CPU.GPR[op.rs]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + vm::write16(vm::cast(addr, HERE), (u16)ppu.GPR[op.rs]); } -void ppu_interpreter::STHU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STHU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - vm::write16(VM_CAST(addr), (u16)CPU.GPR[op.rs]); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + vm::write16(vm::cast(addr, HERE), (u16)ppu.GPR[op.rs]); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::LMW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LMW(PPUThread& ppu, ppu_opcode_t op) { - u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; + u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; for (u32 i = op.rd; i<32; ++i, addr += 4) { - CPU.GPR[i] = vm::read32(VM_CAST(addr)); + ppu.GPR[i] = vm::read32(vm::cast(addr, HERE)); } } -void ppu_interpreter::STMW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STMW(PPUThread& ppu, ppu_opcode_t op) { - u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; + u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; for (u32 i = op.rs; i<32; ++i, addr += 4) { - vm::write32(VM_CAST(addr), (u32)CPU.GPR[i]); + vm::write32(vm::cast(addr, HERE), (u32)ppu.GPR[i]); } } -void ppu_interpreter::LFS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LFS(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - CPU.FPR[op.frd]._double = vm::_ref(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + ppu.FPR[op.frd] = vm::_ref(vm::cast(addr, HERE)); } -void ppu_interpreter::LFSU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LFSU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - CPU.FPR[op.frd]._double = vm::_ref(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + ppu.FPR[op.frd] = vm::_ref(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::LFD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LFD(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - CPU.FPR[op.frd]._double = vm::_ref(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + ppu.FPR[op.frd] = vm::_ref(vm::cast(addr, HERE)); } -void ppu_interpreter::LFDU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LFDU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - CPU.FPR[op.frd]._double = vm::_ref(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + ppu.FPR[op.frd] = vm::_ref(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STFS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STFS(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - vm::_ref(VM_CAST(addr)) = static_cast(CPU.FPR[op.frs]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + vm::_ref(vm::cast(addr, HERE)) = static_cast(ppu.FPR[op.frs]); } -void ppu_interpreter::STFSU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STFSU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - vm::_ref(VM_CAST(addr)) = static_cast(CPU.FPR[op.frs]); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + vm::_ref(vm::cast(addr, HERE)) = static_cast(ppu.FPR[op.frs]); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STFD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STFD(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - vm::_ref(VM_CAST(addr)) = CPU.FPR[op.frs]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + vm::_ref(vm::cast(addr, HERE)) = ppu.FPR[op.frs]; } -void ppu_interpreter::STFDU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STFDU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - vm::_ref(VM_CAST(addr)) = CPU.FPR[op.frs]; - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + vm::_ref(vm::cast(addr, HERE)) = ppu.FPR[op.frs]; + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::LD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LD(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.simm16 & ~3) + (op.ra ? CPU.GPR[op.ra] : 0); - CPU.GPR[op.rd] = vm::read64(VM_CAST(addr)); + const u64 addr = (op.simm16 & ~3) + (op.ra ? ppu.GPR[op.ra] : 0); + ppu.GPR[op.rd] = vm::read64(vm::cast(addr, HERE)); } -void ppu_interpreter::LDU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LDU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + (op.simm16 & ~3); - CPU.GPR[op.rd] = vm::read64(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + (op.simm16 & ~3); + ppu.GPR[op.rd] = vm::read64(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::LWA(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LWA(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.simm16 & ~3) + (op.ra ? CPU.GPR[op.ra] : 0); - CPU.GPR[op.rd] = (s64)(s32)vm::read32(VM_CAST(addr)); + const u64 addr = (op.simm16 & ~3) + (op.ra ? ppu.GPR[op.ra] : 0); + ppu.GPR[op.rd] = (s64)(s32)vm::read32(vm::cast(addr, HERE)); } -void ppu_interpreter::FDIVS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FDIVS(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] / CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] / ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FSUBS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FSUBS(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] - CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] - ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FADDS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FADDS(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] + CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] + ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FSQRTS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FSQRTS(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = sqrt(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(sqrt(ppu.FPR[op.frb])); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FRES(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FRES(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = 1.0 / CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(1.0 / ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FMULS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FMULS(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] * CPU.FPR[op.frc]; - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] * ppu.FPR[op.frc]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FMADDS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FMADDS(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] * CPU.FPR[op.frc] + CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] * ppu.FPR[op.frc] + ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FMSUBS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FMSUBS(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] * CPU.FPR[op.frc] - CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] * ppu.FPR[op.frc] - ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FNMSUBS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FNMSUBS(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = -(CPU.FPR[op.fra] * CPU.FPR[op.frc]) + CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(-(ppu.FPR[op.fra] * ppu.FPR[op.frc]) + ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FNMADDS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FNMADDS(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = -(CPU.FPR[op.fra] * CPU.FPR[op.frc]) - CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(-(ppu.FPR[op.fra] * ppu.FPR[op.frc]) - ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::STD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STD(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.simm16 & ~3) + (op.ra ? CPU.GPR[op.ra] : 0); - vm::write64(VM_CAST(addr), CPU.GPR[op.rs]); + const u64 addr = (op.simm16 & ~3) + (op.ra ? ppu.GPR[op.ra] : 0); + vm::write64(vm::cast(addr, HERE), ppu.GPR[op.rs]); } -void ppu_interpreter::STDU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STDU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + (op.simm16 & ~3); - vm::write64(VM_CAST(addr), CPU.GPR[op.rs]); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + (op.simm16 & ~3); + vm::write64(vm::cast(addr, HERE), ppu.GPR[op.rs]); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::MTFSB1(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MTFSB1(PPUThread& ppu, ppu_opcode_t op) { - u32 mask = 1 << (31 - op.crbd); - if ((op.crbd >= 3 && op.crbd <= 6) && !(CPU.FPSCR.FPSCR & mask)) mask |= 1ULL << 31; //FPSCR.FX - if ((op.crbd == 29) && !CPU.FPSCR.NI) LOG_WARNING(PPU, "Non-IEEE mode enabled"); - CPU.SetFPSCR(CPU.FPSCR.FPSCR | mask); - - if (op.rc) CPU.UpdateCR1(); + LOG_WARNING(PPU, "MTFSB1"); + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::MCRFS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MCRFS(PPUThread& ppu, ppu_opcode_t op) { - CPU.SetCR(op.crfd, (CPU.FPSCR.FPSCR >> ((7 - op.crfs) * 4)) & 0xf); - const u32 exceptions_mask = 0x9FF80700; - CPU.SetFPSCR(CPU.FPSCR.FPSCR & ~(exceptions_mask & 0xf << ((7 - op.crfs) * 4))); + LOG_WARNING(PPU, "MCRFS"); + ppu.SetCR(op.crfd, false, false, false, false); } -void ppu_interpreter::MTFSB0(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MTFSB0(PPUThread& ppu, ppu_opcode_t op) { - u32 mask = 1 << (31 - op.crbd); - if ((op.crbd == 29) && !CPU.FPSCR.NI) LOG_WARNING(PPU, "Non-IEEE mode disabled"); - CPU.SetFPSCR(CPU.FPSCR.FPSCR & ~mask); - - if (op.rc) CPU.UpdateCR1(); + LOG_WARNING(PPU, "MTFSB0"); + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::MTFSFI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MTFSFI(PPUThread& ppu, ppu_opcode_t op) { - u32 mask = 0xF0000000 >> (op.crfd * 4); - u32 val = (op.i & 0xF) << ((7 - op.crfd) * 4); - - const u32 oldNI = CPU.FPSCR.NI; - CPU.SetFPSCR((CPU.FPSCR.FPSCR & ~mask) | val); - if (CPU.FPSCR.NI != oldNI) - { - if (oldNI) - LOG_WARNING(PPU, "Non-IEEE mode disabled"); - else - LOG_WARNING(PPU, "Non-IEEE mode enabled"); - } - - if (op.rc) CPU.UpdateCR1(); + LOG_WARNING(PPU, "MTFSFI"); + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::MFFS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MFFS(PPUThread& ppu, ppu_opcode_t op) { - (u64&)CPU.FPR[op.frd]._double = CPU.FPSCR.FPSCR; - if (op.rc) CPU.UpdateCR1(); + LOG_WARNING(PPU, "MFFS"); + ppu.FPR[op.frd] = 0.0; + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::MTFSF(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MTFSF(PPUThread& ppu, ppu_opcode_t op) { - u32 mask = 0; - for (u32 i = 0; i<8; ++i) - { - if (op.flm & (1 << i)) mask |= 0xf << (i * 4); - } - mask &= ~0x60000000; + LOG_WARNING(PPU, "MTFSF"); + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} - const u32 oldNI = CPU.FPSCR.NI; - CPU.SetFPSCR((CPU.FPSCR.FPSCR & ~mask) | ((u32&)CPU.FPR[op.frb] & mask)); - if (CPU.FPSCR.NI != oldNI) - { - if (oldNI) - LOG_WARNING(PPU, "Non-IEEE mode disabled"); - else - LOG_WARNING(PPU, "Non-IEEE mode enabled"); - } - if (op.rc) CPU.UpdateCR1(); +void ppu_interpreter::FCMPU(PPUThread& ppu, ppu_opcode_t op) +{ + const f64 a = ppu.FPR[op.fra]; + const f64 b = ppu.FPR[op.frb]; + ppu.FG = a > b; + ppu.FL = a < b; + ppu.FE = a == b; + //ppu.FU = a != a || b != b; + ppu.SetCR(op.crfd, ppu.FL, ppu.FG, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FRSP(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = f32(ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FCTIW(PPUThread& ppu, ppu_opcode_t op) +{ + (s32&)ppu.FPR[op.frd] = lrint(ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FCTIWZ(PPUThread& ppu, ppu_opcode_t op) +{ + (s32&)ppu.FPR[op.frd] = static_cast(ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FDIV(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = ppu.FPR[op.fra] / ppu.FPR[op.frb]; + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FSUB(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = ppu.FPR[op.fra] - ppu.FPR[op.frb]; + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FADD(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = ppu.FPR[op.fra] + ppu.FPR[op.frb]; + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FSQRT(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = sqrt(ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FSEL(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = ppu.FPR[op.fra] >= 0.0 ? ppu.FPR[op.frc] : ppu.FPR[op.frb]; + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FMUL(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = ppu.FPR[op.fra] * ppu.FPR[op.frc]; + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FRSQRTE(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = 1.0 / sqrt(ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FMSUB(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = ppu.FPR[op.fra] * ppu.FPR[op.frc] - ppu.FPR[op.frb]; + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FMADD(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = ppu.FPR[op.fra] * ppu.FPR[op.frc] + ppu.FPR[op.frb]; + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FNMSUB(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = -(ppu.FPR[op.fra] * ppu.FPR[op.frc]) + ppu.FPR[op.frb]; + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FNMADD(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = -(ppu.FPR[op.fra] * ppu.FPR[op.frc]) - ppu.FPR[op.frb]; + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FCMPO(PPUThread& ppu, ppu_opcode_t op) +{ + return FCMPU(ppu, op); +} + +void ppu_interpreter::FNEG(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = -ppu.FPR[op.frb]; + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FMR(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = ppu.FPR[op.frb]; + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FNABS(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = -fabs(ppu.FPR[op.frb]); + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FABS(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = fabs(ppu.FPR[op.frb]); + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FCTID(PPUThread& ppu, ppu_opcode_t op) +{ + (s64&)ppu.FPR[op.frd] = llrint(ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FCTIDZ(PPUThread& ppu, ppu_opcode_t op) +{ + (s64&)ppu.FPR[op.frd] = static_cast(ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FCFID(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = static_cast((s64&)ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FCMPU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::UNK(PPUThread& ppu, ppu_opcode_t op) { - s32 cmp_res = FPRdouble::Cmp(CPU.FPR[op.fra], CPU.FPR[op.frb]); - //CPU.FPSCR.FPRF = cmp_res; - CPU.SetCR(op.crfd, cmp_res); -} - -void ppu_interpreter::FRSP(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = static_cast(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FCTIW(PPUThread& CPU, ppu_opcode_t op) -{ - (s32&)CPU.FPR[op.frd]._double = lrint(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FCTIWZ(PPUThread& CPU, ppu_opcode_t op) -{ - (s32&)CPU.FPR[op.frd]._double = static_cast(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FDIV(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] / CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FSUB(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] - CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FADD(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] + CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FSQRT(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = sqrt(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FSEL(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] >= 0.0 ? CPU.FPR[op.frc] : CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FMUL(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] * CPU.FPR[op.frc]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FRSQRTE(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = 1.0 / sqrt(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FMSUB(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] * CPU.FPR[op.frc] - CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FMADD(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] * CPU.FPR[op.frc] + CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FNMSUB(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = -(CPU.FPR[op.fra] * CPU.FPR[op.frc]) + CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FNMADD(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = -(CPU.FPR[op.fra] * CPU.FPR[op.frc]) - CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FCMPO(PPUThread& CPU, ppu_opcode_t op) -{ - s32 cmp_res = FPRdouble::Cmp(CPU.FPR[op.fra], CPU.FPR[op.frb]); - //CPU.FPSCR.FPRF = cmp_res; - CPU.SetCR(op.crfd, cmp_res); -} - -void ppu_interpreter::FNEG(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = -CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FMR(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FNABS(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = -fabs(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FABS(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = fabs(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FCTID(PPUThread& CPU, ppu_opcode_t op) -{ - (s64&)CPU.FPR[op.frd]._double = llrint(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FCTIDZ(PPUThread& CPU, ppu_opcode_t op) -{ - (s64&)CPU.FPR[op.frd]._double = static_cast(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FCFID(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = static_cast((s64&)CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - - -void ppu_interpreter::UNK(PPUThread& CPU, ppu_opcode_t op) -{ - throw EXCEPTION(""); + throw fmt::exception("Unknown/Illegal opcode: 0x%08x" HERE, op.opcode); } diff --git a/rpcs3/Emu/Cell/PPUInterpreter.h b/rpcs3/Emu/Cell/PPUInterpreter.h index 984723c34e..ddca283103 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.h +++ b/rpcs3/Emu/Cell/PPUInterpreter.h @@ -1,4719 +1,403 @@ #pragma once -#include "Emu/Cell/PPUOpcodes.h" -#include "Emu/Memory/Memory.h" +#include "PPUOpcodes.h" -#if defined(_MSC_VER) -#include -#else -#include -#define _rotl64(x,r) (((u64)(x) << (r)) | ((u64)(x) >> (64 - (r)))) -#endif +class PPUThread; -#if defined(__GNUG__) -inline std::uint64_t UMULH64(std::uint64_t a, std::uint64_t b) +using ppu_inter_func_t = void(*)(PPUThread& ppu, ppu_opcode_t op); + +struct ppu_interpreter { - std::uint64_t result; - __asm__("mulq %[b]" : "=d" (result) : [a] "a" (a), [b] "rm" (b)); - return result; -} - -inline std::int64_t MULH64(std::int64_t a, std::int64_t b) -{ - std::int64_t result; - __asm__("imulq %[b]" : "=d" (result) : [a] "a" (a), [b] "rm" (b)); - return result; -} -#else -#define UMULH64 __umulh -#define MULH64 __mulh -#endif - -#include - -extern u64 rotate_mask[64][64]; // defined in PPUThread.cpp -extern u64 get_timebased_time(); - -inline void InitRotateMask() -{ - static bool inited = false; - if(inited) return; - - for(u32 mb=0; mb<64; mb++) for(u32 me=0; me<64; me++) - { - const u64 mask = ((u64)-1 >> mb) ^ ((me >= 63) ? 0 : (u64)-1 >> (me + 1)); - rotate_mask[mb][me] = mb > me ? ~mask : mask; - } - - inited = true; -} - -inline u8 rotl8(const u8 x, const u8 n) { return (x << n) | (x >> (8 - n)); } -inline u8 rotr8(const u8 x, const u8 n) { return (x >> n) | (x << (8 - n)); } - -inline u16 rotl16(const u16 x, const u8 n) { return (x << n) | (x >> (16 - n)); } -inline u16 rotr16(const u16 x, const u8 n) { return (x >> n) | (x << (16 - n)); } -/* -u32 rotl32(const u32 x, const u8 n) { return (x << n) | (x >> (32 - n)); } -u32 rotr32(const u32 x, const u8 n) { return (x >> n) | (x << (32 - n)); } -u64 rotl64(const u64 x, const u8 n) { return (x << n) | (x >> (64 - n)); } -u64 rotr64(const u64 x, const u8 n) { return (x >> n) | (x << (64 - n)); } -*/ - -#define rotl32(x, n) _rotl64((u64)(u32)x | ((u64)(u32)x << 32), n) -#define rotr32(x, n) _rotr64((u64)(u32)x | ((u64)(u32)x << 32), n) -#define rotl64 _rotl64 -#define rotr64 _rotr64 - -static double SilenceNaN(double x) -{ - u64 bits = (u64&)x; - bits |= 0x0008000000000000ULL; - return (double&)bits; -} - -static float SilenceNaN(float x) -{ - return static_cast(SilenceNaN(static_cast(x))); -} - -static void SetHostRoundingMode(u32 rn) -{ - switch (rn) - { - case FPSCR_RN_NEAR: - fesetround(FE_TONEAREST); - break; - case FPSCR_RN_ZERO: - fesetround(FE_TOWARDZERO); - break; - case FPSCR_RN_PINF: - fesetround(FE_UPWARD); - break; - case FPSCR_RN_MINF: - fesetround(FE_DOWNWARD); - break; - } -} - - -namespace ppu_recompiler_llvm { - class Compiler; - class RecompilationEngine; -} - -class ppu_llvm_test_class; - -class PPUInterpreter : public PPUOpcodes -{ -#ifdef PPU_LLVM_RECOMPILER - friend class ppu_recompiler_llvm::Compiler; - friend class ppu_llvm_test_class; - friend class ppu_recompiler_llvm::RecompilationEngine; -#endif -private: - PPUThread& CPU; - -public: - PPUInterpreter(PPUThread& cpu) : CPU(cpu) - { - } - -private: - void CheckHostFPExceptions() - { - CPU.SetFPSCR_FI(fetestexcept(FE_INEXACT) != 0); - if (fetestexcept(FE_UNDERFLOW)) CPU.SetFPSCRException(FPSCR_UX); - if (fetestexcept(FE_OVERFLOW)) CPU.SetFPSCRException(FPSCR_OX); - } - - void NULL_OP() override - { - throw EXCEPTION("Null operation"); - } - - void NOP() override - { - //__asm nop - } - - float CheckVSCR_NJ(const float v) const - { - if(!CPU.VSCR.NJ) return v; - - const int fpc = _fpclass(v); -#ifdef __GNUG__ - if(fpc == FP_SUBNORMAL) - return std::signbit(v) ? -0.0f : 0.0f; -#else - if(fpc & _FPCLASS_ND) return -0.0f; - if(fpc & _FPCLASS_PD) return 0.0f; -#endif - - return v; - } - - bool CheckCondition(u32 bo, u32 bi) - { - const u8 bo0 = (bo & 0x10) ? 1 : 0; - const u8 bo1 = (bo & 0x08) ? 1 : 0; - const u8 bo2 = (bo & 0x04) ? 1 : 0; - const u8 bo3 = (bo & 0x02) ? 1 : 0; - - if(!bo2) --CPU.CTR; - - const u8 ctr_ok = bo2 | ((CPU.CTR != 0) ^ bo3); - const u8 cond_ok = bo0 | (CPU.IsCR(bi) ^ (~bo1 & 0x1)); - - return ctr_ok && cond_ok; - } - - u64 ReadSPR(u32 spr) - { - const u32 n = (spr >> 5) | ((spr & 0x1f) << 5); - - switch (n) - { - case 0x001: return CPU.XER.XER; - case 0x008: return CPU.LR; - case 0x009: return CPU.CTR; - case 0x100: return CPU.VRSAVE; - case 0x103: return CPU.SPRG[3]; - - case 0x10C: CPU.TB = get_timebased_time(); return CPU.TB; - case 0x10D: CPU.TB = get_timebased_time(); return CPU.TB >> 32; - - case 0x110: - case 0x111: - case 0x112: - case 0x113: - case 0x114: - case 0x115: - case 0x116: - case 0x117: return CPU.SPRG[n - 0x110]; - } - - throw EXCEPTION("Unknown SPR (spr=0x%x, n=0x%x)", spr, n); - } - - void WriteSPR(u32 spr, u64 value) - { - const u32 n = (spr >> 5) | ((spr & 0x1f) << 5); - - switch (n) - { - case 0x001: CPU.XER.XER = value; return; - case 0x008: CPU.LR = value; return; - case 0x009: CPU.CTR = value; return; - case 0x100: CPU.VRSAVE = (u32)value; return; - case 0x103: throw EXCEPTION("WriteSPR(0x103, 0x%llx): Write to read-only SPR", value); - - case 0x10C: throw EXCEPTION("WriteSPR(0x10C, 0x%llx): Write to time-based SPR", value); - case 0x10D: throw EXCEPTION("WriteSPR(0x10D, 0x%llx): Write to time-based SPR", value); - - case 0x110: - case 0x111: - case 0x112: - case 0x113: - case 0x114: - case 0x115: - case 0x116: - case 0x117: CPU.SPRG[n - 0x110] = value; return; - } - - throw EXCEPTION("Unknown SPR (spr=0x%x, n=0x%x, value=0x%llx)", spr, n, value); - } - - void TDI(u32 to, u32 ra, s32 simm16) override - { - s64 a = CPU.GPR[ra]; - - if( (a < (s64)simm16 && (to & 0x10)) || - (a > (s64)simm16 && (to & 0x8)) || - (a == (s64)simm16 && (to & 0x4)) || - ((u64)a < (u64)simm16 && (to & 0x2)) || - ((u64)a > (u64)simm16 && (to & 0x1)) ) - { - throw EXCEPTION("Trap! (tdi 0x%x, r%d, 0x%x)", to, ra, simm16); - } - } - - static void TWI_impl(PPUThread *CPU, u32 to, u32 ra, s32 simm16) - { - s32 a = (s32)CPU->GPR[ra]; - - if ((a < simm16 && (to & 0x10)) || - (a > simm16 && (to & 0x8)) || - (a == simm16 && (to & 0x4)) || - ((u32)a < (u32)simm16 && (to & 0x2)) || - ((u32)a > (u32)simm16 && (to & 0x1)) ) - { - throw EXCEPTION("Trap! (twi 0x%x, r%d, 0x%x)", to, ra, simm16); - } - } - - void TWI(u32 to, u32 ra, s32 simm16) override - { - TWI_impl(&CPU, to, ra, simm16); - } - - void MFVSCR(u32 vd) override //nf - { - CPU.VPR[vd].clear(); - CPU.VPR[vd]._u32[0] = CPU.VSCR.VSCR; - } - void MTVSCR(u32 vb) override - { - CPU.VSCR.VSCR = CPU.VPR[vb]._u32[0]; - CPU.VSCR.X = CPU.VSCR.Y = 0; - } - void VADDCUW(u32 vd, u32 va, u32 vb) override //nf - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = ~CPU.VPR[va]._u32[w] < CPU.VPR[vb]._u32[w]; - } - } - void VADDFP(u32 vd, u32 va, u32 vb) override - { - SetHostRoundingMode(FPSCR_RN_NEAR); - for (uint w = 0; w < 4; w++) - { - const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]); - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(a)) - CPU.VPR[vd]._f[w] = SilenceNaN(a); - else if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else if (std::isinf(a) && std::isinf(b) && a != b) - CPU.VPR[vd]._f[w] = (float)FPR_NAN; - else - CPU.VPR[vd]._f[w] = CheckVSCR_NJ(a + b); - } - } - void VADDSBS(u32 vd, u32 va, u32 vb) override //nf - { - for(u32 b=0; b<16; ++b) - { - s16 result = (s16)CPU.VPR[va]._s8[b] + (s16)CPU.VPR[vb]._s8[b]; - - if (result > 0x7f) - { - CPU.VPR[vd]._s8[b] = 0x7f; - CPU.VSCR.SAT = 1; - } - else if (result < -0x80) - { - CPU.VPR[vd]._s8[b] = -0x80; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s8[b] = (s8)result; - } - } - void VADDSHS(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - s32 result = (s32)CPU.VPR[va]._s16[h] + (s32)CPU.VPR[vb]._s16[h]; - - if (result > 0x7fff) - { - CPU.VPR[vd]._s16[h] = 0x7fff; - CPU.VSCR.SAT = 1; - } - else if (result < -0x8000) - { - CPU.VPR[vd]._s16[h] = -0x8000; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s16[h] = result; - } - } - void VADDSWS(u32 vd, u32 va, u32 vb) override //nf - { - for (uint w = 0; w < 4; w++) - { - s64 result = (s64)CPU.VPR[va]._s32[w] + (s64)CPU.VPR[vb]._s32[w]; - - if (result > 0x7fffffff) - { - CPU.VPR[vd]._s32[w] = 0x7fffffff; - CPU.VSCR.SAT = 1; - } - else if (result < (s32)0x80000000) - { - CPU.VPR[vd]._s32[w] = 0x80000000; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s32[w] = (s32)result; - } - } - void VADDUBM(u32 vd, u32 va, u32 vb) override - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = CPU.VPR[va]._u8[b] + CPU.VPR[vb]._u8[b]; - } - } - void VADDUBS(u32 vd, u32 va, u32 vb) override - { - for (uint b = 0; b < 16; b++) - { - u16 result = (u16)CPU.VPR[va]._u8[b] + (u16)CPU.VPR[vb]._u8[b]; - - if (result > 0xff) - { - CPU.VPR[vd]._u8[b] = 0xff; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._u8[b] = (u8)result; - } - } - void VADDUHM(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = CPU.VPR[va]._u16[h] + CPU.VPR[vb]._u16[h]; - } - } - void VADDUHS(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - u32 result = (u32)CPU.VPR[va]._u16[h] + (u32)CPU.VPR[vb]._u16[h]; - - if (result > 0xffff) - { - CPU.VPR[vd]._u16[h] = 0xffff; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._u16[h] = result; - } - } - void VADDUWM(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] + CPU.VPR[vb]._u32[w]; - } - } - void VADDUWS(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - u64 result = (u64)CPU.VPR[va]._u32[w] + (u64)CPU.VPR[vb]._u32[w]; - - if (result > 0xffffffff) - { - CPU.VPR[vd]._u32[w] = 0xffffffff; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._u32[w] = (u32)result; - } - } - void VAND(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] & CPU.VPR[vb]._u32[w]; - } - } - void VANDC(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] & (~CPU.VPR[vb]._u32[w]); - } - } - void VAVGSB(u32 vd, u32 va, u32 vb) override //nf - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._s8[b] = (CPU.VPR[va]._s8[b] + CPU.VPR[vb]._s8[b] + 1) >> 1; - } - } - void VAVGSH(u32 vd, u32 va, u32 vb) override //nf - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._s16[h] = (CPU.VPR[va]._s16[h] + CPU.VPR[vb]._s16[h] + 1) >> 1; - } - } - void VAVGSW(u32 vd, u32 va, u32 vb) override //nf - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s32[w] = ((s64)CPU.VPR[va]._s32[w] + (s64)CPU.VPR[vb]._s32[w] + 1) >> 1; - } - } - void VAVGUB(u32 vd, u32 va, u32 vb) override - { - for (uint b = 0; b < 16; b++) - CPU.VPR[vd]._u8[b] = (CPU.VPR[va]._u8[b] + CPU.VPR[vb]._u8[b] + 1) >> 1; - } - void VAVGUH(u32 vd, u32 va, u32 vb) override //nf - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = (CPU.VPR[va]._u16[h] + CPU.VPR[vb]._u16[h] + 1) >> 1; - } - } - void VAVGUW(u32 vd, u32 va, u32 vb) override //nf - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = ((u64)CPU.VPR[va]._u32[w] + (u64)CPU.VPR[vb]._u32[w] + 1) >> 1; - } - } - void VCFSX(u32 vd, u32 uimm5, u32 vb) override - { - SetHostRoundingMode(FPSCR_RN_NEAR); - u32 scale = 1 << uimm5; - - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._f[w] = ((float)CPU.VPR[vb]._s32[w]) / scale; - } - } - void VCFUX(u32 vd, u32 uimm5, u32 vb) override - { - SetHostRoundingMode(FPSCR_RN_NEAR); - u32 scale = 1 << uimm5; - - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._f[w] = ((float)CPU.VPR[vb]._u32[w]) / scale; - } - } - void VCMPBFP(u32 vd, u32 va, u32 vb, u32 rc) - { - bool allInBounds = true; - - for (uint w = 0; w < 4; w++) - { - u32 mask = 1<<31 | 1<<30; - - const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]); - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - - if (a <= b) mask &= ~(1 << 31); - if (a >= -b) mask &= ~(1 << 30); - - CPU.VPR[vd]._u32[w] = mask; - - if (mask) - allInBounds = false; - } - - if (rc) - { - // Bit n°2 of CR6 - CPU.SetCR(6, 0); - CPU.SetCRBit(6, 0x2, allInBounds); - } - } - void VCMPBFP(u32 vd, u32 va, u32 vb) override {VCMPBFP(vd, va, vb, false);} - void VCMPBFP_(u32 vd, u32 va, u32 vb) override {VCMPBFP(vd, va, vb, true);} - void VCMPEQFP(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_equal = 0x8; - int none_equal = 0x2; - - for (uint w = 0; w < 4; w++) - { - if (CPU.VPR[va]._f[w] == CPU.VPR[vb]._f[w]) - { - CPU.VPR[vd]._u32[w] = 0xffffffff; - none_equal = 0; - } - else - { - CPU.VPR[vd]._u32[w] = 0; - all_equal = 0; - } - } - - if (rc) CPU.CR.cr6 = all_equal | none_equal; - } - void VCMPEQFP(u32 vd, u32 va, u32 vb) override {VCMPEQFP(vd, va, vb, false);} - void VCMPEQFP_(u32 vd, u32 va, u32 vb) override {VCMPEQFP(vd, va, vb, true);} - void VCMPEQUB(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_equal = 0x8; - int none_equal = 0x2; - - for (uint b = 0; b < 16; b++) - { - if (CPU.VPR[va]._u8[b] == CPU.VPR[vb]._u8[b]) - { - CPU.VPR[vd]._u8[b] = 0xff; - none_equal = 0; - } - else - { - CPU.VPR[vd]._u8[b] = 0; - all_equal = 0; - } - } - - if (rc) CPU.CR.cr6 = all_equal | none_equal; - } - void VCMPEQUB(u32 vd, u32 va, u32 vb) override {VCMPEQUB(vd, va, vb, false);} - void VCMPEQUB_(u32 vd, u32 va, u32 vb) override {VCMPEQUB(vd, va, vb, true);} - void VCMPEQUH(u32 vd, u32 va, u32 vb, u32 rc) //nf - { - int all_equal = 0x8; - int none_equal = 0x2; - - for (uint h = 0; h < 8; h++) - { - if (CPU.VPR[va]._u16[h] == CPU.VPR[vb]._u16[h]) - { - CPU.VPR[vd]._u16[h] = 0xffff; - none_equal = 0; - } - else - { - CPU.VPR[vd]._u16[h] = 0; - all_equal = 0; - } - } - - if (rc) CPU.CR.cr6 = all_equal | none_equal; - } - void VCMPEQUH(u32 vd, u32 va, u32 vb) override {VCMPEQUH(vd, va, vb, false);} - void VCMPEQUH_(u32 vd, u32 va, u32 vb) override {VCMPEQUH(vd, va, vb, true);} - void VCMPEQUW(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_equal = 0x8; - int none_equal = 0x2; - - for (uint w = 0; w < 4; w++) - { - if (CPU.VPR[va]._u32[w] == CPU.VPR[vb]._u32[w]) - { - CPU.VPR[vd]._u32[w] = 0xffffffff; - none_equal = 0; - } - else - { - CPU.VPR[vd]._u32[w] = 0; - all_equal = 0; - } - } - - if (rc) CPU.CR.cr6 = all_equal | none_equal; - } - void VCMPEQUW(u32 vd, u32 va, u32 vb) override {VCMPEQUW(vd, va, vb, false);} - void VCMPEQUW_(u32 vd, u32 va, u32 vb) override {VCMPEQUW(vd, va, vb, true);} - void VCMPGEFP(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_ge = 0x8; - int none_ge = 0x2; - - for (uint w = 0; w < 4; w++) - { - if (CPU.VPR[va]._f[w] >= CPU.VPR[vb]._f[w]) - { - CPU.VPR[vd]._u32[w] = 0xffffffff; - none_ge = 0; - } - else - { - CPU.VPR[vd]._u32[w] = 0; - all_ge = 0; - } - } - - if (rc) CPU.CR.cr6 = all_ge | none_ge; - } - void VCMPGEFP(u32 vd, u32 va, u32 vb) override {VCMPGEFP(vd, va, vb, false);} - void VCMPGEFP_(u32 vd, u32 va, u32 vb) override {VCMPGEFP(vd, va, vb, true);} - void VCMPGTFP(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_ge = 0x8; - int none_ge = 0x2; - - for (uint w = 0; w < 4; w++) - { - if (CPU.VPR[va]._f[w] > CPU.VPR[vb]._f[w]) - { - CPU.VPR[vd]._u32[w] = 0xffffffff; - none_ge = 0; - } - else - { - CPU.VPR[vd]._u32[w] = 0; - all_ge = 0; - } - } - - if (rc) CPU.CR.cr6 = all_ge | none_ge; - } - void VCMPGTFP(u32 vd, u32 va, u32 vb) override {VCMPGTFP(vd, va, vb, false);} - void VCMPGTFP_(u32 vd, u32 va, u32 vb) override {VCMPGTFP(vd, va, vb, true);} - void VCMPGTSB(u32 vd, u32 va, u32 vb, u32 rc) //nf - { - int all_gt = 0x8; - int none_gt = 0x2; - - for (uint b = 0; b < 16; b++) - { - if (CPU.VPR[va]._s8[b] > CPU.VPR[vb]._s8[b]) - { - CPU.VPR[vd]._u8[b] = 0xff; - none_gt = 0; - } - else - { - CPU.VPR[vd]._u8[b] = 0; - all_gt = 0; - } - } - - if (rc) CPU.CR.cr6 = all_gt | none_gt; - } - void VCMPGTSB(u32 vd, u32 va, u32 vb) override {VCMPGTSB(vd, va, vb, false);} - void VCMPGTSB_(u32 vd, u32 va, u32 vb) override {VCMPGTSB(vd, va, vb, true);} - void VCMPGTSH(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_gt = 0x8; - int none_gt = 0x2; - - for (uint h = 0; h < 8; h++) - { - if (CPU.VPR[va]._s16[h] > CPU.VPR[vb]._s16[h]) - { - CPU.VPR[vd]._u16[h] = 0xffff; - none_gt = 0; - } - else - { - CPU.VPR[vd]._u16[h] = 0; - all_gt = 0; - } - } - - if (rc) CPU.CR.cr6 = all_gt | none_gt; - } - void VCMPGTSH(u32 vd, u32 va, u32 vb) override {VCMPGTSH(vd, va, vb, false);} - void VCMPGTSH_(u32 vd, u32 va, u32 vb) override {VCMPGTSH(vd, va, vb, true);} - void VCMPGTSW(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_gt = 0x8; - int none_gt = 0x2; - - for (uint w = 0; w < 4; w++) - { - if (CPU.VPR[va]._s32[w] > CPU.VPR[vb]._s32[w]) - { - CPU.VPR[vd]._u32[w] = 0xffffffff; - none_gt = 0; - } - else - { - CPU.VPR[vd]._u32[w] = 0; - all_gt = 0; - } - } - - if (rc) CPU.CR.cr6 = all_gt | none_gt; - } - void VCMPGTSW(u32 vd, u32 va, u32 vb) override {VCMPGTSW(vd, va, vb, false);} - void VCMPGTSW_(u32 vd, u32 va, u32 vb) override {VCMPGTSW(vd, va, vb, true);} - void VCMPGTUB(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_gt = 0x8; - int none_gt = 0x2; - - for (uint b = 0; b < 16; b++) - { - if (CPU.VPR[va]._u8[b] > CPU.VPR[vb]._u8[b]) - { - CPU.VPR[vd]._u8[b] = 0xff; - none_gt = 0; - } - else - { - CPU.VPR[vd]._u8[b] = 0; - all_gt = 0; - } - } - - if (rc) CPU.CR.cr6 = all_gt | none_gt; - } - void VCMPGTUB(u32 vd, u32 va, u32 vb) override {VCMPGTUB(vd, va, vb, false);} - void VCMPGTUB_(u32 vd, u32 va, u32 vb) override {VCMPGTUB(vd, va, vb, true);} - void VCMPGTUH(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_gt = 0x8; - int none_gt = 0x2; - - for (uint h = 0; h < 8; h++) - { - if (CPU.VPR[va]._u16[h] > CPU.VPR[vb]._u16[h]) - { - CPU.VPR[vd]._u16[h] = 0xffff; - none_gt = 0; - } - else - { - CPU.VPR[vd]._u16[h] = 0; - all_gt = 0; - } - } - - if (rc) CPU.CR.cr6 = all_gt | none_gt; - } - void VCMPGTUH(u32 vd, u32 va, u32 vb) override {VCMPGTUH(vd, va, vb, false);} - void VCMPGTUH_(u32 vd, u32 va, u32 vb) override {VCMPGTUH(vd, va, vb, true);} - void VCMPGTUW(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_gt = 0x8; - int none_gt = 0x2; - - for (uint w = 0; w < 4; w++) - { - if (CPU.VPR[va]._u32[w] > CPU.VPR[vb]._u32[w]) - { - CPU.VPR[vd]._u32[w] = 0xffffffff; - none_gt = 0; - } - else - { - CPU.VPR[vd]._u32[w] = 0; - all_gt = 0; - } - } - - if (rc) CPU.CR.cr6 = all_gt | none_gt; - } - void VCMPGTUW(u32 vd, u32 va, u32 vb) override {VCMPGTUW(vd, va, vb, false);} - void VCMPGTUW_(u32 vd, u32 va, u32 vb) override {VCMPGTUW(vd, va, vb, true);} - void VCTSXS(u32 vd, u32 uimm5, u32 vb) override - { - u32 nScale = 1 << uimm5; - - for (uint w = 0; w < 4; w++) - { - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - { - CPU.VPR[vd]._s32[w] = 0; - } - else - { - double result = (double)b * nScale; - if (result > 0x7fffffff) - { - CPU.VPR[vd]._s32[w] = (int)0x7fffffff; - CPU.VSCR.SAT = 1; - } - else if (result < -pow(2, 31)) - { - CPU.VPR[vd]._s32[w] = (int)0x80000000; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s32[w] = (int)trunc(result); - } - } - } - void VCTUXS(u32 vd, u32 uimm5, u32 vb) override - { - u32 nScale = 1 << uimm5; - - for (uint w = 0; w < 4; w++) - { - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - { - CPU.VPR[vd]._s32[w] = 0; - } - else - { - double result = (double)b * nScale; - if (result > 0xffffffffu) - { - CPU.VPR[vd]._u32[w] = 0xffffffffu; - CPU.VSCR.SAT = 1; - } - else if (result < 0) - { - CPU.VPR[vd]._u32[w] = 0; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._u32[w] = (u32)trunc(result); - } - } - } - void VEXPTEFP(u32 vd, u32 vb) override - { - // vd = 2^x - // ISA : Note that the value placed into the element of vD may vary between implementations - // and between different executions on the same implementation. - SetHostRoundingMode(FPSCR_RN_NEAR); - for (uint w = 0; w < 4; w++) - { - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else - CPU.VPR[vd]._f[w] = CheckVSCR_NJ(powf(2.0f, b)); - } - } - void VLOGEFP(u32 vd, u32 vb) override - { - // ISA : Note that the value placed into the element of vD may vary between implementations - // and between different executions on the same implementation. - SetHostRoundingMode(FPSCR_RN_NEAR); - for (uint w = 0; w < 4; w++) - { - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else - CPU.VPR[vd]._f[w] = log2f(b); // Can never be denormal. - } - } - void VMADDFP(u32 vd, u32 va, u32 vc, u32 vb) override - { - SetHostRoundingMode(FPSCR_RN_NEAR); - for (uint w = 0; w < 4; w++) - { - const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]); - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - const float c = CheckVSCR_NJ(CPU.VPR[vc]._f[w]); - if (std::isnan(a)) - CPU.VPR[vd]._f[w] = SilenceNaN(a); - else if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else if (std::isnan(c)) - CPU.VPR[vd]._f[w] = SilenceNaN(c); - else if ((std::isinf(a) && c == 0) || (a == 0 && std::isinf(c))) - CPU.VPR[vd]._f[w] = (float)FPR_NAN; - else - { - const float result = fmaf(a, c, b); - if (std::isnan(result)) - CPU.VPR[vd]._f[w] = (float)FPR_NAN; - else - CPU.VPR[vd]._f[w] = CheckVSCR_NJ(result); - } - } - } - void VMAXFP(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]); - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(a)) - CPU.VPR[vd]._f[w] = SilenceNaN(a); - else if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else if (a > b) - CPU.VPR[vd]._f[w] = a; - else if (b > a) - CPU.VPR[vd]._f[w] = b; - else if (CPU.VPR[vb]._u32[w] == 0x80000000) - CPU.VPR[vd]._f[w] = a; // max(+0,-0) = +0 - else - CPU.VPR[vd]._f[w] = b; - } - } - void VMAXSB(u32 vd, u32 va, u32 vb) override //nf - { - for (uint b = 0; b < 16; b++) - CPU.VPR[vd]._s8[b] = std::max(CPU.VPR[va]._s8[b], CPU.VPR[vb]._s8[b]); - } - void VMAXSH(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._s16[h] = std::max(CPU.VPR[va]._s16[h], CPU.VPR[vb]._s16[h]); - } - } - void VMAXSW(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s32[w] = std::max(CPU.VPR[va]._s32[w], CPU.VPR[vb]._s32[w]); - } - } - void VMAXUB(u32 vd, u32 va, u32 vb) override - { - for (uint b = 0; b < 16; b++) - CPU.VPR[vd]._u8[b] = std::max(CPU.VPR[va]._u8[b], CPU.VPR[vb]._u8[b]); - } - void VMAXUH(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = std::max(CPU.VPR[va]._u16[h], CPU.VPR[vb]._u16[h]); - } - } - void VMAXUW(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = std::max(CPU.VPR[va]._u32[w], CPU.VPR[vb]._u32[w]); - } - } - void VMHADDSHS(u32 vd, u32 va, u32 vb, u32 vc) override - { - for (uint h = 0; h < 8; h++) - { - s32 result = (s32)CPU.VPR[va]._s16[h] * (s32)CPU.VPR[vb]._s16[h]; - result = (result >> 15) + (s32)CPU.VPR[vc]._s16[h]; - - if (result > INT16_MAX) - { - CPU.VPR[vd]._s16[h] = (s16)INT16_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < INT16_MIN) - { - CPU.VPR[vd]._s16[h] = (s16)INT16_MIN; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s16[h] = (s16)result; - } - } - void VMHRADDSHS(u32 vd, u32 va, u32 vb, u32 vc) override - { - for (uint h = 0; h < 8; h++) - { - s32 result = ((s32)CPU.VPR[va]._s16[h] * (s32)CPU.VPR[vb]._s16[h]) + 0x4000; - result = (result >> 15) + (s32)CPU.VPR[vc]._s16[h]; - - if (result > INT16_MAX) - { - CPU.VPR[vd]._s16[h] = (s16)INT16_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < INT16_MIN) - { - CPU.VPR[vd]._s16[h] = (s16)INT16_MIN; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s16[h] = (s16)result; - } - } - void VMINFP(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]); - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(a)) - CPU.VPR[vd]._f[w] = SilenceNaN(a); - else if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else if (a < b) - CPU.VPR[vd]._f[w] = a; - else if (b < a) - CPU.VPR[vd]._f[w] = b; - else if (CPU.VPR[vb]._u32[w] == 0x00000000) - CPU.VPR[vd]._f[w] = a; // min(-0,+0) = -0 - else - CPU.VPR[vd]._f[w] = b; - } - } - void VMINSB(u32 vd, u32 va, u32 vb) override //nf - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._s8[b] = std::min(CPU.VPR[va]._s8[b], CPU.VPR[vb]._s8[b]); - } - } - void VMINSH(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._s16[h] = std::min(CPU.VPR[va]._s16[h], CPU.VPR[vb]._s16[h]); - } - } - void VMINSW(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s32[w] = std::min(CPU.VPR[va]._s32[w], CPU.VPR[vb]._s32[w]); - } - } - void VMINUB(u32 vd, u32 va, u32 vb)override - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = std::min(CPU.VPR[va]._u8[b], CPU.VPR[vb]._u8[b]); - } - } - void VMINUH(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = std::min(CPU.VPR[va]._u16[h], CPU.VPR[vb]._u16[h]); - } - } - void VMINUW(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = std::min(CPU.VPR[va]._u32[w], CPU.VPR[vb]._u32[w]); - } - } - void VMLADDUHM(u32 vd, u32 va, u32 vb, u32 vc) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = CPU.VPR[va]._u16[h] * CPU.VPR[vb]._u16[h] + CPU.VPR[vc]._u16[h]; - } - } - void VMRGHB(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u8[15 - h*2] = VA._u8[15 - h]; - CPU.VPR[vd]._u8[15 - h*2 - 1] = VB._u8[15 - h]; - } - } - void VMRGHH(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u16[7 - w*2] = VA._u16[7 - w]; - CPU.VPR[vd]._u16[7 - w*2 - 1] = VB._u16[7 - w]; - } - } - void VMRGHW(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint d = 0; d < 2; d++) - { - CPU.VPR[vd]._u32[3 - d*2] = VA._u32[3 - d]; - CPU.VPR[vd]._u32[3 - d*2 - 1] = VB._u32[3 - d]; - } - } - void VMRGLB(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u8[15 - h*2] = VA._u8[7 - h]; - CPU.VPR[vd]._u8[15 - h*2 - 1] = VB._u8[7 - h]; - } - } - void VMRGLH(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u16[7 - w*2] = VA._u16[3 - w]; - CPU.VPR[vd]._u16[7 - w*2 - 1] = VB._u16[3 - w]; - } - } - void VMRGLW(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint d = 0; d < 2; d++) - { - CPU.VPR[vd]._u32[3 - d*2] = VA._u32[1 - d]; - CPU.VPR[vd]._u32[3 - d*2 - 1] = VB._u32[1 - d]; - } - } - void VMSUMMBM(u32 vd, u32 va, u32 vb, u32 vc) override //nf - { - for (uint w = 0; w < 4; w++) - { - s32 result = 0; - - for (uint b = 0; b < 4; b++) - { - result += CPU.VPR[va]._s8[w*4 + b] * CPU.VPR[vb]._u8[w*4 + b]; - } - - result += CPU.VPR[vc]._s32[w]; - CPU.VPR[vd]._s32[w] = result; - } - } - void VMSUMSHM(u32 vd, u32 va, u32 vb, u32 vc) override //nf - { - for (uint w = 0; w < 4; w++) - { - s32 result = 0; - - for (uint h = 0; h < 2; h++) - { - result += CPU.VPR[va]._s16[w*2 + h] * CPU.VPR[vb]._s16[w*2 + h]; - } - - result += CPU.VPR[vc]._s32[w]; - CPU.VPR[vd]._s32[w] = result; - } - } - void VMSUMSHS(u32 vd, u32 va, u32 vb, u32 vc) override //nf - { - for (uint w = 0; w < 4; w++) - { - s64 result = 0; - s32 saturated = 0; - - for (uint h = 0; h < 2; h++) - { - result += CPU.VPR[va]._s16[w*2 + h] * CPU.VPR[vb]._s16[w*2 + h]; - } - - result += CPU.VPR[vc]._s32[w]; - - if (result > 0x7fffffff) - { - saturated = 0x7fffffff; - CPU.VSCR.SAT = 1; - } - else if (result < (s64)(s32)0x80000000) - { - saturated = 0x80000000; - CPU.VSCR.SAT = 1; - } - else - saturated = (s32)result; - - CPU.VPR[vd]._s32[w] = saturated; - } - } - void VMSUMUBM(u32 vd, u32 va, u32 vb, u32 vc) override - { - for (uint w = 0; w < 4; w++) - { - u32 result = 0; - - for (uint b = 0; b < 4; b++) - { - result += (u32)CPU.VPR[va]._u8[w*4 + b] * (u32)CPU.VPR[vb]._u8[w*4 + b]; - } - - result += CPU.VPR[vc]._u32[w]; - CPU.VPR[vd]._u32[w] = result; - } - } - void VMSUMUHM(u32 vd, u32 va, u32 vb, u32 vc) override //nf - { - for (uint w = 0; w < 4; w++) - { - u32 result = 0; - - for (uint h = 0; h < 2; h++) - { - result += (u32)CPU.VPR[va]._u16[w*2 + h] * (u32)CPU.VPR[vb]._u16[w*2 + h]; - } - - result += CPU.VPR[vc]._u32[w]; - CPU.VPR[vd]._u32[w] = result; - } - } - void VMSUMUHS(u32 vd, u32 va, u32 vb, u32 vc) override //nf - { - for (uint w = 0; w < 4; w++) - { - u64 result = 0; - u32 saturated = 0; - - for (uint h = 0; h < 2; h++) - { - result += (u64)CPU.VPR[va]._u16[w*2 + h] * (u64)CPU.VPR[vb]._u16[w*2 + h]; - } - - result += CPU.VPR[vc]._u32[w]; - - if (result > 0xffffffffu) - { - saturated = 0xffffffff; - CPU.VSCR.SAT = 1; - } - else - saturated = (u32)result; - - CPU.VPR[vd]._u32[w] = saturated; - } - } - void VMULESB(u32 vd, u32 va, u32 vb) override //nf - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._s16[h] = (s16)CPU.VPR[va]._s8[h*2+1] * (s16)CPU.VPR[vb]._s8[h*2+1]; - } - } - void VMULESH(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s32[w] = (s32)CPU.VPR[va]._s16[w*2+1] * (s32)CPU.VPR[vb]._s16[w*2+1]; - } - } - void VMULEUB(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = (u16)CPU.VPR[va]._u8[h*2+1] * (u16)CPU.VPR[vb]._u8[h*2+1]; - } - } - void VMULEUH(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = (u32)CPU.VPR[va]._u16[w*2+1] * (u32)CPU.VPR[vb]._u16[w*2+1]; - } - } - void VMULOSB(u32 vd, u32 va, u32 vb) override //nf - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._s16[h] = (s16)CPU.VPR[va]._s8[h*2] * (s16)CPU.VPR[vb]._s8[h*2]; - } - } - void VMULOSH(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s32[w] = (s32)CPU.VPR[va]._s16[w*2] * (s32)CPU.VPR[vb]._s16[w*2]; - } - } - void VMULOUB(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = (u16)CPU.VPR[va]._u8[h*2] * (u16)CPU.VPR[vb]._u8[h*2]; - } - } - void VMULOUH(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = (u32)CPU.VPR[va]._u16[w*2] * (u32)CPU.VPR[vb]._u16[w*2]; - } - } - void VNMSUBFP(u32 vd, u32 va, u32 vc, u32 vb) override - { - SetHostRoundingMode(FPSCR_RN_NEAR); - for (uint w = 0; w < 4; w++) - { - const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]); - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - const float c = CheckVSCR_NJ(CPU.VPR[vc]._f[w]); - if (std::isnan(a)) - CPU.VPR[vd]._f[w] = SilenceNaN(a); - else if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else if (std::isnan(c)) - CPU.VPR[vd]._f[w] = SilenceNaN(c); - else if ((std::isinf(a) && c == 0) || (a == 0 && std::isinf(c))) - CPU.VPR[vd]._f[w] = (float)FPR_NAN; - else - { - const float result = -fmaf(a, c, -b); - if (std::isnan(result)) - CPU.VPR[vd]._f[w] = (float)FPR_NAN; - else - CPU.VPR[vd]._f[w] = CheckVSCR_NJ(result); - } - } - } - void VNOR(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = ~(CPU.VPR[va]._u32[w] | CPU.VPR[vb]._u32[w]); - } - } - void VOR(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] | CPU.VPR[vb]._u32[w]; - } - } - void VPERM(u32 vd, u32 va, u32 vb, u32 vc) override - { - u8 tmpSRC[32]; - std::memcpy(tmpSRC, CPU.VPR + vb, 16); - std::memcpy(tmpSRC + 16, CPU.VPR + va, 16); - - for (uint b = 0; b < 16; b++) - { - u8 index = CPU.VPR[vc]._u8[b] & 0x1f; - - CPU.VPR[vd]._u8[b] = tmpSRC[0x1f - index]; - } - } - void VPKPX(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint h = 0; h < 4; h++) - { - u16 bb7 = VB._u8[15 - (h*4 + 0)] & 0x1; - u16 bb8 = VB._u8[15 - (h*4 + 1)] >> 3; - u16 bb16 = VB._u8[15 - (h*4 + 2)] >> 3; - u16 bb24 = VB._u8[15 - (h*4 + 3)] >> 3; - u16 ab7 = VA._u8[15 - (h*4 + 0)] & 0x1; - u16 ab8 = VA._u8[15 - (h*4 + 1)] >> 3; - u16 ab16 = VA._u8[15 - (h*4 + 2)] >> 3; - u16 ab24 = VA._u8[15 - (h*4 + 3)] >> 3; - - CPU.VPR[vd]._u16[3 - h] = (bb7 << 15) | (bb8 << 10) | (bb16 << 5) | bb24; - CPU.VPR[vd]._u16[4 + (3 - h)] = (ab7 << 15) | (ab8 << 10) | (ab16 << 5) | ab24; - } - } - void VPKSHSS(u32 vd, u32 va, u32 vb) override //nf - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint b = 0; b < 8; b++) - { - s16 result = VA._s16[b]; - - if (result > INT8_MAX) - { - result = INT8_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < INT8_MIN) - { - result = INT8_MIN; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._s8[b+8] = (s8)result; - - result = VB._s16[b]; - - if (result > INT8_MAX) - { - result = INT8_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < INT8_MIN) - { - result = INT8_MIN; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._s8[b] = (s8)result; - } - } - void VPKSHUS(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint b = 0; b < 8; b++) - { - s16 result = VA._s16[b]; - - if (result > UINT8_MAX) - { - result = UINT8_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < 0) - { - result = 0; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._u8[b+8] = (u8)result; - - result = VB._s16[b]; - - if (result > UINT8_MAX) - { - result = UINT8_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < 0) - { - result = 0; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._u8[b] = (u8)result; - } - } - void VPKSWSS(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint h = 0; h < 4; h++) - { - s32 result = VA._s32[h]; - - if (result > INT16_MAX) - { - result = INT16_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < INT16_MIN) - { - result = INT16_MIN; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._s16[h+4] = result; - - result = VB._s32[h]; - - if (result > INT16_MAX) - { - result = INT16_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < INT16_MIN) - { - result = INT16_MIN; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._s16[h] = result; - } - } - void VPKSWUS(u32 vd, u32 va, u32 vb) override //nf - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint h = 0; h < 4; h++) - { - s32 result = VA._s32[h]; - - if (result > UINT16_MAX) - { - result = UINT16_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < 0) - { - result = 0; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._u16[h+4] = result; - - result = VB._s32[h]; - - if (result > UINT16_MAX) - { - result = UINT16_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < 0) - { - result = 0; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._u16[h] = result; - } - } - void VPKUHUM(u32 vd, u32 va, u32 vb) override //nf - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint b = 0; b < 8; b++) - { - CPU.VPR[vd]._u8[b+8] = VA._u8[b*2]; - CPU.VPR[vd]._u8[b ] = VB._u8[b*2]; - } - } - void VPKUHUS(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint b = 0; b < 8; b++) - { - u16 result = VA._u16[b]; - - if (result > UINT8_MAX) - { - result = UINT8_MAX; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._u8[b+8] = (u8)result; - - result = VB._u16[b]; - - if (result > UINT8_MAX) - { - result = UINT8_MAX; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._u8[b] = (u8)result; - } - } - void VPKUWUM(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint h = 0; h < 4; h++) - { - CPU.VPR[vd]._u16[h+4] = VA._u16[h*2]; - CPU.VPR[vd]._u16[h ] = VB._u16[h*2]; - } - } - void VPKUWUS(u32 vd, u32 va, u32 vb) override //nf - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint h = 0; h < 4; h++) - { - u32 result = VA._u32[h]; - - if (result > UINT16_MAX) - { - result = UINT16_MAX; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._u16[h+4] = result; - - result = VB._u32[h]; - - if (result > UINT16_MAX) - { - result = UINT16_MAX; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._u16[h] = result; - } - } - void VREFP(u32 vd, u32 vb) override - { - SetHostRoundingMode(FPSCR_RN_NEAR); - for (uint w = 0; w < 4; w++) - { - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else - CPU.VPR[vd]._f[w] = CheckVSCR_NJ(1.0f / b); - } - } - void VRFIM(u32 vd, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else - CPU.VPR[vd]._f[w] = floorf(CPU.VPR[vb]._f[w]); - } - } - void VRFIN(u32 vd, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else - { - SetHostRoundingMode(FPSCR_RN_NEAR); - CPU.VPR[vd]._f[w] = nearbyintf(CPU.VPR[vb]._f[w]); - } - } - } - void VRFIP(u32 vd, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else - CPU.VPR[vd]._f[w] = ceilf(CPU.VPR[vb]._f[w]); - } - } - void VRFIZ(u32 vd, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else - CPU.VPR[vd]._f[w] = truncf(CPU.VPR[vb]._f[w]); - } - } - void VRLB(u32 vd, u32 va, u32 vb) override //nf - { - for (uint b = 0; b < 16; b++) - { - int nRot = CPU.VPR[vb]._u8[b] & 0x7; - - CPU.VPR[vd]._u8[b] = (CPU.VPR[va]._u8[b] << nRot) | (CPU.VPR[va]._u8[b] >> (8 - nRot)); - } - } - void VRLH(u32 vd, u32 va, u32 vb) override //nf - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = rotl16(CPU.VPR[va]._u16[h], CPU.VPR[vb]._u8[h*2] & 0xf); - } - } - void VRLW(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = (u32)rotl32(CPU.VPR[va]._u32[w], CPU.VPR[vb]._u8[w*4] & 0x1f); - } - } - void VRSQRTEFP(u32 vd, u32 vb) override - { - SetHostRoundingMode(FPSCR_RN_NEAR); - for (uint w = 0; w < 4; w++) - { - //TODO: accurate div - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else if (b < 0) - CPU.VPR[vd]._f[w] = (float)FPR_NAN; - else - CPU.VPR[vd]._f[w] = 1.0f / sqrtf(b); // Can never be denormal. - } - } - void VSEL(u32 vd, u32 va, u32 vb, u32 vc) override - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = (CPU.VPR[vb]._u8[b] & CPU.VPR[vc]._u8[b]) | (CPU.VPR[va]._u8[b] & (~CPU.VPR[vc]._u8[b])); - } - } - void VSL(u32 vd, u32 va, u32 vb) override //nf - { - v128 VA = CPU.VPR[va]; - u8 sh = CPU.VPR[vb]._u8[0] & 0x7; - - CPU.VPR[vd]._u8[0] = VA._u8[0] << sh; - for (uint b = 1; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = (VA._u8[b] << sh) | (VA._u8[b-1] >> (8 - sh)); - } - } - void VSLB(u32 vd, u32 va, u32 vb) override - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = CPU.VPR[va]._u8[b] << (CPU.VPR[vb]._u8[b] & 0x7); - } - } - void VSLDOI(u32 vd, u32 va, u32 vb, u32 sh) override - { - u8 tmpSRC[32]; - std::memcpy(tmpSRC, CPU.VPR + vb, 16); - std::memcpy(tmpSRC + 16, CPU.VPR + va, 16); - - for(uint b=0; b<16; b++) - { - CPU.VPR[vd]._u8[15 - b] = tmpSRC[31 - (b + sh)]; - } - } - void VSLH(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = CPU.VPR[va]._u16[h] << (CPU.VPR[vb]._u16[h] & 0xf); - } - } - void VSLO(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - u8 nShift = (CPU.VPR[vb]._u8[0] >> 3) & 0xf; - - CPU.VPR[vd].clear(); - - for (u8 b = 0; b < 16 - nShift; b++) - { - CPU.VPR[vd]._u8[15 - b] = VA._u8[15 - (b + nShift)]; - } - } - void VSLW(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] << (CPU.VPR[vb]._u32[w] & 0x1f); - } - } - void VSPLTB(u32 vd, u32 uimm5, u32 vb) override - { - u8 byte = CPU.VPR[vb]._u8[15 - uimm5]; - - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = byte; - } - } - void VSPLTH(u32 vd, u32 uimm5, u32 vb) override - { - assert(uimm5 < 8); - - u16 hword = CPU.VPR[vb]._u16[7 - uimm5]; - - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = hword; - } - } - void VSPLTISB(u32 vd, s32 simm5) override - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = simm5; - } - } - void VSPLTISH(u32 vd, s32 simm5) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = (s16)simm5; - } - } - void VSPLTISW(u32 vd, s32 simm5) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = (s32)simm5; - } - } - void VSPLTW(u32 vd, u32 uimm5, u32 vb) override - { - assert(uimm5 < 4); - - u32 word = CPU.VPR[vb]._u32[3 - uimm5]; - - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = word; - } - } - void VSR(u32 vd, u32 va, u32 vb) override //nf - { - v128 VA = CPU.VPR[va]; - u8 sh = CPU.VPR[vb]._u8[0] & 0x7; - - CPU.VPR[vd]._u8[15] = VA._u8[15] >> sh; - for (uint b = 14; ~b; b--) - { - CPU.VPR[vd]._u8[b] = (VA._u8[b] >> sh) | (VA._u8[b+1] << (8 - sh)); - } - } - void VSRAB(u32 vd, u32 va, u32 vb) override //nf - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._s8[b] = CPU.VPR[va]._s8[b] >> (CPU.VPR[vb]._u8[b] & 0x7); - } - } - void VSRAH(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._s16[h] = CPU.VPR[va]._s16[h] >> (CPU.VPR[vb]._u16[h] & 0xf); - } - } - void VSRAW(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s32[w] = CPU.VPR[va]._s32[w] >> (CPU.VPR[vb]._u32[w] & 0x1f); - } - } - void VSRB(u32 vd, u32 va, u32 vb) override - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = CPU.VPR[va]._u8[b] >> (CPU.VPR[vb]._u8[b] & 0x7); - } - } - void VSRH(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = CPU.VPR[va]._u16[h] >> (CPU.VPR[vb]._u16[h] & 0xf); - } - } - void VSRO(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - u8 nShift = (CPU.VPR[vb]._u8[0] >> 3) & 0xf; - - CPU.VPR[vd].clear(); - - for (u8 b = 0; b < 16 - nShift; b++) - { - CPU.VPR[vd]._u8[b] = VA._u8[b + nShift]; - } - } - void VSRW(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] >> (CPU.VPR[vb]._u32[w] & 0x1f); - } - } - void VSUBCUW(u32 vd, u32 va, u32 vb) override //nf - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] < CPU.VPR[vb]._u32[w] ? 0 : 1; - } - } - void VSUBFP(u32 vd, u32 va, u32 vb) override - { - SetHostRoundingMode(FPSCR_RN_NEAR); - for (uint w = 0; w < 4; w++) - { - const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]); - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(a)) - CPU.VPR[vd]._f[w] = SilenceNaN(a); - else if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else if (std::isinf(a) && std::isinf(b) && a == b) - CPU.VPR[vd]._f[w] = (float)FPR_NAN; - else - CPU.VPR[vd]._f[w] = CheckVSCR_NJ(a - b); - } - } - void VSUBSBS(u32 vd, u32 va, u32 vb) override //nf - { - for (uint b = 0; b < 16; b++) - { - s16 result = (s16)CPU.VPR[va]._s8[b] - (s16)CPU.VPR[vb]._s8[b]; - - if (result < INT8_MIN) - { - CPU.VPR[vd]._s8[b] = INT8_MIN; - CPU.VSCR.SAT = 1; - } - else if (result > INT8_MAX) - { - CPU.VPR[vd]._s8[b] = INT8_MAX; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s8[b] = (s8)result; - } - } - void VSUBSHS(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - s32 result = (s32)CPU.VPR[va]._s16[h] - (s32)CPU.VPR[vb]._s16[h]; - - if (result < INT16_MIN) - { - CPU.VPR[vd]._s16[h] = (s16)INT16_MIN; - CPU.VSCR.SAT = 1; - } - else if (result > INT16_MAX) - { - CPU.VPR[vd]._s16[h] = (s16)INT16_MAX; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s16[h] = (s16)result; - } - } - void VSUBSWS(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - s64 result = (s64)CPU.VPR[va]._s32[w] - (s64)CPU.VPR[vb]._s32[w]; - - if (result < INT32_MIN) - { - CPU.VPR[vd]._s32[w] = (s32)INT32_MIN; - CPU.VSCR.SAT = 1; - } - else if (result > INT32_MAX) - { - CPU.VPR[vd]._s32[w] = (s32)INT32_MAX; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s32[w] = (s32)result; - } - } - void VSUBUBM(u32 vd, u32 va, u32 vb) override - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = (u8)((CPU.VPR[va]._u8[b] - CPU.VPR[vb]._u8[b]) & 0xff); - } - } - void VSUBUBS(u32 vd, u32 va, u32 vb) override - { - for (uint b = 0; b < 16; b++) - { - s16 result = (s16)CPU.VPR[va]._u8[b] - (s16)CPU.VPR[vb]._u8[b]; - - if (result < 0) - { - CPU.VPR[vd]._u8[b] = 0; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._u8[b] = (u8)result; - } - } - void VSUBUHM(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = CPU.VPR[va]._u16[h] - CPU.VPR[vb]._u16[h]; - } - } - void VSUBUHS(u32 vd, u32 va, u32 vb) override //nf - { - for (uint h = 0; h < 8; h++) - { - s32 result = (s32)CPU.VPR[va]._u16[h] - (s32)CPU.VPR[vb]._u16[h]; - - if (result < 0) - { - CPU.VPR[vd]._u16[h] = 0; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._u16[h] = (u16)result; - } - } - void VSUBUWM(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] - CPU.VPR[vb]._u32[w]; - } - } - void VSUBUWS(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - s64 result = (s64)CPU.VPR[va]._u32[w] - (s64)CPU.VPR[vb]._u32[w]; - - if (result < 0) - { - CPU.VPR[vd]._u32[w] = 0; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._u32[w] = (u32)result; - } - } - void VSUMSWS(u32 vd, u32 va, u32 vb) override - { - s64 sum = CPU.VPR[vb]._s32[0]; - - for (uint w = 0; w < 4; w++) - { - sum += CPU.VPR[va]._s32[w]; - } - - CPU.VPR[vd].clear(); - if (sum > INT32_MAX) - { - CPU.VPR[vd]._s32[0] = (s32)INT32_MAX; - CPU.VSCR.SAT = 1; - } - else if (sum < INT32_MIN) - { - CPU.VPR[vd]._s32[0] = (s32)INT32_MIN; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s32[0] = (s32)sum; - } - void VSUM2SWS(u32 vd, u32 va, u32 vb) override - { - for (uint n = 0; n < 2; n++) - { - s64 sum = (s64)CPU.VPR[va]._s32[n*2] + CPU.VPR[va]._s32[n*2 + 1] + CPU.VPR[vb]._s32[n*2]; - - if (sum > INT32_MAX) - { - CPU.VPR[vd]._s32[n*2] = (s32)INT32_MAX; - CPU.VSCR.SAT = 1; - } - else if (sum < INT32_MIN) - { - CPU.VPR[vd]._s32[n*2] = (s32)INT32_MIN; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s32[n*2] = (s32)sum; - } - CPU.VPR[vd]._s32[1] = 0; - CPU.VPR[vd]._s32[3] = 0; - } - void VSUM4SBS(u32 vd, u32 va, u32 vb) override //nf - { - for (uint w = 0; w < 4; w++) - { - s64 sum = CPU.VPR[vb]._s32[w]; - - for (uint b = 0; b < 4; b++) - { - sum += CPU.VPR[va]._s8[w*4 + b]; - } - - if (sum > INT32_MAX) - { - CPU.VPR[vd]._s32[w] = (s32)INT32_MAX; - CPU.VSCR.SAT = 1; - } - else if (sum < INT32_MIN) - { - CPU.VPR[vd]._s32[w] = (s32)INT32_MIN; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s32[w] = (s32)sum; - } - } - void VSUM4SHS(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - s64 sum = CPU.VPR[vb]._s32[w]; - - for (uint h = 0; h < 2; h++) - { - sum += CPU.VPR[va]._s16[w*2 + h]; - } - - if (sum > INT32_MAX) - { - CPU.VPR[vd]._s32[w] = (s32)INT32_MAX; - CPU.VSCR.SAT = 1; - } - else if (sum < INT32_MIN) - { - CPU.VPR[vd]._s32[w] = (s32)INT32_MIN; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s32[w] = (s32)sum; - } - } - void VSUM4UBS(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - u64 sum = CPU.VPR[vb]._u32[w]; - - for (uint b = 0; b < 4; b++) - { - sum += CPU.VPR[va]._u8[w*4 + b]; - } - - if (sum > UINT32_MAX) - { - CPU.VPR[vd]._u32[w] = (u32)UINT32_MAX; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._u32[w] = (u32)sum; - } - } - void VUPKHPX(u32 vd, u32 vb) override - { - v128 VB = CPU.VPR[vb]; - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s8[w*4 + 3] = VB._s8[8 + w*2 + 1] >> 7; // signed shift sign extends - CPU.VPR[vd]._u8[w*4 + 2] = (VB._u8[8 + w*2 + 1] >> 2) & 0x1f; - CPU.VPR[vd]._u8[w*4 + 1] = ((VB._u8[8 + w*2 + 1] & 0x3) << 3) | ((VB._u8[8 + w*2 + 0] >> 5) & 0x7); - CPU.VPR[vd]._u8[w*4 + 0] = VB._u8[8 + w*2 + 0] & 0x1f; - } - } - void VUPKHSB(u32 vd, u32 vb) override - { - v128 VB = CPU.VPR[vb]; - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._s16[h] = VB._s8[8 + h]; - } - } - void VUPKHSH(u32 vd, u32 vb) override - { - v128 VB = CPU.VPR[vb]; - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s32[w] = VB._s16[4 + w]; - } - } - void VUPKLPX(u32 vd, u32 vb) override - { - v128 VB = CPU.VPR[vb]; - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s8[w*4 + 3] = VB._s8[w*2 + 1] >> 7; // signed shift sign extends - CPU.VPR[vd]._u8[w*4 + 2] = (VB._u8[w*2 + 1] >> 2) & 0x1f; - CPU.VPR[vd]._u8[w*4 + 1] = ((VB._u8[w*2 + 1] & 0x3) << 3) | ((VB._u8[w*2 + 0] >> 5) & 0x7); - CPU.VPR[vd]._u8[w*4 + 0] = VB._u8[w*2 + 0] & 0x1f; - } - } - void VUPKLSB(u32 vd, u32 vb) override //nf - { - v128 VB = CPU.VPR[vb]; - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._s16[h] = VB._s8[h]; - } - } - void VUPKLSH(u32 vd, u32 vb) override - { - v128 VB = CPU.VPR[vb]; - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s32[w] = VB._s16[w]; - } - } - void VXOR(u32 vd, u32 va, u32 vb) override - { - CPU.VPR[vd]._u32[0] = CPU.VPR[va]._u32[0] ^ CPU.VPR[vb]._u32[0]; - CPU.VPR[vd]._u32[1] = CPU.VPR[va]._u32[1] ^ CPU.VPR[vb]._u32[1]; - CPU.VPR[vd]._u32[2] = CPU.VPR[va]._u32[2] ^ CPU.VPR[vb]._u32[2]; - CPU.VPR[vd]._u32[3] = CPU.VPR[va]._u32[3] ^ CPU.VPR[vb]._u32[3]; - } - static void MULLI_impl(PPUThread *CPU, u32 rd, u32 ra, s32 simm16) - { - CPU->GPR[rd] = (s64)CPU->GPR[ra] * simm16; - } - void MULLI(u32 rd, u32 ra, s32 simm16) override - { - MULLI_impl(&CPU, rd, ra, simm16); - } - static void SUBFIC_impl(PPUThread *CPU, u32 rd, u32 ra, s32 simm16) - { - const u64 RA = CPU->GPR[ra]; - const u64 IMM = (s64)simm16; - CPU->GPR[rd] = ~RA + IMM + 1; - - CPU->XER.CA = CPU->IsCarry(~RA, IMM, 1); - } - void SUBFIC(u32 rd, u32 ra, s32 simm16) override - { - SUBFIC_impl(&CPU, rd, ra, simm16); - } - - static void CMPLI_impl(PPUThread *CPU, u32 crfd, u32 l, u32 ra, u32 uimm16) - { - CPU->UpdateCRnU(l, crfd, CPU->GPR[ra], uimm16); - } - void CMPLI(u32 crfd, u32 l, u32 ra, u32 uimm16) override - { - CMPLI_impl(&CPU, crfd, l, ra, uimm16); - } - - static void CMPI_impl(PPUThread *CPU, u32 crfd, u32 l, u32 ra, s32 simm16) - { - CPU->UpdateCRnS(l, crfd, CPU->GPR[ra], simm16); - } - void CMPI(u32 crfd, u32 l, u32 ra, s32 simm16) override - { - CMPI_impl(&CPU, crfd, l, ra, simm16); - } - - static void ADDIC_impl(PPUThread *CPU, u32 rd, u32 ra, s32 simm16) - { - const u64 RA = CPU->GPR[ra]; - CPU->GPR[rd] = RA + simm16; - CPU->XER.CA = CPU->IsCarry(RA, simm16); - } - void ADDIC(u32 rd, u32 ra, s32 simm16) override - { - ADDIC_impl(&CPU, rd, ra, simm16); - } - static void ADDIC__impl(PPUThread *CPU, u32 rd, u32 ra, s32 simm16) - { - const u64 RA = CPU->GPR[ra]; - CPU->GPR[rd] = RA + simm16; - CPU->XER.CA = CPU->IsCarry(RA, simm16); - CPU->UpdateCR0(CPU->GPR[rd]); - } - void ADDIC_(u32 rd, u32 ra, s32 simm16) override - { - ADDIC__impl(&CPU, rd, ra, simm16); - } - - static void ADDI_impl(PPUThread *CPU, u32 rd, u32 ra, s32 simm16) - { - CPU->GPR[rd] = ra ? ((s64)CPU->GPR[ra] + simm16) : simm16; - } - void ADDI(u32 rd, u32 ra, s32 simm16) override - { - ADDI_impl(&CPU, rd, ra, simm16); - } - - static void ADDIS_impl(PPUThread *CPU, u32 rd, u32 ra, s32 simm16) - { - CPU->GPR[rd] = ra ? ((s64)CPU->GPR[ra] + (static_cast(simm16) << 16)) : (static_cast(simm16) << 16); - } - void ADDIS(u32 rd, u32 ra, s32 simm16) override - { - ADDIS_impl(&CPU, rd, ra, simm16); - } - - void BC(u32 bo, u32 bi, s32 bd, u32 aa, u32 lk) override - { - if (CheckCondition(bo, bi)) - { - const u32 nextLR = CPU.PC + 4; - CPU.PC = branchTarget((aa ? 0 : CPU.PC), bd) - 4; - if(lk) CPU.LR = nextLR; - } - } - void HACK(u32 index) override - { - extern void execute_ppu_func_by_index(PPUThread& ppu, u32 index); - - execute_ppu_func_by_index(CPU, index); - } - void SC(u32 lev) override - { - extern void execute_syscall_by_index(PPUThread& ppu, u64 code); - - switch (lev) - { - case 0x0: execute_syscall_by_index(CPU, CPU.GPR[11]); break; - case 0x1: throw EXCEPTION("HyperCall LV1"); - case 0x3: CPU.fast_stop(); break; - default: throw EXCEPTION("Unknown level (0x%x)", lev); - } - } - void B(s32 ll, u32 aa, u32 lk) override - { - const u32 nextLR = CPU.PC + 4; - CPU.PC = branchTarget(aa ? 0 : CPU.PC, ll) - 4; - if(lk) CPU.LR = nextLR; - } - static void MCRF_impl(PPUThread *CPU, u32 crfd, u32 crfs) - { - CPU->SetCR(crfd, CPU->GetCR(crfs)); - } - void MCRF(u32 crfd, u32 crfs) override - { - MCRF_impl(&CPU, crfd, crfs); - } - void BCLR(u32 bo, u32 bi, u32 bh, u32 lk) override - { - if (CheckCondition(bo, bi)) - { - const u32 nextLR = CPU.PC + 4; - CPU.PC = branchTarget(0, (u32)CPU.LR) - 4; - if(lk) CPU.LR = nextLR; - } - } - static void CRNOR_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb) - { - const u8 v = 1 ^ (CPU->IsCR(crba) | CPU->IsCR(crbb)); - CPU->SetCRBit2(crbd, v & 0x1); - } - void CRNOR(u32 crbd, u32 crba, u32 crbb) override - { - CRNOR_impl(&CPU, crbd, crba, crbb); - } - static void CRANDC_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb) - { - const u8 v = CPU->IsCR(crba) & (1 ^ CPU->IsCR(crbb)); - CPU->SetCRBit2(crbd, v & 0x1); - } - void CRANDC(u32 crbd, u32 crba, u32 crbb) override - { - CRANDC_impl(&CPU, crbd, crba, crbb); - } - void ISYNC() override - { - _mm_mfence(); - } - static void CRXOR_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb) - { - const u8 v = CPU->IsCR(crba) ^ CPU->IsCR(crbb); - CPU->SetCRBit2(crbd, v & 0x1); - } - void CRXOR(u32 crbd, u32 crba, u32 crbb) override - { - CRXOR_impl(&CPU, crbd, crba, crbb); - } - static void CRNAND_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb) - { - const u8 v = 1 ^ (CPU->IsCR(crba) & CPU->IsCR(crbb)); - CPU->SetCRBit2(crbd, v & 0x1); - } - void CRNAND(u32 crbd, u32 crba, u32 crbb)override - { - CRNAND_impl(&CPU, crbd, crba, crbb); - } - static void CRAND_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb) - { - const u8 v = CPU->IsCR(crba) & CPU->IsCR(crbb); - CPU->SetCRBit2(crbd, v & 0x1); - } - void CRAND(u32 crbd, u32 crba, u32 crbb) override - { - CRAND_impl(&CPU, crbd, crba, crbb); - } - static void CREQV_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb) - { - const u8 v = 1 ^ (CPU->IsCR(crba) ^ CPU->IsCR(crbb)); - CPU->SetCRBit2(crbd, v & 0x1); - } - void CREQV(u32 crbd, u32 crba, u32 crbb) override - { - CREQV_impl(&CPU, crbd, crba, crbb); - } - static void CRORC_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb) - { - const u8 v = CPU->IsCR(crba) | (1 ^ CPU->IsCR(crbb)); - CPU->SetCRBit2(crbd, v & 0x1); - } - void CRORC(u32 crbd, u32 crba, u32 crbb) override - { - CRORC_impl(&CPU, crbd, crba, crbb); - } - static void CROR_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb) - { - const u8 v = CPU->IsCR(crba) | CPU->IsCR(crbb); - CPU->SetCRBit2(crbd, v & 0x1); - } - void CROR(u32 crbd, u32 crba, u32 crbb) override - { - CROR_impl(&CPU, crbd, crba, crbb); - } - void BCCTR(u32 bo, u32 bi, u32 bh, u32 lk) override - { - if(bo & 0x10 || CPU.IsCR(bi) == ((bo & 0x8) != 0)) - { - const u32 nextLR = CPU.PC + 4; - CPU.PC = branchTarget(0, (u32)CPU.CTR) - 4; - if(lk) CPU.LR = nextLR; - } - } - static void RLWIMI_impl(PPUThread *CPU, u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) - { - const u64 mask = rotate_mask[32 + mb][32 + me]; - CPU->GPR[ra] = (CPU->GPR[ra] & ~mask) | (rotl32(CPU->GPR[rs], sh) & mask); - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void RLWIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) override - { - RLWIMI_impl(&CPU, ra, rs, sh, mb, me, rc); - } - - static void RLWINM_impl(PPUThread *CPU, u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) - { - CPU->GPR[ra] = rotl32(CPU->GPR[rs], sh) & rotate_mask[32 + mb][32 + me]; - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void RLWINM(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) override - { - RLWINM_impl(&CPU, ra, rs, sh, mb, me, rc); - } - static void RLWNM_impl(PPUThread *CPU, u32 ra, u32 rs, u32 rb, u32 mb, u32 me, u32 rc) - { - CPU->GPR[ra] = rotl32(CPU->GPR[rs], CPU->GPR[rb] & 0x1f) & rotate_mask[32 + mb][32 + me]; - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void RLWNM(u32 ra, u32 rs, u32 rb, u32 mb, u32 me, u32 rc) override - { - RLWNM_impl(&CPU, ra, rs, rb, mb, me, rc); - } - - static void ORI_impl(PPUThread *CPU, u32 ra, u32 rs, u32 uimm16) - { - CPU->GPR[ra] = CPU->GPR[rs] | uimm16; - } - void ORI(u32 ra, u32 rs, u32 uimm16) override - { - ORI_impl(&CPU, ra, rs, uimm16); - } - static void ORIS_impl(PPUThread *CPU, u32 ra, u32 rs, u32 uimm16) - { - CPU->GPR[ra] = CPU->GPR[rs] | ((u64)uimm16 << 16); - } - void ORIS(u32 ra, u32 rs, u32 uimm16) override - { - ORIS_impl(&CPU, ra, rs, uimm16); - } - static void XORI_impl(PPUThread *CPU, u32 ra, u32 rs, u32 uimm16) - { - CPU->GPR[ra] = CPU->GPR[rs] ^ uimm16; - } - void XORI(u32 ra, u32 rs, u32 uimm16) override - { - XORI_impl(&CPU, ra, rs, uimm16); - } - static void XORIS_impl(PPUThread *CPU, u32 ra, u32 rs, u32 uimm16) - { - CPU->GPR[ra] = CPU->GPR[rs] ^ ((u64)uimm16 << 16); - } - void XORIS(u32 ra, u32 rs, u32 uimm16) override - { - XORIS_impl(&CPU, ra, rs, uimm16); - } - static void ANDI__impl(PPUThread *CPU, u32 ra, u32 rs, u32 uimm16) - { - CPU->GPR[ra] = CPU->GPR[rs] & uimm16; - CPU->UpdateCR0(CPU->GPR[ra]); - } - void ANDI_(u32 ra, u32 rs, u32 uimm16) override - { - ANDI__impl(&CPU, ra, rs, uimm16); - } - static void ANDIS__impl(PPUThread *CPU, u32 ra, u32 rs, u32 uimm16) - { - CPU->GPR[ra] = CPU->GPR[rs] & ((u64)uimm16 << 16); - CPU->UpdateCR0(CPU->GPR[ra]); - } - void ANDIS_(u32 ra, u32 rs, u32 uimm16) override - { - ANDIS__impl(&CPU, ra, rs, uimm16); - } - - static - void RLDICL_impl(PPUThread *CPU, u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) - { - CPU->GPR[ra] = rotl64(CPU->GPR[rs], sh) & rotate_mask[mb][63]; - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void RLDICL(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) override - { - RLDICL_impl(&CPU, ra, rs, sh, mb, rc); - } - - static - void RLDICR_impl(PPUThread *CPU, u32 ra, u32 rs, u32 sh, u32 me, u32 rc) - { - CPU->GPR[ra] = rotl64(CPU->GPR[rs], sh) & rotate_mask[0][me]; - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - - void RLDICR(u32 ra, u32 rs, u32 sh, u32 me, u32 rc) override - { - RLDICR_impl(&CPU, ra, rs, sh, me, rc); - } - static void RLDIC_impl(PPUThread *CPU, u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) - { - CPU->GPR[ra] = rotl64(CPU->GPR[rs], sh) & rotate_mask[mb][63 - sh]; - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void RLDIC(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) override - { - RLDIC_impl(&CPU, ra, rs, sh, mb, rc); - } - static void RLDIMI_impl(PPUThread *CPU, u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) - { - const u64 mask = rotate_mask[mb][63 - sh]; - CPU->GPR[ra] = (CPU->GPR[ra] & ~mask) | (rotl64(CPU->GPR[rs], sh) & mask); - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void RLDIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) override - { - RLDIMI_impl(&CPU, ra, rs, sh, mb, rc); - } - static void RLDC_LR_impl(PPUThread *CPU, u32 ra, u32 rs, u32 rb, u32 m_eb, u32 is_r, u32 rc) - { - if (is_r) // rldcr - { - RLDICR_impl(CPU, ra, rs, (u32)(CPU->GPR[rb] & 0x3F), m_eb, rc); - } - else // rldcl - { - RLDICL_impl(CPU, ra, rs, (u32)(CPU->GPR[rb] & 0x3F), m_eb, rc); - } - } - void RLDC_LR(u32 ra, u32 rs, u32 rb, u32 m_eb, u32 is_r, u32 rc) override - { - RLDC_LR_impl(&CPU, ra, rs, rb, m_eb, is_r, rc); - } - - static void CMP_impl(PPUThread *CPU, u32 crfd, u32 l, u32 ra, u32 rb) - { - CPU->UpdateCRnS(l, crfd, CPU->GPR[ra], CPU->GPR[rb]); - } - void CMP(u32 crfd, u32 l, u32 ra, u32 rb) override - { - CMP_impl(&CPU, crfd, l, ra, rb); - } - - void TW(u32 to, u32 ra, u32 rb) override - { - s32 a = (s32)CPU.GPR[ra]; - s32 b = (s32)CPU.GPR[rb]; - - if( (a < b && (to & 0x10)) || - (a > b && (to & 0x8)) || - (a == b && (to & 0x4)) || - ((u32)a < (u32)b && (to & 0x2)) || - ((u32)a > (u32)b && (to & 0x1)) ) - { - throw EXCEPTION("Trap! (tw 0x%x, r%d, r%d)", to, ra, rb); - } - } - void LVSL(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - - static const u64 lvsl_values[0x10][2] = - { - {0x08090A0B0C0D0E0F, 0x0001020304050607}, - {0x090A0B0C0D0E0F10, 0x0102030405060708}, - {0x0A0B0C0D0E0F1011, 0x0203040506070809}, - {0x0B0C0D0E0F101112, 0x030405060708090A}, - {0x0C0D0E0F10111213, 0x0405060708090A0B}, - {0x0D0E0F1011121314, 0x05060708090A0B0C}, - {0x0E0F101112131415, 0x060708090A0B0C0D}, - {0x0F10111213141516, 0x0708090A0B0C0D0E}, - {0x1011121314151617, 0x08090A0B0C0D0E0F}, - {0x1112131415161718, 0x090A0B0C0D0E0F10}, - {0x1213141516171819, 0x0A0B0C0D0E0F1011}, - {0x131415161718191A, 0x0B0C0D0E0F101112}, - {0x1415161718191A1B, 0x0C0D0E0F10111213}, - {0x15161718191A1B1C, 0x0D0E0F1011121314}, - {0x161718191A1B1C1D, 0x0E0F101112131415}, - {0x1718191A1B1C1D1E, 0x0F10111213141516}, - }; - - CPU.VPR[vd]._u64[0] = lvsl_values[addr & 0xf][0]; - CPU.VPR[vd]._u64[1] = lvsl_values[addr & 0xf][1]; - } - void LVEBX(u32 vd, u32 ra, u32 rb) override - { - 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)); - // It's bad idea to read 128 bit there - } - void SUBFC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - const u64 RA = CPU.GPR[ra]; - const u64 RB = CPU.GPR[rb]; - CPU.GPR[rd] = ~RA + RB + 1; - CPU.XER.CA = CPU.IsCarry(~RA, RB, 1); - if(oe) CPU.SetOV((~RA>>63 == RB>>63) && (~RA>>63 != CPU.GPR[rd]>>63)); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void MULHDU(u32 rd, u32 ra, u32 rb, u32 rc) override - { - CPU.GPR[rd] = UMULH64(CPU.GPR[ra], CPU.GPR[rb]); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void ADDC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - const u64 RA = CPU.GPR[ra]; - const u64 RB = CPU.GPR[rb]; - CPU.GPR[rd] = RA + RB; - CPU.XER.CA = CPU.IsCarry(RA, RB); - if(oe) CPU.SetOV((RA>>63 == RB>>63) && (RA>>63 != CPU.GPR[rd]>>63)); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void MULHWU(u32 rd, u32 ra, u32 rb, u32 rc) override - { - u32 a = (u32)CPU.GPR[ra]; - u32 b = (u32)CPU.GPR[rb]; - CPU.GPR[rd] = ((u64)a * (u64)b) >> 32; - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - - static void MFOCRF_impl(PPUThread *CPU, u32 a, u32 rd, u32 crm) - { - CPU->GPR[rd] = CPU->CR.CR; - } - void MFOCRF(u32 a, u32 rd, u32 crm) override - { - MFOCRF_impl(&CPU, a, rd, crm); - } - static void LWARX_impl(PPUThread *CPU, u32 rd, u32 ra, u32 rb) - { - const u64 addr = ra ? CPU->GPR[ra] + CPU->GPR[rb] : CPU->GPR[rb]; - - be_t value; - vm::reservation_acquire(&value, VM_CAST(addr), sizeof(value)); - - CPU->GPR[rd] = value; - } - void LWARX(u32 rd, u32 ra, u32 rb) override - { - LWARX_impl(&CPU, rd, ra, rb); - } - void LDX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::ps3::read64(VM_CAST(addr)); - } - void LWZX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::ps3::read32(VM_CAST(addr)); - } - void SLW(u32 ra, u32 rs, u32 rb, u32 rc) override - { - u32 n = CPU.GPR[rb] & 0x1f; - u32 r = (u32)rotl32((u32)CPU.GPR[rs], n); - u32 m = ((u32)CPU.GPR[rb] & 0x20) ? 0 : (u32)rotate_mask[32][63 - n]; - - CPU.GPR[ra] = r & m; - - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void CNTLZW(u32 ra, u32 rs, u32 rc) override - { - u32 i; - for(i=0; i < 32; i++) - { - if(CPU.GPR[rs] & (1ULL << (31 - i))) break; - } - - CPU.GPR[ra] = i; - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void SLD(u32 ra, u32 rs, u32 rb, u32 rc) override - { - u32 n = CPU.GPR[rb] & 0x3f; - u64 r = rotl64(CPU.GPR[rs], n); - u64 m = (CPU.GPR[rb] & 0x40) ? 0 : rotate_mask[0][63 - n]; - - CPU.GPR[ra] = r & m; - - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - - static void AND_impl(PPUThread *CPU, u32 ra, u32 rs, u32 rb, u32 rc) - { - CPU->GPR[ra] = CPU->GPR[rs] & CPU->GPR[rb]; - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void AND(u32 ra, u32 rs, u32 rb, u32 rc) override - { - AND_impl(&CPU, ra, rs, rb, rc); - } - - static void CMPL_impl(PPUThread *CPU, u32 crfd, u32 l, u32 ra, u32 rb) - { - CPU->UpdateCRnU(l, crfd, CPU->GPR[ra], CPU->GPR[rb]); - } - void CMPL(u32 crfd, u32 l, u32 ra, u32 rb) override - { - CMPL_impl(&CPU, crfd, l, ra, rb); - } - - void LVSR(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - - static const u64 lvsr_values[0x10][2] = - { - {0x18191A1B1C1D1E1F, 0x1011121314151617}, - {0x1718191A1B1C1D1E, 0x0F10111213141516}, - {0x161718191A1B1C1D, 0x0E0F101112131415}, - {0x15161718191A1B1C, 0x0D0E0F1011121314}, - {0x1415161718191A1B, 0x0C0D0E0F10111213}, - {0x131415161718191A, 0x0B0C0D0E0F101112}, - {0x1213141516171819, 0x0A0B0C0D0E0F1011}, - {0x1112131415161718, 0x090A0B0C0D0E0F10}, - {0x1011121314151617, 0x08090A0B0C0D0E0F}, - {0x0F10111213141516, 0x0708090A0B0C0D0E}, - {0x0E0F101112131415, 0x060708090A0B0C0D}, - {0x0D0E0F1011121314, 0x05060708090A0B0C}, - {0x0C0D0E0F10111213, 0x0405060708090A0B}, - {0x0B0C0D0E0F101112, 0x030405060708090A}, - {0x0A0B0C0D0E0F1011, 0x0203040506070809}, - {0x090A0B0C0D0E0F10, 0x0102030405060708}, - }; - - CPU.VPR[vd]._u64[0] = lvsr_values[addr & 0xf][0]; - CPU.VPR[vd]._u64[1] = lvsr_values[addr & 0xf][1]; - } - void LVEHX(u32 vd, u32 ra, u32 rb) override - { - 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)); - // It's bad idea to read 128 bit there - } - - static void SUBF_impl(PPUThread *CPU, u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - const u64 RA = CPU->GPR[ra]; - const u64 RB = CPU->GPR[rb]; - CPU->GPR[rd] = RB - RA; - if(oe) CPU->SetOV((~RA >> 63 == RB >> 63) && (~RA >> 63 != CPU->GPR[rd] >> 63)); - if(rc) CPU->UpdateCR0(CPU->GPR[rd]); - } - void SUBF(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - SUBF_impl(&CPU, rd, ra, rb, oe, rc); - } - - void LDUX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - CPU.GPR[rd] = vm::ps3::read64(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void DCBST(u32 ra, u32 rb) override - { - } - void LWZUX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - CPU.GPR[rd] = vm::ps3::read32(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void CNTLZD(u32 ra, u32 rs, u32 rc) override - { - u32 i; - for(i=0; i < 64; i++) - { - if(CPU.GPR[rs] & (1ULL << (63 - i))) break; - } - - CPU.GPR[ra] = i; - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void ANDC(u32 ra, u32 rs, u32 rb, u32 rc) override - { - CPU.GPR[ra] = CPU.GPR[rs] & ~CPU.GPR[rb]; - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void TD(u32 to, u32 ra, u32 rb) override - { - throw EXCEPTION(""); - } - void LVEWX(u32 vd, u32 ra, u32 rb) override - { - 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 bad idea to read 128 bit there - } - void MULHD(u32 rd, u32 ra, u32 rb, u32 rc) override - { - CPU.GPR[rd] = MULH64(CPU.GPR[ra], CPU.GPR[rb]); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void MULHW(u32 rd, u32 ra, u32 rb, u32 rc) override - { - s32 a = (s32)CPU.GPR[ra]; - s32 b = (s32)CPU.GPR[rb]; - CPU.GPR[rd] = ((s64)a * (s64)b) >> 32; - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void LDARX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - - be_t value; - vm::reservation_acquire(&value, VM_CAST(addr), sizeof(value)); - - CPU.GPR[rd] = value; - } - void DCBF(u32 ra, u32 rb) override - { - } - void LBZX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::read8(VM_CAST(addr)); - } - void LVX(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~0xfull; - CPU.VPR[vd] = vm::ps3::_ref(VM_CAST(addr)); - } - - static void NEG_impl(PPUThread *CPU, u32 rd, u32 ra, u32 oe, u32 rc) - { - const u64 RA = CPU->GPR[ra]; - CPU->GPR[rd] = 0 - RA; - if(oe) CPU->SetOV((~RA >> 63 == 0) && (~RA >> 63 != CPU->GPR[rd] >> 63)); - if(rc) CPU->UpdateCR0(CPU->GPR[rd]); - } - void NEG(u32 rd, u32 ra, u32 oe, u32 rc) override - { - NEG_impl(&CPU, rd, ra, oe, rc); - } - - void LBZUX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - CPU.GPR[rd] = vm::read8(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void NOR(u32 ra, u32 rs, u32 rb, u32 rc) override - { - CPU.GPR[ra] = ~(CPU.GPR[rs] | CPU.GPR[rb]); - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void STVEBX(u32 vs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const u8 eb = addr & 0xf; - vm::write8(VM_CAST(addr), CPU.VPR[vs]._u8[15 - eb]); - } - void SUBFE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - const u64 RA = CPU.GPR[ra]; - const u64 RB = CPU.GPR[rb]; - CPU.GPR[rd] = ~RA + RB + CPU.XER.CA; - CPU.XER.CA = CPU.IsCarry(~RA, RB, CPU.XER.CA); - if(oe) CPU.SetOV((~RA>>63 == RB>>63) && (~RA>>63 != CPU.GPR[rd]>>63)); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void ADDE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - const u64 RA = CPU.GPR[ra]; - const u64 RB = CPU.GPR[rb]; - if (CPU.XER.CA) - { - if (RA == ~0ULL) //-1 - { - CPU.GPR[rd] = RB; - CPU.XER.CA = 1; - } - else - { - CPU.GPR[rd] = RA + 1 + RB; - CPU.XER.CA = CPU.IsCarry(RA + 1, RB); - } - } - else - { - CPU.GPR[rd] = RA + RB; - CPU.XER.CA = CPU.IsCarry(RA, RB); - } - if(oe) CPU.SetOV((RA>>63 == RB>>63) && (RA>>63 != CPU.GPR[rd]>>63)); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - - static void MTOCRF_impl(PPUThread *CPU, u32 l, u32 crm, u32 rs) - { - if(l) - { - u32 n = 0, count = 0; - for(u32 i=0; i<8; ++i) - { - if (crm & (1 << i)) - { - n = i; - count++; - } - } - - if(count == 1) - { - //CR[4*n : 4*n+3] = RS[32+4*n : 32+4*n+3]; - CPU->SetCR(7 - n, (CPU->GPR[rs] >> (4 * n)) & 0xf); - } - else - CPU->CR.CR = 0; - } - else - { - for(u32 i=0; i<8; ++i) - { - if(crm & (1 << i)) - { - CPU->SetCR(7 - i, (CPU->GPR[rs] >> (i * 4)) & 0xf); - } - } - } - } - void MTOCRF(u32 l, u32 crm, u32 rs) override - { - MTOCRF_impl(&CPU, l, crm, rs); - } - - void STDX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::ps3::write64(VM_CAST(addr), CPU.GPR[rs]); - } - static void STWCX__impl(PPUThread* CPU, u32 rs, u32 ra, u32 rb) - { - const u64 addr = ra ? CPU->GPR[ra] + CPU->GPR[rb] : CPU->GPR[rb]; - - const be_t value = (u32)CPU->GPR[rs]; - CPU->SetCR_EQ(0, vm::reservation_update(VM_CAST(addr), &value, sizeof(value))); - } - void STWCX_(u32 rs, u32 ra, u32 rb) override - { - STWCX__impl(&CPU, rs, ra, rb); - } - void STWX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[rs]); - } - void STVEHX(u32 vs, u32 ra, u32 rb) override - { - const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~1ULL; - const u8 eb = (addr & 0xf) >> 1; - vm::ps3::write16(VM_CAST(addr), CPU.VPR[vs]._u16[7 - eb]); - } - void STDUX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - vm::ps3::write64(VM_CAST(addr), CPU.GPR[rs]); - CPU.GPR[ra] = addr; - } - void STWUX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[rs]); - CPU.GPR[ra] = addr; - } - void STVEWX(u32 vs, u32 ra, u32 rb) override - { - const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~3ULL; - const u8 eb = (addr & 0xf) >> 2; - vm::ps3::write32(VM_CAST(addr), CPU.VPR[vs]._u32[3 - eb]); - } - void SUBFZE(u32 rd, u32 ra, u32 oe, u32 rc) override - { - const u64 RA = CPU.GPR[ra]; - CPU.GPR[rd] = ~RA + CPU.XER.CA; - CPU.XER.CA = CPU.IsCarry(~RA, CPU.XER.CA); - if(oe) CPU.SetOV((~RA>>63 == 0) && (~RA>>63 != CPU.GPR[rd]>>63)); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void ADDZE(u32 rd, u32 ra, u32 oe, u32 rc) override - { - const u64 RA = CPU.GPR[ra]; - CPU.GPR[rd] = RA + CPU.XER.CA; - CPU.XER.CA = CPU.IsCarry(RA, CPU.XER.CA); - if(oe) CPU.SetOV((RA>>63 == 0) && (RA>>63 != CPU.GPR[rd]>>63)); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void STDCX_(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - - const be_t value = CPU.GPR[rs]; - CPU.SetCR_EQ(0, vm::reservation_update(VM_CAST(addr), &value, sizeof(value))); - } - void STBX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::write8(VM_CAST(addr), (u8)CPU.GPR[rs]); - } - void STVX(u32 vs, u32 ra, u32 rb) override - { - const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~0xfull; - vm::ps3::_ref(VM_CAST(addr)) = CPU.VPR[vs]; - } - void MULLD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - const s64 RA = CPU.GPR[ra]; - const s64 RB = CPU.GPR[rb]; - CPU.GPR[rd] = (s64)(RA * RB); - if(oe) - { - const s64 high = MULH64(RA, RB); - CPU.SetOV(high != s64(CPU.GPR[rd]) >> 63); - } - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void SUBFME(u32 rd, u32 ra, u32 oe, u32 rc) override - { - const u64 RA = CPU.GPR[ra]; - CPU.GPR[rd] = ~RA + CPU.XER.CA + ~0ULL; - CPU.XER.CA = CPU.IsCarry(~RA, CPU.XER.CA, ~0ULL); - if(oe) CPU.SetOV((~RA>>63 == 1) && (~RA>>63 != CPU.GPR[rd]>>63)); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void ADDME(u32 rd, u32 ra, u32 oe, u32 rc) override - { - const s64 RA = CPU.GPR[ra]; - CPU.GPR[rd] = RA + CPU.XER.CA - 1; - CPU.XER.CA |= RA != 0; - - if(oe) CPU.SetOV((u64(RA)>>63 == 1) && (u64(RA)>>63 != CPU.GPR[rd]>>63)); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - - static void MULLW_impl(PPUThread *CPU, u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - CPU->GPR[rd] = (s64)((s64)(s32)CPU->GPR[ra] * (s64)(s32)CPU->GPR[rb]); - if(oe) CPU->SetOV(s64(CPU->GPR[rd]) < s64(-1) << 31 || s64(CPU->GPR[rd]) >= s64(1) << 31); - if(rc) CPU->UpdateCR0(CPU->GPR[rd]); - } - void MULLW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - MULLW_impl(&CPU, rd, ra, rb, oe, rc); - } - - void DCBTST(u32 ra, u32 rb, u32 th) override - { - } - void STBUX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - vm::write8(VM_CAST(addr), (u8)CPU.GPR[rs]); - CPU.GPR[ra] = addr; - } - - static void ADD_impl(PPUThread *CPU, u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - const u64 RA = CPU->GPR[ra]; - const u64 RB = CPU->GPR[rb]; - CPU->GPR[rd] = RA + RB; - if(oe) CPU->SetOV((RA >> 63 == RB >> 63) && (RA >> 63 != CPU->GPR[rd] >> 63)); - if(rc) CPU->UpdateCR0(CPU->GPR[rd]); - } - void ADD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - ADD_impl(&CPU, rd, ra, rb, oe, rc); - } - - void DCBT(u32 ra, u32 rb, u32 th) override - { - } - void LHZX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::ps3::read16(VM_CAST(addr)); - } - void EQV(u32 ra, u32 rs, u32 rb, u32 rc) override - { - CPU.GPR[ra] = ~(CPU.GPR[rs] ^ CPU.GPR[rb]); - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void ECIWX(u32 rd, u32 ra, u32 rb) override - { - throw EXCEPTION("Privileged instruction"); - } - void LHZUX(u32 rd, u32 ra, u32 rb)override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::ps3::read16(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void XOR(u32 ra, u32 rs, u32 rb, u32 rc) override - { - CPU.GPR[ra] = CPU.GPR[rs] ^ CPU.GPR[rb]; - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void MFSPR(u32 rd, u32 spr) override - { - CPU.GPR[rd] = ReadSPR(spr); - } - void LWAX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = (s64)(s32)vm::ps3::read32(VM_CAST(addr)); - } - void DST(u32 ra, u32 rb, u32 strm, u32 t) override - { - } - void LHAX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = (s64)(s16)vm::ps3::read16(VM_CAST(addr)); - } - void LVXL(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~0xfull; - CPU.VPR[vd] = vm::ps3::_ref(VM_CAST(addr)); - } - void MFTB(u32 rd, u32 spr) override - { - const u32 n = (spr >> 5) | ((spr & 0x1f) << 5); - - CPU.TB = get_timebased_time(); - switch(n) - { - case 0x10C: CPU.GPR[rd] = CPU.TB; break; - case 0x10D: CPU.GPR[rd] = CPU.TB >> 32; break; - default: throw EXCEPTION("mftb r%d, %d", rd, spr); - } - } - void LWAUX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = (s64)(s32)vm::ps3::read32(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void DSTST(u32 ra, u32 rb, u32 strm, u32 t) override - { - } - void LHAUX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = (s64)(s16)vm::ps3::read16(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void STHX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::ps3::write16(VM_CAST(addr), (u16)CPU.GPR[rs]); - } - void ORC(u32 ra, u32 rs, u32 rb, u32 rc) override - { - CPU.GPR[ra] = CPU.GPR[rs] | ~CPU.GPR[rb]; - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void ECOWX(u32 rs, u32 ra, u32 rb) override - { - throw EXCEPTION("Privileged instruction"); - } - void STHUX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - vm::ps3::write16(VM_CAST(addr), (u16)CPU.GPR[rs]); - CPU.GPR[ra] = addr; - } - - static void OR_impl(PPUThread *CPU, u32 ra, u32 rs, u32 rb, u32 rc) - { - CPU->GPR[ra] = CPU->GPR[rs] | CPU->GPR[rb]; - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void OR(u32 ra, u32 rs, u32 rb, u32 rc) override - { - OR_impl(&CPU, ra, rs, rb, rc); - } - - void DIVDU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - const u64 RA = CPU.GPR[ra]; - const u64 RB = CPU.GPR[rb]; - - if(RB == 0) - { - if(oe) CPU.SetOV(true); - CPU.GPR[rd] = 0; - } - else - { - if(oe) CPU.SetOV(false); - CPU.GPR[rd] = RA / RB; - } - - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - - static void DIVWU_impl(PPUThread *CPU, u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - const u32 RA = (u32)CPU->GPR[ra]; - const u32 RB = (u32)CPU->GPR[rb]; - - if(RB == 0) - { - if(oe) CPU->SetOV(true); - CPU->GPR[rd] = 0; - } - else - { - if(oe) CPU->SetOV(false); - CPU->GPR[rd] = RA / RB; - } - - if(rc) CPU->UpdateCR0(CPU->GPR[rd]); - } - void DIVWU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - DIVWU_impl(&CPU, rd, ra, rb, oe, rc); - } - - void MTSPR(u32 spr, u32 rs) override - { - WriteSPR(spr, CPU.GPR[rs]); - } - void DCBI(u32 ra, u32 rb) override - { - } - void NAND(u32 ra, u32 rs, u32 rb, u32 rc) override - { - CPU.GPR[ra] = ~(CPU.GPR[rs] & CPU.GPR[rb]); - - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void STVXL(u32 vs, u32 ra, u32 rb) override - { - const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~0xfull; - vm::ps3::_ref(VM_CAST(addr)) = CPU.VPR[vs]; - } - void DIVD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - const s64 RA = CPU.GPR[ra]; - const s64 RB = CPU.GPR[rb]; - - if (RB == 0 || ((u64)RA == (1ULL << 63) && RB == -1)) - { - if(oe) CPU.SetOV(true); - CPU.GPR[rd] = /*(((u64)RA & (1ULL << 63)) && RB == 0) ? -1 :*/ 0; - } - else - { - if(oe) CPU.SetOV(false); - CPU.GPR[rd] = RA / RB; - } - - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - - static void DIVW_impl(PPUThread *CPU, u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - const s32 RA = (s32)CPU->GPR[ra]; - const s32 RB = (s32)CPU->GPR[rb]; - - if (RB == 0 || ((u32)RA == (1 << 31) && RB == -1)) - { - if(oe) CPU->SetOV(true); - CPU->GPR[rd] = /*(((u32)RA & (1 << 31)) && RB == 0) ? -1 :*/ 0; - } - else - { - if(oe) CPU->SetOV(false); - CPU->GPR[rd] = (u32)(RA / RB); - } - - if(rc) CPU->UpdateCR0(CPU->GPR[rd]); - } - void DIVW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - DIVW_impl(&CPU, rd, ra, rb, oe, rc); - } - - void LVLX(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const u32 eb = addr & 0xf; - - CPU.VPR[vd].clear(); - for (u32 i = 0; i < 16u - eb; ++i) CPU.VPR[vd]._u8[15 - i] = vm::read8(VM_CAST(addr + i)); - } - void LDBRX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::ps3::_ref>(VM_CAST(addr)); - } - void LSWX(u32 rd, u32 ra, u32 rb) override - { - u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - u32 count = CPU.XER.XER & 0x7F; - for (; count >= 4; count -= 4, addr += 4, rd = (rd+1) & 31) - { - CPU.GPR[rd] = vm::ps3::_ref(VM_CAST(addr)); - } - if (count) - { - u32 value = 0; - for (u32 byte = 0; byte < count; byte++) - { - u32 byte_value = vm::ps3::_ref(VM_CAST(addr+byte)); - value |= byte_value << ((3^byte)*8); - } - CPU.GPR[rd] = value; - } - } - void LWBRX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::ps3::_ref>(VM_CAST(addr)); - } - void LFSX(u32 frd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const f32 val = vm::ps3::_ref(VM_CAST(addr)); - if (!FPRdouble::IsNaN(val)) - { - CPU.FPR[frd] = val; - } - else - { - u64 bits = (u32&)val; - (u64&)CPU.FPR[frd] = (bits & 0x80000000) << 32 | 7ULL << 60 | (bits & 0x7fffffff) << 29; - } - } - void SRW(u32 ra, u32 rs, u32 rb, u32 rc) override - { - u32 n = CPU.GPR[rb] & 0x1f; - u32 r = (u32)rotl32((u32)CPU.GPR[rs], 64 - n); - u32 m = ((u32)CPU.GPR[rb] & 0x20) ? 0 : (u32)rotate_mask[32 + n][63]; - CPU.GPR[ra] = r & m; - - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void SRD(u32 ra, u32 rs, u32 rb, u32 rc) override - { - u32 n = CPU.GPR[rb] & 0x3f; - u64 r = rotl64(CPU.GPR[rs], 64 - n); - u64 m = (CPU.GPR[rb] & 0x40) ? 0 : rotate_mask[n][63]; - CPU.GPR[ra] = r & m; - - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void LVRX(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const u8 eb = addr & 0xf; - - CPU.VPR[vd].clear(); - for (u32 i = 16 - eb; i < 16; ++i) CPU.VPR[vd]._u8[15 - i] = vm::read8(VM_CAST(addr + i - 16)); - } - void LSWI(u32 rd, u32 ra, u32 nb) override - { - u64 addr = ra ? CPU.GPR[ra] : 0; - u64 N = nb ? nb : 32; - u8 reg = rd; - - while (N > 0) - { - if (N > 3) - { - CPU.GPR[reg] = vm::ps3::read32(VM_CAST(addr)); - addr += 4; - N -= 4; - } - else - { - u32 buf = 0; - u32 i = 3; - while (N > 0) - { - N = N - 1; - buf |= vm::read8(VM_CAST(addr)) << (i * 8); - addr++; - i--; - } - CPU.GPR[reg] = buf; - } - reg = (reg + 1) % 32; - } - } - void LFSUX(u32 frd, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - const f32 val = vm::ps3::_ref(VM_CAST(addr)); - if (!FPRdouble::IsNaN(val)) - { - CPU.FPR[frd] = val; - } - else - { - u64 bits = (u32&)val; - (u64&)CPU.FPR[frd] = (bits & 0x80000000) << 32 | 7ULL << 60 | (bits & 0x7fffffff) << 29; - } - CPU.GPR[ra] = addr; - } - void SYNC(u32 l) override - { - _mm_mfence(); - } - void LFDX(u32 frd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.FPR[frd]._double = vm::ps3::_ref(VM_CAST(addr)); - } - void LFDUX(u32 frd, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - CPU.FPR[frd]._double = vm::ps3::_ref(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void STVLX(u32 vs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const u32 eb = addr & 0xf; - - for (u32 i = 0; i < 16u - eb; ++i) vm::write8(VM_CAST(addr + i), CPU.VPR[vs]._u8[15 - i]); - } - void STDBRX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::ps3::_ref>(VM_CAST(addr)) = CPU.GPR[rs]; - } - void STSWX(u32 rs, u32 ra, u32 rb) override - { - u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - u32 count = CPU.XER.XER & 0x7F; - for (; count >= 4; count -= 4, addr += 4, rs = (rs+1) & 31) - { - vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[rs]); - } - if (count) - { - u32 value = (u32)CPU.GPR[rs]; - for (u32 byte = 0; byte < count; byte++) - { - u32 byte_value = (u8)(value >> ((3^byte)*8)); - vm::write8(VM_CAST(addr+byte), byte_value); - } - } - } - void STWBRX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::ps3::_ref>(VM_CAST(addr)) = (u32)CPU.GPR[rs]; - } - void STFSX(u32 frs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - double val = CPU.FPR[frs]; - if (!FPRdouble::IsNaN(val)) - { - vm::ps3::_ref(VM_CAST(addr)) = (float)val; - } - else - { - u64 bits = (u64&)val; - u32 bits32 = (bits>>32 & 0x80000000) | (bits>>29 & 0x7fffffff); - vm::ps3::_ref(VM_CAST(addr)) = bits32; - } - } - void STVRX(u32 vs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const u8 eb = addr & 0xf; - - for (u32 i = 16 - eb; i < 16; ++i) vm::write8(VM_CAST(addr + i - 16), CPU.VPR[vs]._u8[15 - i]); - } - void STFSUX(u32 frs, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - double val = CPU.FPR[frs]; - if (!FPRdouble::IsNaN(val)) - { - vm::ps3::_ref(VM_CAST(addr)) = (float)val; - } - else - { - u64 bits = (u64&)val; - u32 bits32 = (bits>>32 & 0x80000000) | (bits>>29 & 0x7fffffff); - vm::ps3::_ref(VM_CAST(addr)) = bits32; - } - CPU.GPR[ra] = addr; - } - void STSWI(u32 rd, u32 ra, u32 nb) override - { - u64 addr = ra ? CPU.GPR[ra] : 0; - u64 N = nb ? nb : 32; - u8 reg = rd; - - while (N > 0) - { - if (N > 3) - { - vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[reg]); - addr += 4; - N -= 4; - } - else - { - u32 buf = (u32)CPU.GPR[reg]; - while (N > 0) - { - N = N - 1; - vm::write8(VM_CAST(addr), (0xFF000000 & buf) >> 24); - buf <<= 8; - addr++; - } - } - reg = (reg + 1) % 32; - } - } - void STFDX(u32 frs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::ps3::_ref(VM_CAST(addr)) = CPU.FPR[frs]; - } - void STFDUX(u32 frs, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - vm::ps3::_ref(VM_CAST(addr)) = CPU.FPR[frs]; - CPU.GPR[ra] = addr; - } - void LVLXL(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const u32 eb = addr & 0xf; - - CPU.VPR[vd].clear(); - for (u32 i = 0; i < 16u - eb; ++i) CPU.VPR[vd]._u8[15 - i] = vm::read8(VM_CAST(addr + i)); - } - void LHBRX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::ps3::_ref>(VM_CAST(addr)); - } - void SRAW(u32 ra, u32 rs, u32 rb, u32 rc) override - { - s32 RS = (s32)CPU.GPR[rs]; - u8 shift = CPU.GPR[rb] & 63; - if (shift > 31) - { - CPU.GPR[ra] = 0 - (RS < 0); - CPU.XER.CA = (RS < 0); - } - else - { - CPU.GPR[ra] = RS >> shift; - CPU.XER.CA = (RS < 0) & ((CPU.GPR[ra] << shift) != RS); - } - - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void SRAD(u32 ra, u32 rs, u32 rb, u32 rc) override - { - s64 RS = CPU.GPR[rs]; - u8 shift = CPU.GPR[rb] & 127; - if (shift > 63) - { - CPU.GPR[ra] = 0 - (RS < 0); - CPU.XER.CA = (RS < 0); - } - else - { - CPU.GPR[ra] = RS >> shift; - CPU.XER.CA = (RS < 0) & ((CPU.GPR[ra] << shift) != RS); - } - - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void LVRXL(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const u8 eb = addr & 0xf; - - CPU.VPR[vd].clear(); - for (u32 i = 16 - eb; i < 16; ++i) CPU.VPR[vd]._u8[15 - i] = vm::read8(VM_CAST(addr + i - 16)); - } - void DSS(u32 strm, u32 a) override - { - } - - static void SRAWI_impl(PPUThread *CPU, u32 ra, u32 rs, u32 sh, u32 rc) - { - s32 RS = (u32)CPU->GPR[rs]; - CPU->GPR[ra] = RS >> sh; - CPU->XER.CA = (RS < 0) & ((u32)(CPU->GPR[ra] << sh) != RS); - - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void SRAWI(u32 ra, u32 rs, u32 sh, u32 rc) override - { - SRAWI_impl(&CPU, ra, rs, sh, rc); - } - - void SRADI1(u32 ra, u32 rs, u32 sh, u32 rc) override - { - s64 RS = CPU.GPR[rs]; - CPU.GPR[ra] = RS >> sh; - CPU.XER.CA = (RS < 0) & ((CPU.GPR[ra] << sh) != RS); - - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void SRADI2(u32 ra, u32 rs, u32 sh, u32 rc) override - { - SRADI1(ra, rs, sh, rc); - } - void EIEIO() override - { - _mm_mfence(); - } - void STVLXL(u32 vs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const u32 eb = addr & 0xf; - - for (u32 i = 0; i < 16u - eb; ++i) vm::write8(VM_CAST(addr + i), CPU.VPR[vs]._u8[15 - i]); - } - void STHBRX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::ps3::_ref>(VM_CAST(addr)) = (u16)CPU.GPR[rs]; - } - void EXTSH(u32 ra, u32 rs, u32 rc) override - { - CPU.GPR[ra] = (s64)(s16)CPU.GPR[rs]; - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void STVRXL(u32 vs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const u8 eb = addr & 0xf; - - for (u32 i = 16 - eb; i < 16; ++i) vm::write8(VM_CAST(addr + i - 16), CPU.VPR[vs]._u8[15 - i]); - } - - static void EXTSB_impl(PPUThread *CPU, u32 ra, u32 rs, u32 rc) - { - CPU->GPR[ra] = (s64)(s8)CPU->GPR[rs]; - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void EXTSB(u32 ra, u32 rs, u32 rc) override - { - EXTSB_impl(&CPU, ra, rs, rc); - } - - void STFIWX(u32 frs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::ps3::write32(VM_CAST(addr), (u32&)CPU.FPR[frs]); - } - - static void EXTSW_impl(PPUThread *CPU, u32 ra, u32 rs, u32 rc) - { - CPU->GPR[ra] = (s64)(s32)CPU->GPR[rs]; - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void EXTSW(u32 ra, u32 rs, u32 rc) override - { - EXTSW_impl(&CPU, ra, rs, rc); - } - - void ICBI(u32 ra, u32 rs) override - { - // Clear jit for the specified block? Nothing to do in the interpreter. - } - void DCBZ(u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - - std::memset(vm::base(VM_CAST(addr) & ~127), 0, 128); - } - - static void LWZ_impl(PPUThread *CPU, u32 rd, u32 ra, s32 d) - { - const u64 addr = ra ? CPU->GPR[ra] + d : d; - CPU->GPR[rd] = vm::ps3::read32(VM_CAST(addr)); - } - void LWZ(u32 rd, u32 ra, s32 d) override - { - LWZ_impl(&CPU, rd, ra, d); - } - - void LWZU(u32 rd, u32 ra, s32 d) override - { - const u64 addr = CPU.GPR[ra] + d; - CPU.GPR[rd] = vm::ps3::read32(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - - static void LBZ_impl(PPUThread *CPU, u32 rd, u32 ra, s32 d) - { - const u64 addr = ra ? CPU->GPR[ra] + d : d; - CPU->GPR[rd] = vm::read8(VM_CAST(addr)); - } - void LBZ(u32 rd, u32 ra, s32 d) override - { - LBZ_impl(&CPU, rd, ra, d); - } - - void LBZU(u32 rd, u32 ra, s32 d) override - { - const u64 addr = CPU.GPR[ra] + d; - CPU.GPR[rd] = vm::read8(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - - static void STW_impl(PPUThread *CPU, u32 rs, u32 ra, s32 d) - { - const u64 addr = ra ? CPU->GPR[ra] + d : d; - vm::ps3::write32(VM_CAST(addr), (u32)CPU->GPR[rs]); - } - void STW(u32 rs, u32 ra, s32 d) override - { - STW_impl(&CPU, rs, ra, d); - } - - void STWU(u32 rs, u32 ra, s32 d) override - { - const u64 addr = CPU.GPR[ra] + d; - vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[rs]); - CPU.GPR[ra] = addr; - } - void STB(u32 rs, u32 ra, s32 d) override - { - const u64 addr = ra ? CPU.GPR[ra] + d : d; - vm::write8(VM_CAST(addr), (u8)CPU.GPR[rs]); - } - void STBU(u32 rs, u32 ra, s32 d) override - { - const u64 addr = CPU.GPR[ra] + d; - vm::write8(VM_CAST(addr), (u8)CPU.GPR[rs]); - CPU.GPR[ra] = addr; - } - static void LHZ_impl(PPUThread *CPU, u32 rd, u32 ra, s32 d) - { - const u64 addr = ra ? CPU->GPR[ra] + d : d; - CPU->GPR[rd] = vm::ps3::read16(VM_CAST(addr)); - } - void LHZ(u32 rd, u32 ra, s32 d) override - { - LHZ_impl(&CPU, rd, ra, d); - } - void LHZU(u32 rd, u32 ra, s32 d) override - { - const u64 addr = CPU.GPR[ra] + d; - CPU.GPR[rd] = vm::ps3::read16(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void LHA(u32 rd, u32 ra, s32 d) override - { - const u64 addr = ra ? CPU.GPR[ra] + d : d; - CPU.GPR[rd] = (s64)(s16)vm::ps3::read16(VM_CAST(addr)); - } - void LHAU(u32 rd, u32 ra, s32 d) override - { - const u64 addr = CPU.GPR[ra] + d; - CPU.GPR[rd] = (s64)(s16)vm::ps3::read16(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void STH(u32 rs, u32 ra, s32 d) override - { - const u64 addr = ra ? CPU.GPR[ra] + d : d; - vm::ps3::write16(VM_CAST(addr), (u16)CPU.GPR[rs]); - } - void STHU(u32 rs, u32 ra, s32 d) override - { - const u64 addr = CPU.GPR[ra] + d; - vm::ps3::write16(VM_CAST(addr), (u16)CPU.GPR[rs]); - CPU.GPR[ra] = addr; - } - void LMW(u32 rd, u32 ra, s32 d) override - { - u64 addr = ra ? CPU.GPR[ra] + d : d; - for(u32 i=rd; i<32; ++i, addr += 4) - { - CPU.GPR[i] = vm::ps3::read32(VM_CAST(addr)); - } - } - void STMW(u32 rs, u32 ra, s32 d) override - { - u64 addr = ra ? CPU.GPR[ra] + d : d; - for(u32 i=rs; i<32; ++i, addr += 4) - { - vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[i]); - } - } - - static void LFS_impl(PPUThread *CPU, u32 frd, u32 ra, s32 d) - { - const u64 addr = ra ? CPU->GPR[ra] + d : d; - const f32 val = vm::ps3::_ref(VM_CAST(addr)); - if (!FPRdouble::IsNaN(val)) - { - CPU->FPR[frd] = val; - } - else - { - u64 bits = (u32&)val; - (u64&)CPU->FPR[frd] = (bits & 0x80000000) << 32 | 7ULL << 60 | (bits & 0x7fffffff) << 29; - } - } - void LFS(u32 frd, u32 ra, s32 d) override - { - LFS_impl(&CPU, frd, ra, d); - } - - void LFSU(u32 frd, u32 ra, s32 ds) override - { - const u64 addr = CPU.GPR[ra] + ds; - const f32 val = vm::ps3::_ref(VM_CAST(addr)); - if (!FPRdouble::IsNaN(val)) - { - CPU.FPR[frd] = val; - } - else - { - u64 bits = (u32&)val; - (u64&)CPU.FPR[frd] = (bits & 0x80000000) << 32 | 7ULL << 60 | (bits & 0x7fffffff) << 29; - } - CPU.GPR[ra] = addr; - } - void LFD(u32 frd, u32 ra, s32 d) override - { - const u64 addr = ra ? CPU.GPR[ra] + d : d; - CPU.FPR[frd]._double = vm::ps3::_ref(VM_CAST(addr)); - } - void LFDU(u32 frd, u32 ra, s32 ds) override - { - const u64 addr = CPU.GPR[ra] + ds; - CPU.FPR[frd]._double = vm::ps3::_ref(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - - static void STFS_impl(PPUThread *CPU, u32 frs, u32 ra, s32 d) - { - const u64 addr = ra ? CPU->GPR[ra] + d : d; - double val = CPU->FPR[frs]; - if (!FPRdouble::IsNaN(val)) - { - vm::ps3::_ref(VM_CAST(addr)) = (float)val; - } - else - { - u64 bits = (u64&)val; - u32 bits32 = (bits>>32 & 0x80000000) | (bits>>29 & 0x7fffffff); - vm::ps3::_ref(VM_CAST(addr)) = bits32; - } - } - void STFS(u32 frs, u32 ra, s32 d) override - { - STFS_impl(&CPU, frs, ra, d); - } - - void STFSU(u32 frs, u32 ra, s32 d) override - { - const u64 addr = CPU.GPR[ra] + d; - double val = CPU.FPR[frs]; - if (!FPRdouble::IsNaN(val)) - { - vm::ps3::_ref(VM_CAST(addr)) = (float)val; - } - else - { - u64 bits = (u64&)val; - u32 bits32 = (bits>>32 & 0x80000000) | (bits>>29 & 0x7fffffff); - vm::ps3::_ref(VM_CAST(addr)) = bits32; - } - CPU.GPR[ra] = addr; - } - void STFD(u32 frs, u32 ra, s32 d) override - { - const u64 addr = ra ? CPU.GPR[ra] + d : d; - vm::ps3::_ref(VM_CAST(addr)) = CPU.FPR[frs]; - } - void STFDU(u32 frs, u32 ra, s32 d) override - { - const u64 addr = CPU.GPR[ra] + d; - vm::ps3::_ref(VM_CAST(addr)) = CPU.FPR[frs]; - CPU.GPR[ra] = addr; - } - - static void LD_impl(PPUThread *CPU, u32 rd, u32 ra, s32 ds) - { - const u64 addr = ra ? CPU->GPR[ra] + ds : ds; - CPU->GPR[rd] = vm::ps3::read64(VM_CAST(addr)); - } - void LD(u32 rd, u32 ra, s32 ds) override - { - LD_impl(&CPU, rd, ra, ds); - } - - void LDU(u32 rd, u32 ra, s32 ds) override - { - const u64 addr = CPU.GPR[ra] + ds; - CPU.GPR[rd] = vm::ps3::read64(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void LWA(u32 rd, u32 ra, s32 ds) override - { - const u64 addr = ra ? CPU.GPR[ra] + ds : ds; - CPU.GPR[rd] = (s64)(s32)vm::ps3::read32(VM_CAST(addr)); - } - void FDIVS(u32 frd, u32 fra, u32 frb, u32 rc) override {FDIV(frd, fra, frb, rc, true);} - void FSUBS(u32 frd, u32 fra, u32 frb, u32 rc) override {FSUB(frd, fra, frb, rc, true);} - void FADDS(u32 frd, u32 fra, u32 frb, u32 rc) override {FADD(frd, fra, frb, rc, true);} - void FSQRTS(u32 frd, u32 frb, u32 rc) override {FSQRT(frd, frb, rc, true);} - void FRES(u32 frd, u32 frb, u32 rc) override - { - SetHostRoundingMode(CPU.FPSCR.RN); - const double b = CPU.FPR[frb]; - if(FPRdouble::IsSNaN(b)) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - if(FPRdouble::IsNaN(b)) - { - CPU.FPR[frd] = SilenceNaN(b); - } - else if(b == 0.0) - { - CPU.SetFPSCRException(FPSCR_ZX); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if (CPU.FPSCR.ZE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = 1.0 / b; - } - else - { - feclearexcept(FE_ALL_EXCEPT); - CPU.FPR[frd] = static_cast(1.0 / b); - CheckHostFPExceptions(); - } - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) CPU.UpdateCR1(); - } - void FMULS(u32 frd, u32 fra, u32 frc, u32 rc) override {FMUL(frd, fra, frc, rc, true);} - void FMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, false, false, true);} - void FMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, false, true, true);} - void FNMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, true, true, true);} - void FNMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, true, false, true);} - - static void STD_impl(PPUThread *CPU, u32 rs, u32 ra, s32 d) - { - const u64 addr = ra ? CPU->GPR[ra] + d : d; - vm::ps3::write64(VM_CAST(addr), CPU->GPR[rs]); - } - - void STD(u32 rs, u32 ra, s32 d) override - { - STD_impl(&CPU, rs, ra, d); - } - - static void STDU_impl(PPUThread *CPU, u32 rs, u32 ra, s32 ds) - { - const u64 addr = CPU->GPR[ra] + ds; - vm::ps3::write64(VM_CAST(addr), CPU->GPR[rs]); - CPU->GPR[ra] = addr; - } - - void STDU(u32 rs, u32 ra, s32 ds) override - { - STDU_impl(&CPU, rs, ra, ds); - } - - void MTFSB1(u32 crbd, u32 rc) override - { - u32 mask = 1 << (31 - crbd); - if ((crbd >= 3 && crbd <= 6) && !(CPU.FPSCR.FPSCR & mask)) mask |= 1 << 31; //FPSCR.FX - if ((crbd == 29) && !CPU.FPSCR.NI) LOG_WARNING(PPU, "Non-IEEE mode enabled"); - CPU.SetFPSCR(CPU.FPSCR.FPSCR | mask); - - if(rc) CPU.UpdateCR1(); - } - void MCRFS(u32 crbd, u32 crbs) override - { - CPU.SetCR(crbd, (CPU.FPSCR.FPSCR >> ((7 - crbs) * 4)) & 0xf); - const u32 exceptions_mask = 0x9FF80700; - CPU.SetFPSCR(CPU.FPSCR.FPSCR & ~(exceptions_mask & 0xf << ((7 - crbs) * 4))); - } - void MTFSB0(u32 crbd, u32 rc) override - { - u32 mask = 1 << (31 - crbd); - if ((crbd == 29) && !CPU.FPSCR.NI) LOG_WARNING(PPU, "Non-IEEE mode disabled"); - CPU.SetFPSCR(CPU.FPSCR.FPSCR & ~mask); - - if(rc) CPU.UpdateCR1(); - } - void MTFSFI(u32 crfd, u32 i, u32 rc) override - { - u32 mask = 0xF0000000 >> (crfd * 4); - u32 val = (i & 0xF) << ((7 - crfd) * 4); - - const u32 oldNI = CPU.FPSCR.NI; - CPU.SetFPSCR((CPU.FPSCR.FPSCR & ~mask) | val); - if (CPU.FPSCR.NI != oldNI) - { - if (oldNI) - LOG_WARNING(PPU, "Non-IEEE mode disabled"); - else - LOG_WARNING(PPU, "Non-IEEE mode enabled"); - } - - if(rc) CPU.UpdateCR1(); - } - void MFFS(u32 frd, u32 rc) override - { - (u64&)CPU.FPR[frd] = CPU.FPSCR.FPSCR; - if(rc) CPU.UpdateCR1(); - } - void MTFSF(u32 flm, u32 frb, u32 rc) override - { - u32 mask = 0; - for(u32 i=0; i<8; ++i) - { - if(flm & (1 << i)) mask |= 0xf << (i * 4); - } - mask &= ~0x60000000; - - const u32 oldNI = CPU.FPSCR.NI; - CPU.SetFPSCR((CPU.FPSCR.FPSCR & ~mask) | ((u32&)CPU.FPR[frb] & mask)); - if (CPU.FPSCR.NI != oldNI) - { - if (oldNI) - LOG_WARNING(PPU, "Non-IEEE mode disabled"); - else - LOG_WARNING(PPU, "Non-IEEE mode enabled"); - } - if(rc) CPU.UpdateCR1(); - } - void FCMPU(u32 crfd, u32 fra, u32 frb) override - { - int cmp_res = FPRdouble::Cmp(CPU.FPR[fra], CPU.FPR[frb]); - - if(cmp_res == CR_SO) - { - if(FPRdouble::IsSNaN(CPU.FPR[fra]) || FPRdouble::IsSNaN(CPU.FPR[frb])) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - } - } - - CPU.FPSCR.FPRF = cmp_res; - CPU.SetCR(crfd, cmp_res); - } - void FRSP(u32 frd, u32 frb, u32 rc) override - { - SetHostRoundingMode(CPU.FPSCR.RN); - const double b = CPU.FPR[frb]; - if (FPRdouble::IsSNaN(b)) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if (CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - double b0 = b; - if(CPU.FPSCR.NI) - { - if (((u64&)b0 & DOUBLE_EXP) < 0x3800000000000000ULL) (u64&)b0 &= DOUBLE_SIGN; - } - feclearexcept(FE_ALL_EXCEPT); - const double r = static_cast(b0); - if (FPRdouble::IsNaN(r)) - { - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - } - else - { - CPU.FPSCR.FR = fabs(r) > fabs(b); - CheckHostFPExceptions(); - } - u32 type = PPCdouble(r).GetType(); - if (type == FPR_PN && r < ldexp(1.0, -126)) type = FPR_PD; - else if (type == FPR_NN && r > ldexp(-1.0, -126)) type = FPR_ND; - CPU.FPSCR.FPRF = type; - CPU.FPR[frd] = r; - if(rc) CPU.UpdateCR1(); - } - void FCTIW(u32 frd, u32 frb, u32 rc) override {FCTIW(frd, frb, rc, false);} - void FCTIW(u32 frd, u32 frb, u32 rc, bool truncate) - { - const double b = CPU.FPR[frb]; - u32 r; - if (FPRdouble::IsNaN(b) || b < -(double)0x80000000) - { - CPU.SetFPSCRException(FPSCR_VXCVI); - if(FPRdouble::IsSNaN(b)) CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FI = 0; - CPU.FPSCR.FR = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - r = 0x80000000; - } - else if(b > (double)0x7fffffff) - { - CPU.SetFPSCRException(FPSCR_VXCVI); - CPU.FPSCR.FI = 0; - CPU.FPSCR.FR = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - r = 0x7fffffff; - } - else - { - s32 i = 0; - const u32 rn = truncate ? FPSCR_RN_ZERO : CPU.FPSCR.RN; - switch(rn) - { - case FPSCR_RN_NEAR: - SetHostRoundingMode(FPSCR_RN_NEAR); - i = (s32)nearbyint(b); - break; - case FPSCR_RN_ZERO: - i = (s32)b; - break; - case FPSCR_RN_PINF: - i = (s32)ceil(b); - break; - case FPSCR_RN_MINF: - i = (s32)floor(b); - break; - } - r = (u32)i; - double di = i; - if (di == b) - { - CPU.SetFPSCR_FI(0); - CPU.FPSCR.FR = 0; - } - else - { - CPU.SetFPSCR_FI(1); - CPU.FPSCR.FR = fabs(di) > fabs(b); - } - } - - (u64&)CPU.FPR[frd] = r; - if(rc) CPU.UpdateCR1(); - } - void FCTIWZ(u32 frd, u32 frb, u32 rc) override {FCTIW(frd, frb, rc, true);} - void FDIV(u32 frd, u32 fra, u32 frb, u32 rc) override {FDIV(frd, fra, frb, rc, false);} - void FDIV(u32 frd, u32 fra, u32 frb, u32 rc, bool single) - { - SetHostRoundingMode(CPU.FPSCR.RN); - const double a = CPU.FPR[fra]; - const double b = CPU.FPR[frb]; - if(FPRdouble::IsSNaN(a) || FPRdouble::IsSNaN(b)) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - if(FPRdouble::IsNaN(a)) - { - CPU.FPR[frd] = SilenceNaN(a); - } - else if(FPRdouble::IsNaN(b)) - { - CPU.FPR[frd] = SilenceNaN(b); - } - else if(a == 0.0 && b == 0.0) - { - CPU.SetFPSCRException(FPSCR_VXZDZ); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = FPR_NAN; - } - else if(FPRdouble::IsINF(a) && FPRdouble::IsINF(b)) - { - CPU.SetFPSCRException(FPSCR_VXIDI); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = FPR_NAN; - } - else - { - if(b == 0.0) - { - CPU.SetFPSCRException(FPSCR_ZX); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if (CPU.FPSCR.ZE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - feclearexcept(FE_ALL_EXCEPT); - const double res = a / b; - if(single) CPU.FPR[frd] = (float)res; - else CPU.FPR[frd] = res; - CheckHostFPExceptions(); - } - - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) CPU.UpdateCR1(); - } - void FSUB(u32 frd, u32 fra, u32 frb, u32 rc) override {FSUB(frd, fra, frb, rc, false);} - void FSUB(u32 frd, u32 fra, u32 frb, u32 rc, bool single) - { - SetHostRoundingMode(CPU.FPSCR.RN); - const double a = CPU.FPR[fra]; - const double b = CPU.FPR[frb]; - if(FPRdouble::IsSNaN(a) || FPRdouble::IsSNaN(b)) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - if(FPRdouble::IsNaN(a)) - { - CPU.FPR[frd] = SilenceNaN(a); - } - else if(FPRdouble::IsNaN(b)) - { - CPU.FPR[frd] = SilenceNaN(b); - } - else if(FPRdouble::IsINF(a) && FPRdouble::IsINF(b) && a == b) - { - CPU.SetFPSCRException(FPSCR_VXISI); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = FPR_NAN; - } - else - { - feclearexcept(FE_ALL_EXCEPT); - const double res = a - b; - if(single) CPU.FPR[frd] = (float)res; - else CPU.FPR[frd] = res; - CheckHostFPExceptions(); - } - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) CPU.UpdateCR1(); - } - void FADD(u32 frd, u32 fra, u32 frb, u32 rc) override {FADD(frd, fra, frb, rc, false);} - void FADD(u32 frd, u32 fra, u32 frb, u32 rc, bool single) - { - SetHostRoundingMode(CPU.FPSCR.RN); - const double a = CPU.FPR[fra]; - const double b = CPU.FPR[frb]; - if(FPRdouble::IsSNaN(a) || FPRdouble::IsSNaN(b)) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - if(FPRdouble::IsNaN(a)) - { - CPU.FPR[frd] = SilenceNaN(a); - } - else if(FPRdouble::IsNaN(b)) - { - CPU.FPR[frd] = SilenceNaN(b); - } - else if(FPRdouble::IsINF(a) && FPRdouble::IsINF(b) && a != b) - { - CPU.SetFPSCRException(FPSCR_VXISI); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = FPR_NAN; - } - else - { - feclearexcept(FE_ALL_EXCEPT); - const double res = a + b; - if(single) CPU.FPR[frd] = (float)res; - else CPU.FPR[frd] = res; - CheckHostFPExceptions(); - } - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) CPU.UpdateCR1(); - } - void FSQRT(u32 frd, u32 frb, u32 rc) override {FSQRT(frd, frb, rc, false);} - void FSQRT(u32 frd, u32 frb, u32 rc, bool single) - { - SetHostRoundingMode(CPU.FPSCR.RN); - const double b = CPU.FPR[frb]; - if(FPRdouble::IsSNaN(b)) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - if(FPRdouble::IsNaN(b)) - { - CPU.FPR[frd] = SilenceNaN(b); - } - else if(b < 0.0) - { - CPU.SetFPSCRException(FPSCR_VXSQRT); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = FPR_NAN; - } - else - { - feclearexcept(FE_ALL_EXCEPT); - const double res = sqrt(b); - if(single) CPU.FPR[frd] = (float)res; - else CPU.FPR[frd] = res; - CheckHostFPExceptions(); - } - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) CPU.UpdateCR1(); - } - void FSEL(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override - { - CPU.FPR[frd] = CPU.FPR[fra] >= 0.0 ? CPU.FPR[frc] : CPU.FPR[frb]; - if(rc) CPU.UpdateCR1(); - } - void FMUL(u32 frd, u32 fra, u32 frc, u32 rc) override {FMUL(frd, fra, frc, rc, false);} - void FMUL(u32 frd, u32 fra, u32 frc, u32 rc, bool single) - { - SetHostRoundingMode(CPU.FPSCR.RN); - const double a = CPU.FPR[fra]; - const double c = CPU.FPR[frc]; - if(FPRdouble::IsSNaN(a) || FPRdouble::IsSNaN(c)) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - if(FPRdouble::IsNaN(a)) - { - CPU.FPR[frd] = SilenceNaN(a); - } - else if(FPRdouble::IsNaN(c)) - { - CPU.FPR[frd] = SilenceNaN(c); - } - else if((FPRdouble::IsINF(a) && c == 0.0) || (a == 0.0 && FPRdouble::IsINF(c))) - { - CPU.SetFPSCRException(FPSCR_VXIMZ); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = FPR_NAN; - } - else - { - feclearexcept(FE_ALL_EXCEPT); - const double res = a * c; - if(single) CPU.FPR[frd] = (float)res; - else CPU.FPR[frd] = res; - CheckHostFPExceptions(); - } - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) CPU.UpdateCR1(); - } - void FRSQRTE(u32 frd, u32 frb, u32 rc) override - { - SetHostRoundingMode(CPU.FPSCR.RN); - const double b = CPU.FPR[frb]; - if(FPRdouble::IsSNaN(b)) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - if(FPRdouble::IsNaN(b)) - { - CPU.FPR[frd] = SilenceNaN(b); - } - else if(b < 0.0) - { - CPU.SetFPSCRException(FPSCR_VXSQRT); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = FPR_NAN; - } - else if(b == 0.0) - { - CPU.SetFPSCRException(FPSCR_ZX); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if (CPU.FPSCR.ZE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = 1.0 / b; - } - else - { - feclearexcept(FE_ALL_EXCEPT); - CPU.FPR[frd] = 1.0 / sqrt(b); - CheckHostFPExceptions(); - } - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) CPU.UpdateCR1(); - } - void FMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, false, true, false);} - void FMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, false, false, false);} - void FMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc, bool neg, bool sub, bool single) - { - SetHostRoundingMode(CPU.FPSCR.RN); - const double a = CPU.FPR[fra]; - const double b = CPU.FPR[frb]; - const double c = CPU.FPR[frc]; - if(FPRdouble::IsSNaN(a) || FPRdouble::IsSNaN(b) || FPRdouble::IsSNaN(c)) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - if(FPRdouble::IsNaN(a)) - { - CPU.FPR[frd] = SilenceNaN(a); - } - else if(FPRdouble::IsNaN(b)) - { - CPU.FPR[frd] = SilenceNaN(b); - } - else if(FPRdouble::IsNaN(c)) - { - CPU.FPR[frd] = SilenceNaN(c); - } - else if((FPRdouble::IsINF(a) && c == 0.0) || (a == 0.0 && FPRdouble::IsINF(c))) - { - CPU.SetFPSCRException(FPSCR_VXIMZ); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = FPR_NAN; - } - else - { - const double res = fma(a, c, sub ? -b : b); - if(FPRdouble::IsNaN(res)) - { - CPU.SetFPSCRException(FPSCR_VXISI); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = FPR_NAN; - } - else - { - feclearexcept(FE_ALL_EXCEPT); - if(single) CPU.FPR[frd] = (float)(neg ? -res : res); - else CPU.FPR[frd] = (neg ? -res : res); - CheckHostFPExceptions(); - } - } - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) CPU.UpdateCR1(); - } - void FNMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, true, true, false);} - void FNMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, true, false, false);} - void FCMPO(u32 crfd, u32 fra, u32 frb) override - { - int cmp_res = FPRdouble::Cmp(CPU.FPR[fra], CPU.FPR[frb]); - - if(cmp_res == CR_SO) - { - if(FPRdouble::IsSNaN(CPU.FPR[fra]) || FPRdouble::IsSNaN(CPU.FPR[frb])) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - if(!CPU.FPSCR.VE) CPU.SetFPSCRException(FPSCR_VXVC); - } - else - { - CPU.SetFPSCRException(FPSCR_VXVC); - } - - CPU.FPSCR.FX = 1; - } - - CPU.FPSCR.FPRF = cmp_res; - CPU.SetCR(crfd, cmp_res); - } - void FNEG(u32 frd, u32 frb, u32 rc) override - { - CPU.FPR[frd] = -CPU.FPR[frb]; - if(rc) CPU.UpdateCR1(); - } - void FMR(u32 frd, u32 frb, u32 rc) override - { - CPU.FPR[frd] = CPU.FPR[frb]; - if(rc) CPU.UpdateCR1(); - } - void FNABS(u32 frd, u32 frb, u32 rc) override - { - CPU.FPR[frd] = -fabs(CPU.FPR[frb]); - if(rc) CPU.UpdateCR1(); - } - void FABS(u32 frd, u32 frb, u32 rc) override - { - CPU.FPR[frd] = fabs(CPU.FPR[frb]); - if(rc) CPU.UpdateCR1(); - } - void FCTID(u32 frd, u32 frb, u32 rc) override {FCTID(frd, frb, rc, false);} - void FCTID(u32 frd, u32 frb, u32 rc, bool truncate) - { - const double b = CPU.FPR[frb]; - u64 r; - if (FPRdouble::IsNaN(b) || b < -(double)0x8000000000000000) - { - CPU.SetFPSCRException(FPSCR_VXCVI); - if(FPRdouble::IsSNaN(b)) CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FI = 0; - CPU.FPSCR.FR = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - r = 0x8000000000000000; - } - else if(b >= (double)0x8000000000000000) - { - CPU.SetFPSCRException(FPSCR_VXCVI); - CPU.FPSCR.FI = 0; - CPU.FPSCR.FR = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - r = 0x7fffffffffffffff; - } - else - { - s64 i = 0; - const u32 rn = truncate ? FPSCR_RN_ZERO : CPU.FPSCR.RN; - switch(rn) - { - case FPSCR_RN_NEAR: - SetHostRoundingMode(FPSCR_RN_NEAR); - i = (s64)nearbyint(b); - break; - case FPSCR_RN_ZERO: - i = (s64)b; - break; - case FPSCR_RN_PINF: - i = (s64)ceil(b); - break; - case FPSCR_RN_MINF: - i = (s64)floor(b); - break; - } - r = (u64)i; - double di = (double)i; - if (di == b) - { - CPU.SetFPSCR_FI(0); - CPU.FPSCR.FR = 0; - } - else - { - CPU.SetFPSCR_FI(1); - CPU.FPSCR.FR = fabs(di) > fabs(b); - } - } - - (u64&)CPU.FPR[frd] = r; - if(rc) CPU.UpdateCR1(); - } - void FCTIDZ(u32 frd, u32 frb, u32 rc) override {FCTID(frd, frb, rc, true);} - void FCFID(u32 frd, u32 frb, u32 rc) override - { - s64 bi = (s64&)CPU.FPR[frb]; - double bf = (double)bi; - s64 bfi = (s64)bf; - - if(bi == bfi) - { - CPU.SetFPSCR_FI(0); - CPU.FPSCR.FR = 0; - } - else - { - CPU.SetFPSCR_FI(1); - CPU.FPSCR.FR = std::abs(bfi) > std::abs(bi); - } - - CPU.FPR[frd] = bf; - - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) CPU.UpdateCR1(); - } - - void UNK(const u32 code, const u32 opcode, const u32 gcode) override - { - throw EXCEPTION("Unknown/Illegal opcode! (0x%08x : 0x%x : 0x%x)", code, opcode, gcode); - } + static void TDI(PPUThread&, ppu_opcode_t); + static void TWI(PPUThread&, ppu_opcode_t); + static void MFVSCR(PPUThread&, ppu_opcode_t); + static void MTVSCR(PPUThread&, ppu_opcode_t); + static void VADDCUW(PPUThread&, ppu_opcode_t); + static void VADDFP(PPUThread&, ppu_opcode_t); + static void VADDSBS(PPUThread&, ppu_opcode_t); + static void VADDSHS(PPUThread&, ppu_opcode_t); + static void VADDSWS(PPUThread&, ppu_opcode_t); + static void VADDUBM(PPUThread&, ppu_opcode_t); + static void VADDUBS(PPUThread&, ppu_opcode_t); + static void VADDUHM(PPUThread&, ppu_opcode_t); + static void VADDUHS(PPUThread&, ppu_opcode_t); + static void VADDUWM(PPUThread&, ppu_opcode_t); + static void VADDUWS(PPUThread&, ppu_opcode_t); + static void VAND(PPUThread&, ppu_opcode_t); + static void VANDC(PPUThread&, ppu_opcode_t); + static void VAVGSB(PPUThread&, ppu_opcode_t); + static void VAVGSH(PPUThread&, ppu_opcode_t); + static void VAVGSW(PPUThread&, ppu_opcode_t); + static void VAVGUB(PPUThread&, ppu_opcode_t); + static void VAVGUH(PPUThread&, ppu_opcode_t); + static void VAVGUW(PPUThread&, ppu_opcode_t); + static void VCFSX(PPUThread&, ppu_opcode_t); + static void VCFUX(PPUThread&, ppu_opcode_t); + static void VCMPBFP(PPUThread&, ppu_opcode_t); + static void VCMPEQFP(PPUThread&, ppu_opcode_t); + static void VCMPEQUB(PPUThread&, ppu_opcode_t); + static void VCMPEQUH(PPUThread&, ppu_opcode_t); + static void VCMPEQUW(PPUThread&, ppu_opcode_t); + static void VCMPGEFP(PPUThread&, ppu_opcode_t); + static void VCMPGTFP(PPUThread&, ppu_opcode_t); + static void VCMPGTSB(PPUThread&, ppu_opcode_t); + static void VCMPGTSH(PPUThread&, ppu_opcode_t); + static void VCMPGTSW(PPUThread&, ppu_opcode_t); + static void VCMPGTUB(PPUThread&, ppu_opcode_t); + static void VCMPGTUH(PPUThread&, ppu_opcode_t); + static void VCMPGTUW(PPUThread&, ppu_opcode_t); + static void VCTSXS(PPUThread&, ppu_opcode_t); + static void VCTUXS(PPUThread&, ppu_opcode_t); + static void VEXPTEFP(PPUThread&, ppu_opcode_t); + static void VLOGEFP(PPUThread&, ppu_opcode_t); + static void VMADDFP(PPUThread&, ppu_opcode_t); + static void VMAXFP(PPUThread&, ppu_opcode_t); + static void VMAXSB(PPUThread&, ppu_opcode_t); + static void VMAXSH(PPUThread&, ppu_opcode_t); + static void VMAXSW(PPUThread&, ppu_opcode_t); + static void VMAXUB(PPUThread&, ppu_opcode_t); + static void VMAXUH(PPUThread&, ppu_opcode_t); + static void VMAXUW(PPUThread&, ppu_opcode_t); + static void VMHADDSHS(PPUThread&, ppu_opcode_t); + static void VMHRADDSHS(PPUThread&, ppu_opcode_t); + static void VMINFP(PPUThread&, ppu_opcode_t); + static void VMINSB(PPUThread&, ppu_opcode_t); + static void VMINSH(PPUThread&, ppu_opcode_t); + static void VMINSW(PPUThread&, ppu_opcode_t); + static void VMINUB(PPUThread&, ppu_opcode_t); + static void VMINUH(PPUThread&, ppu_opcode_t); + static void VMINUW(PPUThread&, ppu_opcode_t); + static void VMLADDUHM(PPUThread&, ppu_opcode_t); + static void VMRGHB(PPUThread&, ppu_opcode_t); + static void VMRGHH(PPUThread&, ppu_opcode_t); + static void VMRGHW(PPUThread&, ppu_opcode_t); + static void VMRGLB(PPUThread&, ppu_opcode_t); + static void VMRGLH(PPUThread&, ppu_opcode_t); + static void VMRGLW(PPUThread&, ppu_opcode_t); + static void VMSUMMBM(PPUThread&, ppu_opcode_t); + static void VMSUMSHM(PPUThread&, ppu_opcode_t); + static void VMSUMSHS(PPUThread&, ppu_opcode_t); + static void VMSUMUBM(PPUThread&, ppu_opcode_t); + static void VMSUMUHM(PPUThread&, ppu_opcode_t); + static void VMSUMUHS(PPUThread&, ppu_opcode_t); + static void VMULESB(PPUThread&, ppu_opcode_t); + static void VMULESH(PPUThread&, ppu_opcode_t); + static void VMULEUB(PPUThread&, ppu_opcode_t); + static void VMULEUH(PPUThread&, ppu_opcode_t); + static void VMULOSB(PPUThread&, ppu_opcode_t); + static void VMULOSH(PPUThread&, ppu_opcode_t); + static void VMULOUB(PPUThread&, ppu_opcode_t); + static void VMULOUH(PPUThread&, ppu_opcode_t); + static void VNMSUBFP(PPUThread&, ppu_opcode_t); + static void VNOR(PPUThread&, ppu_opcode_t); + static void VOR(PPUThread&, ppu_opcode_t); + static void VPERM(PPUThread&, ppu_opcode_t); + static void VPKPX(PPUThread&, ppu_opcode_t); + static void VPKSHSS(PPUThread&, ppu_opcode_t); + static void VPKSHUS(PPUThread&, ppu_opcode_t); + static void VPKSWSS(PPUThread&, ppu_opcode_t); + static void VPKSWUS(PPUThread&, ppu_opcode_t); + static void VPKUHUM(PPUThread&, ppu_opcode_t); + static void VPKUHUS(PPUThread&, ppu_opcode_t); + static void VPKUWUM(PPUThread&, ppu_opcode_t); + static void VPKUWUS(PPUThread&, ppu_opcode_t); + static void VREFP(PPUThread&, ppu_opcode_t); + static void VRFIM(PPUThread&, ppu_opcode_t); + static void VRFIN(PPUThread&, ppu_opcode_t); + static void VRFIP(PPUThread&, ppu_opcode_t); + static void VRFIZ(PPUThread&, ppu_opcode_t); + static void VRLB(PPUThread&, ppu_opcode_t); + static void VRLH(PPUThread&, ppu_opcode_t); + static void VRLW(PPUThread&, ppu_opcode_t); + static void VRSQRTEFP(PPUThread&, ppu_opcode_t); + static void VSEL(PPUThread&, ppu_opcode_t); + static void VSL(PPUThread&, ppu_opcode_t); + static void VSLB(PPUThread&, ppu_opcode_t); + static void VSLDOI(PPUThread&, ppu_opcode_t); + static void VSLH(PPUThread&, ppu_opcode_t); + static void VSLO(PPUThread&, ppu_opcode_t); + static void VSLW(PPUThread&, ppu_opcode_t); + static void VSPLTB(PPUThread&, ppu_opcode_t); + static void VSPLTH(PPUThread&, ppu_opcode_t); + static void VSPLTISB(PPUThread&, ppu_opcode_t); + static void VSPLTISH(PPUThread&, ppu_opcode_t); + static void VSPLTISW(PPUThread&, ppu_opcode_t); + static void VSPLTW(PPUThread&, ppu_opcode_t); + static void VSR(PPUThread&, ppu_opcode_t); + static void VSRAB(PPUThread&, ppu_opcode_t); + static void VSRAH(PPUThread&, ppu_opcode_t); + static void VSRAW(PPUThread&, ppu_opcode_t); + static void VSRB(PPUThread&, ppu_opcode_t); + static void VSRH(PPUThread&, ppu_opcode_t); + static void VSRO(PPUThread&, ppu_opcode_t); + static void VSRW(PPUThread&, ppu_opcode_t); + static void VSUBCUW(PPUThread&, ppu_opcode_t); + static void VSUBFP(PPUThread&, ppu_opcode_t); + static void VSUBSBS(PPUThread&, ppu_opcode_t); + static void VSUBSHS(PPUThread&, ppu_opcode_t); + static void VSUBSWS(PPUThread&, ppu_opcode_t); + static void VSUBUBM(PPUThread&, ppu_opcode_t); + static void VSUBUBS(PPUThread&, ppu_opcode_t); + static void VSUBUHM(PPUThread&, ppu_opcode_t); + static void VSUBUHS(PPUThread&, ppu_opcode_t); + static void VSUBUWM(PPUThread&, ppu_opcode_t); + static void VSUBUWS(PPUThread&, ppu_opcode_t); + static void VSUMSWS(PPUThread&, ppu_opcode_t); + static void VSUM2SWS(PPUThread&, ppu_opcode_t); + static void VSUM4SBS(PPUThread&, ppu_opcode_t); + static void VSUM4SHS(PPUThread&, ppu_opcode_t); + static void VSUM4UBS(PPUThread&, ppu_opcode_t); + static void VUPKHPX(PPUThread&, ppu_opcode_t); + static void VUPKHSB(PPUThread&, ppu_opcode_t); + static void VUPKHSH(PPUThread&, ppu_opcode_t); + static void VUPKLPX(PPUThread&, ppu_opcode_t); + static void VUPKLSB(PPUThread&, ppu_opcode_t); + static void VUPKLSH(PPUThread&, ppu_opcode_t); + static void VXOR(PPUThread&, ppu_opcode_t); + static void MULLI(PPUThread&, ppu_opcode_t); + static void SUBFIC(PPUThread&, ppu_opcode_t); + static void CMPLI(PPUThread&, ppu_opcode_t); + static void CMPI(PPUThread&, ppu_opcode_t); + static void ADDIC(PPUThread&, ppu_opcode_t); + static void ADDI(PPUThread&, ppu_opcode_t); + static void ADDIS(PPUThread&, ppu_opcode_t); + static void BC(PPUThread&, ppu_opcode_t); + static void HACK(PPUThread&, ppu_opcode_t); + static void SC(PPUThread&, ppu_opcode_t); + static void B(PPUThread&, ppu_opcode_t); + static void MCRF(PPUThread&, ppu_opcode_t); + static void BCLR(PPUThread&, ppu_opcode_t); + static void CRNOR(PPUThread&, ppu_opcode_t); + static void CRANDC(PPUThread&, ppu_opcode_t); + static void ISYNC(PPUThread&, ppu_opcode_t); + static void CRXOR(PPUThread&, ppu_opcode_t); + static void CRNAND(PPUThread&, ppu_opcode_t); + static void CRAND(PPUThread&, ppu_opcode_t); + static void CREQV(PPUThread&, ppu_opcode_t); + static void CRORC(PPUThread&, ppu_opcode_t); + static void CROR(PPUThread&, ppu_opcode_t); + static void BCCTR(PPUThread&, ppu_opcode_t); + static void RLWIMI(PPUThread&, ppu_opcode_t); + static void RLWINM(PPUThread&, ppu_opcode_t); + static void RLWNM(PPUThread&, ppu_opcode_t); + static void ORI(PPUThread&, ppu_opcode_t); + static void ORIS(PPUThread&, ppu_opcode_t); + static void XORI(PPUThread&, ppu_opcode_t); + static void XORIS(PPUThread&, ppu_opcode_t); + static void ANDI(PPUThread&, ppu_opcode_t); + static void ANDIS(PPUThread&, ppu_opcode_t); + static void RLDICL(PPUThread&, ppu_opcode_t); + static void RLDICR(PPUThread&, ppu_opcode_t); + static void RLDIC(PPUThread&, ppu_opcode_t); + static void RLDIMI(PPUThread&, ppu_opcode_t); + static void RLDCL(PPUThread&, ppu_opcode_t); + static void RLDCR(PPUThread&, ppu_opcode_t); + static void CMP(PPUThread&, ppu_opcode_t); + static void TW(PPUThread&, ppu_opcode_t); + static void LVSL(PPUThread&, ppu_opcode_t); + static void LVEBX(PPUThread&, ppu_opcode_t); + static void SUBFC(PPUThread&, ppu_opcode_t); + static void MULHDU(PPUThread&, ppu_opcode_t); + static void ADDC(PPUThread&, ppu_opcode_t); + static void MULHWU(PPUThread&, ppu_opcode_t); + static void MFOCRF(PPUThread&, ppu_opcode_t); + static void LWARX(PPUThread&, ppu_opcode_t); + static void LDX(PPUThread&, ppu_opcode_t); + static void LWZX(PPUThread&, ppu_opcode_t); + static void SLW(PPUThread&, ppu_opcode_t); + static void CNTLZW(PPUThread&, ppu_opcode_t); + static void SLD(PPUThread&, ppu_opcode_t); + static void AND(PPUThread&, ppu_opcode_t); + static void CMPL(PPUThread&, ppu_opcode_t); + static void LVSR(PPUThread&, ppu_opcode_t); + static void LVEHX(PPUThread&, ppu_opcode_t); + static void SUBF(PPUThread&, ppu_opcode_t); + static void LDUX(PPUThread&, ppu_opcode_t); + static void DCBST(PPUThread&, ppu_opcode_t); + static void LWZUX(PPUThread&, ppu_opcode_t); + static void CNTLZD(PPUThread&, ppu_opcode_t); + static void ANDC(PPUThread&, ppu_opcode_t); + static void TD(PPUThread&, ppu_opcode_t); + static void LVEWX(PPUThread&, ppu_opcode_t); + static void MULHD(PPUThread&, ppu_opcode_t); + static void MULHW(PPUThread&, ppu_opcode_t); + static void LDARX(PPUThread&, ppu_opcode_t); + static void DCBF(PPUThread&, ppu_opcode_t); + static void LBZX(PPUThread&, ppu_opcode_t); + static void LVX(PPUThread&, ppu_opcode_t); + static void NEG(PPUThread&, ppu_opcode_t); + static void LBZUX(PPUThread&, ppu_opcode_t); + static void NOR(PPUThread&, ppu_opcode_t); + static void STVEBX(PPUThread&, ppu_opcode_t); + static void SUBFE(PPUThread&, ppu_opcode_t); + static void ADDE(PPUThread&, ppu_opcode_t); + static void MTOCRF(PPUThread&, ppu_opcode_t); + static void STDX(PPUThread&, ppu_opcode_t); + static void STWCX(PPUThread&, ppu_opcode_t); + static void STWX(PPUThread&, ppu_opcode_t); + static void STVEHX(PPUThread&, ppu_opcode_t); + static void STDUX(PPUThread&, ppu_opcode_t); + static void STWUX(PPUThread&, ppu_opcode_t); + static void STVEWX(PPUThread&, ppu_opcode_t); + static void SUBFZE(PPUThread&, ppu_opcode_t); + static void ADDZE(PPUThread&, ppu_opcode_t); + static void STDCX(PPUThread&, ppu_opcode_t); + static void STBX(PPUThread&, ppu_opcode_t); + static void STVX(PPUThread&, ppu_opcode_t); + static void MULLD(PPUThread&, ppu_opcode_t); + static void SUBFME(PPUThread&, ppu_opcode_t); + static void ADDME(PPUThread&, ppu_opcode_t); + static void MULLW(PPUThread&, ppu_opcode_t); + static void DCBTST(PPUThread&, ppu_opcode_t); + static void STBUX(PPUThread&, ppu_opcode_t); + static void ADD(PPUThread&, ppu_opcode_t); + static void DCBT(PPUThread&, ppu_opcode_t); + static void LHZX(PPUThread&, ppu_opcode_t); + static void EQV(PPUThread&, ppu_opcode_t); + static void ECIWX(PPUThread&, ppu_opcode_t); + static void LHZUX(PPUThread&, ppu_opcode_t); + static void XOR(PPUThread&, ppu_opcode_t); + static void MFSPR(PPUThread&, ppu_opcode_t); + static void LWAX(PPUThread&, ppu_opcode_t); + static void DST(PPUThread&, ppu_opcode_t); + static void LHAX(PPUThread&, ppu_opcode_t); + static void LVXL(PPUThread&, ppu_opcode_t); + static void MFTB(PPUThread&, ppu_opcode_t); + static void LWAUX(PPUThread&, ppu_opcode_t); + static void DSTST(PPUThread&, ppu_opcode_t); + static void LHAUX(PPUThread&, ppu_opcode_t); + static void STHX(PPUThread&, ppu_opcode_t); + static void ORC(PPUThread&, ppu_opcode_t); + static void ECOWX(PPUThread&, ppu_opcode_t); + static void STHUX(PPUThread&, ppu_opcode_t); + static void OR(PPUThread&, ppu_opcode_t); + static void DIVDU(PPUThread&, ppu_opcode_t); + static void DIVWU(PPUThread&, ppu_opcode_t); + static void MTSPR(PPUThread&, ppu_opcode_t); + static void DCBI(PPUThread&, ppu_opcode_t); + static void NAND(PPUThread&, ppu_opcode_t); + static void STVXL(PPUThread&, ppu_opcode_t); + static void DIVD(PPUThread&, ppu_opcode_t); + static void DIVW(PPUThread&, ppu_opcode_t); + static void LVLX(PPUThread&, ppu_opcode_t); + static void LDBRX(PPUThread&, ppu_opcode_t); + static void LSWX(PPUThread&, ppu_opcode_t); + static void LWBRX(PPUThread&, ppu_opcode_t); + static void LFSX(PPUThread&, ppu_opcode_t); + static void SRW(PPUThread&, ppu_opcode_t); + static void SRD(PPUThread&, ppu_opcode_t); + static void LVRX(PPUThread&, ppu_opcode_t); + static void LSWI(PPUThread&, ppu_opcode_t); + static void LFSUX(PPUThread&, ppu_opcode_t); + static void SYNC(PPUThread&, ppu_opcode_t); + static void LFDX(PPUThread&, ppu_opcode_t); + static void LFDUX(PPUThread&, ppu_opcode_t); + static void STVLX(PPUThread&, ppu_opcode_t); + static void STDBRX(PPUThread&, ppu_opcode_t); + static void STSWX(PPUThread&, ppu_opcode_t); + static void STWBRX(PPUThread&, ppu_opcode_t); + static void STFSX(PPUThread&, ppu_opcode_t); + static void STVRX(PPUThread&, ppu_opcode_t); + static void STFSUX(PPUThread&, ppu_opcode_t); + static void STSWI(PPUThread&, ppu_opcode_t); + static void STFDX(PPUThread&, ppu_opcode_t); + static void STFDUX(PPUThread&, ppu_opcode_t); + static void LVLXL(PPUThread&, ppu_opcode_t); + static void LHBRX(PPUThread&, ppu_opcode_t); + static void SRAW(PPUThread&, ppu_opcode_t); + static void SRAD(PPUThread&, ppu_opcode_t); + static void LVRXL(PPUThread&, ppu_opcode_t); + static void DSS(PPUThread&, ppu_opcode_t); + static void SRAWI(PPUThread&, ppu_opcode_t); + static void SRADI(PPUThread&, ppu_opcode_t); + static void EIEIO(PPUThread&, ppu_opcode_t); + static void STVLXL(PPUThread&, ppu_opcode_t); + static void STHBRX(PPUThread&, ppu_opcode_t); + static void EXTSH(PPUThread&, ppu_opcode_t); + static void STVRXL(PPUThread&, ppu_opcode_t); + static void EXTSB(PPUThread&, ppu_opcode_t); + static void STFIWX(PPUThread&, ppu_opcode_t); + static void EXTSW(PPUThread&, ppu_opcode_t); + static void ICBI(PPUThread&, ppu_opcode_t); + static void DCBZ(PPUThread&, ppu_opcode_t); + static void LWZ(PPUThread&, ppu_opcode_t); + static void LWZU(PPUThread&, ppu_opcode_t); + static void LBZ(PPUThread&, ppu_opcode_t); + static void LBZU(PPUThread&, ppu_opcode_t); + static void STW(PPUThread&, ppu_opcode_t); + static void STWU(PPUThread&, ppu_opcode_t); + static void STB(PPUThread&, ppu_opcode_t); + static void STBU(PPUThread&, ppu_opcode_t); + static void LHZ(PPUThread&, ppu_opcode_t); + static void LHZU(PPUThread&, ppu_opcode_t); + static void LHA(PPUThread&, ppu_opcode_t); + static void LHAU(PPUThread&, ppu_opcode_t); + static void STH(PPUThread&, ppu_opcode_t); + static void STHU(PPUThread&, ppu_opcode_t); + static void LMW(PPUThread&, ppu_opcode_t); + static void STMW(PPUThread&, ppu_opcode_t); + static void LFS(PPUThread&, ppu_opcode_t); + static void LFSU(PPUThread&, ppu_opcode_t); + static void LFD(PPUThread&, ppu_opcode_t); + static void LFDU(PPUThread&, ppu_opcode_t); + static void STFS(PPUThread&, ppu_opcode_t); + static void STFSU(PPUThread&, ppu_opcode_t); + static void STFD(PPUThread&, ppu_opcode_t); + static void STFDU(PPUThread&, ppu_opcode_t); + static void LD(PPUThread&, ppu_opcode_t); + static void LDU(PPUThread&, ppu_opcode_t); + static void LWA(PPUThread&, ppu_opcode_t); + static void FDIVS(PPUThread&, ppu_opcode_t); + static void FSUBS(PPUThread&, ppu_opcode_t); + static void FADDS(PPUThread&, ppu_opcode_t); + static void FSQRTS(PPUThread&, ppu_opcode_t); + static void FRES(PPUThread&, ppu_opcode_t); + static void FMULS(PPUThread&, ppu_opcode_t); + static void FMADDS(PPUThread&, ppu_opcode_t); + static void FMSUBS(PPUThread&, ppu_opcode_t); + static void FNMSUBS(PPUThread&, ppu_opcode_t); + static void FNMADDS(PPUThread&, ppu_opcode_t); + static void STD(PPUThread&, ppu_opcode_t); + static void STDU(PPUThread&, ppu_opcode_t); + static void MTFSB1(PPUThread&, ppu_opcode_t); + static void MCRFS(PPUThread&, ppu_opcode_t); + static void MTFSB0(PPUThread&, ppu_opcode_t); + static void MTFSFI(PPUThread&, ppu_opcode_t); + static void MFFS(PPUThread&, ppu_opcode_t); + static void MTFSF(PPUThread&, ppu_opcode_t); + static void FCMPU(PPUThread&, ppu_opcode_t); + static void FRSP(PPUThread&, ppu_opcode_t); + static void FCTIW(PPUThread&, ppu_opcode_t); + static void FCTIWZ(PPUThread&, ppu_opcode_t); + static void FDIV(PPUThread&, ppu_opcode_t); + static void FSUB(PPUThread&, ppu_opcode_t); + static void FADD(PPUThread&, ppu_opcode_t); + static void FSQRT(PPUThread&, ppu_opcode_t); + static void FSEL(PPUThread&, ppu_opcode_t); + static void FMUL(PPUThread&, ppu_opcode_t); + static void FRSQRTE(PPUThread&, ppu_opcode_t); + static void FMSUB(PPUThread&, ppu_opcode_t); + static void FMADD(PPUThread&, ppu_opcode_t); + static void FNMSUB(PPUThread&, ppu_opcode_t); + static void FNMADD(PPUThread&, ppu_opcode_t); + static void FCMPO(PPUThread&, ppu_opcode_t); + static void FNEG(PPUThread&, ppu_opcode_t); + static void FMR(PPUThread&, ppu_opcode_t); + static void FNABS(PPUThread&, ppu_opcode_t); + static void FABS(PPUThread&, ppu_opcode_t); + static void FCTID(PPUThread&, ppu_opcode_t); + static void FCTIDZ(PPUThread&, ppu_opcode_t); + static void FCFID(PPUThread&, ppu_opcode_t); + + static void UNK(PPUThread&, ppu_opcode_t); +}; + +struct ppu_interpreter_precise final : ppu_interpreter +{ + // TODO +}; + +struct ppu_interpreter_fast final : ppu_interpreter +{ + // TODO }; diff --git a/rpcs3/Emu/Cell/PPUInterpreter2.h b/rpcs3/Emu/Cell/PPUInterpreter2.h deleted file mode 100644 index 051c70b3dd..0000000000 --- a/rpcs3/Emu/Cell/PPUInterpreter2.h +++ /dev/null @@ -1,870 +0,0 @@ -#pragma once - -#include "PPUOpcodes.h" - -class PPUThread; - -union ppu_opcode_t -{ - u32 opcode; - - bf_t shh; // 30 - bf_t mbmeh; // 26 - bf_t mbmel; // 21..25 - bf_t shl; // 16..20 - bf_t vuimm; // 11..15 - bf_t vs; // 6..10 - bf_t vsh; // 22..25 - bf_t oe; // 21 - bf_t spr; // 11..20 - bf_t vc; // 21..25 - bf_t vb; // 16..20 - bf_t va; // 11..15 - bf_t vd; // 6..10 - bf_t lk; // 31 - bf_t aa; // 30 - bf_t rb; // 16..20 - bf_t ra; // 11..15 - bf_t rd; // 6..10 - bf_t uimm16; // 16..31 - bf_t l11; // 11 - bf_t rs; // 6..10 - bf_t simm16; // 16..31, signed - bf_t vsimm; // 11..15, signed - bf_t ll; // 6..31, signed - bf_t lev; // 20..26 - bf_t i; // 16..19 - bf_t crfs; // 11..13 - bf_t l10; // 10 - bf_t crfd; // 6..8 - bf_t crbb; // 16..20 - bf_t crba; // 11..15 - bf_t crbd; // 6..10 - bf_t rc; // 31 - bf_t me; // 26..30 - bf_t mb; // 21..25 - bf_t sh; // 16..20 - bf_t bi; // 11..15 - bf_t bo; // 6..10 - bf_t frc; // 21..25 - bf_t frb; // 16..20 - bf_t fra; // 11..15 - bf_t frd; // 6..10 - bf_t crm; // 12..19 - bf_t frs; // 6..10 - bf_t flm; // 7..14 -}; - -namespace ppu_interpreter -{ - void NULL_OP(PPUThread& CPU, ppu_opcode_t op); - void NOP(PPUThread& CPU, ppu_opcode_t op); - - void TDI(PPUThread& CPU, ppu_opcode_t op); - void TWI(PPUThread& CPU, ppu_opcode_t op); - - void MFVSCR(PPUThread& CPU, ppu_opcode_t op); - void MTVSCR(PPUThread& CPU, ppu_opcode_t op); - void VADDCUW(PPUThread& CPU, ppu_opcode_t op); - void VADDFP(PPUThread& CPU, ppu_opcode_t op); - void VADDSBS(PPUThread& CPU, ppu_opcode_t op); - void VADDSHS(PPUThread& CPU, ppu_opcode_t op); - void VADDSWS(PPUThread& CPU, ppu_opcode_t op); - void VADDUBM(PPUThread& CPU, ppu_opcode_t op); - void VADDUBS(PPUThread& CPU, ppu_opcode_t op); - void VADDUHM(PPUThread& CPU, ppu_opcode_t op); - void VADDUHS(PPUThread& CPU, ppu_opcode_t op); - void VADDUWM(PPUThread& CPU, ppu_opcode_t op); - void VADDUWS(PPUThread& CPU, ppu_opcode_t op); - void VAND(PPUThread& CPU, ppu_opcode_t op); - void VANDC(PPUThread& CPU, ppu_opcode_t op); - void VAVGSB(PPUThread& CPU, ppu_opcode_t op); - void VAVGSH(PPUThread& CPU, ppu_opcode_t op); - void VAVGSW(PPUThread& CPU, ppu_opcode_t op); - void VAVGUB(PPUThread& CPU, ppu_opcode_t op); - void VAVGUH(PPUThread& CPU, ppu_opcode_t op); - void VAVGUW(PPUThread& CPU, ppu_opcode_t op); - void VCFSX(PPUThread& CPU, ppu_opcode_t op); - void VCFUX(PPUThread& CPU, ppu_opcode_t op); - void VCMPBFP(PPUThread& CPU, ppu_opcode_t op); - void VCMPBFP_(PPUThread& CPU, ppu_opcode_t op); - void VCMPEQFP(PPUThread& CPU, ppu_opcode_t op); - void VCMPEQFP_(PPUThread& CPU, ppu_opcode_t op); - void VCMPEQUB(PPUThread& CPU, ppu_opcode_t op); - void VCMPEQUB_(PPUThread& CPU, ppu_opcode_t op); - void VCMPEQUH(PPUThread& CPU, ppu_opcode_t op); - void VCMPEQUH_(PPUThread& CPU, ppu_opcode_t op); - void VCMPEQUW(PPUThread& CPU, ppu_opcode_t op); - void VCMPEQUW_(PPUThread& CPU, ppu_opcode_t op); - void VCMPGEFP(PPUThread& CPU, ppu_opcode_t op); - void VCMPGEFP_(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTFP(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTFP_(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTSB(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTSB_(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTSH(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTSH_(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTSW(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTSW_(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTUB(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTUB_(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTUH(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTUH_(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTUW(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTUW_(PPUThread& CPU, ppu_opcode_t op); - void VCTSXS(PPUThread& CPU, ppu_opcode_t op); - void VCTUXS(PPUThread& CPU, ppu_opcode_t op); - void VEXPTEFP(PPUThread& CPU, ppu_opcode_t op); - void VLOGEFP(PPUThread& CPU, ppu_opcode_t op); - void VMADDFP(PPUThread& CPU, ppu_opcode_t op); - void VMAXFP(PPUThread& CPU, ppu_opcode_t op); - void VMAXSB(PPUThread& CPU, ppu_opcode_t op); - void VMAXSH(PPUThread& CPU, ppu_opcode_t op); - void VMAXSW(PPUThread& CPU, ppu_opcode_t op); - void VMAXUB(PPUThread& CPU, ppu_opcode_t op); - void VMAXUH(PPUThread& CPU, ppu_opcode_t op); - void VMAXUW(PPUThread& CPU, ppu_opcode_t op); - void VMHADDSHS(PPUThread& CPU, ppu_opcode_t op); - void VMHRADDSHS(PPUThread& CPU, ppu_opcode_t op); - void VMINFP(PPUThread& CPU, ppu_opcode_t op); - void VMINSB(PPUThread& CPU, ppu_opcode_t op); - void VMINSH(PPUThread& CPU, ppu_opcode_t op); - void VMINSW(PPUThread& CPU, ppu_opcode_t op); - void VMINUB(PPUThread& CPU, ppu_opcode_t op); - void VMINUH(PPUThread& CPU, ppu_opcode_t op); - void VMINUW(PPUThread& CPU, ppu_opcode_t op); - void VMLADDUHM(PPUThread& CPU, ppu_opcode_t op); - void VMRGHB(PPUThread& CPU, ppu_opcode_t op); - void VMRGHH(PPUThread& CPU, ppu_opcode_t op); - void VMRGHW(PPUThread& CPU, ppu_opcode_t op); - void VMRGLB(PPUThread& CPU, ppu_opcode_t op); - void VMRGLH(PPUThread& CPU, ppu_opcode_t op); - void VMRGLW(PPUThread& CPU, ppu_opcode_t op); - void VMSUMMBM(PPUThread& CPU, ppu_opcode_t op); - void VMSUMSHM(PPUThread& CPU, ppu_opcode_t op); - void VMSUMSHS(PPUThread& CPU, ppu_opcode_t op); - void VMSUMUBM(PPUThread& CPU, ppu_opcode_t op); - void VMSUMUHM(PPUThread& CPU, ppu_opcode_t op); - void VMSUMUHS(PPUThread& CPU, ppu_opcode_t op); - void VMULESB(PPUThread& CPU, ppu_opcode_t op); - void VMULESH(PPUThread& CPU, ppu_opcode_t op); - void VMULEUB(PPUThread& CPU, ppu_opcode_t op); - void VMULEUH(PPUThread& CPU, ppu_opcode_t op); - void VMULOSB(PPUThread& CPU, ppu_opcode_t op); - void VMULOSH(PPUThread& CPU, ppu_opcode_t op); - void VMULOUB(PPUThread& CPU, ppu_opcode_t op); - void VMULOUH(PPUThread& CPU, ppu_opcode_t op); - void VNMSUBFP(PPUThread& CPU, ppu_opcode_t op); - void VNOR(PPUThread& CPU, ppu_opcode_t op); - void VOR(PPUThread& CPU, ppu_opcode_t op); - void VPERM(PPUThread& CPU, ppu_opcode_t op); - void VPKPX(PPUThread& CPU, ppu_opcode_t op); - void VPKSHSS(PPUThread& CPU, ppu_opcode_t op); - void VPKSHUS(PPUThread& CPU, ppu_opcode_t op); - void VPKSWSS(PPUThread& CPU, ppu_opcode_t op); - void VPKSWUS(PPUThread& CPU, ppu_opcode_t op); - void VPKUHUM(PPUThread& CPU, ppu_opcode_t op); - void VPKUHUS(PPUThread& CPU, ppu_opcode_t op); - void VPKUWUM(PPUThread& CPU, ppu_opcode_t op); - void VPKUWUS(PPUThread& CPU, ppu_opcode_t op); - void VREFP(PPUThread& CPU, ppu_opcode_t op); - void VRFIM(PPUThread& CPU, ppu_opcode_t op); - void VRFIN(PPUThread& CPU, ppu_opcode_t op); - void VRFIP(PPUThread& CPU, ppu_opcode_t op); - void VRFIZ(PPUThread& CPU, ppu_opcode_t op); - void VRLB(PPUThread& CPU, ppu_opcode_t op); - void VRLH(PPUThread& CPU, ppu_opcode_t op); - void VRLW(PPUThread& CPU, ppu_opcode_t op); - void VRSQRTEFP(PPUThread& CPU, ppu_opcode_t op); - void VSEL(PPUThread& CPU, ppu_opcode_t op); - void VSL(PPUThread& CPU, ppu_opcode_t op); - void VSLB(PPUThread& CPU, ppu_opcode_t op); - void VSLDOI(PPUThread& CPU, ppu_opcode_t op); - void VSLH(PPUThread& CPU, ppu_opcode_t op); - void VSLO(PPUThread& CPU, ppu_opcode_t op); - void VSLW(PPUThread& CPU, ppu_opcode_t op); - void VSPLTB(PPUThread& CPU, ppu_opcode_t op); - void VSPLTH(PPUThread& CPU, ppu_opcode_t op); - void VSPLTISB(PPUThread& CPU, ppu_opcode_t op); - void VSPLTISH(PPUThread& CPU, ppu_opcode_t op); - void VSPLTISW(PPUThread& CPU, ppu_opcode_t op); - void VSPLTW(PPUThread& CPU, ppu_opcode_t op); - void VSR(PPUThread& CPU, ppu_opcode_t op); - void VSRAB(PPUThread& CPU, ppu_opcode_t op); - void VSRAH(PPUThread& CPU, ppu_opcode_t op); - void VSRAW(PPUThread& CPU, ppu_opcode_t op); - void VSRB(PPUThread& CPU, ppu_opcode_t op); - void VSRH(PPUThread& CPU, ppu_opcode_t op); - void VSRO(PPUThread& CPU, ppu_opcode_t op); - void VSRW(PPUThread& CPU, ppu_opcode_t op); - void VSUBCUW(PPUThread& CPU, ppu_opcode_t op); - void VSUBFP(PPUThread& CPU, ppu_opcode_t op); - void VSUBSBS(PPUThread& CPU, ppu_opcode_t op); - void VSUBSHS(PPUThread& CPU, ppu_opcode_t op); - void VSUBSWS(PPUThread& CPU, ppu_opcode_t op); - void VSUBUBM(PPUThread& CPU, ppu_opcode_t op); - void VSUBUBS(PPUThread& CPU, ppu_opcode_t op); - void VSUBUHM(PPUThread& CPU, ppu_opcode_t op); - void VSUBUHS(PPUThread& CPU, ppu_opcode_t op); - void VSUBUWM(PPUThread& CPU, ppu_opcode_t op); - void VSUBUWS(PPUThread& CPU, ppu_opcode_t op); - void VSUMSWS(PPUThread& CPU, ppu_opcode_t op); - void VSUM2SWS(PPUThread& CPU, ppu_opcode_t op); - void VSUM4SBS(PPUThread& CPU, ppu_opcode_t op); - void VSUM4SHS(PPUThread& CPU, ppu_opcode_t op); - void VSUM4UBS(PPUThread& CPU, ppu_opcode_t op); - void VUPKHPX(PPUThread& CPU, ppu_opcode_t op); - void VUPKHSB(PPUThread& CPU, ppu_opcode_t op); - void VUPKHSH(PPUThread& CPU, ppu_opcode_t op); - void VUPKLPX(PPUThread& CPU, ppu_opcode_t op); - void VUPKLSB(PPUThread& CPU, ppu_opcode_t op); - void VUPKLSH(PPUThread& CPU, ppu_opcode_t op); - void VXOR(PPUThread& CPU, ppu_opcode_t op); - void MULLI(PPUThread& CPU, ppu_opcode_t op); - void SUBFIC(PPUThread& CPU, ppu_opcode_t op); - void CMPLI(PPUThread& CPU, ppu_opcode_t op); - void CMPI(PPUThread& CPU, ppu_opcode_t op); - void ADDIC(PPUThread& CPU, ppu_opcode_t op); - void ADDIC_(PPUThread& CPU, ppu_opcode_t op); - void ADDI(PPUThread& CPU, ppu_opcode_t op); - void ADDIS(PPUThread& CPU, ppu_opcode_t op); - void BC(PPUThread& CPU, ppu_opcode_t op); - void HACK(PPUThread& CPU, ppu_opcode_t op); - void SC(PPUThread& CPU, ppu_opcode_t op); - void B(PPUThread& CPU, ppu_opcode_t op); - void MCRF(PPUThread& CPU, ppu_opcode_t op); - void BCLR(PPUThread& CPU, ppu_opcode_t op); - void CRNOR(PPUThread& CPU, ppu_opcode_t op); - void CRANDC(PPUThread& CPU, ppu_opcode_t op); - void ISYNC(PPUThread& CPU, ppu_opcode_t op); - void CRXOR(PPUThread& CPU, ppu_opcode_t op); - void CRNAND(PPUThread& CPU, ppu_opcode_t op); - void CRAND(PPUThread& CPU, ppu_opcode_t op); - void CREQV(PPUThread& CPU, ppu_opcode_t op); - void CRORC(PPUThread& CPU, ppu_opcode_t op); - void CROR(PPUThread& CPU, ppu_opcode_t op); - void BCCTR(PPUThread& CPU, ppu_opcode_t op); - void RLWIMI(PPUThread& CPU, ppu_opcode_t op); - void RLWINM(PPUThread& CPU, ppu_opcode_t op); - void RLWNM(PPUThread& CPU, ppu_opcode_t op); - void ORI(PPUThread& CPU, ppu_opcode_t op); - void ORIS(PPUThread& CPU, ppu_opcode_t op); - void XORI(PPUThread& CPU, ppu_opcode_t op); - void XORIS(PPUThread& CPU, ppu_opcode_t op); - void ANDI_(PPUThread& CPU, ppu_opcode_t op); - void ANDIS_(PPUThread& CPU, ppu_opcode_t op); - void RLDICL(PPUThread& CPU, ppu_opcode_t op); - void RLDICR(PPUThread& CPU, ppu_opcode_t op); - void RLDIC(PPUThread& CPU, ppu_opcode_t op); - void RLDIMI(PPUThread& CPU, ppu_opcode_t op); - void RLDC_LR(PPUThread& CPU, ppu_opcode_t op); - void CMP(PPUThread& CPU, ppu_opcode_t op); - void TW(PPUThread& CPU, ppu_opcode_t op); - void LVSL(PPUThread& CPU, ppu_opcode_t op); - void LVEBX(PPUThread& CPU, ppu_opcode_t op); - void SUBFC(PPUThread& CPU, ppu_opcode_t op); - void MULHDU(PPUThread& CPU, ppu_opcode_t op); - void ADDC(PPUThread& CPU, ppu_opcode_t op); - void MULHWU(PPUThread& CPU, ppu_opcode_t op); - void MFOCRF(PPUThread& CPU, ppu_opcode_t op); - void LWARX(PPUThread& CPU, ppu_opcode_t op); - void LDX(PPUThread& CPU, ppu_opcode_t op); - void LWZX(PPUThread& CPU, ppu_opcode_t op); - void SLW(PPUThread& CPU, ppu_opcode_t op); - void CNTLZW(PPUThread& CPU, ppu_opcode_t op); - void SLD(PPUThread& CPU, ppu_opcode_t op); - void AND(PPUThread& CPU, ppu_opcode_t op); - void CMPL(PPUThread& CPU, ppu_opcode_t op); - void LVSR(PPUThread& CPU, ppu_opcode_t op); - void LVEHX(PPUThread& CPU, ppu_opcode_t op); - void SUBF(PPUThread& CPU, ppu_opcode_t op); - void LDUX(PPUThread& CPU, ppu_opcode_t op); - void DCBST(PPUThread& CPU, ppu_opcode_t op); - void LWZUX(PPUThread& CPU, ppu_opcode_t op); - void CNTLZD(PPUThread& CPU, ppu_opcode_t op); - void ANDC(PPUThread& CPU, ppu_opcode_t op); - void TD(PPUThread& CPU, ppu_opcode_t op); - void LVEWX(PPUThread& CPU, ppu_opcode_t op); - void MULHD(PPUThread& CPU, ppu_opcode_t op); - void MULHW(PPUThread& CPU, ppu_opcode_t op); - void LDARX(PPUThread& CPU, ppu_opcode_t op); - void DCBF(PPUThread& CPU, ppu_opcode_t op); - void LBZX(PPUThread& CPU, ppu_opcode_t op); - void LVX(PPUThread& CPU, ppu_opcode_t op); - void NEG(PPUThread& CPU, ppu_opcode_t op); - void LBZUX(PPUThread& CPU, ppu_opcode_t op); - void NOR(PPUThread& CPU, ppu_opcode_t op); - void STVEBX(PPUThread& CPU, ppu_opcode_t op); - void SUBFE(PPUThread& CPU, ppu_opcode_t op); - void ADDE(PPUThread& CPU, ppu_opcode_t op); - void MTOCRF(PPUThread& CPU, ppu_opcode_t op); - void STDX(PPUThread& CPU, ppu_opcode_t op); - void STWCX_(PPUThread& CPU, ppu_opcode_t op); - void STWX(PPUThread& CPU, ppu_opcode_t op); - void STVEHX(PPUThread& CPU, ppu_opcode_t op); - void STDUX(PPUThread& CPU, ppu_opcode_t op); - void STWUX(PPUThread& CPU, ppu_opcode_t op); - void STVEWX(PPUThread& CPU, ppu_opcode_t op); - void SUBFZE(PPUThread& CPU, ppu_opcode_t op); - void ADDZE(PPUThread& CPU, ppu_opcode_t op); - void STDCX_(PPUThread& CPU, ppu_opcode_t op); - void STBX(PPUThread& CPU, ppu_opcode_t op); - void STVX(PPUThread& CPU, ppu_opcode_t op); - void MULLD(PPUThread& CPU, ppu_opcode_t op); - void SUBFME(PPUThread& CPU, ppu_opcode_t op); - void ADDME(PPUThread& CPU, ppu_opcode_t op); - void MULLW(PPUThread& CPU, ppu_opcode_t op); - void DCBTST(PPUThread& CPU, ppu_opcode_t op); - void STBUX(PPUThread& CPU, ppu_opcode_t op); - void ADD(PPUThread& CPU, ppu_opcode_t op); - void DCBT(PPUThread& CPU, ppu_opcode_t op); - void LHZX(PPUThread& CPU, ppu_opcode_t op); - void EQV(PPUThread& CPU, ppu_opcode_t op); - void ECIWX(PPUThread& CPU, ppu_opcode_t op); - void LHZUX(PPUThread& CPU, ppu_opcode_t op); - void XOR(PPUThread& CPU, ppu_opcode_t op); - void MFSPR(PPUThread& CPU, ppu_opcode_t op); - void LWAX(PPUThread& CPU, ppu_opcode_t op); - void DST(PPUThread& CPU, ppu_opcode_t op); - void LHAX(PPUThread& CPU, ppu_opcode_t op); - void LVXL(PPUThread& CPU, ppu_opcode_t op); - void MFTB(PPUThread& CPU, ppu_opcode_t op); - void LWAUX(PPUThread& CPU, ppu_opcode_t op); - void DSTST(PPUThread& CPU, ppu_opcode_t op); - void LHAUX(PPUThread& CPU, ppu_opcode_t op); - void STHX(PPUThread& CPU, ppu_opcode_t op); - void ORC(PPUThread& CPU, ppu_opcode_t op); - void ECOWX(PPUThread& CPU, ppu_opcode_t op); - void STHUX(PPUThread& CPU, ppu_opcode_t op); - void OR(PPUThread& CPU, ppu_opcode_t op); - void DIVDU(PPUThread& CPU, ppu_opcode_t op); - void DIVWU(PPUThread& CPU, ppu_opcode_t op); - void MTSPR(PPUThread& CPU, ppu_opcode_t op); - void DCBI(PPUThread& CPU, ppu_opcode_t op); - void NAND(PPUThread& CPU, ppu_opcode_t op); - void STVXL(PPUThread& CPU, ppu_opcode_t op); - void DIVD(PPUThread& CPU, ppu_opcode_t op); - void DIVW(PPUThread& CPU, ppu_opcode_t op); - void LVLX(PPUThread& CPU, ppu_opcode_t op); - void LDBRX(PPUThread& CPU, ppu_opcode_t op); - void LSWX(PPUThread& CPU, ppu_opcode_t op); - void LWBRX(PPUThread& CPU, ppu_opcode_t op); - void LFSX(PPUThread& CPU, ppu_opcode_t op); - void SRW(PPUThread& CPU, ppu_opcode_t op); - void SRD(PPUThread& CPU, ppu_opcode_t op); - void LVRX(PPUThread& CPU, ppu_opcode_t op); - void LSWI(PPUThread& CPU, ppu_opcode_t op); - void LFSUX(PPUThread& CPU, ppu_opcode_t op); - void SYNC(PPUThread& CPU, ppu_opcode_t op); - void LFDX(PPUThread& CPU, ppu_opcode_t op); - void LFDUX(PPUThread& CPU, ppu_opcode_t op); - void STVLX(PPUThread& CPU, ppu_opcode_t op); - void STDBRX(PPUThread& CPU, ppu_opcode_t op); - void STSWX(PPUThread& CPU, ppu_opcode_t op); - void STWBRX(PPUThread& CPU, ppu_opcode_t op); - void STFSX(PPUThread& CPU, ppu_opcode_t op); - void STVRX(PPUThread& CPU, ppu_opcode_t op); - void STFSUX(PPUThread& CPU, ppu_opcode_t op); - void STSWI(PPUThread& CPU, ppu_opcode_t op); - void STFDX(PPUThread& CPU, ppu_opcode_t op); - void STFDUX(PPUThread& CPU, ppu_opcode_t op); - void LVLXL(PPUThread& CPU, ppu_opcode_t op); - void LHBRX(PPUThread& CPU, ppu_opcode_t op); - void SRAW(PPUThread& CPU, ppu_opcode_t op); - void SRAD(PPUThread& CPU, ppu_opcode_t op); - void LVRXL(PPUThread& CPU, ppu_opcode_t op); - void DSS(PPUThread& CPU, ppu_opcode_t op); - void SRAWI(PPUThread& CPU, ppu_opcode_t op); - void SRADI(PPUThread& CPU, ppu_opcode_t op); - void EIEIO(PPUThread& CPU, ppu_opcode_t op); - void STVLXL(PPUThread& CPU, ppu_opcode_t op); - void STHBRX(PPUThread& CPU, ppu_opcode_t op); - void EXTSH(PPUThread& CPU, ppu_opcode_t op); - void STVRXL(PPUThread& CPU, ppu_opcode_t op); - void EXTSB(PPUThread& CPU, ppu_opcode_t op); - void STFIWX(PPUThread& CPU, ppu_opcode_t op); - void EXTSW(PPUThread& CPU, ppu_opcode_t op); - void ICBI(PPUThread& CPU, ppu_opcode_t op); - void DCBZ(PPUThread& CPU, ppu_opcode_t op); - void LWZ(PPUThread& CPU, ppu_opcode_t op); - void LWZU(PPUThread& CPU, ppu_opcode_t op); - void LBZ(PPUThread& CPU, ppu_opcode_t op); - void LBZU(PPUThread& CPU, ppu_opcode_t op); - void STW(PPUThread& CPU, ppu_opcode_t op); - void STWU(PPUThread& CPU, ppu_opcode_t op); - void STB(PPUThread& CPU, ppu_opcode_t op); - void STBU(PPUThread& CPU, ppu_opcode_t op); - void LHZ(PPUThread& CPU, ppu_opcode_t op); - void LHZU(PPUThread& CPU, ppu_opcode_t op); - void LHA(PPUThread& CPU, ppu_opcode_t op); - void LHAU(PPUThread& CPU, ppu_opcode_t op); - void STH(PPUThread& CPU, ppu_opcode_t op); - void STHU(PPUThread& CPU, ppu_opcode_t op); - void LMW(PPUThread& CPU, ppu_opcode_t op); - void STMW(PPUThread& CPU, ppu_opcode_t op); - void LFS(PPUThread& CPU, ppu_opcode_t op); - void LFSU(PPUThread& CPU, ppu_opcode_t op); - void LFD(PPUThread& CPU, ppu_opcode_t op); - void LFDU(PPUThread& CPU, ppu_opcode_t op); - void STFS(PPUThread& CPU, ppu_opcode_t op); - void STFSU(PPUThread& CPU, ppu_opcode_t op); - void STFD(PPUThread& CPU, ppu_opcode_t op); - void STFDU(PPUThread& CPU, ppu_opcode_t op); - void LD(PPUThread& CPU, ppu_opcode_t op); - void LDU(PPUThread& CPU, ppu_opcode_t op); - void LWA(PPUThread& CPU, ppu_opcode_t op); - void FDIVS(PPUThread& CPU, ppu_opcode_t op); - void FSUBS(PPUThread& CPU, ppu_opcode_t op); - void FADDS(PPUThread& CPU, ppu_opcode_t op); - void FSQRTS(PPUThread& CPU, ppu_opcode_t op); - void FRES(PPUThread& CPU, ppu_opcode_t op); - void FMULS(PPUThread& CPU, ppu_opcode_t op); - void FMADDS(PPUThread& CPU, ppu_opcode_t op); - void FMSUBS(PPUThread& CPU, ppu_opcode_t op); - void FNMSUBS(PPUThread& CPU, ppu_opcode_t op); - void FNMADDS(PPUThread& CPU, ppu_opcode_t op); - void STD(PPUThread& CPU, ppu_opcode_t op); - void STDU(PPUThread& CPU, ppu_opcode_t op); - void MTFSB1(PPUThread& CPU, ppu_opcode_t op); - void MCRFS(PPUThread& CPU, ppu_opcode_t op); - void MTFSB0(PPUThread& CPU, ppu_opcode_t op); - void MTFSFI(PPUThread& CPU, ppu_opcode_t op); - void MFFS(PPUThread& CPU, ppu_opcode_t op); - void MTFSF(PPUThread& CPU, ppu_opcode_t op); - - void FCMPU(PPUThread& CPU, ppu_opcode_t op); - void FRSP(PPUThread& CPU, ppu_opcode_t op); - void FCTIW(PPUThread& CPU, ppu_opcode_t op); - void FCTIWZ(PPUThread& CPU, ppu_opcode_t op); - void FDIV(PPUThread& CPU, ppu_opcode_t op); - void FSUB(PPUThread& CPU, ppu_opcode_t op); - void FADD(PPUThread& CPU, ppu_opcode_t op); - void FSQRT(PPUThread& CPU, ppu_opcode_t op); - void FSEL(PPUThread& CPU, ppu_opcode_t op); - void FMUL(PPUThread& CPU, ppu_opcode_t op); - void FRSQRTE(PPUThread& CPU, ppu_opcode_t op); - void FMSUB(PPUThread& CPU, ppu_opcode_t op); - void FMADD(PPUThread& CPU, ppu_opcode_t op); - void FNMSUB(PPUThread& CPU, ppu_opcode_t op); - void FNMADD(PPUThread& CPU, ppu_opcode_t op); - void FCMPO(PPUThread& CPU, ppu_opcode_t op); - void FNEG(PPUThread& CPU, ppu_opcode_t op); - void FMR(PPUThread& CPU, ppu_opcode_t op); - void FNABS(PPUThread& CPU, ppu_opcode_t op); - void FABS(PPUThread& CPU, ppu_opcode_t op); - void FCTID(PPUThread& CPU, ppu_opcode_t op); - void FCTIDZ(PPUThread& CPU, ppu_opcode_t op); - void FCFID(PPUThread& CPU, ppu_opcode_t op); - - void UNK(PPUThread& CPU, ppu_opcode_t op); -} - -class PPUInterpreter2 : public PPUOpcodes -{ -public: - virtual ~PPUInterpreter2() {} - - ppu_inter_func_t func; - - virtual void NULL_OP() { func = ppu_interpreter::NULL_OP; } - virtual void NOP() { func = ppu_interpreter::NOP; } - - virtual void TDI(u32 to, u32 ra, s32 simm16) { func = ppu_interpreter::TDI; } - virtual void TWI(u32 to, u32 ra, s32 simm16) { func = ppu_interpreter::TWI; } - - virtual void MFVSCR(u32 vd) { func = ppu_interpreter::MFVSCR; } - virtual void MTVSCR(u32 vb) { func = ppu_interpreter::MTVSCR; } - virtual void VADDCUW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDCUW; } - virtual void VADDFP(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDFP; } - virtual void VADDSBS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDSBS; } - virtual void VADDSHS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDSHS; } - virtual void VADDSWS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDSWS; } - virtual void VADDUBM(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDUBM; } - virtual void VADDUBS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDUBS; } - virtual void VADDUHM(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDUHM; } - virtual void VADDUHS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDUHS; } - virtual void VADDUWM(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDUWM; } - virtual void VADDUWS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDUWS; } - virtual void VAND(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VAND; } - virtual void VANDC(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VANDC; } - virtual void VAVGSB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VAVGSB; } - virtual void VAVGSH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VAVGSH; } - virtual void VAVGSW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VAVGSW; } - virtual void VAVGUB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VAVGUB; } - virtual void VAVGUH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VAVGUH; } - virtual void VAVGUW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VAVGUW; } - virtual void VCFSX(u32 vd, u32 uimm5, u32 vb) { func = ppu_interpreter::VCFSX; } - virtual void VCFUX(u32 vd, u32 uimm5, u32 vb) { func = ppu_interpreter::VCFUX; } - virtual void VCMPBFP(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPBFP; } - virtual void VCMPBFP_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPBFP_; } - virtual void VCMPEQFP(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPEQFP; } - virtual void VCMPEQFP_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPEQFP_; } - virtual void VCMPEQUB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPEQUB; } - virtual void VCMPEQUB_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPEQUB_; } - virtual void VCMPEQUH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPEQUH; } - virtual void VCMPEQUH_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPEQUH_; } - virtual void VCMPEQUW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPEQUW; } - virtual void VCMPEQUW_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPEQUW_; } - virtual void VCMPGEFP(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGEFP; } - virtual void VCMPGEFP_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGEFP_; } - virtual void VCMPGTFP(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTFP; } - virtual void VCMPGTFP_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTFP_; } - virtual void VCMPGTSB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTSB; } - virtual void VCMPGTSB_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTSB_; } - virtual void VCMPGTSH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTSH; } - virtual void VCMPGTSH_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTSH_; } - virtual void VCMPGTSW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTSW; } - virtual void VCMPGTSW_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTSW_; } - virtual void VCMPGTUB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTUB; } - virtual void VCMPGTUB_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTUB_; } - virtual void VCMPGTUH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTUH; } - virtual void VCMPGTUH_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTUH_; } - virtual void VCMPGTUW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTUW; } - virtual void VCMPGTUW_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTUW_; } - virtual void VCTSXS(u32 vd, u32 uimm5, u32 vb) { func = ppu_interpreter::VCTSXS; } - virtual void VCTUXS(u32 vd, u32 uimm5, u32 vb) { func = ppu_interpreter::VCTUXS; } - virtual void VEXPTEFP(u32 vd, u32 vb) { func = ppu_interpreter::VEXPTEFP; } - virtual void VLOGEFP(u32 vd, u32 vb) { func = ppu_interpreter::VLOGEFP; } - virtual void VMADDFP(u32 vd, u32 va, u32 vc, u32 vb) { func = ppu_interpreter::VMADDFP; } - virtual void VMAXFP(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMAXFP; } - virtual void VMAXSB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMAXSB; } - virtual void VMAXSH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMAXSH; } - virtual void VMAXSW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMAXSW; } - virtual void VMAXUB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMAXUB; } - virtual void VMAXUH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMAXUH; } - virtual void VMAXUW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMAXUW; } - virtual void VMHADDSHS(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VMHADDSHS; } - virtual void VMHRADDSHS(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VMHRADDSHS; } - virtual void VMINFP(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMINFP; } - virtual void VMINSB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMINSB; } - virtual void VMINSH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMINSH; } - virtual void VMINSW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMINSW; } - virtual void VMINUB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMINUB; } - virtual void VMINUH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMINUH; } - virtual void VMINUW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMINUW; } - virtual void VMLADDUHM(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VMLADDUHM; } - virtual void VMRGHB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMRGHB; } - virtual void VMRGHH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMRGHH; } - virtual void VMRGHW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMRGHW; } - virtual void VMRGLB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMRGLB; } - virtual void VMRGLH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMRGLH; } - virtual void VMRGLW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMRGLW; } - virtual void VMSUMMBM(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VMSUMMBM; } - virtual void VMSUMSHM(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VMSUMSHM; } - virtual void VMSUMSHS(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VMSUMSHS; } - virtual void VMSUMUBM(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VMSUMUBM; } - virtual void VMSUMUHM(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VMSUMUHM; } - virtual void VMSUMUHS(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VMSUMUHS; } - virtual void VMULESB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMULESB; } - virtual void VMULESH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMULESH; } - virtual void VMULEUB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMULEUB; } - virtual void VMULEUH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMULEUH; } - virtual void VMULOSB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMULOSB; } - virtual void VMULOSH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMULOSH; } - virtual void VMULOUB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMULOUB; } - virtual void VMULOUH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMULOUH; } - virtual void VNMSUBFP(u32 vd, u32 va, u32 vc, u32 vb) { func = ppu_interpreter::VNMSUBFP; } - virtual void VNOR(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VNOR; } - virtual void VOR(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VOR; } - virtual void VPERM(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VPERM; } - virtual void VPKPX(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VPKPX; } - virtual void VPKSHSS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VPKSHSS; } - virtual void VPKSHUS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VPKSHUS; } - virtual void VPKSWSS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VPKSWSS; } - virtual void VPKSWUS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VPKSWUS; } - virtual void VPKUHUM(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VPKUHUM; } - virtual void VPKUHUS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VPKUHUS; } - virtual void VPKUWUM(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VPKUWUM; } - virtual void VPKUWUS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VPKUWUS; } - virtual void VREFP(u32 vd, u32 vb) { func = ppu_interpreter::VREFP; } - virtual void VRFIM(u32 vd, u32 vb) { func = ppu_interpreter::VRFIM; } - virtual void VRFIN(u32 vd, u32 vb) { func = ppu_interpreter::VRFIN; } - virtual void VRFIP(u32 vd, u32 vb) { func = ppu_interpreter::VRFIP; } - virtual void VRFIZ(u32 vd, u32 vb) { func = ppu_interpreter::VRFIZ; } - virtual void VRLB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VRLB; } - virtual void VRLH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VRLH; } - virtual void VRLW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VRLW; } - virtual void VRSQRTEFP(u32 vd, u32 vb) { func = ppu_interpreter::VRSQRTEFP; } - virtual void VSEL(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VSEL; } - virtual void VSL(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSL; } - virtual void VSLB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSLB; } - virtual void VSLDOI(u32 vd, u32 va, u32 vb, u32 sh) { func = ppu_interpreter::VSLDOI; } - virtual void VSLH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSLH; } - virtual void VSLO(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSLO; } - virtual void VSLW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSLW; } - virtual void VSPLTB(u32 vd, u32 uimm5, u32 vb) { func = ppu_interpreter::VSPLTB; } - virtual void VSPLTH(u32 vd, u32 uimm5, u32 vb) { func = ppu_interpreter::VSPLTH; } - virtual void VSPLTISB(u32 vd, s32 simm5) { func = ppu_interpreter::VSPLTISB; } - virtual void VSPLTISH(u32 vd, s32 simm5) { func = ppu_interpreter::VSPLTISH; } - virtual void VSPLTISW(u32 vd, s32 simm5) { func = ppu_interpreter::VSPLTISW; } - virtual void VSPLTW(u32 vd, u32 uimm5, u32 vb) { func = ppu_interpreter::VSPLTW; } - virtual void VSR(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSR; } - virtual void VSRAB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSRAB; } - virtual void VSRAH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSRAH; } - virtual void VSRAW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSRAW; } - virtual void VSRB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSRB; } - virtual void VSRH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSRH; } - virtual void VSRO(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSRO; } - virtual void VSRW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSRW; } - virtual void VSUBCUW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBCUW; } - virtual void VSUBFP(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBFP; } - virtual void VSUBSBS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBSBS; } - virtual void VSUBSHS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBSHS; } - virtual void VSUBSWS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBSWS; } - virtual void VSUBUBM(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBUBM; } - virtual void VSUBUBS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBUBS; } - virtual void VSUBUHM(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBUHM; } - virtual void VSUBUHS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBUHS; } - virtual void VSUBUWM(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBUWM; } - virtual void VSUBUWS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBUWS; } - virtual void VSUMSWS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUMSWS; } - virtual void VSUM2SWS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUM2SWS; } - virtual void VSUM4SBS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUM4SBS; } - virtual void VSUM4SHS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUM4SHS; } - virtual void VSUM4UBS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUM4UBS; } - virtual void VUPKHPX(u32 vd, u32 vb) { func = ppu_interpreter::VUPKHPX; } - virtual void VUPKHSB(u32 vd, u32 vb) { func = ppu_interpreter::VUPKHSB; } - virtual void VUPKHSH(u32 vd, u32 vb) { func = ppu_interpreter::VUPKHSH; } - virtual void VUPKLPX(u32 vd, u32 vb) { func = ppu_interpreter::VUPKLPX; } - virtual void VUPKLSB(u32 vd, u32 vb) { func = ppu_interpreter::VUPKLSB; } - virtual void VUPKLSH(u32 vd, u32 vb) { func = ppu_interpreter::VUPKLSH; } - virtual void VXOR(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VXOR; } - virtual void MULLI(u32 rd, u32 ra, s32 simm16) { func = ppu_interpreter::MULLI; } - virtual void SUBFIC(u32 rd, u32 ra, s32 simm16) { func = ppu_interpreter::SUBFIC; } - virtual void CMPLI(u32 bf, u32 l, u32 ra, u32 uimm16) { func = ppu_interpreter::CMPLI; } - virtual void CMPI(u32 bf, u32 l, u32 ra, s32 simm16) { func = ppu_interpreter::CMPI; } - virtual void ADDIC(u32 rd, u32 ra, s32 simm16) { func = ppu_interpreter::ADDIC; } - virtual void ADDIC_(u32 rd, u32 ra, s32 simm16) { func = ppu_interpreter::ADDIC_; } - virtual void ADDI(u32 rd, u32 ra, s32 simm16) { func = ppu_interpreter::ADDI; } - virtual void ADDIS(u32 rd, u32 ra, s32 simm16) { func = ppu_interpreter::ADDIS; } - virtual void BC(u32 bo, u32 bi, s32 bd, u32 aa, u32 lk) { func = ppu_interpreter::BC; } - virtual void HACK(u32 index) { func = ppu_interpreter::HACK; } - virtual void SC(u32 lev) { func = ppu_interpreter::SC; } - virtual void B(s32 ll, u32 aa, u32 lk) { func = ppu_interpreter::B; } - virtual void MCRF(u32 crfd, u32 crfs) { func = ppu_interpreter::MCRF; } - virtual void BCLR(u32 bo, u32 bi, u32 bh, u32 lk) { func = ppu_interpreter::BCLR; } - virtual void CRNOR(u32 bt, u32 ba, u32 bb) { func = ppu_interpreter::CRNOR; } - virtual void CRANDC(u32 bt, u32 ba, u32 bb) { func = ppu_interpreter::CRANDC; } - virtual void ISYNC() { func = ppu_interpreter::ISYNC; } - virtual void CRXOR(u32 bt, u32 ba, u32 bb) { func = ppu_interpreter::CRXOR; } - virtual void CRNAND(u32 bt, u32 ba, u32 bb) { func = ppu_interpreter::CRNAND; } - virtual void CRAND(u32 bt, u32 ba, u32 bb) { func = ppu_interpreter::CRAND; } - virtual void CREQV(u32 bt, u32 ba, u32 bb) { func = ppu_interpreter::CREQV; } - virtual void CRORC(u32 bt, u32 ba, u32 bb) { func = ppu_interpreter::CRORC; } - virtual void CROR(u32 bt, u32 ba, u32 bb) { func = ppu_interpreter::CROR; } - virtual void BCCTR(u32 bo, u32 bi, u32 bh, u32 lk) { func = ppu_interpreter::BCCTR; } - virtual void RLWIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) { func = ppu_interpreter::RLWIMI; } - virtual void RLWINM(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) { func = ppu_interpreter::RLWINM; } - virtual void RLWNM(u32 ra, u32 rs, u32 rb, u32 MB, u32 ME, u32 rc) { func = ppu_interpreter::RLWNM; } - virtual void ORI(u32 rs, u32 ra, u32 uimm16) { func = ppu_interpreter::ORI; } - virtual void ORIS(u32 rs, u32 ra, u32 uimm16) { func = ppu_interpreter::ORIS; } - virtual void XORI(u32 ra, u32 rs, u32 uimm16) { func = ppu_interpreter::XORI; } - virtual void XORIS(u32 ra, u32 rs, u32 uimm16) { func = ppu_interpreter::XORIS; } - virtual void ANDI_(u32 ra, u32 rs, u32 uimm16) { func = ppu_interpreter::ANDI_; } - virtual void ANDIS_(u32 ra, u32 rs, u32 uimm16) { func = ppu_interpreter::ANDIS_; } - virtual void RLDICL(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) { func = ppu_interpreter::RLDICL; } - virtual void RLDICR(u32 ra, u32 rs, u32 sh, u32 me, u32 rc) { func = ppu_interpreter::RLDICR; } - virtual void RLDIC(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) { func = ppu_interpreter::RLDIC; } - virtual void RLDIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) { func = ppu_interpreter::RLDIMI; } - virtual void RLDC_LR(u32 ra, u32 rs, u32 rb, u32 m_eb, u32 is_r, u32 rc) { func = ppu_interpreter::RLDC_LR; } - virtual void CMP(u32 crfd, u32 l, u32 ra, u32 rb) { func = ppu_interpreter::CMP; } - virtual void TW(u32 to, u32 ra, u32 rb) { func = ppu_interpreter::TW; } - virtual void LVSL(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVSL; } - virtual void LVEBX(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVEBX; } - virtual void SUBFC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::SUBFC; } - virtual void MULHDU(u32 rd, u32 ra, u32 rb, u32 rc) { func = ppu_interpreter::MULHDU; } - virtual void ADDC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::ADDC; } - virtual void MULHWU(u32 rd, u32 ra, u32 rb, u32 rc) { func = ppu_interpreter::MULHWU; } - virtual void MFOCRF(u32 a, u32 rd, u32 crm) { func = ppu_interpreter::MFOCRF; } - virtual void LWARX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LWARX; } - virtual void LDX(u32 ra, u32 rs, u32 rb) { func = ppu_interpreter::LDX; } - virtual void LWZX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LWZX; } - virtual void SLW(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::SLW; } - virtual void CNTLZW(u32 ra, u32 rs, u32 rc) { func = ppu_interpreter::CNTLZW; } - virtual void SLD(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::SLD; } - virtual void AND(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::AND; } - virtual void CMPL(u32 bf, u32 l, u32 ra, u32 rb) { func = ppu_interpreter::CMPL; } - virtual void LVSR(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVSR; } - virtual void LVEHX(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVEHX; } - virtual void SUBF(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::SUBF; } - virtual void LDUX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LDUX; } - virtual void DCBST(u32 ra, u32 rb) { func = ppu_interpreter::DCBST; } - virtual void LWZUX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LWZUX; } - virtual void CNTLZD(u32 ra, u32 rs, u32 rc) { func = ppu_interpreter::CNTLZD; } - virtual void ANDC(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::ANDC; } - virtual void TD(u32 to, u32 ra, u32 rb) { func = ppu_interpreter::TD; } - virtual void LVEWX(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVEWX; } - virtual void MULHD(u32 rd, u32 ra, u32 rb, u32 rc) { func = ppu_interpreter::MULHD; } - virtual void MULHW(u32 rd, u32 ra, u32 rb, u32 rc) { func = ppu_interpreter::MULHW; } - virtual void LDARX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LDARX; } - virtual void DCBF(u32 ra, u32 rb) { func = ppu_interpreter::DCBF; } - virtual void LBZX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LBZX; } - virtual void LVX(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVX; } - virtual void NEG(u32 rd, u32 ra, u32 oe, u32 rc) { func = ppu_interpreter::NEG; } - virtual void LBZUX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LBZUX; } - virtual void NOR(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::NOR; } - virtual void STVEBX(u32 vs, u32 ra, u32 rb) { func = ppu_interpreter::STVEBX; } - virtual void SUBFE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::SUBFE; } - virtual void ADDE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::ADDE; } - virtual void MTOCRF(u32 l, u32 crm, u32 rs) { func = ppu_interpreter::MTOCRF; } - virtual void STDX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STDX; } - virtual void STWCX_(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STWCX_; } - virtual void STWX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STWX; } - virtual void STVEHX(u32 vs, u32 ra, u32 rb) { func = ppu_interpreter::STVEHX; } - virtual void STDUX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STDUX; } - virtual void STWUX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STWUX; } - virtual void STVEWX(u32 vs, u32 ra, u32 rb) { func = ppu_interpreter::STVEWX; } - virtual void SUBFZE(u32 rd, u32 ra, u32 oe, u32 rc) { func = ppu_interpreter::SUBFZE; } - virtual void ADDZE(u32 rd, u32 ra, u32 oe, u32 rc) { func = ppu_interpreter::ADDZE; } - virtual void STDCX_(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STDCX_; } - virtual void STBX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STBX; } - virtual void STVX(u32 vs, u32 ra, u32 rb) { func = ppu_interpreter::STVX; } - virtual void MULLD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::MULLD; } - virtual void SUBFME(u32 rd, u32 ra, u32 oe, u32 rc) { func = ppu_interpreter::SUBFME; } - virtual void ADDME(u32 rd, u32 ra, u32 oe, u32 rc) { func = ppu_interpreter::ADDME; } - virtual void MULLW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::MULLW; } - virtual void DCBTST(u32 ra, u32 rb, u32 th) { func = ppu_interpreter::DCBTST; } - virtual void STBUX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STBUX; } - virtual void ADD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::ADD; } - virtual void DCBT(u32 ra, u32 rb, u32 th) { func = ppu_interpreter::DCBT; } - virtual void LHZX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LHZX; } - virtual void EQV(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::EQV; } - virtual void ECIWX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::ECIWX; } - virtual void LHZUX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LHZUX; } - virtual void XOR(u32 rs, u32 ra, u32 rb, u32 rc) { func = ppu_interpreter::XOR; } - virtual void MFSPR(u32 rd, u32 spr) { func = ppu_interpreter::MFSPR; } - virtual void LWAX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LWAX; } - virtual void DST(u32 ra, u32 rb, u32 strm, u32 t) { func = ppu_interpreter::DST; } - virtual void LHAX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LHAX; } - virtual void LVXL(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVXL; } - virtual void MFTB(u32 rd, u32 spr) { func = ppu_interpreter::MFTB; } - virtual void LWAUX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LWAUX; } - virtual void DSTST(u32 ra, u32 rb, u32 strm, u32 t) { func = ppu_interpreter::DSTST; } - virtual void LHAUX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LHAUX; } - virtual void STHX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STHX; } - virtual void ORC(u32 rs, u32 ra, u32 rb, u32 rc) { func = ppu_interpreter::ORC; } - virtual void ECOWX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::ECOWX; } - virtual void STHUX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STHUX; } - virtual void OR(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::OR; } - virtual void DIVDU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::DIVDU; } - virtual void DIVWU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::DIVWU; } - virtual void MTSPR(u32 spr, u32 rs) { func = ppu_interpreter::MTSPR; } - virtual void DCBI(u32 ra, u32 rb) { func = ppu_interpreter::DCBI; } - virtual void NAND(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::NAND; } - virtual void STVXL(u32 vs, u32 ra, u32 rb) { func = ppu_interpreter::STVXL; } - virtual void DIVD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::DIVD; } - virtual void DIVW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::DIVW; } - virtual void LVLX(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVLX; } - virtual void LDBRX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LDBRX; } - virtual void LSWX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LSWX; } - virtual void LWBRX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LWBRX; } - virtual void LFSX(u32 frd, u32 ra, u32 rb) { func = ppu_interpreter::LFSX; } - virtual void SRW(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::SRW; } - virtual void SRD(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::SRD; } - virtual void LVRX(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVRX; } - virtual void LSWI(u32 rd, u32 ra, u32 nb) { func = ppu_interpreter::LSWI; } - virtual void LFSUX(u32 frd, u32 ra, u32 rb) { func = ppu_interpreter::LFSUX; } - virtual void SYNC(u32 l) { func = ppu_interpreter::SYNC; } - virtual void LFDX(u32 frd, u32 ra, u32 rb) { func = ppu_interpreter::LFDX; } - virtual void LFDUX(u32 frd, u32 ra, u32 rb) { func = ppu_interpreter::LFDUX; } - virtual void STVLX(u32 vs, u32 ra, u32 rb) { func = ppu_interpreter::STVLX; } - virtual void STDBRX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STDBRX; } - virtual void STSWX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STSWX; } - virtual void STWBRX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STWBRX; } - virtual void STFSX(u32 frs, u32 ra, u32 rb) { func = ppu_interpreter::STFSX; } - virtual void STVRX(u32 vs, u32 ra, u32 rb) { func = ppu_interpreter::STVRX; } - virtual void STFSUX(u32 frs, u32 ra, u32 rb) { func = ppu_interpreter::STFSUX; } - virtual void STSWI(u32 rd, u32 ra, u32 nb) { func = ppu_interpreter::STSWI; } - virtual void STFDX(u32 frs, u32 ra, u32 rb) { func = ppu_interpreter::STFDX; } - virtual void STFDUX(u32 frs, u32 ra, u32 rb) { func = ppu_interpreter::STFDUX; } - virtual void LVLXL(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVLXL; } - virtual void LHBRX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LHBRX; } - virtual void SRAW(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::SRAW; } - virtual void SRAD(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::SRAD; } - virtual void LVRXL(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVRXL; } - virtual void DSS(u32 strm, u32 a) { func = ppu_interpreter::DSS; } - virtual void SRAWI(u32 ra, u32 rs, u32 sh, u32 rc) { func = ppu_interpreter::SRAWI; } - virtual void SRADI1(u32 ra, u32 rs, u32 sh, u32 rc) { func = ppu_interpreter::SRADI; } - virtual void SRADI2(u32 ra, u32 rs, u32 sh, u32 rc) { func = ppu_interpreter::SRADI; } - virtual void EIEIO() { func = ppu_interpreter::EIEIO; } - virtual void STVLXL(u32 vs, u32 ra, u32 rb) { func = ppu_interpreter::STVLXL; } - virtual void STHBRX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STHBRX; } - virtual void EXTSH(u32 ra, u32 rs, u32 rc) { func = ppu_interpreter::EXTSH; } - virtual void STVRXL(u32 sd, u32 ra, u32 rb) { func = ppu_interpreter::STVRXL; } - virtual void EXTSB(u32 ra, u32 rs, u32 rc) { func = ppu_interpreter::EXTSB; } - virtual void STFIWX(u32 frs, u32 ra, u32 rb) { func = ppu_interpreter::STFIWX; } - virtual void EXTSW(u32 ra, u32 rs, u32 rc) { func = ppu_interpreter::EXTSW; } - virtual void ICBI(u32 ra, u32 rb) { func = ppu_interpreter::ICBI; } - virtual void DCBZ(u32 ra, u32 rb) { func = ppu_interpreter::DCBZ; } - virtual void LWZ(u32 rd, u32 ra, s32 d) { func = ppu_interpreter::LWZ; } - virtual void LWZU(u32 rd, u32 ra, s32 d) { func = ppu_interpreter::LWZU; } - virtual void LBZ(u32 rd, u32 ra, s32 d) { func = ppu_interpreter::LBZ; } - virtual void LBZU(u32 rd, u32 ra, s32 d) { func = ppu_interpreter::LBZU; } - virtual void STW(u32 rs, u32 ra, s32 d) { func = ppu_interpreter::STW; } - virtual void STWU(u32 rs, u32 ra, s32 d) { func = ppu_interpreter::STWU; } - virtual void STB(u32 rs, u32 ra, s32 d) { func = ppu_interpreter::STB; } - virtual void STBU(u32 rs, u32 ra, s32 d) { func = ppu_interpreter::STBU; } - virtual void LHZ(u32 rd, u32 ra, s32 d) { func = ppu_interpreter::LHZ; } - virtual void LHZU(u32 rd, u32 ra, s32 d) { func = ppu_interpreter::LHZU; } - virtual void LHA(u32 rs, u32 ra, s32 d) { func = ppu_interpreter::LHA; } - virtual void LHAU(u32 rs, u32 ra, s32 d) { func = ppu_interpreter::LHAU; } - virtual void STH(u32 rs, u32 ra, s32 d) { func = ppu_interpreter::STH; } - virtual void STHU(u32 rs, u32 ra, s32 d) { func = ppu_interpreter::STHU; } - virtual void LMW(u32 rd, u32 ra, s32 d) { func = ppu_interpreter::LMW; } - virtual void STMW(u32 rs, u32 ra, s32 d) { func = ppu_interpreter::STMW; } - virtual void LFS(u32 frd, u32 ra, s32 d) { func = ppu_interpreter::LFS; } - virtual void LFSU(u32 frd, u32 ra, s32 d) { func = ppu_interpreter::LFSU; } - virtual void LFD(u32 frd, u32 ra, s32 d) { func = ppu_interpreter::LFD; } - virtual void LFDU(u32 frd, u32 ra, s32 d) { func = ppu_interpreter::LFDU; } - virtual void STFS(u32 frs, u32 ra, s32 d) { func = ppu_interpreter::STFS; } - virtual void STFSU(u32 frs, u32 ra, s32 d) { func = ppu_interpreter::STFSU; } - virtual void STFD(u32 frs, u32 ra, s32 d) { func = ppu_interpreter::STFD; } - virtual void STFDU(u32 frs, u32 ra, s32 d) { func = ppu_interpreter::STFDU; } - virtual void LD(u32 rd, u32 ra, s32 ds) { func = ppu_interpreter::LD; } - virtual void LDU(u32 rd, u32 ra, s32 ds) { func = ppu_interpreter::LDU; } - virtual void LWA(u32 rd, u32 ra, s32 ds) { func = ppu_interpreter::LWA; } - virtual void FDIVS(u32 frd, u32 fra, u32 frb, u32 rc) { func = ppu_interpreter::FDIVS; } - virtual void FSUBS(u32 frd, u32 fra, u32 frb, u32 rc) { func = ppu_interpreter::FSUBS; } - virtual void FADDS(u32 frd, u32 fra, u32 frb, u32 rc) { func = ppu_interpreter::FADDS; } - virtual void FSQRTS(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FSQRTS; } - virtual void FRES(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FRES; } - virtual void FMULS(u32 frd, u32 fra, u32 frc, u32 rc) { func = ppu_interpreter::FMULS; } - virtual void FMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { func = ppu_interpreter::FMADDS; } - virtual void FMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { func = ppu_interpreter::FMSUBS; } - virtual void FNMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { func = ppu_interpreter::FNMSUBS; } - virtual void FNMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { func = ppu_interpreter::FNMADDS; } - virtual void STD(u32 rs, u32 ra, s32 ds) { func = ppu_interpreter::STD; } - virtual void STDU(u32 rs, u32 ra, s32 ds) { func = ppu_interpreter::STDU; } - virtual void MTFSB1(u32 bt, u32 rc) { func = ppu_interpreter::MTFSB1; } - virtual void MCRFS(u32 bf, u32 bfa) { func = ppu_interpreter::MCRFS; } - virtual void MTFSB0(u32 bt, u32 rc) { func = ppu_interpreter::MTFSB0; } - virtual void MTFSFI(u32 crfd, u32 i, u32 rc) { func = ppu_interpreter::MTFSFI; } - virtual void MFFS(u32 frd, u32 rc) { func = ppu_interpreter::MFFS; } - virtual void MTFSF(u32 flm, u32 frb, u32 rc) { func = ppu_interpreter::MTFSF; } - - virtual void FCMPU(u32 bf, u32 fra, u32 frb) { func = ppu_interpreter::FCMPU; } - virtual void FRSP(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FRSP; } - virtual void FCTIW(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FCTIW; } - virtual void FCTIWZ(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FCTIWZ; } - virtual void FDIV(u32 frd, u32 fra, u32 frb, u32 rc) { func = ppu_interpreter::FDIV; } - virtual void FSUB(u32 frd, u32 fra, u32 frb, u32 rc) { func = ppu_interpreter::FSUB; } - virtual void FADD(u32 frd, u32 fra, u32 frb, u32 rc) { func = ppu_interpreter::FADD; } - virtual void FSQRT(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FSQRT; } - virtual void FSEL(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { func = ppu_interpreter::FSEL; } - virtual void FMUL(u32 frd, u32 fra, u32 frc, u32 rc) { func = ppu_interpreter::FMUL; } - virtual void FRSQRTE(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FRSQRTE; } - virtual void FMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { func = ppu_interpreter::FMSUB; } - virtual void FMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { func = ppu_interpreter::FMADD; } - virtual void FNMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { func = ppu_interpreter::FNMSUB; } - virtual void FNMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { func = ppu_interpreter::FNMADD; } - virtual void FCMPO(u32 crfd, u32 fra, u32 frb) { func = ppu_interpreter::FCMPO; } - virtual void FNEG(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FNEG; } - virtual void FMR(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FMR; } - virtual void FNABS(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FNABS; } - virtual void FABS(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FABS; } - virtual void FCTID(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FCTID; } - virtual void FCTIDZ(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FCTIDZ; } - virtual void FCFID(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FCFID; } - - virtual void UNK(const u32 code, const u32 opcode, const u32 gcode) { func = ppu_interpreter::UNK; } -}; \ No newline at end of file diff --git a/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp deleted file mode 100644 index d1e621c44d..0000000000 --- a/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp +++ /dev/null @@ -1,680 +0,0 @@ -#include "stdafx.h" -#ifdef LLVM_AVAILABLE -#include "Emu/System.h" -#include "Emu/state.h" -#include "Emu/Cell/PPUDisAsm.h" -#include "Emu/Cell/PPULLVMRecompiler.h" -#include "Emu/Memory/Memory.h" -#include "Utilities/VirtualMemory.h" -#ifdef _MSC_VER -#pragma warning(push, 0) -#endif -#include "llvm/Support/TargetSelect.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/ExecutionEngine/GenericValue.h" -#include "llvm/ExecutionEngine/MCJIT.h" -#include "llvm/IR/Intrinsics.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Analysis/Passes.h" -#include "llvm/Analysis/TargetTransformInfo.h" -#include "llvm/Analysis/MemoryDependenceAnalysis.h" -#include "llvm/Analysis/LoopInfo.h" -#include "llvm/Analysis/ScalarEvolution.h" -#include "llvm/IR/Dominators.h" -#include "llvm/Transforms/Scalar.h" -#include "llvm/Transforms/Vectorize.h" -#include "llvm/MC/MCDisassembler.h" -#include "llvm/IR/Verifier.h" -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -using namespace llvm; -using namespace ppu_recompiler_llvm; - -#ifdef ID_MANAGER_INCLUDED -#error "ID Manager cannot be used in this module" -#endif - -// PS3 can address 32 bits aligned on 4 bytes boundaries : 2^30 pointers -#define VIRTUAL_INSTRUCTION_COUNT 0x40000000 -#define PAGE_SIZE 4096 - -u64 Compiler::s_rotate_mask[64][64]; -bool Compiler::s_rotate_mask_inited = false; - -std::unique_ptr Compiler::create_module(LLVMContext &llvm_context) -{ - const std::vector arg_types = { Type::getInt8PtrTy(llvm_context), Type::getInt64Ty(llvm_context) }; - FunctionType *compiled_function_type = FunctionType::get(Type::getInt32Ty(llvm_context), arg_types, false); - - std::unique_ptr result(new llvm::Module("Module", llvm_context)); - Function *execute_unknown_function = (Function *)result->getOrInsertFunction("execute_unknown_function", compiled_function_type); - execute_unknown_function->setCallingConv(CallingConv::X86_64_Win64); - - Function *execute_unknown_block = (Function *)result->getOrInsertFunction("execute_unknown_block", compiled_function_type); - execute_unknown_block->setCallingConv(CallingConv::X86_64_Win64); - - std::string targetTriple = "x86_64-pc-windows-elf"; - result->setTargetTriple(targetTriple); - - return result; -} - -void Compiler::optimise_module(llvm::Module *module) -{ - llvm::FunctionPassManager fpm(module); - fpm.add(createNoAAPass()); - fpm.add(createBasicAliasAnalysisPass()); - fpm.add(createNoTargetTransformInfoPass()); - fpm.add(createEarlyCSEPass()); - fpm.add(createTailCallEliminationPass()); - fpm.add(createReassociatePass()); - fpm.add(createInstructionCombiningPass()); - fpm.add(new DominatorTreeWrapperPass()); - fpm.add(new MemoryDependenceAnalysis()); - fpm.add(createGVNPass()); - fpm.add(createInstructionCombiningPass()); - fpm.add(new MemoryDependenceAnalysis()); - fpm.add(createDeadStoreEliminationPass()); - fpm.add(new LoopInfo()); - fpm.add(new ScalarEvolution()); - fpm.add(createSLPVectorizerPass()); - fpm.add(createInstructionCombiningPass()); - fpm.add(createCFGSimplificationPass()); - fpm.doInitialization(); - - for (auto I = module->begin(), E = module->end(); I != E; ++I) - fpm.run(*I); -} - - -Compiler::Compiler(LLVMContext *context, llvm::IRBuilder<> *builder, std::unordered_map &function_ptrs) - : m_llvm_context(context), - m_ir_builder(builder), - m_executable_map(function_ptrs) { - - std::vector arg_types; - arg_types.push_back(m_ir_builder->getInt8PtrTy()); - arg_types.push_back(m_ir_builder->getInt64Ty()); - m_compiled_function_type = FunctionType::get(m_ir_builder->getInt32Ty(), arg_types, false); - - if (!s_rotate_mask_inited) { - InitRotateMask(); - s_rotate_mask_inited = true; - } -} - -Compiler::~Compiler() { -} - -void Compiler::initiate_function(const std::string &name) -{ - m_state.function = (Function *)m_module->getOrInsertFunction(name, m_compiled_function_type); - m_state.function->setCallingConv(CallingConv::X86_64_Win64); - auto arg_i = m_state.function->arg_begin(); - arg_i->setName("ppu_state"); - m_state.args[CompileTaskState::Args::State] = arg_i; - (++arg_i)->setName("context"); - m_state.args[CompileTaskState::Args::Context] = arg_i; -} - -void ppu_recompiler_llvm::Compiler::translate_to_llvm_ir(llvm::Module *module, const std::string & name, u32 start_address, u32 instruction_count) -{ - m_module = module; - - m_execute_unknown_function = module->getFunction("execute_unknown_function"); - m_execute_unknown_block = module->getFunction("execute_unknown_block"); - - initiate_function(name); - - // Create the entry block and add code to branch to the first instruction - m_ir_builder->SetInsertPoint(GetBasicBlockFromAddress(0)); - m_ir_builder->CreateBr(GetBasicBlockFromAddress(start_address)); - - // Convert each instruction in the CFG to LLVM IR - std::vector exit_instr_list; - for (u32 instructionAddress = start_address; instructionAddress < start_address + instruction_count * 4; instructionAddress += 4) { - m_state.hit_branch_instruction = false; - m_state.current_instruction_address = instructionAddress; - BasicBlock *instr_bb = GetBasicBlockFromAddress(instructionAddress); - m_ir_builder->SetInsertPoint(instr_bb); - - u32 instr = vm::ps3::read32(instructionAddress); - - Decode(instr); - if (!m_state.hit_branch_instruction) - m_ir_builder->CreateBr(GetBasicBlockFromAddress(instructionAddress + 4)); - } - - // Generate exit logic for all empty blocks - const std::string &default_exit_block_name = GetBasicBlockNameFromAddress(0xFFFFFFFF); - for (BasicBlock &block_i : *m_state.function) { - if (!block_i.getInstList().empty() || block_i.getName() == default_exit_block_name) - continue; - - // Found an empty block - m_state.current_instruction_address = GetAddressFromBasicBlockName(block_i.getName()); - - m_ir_builder->SetInsertPoint(&block_i); - PHINode *exit_instr_i32 = m_ir_builder->CreatePHI(m_ir_builder->getInt32Ty(), 0); - exit_instr_list.push_back(exit_instr_i32); - - SetPc(m_ir_builder->getInt32(m_state.current_instruction_address)); - - m_ir_builder->CreateRet(m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusBlockEnded)); - } - - // If the function has a default exit block then generate code for it - BasicBlock *default_exit_bb = GetBasicBlockFromAddress(0xFFFFFFFF, "", false); - if (default_exit_bb) { - m_ir_builder->SetInsertPoint(default_exit_bb); - PHINode *exit_instr_i32 = m_ir_builder->CreatePHI(m_ir_builder->getInt32Ty(), 0); - exit_instr_list.push_back(exit_instr_i32); - - m_ir_builder->CreateRet(m_ir_builder->getInt32(0)); - } - - // Add incoming values for all exit instr PHI nodes - for (PHINode *exit_instr_i : exit_instr_list) { - BasicBlock *block = exit_instr_i->getParent(); - for (pred_iterator pred_i = pred_begin(block); pred_i != pred_end(block); pred_i++) { - u32 pred_address = GetAddressFromBasicBlockName((*pred_i)->getName()); - exit_instr_i->addIncoming(m_ir_builder->getInt32(pred_address), *pred_i); - } - } - - std::string verify; - raw_string_ostream verify_ostream(verify); - if (verifyFunction(*m_state.function, &verify_ostream)) { -// m_recompilation_engine.trace() << "Verification failed: " << verify_ostream.str() << "\n"; - } - - m_module = nullptr; - m_state.function = nullptr; -} - -void Compiler::Decode(const u32 code) { - (*PPU_instr::main_list)(this, code); -} - -std::mutex RecompilationEngine::s_mutex; -std::shared_ptr RecompilationEngine::s_the_instance = nullptr; - -RecompilationEngine::RecompilationEngine() - : m_log(nullptr) - , m_currentId(0) - , m_last_cache_clear_time(std::chrono::high_resolution_clock::now()) - , m_llvm_context(getGlobalContext()) - , m_ir_builder(getGlobalContext()) { - InitializeNativeTarget(); - InitializeNativeTargetAsmPrinter(); - InitializeNativeTargetDisassembler(); - - FunctionCache = (ExecutableStorageType *)memory_helper::reserve_memory(VIRTUAL_INSTRUCTION_COUNT * sizeof(ExecutableStorageType)); - // Each char can store 8 page status - FunctionCachePagesCommited = (char *)malloc(VIRTUAL_INSTRUCTION_COUNT / (8 * PAGE_SIZE)); - if (FunctionCachePagesCommited == nullptr) - throw EXCEPTION("Memory error"); - memset(FunctionCachePagesCommited, 0, VIRTUAL_INSTRUCTION_COUNT / (8 * PAGE_SIZE)); -} - -RecompilationEngine::~RecompilationEngine() { - m_executable_storage.clear(); - memory_helper::free_reserved_memory(FunctionCache, VIRTUAL_INSTRUCTION_COUNT * sizeof(ExecutableStorageType)); - free(FunctionCachePagesCommited); -} - -bool RecompilationEngine::isAddressCommited(u32 address) const -{ - size_t offset = address * sizeof(ExecutableStorageType); - size_t page = offset / 4096; - // Since bool is stored in char, the char index is page / 8 (or page >> 3) - // and we shr the value with the remaining bits (page & 7) - return (FunctionCachePagesCommited[page >> 3] >> (page & 7)) & 1; -} - -void RecompilationEngine::commitAddress(u32 address) -{ - size_t offset = address * sizeof(ExecutableStorageType); - size_t page = offset / 4096; - memory_helper::commit_page_memory((u8*)FunctionCache + page * 4096, 4096); - // Reverse of isAddressCommited : we set the (page & 7)th bit of (page / 8) th char - // in the array - FunctionCachePagesCommited[page >> 3] |= (1 << (page & 7)); -} - -const Executable RecompilationEngine::GetCompiledExecutableIfAvailable(u32 address) const -{ - if (!isAddressCommited(address / 4)) - return nullptr; - u32 id = FunctionCache[address / 4].second; - if (rpcs3::state.config.core.llvm.exclusion_range.value() && - (id >= rpcs3::state.config.core.llvm.min_id.value() && id <= rpcs3::state.config.core.llvm.max_id.value())) - return nullptr; - return FunctionCache[address / 4].first; -} - -void RecompilationEngine::NotifyBlockStart(u32 address) { - { - std::lock_guard lock(m_pending_address_start_lock); - if (m_pending_address_start.size() > 10000) - m_pending_address_start.clear(); - m_pending_address_start.push_back(address); - } - - if (!is_started()) { - start(); - } - - cv.notify_one(); - // TODO: Increase the priority of the recompilation engine thread -} - -raw_fd_ostream & RecompilationEngine::Log() { - if (!m_log) { - std::error_code error; - m_log = new raw_fd_ostream("PPULLVMRecompiler.log", error, sys::fs::F_Text); - m_log->SetUnbuffered(); - } - - return *m_log; -} - -void RecompilationEngine::on_task() { - std::chrono::nanoseconds idling_time(0); - std::chrono::nanoseconds recompiling_time(0); - - auto start = std::chrono::high_resolution_clock::now(); - while (!Emu.IsStopped()) { - bool work_done_this_iteration = false; - std::list m_current_execution_traces; - - { - std::lock_guard lock(m_pending_address_start_lock); - m_current_execution_traces.swap(m_pending_address_start); - } - - if (!m_current_execution_traces.empty()) { - for (u32 address : m_current_execution_traces) - work_done_this_iteration |= IncreaseHitCounterAndBuild(address); - } - - if (!work_done_this_iteration) { - // Wait a few ms for something to happen - auto idling_start = std::chrono::high_resolution_clock::now(); - std::unique_lock lock(mutex); - cv.wait_for(lock, std::chrono::milliseconds(10)); - auto idling_end = std::chrono::high_resolution_clock::now(); - idling_time += std::chrono::duration_cast(idling_end - idling_start); - } - } - - s_the_instance = nullptr; // Can cause deadlock if this is the last instance. Need to fix this. -} - -bool RecompilationEngine::IncreaseHitCounterAndBuild(u32 address) { - auto It = m_block_table.find(address); - if (It == m_block_table.end()) - It = m_block_table.emplace(address, BlockEntry(address)).first; - BlockEntry &block = It->second; - if (!block.is_compiled) { - block.num_hits++; - if (block.num_hits >= rpcs3::state.config.core.llvm.threshold.value()) { - CompileBlock(block); - return true; - } - } - return false; -} - -extern void execute_ppu_func_by_index(PPUThread& ppu, u32 id); -extern void execute_syscall_by_index(PPUThread& ppu, u64 code); - -static u32 -wrappedExecutePPUFuncByIndex(PPUThread &CPU, u32 index) noexcept { - try - { - execute_ppu_func_by_index(CPU, index); - return ExecutionStatus::ExecutionStatusBlockEnded; - } - catch (...) - { - CPU.pending_exception = std::current_exception(); - return ExecutionStatus::ExecutionStatusPropagateException; - } -} - -static u32 wrappedDoSyscall(PPUThread &CPU, u64 code) noexcept { - try - { - execute_syscall_by_index(CPU, code); - return ExecutionStatus::ExecutionStatusBlockEnded; - } - catch (...) - { - CPU.pending_exception = std::current_exception(); - return ExecutionStatus::ExecutionStatusPropagateException; - } -} - -static void wrapped_fast_stop(PPUThread &CPU) -{ - CPU.fast_stop(); -} - -static void wrapped_trap(PPUThread &CPU, u32) noexcept { - try - { - throw EXCEPTION("trap"); - } - catch (...) - { - CPU.pending_exception = std::current_exception(); - } -} - -std::pair RecompilationEngine::compile(const std::string & name, u32 start_address, u32 instruction_count) { - std::unique_ptr module = Compiler::create_module(m_llvm_context); - - std::unordered_map function_ptrs; - function_ptrs["execute_unknown_function"] = reinterpret_cast(CPUHybridDecoderRecompiler::ExecuteFunction); - function_ptrs["execute_unknown_block"] = reinterpret_cast(CPUHybridDecoderRecompiler::ExecuteTillReturn); - function_ptrs["PollStatus"] = reinterpret_cast(CPUHybridDecoderRecompiler::PollStatus); - function_ptrs["PPUThread.fast_stop"] = reinterpret_cast(wrapped_fast_stop); - function_ptrs["vm.reservation_acquire"] = reinterpret_cast(vm::reservation_acquire); - function_ptrs["vm.reservation_update"] = reinterpret_cast(vm::reservation_update); - function_ptrs["get_timebased_time"] = reinterpret_cast(get_timebased_time); - function_ptrs["wrappedExecutePPUFuncByIndex"] = reinterpret_cast(wrappedExecutePPUFuncByIndex); - function_ptrs["wrappedDoSyscall"] = reinterpret_cast(wrappedDoSyscall); - function_ptrs["trap"] = reinterpret_cast(wrapped_trap); - -#define REGISTER_FUNCTION_PTR(name) \ - function_ptrs[#name] = reinterpret_cast(PPUInterpreter::name##_impl); - - MACRO_PPU_INST_MAIN_EXPANDERS(REGISTER_FUNCTION_PTR) - MACRO_PPU_INST_G_13_EXPANDERS(REGISTER_FUNCTION_PTR) - MACRO_PPU_INST_G_1E_EXPANDERS(REGISTER_FUNCTION_PTR) - MACRO_PPU_INST_G_1F_EXPANDERS(REGISTER_FUNCTION_PTR) - MACRO_PPU_INST_G_3A_EXPANDERS(REGISTER_FUNCTION_PTR) - MACRO_PPU_INST_G_3E_EXPANDERS(REGISTER_FUNCTION_PTR) - - Compiler(&m_llvm_context, &m_ir_builder, function_ptrs) - .translate_to_llvm_ir(module.get(), name, start_address, instruction_count); - - llvm::Module *module_ptr = module.get(); - - Log() << *module_ptr; - Compiler::optimise_module(module_ptr); - - llvm::ExecutionEngine *execution_engine = - EngineBuilder(std::move(module)) - .setEngineKind(EngineKind::JIT) - .setMCJITMemoryManager(std::unique_ptr(new CustomSectionMemoryManager(function_ptrs))) - .setOptLevel(llvm::CodeGenOpt::Aggressive) - .setMCPU("nehalem") - .create(); - module_ptr->setDataLayout(execution_engine->getDataLayout()); - - // Translate to machine code - execution_engine->finalizeObject(); - - Function *llvm_function = module_ptr->getFunction(name); - void *function = execution_engine->getPointerToFunction(llvm_function); - - /* m_recompilation_engine.trace() << "\nDisassembly:\n"; - auto disassembler = LLVMCreateDisasm(sys::getProcessTriple().c_str(), nullptr, 0, nullptr, nullptr); - for (size_t pc = 0; pc < mci.size();) { - char str[1024]; - - auto size = LLVMDisasmInstruction(disassembler, ((u8 *)mci.address()) + pc, mci.size() - pc, (uint64_t)(((u8 *)mci.address()) + pc), str, sizeof(str)); - m_recompilation_engine.trace() << fmt::format("0x%08X: ", (u64)(((u8 *)mci.address()) + pc)) << str << '\n'; - pc += size; - } - - LLVMDisasmDispose(disassembler);*/ - - assert(function != nullptr); - return std::make_pair((Executable)function, execution_engine); -} - -/** -* This code is inspired from Dolphin PPC Analyst -*/ -inline s32 SignExt16(s16 x) { return (s32)(s16)x; } -inline s32 SignExt26(u32 x) { return x & 0x2000000 ? (s32)(x | 0xFC000000) : (s32)(x); } - -bool RecompilationEngine::AnalyseBlock(BlockEntry &functionData, size_t maxSize) -{ - u32 startAddress = functionData.address; - u32 farthestBranchTarget = startAddress; - functionData.instructionCount = 0; - functionData.calledFunctions.clear(); - functionData.is_analysed = true; - functionData.is_compilable_function = true; - Log() << "Analysing " << (void*)(uint64_t)startAddress << "hit " << functionData.num_hits << "\n"; - // Used to decode instructions - PPUDisAsm dis_asm(CPUDisAsm_DumpMode); - dis_asm.offset = vm::ps3::_ptr(startAddress); - for (u32 instructionAddress = startAddress; instructionAddress < startAddress + maxSize; instructionAddress += 4) - { - u32 instr = vm::ps3::read32((u32)instructionAddress); - - dis_asm.dump_pc = instructionAddress - startAddress; - (*PPU_instr::main_list)(&dis_asm, instr); - Log() << dis_asm.last_opcode; - functionData.instructionCount++; - if (instr == PPU_instr::implicts::BLR() && instructionAddress >= farthestBranchTarget && functionData.is_compilable_function) - { - Log() << "Analysis: Block is compilable into a function \n"; - return true; - } - else if (PPU_instr::fields::GD_13(instr) == PPU_opcodes::G_13Opcodes::BCCTR) - { - if (!PPU_instr::fields::LK(instr)) - { - Log() << "Analysis: indirect branching found \n"; - functionData.is_compilable_function = false; - return true; - } - } - else if (PPU_instr::fields::OPCD(instr) == PPU_opcodes::PPU_MainOpcodes::BC) - { - u32 target = SignExt16(PPU_instr::fields::BD(instr)); - if (!PPU_instr::fields::AA(instr)) // Absolute address - target += (u32)instructionAddress; - if (target > farthestBranchTarget && !PPU_instr::fields::LK(instr)) - farthestBranchTarget = target; - } - else if (PPU_instr::fields::OPCD(instr) == PPU_opcodes::PPU_MainOpcodes::B) - { - u32 target = SignExt26(PPU_instr::fields::LL(instr)); - if (!PPU_instr::fields::AA(instr)) // Absolute address - target += (u32)instructionAddress; - - if (!PPU_instr::fields::LK(instr)) - { - if (target < startAddress) - { - Log() << "Analysis: branch to previous block\n"; - functionData.is_compilable_function = false; - return true; - } - else if (target > farthestBranchTarget) - farthestBranchTarget = target; - } - else - functionData.calledFunctions.insert(target); - } - } - Log() << "Analysis: maxSize reached \n"; - functionData.is_compilable_function = false; - return true; -} - -void RecompilationEngine::CompileBlock(BlockEntry & block_entry) { - if (block_entry.is_analysed) - return; - - if (!AnalyseBlock(block_entry)) - return; - Log() << "Compile: " << block_entry.ToString() << "\n"; - - { - // We create a lock here so that data are properly stored at the end of the function. - /// Lock for accessing compiler - std::mutex local_mutex; - std::unique_lock lock(local_mutex); - - const std::pair &compileResult = - compile(fmt::format("fn_0x%08X", block_entry.address), block_entry.address, block_entry.instructionCount); - - if (!isAddressCommited(block_entry.address / 4)) - commitAddress(block_entry.address / 4); - - m_executable_storage.push_back(std::unique_ptr(compileResult.second)); - Log() << "Associating " << (void*)(uint64_t)block_entry.address << " with ID " << m_currentId << "\n"; - FunctionCache[block_entry.address / 4] = std::make_pair(compileResult.first, m_currentId); - m_currentId++; - block_entry.is_compiled = true; - } -} - -std::shared_ptr RecompilationEngine::GetInstance() { - std::lock_guard lock(s_mutex); - - if (s_the_instance == nullptr) { - s_the_instance = std::shared_ptr(new RecompilationEngine()); - } - - return s_the_instance; -} - -ppu_recompiler_llvm::CPUHybridDecoderRecompiler::CPUHybridDecoderRecompiler(PPUThread & ppu) - : m_ppu(ppu) - , m_interpreter(new PPUInterpreter(ppu)) - , m_decoder(m_interpreter) - , m_recompilation_engine(RecompilationEngine::GetInstance()) { -} - -ppu_recompiler_llvm::CPUHybridDecoderRecompiler::~CPUHybridDecoderRecompiler() { -} - -u32 ppu_recompiler_llvm::CPUHybridDecoderRecompiler::DecodeMemory(const u32 address) { - ExecuteFunction(&m_ppu, 0); - if (m_ppu.pending_exception != nullptr) { - std::exception_ptr exn = m_ppu.pending_exception; - m_ppu.pending_exception = nullptr; - std::rethrow_exception(exn); - } - return 0; -} - -u32 ppu_recompiler_llvm::CPUHybridDecoderRecompiler::ExecuteFunction(PPUThread * ppu_state, u64 context) { - auto execution_engine = (CPUHybridDecoderRecompiler *)ppu_state->GetDecoder(); - if (ExecuteTillReturn(ppu_state, 0) == ExecutionStatus::ExecutionStatusPropagateException) - return ExecutionStatus::ExecutionStatusPropagateException; - return ExecutionStatus::ExecutionStatusReturn; -} - -/// Get the branch type from a branch instruction -static BranchType GetBranchTypeFromInstruction(u32 instruction) -{ - u32 instructionOpcode = PPU_instr::fields::OPCD(instruction); - u32 lk = instruction & 1; - - if (instructionOpcode == PPU_opcodes::PPU_MainOpcodes::B || - instructionOpcode == PPU_opcodes::PPU_MainOpcodes::BC) - return lk ? BranchType::FunctionCall : BranchType::LocalBranch; - if (instructionOpcode == PPU_opcodes::PPU_MainOpcodes::G_13) { - u32 G13Opcode = PPU_instr::fields::GD_13(instruction); - if (G13Opcode == PPU_opcodes::G_13Opcodes::BCLR) - return lk ? BranchType::FunctionCall : BranchType::Return; - if (G13Opcode == PPU_opcodes::G_13Opcodes::BCCTR) - return lk ? BranchType::FunctionCall : BranchType::LocalBranch; - return BranchType::NonBranch; - } - if (instructionOpcode == PPU_opcodes::PPU_MainOpcodes::HACK && (instruction & EIF_PERFORM_BLR)) // classify HACK instruction - return instruction & EIF_USE_BRANCH ? BranchType::FunctionCall : BranchType::Return; - if (instructionOpcode == PPU_opcodes::PPU_MainOpcodes::HACK && (instruction & EIF_USE_BRANCH)) - return BranchType::LocalBranch; - return BranchType::NonBranch; -} - -u32 ppu_recompiler_llvm::CPUHybridDecoderRecompiler::ExecuteTillReturn(PPUThread * ppu_state, u64 context) { - CPUHybridDecoderRecompiler *execution_engine = (CPUHybridDecoderRecompiler *)ppu_state->GetDecoder(); - - // A block is a sequence of contiguous address. - bool previousInstContigousAndInterp = false; - - while (PollStatus(ppu_state) == false) { - const Executable executable = execution_engine->m_recompilation_engine->GetCompiledExecutableIfAvailable(ppu_state->PC); - if (executable) - { - auto entry = ppu_state->PC; - u32 exit = (u32)executable(ppu_state, 0); - if (exit == ExecutionStatus::ExecutionStatusReturn) - { - if (Emu.GetCPUThreadStop() == ppu_state->PC) ppu_state->fast_stop(); - return ExecutionStatus::ExecutionStatusReturn; - } - if (exit == ExecutionStatus::ExecutionStatusPropagateException) - return ExecutionStatus::ExecutionStatusPropagateException; - previousInstContigousAndInterp = false; - continue; - } - // if previousInstContigousAndInterp is true, ie previous step was either a compiled block or a branch inst - // that caused a "gap" in instruction flow, we notify a new block. - if (!previousInstContigousAndInterp) - execution_engine->m_recompilation_engine->NotifyBlockStart(ppu_state->PC); - u32 instruction = vm::ps3::read32(ppu_state->PC); - u32 oldPC = ppu_state->PC; - try - { - execution_engine->m_decoder.Decode(instruction); - } - catch (...) - { - ppu_state->pending_exception = std::current_exception(); - return ExecutionStatus::ExecutionStatusPropagateException; - } - previousInstContigousAndInterp = (oldPC == ppu_state->PC); - auto branch_type = ppu_state->PC != oldPC ? GetBranchTypeFromInstruction(instruction) : BranchType::NonBranch; - ppu_state->PC += 4; - - switch (branch_type) { - case BranchType::Return: - if (Emu.GetCPUThreadStop() == ppu_state->PC) ppu_state->fast_stop(); - return 0; - case BranchType::FunctionCall: { - u32 status = ExecuteFunction(ppu_state, 0); - if (status == ExecutionStatus::ExecutionStatusPropagateException) - return ExecutionStatus::ExecutionStatusPropagateException; - break; - } - case BranchType::LocalBranch: - break; - case BranchType::NonBranch: - break; - default: - assert(0); - break; - } - } - - return 0; -} - -bool ppu_recompiler_llvm::CPUHybridDecoderRecompiler::PollStatus(PPUThread * ppu_state) { - try - { - return ppu_state->check_status(); - } - catch (...) - { - ppu_state->pending_exception = std::current_exception(); - return true; - } -} -#endif // LLVM_AVAILABLE diff --git a/rpcs3/Emu/Cell/PPULLVMRecompiler.h b/rpcs3/Emu/Cell/PPULLVMRecompiler.h deleted file mode 100644 index 1b882f68d5..0000000000 --- a/rpcs3/Emu/Cell/PPULLVMRecompiler.h +++ /dev/null @@ -1,946 +0,0 @@ -#ifndef PPU_LLVM_RECOMPILER_H -#define PPU_LLVM_RECOMPILER_H - -#ifdef LLVM_AVAILABLE -#define PPU_LLVM_RECOMPILER 1 - -#include -#include "Emu/Cell/PPUDecoder.h" -#include "Emu/Cell/PPUThread.h" -#include "Emu/Cell/PPUInterpreter.h" -#ifdef _MSC_VER -#pragma warning(push, 0) -#endif -#include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/ExecutionEngine/SectionMemoryManager.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/GlobalVariable.h" -#include "llvm/PassManager.h" -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -namespace ppu_recompiler_llvm { - enum ExecutionStatus - { - ExecutionStatusReturn = 0, ///< Block has hit a return, caller can continue execution - ExecutionStatusBlockEnded, ///< Block has been executed but no return was hit, at least another block must be executed before caller can continue - ExecutionStatusPropagateException, ///< an exception was thrown - }; - - class Compiler; - class RecompilationEngine; - class ExecutionEngine; - struct PPUState; - - enum class BranchType { - NonBranch, - LocalBranch, - FunctionCall, - Return, - }; - - /// Pointer to an executable - typedef u32(*Executable)(PPUThread * ppu_state, u64 context); - - /// Parses PPU opcodes and translate them into llvm ir. - class Compiler : protected PPUOpcodes, protected PPCDecoder { - public: - Compiler(llvm::LLVMContext *context, llvm::IRBuilder<> *builder, std::unordered_map &function_ptrs); - - Compiler(const Compiler&) = delete; // Delete copy/move constructors and copy/move operators - - virtual ~Compiler(); - - /// Create a module setting target triples and some callbacks - static std::unique_ptr create_module(llvm::LLVMContext &llvm_context); - - /// Create a function called name in module and populates it by translating block at start_address with instruction_count length. - void translate_to_llvm_ir(llvm::Module *module, const std::string & name, u32 start_address, u32 instruction_count); - - static void optimise_module(llvm::Module *module); - - protected: - void Decode(const u32 code) override; - - void NULL_OP() override; - void NOP() override; - - void TDI(u32 to, u32 ra, s32 simm16) override; - void TWI(u32 to, u32 ra, s32 simm16) override; - - void MFVSCR(u32 vd) override; - void MTVSCR(u32 vb) override; - void VADDCUW(u32 vd, u32 va, u32 vb) override; - void VADDFP(u32 vd, u32 va, u32 vb) override; - void VADDSBS(u32 vd, u32 va, u32 vb) override; - void VADDSHS(u32 vd, u32 va, u32 vb) override; - void VADDSWS(u32 vd, u32 va, u32 vb) override; - void VADDUBM(u32 vd, u32 va, u32 vb) override; - void VADDUBS(u32 vd, u32 va, u32 vb) override; - void VADDUHM(u32 vd, u32 va, u32 vb) override; - void VADDUHS(u32 vd, u32 va, u32 vb) override; - void VADDUWM(u32 vd, u32 va, u32 vb) override; - void VADDUWS(u32 vd, u32 va, u32 vb) override; - void VAND(u32 vd, u32 va, u32 vb) override; - void VANDC(u32 vd, u32 va, u32 vb) override; - void VAVGSB(u32 vd, u32 va, u32 vb) override; - void VAVGSH(u32 vd, u32 va, u32 vb) override; - void VAVGSW(u32 vd, u32 va, u32 vb) override; - void VAVGUB(u32 vd, u32 va, u32 vb) override; - void VAVGUH(u32 vd, u32 va, u32 vb) override; - void VAVGUW(u32 vd, u32 va, u32 vb) override; - void VCFSX(u32 vd, u32 uimm5, u32 vb) override; - void VCFUX(u32 vd, u32 uimm5, u32 vb) override; - void VCMPBFP(u32 vd, u32 va, u32 vb) override; - void VCMPBFP_(u32 vd, u32 va, u32 vb) override; - void VCMPEQFP(u32 vd, u32 va, u32 vb) override; - void VCMPEQFP_(u32 vd, u32 va, u32 vb) override; - void VCMPEQUB(u32 vd, u32 va, u32 vb) override; - void VCMPEQUB_(u32 vd, u32 va, u32 vb) override; - void VCMPEQUH(u32 vd, u32 va, u32 vb) override; - void VCMPEQUH_(u32 vd, u32 va, u32 vb) override; - void VCMPEQUW(u32 vd, u32 va, u32 vb) override; - void VCMPEQUW_(u32 vd, u32 va, u32 vb) override; - void VCMPGEFP(u32 vd, u32 va, u32 vb) override; - void VCMPGEFP_(u32 vd, u32 va, u32 vb) override; - void VCMPGTFP(u32 vd, u32 va, u32 vb) override; - void VCMPGTFP_(u32 vd, u32 va, u32 vb) override; - void VCMPGTSB(u32 vd, u32 va, u32 vb) override; - void VCMPGTSB_(u32 vd, u32 va, u32 vb) override; - void VCMPGTSH(u32 vd, u32 va, u32 vb) override; - void VCMPGTSH_(u32 vd, u32 va, u32 vb) override; - void VCMPGTSW(u32 vd, u32 va, u32 vb) override; - void VCMPGTSW_(u32 vd, u32 va, u32 vb) override; - void VCMPGTUB(u32 vd, u32 va, u32 vb) override; - void VCMPGTUB_(u32 vd, u32 va, u32 vb) override; - void VCMPGTUH(u32 vd, u32 va, u32 vb) override; - void VCMPGTUH_(u32 vd, u32 va, u32 vb) override; - void VCMPGTUW(u32 vd, u32 va, u32 vb) override; - void VCMPGTUW_(u32 vd, u32 va, u32 vb) override; - void VCTSXS(u32 vd, u32 uimm5, u32 vb) override; - void VCTUXS(u32 vd, u32 uimm5, u32 vb) override; - void VEXPTEFP(u32 vd, u32 vb) override; - void VLOGEFP(u32 vd, u32 vb) override; - void VMADDFP(u32 vd, u32 va, u32 vc, u32 vb) override; - void VMAXFP(u32 vd, u32 va, u32 vb) override; - void VMAXSB(u32 vd, u32 va, u32 vb) override; - void VMAXSH(u32 vd, u32 va, u32 vb) override; - void VMAXSW(u32 vd, u32 va, u32 vb) override; - void VMAXUB(u32 vd, u32 va, u32 vb) override; - void VMAXUH(u32 vd, u32 va, u32 vb) override; - void VMAXUW(u32 vd, u32 va, u32 vb) override; - void VMHADDSHS(u32 vd, u32 va, u32 vb, u32 vc) override; - void VMHRADDSHS(u32 vd, u32 va, u32 vb, u32 vc) override; - void VMINFP(u32 vd, u32 va, u32 vb) override; - void VMINSB(u32 vd, u32 va, u32 vb) override; - void VMINSH(u32 vd, u32 va, u32 vb) override; - void VMINSW(u32 vd, u32 va, u32 vb) override; - void VMINUB(u32 vd, u32 va, u32 vb) override; - void VMINUH(u32 vd, u32 va, u32 vb) override; - void VMINUW(u32 vd, u32 va, u32 vb) override; - void VMLADDUHM(u32 vd, u32 va, u32 vb, u32 vc) override; - void VMRGHB(u32 vd, u32 va, u32 vb) override; - void VMRGHH(u32 vd, u32 va, u32 vb) override; - void VMRGHW(u32 vd, u32 va, u32 vb) override; - void VMRGLB(u32 vd, u32 va, u32 vb) override; - void VMRGLH(u32 vd, u32 va, u32 vb) override; - void VMRGLW(u32 vd, u32 va, u32 vb) override; - void VMSUMMBM(u32 vd, u32 va, u32 vb, u32 vc) override; - void VMSUMSHM(u32 vd, u32 va, u32 vb, u32 vc) override; - void VMSUMSHS(u32 vd, u32 va, u32 vb, u32 vc) override; - void VMSUMUBM(u32 vd, u32 va, u32 vb, u32 vc) override; - void VMSUMUHM(u32 vd, u32 va, u32 vb, u32 vc) override; - void VMSUMUHS(u32 vd, u32 va, u32 vb, u32 vc) override; - void VMULESB(u32 vd, u32 va, u32 vb) override; - void VMULESH(u32 vd, u32 va, u32 vb) override; - void VMULEUB(u32 vd, u32 va, u32 vb) override; - void VMULEUH(u32 vd, u32 va, u32 vb) override; - void VMULOSB(u32 vd, u32 va, u32 vb) override; - void VMULOSH(u32 vd, u32 va, u32 vb) override; - void VMULOUB(u32 vd, u32 va, u32 vb) override; - void VMULOUH(u32 vd, u32 va, u32 vb) override; - void VNMSUBFP(u32 vd, u32 va, u32 vc, u32 vb) override; - void VNOR(u32 vd, u32 va, u32 vb) override; - void VOR(u32 vd, u32 va, u32 vb) override; - void VPERM(u32 vd, u32 va, u32 vb, u32 vc) override; - void VPKPX(u32 vd, u32 va, u32 vb) override; - void VPKSHSS(u32 vd, u32 va, u32 vb) override; - void VPKSHUS(u32 vd, u32 va, u32 vb) override; - void VPKSWSS(u32 vd, u32 va, u32 vb) override; - void VPKSWUS(u32 vd, u32 va, u32 vb) override; - void VPKUHUM(u32 vd, u32 va, u32 vb) override; - void VPKUHUS(u32 vd, u32 va, u32 vb) override; - void VPKUWUM(u32 vd, u32 va, u32 vb) override; - void VPKUWUS(u32 vd, u32 va, u32 vb) override; - void VREFP(u32 vd, u32 vb) override; - void VRFIM(u32 vd, u32 vb) override; - void VRFIN(u32 vd, u32 vb) override; - void VRFIP(u32 vd, u32 vb) override; - void VRFIZ(u32 vd, u32 vb) override; - void VRLB(u32 vd, u32 va, u32 vb) override; - void VRLH(u32 vd, u32 va, u32 vb) override; - void VRLW(u32 vd, u32 va, u32 vb) override; - void VRSQRTEFP(u32 vd, u32 vb) override; - void VSEL(u32 vd, u32 va, u32 vb, u32 vc) override; - void VSL(u32 vd, u32 va, u32 vb) override; - void VSLB(u32 vd, u32 va, u32 vb) override; - void VSLDOI(u32 vd, u32 va, u32 vb, u32 sh) override; - void VSLH(u32 vd, u32 va, u32 vb) override; - void VSLO(u32 vd, u32 va, u32 vb) override; - void VSLW(u32 vd, u32 va, u32 vb) override; - void VSPLTB(u32 vd, u32 uimm5, u32 vb) override; - void VSPLTH(u32 vd, u32 uimm5, u32 vb) override; - void VSPLTISB(u32 vd, s32 simm5) override; - void VSPLTISH(u32 vd, s32 simm5) override; - void VSPLTISW(u32 vd, s32 simm5) override; - void VSPLTW(u32 vd, u32 uimm5, u32 vb) override; - void VSR(u32 vd, u32 va, u32 vb) override; - void VSRAB(u32 vd, u32 va, u32 vb) override; - void VSRAH(u32 vd, u32 va, u32 vb) override; - void VSRAW(u32 vd, u32 va, u32 vb) override; - void VSRB(u32 vd, u32 va, u32 vb) override; - void VSRH(u32 vd, u32 va, u32 vb) override; - void VSRO(u32 vd, u32 va, u32 vb) override; - void VSRW(u32 vd, u32 va, u32 vb) override; - void VSUBCUW(u32 vd, u32 va, u32 vb) override; - void VSUBFP(u32 vd, u32 va, u32 vb) override; - void VSUBSBS(u32 vd, u32 va, u32 vb) override; - void VSUBSHS(u32 vd, u32 va, u32 vb) override; - void VSUBSWS(u32 vd, u32 va, u32 vb) override; - void VSUBUBM(u32 vd, u32 va, u32 vb) override; - void VSUBUBS(u32 vd, u32 va, u32 vb) override; - void VSUBUHM(u32 vd, u32 va, u32 vb) override; - void VSUBUHS(u32 vd, u32 va, u32 vb) override; - void VSUBUWM(u32 vd, u32 va, u32 vb) override; - void VSUBUWS(u32 vd, u32 va, u32 vb) override; - void VSUMSWS(u32 vd, u32 va, u32 vb) override; - void VSUM2SWS(u32 vd, u32 va, u32 vb) override; - void VSUM4SBS(u32 vd, u32 va, u32 vb) override; - void VSUM4SHS(u32 vd, u32 va, u32 vb) override; - void VSUM4UBS(u32 vd, u32 va, u32 vb) override; - void VUPKHPX(u32 vd, u32 vb) override; - void VUPKHSB(u32 vd, u32 vb) override; - void VUPKHSH(u32 vd, u32 vb) override; - void VUPKLPX(u32 vd, u32 vb) override; - void VUPKLSB(u32 vd, u32 vb) override; - void VUPKLSH(u32 vd, u32 vb) override; - void VXOR(u32 vd, u32 va, u32 vb) override; - void MULLI(u32 rd, u32 ra, s32 simm16) override; - void SUBFIC(u32 rd, u32 ra, s32 simm16) override; - void CMPLI(u32 bf, u32 l, u32 ra, u32 uimm16) override; - void CMPI(u32 bf, u32 l, u32 ra, s32 simm16) override; - void ADDIC(u32 rd, u32 ra, s32 simm16) override; - void ADDIC_(u32 rd, u32 ra, s32 simm16) override; - void ADDI(u32 rd, u32 ra, s32 simm16) override; - void ADDIS(u32 rd, u32 ra, s32 simm16) override; - void BC(u32 bo, u32 bi, s32 bd, u32 aa, u32 lk) override; - void HACK(u32 id) override; - void SC(u32 sc_code) override; - void B(s32 ll, u32 aa, u32 lk) override; - void MCRF(u32 crfd, u32 crfs) override; - void BCLR(u32 bo, u32 bi, u32 bh, u32 lk) override; - void CRNOR(u32 bt, u32 ba, u32 bb) override; - void CRANDC(u32 bt, u32 ba, u32 bb) override; - void ISYNC() override; - void CRXOR(u32 bt, u32 ba, u32 bb) override; - void CRNAND(u32 bt, u32 ba, u32 bb) override; - void CRAND(u32 bt, u32 ba, u32 bb) override; - void CREQV(u32 bt, u32 ba, u32 bb) override; - void CRORC(u32 bt, u32 ba, u32 bb) override; - void CROR(u32 bt, u32 ba, u32 bb) override; - void BCCTR(u32 bo, u32 bi, u32 bh, u32 lk) override; - void RLWIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) override; - void RLWINM(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) override; - void RLWNM(u32 ra, u32 rs, u32 rb, u32 MB, u32 ME, u32 rc) override; - void ORI(u32 rs, u32 ra, u32 uimm16) override; - void ORIS(u32 rs, u32 ra, u32 uimm16) override; - void XORI(u32 ra, u32 rs, u32 uimm16) override; - void XORIS(u32 ra, u32 rs, u32 uimm16) override; - void ANDI_(u32 ra, u32 rs, u32 uimm16) override; - void ANDIS_(u32 ra, u32 rs, u32 uimm16) override; - void RLDICL(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) override; - void RLDICR(u32 ra, u32 rs, u32 sh, u32 me, u32 rc) override; - void RLDIC(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) override; - void RLDIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) override; - void RLDC_LR(u32 ra, u32 rs, u32 rb, u32 m_eb, u32 is_r, u32 rc) override; - void CMP(u32 crfd, u32 l, u32 ra, u32 rb) override; - void TW(u32 to, u32 ra, u32 rb) override; - void LVSL(u32 vd, u32 ra, u32 rb) override; - void LVEBX(u32 vd, u32 ra, u32 rb) override; - void SUBFC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override; - void MULHDU(u32 rd, u32 ra, u32 rb, u32 rc) override; - void ADDC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override; - void MULHWU(u32 rd, u32 ra, u32 rb, u32 rc) override; - void MFOCRF(u32 a, u32 rd, u32 crm) override; - void LWARX(u32 rd, u32 ra, u32 rb) override; - void LDX(u32 ra, u32 rs, u32 rb) override; - void LWZX(u32 rd, u32 ra, u32 rb) override; - void SLW(u32 ra, u32 rs, u32 rb, u32 rc) override; - void CNTLZW(u32 ra, u32 rs, u32 rc) override; - void SLD(u32 ra, u32 rs, u32 rb, u32 rc) override; - void AND(u32 ra, u32 rs, u32 rb, u32 rc) override; - void CMPL(u32 bf, u32 l, u32 ra, u32 rb) override; - void LVSR(u32 vd, u32 ra, u32 rb) override; - void LVEHX(u32 vd, u32 ra, u32 rb) override; - void SUBF(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override; - void LDUX(u32 rd, u32 ra, u32 rb) override; - void DCBST(u32 ra, u32 rb) override; - void LWZUX(u32 rd, u32 ra, u32 rb) override; - void CNTLZD(u32 ra, u32 rs, u32 rc) override; - void ANDC(u32 ra, u32 rs, u32 rb, u32 rc) override; - void TD(u32 to, u32 ra, u32 rb) override; - void LVEWX(u32 vd, u32 ra, u32 rb) override; - void MULHD(u32 rd, u32 ra, u32 rb, u32 rc) override; - void MULHW(u32 rd, u32 ra, u32 rb, u32 rc) override; - void LDARX(u32 rd, u32 ra, u32 rb) override; - void DCBF(u32 ra, u32 rb) override; - void LBZX(u32 rd, u32 ra, u32 rb) override; - void LVX(u32 vd, u32 ra, u32 rb) override; - void NEG(u32 rd, u32 ra, u32 oe, u32 rc) override; - void LBZUX(u32 rd, u32 ra, u32 rb) override; - void NOR(u32 ra, u32 rs, u32 rb, u32 rc) override; - void STVEBX(u32 vs, u32 ra, u32 rb) override; - void SUBFE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override; - void ADDE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override; - void MTOCRF(u32 l, u32 crm, u32 rs) override; - void STDX(u32 rs, u32 ra, u32 rb) override; - void STWCX_(u32 rs, u32 ra, u32 rb) override; - void STWX(u32 rs, u32 ra, u32 rb) override; - void STVEHX(u32 vs, u32 ra, u32 rb) override; - void STDUX(u32 rs, u32 ra, u32 rb) override; - void STWUX(u32 rs, u32 ra, u32 rb) override; - void STVEWX(u32 vs, u32 ra, u32 rb) override; - void SUBFZE(u32 rd, u32 ra, u32 oe, u32 rc) override; - void ADDZE(u32 rd, u32 ra, u32 oe, u32 rc) override; - void STDCX_(u32 rs, u32 ra, u32 rb) override; - void STBX(u32 rs, u32 ra, u32 rb) override; - void STVX(u32 vs, u32 ra, u32 rb) override; - void MULLD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override; - void SUBFME(u32 rd, u32 ra, u32 oe, u32 rc) override; - void ADDME(u32 rd, u32 ra, u32 oe, u32 rc) override; - void MULLW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override; - void DCBTST(u32 ra, u32 rb, u32 th) override; - void STBUX(u32 rs, u32 ra, u32 rb) override; - void ADD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override; - void DCBT(u32 ra, u32 rb, u32 th) override; - void LHZX(u32 rd, u32 ra, u32 rb) override; - void EQV(u32 ra, u32 rs, u32 rb, u32 rc) override; - void ECIWX(u32 rd, u32 ra, u32 rb) override; - void LHZUX(u32 rd, u32 ra, u32 rb) override; - void XOR(u32 rs, u32 ra, u32 rb, u32 rc) override; - void MFSPR(u32 rd, u32 spr) override; - void LWAX(u32 rd, u32 ra, u32 rb) override; - void DST(u32 ra, u32 rb, u32 strm, u32 t) override; - void LHAX(u32 rd, u32 ra, u32 rb) override; - void LVXL(u32 vd, u32 ra, u32 rb) override; - void MFTB(u32 rd, u32 spr) override; - void LWAUX(u32 rd, u32 ra, u32 rb) override; - void DSTST(u32 ra, u32 rb, u32 strm, u32 t) override; - void LHAUX(u32 rd, u32 ra, u32 rb) override; - void STHX(u32 rs, u32 ra, u32 rb) override; - void ORC(u32 rs, u32 ra, u32 rb, u32 rc) override; - void ECOWX(u32 rs, u32 ra, u32 rb) override; - void STHUX(u32 rs, u32 ra, u32 rb) override; - void OR(u32 ra, u32 rs, u32 rb, u32 rc) override; - void DIVDU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override; - void DIVWU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override; - void MTSPR(u32 spr, u32 rs) override; - void DCBI(u32 ra, u32 rb) override; - void NAND(u32 ra, u32 rs, u32 rb, u32 rc) override; - void STVXL(u32 vs, u32 ra, u32 rb) override; - void DIVD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override; - void DIVW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override; - void LVLX(u32 vd, u32 ra, u32 rb) override; - void LDBRX(u32 rd, u32 ra, u32 rb) override; - void LSWX(u32 rd, u32 ra, u32 rb) override; - void LWBRX(u32 rd, u32 ra, u32 rb) override; - void LFSX(u32 frd, u32 ra, u32 rb) override; - void SRW(u32 ra, u32 rs, u32 rb, u32 rc) override; - void SRD(u32 ra, u32 rs, u32 rb, u32 rc) override; - void LVRX(u32 vd, u32 ra, u32 rb) override; - void LSWI(u32 rd, u32 ra, u32 nb) override; - void LFSUX(u32 frd, u32 ra, u32 rb) override; - void SYNC(u32 l) override; - void LFDX(u32 frd, u32 ra, u32 rb) override; - void LFDUX(u32 frd, u32 ra, u32 rb) override; - void STVLX(u32 vs, u32 ra, u32 rb) override; - void STDBRX(u32 rd, u32 ra, u32 rb) override; - void STSWX(u32 rs, u32 ra, u32 rb) override; - void STWBRX(u32 rs, u32 ra, u32 rb) override; - void STFSX(u32 frs, u32 ra, u32 rb) override; - void STVRX(u32 vs, u32 ra, u32 rb) override; - void STFSUX(u32 frs, u32 ra, u32 rb) override; - void STSWI(u32 rd, u32 ra, u32 nb) override; - void STFDX(u32 frs, u32 ra, u32 rb) override; - void STFDUX(u32 frs, u32 ra, u32 rb) override; - void LVLXL(u32 vd, u32 ra, u32 rb) override; - void LHBRX(u32 rd, u32 ra, u32 rb) override; - void SRAW(u32 ra, u32 rs, u32 rb, u32 rc) override; - void SRAD(u32 ra, u32 rs, u32 rb, u32 rc) override; - void LVRXL(u32 vd, u32 ra, u32 rb) override; - void DSS(u32 strm, u32 a) override; - void SRAWI(u32 ra, u32 rs, u32 sh, u32 rc) override; - void SRADI1(u32 ra, u32 rs, u32 sh, u32 rc) override; - void SRADI2(u32 ra, u32 rs, u32 sh, u32 rc) override; - void EIEIO() override; - void STVLXL(u32 vs, u32 ra, u32 rb) override; - void STHBRX(u32 rs, u32 ra, u32 rb) override; - void EXTSH(u32 ra, u32 rs, u32 rc) override; - void STVRXL(u32 sd, u32 ra, u32 rb) override; - void EXTSB(u32 ra, u32 rs, u32 rc) override; - void STFIWX(u32 frs, u32 ra, u32 rb) override; - void EXTSW(u32 ra, u32 rs, u32 rc) override; - void ICBI(u32 ra, u32 rb) override; - void DCBZ(u32 ra, u32 rb) override; - void LWZ(u32 rd, u32 ra, s32 d) override; - void LWZU(u32 rd, u32 ra, s32 d) override; - void LBZ(u32 rd, u32 ra, s32 d) override; - void LBZU(u32 rd, u32 ra, s32 d) override; - void STW(u32 rs, u32 ra, s32 d) override; - void STWU(u32 rs, u32 ra, s32 d) override; - void STB(u32 rs, u32 ra, s32 d) override; - void STBU(u32 rs, u32 ra, s32 d) override; - void LHZ(u32 rd, u32 ra, s32 d) override; - void LHZU(u32 rd, u32 ra, s32 d) override; - void LHA(u32 rs, u32 ra, s32 d) override; - void LHAU(u32 rs, u32 ra, s32 d) override; - void STH(u32 rs, u32 ra, s32 d) override; - void STHU(u32 rs, u32 ra, s32 d) override; - void LMW(u32 rd, u32 ra, s32 d) override; - void STMW(u32 rs, u32 ra, s32 d) override; - void LFS(u32 frd, u32 ra, s32 d) override; - void LFSU(u32 frd, u32 ra, s32 d) override; - void LFD(u32 frd, u32 ra, s32 d) override; - void LFDU(u32 frd, u32 ra, s32 d) override; - void STFS(u32 frs, u32 ra, s32 d) override; - void STFSU(u32 frs, u32 ra, s32 d) override; - void STFD(u32 frs, u32 ra, s32 d) override; - void STFDU(u32 frs, u32 ra, s32 d) override; - void LD(u32 rd, u32 ra, s32 ds) override; - void LDU(u32 rd, u32 ra, s32 ds) override; - void LWA(u32 rd, u32 ra, s32 ds) override; - void FDIVS(u32 frd, u32 fra, u32 frb, u32 rc) override; - void FSUBS(u32 frd, u32 fra, u32 frb, u32 rc) override; - void FADDS(u32 frd, u32 fra, u32 frb, u32 rc) override; - void FSQRTS(u32 frd, u32 frb, u32 rc) override; - void FRES(u32 frd, u32 frb, u32 rc) override; - void FMULS(u32 frd, u32 fra, u32 frc, u32 rc) override; - void FMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override; - void FMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override; - void FNMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override; - void FNMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override; - void STD(u32 rs, u32 ra, s32 ds) override; - void STDU(u32 rs, u32 ra, s32 ds) override; - void MTFSB1(u32 bt, u32 rc) override; - void MCRFS(u32 bf, u32 bfa) override; - void MTFSB0(u32 bt, u32 rc) override; - void MTFSFI(u32 crfd, u32 i, u32 rc) override; - void MFFS(u32 frd, u32 rc) override; - void MTFSF(u32 flm, u32 frb, u32 rc) override; - - void FCMPU(u32 bf, u32 fra, u32 frb) override; - void FRSP(u32 frd, u32 frb, u32 rc) override; - void FCTIW(u32 frd, u32 frb, u32 rc) override; - void FCTIWZ(u32 frd, u32 frb, u32 rc) override; - void FDIV(u32 frd, u32 fra, u32 frb, u32 rc) override; - void FSUB(u32 frd, u32 fra, u32 frb, u32 rc) override; - void FADD(u32 frd, u32 fra, u32 frb, u32 rc) override; - void FSQRT(u32 frd, u32 frb, u32 rc) override; - void FSEL(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override; - void FMUL(u32 frd, u32 fra, u32 frc, u32 rc) override; - void FRSQRTE(u32 frd, u32 frb, u32 rc) override; - void FMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override; - void FMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override; - void FNMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override; - void FNMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override; - void FCMPO(u32 crfd, u32 fra, u32 frb) override; - void FNEG(u32 frd, u32 frb, u32 rc) override; - void FMR(u32 frd, u32 frb, u32 rc) override; - void FNABS(u32 frd, u32 frb, u32 rc) override; - void FABS(u32 frd, u32 frb, u32 rc) override; - void FCTID(u32 frd, u32 frb, u32 rc) override; - void FCTIDZ(u32 frd, u32 frb, u32 rc) override; - void FCFID(u32 frd, u32 frb, u32 rc) override; - - void UNK(const u32 code, const u32 opcode, const u32 gcode) override; - - /// Utility function creating a function called name with Executable signature - void initiate_function(const std::string &name); - - protected: - /// State of a compilation task - struct CompileTaskState { - enum Args { - State, - Context, - MaxArgs, - }; - - /// The LLVM function for the compilation task - llvm::Function * function; - - /// Args of the LLVM function - llvm::Value * args[MaxArgs]; - - /// Address of the current instruction being compiled - u32 current_instruction_address; - - /// A flag used to detect branch instructions. - /// This is set to false at the start of compilation of an instruction. - /// If a branch instruction is encountered, this is set to true by the decode function. - bool hit_branch_instruction; - }; - - /// The function that will be called to execute unknown functions - llvm::Function * m_execute_unknown_function; - - /// The executable that will be called to execute unknown blocks - llvm::Function * m_execute_unknown_block; - - /// Maps function name to executable memory pointer - std::unordered_map &m_executable_map; - - /// LLVM context - llvm::LLVMContext * m_llvm_context; - - /// LLVM IR builder - llvm::IRBuilder<> * m_ir_builder; - - /// Module to which all generated code is output to - llvm::Module * m_module; - - /// LLVM type of the functions genreated by the compiler - llvm::FunctionType * m_compiled_function_type; - - /// State of the current compilation task - CompileTaskState m_state; - - /// Get the name of the basic block for the specified address - std::string GetBasicBlockNameFromAddress(u32 address, const std::string & suffix = "") const; - - /// Get the address of a basic block from its name - u32 GetAddressFromBasicBlockName(const std::string & name) const; - - /// Get the basic block in for the specified address. - llvm::BasicBlock * GetBasicBlockFromAddress(u32 address, const std::string & suffix = "", bool create_if_not_exist = true); - - /// Get a bit - llvm::Value * GetBit(llvm::Value * val, u32 n); - - /// Clear a bit - llvm::Value * ClrBit(llvm::Value * val, u32 n); - - /// Set a bit - llvm::Value * SetBit(llvm::Value * val, u32 n, llvm::Value * bit, bool doClear = true); - - /// Get a nibble - llvm::Value * GetNibble(llvm::Value * val, u32 n); - - /// Clear a nibble - llvm::Value * ClrNibble(llvm::Value * val, u32 n); - - /// Set a nibble - llvm::Value * SetNibble(llvm::Value * val, u32 n, llvm::Value * nibble, bool doClear = true); - - /// Set a nibble - llvm::Value * SetNibble(llvm::Value * val, u32 n, llvm::Value * b0, llvm::Value * b1, llvm::Value * b2, llvm::Value * b3, bool doClear = true); - - /// Load PC - llvm::Value * GetPc(); - - /// Set PC - void SetPc(llvm::Value * val_ix); - - /// Load GPR - llvm::Value * GetGpr(u32 r, u32 num_bits = 64); - - /// Set GPR - void SetGpr(u32 r, llvm::Value * val_x64); - - /// Load CR - llvm::Value * GetCr(); - - /// Load CR and get field CRn - llvm::Value * GetCrField(u32 n); - - /// Set CR - void SetCr(llvm::Value * val_x32); - - /// Set CR field - void SetCrField(u32 n, llvm::Value * field); - - /// Set CR field - void SetCrField(u32 n, llvm::Value * b0, llvm::Value * b1, llvm::Value * b2, llvm::Value * b3); - - /// Set CR field based on signed comparison - void SetCrFieldSignedCmp(u32 n, llvm::Value * a, llvm::Value * b); - - /// Set CR field based on unsigned comparison - void SetCrFieldUnsignedCmp(u32 n, llvm::Value * a, llvm::Value * b); - - /// Set CR6 based on the result of the vector compare instruction - void SetCr6AfterVectorCompare(u32 vr); - - /// Get LR - llvm::Value * GetLr(); - - /// Set LR - void SetLr(llvm::Value * val_x64); - - /// Get CTR - llvm::Value * GetCtr(); - - /// Set CTR - void SetCtr(llvm::Value * val_x64); - - /// Load XER and convert it to an i64 - llvm::Value * GetXer(); - - /// Load XER and return the CA bit - llvm::Value * GetXerCa(); - - /// Load XER and return the SO bit - llvm::Value * GetXerSo(); - - /// Set XER - void SetXer(llvm::Value * val_x64); - - /// Set the CA bit of XER - void SetXerCa(llvm::Value * ca); - - /// Set the SO bit of XER - void SetXerSo(llvm::Value * so); - - /// Get VRSAVE - llvm::Value * GetVrsave(); - - /// Set VRSAVE - void SetVrsave(llvm::Value * val_x64); - - /// Load FPSCR - llvm::Value * GetFpscr(); - - /// Set FPSCR - void SetFpscr(llvm::Value * val_x32); - - /// Get FPR - llvm::Value * GetFpr(u32 r, u32 bits = 64, bool as_int = false); - - /// Set FPR - void SetFpr(u32 r, llvm::Value * val); - - /// Load VSCR - llvm::Value * GetVscr(); - - /// Set VSCR - void SetVscr(llvm::Value * val_x32); - - /// Load VR - llvm::Value * GetVr(u32 vr); - - /// Load VR and convert it to an integer vector - llvm::Value * GetVrAsIntVec(u32 vr, u32 vec_elt_num_bits); - - /// Load VR and convert it to a float vector with 4 elements - llvm::Value * GetVrAsFloatVec(u32 vr); - - /// Load VR and convert it to a double vector with 2 elements - llvm::Value * GetVrAsDoubleVec(u32 vr); - - /// Set VR to the specified value - void SetVr(u32 vr, llvm::Value * val_x128); - - /// Check condition for branch instructions - llvm::Value * CheckBranchCondition(u32 bo, u32 bi); - - /// Create IR for a branch instruction - void CreateBranch(llvm::Value * cmp_i1, llvm::Value * target_i32, bool lk, bool target_is_lr = false); - - /// Read from memory - llvm::Value * ReadMemory(llvm::Value * addr_i64, u32 bits, u32 alignment = 0, bool bswap = true, bool could_be_mmio = true); - - /// Write to memory - void WriteMemory(llvm::Value * addr_i64, llvm::Value * val_ix, u32 alignment = 0, bool bswap = true, bool could_be_mmio = true); - - /// Convert a C++ type to an LLVM type - template - llvm::Type * CppToLlvmType() { - if (std::is_void::value) { - return m_ir_builder->getVoidTy(); - } - else if (std::is_same::value || std::is_same::value) { - return m_ir_builder->getInt64Ty(); - } - else if (std::is_same::value || std::is_same::value) { - return m_ir_builder->getInt32Ty(); - } - else if (std::is_same::value || std::is_same::value) { - return m_ir_builder->getInt16Ty(); - } - else if (std::is_same::value || std::is_same::value) { - return m_ir_builder->getInt8Ty(); - } - else if (std::is_same::value) { - return m_ir_builder->getFloatTy(); - } - else if (std::is_same::value) { - return m_ir_builder->getDoubleTy(); - } - else if (std::is_same::value) { - return m_ir_builder->getInt1Ty(); - } - else if (std::is_pointer::value) { - return m_ir_builder->getInt8PtrTy(); - } - else { - assert(0); - } - - return nullptr; - } - - /// Call a function - template - llvm::Value * Call(const char * name, Args... args) { - auto fn = m_module->getFunction(name); - if (!fn) { - std::vector fn_args_type = { args->getType()... }; - auto fn_type = llvm::FunctionType::get(CppToLlvmType(), fn_args_type, false); - fn = llvm::cast(m_module->getOrInsertFunction(name, fn_type)); - fn->setCallingConv(llvm::CallingConv::X86_64_Win64); - // Create an entry in m_executable_map that will be populated outside of compiler - (void)m_executable_map[name]; - } - - std::vector fn_args = { args... }; - return m_ir_builder->CreateCall(fn, fn_args); - } - - /// Handle compilation errors - void CompilationError(const std::string & error); - - /// A mask used in rotate instructions - static u64 s_rotate_mask[64][64]; - - /// A flag indicating whether s_rotate_mask has been initialised or not - static bool s_rotate_mask_inited; - - /// Initialse s_rotate_mask - static void InitRotateMask(); - }; - - /** - * Manages block compilation. - * PPUInterpreter1 execution is traced (using Tracer class) - * Periodically RecompilationEngine process traces result to find blocks - * whose compilation can improve performances. - * It then builds them asynchroneously and update the executable mapping - * using atomic based locks to avoid undefined behavior. - **/ - class RecompilationEngine final : public named_thread_t { - friend class CPUHybridDecoderRecompiler; - public: - virtual ~RecompilationEngine() override; - - /** - * Get the executable for the specified address if a compiled version is - * available, otherwise returns nullptr. - **/ - const Executable GetCompiledExecutableIfAvailable(u32 address) const; - - /// Notify the recompilation engine about a newly detected block start. - void NotifyBlockStart(u32 address); - - /// Log - llvm::raw_fd_ostream & Log(); - - std::string get_name() const override { return "PPU Recompilation Engine"; } - - void on_task() override; - - /// Get a pointer to the instance of this class - static std::shared_ptr GetInstance(); - - private: - /// An entry in the block table - struct BlockEntry { - /// Start address - u32 address; - - /// Number of times this block was hit - u32 num_hits; - - /// Indicates whether this function has been analysed or not - bool is_analysed; - - /// Indicates whether the block has been compiled or not - bool is_compiled; - - /// Indicate wheter the block is a function that can be completly compiled - /// that is, that has a clear "return" semantic and no indirect branch - bool is_compilable_function; - - /// If the analysis was successfull, how long the block is. - u32 instructionCount; - - /// If the analysis was successfull, which function does it call. - std::set calledFunctions; - - BlockEntry(u32 start_address) - : num_hits(0) - , address(start_address) - , is_compiled(false) - , is_analysed(false) - , is_compilable_function(false) - , instructionCount(0) { - } - - std::string ToString() const { - return fmt::format("0x%08X: NumHits=%u, IsCompiled=%c", - address, num_hits, is_compiled ? 'Y' : 'N'); - } - - bool operator == (const BlockEntry & other) const { - return address == other.address; - } - }; - - /// Log - llvm::raw_fd_ostream * m_log; - - /// Lock for accessing m_pending_address_start. TODO: Eliminate this and use a lock-free queue. - std::mutex m_pending_address_start_lock; - - /// Queue of block start address to process - std::list m_pending_address_start; - - /// Block table - std::unordered_map m_block_table; - - int m_currentId; - - /// (function, id). - typedef std::pair ExecutableStorageType; - - /// Virtual memory allocated array. - /// Store pointer to every compiled function/block and a unique Id. - /// We need to map every instruction in PS3 Ram so it's a big table - /// But a lot of it won't be accessed. Fortunatly virtual memory help here... - ExecutableStorageType* FunctionCache; - - // Bitfield recording page status in FunctionCache reserved memory. - char *FunctionCachePagesCommited; - - bool isAddressCommited(u32) const; - void commitAddress(u32); - - /// vector storing all exec engine - std::vector > m_executable_storage; - - - /// LLVM context - llvm::LLVMContext &m_llvm_context; - - /// LLVM IR builder - llvm::IRBuilder<> m_ir_builder; - - /** - * 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 - */ - std::pair compile(const std::string & name, u32 start_address, u32 instruction_count); - - /// The time at which the m_address_to_ordinal cache was last cleared - std::chrono::high_resolution_clock::time_point m_last_cache_clear_time; - - RecompilationEngine(); - - 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 - bool IncreaseHitCounterAndBuild(u32 addr); - - /** - * Analyse block to get useful info (function called, has indirect branch...) - * This code is inspired from Dolphin PPC Analyst - * Return true if analysis is successful. - */ - bool AnalyseBlock(BlockEntry &functionData, size_t maxSize = 10000); - - /// Compile a block - void CompileBlock(BlockEntry & block_entry); - - /// Mutex used to prevent multiple creation - static std::mutex s_mutex; - - /// The instance - static std::shared_ptr s_the_instance; - }; - - /** - * PPU execution engine - * Relies on PPUInterpreter1 to execute uncompiled code. - * Traces execution to determine which block to compile. - * Use LLVM to compile block into native code. - */ - class CPUHybridDecoderRecompiler : public CPUDecoder { - friend class RecompilationEngine; - friend class Compiler; - public: - CPUHybridDecoderRecompiler(PPUThread & ppu); - - CPUHybridDecoderRecompiler(const CPUHybridDecoderRecompiler&) = delete; // Delete copy/move constructors and copy/move operators - - virtual ~CPUHybridDecoderRecompiler(); - - u32 DecodeMemory(const u32 address) override; - - private: - /// PPU processor context - PPUThread & m_ppu; - - /// PPU Interpreter - PPUInterpreter * m_interpreter; - - /// PPU instruction Decoder - PPUDecoder m_decoder; - - /// Recompilation engine - std::shared_ptr m_recompilation_engine; - - /// Execute a function - static u32 ExecuteFunction(PPUThread * ppu_state, u64 context); - - /// Execute till the current function returns - static u32 ExecuteTillReturn(PPUThread * ppu_state, u64 context); - - /// Check thread status. Returns true if the thread must exit. - static bool PollStatus(PPUThread * ppu_state); - }; - - class CustomSectionMemoryManager : public llvm::SectionMemoryManager { - private: - std::unordered_map &executableMap; - public: - CustomSectionMemoryManager(std::unordered_map &map) : - executableMap(map) - {} - ~CustomSectionMemoryManager() override {} - - virtual uint64_t getSymbolAddress(const std::string &Name) override - { - std::unordered_map::const_iterator It = executableMap.find(Name); - if (It != executableMap.end()) - return (uint64_t)It->second; - return getSymbolAddressInProcess(Name); - } - }; -} - -#endif // LLVM_AVAILABLE -#endif // PPU_LLVM_RECOMPILER_H diff --git a/rpcs3/Emu/Cell/PPULLVMRecompilerCore.cpp b/rpcs3/Emu/Cell/PPULLVMRecompilerCore.cpp deleted file mode 100644 index b9a0c065d2..0000000000 --- a/rpcs3/Emu/Cell/PPULLVMRecompilerCore.cpp +++ /dev/null @@ -1,5527 +0,0 @@ -#include "stdafx.h" -#ifdef LLVM_AVAILABLE -#include "Emu/state.h" -#include "Emu/System.h" -#include "Emu/Cell/PPULLVMRecompiler.h" -#include "Emu/Memory/Memory.h" -#ifdef _MSC_VER -#pragma warning(push, 0) -#endif -#include "llvm/Support/TargetSelect.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/ExecutionEngine/GenericValue.h" -#include "llvm/ExecutionEngine/MCJIT.h" -#include "llvm/ExecutionEngine/SectionMemoryManager.h" -#include "llvm/IR/Intrinsics.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Analysis/Passes.h" -#include "llvm/Analysis/TargetTransformInfo.h" -#include "llvm/Analysis/MemoryDependenceAnalysis.h" -#include "llvm/Analysis/LoopInfo.h" -#include "llvm/Analysis/ScalarEvolution.h" -#include "llvm/IR/Dominators.h" -#include "llvm/Transforms/Scalar.h" -#include "llvm/Transforms/Vectorize.h" -#include "llvm/MC/MCDisassembler.h" -#include "llvm/IR/Verifier.h" -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -#define USE_INTERP_IF_REQUESTED(inst, ...) \ - if (!rpcs3::state.config.core.llvm.enable_##inst.value()) \ - { \ - Call(#inst, m_state.args[CompileTaskState::Args::State], __VA_ARGS__); \ - return; \ - } - -using namespace llvm; -using namespace ppu_recompiler_llvm; - -void Compiler::NULL_OP() { - CompilationError("NULL_OP"); -} - -void Compiler::NOP() { - m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::donothing)); -} - -void Compiler::TDI(u32 to, u32 ra, s32 simm16) { - llvm::Value *gpr_a = GetGpr(ra); - llvm::Value *cst_simm16 = m_ir_builder->getInt64(simm16); - llvm::Value *trap_condition = m_ir_builder->getFalse(); - - if (to & 0x10) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpSLT(gpr_a, cst_simm16)); - if (to & 0x8) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpSGT(gpr_a, cst_simm16)); - if (to & 0x4) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpEQ(gpr_a, cst_simm16)); - if (to & 0x2) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpULT(gpr_a, cst_simm16)); - if (to & 0x1) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpUGT(gpr_a, cst_simm16)); - - llvm::BasicBlock *trap_block = GetBasicBlockFromAddress(m_state.current_instruction_address, "trap_block"); - llvm::BasicBlock *normal_execution = GetBasicBlockFromAddress(m_state.current_instruction_address, "normal_execution"); - m_ir_builder->CreateCondBr(trap_condition, trap_block, normal_execution); - - m_ir_builder->SetInsertPoint(trap_block); - Call("trap"); - m_ir_builder->CreateRet(m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusPropagateException)); - - m_ir_builder->SetInsertPoint(normal_execution); -} - -void Compiler::TWI(u32 to, u32 ra, s32 simm16) { - llvm::Value *gpr_a = GetGpr(ra, 32); - llvm::Value *cst_simm16 = m_ir_builder->getInt32(simm16); - llvm::Value *trap_condition = m_ir_builder->getFalse(); - - if (to & 0x10) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpSLT(gpr_a, cst_simm16)); - if (to & 0x8) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpSGT(gpr_a, cst_simm16)); - if (to & 0x4) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpEQ(gpr_a, cst_simm16)); - if (to & 0x2) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpULT(gpr_a, cst_simm16)); - if (to & 0x1) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpUGT(gpr_a, cst_simm16)); - - llvm::BasicBlock *trap_block = GetBasicBlockFromAddress(m_state.current_instruction_address, "trap_block"); - llvm::BasicBlock *normal_execution = GetBasicBlockFromAddress(m_state.current_instruction_address, "normal_execution"); - m_ir_builder->CreateCondBr(trap_condition, trap_block, normal_execution); - - m_ir_builder->SetInsertPoint(trap_block); - Call("trap"); - m_ir_builder->CreateRet(m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusPropagateException)); - - m_ir_builder->SetInsertPoint(normal_execution); -} - -void Compiler::MFVSCR(u32 vd) { - auto vscr_i32 = GetVscr(); - auto vscr_i128 = m_ir_builder->CreateZExt(vscr_i32, m_ir_builder->getIntNTy(128)); - SetVr(vd, vscr_i128); -} - -void Compiler::MTVSCR(u32 vb) { - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto vscr_i32 = m_ir_builder->CreateExtractElement(vb_v4i32, m_ir_builder->getInt32(0)); - vscr_i32 = m_ir_builder->CreateAnd(vscr_i32, 0x00010001); - SetVscr(vscr_i32); -} - -void Compiler::VADDCUW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - - va_v4i32 = m_ir_builder->CreateNot(va_v4i32); - auto cmpv4i1 = m_ir_builder->CreateICmpULT(va_v4i32, vb_v4i32); - auto cmpv4i32 = m_ir_builder->CreateZExt(cmpv4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, cmpv4i32); -} - -void Compiler::VADDFP(u32 vd, u32 va, u32 vb) { - auto va_v4f32 = GetVrAsFloatVec(va); - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto sum_v4f32 = m_ir_builder->CreateFAdd(va_v4f32, vb_v4f32); - SetVr(vd, sum_v4f32); -} - -void Compiler::VADDSBS(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto sum_v16i8 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_padds_b), va_v16i8, vb_v16i8); - SetVr(vd, sum_v16i8); - - // TODO: Set VSCR.SAT -} - -void Compiler::VADDSHS(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto sum_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_padds_w), va_v8i16, vb_v8i16); - SetVr(vd, sum_v8i16); - - // TODO: Set VSCR.SAT -} - -void Compiler::VADDSWS(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - - // It looks like x86 does not have an instruction to add 32 bit intergers with signed/unsigned saturation. - // To implement add with saturation, we first determine what the result would be if the operation were to cause - // an overflow. If two -ve numbers are being added and cause an overflow, the result would be 0x80000000. - // If two +ve numbers are being added and cause an overflow, the result would be 0x7FFFFFFF. Addition of a -ve - // number and a +ve number cannot cause overflow. So the result in case of an overflow is 0x7FFFFFFF + sign bit - // of any one of the operands. - auto tmp1_v4i32 = m_ir_builder->CreateLShr(va_v4i32, 31); - tmp1_v4i32 = m_ir_builder->CreateAdd(tmp1_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0x7FFFFFFF))); - auto tmp1_v16i8 = m_ir_builder->CreateBitCast(tmp1_v4i32, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - - // Next, we find if the addition can actually result in an overflow. Since an overflow can only happen if the operands - // have the same sign, we bitwise XOR both the operands. If the sign bit of the result is 0 then the operands have the - // same sign and so may cause an overflow. We invert the result so that the sign bit is 1 when the operands have the - // same sign. - auto tmp2_v4i32 = m_ir_builder->CreateXor(va_v4i32, vb_v4i32); - tmp2_v4i32 = m_ir_builder->CreateNot(tmp2_v4i32); - - // Perform the sum. - auto sum_v4i32 = m_ir_builder->CreateAdd(va_v4i32, vb_v4i32); - auto sum_v16i8 = m_ir_builder->CreateBitCast(sum_v4i32, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - - // If an overflow occurs, then the sign of the sum will be different from the sign of the operands. So, we xor the - // result with one of the operands. The sign bit of the result will be 1 if the sign bit of the sum and the sign bit of the - // result is different. This result is again ANDed with tmp3 (the sign bit of tmp3 is 1 only if the operands have the same - // sign and so can cause an overflow). - auto tmp3_v4i32 = m_ir_builder->CreateXor(va_v4i32, sum_v4i32); - tmp3_v4i32 = m_ir_builder->CreateAnd(tmp2_v4i32, tmp3_v4i32); - tmp3_v4i32 = m_ir_builder->CreateAShr(tmp3_v4i32, 31); - auto tmp3_v16i8 = m_ir_builder->CreateBitCast(tmp3_v4i32, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - - // tmp4 is equal to 0xFFFFFFFF if an overflow occured and 0x00000000 otherwise. - auto res_v16i8 = m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pblendvb), sum_v16i8, tmp1_v16i8, tmp3_v16i8); - SetVr(vd, res_v16i8); - - // TODO: Set SAT -} - -void Compiler::VADDUBM(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto sum_v16i8 = m_ir_builder->CreateAdd(va_v16i8, vb_v16i8); - SetVr(vd, sum_v16i8); -} - -void Compiler::VADDUBS(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto sum_v16i8 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_paddus_b), va_v16i8, vb_v16i8); - SetVr(vd, sum_v16i8); - - // TODO: Set SAT -} - -void Compiler::VADDUHM(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto sum_v8i16 = m_ir_builder->CreateAdd(va_v8i16, vb_v8i16); - SetVr(vd, sum_v8i16); -} - -void Compiler::VADDUHS(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto sum_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_paddus_w), va_v8i16, vb_v8i16); - SetVr(vd, sum_v8i16); - - // TODO: Set SAT -} - -void Compiler::VADDUWM(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto sum_v4i32 = m_ir_builder->CreateAdd(va_v4i32, vb_v4i32); - SetVr(vd, sum_v4i32); -} - -void Compiler::VADDUWS(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto sum_v4i32 = m_ir_builder->CreateAdd(va_v4i32, vb_v4i32); - auto cmp_v4i1 = m_ir_builder->CreateICmpULT(sum_v4i32, va_v4i32); - auto cmp_v4i32 = m_ir_builder->CreateSExt(cmp_v4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - auto res_v4i32 = m_ir_builder->CreateOr(sum_v4i32, cmp_v4i32); - SetVr(vd, res_v4i32); - - // TODO: Set SAT -} - -void Compiler::VAND(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto res_v4i32 = m_ir_builder->CreateAnd(va_v4i32, vb_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VANDC(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - vb_v4i32 = m_ir_builder->CreateNot(vb_v4i32); - auto res_v4i32 = m_ir_builder->CreateAnd(va_v4i32, vb_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VAVGSB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto va_v16i16 = m_ir_builder->CreateSExt(va_v16i8, VectorType::get(m_ir_builder->getInt16Ty(), 16)); - auto vb_v16i16 = m_ir_builder->CreateSExt(vb_v16i8, VectorType::get(m_ir_builder->getInt16Ty(), 16)); - auto sum_v16i16 = m_ir_builder->CreateAdd(va_v16i16, vb_v16i16); - sum_v16i16 = m_ir_builder->CreateAdd(sum_v16i16, m_ir_builder->CreateVectorSplat(16, m_ir_builder->getInt16(1))); - auto avg_v16i16 = m_ir_builder->CreateAShr(sum_v16i16, 1); - auto avg_v16i8 = m_ir_builder->CreateTrunc(avg_v16i16, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - SetVr(vd, avg_v16i8); -} - -void Compiler::VAVGSH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto va_v8i32 = m_ir_builder->CreateSExt(va_v8i16, VectorType::get(m_ir_builder->getInt32Ty(), 8)); - auto vb_v8i32 = m_ir_builder->CreateSExt(vb_v8i16, VectorType::get(m_ir_builder->getInt32Ty(), 8)); - auto sum_v8i32 = m_ir_builder->CreateAdd(va_v8i32, vb_v8i32); - sum_v8i32 = m_ir_builder->CreateAdd(sum_v8i32, m_ir_builder->CreateVectorSplat(8, m_ir_builder->getInt32(1))); - auto avg_v8i32 = m_ir_builder->CreateAShr(sum_v8i32, 1); - auto avg_v8i16 = m_ir_builder->CreateTrunc(avg_v8i32, VectorType::get(m_ir_builder->getInt16Ty(), 8)); - SetVr(vd, avg_v8i16); -} - -void Compiler::VAVGSW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto va_v4i64 = m_ir_builder->CreateSExt(va_v4i32, VectorType::get(m_ir_builder->getInt64Ty(), 4)); - auto vb_v4i64 = m_ir_builder->CreateSExt(vb_v4i32, VectorType::get(m_ir_builder->getInt64Ty(), 4)); - auto sum_v4i64 = m_ir_builder->CreateAdd(va_v4i64, vb_v4i64); - sum_v4i64 = m_ir_builder->CreateAdd(sum_v4i64, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt64(1))); - auto avg_v4i64 = m_ir_builder->CreateAShr(sum_v4i64, 1); - auto avg_v4i32 = m_ir_builder->CreateTrunc(avg_v4i64, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, avg_v4i32); -} - -void Compiler::VAVGUB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto avg_v16i8 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_pavg_b), va_v16i8, vb_v16i8); - SetVr(vd, avg_v16i8); -} - -void Compiler::VAVGUH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto avg_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_pavg_w), va_v8i16, vb_v8i16); - SetVr(vd, avg_v8i16); -} - -void Compiler::VAVGUW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto va_v4i64 = m_ir_builder->CreateZExt(va_v4i32, VectorType::get(m_ir_builder->getInt64Ty(), 4)); - auto vb_v4i64 = m_ir_builder->CreateZExt(vb_v4i32, VectorType::get(m_ir_builder->getInt64Ty(), 4)); - auto sum_v4i64 = m_ir_builder->CreateAdd(va_v4i64, vb_v4i64); - sum_v4i64 = m_ir_builder->CreateAdd(sum_v4i64, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt64(1))); - auto avg_v4i64 = m_ir_builder->CreateLShr(sum_v4i64, 1); - auto avg_v4i32 = m_ir_builder->CreateTrunc(avg_v4i64, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, avg_v4i32); -} - -void Compiler::VCFSX(u32 vd, u32 uimm5, u32 vb) { - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto res_v4f32 = m_ir_builder->CreateSIToFP(vb_v4i32, VectorType::get(m_ir_builder->getFloatTy(), 4)); - - if (uimm5) { - float scale = (float)((u64)1 << uimm5); - res_v4f32 = m_ir_builder->CreateFDiv(res_v4f32, m_ir_builder->CreateVectorSplat(4, ConstantFP::get(m_ir_builder->getFloatTy(), scale))); - } - - SetVr(vd, res_v4f32); -} - -void Compiler::VCFUX(u32 vd, u32 uimm5, u32 vb) { - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto res_v4f32 = m_ir_builder->CreateUIToFP(vb_v4i32, VectorType::get(m_ir_builder->getFloatTy(), 4)); - - if (uimm5) { - float scale = (float)((u64)1 << uimm5); - res_v4f32 = m_ir_builder->CreateFDiv(res_v4f32, m_ir_builder->CreateVectorSplat(4, ConstantFP::get(m_ir_builder->getFloatTy(), scale))); - } - - SetVr(vd, res_v4f32); -} - -void Compiler::VCMPBFP(u32 vd, u32 va, u32 vb) { - auto va_v4f32 = GetVrAsFloatVec(va); - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto cmp_gt_v4i1 = m_ir_builder->CreateFCmpOGT(va_v4f32, vb_v4f32); - vb_v4f32 = m_ir_builder->CreateFNeg(vb_v4f32); - auto cmp_lt_v4i1 = m_ir_builder->CreateFCmpOLT(va_v4f32, vb_v4f32); - auto cmp_gt_v4i32 = m_ir_builder->CreateZExt(cmp_gt_v4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - auto cmp_lt_v4i32 = m_ir_builder->CreateZExt(cmp_lt_v4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - cmp_gt_v4i32 = m_ir_builder->CreateShl(cmp_gt_v4i32, 31); - cmp_lt_v4i32 = m_ir_builder->CreateShl(cmp_lt_v4i32, 30); - auto res_v4i32 = m_ir_builder->CreateOr(cmp_gt_v4i32, cmp_lt_v4i32); - SetVr(vd, res_v4i32); - - // TODO: Implement NJ mode -} - -void Compiler::VCMPBFP_(u32 vd, u32 va, u32 vb) { - VCMPBFP(vd, va, vb); - - auto vd_v16i8 = GetVrAsIntVec(vd, 8); - u32 mask_v16i32[16] = { 3, 7, 11, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - vd_v16i8 = m_ir_builder->CreateShuffleVector(vd_v16i8, UndefValue::get(VectorType::get(m_ir_builder->getInt8Ty(), 16)), ConstantDataVector::get(m_ir_builder->getContext(), mask_v16i32)); - auto vd_v4i32 = m_ir_builder->CreateBitCast(vd_v16i8, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - auto vd_mask_i32 = m_ir_builder->CreateExtractElement(vd_v4i32, m_ir_builder->getInt32(0)); - auto cmp_i1 = m_ir_builder->CreateICmpEQ(vd_mask_i32, m_ir_builder->getInt32(0)); - SetCrField(6, nullptr, nullptr, cmp_i1, nullptr); -} - -void Compiler::VCMPEQFP(u32 vd, u32 va, u32 vb) { - auto va_v4f32 = GetVrAsFloatVec(va); - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto cmp_v4i1 = m_ir_builder->CreateFCmpOEQ(va_v4f32, vb_v4f32); - auto cmp_v4i32 = m_ir_builder->CreateSExt(cmp_v4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, cmp_v4i32); -} - -void Compiler::VCMPEQFP_(u32 vd, u32 va, u32 vb) { - VCMPEQFP(vd, va, vb); - SetCr6AfterVectorCompare(vd); -} - -void Compiler::VCMPEQUB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto cmp_v16i1 = m_ir_builder->CreateICmpEQ(va_v16i8, vb_v16i8); - auto cmp_v16i8 = m_ir_builder->CreateSExt(cmp_v16i1, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - SetVr(vd, cmp_v16i8); -} - -void Compiler::VCMPEQUB_(u32 vd, u32 va, u32 vb) { - VCMPEQUB(vd, va, vb); - SetCr6AfterVectorCompare(vd); -} - -void Compiler::VCMPEQUH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto cmp_v8i1 = m_ir_builder->CreateICmpEQ(va_v8i16, vb_v8i16); - auto cmp_v8i16 = m_ir_builder->CreateSExt(cmp_v8i1, VectorType::get(m_ir_builder->getInt16Ty(), 8)); - SetVr(vd, cmp_v8i16); -} - -void Compiler::VCMPEQUH_(u32 vd, u32 va, u32 vb) { - VCMPEQUH(vd, va, vb); - SetCr6AfterVectorCompare(vd); -} - -void Compiler::VCMPEQUW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto cmp_v4i1 = m_ir_builder->CreateICmpEQ(va_v4i32, vb_v4i32); - auto cmp_v4i32 = m_ir_builder->CreateSExt(cmp_v4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, cmp_v4i32); -} - -void Compiler::VCMPEQUW_(u32 vd, u32 va, u32 vb) { - VCMPEQUW(vd, va, vb); - SetCr6AfterVectorCompare(vd); -} - -void Compiler::VCMPGEFP(u32 vd, u32 va, u32 vb) { - auto va_v4f32 = GetVrAsFloatVec(va); - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto cmp_v4i1 = m_ir_builder->CreateFCmpOGE(va_v4f32, vb_v4f32); - auto cmp_v4i32 = m_ir_builder->CreateSExt(cmp_v4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, cmp_v4i32); -} - -void Compiler::VCMPGEFP_(u32 vd, u32 va, u32 vb) { - VCMPGEFP(vd, va, vb); - SetCr6AfterVectorCompare(vd); -} - -void Compiler::VCMPGTFP(u32 vd, u32 va, u32 vb) { - auto va_v4f32 = GetVrAsFloatVec(va); - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto cmp_v4i1 = m_ir_builder->CreateFCmpOGT(va_v4f32, vb_v4f32); - auto cmp_v4i32 = m_ir_builder->CreateSExt(cmp_v4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, cmp_v4i32); -} - -void Compiler::VCMPGTFP_(u32 vd, u32 va, u32 vb) { - VCMPGTFP(vd, va, vb); - SetCr6AfterVectorCompare(vd); -} - -void Compiler::VCMPGTSB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto cmp_v16i1 = m_ir_builder->CreateICmpSGT(va_v16i8, vb_v16i8); - auto cmp_v16i8 = m_ir_builder->CreateSExt(cmp_v16i1, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - SetVr(vd, cmp_v16i8); -} - -void Compiler::VCMPGTSB_(u32 vd, u32 va, u32 vb) { - VCMPGTSB(vd, va, vb); - SetCr6AfterVectorCompare(vd); -} - -void Compiler::VCMPGTSH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto cmp_v8i1 = m_ir_builder->CreateICmpSGT(va_v8i16, vb_v8i16); - auto cmp_v8i16 = m_ir_builder->CreateSExt(cmp_v8i1, VectorType::get(m_ir_builder->getInt16Ty(), 8)); - SetVr(vd, cmp_v8i16); -} - -void Compiler::VCMPGTSH_(u32 vd, u32 va, u32 vb) { - VCMPGTSH(vd, va, vb); - SetCr6AfterVectorCompare(vd); -} - -void Compiler::VCMPGTSW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto cmp_v4i1 = m_ir_builder->CreateICmpSGT(va_v4i32, vb_v4i32); - auto cmp_v4i32 = m_ir_builder->CreateSExt(cmp_v4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, cmp_v4i32); -} - -void Compiler::VCMPGTSW_(u32 vd, u32 va, u32 vb) { - VCMPGTSW(vd, va, vb); - SetCr6AfterVectorCompare(vd); -} - -void Compiler::VCMPGTUB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto cmp_v16i1 = m_ir_builder->CreateICmpUGT(va_v16i8, vb_v16i8); - auto cmp_v16i8 = m_ir_builder->CreateSExt(cmp_v16i1, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - SetVr(vd, cmp_v16i8); -} - -void Compiler::VCMPGTUB_(u32 vd, u32 va, u32 vb) { - VCMPGTUB(vd, va, vb); - SetCr6AfterVectorCompare(vd); -} - -void Compiler::VCMPGTUH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto cmp_v8i1 = m_ir_builder->CreateICmpUGT(va_v8i16, vb_v8i16); - auto cmp_v8i16 = m_ir_builder->CreateSExt(cmp_v8i1, VectorType::get(m_ir_builder->getInt16Ty(), 8)); - SetVr(vd, cmp_v8i16); -} - -void Compiler::VCMPGTUH_(u32 vd, u32 va, u32 vb) { - VCMPGTUH(vd, va, vb); - SetCr6AfterVectorCompare(vd); -} - -void Compiler::VCMPGTUW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto cmp_v4i1 = m_ir_builder->CreateICmpUGT(va_v4i32, vb_v4i32); - auto cmp_v4i32 = m_ir_builder->CreateSExt(cmp_v4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, cmp_v4i32); -} - -void Compiler::VCMPGTUW_(u32 vd, u32 va, u32 vb) { - VCMPGTUW(vd, va, vb); - SetCr6AfterVectorCompare(vd); -} - -void Compiler::VCTSXS(u32 vd, u32 uimm5, u32 vb) { - auto vb_v4f32 = GetVrAsFloatVec(vb); - if (uimm5) { - u64 power_of_two = UINT64_C(1) << uimm5; - vb_v4f32 = m_ir_builder->CreateFMul(vb_v4f32, m_ir_builder->CreateVectorSplat(4, ConstantFP::get(m_ir_builder->getFloatTy(), static_cast(power_of_two)))); - } - - auto res_v4i32 = (Value *)m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_cvtps2dq), vb_v4f32); - auto cmp_v4i1 = m_ir_builder->CreateFCmpOGE(vb_v4f32, m_ir_builder->CreateVectorSplat(4, ConstantFP::get(m_ir_builder->getFloatTy(), 0x7FFFFFFF))); - auto cmp_v4i32 = m_ir_builder->CreateSExt(cmp_v4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - res_v4i32 = m_ir_builder->CreateXor(cmp_v4i32, res_v4i32); - SetVr(vd, res_v4i32); - - // TODO: Set VSCR.SAT -} - -void Compiler::VCTUXS(u32 vd, u32 uimm5, u32 vb) { - auto vb_v4f32 = GetVrAsFloatVec(vb); - if (uimm5) { - u64 power_of_two = UINT64_C(1) << uimm5; - vb_v4f32 = m_ir_builder->CreateFMul(vb_v4f32, m_ir_builder->CreateVectorSplat(4, ConstantFP::get(m_ir_builder->getFloatTy(), static_cast(power_of_two)))); - } - - auto res_v4f32 = (Value *)m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse_max_ps), vb_v4f32, m_ir_builder->CreateVectorSplat(4, ConstantFP::get(m_ir_builder->getFloatTy(), 0))); - auto cmp_v4i1 = m_ir_builder->CreateFCmpOGE(res_v4f32, m_ir_builder->CreateVectorSplat(4, ConstantFP::get(m_ir_builder->getFloatTy(), 0xFFFFFFFFu))); - auto cmp_v4i32 = m_ir_builder->CreateSExt(cmp_v4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - auto res_v4i32 = m_ir_builder->CreateFPToUI(res_v4f32, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - res_v4i32 = m_ir_builder->CreateOr(res_v4i32, cmp_v4i32); - SetVr(vd, res_v4i32); - - // TODO: Set VSCR.SAT -} - -void Compiler::VEXPTEFP(u32 vd, u32 vb) { - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto res_v4f32 = (Value *)m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::pow, VectorType::get(m_ir_builder->getFloatTy(), 4)), - m_ir_builder->CreateVectorSplat(4, ConstantFP::get(m_ir_builder->getFloatTy(), 2.0f)), vb_v4f32); - SetVr(vd, res_v4f32); -} - -void Compiler::VLOGEFP(u32 vd, u32 vb) { - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto res_v4f32 = (Value *)m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::log2, VectorType::get(m_ir_builder->getFloatTy(), 4)), vb_v4f32); - SetVr(vd, res_v4f32); -} - -void Compiler::VMADDFP(u32 vd, u32 va, u32 vc, u32 vb) { - auto va_v4f32 = GetVrAsFloatVec(va); - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto vc_v4f32 = GetVrAsFloatVec(vc); - auto res_v4f32 = m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::fmuladd, VectorType::get(m_ir_builder->getFloatTy(), 4)), va_v4f32, vc_v4f32, vb_v4f32); - SetVr(vd, res_v4f32); -} - -void Compiler::VMAXFP(u32 vd, u32 va, u32 vb) { - auto va_v4f32 = GetVrAsFloatVec(va); - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto res_v4f32 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse_max_ps), va_v4f32, vb_v4f32); - SetVr(vd, res_v4f32); -} - -void Compiler::VMAXSB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto res_v16i8 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pmaxsb), va_v16i8, vb_v16i8); - SetVr(vd, res_v16i8); -} - -void Compiler::VMAXSH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto res_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_pmaxs_w), va_v8i16, vb_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VMAXSW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto res_v4i32 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pmaxsd), va_v4i32, vb_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VMAXUB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto res_v16i8 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_pmaxu_b), va_v16i8, vb_v16i8); - SetVr(vd, res_v16i8); -} - -void Compiler::VMAXUH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto res_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pmaxuw), va_v8i16, vb_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VMAXUW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto res_v4i32 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pmaxud), va_v4i32, vb_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VMHADDSHS(u32 vd, u32 va, u32 vb, u32 vc) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto vc_v8i16 = GetVrAsIntVec(vc, 16); - auto va_v8i32 = m_ir_builder->CreateSExt(va_v8i16, VectorType::get(m_ir_builder->getInt32Ty(), 8)); - auto vb_v8i32 = m_ir_builder->CreateSExt(vb_v8i16, VectorType::get(m_ir_builder->getInt32Ty(), 8)); - auto vc_v8i32 = m_ir_builder->CreateSExt(vc_v8i16, VectorType::get(m_ir_builder->getInt32Ty(), 8)); - auto res_v8i32 = m_ir_builder->CreateMul(va_v8i32, vb_v8i32); - res_v8i32 = m_ir_builder->CreateAShr(res_v8i32, 15); - res_v8i32 = m_ir_builder->CreateAdd(res_v8i32, vc_v8i32); - - u32 mask1_v4i32[4] = { 0, 1, 2, 3 }; - auto res1_v4i32 = m_ir_builder->CreateShuffleVector(res_v8i32, UndefValue::get(VectorType::get(m_ir_builder->getInt32Ty(), 8)), ConstantDataVector::get(m_ir_builder->getContext(), mask1_v4i32)); - u32 mask2_v4i32[4] = { 4, 5, 6, 7 }; - auto res2_v4i32 = m_ir_builder->CreateShuffleVector(res_v8i32, UndefValue::get(VectorType::get(m_ir_builder->getInt32Ty(), 8)), ConstantDataVector::get(m_ir_builder->getContext(), mask2_v4i32)); - auto res_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_packssdw_128), res1_v4i32, res2_v4i32); - SetVr(vd, res_v8i16); - - // TODO: Set VSCR.SAT -} - -void Compiler::VMHRADDSHS(u32 vd, u32 va, u32 vb, u32 vc) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto vc_v8i16 = GetVrAsIntVec(vc, 16); - auto va_v8i32 = m_ir_builder->CreateSExt(va_v8i16, VectorType::get(m_ir_builder->getInt32Ty(), 8)); - auto vb_v8i32 = m_ir_builder->CreateSExt(vb_v8i16, VectorType::get(m_ir_builder->getInt32Ty(), 8)); - auto vc_v8i32 = m_ir_builder->CreateSExt(vc_v8i16, VectorType::get(m_ir_builder->getInt32Ty(), 8)); - auto res_v8i32 = m_ir_builder->CreateMul(va_v8i32, vb_v8i32); - res_v8i32 = m_ir_builder->CreateAdd(res_v8i32, m_ir_builder->CreateVectorSplat(8, m_ir_builder->getInt32(0x4000))); - res_v8i32 = m_ir_builder->CreateAShr(res_v8i32, 15); - res_v8i32 = m_ir_builder->CreateAdd(res_v8i32, vc_v8i32); - - u32 mask1_v4i32[4] = { 0, 1, 2, 3 }; - auto res1_v4i32 = m_ir_builder->CreateShuffleVector(res_v8i32, UndefValue::get(VectorType::get(m_ir_builder->getInt32Ty(), 8)), ConstantDataVector::get(m_ir_builder->getContext(), mask1_v4i32)); - u32 mask2_v4i32[4] = { 4, 5, 6, 7 }; - auto res2_v4i32 = m_ir_builder->CreateShuffleVector(res_v8i32, UndefValue::get(VectorType::get(m_ir_builder->getInt32Ty(), 8)), ConstantDataVector::get(m_ir_builder->getContext(), mask2_v4i32)); - auto res_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_packssdw_128), res1_v4i32, res2_v4i32); - SetVr(vd, res_v8i16); - - // TODO: Set VSCR.SAT -} - -void Compiler::VMINFP(u32 vd, u32 va, u32 vb) { - auto va_v4f32 = GetVrAsFloatVec(va); - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto res_v4f32 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse_min_ps), va_v4f32, vb_v4f32); - SetVr(vd, res_v4f32); -} - -void Compiler::VMINSB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto res_v16i8 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pminsb), va_v16i8, vb_v16i8); - SetVr(vd, res_v16i8); -} - -void Compiler::VMINSH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto res_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_pmins_w), va_v8i16, vb_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VMINSW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto res_v4i32 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pminsd), va_v4i32, vb_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VMINUB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto res_v16i8 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_pminu_b), va_v16i8, vb_v16i8); - SetVr(vd, res_v16i8); -} - -void Compiler::VMINUH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto res_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pminuw), va_v8i16, vb_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VMINUW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto res_v4i32 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pminud), va_v4i32, vb_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VMLADDUHM(u32 vd, u32 va, u32 vb, u32 vc) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto vc_v8i16 = GetVrAsIntVec(vc, 16); - auto res_v8i16 = m_ir_builder->CreateMul(va_v8i16, vb_v8i16); - res_v8i16 = m_ir_builder->CreateAdd(res_v8i16, vc_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VMRGHB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - u32 mask_v16i32[16] = { 24, 8, 25, 9, 26, 10, 27, 11, 28, 12, 29, 13, 30, 14, 31, 15 }; - auto vd_v16i8 = m_ir_builder->CreateShuffleVector(va_v16i8, vb_v16i8, ConstantDataVector::get(m_ir_builder->getContext(), mask_v16i32)); - SetVr(vd, vd_v16i8); -} - -void Compiler::VMRGHH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - u32 mask_v8i32[8] = { 12, 4, 13, 5, 14, 6, 15, 7 }; - auto vd_v8i16 = m_ir_builder->CreateShuffleVector(va_v8i16, vb_v8i16, ConstantDataVector::get(m_ir_builder->getContext(), mask_v8i32)); - SetVr(vd, vd_v8i16); -} - -void Compiler::VMRGHW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - u32 mask_v4i32[4] = { 6, 2, 7, 3 }; - auto vd_v4i32 = m_ir_builder->CreateShuffleVector(va_v4i32, vb_v4i32, ConstantDataVector::get(m_ir_builder->getContext(), mask_v4i32)); - SetVr(vd, vd_v4i32); -} - -void Compiler::VMRGLB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - u32 mask_v16i32[16] = { 16, 0, 17, 1, 18, 2, 19, 3, 20, 4, 21, 5, 22, 6, 23, 7 }; - auto vd_v16i8 = m_ir_builder->CreateShuffleVector(va_v16i8, vb_v16i8, ConstantDataVector::get(m_ir_builder->getContext(), mask_v16i32)); - SetVr(vd, vd_v16i8); -} - -void Compiler::VMRGLH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - u32 mask_v8i32[8] = { 8, 0, 9, 1, 10, 2, 11, 3 }; - auto vd_v8i16 = m_ir_builder->CreateShuffleVector(va_v8i16, vb_v8i16, ConstantDataVector::get(m_ir_builder->getContext(), mask_v8i32)); - SetVr(vd, vd_v8i16); -} - -void Compiler::VMRGLW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - u32 mask_v4i32[4] = { 4, 0, 5, 1 }; - auto vd_v4i32 = m_ir_builder->CreateShuffleVector(va_v4i32, vb_v4i32, ConstantDataVector::get(m_ir_builder->getContext(), mask_v4i32)); - SetVr(vd, vd_v4i32); -} - -void Compiler::VMSUMMBM(u32 vd, u32 va, u32 vb, u32 vc) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto va_v16i16 = m_ir_builder->CreateSExt(va_v16i8, VectorType::get(m_ir_builder->getInt16Ty(), 16)); - auto vb_v16i16 = m_ir_builder->CreateZExt(vb_v16i8, VectorType::get(m_ir_builder->getInt16Ty(), 16)); - auto tmp_v16i16 = m_ir_builder->CreateMul(va_v16i16, vb_v16i16); - - auto undef_v16i16 = UndefValue::get(VectorType::get(m_ir_builder->getInt16Ty(), 16)); - u32 mask1_v4i32[4] = { 0, 4, 8, 12 }; - auto tmp1_v4i16 = m_ir_builder->CreateShuffleVector(tmp_v16i16, undef_v16i16, ConstantDataVector::get(m_ir_builder->getContext(), mask1_v4i32)); - auto tmp1_v4i32 = m_ir_builder->CreateSExt(tmp1_v4i16, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - u32 mask2_v4i32[4] = { 1, 5, 9, 13 }; - auto tmp2_v4i16 = m_ir_builder->CreateShuffleVector(tmp_v16i16, undef_v16i16, ConstantDataVector::get(m_ir_builder->getContext(), mask2_v4i32)); - auto tmp2_v4i32 = m_ir_builder->CreateSExt(tmp2_v4i16, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - u32 mask3_v4i32[4] = { 2, 6, 10, 14 }; - auto tmp3_v4i16 = m_ir_builder->CreateShuffleVector(tmp_v16i16, undef_v16i16, ConstantDataVector::get(m_ir_builder->getContext(), mask3_v4i32)); - auto tmp3_v4i32 = m_ir_builder->CreateSExt(tmp3_v4i16, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - u32 mask4_v4i32[4] = { 3, 7, 11, 15 }; - auto tmp4_v4i16 = m_ir_builder->CreateShuffleVector(tmp_v16i16, undef_v16i16, ConstantDataVector::get(m_ir_builder->getContext(), mask4_v4i32)); - auto tmp4_v4i32 = m_ir_builder->CreateSExt(tmp4_v4i16, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - - auto vc_v4i32 = GetVrAsIntVec(vc, 32); - auto res_v4i32 = m_ir_builder->CreateAdd(tmp1_v4i32, tmp2_v4i32); - res_v4i32 = m_ir_builder->CreateAdd(res_v4i32, tmp3_v4i32); - res_v4i32 = m_ir_builder->CreateAdd(res_v4i32, tmp4_v4i32); - res_v4i32 = m_ir_builder->CreateAdd(res_v4i32, vc_v4i32); - - SetVr(vd, res_v4i32); - - // TODO: Try to optimize with horizontal add -} - -void Compiler::VMSUMSHM(u32 vd, u32 va, u32 vb, u32 vc) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto vc_v4i32 = GetVrAsIntVec(vc, 32); - auto res_v4i32 = (Value *)m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_pmadd_wd), va_v8i16, vb_v8i16); - res_v4i32 = m_ir_builder->CreateAdd(res_v4i32, vc_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VMSUMSHS(u32 vd, u32 va, u32 vb, u32 vc) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto vc_v4i32 = GetVrAsIntVec(vc, 32); - auto res_v4i32 = (Value *)m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_pmadd_wd), va_v8i16, vb_v8i16); - - auto tmp1_v4i32 = m_ir_builder->CreateLShr(vc_v4i32, 31); - tmp1_v4i32 = m_ir_builder->CreateAdd(tmp1_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0x7FFFFFFF))); - auto tmp1_v16i8 = m_ir_builder->CreateBitCast(tmp1_v4i32, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - auto tmp2_v4i32 = m_ir_builder->CreateXor(vc_v4i32, res_v4i32); - tmp2_v4i32 = m_ir_builder->CreateNot(tmp2_v4i32); - auto sum_v4i32 = m_ir_builder->CreateAdd(vc_v4i32, res_v4i32); - auto sum_v16i8 = m_ir_builder->CreateBitCast(sum_v4i32, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - auto tmp3_v4i32 = m_ir_builder->CreateXor(vc_v4i32, sum_v4i32); - tmp3_v4i32 = m_ir_builder->CreateAnd(tmp2_v4i32, tmp3_v4i32); - tmp3_v4i32 = m_ir_builder->CreateAShr(tmp3_v4i32, 31); - auto tmp3_v16i8 = m_ir_builder->CreateBitCast(tmp3_v4i32, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - auto res_v16i8 = m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pblendvb), sum_v16i8, tmp1_v16i8, tmp3_v16i8); - SetVr(vd, res_v16i8); - - // TODO: Set VSCR.SAT -} - -void Compiler::VMSUMUBM(u32 vd, u32 va, u32 vb, u32 vc) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto va_v16i16 = m_ir_builder->CreateZExt(va_v16i8, VectorType::get(m_ir_builder->getInt16Ty(), 16)); - auto vb_v16i16 = m_ir_builder->CreateZExt(vb_v16i8, VectorType::get(m_ir_builder->getInt16Ty(), 16)); - auto tmp_v16i16 = m_ir_builder->CreateMul(va_v16i16, vb_v16i16); - - auto undef_v16i16 = UndefValue::get(VectorType::get(m_ir_builder->getInt16Ty(), 16)); - u32 mask1_v4i32[4] = { 0, 4, 8, 12 }; - auto tmp1_v4i16 = m_ir_builder->CreateShuffleVector(tmp_v16i16, undef_v16i16, ConstantDataVector::get(m_ir_builder->getContext(), mask1_v4i32)); - auto tmp1_v4i32 = m_ir_builder->CreateZExt(tmp1_v4i16, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - u32 mask2_v4i32[4] = { 1, 5, 9, 13 }; - auto tmp2_v4i16 = m_ir_builder->CreateShuffleVector(tmp_v16i16, undef_v16i16, ConstantDataVector::get(m_ir_builder->getContext(), mask2_v4i32)); - auto tmp2_v4i32 = m_ir_builder->CreateZExt(tmp2_v4i16, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - u32 mask3_v4i32[4] = { 2, 6, 10, 14 }; - auto tmp3_v4i16 = m_ir_builder->CreateShuffleVector(tmp_v16i16, undef_v16i16, ConstantDataVector::get(m_ir_builder->getContext(), mask3_v4i32)); - auto tmp3_v4i32 = m_ir_builder->CreateZExt(tmp3_v4i16, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - u32 mask4_v4i32[4] = { 3, 7, 11, 15 }; - auto tmp4_v4i16 = m_ir_builder->CreateShuffleVector(tmp_v16i16, undef_v16i16, ConstantDataVector::get(m_ir_builder->getContext(), mask4_v4i32)); - auto tmp4_v4i32 = m_ir_builder->CreateZExt(tmp4_v4i16, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - - auto vc_v4i32 = GetVrAsIntVec(vc, 32); - auto res_v4i32 = m_ir_builder->CreateAdd(tmp1_v4i32, tmp2_v4i32); - res_v4i32 = m_ir_builder->CreateAdd(res_v4i32, tmp3_v4i32); - res_v4i32 = m_ir_builder->CreateAdd(res_v4i32, tmp4_v4i32); - res_v4i32 = m_ir_builder->CreateAdd(res_v4i32, vc_v4i32); - - SetVr(vd, res_v4i32); - - // TODO: Try to optimize with horizontal add -} - -void Compiler::VMSUMUHM(u32 vd, u32 va, u32 vb, u32 vc) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto va_v8i32 = m_ir_builder->CreateZExt(va_v8i16, VectorType::get(m_ir_builder->getInt32Ty(), 8)); - auto vb_v8i32 = m_ir_builder->CreateZExt(vb_v8i16, VectorType::get(m_ir_builder->getInt32Ty(), 8)); - auto tmp_v8i32 = m_ir_builder->CreateMul(va_v8i32, vb_v8i32); - - auto undef_v8i32 = UndefValue::get(VectorType::get(m_ir_builder->getInt32Ty(), 8)); - u32 mask1_v4i32[4] = { 0, 2, 4, 6 }; - auto tmp1_v4i32 = m_ir_builder->CreateShuffleVector(tmp_v8i32, undef_v8i32, ConstantDataVector::get(m_ir_builder->getContext(), mask1_v4i32)); - u32 mask2_v4i32[4] = { 1, 3, 5, 7 }; - auto tmp2_v4i32 = m_ir_builder->CreateShuffleVector(tmp_v8i32, undef_v8i32, ConstantDataVector::get(m_ir_builder->getContext(), mask2_v4i32)); - - auto vc_v4i32 = GetVrAsIntVec(vc, 32); - auto res_v4i32 = m_ir_builder->CreateAdd(tmp1_v4i32, tmp2_v4i32); - res_v4i32 = m_ir_builder->CreateAdd(res_v4i32, vc_v4i32); - - SetVr(vd, res_v4i32); - - // TODO: Try to optimize with horizontal add -} - -void Compiler::VMSUMUHS(u32 vd, u32 va, u32 vb, u32 vc) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto va_v8i32 = m_ir_builder->CreateZExt(va_v8i16, VectorType::get(m_ir_builder->getInt32Ty(), 8)); - auto vb_v8i32 = m_ir_builder->CreateZExt(vb_v8i16, VectorType::get(m_ir_builder->getInt32Ty(), 8)); - auto tmp_v8i32 = m_ir_builder->CreateMul(va_v8i32, vb_v8i32); - auto tmp_v8i64 = m_ir_builder->CreateZExt(tmp_v8i32, VectorType::get(m_ir_builder->getInt64Ty(), 8)); - - u32 mask1_v4i32[4] = { 0, 2, 4, 6 }; - u32 mask2_v4i32[4] = { 1, 3, 5, 7 }; - auto tmp1_v4i64 = m_ir_builder->CreateShuffleVector(tmp_v8i64, UndefValue::get(tmp_v8i64->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask1_v4i32)); - auto tmp2_v4i64 = m_ir_builder->CreateShuffleVector(tmp_v8i64, UndefValue::get(tmp_v8i64->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask2_v4i32)); - - auto vc_v4i32 = GetVrAsIntVec(vc, 32); - auto vc_v4i64 = m_ir_builder->CreateZExt(vc_v4i32, VectorType::get(m_ir_builder->getInt64Ty(), 4)); - auto res_v4i64 = m_ir_builder->CreateAdd(tmp1_v4i64, tmp2_v4i64); - res_v4i64 = m_ir_builder->CreateAdd(res_v4i64, vc_v4i64); - auto gt_v4i1 = m_ir_builder->CreateICmpUGT(res_v4i64, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt64(0xFFFFFFFF))); - auto gt_v4i64 = m_ir_builder->CreateSExt(gt_v4i1, VectorType::get(m_ir_builder->getInt64Ty(), 4)); - res_v4i64 = m_ir_builder->CreateOr(res_v4i64, gt_v4i64); - auto res_v4i32 = m_ir_builder->CreateTrunc(res_v4i64, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, res_v4i32); - - // TODO: Set VSCR.SAT -} - -void Compiler::VMULESB(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - va_v8i16 = m_ir_builder->CreateAShr(va_v8i16, 8); - vb_v8i16 = m_ir_builder->CreateAShr(vb_v8i16, 8); - auto res_v8i16 = m_ir_builder->CreateMul(va_v8i16, vb_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VMULESH(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - va_v4i32 = m_ir_builder->CreateAShr(va_v4i32, 16); - vb_v4i32 = m_ir_builder->CreateAShr(vb_v4i32, 16); - auto res_v4i32 = m_ir_builder->CreateMul(va_v4i32, vb_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VMULEUB(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - va_v8i16 = m_ir_builder->CreateLShr(va_v8i16, 8); - vb_v8i16 = m_ir_builder->CreateLShr(vb_v8i16, 8); - auto res_v8i16 = m_ir_builder->CreateMul(va_v8i16, vb_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VMULEUH(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - va_v4i32 = m_ir_builder->CreateLShr(va_v4i32, 16); - vb_v4i32 = m_ir_builder->CreateLShr(vb_v4i32, 16); - auto res_v4i32 = m_ir_builder->CreateMul(va_v4i32, vb_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VMULOSB(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - va_v8i16 = m_ir_builder->CreateShl(va_v8i16, 8); - va_v8i16 = m_ir_builder->CreateAShr(va_v8i16, 8); - vb_v8i16 = m_ir_builder->CreateShl(vb_v8i16, 8); - vb_v8i16 = m_ir_builder->CreateAShr(vb_v8i16, 8); - auto res_v8i16 = m_ir_builder->CreateMul(va_v8i16, vb_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VMULOSH(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - va_v4i32 = m_ir_builder->CreateShl(va_v4i32, 16); - va_v4i32 = m_ir_builder->CreateAShr(va_v4i32, 16); - vb_v4i32 = m_ir_builder->CreateShl(vb_v4i32, 16); - vb_v4i32 = m_ir_builder->CreateAShr(vb_v4i32, 16); - auto res_v4i32 = m_ir_builder->CreateMul(va_v4i32, vb_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VMULOUB(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - va_v8i16 = m_ir_builder->CreateShl(va_v8i16, 8); - va_v8i16 = m_ir_builder->CreateLShr(va_v8i16, 8); - vb_v8i16 = m_ir_builder->CreateShl(vb_v8i16, 8); - vb_v8i16 = m_ir_builder->CreateLShr(vb_v8i16, 8); - auto res_v8i16 = m_ir_builder->CreateMul(va_v8i16, vb_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VMULOUH(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - va_v4i32 = m_ir_builder->CreateShl(va_v4i32, 16); - va_v4i32 = m_ir_builder->CreateLShr(va_v4i32, 16); - vb_v4i32 = m_ir_builder->CreateShl(vb_v4i32, 16); - vb_v4i32 = m_ir_builder->CreateLShr(vb_v4i32, 16); - auto res_v4i32 = m_ir_builder->CreateMul(va_v4i32, vb_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VNMSUBFP(u32 vd, u32 va, u32 vc, u32 vb) { - auto va_v4f32 = GetVrAsFloatVec(va); - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto vc_v4f32 = GetVrAsFloatVec(vc); - vc_v4f32 = m_ir_builder->CreateFNeg(vc_v4f32); - auto res_v4f32 = (Value *)m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::fmuladd, VectorType::get(m_ir_builder->getFloatTy(), 4)), va_v4f32, vc_v4f32, vb_v4f32); - SetVr(vd, res_v4f32); -} - -void Compiler::VNOR(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto res_v8i16 = m_ir_builder->CreateOr(va_v8i16, vb_v8i16); - res_v8i16 = m_ir_builder->CreateNot(res_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VOR(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto res_v8i16 = m_ir_builder->CreateOr(va_v8i16, vb_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VPERM(u32 vd, u32 va, u32 vb, u32 vc) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto vc_v16i8 = GetVrAsIntVec(vc, 8); - - auto thrity_one_v16i8 = m_ir_builder->CreateVectorSplat(16, m_ir_builder->getInt8(31)); - vc_v16i8 = m_ir_builder->CreateAnd(vc_v16i8, thrity_one_v16i8); - - auto fifteen_v16i8 = m_ir_builder->CreateVectorSplat(16, m_ir_builder->getInt8(15)); - auto vc_le15_v16i8 = m_ir_builder->CreateSub(fifteen_v16i8, vc_v16i8); - auto res_va_v16i8 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_ssse3_pshuf_b_128), va_v16i8, vc_le15_v16i8); - - auto vc_gt15_v16i8 = m_ir_builder->CreateSub(thrity_one_v16i8, vc_v16i8); - auto cmp_i1 = m_ir_builder->CreateICmpUGT(vc_gt15_v16i8, fifteen_v16i8); - auto cmp_i8 = m_ir_builder->CreateSExt(cmp_i1, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - vc_gt15_v16i8 = m_ir_builder->CreateOr(cmp_i8, vc_gt15_v16i8); - auto res_vb_v16i8 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_ssse3_pshuf_b_128), vb_v16i8, vc_gt15_v16i8); - - auto res_v16i8 = m_ir_builder->CreateOr(res_vb_v16i8, res_va_v16i8); - SetVr(vd, res_v16i8); -} - -void Compiler::VPKPX(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - - auto tmpa_v4i32 = m_ir_builder->CreateShl(va_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(7))); - tmpa_v4i32 = m_ir_builder->CreateAnd(tmpa_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0xFC000000))); - va_v4i32 = m_ir_builder->CreateShl(va_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(10))); - va_v4i32 = m_ir_builder->CreateAnd(va_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(~0xFC000000))); - tmpa_v4i32 = m_ir_builder->CreateOr(tmpa_v4i32, va_v4i32); - tmpa_v4i32 = m_ir_builder->CreateAnd(tmpa_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0xFFE00000))); - va_v4i32 = m_ir_builder->CreateShl(va_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(3))); - va_v4i32 = m_ir_builder->CreateAnd(va_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(~0xFFE00000))); - tmpa_v4i32 = m_ir_builder->CreateOr(tmpa_v4i32, va_v4i32); - auto tmpa_v8i16 = m_ir_builder->CreateBitCast(tmpa_v4i32, VectorType::get(m_ir_builder->getInt16Ty(), 8)); - - auto tmpb_v4i32 = m_ir_builder->CreateShl(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(7))); - tmpb_v4i32 = m_ir_builder->CreateAnd(tmpb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0xFC000000))); - vb_v4i32 = m_ir_builder->CreateShl(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(10))); - vb_v4i32 = m_ir_builder->CreateAnd(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(~0xFC000000))); - tmpb_v4i32 = m_ir_builder->CreateOr(tmpb_v4i32, vb_v4i32); - tmpb_v4i32 = m_ir_builder->CreateAnd(tmpb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0xFFE00000))); - vb_v4i32 = m_ir_builder->CreateShl(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(3))); - vb_v4i32 = m_ir_builder->CreateAnd(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(~0xFFE00000))); - tmpb_v4i32 = m_ir_builder->CreateOr(tmpb_v4i32, vb_v4i32); - auto tmpb_v8i16 = m_ir_builder->CreateBitCast(tmpb_v4i32, VectorType::get(m_ir_builder->getInt16Ty(), 8)); - - u32 mask_v8i32[8] = { 1, 3, 5, 7, 9, 11, 13, 15 }; - auto res_v8i16 = m_ir_builder->CreateShuffleVector(tmpb_v8i16, tmpa_v8i16, ConstantDataVector::get(m_ir_builder->getContext(), mask_v8i32)); - - SetVr(vd, res_v8i16); - - // TODO: Implement with pext on CPUs with BMI -} - -void Compiler::VPKSHSS(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto res_v16i8 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_packsswb_128), vb_v8i16, va_v8i16); - SetVr(vd, res_v16i8); - - // TODO: VSCR.SAT -} - -void Compiler::VPKSHUS(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto res_v16i8 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_packuswb_128), vb_v8i16, va_v8i16); - SetVr(vd, res_v16i8); - - // TODO: VSCR.SAT -} - -void Compiler::VPKSWSS(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto res_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_packssdw_128), vb_v4i32, va_v4i32); - SetVr(vd, res_v8i16); - - // TODO: VSCR.SAT -} - -void Compiler::VPKSWUS(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto res_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_packusdw), vb_v4i32, va_v4i32); - SetVr(vd, res_v8i16); - - // TODO: VSCR.SAT -} - -void Compiler::VPKUHUM(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - - u32 mask_v16i32[16] = { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30 }; - auto res_v16i8 = m_ir_builder->CreateShuffleVector(vb_v16i8, va_v16i8, ConstantDataVector::get(m_ir_builder->getContext(), mask_v16i32)); - SetVr(vd, res_v16i8); -} - -void Compiler::VPKUHUS(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - va_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pminuw), va_v8i16, m_ir_builder->CreateVectorSplat(8, m_ir_builder->getInt16(0xFF))); - vb_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pminuw), vb_v8i16, m_ir_builder->CreateVectorSplat(8, m_ir_builder->getInt16(0xFF))); - auto va_v16i8 = m_ir_builder->CreateBitCast(va_v8i16, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - auto vb_v16i8 = m_ir_builder->CreateBitCast(vb_v8i16, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - - u32 mask_v16i32[16] = { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30 }; - auto res_v16i8 = m_ir_builder->CreateShuffleVector(vb_v16i8, va_v16i8, ConstantDataVector::get(m_ir_builder->getContext(), mask_v16i32)); - SetVr(vd, res_v16i8); - - // TODO: Set VSCR.SAT -} - -void Compiler::VPKUWUM(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - - u32 mask_v8i32[8] = { 0, 2, 4, 6, 8, 10, 12, 14 }; - auto res_v8i16 = m_ir_builder->CreateShuffleVector(vb_v8i16, va_v8i16, ConstantDataVector::get(m_ir_builder->getContext(), mask_v8i32)); - SetVr(vd, res_v8i16); -} - -void Compiler::VPKUWUS(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - va_v4i32 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pminud), va_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0xFFFF))); - vb_v4i32 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pminud), vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0xFFFF))); - auto va_v8i16 = m_ir_builder->CreateBitCast(va_v4i32, VectorType::get(m_ir_builder->getInt16Ty(), 8)); - auto vb_v8i16 = m_ir_builder->CreateBitCast(vb_v4i32, VectorType::get(m_ir_builder->getInt16Ty(), 8)); - - u32 mask_v8i32[8] = { 0, 2, 4, 6, 8, 10, 12, 14 }; - auto res_v8i16 = m_ir_builder->CreateShuffleVector(vb_v8i16, va_v8i16, ConstantDataVector::get(m_ir_builder->getContext(), mask_v8i32)); - SetVr(vd, res_v8i16); - - // TODO: Set VSCR.SAT -} - -void Compiler::VREFP(u32 vd, u32 vb) { - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto res_v4f32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse_rcp_ps), vb_v4f32); - SetVr(vd, res_v4f32); -} - -void Compiler::VRFIM(u32 vd, u32 vb) { - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto res_v4f32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::floor, VectorType::get(m_ir_builder->getFloatTy(), 4)), vb_v4f32); - SetVr(vd, res_v4f32); -} - -void Compiler::VRFIN(u32 vd, u32 vb) { - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto res_v4f32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::nearbyint, VectorType::get(m_ir_builder->getFloatTy(), 4)), vb_v4f32); - SetVr(vd, res_v4f32); -} - -void Compiler::VRFIP(u32 vd, u32 vb) { - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto res_v4f32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::ceil, VectorType::get(m_ir_builder->getFloatTy(), 4)), vb_v4f32); - SetVr(vd, res_v4f32); -} - -void Compiler::VRFIZ(u32 vd, u32 vb) { - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto res_v4f32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::trunc, VectorType::get(m_ir_builder->getFloatTy(), 4)), vb_v4f32); - SetVr(vd, res_v4f32); -} - -void Compiler::VRLB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - vb_v16i8 = m_ir_builder->CreateAnd(vb_v16i8, m_ir_builder->CreateVectorSplat(16, m_ir_builder->getInt8(7))); - auto tmp1_v16i8 = m_ir_builder->CreateShl(va_v16i8, vb_v16i8); - vb_v16i8 = m_ir_builder->CreateSub(m_ir_builder->CreateVectorSplat(16, m_ir_builder->getInt8(8)), vb_v16i8); - auto tmp2_v16i8 = m_ir_builder->CreateLShr(va_v16i8, vb_v16i8); - auto res_v16i8 = m_ir_builder->CreateOr(tmp1_v16i8, tmp2_v16i8); - SetVr(vd, res_v16i8); -} - -void Compiler::VRLH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - vb_v8i16 = m_ir_builder->CreateAnd(vb_v8i16, m_ir_builder->CreateVectorSplat(8, m_ir_builder->getInt16(0xF))); - auto tmp1_v8i16 = m_ir_builder->CreateShl(va_v8i16, vb_v8i16); - vb_v8i16 = m_ir_builder->CreateSub(m_ir_builder->CreateVectorSplat(8, m_ir_builder->getInt16(0x10)), vb_v8i16); - auto tmp2_v8i16 = m_ir_builder->CreateLShr(va_v8i16, vb_v8i16); - auto res_v8i16 = m_ir_builder->CreateOr(tmp1_v8i16, tmp2_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VRLW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - vb_v4i32 = m_ir_builder->CreateAnd(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0x1F))); - auto tmp1_v4i32 = m_ir_builder->CreateShl(va_v4i32, vb_v4i32); - vb_v4i32 = m_ir_builder->CreateSub(m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0x20)), vb_v4i32); - auto tmp2_v4i32 = m_ir_builder->CreateLShr(va_v4i32, vb_v4i32); - auto res_v4i32 = m_ir_builder->CreateOr(tmp1_v4i32, tmp2_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VRSQRTEFP(u32 vd, u32 vb) { - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto res_v4f32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::sqrt, VectorType::get(m_ir_builder->getFloatTy(), 4)), vb_v4f32); - res_v4f32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse_rcp_ps), res_v4f32); - SetVr(vd, res_v4f32); -} - -void Compiler::VSEL(u32 vd, u32 va, u32 vb, u32 vc) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto vc_v4i32 = GetVrAsIntVec(vc, 32); - vb_v4i32 = m_ir_builder->CreateAnd(vb_v4i32, vc_v4i32); - vc_v4i32 = m_ir_builder->CreateNot(vc_v4i32); - va_v4i32 = m_ir_builder->CreateAnd(va_v4i32, vc_v4i32); - auto vd_v4i32 = m_ir_builder->CreateOr(va_v4i32, vb_v4i32); - SetVr(vd, vd_v4i32); -} - -void Compiler::VSL(u32 vd, u32 va, u32 vb) { - auto va_i128 = GetVr(va); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto sh_i8 = m_ir_builder->CreateExtractElement(vb_v16i8, m_ir_builder->getInt8(0)); - sh_i8 = m_ir_builder->CreateAnd(sh_i8, 0x7); - auto sh_i128 = m_ir_builder->CreateZExt(sh_i8, m_ir_builder->getIntNTy(128)); - va_i128 = m_ir_builder->CreateShl(va_i128, sh_i128); - SetVr(vd, va_i128); -} - -void Compiler::VSLB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - vb_v16i8 = m_ir_builder->CreateAnd(vb_v16i8, m_ir_builder->CreateVectorSplat(16, m_ir_builder->getInt8(0x7))); - auto res_v16i8 = m_ir_builder->CreateShl(va_v16i8, vb_v16i8); - SetVr(vd, res_v16i8); -} - -void Compiler::VSLDOI(u32 vd, u32 va, u32 vb, u32 sh) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - sh = 16 - sh; - u32 mask_v16i32[16] = { sh, sh + 1, sh + 2, sh + 3, sh + 4, sh + 5, sh + 6, sh + 7, sh + 8, sh + 9, sh + 10, sh + 11, sh + 12, sh + 13, sh + 14, sh + 15 }; - auto vd_v16i8 = m_ir_builder->CreateShuffleVector(vb_v16i8, va_v16i8, ConstantDataVector::get(m_ir_builder->getContext(), mask_v16i32)); - SetVr(vd, vd_v16i8); -} - -void Compiler::VSLH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - vb_v8i16 = m_ir_builder->CreateAnd(vb_v8i16, m_ir_builder->CreateVectorSplat(8, m_ir_builder->getInt16(0xF))); - auto res_v8i16 = m_ir_builder->CreateShl(va_v8i16, vb_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VSLO(u32 vd, u32 va, u32 vb) { - auto va_i128 = GetVr(va); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto sh_i8 = m_ir_builder->CreateExtractElement(vb_v16i8, m_ir_builder->getInt8(0)); - sh_i8 = m_ir_builder->CreateAnd(sh_i8, 0x78); - auto sh_i128 = m_ir_builder->CreateZExt(sh_i8, m_ir_builder->getIntNTy(128)); - va_i128 = m_ir_builder->CreateShl(va_i128, sh_i128); - SetVr(vd, va_i128); -} - -void Compiler::VSLW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - vb_v4i32 = m_ir_builder->CreateAnd(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0x1F))); - auto res_v4i32 = m_ir_builder->CreateShl(va_v4i32, vb_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VSPLTB(u32 vd, u32 uimm5, u32 vb) { - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto undef_v16i8 = UndefValue::get(VectorType::get(m_ir_builder->getInt8Ty(), 16)); - auto mask_v16i32 = m_ir_builder->CreateVectorSplat(16, m_ir_builder->getInt32(15 - uimm5)); - auto res_v16i8 = m_ir_builder->CreateShuffleVector(vb_v16i8, undef_v16i8, mask_v16i32); - SetVr(vd, res_v16i8); -} - -void Compiler::VSPLTH(u32 vd, u32 uimm5, u32 vb) { - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto undef_v8i16 = UndefValue::get(VectorType::get(m_ir_builder->getInt16Ty(), 8)); - auto mask_v8i32 = m_ir_builder->CreateVectorSplat(8, m_ir_builder->getInt32(7 - uimm5)); - auto res_v8i16 = m_ir_builder->CreateShuffleVector(vb_v8i16, undef_v8i16, mask_v8i32); - SetVr(vd, res_v8i16); -} - -void Compiler::VSPLTISB(u32 vd, s32 simm5) { - auto vd_v16i8 = m_ir_builder->CreateVectorSplat(16, m_ir_builder->getInt8((s8)simm5)); - SetVr(vd, vd_v16i8); -} - -void Compiler::VSPLTISH(u32 vd, s32 simm5) { - auto vd_v8i16 = m_ir_builder->CreateVectorSplat(8, m_ir_builder->getInt16((s16)simm5)); - SetVr(vd, vd_v8i16); -} - -void Compiler::VSPLTISW(u32 vd, s32 simm5) { - auto vd_v4i32 = m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32((s32)simm5)); - SetVr(vd, vd_v4i32); -} - -void Compiler::VSPLTW(u32 vd, u32 uimm5, u32 vb) { - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto undef_v4i32 = UndefValue::get(VectorType::get(m_ir_builder->getInt32Ty(), 4)); - auto mask_v4i32 = m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(3 - uimm5)); - auto res_v4i32 = m_ir_builder->CreateShuffleVector(vb_v4i32, undef_v4i32, mask_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VSR(u32 vd, u32 va, u32 vb) { - auto va_i128 = GetVr(va); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto sh_i8 = m_ir_builder->CreateExtractElement(vb_v16i8, m_ir_builder->getInt8(0)); - sh_i8 = m_ir_builder->CreateAnd(sh_i8, 0x7); - auto sh_i128 = m_ir_builder->CreateZExt(sh_i8, m_ir_builder->getIntNTy(128)); - va_i128 = m_ir_builder->CreateLShr(va_i128, sh_i128); - SetVr(vd, va_i128); -} - -void Compiler::VSRAB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - vb_v16i8 = m_ir_builder->CreateAnd(vb_v16i8, m_ir_builder->CreateVectorSplat(16, m_ir_builder->getInt8(0x7))); - auto res_v16i8 = m_ir_builder->CreateAShr(va_v16i8, vb_v16i8); - SetVr(vd, res_v16i8); -} - -void Compiler::VSRAH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - vb_v8i16 = m_ir_builder->CreateAnd(vb_v8i16, m_ir_builder->CreateVectorSplat(8, m_ir_builder->getInt16(0xF))); - auto res_v8i16 = m_ir_builder->CreateAShr(va_v8i16, vb_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VSRAW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - vb_v4i32 = m_ir_builder->CreateAnd(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0x1F))); - auto res_v4i32 = m_ir_builder->CreateAShr(va_v4i32, vb_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VSRB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - vb_v16i8 = m_ir_builder->CreateAnd(vb_v16i8, m_ir_builder->CreateVectorSplat(16, m_ir_builder->getInt8(0x7))); - auto res_v16i8 = m_ir_builder->CreateLShr(va_v16i8, vb_v16i8); - SetVr(vd, res_v16i8); -} - -void Compiler::VSRH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - vb_v8i16 = m_ir_builder->CreateAnd(vb_v8i16, m_ir_builder->CreateVectorSplat(8, m_ir_builder->getInt16(0xF))); - auto res_v8i16 = m_ir_builder->CreateLShr(va_v8i16, vb_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VSRO(u32 vd, u32 va, u32 vb) { - auto va_i128 = GetVr(va); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto sh_i8 = m_ir_builder->CreateExtractElement(vb_v16i8, m_ir_builder->getInt8(0)); - sh_i8 = m_ir_builder->CreateAnd(sh_i8, 0x78); - auto sh_i128 = m_ir_builder->CreateZExt(sh_i8, m_ir_builder->getIntNTy(128)); - va_i128 = m_ir_builder->CreateLShr(va_i128, sh_i128); - SetVr(vd, va_i128); -} - -void Compiler::VSRW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - vb_v4i32 = m_ir_builder->CreateAnd(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0x1F))); - auto res_v4i32 = m_ir_builder->CreateLShr(va_v4i32, vb_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VSUBCUW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - - auto cmpv4i1 = m_ir_builder->CreateICmpUGE(va_v4i32, vb_v4i32); - auto cmpv4i32 = m_ir_builder->CreateZExt(cmpv4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, cmpv4i32); -} - -void Compiler::VSUBFP(u32 vd, u32 va, u32 vb) { - auto va_v4f32 = GetVrAsFloatVec(va); - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto diff_v4f32 = m_ir_builder->CreateFSub(va_v4f32, vb_v4f32); - SetVr(vd, diff_v4f32); -} - -void Compiler::VSUBSBS(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto diff_v16i8 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_psubs_b), va_v16i8, vb_v16i8); - SetVr(vd, diff_v16i8); - - // TODO: Set VSCR.SAT -} - -void Compiler::VSUBSHS(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto diff_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_psubs_w), va_v8i16, vb_v8i16); - SetVr(vd, diff_v8i16); - - // TODO: Set VSCR.SAT -} - -void Compiler::VSUBSWS(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - - // See the comments for VADDSWS for a detailed description of how this works - - // Find the result in case of an overflow - auto tmp1_v4i32 = m_ir_builder->CreateLShr(va_v4i32, 31); - tmp1_v4i32 = m_ir_builder->CreateAdd(tmp1_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0x7FFFFFFF))); - auto tmp1_v16i8 = m_ir_builder->CreateBitCast(tmp1_v4i32, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - - // Find the elements that can overflow (elements with opposite sign bits) - auto tmp2_v4i32 = m_ir_builder->CreateXor(va_v4i32, vb_v4i32); - - // Perform the sub - auto diff_v4i32 = m_ir_builder->CreateSub(va_v4i32, vb_v4i32); - auto diff_v16i8 = m_ir_builder->CreateBitCast(diff_v4i32, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - - // Find the elements that overflowed - auto tmp3_v4i32 = m_ir_builder->CreateXor(va_v4i32, diff_v4i32); - tmp3_v4i32 = m_ir_builder->CreateAnd(tmp2_v4i32, tmp3_v4i32); - tmp3_v4i32 = m_ir_builder->CreateAShr(tmp3_v4i32, 31); - auto tmp3_v16i8 = m_ir_builder->CreateBitCast(tmp3_v4i32, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - - // tmp4 is equal to 0xFFFFFFFF if an overflow occured and 0x00000000 otherwise. - auto res_v16i8 = m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pblendvb), diff_v16i8, tmp1_v16i8, tmp3_v16i8); - SetVr(vd, res_v16i8); - - // TODO: Set SAT -} - -void Compiler::VSUBUBM(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto diff_v16i8 = m_ir_builder->CreateSub(va_v16i8, vb_v16i8); - SetVr(vd, diff_v16i8); -} - -void Compiler::VSUBUBS(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto diff_v16i8 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_psubus_b), va_v16i8, vb_v16i8); - SetVr(vd, diff_v16i8); - - // TODO: Set SAT -} - -void Compiler::VSUBUHM(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto diff_v8i16 = m_ir_builder->CreateSub(va_v8i16, vb_v8i16); - SetVr(vd, diff_v8i16); -} - -void Compiler::VSUBUHS(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto diff_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_psubus_w), va_v8i16, vb_v8i16); - SetVr(vd, diff_v8i16); - - // TODO: Set SAT -} - -void Compiler::VSUBUWM(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto diff_v4i32 = m_ir_builder->CreateSub(va_v4i32, vb_v4i32); - SetVr(vd, diff_v4i32); -} - -void Compiler::VSUBUWS(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto diff_v4i32 = m_ir_builder->CreateSub(va_v4i32, vb_v4i32); - auto cmp_v4i1 = m_ir_builder->CreateICmpULE(diff_v4i32, va_v4i32); - auto cmp_v4i32 = m_ir_builder->CreateSExt(cmp_v4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - auto res_v4i32 = m_ir_builder->CreateAnd(diff_v4i32, cmp_v4i32); - SetVr(vd, res_v4i32); - - // TODO: Set SAT -} - -void Compiler::VSUMSWS(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - - auto res_i32 = m_ir_builder->CreateExtractElement(vb_v4i32, m_ir_builder->getInt32(3)); - auto res_i64 = m_ir_builder->CreateSExt(res_i32, m_ir_builder->getInt64Ty()); - for (auto i = 0; i < 4; i++) { - auto va_i32 = m_ir_builder->CreateExtractElement(va_v4i32, m_ir_builder->getInt32(i)); - auto va_i64 = m_ir_builder->CreateSExt(va_i32, m_ir_builder->getInt64Ty()); - res_i64 = m_ir_builder->CreateAdd(res_i64, va_i64); - } - - auto gt_i1 = m_ir_builder->CreateICmpSGT(res_i64, m_ir_builder->getInt64(0x7FFFFFFFull)); - auto lt_i1 = m_ir_builder->CreateICmpSLT(res_i64, m_ir_builder->getInt64(0xFFFFFFFF80000000ull)); - res_i64 = m_ir_builder->CreateSelect(gt_i1, m_ir_builder->getInt64(0x7FFFFFFFull), res_i64); - res_i64 = m_ir_builder->CreateSelect(lt_i1, m_ir_builder->getInt64(0xFFFFFFFF80000000ull), res_i64); - auto res_i128 = m_ir_builder->CreateZExt(res_i64, m_ir_builder->getIntNTy(128)); - - SetVr(vd, res_i128); - - // TODO: Set VSCR.SAT -} - -void Compiler::VSUM2SWS(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - - u32 mask1_v2i32[2] = { 0, 2 }; - u32 mask2_v2i32[2] = { 1, 3 }; - auto va_v4i64 = m_ir_builder->CreateSExt(va_v4i32, VectorType::get(m_ir_builder->getInt64Ty(), 4)); - auto va1_v2i64 = m_ir_builder->CreateShuffleVector(va_v4i64, UndefValue::get(va_v4i64->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask1_v2i32)); - auto va2_v2i64 = m_ir_builder->CreateShuffleVector(va_v4i64, UndefValue::get(va_v4i64->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask2_v2i32)); - auto vb_v4i64 = m_ir_builder->CreateSExt(vb_v4i32, VectorType::get(m_ir_builder->getInt64Ty(), 4)); - auto vb_v2i64 = m_ir_builder->CreateShuffleVector(vb_v4i64, UndefValue::get(vb_v4i64->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask1_v2i32)); - - auto res_v2i64 = m_ir_builder->CreateAdd(va1_v2i64, va2_v2i64); - res_v2i64 = m_ir_builder->CreateAdd(res_v2i64, vb_v2i64); - auto gt_v2i1 = m_ir_builder->CreateICmpSGT(res_v2i64, m_ir_builder->CreateVectorSplat(2, m_ir_builder->getInt64(0x7FFFFFFFull))); - auto lt_v2i1 = m_ir_builder->CreateICmpSLT(res_v2i64, m_ir_builder->CreateVectorSplat(2, m_ir_builder->getInt64(0xFFFFFFFF80000000ull))); - res_v2i64 = m_ir_builder->CreateSelect(gt_v2i1, m_ir_builder->CreateVectorSplat(2, m_ir_builder->getInt64(0x7FFFFFFFull)), res_v2i64); - res_v2i64 = m_ir_builder->CreateSelect(lt_v2i1, m_ir_builder->CreateVectorSplat(2, m_ir_builder->getInt64(0x80000000ull)), res_v2i64); - SetVr(vd, res_v2i64); - - // TODO: Set VSCR.SAT -} - -void Compiler::VSUM4SBS(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - - u32 mask1_v4i32[4] = { 0, 4, 8, 12 }; - u32 mask2_v4i32[4] = { 1, 5, 9, 13 }; - u32 mask3_v4i32[4] = { 2, 6, 10, 14 }; - u32 mask4_v4i32[4] = { 3, 7, 11, 15 }; - auto va_v16i64 = m_ir_builder->CreateSExt(va_v16i8, VectorType::get(m_ir_builder->getInt64Ty(), 16)); - auto va1_v4i64 = m_ir_builder->CreateShuffleVector(va_v16i64, UndefValue::get(va_v16i64->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask1_v4i32)); - auto va2_v4i64 = m_ir_builder->CreateShuffleVector(va_v16i64, UndefValue::get(va_v16i64->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask2_v4i32)); - auto va3_v4i64 = m_ir_builder->CreateShuffleVector(va_v16i64, UndefValue::get(va_v16i64->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask3_v4i32)); - auto va4_v4i64 = m_ir_builder->CreateShuffleVector(va_v16i64, UndefValue::get(va_v16i64->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask4_v4i32)); - auto vb_v4i64 = m_ir_builder->CreateSExt(vb_v4i32, VectorType::get(m_ir_builder->getInt64Ty(), 4)); - - auto res_v4i64 = m_ir_builder->CreateAdd(va1_v4i64, va2_v4i64); - res_v4i64 = m_ir_builder->CreateAdd(res_v4i64, va3_v4i64); - res_v4i64 = m_ir_builder->CreateAdd(res_v4i64, va4_v4i64); - res_v4i64 = m_ir_builder->CreateAdd(res_v4i64, vb_v4i64); - auto gt_v4i1 = m_ir_builder->CreateICmpSGT(res_v4i64, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt64(0x7FFFFFFFull))); - auto lt_v4i1 = m_ir_builder->CreateICmpSLT(res_v4i64, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt64(0xFFFFFFFF80000000ull))); - res_v4i64 = m_ir_builder->CreateSelect(gt_v4i1, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt64(0x7FFFFFFFull)), res_v4i64); - res_v4i64 = m_ir_builder->CreateSelect(lt_v4i1, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt64(0x80000000ull)), res_v4i64); - auto res_v4i32 = m_ir_builder->CreateTrunc(res_v4i64, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, res_v4i32); - - // TODO: Set VSCR.SAT -} - -void Compiler::VSUM4SHS(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - - u32 mask1_v4i32[4] = { 0, 2, 4, 6 }; - u32 mask2_v4i32[4] = { 1, 3, 5, 7 }; - auto va_v8i64 = m_ir_builder->CreateSExt(va_v8i16, VectorType::get(m_ir_builder->getInt64Ty(), 8)); - auto va1_v4i64 = m_ir_builder->CreateShuffleVector(va_v8i64, UndefValue::get(va_v8i64->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask1_v4i32)); - auto va2_v4i64 = m_ir_builder->CreateShuffleVector(va_v8i64, UndefValue::get(va_v8i64->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask2_v4i32)); - auto vb_v4i64 = m_ir_builder->CreateSExt(vb_v4i32, VectorType::get(m_ir_builder->getInt64Ty(), 4)); - - auto res_v4i64 = m_ir_builder->CreateAdd(va1_v4i64, va2_v4i64); - res_v4i64 = m_ir_builder->CreateAdd(res_v4i64, vb_v4i64); - auto gt_v4i1 = m_ir_builder->CreateICmpSGT(res_v4i64, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt64(0x7FFFFFFFull))); - auto lt_v4i1 = m_ir_builder->CreateICmpSLT(res_v4i64, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt64(0xFFFFFFFF80000000ull))); - res_v4i64 = m_ir_builder->CreateSelect(gt_v4i1, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt64(0x7FFFFFFFull)), res_v4i64); - res_v4i64 = m_ir_builder->CreateSelect(lt_v4i1, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt64(0x80000000ull)), res_v4i64); - auto res_v4i32 = m_ir_builder->CreateTrunc(res_v4i64, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, res_v4i32); - - // TODO: Set VSCR.SAT -} - -void Compiler::VSUM4UBS(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - - u32 mask1_v4i32[4] = { 0, 4, 8, 12 }; - u32 mask2_v4i32[4] = { 1, 5, 9, 13 }; - u32 mask3_v4i32[4] = { 2, 6, 10, 14 }; - u32 mask4_v4i32[4] = { 3, 7, 11, 15 }; - auto va1_v4i8 = m_ir_builder->CreateShuffleVector(va_v16i8, UndefValue::get(va_v16i8->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask1_v4i32)); - auto va1_v4i32 = m_ir_builder->CreateZExt(va1_v4i8, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - auto va2_v4i8 = m_ir_builder->CreateShuffleVector(va_v16i8, UndefValue::get(va_v16i8->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask2_v4i32)); - auto va2_v4i32 = m_ir_builder->CreateZExt(va2_v4i8, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - auto va3_v4i8 = m_ir_builder->CreateShuffleVector(va_v16i8, UndefValue::get(va_v16i8->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask3_v4i32)); - auto va3_v4i32 = m_ir_builder->CreateZExt(va3_v4i8, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - auto va4_v4i8 = m_ir_builder->CreateShuffleVector(va_v16i8, UndefValue::get(va_v16i8->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask4_v4i32)); - auto va4_v4i32 = m_ir_builder->CreateZExt(va4_v4i8, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - - auto res_v4i32 = m_ir_builder->CreateAdd(va1_v4i32, va2_v4i32); - res_v4i32 = m_ir_builder->CreateAdd(res_v4i32, va3_v4i32); - res_v4i32 = m_ir_builder->CreateAdd(res_v4i32, va4_v4i32); - res_v4i32 = m_ir_builder->CreateAdd(res_v4i32, vb_v4i32); - auto lt_v4i1 = m_ir_builder->CreateICmpULT(res_v4i32, vb_v4i32); - auto lt_v4i32 = m_ir_builder->CreateSExt(lt_v4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - res_v4i32 = m_ir_builder->CreateOr(lt_v4i32, res_v4i32); - SetVr(vd, res_v4i32); - - // TODO: Set VSCR.SAT -} - -void Compiler::VUPKHPX(u32 vd, u32 vb) { - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - u32 mask_v8i32[8] = { 4, 4, 5, 5, 6, 6, 7, 7 }; - vb_v8i16 = m_ir_builder->CreateShuffleVector(vb_v8i16, UndefValue::get(VectorType::get(m_ir_builder->getInt16Ty(), 8)), ConstantDataVector::get(m_ir_builder->getContext(), mask_v8i32)); - - auto vb_v4i32 = m_ir_builder->CreateBitCast(vb_v8i16, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - vb_v4i32 = m_ir_builder->CreateAShr(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(10))); - auto tmp1_v4i32 = m_ir_builder->CreateLShr(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(3))); - tmp1_v4i32 = m_ir_builder->CreateAnd(tmp1_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0x00001F00))); - auto tmp2_v4i32 = m_ir_builder->CreateLShr(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(6))); - tmp2_v4i32 = m_ir_builder->CreateAnd(tmp2_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0x0000001F))); - auto res_v4i32 = m_ir_builder->CreateAnd(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0xFF1F0000))); - res_v4i32 = m_ir_builder->CreateOr(res_v4i32, tmp1_v4i32); - res_v4i32 = m_ir_builder->CreateOr(res_v4i32, tmp2_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VUPKHSB(u32 vd, u32 vb) { - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - u32 mask_v8i32[8] = { 8, 9, 10, 11, 12, 13, 14, 15 }; - auto vb_v8i8 = m_ir_builder->CreateShuffleVector(vb_v16i8, UndefValue::get(VectorType::get(m_ir_builder->getInt8Ty(), 16)), ConstantDataVector::get(m_ir_builder->getContext(), mask_v8i32)); - auto res_v8i16 = m_ir_builder->CreateSExt(vb_v8i8, VectorType::get(m_ir_builder->getInt16Ty(), 8)); - SetVr(vd, res_v8i16); -} - -void Compiler::VUPKHSH(u32 vd, u32 vb) { - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - u32 mask_v4i32[4] = { 4, 5, 6, 7 }; - auto vb_v4i16 = m_ir_builder->CreateShuffleVector(vb_v8i16, UndefValue::get(VectorType::get(m_ir_builder->getInt16Ty(), 8)), ConstantDataVector::get(m_ir_builder->getContext(), mask_v4i32)); - auto res_v4i32 = m_ir_builder->CreateSExt(vb_v4i16, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, res_v4i32); -} - -void Compiler::VUPKLPX(u32 vd, u32 vb) { - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - u32 mask_v8i32[8] = { 0, 0, 1, 1, 2, 2, 3, 3 }; - vb_v8i16 = m_ir_builder->CreateShuffleVector(vb_v8i16, UndefValue::get(VectorType::get(m_ir_builder->getInt16Ty(), 8)), ConstantDataVector::get(m_ir_builder->getContext(), mask_v8i32)); - - auto vb_v4i32 = m_ir_builder->CreateBitCast(vb_v8i16, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - vb_v4i32 = m_ir_builder->CreateAShr(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(10))); - auto tmp1_v4i32 = m_ir_builder->CreateLShr(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(3))); - tmp1_v4i32 = m_ir_builder->CreateAnd(tmp1_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0x00001F00))); - auto tmp2_v4i32 = m_ir_builder->CreateLShr(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(6))); - tmp2_v4i32 = m_ir_builder->CreateAnd(tmp2_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0x0000001F))); - auto res_v4i32 = m_ir_builder->CreateAnd(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0xFF1F0000))); - res_v4i32 = m_ir_builder->CreateOr(res_v4i32, tmp1_v4i32); - res_v4i32 = m_ir_builder->CreateOr(res_v4i32, tmp2_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VUPKLSB(u32 vd, u32 vb) { - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - u32 mask_v8i32[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; - auto vb_v8i8 = m_ir_builder->CreateShuffleVector(vb_v16i8, UndefValue::get(VectorType::get(m_ir_builder->getInt8Ty(), 16)), ConstantDataVector::get(m_ir_builder->getContext(), mask_v8i32)); - auto res_v8i16 = m_ir_builder->CreateSExt(vb_v8i8, VectorType::get(m_ir_builder->getInt16Ty(), 8)); - SetVr(vd, res_v8i16); -} - -void Compiler::VUPKLSH(u32 vd, u32 vb) { - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - u32 mask_v4i32[4] = { 0, 1, 2, 3 }; - auto vb_v4i16 = m_ir_builder->CreateShuffleVector(vb_v8i16, UndefValue::get(VectorType::get(m_ir_builder->getInt16Ty(), 8)), ConstantDataVector::get(m_ir_builder->getContext(), mask_v4i32)); - auto res_v4i32 = m_ir_builder->CreateSExt(vb_v4i16, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, res_v4i32); -} - -void Compiler::VXOR(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto res_v8i16 = m_ir_builder->CreateXor(va_v8i16, vb_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::MULLI(u32 rd, u32 ra, s32 simm16) { - USE_INTERP_IF_REQUESTED(MULLI, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(simm16)); - - auto ra_i64 = GetGpr(ra); - auto res_i64 = m_ir_builder->CreateMul(ra_i64, m_ir_builder->getInt64((s64)simm16)); - SetGpr(rd, res_i64); -} - -void Compiler::SUBFIC(u32 rd, u32 ra, s32 simm16) { - USE_INTERP_IF_REQUESTED(SUBFIC, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(simm16)) - - auto ra_i64 = GetGpr(ra); - ra_i64 = m_ir_builder->CreateNeg(ra_i64); // simpler way of doing ~ra + 1 - auto res_s = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::uadd_with_overflow, m_ir_builder->getInt64Ty()), ra_i64, m_ir_builder->getInt64((s64)simm16)); - auto diff_i64 = m_ir_builder->CreateExtractValue(res_s, { 0 }); - auto carry_i1 = m_ir_builder->CreateExtractValue(res_s, { 1 }); - auto is_zero = m_ir_builder->CreateICmpEQ(ra_i64, m_ir_builder->getInt64(0)); // if ra is zero when ~ra + 1 = 0 sets overflow bit - carry_i1 = m_ir_builder->CreateOr(is_zero, carry_i1); - SetGpr(rd, diff_i64); - SetXerCa(carry_i1); -} - -void Compiler::CMPLI(u32 crfd, u32 l, u32 ra, u32 uimm16) { - USE_INTERP_IF_REQUESTED(CMPLI, m_ir_builder->getInt32(crfd), m_ir_builder->getInt32(l), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(uimm16)); - - Value * ra_i64; - if (l == 0) { - ra_i64 = m_ir_builder->CreateZExt(GetGpr(ra, 32), m_ir_builder->getInt64Ty()); - } - else { - ra_i64 = GetGpr(ra); - } - - SetCrFieldUnsignedCmp(crfd, ra_i64, m_ir_builder->getInt64(uimm16)); -} - -void Compiler::CMPI(u32 crfd, u32 l, u32 ra, s32 simm16) { - USE_INTERP_IF_REQUESTED(CMPI, m_ir_builder->getInt32(crfd), m_ir_builder->getInt32(l), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(simm16)); - - Value * ra_i64; - if (l == 0) { - ra_i64 = m_ir_builder->CreateSExt(GetGpr(ra, 32), m_ir_builder->getInt64Ty()); - } - else { - ra_i64 = GetGpr(ra); - } - - SetCrFieldSignedCmp(crfd, ra_i64, m_ir_builder->getInt64((s64)simm16)); -} - -void Compiler::ADDIC(u32 rd, u32 ra, s32 simm16) { - USE_INTERP_IF_REQUESTED(ADDIC, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(simm16)); - - auto ra_i64 = GetGpr(ra); - auto res_s = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::uadd_with_overflow, m_ir_builder->getInt64Ty()), m_ir_builder->getInt64((s64)simm16), ra_i64); - auto sum_i64 = m_ir_builder->CreateExtractValue(res_s, { 0 }); - auto carry_i1 = m_ir_builder->CreateExtractValue(res_s, { 1 }); - SetGpr(rd, sum_i64); - SetXerCa(carry_i1); -} - -void Compiler::ADDIC_(u32 rd, u32 ra, s32 simm16) { - USE_INTERP_IF_REQUESTED(ADDIC_, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(simm16)); - - ADDIC(rd, ra, simm16); - SetCrFieldSignedCmp(0, GetGpr(rd), m_ir_builder->getInt64(0)); -} - -void Compiler::ADDI(u32 rd, u32 ra, s32 simm16) { - USE_INTERP_IF_REQUESTED(ADDI, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(simm16)); - - if (ra == 0) { - SetGpr(rd, m_ir_builder->getInt64((s64)simm16)); - } - else { - auto ra_i64 = GetGpr(ra); - auto sum_i64 = m_ir_builder->CreateAdd(ra_i64, m_ir_builder->getInt64((s64)simm16)); - SetGpr(rd, sum_i64); - } -} - -void Compiler::ADDIS(u32 rd, u32 ra, s32 simm16) { - USE_INTERP_IF_REQUESTED(ADDIS, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(simm16)); - - if (ra == 0) { - SetGpr(rd, m_ir_builder->getInt64((s64)simm16 << 16)); - } - else { - auto ra_i64 = GetGpr(ra); - auto sum_i64 = m_ir_builder->CreateAdd(ra_i64, m_ir_builder->getInt64((s64)simm16 << 16)); - SetGpr(rd, sum_i64); - } -} - -void Compiler::BC(u32 bo, u32 bi, s32 bd, u32 aa, u32 lk) { - auto target_i64 = m_ir_builder->getInt64(branchTarget(aa ? 0 : m_state.current_instruction_address, bd)); - auto target_i32 = m_ir_builder->CreateTrunc(target_i64, m_ir_builder->getInt32Ty()); - CreateBranch(CheckBranchCondition(bo, bi), target_i32, lk ? true : false); -} - -void Compiler::HACK(u32 index) { - llvm::Value *status = Call("wrappedExecutePPUFuncByIndex", m_state.args[CompileTaskState::Args::State], m_ir_builder->getInt32(index & EIF_USE_BRANCH ? index : index & ~EIF_PERFORM_BLR)); - llvm::BasicBlock *cputhreadexitblock = GetBasicBlockFromAddress(m_state.current_instruction_address, "early_exit"); - llvm::Value *isCPUThreadExit = m_ir_builder->CreateICmpEQ(status, m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusPropagateException)); - llvm::BasicBlock *normal_execution = GetBasicBlockFromAddress(m_state.current_instruction_address, "normal_execution"); - m_ir_builder->CreateCondBr(isCPUThreadExit, cputhreadexitblock, normal_execution); - m_ir_builder->SetInsertPoint(cputhreadexitblock); - m_ir_builder->CreateRet(m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusPropagateException)); - - m_ir_builder->SetInsertPoint(normal_execution); - if (index & EIF_PERFORM_BLR || index & EIF_USE_BRANCH) { - auto lr_i32 = index & EIF_USE_BRANCH ? GetPc() : m_ir_builder->CreateTrunc(m_ir_builder->CreateAnd(GetLr(), ~0x3ULL), m_ir_builder->getInt32Ty()); - CreateBranch(nullptr, lr_i32, false, (index & EIF_USE_BRANCH) == 0); - } -} - -void Compiler::SC(u32 lev) { - switch (lev) { - case 0: - { - llvm::Value *status = Call("wrappedDoSyscall", m_state.args[CompileTaskState::Args::State], GetGpr(11)); - llvm::BasicBlock *cputhreadexitblock = GetBasicBlockFromAddress(m_state.current_instruction_address, "early_exit"); - llvm::Value *isCPUThreadExit = m_ir_builder->CreateICmpEQ(status, m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusPropagateException)); - llvm::BasicBlock *normal_execution = GetBasicBlockFromAddress(m_state.current_instruction_address, "normal_execution"); - m_ir_builder->CreateCondBr(isCPUThreadExit, cputhreadexitblock, normal_execution); - m_ir_builder->SetInsertPoint(cputhreadexitblock); - m_ir_builder->CreateRet(m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusPropagateException)); - m_ir_builder->SetInsertPoint(normal_execution); - } - break; - case 3: - Call("PPUThread.fast_stop", m_state.args[CompileTaskState::Args::State]); - break; - default: - CompilationError(fmt::format("SC %u", lev)); - break; - } - - auto ret_i1 = Call("PollStatus", m_state.args[CompileTaskState::Args::State]); - auto cmp_i1 = m_ir_builder->CreateICmpEQ(ret_i1, m_ir_builder->getInt1(true)); - auto then_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "then_true"); - auto merge_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "merge_true"); - m_ir_builder->CreateCondBr(cmp_i1, then_bb, merge_bb); - m_ir_builder->SetInsertPoint(then_bb); - m_ir_builder->CreateRet(m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusBlockEnded)); - m_ir_builder->SetInsertPoint(merge_bb); -} - -void Compiler::B(s32 ll, u32 aa, u32 lk) { - auto target_i64 = m_ir_builder->getInt64(branchTarget(aa ? 0 : m_state.current_instruction_address, ll)); - auto target_i32 = m_ir_builder->CreateTrunc(target_i64, m_ir_builder->getInt32Ty()); - CreateBranch(nullptr, target_i32, lk ? true : false); -} - -void Compiler::MCRF(u32 crfd, u32 crfs) { - USE_INTERP_IF_REQUESTED(MCRF, m_ir_builder->getInt32(crfd), m_ir_builder->getInt32(crfs)); - - if (crfd != crfs) { - auto cr_i32 = GetCr(); - auto crf_i32 = GetNibble(cr_i32, crfs); - cr_i32 = SetNibble(cr_i32, crfd, crf_i32); - SetCr(cr_i32); - } -} - -void Compiler::BCLR(u32 bo, u32 bi, u32 bh, u32 lk) { - auto lr_i64 = GetLr(); - lr_i64 = m_ir_builder->CreateAnd(lr_i64, ~0x3ULL); - auto lr_i32 = m_ir_builder->CreateTrunc(lr_i64, m_ir_builder->getInt32Ty()); - CreateBranch(CheckBranchCondition(bo, bi), lr_i32, lk ? true : false, true); -} - -void Compiler::CRNOR(u32 crbd, u32 crba, u32 crbb) { - USE_INTERP_IF_REQUESTED(CRNOR, m_ir_builder->getInt32(crbd), m_ir_builder->getInt32(crba), m_ir_builder->getInt32(crbb)); - - auto cr_i32 = GetCr(); - auto ba_i32 = GetBit(cr_i32, crba); - auto bb_i32 = GetBit(cr_i32, crbb); - auto res_i32 = m_ir_builder->CreateOr(ba_i32, bb_i32); - res_i32 = m_ir_builder->CreateXor(res_i32, 1); - cr_i32 = SetBit(cr_i32, crbd, res_i32); - SetCr(cr_i32); -} - -void Compiler::CRANDC(u32 crbd, u32 crba, u32 crbb) { - USE_INTERP_IF_REQUESTED(CRANDC, m_ir_builder->getInt32(crbd), m_ir_builder->getInt32(crba), m_ir_builder->getInt32(crbb)); - - auto cr_i32 = GetCr(); - auto ba_i32 = GetBit(cr_i32, crba); - auto bb_i32 = GetBit(cr_i32, crbb); - auto res_i32 = m_ir_builder->CreateXor(bb_i32, 1); - res_i32 = m_ir_builder->CreateAnd(ba_i32, res_i32); - cr_i32 = SetBit(cr_i32, crbd, res_i32); - SetCr(cr_i32); -} - -void Compiler::ISYNC() { - m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_mfence)); -} - -void Compiler::CRXOR(u32 crbd, u32 crba, u32 crbb) { - USE_INTERP_IF_REQUESTED(CRXOR, m_ir_builder->getInt32(crbd), m_ir_builder->getInt32(crba), m_ir_builder->getInt32(crbb)); - - auto cr_i32 = GetCr(); - auto ba_i32 = GetBit(cr_i32, crba); - auto bb_i32 = GetBit(cr_i32, crbb); - auto res_i32 = m_ir_builder->CreateXor(ba_i32, bb_i32); - cr_i32 = SetBit(cr_i32, crbd, res_i32); - SetCr(cr_i32); -} - -void Compiler::DCBI(u32 ra, u32 rb) { - // TODO: See if this can be translated to cache flush - m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::donothing)); -} - -void Compiler::CRNAND(u32 crbd, u32 crba, u32 crbb) { - USE_INTERP_IF_REQUESTED(CRNAND, m_ir_builder->getInt32(crbd), m_ir_builder->getInt32(crba), m_ir_builder->getInt32(crbb)); - - auto cr_i32 = GetCr(); - auto ba_i32 = GetBit(cr_i32, crba); - auto bb_i32 = GetBit(cr_i32, crbb); - auto res_i32 = m_ir_builder->CreateAnd(ba_i32, bb_i32); - res_i32 = m_ir_builder->CreateXor(res_i32, 1); - cr_i32 = SetBit(cr_i32, crbd, res_i32); - SetCr(cr_i32); -} - -void Compiler::CRAND(u32 crbd, u32 crba, u32 crbb) { - USE_INTERP_IF_REQUESTED(CRAND, m_ir_builder->getInt32(crbd), m_ir_builder->getInt32(crba), m_ir_builder->getInt32(crbb)); - - auto cr_i32 = GetCr(); - auto ba_i32 = GetBit(cr_i32, crba); - auto bb_i32 = GetBit(cr_i32, crbb); - auto res_i32 = m_ir_builder->CreateAnd(ba_i32, bb_i32); - cr_i32 = SetBit(cr_i32, crbd, res_i32); - SetCr(cr_i32); -} - -void Compiler::CREQV(u32 crbd, u32 crba, u32 crbb) { - USE_INTERP_IF_REQUESTED(CREQV, m_ir_builder->getInt32(crbd), m_ir_builder->getInt32(crba), m_ir_builder->getInt32(crbb)); - - auto cr_i32 = GetCr(); - auto ba_i32 = GetBit(cr_i32, crba); - auto bb_i32 = GetBit(cr_i32, crbb); - auto res_i32 = m_ir_builder->CreateXor(ba_i32, bb_i32); - res_i32 = m_ir_builder->CreateXor(res_i32, 1); - cr_i32 = SetBit(cr_i32, crbd, res_i32); - SetCr(cr_i32); -} - -void Compiler::CRORC(u32 crbd, u32 crba, u32 crbb) { - USE_INTERP_IF_REQUESTED(CRORC, m_ir_builder->getInt32(crbd), m_ir_builder->getInt32(crba), m_ir_builder->getInt32(crbb)); - - auto cr_i32 = GetCr(); - auto ba_i32 = GetBit(cr_i32, crba); - auto bb_i32 = GetBit(cr_i32, crbb); - auto res_i32 = m_ir_builder->CreateXor(bb_i32, 1); - res_i32 = m_ir_builder->CreateOr(ba_i32, res_i32); - cr_i32 = SetBit(cr_i32, crbd, res_i32); - SetCr(cr_i32); -} - -void Compiler::CROR(u32 crbd, u32 crba, u32 crbb) { - USE_INTERP_IF_REQUESTED(CROR, m_ir_builder->getInt32(crbd), m_ir_builder->getInt32(crba), m_ir_builder->getInt32(crbb)); - - auto cr_i32 = GetCr(); - auto ba_i32 = GetBit(cr_i32, crba); - auto bb_i32 = GetBit(cr_i32, crbb); - auto res_i32 = m_ir_builder->CreateOr(ba_i32, bb_i32); - cr_i32 = SetBit(cr_i32, crbd, res_i32); - SetCr(cr_i32); -} - -void Compiler::BCCTR(u32 bo, u32 bi, u32 bh, u32 lk) { - auto ctr_i64 = GetCtr(); - ctr_i64 = m_ir_builder->CreateAnd(ctr_i64, ~0x3ULL); - auto ctr_i32 = m_ir_builder->CreateTrunc(ctr_i64, m_ir_builder->getInt32Ty()); - CreateBranch(CheckBranchCondition(bo, bi), ctr_i32, lk ? true : false); -} - -void Compiler::RLWIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) { - USE_INTERP_IF_REQUESTED(RLWIMI, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(sh), m_ir_builder->getInt32(mb), m_ir_builder->getInt32(me), m_ir_builder->getInt32(rc)); - - auto rs_i32 = GetGpr(rs, 32); - auto rs_i64 = m_ir_builder->CreateZExt(rs_i32, m_ir_builder->getInt64Ty()); - auto rsh_i64 = m_ir_builder->CreateShl(rs_i64, 32); - rs_i64 = m_ir_builder->CreateOr(rs_i64, rsh_i64); - auto ra_i64 = GetGpr(ra); - auto res_i64 = rs_i64; - if (sh) { - auto resl_i64 = m_ir_builder->CreateLShr(rs_i64, 64 - sh); - auto resh_i64 = m_ir_builder->CreateShl(rs_i64, sh); - res_i64 = m_ir_builder->CreateOr(resh_i64, resl_i64); - } - - u64 mask = s_rotate_mask[32 + mb][32 + me]; - res_i64 = m_ir_builder->CreateAnd(res_i64, mask); - ra_i64 = m_ir_builder->CreateAnd(ra_i64, ~mask); - res_i64 = m_ir_builder->CreateOr(res_i64, ra_i64); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::RLWINM(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) { - USE_INTERP_IF_REQUESTED(RLWINM, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(sh), m_ir_builder->getInt32(mb), m_ir_builder->getInt32(me), m_ir_builder->getInt32(rc)); - - auto rs_i32 = GetGpr(rs, 32); - auto rs_i64 = m_ir_builder->CreateZExt(rs_i32, m_ir_builder->getInt64Ty()); - auto rsh_i64 = m_ir_builder->CreateShl(rs_i64, 32); - rs_i64 = m_ir_builder->CreateOr(rs_i64, rsh_i64); - auto res_i64 = rs_i64; - if (sh) { - auto resl_i64 = m_ir_builder->CreateLShr(rs_i64, 64 - sh); - auto resh_i64 = m_ir_builder->CreateShl(rs_i64, sh); - res_i64 = m_ir_builder->CreateOr(resh_i64, resl_i64); - } - - res_i64 = m_ir_builder->CreateAnd(res_i64, s_rotate_mask[32 + mb][32 + me]); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::RLWNM(u32 ra, u32 rs, u32 rb, u32 mb, u32 me, u32 rc) { - USE_INTERP_IF_REQUESTED(RLWNM, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(rb), m_ir_builder->getInt32(mb), m_ir_builder->getInt32(me), m_ir_builder->getInt32(rc)); - - auto rs_i32 = GetGpr(rs, 32); - auto rs_i64 = m_ir_builder->CreateZExt(rs_i32, m_ir_builder->getInt64Ty()); - auto rsh_i64 = m_ir_builder->CreateShl(rs_i64, 32); - rs_i64 = m_ir_builder->CreateOr(rs_i64, rsh_i64); - auto rb_i64 = GetGpr(rb); - auto shl_i64 = m_ir_builder->CreateAnd(rb_i64, 0x1F); - auto shr_i64 = m_ir_builder->CreateSub(m_ir_builder->getInt64(32), shl_i64); - auto resl_i64 = m_ir_builder->CreateLShr(rs_i64, shr_i64); - auto resh_i64 = m_ir_builder->CreateShl(rs_i64, shl_i64); - auto res_i64 = m_ir_builder->CreateOr(resh_i64, resl_i64); - res_i64 = m_ir_builder->CreateAnd(res_i64, s_rotate_mask[32 + mb][32 + me]); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::ORI(u32 ra, u32 rs, u32 uimm16) { - USE_INTERP_IF_REQUESTED(ORI, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(uimm16)); - - auto rs_i64 = GetGpr(rs); - auto res_i64 = m_ir_builder->CreateOr(rs_i64, uimm16); - SetGpr(ra, res_i64); -} - -void Compiler::ORIS(u32 ra, u32 rs, u32 uimm16) { - USE_INTERP_IF_REQUESTED(ORIS, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(uimm16)); - - auto rs_i64 = GetGpr(rs); - auto res_i64 = m_ir_builder->CreateOr(rs_i64, (u64)uimm16 << 16); - SetGpr(ra, res_i64); -} - -void Compiler::XORI(u32 ra, u32 rs, u32 uimm16) { - USE_INTERP_IF_REQUESTED(XORI, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(uimm16)); - - auto rs_i64 = GetGpr(rs); - auto res_i64 = m_ir_builder->CreateXor(rs_i64, uimm16); - SetGpr(ra, res_i64); -} - -void Compiler::XORIS(u32 ra, u32 rs, u32 uimm16) { - USE_INTERP_IF_REQUESTED(XORIS, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(uimm16)); - - auto rs_i64 = GetGpr(rs); - auto res_i64 = m_ir_builder->CreateXor(rs_i64, (u64)uimm16 << 16); - SetGpr(ra, res_i64); -} - -void Compiler::ANDI_(u32 ra, u32 rs, u32 uimm16) { - USE_INTERP_IF_REQUESTED(ANDI_, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(uimm16)); - - auto rs_i64 = GetGpr(rs); - auto res_i64 = m_ir_builder->CreateAnd(rs_i64, uimm16); - SetGpr(ra, res_i64); - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); -} - -void Compiler::ANDIS_(u32 ra, u32 rs, u32 uimm16) { - USE_INTERP_IF_REQUESTED(ANDIS_, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(uimm16)); - - auto rs_i64 = GetGpr(rs); - auto res_i64 = m_ir_builder->CreateAnd(rs_i64, (u64)uimm16 << 16); - SetGpr(ra, res_i64); - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); -} - -void Compiler::RLDICL(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) { - USE_INTERP_IF_REQUESTED(RLDICL, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(sh), m_ir_builder->getInt32(mb), m_ir_builder->getInt32(rc)); - - auto rs_i64 = GetGpr(rs); - auto res_i64 = rs_i64; - if (sh) { - auto resl_i64 = m_ir_builder->CreateLShr(rs_i64, 64 - sh); - auto resh_i64 = m_ir_builder->CreateShl(rs_i64, sh); - res_i64 = m_ir_builder->CreateOr(resh_i64, resl_i64); - } - - res_i64 = m_ir_builder->CreateAnd(res_i64, s_rotate_mask[mb][63]); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::RLDICR(u32 ra, u32 rs, u32 sh, u32 me, u32 rc) { - USE_INTERP_IF_REQUESTED(RLDICR, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(sh), m_ir_builder->getInt32(me), m_ir_builder->getInt32(rc)); - - auto rs_i64 = GetGpr(rs); - auto res_i64 = rs_i64; - if (sh) { - auto resl_i64 = m_ir_builder->CreateLShr(rs_i64, 64 - sh); - auto resh_i64 = m_ir_builder->CreateShl(rs_i64, sh); - res_i64 = m_ir_builder->CreateOr(resh_i64, resl_i64); - } - - res_i64 = m_ir_builder->CreateAnd(res_i64, s_rotate_mask[0][me]); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::RLDIC(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) { - USE_INTERP_IF_REQUESTED(RLDIC, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(sh), m_ir_builder->getInt32(mb), m_ir_builder->getInt32(rc)); - - auto rs_i64 = GetGpr(rs); - auto res_i64 = rs_i64; - if (sh) { - auto resl_i64 = m_ir_builder->CreateLShr(rs_i64, 64 - sh); - auto resh_i64 = m_ir_builder->CreateShl(rs_i64, sh); - res_i64 = m_ir_builder->CreateOr(resh_i64, resl_i64); - } - - res_i64 = m_ir_builder->CreateAnd(res_i64, s_rotate_mask[mb][63 - sh]); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::RLDIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) { - USE_INTERP_IF_REQUESTED(RLDIMI, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(sh), m_ir_builder->getInt32(mb), m_ir_builder->getInt32(rc)); - - auto rs_i64 = GetGpr(rs); - auto ra_i64 = GetGpr(ra); - auto res_i64 = rs_i64; - if (sh) { - auto resl_i64 = m_ir_builder->CreateLShr(rs_i64, 64 - sh); - auto resh_i64 = m_ir_builder->CreateShl(rs_i64, sh); - res_i64 = m_ir_builder->CreateOr(resh_i64, resl_i64); - } - - u64 mask = s_rotate_mask[mb][63 - sh]; - res_i64 = m_ir_builder->CreateAnd(res_i64, mask); - ra_i64 = m_ir_builder->CreateAnd(ra_i64, ~mask); - res_i64 = m_ir_builder->CreateOr(res_i64, ra_i64); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::RLDC_LR(u32 ra, u32 rs, u32 rb, u32 m_eb, u32 is_r, u32 rc) { - USE_INTERP_IF_REQUESTED(RLDC_LR, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(rb), m_ir_builder->getInt32(m_eb), m_ir_builder->getInt32(is_r), m_ir_builder->getInt32(rc)); - - auto rs_i64 = GetGpr(rs); - auto rb_i64 = GetGpr(rb); - auto shl_i64 = m_ir_builder->CreateAnd(rb_i64, 0x3F); - auto shr_i64 = m_ir_builder->CreateSub(m_ir_builder->getInt64(64), shl_i64); - auto resl_i64 = m_ir_builder->CreateLShr(rs_i64, shr_i64); - auto resh_i64 = m_ir_builder->CreateShl(rs_i64, shl_i64); - auto res_i64 = m_ir_builder->CreateOr(resh_i64, resl_i64); - - if (is_r) { - res_i64 = m_ir_builder->CreateAnd(res_i64, s_rotate_mask[0][m_eb]); - } - else { - res_i64 = m_ir_builder->CreateAnd(res_i64, s_rotate_mask[m_eb][63]); - } - - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::CMP(u32 crfd, u32 l, u32 ra, u32 rb) { - USE_INTERP_IF_REQUESTED(CMP, m_ir_builder->getInt32(crfd), m_ir_builder->getInt32(l), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rb)); - - Value * ra_i64; - Value * rb_i64; - if (l == 0) { - ra_i64 = m_ir_builder->CreateSExt(GetGpr(ra, 32), m_ir_builder->getInt64Ty()); - rb_i64 = m_ir_builder->CreateSExt(GetGpr(rb, 32), m_ir_builder->getInt64Ty()); - } - else { - ra_i64 = GetGpr(ra); - rb_i64 = GetGpr(rb); - } - - SetCrFieldSignedCmp(crfd, ra_i64, rb_i64); -} - -void Compiler::TW(u32 to, u32 ra, u32 rb) { - llvm::Value *gpr_a = GetGpr(ra, 32); - llvm::Value *gpr_b = GetGpr(rb, 32); - llvm::Value *trap_condition = m_ir_builder->getFalse(); - - if (to & 0x10) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpSLT(gpr_a, gpr_b)); - if (to & 0x8) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpSGT(gpr_a, gpr_b)); - if (to & 0x4) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpEQ(gpr_a, gpr_b)); - if (to & 0x2) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpULT(gpr_a, gpr_b)); - if (to & 0x1) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpUGT(gpr_a, gpr_b)); - - llvm::BasicBlock *trap_block = GetBasicBlockFromAddress(m_state.current_instruction_address, "trap_block"); - llvm::BasicBlock *normal_execution = GetBasicBlockFromAddress(m_state.current_instruction_address, "normal_execution"); - m_ir_builder->CreateCondBr(trap_condition, trap_block, normal_execution); - - m_ir_builder->SetInsertPoint(trap_block); - Call("trap"); - m_ir_builder->CreateRet(m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusPropagateException)); - - m_ir_builder->SetInsertPoint(normal_execution); -} - -void Compiler::LVSL(u32 vd, u32 ra, u32 rb) { - static const u64 s_lvsl_values[0x10][2] = { - { 0x08090A0B0C0D0E0F, 0x0001020304050607 }, - { 0x090A0B0C0D0E0F10, 0x0102030405060708 }, - { 0x0A0B0C0D0E0F1011, 0x0203040506070809 }, - { 0x0B0C0D0E0F101112, 0x030405060708090A }, - { 0x0C0D0E0F10111213, 0x0405060708090A0B }, - { 0x0D0E0F1011121314, 0x05060708090A0B0C }, - { 0x0E0F101112131415, 0x060708090A0B0C0D }, - { 0x0F10111213141516, 0x0708090A0B0C0D0E }, - { 0x1011121314151617, 0x08090A0B0C0D0E0F }, - { 0x1112131415161718, 0x090A0B0C0D0E0F10 }, - { 0x1213141516171819, 0x0A0B0C0D0E0F1011 }, - { 0x131415161718191A, 0x0B0C0D0E0F101112 }, - { 0x1415161718191A1B, 0x0C0D0E0F10111213 }, - { 0x15161718191A1B1C, 0x0D0E0F1011121314 }, - { 0x161718191A1B1C1D, 0x0E0F101112131415 }, - { 0x1718191A1B1C1D1E, 0x0F10111213141516 }, - }; - - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto index_i64 = m_ir_builder->CreateAnd(addr_i64, 0xF); - auto lvsl_values_v16i8_ptr = m_ir_builder->CreateIntToPtr(m_ir_builder->getInt64((u64)s_lvsl_values), VectorType::get(m_ir_builder->getInt8Ty(), 16)->getPointerTo()); - lvsl_values_v16i8_ptr = m_ir_builder->CreateGEP(lvsl_values_v16i8_ptr, index_i64); - auto val_v16i8 = m_ir_builder->CreateAlignedLoad(lvsl_values_v16i8_ptr, 16); - SetVr(vd, val_v16i8); -} - -void Compiler::LVEBX(u32 vd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto val_i8 = ReadMemory(addr_i64, 8); - auto index_i64 = m_ir_builder->CreateAnd(addr_i64, 0xf); - index_i64 = m_ir_builder->CreateSub(m_ir_builder->getInt64(15), index_i64); - auto vd_v16i8 = GetVrAsIntVec(vd, 8); - vd_v16i8 = m_ir_builder->CreateInsertElement(vd_v16i8, val_i8, index_i64); - SetVr(vd, vd_v16i8); -} - -void Compiler::SUBFC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { - auto ra_i64 = GetGpr(ra); - ra_i64 = m_ir_builder->CreateNeg(ra_i64); - auto rb_i64 = GetGpr(rb); - auto res_s = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::uadd_with_overflow, m_ir_builder->getInt64Ty()), ra_i64, rb_i64); - auto diff_i64 = m_ir_builder->CreateExtractValue(res_s, { 0 }); - auto carry_i1 = m_ir_builder->CreateExtractValue(res_s, { 1 }); - SetGpr(rd, diff_i64); - SetXerCa(carry_i1); - - if (rc) { - SetCrFieldSignedCmp(0, diff_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO: Implement this - CompilationError("SUBFCO"); - } -} - -void Compiler::ADDC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { - auto ra_i64 = GetGpr(ra); - auto rb_i64 = GetGpr(rb); - auto res_s = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::uadd_with_overflow, m_ir_builder->getInt64Ty()), ra_i64, rb_i64); - auto sum_i64 = m_ir_builder->CreateExtractValue(res_s, { 0 }); - auto carry_i1 = m_ir_builder->CreateExtractValue(res_s, { 1 }); - SetGpr(rd, sum_i64); - SetXerCa(carry_i1); - - if (rc) { - SetCrFieldSignedCmp(0, sum_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO: Implement this - } -} - -void Compiler::MULHDU(u32 rd, u32 ra, u32 rb, u32 rc) { - auto ra_i64 = GetGpr(ra); - auto rb_i64 = GetGpr(rb); - auto ra_i128 = m_ir_builder->CreateZExt(ra_i64, m_ir_builder->getIntNTy(128)); - auto rb_i128 = m_ir_builder->CreateZExt(rb_i64, m_ir_builder->getIntNTy(128)); - auto prod_i128 = m_ir_builder->CreateMul(ra_i128, rb_i128); - prod_i128 = m_ir_builder->CreateLShr(prod_i128, 64); - auto prod_i64 = m_ir_builder->CreateTrunc(prod_i128, m_ir_builder->getInt64Ty()); - SetGpr(rd, prod_i64); - - if (rc) { - SetCrFieldSignedCmp(0, prod_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::MULHWU(u32 rd, u32 ra, u32 rb, u32 rc) { - auto ra_i32 = GetGpr(ra, 32); - auto rb_i32 = GetGpr(rb, 32); - auto ra_i64 = m_ir_builder->CreateZExt(ra_i32, m_ir_builder->getInt64Ty()); - auto rb_i64 = m_ir_builder->CreateZExt(rb_i32, m_ir_builder->getInt64Ty()); - auto prod_i64 = m_ir_builder->CreateMul(ra_i64, rb_i64); - prod_i64 = m_ir_builder->CreateLShr(prod_i64, 32); - SetGpr(rd, prod_i64); - - if (rc) { - SetCrFieldSignedCmp(0, prod_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::MFOCRF(u32 a, u32 rd, u32 crm) { - USE_INTERP_IF_REQUESTED(MFOCRF, m_ir_builder->getInt32(a), m_ir_builder->getInt32(rd), m_ir_builder->getInt32(crm)); - - auto cr_i32 = GetCr(); - auto cr_i64 = m_ir_builder->CreateZExt(cr_i32, m_ir_builder->getInt64Ty()); - SetGpr(rd, cr_i64); -} - -void Compiler::LWARX(u32 rd, u32 ra, u32 rb) { - USE_INTERP_IF_REQUESTED(LWARX, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rb)); - - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto addr_i32 = m_ir_builder->CreateTrunc(addr_i64, m_ir_builder->getInt32Ty()); - auto val_i32_ptr = m_ir_builder->CreateAlloca(m_ir_builder->getInt32Ty()); - val_i32_ptr->setAlignment(4); - Call("vm.reservation_acquire", m_ir_builder->CreateBitCast(val_i32_ptr, m_ir_builder->getInt8PtrTy()), addr_i32, m_ir_builder->getInt32(4)); - auto val_i32 = (Value *)m_ir_builder->CreateLoad(val_i32_ptr); - val_i32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, m_ir_builder->getInt32Ty()), val_i32); - auto val_i64 = m_ir_builder->CreateZExt(val_i32, m_ir_builder->getInt64Ty()); - SetGpr(rd, val_i64); -} - -void Compiler::LDX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i64 = ReadMemory(addr_i64, 64); - SetGpr(rd, mem_i64); -} - -void Compiler::LWZX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i32 = ReadMemory(addr_i64, 32); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i32, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); -} - -void Compiler::SLW(u32 ra, u32 rs, u32 rb, u32 rc) { - auto rs_i32 = GetGpr(rs, 32); - auto rs_i64 = m_ir_builder->CreateZExt(rs_i32, m_ir_builder->getInt64Ty()); - auto rb_i8 = GetGpr(rb, 8); - rb_i8 = m_ir_builder->CreateAnd(rb_i8, 0x3F); - auto rb_i64 = m_ir_builder->CreateZExt(rb_i8, m_ir_builder->getInt64Ty()); - auto res_i64 = m_ir_builder->CreateShl(rs_i64, rb_i64); - auto res_i32 = m_ir_builder->CreateTrunc(res_i64, m_ir_builder->getInt32Ty()); - res_i64 = m_ir_builder->CreateZExt(res_i32, m_ir_builder->getInt64Ty()); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::CNTLZW(u32 ra, u32 rs, u32 rc) { - auto rs_i32 = GetGpr(rs, 32); - auto res_i32 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::ctlz, m_ir_builder->getInt32Ty()), rs_i32, m_ir_builder->getInt1(false)); - auto res_i64 = m_ir_builder->CreateZExt(res_i32, m_ir_builder->getInt64Ty()); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::SLD(u32 ra, u32 rs, u32 rb, u32 rc) { - auto rs_i64 = GetGpr(rs); - auto rs_i128 = m_ir_builder->CreateZExt(rs_i64, m_ir_builder->getIntNTy(128)); - auto rb_i8 = GetGpr(rb, 8); - rb_i8 = m_ir_builder->CreateAnd(rb_i8, 0x7F); - auto rb_i128 = m_ir_builder->CreateZExt(rb_i8, m_ir_builder->getIntNTy(128)); - auto res_i128 = m_ir_builder->CreateShl(rs_i128, rb_i128); - auto res_i64 = m_ir_builder->CreateTrunc(res_i128, m_ir_builder->getInt64Ty()); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::AND(u32 ra, u32 rs, u32 rb, u32 rc) { - USE_INTERP_IF_REQUESTED(AND, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(rb), m_ir_builder->getInt32(rc)); - - auto rs_i64 = GetGpr(rs); - auto rb_i64 = GetGpr(rb); - auto res_i64 = m_ir_builder->CreateAnd(rs_i64, rb_i64); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::CMPL(u32 crfd, u32 l, u32 ra, u32 rb) { - USE_INTERP_IF_REQUESTED(CMPL, m_ir_builder->getInt32(crfd), m_ir_builder->getInt32(l), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rb)); - - Value * ra_i64; - Value * rb_i64; - if (l == 0) { - ra_i64 = m_ir_builder->CreateZExt(GetGpr(ra, 32), m_ir_builder->getInt64Ty()); - rb_i64 = m_ir_builder->CreateZExt(GetGpr(rb, 32), m_ir_builder->getInt64Ty()); - } - else { - ra_i64 = GetGpr(ra); - rb_i64 = GetGpr(rb); - } - - SetCrFieldUnsignedCmp(crfd, ra_i64, rb_i64); -} - -void Compiler::LVSR(u32 vd, u32 ra, u32 rb) { - static const u64 s_lvsr_values[0x10][2] = { - { 0x18191A1B1C1D1E1F, 0x1011121314151617 }, - { 0x1718191A1B1C1D1E, 0x0F10111213141516 }, - { 0x161718191A1B1C1D, 0x0E0F101112131415 }, - { 0x15161718191A1B1C, 0x0D0E0F1011121314 }, - { 0x1415161718191A1B, 0x0C0D0E0F10111213 }, - { 0x131415161718191A, 0x0B0C0D0E0F101112 }, - { 0x1213141516171819, 0x0A0B0C0D0E0F1011 }, - { 0x1112131415161718, 0x090A0B0C0D0E0F10 }, - { 0x1011121314151617, 0x08090A0B0C0D0E0F }, - { 0x0F10111213141516, 0x0708090A0B0C0D0E }, - { 0x0E0F101112131415, 0x060708090A0B0C0D }, - { 0x0D0E0F1011121314, 0x05060708090A0B0C }, - { 0x0C0D0E0F10111213, 0x0405060708090A0B }, - { 0x0B0C0D0E0F101112, 0x030405060708090A }, - { 0x0A0B0C0D0E0F1011, 0x0203040506070809 }, - { 0x090A0B0C0D0E0F10, 0x0102030405060708 }, - }; - - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto index_i64 = m_ir_builder->CreateAnd(addr_i64, 0xF); - auto lvsr_values_v16i8_ptr = m_ir_builder->CreateIntToPtr(m_ir_builder->getInt64((u64)s_lvsr_values), VectorType::get(m_ir_builder->getInt8Ty(), 16)->getPointerTo()); - lvsr_values_v16i8_ptr = m_ir_builder->CreateGEP(lvsr_values_v16i8_ptr, index_i64); - auto val_v16i8 = m_ir_builder->CreateAlignedLoad(lvsr_values_v16i8_ptr, 16); - SetVr(vd, val_v16i8); -} - -void Compiler::LVEHX(u32 vd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - addr_i64 = m_ir_builder->CreateAnd(addr_i64, 0xFFFFFFFFFFFFFFFEULL); - auto val_i16 = ReadMemory(addr_i64, 16, 2); - auto index_i64 = m_ir_builder->CreateAnd(addr_i64, 0xf); - index_i64 = m_ir_builder->CreateLShr(index_i64, 1); - index_i64 = m_ir_builder->CreateSub(m_ir_builder->getInt64(7), index_i64); - auto vd_v8i16 = GetVrAsIntVec(vd, 16); - vd_v8i16 = m_ir_builder->CreateInsertElement(vd_v8i16, val_i16, index_i64); - SetVr(vd, vd_v8i16); -} - -void Compiler::SUBF(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { - USE_INTERP_IF_REQUESTED(SUBF, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rb), m_ir_builder->getInt32(oe), m_ir_builder->getInt32(rc)); - - auto ra_i64 = GetGpr(ra); - auto rb_i64 = GetGpr(rb); - auto diff_i64 = m_ir_builder->CreateSub(rb_i64, ra_i64); - SetGpr(rd, diff_i64); - - if (rc) { - SetCrFieldSignedCmp(0, diff_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO: Implement this - CompilationError("SUBFO"); - } -} - -void Compiler::LDUX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto mem_i64 = ReadMemory(addr_i64, 64); - SetGpr(rd, mem_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::DCBST(u32 ra, u32 rb) { - // TODO: Implement this - m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::donothing)); -} - -void Compiler::LWZUX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto mem_i32 = ReadMemory(addr_i64, 32); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i32, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::CNTLZD(u32 ra, u32 rs, u32 rc) { - auto rs_i64 = GetGpr(rs); - auto res_i64 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::ctlz, m_ir_builder->getInt64Ty()), rs_i64, m_ir_builder->getInt1(false)); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::ANDC(u32 ra, u32 rs, u32 rb, u32 rc) { - auto rs_i64 = GetGpr(rs); - auto rb_i64 = GetGpr(rb); - rb_i64 = m_ir_builder->CreateNot(rb_i64); - auto res_i64 = m_ir_builder->CreateAnd(rs_i64, rb_i64); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::TD(u32 to, u32 ra, u32 rb) { - Call("trap"); - m_ir_builder->CreateRet(m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusPropagateException)); -} - -void Compiler::LVEWX(u32 vd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - addr_i64 = m_ir_builder->CreateAnd(addr_i64, 0xFFFFFFFFFFFFFFFCULL); - auto val_i32 = ReadMemory(addr_i64, 32, 4); - auto index_i64 = m_ir_builder->CreateAnd(addr_i64, 0xf); - index_i64 = m_ir_builder->CreateLShr(index_i64, 2); - index_i64 = m_ir_builder->CreateSub(m_ir_builder->getInt64(3), index_i64); - auto vd_v4i32 = GetVrAsIntVec(vd, 32); - vd_v4i32 = m_ir_builder->CreateInsertElement(vd_v4i32, val_i32, index_i64); - SetVr(vd, vd_v4i32); -} - -void Compiler::MULHD(u32 rd, u32 ra, u32 rb, u32 rc) { - auto ra_i64 = GetGpr(ra); - auto rb_i64 = GetGpr(rb); - auto ra_i128 = m_ir_builder->CreateSExt(ra_i64, m_ir_builder->getIntNTy(128)); - auto rb_i128 = m_ir_builder->CreateSExt(rb_i64, m_ir_builder->getIntNTy(128)); - auto prod_i128 = m_ir_builder->CreateMul(ra_i128, rb_i128); - prod_i128 = m_ir_builder->CreateLShr(prod_i128, 64); - auto prod_i64 = m_ir_builder->CreateTrunc(prod_i128, m_ir_builder->getInt64Ty()); - SetGpr(rd, prod_i64); - - if (rc) { - SetCrFieldSignedCmp(0, prod_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::MULHW(u32 rd, u32 ra, u32 rb, u32 rc) { - auto ra_i32 = GetGpr(ra, 32); - auto rb_i32 = GetGpr(rb, 32); - auto ra_i64 = m_ir_builder->CreateSExt(ra_i32, m_ir_builder->getInt64Ty()); - auto rb_i64 = m_ir_builder->CreateSExt(rb_i32, m_ir_builder->getInt64Ty()); - auto prod_i64 = m_ir_builder->CreateMul(ra_i64, rb_i64); - prod_i64 = m_ir_builder->CreateAShr(prod_i64, 32); - SetGpr(rd, prod_i64); - - if (rc) { - SetCrFieldSignedCmp(0, prod_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::LDARX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto addr_i32 = m_ir_builder->CreateTrunc(addr_i64, m_ir_builder->getInt32Ty()); - auto val_i64_ptr = m_ir_builder->CreateAlloca(m_ir_builder->getInt64Ty()); - val_i64_ptr->setAlignment(8); - Call("vm.reservation_acquire", m_ir_builder->CreateBitCast(val_i64_ptr, m_ir_builder->getInt8PtrTy()), addr_i32, m_ir_builder->getInt32(8)); - auto val_i64 = (Value *)m_ir_builder->CreateLoad(val_i64_ptr); - val_i64 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, m_ir_builder->getInt64Ty()), val_i64); - SetGpr(rd, val_i64); -} - -void Compiler::DCBF(u32 ra, u32 rb) { - // TODO: Implement this - m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::donothing)); -} - -void Compiler::LBZX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i8 = ReadMemory(addr_i64, 8); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i8, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); -} - -void Compiler::LVX(u32 vd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - addr_i64 = m_ir_builder->CreateAnd(addr_i64, 0xFFFFFFFFFFFFFFF0ULL); - auto mem_i128 = ReadMemory(addr_i64, 128, 16); - SetVr(vd, mem_i128); -} - -void Compiler::NEG(u32 rd, u32 ra, u32 oe, u32 rc) { - USE_INTERP_IF_REQUESTED(NEG, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(oe), m_ir_builder->getInt32(rc)); - - auto ra_i64 = GetGpr(ra); - auto diff_i64 = m_ir_builder->CreateSub(m_ir_builder->getInt64(0), ra_i64); - SetGpr(rd, diff_i64); - - if (rc) { - SetCrFieldSignedCmp(0, diff_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO: Implement this - CompilationError("NEGO"); - } -} - -void Compiler::LBZUX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto mem_i8 = ReadMemory(addr_i64, 8); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i8, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::NOR(u32 ra, u32 rs, u32 rb, u32 rc) { - auto rs_i64 = GetGpr(rs); - auto rb_i64 = GetGpr(rb); - auto res_i64 = m_ir_builder->CreateOr(rs_i64, rb_i64); - res_i64 = m_ir_builder->CreateXor(res_i64, (s64)-1); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::STVEBX(u32 vs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto index_i64 = m_ir_builder->CreateAnd(addr_i64, 0xf); - index_i64 = m_ir_builder->CreateSub(m_ir_builder->getInt64(15), index_i64); - auto vs_v16i8 = GetVrAsIntVec(vs, 8); - auto val_i8 = m_ir_builder->CreateExtractElement(vs_v16i8, index_i64); - WriteMemory(addr_i64, val_i8); -} - -void Compiler::SUBFE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { - auto ca_i64 = GetXerCa(); - auto ra_i64 = GetGpr(ra); - auto rb_i64 = GetGpr(rb); - ra_i64 = m_ir_builder->CreateNot(ra_i64); - auto res_s = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::uadd_with_overflow, m_ir_builder->getInt64Ty()), ra_i64, ca_i64); - auto res_i64 = m_ir_builder->CreateExtractValue(res_s, { 0 }); - auto carry1_i1 = m_ir_builder->CreateExtractValue(res_s, { 1 }); - res_s = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::uadd_with_overflow, m_ir_builder->getInt64Ty()), res_i64, rb_i64); - res_i64 = m_ir_builder->CreateExtractValue(res_s, { 0 }); - auto carry2_i1 = m_ir_builder->CreateExtractValue(res_s, { 1 }); - auto carry_i1 = m_ir_builder->CreateOr(carry1_i1, carry2_i1); - SetGpr(rd, res_i64); - SetXerCa(carry_i1); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO: Implement this - CompilationError("SUBFEO"); - } -} - -void Compiler::ADDE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { - auto ca_i64 = GetXerCa(); - auto ra_i64 = GetGpr(ra); - auto rb_i64 = GetGpr(rb); - auto res_s = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::uadd_with_overflow, m_ir_builder->getInt64Ty()), ra_i64, ca_i64); - auto res_i64 = m_ir_builder->CreateExtractValue(res_s, { 0 }); - auto carry1_i1 = m_ir_builder->CreateExtractValue(res_s, { 1 }); - res_s = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::uadd_with_overflow, m_ir_builder->getInt64Ty()), res_i64, rb_i64); - res_i64 = m_ir_builder->CreateExtractValue(res_s, { 0 }); - auto carry2_i1 = m_ir_builder->CreateExtractValue(res_s, { 1 }); - auto carry_i1 = m_ir_builder->CreateOr(carry1_i1, carry2_i1); - SetGpr(rd, res_i64); - SetXerCa(carry_i1); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO: Implement this - CompilationError("ADDEO"); - } -} - -void Compiler::MTOCRF(u32 l, u32 crm, u32 rs) { - USE_INTERP_IF_REQUESTED(MTOCRF, m_ir_builder->getInt32(l), m_ir_builder->getInt32(crm), m_ir_builder->getInt32(rs)); - - auto rs_i32 = GetGpr(rs, 32); - auto cr_i32 = GetCr(); - u64 mask = 0; - - for (u32 i = 0; i < 8; i++) { - if (crm & (1 << i)) { - mask |= UINT64_C(0xF) << (i * 4); // move 0xF to the left i positions (in hex form) - if (l) { - break; - } - } - } - - cr_i32 = m_ir_builder->CreateAnd(cr_i32, ~mask); // null ith nibble - rs_i32 = m_ir_builder->CreateAnd(rs_i32, mask); // null everything except ith nibble - cr_i32 = m_ir_builder->CreateOr(cr_i32, rs_i32); // now ith cr nibble == ith rs nibble - SetCr(cr_i32); -} - -void Compiler::STDX(u32 rs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - WriteMemory(addr_i64, GetGpr(rs, 64)); -} - -void Compiler::STWCX_(u32 rs, u32 ra, u32 rb) { - USE_INTERP_IF_REQUESTED(STWCX_, m_ir_builder->getInt32(rs), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rb)); - - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto addr_i32 = m_ir_builder->CreateTrunc(addr_i64, m_ir_builder->getInt32Ty()); - auto rs_i32 = GetGpr(rs, 32); - rs_i32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, m_ir_builder->getInt32Ty()), rs_i32); - auto rs_i32_ptr = m_ir_builder->CreateAlloca(m_ir_builder->getInt32Ty()); - rs_i32_ptr->setAlignment(4); - m_ir_builder->CreateStore(rs_i32, rs_i32_ptr); - auto success_i1 = Call("vm.reservation_update", addr_i32, m_ir_builder->CreateBitCast(rs_i32_ptr, m_ir_builder->getInt8PtrTy()), m_ir_builder->getInt32(4)); - - auto cr_i32 = GetCr(); - cr_i32 = SetBit(cr_i32, 2, success_i1); - SetCr(cr_i32); -} - -void Compiler::STWX(u32 rs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - WriteMemory(addr_i64, GetGpr(rs, 32)); -} - -void Compiler::STVEHX(u32 vs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - addr_i64 = m_ir_builder->CreateAnd(addr_i64, 0xFFFFFFFFFFFFFFFEULL); - auto index_i64 = m_ir_builder->CreateAnd(addr_i64, 0xf); - index_i64 = m_ir_builder->CreateLShr(index_i64, 1); - index_i64 = m_ir_builder->CreateSub(m_ir_builder->getInt64(7), index_i64); - auto vs_v8i16 = GetVrAsIntVec(vs, 16); - auto val_i16 = m_ir_builder->CreateExtractElement(vs_v8i16, index_i64); - WriteMemory(addr_i64, val_i16, 2); -} - -void Compiler::STDUX(u32 rs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - WriteMemory(addr_i64, GetGpr(rs, 64)); - SetGpr(ra, addr_i64); -} - -void Compiler::STWUX(u32 rs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - WriteMemory(addr_i64, GetGpr(rs, 32)); - SetGpr(ra, addr_i64); -} - -void Compiler::STVEWX(u32 vs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - addr_i64 = m_ir_builder->CreateAnd(addr_i64, 0xFFFFFFFFFFFFFFFCULL); - auto index_i64 = m_ir_builder->CreateAnd(addr_i64, 0xf); - index_i64 = m_ir_builder->CreateLShr(index_i64, 2); - index_i64 = m_ir_builder->CreateSub(m_ir_builder->getInt64(3), index_i64); - auto vs_v4i32 = GetVrAsIntVec(vs, 32); - auto val_i32 = m_ir_builder->CreateExtractElement(vs_v4i32, index_i64); - WriteMemory(addr_i64, val_i32, 4); -} - -void Compiler::ADDZE(u32 rd, u32 ra, u32 oe, u32 rc) { - auto ra_i64 = GetGpr(ra); - auto ca_i64 = GetXerCa(); - auto res_s = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::uadd_with_overflow, m_ir_builder->getInt64Ty()), ra_i64, ca_i64); - auto sum_i64 = m_ir_builder->CreateExtractValue(res_s, { 0 }); - auto carry_i1 = m_ir_builder->CreateExtractValue(res_s, { 1 }); - SetGpr(rd, sum_i64); - SetXerCa(carry_i1); - - if (rc) { - SetCrFieldSignedCmp(0, sum_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO: Implement this - CompilationError("ADDZEO"); - } -} - -void Compiler::SUBFZE(u32 rd, u32 ra, u32 oe, u32 rc) { - auto ra_i64 = GetGpr(ra); - ra_i64 = m_ir_builder->CreateNot(ra_i64); - auto ca_i64 = GetXerCa(); - auto res_s = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::uadd_with_overflow, m_ir_builder->getInt64Ty()), ra_i64, ca_i64); - auto res_i64 = m_ir_builder->CreateExtractValue(res_s, { 0 }); - auto carry_i1 = m_ir_builder->CreateExtractValue(res_s, { 1 }); - SetGpr(rd, res_i64); - SetXerCa(carry_i1); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO: Implement this - CompilationError("SUBFZEO"); - } -} - -void Compiler::STDCX_(u32 rs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto addr_i32 = m_ir_builder->CreateTrunc(addr_i64, m_ir_builder->getInt32Ty()); - auto rs_i64 = GetGpr(rs); - rs_i64 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, m_ir_builder->getInt64Ty()), rs_i64); - auto rs_i64_ptr = m_ir_builder->CreateAlloca(m_ir_builder->getInt64Ty()); - rs_i64_ptr->setAlignment(8); - m_ir_builder->CreateStore(rs_i64, rs_i64_ptr); - auto success_i1 = Call("vm.reservation_update", addr_i32, m_ir_builder->CreateBitCast(rs_i64_ptr, m_ir_builder->getInt8PtrTy()), m_ir_builder->getInt32(8)); - - auto cr_i32 = GetCr(); - cr_i32 = SetBit(cr_i32, 2, success_i1); - SetCr(cr_i32); -} - -void Compiler::STBX(u32 rs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - WriteMemory(addr_i64, GetGpr(rs, 8)); -} - -void Compiler::STVX(u32 vs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - addr_i64 = m_ir_builder->CreateAnd(addr_i64, 0xFFFFFFFFFFFFFFF0ULL); - WriteMemory(addr_i64, GetVr(vs), 16); -} - -void Compiler::SUBFME(u32 rd, u32 ra, u32 oe, u32 rc) { - auto ca_i64 = GetXerCa(); - auto ra_i64 = GetGpr(ra); - ra_i64 = m_ir_builder->CreateNot(ra_i64); - auto res_s = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::uadd_with_overflow, m_ir_builder->getInt64Ty()), ra_i64, ca_i64); - auto res_i64 = m_ir_builder->CreateExtractValue(res_s, { 0 }); - auto carry1_i1 = m_ir_builder->CreateExtractValue(res_s, { 1 }); - res_s = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::uadd_with_overflow, m_ir_builder->getInt64Ty()), res_i64, m_ir_builder->getInt64((s64)-1)); - res_i64 = m_ir_builder->CreateExtractValue(res_s, { 0 }); - auto carry2_i1 = m_ir_builder->CreateExtractValue(res_s, { 1 }); - auto carry_i1 = m_ir_builder->CreateOr(carry1_i1, carry2_i1); - SetGpr(rd, res_i64); - SetXerCa(carry_i1); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO: Implement this - CompilationError("SUBFMEO"); - } -} - -void Compiler::MULLD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { - auto ra_i64 = GetGpr(ra); - auto rb_i64 = GetGpr(rb); - auto prod_i64 = m_ir_builder->CreateMul(ra_i64, rb_i64); - SetGpr(rd, prod_i64); - - if (rc) { - SetCrFieldSignedCmp(0, prod_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO implement oe - CompilationError("MULLDO"); - } -} - -void Compiler::ADDME(u32 rd, u32 ra, u32 oe, u32 rc) { - auto ca_i64 = GetXerCa(); - auto ra_i64 = GetGpr(ra); - auto res_s = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::uadd_with_overflow, m_ir_builder->getInt64Ty()), ra_i64, ca_i64); - auto res_i64 = m_ir_builder->CreateExtractValue(res_s, { 0 }); - auto carry1_i1 = m_ir_builder->CreateExtractValue(res_s, { 1 }); - res_s = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::uadd_with_overflow, m_ir_builder->getInt64Ty()), res_i64, m_ir_builder->getInt64((s64)-1)); - res_i64 = m_ir_builder->CreateExtractValue(res_s, { 0 }); - auto carry2_i1 = m_ir_builder->CreateExtractValue(res_s, { 1 }); - auto carry_i1 = m_ir_builder->CreateOr(carry1_i1, carry2_i1); - SetGpr(rd, res_i64); - SetXerCa(carry_i1); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO: Implement this - CompilationError("ADDMEO"); - } -} - -void Compiler::MULLW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { - USE_INTERP_IF_REQUESTED(MULLW, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rb), m_ir_builder->getInt32(oe), m_ir_builder->getInt32(rc)); - - auto ra_i32 = GetGpr(ra, 32); - auto rb_i32 = GetGpr(rb, 32); - auto ra_i64 = m_ir_builder->CreateSExt(ra_i32, m_ir_builder->getInt64Ty()); - auto rb_i64 = m_ir_builder->CreateSExt(rb_i32, m_ir_builder->getInt64Ty()); - auto prod_i64 = m_ir_builder->CreateMul(ra_i64, rb_i64); - SetGpr(rd, prod_i64); - - if (rc) { - SetCrFieldSignedCmp(0, prod_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO implement oe - CompilationError("MULLWO"); - } -} - -void Compiler::DCBTST(u32 ra, u32 rb, u32 th) { - // TODO: Implement this - m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::donothing)); -} - -void Compiler::STBUX(u32 rs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - WriteMemory(addr_i64, GetGpr(rs, 8)); - SetGpr(ra, addr_i64); -} - -void Compiler::ADD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { - USE_INTERP_IF_REQUESTED(ADD, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rb), m_ir_builder->getInt32(oe), m_ir_builder->getInt32(rc)); - - auto ra_i64 = GetGpr(ra); - auto rb_i64 = GetGpr(rb); - auto sum_i64 = m_ir_builder->CreateAdd(ra_i64, rb_i64); - SetGpr(rd, sum_i64); - - if (rc) { - SetCrFieldSignedCmp(0, sum_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO: Implement this - CompilationError("ADDO"); - } -} - -void Compiler::DCBT(u32 ra, u32 rb, u32 th) { - // TODO: Implement this using prefetch - m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::donothing)); -} - -void Compiler::LHZX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i16 = ReadMemory(addr_i64, 16); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i16, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); -} - -void Compiler::EQV(u32 ra, u32 rs, u32 rb, u32 rc) { - auto rs_i64 = GetGpr(rs); - auto rb_i64 = GetGpr(rb); - auto res_i64 = m_ir_builder->CreateXor(rs_i64, rb_i64); - res_i64 = m_ir_builder->CreateNot(res_i64); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::ECIWX(u32 rd, u32 ra, u32 rb) { - CompilationError("ECIWX"); - //auto addr_i64 = GetGpr(rb); - //if (ra) { - // auto ra_i64 = GetGpr(ra); - // addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - //} - - //auto mem_i32 = ReadMemory(addr_i64, 32); - //auto mem_i64 = m_ir_builder->CreateZExt(mem_i32, m_ir_builder->getInt64Ty()); - //SetGpr(rd, mem_i64); -} - -void Compiler::LHZUX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto mem_i16 = ReadMemory(addr_i64, 16); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i16, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::XOR(u32 ra, u32 rs, u32 rb, u32 rc) { - auto rs_i64 = GetGpr(rs); - auto rb_i64 = GetGpr(rb); - auto res_i64 = m_ir_builder->CreateXor(rs_i64, rb_i64); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::MFSPR(u32 rd, u32 spr) { - Value * rd_i64; - auto n = (spr >> 5) | ((spr & 0x1f) << 5); - - switch (n) { - case 0x001: - rd_i64 = GetXer(); - break; - case 0x008: - rd_i64 = GetLr(); - break; - case 0x009: - rd_i64 = GetCtr(); - break; - case 0x100: - rd_i64 = GetVrsave(); - break; - case 0x10C: - rd_i64 = Call("get_timebased_time"); - break; - case 0x10D: - rd_i64 = Call("get_timebased_time"); - rd_i64 = m_ir_builder->CreateLShr(rd_i64, 32); - break; - default: - assert(0); - break; - } - - SetGpr(rd, rd_i64); -} - -void Compiler::LWAX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i32 = ReadMemory(addr_i64, 32); - auto mem_i64 = m_ir_builder->CreateSExt(mem_i32, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); -} - -void Compiler::DST(u32 ra, u32 rb, u32 strm, u32 t) { - // TODO: Revisit - m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::donothing)); -} - -void Compiler::LHAX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i16 = ReadMemory(addr_i64, 16); - auto mem_i64 = m_ir_builder->CreateSExt(mem_i16, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); -} - -void Compiler::LVXL(u32 vd, u32 ra, u32 rb) { - LVX(vd, ra, rb); -} - -void Compiler::MFTB(u32 rd, u32 spr) { - auto tb_i64 = Call("get_timebased_time"); - - u32 n = (spr >> 5) | ((spr & 0x1f) << 5); - if (n == 0x10D) { - tb_i64 = m_ir_builder->CreateLShr(tb_i64, 32); - } - - SetGpr(rd, tb_i64); -} - -void Compiler::LWAUX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto mem_i32 = ReadMemory(addr_i64, 32); - auto mem_i64 = m_ir_builder->CreateSExt(mem_i32, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::DSTST(u32 ra, u32 rb, u32 strm, u32 t) { - // TODO: Revisit - m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::donothing)); -} - -void Compiler::LHAUX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto mem_i16 = ReadMemory(addr_i64, 16); - auto mem_i64 = m_ir_builder->CreateSExt(mem_i16, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::STHX(u32 rs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - WriteMemory(addr_i64, GetGpr(rs, 16)); -} - -void Compiler::ORC(u32 ra, u32 rs, u32 rb, u32 rc) { - auto rs_i64 = GetGpr(rs); - auto rb_i64 = GetGpr(rb); - rb_i64 = m_ir_builder->CreateNot(rb_i64); - auto res_i64 = m_ir_builder->CreateOr(rs_i64, rb_i64); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::ECOWX(u32 rs, u32 ra, u32 rb) { - CompilationError("ECOWX"); - //auto addr_i64 = GetGpr(rb); - //if (ra) { - // auto ra_i64 = GetGpr(ra); - // addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - //} - - //WriteMemory(addr_i64, GetGpr(rs, 32)); -} - -void Compiler::STHUX(u32 rs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - WriteMemory(addr_i64, GetGpr(rs, 16)); - SetGpr(ra, addr_i64); -} - -void Compiler::OR(u32 ra, u32 rs, u32 rb, u32 rc) { - USE_INTERP_IF_REQUESTED(OR, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(rb), m_ir_builder->getInt32(rc)); - - auto rs_i64 = GetGpr(rs); - auto rb_i64 = GetGpr(rb); - auto res_i64 = m_ir_builder->CreateOr(rs_i64, rb_i64); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::DIVDU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { - auto ra_i64 = GetGpr(ra); - auto rb_i64 = GetGpr(rb); - auto res_i64 = m_ir_builder->CreateUDiv(ra_i64, rb_i64); - SetGpr(rd, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO implement oe - CompilationError("DIVDUO"); - } - - // TODO make sure an exception does not occur on divide by 0 and overflow -} - -void Compiler::DIVWU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { - USE_INTERP_IF_REQUESTED(DIVWU, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rb), m_ir_builder->getInt32(oe), m_ir_builder->getInt32(rc)); - - auto ra_i32 = GetGpr(ra, 32); - auto rb_i32 = GetGpr(rb, 32); - auto res_i32 = m_ir_builder->CreateUDiv(ra_i32, rb_i32); - auto res_i64 = m_ir_builder->CreateZExt(res_i32, m_ir_builder->getInt64Ty()); - SetGpr(rd, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO implement oe - CompilationError("DIVWUO"); - } - - // TODO make sure an exception does not occur on divide by 0 and overflow -} - -void Compiler::MTSPR(u32 spr, u32 rs) { - auto rs_i64 = GetGpr(rs); - auto n = (spr >> 5) | ((spr & 0x1f) << 5); - - switch (n) { - case 0x001: - SetXer(rs_i64); - break; - case 0x008: - SetLr(rs_i64); - break; - case 0x009: - SetCtr(rs_i64); - break; - case 0x100: - SetVrsave(rs_i64); - break; - default: - assert(0); - break; - } -} - -void Compiler::NAND(u32 ra, u32 rs, u32 rb, u32 rc) { - auto rs_i64 = GetGpr(rs); - auto rb_i64 = GetGpr(rb); - auto res_i64 = m_ir_builder->CreateAnd(rs_i64, rb_i64); - res_i64 = m_ir_builder->CreateNot(res_i64); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::STVXL(u32 vs, u32 ra, u32 rb) { - STVX(vs, ra, rb); -} - -void Compiler::DIVD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { - auto ra_i64 = GetGpr(ra); - auto rb_i64 = GetGpr(rb); - auto res_i64 = m_ir_builder->CreateSDiv(ra_i64, rb_i64); - SetGpr(rd, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO implement oe - CompilationError("DIVDO"); - } - - // TODO make sure an exception does not occur on divide by 0 and overflow -} - -void Compiler::DIVW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { - USE_INTERP_IF_REQUESTED(DIVW, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rb), m_ir_builder->getInt32(oe), m_ir_builder->getInt32(rc)); - - auto ra_i32 = GetGpr(ra, 32); - auto rb_i32 = GetGpr(rb, 32); - auto res_i32 = m_ir_builder->CreateSDiv(ra_i32, rb_i32); - auto res_i64 = m_ir_builder->CreateZExt(res_i32, m_ir_builder->getInt64Ty()); - SetGpr(rd, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO implement oe - CompilationError("DIVWO"); - } - - // TODO make sure an exception does not occur on divide by 0 and overflow -} - -void Compiler::LVLX(u32 vd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto eb_i64 = m_ir_builder->CreateAnd(addr_i64, 0xF); - eb_i64 = m_ir_builder->CreateShl(eb_i64, 3); - auto eb_i128 = m_ir_builder->CreateZExt(eb_i64, m_ir_builder->getIntNTy(128)); - addr_i64 = m_ir_builder->CreateAnd(addr_i64, 0xFFFFFFFFFFFFFFF0ULL); - auto mem_i128 = ReadMemory(addr_i64, 128, 16); - mem_i128 = m_ir_builder->CreateShl(mem_i128, eb_i128); - SetVr(vd, mem_i128); -} - -void Compiler::LDBRX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i64 = ReadMemory(addr_i64, 64, 0, false); - SetGpr(rd, mem_i64); -} - -void Compiler::LSWX(u32 rd, u32 ra, u32 rb) { - CompilationError("LSWX"); -} - -void Compiler::LWBRX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i32 = ReadMemory(addr_i64, 32, 0, false); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i32, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); -} - -void Compiler::LFSX(u32 frd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i32 = ReadMemory(addr_i64, 32); - SetFpr(frd, mem_i32); -} - -void Compiler::SRW(u32 ra, u32 rs, u32 rb, u32 rc) { - auto rs_i32 = GetGpr(rs, 32); - auto rs_i64 = m_ir_builder->CreateZExt(rs_i32, m_ir_builder->getInt64Ty()); - auto rb_i8 = GetGpr(rb, 8); - rb_i8 = m_ir_builder->CreateAnd(rb_i8, 0x3F); - auto rb_i64 = m_ir_builder->CreateZExt(rb_i8, m_ir_builder->getInt64Ty()); - auto res_i64 = m_ir_builder->CreateLShr(rs_i64, rb_i64); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::SRD(u32 ra, u32 rs, u32 rb, u32 rc) { - auto rs_i64 = GetGpr(rs); - auto rs_i128 = m_ir_builder->CreateZExt(rs_i64, m_ir_builder->getIntNTy(128)); - auto rb_i8 = GetGpr(rb, 8); - rb_i8 = m_ir_builder->CreateAnd(rb_i8, 0x7F); - auto rb_i128 = m_ir_builder->CreateZExt(rb_i8, m_ir_builder->getIntNTy(128)); - auto res_i128 = m_ir_builder->CreateLShr(rs_i128, rb_i128); - auto res_i64 = m_ir_builder->CreateTrunc(res_i128, m_ir_builder->getInt64Ty()); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::LVRX(u32 vd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto eb_i64 = m_ir_builder->CreateSub(m_ir_builder->getInt64(16), addr_i64); - eb_i64 = m_ir_builder->CreateAnd(eb_i64, 0xF); - eb_i64 = m_ir_builder->CreateShl(eb_i64, 3); - auto eb_i128 = m_ir_builder->CreateZExt(eb_i64, m_ir_builder->getIntNTy(128)); - addr_i64 = m_ir_builder->CreateAnd(addr_i64, 0xFFFFFFFFFFFFFFF0ULL); - auto mem_i128 = ReadMemory(addr_i64, 128, 16); - mem_i128 = m_ir_builder->CreateLShr(mem_i128, eb_i128); - auto cmp_i1 = m_ir_builder->CreateICmpNE(eb_i64, m_ir_builder->getInt64(0)); - auto cmp_i128 = m_ir_builder->CreateSExt(cmp_i1, m_ir_builder->getIntNTy(128)); - mem_i128 = m_ir_builder->CreateAnd(mem_i128, cmp_i128); - SetVr(vd, mem_i128); -} - -void Compiler::LSWI(u32 rd, u32 ra, u32 nb) { - auto addr_i64 = ra ? GetGpr(ra) : m_ir_builder->getInt64(0); - - nb = nb ? nb : 32; - for (u32 i = 0; i < nb; i += 4) { - auto val_i32 = ReadMemory(addr_i64, 32, 0, true, false); - - if (i + 4 <= nb) { - addr_i64 = m_ir_builder->CreateAdd(addr_i64, m_ir_builder->getInt64(4)); - } - else { - u32 mask = 0xFFFFFFFF << ((4 - (nb - i)) * 8); - val_i32 = m_ir_builder->CreateAnd(val_i32, mask); - } - - auto val_i64 = m_ir_builder->CreateZExt(val_i32, m_ir_builder->getInt64Ty()); - SetGpr(rd, val_i64); - rd = (rd + 1) % 32; - } -} - -void Compiler::LFSUX(u32 frd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - auto mem_i32 = ReadMemory(addr_i64, 32); - SetFpr(frd, mem_i32); - SetGpr(ra, addr_i64); -} - -void Compiler::SYNC(u32 l) { - m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_mfence)); -} - -void Compiler::LFDX(u32 frd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i64 = ReadMemory(addr_i64, 64); - SetFpr(frd, mem_i64); -} - -void Compiler::LFDUX(u32 frd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - auto mem_i64 = ReadMemory(addr_i64, 64); - SetFpr(frd, mem_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::STVLX(u32 vs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - 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::base(0))); - auto addr_i8_ptr = m_ir_builder->CreateIntToPtr(addr_i64, m_ir_builder->getInt8PtrTy()); - - auto vs_i128 = GetVr(vs); - vs_i128 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, vs_i128->getType()), vs_i128); - auto vs_i128_ptr = m_ir_builder->CreateAlloca(vs_i128->getType()); - vs_i128_ptr->setAlignment(16); - m_ir_builder->CreateAlignedStore(vs_i128, vs_i128_ptr, 16); - auto vs_i8_ptr = m_ir_builder->CreateBitCast(vs_i128_ptr, m_ir_builder->getInt8PtrTy()); - - Type * types[3] = { m_ir_builder->getInt8PtrTy(), m_ir_builder->getInt8PtrTy(), m_ir_builder->getInt64Ty() }; - m_ir_builder->CreateCall5(Intrinsic::getDeclaration(m_module, Intrinsic::memcpy, types), - addr_i8_ptr, vs_i8_ptr, size_i64, m_ir_builder->getInt32(1), m_ir_builder->getInt1(false)); -} - -void Compiler::STDBRX(u32 rs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - WriteMemory(addr_i64, GetGpr(rs), 0, false); -} - -void Compiler::STSWX(u32 rs, u32 ra, u32 rb) { - CompilationError("STSWX"); -} - -void Compiler::STWBRX(u32 rs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - WriteMemory(addr_i64, GetGpr(rs, 32), 0, false); -} - -void Compiler::STFSX(u32 frs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto frs_i32 = m_ir_builder->CreateBitCast(GetFpr(frs, 32), m_ir_builder->getInt32Ty()); - WriteMemory(addr_i64, frs_i32); -} - -void Compiler::STVRX(u32 vs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - 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::base(0))); - auto addr_i8_ptr = m_ir_builder->CreateIntToPtr(addr_i64, m_ir_builder->getInt8PtrTy()); - - auto vs_i128 = GetVr(vs); - vs_i128 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, vs_i128->getType()), vs_i128); - auto vs_i128_ptr = m_ir_builder->CreateAlloca(vs_i128->getType()); - vs_i128_ptr->setAlignment(16); - m_ir_builder->CreateAlignedStore(vs_i128, vs_i128_ptr, 16); - auto vs_i8_ptr = m_ir_builder->CreateBitCast(vs_i128_ptr, m_ir_builder->getInt8PtrTy()); - vs_i8_ptr = m_ir_builder->CreateGEP(vs_i8_ptr, index_i64); - - Type * types[3] = { m_ir_builder->getInt8PtrTy(), m_ir_builder->getInt8PtrTy(), m_ir_builder->getInt64Ty() }; - m_ir_builder->CreateCall5(Intrinsic::getDeclaration(m_module, Intrinsic::memcpy, types), - addr_i8_ptr, vs_i8_ptr, size_i64, m_ir_builder->getInt32(1), m_ir_builder->getInt1(false)); -} - -void Compiler::STFSUX(u32 frs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto frs_i32 = m_ir_builder->CreateBitCast(GetFpr(frs, 32), m_ir_builder->getInt32Ty()); - WriteMemory(addr_i64, frs_i32); - SetGpr(ra, addr_i64); -} - -void Compiler::STSWI(u32 rd, u32 ra, u32 nb) { - auto addr_i64 = ra ? GetGpr(ra) : m_ir_builder->getInt64(0); - - nb = nb ? nb : 32; - for (u32 i = 0; i < nb; i += 4) { - auto val_i32 = GetGpr(rd, 32); - - if (i + 4 <= nb) { - WriteMemory(addr_i64, val_i32, 0, true, false); - addr_i64 = m_ir_builder->CreateAdd(addr_i64, m_ir_builder->getInt64(4)); - rd = (rd + 1) % 32; - } - else { - u32 n = nb - i; - if (n >= 2) { - auto val_i16 = m_ir_builder->CreateLShr(val_i32, 16); - val_i16 = m_ir_builder->CreateTrunc(val_i16, m_ir_builder->getInt16Ty()); - WriteMemory(addr_i64, val_i16); - - if (n == 3) { - auto val_i8 = m_ir_builder->CreateLShr(val_i32, 8); - val_i8 = m_ir_builder->CreateTrunc(val_i8, m_ir_builder->getInt8Ty()); - addr_i64 = m_ir_builder->CreateAdd(addr_i64, m_ir_builder->getInt64(2)); - WriteMemory(addr_i64, val_i8); - } - } - else { - auto val_i8 = m_ir_builder->CreateLShr(val_i32, 24); - val_i8 = m_ir_builder->CreateTrunc(val_i8, m_ir_builder->getInt8Ty()); - WriteMemory(addr_i64, val_i8); - } - } - } -} - -void Compiler::STFDX(u32 frs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto frs_i64 = m_ir_builder->CreateBitCast(GetFpr(frs), m_ir_builder->getInt64Ty()); - WriteMemory(addr_i64, frs_i64); -} - -void Compiler::STFDUX(u32 frs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto frs_i64 = m_ir_builder->CreateBitCast(GetFpr(frs), m_ir_builder->getInt64Ty()); - WriteMemory(addr_i64, frs_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::LVLXL(u32 vd, u32 ra, u32 rb) { - LVLX(vd, ra, rb); -} - -void Compiler::LHBRX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i16 = ReadMemory(addr_i64, 16, 0, false); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i16, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); -} - -void Compiler::SRAW(u32 ra, u32 rs, u32 rb, u32 rc) { - auto rs_i32 = GetGpr(rs, 32); - auto rs_i64 = m_ir_builder->CreateZExt(rs_i32, m_ir_builder->getInt64Ty()); - rs_i64 = m_ir_builder->CreateShl(rs_i64, 32); - auto rb_i8 = GetGpr(rb, 8); - rb_i8 = m_ir_builder->CreateAnd(rb_i8, 0x3F); - auto rb_i64 = m_ir_builder->CreateZExt(rb_i8, m_ir_builder->getInt64Ty()); - auto res_i64 = m_ir_builder->CreateAShr(rs_i64, rb_i64); - auto ra_i64 = m_ir_builder->CreateAShr(res_i64, 32); - SetGpr(ra, ra_i64); - - auto res_i32 = m_ir_builder->CreateTrunc(res_i64, m_ir_builder->getInt32Ty()); - auto ca1_i1 = m_ir_builder->CreateICmpSLT(ra_i64, m_ir_builder->getInt64(0)); - auto ca2_i1 = m_ir_builder->CreateICmpNE(res_i32, m_ir_builder->getInt32(0)); - auto ca_i1 = m_ir_builder->CreateAnd(ca1_i1, ca2_i1); - SetXerCa(ca_i1); - - if (rc) { - SetCrFieldSignedCmp(0, ra_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::SRAD(u32 ra, u32 rs, u32 rb, u32 rc) { - auto rs_i64 = GetGpr(rs); - auto rs_i128 = m_ir_builder->CreateZExt(rs_i64, m_ir_builder->getIntNTy(128)); - rs_i128 = m_ir_builder->CreateShl(rs_i128, 64); - auto rb_i8 = GetGpr(rb, 8); - rb_i8 = m_ir_builder->CreateAnd(rb_i8, 0x7F); - auto rb_i128 = m_ir_builder->CreateZExt(rb_i8, m_ir_builder->getIntNTy(128)); - auto res_i128 = m_ir_builder->CreateAShr(rs_i128, rb_i128); - auto ra_i128 = m_ir_builder->CreateAShr(res_i128, 64); - auto ra_i64 = m_ir_builder->CreateTrunc(ra_i128, m_ir_builder->getInt64Ty()); - SetGpr(ra, ra_i64); - - auto res_i64 = m_ir_builder->CreateTrunc(res_i128, m_ir_builder->getInt64Ty()); - auto ca1_i1 = m_ir_builder->CreateICmpSLT(ra_i64, m_ir_builder->getInt64(0)); - auto ca2_i1 = m_ir_builder->CreateICmpNE(res_i64, m_ir_builder->getInt64(0)); - auto ca_i1 = m_ir_builder->CreateAnd(ca1_i1, ca2_i1); - SetXerCa(ca_i1); - - if (rc) { - SetCrFieldSignedCmp(0, ra_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::LVRXL(u32 vd, u32 ra, u32 rb) { - LVRX(vd, ra, rb); -} - -void Compiler::DSS(u32 strm, u32 a) { - // TODO: Revisit - m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::donothing)); -} - -void Compiler::SRAWI(u32 ra, u32 rs, u32 sh, u32 rc) { - USE_INTERP_IF_REQUESTED(SRAWI, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(sh), m_ir_builder->getInt32(rc)); - - auto rs_i32 = GetGpr(rs, 32); - auto rs_i64 = m_ir_builder->CreateZExt(rs_i32, m_ir_builder->getInt64Ty()); - rs_i64 = m_ir_builder->CreateShl(rs_i64, 32); - auto res_i64 = m_ir_builder->CreateAShr(rs_i64, sh); - auto ra_i64 = m_ir_builder->CreateAShr(res_i64, 32); - SetGpr(ra, ra_i64); - - auto res_i32 = m_ir_builder->CreateTrunc(res_i64, m_ir_builder->getInt32Ty()); - auto ca1_i1 = m_ir_builder->CreateICmpSLT(ra_i64, m_ir_builder->getInt64(0)); - auto ca2_i1 = m_ir_builder->CreateICmpNE(res_i32, m_ir_builder->getInt32(0)); - auto ca_i1 = m_ir_builder->CreateAnd(ca1_i1, ca2_i1); - SetXerCa(ca_i1); - - if (rc) { - SetCrFieldSignedCmp(0, ra_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::SRADI1(u32 ra, u32 rs, u32 sh, u32 rc) { - auto rs_i64 = GetGpr(rs); - auto rs_i128 = m_ir_builder->CreateZExt(rs_i64, m_ir_builder->getIntNTy(128)); - rs_i128 = m_ir_builder->CreateShl(rs_i128, 64); - auto res_i128 = m_ir_builder->CreateAShr(rs_i128, sh); - auto ra_i128 = m_ir_builder->CreateAShr(res_i128, 64); - auto ra_i64 = m_ir_builder->CreateTrunc(ra_i128, m_ir_builder->getInt64Ty()); - SetGpr(ra, ra_i64); - - auto res_i64 = m_ir_builder->CreateTrunc(res_i128, m_ir_builder->getInt64Ty()); - auto ca1_i1 = m_ir_builder->CreateICmpSLT(ra_i64, m_ir_builder->getInt64(0)); - auto ca2_i1 = m_ir_builder->CreateICmpNE(res_i64, m_ir_builder->getInt64(0)); - auto ca_i1 = m_ir_builder->CreateAnd(ca1_i1, ca2_i1); - SetXerCa(ca_i1); - - if (rc) { - SetCrFieldSignedCmp(0, ra_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::SRADI2(u32 ra, u32 rs, u32 sh, u32 rc) { - SRADI1(ra, rs, sh, rc); -} - -void Compiler::EIEIO() { - m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_mfence)); -} - -void Compiler::STVLXL(u32 vs, u32 ra, u32 rb) { - STVLX(vs, ra, rb); -} - -void Compiler::STHBRX(u32 rs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - WriteMemory(addr_i64, GetGpr(rs, 16), 0, false); -} - -void Compiler::EXTSH(u32 ra, u32 rs, u32 rc) { - auto rs_i16 = GetGpr(rs, 16); - auto rs_i64 = m_ir_builder->CreateSExt(rs_i16, m_ir_builder->getInt64Ty()); - SetGpr(ra, rs_i64); - - if (rc) { - SetCrFieldSignedCmp(0, rs_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::STVRXL(u32 vs, u32 ra, u32 rb) { - STVRX(vs, ra, rb); -} - -void Compiler::EXTSB(u32 ra, u32 rs, u32 rc) { - USE_INTERP_IF_REQUESTED(EXTSB, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(rc)); - - auto rs_i8 = GetGpr(rs, 8); - auto rs_i64 = m_ir_builder->CreateSExt(rs_i8, m_ir_builder->getInt64Ty()); - SetGpr(ra, rs_i64); - - if (rc) { - SetCrFieldSignedCmp(0, rs_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::STFIWX(u32 frs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto frs_i64 = m_ir_builder->CreateBitCast(GetFpr(frs), m_ir_builder->getInt64Ty()); - auto frs_i32 = m_ir_builder->CreateTrunc(frs_i64, m_ir_builder->getInt32Ty()); - WriteMemory(addr_i64, frs_i32); -} - -void Compiler::EXTSW(u32 ra, u32 rs, u32 rc) { - USE_INTERP_IF_REQUESTED(EXTSW, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(rc)); - - auto rs_i32 = GetGpr(rs, 32); - auto rs_i64 = m_ir_builder->CreateSExt(rs_i32, m_ir_builder->getInt64Ty()); - SetGpr(ra, rs_i64); - - if (rc) { - SetCrFieldSignedCmp(0, rs_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::ICBI(u32 ra, u32 rs) { - // TODO: Revisit - m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::donothing)); -} - -void Compiler::DCBZ(u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - addr_i64 = m_ir_builder->CreateAnd(addr_i64, ~(127ULL)); - 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 types = { (Type *)m_ir_builder->getInt8PtrTy(), (Type *)m_ir_builder->getInt32Ty() }; - m_ir_builder->CreateCall5(Intrinsic::getDeclaration(m_module, Intrinsic::memset, types), - addr_i8_ptr, m_ir_builder->getInt8(0), m_ir_builder->getInt32(128), m_ir_builder->getInt32(128), m_ir_builder->getInt1(true)); -} - -void Compiler::LWZ(u32 rd, u32 ra, s32 d) { - USE_INTERP_IF_REQUESTED(LWZ, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(d)); - - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i32 = ReadMemory(addr_i64, 32); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i32, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); -} - -void Compiler::LWZU(u32 rd, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto mem_i32 = ReadMemory(addr_i64, 32); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i32, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::LBZ(u32 rd, u32 ra, s32 d) { - USE_INTERP_IF_REQUESTED(LBZ, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(d)); - - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i8 = ReadMemory(addr_i64, 8); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i8, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); -} - -void Compiler::LBZU(u32 rd, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto mem_i8 = ReadMemory(addr_i64, 8); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i8, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::STW(u32 rs, u32 ra, s32 d) { - USE_INTERP_IF_REQUESTED(STW, m_ir_builder->getInt32(rs), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(d)); - - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - WriteMemory(addr_i64, GetGpr(rs, 32)); -} - -void Compiler::STWU(u32 rs, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - WriteMemory(addr_i64, GetGpr(rs, 32)); - SetGpr(ra, addr_i64); -} - -void Compiler::STB(u32 rs, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - WriteMemory(addr_i64, GetGpr(rs, 8)); -} - -void Compiler::STBU(u32 rs, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - WriteMemory(addr_i64, GetGpr(rs, 8)); - SetGpr(ra, addr_i64); -} - -void Compiler::LHZ(u32 rd, u32 ra, s32 d) { - USE_INTERP_IF_REQUESTED(LHZ, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(d)); - - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i16 = ReadMemory(addr_i64, 16); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i16, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); -} - -void Compiler::LHZU(u32 rd, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto mem_i16 = ReadMemory(addr_i64, 16); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i16, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::LHA(u32 rd, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i16 = ReadMemory(addr_i64, 16); - auto mem_i64 = m_ir_builder->CreateSExt(mem_i16, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); -} - -void Compiler::LHAU(u32 rd, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto mem_i16 = ReadMemory(addr_i64, 16); - auto mem_i64 = m_ir_builder->CreateSExt(mem_i16, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::STH(u32 rs, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - WriteMemory(addr_i64, GetGpr(rs, 16)); -} - -void Compiler::STHU(u32 rs, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - WriteMemory(addr_i64, GetGpr(rs, 16)); - SetGpr(ra, addr_i64); -} - -void Compiler::LMW(u32 rd, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - if (ra) { - addr_i64 = m_ir_builder->CreateAdd(addr_i64, GetGpr(ra)); - } - - for (u32 i = rd; i < 32; i++) { - auto val_i32 = ReadMemory(addr_i64, 32); - auto val_i64 = m_ir_builder->CreateZExt(val_i32, m_ir_builder->getInt64Ty()); - SetGpr(i, val_i64); - addr_i64 = m_ir_builder->CreateAdd(addr_i64, m_ir_builder->getInt64(4)); - } -} - -void Compiler::STMW(u32 rs, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - if (ra) { - addr_i64 = m_ir_builder->CreateAdd(addr_i64, GetGpr(ra)); - } - - for (u32 i = rs; i < 32; i++) { - auto val_i32 = GetGpr(i, 32); - WriteMemory(addr_i64, val_i32); - addr_i64 = m_ir_builder->CreateAdd(addr_i64, m_ir_builder->getInt64(4)); - } -} - -void Compiler::LFS(u32 frd, u32 ra, s32 d) { - USE_INTERP_IF_REQUESTED(LFS, m_ir_builder->getInt32(frd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(d)); - - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i32 = ReadMemory(addr_i64, 32); - SetFpr(frd, mem_i32); -} - -void Compiler::LFSU(u32 frd, u32 ra, s32 ds) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)ds); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - auto mem_i32 = ReadMemory(addr_i64, 32); - SetFpr(frd, mem_i32); - SetGpr(ra, addr_i64); -} - -void Compiler::LFD(u32 frd, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i64 = ReadMemory(addr_i64, 64); - SetFpr(frd, mem_i64); -} - -void Compiler::LFDU(u32 frd, u32 ra, s32 ds) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)ds); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto mem_i64 = ReadMemory(addr_i64, 64); - SetFpr(frd, mem_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::STFS(u32 frs, u32 ra, s32 d) { - USE_INTERP_IF_REQUESTED(STFS, m_ir_builder->getInt32(frs), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(d)); - - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto frs_i32 = m_ir_builder->CreateBitCast(GetFpr(frs, 32), m_ir_builder->getInt32Ty()); - WriteMemory(addr_i64, frs_i32); -} - -void Compiler::STFSU(u32 frs, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto frs_i32 = m_ir_builder->CreateBitCast(GetFpr(frs, 32), m_ir_builder->getInt32Ty()); - WriteMemory(addr_i64, frs_i32); - SetGpr(ra, addr_i64); -} - -void Compiler::STFD(u32 frs, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto frs_i64 = m_ir_builder->CreateBitCast(GetFpr(frs), m_ir_builder->getInt64Ty()); - WriteMemory(addr_i64, frs_i64); -} - -void Compiler::STFDU(u32 frs, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto frs_i64 = m_ir_builder->CreateBitCast(GetFpr(frs), m_ir_builder->getInt64Ty()); - WriteMemory(addr_i64, frs_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::LD(u32 rd, u32 ra, s32 ds) { - USE_INTERP_IF_REQUESTED(LD, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(ds)); - - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)ds); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i64 = ReadMemory(addr_i64, 64); - SetGpr(rd, mem_i64); -} - -void Compiler::LDU(u32 rd, u32 ra, s32 ds) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)ds); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto mem_i64 = ReadMemory(addr_i64, 64); - SetGpr(rd, mem_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::LWA(u32 rd, u32 ra, s32 ds) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)ds); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i32 = ReadMemory(addr_i64, 32); - auto mem_i64 = m_ir_builder->CreateSExt(mem_i32, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); -} - -void Compiler::FDIVS(u32 frd, u32 fra, u32 frb, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto res_f64 = m_ir_builder->CreateFDiv(ra_f64, rb_f64); - auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy()); - SetFpr(frd, res_f32); - - if (rc) { - // TODO: Implement this - CompilationError("FDIVS."); - } - - // TODO: Set flags -} - -void Compiler::FSUBS(u32 frd, u32 fra, u32 frb, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto res_f64 = m_ir_builder->CreateFSub(ra_f64, rb_f64); - auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy()); - SetFpr(frd, res_f32); - - if (rc) { - // TODO: Implement this - CompilationError("FSUBS."); - } - - // TODO: Set flags -} - -void Compiler::FADDS(u32 frd, u32 fra, u32 frb, u32 rc) { - - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto res_f64 = m_ir_builder->CreateFAdd(ra_f64, rb_f64); - auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy()); - SetFpr(frd, res_f32); - - if (rc) { - // TODO: Implement this - CompilationError("FADDS."); - } - - // TODO: Set flags -} - -void Compiler::FSQRTS(u32 frd, u32 frb, u32 rc) { - auto rb_f64 = GetFpr(frb); - auto res_f64 = (Value *)m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::sqrt, m_ir_builder->getDoubleTy()), rb_f64); - auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy()); - SetFpr(frd, res_f32); - - if (rc) { - // TODO: Implement this - CompilationError("FSQRTS."); - } - - // TODO: Set flags -} - -void Compiler::FRES(u32 frd, u32 frb, u32 rc) { - auto rb_f64 = GetFpr(frb); - auto res_f64 = m_ir_builder->CreateFDiv(ConstantFP::get(m_ir_builder->getDoubleTy(), 1.0), rb_f64); - auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy()); - SetFpr(frd, res_f32); - - if (rc) { - // TODO: Implement this - CompilationError("FRES."); - } - - // TODO: Set flags -} - -void Compiler::FMULS(u32 frd, u32 fra, u32 frc, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rc_f64 = GetFpr(frc); - auto res_f64 = m_ir_builder->CreateFMul(ra_f64, rc_f64); - auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy()); - SetFpr(frd, res_f32); - - if (rc) { - // TODO: Implement this - CompilationError("FMULS."); - } - - // TODO: Set flags -} - -void Compiler::FMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto rc_f64 = GetFpr(frc); - auto res_f64 = (Value *)m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::fmuladd, m_ir_builder->getDoubleTy()), ra_f64, rc_f64, rb_f64); - auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy()); - SetFpr(frd, res_f32); - - if (rc) { - // TODO: Implement this - CompilationError("FMADDS."); - } - - // TODO: Set flags -} - -void Compiler::FMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto rc_f64 = GetFpr(frc); - rb_f64 = m_ir_builder->CreateFNeg(rb_f64); - auto res_f64 = (Value *)m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::fmuladd, m_ir_builder->getDoubleTy()), ra_f64, rc_f64, rb_f64); - auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy()); - SetFpr(frd, res_f32); - - if (rc) { - // TODO: Implement this - CompilationError("FMSUBS."); - } - - // TODO: Set flags -} - -void Compiler::FNMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto rc_f64 = GetFpr(frc); - rb_f64 = m_ir_builder->CreateFNeg(rb_f64); - auto res_f64 = (Value *)m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::fmuladd, m_ir_builder->getDoubleTy()), ra_f64, rc_f64, rb_f64); - res_f64 = m_ir_builder->CreateFNeg(res_f64); - auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy()); - SetFpr(frd, res_f32); - - if (rc) { - // TODO: Implement this - CompilationError("FNMSUBS."); - } - - // TODO: Set flags -} - -void Compiler::FNMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto rc_f64 = GetFpr(frc); - auto res_f64 = (Value *)m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::fmuladd, m_ir_builder->getDoubleTy()), ra_f64, rc_f64, rb_f64); - res_f64 = m_ir_builder->CreateFNeg(res_f64); - auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy()); - SetFpr(frd, res_f32); - - if (rc) { - // TODO: Implement this - CompilationError("FNMADDS."); - } - - // TODO: Set flags -} - -void Compiler::STD(u32 rs, u32 ra, s32 d) { - USE_INTERP_IF_REQUESTED(STD, m_ir_builder->getInt32(rs), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(d)); - - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - WriteMemory(addr_i64, GetGpr(rs, 64)); -} - -void Compiler::STDU(u32 rs, u32 ra, s32 ds) { - USE_INTERP_IF_REQUESTED(STDU, m_ir_builder->getInt32(rs), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(ds)); - - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)ds); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - WriteMemory(addr_i64, GetGpr(rs, 64)); - SetGpr(ra, addr_i64); -} - -void Compiler::MTFSB1(u32 crbd, u32 rc) { - auto fpscr_i32 = GetFpscr(); - fpscr_i32 = SetBit(fpscr_i32, crbd, m_ir_builder->getInt32(1), false); - SetFpscr(fpscr_i32); - - if (rc) { - // TODO: Implement this - CompilationError("MTFSB1."); - } -} - -void Compiler::MCRFS(u32 crbd, u32 crbs) { - auto fpscr_i32 = GetFpscr(); - auto val_i32 = GetNibble(fpscr_i32, crbs); - SetCrField(crbd, val_i32); - - switch (crbs) { - case 0: - fpscr_i32 = ClrBit(fpscr_i32, 0); - fpscr_i32 = ClrBit(fpscr_i32, 3); - break; - case 1: - fpscr_i32 = ClrNibble(fpscr_i32, 1); - break; - case 2: - fpscr_i32 = ClrNibble(fpscr_i32, 2); - break; - case 3: - fpscr_i32 = ClrBit(fpscr_i32, 12); - break; - case 5: - fpscr_i32 = ClrBit(fpscr_i32, 21); - fpscr_i32 = ClrBit(fpscr_i32, 22); - fpscr_i32 = ClrBit(fpscr_i32, 23); - break; - default: - break; - } - - SetFpscr(fpscr_i32); -} - -void Compiler::MTFSB0(u32 crbd, u32 rc) { - auto fpscr_i32 = GetFpscr(); - fpscr_i32 = ClrBit(fpscr_i32, crbd); - SetFpscr(fpscr_i32); - - if (rc) { - // TODO: Implement this - CompilationError("MTFSB0."); - } -} - -void Compiler::MTFSFI(u32 crfd, u32 i, u32 rc) { - auto fpscr_i32 = GetFpscr(); - fpscr_i32 = SetNibble(fpscr_i32, crfd, m_ir_builder->getInt32(i & 0xF)); - SetFpscr(fpscr_i32); - - if (rc) { - // TODO: Implement this - CompilationError("MTFSFI."); - } -} - -void Compiler::MFFS(u32 frd, u32 rc) { - auto fpscr_i32 = GetFpscr(); - auto fpscr_i64 = m_ir_builder->CreateZExt(fpscr_i32, m_ir_builder->getInt64Ty()); - SetFpr(frd, fpscr_i64); - - if (rc) { - // TODO: Implement this - CompilationError("MFFS."); - } -} - -void Compiler::MTFSF(u32 flm, u32 frb, u32 rc) { - u64 mask = 0; - for (u32 i = 0; i < 8; i++) { - if (flm & (1 << i)) { - mask |= UINT64_C(0xF) << (i * 4); - } - } - - auto rb_i32 = GetFpr(frb, 32, true); - auto fpscr_i32 = GetFpscr(); - fpscr_i32 = m_ir_builder->CreateAnd(fpscr_i32, ~mask); - rb_i32 = m_ir_builder->CreateAnd(rb_i32, mask); - fpscr_i32 = m_ir_builder->CreateOr(fpscr_i32, rb_i32); - SetFpscr(fpscr_i32); - - if (rc) { - // TODO: Implement this - CompilationError("MTFSF."); - } -} - -void Compiler::FCMPU(u32 crfd, u32 fra, u32 frb) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto lt_i1 = m_ir_builder->CreateFCmpOLT(ra_f64, rb_f64); - auto gt_i1 = m_ir_builder->CreateFCmpOGT(ra_f64, rb_f64); - auto eq_i1 = m_ir_builder->CreateFCmpOEQ(ra_f64, rb_f64); - auto cr_i32 = GetCr(); - cr_i32 = SetNibble(cr_i32, crfd, lt_i1, gt_i1, eq_i1, m_ir_builder->getInt1(false)); - SetCr(cr_i32); - - // TODO: Set flags / Handle NaN -} - -void Compiler::FRSP(u32 frd, u32 frb, u32 rc) { - auto rb_f64 = GetFpr(frb); - auto res_f32 = m_ir_builder->CreateFPTrunc(rb_f64, m_ir_builder->getFloatTy()); - auto res_f64 = m_ir_builder->CreateFPExt(res_f32, m_ir_builder->getDoubleTy()); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FRSP."); - } - - // TODO: Revisit this - // TODO: Set flags -} - -void Compiler::FCTIW(u32 frd, u32 frb, u32 rc) { - auto rb_f64 = GetFpr(frb); - auto max_i1 = m_ir_builder->CreateFCmpOGT(rb_f64, ConstantFP::get(m_ir_builder->getDoubleTy(), 2147483647.0)); - auto min_i1 = m_ir_builder->CreateFCmpULT(rb_f64, ConstantFP::get(m_ir_builder->getDoubleTy(), -2147483648.0)); - auto res_i32 = m_ir_builder->CreateFPToSI(rb_f64, m_ir_builder->getInt32Ty()); - auto res_i64 = m_ir_builder->CreateZExt(res_i32, m_ir_builder->getInt64Ty()); - res_i64 = m_ir_builder->CreateSelect(max_i1, m_ir_builder->getInt64(0x7FFFFFFF), res_i64); - res_i64 = m_ir_builder->CreateSelect(min_i1, m_ir_builder->getInt64(0x80000000), res_i64); - SetFpr(frd, res_i64); - - if (rc) { - // TODO: Implement this - CompilationError("FCTIW."); - } - - // TODO: Set flags / Implement rounding modes -} - -void Compiler::FCTIWZ(u32 frd, u32 frb, u32 rc) { - auto rb_f64 = GetFpr(frb); - auto max_i1 = m_ir_builder->CreateFCmpOGT(rb_f64, ConstantFP::get(m_ir_builder->getDoubleTy(), 2147483647.0)); - auto min_i1 = m_ir_builder->CreateFCmpULT(rb_f64, ConstantFP::get(m_ir_builder->getDoubleTy(), -2147483648.0)); - auto res_i32 = m_ir_builder->CreateFPToSI(rb_f64, m_ir_builder->getInt32Ty()); - auto res_i64 = m_ir_builder->CreateZExt(res_i32, m_ir_builder->getInt64Ty()); - res_i64 = m_ir_builder->CreateSelect(max_i1, m_ir_builder->getInt64(0x7FFFFFFF), res_i64); - res_i64 = m_ir_builder->CreateSelect(min_i1, m_ir_builder->getInt64(0x80000000), res_i64); - SetFpr(frd, res_i64); - - if (rc) { - // TODO: Implement this - CompilationError("FCTIWZ."); - } - - // TODO: Set flags -} - -void Compiler::FDIV(u32 frd, u32 fra, u32 frb, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto res_f64 = m_ir_builder->CreateFDiv(ra_f64, rb_f64); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FDIV."); - } - - // TODO: Set flags -} - -void Compiler::FSUB(u32 frd, u32 fra, u32 frb, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto res_f64 = m_ir_builder->CreateFSub(ra_f64, rb_f64); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FSUB."); - } - - // TODO: Set flags -} - -void Compiler::FADD(u32 frd, u32 fra, u32 frb, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto res_f64 = m_ir_builder->CreateFAdd(ra_f64, rb_f64); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FADD."); - } - - // TODO: Set flags -} - -void Compiler::FSQRT(u32 frd, u32 frb, u32 rc) { - auto rb_f64 = GetFpr(frb); - auto res_f64 = (Value *)m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::sqrt, m_ir_builder->getDoubleTy()), rb_f64); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FSQRT."); - } - - // TODO: Set flags -} - -void Compiler::FSEL(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto rc_f64 = GetFpr(frc); - auto cmp_i1 = m_ir_builder->CreateFCmpOGE(ra_f64, ConstantFP::get(m_ir_builder->getDoubleTy(), 0.0)); - auto res_f64 = m_ir_builder->CreateSelect(cmp_i1, rc_f64, rb_f64); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FSEL."); - } - - // TODO: Set flags -} - -void Compiler::FMUL(u32 frd, u32 fra, u32 frc, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rc_f64 = GetFpr(frc); - auto res_f64 = m_ir_builder->CreateFMul(ra_f64, rc_f64); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FMUL."); - } - - // TODO: Set flags -} - -void Compiler::FRSQRTE(u32 frd, u32 frb, u32 rc) { - auto rb_f64 = GetFpr(frb); - auto res_f64 = (Value *)m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::sqrt, m_ir_builder->getDoubleTy()), rb_f64); - res_f64 = m_ir_builder->CreateFDiv(ConstantFP::get(m_ir_builder->getDoubleTy(), 1.0), res_f64); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FRSQRTE."); - } -} - -void Compiler::FMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto rc_f64 = GetFpr(frc); - rb_f64 = m_ir_builder->CreateFNeg(rb_f64); - auto res_f64 = m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::fmuladd, m_ir_builder->getDoubleTy()), ra_f64, rc_f64, rb_f64); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FMSUB."); - } - - // TODO: Set flags -} - -void Compiler::FMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto rc_f64 = GetFpr(frc); - auto res_f64 = m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::fmuladd, m_ir_builder->getDoubleTy()), ra_f64, rc_f64, rb_f64); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FMADD."); - } - - // TODO: Set flags -} - -void Compiler::FNMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto rc_f64 = GetFpr(frc); - rc_f64 = m_ir_builder->CreateFNeg(rc_f64); - auto res_f64 = (Value *)m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::fmuladd, m_ir_builder->getDoubleTy()), ra_f64, rc_f64, rb_f64); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FNMSUB."); - } - - // TODO: Set flags -} - -void Compiler::FNMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto rc_f64 = GetFpr(frc); - rb_f64 = m_ir_builder->CreateFNeg(rb_f64); - rc_f64 = m_ir_builder->CreateFNeg(rc_f64); - auto res_f64 = (Value *)m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::fmuladd, m_ir_builder->getDoubleTy()), ra_f64, rc_f64, rb_f64); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FNMADD."); - } - - // TODO: Set flags -} - -void Compiler::FCMPO(u32 crfd, u32 fra, u32 frb) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto lt_i1 = m_ir_builder->CreateFCmpOLT(ra_f64, rb_f64); - auto gt_i1 = m_ir_builder->CreateFCmpOGT(ra_f64, rb_f64); - auto eq_i1 = m_ir_builder->CreateFCmpOEQ(ra_f64, rb_f64); - auto cr_i32 = GetCr(); - cr_i32 = SetNibble(cr_i32, crfd, lt_i1, gt_i1, eq_i1, m_ir_builder->getInt1(false)); - SetCr(cr_i32); - - // TODO: Set flags / Handle NaN -} - -void Compiler::FNEG(u32 frd, u32 frb, u32 rc) { - auto rb_f64 = GetFpr(frb); - rb_f64 = m_ir_builder->CreateFNeg(rb_f64); - SetFpr(frd, rb_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FNEG."); - } - - // TODO: Set flags -} - -void Compiler::FMR(u32 frd, u32 frb, u32 rc) { - SetFpr(frd, GetFpr(frb)); - - if (rc) { - // TODO: Implement this - CompilationError("FMR."); - } - - // TODO: Set flags -} - -void Compiler::FNABS(u32 frd, u32 frb, u32 rc) { - auto rb_f64 = GetFpr(frb); - auto res_f64 = (Value *)m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::fabs, m_ir_builder->getDoubleTy()), rb_f64); - res_f64 = m_ir_builder->CreateFNeg(res_f64); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FNABS."); - } - - // TODO: Set flags -} - -void Compiler::FABS(u32 frd, u32 frb, u32 rc) { - auto rb_f64 = GetFpr(frb); - auto res_f64 = (Value *)m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::fabs, m_ir_builder->getDoubleTy()), rb_f64); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FABS."); - } - - // TODO: Set flags -} - -void Compiler::FCTID(u32 frd, u32 frb, u32 rc) { - auto rb_f64 = GetFpr(frb); - auto max_i1 = m_ir_builder->CreateFCmpOGT(rb_f64, ConstantFP::get(m_ir_builder->getDoubleTy(), 9223372036854775807.0)); - auto min_i1 = m_ir_builder->CreateFCmpULT(rb_f64, ConstantFP::get(m_ir_builder->getDoubleTy(), -9223372036854775808.0)); - auto res_i64 = m_ir_builder->CreateFPToSI(rb_f64, m_ir_builder->getInt64Ty()); - res_i64 = m_ir_builder->CreateSelect(max_i1, m_ir_builder->getInt64(0x7FFFFFFFFFFFFFFF), res_i64); - res_i64 = m_ir_builder->CreateSelect(min_i1, m_ir_builder->getInt64(0x8000000000000000), res_i64); - SetFpr(frd, res_i64); - - if (rc) { - // TODO: Implement this - CompilationError("FCTID."); - } - - // TODO: Set flags / Implement rounding modes -} - -void Compiler::FCTIDZ(u32 frd, u32 frb, u32 rc) { - auto rb_f64 = GetFpr(frb); - auto max_i1 = m_ir_builder->CreateFCmpOGT(rb_f64, ConstantFP::get(m_ir_builder->getDoubleTy(), 9223372036854775807.0)); - auto min_i1 = m_ir_builder->CreateFCmpULT(rb_f64, ConstantFP::get(m_ir_builder->getDoubleTy(), -9223372036854775808.0)); - auto res_i64 = m_ir_builder->CreateFPToSI(rb_f64, m_ir_builder->getInt64Ty()); - res_i64 = m_ir_builder->CreateSelect(max_i1, m_ir_builder->getInt64(0x7FFFFFFFFFFFFFFF), res_i64); - res_i64 = m_ir_builder->CreateSelect(min_i1, m_ir_builder->getInt64(0x8000000000000000), res_i64); - SetFpr(frd, res_i64); - - if (rc) { - // TODO: Implement this - CompilationError("FCTIDZ."); - } - - // TODO: Set flags -} - -void Compiler::FCFID(u32 frd, u32 frb, u32 rc) { - auto rb_i64 = GetFpr(frb, 64, true); - auto res_f64 = m_ir_builder->CreateSIToFP(rb_i64, m_ir_builder->getDoubleTy()); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FCFID."); - } - - // TODO: Set flags -} - -void Compiler::UNK(const u32 code, const u32 opcode, const u32 gcode) { - CompilationError(fmt::format("Unknown/Illegal opcode! (0x%08x : 0x%x : 0x%x)", code, opcode, gcode)); -} - -std::string Compiler::GetBasicBlockNameFromAddress(u32 address, const std::string & suffix) const { - std::string name; - - if (address == 0) { - name = "entry"; - } - else if (address == 0xFFFFFFFF) { - name = "default_exit"; - } - else { - name = fmt::format("instr_0x%08X", address); - } - - if (suffix != "") { - name += "_" + suffix; - } - - return name; -} - -u32 Compiler::GetAddressFromBasicBlockName(const std::string & name) const { - if (name.compare(0, 6, "instr_") == 0) { - return strtoul(name.c_str() + 6, nullptr, 0); - } - else if (name == GetBasicBlockNameFromAddress(0)) { - return 0; - } - else if (name == GetBasicBlockNameFromAddress(0xFFFFFFFF)) { - return 0xFFFFFFFF; - } - - return 0; -} - -BasicBlock * Compiler::GetBasicBlockFromAddress(u32 address, const std::string & suffix, bool create_if_not_exist) { - auto block_name = GetBasicBlockNameFromAddress(address, suffix); - BasicBlock * block = nullptr; - BasicBlock * next_block = nullptr; - for (auto i = m_state.function->begin(); i != m_state.function->end(); i++) { - if (i->getName() == block_name) { - block = &(*i); - break; - } - - auto block_address = GetAddressFromBasicBlockName(i->getName()); - if (block_address > address) { - next_block = &(*i); - break; - } - } - - if (!block && create_if_not_exist) { - block = BasicBlock::Create(m_ir_builder->getContext(), block_name, m_state.function, next_block); - } - - return block; -} - -Value * Compiler::GetBit(Value * val, u32 n) { - Value * bit = val; - -#ifdef PPU_LLVM_RECOMPILER_USE_BMI - if (val->getType()->isIntegerTy(32)) { - bit = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_bmi_pext_32), val, m_ir_builder->getInt32(1 << (31 - n))); - } - else if (val->getType()->isIntegerTy(64)) { - bit = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_bmi_pext_64), val, m_ir_builder->getInt64((u64)1 << (63 - n))); - } - else { -#endif - if (val->getType()->getIntegerBitWidth() != (n + 1)) { - bit = m_ir_builder->CreateLShr(val, val->getType()->getIntegerBitWidth() - n - 1); - } - - bit = m_ir_builder->CreateAnd(bit, 1); -#ifdef PPU_LLVM_RECOMPILER_USE_BMI - } -#endif - - return bit; -} - -Value * Compiler::ClrBit(Value * val, u32 n) { - return m_ir_builder->CreateAnd(val, ~((u64)1 << (val->getType()->getIntegerBitWidth() - n - 1))); -} - -Value * Compiler::SetBit(Value * val, u32 n, Value * bit, bool doClear) { - if (doClear) { - val = ClrBit(val, n); - } - - if (bit->getType()->getIntegerBitWidth() < val->getType()->getIntegerBitWidth()) { - bit = m_ir_builder->CreateZExt(bit, val->getType()); - } - else if (bit->getType()->getIntegerBitWidth() > val->getType()->getIntegerBitWidth()) { - bit = m_ir_builder->CreateTrunc(bit, val->getType()); - } - - if (val->getType()->getIntegerBitWidth() != (n + 1)) { - bit = m_ir_builder->CreateShl(bit, bit->getType()->getIntegerBitWidth() - n - 1); - } - - return m_ir_builder->CreateOr(val, bit); -} - -Value * Compiler::GetNibble(Value * val, u32 n) { - Value * nibble; - -#ifdef PPU_LLVM_RECOMPILER_USE_BMI - if (val->getType()->isIntegerTy(32)) { - nibble = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_bmi_pext_32), val, m_ir_builder->getInt32((u64)0xF << ((7 - n) * 4))); - } - else if (val->getType()->isIntegerTy(64)) { - nibble = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_bmi_pext_64), val, m_ir_builder->getInt64((u64)0xF << ((15 - n) * 4))); - } - else { -#endif - if ((val->getType()->getIntegerBitWidth() >> 2) != (n + 1)) { - val = m_ir_builder->CreateLShr(val, (((val->getType()->getIntegerBitWidth() >> 2) - 1) - n) * 4); - } - - nibble = m_ir_builder->CreateAnd(val, 0xF); -#ifdef PPU_LLVM_RECOMPILER_USE_BMI - } -#endif - - return nibble; -} - -Value * Compiler::ClrNibble(Value * val, u32 n) { - return m_ir_builder->CreateAnd(val, ~((u64)0xF << ((((val->getType()->getIntegerBitWidth() >> 2) - 1) - n) * 4))); -} - -Value * Compiler::SetNibble(Value * val, u32 n, Value * nibble, bool doClear) { - if (doClear) { - val = ClrNibble(val, n); - } - - if (nibble->getType()->getIntegerBitWidth() < val->getType()->getIntegerBitWidth()) { - nibble = m_ir_builder->CreateZExt(nibble, val->getType()); - } - else if (nibble->getType()->getIntegerBitWidth() > val->getType()->getIntegerBitWidth()) { - nibble = m_ir_builder->CreateTrunc(nibble, val->getType()); - } - - if ((val->getType()->getIntegerBitWidth() >> 2) != (n + 1)) { - nibble = m_ir_builder->CreateShl(nibble, (((val->getType()->getIntegerBitWidth() >> 2) - 1) - n) * 4); - } - - return m_ir_builder->CreateOr(val, nibble); -} - -Value * Compiler::SetNibble(Value * val, u32 n, Value * b0, Value * b1, Value * b2, Value * b3, bool doClear) { - if (doClear) { - val = ClrNibble(val, n); - } - - if (b0) { - val = SetBit(val, n * 4, b0, false); - } - - if (b1) { - val = SetBit(val, (n * 4) + 1, b1, false); - } - - if (b2) { - val = SetBit(val, (n * 4) + 2, b2, false); - } - - if (b3) { - val = SetBit(val, (n * 4) + 3, b3, false); - } - - return val; -} - -Value * Compiler::GetPc() { - auto pc_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, PC)); - auto pc_i32_ptr = m_ir_builder->CreateBitCast(pc_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo()); - return m_ir_builder->CreateAlignedLoad(pc_i32_ptr, 4); -} - -void Compiler::SetPc(Value * val_ix) { - auto pc_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, PC)); - auto pc_i32_ptr = m_ir_builder->CreateBitCast(pc_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo()); - auto val_i32 = m_ir_builder->CreateZExtOrTrunc(val_ix, m_ir_builder->getInt32Ty()); - m_ir_builder->CreateAlignedStore(val_i32, pc_i32_ptr, 4); -} - -Value * Compiler::GetGpr(u32 r, u32 num_bits) { - auto r_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, GPR[r])); - auto r_ix_ptr = m_ir_builder->CreateBitCast(r_i8_ptr, m_ir_builder->getIntNTy(num_bits)->getPointerTo()); - return m_ir_builder->CreateAlignedLoad(r_ix_ptr, 8); -} - -void Compiler::SetGpr(u32 r, Value * val_x64) { - auto r_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, GPR[r])); - auto r_i64_ptr = m_ir_builder->CreateBitCast(r_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); - auto val_i64 = m_ir_builder->CreateBitCast(val_x64, m_ir_builder->getInt64Ty()); - m_ir_builder->CreateAlignedStore(val_i64, r_i64_ptr, 8); -} - -Value * Compiler::GetCr() { - auto cr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, CR)); - auto cr_i32_ptr = m_ir_builder->CreateBitCast(cr_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo()); - return m_ir_builder->CreateAlignedLoad(cr_i32_ptr, 4); -} - -Value * Compiler::GetCrField(u32 n) { - return GetNibble(GetCr(), n); -} - -void Compiler::SetCr(Value * val_x32) { - auto val_i32 = m_ir_builder->CreateBitCast(val_x32, m_ir_builder->getInt32Ty()); - auto cr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, CR)); - auto cr_i32_ptr = m_ir_builder->CreateBitCast(cr_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo()); - m_ir_builder->CreateAlignedStore(val_i32, cr_i32_ptr, 4); -} - -void Compiler::SetCrField(u32 n, Value * field) { - SetCr(SetNibble(GetCr(), n, field)); -} - -void Compiler::SetCrField(u32 n, Value * b0, Value * b1, Value * b2, Value * b3) { - SetCr(SetNibble(GetCr(), n, b0, b1, b2, b3)); -} - -void Compiler::SetCrFieldSignedCmp(u32 n, Value * a, Value * b) { - auto lt_i1 = m_ir_builder->CreateICmpSLT(a, b); - auto gt_i1 = m_ir_builder->CreateICmpSGT(a, b); - auto eq_i1 = m_ir_builder->CreateICmpEQ(a, b); - auto cr_i32 = GetCr(); - cr_i32 = SetNibble(cr_i32, n, lt_i1, gt_i1, eq_i1, GetXerSo()); - SetCr(cr_i32); -} - -void Compiler::SetCrFieldUnsignedCmp(u32 n, Value * a, Value * b) { - auto lt_i1 = m_ir_builder->CreateICmpULT(a, b); - auto gt_i1 = m_ir_builder->CreateICmpUGT(a, b); - auto eq_i1 = m_ir_builder->CreateICmpEQ(a, b); - auto cr_i32 = GetCr(); - cr_i32 = SetNibble(cr_i32, n, lt_i1, gt_i1, eq_i1, GetXerSo()); - SetCr(cr_i32); -} - -void Compiler::SetCr6AfterVectorCompare(u32 vr) { - auto vr_v16i8 = GetVrAsIntVec(vr, 8); - auto vr_mask_i32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_pmovmskb_128), vr_v16i8); - auto cmp0_i1 = m_ir_builder->CreateICmpEQ(vr_mask_i32, m_ir_builder->getInt32(0)); - auto cmp1_i1 = m_ir_builder->CreateICmpEQ(vr_mask_i32, m_ir_builder->getInt32(0xFFFF)); - auto cr_i32 = GetCr(); - cr_i32 = SetNibble(cr_i32, 6, cmp1_i1, nullptr, cmp0_i1, nullptr); - SetCr(cr_i32); -} - -Value * Compiler::GetLr() { - auto lr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, LR)); - auto lr_i64_ptr = m_ir_builder->CreateBitCast(lr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); - return m_ir_builder->CreateAlignedLoad(lr_i64_ptr, 8); -} - -void Compiler::SetLr(Value * val_x64) { - auto val_i64 = m_ir_builder->CreateBitCast(val_x64, m_ir_builder->getInt64Ty()); - auto lr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, LR)); - auto lr_i64_ptr = m_ir_builder->CreateBitCast(lr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); - m_ir_builder->CreateAlignedStore(val_i64, lr_i64_ptr, 8); -} - -Value * Compiler::GetCtr() { - auto ctr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, CTR)); - auto ctr_i64_ptr = m_ir_builder->CreateBitCast(ctr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); - return m_ir_builder->CreateAlignedLoad(ctr_i64_ptr, 8); -} - -void Compiler::SetCtr(Value * val_x64) { - auto val_i64 = m_ir_builder->CreateBitCast(val_x64, m_ir_builder->getInt64Ty()); - auto ctr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, CTR)); - auto ctr_i64_ptr = m_ir_builder->CreateBitCast(ctr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); - m_ir_builder->CreateAlignedStore(val_i64, ctr_i64_ptr, 8); -} - -Value * Compiler::GetXer() { - auto xer_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, XER)); - auto xer_i64_ptr = m_ir_builder->CreateBitCast(xer_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); - return m_ir_builder->CreateAlignedLoad(xer_i64_ptr, 8); -} - -Value * Compiler::GetXerCa() { - return GetBit(GetXer(), 34); -} - -Value * Compiler::GetXerSo() { - return GetBit(GetXer(), 32); -} - -void Compiler::SetXer(Value * val_x64) { - auto val_i64 = m_ir_builder->CreateBitCast(val_x64, m_ir_builder->getInt64Ty()); - auto xer_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, XER)); - auto xer_i64_ptr = m_ir_builder->CreateBitCast(xer_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); - m_ir_builder->CreateAlignedStore(val_i64, xer_i64_ptr, 8); -} - -void Compiler::SetXerCa(Value * ca) { - auto xer_i64 = GetXer(); - xer_i64 = SetBit(xer_i64, 34, ca); - SetXer(xer_i64); -} - -void Compiler::SetXerSo(Value * so) { - auto xer_i64 = GetXer(); - xer_i64 = SetBit(xer_i64, 32, so); - SetXer(xer_i64); -} - -Value * Compiler::GetVrsave() { - auto vrsave_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, VRSAVE)); - auto vrsave_i32_ptr = m_ir_builder->CreateBitCast(vrsave_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo()); - auto val_i32 = m_ir_builder->CreateAlignedLoad(vrsave_i32_ptr, 4); - return m_ir_builder->CreateZExtOrTrunc(val_i32, m_ir_builder->getInt64Ty()); -} - -void Compiler::SetVrsave(Value * val_x64) { - auto val_i64 = m_ir_builder->CreateBitCast(val_x64, m_ir_builder->getInt64Ty()); - auto val_i32 = m_ir_builder->CreateZExtOrTrunc(val_i64, m_ir_builder->getInt32Ty()); - auto vrsave_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, VRSAVE)); - auto vrsave_i32_ptr = m_ir_builder->CreateBitCast(vrsave_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo()); - m_ir_builder->CreateAlignedStore(val_i32, vrsave_i32_ptr, 8); -} - -Value * Compiler::GetFpscr() { - auto fpscr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, FPSCR)); - auto fpscr_i32_ptr = m_ir_builder->CreateBitCast(fpscr_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo()); - return m_ir_builder->CreateAlignedLoad(fpscr_i32_ptr, 4); -} - -void Compiler::SetFpscr(Value * val_x32) { - auto val_i32 = m_ir_builder->CreateBitCast(val_x32, m_ir_builder->getInt32Ty()); - auto fpscr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, FPSCR)); - auto fpscr_i32_ptr = m_ir_builder->CreateBitCast(fpscr_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo()); - m_ir_builder->CreateAlignedStore(val_i32, fpscr_i32_ptr, 4); -} - -Value * Compiler::GetFpr(u32 r, u32 bits, bool as_int) { - auto r_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, FPR[r])); - if (!as_int) { - auto r_f64_ptr = m_ir_builder->CreateBitCast(r_i8_ptr, m_ir_builder->getDoubleTy()->getPointerTo()); - auto r_f64 = m_ir_builder->CreateAlignedLoad(r_f64_ptr, 8); - if (bits == 32) { - return m_ir_builder->CreateFPTrunc(r_f64, m_ir_builder->getFloatTy()); - } - else { - return r_f64; - } - } - else { - auto r_i64_ptr = m_ir_builder->CreateBitCast(r_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); - auto r_i64 = m_ir_builder->CreateAlignedLoad(r_i64_ptr, 8); - if (bits == 32) { - return m_ir_builder->CreateTrunc(r_i64, m_ir_builder->getInt32Ty()); - } - else { - return r_i64; - } - } -} - -void Compiler::SetFpr(u32 r, Value * val) { - auto r_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, FPR[r])); - auto r_f64_ptr = m_ir_builder->CreateBitCast(r_i8_ptr, m_ir_builder->getDoubleTy()->getPointerTo()); - - Value* val_f64; - if (val->getType()->isDoubleTy() || val->getType()->isIntegerTy(64)) { - val_f64 = m_ir_builder->CreateBitCast(val, m_ir_builder->getDoubleTy()); - } - else if (val->getType()->isFloatTy() || val->getType()->isIntegerTy(32)) { - auto val_f32 = m_ir_builder->CreateBitCast(val, m_ir_builder->getFloatTy()); - val_f64 = m_ir_builder->CreateFPExt(val_f32, m_ir_builder->getDoubleTy()); - } - else { - assert(0); - } - - m_ir_builder->CreateAlignedStore(val_f64, r_f64_ptr, 8); -} - -Value * Compiler::GetVscr() { - auto vscr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, VSCR)); - auto vscr_i32_ptr = m_ir_builder->CreateBitCast(vscr_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo()); - return m_ir_builder->CreateAlignedLoad(vscr_i32_ptr, 4); -} - -void Compiler::SetVscr(Value * val_x32) { - auto val_i32 = m_ir_builder->CreateBitCast(val_x32, m_ir_builder->getInt32Ty()); - auto vscr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, VSCR)); - auto vscr_i32_ptr = m_ir_builder->CreateBitCast(vscr_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo()); - m_ir_builder->CreateAlignedStore(val_i32, vscr_i32_ptr, 4); -} - -Value * Compiler::GetVr(u32 vr) { - auto vr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, VPR[vr])); - auto vr_i128_ptr = m_ir_builder->CreateBitCast(vr_i8_ptr, m_ir_builder->getIntNTy(128)->getPointerTo()); - return m_ir_builder->CreateAlignedLoad(vr_i128_ptr, 16); -} - -Value * Compiler::GetVrAsIntVec(u32 vr, u32 vec_elt_num_bits) { - auto vr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, VPR[vr])); - auto vr_i128_ptr = m_ir_builder->CreateBitCast(vr_i8_ptr, m_ir_builder->getIntNTy(128)->getPointerTo()); - auto vr_vec_ptr = m_ir_builder->CreateBitCast(vr_i128_ptr, VectorType::get(m_ir_builder->getIntNTy(vec_elt_num_bits), 128 / vec_elt_num_bits)->getPointerTo()); - return m_ir_builder->CreateAlignedLoad(vr_vec_ptr, 16); -} - -Value * Compiler::GetVrAsFloatVec(u32 vr) { - auto vr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, VPR[vr])); - auto vr_i128_ptr = m_ir_builder->CreateBitCast(vr_i8_ptr, m_ir_builder->getIntNTy(128)->getPointerTo()); - auto vr_v4f32_ptr = m_ir_builder->CreateBitCast(vr_i128_ptr, VectorType::get(m_ir_builder->getFloatTy(), 4)->getPointerTo()); - return m_ir_builder->CreateAlignedLoad(vr_v4f32_ptr, 16); -} - -Value * Compiler::GetVrAsDoubleVec(u32 vr) { - auto vr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, VPR[vr])); - auto vr_i128_ptr = m_ir_builder->CreateBitCast(vr_i8_ptr, m_ir_builder->getIntNTy(128)->getPointerTo()); - auto vr_v2f64_ptr = m_ir_builder->CreateBitCast(vr_i128_ptr, VectorType::get(m_ir_builder->getDoubleTy(), 2)->getPointerTo()); - return m_ir_builder->CreateAlignedLoad(vr_v2f64_ptr, 16); -} - -void Compiler::SetVr(u32 vr, Value * val_x128) { - auto vr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, VPR[vr])); - auto vr_i128_ptr = m_ir_builder->CreateBitCast(vr_i8_ptr, m_ir_builder->getIntNTy(128)->getPointerTo()); - auto val_i128 = m_ir_builder->CreateBitCast(val_x128, m_ir_builder->getIntNTy(128)); - m_ir_builder->CreateAlignedStore(val_i128, vr_i128_ptr, 16); -} - -Value * Compiler::CheckBranchCondition(u32 bo, u32 bi) { - bool bo0 = bo & 0x10 ? true : false; - bool bo1 = bo & 0x08 ? true : false; - bool bo2 = bo & 0x04 ? true : false; - bool bo3 = bo & 0x02 ? true : false; - - auto ctr_i64 = GetCtr(); - if (!bo2) { - ctr_i64 = m_ir_builder->CreateSub(ctr_i64, m_ir_builder->getInt64(1)); - SetCtr(ctr_i64); - } - - Value * ctr_ok_i1 = nullptr; - if (!bo2) { - // TODO: Check if we should compare all bits or just the lower 32 bits. This depends on MSR[SF]. Not sure what it is for PS3. - ctr_ok_i1 = m_ir_builder->CreateICmpNE(ctr_i64, m_ir_builder->getInt64(0)); - if (bo3) { - ctr_ok_i1 = m_ir_builder->CreateXor(ctr_ok_i1, m_ir_builder->getInt1(bo3)); - } - } - - Value * cond_ok_i1 = nullptr; - if (!bo0) { - auto cr_bi_i32 = GetBit(GetCr(), bi); - cond_ok_i1 = m_ir_builder->CreateTrunc(cr_bi_i32, m_ir_builder->getInt1Ty()); - if (!bo1) { - cond_ok_i1 = m_ir_builder->CreateXor(cond_ok_i1, m_ir_builder->getInt1(!bo1)); - } - } - - Value * cmp_i1 = nullptr; - if (ctr_ok_i1 && cond_ok_i1) { - cmp_i1 = m_ir_builder->CreateAnd(ctr_ok_i1, cond_ok_i1); - } - else if (ctr_ok_i1) { - cmp_i1 = ctr_ok_i1; - } - else if (cond_ok_i1) { - cmp_i1 = cond_ok_i1; - } - - return cmp_i1; -} - -void Compiler::CreateBranch(llvm::Value * cmp_i1, llvm::Value * target_i32, bool lk, bool target_is_lr) { - if (lk) - SetLr(m_ir_builder->getInt64(m_state.current_instruction_address + 4)); - - BasicBlock *current_block = m_ir_builder->GetInsertBlock(); - - BasicBlock * target_block = nullptr; - if (dyn_cast(target_i32)) { - // Target address is an immediate value. - u32 target_address = (u32)(dyn_cast(target_i32)->getLimitedValue()); - if (lk) { - // Function call - if (cmp_i1) { // There is no need to create a new block for an unconditional jump - target_block = GetBasicBlockFromAddress(m_state.current_instruction_address, "target"); - m_ir_builder->SetInsertPoint(target_block); - } - - SetPc(target_i32); -// Function *fn = m_module->getFunction(fmt::format("function_0x%08X", target_address)); - llvm::Value *execStatus; -// if (fn) -// execStatus = m_ir_builder->CreateCall2(fn, m_state.args[CompileTaskState::Args::State], m_ir_builder->getInt64(0)); -// else - execStatus = Call("execute_unknown_function", m_state.args[CompileTaskState::Args::State], m_ir_builder->getInt64(0)); - - llvm::BasicBlock *cputhreadexitblock = GetBasicBlockFromAddress(m_state.current_instruction_address, "early_exit"); - llvm::Value *isCPUThreadExit = m_ir_builder->CreateICmpEQ(execStatus, m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusPropagateException)); - llvm::BasicBlock *normal_execution = GetBasicBlockFromAddress(m_state.current_instruction_address, "normal_execution"); - m_ir_builder->CreateCondBr(isCPUThreadExit, cputhreadexitblock, normal_execution); - m_ir_builder->SetInsertPoint(cputhreadexitblock); - m_ir_builder->CreateRet(m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusPropagateException)); - m_ir_builder->SetInsertPoint(normal_execution); - - m_ir_builder->CreateBr(GetBasicBlockFromAddress(m_state.current_instruction_address + 4)); - } - else { - // Local branch - target_block = GetBasicBlockFromAddress(target_address); - } - } - else { - // Target address is in a register - if (cmp_i1) { // There is no need to create a new block for an unconditional jump - target_block = GetBasicBlockFromAddress(m_state.current_instruction_address, "target"); - m_ir_builder->SetInsertPoint(target_block); - } - - SetPc(target_i32); - if (target_is_lr && !lk) { - // Return from this function - m_ir_builder->CreateRet(m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusReturn)); - } - else if (lk) { - BasicBlock *next_block = GetBasicBlockFromAddress(m_state.current_instruction_address + 4); - - llvm::Value *execStatus = m_ir_builder->CreateCall2(m_execute_unknown_function, m_state.args[CompileTaskState::Args::State], m_ir_builder->getInt64(0)); - - llvm::BasicBlock *cputhreadexitblock = GetBasicBlockFromAddress(m_state.current_instruction_address, "early_exit"); - llvm::Value *isCPUThreadExit = m_ir_builder->CreateICmpEQ(execStatus, m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusPropagateException)); - llvm::BasicBlock *normal_execution = GetBasicBlockFromAddress(m_state.current_instruction_address, "normal_execution"); - m_ir_builder->CreateCondBr(isCPUThreadExit, cputhreadexitblock, normal_execution); - m_ir_builder->SetInsertPoint(cputhreadexitblock); - m_ir_builder->CreateRet(m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusPropagateException)); - m_ir_builder->SetInsertPoint(normal_execution); - - m_ir_builder->CreateBr(next_block); - } - else { - m_ir_builder->CreateRet(m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusBlockEnded)); - } - } - - if (cmp_i1) { - // Conditional branch - auto next_block = GetBasicBlockFromAddress(m_state.current_instruction_address + 4); - m_ir_builder->SetInsertPoint(current_block); - m_ir_builder->CreateCondBr(cmp_i1, target_block, next_block); - } - else { - // Unconditional branch - if (target_block) { - m_ir_builder->SetInsertPoint(current_block); - m_ir_builder->CreateBr(target_block); - } - } - - m_state.hit_branch_instruction = true; -} - -// FIXME: Find out why alignement is needed -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::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); - if (bits > 8 && bswap) { - val_ix = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, m_ir_builder->getIntNTy(bits)), val_ix); - } - - return val_ix; -} - -void Compiler::WriteMemory(Value * addr_i64, Value * val_ix, u32 alignment, bool bswap, bool could_be_mmio) { - if (val_ix->getType()->getIntegerBitWidth() > 8 && bswap) { - val_ix = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, val_ix->getType()), val_ix); - } - - addr_i64 = m_ir_builder->CreateAnd(addr_i64, 0xFFFFFFFF); - 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); -} - -void Compiler::CompilationError(const std::string & error) { - LOG_ERROR(PPU, "[0x%08X] %s", m_state.current_instruction_address, error.c_str()); - Emu.Pause(); -} - -void Compiler::InitRotateMask() { - for (u32 mb = 0; mb < 64; mb++) { - for (u32 me = 0; me < 64; me++) { - u64 mask = ((u64)-1 >> mb) ^ ((me >= 63) ? 0 : (u64)-1 >> (me + 1)); - s_rotate_mask[mb][me] = mb > me ? ~mask : mask; - } - } -} -#endif diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp new file mode 100644 index 0000000000..faec008071 --- /dev/null +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -0,0 +1,1152 @@ +#include "stdafx.h" +#include "Utilities/AutoPause.h" +#include "Crypto/sha1.h" +#include "Loader/ELF.h" +#include "Emu/System.h" +#include "Emu/IdManager.h" + +#include "Emu/Cell/PPUOpcodes.h" +#include "Emu/Cell/PPUModule.h" + +#include "Emu/Cell/lv2/sys_prx.h" + +cfg::bool_entry g_cfg_hook_ppu_funcs(cfg::root.core, "Hook static functions"); +cfg::bool_entry g_cfg_load_liblv2(cfg::root.core, "Load liblv2.sprx only"); + +cfg::set_entry g_cfg_load_libs(cfg::root.core, "Load libraries"); + +extern std::string ppu_get_function_name(const std::string& module, u32 fnid); +extern std::string ppu_get_variable_name(const std::string& module, u32 vnid); + +extern void sys_initialize_tls(PPUThread&, u64, u32, u32, u32); + +// Function lookup table. Not supposed to grow after emulation start. +std::vector g_ppu_function_cache; + +// Function NID cache for autopause. Autopause tool should probably be rewritten. +std::vector g_ppu_fnid_cache; + +extern void ppu_execute_function(PPUThread& ppu, u32 index) +{ + if (index < g_ppu_function_cache.size()) + { + // If autopause occures, check_status() will hold the thread until unpaused. + if (debug::autopause::pause_function(g_ppu_fnid_cache[index]) && ppu.check_status()) throw cpu_state::ret; + + if (const auto func = g_ppu_function_cache[index]) + { + const auto previous_function = ppu.last_function; // TODO: use gsl::finally or something, but only if it's equally fast + + try + { + func(ppu); + } + catch (...) + { + LOG_WARNING(PPU, "Function '%s' aborted", ppu.last_function); + ppu.last_function = previous_function; + throw; + } + + LOG_TRACE(PPU, "Function '%s' finished, r3=0x%llx", ppu.last_function, ppu.GPR[3]); + ppu.last_function = previous_function; + return; + } + } + + throw fmt::exception("Function not registered (index %u)" HERE, index); +} + +extern u32 ppu_generate_id(const char* name) +{ + // Symbol name suffix + const auto suffix = "\x67\x59\x65\x99\x04\x25\x04\x90\x56\x64\x27\x49\x94\x89\x74\x1A"; + + sha1_context ctx; + u8 output[20]; + + // Compute SHA-1 hash + sha1_starts(&ctx); + sha1_update(&ctx, reinterpret_cast(name), std::strlen(name)); + sha1_update(&ctx, reinterpret_cast(suffix), std::strlen(suffix)); + sha1_finish(&ctx, output); + + return reinterpret_cast&>(output[0]); +} + +ppu_static_module::ppu_static_module(const char* name) + : name(name) +{ + ppu_module_manager::register_module(this); +} + +// Initialize static modules. +static void ppu_initialize_modules() +{ + const std::initializer_list registered + { + &ppu_module_manager::cellAdec, + &ppu_module_manager::cellAtrac, + &ppu_module_manager::cellAtracMulti, + &ppu_module_manager::cellAudio, + &ppu_module_manager::cellAvconfExt, + &ppu_module_manager::cellBGDL, + &ppu_module_manager::cellCamera, + &ppu_module_manager::cellCelp8Enc, + &ppu_module_manager::cellCelpEnc, + &ppu_module_manager::cellDaisy, + &ppu_module_manager::cellDmux, + &ppu_module_manager::cellFiber, + &ppu_module_manager::cellFont, + &ppu_module_manager::cellFontFT, + &ppu_module_manager::cellFs, + &ppu_module_manager::cellGame, + &ppu_module_manager::cellGameExec, + &ppu_module_manager::cellGcmSys, + &ppu_module_manager::cellGem, + &ppu_module_manager::cellGifDec, + &ppu_module_manager::cellHttp, + &ppu_module_manager::cellHttps, + &ppu_module_manager::cellHttpUtil, + &ppu_module_manager::cellImeJp, + &ppu_module_manager::cellJpgDec, + &ppu_module_manager::cellJpgEnc, + &ppu_module_manager::cellKey2char, + &ppu_module_manager::cellL10n, + &ppu_module_manager::cellMic, + &ppu_module_manager::cellMusic, + &ppu_module_manager::cellMusicDecode, + &ppu_module_manager::cellMusicExport, + &ppu_module_manager::cellNetCtl, + &ppu_module_manager::cellOskDialog, + &ppu_module_manager::cellOvis, + &ppu_module_manager::cellPamf, + &ppu_module_manager::cellPhotoDecode, + &ppu_module_manager::cellPhotoExport, + &ppu_module_manager::cellPhotoImportUtil, + &ppu_module_manager::cellPngDec, + &ppu_module_manager::cellPngEnc, + &ppu_module_manager::cellPrint, + &ppu_module_manager::cellRec, + &ppu_module_manager::cellRemotePlay, + &ppu_module_manager::cellResc, + &ppu_module_manager::cellRtc, + &ppu_module_manager::cellRudp, + &ppu_module_manager::cellSail, + &ppu_module_manager::cellSailRec, + &ppu_module_manager::cellSaveData, + &ppu_module_manager::cellMinisSaveData, + &ppu_module_manager::cellScreenShot, + &ppu_module_manager::cellSearch, + &ppu_module_manager::cellSheap, + &ppu_module_manager::cellSpudll, + &ppu_module_manager::cellSpurs, + &ppu_module_manager::cellSpursJq, + &ppu_module_manager::cellSsl, + &ppu_module_manager::cellSubdisplay, + &ppu_module_manager::cellSync, + &ppu_module_manager::cellSync2, + &ppu_module_manager::cellSysconf, + &ppu_module_manager::cellSysmodule, + &ppu_module_manager::cellSysutil, + &ppu_module_manager::cellSysutilAp, + &ppu_module_manager::cellSysutilAvc, + &ppu_module_manager::cellSysutilAvc2, + &ppu_module_manager::cellSysutilMisc, + &ppu_module_manager::cellUsbd, + &ppu_module_manager::cellUsbPspcm, + &ppu_module_manager::cellUserInfo, + &ppu_module_manager::cellVdec, + &ppu_module_manager::cellVideoExport, + &ppu_module_manager::cellVideoUpload, + &ppu_module_manager::cellVoice, + &ppu_module_manager::cellVpost, + &ppu_module_manager::libmixer, + &ppu_module_manager::libsnd3, + &ppu_module_manager::libsynth2, + &ppu_module_manager::sceNp, + &ppu_module_manager::sceNp2, + &ppu_module_manager::sceNpClans, + &ppu_module_manager::sceNpCommerce2, + &ppu_module_manager::sceNpSns, + &ppu_module_manager::sceNpTrophy, + &ppu_module_manager::sceNpTus, + &ppu_module_manager::sceNpUtil, + &ppu_module_manager::sys_io, + &ppu_module_manager::libnet, + &ppu_module_manager::sysPrxForUser, + &ppu_module_manager::sys_libc, + &ppu_module_manager::sys_lv2dbg, + }; + + // Reinitialize function cache + g_ppu_function_cache = ppu_function_manager::get(); + g_ppu_fnid_cache = std::vector(g_ppu_function_cache.size()); + + // "Use" all the modules for correct linkage + for (auto& module : registered) + { + LOG_TRACE(LOADER, "Registered static module: %s", module->name); + + for (auto& function : module->functions) + { + LOG_TRACE(LOADER, "** 0x%08X: %s", function.first, function.second.name); + g_ppu_fnid_cache.at(function.second.index) = function.first; + } + + for (auto& variable : module->variables) + { + LOG_TRACE(LOADER, "** &0x%08X: %s (size=0x%x, align=0x%x)", variable.first, variable.second.name, variable.second.size, variable.second.align); + variable.second.var->set(0); + } + } +} + +// Detect import stub at specified address and inject HACK instruction with index immediate. +static bool ppu_patch_import_stub(u32 addr, u32 index) +{ + const auto data = vm::cptr::make(addr); + + using namespace ppu_instructions; + + // Check various patterns: + + if (vm::check_addr(addr, 32) && + (data[0] & 0xffff0000) == LI(r12, 0) && + (data[1] & 0xffff0000) == ORIS(r12, r12, 0) && + (data[2] & 0xffff0000) == LWZ(r12, r12, 0) && + data[3] == STD(r2, r1, 0x28) && + data[4] == LWZ(r0, r12, 0) && + data[5] == LWZ(r2, r12, 4) && + data[6] == MTCTR(r0) && + data[7] == BCTR()) + { + std::memset(vm::base(addr), 0, 32); + vm::write32(addr + 0, STD(r2, r1, 0x28)); // Save RTOC + vm::write32(addr + 4, HACK(index)); + vm::write32(addr + 8, BLR()); + return true; + } + + if (vm::check_addr(addr, 12) && + (data[0] & 0xffff0000) == LI(r0, 0) && + (data[1] & 0xffff0000) == ORIS(r0, r0, 0) && + (data[2] & 0xfc000003) == B(0, 0, 0)) + { + const auto sub = vm::cptr::make(addr + 8 + ((s32)data[2] << 6 >> 8 << 2)); + + if (vm::check_addr(sub.addr(), 60) && + sub[0x0] == STDU(r1, r1, -0x80) && + sub[0x1] == STD(r2, r1, 0x70) && + sub[0x2] == MR(r2, r0) && + sub[0x3] == MFLR(r0) && + sub[0x4] == STD(r0, r1, 0x90) && + sub[0x5] == LWZ(r2, r2, 0) && + sub[0x6] == LWZ(r0, r2, 0) && + sub[0x7] == LWZ(r2, r2, 4) && + sub[0x8] == MTCTR(r0) && + sub[0x9] == BCTRL() && + sub[0xa] == LD(r2, r1, 0x70) && + sub[0xb] == ADDI(r1, r1, 0x80) && + sub[0xc] == LD(r0, r1, 0x10) && + sub[0xd] == MTLR(r0) && + sub[0xe] == BLR()) + { + vm::write32(addr + 0, HACK(index)); + vm::write32(addr + 4, BLR()); + vm::write32(addr + 8, 0); + return true; + } + } + + if (vm::check_addr(addr, 64) && + data[0x0] == MFLR(r0) && + data[0x1] == STD(r0, r1, 0x10) && + data[0x2] == STDU(r1, r1, -0x80) && + data[0x3] == STD(r2, r1, 0x70) && + (data[0x4] & 0xffff0000) == LI(r2, 0) && + (data[0x5] & 0xffff0000) == ORIS(r2, r2, 0) && + data[0x6] == LWZ(r2, r2, 0) && + data[0x7] == LWZ(r0, r2, 0) && + data[0x8] == LWZ(r2, r2, 4) && + data[0x9] == MTCTR(r0) && + data[0xa] == BCTRL() && + data[0xb] == LD(r2, r1, 0x70) && + data[0xc] == ADDI(r1, r1, 0x80) && + data[0xd] == LD(r0, r1, 0x10) && + data[0xe] == MTLR(r0) && + data[0xf] == BLR()) + { + std::memset(vm::base(addr), 0, 64); + vm::write32(addr + 0, HACK(index)); + vm::write32(addr + 4, BLR()); + return true; + } + + if (vm::check_addr(addr, 64) && + data[0x0] == MFLR(r0) && + data[0x1] == STD(r0, r1, 0x10) && + data[0x2] == STDU(r1, r1, -0x80) && + data[0x3] == STD(r2, r1, 0x70) && + (data[0x4] & 0xffff0000) == LIS(r12, 0) && + (data[0x5] & 0xffff0000) == LWZ(r12, r12, 0) && + data[0x6] == LWZ(r0, r12, 0) && + data[0x7] == LWZ(r2, r12, 4) && + data[0x8] == MTCTR(r0) && + data[0x9] == BCTRL() && + data[0xa] == LD(r2, r1, 0x70) && + data[0xb] == ADDI(r1, r1, 0x80) && + data[0xc] == LD(r0, r1, 0x10) && + data[0xd] == MTLR(r0) && + data[0xe] == BLR()) + { + std::memset(vm::base(addr), 0, 64); + vm::write32(addr + 0, HACK(index)); + vm::write32(addr + 4, BLR()); + return true; + } + + if (vm::check_addr(addr, 56) && + (data[0x0] & 0xffff0000) == LI(r12, 0) && + (data[0x1] & 0xffff0000) == ORIS(r12, r12, 0) && + (data[0x2] & 0xffff0000) == LWZ(r12, r12, 0) && + data[0x3] == STD(r2, r1, 0x28) && + data[0x4] == MFLR(r0) && + data[0x5] == STD(r0, r1, 0x20) && + data[0x6] == LWZ(r0, r12, 0) && + data[0x7] == LWZ(r2, r12, 4) && + data[0x8] == MTCTR(r0) && + data[0x9] == BCTRL() && + data[0xa] == LD(r0, r1, 0x20) && + data[0xb] == MTLR(r0) && + data[0xc] == LD(r2, r1, 0x28) && + data[0xd] == BLR()) + { + std::memset(vm::base(addr), 0, 56); + vm::write32(addr + 0, HACK(index)); + vm::write32(addr + 4, BLR()); + return true; + } + + return false; +} + +// Global linkage information +struct ppu_linkage_info +{ + struct module + { + using info_t = std::unordered_map>>; + + info_t functions; + info_t variables; + }; + + // Module -> (NID -> (export; [imports...])) + std::unordered_map modules; +}; + +// Link variable +static void ppu_patch_variable_stub(u32 vref, u32 vaddr) +{ + struct vref_t + { + be_t type; + be_t addr; + be_t unk0; + }; + + for (auto ref = vm::ptr::make(vref); ref->type; ref++) + { + if (ref->unk0) LOG_ERROR(LOADER, "**** VREF(%u): Unknown values (0x%x, 0x%x)", ref->type, ref->addr, ref->unk0); + + // OPs are probably similar to relocations + switch (u32 type = ref->type) + { + case 0x1: + { + const u32 value = vm::_ref(ref->addr) = vaddr; + LOG_WARNING(LOADER, "**** VREF(1): 0x%x <- 0x%x", ref->addr, value); + break; + } + + case 0x4: + case 0x6: + default: LOG_ERROR(LOADER, "**** VREF(%u): Unknown/Illegal type (0x%x, 0x%x)", ref->type, ref->addr, ref->unk0); + } + } +} + +// Export or import module struct +struct ppu_prx_module_info +{ + u8 size; + u8 unk0; + be_t version; + be_t attributes; + be_t num_func; + be_t num_var; + be_t num_tlsvar; + u8 info_hash; + u8 info_tlshash; + u8 unk1[2]; + vm::bcptr name; + vm::bcptr nids; // Imported FNIDs, Exported NIDs + vm::bptr addrs; + vm::bcptr vnids; // Imported VNIDs + vm::bcptr vstubs; + be_t unk4; + be_t unk5; +}; + +// Load and register exports; return special exports found (nameless module) +static auto ppu_load_exports(const std::shared_ptr& link, u32 exports_start, u32 exports_end) +{ + std::unordered_map result; + + for (u32 addr = exports_start; addr < exports_end;) + { + const auto& lib = vm::_ref(addr); + + if (!lib.name) + { + // Set special exports + for (u32 i = 0, end = lib.num_func + lib.num_var; i < end; i++) + { + const u32 nid = lib.nids[i]; + const u32 addr = lib.addrs[i]; + + if (i < lib.num_func) + { + LOG_NOTICE(LOADER, "** Special: [%s] at 0x%x", ppu_get_function_name({}, nid), addr); + } + else + { + LOG_NOTICE(LOADER, "** Special: &[%s] at 0x%x", ppu_get_variable_name({}, nid), addr); + } + + result.emplace(nid, addr); + } + + addr += lib.size ? lib.size : sizeof(ppu_prx_module_info); + continue; + } + + const std::string module_name(lib.name.get_ptr()); + + LOG_NOTICE(LOADER, "** Exported module '%s' (0x%x, 0x%x, 0x%x, 0x%x)", module_name, lib.vnids, lib.vstubs, lib.unk4, lib.unk5); + + if (lib.num_tlsvar) + { + LOG_FATAL(LOADER, "Unexpected num_tlsvar (%u)!", lib.num_tlsvar); + } + + // Static module + const auto _sm = ppu_module_manager::get_module(module_name); + + const auto fnids = +lib.nids; + const auto faddrs = +lib.addrs; + + // Get functions + for (u32 i = 0, end = lib.num_func; i < end; i++) + { + const u32 fnid = fnids[i]; + const u32 faddr = faddrs[i]; + LOG_NOTICE(LOADER, "**** %s export: [%s] at 0x%x", module_name, ppu_get_function_name(module_name, fnid), faddr); + + // Function linkage info + auto& flink = link->modules[module_name].functions[fnid]; + + if (flink.first) + { + LOG_FATAL(LOADER, "Already linked function '%s' in module '%s'", ppu_get_function_name(module_name, fnid), module_name); + } + else + { + // Static function + const auto _sf = _sm && _sm->functions.count(fnid) ? &_sm->functions.at(fnid) : nullptr; + + if (_sf && (_sf->flags & MFF_FORCED_HLE)) + { + // Inject HACK instruction (TODO: guess function size and analyse B instruction, or reimplement BLR flag for HACK instruction) + const auto code = vm::ptr::make(vm::read32(faddr)); + code[0] = ppu_instructions::HACK(_sf->index); + code[1] = ppu_instructions::BLR(); + } + else + { + // Set exported function + flink.first = faddr; + + // Fix imports + for (const auto addr : flink.second) + { + vm::write32(addr, faddr); + //LOG_WARNING(LOADER, "Exported function '%s' in module '%s'", ppu_get_function_name(module_name, fnid), module_name); + } + } + } + } + + const auto vnids = lib.nids + lib.num_func; + const auto vaddrs = lib.addrs + lib.num_func; + + // Get variables + for (u32 i = 0, end = lib.num_var; i < end; i++) + { + const u32 vnid = vnids[i]; + const u32 vaddr = vaddrs[i]; + LOG_NOTICE(LOADER, "**** %s export: &[%s] at 0x%x", module_name, ppu_get_variable_name(module_name, vnid), vaddr); + + // Variable linkage info + auto& vlink = link->modules[module_name].variables[vnid]; + + if (vlink.first) + { + LOG_FATAL(LOADER, "Already linked variable '%s' in module '%s'", ppu_get_variable_name(module_name, vnid), module_name); + } + else + { + // Set exported variable + vlink.first = vaddr; + + // Fix imports + for (const auto vref : vlink.second) + { + ppu_patch_variable_stub(vref, vaddr); + //LOG_WARNING(LOADER, "Exported variable '%s' in module '%s'", ppu_get_variable_name(module_name, vnid), module_name); + } + } + } + + addr += lib.size ? lib.size : sizeof(ppu_prx_module_info); + } + + return result; +} + +static void ppu_load_imports(const std::shared_ptr& link, u32 imports_start, u32 imports_end) +{ + for (u32 addr = imports_start; addr < imports_end;) + { + const auto& lib = vm::_ref(addr); + + const std::string module_name(lib.name.get_ptr()); + + LOG_NOTICE(LOADER, "** Imported module '%s' (0x%x, 0x%x)", module_name, lib.unk4, lib.unk5); + + if (lib.num_tlsvar) + { + LOG_FATAL(LOADER, "Unexpected num_tlsvar (%u)!", lib.num_tlsvar); + } + + // Static module + const auto _sm = ppu_module_manager::get_module(module_name); + + const auto fnids = +lib.nids; + const auto faddrs = +lib.addrs; + + for (u32 i = 0, end = lib.num_func; i < end; i++) + { + const u32 fnid = fnids[i]; + const u32 fstub = faddrs[i]; + const u32 faddr = (faddrs + i).addr(); + LOG_NOTICE(LOADER, "**** %s import: [%s] -> 0x%x", module_name, ppu_get_function_name(module_name, fnid), fstub); + + // Function linkage info + auto& flink = link->modules[module_name].functions[fnid]; + + // Add new import + flink.second.emplace(faddr); + + // Link if available + if (flink.first) vm::write32(faddr, flink.first); + + //LOG_WARNING(LOADER, "Imported function '%s' in module '%s' (0x%x)", ppu_get_function_name(module_name, fnid), module_name, faddr); + } + + const auto vnids = +lib.vnids; + const auto vstubs = +lib.vstubs; + + for (u32 i = 0, end = lib.num_var; i < end; i++) + { + const u32 vnid = vnids[i]; + const u32 vref = vstubs[i]; + LOG_NOTICE(LOADER, "**** %s import: &[%s] (ref=*0x%x)", module_name, ppu_get_variable_name(module_name, vnid), vref); + + // Variable linkage info + auto& vlink = link->modules[module_name].variables[vnid]; + + // Add new import + vlink.second.emplace(vref); + + // Link if available + if (vlink.first) ppu_patch_variable_stub(vref, vlink.first); + + //LOG_WARNING(LOADER, "Imported variable '%s' in module '%s' (0x%x)", ppu_get_variable_name(module_name, vnid), module_name, vlink.first); + } + + addr += lib.size ? lib.size : sizeof(ppu_prx_module_info); + } +} + +template<> +std::shared_ptr ppu_prx_loader::load() const +{ + std::vector segments; + + for (const auto& prog : progs) + { + LOG_NOTICE(LOADER, "** Segment: p_type=0x%x, p_vaddr=0x%llx, p_filesz=0x%llx, p_memsz=0x%llx, flags=0x%x", prog.p_type, prog.p_vaddr, prog.p_filesz, prog.p_memsz, prog.p_flags); + + switch (const u32 p_type = prog.p_type) + { + case 0x1: // LOAD + { + if (prog.p_memsz) + { + const u32 mem_size = fmt::narrow("Invalid p_memsz (0x%llx)" HERE, prog.p_memsz); + const u32 file_size = fmt::narrow("Invalid p_filesz (0x%llx)" HERE, prog.p_filesz); + const u32 init_addr = fmt::narrow("Invalid p_vaddr (0x%llx)" HERE, prog.p_vaddr); + + // Alloc segment memory + const u32 addr = vm::alloc(mem_size, vm::main); + + if (!addr) + { + throw fmt::exception("vm::alloc() failed (size=0x%x)", mem_size); + } + + // Copy data + std::memcpy(vm::base(addr), prog.bin.data(), file_size); + LOG_WARNING(LOADER, "**** Loaded to 0x%x (size=0x%x)", addr, mem_size); + + segments.push_back(addr); + } + + break; + } + + case 0x700000a4: break; // Relocations + + default: LOG_ERROR(LOADER, "Unknown segment type! 0x%08x", p_type); + } + } + + // Do relocations + for (auto& prog : progs) + { + switch (const u32 p_type = prog.p_type) + { + case 0x700000a4: + { + // Relocation information of the SCE_PPURELA segment + struct ppu_prx_relocation_info + { + be_t offset; + be_t unk0; + u8 index_value; + u8 index_addr; + be_t type; + vm::bptr ptr; + }; + + for (uint i = 0; i < prog.p_filesz; i += sizeof(ppu_prx_relocation_info)) + { + const auto& rel = reinterpret_cast(prog.bin[i]); + + const u32 raddr = vm::cast(segments.at(rel.index_addr) + rel.offset, HERE); + const u64 rdata = segments.at(rel.index_value) + rel.ptr.addr(); + + switch (const u32 type = rel.type) + { + case 1: + { + const u32 value = vm::_ref(raddr) = static_cast(rdata); + LOG_TRACE(LOADER, "**** RELOCATION(1): 0x%x <- 0x%08x (0x%llx)", raddr, value, rdata); + break; + } + + case 4: + { + const u16 value = vm::_ref(raddr) = static_cast(rdata); + LOG_TRACE(LOADER, "**** RELOCATION(4): 0x%x <- 0x%04x (0x%llx)", raddr, value, rdata); + break; + } + + case 5: + { + const u16 value = vm::_ref(raddr) = static_cast(rdata >> 16); + LOG_TRACE(LOADER, "**** RELOCATION(5): 0x%x <- 0x%04x (0x%llx)", raddr, value, rdata); + break; + } + + case 6: + { + const u16 value = vm::_ref(raddr) = static_cast(rdata >> 16) + (rdata & 0x8000 ? 1 : 0); + LOG_TRACE(LOADER, "**** RELOCATION(6): 0x%x <- 0x%04x (0x%llx)", raddr, value, rdata); + break; + } + + case 10: + case 44: + case 57: + default: LOG_ERROR(LOADER, "**** RELOCATION(%u): Illegal/Unknown type! (addr=0x%x)", type, raddr); + } + } + + break; + } + } + } + + // Access linkage information object + const auto link = fxm::get_always(); + + // Create new PRX object + auto prx = idm::make_ptr(); + + if (!progs.empty() && progs[0].p_paddr) + { + struct ppu_prx_library_info + { + be_t attributes; + be_t version; + char name[28]; + be_t toc; + be_t exports_start; + be_t exports_end; + be_t imports_start; + be_t imports_end; + }; + + // Access library information (TODO) + const auto& lib_info = vm::_ref(vm::cast(segments[0] + progs[0].p_paddr - progs[0].p_offset, HERE)); + const auto& lib_name = std::string(lib_info.name); + + LOG_WARNING(LOADER, "Library %s (toc=0x%x, rtoc=0x%x):", lib_name, lib_info.toc, lib_info.toc + segments[0]); + + prx->specials = ppu_load_exports(link, lib_info.exports_start, lib_info.exports_end); + + ppu_load_imports(link, lib_info.imports_start, lib_info.imports_end); + } + else + { + LOG_FATAL(LOADER, "Library %s: PRX library info not found"); + } + + prx->start.set(prx->specials[0xbc9a0086]); + prx->stop.set(prx->specials[0xab779874]); + prx->exit.set(prx->specials[0x3ab9a95e]); + + return prx; +} + +template<> +void ppu_exec_loader::load() const +{ + ppu_initialize_modules(); + + if (g_cfg_hook_ppu_funcs) + { + LOG_TODO(LOADER, "'Hook static functions' option deactivated"); + } + + // Access linkage information object + const auto link = fxm::get_always(); + + // Allocate memory at fixed positions + for (const auto& prog : progs) + { + const u32 addr = vm::cast(prog.p_vaddr, HERE); + const u32 size = fmt::narrow("Invalid p_memsz: 0x%llx" HERE, prog.p_memsz); + + if (prog.p_type == 0x1 /* LOAD */ && prog.p_memsz) + { + if (prog.bin.size() > size || prog.bin.size() != prog.p_filesz) + throw fmt::exception("Invalid binary size (0x%llx, memsz=0x%x)", prog.bin.size(), size); + + if (!vm::falloc(addr, size, vm::main)) + throw fmt::exception("vm::falloc() failed (addr=0x%x, memsz=0x%x)", addr, size); + + std::memcpy(vm::base(addr), prog.bin.data(), prog.bin.size()); + } + } + + // Load other programs + for (auto& prog : progs) + { + switch (const u32 p_type = prog.p_type) + { + case 0x00000001: break; //LOAD + + case 0x00000007: //TLS + { + const u32 addr = vm::cast(prog.p_vaddr, HERE); + const u32 filesz = fmt::narrow("Invalid p_filesz (0x%llx)" HERE, prog.p_filesz); + const u32 memsz = fmt::narrow("Invalid p_memsz (0x%llx)" HERE, prog.p_memsz); + Emu.SetTLSData(addr, filesz, memsz); + LOG_NOTICE(LOADER, "*** TLS segment addr: 0x%08x", Emu.GetTLSAddr()); + LOG_NOTICE(LOADER, "*** TLS segment size: 0x%08x", Emu.GetTLSFilesz()); + LOG_NOTICE(LOADER, "*** TLS memory size: 0x%08x", Emu.GetTLSMemsz()); + break; + } + + case 0x60000001: //LOOS+1 + { + if (prog.p_filesz) + { + struct process_param_t + { + be_t size; + be_t magic; + be_t version; + be_t sdk_version; + be_t primary_prio; + be_t primary_stacksize; + be_t malloc_pagesize; + be_t ppc_seg; + //be_t crash_dump_param_addr; + }; + + const auto& info = vm::ps3::_ref(vm::cast(prog.p_vaddr, HERE)); + + if (info.size < sizeof(process_param_t)) + { + LOG_WARNING(LOADER, "Bad process_param size! [0x%x : 0x%x]", info.size, SIZE_32(process_param_t)); + } + if (info.magic != 0x13bcc5f6) + { + LOG_ERROR(LOADER, "Bad process_param magic! [0x%x]", info.magic); + } + else + { + LOG_NOTICE(LOADER, "*** sdk version: 0x%x", info.sdk_version); + LOG_NOTICE(LOADER, "*** primary prio: %d", info.primary_prio); + LOG_NOTICE(LOADER, "*** primary stacksize: 0x%x", info.primary_stacksize); + LOG_NOTICE(LOADER, "*** malloc pagesize: 0x%x", info.malloc_pagesize); + LOG_NOTICE(LOADER, "*** ppc seg: 0x%x", info.ppc_seg); + //LOG_NOTICE(LOADER, "*** crash dump param addr: 0x%x", info.crash_dump_param_addr); + + Emu.SetParams(info.sdk_version, info.malloc_pagesize, std::max(info.primary_stacksize, 0x4000), info.primary_prio); + } + } + break; + } + + case 0x60000002: //LOOS+2 + { + if (prog.p_filesz) + { + struct ppu_proc_prx_param_t + { + be_t size; + be_t magic; + be_t version; + be_t unk0; + be_t libent_start; + be_t libent_end; + be_t libstub_start; + be_t libstub_end; + be_t ver; + be_t unk1; + be_t unk2; + }; + + const auto& proc_prx_param = vm::_ref(vm::cast(prog.p_vaddr, HERE)); + + if (proc_prx_param.magic != 0x1b434cec) + { + throw fmt::exception("Bad magic! (0x%x)", proc_prx_param.magic); + } + + ppu_load_exports(link, proc_prx_param.libent_start, proc_prx_param.libent_end); + ppu_load_imports(link, proc_prx_param.libstub_start, proc_prx_param.libstub_end); + } + break; + } + default: + { + LOG_ERROR(LOADER, "Unknown phdr type (0x%08x)", p_type); + } + } + } + + // Initialize process + std::vector start_funcs; + + // Load modules + const std::string& lle_dir = vfs::get("/dev_flash/sys/external"); + + if (g_cfg_load_liblv2) + { + const ppu_prx_loader loader = fs::file(lle_dir + "/liblv2.sprx"); + + if (loader == elf_error::ok) + { + start_funcs.push_back(loader.load()->start.addr()); + } + else + { + throw fmt::exception("Failed to load liblv2.sprx: %s", bijective_find(loader, "???")); + } + } + else + { + for (const auto& name : g_cfg_load_libs.get_set()) + { + const ppu_prx_loader loader = fs::file(lle_dir + '/' + name); + + if (loader == elf_error::ok) + { + LOG_WARNING(LOADER, "Loading library: %s", name); + + const auto prx = loader.load(); + + if (prx->start) + { + start_funcs.push_back(prx->start.addr()); + } + } + else + { + LOG_FATAL(LOADER, "Failed to load %s: %s", name, bijective_find(loader, "???")); + } + } + } + + // Check unlinked functions and variables + for (auto& module : link->modules) + { + const auto _sm = ppu_module_manager::get_module(module.first); + + if (!_sm) + { + LOG_ERROR(LOADER, "Unknown module '%s'", module.first); + } + else + { + // Allocate HLE variables (TODO) + for (auto& var : _sm->variables) + { + var.second.var->set(vm::alloc(var.second.size, vm::main, std::max(var.second.align, 4096))); + LOG_WARNING(LOADER, "Allocated variable '%s' in module '%s' at *0x%x", var.second.name, module.first, var.second.var->addr()); + } + + // Initialize HLE variables (TODO) + for (auto& var : _sm->variables) + { + var.second.init(); + } + } + + for (auto& entry : module.second.functions) + { + const u32 fnid = entry.first; + const u32 faddr = entry.second.first; + + if (faddr == 0) + { + if (const auto _sf = _sm && _sm->functions.count(fnid) ? &_sm->functions.at(fnid) : nullptr) + { + // Static function + for (auto& import : entry.second.second) + { + const u32 stub = vm::read32(import); + + if (!ppu_patch_import_stub(stub, _sf->index)) + { + LOG_ERROR(LOADER, "Failed to inject code for function '%s' in module '%s' (0x%x)", _sf->name, module.first, stub); + } + else + { + LOG_NOTICE(LOADER, "Injected hack for function '%s' in module '%s' (*0x%x)", _sf->name, module.first, stub); + } + } + } + else + { + // TODO + const u32 index = ::size32(g_ppu_function_cache); + g_ppu_function_cache.emplace_back(); + g_ppu_fnid_cache.emplace_back(fnid); + + LOG_ERROR(LOADER, "Unknown function '%s' in module '%s' (index %u)", ppu_get_function_name(module.first, fnid), module.first, index); + + for (auto& import : entry.second.second) + { + if (_sm) + { + const u32 stub = vm::read32(import); + + if (!ppu_patch_import_stub(stub, index)) + { + LOG_ERROR(LOADER, "Failed to inject code for function '%s' in module '%s' (0x%x)", ppu_get_function_name(module.first, fnid), module.first, stub); + } + else + { + LOG_NOTICE(LOADER, "Injected hack for function '%s' in module '%s' (*0x%x)", ppu_get_function_name(module.first, fnid), module.first, stub); + } + } + + LOG_WARNING(LOADER, "** Not linked at *0x%x", import); + } + } + } + } + + for (auto& entry : module.second.variables) + { + const u32 vnid = entry.first; + const u32 vaddr = entry.second.first; + + if (vaddr == 0) + { + // Static variable + if (const auto _sv = _sm && _sm->variables.count(vnid) ? &_sm->variables.at(vnid) : nullptr) + { + LOG_NOTICE(LOADER, "Linking HLE variable '%s' in module '%s' (*0x%x):", ppu_get_variable_name(module.first, vnid), module.first, _sv->var->addr()); + + for (auto& ref : entry.second.second) + { + ppu_patch_variable_stub(ref, _sv->var->addr()); + LOG_NOTICE(LOADER, "** Linked at ref=*0x%x", ref); + } + } + else + { + LOG_ERROR(LOADER, "Unknown variable '%s' in module '%s'", ppu_get_variable_name(module.first, vnid), module.first); + + for (auto& ref : entry.second.second) + { + LOG_WARNING(LOADER, "** Not linked at ref=*0x%x", ref); + } + } + } + else + { + // Retro-link LLE variable (TODO: HLE must not be allocated/initialized in this case) + if (const auto _sv = _sm && _sm->variables.count(vnid) ? &_sm->variables.at(vnid) : nullptr) + { + _sv->var->set(vaddr); + LOG_NOTICE(LOADER, "Linked LLE variable '%s' in module '%s' -> 0x%x", ppu_get_variable_name(module.first, vnid), module.first, vaddr); + } + } + } + } + + // TODO: adjust for liblv2 loading option + using namespace ppu_instructions; + + auto ppu_thr_stop_data = vm::ptr::make(vm::alloc(2 * 4, vm::main)); + Emu.SetCPUThreadStop(ppu_thr_stop_data.addr()); + ppu_thr_stop_data[0] = HACK(1); + ppu_thr_stop_data[1] = BLR(); + + static const int branch_size = 10 * 4; + + auto make_branch = [](vm::ptr& ptr, u32 addr) + { + const u32 stub = vm::read32(addr); + const u32 rtoc = vm::read32(addr + 4); + + *ptr++ = LI(r0, 0); + *ptr++ = ORI(r0, r0, stub & 0xffff); + *ptr++ = ORIS(r0, r0, stub >> 16); + *ptr++ = LI(r2, 0); + *ptr++ = ORI(r2, r2, rtoc & 0xffff); + *ptr++ = ORIS(r2, r2, rtoc >> 16); + *ptr++ = MTCTR(r0); + *ptr++ = BCTRL(); + }; + + auto entry = vm::ptr::make(vm::alloc(48 + branch_size * (::size32(start_funcs) + 1), vm::main)); + + // Save initialization args + *entry++ = MR(r14, r3); + *entry++ = MR(r15, r4); + *entry++ = MR(r16, r5); + *entry++ = MR(r17, r6); + *entry++ = MR(r18, r11); + *entry++ = MR(r19, r12); + + if (!g_cfg_load_liblv2) + { + // Call sys_initialize_tls explicitly + *entry++ = MR(r3, r7); + *entry++ = MR(r4, r8); + *entry++ = MR(r5, r9); + *entry++ = MR(r6, r10); + *entry++ = HACK(FIND_FUNC(sys_initialize_tls)); + } + + for (auto& f : start_funcs) + { + // Reset arguments (TODO) + *entry++ = LI(r3, 0); + *entry++ = LI(r4, 0); + make_branch(entry, f); + } + + // Restore initialization args + *entry++ = MR(r3, r14); + *entry++ = MR(r4, r15); + *entry++ = MR(r5, r16); + *entry++ = MR(r6, r17); + *entry++ = MR(r11, r18); + *entry++ = MR(r12, r19); + + // Branch to initialization + make_branch(entry, vm::cast(header.e_entry, HERE)); + + auto ppu = idm::make_ptr("main_thread"); + + ppu->PC = entry.addr() & -0x1000; + ppu->stack_size = Emu.GetPrimaryStackSize(); + ppu->prio = Emu.GetPrimaryPrio(); + ppu->cpu_init(); + + ppu->GPR[2] = 0xdeadbeef; // rtoc + ppu->GPR[11] = 0xabadcafe; // OPD ??? + ppu->GPR[12] = Emu.GetMallocPageSize(); + + std::initializer_list args = { Emu.GetPath()/*, "-emu"s*/ }; + + auto argv = vm::ptr::make(vm::alloc(SIZE_32(u64) * ::size32(args), vm::main)); + auto envp = vm::ptr::make(vm::alloc(::align(SIZE_32(u64), 0x10), vm::main)); + *envp = 0; + + ppu->GPR[3] = args.size(); // argc + ppu->GPR[4] = argv.addr(); + ppu->GPR[5] = envp.addr(); + ppu->GPR[6] = 0; // ??? + + for (const auto& arg : args) + { + const u32 arg_size = ::align(::size32(arg) + 1, 0x10); + const u32 arg_addr = vm::alloc(arg_size, vm::main); + + std::memcpy(vm::base(arg_addr), arg.data(), arg_size); + + *argv++ = arg_addr; + } + + // Arguments for sys_initialize_tls() + ppu->GPR[7] = ppu->id; + ppu->GPR[8] = Emu.GetTLSAddr(); + ppu->GPR[9] = Emu.GetTLSFilesz(); + ppu->GPR[10] = Emu.GetTLSMemsz(); + + // Set memory protections + //for (const auto& prog : progs) + //{ + // const u32 addr = static_cast(prog.p_vaddr); + // const u32 size = static_cast(prog.p_memsz); + + // if (prog.p_type == 0x1 /* LOAD */ && prog.p_memsz && (prog.p_flags & 0x2) == 0 /* W */) + // { + // // Set memory protection to read-only where necessary + // ASSERT(vm::page_protect(addr, ::align(size, 0x1000), 0, 0, vm::page_writable)); + // } + //} +} diff --git a/rpcs3/Emu/Cell/PPUModule.h b/rpcs3/Emu/Cell/PPUModule.h new file mode 100644 index 0000000000..81d4dadfcf --- /dev/null +++ b/rpcs3/Emu/Cell/PPUModule.h @@ -0,0 +1,255 @@ +#pragma once + +#include "Utilities/Config.h" +#include "PPUFunction.h" +#include "PPUCallback.h" +#include "ErrorCodes.h" + +namespace vm { using namespace ps3; } + +// Generate FNID or VNID for given name +extern u32 ppu_generate_id(const char* name); + +// Flags set with REG_FUNC +enum ppu_static_function_flags : u32 +{ + MFF_FORCED_HLE = (1 << 0), // Always call HLE function (TODO: deactivated) + + MFF_PERFECT = MFF_FORCED_HLE, // Indicates that function is completely implemented and can replace LLE implementation +}; + +// HLE function information +struct ppu_static_function +{ + const char* name; + u32 index; // Index for ppu_function_manager + u32 flags; +}; + +// HLE variable information +struct ppu_static_variable +{ + const char* name; + vm::gvar* var; // Pointer to variable address storage + void(*init)(); // Variable initialization function + u32 size; + u32 align; +}; + +// HLE module information +class ppu_static_module final +{ +public: + const std::string name; + + task_stack on_load; + task_stack on_unload; + + std::unordered_map functions; + std::unordered_map variables; + +public: + ppu_static_module(const char* name); + + ppu_static_module(const char* name, void(*init)()) + : ppu_static_module(name) + { + init(); + } + + ppu_static_module(const char* name, void(*init)(ppu_static_module* _this)) + : ppu_static_module(name) + { + init(this); + } +}; + +class ppu_module_manager final +{ + friend class ppu_static_module; + + static never_inline auto& access() + { + static std::unordered_map map; + + return map; + } + + static never_inline void register_module(ppu_static_module* module) + { + access().emplace(module->name, module); + } + + static never_inline auto& access_static_function(const char* module, u32 fnid) + { + return access().at(module)->functions[fnid]; + } + + static never_inline auto& access_static_variable(const char* module, u32 vnid) + { + return access().at(module)->variables[vnid]; + } + +public: + static never_inline const ppu_static_module* get_module(const std::string& name) + { + const auto& map = access(); + const auto found = map.find(name); + return found != map.end() ? found->second : nullptr; + } + + template + static void register_static_function(const char* module, const char* name, ppu_function_t func, u32 fnid, u32 flags) + { + auto& info = access_static_function(module, fnid); + + info.name = name; + info.index = ppu_function_manager::register_function(func); + info.flags = flags; + } + + template + static void register_static_variable(const char* module, const char* name, u32 vnid, void(*init)()) + { + static_assert(std::is_same::value, "Static variable registration: vm::gvar expected"); + + auto& info = access_static_variable(module, vnid); + + info.name = name; + info.var = reinterpret_cast*>(Var); + info.init = init ? init : [] {}; + info.size = SIZE_32(typename T::type); + info.align = ALIGN_32(typename T::type); + } + + static const ppu_static_module cellAdec; + static const ppu_static_module cellAtrac; + static const ppu_static_module cellAtracMulti; + static const ppu_static_module cellAudio; + static const ppu_static_module cellAvconfExt; + static const ppu_static_module cellBGDL; + static const ppu_static_module cellCamera; + static const ppu_static_module cellCelp8Enc; + static const ppu_static_module cellCelpEnc; + static const ppu_static_module cellDaisy; + static const ppu_static_module cellDmux; + static const ppu_static_module cellFiber; + static const ppu_static_module cellFont; + static const ppu_static_module cellFontFT; + static const ppu_static_module cellFs; + static const ppu_static_module cellGame; + static const ppu_static_module cellGameExec; + static const ppu_static_module cellGcmSys; + static const ppu_static_module cellGem; + static const ppu_static_module cellGifDec; + static const ppu_static_module cellHttp; + static const ppu_static_module cellHttps; + static const ppu_static_module cellHttpUtil; + static const ppu_static_module cellImeJp; + static const ppu_static_module cellJpgDec; + static const ppu_static_module cellJpgEnc; + static const ppu_static_module cellKey2char; + static const ppu_static_module cellL10n; + static const ppu_static_module cellMic; + static const ppu_static_module cellMusic; + static const ppu_static_module cellMusicDecode; + static const ppu_static_module cellMusicExport; + static const ppu_static_module cellNetCtl; + static const ppu_static_module cellOskDialog; + static const ppu_static_module cellOvis; + static const ppu_static_module cellPamf; + static const ppu_static_module cellPhotoDecode; + static const ppu_static_module cellPhotoExport; + static const ppu_static_module cellPhotoImportUtil; + static const ppu_static_module cellPngDec; + static const ppu_static_module cellPngEnc; + static const ppu_static_module cellPrint; + static const ppu_static_module cellRec; + static const ppu_static_module cellRemotePlay; + static const ppu_static_module cellResc; + static const ppu_static_module cellRtc; + static const ppu_static_module cellRudp; + static const ppu_static_module cellSail; + static const ppu_static_module cellSailRec; + static const ppu_static_module cellSaveData; + static const ppu_static_module cellMinisSaveData; + static const ppu_static_module cellScreenShot; + static const ppu_static_module cellSearch; + static const ppu_static_module cellSheap; + static const ppu_static_module cellSpudll; + static const ppu_static_module cellSpurs; + static const ppu_static_module cellSpursJq; + static const ppu_static_module cellSsl; + static const ppu_static_module cellSubdisplay; + static const ppu_static_module cellSync; + static const ppu_static_module cellSync2; + static const ppu_static_module cellSysconf; + static const ppu_static_module cellSysmodule; + static const ppu_static_module cellSysutil; + static const ppu_static_module cellSysutilAp; + static const ppu_static_module cellSysutilAvc; + static const ppu_static_module cellSysutilAvc2; + static const ppu_static_module cellSysutilMisc; + static const ppu_static_module cellUsbd; + static const ppu_static_module cellUsbPspcm; + static const ppu_static_module cellUserInfo; + static const ppu_static_module cellVdec; + static const ppu_static_module cellVideoExport; + static const ppu_static_module cellVideoUpload; + static const ppu_static_module cellVoice; + static const ppu_static_module cellVpost; + static const ppu_static_module libmixer; + static const ppu_static_module libsnd3; + static const ppu_static_module libsynth2; + static const ppu_static_module sceNp; + static const ppu_static_module sceNp2; + static const ppu_static_module sceNpClans; + static const ppu_static_module sceNpCommerce2; + static const ppu_static_module sceNpSns; + static const ppu_static_module sceNpTrophy; + static const ppu_static_module sceNpTus; + static const ppu_static_module sceNpUtil; + static const ppu_static_module sys_io; + static const ppu_static_module libnet; + static const ppu_static_module sysPrxForUser; + static const ppu_static_module sys_libc; + static const ppu_static_module sys_lv2dbg; +}; + +// Call specified function directly if LLE is not available, call LLE equivalent in callback style otherwise +template> +inline RT ppu_execute_function_or_callback(const char* name, PPUThread& ppu, Args&&... args) +{ + const auto previous_function = ppu.last_function; // TODO + + try + { + return Func(std::forward(args)...); + } + catch (const std::exception&) + { + LOG_ERROR(PPU, "Function '%s' aborted", ppu.last_function); + ppu.last_function = previous_function; + throw; + } + catch (...) + { + LOG_WARNING(PPU, "Function '%s' aborted", ppu.last_function); + ppu.last_function = previous_function; + throw; + } + + ppu.last_function = previous_function; +} + +#define CALL_FUNC(ppu, func, ...) ppu_execute_function_or_callback(#func, ppu, __VA_ARGS__) + +#define REG_FNID(module, nid, func, ...) ppu_module_manager::register_static_function(#module, #func, BIND_FUNC(func), nid, {__VA_ARGS__}) + +#define REG_FUNC(module, func, ...) REG_FNID(module, ppu_generate_id(#func), func, __VA_ARGS__) + +#define REG_VNID(module, nid, var, ...) ppu_module_manager::register_static_variable(#module, #var, nid, {__VA_ARGS__}) + +#define REG_VAR(module, var, ...) REG_VNID(module, ppu_generate_id(#var), var, __VA_ARGS__) + +#define UNIMPLEMENTED_FUNC(module) module.todo("%s", __func__) diff --git a/rpcs3/Emu/Cell/PPUOpcodes.h b/rpcs3/Emu/Cell/PPUOpcodes.h index 185f22905b..36691c9c8e 100644 --- a/rpcs3/Emu/Cell/PPUOpcodes.h +++ b/rpcs3/Emu/Cell/PPUOpcodes.h @@ -1,881 +1,652 @@ #pragma once -namespace PPU_opcodes +#include "../../../Utilities/BitField.h" + +template using ppu_bf_t = bf_t; + +union ppu_opcode_t { - enum PPU_MainOpcodes - { - HACK = 0x01, //HLE Call - TDI = 0x02, //Trap Doubleword Immediate - TWI = 0x03, //Trap Word Immediate - G_04 = 0x04, - MULLI = 0x07, //Multiply Low Immediate - SUBFIC = 0x08, //Subtract from Immediate Carrying - //DOZI = 0x09, - CMPLI = 0x0a, //Compare Logical Immediate - CMPI = 0x0b, //Compare Immediate - ADDIC = 0x0c, //Add Immediate Carrying - ADDIC_ = 0x0d, //Add Immediate Carrying and Record - ADDI = 0x0e, //Add Immediate - ADDIS = 0x0f, //Add Immediate Shifted - BC = 0x10, //Branch Conditional - SC = 0x11, //System Call - B = 0x12, //Branch - G_13 = 0x13, - RLWIMI = 0x14, //Rotate Left Word Immediate then Mask Insert - RLWINM = 0x15, //Rotate Left Word Immediate then AND with Mask - RLWNM = 0x17, //Rotate Left Word then AND with Mask - ORI = 0x18, //OR Immediate - ORIS = 0x19, //OR Immediate Shifted - XORI = 0x1a, //XOR Immediate - XORIS = 0x1b, //XOR Immediate Shifted - ANDI_ = 0x1c, //AND Immediate - ANDIS_ = 0x1d, //AND Immediate Shifted - G_1e = 0x1e, - G_1f = 0x1f, - LWZ = 0x20, //Load Word and Zero Indexed - LWZU = 0x21, //Load Word and Zero with Update Indexed - LBZ = 0x22, //Load Byte and Zero - LBZU = 0x23, //Load Byte and Zero with Update - STW = 0x24, //Store Word - STWU = 0x25, //Store Word with Update - STB = 0x26, //Store Byte - STBU = 0x27, //Store Byte with Update - LHZ = 0x28, //Load Halfword and Zero - LHZU = 0x29, //Load Halfword and Zero with Update - LHA = 0x2a, //Load Halfword Algebraic with Update - LHAU = 0x2b, //Load Halfword Algebraic - STH = 0x2c, //Store Halfword - STHU = 0x2d, //Store Halfword with Update - LMW = 0x2e, //Load Multiple Word - STMW = 0x2f, //Store Multiple Word - LFS = 0x30, //Load Floating-Point Single - LFSU = 0x31, //Load Floating-Point Single with Update - LFD = 0x32, //Load Floating-Point Double - LFDU = 0x33, //Load Floating-Point Double with Update - STFS = 0x34, //Store Floating-Point Single - STFSU = 0x35, //Store Floating-Point Single with Update - STFD = 0x36, //Store Floating-Point Double - STFDU = 0x37, //Store Floating-Point Double with Update - LFQ = 0x38, // - LFQU = 0x39, // - G_3a = 0x3a, - G_3b = 0x3b, - G_3e = 0x3e, - G_3f = 0x3f, - }; + u32 opcode; - enum G_04Opcodes - { - VADDUBM = 0x0, - VMAXUB = 0x2, - VRLB = 0x4, - VCMPEQUB = 0x6, - VMULOUB = 0x8, - VADDFP = 0xa, - VMRGHB = 0xc, - VPKUHUM = 0xe, - VADDUHM = 0x40, - VMAXUH = 0x42, - VRLH = 0x44, - VCMPEQUH = 0x46, - VMULOUH = 0x48, - VSUBFP = 0x4a, - VMRGHH = 0x4c, - VPKUWUM = 0x4e, - VADDUWM = 0x80, - VMAXUW = 0x82, - VRLW = 0x84, - VCMPEQUW = 0x86, - VMRGHW = 0x8c, - VPKUHUS = 0x8e, - VCMPEQFP = 0xc6, - VPKUWUS = 0xce, - VMAXSB = 0x102, - VSLB = 0x104, - VMULOSB = 0x108, - VREFP = 0x10a, - VMRGLB = 0x10c, - VPKSHUS = 0x10e, - VMAXSH = 0x142, - VSLH = 0x144, - VMULOSH = 0x148, - VRSQRTEFP = 0x14a, - VMRGLH = 0x14c, - VPKSWUS = 0x14e, - VADDCUW = 0x180, - VMAXSW = 0x182, - VSLW = 0x184, - VEXPTEFP = 0x18a, - VMRGLW = 0x18c, - VPKSHSS = 0x18e, - VSL = 0x1c4, - VCMPGEFP = 0x1c6, - VLOGEFP = 0x1ca, - VPKSWSS = 0x1ce, - VADDUBS = 0x200, - VMINUB = 0x202, - VSRB = 0x204, - VCMPGTUB = 0x206, - VMULEUB = 0x208, - VRFIN = 0x20a, - VSPLTB = 0x20c, - VUPKHSB = 0x20e, - VADDUHS = 0x240, - VMINUH = 0x242, - VSRH = 0x244, - VCMPGTUH = 0x246, - VMULEUH = 0x248, - VRFIZ = 0x24a, - VSPLTH = 0x24c, - VUPKHSH = 0x24e, - VADDUWS = 0x280, - VMINUW = 0x282, - VSRW = 0x284, - VCMPGTUW = 0x286, - VRFIP = 0x28a, - VSPLTW = 0x28c, - VUPKLSB = 0x28e, - VSR = 0x2c4, - VCMPGTFP = 0x2c6, - VRFIM = 0x2ca, - VUPKLSH = 0x2ce, - VADDSBS = 0x300, - VMINSB = 0x302, - VSRAB = 0x304, - VCMPGTSB = 0x306, - VMULESB = 0x308, - VCFUX = 0x30a, - VSPLTISB = 0x30c, - VPKPX = 0x30e, - VADDSHS = 0x340, - VMINSH = 0x342, - VSRAH = 0x344, - VCMPGTSH = 0x346, - VMULESH = 0x348, - VCFSX = 0x34a, - VSPLTISH = 0x34c, - VUPKHPX = 0x34e, - VADDSWS = 0x380, - VMINSW = 0x382, - VSRAW = 0x384, - VCMPGTSW = 0x386, - VCTUXS = 0x38a, - VSPLTISW = 0x38c, - VCMPBFP = 0x3c6, - VCTSXS = 0x3ca, - VUPKLPX = 0x3ce, - VSUBUBM = 0x400, - VAVGUB = 0x402, - VAND = 0x404, - VCMPEQUB_ = 0x406, - VMAXFP = 0x40a, - VSLO = 0x40c, - VSUBUHM = 0x440, - VAVGUH = 0x442, - VANDC = 0x444, - VCMPEQUH_ = 0x446, - VMINFP = 0x44a, - VSRO = 0x44c, - VSUBUWM = 0x480, - VAVGUW = 0x482, - VOR = 0x484, - VCMPEQUW_ = 0x486, - VXOR = 0x4c4, - VCMPEQFP_ = 0x4c6, - VAVGSB = 0x502, - VNOR = 0x504, - VAVGSH = 0x542, - VSUBCUW = 0x580, - VAVGSW = 0x582, - VCMPGEFP_ = 0x5c6, - VSUBUBS = 0x600, - MFVSCR = 0x604, - VCMPGTUB_ = 0x606, - VSUM4UBS = 0x608, - VSUBUHS = 0x640, - MTVSCR = 0x644, - VCMPGTUH_ = 0x646, - VSUM4SHS = 0x648, - VSUBUWS = 0x680, - VCMPGTUW_ = 0x686, - VSUM2SWS = 0x688, - VCMPGTFP_ = 0x6c6, - VSUBSBS = 0x700, - VCMPGTSB_ = 0x706, - VSUM4SBS = 0x708, - VSUBSHS = 0x740, - VCMPGTSH_ = 0x746, - VSUBSWS = 0x780, - VCMPGTSW_ = 0x786, - VSUMSWS = 0x788, - VCMPBFP_ = 0x7c6, - }; + ppu_bf_t main; // 0..5 + cf_t, ppu_bf_t> sh64; // 30 + 16..20 + cf_t, ppu_bf_t> mbe64; // 26 + 21..25 + ppu_bf_t vuimm; // 11..15 + ppu_bf_t vs; // 6..10 + ppu_bf_t vsh; // 22..25 + ppu_bf_t oe; // 21 + ppu_bf_t spr; // 11..20 + ppu_bf_t vc; // 21..25 + ppu_bf_t vb; // 16..20 + ppu_bf_t va; // 11..15 + ppu_bf_t vd; // 6..10 + ppu_bf_t lk; // 31 + ppu_bf_t aa; // 30 + ppu_bf_t rb; // 16..20 + ppu_bf_t ra; // 11..15 + ppu_bf_t rd; // 6..10 + ppu_bf_t uimm16; // 16..31 + ppu_bf_t l11; // 11 + ppu_bf_t rs; // 6..10 + ppu_bf_t simm16; // 16..31, signed + ppu_bf_t ds; // 16..29, signed + ppu_bf_t vsimm; // 11..15, signed + ppu_bf_t ll; // 6..31, signed + ppu_bf_t lev; // 20..26 + ppu_bf_t i; // 16..19 + ppu_bf_t crfs; // 11..13 + ppu_bf_t l10; // 10 + ppu_bf_t crfd; // 6..8 + ppu_bf_t crbb; // 16..20 + ppu_bf_t crba; // 11..15 + ppu_bf_t crbd; // 6..10 + ppu_bf_t rc; // 31 + ppu_bf_t me32; // 26..30 + ppu_bf_t mb32; // 21..25 + ppu_bf_t sh32; // 16..20 + ppu_bf_t bi; // 11..15 + ppu_bf_t bo; // 6..10 + ppu_bf_t bh; // 19..20 + ppu_bf_t frc; // 21..25 + ppu_bf_t frb; // 16..20 + ppu_bf_t fra; // 11..15 + ppu_bf_t frd; // 6..10 + ppu_bf_t crm; // 12..19 + ppu_bf_t frs; // 6..10 + ppu_bf_t flm; // 7..14 + ppu_bf_t l6; // 6 + ppu_bf_t l15; // 15 +}; - enum G_04_VA_Opcodes - { - VMHADDSHS = 0x20, - VMHRADDSHS = 0x21, - VMLADDUHM = 0x22, - VMSUMUBM = 0x24, - VMSUMMBM = 0x25, - VMSUMUHM = 0x26, - VMSUMUHS = 0x27, - VMSUMSHM = 0x28, - VMSUMSHS = 0x29, - VSEL = 0x2a, - VPERM = 0x2b, - VSLDOI = 0x2c, - VMADDFP = 0x2e, - VNMSUBFP = 0x2f, - }; - - enum G_13Opcodes //Field 21 - 30 - { - MCRF = 0x000, - BCLR = 0x010, - CRNOR = 0x021, - CRANDC = 0x081, - ISYNC = 0x096, - CRXOR = 0x0c1, - CRNAND = 0x0e1, - CRAND = 0x101, - CREQV = 0x121, - CRORC = 0x1a1, - CROR = 0x1c1, - BCCTR = 0x210, - }; - - enum G_1eOpcodes //Field 27 - 29 - { - RLDICL = 0x0, - RLDICR = 0x1, - RLDIC = 0x2, - RLDIMI = 0x3, - RLDC_LR = 0x4, - }; - - enum G_1fOpcodes //Field 21 - 30 - { - CMP = 0x000, - TW = 0x004, - LVSL = 0x006, //Load Vector for Shift Left - LVEBX = 0x007, //Load Vector Element Byte Indexed - SUBFC = 0x008, //Subtract from Carrying - MULHDU = 0x009, - ADDC = 0x00a, - MULHWU = 0x00b, - MFOCRF = 0x013, - LWARX = 0x014, - LDX = 0x015, - LWZX = 0x017, - SLW = 0x018, - CNTLZW = 0x01a, - SLD = 0x01b, - AND = 0x01c, - CMPL = 0x020, - LVSR = 0x026, //Load Vector for Shift Right - LVEHX = 0x027, //Load Vector Element Halfword Indexed - SUBF = 0x028, - LDUX = 0x035, //Load Doubleword with Update Indexed - DCBST = 0x036, //Data Cache Block Store - LWZUX = 0x037, - CNTLZD = 0x03a, - ANDC = 0x03c, - TD = 0x044, - LVEWX = 0x047, //Load Vector Element Word Indexed - MULHD = 0x049, - MULHW = 0x04b, - LDARX = 0x054, - DCBF = 0x056, //Data Cache Block Flush - LBZX = 0x057, - LVX = 0x067, //Load Vector Indexed - NEG = 0x068, - LBZUX = 0x077, - NOR = 0x07c, - STVEBX = 0x087, //Store Vector Element Byte Indexed - SUBFE = 0x088, //Subtract from Extended - ADDE = 0x08a, - MTOCRF = 0x090, - STDX = 0x095, - STWCX_ = 0x096, - STWX = 0x097, - STVEHX = 0x0a7, //Store Vector Element Halfword Indexed - STDUX = 0x0b5, - STWUX = 0x0b7, - STVEWX = 0x0c7, //Store Vector Element Word Indexed - SUBFZE = 0x0c8, - ADDZE = 0x0ca, - STDCX_ = 0x0d6, - STBX = 0x0d7, - STVX = 0x0e7, - SUBFME = 0x0e8, - MULLD = 0x0e9, - ADDME = 0x0ea, - MULLW = 0x0eb, - DCBTST = 0x0f6, //Data Cache Block Touch for Store - STBUX = 0x0f7, - DOZ = 0x108, - ADD = 0x10a, - DCBT = 0x116, //Data Cache Block Touch - LHZX = 0x117, - EQV = 0x11c, - ECIWX = 0x136, - LHZUX = 0x137, - XOR = 0x13c, - MFSPR = 0x153, - LWAX = 0x155, - DST = 0x156, //Data Stream Touch - LHAX = 0x157, - LVXL = 0x167, //Load Vector Indexed Last - MFTB = 0x173, - LWAUX = 0x175, - DSTST = 0x176, //Data Stream Touch for Store - LHAUX = 0x177, - STHX = 0x197, //Store Halfword Indexed - ORC = 0x19c, //OR with Complement - ECOWX = 0x1b6, - STHUX = 0x1b7, - OR = 0x1bc, - DIVDU = 0x1c9, - DIVWU = 0x1cb, - MTSPR = 0x1d3, - DCBI = 0x1d6, //Data Cache Block Invalidate - NAND = 0x1dc, - STVXL = 0x1e7, //Store Vector Indexed Last - DIVD = 0x1e9, - DIVW = 0x1eb, - LVLX = 0x207, //Load Vector Left Indexed - SUBFCO = 0x208, - ADDCO = 0x20a, - LDBRX = 0x214, - LSWX = 0x215, - LWBRX = 0x216, - LFSX = 0x217, - SRW = 0x218, - SRD = 0x21b, - LVRX = 0x227, //Load Vector Right Indexed - SUBFO = 0x228, - LFSUX = 0x237, - LSWI = 0x255, - SYNC = 0x256, - LFDX = 0x257, - NEGO = 0x268, - LFDUX = 0x277, - STVLX = 0x287, //Store Vector Left Indexed - SUBFEO = 0x288, - ADDEO = 0x28a, - STDBRX = 0x294, - STSWX = 0x295, - STWBRX = 0x296, - STFSX = 0x297, - STVRX = 0x2a7, //Store Vector Right Indexed - STFSUX = 0x2b7, - SUBFZEO= 0x2c8, - ADDZEO = 0x2ca, - STSWI = 0x2d5, - STFDX = 0x2d7, //Store Floating-Point Double Indexed - SUBFMEO= 0x2e8, - MULLDO = 0x2e9, - ADDMEO = 0x2ea, - MULLWO = 0x2eb, - STFDUX = 0x2f7, - LVLXL = 0x307, //Load Vector Left Indexed Last - ADDO = 0x30a, - LHBRX = 0x316, - SRAW = 0x318, - SRAD = 0x31a, - LVRXL = 0x327, //Load Vector Right Indexed Last - DSS = 0x336, //Data Stream Stop - SRAWI = 0x338, - SRADI1 = 0x33a, //sh_5 == 0 - SRADI2 = 0x33b, //sh_5 != 0 - EIEIO = 0x356, - STVLXL = 0x387, //Store Vector Left Indexed Last - STHBRX = 0x396, - EXTSH = 0x39a, - STVRXL = 0x3a7, //Store Vector Right Indexed Last - EXTSB = 0x3ba, - DIVDUO = 0x3c9, - DIVWUO = 0x3cb, - STFIWX = 0x3d7, - EXTSW = 0x3da, - ICBI = 0x3d6, //Instruction Cache Block Invalidate - DIVDO = 0x3e9, - DIVWO = 0x3eb, - DCBZ = 0x3f6, //Data Cache Block Set to Zero - }; - - enum G_3aOpcodes //Field 30 - 31 - { - LD = 0x0, - LDU = 0x1, - LWA = 0x2, - }; - - enum G_3bOpcodes //Field 26 - 30 - { - FDIVS = 0x12, - FSUBS = 0x14, - FADDS = 0x15, - FSQRTS = 0x16, - FRES = 0x18, - FMULS = 0x19, - FMSUBS = 0x1c, - FMADDS = 0x1d, - FNMSUBS = 0x1e, - FNMADDS = 0x1f, - }; - - enum G_3eOpcodes //Field 30 - 31 - { - STD = 0x0, - STDU = 0x1, - }; - - enum G_3fOpcodes //Field 21 - 30 - { - MTFSB1 = 0x026, - MCRFS = 0x040, - MTFSB0 = 0x046, - MTFSFI = 0x086, - MFFS = 0x247, - MTFSF = 0x2c7, - - FCMPU = 0x000, - FRSP = 0x00c, - FCTIW = 0x00e, - FCTIWZ = 0x00f, - FDIV = 0x012, - FSUB = 0x014, - FADD = 0x015, - FSQRT = 0x016, - FSEL = 0x017, - FMUL = 0x019, - FRSQRTE = 0x01a, - FMSUB = 0x01c, - FMADD = 0x01d, - FNMSUB = 0x01e, - FNMADD = 0x01f, - FCMPO = 0x020, - FNEG = 0x028, - FMR = 0x048, - FNABS = 0x088, - FABS = 0x108, - FCTID = 0x32e, - FCTIDZ = 0x32f, - FCFID = 0x34e, - }; +inline u32 ppu_branch_target(u32 pc, u32 imm) +{ + return pc + (imm & ~0x3u); } -class PPUOpcodes +inline u64 ppu_branch_target(u64 pc, u64 imm) { -public: - virtual ~PPUOpcodes() {} + return pc + (imm & ~0x3ull); +} - static u32 branchTarget(const u32 pc, const u32 imm) +inline u64 ppu_rotate_mask(u32 mb, u32 me) +{ + const u64 mask = ~0ull << (63 ^ (me - mb)); + return mask >> mb | mask << (64 - mb); // Rotate +} + +inline u32 ppu_decode(u32 inst) +{ + return (inst >> 26 | inst << (32 - 26)) & 0x1ffff; // Rotate + mask +} + +// PPU decoder object. D provides functions. T is function pointer type returned. +template +class ppu_decoder +{ + // Fast lookup table + std::array m_table; + + struct instruction_info { - return pc + (imm & ~0x3ULL); + u32 value; + T pointer; + u32 magn; // Non-zero for "columns" (effectively, number of most significant bits "eaten") + }; + + // Fill lookup table + void fill_table(u32 main_op, u32 count, u32 sh, std::initializer_list entries) + { + if (sh < 11) + { + for (const auto& v : entries) + { + for (u32 i = 0; i < 1u << (v.magn + (11 - sh - count)); i++) + { + for (u32 j = 0; j < 1u << sh; j++) + { + m_table.at((((((i << (count - v.magn)) | v.value) << sh) | j) << 6) | main_op) = v.pointer; + } + } + } + } + else + { + // Main table (special case) + for (const auto& v : entries) + { + for (u32 i = 0; i < 1u << 11; i++) + { + m_table.at(i << 6 | v.value) = v.pointer; + } + } + } } - virtual void NULL_OP() = 0; - virtual void NOP() = 0; +public: + ppu_decoder() + { + m_table.fill(&D::UNK); - virtual void TDI(u32 to, u32 ra, s32 simm16) = 0; - virtual void TWI(u32 to, u32 ra, s32 simm16) = 0; + // Main opcodes (field 0..5) + fill_table(0x00, 6, -1, + { + { 0x01, &D::HACK }, + { 0x02, &D::TDI }, + { 0x03, &D::TWI }, + { 0x07, &D::MULLI }, + { 0x08, &D::SUBFIC }, + { 0x0a, &D::CMPLI }, + { 0x0b, &D::CMPI }, + { 0x0c, &D::ADDIC }, + { 0x0d, &D::ADDIC }, + { 0x0e, &D::ADDI }, + { 0x0f, &D::ADDIS }, + { 0x10, &D::BC }, + { 0x11, &D::SC }, + { 0x12, &D::B }, + { 0x14, &D::RLWIMI }, + { 0x15, &D::RLWINM }, + { 0x17, &D::RLWNM }, + { 0x18, &D::ORI }, + { 0x19, &D::ORIS }, + { 0x1a, &D::XORI }, + { 0x1b, &D::XORIS }, + { 0x1c, &D::ANDI }, + { 0x1d, &D::ANDIS }, + { 0x20, &D::LWZ }, + { 0x21, &D::LWZU }, + { 0x22, &D::LBZ }, + { 0x23, &D::LBZU }, + { 0x24, &D::STW }, + { 0x25, &D::STWU }, + { 0x26, &D::STB }, + { 0x27, &D::STBU }, + { 0x28, &D::LHZ }, + { 0x29, &D::LHZU }, + { 0x2a, &D::LHA }, + { 0x2b, &D::LHAU }, + { 0x2c, &D::STH }, + { 0x2d, &D::STHU }, + { 0x2e, &D::LMW }, + { 0x2f, &D::STMW }, + { 0x30, &D::LFS }, + { 0x31, &D::LFSU }, + { 0x32, &D::LFD }, + { 0x33, &D::LFDU }, + { 0x34, &D::STFS }, + { 0x35, &D::STFSU }, + { 0x36, &D::STFD }, + { 0x37, &D::STFDU }, + }); - virtual void MFVSCR(u32 vd) = 0; - virtual void MTVSCR(u32 vb) = 0; - virtual void VADDCUW(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDFP(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDSBS(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDSHS(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDSWS(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDUBM(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDUBS(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDUHM(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDUHS(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDUWM(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDUWS(u32 vd, u32 va, u32 vb) = 0; - virtual void VAND(u32 vd, u32 va, u32 vb) = 0; - virtual void VANDC(u32 vd, u32 va, u32 vb) = 0; - virtual void VAVGSB(u32 vd, u32 va, u32 vb) = 0; - virtual void VAVGSH(u32 vd, u32 va, u32 vb) = 0; - virtual void VAVGSW(u32 vd, u32 va, u32 vb) = 0; - virtual void VAVGUB(u32 vd, u32 va, u32 vb) = 0; - virtual void VAVGUH(u32 vd, u32 va, u32 vb) = 0; - virtual void VAVGUW(u32 vd, u32 va, u32 vb) = 0; - virtual void VCFSX(u32 vd, u32 uimm5, u32 vb) = 0; - virtual void VCFUX(u32 vd, u32 uimm5, u32 vb) = 0; - virtual void VCMPBFP(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPBFP_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPEQFP(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPEQFP_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPEQUB(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPEQUB_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPEQUH(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPEQUH_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPEQUW(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPEQUW_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGEFP(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGEFP_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTFP(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTFP_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTSB(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTSB_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTSH(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTSH_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTSW(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTSW_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTUB(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTUB_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTUH(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTUH_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTUW(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTUW_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCTSXS(u32 vd, u32 uimm5, u32 vb) = 0; - virtual void VCTUXS(u32 vd, u32 uimm5, u32 vb) = 0; - virtual void VEXPTEFP(u32 vd, u32 vb) = 0; - virtual void VLOGEFP(u32 vd, u32 vb) = 0; - virtual void VMADDFP(u32 vd, u32 va, u32 vc, u32 vb) = 0; - virtual void VMAXFP(u32 vd, u32 va, u32 vb) = 0; - virtual void VMAXSB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMAXSH(u32 vd, u32 va, u32 vb) = 0; - virtual void VMAXSW(u32 vd, u32 va, u32 vb) = 0; - virtual void VMAXUB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMAXUH(u32 vd, u32 va, u32 vb) = 0; - virtual void VMAXUW(u32 vd, u32 va, u32 vb) = 0; - virtual void VMHADDSHS(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VMHRADDSHS(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VMINFP(u32 vd, u32 va, u32 vb) = 0; - virtual void VMINSB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMINSH(u32 vd, u32 va, u32 vb) = 0; - virtual void VMINSW(u32 vd, u32 va, u32 vb) = 0; - virtual void VMINUB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMINUH(u32 vd, u32 va, u32 vb) = 0; - virtual void VMINUW(u32 vd, u32 va, u32 vb) = 0; - virtual void VMLADDUHM(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VMRGHB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMRGHH(u32 vd, u32 va, u32 vb) = 0; - virtual void VMRGHW(u32 vd, u32 va, u32 vb) = 0; - virtual void VMRGLB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMRGLH(u32 vd, u32 va, u32 vb) = 0; - virtual void VMRGLW(u32 vd, u32 va, u32 vb) = 0; - virtual void VMSUMMBM(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VMSUMSHM(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VMSUMSHS(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VMSUMUBM(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VMSUMUHM(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VMSUMUHS(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VMULESB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMULESH(u32 vd, u32 va, u32 vb) = 0; - virtual void VMULEUB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMULEUH(u32 vd, u32 va, u32 vb) = 0; - virtual void VMULOSB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMULOSH(u32 vd, u32 va, u32 vb) = 0; - virtual void VMULOUB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMULOUH(u32 vd, u32 va, u32 vb) = 0; - virtual void VNMSUBFP(u32 vd, u32 va, u32 vc, u32 vb) = 0; - virtual void VNOR(u32 vd, u32 va, u32 vb) = 0; - virtual void VOR(u32 vd, u32 va, u32 vb) = 0; - virtual void VPERM(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VPKPX(u32 vd, u32 va, u32 vb) = 0; - virtual void VPKSHSS(u32 vd, u32 va, u32 vb) = 0; - virtual void VPKSHUS(u32 vd, u32 va, u32 vb) = 0; - virtual void VPKSWSS(u32 vd, u32 va, u32 vb) = 0; - virtual void VPKSWUS(u32 vd, u32 va, u32 vb) = 0; - virtual void VPKUHUM(u32 vd, u32 va, u32 vb) = 0; - virtual void VPKUHUS(u32 vd, u32 va, u32 vb) = 0; - virtual void VPKUWUM(u32 vd, u32 va, u32 vb) = 0; - virtual void VPKUWUS(u32 vd, u32 va, u32 vb) = 0; - virtual void VREFP(u32 vd, u32 vb) = 0; - virtual void VRFIM(u32 vd, u32 vb) = 0; - virtual void VRFIN(u32 vd, u32 vb) = 0; - virtual void VRFIP(u32 vd, u32 vb) = 0; - virtual void VRFIZ(u32 vd, u32 vb) = 0; - virtual void VRLB(u32 vd, u32 va, u32 vb) = 0; - virtual void VRLH(u32 vd, u32 va, u32 vb) = 0; - virtual void VRLW(u32 vd, u32 va, u32 vb) = 0; - virtual void VRSQRTEFP(u32 vd, u32 vb) = 0; - virtual void VSEL(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VSL(u32 vd, u32 va, u32 vb) = 0; - virtual void VSLB(u32 vd, u32 va, u32 vb) = 0; - virtual void VSLDOI(u32 vd, u32 va, u32 vb, u32 sh) = 0; - virtual void VSLH(u32 vd, u32 va, u32 vb) = 0; - virtual void VSLO(u32 vd, u32 va, u32 vb) = 0; - virtual void VSLW(u32 vd, u32 va, u32 vb) = 0; - virtual void VSPLTB(u32 vd, u32 uimm5, u32 vb) = 0; - virtual void VSPLTH(u32 vd, u32 uimm5, u32 vb) = 0; - virtual void VSPLTISB(u32 vd, s32 simm5) = 0; - virtual void VSPLTISH(u32 vd, s32 simm5) = 0; - virtual void VSPLTISW(u32 vd, s32 simm5) = 0; - virtual void VSPLTW(u32 vd, u32 uimm5, u32 vb) = 0; - virtual void VSR(u32 vd, u32 va, u32 vb) = 0; - virtual void VSRAB(u32 vd, u32 va, u32 vb) = 0; - virtual void VSRAH(u32 vd, u32 va, u32 vb) = 0; - virtual void VSRAW(u32 vd, u32 va, u32 vb) = 0; - virtual void VSRB(u32 vd, u32 va, u32 vb) = 0; - virtual void VSRH(u32 vd, u32 va, u32 vb) = 0; - virtual void VSRO(u32 vd, u32 va, u32 vb) = 0; - virtual void VSRW(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBCUW(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBFP(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBSBS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBSHS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBSWS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBUBM(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBUBS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBUHM(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBUHS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBUWM(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBUWS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUMSWS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUM2SWS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUM4SBS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUM4SHS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUM4UBS(u32 vd, u32 va, u32 vb) = 0; - virtual void VUPKHPX(u32 vd, u32 vb) = 0; - virtual void VUPKHSB(u32 vd, u32 vb) = 0; - virtual void VUPKHSH(u32 vd, u32 vb) = 0; - virtual void VUPKLPX(u32 vd, u32 vb) = 0; - virtual void VUPKLSB(u32 vd, u32 vb) = 0; - virtual void VUPKLSH(u32 vd, u32 vb) = 0; - virtual void VXOR(u32 vd, u32 va, u32 vb) = 0; - virtual void MULLI(u32 rd, u32 ra, s32 simm16) = 0; - virtual void SUBFIC(u32 rd, u32 ra, s32 simm16) = 0; - virtual void CMPLI(u32 bf, u32 l, u32 ra, u32 uimm16) = 0; - virtual void CMPI(u32 bf, u32 l, u32 ra, s32 simm16) = 0; - virtual void ADDIC(u32 rd, u32 ra, s32 simm16) = 0; - virtual void ADDIC_(u32 rd, u32 ra, s32 simm16) = 0; - virtual void ADDI(u32 rd, u32 ra, s32 simm16) = 0; - virtual void ADDIS(u32 rd, u32 ra, s32 simm16) = 0; - virtual void BC(u32 bo, u32 bi, s32 bd, u32 aa, u32 lk) = 0; - virtual void HACK(u32 index) = 0; - virtual void SC(u32 lev) = 0; - virtual void B(s32 ll, u32 aa, u32 lk) = 0; - virtual void MCRF(u32 crfd, u32 crfs) = 0; - virtual void BCLR(u32 bo, u32 bi, u32 bh, u32 lk) = 0; - virtual void CRNOR(u32 bt, u32 ba, u32 bb) = 0; - virtual void CRANDC(u32 bt, u32 ba, u32 bb) = 0; - virtual void ISYNC() = 0; - virtual void CRXOR(u32 bt, u32 ba, u32 bb) = 0; - virtual void CRNAND(u32 bt, u32 ba, u32 bb) = 0; - virtual void CRAND(u32 bt, u32 ba, u32 bb) = 0; - virtual void CREQV(u32 bt, u32 ba, u32 bb) = 0; - virtual void CRORC(u32 bt, u32 ba, u32 bb) = 0; - virtual void CROR(u32 bt, u32 ba, u32 bb) = 0; - virtual void BCCTR(u32 bo, u32 bi, u32 bh, u32 lk) = 0; - virtual void RLWIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) = 0; - virtual void RLWINM(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) = 0; - virtual void RLWNM(u32 ra, u32 rs, u32 rb, u32 MB, u32 ME, u32 rc) = 0; - virtual void ORI(u32 rs, u32 ra, u32 uimm16) = 0; - virtual void ORIS(u32 rs, u32 ra, u32 uimm16) = 0; - virtual void XORI(u32 ra, u32 rs, u32 uimm16) = 0; - virtual void XORIS(u32 ra, u32 rs, u32 uimm16) = 0; - virtual void ANDI_(u32 ra, u32 rs, u32 uimm16) = 0; - virtual void ANDIS_(u32 ra, u32 rs, u32 uimm16) = 0; - virtual void RLDICL(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) = 0; - virtual void RLDICR(u32 ra, u32 rs, u32 sh, u32 me, u32 rc) = 0; - virtual void RLDIC(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) = 0; - virtual void RLDIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) = 0; - virtual void RLDC_LR(u32 ra, u32 rs, u32 rb, u32 m_eb, u32 is_r, u32 rc) = 0; - virtual void CMP(u32 crfd, u32 l, u32 ra, u32 rb) = 0; - virtual void TW(u32 to, u32 ra, u32 rb) = 0; - virtual void LVSL(u32 vd, u32 ra, u32 rb) = 0; - virtual void LVEBX(u32 vd, u32 ra, u32 rb) = 0; - virtual void SUBFC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void MULHDU(u32 rd, u32 ra, u32 rb, u32 rc) = 0; - virtual void ADDC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void MULHWU(u32 rd, u32 ra, u32 rb, u32 rc) = 0; - virtual void MFOCRF(u32 a, u32 rd, u32 crm) = 0; - virtual void LWARX(u32 rd, u32 ra, u32 rb) = 0; - virtual void LDX(u32 ra, u32 rs, u32 rb) = 0; - virtual void LWZX(u32 rd, u32 ra, u32 rb) = 0; - virtual void SLW(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void CNTLZW(u32 ra, u32 rs, u32 rc) = 0; - virtual void SLD(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void AND(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void CMPL(u32 bf, u32 l, u32 ra, u32 rb) = 0; - virtual void LVSR(u32 vd, u32 ra, u32 rb) = 0; - virtual void LVEHX(u32 vd, u32 ra, u32 rb) = 0; - virtual void SUBF(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void LDUX(u32 rd, u32 ra, u32 rb) = 0; - virtual void DCBST(u32 ra, u32 rb) = 0; - virtual void LWZUX(u32 rd, u32 ra, u32 rb) = 0; - virtual void CNTLZD(u32 ra, u32 rs, u32 rc) = 0; - virtual void ANDC(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void TD(u32 to, u32 ra, u32 rb) = 0; - virtual void LVEWX(u32 vd, u32 ra, u32 rb) = 0; - virtual void MULHD(u32 rd, u32 ra, u32 rb, u32 rc) = 0; - virtual void MULHW(u32 rd, u32 ra, u32 rb, u32 rc) = 0; - virtual void LDARX(u32 rd, u32 ra, u32 rb) = 0; - virtual void DCBF(u32 ra, u32 rb) = 0; - virtual void LBZX(u32 rd, u32 ra, u32 rb) = 0; - virtual void LVX(u32 vd, u32 ra, u32 rb) = 0; - virtual void NEG(u32 rd, u32 ra, u32 oe, u32 rc) = 0; - virtual void LBZUX(u32 rd, u32 ra, u32 rb) = 0; - virtual void NOR(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void STVEBX(u32 vs, u32 ra, u32 rb) = 0; - virtual void SUBFE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void ADDE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void MTOCRF(u32 l, u32 crm, u32 rs) = 0; - virtual void STDX(u32 rs, u32 ra, u32 rb) = 0; - virtual void STWCX_(u32 rs, u32 ra, u32 rb) = 0; - virtual void STWX(u32 rs, u32 ra, u32 rb) = 0; - virtual void STVEHX(u32 vs, u32 ra, u32 rb) = 0; - virtual void STDUX(u32 rs, u32 ra, u32 rb) = 0; - virtual void STWUX(u32 rs, u32 ra, u32 rb) = 0; - virtual void STVEWX(u32 vs, u32 ra, u32 rb) = 0; - virtual void SUBFZE(u32 rd, u32 ra, u32 oe, u32 rc) = 0; - virtual void ADDZE(u32 rd, u32 ra, u32 oe, u32 rc) = 0; - virtual void STDCX_(u32 rs, u32 ra, u32 rb) = 0; - virtual void STBX(u32 rs, u32 ra, u32 rb) = 0; - virtual void STVX(u32 vs, u32 ra, u32 rb) = 0; - virtual void MULLD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void SUBFME(u32 rd, u32 ra, u32 oe, u32 rc) = 0; - virtual void ADDME(u32 rd, u32 ra, u32 oe, u32 rc) = 0; - virtual void MULLW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void DCBTST(u32 ra, u32 rb, u32 th) = 0; - virtual void STBUX(u32 rs, u32 ra, u32 rb) = 0; - virtual void ADD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void DCBT(u32 ra, u32 rb, u32 th) = 0; - virtual void LHZX(u32 rd, u32 ra, u32 rb) = 0; - virtual void EQV(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void ECIWX(u32 rd, u32 ra, u32 rb) = 0; - virtual void LHZUX(u32 rd, u32 ra, u32 rb) = 0; - virtual void XOR(u32 rs, u32 ra, u32 rb, u32 rc) = 0; - virtual void MFSPR(u32 rd, u32 spr) = 0; - virtual void LWAX(u32 rd, u32 ra, u32 rb) = 0; - virtual void DST(u32 ra, u32 rb, u32 strm, u32 t) = 0; - virtual void LHAX(u32 rd, u32 ra, u32 rb) = 0; - virtual void LVXL(u32 vd, u32 ra, u32 rb) = 0; - virtual void MFTB(u32 rd, u32 spr) = 0; - virtual void LWAUX(u32 rd, u32 ra, u32 rb) = 0; - virtual void DSTST(u32 ra, u32 rb, u32 strm, u32 t) = 0; - virtual void LHAUX(u32 rd, u32 ra, u32 rb) = 0; - virtual void STHX(u32 rs, u32 ra, u32 rb) = 0; - virtual void ORC(u32 rs, u32 ra, u32 rb, u32 rc) = 0; - virtual void ECOWX(u32 rs, u32 ra, u32 rb) = 0; - virtual void STHUX(u32 rs, u32 ra, u32 rb) = 0; - virtual void OR(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void DIVDU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void DIVWU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void MTSPR(u32 spr, u32 rs) = 0; - virtual void DCBI(u32 ra, u32 rb) = 0; - virtual void NAND(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void STVXL(u32 vs, u32 ra, u32 rb) = 0; - virtual void DIVD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void DIVW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void LVLX(u32 vd, u32 ra, u32 rb) = 0; - virtual void LDBRX(u32 rd, u32 ra, u32 rb) = 0; - virtual void LSWX(u32 rd, u32 ra, u32 rb) = 0; - virtual void LWBRX(u32 rd, u32 ra, u32 rb) = 0; - virtual void LFSX(u32 frd, u32 ra, u32 rb) = 0; - virtual void SRW(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void SRD(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void LVRX(u32 vd, u32 ra, u32 rb) = 0; - virtual void LSWI(u32 rd, u32 ra, u32 nb) = 0; - virtual void LFSUX(u32 frd, u32 ra, u32 rb) = 0; - virtual void SYNC(u32 l) = 0; - virtual void LFDX(u32 frd, u32 ra, u32 rb) = 0; - virtual void LFDUX(u32 frd, u32 ra, u32 rb) = 0; - virtual void STVLX(u32 vs, u32 ra, u32 rb) = 0; - virtual void STDBRX(u32 rs, u32 ra, u32 rb) = 0; - virtual void STSWX(u32 rs, u32 ra, u32 rb) = 0; - virtual void STWBRX(u32 rs, u32 ra, u32 rb) = 0; - virtual void STFSX(u32 frs, u32 ra, u32 rb) = 0; - virtual void STVRX(u32 vs, u32 ra, u32 rb) = 0; - virtual void STFSUX(u32 frs, u32 ra, u32 rb) = 0; - virtual void STSWI(u32 rd, u32 ra, u32 nb) = 0; - virtual void STFDX(u32 frs, u32 ra, u32 rb) = 0; - virtual void STFDUX(u32 frs, u32 ra, u32 rb) = 0; - virtual void LVLXL(u32 vd, u32 ra, u32 rb) = 0; - virtual void LHBRX(u32 rd, u32 ra, u32 rb) = 0; - virtual void SRAW(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void SRAD(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void LVRXL(u32 vd, u32 ra, u32 rb) = 0; - virtual void DSS(u32 strm, u32 a) = 0; - virtual void SRAWI(u32 ra, u32 rs, u32 sh, u32 rc) = 0; - virtual void SRADI1(u32 ra, u32 rs, u32 sh, u32 rc) = 0; - virtual void SRADI2(u32 ra, u32 rs, u32 sh, u32 rc) = 0; - virtual void EIEIO() = 0; - virtual void STVLXL(u32 vs, u32 ra, u32 rb) = 0; - virtual void STHBRX(u32 rs, u32 ra, u32 rb) = 0; - virtual void EXTSH(u32 ra, u32 rs, u32 rc) = 0; - virtual void STVRXL(u32 sd, u32 ra, u32 rb) = 0; - virtual void EXTSB(u32 ra, u32 rs, u32 rc) = 0; - virtual void STFIWX(u32 frs, u32 ra, u32 rb) = 0; - virtual void EXTSW(u32 ra, u32 rs, u32 rc) = 0; - virtual void ICBI(u32 ra, u32 rb) = 0; - virtual void DCBZ(u32 ra, u32 rb) = 0; - virtual void LWZ(u32 rd, u32 ra, s32 d) = 0; - virtual void LWZU(u32 rd, u32 ra, s32 d) = 0; - virtual void LBZ(u32 rd, u32 ra, s32 d) = 0; - virtual void LBZU(u32 rd, u32 ra, s32 d) = 0; - virtual void STW(u32 rs, u32 ra, s32 d) = 0; - virtual void STWU(u32 rs, u32 ra, s32 d) = 0; - virtual void STB(u32 rs, u32 ra, s32 d) = 0; - virtual void STBU(u32 rs, u32 ra, s32 d) = 0; - virtual void LHZ(u32 rd, u32 ra, s32 d) = 0; - virtual void LHZU(u32 rd, u32 ra, s32 d) = 0; - virtual void LHA(u32 rs, u32 ra, s32 d) = 0; - virtual void LHAU(u32 rs, u32 ra, s32 d) = 0; - virtual void STH(u32 rs, u32 ra, s32 d) = 0; - virtual void STHU(u32 rs, u32 ra, s32 d) = 0; - virtual void LMW(u32 rd, u32 ra, s32 d) = 0; - virtual void STMW(u32 rs, u32 ra, s32 d) = 0; - virtual void LFS(u32 frd, u32 ra, s32 d) = 0; - virtual void LFSU(u32 frd, u32 ra, s32 d) = 0; - virtual void LFD(u32 frd, u32 ra, s32 d) = 0; - virtual void LFDU(u32 frd, u32 ra, s32 d) = 0; - virtual void STFS(u32 frs, u32 ra, s32 d) = 0; - virtual void STFSU(u32 frs, u32 ra, s32 d) = 0; - virtual void STFD(u32 frs, u32 ra, s32 d) = 0; - virtual void STFDU(u32 frs, u32 ra, s32 d) = 0; - virtual void LD(u32 rd, u32 ra, s32 ds) = 0; - virtual void LDU(u32 rd, u32 ra, s32 ds) = 0; - virtual void LWA(u32 rd, u32 ra, s32 ds) = 0; - virtual void FDIVS(u32 frd, u32 fra, u32 frb, u32 rc) = 0; - virtual void FSUBS(u32 frd, u32 fra, u32 frb, u32 rc) = 0; - virtual void FADDS(u32 frd, u32 fra, u32 frb, u32 rc) = 0; - virtual void FSQRTS(u32 frd, u32 frb, u32 rc) = 0; - virtual void FRES(u32 frd, u32 frb, u32 rc) = 0; - virtual void FMULS(u32 frd, u32 fra, u32 frc, u32 rc) = 0; - virtual void FMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) = 0; - virtual void FMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) = 0; - virtual void FNMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) = 0; - virtual void FNMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) = 0; - virtual void STD(u32 rs, u32 ra, s32 ds) = 0; - virtual void STDU(u32 rs, u32 ra, s32 ds) = 0; - virtual void MTFSB1(u32 bt, u32 rc) = 0; - virtual void MCRFS(u32 bf, u32 bfa) = 0; - virtual void MTFSB0(u32 bt, u32 rc) = 0; - virtual void MTFSFI(u32 crfd, u32 i, u32 rc) = 0; - virtual void MFFS(u32 frd, u32 rc) = 0; - virtual void MTFSF(u32 flm, u32 frb, u32 rc) = 0; + // Group 0x04 opcodes (field 21..31) + fill_table(0x04, 11, 0, + { + { 0x0, &D::VADDUBM }, + { 0x2, &D::VMAXUB }, + { 0x4, &D::VRLB }, + { 0x6, &D::VCMPEQUB, 1 }, + { 0x8, &D::VMULOUB }, + { 0xa, &D::VADDFP }, + { 0xc, &D::VMRGHB }, + { 0xe, &D::VPKUHUM }, - virtual void FCMPU(u32 bf, u32 fra, u32 frb) = 0; - virtual void FRSP(u32 frd, u32 frb, u32 rc) = 0; - virtual void FCTIW(u32 frd, u32 frb, u32 rc) = 0; - virtual void FCTIWZ(u32 frd, u32 frb, u32 rc) = 0; - virtual void FDIV(u32 frd, u32 fra, u32 frb, u32 rc) = 0; - virtual void FSUB(u32 frd, u32 fra, u32 frb, u32 rc) = 0; - virtual void FADD(u32 frd, u32 fra, u32 frb, u32 rc) = 0; - virtual void FSQRT(u32 frd, u32 frb, u32 rc) = 0; - virtual void FSEL(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) = 0; - virtual void FMUL(u32 frd, u32 fra, u32 frc, u32 rc) = 0; - virtual void FRSQRTE(u32 frd, u32 frb, u32 rc) = 0; - virtual void FMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) = 0; - virtual void FMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) = 0; - virtual void FNMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) = 0; - virtual void FNMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) = 0; - virtual void FCMPO(u32 crfd, u32 fra, u32 frb) = 0; - virtual void FNEG(u32 frd, u32 frb, u32 rc) = 0; - virtual void FMR(u32 frd, u32 frb, u32 rc) = 0; - virtual void FNABS(u32 frd, u32 frb, u32 rc) = 0; - virtual void FABS(u32 frd, u32 frb, u32 rc) = 0; - virtual void FCTID(u32 frd, u32 frb, u32 rc) = 0; - virtual void FCTIDZ(u32 frd, u32 frb, u32 rc) = 0; - virtual void FCFID(u32 frd, u32 frb, u32 rc) = 0; + { 0x20, &D::VMHADDSHS, 5 }, + { 0x21, &D::VMHRADDSHS, 5 }, + { 0x22, &D::VMLADDUHM, 5 }, + { 0x24, &D::VMSUMUBM, 5 }, + { 0x25, &D::VMSUMMBM, 5 }, + { 0x26, &D::VMSUMUHM, 5 }, + { 0x27, &D::VMSUMUHS, 5 }, + { 0x28, &D::VMSUMSHM, 5 }, + { 0x29, &D::VMSUMSHS, 5 }, + { 0x2a, &D::VSEL, 5 }, + { 0x2b, &D::VPERM, 5 }, + { 0x2c, &D::VSLDOI, 5 }, + { 0x2e, &D::VMADDFP, 5 }, + { 0x2f, &D::VNMSUBFP, 5 }, - virtual void UNK(const u32 code, const u32 opcode, const u32 gcode) = 0; + { 0x40, &D::VADDUHM }, + { 0x42, &D::VMAXUH }, + { 0x44, &D::VRLH }, + { 0x46, &D::VCMPEQUH, 1 }, + { 0x48, &D::VMULOUH }, + { 0x4a, &D::VSUBFP }, + { 0x4c, &D::VMRGHH }, + { 0x4e, &D::VPKUWUM }, + { 0x80, &D::VADDUWM }, + { 0x82, &D::VMAXUW }, + { 0x84, &D::VRLW }, + { 0x86, &D::VCMPEQUW, 1 }, + { 0x8c, &D::VMRGHW }, + { 0x8e, &D::VPKUHUS }, + { 0xc6, &D::VCMPEQFP, 1 }, + { 0xce, &D::VPKUWUS }, + + { 0x102, &D::VMAXSB }, + { 0x104, &D::VSLB }, + { 0x108, &D::VMULOSB }, + { 0x10a, &D::VREFP }, + { 0x10c, &D::VMRGLB }, + { 0x10e, &D::VPKSHUS }, + { 0x142, &D::VMAXSH }, + { 0x144, &D::VSLH }, + { 0x148, &D::VMULOSH }, + { 0x14a, &D::VRSQRTEFP }, + { 0x14c, &D::VMRGLH }, + { 0x14e, &D::VPKSWUS }, + { 0x180, &D::VADDCUW }, + { 0x182, &D::VMAXSW }, + { 0x184, &D::VSLW }, + { 0x18a, &D::VEXPTEFP }, + { 0x18c, &D::VMRGLW }, + { 0x18e, &D::VPKSHSS }, + { 0x1c4, &D::VSL }, + { 0x1c6, &D::VCMPGEFP, 1 }, + { 0x1ca, &D::VLOGEFP }, + { 0x1ce, &D::VPKSWSS }, + { 0x200, &D::VADDUBS }, + { 0x202, &D::VMINUB }, + { 0x204, &D::VSRB }, + { 0x206, &D::VCMPGTUB, 1 }, + { 0x208, &D::VMULEUB }, + { 0x20a, &D::VRFIN }, + { 0x20c, &D::VSPLTB }, + { 0x20e, &D::VUPKHSB }, + { 0x240, &D::VADDUHS }, + { 0x242, &D::VMINUH }, + { 0x244, &D::VSRH }, + { 0x246, &D::VCMPGTUH, 1 }, + { 0x248, &D::VMULEUH }, + { 0x24a, &D::VRFIZ }, + { 0x24c, &D::VSPLTH }, + { 0x24e, &D::VUPKHSH }, + { 0x280, &D::VADDUWS }, + { 0x282, &D::VMINUW }, + { 0x284, &D::VSRW }, + { 0x286, &D::VCMPGTUW, 1 }, + { 0x28a, &D::VRFIP }, + { 0x28c, &D::VSPLTW }, + { 0x28e, &D::VUPKLSB }, + { 0x2c4, &D::VSR }, + { 0x2c6, &D::VCMPGTFP, 1 }, + { 0x2ca, &D::VRFIM }, + { 0x2ce, &D::VUPKLSH }, + { 0x300, &D::VADDSBS }, + { 0x302, &D::VMINSB }, + { 0x304, &D::VSRAB }, + { 0x306, &D::VCMPGTSB, 1 }, + { 0x308, &D::VMULESB }, + { 0x30a, &D::VCFUX }, + { 0x30c, &D::VSPLTISB }, + { 0x30e, &D::VPKPX }, + { 0x340, &D::VADDSHS }, + { 0x342, &D::VMINSH }, + { 0x344, &D::VSRAH }, + { 0x346, &D::VCMPGTSH, 1 }, + { 0x348, &D::VMULESH }, + { 0x34a, &D::VCFSX }, + { 0x34c, &D::VSPLTISH }, + { 0x34e, &D::VUPKHPX }, + { 0x380, &D::VADDSWS }, + { 0x382, &D::VMINSW }, + { 0x384, &D::VSRAW }, + { 0x386, &D::VCMPGTSW, 1 }, + { 0x38a, &D::VCTUXS }, + { 0x38c, &D::VSPLTISW }, + { 0x3c6, &D::VCMPBFP, 1 }, + { 0x3ca, &D::VCTSXS }, + { 0x3ce, &D::VUPKLPX }, + { 0x400, &D::VSUBUBM }, + { 0x402, &D::VAVGUB }, + { 0x404, &D::VAND }, + { 0x40a, &D::VMAXFP }, + { 0x40c, &D::VSLO }, + { 0x440, &D::VSUBUHM }, + { 0x442, &D::VAVGUH }, + { 0x444, &D::VANDC }, + { 0x44a, &D::VMINFP }, + { 0x44c, &D::VSRO }, + { 0x480, &D::VSUBUWM }, + { 0x482, &D::VAVGUW }, + { 0x484, &D::VOR }, + { 0x4c4, &D::VXOR }, + { 0x502, &D::VAVGSB }, + { 0x504, &D::VNOR }, + { 0x542, &D::VAVGSH }, + { 0x580, &D::VSUBCUW }, + { 0x582, &D::VAVGSW }, + { 0x600, &D::VSUBUBS }, + { 0x604, &D::MFVSCR }, + { 0x608, &D::VSUM4UBS }, + { 0x640, &D::VSUBUHS }, + { 0x644, &D::MTVSCR }, + { 0x648, &D::VSUM4SHS }, + { 0x680, &D::VSUBUWS }, + { 0x688, &D::VSUM2SWS }, + { 0x700, &D::VSUBSBS }, + { 0x708, &D::VSUM4SBS }, + { 0x740, &D::VSUBSHS }, + { 0x780, &D::VSUBSWS }, + { 0x788, &D::VSUMSWS }, + }); + + // Group 0x13 opcodes (field 21..30) + fill_table(0x13, 10, 1, + { + { 0x000, &D::MCRF }, + { 0x010, &D::BCLR }, + { 0x021, &D::CRNOR }, + { 0x081, &D::CRANDC }, + { 0x096, &D::ISYNC }, + { 0x0c1, &D::CRXOR }, + { 0x0e1, &D::CRNAND }, + { 0x101, &D::CRAND }, + { 0x121, &D::CREQV }, + { 0x1a1, &D::CRORC }, + { 0x1c1, &D::CROR }, + { 0x210, &D::BCCTR }, + }); + + // Group 0x1e opcodes (field 27..30) + fill_table(0x1e, 4, 1, + { + { 0x0, &D::RLDICL }, + { 0x1, &D::RLDICL }, + { 0x2, &D::RLDICR }, + { 0x3, &D::RLDICR }, + { 0x4, &D::RLDIC }, + { 0x5, &D::RLDIC }, + { 0x6, &D::RLDIMI }, + { 0x7, &D::RLDIMI }, + { 0x8, &D::RLDCL }, + { 0x9, &D::RLDCR }, + }); + + // Group 0x1f opcodes (field 21..30) + fill_table(0x1f, 10, 1, + { + { 0x000, &D::CMP }, + { 0x004, &D::TW }, + { 0x006, &D::LVSL }, + { 0x007, &D::LVEBX }, + { 0x008, &D::SUBFC, 1 }, + { 0x009, &D::MULHDU }, + { 0x00a, &D::ADDC, 1 }, + { 0x00b, &D::MULHWU }, + { 0x013, &D::MFOCRF }, + { 0x014, &D::LWARX }, + { 0x015, &D::LDX }, + { 0x017, &D::LWZX }, + { 0x018, &D::SLW }, + { 0x01a, &D::CNTLZW }, + { 0x01b, &D::SLD }, + { 0x01c, &D::AND }, + { 0x020, &D::CMPL }, + { 0x026, &D::LVSR }, + { 0x027, &D::LVEHX }, + { 0x028, &D::SUBF, 1 }, + { 0x035, &D::LDUX }, + { 0x036, &D::DCBST }, + { 0x037, &D::LWZUX }, + { 0x03a, &D::CNTLZD }, + { 0x03c, &D::ANDC }, + { 0x044, &D::TD }, + { 0x047, &D::LVEWX }, + { 0x049, &D::MULHD }, + { 0x04b, &D::MULHW }, + { 0x054, &D::LDARX }, + { 0x056, &D::DCBF }, + { 0x057, &D::LBZX }, + { 0x067, &D::LVX }, + { 0x068, &D::NEG, 1 }, + { 0x077, &D::LBZUX }, + { 0x07c, &D::NOR }, + { 0x087, &D::STVEBX }, + { 0x088, &D::SUBFE, 1 }, + { 0x08a, &D::ADDE, 1 }, + { 0x090, &D::MTOCRF }, + { 0x095, &D::STDX }, + { 0x096, &D::STWCX }, + { 0x097, &D::STWX }, + { 0x0a7, &D::STVEHX }, + { 0x0b5, &D::STDUX }, + { 0x0b7, &D::STWUX }, + { 0x0c7, &D::STVEWX }, + { 0x0c8, &D::SUBFZE, 1 }, + { 0x0ca, &D::ADDZE, 1 }, + { 0x0d6, &D::STDCX }, + { 0x0d7, &D::STBX }, + { 0x0e7, &D::STVX }, + { 0x0e8, &D::SUBFME, 1 }, + { 0x0e9, &D::MULLD, 1 }, + { 0x0ea, &D::ADDME, 1 }, + { 0x0eb, &D::MULLW, 1 }, + { 0x0f6, &D::DCBTST }, + { 0x0f7, &D::STBUX }, + { 0x10a, &D::ADD, 1 }, + { 0x116, &D::DCBT }, + { 0x117, &D::LHZX }, + { 0x11c, &D::EQV }, + { 0x136, &D::ECIWX }, + { 0x137, &D::LHZUX }, + { 0x13c, &D::XOR }, + { 0x153, &D::MFSPR }, + { 0x155, &D::LWAX }, + { 0x156, &D::DST }, + { 0x157, &D::LHAX }, + { 0x167, &D::LVXL }, + { 0x173, &D::MFTB }, + { 0x175, &D::LWAUX }, + { 0x176, &D::DSTST }, + { 0x177, &D::LHAUX }, + { 0x197, &D::STHX }, + { 0x19c, &D::ORC }, + { 0x1b6, &D::ECOWX }, + { 0x1b7, &D::STHUX }, + { 0x1bc, &D::OR }, + { 0x1c9, &D::DIVDU, 1 }, + { 0x1cb, &D::DIVWU, 1 }, + { 0x1d3, &D::MTSPR }, + { 0x1d6, &D::DCBI }, + { 0x1dc, &D::NAND }, + { 0x1e7, &D::STVXL }, + { 0x1e9, &D::DIVD, 1 }, + { 0x1eb, &D::DIVW, 1 }, + { 0x207, &D::LVLX }, + { 0x214, &D::LDBRX }, + { 0x215, &D::LSWX }, + { 0x216, &D::LWBRX }, + { 0x217, &D::LFSX }, + { 0x218, &D::SRW }, + { 0x21b, &D::SRD }, + { 0x227, &D::LVRX }, + { 0x237, &D::LFSUX }, + { 0x255, &D::LSWI }, + { 0x256, &D::SYNC }, + { 0x257, &D::LFDX }, + { 0x277, &D::LFDUX }, + { 0x287, &D::STVLX }, + { 0x294, &D::STDBRX }, + { 0x295, &D::STSWX }, + { 0x296, &D::STWBRX }, + { 0x297, &D::STFSX }, + { 0x2a7, &D::STVRX }, + { 0x2b7, &D::STFSUX }, + { 0x2d5, &D::STSWI }, + { 0x2d7, &D::STFDX }, + { 0x2f7, &D::STFDUX }, + { 0x307, &D::LVLXL }, + { 0x316, &D::LHBRX }, + { 0x318, &D::SRAW }, + { 0x31a, &D::SRAD }, + { 0x327, &D::LVRXL }, + { 0x336, &D::DSS }, + { 0x338, &D::SRAWI }, + { 0x33a, &D::SRADI }, + { 0x33b, &D::SRADI }, + { 0x356, &D::EIEIO }, + { 0x387, &D::STVLXL }, + { 0x396, &D::STHBRX }, + { 0x39a, &D::EXTSH }, + { 0x3a7, &D::STVRXL }, + { 0x3ba, &D::EXTSB }, + { 0x3d7, &D::STFIWX }, + { 0x3da, &D::EXTSW }, + { 0x3d6, &D::ICBI }, + { 0x3f6, &D::DCBZ }, + }); + + // Group 0x3a opcodes (field 30..31) + fill_table(0x3a, 2, 0, + { + { 0x0, &D::LD }, + { 0x1, &D::LDU }, + { 0x2, &D::LWA }, + }); + + // Group 0x3b opcodes (field 21..30) + fill_table(0x3b, 10, 1, + { + { 0x12, &D::FDIVS, 5 }, + { 0x14, &D::FSUBS, 5 }, + { 0x15, &D::FADDS, 5 }, + { 0x16, &D::FSQRTS, 5 }, + { 0x18, &D::FRES, 5 }, + { 0x19, &D::FMULS, 5 }, + { 0x1c, &D::FMSUBS, 5 }, + { 0x1d, &D::FMADDS, 5 }, + { 0x1e, &D::FNMSUBS, 5 }, + { 0x1f, &D::FNMADDS, 5 }, + }); + + // Group 0x3e opcodes (field 30..31) + fill_table(0x3e, 2, 0, + { + { 0x0, &D::STD }, + { 0x1, &D::STDU }, + }); + + // Group 0x3f opcodes (field 21..30) + fill_table(0x3f, 10, 1, + { + { 0x026, &D::MTFSB1 }, + { 0x040, &D::MCRFS }, + { 0x046, &D::MTFSB0 }, + { 0x086, &D::MTFSFI }, + { 0x247, &D::MFFS }, + { 0x2c7, &D::MTFSF }, + + { 0x000, &D::FCMPU }, + { 0x00c, &D::FRSP }, + { 0x00e, &D::FCTIW }, + { 0x00f, &D::FCTIWZ }, + + { 0x012, &D::FDIV, 5 }, + { 0x014, &D::FSUB, 5 }, + { 0x015, &D::FADD, 5 }, + { 0x016, &D::FSQRT, 5 }, + { 0x017, &D::FSEL, 5 }, + { 0x019, &D::FMUL, 5 }, + { 0x01a, &D::FRSQRTE, 5 }, + { 0x01c, &D::FMSUB, 5 }, + { 0x01d, &D::FMADD, 5 }, + { 0x01e, &D::FNMSUB, 5 }, + { 0x01f, &D::FNMADD, 5 }, + + { 0x020, &D::FCMPO }, + { 0x028, &D::FNEG }, + { 0x048, &D::FMR }, + { 0x088, &D::FNABS }, + { 0x108, &D::FABS }, + { 0x32e, &D::FCTID }, + { 0x32f, &D::FCTIDZ }, + { 0x34e, &D::FCFID }, + }); + } + + const std::array& get_table() const + { + return m_table; + } + + T decode(u32 inst) const + { + return m_table[ppu_decode(inst)]; + } }; + +namespace ppu_instructions +{ + namespace fields + { + enum + { + r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, + r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, + r22, r23, r24, r25, r26, r27, r28, r29, r30, r31, + }; + } + + using namespace fields; + + inline u32 ADDI(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x0eu << 26 }; op.rd = rt; op.ra = ra; op.simm16 = si; return op.opcode; } + inline u32 ADDIS(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x0fu << 26 }; op.rd = rt; op.ra = ra; op.simm16 = si; return op.opcode; } + inline u32 ORI(u32 rt, u32 ra, u32 ui) { ppu_opcode_t op{ 0x18u << 26 }; op.rd = rt; op.ra = ra; op.uimm16 = ui; return op.opcode; } + inline u32 ORIS(u32 rt, u32 ra, u32 ui) { ppu_opcode_t op{ 0x19u << 26 }; op.rd = rt; op.ra = ra; op.uimm16 = ui; return op.opcode; } + inline u32 OR(u32 ra, u32 rs, u32 rb, bool rc = false) { ppu_opcode_t op{ 0x1fu << 26 | 0x1bcu << 1 }; op.rs = rs; op.ra = ra; op.rb = rb; op.rc = rc; return op.opcode; } + inline u32 SC(u32 lev) { ppu_opcode_t op{ 0x11u << 26 }; op.lev = lev; return op.opcode; } + inline u32 B(s32 li, bool aa = false, bool lk = false) { ppu_opcode_t op{ 0x12u << 26 }; op.ll = li; op.aa = aa; op.lk = lk; return op.opcode; } + inline u32 BC(u32 bo, u32 bi, s32 bd, bool aa = false, bool lk = false) { ppu_opcode_t op{ 0x10u << 26 }; op.bo = bo; op.bi = bi; op.ds = bd / 4; op.aa = aa; op.lk = lk; return op.opcode; } + inline u32 BCLR(u32 bo, u32 bi, u32 bh, bool lk = false) { ppu_opcode_t op{ 0x13u << 26 | 0x10u << 1 }; op.bo = bo; op.bi = bi; op.bh = bh; op.lk = lk; return op.opcode; } + inline u32 BCCTR(u32 bo, u32 bi, u32 bh, bool lk = false) { ppu_opcode_t op{ 0x13u << 26 | 0x210u << 1 }; op.bo = bo; op.bi = bi; op.bh = bh; op.lk = lk; return op.opcode; } + inline u32 MFSPR(u32 rt, u32 spr) { ppu_opcode_t op{ 0x1fu << 26 | 0x153u << 1 }; op.rd = rt; op.spr = spr; return op.opcode; } + inline u32 MTSPR(u32 spr, u32 rs) { ppu_opcode_t op{ 0x1fu << 26 | 0x1d3u << 1 }; op.rs = rs; op.spr = spr; return op.opcode; } + inline u32 LWZ(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x20u << 26 }; op.rd = rt; op.ra = ra; op.simm16 = si; return op.opcode; } + inline u32 STD(u32 rs, u32 ra, s32 si) { ppu_opcode_t op{ 0x3eu << 26 }; op.rs = rs; op.ra = ra; op.ds = si / 4; return op.opcode; } + inline u32 STDU(u32 rs, u32 ra, s32 si) { ppu_opcode_t op{ 0x3eu << 26 | 1 }; op.rs = rs; op.ra = ra; op.ds = si / 4; return op.opcode; } + inline u32 LD(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x3au << 26 }; op.rd = rt; op.ra = ra; op.ds = si / 4; return op.opcode; } + inline u32 LDU(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x3au << 26 | 1 }; op.rd = rt; op.ra = ra; op.ds = si / 4; return op.opcode; } + //inline u32 CMPI(u32 bf, u32 l, u32 ra, u32 ui) { ppu_opcode_t op{ 0xbu << 26 }; op.crfd = bf; op.l10 = l; op.ra = ra; op.uimm16 = ui; return op.opcode; } + //inline u32 CMPLI(u32 bf, u32 l, u32 ra, u32 ui) { ppu_opcode_t op{ 0xau << 26 }; op.crfd = bf; op.l10 = l; op.ra = ra; op.uimm16 = ui; return op.opcode; } + inline u32 RLDICL(u32 ra, u32 rs, u32 sh, u32 mb, bool rc = false) { ppu_opcode_t op{ 30 << 26 }; op.ra = ra; op.rs = rs; op.sh64 = sh; op.mbe64 = mb; op.rc = rc; return op.opcode; } + + namespace implicts + { + inline u32 HACK(u32 index) { return 0x01 << 26 | index; } + inline u32 NOP() { return ORI(r0, r0, 0); } + inline u32 MR(u32 rt, u32 ra) { return OR(rt, ra, ra, false); } + inline u32 LI(u32 rt, u32 imm) { return ADDI(rt, r0, imm); } + inline u32 LIS(u32 rt, u32 imm) { return ADDIS(rt, r0, imm); } + + inline u32 BLR() { return BCLR(0x10 | 0x04, 0, 0); } + inline u32 BCTR() { return BCCTR(0x10 | 0x04, 0, 0); } + inline u32 BCTRL() { return BCCTR(0x10 | 0x04, 0, 0, true); } + inline u32 MFCTR(u32 reg) { return MFSPR(reg, 9 << 5); } + inline u32 MTCTR(u32 reg) { return MTSPR(9 << 5, reg); } + inline u32 MFLR(u32 reg) { return MFSPR(reg, 8 << 5); } + inline u32 MTLR(u32 reg) { return MTSPR(8 << 5, reg); } + + //inline u32 BNE(u32 cr, s32 imm) { return BC(4, 2 | cr << 2, imm); } + //inline u32 BEQ(u32 cr, s32 imm) { return BC(12, 2 | cr << 2, imm); } + //inline u32 BGT(u32 cr, s32 imm) { return BC(12, 1 | cr << 2, imm); } + //inline u32 BNE(s32 imm) { return BNE(cr0, imm); } + //inline u32 BEQ(s32 imm) { return BEQ(cr0, imm); } + //inline u32 BGT(s32 imm) { return BGT(cr0, imm); } + + //inline u32 CMPDI(u32 cr, u32 reg, u32 imm) { return CMPI(cr, 1, reg, imm); } + //inline u32 CMPDI(u32 reg, u32 imm) { return CMPDI(cr0, reg, imm); } + //inline u32 CMPWI(u32 cr, u32 reg, u32 imm) { return CMPI(cr, 0, reg, imm); } + //inline u32 CMPWI(u32 reg, u32 imm) { return CMPWI(cr0, reg, imm); } + //inline u32 CMPLDI(u32 cr, u32 reg, u32 imm) { return CMPLI(cr, 1, reg, imm); } + //inline u32 CMPLDI(u32 reg, u32 imm) { return CMPLDI(cr0, reg, imm); } + //inline u32 CMPLWI(u32 cr, u32 reg, u32 imm) { return CMPLI(cr, 0, reg, imm); } + //inline u32 CMPLWI(u32 reg, u32 imm) { return CMPLWI(cr0, reg, imm); } + + inline u32 EXTRDI(u32 x, u32 y, u32 n, u32 b) { return RLDICL(x, y, b + n, 64 - b, false); } + inline u32 SRDI(u32 x, u32 y, u32 n) { return RLDICL(x, y, 64 - n, n, false); } + inline u32 CLRLDI(u32 x, u32 y, u32 n) { return RLDICL(x, y, 0, n, false); } + } + + using namespace implicts; +} diff --git a/rpcs3/Emu/Cell/PPUProgramCompiler.cpp b/rpcs3/Emu/Cell/PPUProgramCompiler.cpp deleted file mode 100644 index 26480c2cdb..0000000000 --- a/rpcs3/Emu/Cell/PPUProgramCompiler.cpp +++ /dev/null @@ -1,1735 +0,0 @@ -#include "stdafx.h" -#include "stdafx_gui.h" -#include "PPUProgramCompiler.h" -/* -using namespace PPU_instr; - -template -InstrBase* GetInstruction(T* list, const std::string& str) -{ - for(int i=0; icount; ++i) - { - auto instr = list->get_instr_info(i); - - if(instr) - { - if(instr->GetName() == str) - { - return instr; - } - } - } - - return nullptr; -} - -template -InstrBase* GetInstruction(const std::string& str) -{ - if(auto res = GetInstruction(main_list, str)) return res; - if(auto res = GetInstruction(g04_list, str)) return res; - if(auto res = GetInstruction(g04_0_list, str)) return res; - if(auto res = GetInstruction(g13_list, str)) return res; - if(auto res = GetInstruction(g1e_list, str)) return res; - if(auto res = GetInstruction(g1f_list, str)) return res; - if(auto res = GetInstruction(g3a_list, str)) return res; - if(auto res = GetInstruction(g3b_list, str)) return res; - if(auto res = GetInstruction(g3e_list, str)) return res; - if(auto res = GetInstruction(g3f_list, str)) return res; - if(auto res = GetInstruction(g3f_0_list, str)) return res; - - return nullptr; -} - -s64 FindOp(const std::string& text, const std::string& op, s64 from) -{ - if (text.length() < op.length()) return -1; - - for (s64 i = from; i < (s64)text.length(); ++i) - { - if(i - 1 < 0 || text[(size_t)i - 1] == '\n' || CompilePPUProgram::IsSkip(text[(size_t)i - 1])) - { - if (text.length() - i < op.length()) return -1; - - if (text.substr(i, op.length()).compare(op) != 0) continue; - if (i + op.length() >= text.length() || text[(size_t) i + op.length()] == '\n' || - CompilePPUProgram::IsSkip(text[(size_t) i + op.length()])) return i; - } - } - - return -1; -} - -std::vector sections_list; -u32 section_name_offs = 0; -u32 section_offs = 0; - -SectionInfo::SectionInfo(const std::string& _name) -{ - name = _name; - memset(&shdr, 0, sizeof(Elf64_Shdr)); - - sections_list.push_back(this); - section_num = sections_list.size() - 1; - - shdr.sh_offset = section_offs; - shdr.sh_name = section_name_offs; - - section_name_offs += name.length() + 1; -} - -void SectionInfo::SetDataSize(u32 size, u32 addralign) -{ - if (addralign) shdr.sh_addralign = addralign; - if (shdr.sh_addralign) size = align(size, shdr.sh_addralign); - - if(!code.empty()) - { - for(u32 i=section_num + 1; ishdr.sh_offset -= code.size(); - } - - section_offs -= code.size(); - } - - code.resize(size); - - section_offs += size; - - for(u32 i=section_num + 1; ishdr.sh_offset += size; - } -} - -SectionInfo::~SectionInfo() -{ - sections_list.erase(sections_list.begin() + section_num); - - for(u32 i=section_num + 1; ishdr.sh_offset -= code.size(); - sections_list[i]->shdr.sh_name -= name.length(); - } - - section_offs -= code.size(); - section_name_offs -= name.length(); -} - -CompilePPUProgram::CompilePPUProgram( - const std::string& asm_, - const std::string& file_path, - wxTextCtrl* asm_list, - wxTextCtrl* hex_list, - wxTextCtrl* err_list, - bool analyze) - : m_asm(asm_) - , m_file_path(file_path) - , m_asm_list(asm_list) - , m_hex_list(hex_list) - , m_err_list(err_list) - , m_analyze(analyze) - , p(0) - , m_error(false) - , m_line(1) - , m_end_args(false) - , m_branch_pos(0) - , m_text_addr(0) -{ -} - -void CompilePPUProgram::WriteHex(const std::string& text) -{ - if(m_hex_list) - { - m_hex_list->WriteText(fmt::FromUTF8(text)); - } -} - -void CompilePPUProgram::WriteError(const std::string& error) -{ - if(m_err_list) - { - m_err_list->WriteText(fmt::FromUTF8(fmt::format("line %lld: %s\n", m_line, error.c_str()))); - } -} - -bool CompilePPUProgram::IsSkip(const char c) { return c == ' ' || c == '\t'; } -bool CompilePPUProgram::IsCommit(const char c) { return c == '#'; } -bool CompilePPUProgram::IsEnd() const { return p >= (s64)m_asm.length(); } -bool CompilePPUProgram::IsEndLn(const char c) const { return c == '\n' || p - 1 >= (s64)m_asm.length(); } - -char CompilePPUProgram::NextChar() { return *m_asm.substr(p++, 1).c_str(); } -void CompilePPUProgram::NextLn() { while( !IsEndLn(NextChar()) ) continue; if(!IsEnd()) m_line++; } -void CompilePPUProgram::EndLn() -{ - NextLn(); - p--; - m_line--; -} - -void CompilePPUProgram::FirstChar() -{ - p = 0; - m_line = 1; - m_branch_pos = 0; -} - -void CompilePPUProgram::PrevArg() -{ - while( --p >= 0 && (IsSkip(m_asm[(size_t)p]) || m_asm[(size_t)p] == ',')); - while( --p >= 0 && !IsSkip(m_asm[(size_t)p]) && !IsEndLn(m_asm[(size_t)p]) ); - if(IsEndLn(m_asm[(size_t)p])) p++; -} - -bool CompilePPUProgram::GetOp(std::string& result) -{ - s64 from = -1; - - for(;;) - { - const char cur_char = NextChar(); - - const bool skip = IsSkip(cur_char); - const bool commit = IsCommit(cur_char); - const bool endln = IsEndLn(cur_char); - - if(endln) p--; - - if(from == -1) - { - if(endln || commit) return false; - if(!skip) from = p - 1; - continue; - } - - if(skip || endln || commit) - { - const s64 to = (endln ? p : p - 1) - from; - result = m_asm.substr(from, to); - - return true; - } - } - - return false; -} - -int CompilePPUProgram::GetArg(std::string& result, bool func) -{ - s64 from = -1; - - for(char cur_char = NextChar(); !m_error; cur_char = NextChar()) - { - const bool skip = IsSkip(cur_char); - const bool commit = IsCommit(cur_char); - const bool endln = IsEndLn(cur_char); - const bool end = cur_char == ',' || (func && cur_char == ']'); - - if(endln) p--; - - if(from == -1) - { - if(endln || commit || end) return 0; - if(!skip) from = p - 1; - continue; - } - - const bool text = m_asm[(size_t)from] == '"'; - const bool end_text = cur_char == '"'; - - if((text ? end_text : (skip || commit || end)) || endln) - { - if(text && p > 2 && m_asm[(size_t)p - 2] == '\\' && (p <= 3 || m_asm[(size_t)p - 3] != '\\')) - { - continue; - } - - if(text && !end_text) - { - WriteError("'\"' not found."); - m_error = true; - } - - const s64 to = ((endln || text) ? p : p - 1) - from; - int ret = 1; - - if(skip || text) - { - for(char cur_char = NextChar(); !m_error; cur_char = NextChar()) - { - const bool skip = IsSkip(cur_char); - const bool commit = IsCommit(cur_char); - const bool endln = IsEndLn(cur_char); - const bool end = cur_char == ',' || (func && cur_char == ']'); - - if(skip) continue; - if(end) break; - - if(commit) - { - EndLn(); - ret = -1; - break; - } - - if(endln) - { - p--; - break; - } - - WriteError(fmt::format("Bad symbol '%c'", cur_char)); - m_error = true; - break; - } - } - - result = m_asm.substr(from, to); - - if(text) - { - for(u32 pos = 0; (s32)(pos = result.find('\\', pos)) != std::string::npos;) - { - if(pos + 1 < result.length() && result[pos + 1] == '\\') - { - pos += 2; - continue; - } - - const char v = result[pos + 1]; - switch(v) - { - case 'n': result = result.substr(0, pos) + '\n' + result.substr(pos + 2, result.length() - (pos + 2)); break; - case 'r': result = result.substr(0, pos) + '\r' + result.substr(pos + 2, result.length() - (pos + 2)); break; - case 't': result = result.substr(0, pos) + '\t' + result.substr(pos + 2, result.length() - (pos + 2)); break; - } - - pos++; - } - } - - return ret; - } - } - - return 0; -} - -bool CompilePPUProgram::CheckEnd(bool show_err) -{ - if(m_error) - { - NextLn(); - return false; - } - - while(true) - { - const char cur_char = NextChar(); - const bool skip = IsSkip(cur_char); - const bool commit = IsCommit(cur_char); - const bool endln = IsEndLn(cur_char); - - if(skip) continue; - - if(commit) - { - NextLn(); - return true; - } - - if(endln) - { - p--; - NextLn(); - return true; - } - - WriteError(fmt::format("Bad symbol '%c'", cur_char)); - NextLn(); - return false; - } - - return false; -} - -void CompilePPUProgram::DetectArgInfo(Arg& arg) -{ - const std::string str = arg.string; - - if(str.empty()) - { - arg.type = ARG_ERR; - return; - } - - if(GetInstruction(str)) - { - arg.type = ARG_INSTR; - return; - } - - if(str.length() > 1) - { - for(const Branch& branch : m_branches) - { - if(str != branch.m_name) - continue; - - arg.type = ARG_BRANCH; - arg.value = GetBranchValue(str); - return; - } - } - - switch((char)str[0]) - { - case 'r': case 'f': case 'v': - { - if(str.length() < 2) - { - arg.type = ARG_ERR; - return; - } - - if(str == "rtoc") - { - arg.type = ARG_REG_R; - arg.value = 2; - return; - } - - for(u32 i=1; i '9') - { - arg.type = ARG_ERR; - return; - } - } - - u32 reg = std::stoul(str.substr(1, str.length() - 1)); - - if(reg >= 32) - { - arg.type = ARG_ERR; - return; - } - - switch(str[0]) - { - case 'r': arg.type = ARG_REG_R; break; - case 'f': arg.type = ARG_REG_F; break; - case 'v': arg.type = ARG_REG_V; break; - default: arg.type = ARG_ERR; break; - } - - arg.value = reg; - } - return; - - case 'c': - if(str.length() > 2 && str[1] == 'r') - { - for(u32 i=2; i '9') - { - arg.type = ARG_ERR; - return; - } - } - - u32 reg; - sscanf(str.c_str(), "cr%d", ®); - - if(reg < 8) - { - arg.type = ARG_REG_CR; - arg.value = reg; - } - else - { - arg.type = ARG_ERR; - } - - return; - } - break; - - case '"': - if(str.length() < 2) - { - arg.type = ARG_ERR; - return; - } - - if(str[str.length() - 1] != '"') - { - arg.type = ARG_ERR; - return; - } - - arg.string = str.substr(1, str.length() - 2); - arg.type = ARG_TXT; - return; - } - - // Hex numbers - if(str.length() > 2 && str.substr(0, 2) == "0x") - { - for(u32 i=2; i= '0' && str[i] <= '9') || - (str[i] >= 'a' && str[i] <= 'f') || - (str[i] >= 'A' && str[i] <= 'F') - ) continue; - - arg.type = ARG_ERR; - return; - } - - arg.type = ARG_NUM16; - arg.value = std::stoul(str, nullptr, 16); - return; - } - - for(u32 i= str[0] == '-' ? 1 : 0; i '9') - { - arg.type = ARG_ERR; - return; - } - } - - arg.type = ARG_NUM; - arg.value = std::stoul(str); -} - -void CompilePPUProgram::LoadArgs() -{ - m_args.clear(); - m_cur_arg = 0; - - std::string str; - while(int r = GetArg(str)) - { - m_args.emplace_back(str); - DetectArgInfo(m_args[m_args.size() -1]); - - if(r == -1) - break; - } - - m_end_args = m_args.size() > 0; -} - -u32 CompilePPUProgram::GetBranchValue(const std::string& branch_name) const -{ - for(const Branch& branch : m_branches) - { - if(branch_name != branch.m_name) - continue; - - if(branch.m_pos >= 0) - return m_text_addr + branch.m_pos * 4; - - return branch.m_addr; - } - - return 0; -} - -bool CompilePPUProgram::SetNextArgType(u32 types, bool show_err) -{ - if(m_error) return false; - - if(m_cur_arg >= m_args.size()) - { - if(show_err) - { - WriteError(fmt::format("%d arg not found", m_cur_arg + 1)); - m_error = true; - } - - return false; - } - - const Arg& arg = m_args[m_cur_arg]; - - if(arg.type & types) - { - m_cur_arg++; - return true; - } - - if(show_err) - { - WriteError(fmt::format("Bad arg '%s'", arg.string.c_str())); - m_error = true; - } - - return false; -} - -bool CompilePPUProgram::SetNextArgBranch(u8 aa, bool show_err) -{ - const u32 pos = m_cur_arg; - const bool ret = SetNextArgType(ARG_BRANCH | ARG_IMM, show_err); - - if(!aa && pos < m_args.size()) - { - switch(m_args[pos].type) - { - case ARG_NUM: - m_args[pos].value += m_text_addr + m_branch_pos * 4; - break; - - case ARG_BRANCH: - m_args[pos].value -= m_text_addr + m_branch_pos * 4; - break; - } - } - - return ret; -} - -bool CompilePPUProgram::IsBranchOp(const std::string& op) -{ - return op.length() > 1 && op[op.length() - 1] == ':'; -} - -bool CompilePPUProgram::IsFuncOp(const std::string& op) -{ - return op.length() >= 1 && op[0] == '['; -} - -CompilePPUProgram::SP_TYPE CompilePPUProgram::GetSpType(const std::string& op) -{ - if (op.compare(".int") == 0) return SP_INT; - if (op.compare(".string") == 0) return SP_STRING; - if (op.compare(".strlen") == 0) return SP_STRLEN; - if (op.compare(".buf") == 0) return SP_BUF; - if (op.compare(".srl") == 0) return SP_SRL; - if (op.compare(".srr") == 0) return SP_SRR; - if (op.compare(".mul") == 0) return SP_MUL; - if (op.compare(".div") == 0) return SP_DIV; - if (op.compare(".add") == 0) return SP_ADD; - if (op.compare(".sub") == 0) return SP_SUB; - if (op.compare(".and") == 0) return SP_AND; - if (op.compare(".or") == 0) return SP_OR; - if (op.compare(".xor") == 0) return SP_XOR; - if (op.compare(".not") == 0) return SP_NOT; - if (op.compare(".nor") == 0) return SP_NOR; - - return SP_ERR; -} - -std::string CompilePPUProgram::GetSpStyle(const SP_TYPE sp) -{ - switch(sp) - { - case SP_INT: - case SP_STRING: - case SP_STRLEN: - case SP_NOT: - return "[dst, src]"; - - case SP_BUF: - return "[dst, size]"; - - case SP_SRL: - case SP_SRR: - case SP_MUL: - case SP_DIV: - case SP_ADD: - case SP_SUB: - case SP_AND: - case SP_OR: - case SP_XOR: - case SP_NOR: - return "[dst, src1, src2]"; - } - - return "error"; -} - -bool CompilePPUProgram::IsSpOp(const std::string& op) -{ - return GetSpType(op) != SP_ERR; -} - -CompilePPUProgram::Branch& CompilePPUProgram::GetBranch(const std::string& name) -{ - for(Branch& branch : m_branches) - { - if(name != branch.m_name) - continue; - - return branch; - } - - return m_branches[0]; -} - -void CompilePPUProgram::SetSp(const std::string& name, u32 addr, bool create) -{ - if(create) - { - m_branches.emplace_back(name, -1, addr); - return; - } - - GetBranch(name); - - for(Branch& branch : m_branches) - { - if(name != branch.m_name) - continue; - - branch.m_addr = addr; - } -} - -void CompilePPUProgram::LoadSp(const std::string& op, Elf64_Shdr& s_opd) -{ - SP_TYPE sp = GetSpType(op); - - std::string test; - if(!GetArg(test) || test[0] != '[') - { - if(m_analyze) WriteHex("error\n"); - WriteError(fmt::format("data not found. style: %s", GetSpStyle(sp).c_str())); - m_error = true; - NextLn(); - return; - } - - while(p > 0 && m_asm[(size_t)p] != '[') p--; - p++; - - std::string dst; - if(!GetArg(dst)) - { - if(m_analyze) WriteHex("error\n"); - WriteError(fmt::format("dst not found. style: %s", GetSpStyle(sp).c_str())); - m_error = true; - NextLn(); - return; - } - - Arg a_dst(dst); - DetectArgInfo(a_dst); - - Branch* dst_branch = NULL; - - switch(a_dst.type) - { - case ARG_BRANCH: - { - Branch& b = GetBranch(dst); - if(b.m_addr >= 0 && b.m_id < 0 && b.m_pos < 0) dst_branch = &b; - } - break; - - case ARG_ERR: - { - m_branches.emplace_back("", -1, 0); - dst_branch = &m_branches[m_branches.size() - 1]; - } - break; - } - - if(!dst_branch) - { - if(m_analyze) WriteHex("error\n"); - WriteError(fmt::format("bad dst type. style: %s", GetSpStyle(sp).c_str())); - m_error = true; - NextLn(); - return; - } - - switch(sp) - { - case SP_INT: - case SP_STRING: - case SP_STRLEN: - case SP_BUF: - case SP_NOT: - { - std::string src1; - if(!GetArg(src1, true)) - { - if(m_analyze) WriteHex("error\n"); - WriteError(fmt::format("src not found. style: %s", GetSpStyle(sp).c_str())); - m_error = true; - NextLn(); - return; - } - - Arg a_src1(src1); - DetectArgInfo(a_src1); - - if(sp == SP_STRLEN - ? ~(ARG_TXT | ARG_BRANCH) & a_src1.type - : sp == SP_STRING - ? ~ARG_TXT & a_src1.type - : ~(ARG_IMM | ARG_BRANCH) & a_src1.type) - { - if(m_analyze) WriteHex("error\n"); - WriteError(fmt::format("bad src type. style: %s", GetSpStyle(sp).c_str())); - m_error = true; - NextLn(); - return; - } - - if(m_asm[(size_t)p - 1] != ']') - { - if(m_analyze) WriteHex("error\n"); - WriteError(fmt::format("']' not found. style: %s", GetSpStyle(sp).c_str())); - m_error = true; - NextLn(); - return; - } - - if(!CheckEnd()) - { - if(m_analyze) WriteHex("error\n"); - return; - } - - if(sp == SP_STRING) - { - src1 = src1.substr(1, src1.length()-2); - bool founded = false; - - for(const SpData& sp_str : m_sp_string) - { - if(src1 != sp_str.m_data) - continue; - - *dst_branch = Branch(dst, -1, sp_str.m_addr); - founded = true; - } - - if(!founded) - { - const u32 addr = s_opd.sh_addr + s_opd.sh_size; - m_sp_string.emplace_back(src1, addr); - s_opd.sh_size += src1.length() + 1; - *dst_branch = Branch(dst, -1, addr); - } - } - else if(sp == SP_STRLEN) - { - switch(a_src1.type) - { - case ARG_TXT: *dst_branch = Branch(dst, -1, src1.length() - 2); break; - case ARG_BRANCH: - { - for(const SpData& sp_str : m_sp_string) - { - if(sp_str.m_addr == a_src1.value) - { - *dst_branch = Branch(dst, -1, sp_str.m_data.length()); - break; - } - } - } - break; - } - } - else - { - switch(sp) - { - case SP_INT: *dst_branch = Branch(dst, -1, a_src1.value); break; - case SP_BUF: - *dst_branch = Branch(dst, -1, s_opd.sh_addr + s_opd.sh_size); - s_opd.sh_size += a_src1.value; - break; - case SP_NOT: *dst_branch = Branch(dst, -1, ~a_src1.value); break; - } - } - } - break; - - case SP_SRL: - case SP_SRR: - case SP_MUL: - case SP_DIV: - case SP_ADD: - case SP_SUB: - case SP_AND: - case SP_OR: - case SP_XOR: - case SP_NOR: - { - std::string src1; - if(!GetArg(src1)) - { - if(m_analyze) WriteHex("error\n"); - WriteError(fmt::format("src1 not found. style: %s", GetSpStyle(sp).c_str())); - m_error = true; - NextLn(); - return; - } - - Arg a_src1(src1); - DetectArgInfo(a_src1); - - if(~(ARG_IMM | ARG_BRANCH) & a_src1.type) - { - if(m_analyze) WriteHex("error\n"); - WriteError(fmt::format("bad src1 type. style: %s", GetSpStyle(sp).c_str())); - m_error = true; - NextLn(); - return; - } - - std::string src2; - if(!GetArg(src2, true)) - { - if(m_analyze) WriteHex("error\n"); - WriteError(fmt::format("src2 not found. style: %s", GetSpStyle(sp).c_str())); - m_error = true; - return; - } - - Arg a_src2(src2); - DetectArgInfo(a_src2); - - if(~(ARG_IMM | ARG_BRANCH) & a_src2.type) - { - if(m_analyze) WriteHex("error\n"); - WriteError(fmt::format("bad src2 type. style: %s", GetSpStyle(sp).c_str())); - m_error = true; - NextLn(); - return; - } - - if(m_asm[(size_t)p - 1] != ']') - { - if(m_analyze) WriteHex("error\n"); - WriteError(fmt::format("']' not found. style: %s", GetSpStyle(sp).c_str())); - m_error = true; - NextLn(); - return; - } - - if(!CheckEnd()) - { - if(m_analyze) WriteHex("error\n"); - return; - } - - switch(sp) - { - case SP_SRL: *dst_branch = Branch(dst, -1, a_src1.value << a_src2.value); break; - case SP_SRR: *dst_branch = Branch(dst, -1, a_src1.value >> a_src2.value); break; - case SP_MUL: *dst_branch = Branch(dst, -1, a_src1.value * a_src2.value); break; - case SP_DIV: *dst_branch = Branch(dst, -1, a_src1.value / a_src2.value); break; - case SP_ADD: *dst_branch = Branch(dst, -1, a_src1.value + a_src2.value); break; - case SP_SUB: *dst_branch = Branch(dst, -1, a_src1.value - a_src2.value); break; - case SP_AND: *dst_branch = Branch(dst, -1, a_src1.value & a_src2.value); break; - case SP_OR: *dst_branch = Branch(dst, -1, a_src1.value | a_src2.value); break; - case SP_XOR: *dst_branch = Branch(dst, -1, a_src1.value ^ a_src2.value); break; - case SP_NOR: *dst_branch = Branch(dst, -1, ~(a_src1.value | a_src2.value)); break; - } - } - break; - } - - if(m_analyze) WriteHex("\n"); -} - -void CompilePPUProgram::Compile() -{ - if(m_err_list) - { - m_err_list->Freeze(); - m_err_list->Clear(); - } - - if(m_analyze && m_hex_list) - { - m_hex_list->Freeze(); - m_hex_list->Clear(); - } - - m_code.clear(); - m_branches.clear(); - - u32 text_size = 0; - while(!IsEnd()) - { - std::string op; - if(GetOp(op) && !IsFuncOp(op) && !IsBranchOp(op) && !IsSpOp(op)) - { - text_size += 4; - } - - NextLn(); - } - - Elf64_Ehdr elf_info; - memset(&elf_info, 0, sizeof(Elf64_Ehdr)); - elf_info.e_phentsize = sizeof(Elf64_Phdr); - elf_info.e_shentsize = sizeof(Elf64_Shdr); - elf_info.e_ehsize = sizeof(Elf64_Ehdr); - elf_info.e_phnum = 5; - elf_info.e_shnum = 15; - elf_info.e_shstrndx = elf_info.e_shnum - 1; - elf_info.e_phoff = elf_info.e_ehsize; - u32 section_offset = align(elf_info.e_phoff + elf_info.e_phnum * elf_info.e_phentsize, 0x100); - - static const u32 sceStub_text_block = 8 * 4; - - Elf64_Shdr s_null; - memset(&s_null, 0, sizeof(Elf64_Shdr)); - - std::vector sections_names; - u32 section_name_offset = 1; - - Elf64_Shdr s_text; - memset(&s_text, 0, sizeof(Elf64_Shdr)); - s_text.sh_type = 1; - s_text.sh_offset = section_offset; - s_text.sh_addr = section_offset + 0x10000; - s_text.sh_size = text_size; - s_text.sh_addralign = 4; - s_text.sh_flags = 6; - s_text.sh_name = section_name_offset; - sections_names.push_back(".text"); - section_name_offset += std::string(".text").length() + 1; - section_offset += s_text.sh_size; - - m_text_addr = s_text.sh_addr; - - struct Module - { - std::string m_name; - std::vector m_imports; - - Module(const std::string& name, u32 import) : m_name(name) - { - Add(import); - } - - void Add(u32 import) - { - m_imports.push_back(import); - } - - void Clear() - { - m_name.clear(); - m_imports.clear(); - } - }; - - std::vector modules; - - FirstChar(); - while(!IsEnd()) - { - std::string op; - if(!GetOp(op) || !IsFuncOp(op)) - { - NextLn(); - continue; - } - - while(p > 0 && m_asm[(size_t)p] != '[') p--; - p++; - - std::string module_name, name, id; - - if(!GetArg(module_name)) - { - WriteError("module not found. style: [module, name, id]"); - m_error = true; - NextLn(); - continue; - } - - Arg a_module(module_name); - DetectArgInfo(a_module); - - if(~ARG_ERR & a_module.type) - { - WriteError("bad module type. style: [module, name, id]"); - m_error = true; - NextLn(); - continue; - } - - if(!GetArg(name)) - { - WriteError("name not found. style: [module, name, id]"); - m_error = true; - NextLn(); - continue; - } - - Arg a_name(name); - DetectArgInfo(a_name); - - if(~ARG_ERR & a_name.type) - { - WriteError("bad name type. style: [module, name, id]"); - m_error = true; - NextLn(); - continue; - } - - if(!GetArg(id, true)) - { - WriteError("id not found. style: [module, name, id]"); - m_error = true; - NextLn(); - continue; - } - - Arg a_id(id); - DetectArgInfo(a_id); - - if(~ARG_IMM & a_id.type) - { - WriteError("bad id type. style: [module, name, id]"); - m_error = true; - NextLn(); - continue; - } - - if(m_asm[(size_t)p - 1] != ']') - { - WriteError("']' not found. style: [module, name, id]"); - m_error = true; - NextLn(); - continue; - } - - if(!CheckEnd()) continue; - - m_branches.emplace_back(name, a_id.value, 0); - const u32 import = m_branches.size() - 1; - - bool founded = false; - for(Module& module : modules) - { - if(module.m_name != module_name) - continue; - - founded = true; - module.Add(import); - break; - } - - if(!founded) modules.emplace_back(module_name, import); - } - - u32 imports_count = 0; - - for(const Module& module : modules) - { - imports_count += module.m_imports.size(); - } - - Elf64_Shdr s_sceStub_text; - memset(&s_sceStub_text, 0, sizeof(Elf64_Shdr)); - s_sceStub_text.sh_addralign = 4; - section_offset = align(section_offset, s_sceStub_text.sh_addralign); - s_sceStub_text.sh_type = 1; - s_sceStub_text.sh_offset = section_offset; - s_sceStub_text.sh_addr = section_offset + 0x10000; - s_sceStub_text.sh_name = section_name_offset; - s_sceStub_text.sh_flags = 6; - s_sceStub_text.sh_size = imports_count * sceStub_text_block; - sections_names.push_back(".sceStub.text"); - section_name_offset += std::string(".sceStub.text").length() + 1; - section_offset += s_sceStub_text.sh_size; - - for(const Module& module : modules) - { - u32 pos = 0; - for(const u32& import : module.m_imports) - { - m_branches[import].m_addr = s_sceStub_text.sh_addr + sceStub_text_block * pos; - ++pos; - } - } - - Elf64_Shdr s_lib_stub_top; - memset(&s_lib_stub_top, 0, sizeof(Elf64_Shdr)); - s_lib_stub_top.sh_addralign = 4; - section_offset = align(section_offset, s_lib_stub_top.sh_addralign); - s_lib_stub_top.sh_type = 1; - s_lib_stub_top.sh_name = section_name_offset; - s_lib_stub_top.sh_offset = section_offset; - s_lib_stub_top.sh_addr = section_offset + 0x10000; - s_lib_stub_top.sh_flags = 2; - s_lib_stub_top.sh_size = 4; - sections_names.push_back(".lib.stub.top"); - section_name_offset += std::string(".lib.stub.top").length() + 1; - section_offset += s_lib_stub_top.sh_size; - - Elf64_Shdr s_lib_stub; - memset(&s_lib_stub, 0, sizeof(Elf64_Shdr)); - s_lib_stub.sh_addralign = 4; - s_lib_stub.sh_type = 1; - s_lib_stub.sh_name = section_name_offset; - s_lib_stub.sh_offset = section_offset; - s_lib_stub.sh_addr = section_offset + 0x10000; - s_lib_stub.sh_flags = 2; - s_lib_stub.sh_size = sizeof(sys_stub) * modules.size(); - sections_names.push_back(".lib.stub"); - section_name_offset += std::string(".lib.stub").length() + 1; - section_offset += s_lib_stub.sh_size; - - Elf64_Shdr s_lib_stub_btm; - memset(&s_lib_stub_btm, 0, sizeof(Elf64_Shdr)); - s_lib_stub_btm.sh_addralign = 4; - s_lib_stub_btm.sh_type = 1; - s_lib_stub_btm.sh_name = section_name_offset; - s_lib_stub_btm.sh_offset = section_offset; - s_lib_stub_btm.sh_addr = section_offset + 0x10000; - s_lib_stub_btm.sh_flags = 2; - s_lib_stub_btm.sh_size = 4; - sections_names.push_back(".lib.stub.btm"); - section_name_offset += std::string(".lib.stub.btm").length() + 1; - section_offset += s_lib_stub_btm.sh_size; - - Elf64_Shdr s_rodata_sceFNID; - memset(&s_rodata_sceFNID, 0, sizeof(Elf64_Shdr)); - s_rodata_sceFNID.sh_addralign = 4; - section_offset = align(section_offset, s_rodata_sceFNID.sh_addralign); - s_rodata_sceFNID.sh_type = 1; - s_rodata_sceFNID.sh_name = section_name_offset; - s_rodata_sceFNID.sh_offset = section_offset; - s_rodata_sceFNID.sh_addr = section_offset + 0x10000; - s_rodata_sceFNID.sh_flags = 2; - s_rodata_sceFNID.sh_size = imports_count * 4; - sections_names.push_back(".rodata.sceFNID"); - section_name_offset += std::string(".rodata.sceFNID").length() + 1; - section_offset += s_rodata_sceFNID.sh_size; - - Elf64_Shdr s_rodata_sceResident; - memset(&s_rodata_sceResident, 0, sizeof(Elf64_Shdr)); - s_rodata_sceResident.sh_addralign = 4; - section_offset = align(section_offset, s_rodata_sceResident.sh_addralign); - s_rodata_sceResident.sh_type = 1; - s_rodata_sceResident.sh_name = section_name_offset; - s_rodata_sceResident.sh_offset = section_offset; - s_rodata_sceResident.sh_addr = section_offset + 0x10000; - s_rodata_sceResident.sh_flags = 2; - s_rodata_sceResident.sh_size = 4; - for(const Module& module : modules) - { - s_rodata_sceResident.sh_size += module.m_name.length() + 1; - } - s_rodata_sceResident.sh_size = align(s_rodata_sceResident.sh_size, s_rodata_sceResident.sh_addralign); - sections_names.push_back(".rodata.sceResident"); - section_name_offset += std::string(".rodata.sceResident").length() + 1; - section_offset += s_rodata_sceResident.sh_size; - - Elf64_Shdr s_lib_ent_top; - memset(&s_lib_ent_top, 0, sizeof(Elf64_Shdr)); - s_lib_ent_top.sh_addralign = 4; - section_offset = align(section_offset, s_lib_ent_top.sh_addralign); - s_lib_ent_top.sh_size = 4; - s_lib_ent_top.sh_flags = 2; - s_lib_ent_top.sh_type = 1; - s_lib_ent_top.sh_name = section_name_offset; - s_lib_ent_top.sh_offset = section_offset; - s_lib_ent_top.sh_addr = section_offset + 0x10000; - sections_names.push_back(".lib.ent.top"); - section_name_offset += std::string(".lib.ent.top").length() + 1; - section_offset += s_lib_ent_top.sh_size; - - Elf64_Shdr s_lib_ent_btm; - memset(&s_lib_ent_btm, 0, sizeof(Elf64_Shdr)); - s_lib_ent_btm.sh_addralign = 4; - s_lib_ent_btm.sh_size = 4; - s_lib_ent_btm.sh_flags = 2; - s_lib_ent_btm.sh_type = 1; - s_lib_ent_btm.sh_name = section_name_offset; - s_lib_ent_btm.sh_offset = section_offset; - s_lib_ent_btm.sh_addr = section_offset + 0x10000; - sections_names.push_back(".lib.ent.btm"); - section_name_offset += std::string(".lib.ent.btm").length() + 1; - section_offset += s_lib_ent_btm.sh_size; - - Elf64_Shdr s_sys_proc_prx_param; - memset(&s_sys_proc_prx_param, 0, sizeof(Elf64_Shdr)); - s_sys_proc_prx_param.sh_addralign = 4; - section_offset = align(section_offset, s_sys_proc_prx_param.sh_addralign); - s_sys_proc_prx_param.sh_type = 1; - s_sys_proc_prx_param.sh_size = sizeof(sys_proc_prx_param); - s_sys_proc_prx_param.sh_name = section_name_offset; - s_sys_proc_prx_param.sh_offset = section_offset; - s_sys_proc_prx_param.sh_addr = section_offset + 0x10000; - s_sys_proc_prx_param.sh_flags = 2; - sections_names.push_back(".sys_proc_prx_param"); - section_name_offset += std::string(".sys_proc_prx_param").length() + 1; - section_offset += s_sys_proc_prx_param.sh_size; - - const u32 prog_load_0_end = section_offset; - - section_offset = align(section_offset + 0x10000, 0x10000); - const u32 prog_load_1_start = section_offset; - - Elf64_Shdr s_data_sceFStub; - memset(&s_data_sceFStub, 0, sizeof(Elf64_Shdr)); - s_data_sceFStub.sh_name = section_name_offset; - s_data_sceFStub.sh_addralign = 4; - section_offset = align(section_offset, s_data_sceFStub.sh_addralign); - s_data_sceFStub.sh_flags = 3; - s_data_sceFStub.sh_type = 1; - s_data_sceFStub.sh_offset = section_offset; - s_data_sceFStub.sh_addr = section_offset + 0x10000; - s_data_sceFStub.sh_size = imports_count * 4; - sections_names.push_back(".data.sceFStub"); - section_name_offset += std::string(".data.sceFStub").length() + 1; - section_offset += s_data_sceFStub.sh_size; - - Elf64_Shdr s_tbss; - memset(&s_tbss, 0, sizeof(Elf64_Shdr)); - s_tbss.sh_addralign = 4; - section_offset = align(section_offset, s_tbss.sh_addralign); - s_tbss.sh_size = 4; - s_tbss.sh_flags = 0x403; - s_tbss.sh_type = 8; - s_tbss.sh_name = section_name_offset; - s_tbss.sh_offset = section_offset; - s_tbss.sh_addr = section_offset + 0x10000; - sections_names.push_back(".tbss"); - section_name_offset += std::string(".tbss").length() + 1; - section_offset += s_tbss.sh_size; - - Elf64_Shdr s_opd; - memset(&s_opd, 0, sizeof(Elf64_Shdr)); - s_opd.sh_addralign = 8; - section_offset = align(section_offset, s_opd.sh_addralign); - s_opd.sh_size = 2*4; - s_opd.sh_type = 1; - s_opd.sh_offset = section_offset; - s_opd.sh_addr = section_offset + 0x10000; - s_opd.sh_name = section_name_offset; - s_opd.sh_flags = 3; - sections_names.push_back(".opd"); - section_name_offset += std::string(".opd").length() + 1; - - FirstChar(); - - while(!IsEnd()) - { - std::string op; - if(!GetOp(op) || IsFuncOp(op) || IsSpOp(op)) - { - NextLn(); - continue; - } - - if(IsBranchOp(op)) - { - const std::string& name = op.substr(0, op.length() - 1); - - for(const Branch& branch : m_branches) - { - if(name != branch.m_name) - continue; - - WriteError(fmt::format("'%s' already declared", name.c_str())); - m_error = true; - break; - } - - Arg a_name(name); - DetectArgInfo(a_name); - - if(a_name.type != ARG_ERR) - { - WriteError(fmt::format("bad name '%s'", name.c_str())); - m_error = true; - } - - if(m_error) break; - - m_branches.emplace_back(name, m_branch_pos); - - CheckEnd(); - continue; - } - - m_branch_pos++; - NextLn(); - } - - bool has_entry = false; - for(const Branch& branch : m_branches) - { - if(branch.m_name != "entry") - continue; - - has_entry = true; - break; - } - - if(!has_entry) m_branches.emplace_back("entry", 0); - - if(m_analyze) m_error = false; - FirstChar(); - - while(!IsEnd()) - { - m_args.clear(); - m_end_args = false; - - std::string op; - if(!GetOp(op) || IsBranchOp(op) || IsFuncOp(op)) - { - if(m_analyze) WriteHex("\n"); - NextLn(); - continue; - } - - if(IsSpOp(op)) - { - LoadSp(op, s_opd); - continue; - } - - LoadArgs(); - - auto instr = GetInstruction(op); - if(instr) - { - uint type[] = - { - ARG_IMM, - ARG_REG_R, - ARG_REG_F, - ARG_REG_V, - ARG_REG_CR, - }; - - for(uint i=0; iGetArgCount(); ++i) - { - switch(instr->GetArg(i).m_type) - { - case FIELD_BRANCH: - SetNextArgBranch(0); //TODO - break; - - default: - SetNextArgType(type[instr->GetArg(i).m_type]); - break; - } - } - } - else - { - WriteError(fmt::format("unknown instruction '%s'", op.c_str())); - EndLn(); - m_error = true; - } - - CheckEnd(); - - if(m_error) - { - if(m_analyze) - { - WriteHex("error\n"); - m_error = false; - continue; - } - - break; - } - - u32 code; - - { - std::vector args; - args.resize(m_args.size()); - for(uint i=0; i::make(s_lib_stub_top.sh_addr + s_lib_stub_top.sh_size); - prx_param.libstubend = vm::bptr::make(s_lib_stub_btm.sh_addr); - prx_param.ver = 0x101; - - elf_info.e_entry = s_opd.sh_addr; - - f.Seek(0); - WriteEhdr(f, elf_info); - - f.Seek(elf_info.e_shoff); - WriteShdr(f, s_null); - WriteShdr(f, s_text); - WriteShdr(f, s_opd); - WriteShdr(f, s_sceStub_text); - WriteShdr(f, s_lib_stub_top); - WriteShdr(f, s_lib_stub); - WriteShdr(f, s_lib_stub_btm); - WriteShdr(f, s_data_sceFStub); - WriteShdr(f, s_rodata_sceFNID); - WriteShdr(f, s_rodata_sceResident); - WriteShdr(f, s_sys_proc_prx_param); - WriteShdr(f, s_lib_ent_top); - WriteShdr(f, s_lib_ent_btm); - WriteShdr(f, s_tbss); - WriteShdr(f, s_shstrtab); - - f.Seek(s_text.sh_offset); - for(const u32& code : m_code) - { - Write32(f, code); - } - - f.Seek(s_opd.sh_offset); - f.Write(opd_data, 8); - for(u32 i=0; i> 16)); - Write32(f, LWZ(12, 12, addr)); - Write32(f, STD(2, 1, 40)); - Write32(f, LWZ(0, 12, 0)); - Write32(f, LWZ(2, 12, 4)); - Write32(f, MTSPR(0x009, 0)); - Write32(f, BCCTR(20, 0, 0, 0)); - } - - f.Seek(s_lib_stub_top.sh_offset); - f.Seek(s_lib_stub_top.sh_size, rFromCurrent); - - f.Seek(s_lib_stub.sh_offset); - for(u32 i=0, nameoffs=4, dataoffs=0; i::make(s_rodata_sceResident.sh_addr + nameoffs); - stub.s_nid = vm::bptr::make(s_rodata_sceFNID.sh_addr + dataoffs); - stub.s_text = vm::bptr::make(s_data_sceFStub.sh_addr + dataoffs); - stub.s_imports = modules[i].m_imports.size(); - - dataoffs += modules[i].m_imports.size() * 4; - - f.Write(&stub, sizeof(sys_stub)); - nameoffs += modules[i].m_name.length() + 1; - } - - f.Seek(s_lib_stub_btm.sh_offset); - f.Seek(s_lib_stub_btm.sh_size, rFromCurrent); - - f.Seek(s_data_sceFStub.sh_offset); - for(const Module& module : modules) - { - for(const u32& import : module.m_imports) - { - Write32(f, m_branches[import].m_addr); - } - } - - f.Seek(s_rodata_sceFNID.sh_offset); - for(const Module& module : modules) - { - for(const u32& import : module.m_imports) - { - Write32(f, m_branches[import].m_id); - } - } - - f.Seek(s_rodata_sceResident.sh_offset + 4); - for(u32 i=0; iThaw(); - - if(m_analyze) - { - if(m_hex_list) - { - m_hex_list->Thaw(); - } - } - else - { - //TODO: doesn't look portable - system("make_fself.cmd"); - } -} -*/ \ No newline at end of file diff --git a/rpcs3/Emu/Cell/PPUProgramCompiler.h b/rpcs3/Emu/Cell/PPUProgramCompiler.h deleted file mode 100644 index f7d5a00559..0000000000 --- a/rpcs3/Emu/Cell/PPUProgramCompiler.h +++ /dev/null @@ -1,192 +0,0 @@ -#pragma once -/*#include "PPUInstrTable.h" -#include "Loader/ELF64.h" - -enum ArgType -{ - ARG_ERR = 0, - ARG_NUM = 1 << 0, - ARG_NUM16 = 1 << 1, - ARG_TXT = 1 << 2, - ARG_REG_R = 1 << 3, - ARG_REG_F = 1 << 4, - ARG_REG_V = 1 << 5, - ARG_REG_CR = 1 << 6, - ARG_BRANCH = 1 << 7, - ARG_INSTR = 1 << 8, - ARG_IMM = ARG_NUM | ARG_NUM16 | ARG_BRANCH, -}; - -struct Arg -{ - std::string string; - u32 value; - ArgType type; - - Arg(const std::string& _string, const u32 _value = 0, const ArgType _type = ARG_ERR) - : string(_string) - , value(_value) - , type(_type) - { - } -}; - -struct SectionInfo -{ - Elf64_Shdr shdr; - std::string name; - std::vector code; - u32 section_num; - - SectionInfo(const std::string& name); - ~SectionInfo(); - - void SetDataSize(u32 size, u32 align = 0); -}; - -struct ProgramInfo -{ - std::vector code; - Elf64_Phdr phdr; - bool is_preload; - - ProgramInfo() - { - is_preload = false; - memset(&phdr, 0, sizeof(Elf64_Phdr)); - } -}; - -class CompilePPUProgram -{ - struct Branch - { - std::string m_name; - s32 m_pos; - s32 m_id; - s32 m_addr; - - Branch(const std::string& name, s32 pos) - : m_name(name) - , m_pos(pos) - , m_id(-1) - , m_addr(-1) - { - } - - Branch(const std::string& name, u32 id, u32 addr) - : m_name(name) - , m_pos(-1) - , m_id(id) - , m_addr(addr) - { - } - }; - - bool m_analyze; - s64 p; - u64 m_line; - const std::string& m_asm; - wxTextCtrl* m_asm_list; - wxTextCtrl* m_hex_list; - wxTextCtrl* m_err_list; - bool m_error; - std::vector m_code; - bool m_end_args; - std::vector m_branches; - s32 m_branch_pos; - u32 m_text_addr; - std::string m_file_path; - - struct SpData - { - std::string m_data; - u32 m_addr; - - SpData(const std::string& data, u32 addr) - : m_data(data) - , m_addr(addr) - { - } - }; - - std::vector m_sp_string; - std::vector m_args; - u32 m_cur_arg; - -public: - CompilePPUProgram( - const std::string& asm_, - const std::string& file_path = "", - wxTextCtrl* asm_list = nullptr, - wxTextCtrl* hex_list = nullptr, - wxTextCtrl* err_list = nullptr, - bool analyze = false); - - static bool IsSkip(const char c); - static bool IsCommit(const char c); - -protected: - bool IsEnd() const; - bool IsEndLn(const char c) const; - - void WriteHex(const std::string& text); - void WriteError(const std::string& error); - - char NextChar(); - void NextLn(); - void EndLn(); - - void FirstChar(); - void PrevArg(); - - bool GetOp(std::string& result); - int GetArg(std::string& result, bool func = false); - - bool CheckEnd(bool show_err = true); - - void DetectArgInfo(Arg& arg); - void LoadArgs(); - u32 GetBranchValue(const std::string& branch) const; - - bool SetNextArgType(u32 types, bool show_err = true); - bool SetNextArgBranch(u8 aa, bool show_err = true); - -public: - static bool IsBranchOp(const std::string& op); - static bool IsFuncOp(const std::string& op); - - enum SP_TYPE - { - SP_ERR, - SP_INT, - SP_STRING, - SP_STRLEN, - SP_BUF, - SP_SRL, - SP_SRR, - SP_MUL, - SP_DIV, - SP_ADD, - SP_SUB, - SP_AND, - SP_OR, - SP_XOR, - SP_NOT, - SP_NOR, - }; - - static SP_TYPE GetSpType(const std::string& op); - static std::string GetSpStyle(const SP_TYPE sp); - - static bool IsSpOp(const std::string& op); - -protected: - Branch& GetBranch(const std::string& name); - void SetSp(const std::string& name, u32 addr, bool create); - void LoadSp(const std::string& op, Elf64_Shdr& s_opd); - -public: - void Compile(); -}; -*/ \ No newline at end of file diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 58be498031..ccce38e9e6 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -1,108 +1,62 @@ #include "stdafx.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/state.h" #include "Emu/IdManager.h" -#include "Emu/Cell/PPUThread.h" -#include "Emu/Cell/PPUDecoder.h" -#include "Emu/Cell/PPUInterpreter.h" -#include "Emu/Cell/PPUInterpreter2.h" -#include "Emu/Cell/PPULLVMRecompiler.h" -//#include "Emu/Cell/PPURecompiler.h" -#include "Utilities/VirtualMemory.h" +#include "PPUThread.h" +#include "PPUInterpreter.h" +#include "PPUModule.h" -#ifdef _WIN32 -#include -#else -#include -#include -#endif - -u64 rotate_mask[64][64]; - -extern u32 ppu_get_tls(u32 thread); -extern void ppu_free_tls(u32 thread); - -//thread_local const std::weak_ptr g_tls_ppu_decoder_cache = fxm::get(); -thread_local const ppu_decoder_cache_t* g_tls_ppu_decoder_cache = nullptr; // temporarily, because thread_local is not fully available - -ppu_decoder_cache_t::ppu_decoder_cache_t() - : pointer(static_cast(memory_helper::reserve_memory(0x200000000))) +enum class ppu_decoder_type { -} + precise, + fast, + llvm, +}; -ppu_decoder_cache_t::~ppu_decoder_cache_t() +cfg::map_entry g_cfg_ppu_decoder(cfg::root.core, "PPU Decoder", 1, { - memory_helper::free_reserved_memory(pointer, 0x200000000); -} + { "Interpreter (precise)", ppu_decoder_type::precise }, + { "Interpreter (fast)", ppu_decoder_type::fast }, + { "Recompiler (LLVM)", ppu_decoder_type::llvm }, +}); -void ppu_decoder_cache_t::initialize(u32 addr, u32 size) -{ - memory_helper::commit_page_memory(pointer + addr / 4, size * 2); - - PPUInterpreter2* inter; - PPUDecoder dec(inter = new PPUInterpreter2); - - for (u32 pos = addr; pos < addr + size; pos += 4) - { - inter->func = ppu_interpreter::NULL_OP; - - // decode PPU opcode - dec.Decode(vm::ps3::read32(pos)); - - // store function address - pointer[pos / 4] = inter->func; - } -} - -PPUThread::PPUThread(const std::string& name) - : CPUThread(CPU_THREAD_PPU, name) -{ - InitRotateMask(); -} - -PPUThread::~PPUThread() -{ - close_stack(); - ppu_free_tls(m_id); -} +const ppu_decoder s_ppu_interpreter_precise; +const ppu_decoder s_ppu_interpreter_fast; std::string PPUThread::get_name() const { - return fmt::format("PPU Thread[0x%x] (%s)[0x%08x]", m_id, CPUThread::get_name(), PC); + return fmt::format("PPU[0x%x] Thread (%s)", id, name); } -void PPUThread::dump_info() const +std::string PPUThread::dump() const { - extern std::string get_ps3_function_name(u64 fid); + std::string ret = "Registers:\n=========\n"; - if (~hle_code < 1024) - { - LOG_SUCCESS(HLE, "Last syscall: %lld (%s)", ~hle_code, get_ps3_function_name(hle_code)); - } - else if (hle_code) - { - LOG_SUCCESS(HLE, "Last function: %s (0x%llx)", get_ps3_function_name(hle_code), hle_code); - } + for (uint i = 0; i<32; ++i) ret += fmt::format("GPR[%d] = 0x%llx\n", i, GPR[i]); + for (uint i = 0; i<32; ++i) ret += fmt::format("FPR[%d] = %.6G\n", i, FPR[i]); + for (uint i = 0; i<32; ++i) ret += fmt::format("VR[%d] = 0x%s [%s]\n", i, VR[i].to_hex().c_str(), VR[i].to_xyzw().c_str()); + ret += fmt::format("CR = 0x%08x\n", GetCR()); + ret += fmt::format("LR = 0x%llx\n", LR); + ret += fmt::format("CTR = 0x%llx\n", CTR); + ret += fmt::format("XER = [CA=%u | OV=%u | SO=%u | CNT=%u]\n", u32{ CA }, u32{ OV }, u32{ SO }, u32{ XCNT }); + //ret += fmt::format("FPSCR = 0x%x " + // "[RN=%d | NI=%d | XE=%d | ZE=%d | UE=%d | OE=%d | VE=%d | " + // "VXCVI=%d | VXSQRT=%d | VXSOFT=%d | FPRF=%d | " + // "FI=%d | FR=%d | VXVC=%d | VXIMZ=%d | " + // "VXZDZ=%d | VXIDI=%d | VXISI=%d | VXSNAN=%d | " + // "XX=%d | ZX=%d | UX=%d | OX=%d | VX=%d | FEX=%d | FX=%d]\n", + // FPSCR.FPSCR, + // u32{ FPSCR.RN }, + // u32{ FPSCR.NI }, u32{ FPSCR.XE }, u32{ FPSCR.ZE }, u32{ FPSCR.UE }, u32{ FPSCR.OE }, u32{ FPSCR.VE }, + // u32{ FPSCR.VXCVI }, u32{ FPSCR.VXSQRT }, u32{ FPSCR.VXSOFT }, u32{ FPSCR.FPRF }, + // u32{ FPSCR.FI }, u32{ FPSCR.FR }, u32{ FPSCR.VXVC }, u32{ FPSCR.VXIMZ }, + // u32{ FPSCR.VXZDZ }, u32{ FPSCR.VXIDI }, u32{ FPSCR.VXISI }, u32{ FPSCR.VXSNAN }, + // u32{ FPSCR.XX }, u32{ FPSCR.ZX }, u32{ FPSCR.UX }, u32{ FPSCR.OX }, u32{ FPSCR.VX }, u32{ FPSCR.FEX }, u32{ FPSCR.FX }); - CPUThread::dump_info(); + return ret; } -void PPUThread::init_regs() -{ - GPR[1] = align(stack_addr + stack_size, 0x200) - 0x200; - GPR[13] = ppu_get_tls(m_id) + 0x7000; // 0x7000 is subtracted from r13 to access first TLS element - - LR = 0; - CTR = PC; - CR.CR = 0x22000082; - VSCR.NJ = 1; - TB = 0; - - //m_state |= CPU_STATE_INTR; -} - -void PPUThread::init_stack() +void PPUThread::cpu_init() { if (!stack_addr) { @@ -118,14 +72,70 @@ void PPUThread::init_stack() throw EXCEPTION("Out of stack memory"); } } + + GPR[1] = align(stack_addr + stack_size, 0x200) - 0x200; } -void PPUThread::close_stack() +void PPUThread::cpu_task() { - if (stack_addr) + //SetHostRoundingMode(FPSCR_RN_NEAR); + + if (custom_task) { - vm::dealloc_verbose_nothrow(stack_addr, vm::stack); - stack_addr = 0; + if (check_status()) return; + + return custom_task(*this); + } + + _log::g_tls_make_prefix = [](const auto&, auto, const auto&) + { + const auto cpu = static_cast(get_current_cpu_thread()); + + return fmt::format("%s [0x%08x]", cpu->get_name(), cpu->PC); + }; + + const auto base = vm::_ptr(0); + + // Select opcode table + const auto& table = *( + g_cfg_ppu_decoder.get() == ppu_decoder_type::precise ? &s_ppu_interpreter_precise.get_table() : + g_cfg_ppu_decoder.get() == ppu_decoder_type::fast ? &s_ppu_interpreter_fast.get_table() : + throw std::logic_error("Invalid PPU decoder")); + + u32 _pc{}; + u32 op0, op1, op2; + ppu_inter_func_t func0, func1, func2; + + while (true) + { + if (_pc == PC && !state.load()) + { + func0(*this, { op0 }); + + if ((_pc += 4) == (PC += 4) && !state.load()) + { + func1(*this, { op1 }); + + if ((_pc += 4) == (PC += 4)) + { + op0 = op2; + func0 = func2; + const auto ops = reinterpret_cast*>(base + _pc); + func1 = table[ppu_decode(op1 = ops[1])]; + func2 = table[ppu_decode(op2 = ops[2])]; + continue; + } + } + } + + // Reinitialize + _pc = PC; + const auto ops = reinterpret_cast*>(base + _pc); + func0 = table[ppu_decode(op0 = ops[0])]; + func1 = table[ppu_decode(op1 = ops[1])]; + func2 = table[ppu_decode(op2 = ops[2])]; + + if (check_status()) return; } } @@ -134,99 +144,28 @@ bool PPUThread::handle_interrupt() return false; } -void PPUThread::do_run() +PPUThread::~PPUThread() { - m_dec.reset(); - - switch (auto mode = rpcs3::state.config.core.ppu_decoder.value()) + if (stack_addr) { - case ppu_decoder_type::interpreter: // original interpreter - { - m_dec.reset(new PPUDecoder(new PPUInterpreter(*this))); - break; - } - - case ppu_decoder_type::interpreter2: // alternative interpreter - { - break; - } - - case ppu_decoder_type::recompiler_llvm: - { -#ifdef PPU_LLVM_RECOMPILER - m_dec.reset(new ppu_recompiler_llvm::CPUHybridDecoderRecompiler(*this)); -#else - LOG_ERROR(PPU, "This image does not include PPU JIT (LLVM)"); - Emu.Pause(); -#endif - break; - } - - //case 3: m_dec.reset(new PPURecompiler(*this)); break; - - default: - { - LOG_ERROR(PPU, "Invalid CPU decoder mode: %d", mode); - Emu.Pause(); - } + vm::dealloc_verbose_nothrow(stack_addr, vm::stack); } } -bool FPRdouble::IsINF(PPCdouble d) +be_t* PPUThread::get_stack_arg(s32 i, u64 align) { - return ((u64&)d & 0x7FFFFFFFFFFFFFFFULL) == 0x7FF0000000000000ULL; -} - -bool FPRdouble::IsNaN(PPCdouble d) -{ - return std::isnan((double)d) ? 1 : 0; -} - -bool FPRdouble::IsQNaN(PPCdouble d) -{ - return - ((u64&)d & 0x7FF0000000000000ULL) == 0x7FF0000000000000ULL && - ((u64&)d & 0x0007FFFFFFFFFFFULL) == 0ULL && - ((u64&)d & 0x000800000000000ULL) != 0ULL; -} - -bool FPRdouble::IsSNaN(PPCdouble d) -{ - return - ((u64&)d & 0x7FF0000000000000ULL) == 0x7FF0000000000000ULL && - ((u64&)d & 0x000FFFFFFFFFFFFFULL) != 0ULL && - ((u64&)d & 0x0008000000000000ULL) == 0ULL; -} - -int FPRdouble::Cmp(PPCdouble a, PPCdouble b) -{ - if(a < b) return CR_LT; - if(a > b) return CR_GT; - if(a == b) return CR_EQ; - - return CR_SO; -} - -u64 PPUThread::get_stack_arg(s32 i) -{ - return vm::ps3::read64(VM_CAST(GPR[1] + 0x70 + 0x8 * (i - 9))); + if (align != 1 && align != 2 && align != 4 && align != 8 && align != 16) throw fmt::exception("Unsupported alignment: 0x%llx" HERE, align); + return vm::_ptr(vm::cast((GPR[1] + 0x30 + 0x8 * (i - 1)) & (0 - align), HERE)); } void PPUThread::fast_call(u32 addr, u32 rtoc) { - if (!is_current()) - { - throw EXCEPTION("Called from the wrong thread"); - } - auto old_PC = PC; auto old_stack = GPR[1]; auto old_rtoc = GPR[2]; auto old_LR = LR; auto old_task = std::move(custom_task); - assert(!old_task || !custom_task); - PC = addr; GPR[2] = rtoc; LR = Emu.GetCPUThreadStop(); @@ -236,11 +175,13 @@ void PPUThread::fast_call(u32 addr, u32 rtoc) { cpu_task(); } - catch (CPUThreadReturn) + catch (cpu_state _s) { + state += _s; + if (_s != cpu_state::ret) throw; } - m_state &= ~CPU_STATE_RETURN; + state -= cpu_state::ret; PC = old_PC; @@ -253,135 +194,3 @@ void PPUThread::fast_call(u32 addr, u32 rtoc) LR = old_LR; custom_task = std::move(old_task); } - -void PPUThread::fast_stop() -{ - m_state |= CPU_STATE_RETURN; -} - -void PPUThread::cpu_task() -{ - SetHostRoundingMode(FPSCR_RN_NEAR); - - if (custom_task) - { - if (check_status()) return; - - return custom_task(*this); - } - - if (!g_tls_ppu_decoder_cache) - { - const auto decoder_cache = fxm::get(); - - if (!decoder_cache) - { - throw EXCEPTION("PPU Decoder Cache not initialized"); - } - - g_tls_ppu_decoder_cache = decoder_cache.get(); // unsafe (TODO) - } - - const auto exec_map = g_tls_ppu_decoder_cache->pointer; - - if (m_dec) - { - while (true) - { - if (m_state && check_status()) break; - - // decode instruction using specified decoder - m_dec->DecodeMemory(PC); - - // next instruction - PC += 4; - } - } - else - { - while (true) - { - // get cached interpreter function address - const auto func = exec_map[PC / 4]; - - // check status - if (!m_state) - { - // call interpreter function - func(*this, { vm::ps3::read32(PC) }); - - // next instruction - PC += 4; - - continue; - } - - if (check_status()) - { - break; - } - } - } -} - -ppu_thread::ppu_thread(u32 entry, const std::string& name, u32 stack_size, s32 prio) -{ - auto ppu = idm::make_ptr(name); - - if (entry) - { - ppu->PC = vm::ps3::read32(entry); - ppu->GPR[2] = vm::ps3::read32(entry + 4); // rtoc - } - - ppu->stack_size = stack_size ? stack_size : Emu.GetPrimaryStackSize(); - ppu->prio = prio ? prio : Emu.GetPrimaryPrio(); - - thread = std::move(ppu); - - argc = 0; -} - -cpu_thread& ppu_thread::args(std::initializer_list values) -{ - if (!values.size()) - return *this; - - assert(argc == 0); - - envp.set(vm::alloc(align(SIZE_32(*envp), stack_align), vm::main)); - *envp = 0; - argv.set(vm::alloc(SIZE_32(*argv) * (u32)values.size(), vm::main)); - - for (auto &arg : 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::base(arg_addr), arg.c_str(), arg.size() + 1); - - argv[argc++] = arg_addr; - } - - return *this; -} - -cpu_thread& ppu_thread::run() -{ - thread->run(); - - gpr(3, argc); - gpr(4, argv.addr()); - gpr(5, envp.addr()); - - return *this; -} - -ppu_thread& ppu_thread::gpr(uint index, u64 value) -{ - assert(index < 32); - - static_cast(*thread).GPR[index] = value; - - return *this; -} diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h index 897864d611..4c007110e8 100644 --- a/rpcs3/Emu/Cell/PPUThread.h +++ b/rpcs3/Emu/Cell/PPUThread.h @@ -4,246 +4,32 @@ #include "Emu/CPU/CPUThread.h" #include "Emu/Memory/vm.h" -enum +class PPUThread final : public cpu_thread { - XER_SO = 0x80000000, - XER_OV = 0x40000000, - XER_CA = 0x20000000, -}; +public: + virtual std::string get_name() const override; + virtual std::string dump() const override; + virtual void cpu_init() override; + virtual void cpu_task() override; + virtual bool handle_interrupt() override; -enum -{ - CR_LT = 0x8, - CR_GT = 0x4, - CR_EQ = 0x2, - CR_SO = 0x1, -}; - -enum FPSCR_EXP -{ - FPSCR_FX = 0x80000000, - FPSCR_FEX = 0x40000000, - FPSCR_VX = 0x20000000, - FPSCR_OX = 0x10000000, - - FPSCR_UX = 0x08000000, - FPSCR_ZX = 0x04000000, - FPSCR_XX = 0x02000000, - FPSCR_VXSNAN = 0x01000000, - - FPSCR_VXISI = 0x00800000, - FPSCR_VXIDI = 0x00400000, - FPSCR_VXZDZ = 0x00200000, - FPSCR_VXIMZ = 0x00100000, - - FPSCR_VXVC = 0x00080000, - FPSCR_FR = 0x00040000, - FPSCR_FI = 0x00020000, - - FPSCR_VXSOFT = 0x00000400, - FPSCR_VXSQRT = 0x00000200, - FPSCR_VXCVI = 0x00000100, - - FPSCR_VX_ALL = FPSCR_VXSNAN | FPSCR_VXISI | FPSCR_VXIDI | FPSCR_VXZDZ | FPSCR_VXIMZ | FPSCR_VXVC | FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI, -}; - -static const u64 DOUBLE_SIGN = 0x8000000000000000ULL; -static const u64 DOUBLE_EXP = 0x7FF0000000000000ULL; -static const u64 DOUBLE_FRAC = 0x000FFFFFFFFFFFFFULL; -static const u64 DOUBLE_ZERO = 0x0000000000000000ULL; - -union FPSCRhdr -{ - struct + PPUThread(const std::string& name) + : cpu_thread(cpu_type::ppu, name) { - u32 RN :2; //Floating-point rounding control - u32 NI :1; //Floating-point non-IEEE mode - u32 XE :1; //Floating-point inexact exception enable - u32 ZE :1; //IEEE floating-point zero divide exception enable - u32 UE :1; //IEEE floating-point underflow exception enable - u32 OE :1; //IEEE floating-point overflow exception enable - u32 VE :1; //Floating-point invalid operation exception enable - u32 VXCVI :1; //Floating-point invalid operation exception for invalid integer convert - u32 VXSQRT :1; //Floating-point invalid operation exception for invalid square root - u32 VXSOFT :1; //Floating-point invalid operation exception for software request - u32 :1; //Reserved - u32 FPRF :5; //Floating-point result flags - u32 FI :1; //Floating-point fraction inexact - u32 FR :1; //Floating-point fraction rounded - u32 VXVC :1; //Floating-point invalid operation exception for invalid compare - u32 VXIMZ :1; //Floating-point invalid operation exception for * * 0 - u32 VXZDZ :1; //Floating-point invalid operation exception for 0 / 0 - u32 VXIDI :1; //Floating-point invalid operation exception for * + * - u32 VXISI :1; //Floating-point invalid operation exception for * - * - u32 VXSNAN :1; //Floating-point invalid operation exception for SNaN - u32 XX :1; //Floating-point inexact exception - u32 ZX :1; //Floating-point zero divide exception - u32 UX :1; //Floating-point underflow exception - u32 OX :1; //Floating-point overflow exception - u32 VX :1; //Floating-point invalid operation exception summary - u32 FEX :1; //Floating-point enabled exception summary - u32 FX :1; //Floating-point exception summary - }; + } - u32 FPSCR; -}; + virtual ~PPUThread() override; -union MSRhdr -{ - struct - { - //Little-endian mode enable - //0 The processor runs in big-endian mode. - //1 The processor runs in little-endian mode. - u64 LE : 1; + u64 GPR[32]{}; // General-Purpose Registers + f64 FPR[32]{}; // Floating Point Registers + v128 VR[32]{}; // Vector Registers + alignas(16) bool CR[32]{}; // Condition Registers + bool SO{}; // XER: Summary overflow + bool OV{}; // XER: Overflow + bool CA{}; // XER: Carry + u8 XCNT{}; // XER: 0..6 - //Recoverable exception (for system reset and machine check exceptions). - //0 Exception is not recoverable. - //1 Exception is recoverable. - u64 RI : 1; - - //Reserved - u64 : 2; - - //Data address translation - //0 Data address translation is disabled. - //1 Data address translation is enabled. - u64 DR : 1; - - //Instruction address translation - //0 Instruction address translation is disabled. - //1 Instruction address translation is enabled. - u64 IR : 1; - - //Exception prefix. The setting of this bit specifies whether an exception vector offset - //is prepended with Fs or 0s. In the following description, nnnnn is the offset of the - //exception. - //0 Exceptions are vectored to the physical address 0x0000_0000_000n_nnnn in 64-bit implementations. - //1 Exceptions are vectored to the physical address 0xFFFF_FFFF_FFFn_nnnn in 64-bit implementations. - u64 IP : 1; - - //Reserved - u64 : 1; - - //Floating-point exception mode 1 - u64 FE1 : 1; - - //Branch trace enable (Optional) - //0 The processor executes branch instructions normally. - //1 The processor generates a branch trace exception after completing the - //execution of a branch instruction, regardless of whether or not the branch was - //taken. - //Note: If the function is not implemented, this bit is treated as reserved. - u64 BE : 1; - - //Single-step trace enable (Optional) - //0 The processor executes instructions normally. - //1 The processor generates a single-step trace exception upon the successful - //execution of the next instruction. - //Note: If the function is not implemented, this bit is treated as reserved. - u64 SE : 1; - - //Floating-point exception mode 0 - u64 FE0 : 1; - - //Machine check enable - //0 Machine check exceptions are disabled. - //1 Machine check exceptions are enabled. - u64 ME : 1; - - //Floating-point available - //0 The processor prevents dispatch of floating-point instructions, including - //floating-point loads, stores, and moves. - //1 The processor can execute floating-point instructions. - u64 FP : 1; - - //Privilege level - //0 The processor can execute both user- and supervisor-level instructions. - //1 The processor can only execute user-level instructions. - u64 PR : 1; - - //External interrupt enable - //0 While the bit is cleared the processor delays recognition of external interrupts - //and decrementer exception conditions. - //1 The processor is enabled to take an external interrupt or the decrementer - //exception. - u64 EE : 1; - - //Exception little-endian mode. When an exception occurs, this bit is copied into - //MSR[LE] to select the endian mode for the context established by the exception - u64 ILE : 1; - - //Reserved - u64 : 1; - - //Power management enable - //0 Power management disabled (normal operation mode). - //1 Power management enabled (reduced power mode). - //Note: Power management functions are implementation-dependent. If the function - //is not implemented, this bit is treated as reserved. - u64 POW : 1; - - //Reserved - u64 : 44; - - //Sixty-four bit mode - //0 The 64-bit processor runs in 32-bit mode. - //1 The 64-bit processor runs in 64-bit mode. Note that this is the default setting. - u64 SF : 1; - }; - - u64 MSR; -}; - -union PVRhdr -{ - struct - { - u16 revision; - u16 version; - }; - - u32 PVR; -}; - -union CRhdr -{ - u32 CR; - - struct - { - u8 cr7 : 4; - u8 cr6 : 4; - u8 cr5 : 4; - u8 cr4 : 4; - u8 cr3 : 4; - u8 cr2 : 4; - u8 cr1 : 4; - u8 cr0 : 4; - }; -}; - -union XERhdr -{ - u64 XER; - - struct - { - u32 L : 29; - u32 CA : 1; - u32 OV : 1; - u32 SO : 1; - u32 : 32; - }; -}; - -union VSCRhdr -{ - u32 VSCR; - - struct - { - /* + /* Saturation. A sticky status bit indicating that some field in a saturating instruction saturated since the last time SAT was cleared. In other words when SAT = '1' it remains set to '1' until it is cleared to '0' by an mtvscr instruction. @@ -261,11 +47,10 @@ union VSCRhdr Vector Pack with Saturation (vpkuhus, vpkuwus, vpkshus, vpkswus, vpkshss, vpkswss) Vector Convert to Fixed-Point with Saturation (vctuxs, vctsxs) 0 Indicates no saturation occurred; mtvscr can explicitly clear this bit. - */ - u32 SAT : 1; - u32 X : 15; + */ + bool SAT{}; - /* + /* Non-Java. A mode control bit that determines whether vector floating-point operations will be performed in a Java-IEEE-C9X-compliant mode or a possibly faster non-Java/non-IEEE mode. 0 The Java-IEEE-C9X-compliant mode is selected. Denormalized values are handled as specified @@ -274,759 +59,162 @@ union VSCRhdr contains a denormalized value, the value '0' is used instead. If an instruction causes an underflow exception, the corresponding element in the target VR is cleared to '0'. In both cases, the '0' has the same sign as the denormalized or underflowing value. - */ - u32 NJ : 1; - u32 Y : 15; - }; -}; + */ + bool NJ{ true }; -enum FPRType -{ - //FPR_NORM, - //FPR_ZERO, - //FPR_SNAN, - //FPR_QNAN, - //FPR_INF, - FPR_PZ = 0x2, - FPR_PN = 0x4, - FPR_PINF = 0x5, - FPR_NN = 0x8, - FPR_NINF = 0x9, - FPR_QNAN = 0x11, - FPR_NZ = 0x12, - FPR_PD = 0x14, - FPR_ND = 0x18, -}; + bool FL{}; // FPSCR.FPCC.FL + bool FG{}; // FPSCR.FPCC.FG + bool FE{}; // FPSCR.FPCC.FE + bool FU{}; // FPSCR.FPCC.FU -static const u64 FPR_NAN_I = 0x7FF8000000000000ULL; -static const double& FPR_NAN = (double&)FPR_NAN_I; + u64 LR{}; // Link Register + u64 CTR{}; // Counter Register + u32 VRSAVE{}; + u32 PC{}; -struct PPCdouble -{ - union - { - double _double; - u64 _u64; - - struct - { - u64 frac : 52; - u64 exp : 11; - u64 sign : 1; - }; - - struct - { - u64 : 51; - u64 nan : 1; - u64 : 12; - }; - }; - - FPRType type; - - operator double&() { return _double; } - operator const double&() const { return _double; } - - PPCdouble& operator = (const PPCdouble& r) - { - _u64 = r._u64; - type = UpdateType(); - return *this; - } - - FPRType UpdateType() const - { - const int fpc = _fpclass(_double); - -#ifndef __GNUG__ - switch(fpc) - { - case _FPCLASS_SNAN:// return FPR_SNAN; - case _FPCLASS_QNAN: return FPR_QNAN; - case _FPCLASS_NINF: return FPR_NINF; - case _FPCLASS_NN: return FPR_NN; - case _FPCLASS_ND: return FPR_ND; - case _FPCLASS_NZ: return FPR_NZ; - case _FPCLASS_PZ: return FPR_PZ; - case _FPCLASS_PD: return FPR_PD; - case _FPCLASS_PN: return FPR_PN; - case _FPCLASS_PINF: return FPR_PINF; - default: throw EXCEPTION("Unknown fpclass (0x%04x)", fpc); - } -#else - switch (fpc) - { - case FP_NAN: return FPR_QNAN; - case FP_INFINITE: return std::signbit(_double) ? FPR_NINF : FPR_PINF; - case FP_SUBNORMAL: return std::signbit(_double) ? FPR_ND : FPR_PD; - case FP_ZERO: return std::signbit(_double) ? FPR_NZ : FPR_PZ; - default: return std::signbit(_double) ? FPR_NN : FPR_PN; - } -#endif - } - - FPRType GetType() const - { - return type; - } - - u32 To32() const - { - float res = (float)_double; - - return (u32&)res; - } - - u64 To64() const - { - return (u64&)_double; - } - - u32 GetZerosCount() const - { - u32 ret; - u32 dd = frac >> 32; - if(dd) - { - ret = 31; - } - else - { - dd = frac; - ret = 63; - } - - if(dd > 0xffff) - { - ret -= 16; - dd >>= 16; - } - if(dd > 0xff) - { - ret -= 8; - dd >>= 8; - } - if(dd & 0xf0) - { - ret -= 4; - dd >>= 4; - } - if(dd & 0xc) - { - ret -= 2; - dd >>= 2; - } - if(dd & 0x2) ret--; - - return ret; - } - - PPCdouble() : _u64(0) - { - type = UpdateType(); - } - - PPCdouble(double val) : _double(val) - { - type = UpdateType(); - } - - PPCdouble(u64 val) : _u64(val) - { - type = UpdateType(); - } - - PPCdouble(u32 val) : _u64(val) - { - type = UpdateType(); - } -}; - -struct FPRdouble -{ - static const u64 double_sign = 0x8000000000000000ULL; - static const u64 double_frac = 0x000FFFFFFFFFFFFFULL; - - static bool IsINF(PPCdouble d); - static bool IsNaN(PPCdouble d); - static bool IsQNaN(PPCdouble d); - static bool IsSNaN(PPCdouble d); - - static int Cmp(PPCdouble a, PPCdouble b); -}; - -class PPUThread final : public CPUThread -{ -public: - PPCdouble FPR[32]{}; //Floating Point Register - FPSCRhdr FPSCR{}; //Floating Point Status and Control Register - u64 GPR[32]{}; //General-Purpose Register - v128 VPR[32]{}; - u32 vpcr = 0; - - CRhdr CR{}; //Condition Register - //CR0 - // 0 : LT - Negative (is negative) - // : 0 - Result is not negative - // : 1 - Result is negative - // 1 : GT - Positive (is positive) - // : 0 - Result is not positive - // : 1 - Result is positive - // 2 : EQ - Zero (is zero) - // : 0 - Result is not equal to zero - // : 1 - Result is equal to zero - // 3 : SO - Summary overflow (copy of the final state XER[S0]) - // : 0 - No overflow occurred - // : 1 - Overflow occurred - - //CRn - // 0 : LT - Less than (rA > X) - // : 0 - rA is not less than - // : 1 - rA is less than - // 1 : GT - Greater than (rA < X) - // : 0 - rA is not greater than - // : 1 - rA is greater than - // 2 : EQ - Equal to (rA == X) - // : 0 - Result is not equal to zero - // : 1 - Result is equal to zero - // 3 : SO - Summary overflow (copy of the final state XER[S0]) - // : 0 - No overflow occurred - // : 1 - Overflow occurred - - //SPR : Special-Purpose Registers - - XERhdr XER{}; //SPR 0x001 : Fixed-Point Expection Register - // 0 : SO - Summary overflow - // : 0 - No overflow occurred - // : 1 - Overflow occurred - // 1 : OV - Overflow - // : 0 - No overflow occurred - // : 1 - Overflow occurred - // 2 : CA - Carry - // : 0 - Carry did not occur - // : 1 - Carry occured - // 3 - 24 : Reserved - // 25 - 31 : TBC - // Transfer-byte count - - MSRhdr MSR{}; //Machine State Register - PVRhdr PVR{}; //Processor Version Register - - VSCRhdr VSCR{}; // Vector Status and Control Register - - u64 LR = 0; //SPR 0x008 : Link Register - u64 CTR = 0; //SPR 0x009 : Count Register - - u32 VRSAVE = 0; //SPR 0x100: VR Save/Restore Register (32 bits) - - u64 SPRG[8]{}; //SPR 0x110 - 0x117 : SPR General-Purpose Registers - - //TBR : Time-Base Registers - u64 TB = 0; //TBR 0x10C - 0x10D - - u32 PC = 0; - s32 prio = 0; // thread priority - u32 stack_addr = 0; // stack address - u32 stack_size = 0; // stack size + s32 prio = 0; // Thread priority + u32 stack_addr = 0; // Stack address + u32 stack_size = 0; // Stack size bool is_joinable = true; bool is_joining = false; - u64 hle_code = 0; // current syscall (~0..~1023) or function id (1..UINT32_MAX) + std::function custom_task; - std::function custom_task; + // Function name can be stored here. Used to print the last called function. + const char* last_function = nullptr; // When a thread has met an exception, this variable is used to retro propagate it through stack call. std::exception_ptr pending_exception; -public: - PPUThread(const std::string& name); - virtual ~PPUThread() override; - - virtual std::string get_name() const override; - virtual void dump_info() const override; - virtual u32 get_pc() const override { return PC; } - virtual u32 get_offset() const override { return 0; } - virtual void do_run() override; - virtual void cpu_task() override; - - virtual void init_regs() override; - virtual void init_stack() override; - virtual void close_stack() override; - - virtual bool handle_interrupt() override; - - u8 GetCR(const u8 n) const + // Pack CR bits + u32 GetCR() const { - switch(n) + u32 result{}; + + for (u32 bit : CR) { - case 0: return CR.cr0; - case 1: return CR.cr1; - case 2: return CR.cr2; - case 3: return CR.cr3; - case 4: return CR.cr4; - case 5: return CR.cr5; - case 6: return CR.cr6; - case 7: return CR.cr7; + result = (result << 1) | bit; } - return 0; + return result; } - void SetCR(const u8 n, const u32 value) + // Unpack CR bits + void SetCR(u32 value) { - switch(n) + for (bool& b : CR) { - case 0: CR.cr0 = value; break; - case 1: CR.cr1 = value; break; - case 2: CR.cr2 = value; break; - case 3: CR.cr3 = value; break; - case 4: CR.cr4 = value; break; - case 5: CR.cr5 = value; break; - case 6: CR.cr6 = value; break; - case 7: CR.cr7 = value; break; + b = (value & 0x1) != 0; + value >>= 1; } } - void SetCRBit(const u8 n, const u32 bit, const bool value) + // Set CR field + void SetCR(u32 field, bool le, bool gt, bool eq, bool so) { - switch(n) - { - case 0: CR.cr0 = (value ? CR.cr0 | bit : CR.cr0 & ~bit); break; - case 1: CR.cr1 = (value ? CR.cr1 | bit : CR.cr1 & ~bit); break; - case 2: CR.cr2 = (value ? CR.cr2 | bit : CR.cr2 & ~bit); break; - case 3: CR.cr3 = (value ? CR.cr3 | bit : CR.cr3 & ~bit); break; - case 4: CR.cr4 = (value ? CR.cr4 | bit : CR.cr4 & ~bit); break; - case 5: CR.cr5 = (value ? CR.cr5 | bit : CR.cr5 & ~bit); break; - case 6: CR.cr6 = (value ? CR.cr6 | bit : CR.cr6 & ~bit); break; - case 7: CR.cr7 = (value ? CR.cr7 | bit : CR.cr7 & ~bit); break; - } + CR[field * 4 + 0] = le; + CR[field * 4 + 1] = gt; + CR[field * 4 + 2] = eq; + CR[field * 4 + 3] = so; } - 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); } - - 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 void UpdateCRn(const u8 n, const T a, const T b) + // Set CR field for comparison + template + void SetCR(u32 field, const T& a, const T& b) { - if (a < b) SetCR(n, CR_LT); - else if (a > b) SetCR(n, CR_GT); - else if (a == b) SetCR(n, CR_EQ); - - SetCR_SO(n, XER.SO); + SetCR(field, a < b, a > b, a == b, SO); } - void UpdateCRnU(const u8 l, const u8 n, const u64 a, const u64 b) - { - if(l) - { - UpdateCRn(n, a, b); - } - else - { - UpdateCRn(n, (u32)a, (u32)b); - } - } - - void UpdateCRnS(const u8 l, const u8 n, const u64 a, const u64 b) - { - if(l) - { - UpdateCRn(n, (s64)a, (s64)b); - } - else - { - UpdateCRn(n, (s32)a, (s32)b); - } - } - - template void UpdateCR0(const T val) - { - UpdateCRn(0, val, 0); - } - - void UpdateCR1() - { - SetCR_LT(1, FPSCR.FX); - SetCR_GT(1, FPSCR.FEX); - SetCR_EQ(1, FPSCR.VX); - SetCR_SO(1, FPSCR.OX); - } - - const u8 GetCRBit(const u32 bit) const { return 1 << (3 - (bit % 4)); } - - void SetCRBit (const u32 bit, bool set) { SetCRBit(bit >> 2, GetCRBit(bit), set); } - void SetCRBit2(const u32 bit, bool set) { SetCRBit(bit >> 2, 0x8 >> (bit & 3), set); } - - const u8 IsCR(const u32 bit) const { return (GetCR(bit >> 2) & GetCRBit(bit)) ? 1 : 0; } - - bool IsCarry(const u64 a, const u64 b) { return (a + b) < a; } - bool IsCarry(const u64 a, const u64 b, const u64 c) { return IsCarry(a, b) || IsCarry(a + b, c); } - + // Set overflow bit void SetOV(const bool set) { - XER.OV = set; - XER.SO |= set; + OV = set; + SO |= set; } - void UpdateFPSCR_FEX() + u64 get_next_arg(u32& g_count) { - const u32 exceptions = (FPSCR.FPSCR >> 25) & 0x1F; - const u32 enabled = (FPSCR.FPSCR >> 3) & 0x1F; - if (exceptions & enabled) FPSCR.FEX = 1; - } - - void UpdateFPSCR_VX() - { - if (FPSCR.FPSCR & FPSCR_VX_ALL) FPSCR.VX = 1; - } - - void SetFPSCR(const u32 val) - { - FPSCR.FPSCR = val & ~(FPSCR_FEX | FPSCR_VX); - UpdateFPSCR_VX(); - UpdateFPSCR_FEX(); - } - - void SetFPSCRException(const FPSCR_EXP mask) - { - if ((FPSCR.FPSCR & mask) != mask) FPSCR.FX = 1; - FPSCR.FPSCR |= mask; - UpdateFPSCR_VX(); - UpdateFPSCR_FEX(); - } - - void SetFPSCR_FI(const u32 val) - { - if(val) SetFPSCRException(FPSCR_XX); - FPSCR.FI = val; - } - - virtual std::string RegsToString() const override - { - std::string ret = "Registers:\n=========\n"; - - for(uint i=0; i<32; ++i) ret += fmt::format("GPR[%d] = 0x%llx\n", i, GPR[i]); - for(uint i=0; i<32; ++i) ret += fmt::format("FPR[%d] = %.6G\n", i, (double)FPR[i]); - for(uint i=0; i<32; ++i) ret += fmt::format("VPR[%d] = 0x%s [%s]\n", i, VPR[i].to_hex().c_str(), VPR[i].to_xyzw().c_str()); - ret += fmt::format("CR = 0x%08x\n", CR.CR); - ret += fmt::format("LR = 0x%llx\n", LR); - ret += fmt::format("CTR = 0x%llx\n", CTR); - ret += fmt::format("XER = 0x%llx [CA=%lld | OV=%lld | SO=%lld]\n", XER.XER, u32{ XER.CA }, u32{ XER.OV }, u32{ XER.SO }); - ret += fmt::format("FPSCR = 0x%x " - "[RN=%d | NI=%d | XE=%d | ZE=%d | UE=%d | OE=%d | VE=%d | " - "VXCVI=%d | VXSQRT=%d | VXSOFT=%d | FPRF=%d | " - "FI=%d | FR=%d | VXVC=%d | VXIMZ=%d | " - "VXZDZ=%d | VXIDI=%d | VXISI=%d | VXSNAN=%d | " - "XX=%d | ZX=%d | UX=%d | OX=%d | VX=%d | FEX=%d | FX=%d]\n", - FPSCR.FPSCR, - u32{ FPSCR.RN }, - u32{ FPSCR.NI }, u32{ FPSCR.XE }, u32{ FPSCR.ZE }, u32{ FPSCR.UE }, u32{ FPSCR.OE }, u32{ FPSCR.VE }, - u32{ FPSCR.VXCVI }, u32{ FPSCR.VXSQRT }, u32{ FPSCR.VXSOFT }, u32{ FPSCR.FPRF }, - u32{ FPSCR.FI }, u32{ FPSCR.FR }, u32{ FPSCR.VXVC }, u32{ FPSCR.VXIMZ }, - u32{ FPSCR.VXZDZ }, u32{ FPSCR.VXIDI }, u32{ FPSCR.VXISI }, u32{ FPSCR.VXSNAN }, - u32{ FPSCR.XX }, u32{ FPSCR.ZX }, u32{ FPSCR.UX }, u32{ FPSCR.OX }, u32{ FPSCR.VX }, u32{ FPSCR.FEX }, u32{ FPSCR.FX }); - - return ret; - } - - virtual std::string ReadRegString(const std::string& reg) const override - { - std::string::size_type first_brk = reg.find('['); - if (first_brk != std::string::npos) - { - long reg_index = atol(reg.substr(first_brk+1,reg.length()-first_brk-2).c_str()); - if (reg.find("GPR")==0) return fmt::format("%016llx", GPR[reg_index]); - if (reg.find("FPR")==0) return fmt::format("%016llx", (double)FPR[reg_index]); - if (reg.find("VPR")==0) return fmt::format("%016llx%016llx", VPR[reg_index]._u64[1], VPR[reg_index]._u64[0]); - } - if (reg == "CR") return fmt::format("%08x", CR.CR); - if (reg == "LR") return fmt::format("%016llx", LR); - if (reg == "CTR") return fmt::format("%016llx", CTR); - if (reg == "XER") return fmt::format("%016llx", XER.XER); - if (reg == "FPSCR") return fmt::format("%08x", FPSCR.FPSCR); - - return ""; - } - - bool WriteRegString(const std::string& reg, std::string value) override - { - while (value.length() < 32) value = "0"+value; - std::string::size_type first_brk = reg.find('['); - try - { - if (first_brk != std::string::npos) - { - long reg_index = atol(reg.substr(first_brk + 1, reg.length() - first_brk - 2).c_str()); - if (reg.find("GPR")==0 || reg.find("FPR")==0 ) - { - unsigned long long reg_value; - reg_value = std::stoull(value.substr(16, 31),0,16); - if (reg.find("GPR")==0) GPR[reg_index] = (u64)reg_value; - if (reg.find("FPR")==0) FPR[reg_index] = (u64)reg_value; - return true; - } - if (reg.find("VPR")==0) - { - unsigned long long reg_value0; - unsigned long long reg_value1; - reg_value0 = std::stoull(value.substr(16, 31), 0, 16); - reg_value1 = std::stoull(value.substr(0, 15), 0, 16); - VPR[reg_index]._u64[0] = (u64)reg_value0; - VPR[reg_index]._u64[1] = (u64)reg_value1; - return true; - } - } - if (reg == "LR" || reg == "CTR" || reg == "XER") - { - unsigned long long reg_value; - reg_value = std::stoull(value.substr(16, 31), 0, 16); - if (reg == "LR") LR = (u64)reg_value; - if (reg == "CTR") CTR = (u64)reg_value; - if (reg == "XER") XER.XER = (u64)reg_value; - return true; - } - if (reg == "CR" || reg == "FPSCR") - { - unsigned long long reg_value; - reg_value = std::stoull(value.substr(24, 31), 0, 16); - if (reg == "CR") CR.CR = (u32)reg_value; - if (reg == "FPSCR") FPSCR.FPSCR = (u32)reg_value; - return true; - } - } - catch (std::invalid_argument&)//if any of the stoull conversion fail - { - return false; - } - return false; - } - - u64 get_next_gpr_arg(u32& g_count, u32& f_count, u32& v_count) - { - assert(!f_count && !v_count); // not supported - if (g_count < 8) { return GPR[g_count++ + 3]; } else { - return get_stack_arg(++g_count); + return *get_stack_arg(++g_count); } } -public: - u64 get_stack_arg(s32 i); + be_t* get_stack_arg(s32 i, u64 align = alignof(u64)); void fast_call(u32 addr, u32 rtoc); - void fast_stop(); }; -class ppu_thread : cpu_thread +template +struct ppu_gpr_cast_impl { - static const u32 stack_align = 0x10; - vm::_ptr_base> argv; - u32 argc; - vm::_ptr_base> envp; - -public: - ppu_thread(u32 entry, const std::string& name = "", u32 stack_size = 0, s32 prio = 0); - - cpu_thread& args(std::initializer_list values) override; - cpu_thread& run() override; - ppu_thread& gpr(uint index, u64 value); + static_assert(!sizeof(T), "Invalid type for ppu_gpr_cast<>"); }; -template::value> -struct cast_ppu_gpr +template +struct ppu_gpr_cast_impl::value || std::is_enum::value>> { - static_assert(is_enum, "Invalid type for cast_ppu_gpr"); + static_assert(sizeof(T) <= 8, "Too big integral type for ppu_gpr_cast<>()"); + static_assert(std::is_same::value == false, "bool type is deprecated in ppu_gpr_cast<>(), use b8 instead"); - force_inline static u64 to_gpr(const T& value) + static inline u64 to(const T& value) { - return cast_ppu_gpr>::to_gpr(static_cast>(value)); + return static_cast(value); } - force_inline static T from_gpr(const u64 reg) + static inline T from(const u64 reg) { - return static_cast(cast_ppu_gpr>::from_gpr(reg)); + return static_cast(reg); } }; template<> -struct cast_ppu_gpr +struct ppu_gpr_cast_impl { - force_inline static u64 to_gpr(const u8& value) + static inline u64 to(const b8& value) { return value; } - force_inline static u8 from_gpr(const u64 reg) - { - return static_cast(reg); - } -}; - -template<> -struct cast_ppu_gpr -{ - force_inline static u64 to_gpr(const u16& value) - { - return value; - } - - force_inline static u16 from_gpr(const u64 reg) - { - return static_cast(reg); - } -}; - -template<> -struct cast_ppu_gpr -{ - force_inline static u64 to_gpr(const u32& value) - { - return value; - } - - force_inline static u32 from_gpr(const u64 reg) - { - return static_cast(reg); - } -}; - -#ifdef __APPLE__ -template<> -struct cast_ppu_gpr -{ - force_inline static u64 to_gpr(const unsigned long& value) - { - return value; - } - - force_inline static unsigned long from_gpr(const u64 reg) - { - return static_cast(reg); - } -}; -#endif - -template<> -struct cast_ppu_gpr -{ - force_inline static u64 to_gpr(const u64& value) - { - return value; - } - - force_inline static u64 from_gpr(const u64 reg) - { - return reg; - } -}; - -template<> -struct cast_ppu_gpr -{ - force_inline static u64 to_gpr(const s8& value) - { - return value; - } - - force_inline static s8 from_gpr(const u64 reg) - { - return static_cast(reg); - } -}; - -template<> -struct cast_ppu_gpr -{ - force_inline static u64 to_gpr(const s16& value) - { - return value; - } - - force_inline static s16 from_gpr(const u64 reg) - { - return static_cast(reg); - } -}; - -template<> -struct cast_ppu_gpr -{ - force_inline static u64 to_gpr(const s32& value) - { - return value; - } - - force_inline static s32 from_gpr(const u64 reg) - { - return static_cast(reg); - } -}; - -template<> -struct cast_ppu_gpr -{ - force_inline static u64 to_gpr(const s64& value) - { - return value; - } - - force_inline static s64 from_gpr(const u64 reg) - { - return static_cast(reg); - } -}; - -template<> -struct cast_ppu_gpr -{ - force_inline static u64 to_gpr(const b8& value) - { - return value; - } - - force_inline static b8 from_gpr(const u64& reg) + static inline b8 from(const u64 reg) { return static_cast(reg) != 0; } }; -template -force_inline u64 cast_to_ppu_gpr(const T& value) +template +struct ppu_gpr_cast_impl, void> { - return cast_ppu_gpr::to_gpr(value); -} + static inline u64 to(const vm::_ptr_base& value) + { + return ppu_gpr_cast_impl::to(value.addr()); + } -template -force_inline T cast_from_ppu_gpr(const u64 reg) -{ - return cast_ppu_gpr::from_gpr(reg); -} - -// flags set in ModuleFunc -enum : u32 -{ - MFF_FORCED_HLE = (1 << 0), // always call HLE function - MFF_NO_RETURN = (1 << 1), // uses EIF_USE_BRANCH flag with LLE, ignored with MFF_FORCED_HLE - - MFF_PERFECT = /* 0 */ MFF_FORCED_HLE, // can be set for fully implemented functions with LLE compatibility + static inline vm::_ptr_base from(const u64 reg) + { + return{ ppu_gpr_cast_impl::from(reg), vm::addr }; + } }; -// flags passed with index -enum : u32 +template +struct ppu_gpr_cast_impl, void> { - EIF_SAVE_RTOC = (1 << 25), // save RTOC in [SP+0x28] before calling HLE/LLE function - EIF_PERFORM_BLR = (1 << 24), // do BLR after calling HLE/LLE function - EIF_USE_BRANCH = (1 << 23), // do only branch, LLE must be set, last_syscall must be zero + static inline u64 to(const vm::_ref_base& value) + { + return ppu_gpr_cast_impl::to(value.addr()); + } - EIF_FLAGS = 0x3800000, // all flags + static inline vm::_ref_base from(const u64 reg) + { + return{ ppu_gpr_cast_impl::from(reg), vm::addr }; + } }; + +template +inline To ppu_gpr_cast(const From& value) +{ + return ppu_gpr_cast_impl::from(ppu_gpr_cast_impl::to(value)); +} diff --git a/rpcs3/Emu/Cell/RawSPUThread.cpp b/rpcs3/Emu/Cell/RawSPUThread.cpp index f0c9c06f6a..facaa0fa3e 100644 --- a/rpcs3/Emu/Cell/RawSPUThread.cpp +++ b/rpcs3/Emu/Cell/RawSPUThread.cpp @@ -1,17 +1,27 @@ #include "stdafx.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Callback.h" +#include "Emu/IdManager.h" +#include "Loader/ELF.h" #include "Emu/Cell/RawSPUThread.h" // Originally, SPU MFC registers are accessed externally in a concurrent manner (don't mix with channels, SPU MFC channels are isolated) thread_local spu_mfc_arg_t raw_spu_mfc[8] = {}; -RawSPUThread::RawSPUThread(const std::string& name, u32 index) - : SPUThread(CPU_THREAD_RAW_SPU, name, index, RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index) +void RawSPUThread::cpu_task() { - CHECK_ASSERTION(vm::falloc(offset, 0x40000) == offset); + // get next PC and SPU Interrupt status + pc = npc.exchange(0); + + set_interrupt_status((pc & 1) != 0); + + pc &= 0x3fffc; + + SPUThread::cpu_task(); + + // save next PC and current SPU Interrupt status + npc = pc | ((ch_event_stat & SPU_EVENT_INTR_ENABLED) != 0); } bool RawSPUThread::read_reg(const u32 addr, u32& value) @@ -81,7 +91,8 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value) } })) { - exec(); + state -= cpu_state::stop; + safe_notify(); } }; @@ -182,7 +193,7 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value) else if (value == SPU_RUNCNTL_STOP_REQUEST) { status &= ~SPU_STATUS_RUNNING; - stop(); + state += cpu_state::stop; } else { @@ -221,17 +232,19 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value) return false; } -void RawSPUThread::cpu_task() +template<> +void spu_exec_loader::load() const { - // get next PC and SPU Interrupt status - pc = npc.exchange(0); + auto spu = idm::make_ptr("TEST_SPU"); - set_interrupt_status((pc & 1) != 0); + for (const auto& prog : progs) + { + if (prog.p_type == 0x1 /* LOAD */ && prog.p_memsz) + { + std::memcpy(vm::base(spu->offset + prog.p_vaddr), prog.bin.data(), prog.p_filesz); + } + } - pc &= 0x3fffc; - - SPUThread::cpu_task(); - - // save next PC and current SPU Interrupt status - npc = pc | ((ch_event_stat & SPU_EVENT_INTR_ENABLED) != 0); + spu->cpu_init(); + spu->npc = header.e_entry; } diff --git a/rpcs3/Emu/Cell/RawSPUThread.h b/rpcs3/Emu/Cell/RawSPUThread.h index 32cf470052..c3a27aa46f 100644 --- a/rpcs3/Emu/Cell/RawSPUThread.h +++ b/rpcs3/Emu/Cell/RawSPUThread.h @@ -2,27 +2,36 @@ #include "SPUThread.h" -enum : u32 -{ - RAW_SPU_OFFSET = 0x00100000, - RAW_SPU_BASE_ADDR = 0xE0000000, - RAW_SPU_LS_OFFSET = 0x00000000, - RAW_SPU_PROB_OFFSET = 0x00040000, -}; - -force_inline static u32 GetRawSPURegAddrByNum(int num, int offset) -{ - return RAW_SPU_OFFSET * num + RAW_SPU_BASE_ADDR + RAW_SPU_PROB_OFFSET + offset; -} - class RawSPUThread final : public SPUThread { + void cpu_task() override; + public: - RawSPUThread(const std::string& name, u32 index); + /* IdManager setups */ + + using id_base = RawSPUThread; + + static constexpr u32 id_min = 0; + static constexpr u32 id_max = 4; + + void on_init() override + { + if (!offset) + { + // Install correct SPU index and LS address + const_cast(index) = id; + const_cast(offset) = vm::falloc(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index, 0x40000); + ASSERT(offset); + + SPUThread::on_init(); + } + } + + RawSPUThread(const std::string& name) + : SPUThread(name) + { + } bool read_reg(const u32 addr, u32& value); bool write_reg(const u32 addr, const u32 value); - -private: - virtual void cpu_task() override; }; diff --git a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp index 1f5f43f9c4..a20f92c4b0 100644 --- a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp @@ -1,4 +1,5 @@ #include "stdafx.h" +#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "SPUDisAsm.h" @@ -9,10 +10,6 @@ #define ASMJIT_STATIC #define ASMJIT_DEBUG -#ifdef _MSC_VER -#pragma comment(lib, "asmjit.lib") -#endif - #include "asmjit.h" #define SPU_OFF_128(x) asmjit::host::oword_ptr(*cpu, OFFSET_32(SPUThread, x)) @@ -21,6 +18,9 @@ #define SPU_OFF_16(x) asmjit::host::word_ptr(*cpu, OFFSET_32(SPUThread, x)) #define SPU_OFF_8(x) asmjit::host::byte_ptr(*cpu, OFFSET_32(SPUThread, x)) +const spu_decoder s_spu_interpreter; // TODO: remove +const spu_decoder s_spu_decoder; + spu_recompiler::spu_recompiler() : m_jit(std::make_shared()) { @@ -29,7 +29,7 @@ spu_recompiler::spu_recompiler() LOG_SUCCESS(SPU, "SPU Recompiler (ASMJIT) created..."); - fs::file(fs::get_config_dir() + "SPUJIT.log", fom::rewrite).write(fmt::format("SPU JIT initialization...\n\nTitle: %s\nTitle ID: %s\n\n", Emu.GetTitle().c_str(), Emu.GetTitleID().c_str())); + fs::file(fs::get_config_dir() + "SPUJIT.log", fs::rewrite).write(fmt::format("SPU JIT initialization...\n\nTitle: %s\nTitle ID: %s\n\n", Emu.GetTitle().c_str(), Emu.GetTitleID().c_str())); } void spu_recompiler::compile(spu_function_t& f) @@ -145,13 +145,13 @@ void spu_recompiler::compile(spu_function_t& f) // Disasm dis_asm.dump_pc = m_pos; - dis_asm.do_disasm(op); + dis_asm.disasm(m_pos); compiler.addComment(dis_asm.last_opcode.c_str()); log += dis_asm.last_opcode.c_str(); log += '\n'; // Recompiler function - (this->*spu_recompiler::opcodes[op])({ op }); + (this->*s_spu_decoder.decode(op))({ op }); // Collect allocated xmm vars for (u32 i = 0; i < vec_vars.size(); i++) @@ -214,7 +214,7 @@ void spu_recompiler::compile(spu_function_t& f) log += "\n\n\n"; // Append log file - fs::file(fs::get_config_dir() + "SPUJIT.log", fom::write | fom::append).write(log); + fs::file(fs::get_config_dir() + "SPUJIT.log", fs::write + fs::append).write(log); } spu_recompiler::XmmLink spu_recompiler::XmmAlloc() // get empty xmm register @@ -267,7 +267,7 @@ void spu_recompiler::InterpreterCall(spu_opcode_t op) const u32 old_pc = _spu->pc; - if (_spu->m_state && _spu->check_status()) + if (_spu->state.load() && _spu->check_status()) { return 0x2000000 | _spu->pc; } @@ -294,7 +294,7 @@ void spu_recompiler::InterpreterCall(spu_opcode_t op) asmjit::X86CallNode* call = c->call(asmjit::imm_ptr(asmjit_cast(gate)), asmjit::kFuncConvHost, asmjit::FuncBuilder3()); call->setArg(0, *cpu); call->setArg(1, asmjit::imm_u(op.opcode)); - call->setArg(2, asmjit::imm_ptr(asmjit_cast(spu_interpreter::fast::g_spu_opcode_table[op.opcode]))); + call->setArg(2, asmjit::imm_ptr(asmjit_cast(s_spu_interpreter.decode(op.opcode)))); call->setRet(0, *addr); // return immediately if an error occured @@ -338,21 +338,20 @@ void spu_recompiler::FunctionCall() LOG_ERROR(SPU, "Branch-to-self"); } - while (!_spu->m_state || !_spu->check_status()) + while (!_spu->state.load() || !_spu->check_status()) { - // Call override function directly since the type is known - static_cast(*_spu->m_dec).DecodeMemory(_spu->offset + _spu->pc); + // Proceed recursively + spu_recompiler_base::enter(*_spu); - if (_spu->m_state & CPU_STATE_RETURN) + if (_spu->state & cpu_state::ret) { break; } if (_spu->pc == link) { - // returned successfully _spu->recursion_level--; - return 0; + return 0; // Successfully returned } } @@ -2185,7 +2184,7 @@ void spu_recompiler::BR(spu_opcode_t op) 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->lock().or_(SPU_OFF_32(state), (to_mset(cpu_state::stop) + cpu_state::ret)._value()); c->jmp(*end); c->unuse(*addr); return; @@ -2614,7 +2613,6 @@ void spu_recompiler::FMS(spu_opcode_t op) void spu_recompiler::UNK(spu_opcode_t op) { - throw EXCEPTION("Unknown/Illegal opcode (0x%08x)", op.opcode); + LOG_ERROR(SPU, "0x%05x: Unknown/Illegal opcode (0x%08x)", m_pos, op.opcode); + c->int3(); } - -const spu_opcode_table_t spu_recompiler::opcodes{ DEFINE_SPU_OPCODES(&spu_recompiler::), &spu_recompiler::UNK }; diff --git a/rpcs3/Emu/Cell/SPUASMJITRecompiler.h b/rpcs3/Emu/Cell/SPUASMJITRecompiler.h index 9655b19ce9..2055a778ca 100644 --- a/rpcs3/Emu/Cell/SPUASMJITRecompiler.h +++ b/rpcs3/Emu/Cell/SPUASMJITRecompiler.h @@ -13,7 +13,7 @@ namespace asmjit } // SPU ASMJIT Recompiler -class spu_recompiler : public SPURecompilerBase +class spu_recompiler : public spu_recompiler_base { const std::shared_ptr m_jit; @@ -75,7 +75,7 @@ private: asmjit::X86Mem XmmConst(__m128 data); asmjit::X86Mem XmmConst(__m128i data); -private: +public: void InterpreterCall(spu_opcode_t op); void FunctionCall(); @@ -280,6 +280,4 @@ private: void FMS(spu_opcode_t op); void UNK(spu_opcode_t op); - - static const spu_opcode_table_t opcodes; }; diff --git a/rpcs3/Emu/Cell/SPUAnalyser.cpp b/rpcs3/Emu/Cell/SPUAnalyser.cpp index d8e063c7b2..57cc2d4b14 100644 --- a/rpcs3/Emu/Cell/SPUAnalyser.cpp +++ b/rpcs3/Emu/Cell/SPUAnalyser.cpp @@ -4,7 +4,7 @@ #include "SPURecompiler.h" #include "SPUAnalyser.h" -const spu_opcode_table_t g_spu_itype{ DEFINE_SPU_OPCODES(spu_itype::), spu_itype::UNK }; +const spu_decoder s_spu_itype; std::shared_ptr SPUDatabase::find(const be_t* data, u64 key, u32 max_size) { @@ -83,7 +83,7 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en { const spu_opcode_t op{ ls[pos / 4] }; - const spu_itype_t type = g_spu_itype[op.opcode]; + const auto type = s_spu_itype.decode(op.opcode); using namespace spu_itype; @@ -172,15 +172,15 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en break; } - if (type == BI || type == IRET) // Branch Indirect + if (type == &type::BI || type == &type::IRET) // Branch Indirect { - if (type == IRET) LOG_ERROR(SPU, "[0x%05x] Interrupt Return", pos); + if (type == &type::IRET) LOG_ERROR(SPU, "[0x%05x] Interrupt Return", pos); blocks.emplace(start); start = pos + 4; } - else if (type == BR || type == BRA) // Branch Relative/Absolute + else if (type == &type::BR || type == &type::BRA) // Branch Relative/Absolute { - const u32 target = spu_branch_target(type == BR ? pos : 0, op.i16); + const u32 target = spu_branch_target(type == &type::BR ? pos : 0, op.i16); // Add adjacent function because it always could be adjacent.emplace(target); @@ -192,9 +192,9 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en blocks.emplace(start); start = pos + 4; } - else if (type == BRSL || type == BRASL) // Branch Relative/Absolute and Set Link + else if (type == &type::BRSL || type == &type::BRASL) // Branch Relative/Absolute and Set Link { - const u32 target = spu_branch_target(type == BRSL ? pos : 0, op.i16); + const u32 target = spu_branch_target(type == &type::BRSL ? pos : 0, op.i16); if (target == pos + 4) { @@ -215,11 +215,11 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en if (op.rt != 0) LOG_ERROR(SPU, "[0x%05x] Function call without $LR", pos); } } - else if (type == BISL || type == BISLED) // Branch Indirect and Set Link + else if (type == &type::BISL || type == &type::BISLED) // Branch Indirect and Set Link { if (op.rt != 0) LOG_ERROR(SPU, "[0x%05x] Indirect function call without $LR", pos); } - else if (type == BRNZ || type == BRZ || type == BRHNZ || type == BRHZ) // Branch Relative if (Not) Zero (Half)word + else if (type == &type::BRNZ || type == &type::BRZ || type == &type::BRHNZ || type == &type::BRHZ) // Branch Relative if (Not) Zero (Half)word { const u32 target = spu_branch_target(pos, op.i16); @@ -231,24 +231,24 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en blocks.emplace(target); } } - else if (type == BINZ || type == BIZ || type == BIHNZ || type == BIHZ) // Branch Indirect if (Not) Zero (Half)word + else if (type == &type::BINZ || type == &type::BIZ || type == &type::BIHNZ || type == &type::BIHZ) // Branch Indirect if (Not) Zero (Half)word { } - else if (type == HBR || type == HBRA || type == HBRR) // Hint for Branch + else if (type == &type::HBR || type == &type::HBRA || type == &type::HBRR) // Hint for Branch { } - else if (type == STQA || type == STQD || type == STQR || type == STQX || type == FSCRWR || type == MTSPR || type == WRCH) // Store + else if (type == &type::STQA || type == &type::STQD || type == &type::STQR || type == &type::STQX || type == &type::FSCRWR || type == &type::MTSPR || type == &type::WRCH) // Store { } - else if (type == HEQ || type == HEQI || type == HGT || type == HGTI || type == HLGT || type == HLGTI) // Halt + else if (type == &type::HEQ || type == &type::HEQI || type == &type::HGT || type == &type::HGTI || type == &type::HLGT || type == &type::HLGTI) // Halt { } - else if (type == STOP || type == STOPD || type == NOP || type == LNOP || type == SYNC || type == DSYNC) // Miscellaneous + else if (type == &type::STOP || type == &type::STOPD || type == &type::NOP || type == &type::LNOP || type == &type::SYNC || type == &type::DSYNC) // Miscellaneous { } 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 == &type::SELB || type == &type::SHUFB || type == &type::MPYA || type == &type::FNMS || type == &type::FMA || type == &type::FMS ? +op.rc : +op.rt; // Analyse link register access if (rt == 0) @@ -258,7 +258,7 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en // Analyse stack pointer access if (rt == 1) { - if (type == ILA && pos < ila_sp_pos) + if (type == &type::ILA && pos < ila_sp_pos) { // set minimal ila $SP,* instruction position ila_sp_pos = pos; @@ -272,7 +272,7 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en { const spu_opcode_t op{ ls[pos / 4] }; - const spu_itype_t type = g_spu_itype[op.opcode]; + const auto type = s_spu_itype.decode(op.opcode); using namespace spu_itype; @@ -280,9 +280,9 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en { break; } - else if (type == BRSL || type == BRASL) // Branch Relative/Absolute and Set Link + else if (type == &type::BRSL || type == &type::BRASL) // Branch Relative/Absolute and Set Link { - const u32 target = spu_branch_target(type == BRSL ? pos : 0, op.i16); + const u32 target = spu_branch_target(type == &type::BRSL ? pos : 0, op.i16); if (target != pos + 4 && target > entry && limit > target) { diff --git a/rpcs3/Emu/Cell/SPUAnalyser.h b/rpcs3/Emu/Cell/SPUAnalyser.h index c03429f134..1588d31c8a 100644 --- a/rpcs3/Emu/Cell/SPUAnalyser.h +++ b/rpcs3/Emu/Cell/SPUAnalyser.h @@ -3,250 +3,246 @@ #include "Emu/Cell/SPUOpcodes.h" #include "Utilities/SharedMutex.h" +#include + class SPUThread; // Type of the runtime functions generated by SPU recompiler using spu_jit_func_t = u32(*)(SPUThread* _spu, be_t* _ls); -// SPU instruction classification namespace +// SPU Instruction Classifier namespace spu_itype { - enum spu_itype_t : u32 + struct type { - UNK = 0, - - STOP, - LNOP, - SYNC, - DSYNC, - MFSPR, - RDCH, - RCHCNT, - SF, - OR, - BG, - SFH, - NOR, - ABSDB, - ROT, - ROTM, - ROTMA, - SHL, - ROTH, - ROTHM, - ROTMAH, - SHLH, - ROTI, - ROTMI, - ROTMAI, - SHLI, - ROTHI, - ROTHMI, - ROTMAHI, - SHLHI, - A, - AND, - CG, - AH, - NAND, - AVGB, - MTSPR, - WRCH, - BIZ, - BINZ, - BIHZ, - BIHNZ, - STOPD, - STQX, - BI, - BISL, - IRET, - BISLED, - HBR, - GB, - GBH, - GBB, - FSM, - FSMH, - FSMB, - FREST, - FRSQEST, - LQX, - ROTQBYBI, - ROTQMBYBI, - SHLQBYBI, - CBX, - CHX, - CWX, - CDX, - ROTQBI, - ROTQMBI, - SHLQBI, - ROTQBY, - ROTQMBY, - SHLQBY, - ORX, - CBD, - CHD, - CWD, - CDD, - ROTQBII, - ROTQMBII, - SHLQBII, - ROTQBYI, - ROTQMBYI, - SHLQBYI, - NOP, - CGT, - XOR, - CGTH, - EQV, - CGTB, - SUMB, - HGT, - CLZ, - XSWD, - XSHW, - CNTB, - XSBH, - CLGT, - ANDC, - FCGT, - DFCGT, - FA, - FS, - FM, - CLGTH, - ORC, - FCMGT, - DFCMGT, - DFA, - DFS, - DFM, - CLGTB, - HLGT, - DFMA, - DFMS, - DFNMS, - DFNMA, - CEQ, - MPYHHU, - ADDX, - SFX, - CGX, - BGX, - MPYHHA, - MPYHHAU, - FSCRRD, - FESD, - FRDS, - FSCRWR, - DFTSV, - FCEQ, - DFCEQ, - MPY, - MPYH, - MPYHH, - MPYS, - CEQH, - FCMEQ, - DFCMEQ, - MPYU, - CEQB, - FI, - HEQ, - CFLTS, - CFLTU, - CSFLT, - CUFLT, - BRZ, - STQA, - BRNZ, - BRHZ, - BRHNZ, - STQR, - BRA, - LQA, - BRASL, - BR, - FSMBI, - BRSL, - LQR, - IL, - ILHU, - ILH, - IOHL, - ORI, - ORHI, - ORBI, - SFI, - SFHI, - ANDI, - ANDHI, - ANDBI, - AI, - AHI, - STQD, - LQD, - XORI, - XORHI, - XORBI, - CGTI, - CGTHI, - CGTBI, - HGTI, - CLGTI, - CLGTHI, - CLGTBI, - HLGTI, - MPYI, - MPYUI, - CEQI, - CEQHI, - CEQBI, - HEQI, - HBRA, - HBRR, - ILA, - SELB, - SHUFB, - MPYA, - FNMS, - FMA, - FMS, + u32 UNK; + u32 STOP; + u32 LNOP; + u32 SYNC; + u32 DSYNC; + u32 MFSPR; + u32 RDCH; + u32 RCHCNT; + u32 SF; + u32 OR; + u32 BG; + u32 SFH; + u32 NOR; + u32 ABSDB; + u32 ROT; + u32 ROTM; + u32 ROTMA; + u32 SHL; + u32 ROTH; + u32 ROTHM; + u32 ROTMAH; + u32 SHLH; + u32 ROTI; + u32 ROTMI; + u32 ROTMAI; + u32 SHLI; + u32 ROTHI; + u32 ROTHMI; + u32 ROTMAHI; + u32 SHLHI; + u32 A; + u32 AND; + u32 CG; + u32 AH; + u32 NAND; + u32 AVGB; + u32 MTSPR; + u32 WRCH; + u32 BIZ; + u32 BINZ; + u32 BIHZ; + u32 BIHNZ; + u32 STOPD; + u32 STQX; + u32 BI; + u32 BISL; + u32 IRET; + u32 BISLED; + u32 HBR; + u32 GB; + u32 GBH; + u32 GBB; + u32 FSM; + u32 FSMH; + u32 FSMB; + u32 FREST; + u32 FRSQEST; + u32 LQX; + u32 ROTQBYBI; + u32 ROTQMBYBI; + u32 SHLQBYBI; + u32 CBX; + u32 CHX; + u32 CWX; + u32 CDX; + u32 ROTQBI; + u32 ROTQMBI; + u32 SHLQBI; + u32 ROTQBY; + u32 ROTQMBY; + u32 SHLQBY; + u32 ORX; + u32 CBD; + u32 CHD; + u32 CWD; + u32 CDD; + u32 ROTQBII; + u32 ROTQMBII; + u32 SHLQBII; + u32 ROTQBYI; + u32 ROTQMBYI; + u32 SHLQBYI; + u32 NOP; + u32 CGT; + u32 XOR; + u32 CGTH; + u32 EQV; + u32 CGTB; + u32 SUMB; + u32 HGT; + u32 CLZ; + u32 XSWD; + u32 XSHW; + u32 CNTB; + u32 XSBH; + u32 CLGT; + u32 ANDC; + u32 FCGT; + u32 DFCGT; + u32 FA; + u32 FS; + u32 FM; + u32 CLGTH; + u32 ORC; + u32 FCMGT; + u32 DFCMGT; + u32 DFA; + u32 DFS; + u32 DFM; + u32 CLGTB; + u32 HLGT; + u32 DFMA; + u32 DFMS; + u32 DFNMS; + u32 DFNMA; + u32 CEQ; + u32 MPYHHU; + u32 ADDX; + u32 SFX; + u32 CGX; + u32 BGX; + u32 MPYHHA; + u32 MPYHHAU; + u32 FSCRRD; + u32 FESD; + u32 FRDS; + u32 FSCRWR; + u32 DFTSV; + u32 FCEQ; + u32 DFCEQ; + u32 MPY; + u32 MPYH; + u32 MPYHH; + u32 MPYS; + u32 CEQH; + u32 FCMEQ; + u32 DFCMEQ; + u32 MPYU; + u32 CEQB; + u32 FI; + u32 HEQ; + u32 CFLTS; + u32 CFLTU; + u32 CSFLT; + u32 CUFLT; + u32 BRZ; + u32 STQA; + u32 BRNZ; + u32 BRHZ; + u32 BRHNZ; + u32 STQR; + u32 BRA; + u32 LQA; + u32 BRASL; + u32 BR; + u32 FSMBI; + u32 BRSL; + u32 LQR; + u32 IL; + u32 ILHU; + u32 ILH; + u32 IOHL; + u32 ORI; + u32 ORHI; + u32 ORBI; + u32 SFI; + u32 SFHI; + u32 ANDI; + u32 ANDHI; + u32 ANDBI; + u32 AI; + u32 AHI; + u32 STQD; + u32 LQD; + u32 XORI; + u32 XORHI; + u32 XORBI; + u32 CGTI; + u32 CGTHI; + u32 CGTBI; + u32 HGTI; + u32 CLGTI; + u32 CLGTHI; + u32 CLGTBI; + u32 HLGTI; + u32 MPYI; + u32 MPYUI; + u32 CEQI; + u32 CEQHI; + u32 CEQBI; + u32 HEQI; + u32 HBRA; + u32 HBRR; + u32 ILA; + u32 SELB; + u32 SHUFB; + u32 MPYA; + u32 FNMS; + u32 FMA; + u32 FMS; }; -} - -using spu_itype::spu_itype_t; - -// SPU Instruction Classification table -extern const spu_opcode_table_t g_spu_itype; +}; // SPU basic function information structure struct spu_function_t { - // entry point (LS address) + // Entry point (LS address) const u32 addr; - // function size (in bytes) + // Function size (in bytes) const u32 size; - // function contents (binary copy) + // Function contents (binary copy) std::vector> data; - // basic blocks (start addresses) + // Basic blocks (start addresses) std::set blocks; - // functions possibly called by this function (may not be available) + // Functions possibly called by this function (may not be available) std::set adjacent; - // jump table values (start addresses) + // Jump table values (start addresses) std::set jtable; - // whether ila $SP,* instruction found + // Whether ila $SP,* instruction found bool does_reset_stack; - // pointer to the compiled function + // Pointer to the compiled function spu_jit_func_t compiled = nullptr; spu_function_t(u32 addr, u32 size) diff --git a/rpcs3/Emu/Cell/SPUContext.h b/rpcs3/Emu/Cell/SPUContext.h deleted file mode 100644 index 9c408ffdd2..0000000000 --- a/rpcs3/Emu/Cell/SPUContext.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -struct spu_context_t -{ -}; diff --git a/rpcs3/Emu/Cell/SPUDisAsm.cpp b/rpcs3/Emu/Cell/SPUDisAsm.cpp new file mode 100644 index 0000000000..85b5eeb14e --- /dev/null +++ b/rpcs3/Emu/Cell/SPUDisAsm.cpp @@ -0,0 +1,11 @@ +#include "stdafx.h" +#include "SPUDisAsm.h" + +const spu_decoder s_spu_disasm; + +u32 SPUDisAsm::disasm(u32 pc) +{ + const u32 op = *(be_t*)(offset + pc); + (this->*(s_spu_disasm.decode(op)))({ op }); + return 4; +} diff --git a/rpcs3/Emu/Cell/SPUDisAsm.h b/rpcs3/Emu/Cell/SPUDisAsm.h index 0583d9fa04..69d10c4c8a 100644 --- a/rpcs3/Emu/Cell/SPUDisAsm.h +++ b/rpcs3/Emu/Cell/SPUDisAsm.h @@ -66,7 +66,7 @@ static const char* spu_ch_name[128] = "$ch121", "$ch122", "$ch123", "$ch124", "$ch125", "$ch126", "$ch127", }; -class SPUDisAsm : public PPCDisAsm +class SPUDisAsm final : public PPCDisAsm { public: SPUDisAsm(CPUDisAsmMode mode) : PPCDisAsm(mode) @@ -133,6 +133,10 @@ private: { Write(fmt::format("%s %s,%s,%s,%s", FixOp(op).c_str(), a1, a2, a3, a4)); } + +public: + u32 disasm(u32 pc) override; + //0 - 10 void STOP(spu_opcode_t op) { @@ -945,12 +949,4 @@ private: { Write(fmt::format("Unknown/Illegal opcode! (0x%08x)", op.opcode)); } - - static const spu_opcode_table_t opcodes; - -public: - void do_disasm(u32 opcode) - { - (this->*opcodes[opcode])({ opcode }); - } }; diff --git a/rpcs3/Emu/Cell/SPUInterpreter.cpp b/rpcs3/Emu/Cell/SPUInterpreter.cpp index 0c669c37ac..8af145cbe6 100644 --- a/rpcs3/Emu/Cell/SPUInterpreter.cpp +++ b/rpcs3/Emu/Cell/SPUInterpreter.cpp @@ -7,20 +7,7 @@ #include -namespace spu_interpreter -{ - namespace fast - { - const spu_opcode_table_t g_spu_opcode_table{ DEFINE_SPU_OPCODES(+), default_function }; - } - - namespace precise - { - const spu_opcode_table_t g_spu_opcode_table{ DEFINE_SPU_OPCODES(+), default_function }; - } -} - -void spu_interpreter::default_function(SPUThread& spu, spu_opcode_t op) +void spu_interpreter::UNK(SPUThread& spu, spu_opcode_t op) { throw EXCEPTION("Unknown/Illegal instruction (0x%08x)", op.opcode); } @@ -396,12 +383,12 @@ void spu_interpreter::FSMB(SPUThread& spu, spu_opcode_t op) spu.gpr[op.rt] = g_spu_imm.fsmb[spu.gpr[op.ra]._u32[3] & 0xffff]; } -void spu_interpreter::fast::FREST(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FREST(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vf = _mm_rcp_ps(spu.gpr[op.ra].vf); } -void spu_interpreter::fast::FRSQEST(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FRSQEST(SPUThread& spu, spu_opcode_t op) { const auto mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)); spu.gpr[op.rt].vf = _mm_rsqrt_ps(_mm_and_ps(spu.gpr[op.ra].vf, mask)); @@ -687,7 +674,7 @@ void spu_interpreter::ANDC(SPUThread& spu, spu_opcode_t op) spu.gpr[op.rt] = v128::andnot(spu.gpr[op.rb], spu.gpr[op.ra]); } -void spu_interpreter::fast::FCGT(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FCGT(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vf = _mm_cmplt_ps(spu.gpr[op.rb].vf, spu.gpr[op.ra].vf); } @@ -697,17 +684,17 @@ void spu_interpreter::DFCGT(SPUThread& spu, spu_opcode_t op) throw EXCEPTION("Unexpected instruction"); } -void spu_interpreter::fast::FA(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FA(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt] = v128::addfs(spu.gpr[op.ra], spu.gpr[op.rb]); } -void spu_interpreter::fast::FS(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FS(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt] = v128::subfs(spu.gpr[op.ra], spu.gpr[op.rb]); } -void spu_interpreter::fast::FM(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FM(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vf = _mm_mul_ps(spu.gpr[op.ra].vf, spu.gpr[op.rb].vf); } @@ -722,7 +709,7 @@ void spu_interpreter::ORC(SPUThread& spu, spu_opcode_t op) spu.gpr[op.rt] = spu.gpr[op.ra] | ~spu.gpr[op.rb]; } -void spu_interpreter::fast::FCMGT(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FCMGT(SPUThread& spu, spu_opcode_t op) { const auto mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)); spu.gpr[op.rt].vf = _mm_cmplt_ps(_mm_and_ps(spu.gpr[op.rb].vf, mask), _mm_and_ps(spu.gpr[op.ra].vf, mask)); @@ -733,17 +720,17 @@ void spu_interpreter::DFCMGT(SPUThread& spu, spu_opcode_t op) throw EXCEPTION("Unexpected instruction"); } -void spu_interpreter::fast::DFA(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::DFA(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt] = v128::addfd(spu.gpr[op.ra], spu.gpr[op.rb]); } -void spu_interpreter::fast::DFS(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::DFS(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt] = v128::subfd(spu.gpr[op.ra], spu.gpr[op.rb]); } -void spu_interpreter::fast::DFM(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::DFM(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vd = _mm_mul_pd(spu.gpr[op.ra].vd, spu.gpr[op.rb].vd); } @@ -761,22 +748,22 @@ void spu_interpreter::HLGT(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::fast::DFMA(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::DFMA(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vd = _mm_add_pd(_mm_mul_pd(spu.gpr[op.ra].vd, spu.gpr[op.rb].vd), spu.gpr[op.rt].vd); } -void spu_interpreter::fast::DFMS(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::DFMS(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vd = _mm_sub_pd(_mm_mul_pd(spu.gpr[op.ra].vd, spu.gpr[op.rb].vd), spu.gpr[op.rt].vd); } -void spu_interpreter::fast::DFNMS(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::DFNMS(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vd = _mm_sub_pd(spu.gpr[op.rt].vd, _mm_mul_pd(spu.gpr[op.ra].vd, spu.gpr[op.rb].vd)); } -void spu_interpreter::fast::DFNMA(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::DFNMA(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vd = _mm_sub_pd(_mm_set1_pd(0.0), _mm_add_pd(_mm_mul_pd(spu.gpr[op.ra].vd, spu.gpr[op.rb].vd), spu.gpr[op.rt].vd)); } @@ -833,24 +820,24 @@ void spu_interpreter::MPYHHAU(SPUThread& spu, spu_opcode_t op) spu.gpr[op.rt].vi = _mm_add_epi32(spu.gpr[op.rt].vi, _mm_or_si128(_mm_srli_epi32(_mm_mullo_epi16(a, b), 16), _mm_and_si128(_mm_mulhi_epu16(a, b), _mm_set1_epi32(0xffff0000)))); } -void spu_interpreter::fast::FSCRRD(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FSCRRD(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].clear(); } -void spu_interpreter::fast::FESD(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FESD(SPUThread& spu, spu_opcode_t op) { const auto a = spu.gpr[op.ra].vf; spu.gpr[op.rt].vd = _mm_cvtps_pd(_mm_shuffle_ps(a, a, 0x8d)); } -void spu_interpreter::fast::FRDS(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FRDS(SPUThread& spu, spu_opcode_t op) { const auto t = _mm_cvtpd_ps(spu.gpr[op.ra].vd); spu.gpr[op.rt].vf = _mm_shuffle_ps(t, t, 0x72); } -void spu_interpreter::fast::FSCRWR(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FSCRWR(SPUThread& spu, spu_opcode_t op) { } @@ -859,7 +846,7 @@ void spu_interpreter::DFTSV(SPUThread& spu, spu_opcode_t op) throw EXCEPTION("Unexpected instruction"); } -void spu_interpreter::fast::FCEQ(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FCEQ(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vf = _mm_cmpeq_ps(spu.gpr[op.rb].vf, spu.gpr[op.ra].vf); } @@ -895,7 +882,7 @@ void spu_interpreter::CEQH(SPUThread& spu, spu_opcode_t op) spu.gpr[op.rt].vi = _mm_cmpeq_epi16(spu.gpr[op.ra].vi, spu.gpr[op.rb].vi); } -void spu_interpreter::fast::FCMEQ(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FCMEQ(SPUThread& spu, spu_opcode_t op) { const auto mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)); spu.gpr[op.rt].vf = _mm_cmpeq_ps(_mm_and_ps(spu.gpr[op.rb].vf, mask), _mm_and_ps(spu.gpr[op.ra].vf, mask)); @@ -918,7 +905,7 @@ void spu_interpreter::CEQB(SPUThread& spu, spu_opcode_t op) spu.gpr[op.rt].vi = _mm_cmpeq_epi8(spu.gpr[op.ra].vi, spu.gpr[op.rb].vi); } -void spu_interpreter::fast::FI(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FI(SPUThread& spu, spu_opcode_t op) { // TODO const auto mask_se = _mm_castsi128_ps(_mm_set1_epi32(0xff800000)); // sign and exponent mask @@ -940,25 +927,25 @@ void spu_interpreter::HEQ(SPUThread& spu, spu_opcode_t op) } -void spu_interpreter::fast::CFLTS(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::CFLTS(SPUThread& spu, spu_opcode_t op) { const auto scaled = _mm_mul_ps(spu.gpr[op.ra].vf, g_spu_imm.scale[173 - op.i8]); spu.gpr[op.rt].vi = _mm_xor_si128(_mm_cvttps_epi32(scaled), _mm_castps_si128(_mm_cmpge_ps(scaled, _mm_set1_ps(0x80000000)))); } -void spu_interpreter::fast::CFLTU(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::CFLTU(SPUThread& spu, spu_opcode_t op) { const auto scaled1 = _mm_max_ps(_mm_mul_ps(spu.gpr[op.ra].vf, g_spu_imm.scale[173 - op.i8]), _mm_set1_ps(0.0f)); const auto scaled2 = _mm_and_ps(_mm_sub_ps(scaled1, _mm_set1_ps(0x80000000)), _mm_cmpge_ps(scaled1, _mm_set1_ps(0x80000000))); spu.gpr[op.rt].vi = _mm_or_si128(_mm_or_si128(_mm_cvttps_epi32(scaled1), _mm_cvttps_epi32(scaled2)), _mm_castps_si128(_mm_cmpge_ps(scaled1, _mm_set1_ps(0x100000000)))); } -void spu_interpreter::fast::CSFLT(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::CSFLT(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vf = _mm_mul_ps(_mm_cvtepi32_ps(spu.gpr[op.ra].vi), g_spu_imm.scale[op.i8 - 155]); } -void spu_interpreter::fast::CUFLT(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::CUFLT(SPUThread& spu, spu_opcode_t op) { const auto a = spu.gpr[op.ra].vi; const auto fix = _mm_and_ps(_mm_castsi128_ps(_mm_srai_epi32(a, 31)), _mm_set1_ps(0x80000000)); @@ -1265,17 +1252,17 @@ void spu_interpreter::MPYA(SPUThread& spu, spu_opcode_t op) 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) +void spu_interpreter_fast::FNMS(SPUThread& spu, spu_opcode_t op) { 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) +void spu_interpreter_fast::FMA(SPUThread& spu, spu_opcode_t op) { 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) +void spu_interpreter_fast::FMS(SPUThread& spu, spu_opcode_t op) { 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); } @@ -1360,7 +1347,7 @@ inline bool isdenormal(double x) #endif } -void spu_interpreter::precise::FREST(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FREST(SPUThread& spu, spu_opcode_t op) { SetHostRoundingMode(FPSCR_RN_ZERO); for (int i = 0; i < 4; i++) @@ -1380,7 +1367,7 @@ void spu_interpreter::precise::FREST(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::FRSQEST(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FRSQEST(SPUThread& spu, spu_opcode_t op) { SetHostRoundingMode(FPSCR_RN_ZERO); for (int i = 0; i < 4; i++) @@ -1400,7 +1387,7 @@ void spu_interpreter::precise::FRSQEST(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::FCGT(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FCGT(SPUThread& spu, spu_opcode_t op) { for (int i = 0; i < 4; i++) { @@ -1508,11 +1495,11 @@ static void FA_FS(SPUThread& spu, spu_opcode_t op, bool sub) } } -void spu_interpreter::precise::FA(SPUThread& spu, spu_opcode_t op) { FA_FS(spu, op, false); } +void spu_interpreter_precise::FA(SPUThread& spu, spu_opcode_t op) { FA_FS(spu, op, false); } -void spu_interpreter::precise::FS(SPUThread& spu, spu_opcode_t op) { FA_FS(spu, op, true); } +void spu_interpreter_precise::FS(SPUThread& spu, spu_opcode_t op) { FA_FS(spu, op, true); } -void spu_interpreter::precise::FM(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FM(SPUThread& spu, spu_opcode_t op) { SetHostRoundingMode(FPSCR_RN_ZERO); for (int w = 0; w < 4; w++) @@ -1585,7 +1572,7 @@ void spu_interpreter::precise::FM(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::FCMGT(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FCMGT(SPUThread& spu, spu_opcode_t op) { for (int i = 0; i < 4; i++) { @@ -1666,11 +1653,11 @@ static void DFASM(SPUThread& spu, spu_opcode_t op, DoubleOp operation) } } -void spu_interpreter::precise::DFA(SPUThread& spu, spu_opcode_t op) { DFASM(spu, op, DFASM_A); } +void spu_interpreter_precise::DFA(SPUThread& spu, spu_opcode_t op) { DFASM(spu, op, DFASM_A); } -void spu_interpreter::precise::DFS(SPUThread& spu, spu_opcode_t op) { DFASM(spu, op, DFASM_S); } +void spu_interpreter_precise::DFS(SPUThread& spu, spu_opcode_t op) { DFASM(spu, op, DFASM_S); } -void spu_interpreter::precise::DFM(SPUThread& spu, spu_opcode_t op) { DFASM(spu, op, DFASM_M); } +void spu_interpreter_precise::DFM(SPUThread& spu, spu_opcode_t op) { DFASM(spu, op, DFASM_M); } static void DFMA(SPUThread& spu, spu_opcode_t op, bool neg, bool sub) { @@ -1727,20 +1714,20 @@ static void DFMA(SPUThread& spu, spu_opcode_t op, bool neg, bool sub) } } -void spu_interpreter::precise::DFMA(SPUThread& spu, spu_opcode_t op) { DFMA(spu, op, false, false); } +void spu_interpreter_precise::DFMA(SPUThread& spu, spu_opcode_t op) { ::DFMA(spu, op, false, false); } -void spu_interpreter::precise::DFMS(SPUThread& spu, spu_opcode_t op) { DFMA(spu, op, false, true); } +void spu_interpreter_precise::DFMS(SPUThread& spu, spu_opcode_t op) { ::DFMA(spu, op, false, true); } -void spu_interpreter::precise::DFNMS(SPUThread& spu, spu_opcode_t op) { DFMA(spu, op, true, true); } +void spu_interpreter_precise::DFNMS(SPUThread& spu, spu_opcode_t op) { ::DFMA(spu, op, true, true); } -void spu_interpreter::precise::DFNMA(SPUThread& spu, spu_opcode_t op) { DFMA(spu, op, true, false); } +void spu_interpreter_precise::DFNMA(SPUThread& spu, spu_opcode_t op) { ::DFMA(spu, op, true, false); } -void spu_interpreter::precise::FSCRRD(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FSCRRD(SPUThread& spu, spu_opcode_t op) { spu.fpscr.Read(spu.gpr[op.rt]); } -void spu_interpreter::precise::FESD(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FESD(SPUThread& spu, spu_opcode_t op) { for (int i = 0; i < 2; i++) { @@ -1764,7 +1751,7 @@ void spu_interpreter::precise::FESD(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::FRDS(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FRDS(SPUThread& spu, spu_opcode_t op) { for (int i = 0; i < 2; i++) { @@ -1792,12 +1779,12 @@ void spu_interpreter::precise::FRDS(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::FSCRWR(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FSCRWR(SPUThread& spu, spu_opcode_t op) { spu.fpscr.Write(spu.gpr[op.ra]); } -void spu_interpreter::precise::FCEQ(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FCEQ(SPUThread& spu, spu_opcode_t op) { for (int i = 0; i < 4; i++) { @@ -1812,7 +1799,7 @@ void spu_interpreter::precise::FCEQ(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::FCMEQ(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FCMEQ(SPUThread& spu, spu_opcode_t op) { for (int i = 0; i < 4; i++) { @@ -1827,13 +1814,13 @@ void spu_interpreter::precise::FCMEQ(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::FI(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FI(SPUThread& spu, spu_opcode_t op) { // TODO spu.gpr[op.rt] = spu.gpr[op.rb]; } -void spu_interpreter::precise::CFLTS(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::CFLTS(SPUThread& spu, spu_opcode_t op) { const int scale = 173 - (op.i8 & 0xff); //unsigned immediate for (int i = 0; i < 4; i++) @@ -1855,7 +1842,7 @@ void spu_interpreter::precise::CFLTS(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::CFLTU(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::CFLTU(SPUThread& spu, spu_opcode_t op) { const int scale = 173 - (op.i8 & 0xff); //unsigned immediate for (int i = 0; i < 4; i++) @@ -1877,7 +1864,7 @@ void spu_interpreter::precise::CFLTU(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::CSFLT(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::CSFLT(SPUThread& spu, spu_opcode_t op) { SetHostRoundingMode(FPSCR_RN_ZERO); const int scale = 155 - (op.i8 & 0xff); //unsigned immediate @@ -1900,7 +1887,7 @@ void spu_interpreter::precise::CSFLT(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::CUFLT(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::CUFLT(SPUThread& spu, spu_opcode_t op) { SetHostRoundingMode(FPSCR_RN_ZERO); const int scale = 155 - (op.i8 & 0xff); //unsigned immediate @@ -2068,8 +2055,8 @@ static void FMA(SPUThread& spu, spu_opcode_t op, bool neg, bool sub) } } -void spu_interpreter::precise::FNMS(SPUThread& spu, spu_opcode_t op) { FMA(spu, op, true, true); } +void spu_interpreter_precise::FNMS(SPUThread& spu, spu_opcode_t op) { ::FMA(spu, op, true, true); } -void spu_interpreter::precise::FMA(SPUThread& spu, spu_opcode_t op) { FMA(spu, op, false, false); } +void spu_interpreter_precise::FMA(SPUThread& spu, spu_opcode_t op) { ::FMA(spu, op, false, false); } -void spu_interpreter::precise::FMS(SPUThread& spu, spu_opcode_t op) { FMA(spu, op, false, true); } +void spu_interpreter_precise::FMS(SPUThread& spu, spu_opcode_t op) { ::FMA(spu, op, false, true); } diff --git a/rpcs3/Emu/Cell/SPUInterpreter.h b/rpcs3/Emu/Cell/SPUInterpreter.h index 5b57cd671e..68c0d4f9f9 100644 --- a/rpcs3/Emu/Cell/SPUInterpreter.h +++ b/rpcs3/Emu/Cell/SPUInterpreter.h @@ -4,256 +4,246 @@ class SPUThread; -using spu_inter_func_t = void(*)(SPUThread& spu, spu_opcode_t opcode); +using spu_inter_func_t = void(*)(SPUThread& spu, spu_opcode_t op); -namespace spu_interpreter +struct spu_interpreter { - namespace fast - { - extern const spu_opcode_table_t g_spu_opcode_table; - } + static void UNK(SPUThread&, spu_opcode_t); + static void set_interrupt_status(SPUThread&, spu_opcode_t); - namespace precise - { - extern const spu_opcode_table_t g_spu_opcode_table; - } + static void STOP(SPUThread&, spu_opcode_t); + static void LNOP(SPUThread&, spu_opcode_t); + static void SYNC(SPUThread&, spu_opcode_t); + static void DSYNC(SPUThread&, spu_opcode_t); + static void MFSPR(SPUThread&, spu_opcode_t); + static void RDCH(SPUThread&, spu_opcode_t); + static void RCHCNT(SPUThread&, spu_opcode_t); + static void SF(SPUThread&, spu_opcode_t); + static void OR(SPUThread&, spu_opcode_t); + static void BG(SPUThread&, spu_opcode_t); + static void SFH(SPUThread&, spu_opcode_t); + static void NOR(SPUThread&, spu_opcode_t); + static void ABSDB(SPUThread&, spu_opcode_t); + static void ROT(SPUThread&, spu_opcode_t); + static void ROTM(SPUThread&, spu_opcode_t); + static void ROTMA(SPUThread&, spu_opcode_t); + static void SHL(SPUThread&, spu_opcode_t); + static void ROTH(SPUThread&, spu_opcode_t); + static void ROTHM(SPUThread&, spu_opcode_t); + static void ROTMAH(SPUThread&, spu_opcode_t); + static void SHLH(SPUThread&, spu_opcode_t); + static void ROTI(SPUThread&, spu_opcode_t); + static void ROTMI(SPUThread&, spu_opcode_t); + static void ROTMAI(SPUThread&, spu_opcode_t); + static void SHLI(SPUThread&, spu_opcode_t); + static void ROTHI(SPUThread&, spu_opcode_t); + static void ROTHMI(SPUThread&, spu_opcode_t); + static void ROTMAHI(SPUThread&, spu_opcode_t); + static void SHLHI(SPUThread&, spu_opcode_t); + static void A(SPUThread&, spu_opcode_t); + static void AND(SPUThread&, spu_opcode_t); + static void CG(SPUThread&, spu_opcode_t); + static void AH(SPUThread&, spu_opcode_t); + static void NAND(SPUThread&, spu_opcode_t); + static void AVGB(SPUThread&, spu_opcode_t); + static void MTSPR(SPUThread&, spu_opcode_t); + static void WRCH(SPUThread&, spu_opcode_t); + static void BIZ(SPUThread&, spu_opcode_t); + static void BINZ(SPUThread&, spu_opcode_t); + static void BIHZ(SPUThread&, spu_opcode_t); + static void BIHNZ(SPUThread&, spu_opcode_t); + static void STOPD(SPUThread&, spu_opcode_t); + static void STQX(SPUThread&, spu_opcode_t); + static void BI(SPUThread&, spu_opcode_t); + static void BISL(SPUThread&, spu_opcode_t); + static void IRET(SPUThread&, spu_opcode_t); + static void BISLED(SPUThread&, spu_opcode_t); + static void HBR(SPUThread&, spu_opcode_t); + static void GB(SPUThread&, spu_opcode_t); + static void GBH(SPUThread&, spu_opcode_t); + static void GBB(SPUThread&, spu_opcode_t); + static void FSM(SPUThread&, spu_opcode_t); + static void FSMH(SPUThread&, spu_opcode_t); + static void FSMB(SPUThread&, spu_opcode_t); + static void LQX(SPUThread&, spu_opcode_t); + static void ROTQBYBI(SPUThread&, spu_opcode_t); + static void ROTQMBYBI(SPUThread&, spu_opcode_t); + static void SHLQBYBI(SPUThread&, spu_opcode_t); + static void CBX(SPUThread&, spu_opcode_t); + static void CHX(SPUThread&, spu_opcode_t); + static void CWX(SPUThread&, spu_opcode_t); + static void CDX(SPUThread&, spu_opcode_t); + static void ROTQBI(SPUThread&, spu_opcode_t); + static void ROTQMBI(SPUThread&, spu_opcode_t); + static void SHLQBI(SPUThread&, spu_opcode_t); + static void ROTQBY(SPUThread&, spu_opcode_t); + static void ROTQMBY(SPUThread&, spu_opcode_t); + static void SHLQBY(SPUThread&, spu_opcode_t); + static void ORX(SPUThread&, spu_opcode_t); + static void CBD(SPUThread&, spu_opcode_t); + static void CHD(SPUThread&, spu_opcode_t); + static void CWD(SPUThread&, spu_opcode_t); + static void CDD(SPUThread&, spu_opcode_t); + static void ROTQBII(SPUThread&, spu_opcode_t); + static void ROTQMBII(SPUThread&, spu_opcode_t); + static void SHLQBII(SPUThread&, spu_opcode_t); + static void ROTQBYI(SPUThread&, spu_opcode_t); + static void ROTQMBYI(SPUThread&, spu_opcode_t); + static void SHLQBYI(SPUThread&, spu_opcode_t); + static void NOP(SPUThread&, spu_opcode_t); + static void CGT(SPUThread&, spu_opcode_t); + static void XOR(SPUThread&, spu_opcode_t); + static void CGTH(SPUThread&, spu_opcode_t); + static void EQV(SPUThread&, spu_opcode_t); + static void CGTB(SPUThread&, spu_opcode_t); + static void SUMB(SPUThread&, spu_opcode_t); + static void HGT(SPUThread&, spu_opcode_t); + static void CLZ(SPUThread&, spu_opcode_t); + static void XSWD(SPUThread&, spu_opcode_t); + static void XSHW(SPUThread&, spu_opcode_t); + static void CNTB(SPUThread&, spu_opcode_t); + static void XSBH(SPUThread&, spu_opcode_t); + static void CLGT(SPUThread&, spu_opcode_t); + static void ANDC(SPUThread&, spu_opcode_t); + static void CLGTH(SPUThread&, spu_opcode_t); + static void ORC(SPUThread&, spu_opcode_t); + static void CLGTB(SPUThread&, spu_opcode_t); + static void HLGT(SPUThread&, spu_opcode_t); + static void CEQ(SPUThread&, spu_opcode_t); + static void MPYHHU(SPUThread&, spu_opcode_t); + static void ADDX(SPUThread&, spu_opcode_t); + static void SFX(SPUThread&, spu_opcode_t); + static void CGX(SPUThread&, spu_opcode_t); + static void BGX(SPUThread&, spu_opcode_t); + static void MPYHHA(SPUThread&, spu_opcode_t); + static void MPYHHAU(SPUThread&, spu_opcode_t); + static void MPY(SPUThread&, spu_opcode_t); + static void MPYH(SPUThread&, spu_opcode_t); + static void MPYHH(SPUThread&, spu_opcode_t); + static void MPYS(SPUThread&, spu_opcode_t); + static void CEQH(SPUThread&, spu_opcode_t); + static void MPYU(SPUThread&, spu_opcode_t); + static void CEQB(SPUThread&, spu_opcode_t); + static void HEQ(SPUThread&, spu_opcode_t); + static void BRZ(SPUThread&, spu_opcode_t); + static void STQA(SPUThread&, spu_opcode_t); + static void BRNZ(SPUThread&, spu_opcode_t); + static void BRHZ(SPUThread&, spu_opcode_t); + static void BRHNZ(SPUThread&, spu_opcode_t); + static void STQR(SPUThread&, spu_opcode_t); + static void BRA(SPUThread&, spu_opcode_t); + static void LQA(SPUThread&, spu_opcode_t); + static void BRASL(SPUThread&, spu_opcode_t); + static void BR(SPUThread&, spu_opcode_t); + static void FSMBI(SPUThread&, spu_opcode_t); + static void BRSL(SPUThread&, spu_opcode_t); + static void LQR(SPUThread&, spu_opcode_t); + static void IL(SPUThread&, spu_opcode_t); + static void ILHU(SPUThread&, spu_opcode_t); + static void ILH(SPUThread&, spu_opcode_t); + static void IOHL(SPUThread&, spu_opcode_t); + static void ORI(SPUThread&, spu_opcode_t); + static void ORHI(SPUThread&, spu_opcode_t); + static void ORBI(SPUThread&, spu_opcode_t); + static void SFI(SPUThread&, spu_opcode_t); + static void SFHI(SPUThread&, spu_opcode_t); + static void ANDI(SPUThread&, spu_opcode_t); + static void ANDHI(SPUThread&, spu_opcode_t); + static void ANDBI(SPUThread&, spu_opcode_t); + static void AI(SPUThread&, spu_opcode_t); + static void AHI(SPUThread&, spu_opcode_t); + static void STQD(SPUThread&, spu_opcode_t); + static void LQD(SPUThread&, spu_opcode_t); + static void XORI(SPUThread&, spu_opcode_t); + static void XORHI(SPUThread&, spu_opcode_t); + static void XORBI(SPUThread&, spu_opcode_t); + static void CGTI(SPUThread&, spu_opcode_t); + static void CGTHI(SPUThread&, spu_opcode_t); + static void CGTBI(SPUThread&, spu_opcode_t); + static void HGTI(SPUThread&, spu_opcode_t); + static void CLGTI(SPUThread&, spu_opcode_t); + static void CLGTHI(SPUThread&, spu_opcode_t); + static void CLGTBI(SPUThread&, spu_opcode_t); + static void HLGTI(SPUThread&, spu_opcode_t); + static void MPYI(SPUThread&, spu_opcode_t); + static void MPYUI(SPUThread&, spu_opcode_t); + static void CEQI(SPUThread&, spu_opcode_t); + static void CEQHI(SPUThread&, spu_opcode_t); + static void CEQBI(SPUThread&, spu_opcode_t); + static void HEQI(SPUThread&, spu_opcode_t); + static void HBRA(SPUThread&, spu_opcode_t); + static void HBRR(SPUThread&, spu_opcode_t); + static void ILA(SPUThread&, spu_opcode_t); + static void SELB(SPUThread&, spu_opcode_t); + static void SHUFB(SPUThread&, spu_opcode_t); + static void MPYA(SPUThread&, spu_opcode_t); + static void DFCGT(SPUThread&, spu_opcode_t); + static void DFCMGT(SPUThread&, spu_opcode_t); + static void DFTSV(SPUThread&, spu_opcode_t); + static void DFCEQ(SPUThread&, spu_opcode_t); + static void DFCMEQ(SPUThread&, spu_opcode_t); +}; - void default_function(SPUThread& spu, spu_opcode_t op); - void set_interrupt_status(SPUThread& spu, spu_opcode_t op); +struct spu_interpreter_fast final : spu_interpreter +{ + static void FREST(SPUThread&, spu_opcode_t); + static void FRSQEST(SPUThread&, spu_opcode_t); + static void FCGT(SPUThread&, spu_opcode_t); + static void FA(SPUThread&, spu_opcode_t); + static void FS(SPUThread&, spu_opcode_t); + static void FM(SPUThread&, spu_opcode_t); + static void FCMGT(SPUThread&, spu_opcode_t); + static void DFA(SPUThread&, spu_opcode_t); + static void DFS(SPUThread&, spu_opcode_t); + static void DFM(SPUThread&, spu_opcode_t); + static void DFMA(SPUThread&, spu_opcode_t); + static void DFMS(SPUThread&, spu_opcode_t); + static void DFNMS(SPUThread&, spu_opcode_t); + static void DFNMA(SPUThread&, spu_opcode_t); + static void FSCRRD(SPUThread&, spu_opcode_t); + static void FESD(SPUThread&, spu_opcode_t); + static void FRDS(SPUThread&, spu_opcode_t); + static void FSCRWR(SPUThread&, spu_opcode_t); + static void FCEQ(SPUThread&, spu_opcode_t); + static void FCMEQ(SPUThread&, spu_opcode_t); + static void FI(SPUThread&, spu_opcode_t); + static void CFLTS(SPUThread&, spu_opcode_t); + static void CFLTU(SPUThread&, spu_opcode_t); + static void CSFLT(SPUThread&, spu_opcode_t); + static void CUFLT(SPUThread&, spu_opcode_t); + static void FNMS(SPUThread&, spu_opcode_t); + static void FMA(SPUThread&, spu_opcode_t); + static void FMS(SPUThread&, spu_opcode_t); +}; - void STOP(SPUThread& spu, spu_opcode_t op); - void LNOP(SPUThread& spu, spu_opcode_t op); - void SYNC(SPUThread& spu, spu_opcode_t op); - void DSYNC(SPUThread& spu, spu_opcode_t op); - void MFSPR(SPUThread& spu, spu_opcode_t op); - void RDCH(SPUThread& spu, spu_opcode_t op); - void RCHCNT(SPUThread& spu, spu_opcode_t op); - void SF(SPUThread& spu, spu_opcode_t op); - void OR(SPUThread& spu, spu_opcode_t op); - void BG(SPUThread& spu, spu_opcode_t op); - void SFH(SPUThread& spu, spu_opcode_t op); - void NOR(SPUThread& spu, spu_opcode_t op); - void ABSDB(SPUThread& spu, spu_opcode_t op); - void ROT(SPUThread& spu, spu_opcode_t op); - void ROTM(SPUThread& spu, spu_opcode_t op); - void ROTMA(SPUThread& spu, spu_opcode_t op); - void SHL(SPUThread& spu, spu_opcode_t op); - void ROTH(SPUThread& spu, spu_opcode_t op); - void ROTHM(SPUThread& spu, spu_opcode_t op); - void ROTMAH(SPUThread& spu, spu_opcode_t op); - void SHLH(SPUThread& spu, spu_opcode_t op); - void ROTI(SPUThread& spu, spu_opcode_t op); - void ROTMI(SPUThread& spu, spu_opcode_t op); - void ROTMAI(SPUThread& spu, spu_opcode_t op); - void SHLI(SPUThread& spu, spu_opcode_t op); - void ROTHI(SPUThread& spu, spu_opcode_t op); - void ROTHMI(SPUThread& spu, spu_opcode_t op); - void ROTMAHI(SPUThread& spu, spu_opcode_t op); - void SHLHI(SPUThread& spu, spu_opcode_t op); - void A(SPUThread& spu, spu_opcode_t op); - void AND(SPUThread& spu, spu_opcode_t op); - void CG(SPUThread& spu, spu_opcode_t op); - void AH(SPUThread& spu, spu_opcode_t op); - void NAND(SPUThread& spu, spu_opcode_t op); - void AVGB(SPUThread& spu, spu_opcode_t op); - void MTSPR(SPUThread& spu, spu_opcode_t op); - void WRCH(SPUThread& spu, spu_opcode_t op); - void BIZ(SPUThread& spu, spu_opcode_t op); - void BINZ(SPUThread& spu, spu_opcode_t op); - void BIHZ(SPUThread& spu, spu_opcode_t op); - void BIHNZ(SPUThread& spu, spu_opcode_t op); - void STOPD(SPUThread& spu, spu_opcode_t op); - void STQX(SPUThread& spu, spu_opcode_t op); - void BI(SPUThread& spu, spu_opcode_t op); - void BISL(SPUThread& spu, spu_opcode_t op); - void IRET(SPUThread& spu, spu_opcode_t op); - void BISLED(SPUThread& spu, spu_opcode_t op); - void HBR(SPUThread& spu, spu_opcode_t op); - void GB(SPUThread& spu, spu_opcode_t op); - void GBH(SPUThread& spu, spu_opcode_t op); - void GBB(SPUThread& spu, spu_opcode_t op); - void FSM(SPUThread& spu, spu_opcode_t op); - void FSMH(SPUThread& spu, spu_opcode_t op); - void FSMB(SPUThread& spu, spu_opcode_t op); - void LQX(SPUThread& spu, spu_opcode_t op); - void ROTQBYBI(SPUThread& spu, spu_opcode_t op); - void ROTQMBYBI(SPUThread& spu, spu_opcode_t op); - void SHLQBYBI(SPUThread& spu, spu_opcode_t op); - void CBX(SPUThread& spu, spu_opcode_t op); - void CHX(SPUThread& spu, spu_opcode_t op); - void CWX(SPUThread& spu, spu_opcode_t op); - void CDX(SPUThread& spu, spu_opcode_t op); - void ROTQBI(SPUThread& spu, spu_opcode_t op); - void ROTQMBI(SPUThread& spu, spu_opcode_t op); - void SHLQBI(SPUThread& spu, spu_opcode_t op); - void ROTQBY(SPUThread& spu, spu_opcode_t op); - void ROTQMBY(SPUThread& spu, spu_opcode_t op); - void SHLQBY(SPUThread& spu, spu_opcode_t op); - void ORX(SPUThread& spu, spu_opcode_t op); - void CBD(SPUThread& spu, spu_opcode_t op); - void CHD(SPUThread& spu, spu_opcode_t op); - void CWD(SPUThread& spu, spu_opcode_t op); - void CDD(SPUThread& spu, spu_opcode_t op); - void ROTQBII(SPUThread& spu, spu_opcode_t op); - void ROTQMBII(SPUThread& spu, spu_opcode_t op); - void SHLQBII(SPUThread& spu, spu_opcode_t op); - void ROTQBYI(SPUThread& spu, spu_opcode_t op); - void ROTQMBYI(SPUThread& spu, spu_opcode_t op); - void SHLQBYI(SPUThread& spu, spu_opcode_t op); - void NOP(SPUThread& spu, spu_opcode_t op); - void CGT(SPUThread& spu, spu_opcode_t op); - void XOR(SPUThread& spu, spu_opcode_t op); - void CGTH(SPUThread& spu, spu_opcode_t op); - void EQV(SPUThread& spu, spu_opcode_t op); - void CGTB(SPUThread& spu, spu_opcode_t op); - void SUMB(SPUThread& spu, spu_opcode_t op); - void HGT(SPUThread& spu, spu_opcode_t op); - void CLZ(SPUThread& spu, spu_opcode_t op); - void XSWD(SPUThread& spu, spu_opcode_t op); - void XSHW(SPUThread& spu, spu_opcode_t op); - void CNTB(SPUThread& spu, spu_opcode_t op); - void XSBH(SPUThread& spu, spu_opcode_t op); - void CLGT(SPUThread& spu, spu_opcode_t op); - void ANDC(SPUThread& spu, spu_opcode_t op); - void CLGTH(SPUThread& spu, spu_opcode_t op); - void ORC(SPUThread& spu, spu_opcode_t op); - void CLGTB(SPUThread& spu, spu_opcode_t op); - void HLGT(SPUThread& spu, spu_opcode_t op); - void CEQ(SPUThread& spu, spu_opcode_t op); - void MPYHHU(SPUThread& spu, spu_opcode_t op); - void ADDX(SPUThread& spu, spu_opcode_t op); - void SFX(SPUThread& spu, spu_opcode_t op); - void CGX(SPUThread& spu, spu_opcode_t op); - void BGX(SPUThread& spu, spu_opcode_t op); - void MPYHHA(SPUThread& spu, spu_opcode_t op); - void MPYHHAU(SPUThread& spu, spu_opcode_t op); - void MPY(SPUThread& spu, spu_opcode_t op); - void MPYH(SPUThread& spu, spu_opcode_t op); - void MPYHH(SPUThread& spu, spu_opcode_t op); - void MPYS(SPUThread& spu, spu_opcode_t op); - void CEQH(SPUThread& spu, spu_opcode_t op); - void MPYU(SPUThread& spu, spu_opcode_t op); - void CEQB(SPUThread& spu, spu_opcode_t op); - void HEQ(SPUThread& spu, spu_opcode_t op); - void BRZ(SPUThread& spu, spu_opcode_t op); - void STQA(SPUThread& spu, spu_opcode_t op); - void BRNZ(SPUThread& spu, spu_opcode_t op); - void BRHZ(SPUThread& spu, spu_opcode_t op); - void BRHNZ(SPUThread& spu, spu_opcode_t op); - void STQR(SPUThread& spu, spu_opcode_t op); - void BRA(SPUThread& spu, spu_opcode_t op); - void LQA(SPUThread& spu, spu_opcode_t op); - void BRASL(SPUThread& spu, spu_opcode_t op); - void BR(SPUThread& spu, spu_opcode_t op); - void FSMBI(SPUThread& spu, spu_opcode_t op); - void BRSL(SPUThread& spu, spu_opcode_t op); - void LQR(SPUThread& spu, spu_opcode_t op); - void IL(SPUThread& spu, spu_opcode_t op); - void ILHU(SPUThread& spu, spu_opcode_t op); - void ILH(SPUThread& spu, spu_opcode_t op); - void IOHL(SPUThread& spu, spu_opcode_t op); - void ORI(SPUThread& spu, spu_opcode_t op); - void ORHI(SPUThread& spu, spu_opcode_t op); - void ORBI(SPUThread& spu, spu_opcode_t op); - void SFI(SPUThread& spu, spu_opcode_t op); - void SFHI(SPUThread& spu, spu_opcode_t op); - void ANDI(SPUThread& spu, spu_opcode_t op); - void ANDHI(SPUThread& spu, spu_opcode_t op); - void ANDBI(SPUThread& spu, spu_opcode_t op); - void AI(SPUThread& spu, spu_opcode_t op); - void AHI(SPUThread& spu, spu_opcode_t op); - void STQD(SPUThread& spu, spu_opcode_t op); - void LQD(SPUThread& spu, spu_opcode_t op); - void XORI(SPUThread& spu, spu_opcode_t op); - void XORHI(SPUThread& spu, spu_opcode_t op); - void XORBI(SPUThread& spu, spu_opcode_t op); - void CGTI(SPUThread& spu, spu_opcode_t op); - void CGTHI(SPUThread& spu, spu_opcode_t op); - void CGTBI(SPUThread& spu, spu_opcode_t op); - void HGTI(SPUThread& spu, spu_opcode_t op); - void CLGTI(SPUThread& spu, spu_opcode_t op); - void CLGTHI(SPUThread& spu, spu_opcode_t op); - void CLGTBI(SPUThread& spu, spu_opcode_t op); - void HLGTI(SPUThread& spu, spu_opcode_t op); - void MPYI(SPUThread& spu, spu_opcode_t op); - void MPYUI(SPUThread& spu, spu_opcode_t op); - void CEQI(SPUThread& spu, spu_opcode_t op); - void CEQHI(SPUThread& spu, spu_opcode_t op); - void CEQBI(SPUThread& spu, spu_opcode_t op); - void HEQI(SPUThread& spu, spu_opcode_t op); - void HBRA(SPUThread& spu, spu_opcode_t op); - void HBRR(SPUThread& spu, spu_opcode_t op); - void ILA(SPUThread& spu, spu_opcode_t op); - void SELB(SPUThread& spu, spu_opcode_t op); - void SHUFB(SPUThread& spu, spu_opcode_t op); - void MPYA(SPUThread& spu, spu_opcode_t op); - void DFCGT(SPUThread& spu, spu_opcode_t op); - void DFCMGT(SPUThread& spu, spu_opcode_t op); - void DFTSV(SPUThread& spu, spu_opcode_t op); - void DFCEQ(SPUThread& spu, spu_opcode_t op); - void DFCMEQ(SPUThread& spu, spu_opcode_t op); - - namespace fast - { - void FREST(SPUThread& spu, spu_opcode_t op); - void FRSQEST(SPUThread& spu, spu_opcode_t op); - void FCGT(SPUThread& spu, spu_opcode_t op); - void FA(SPUThread& spu, spu_opcode_t op); - void FS(SPUThread& spu, spu_opcode_t op); - void FM(SPUThread& spu, spu_opcode_t op); - void FCMGT(SPUThread& spu, spu_opcode_t op); - void DFA(SPUThread& spu, spu_opcode_t op); - void DFS(SPUThread& spu, spu_opcode_t op); - void DFM(SPUThread& spu, spu_opcode_t op); - void DFMA(SPUThread& spu, spu_opcode_t op); - void DFMS(SPUThread& spu, spu_opcode_t op); - void DFNMS(SPUThread& spu, spu_opcode_t op); - void DFNMA(SPUThread& spu, spu_opcode_t op); - void FSCRRD(SPUThread& spu, spu_opcode_t op); - void FESD(SPUThread& spu, spu_opcode_t op); - void FRDS(SPUThread& spu, spu_opcode_t op); - void FSCRWR(SPUThread& spu, spu_opcode_t op); - void FCEQ(SPUThread& spu, spu_opcode_t op); - void FCMEQ(SPUThread& spu, spu_opcode_t op); - void FI(SPUThread& spu, spu_opcode_t op); - void CFLTS(SPUThread& spu, spu_opcode_t op); - void CFLTU(SPUThread& spu, spu_opcode_t op); - void CSFLT(SPUThread& spu, spu_opcode_t op); - void CUFLT(SPUThread& spu, spu_opcode_t op); - void FNMS(SPUThread& spu, spu_opcode_t op); - void FMA(SPUThread& spu, spu_opcode_t op); - void FMS(SPUThread& spu, spu_opcode_t op); - } - - namespace precise - { - void FREST(SPUThread& spu, spu_opcode_t op); - void FRSQEST(SPUThread& spu, spu_opcode_t op); - void FCGT(SPUThread& spu, spu_opcode_t op); - void FA(SPUThread& spu, spu_opcode_t op); - void FS(SPUThread& spu, spu_opcode_t op); - void FM(SPUThread& spu, spu_opcode_t op); - void FCMGT(SPUThread& spu, spu_opcode_t op); - void DFA(SPUThread& spu, spu_opcode_t op); - void DFS(SPUThread& spu, spu_opcode_t op); - void DFM(SPUThread& spu, spu_opcode_t op); - void DFMA(SPUThread& spu, spu_opcode_t op); - void DFMS(SPUThread& spu, spu_opcode_t op); - void DFNMS(SPUThread& spu, spu_opcode_t op); - void DFNMA(SPUThread& spu, spu_opcode_t op); - void FSCRRD(SPUThread& spu, spu_opcode_t op); - void FESD(SPUThread& spu, spu_opcode_t op); - void FRDS(SPUThread& spu, spu_opcode_t op); - void FSCRWR(SPUThread& spu, spu_opcode_t op); - void FCEQ(SPUThread& spu, spu_opcode_t op); - void FCMEQ(SPUThread& spu, spu_opcode_t op); - void FI(SPUThread& spu, spu_opcode_t op); - void CFLTS(SPUThread& spu, spu_opcode_t op); - void CFLTU(SPUThread& spu, spu_opcode_t op); - void CSFLT(SPUThread& spu, spu_opcode_t op); - void CUFLT(SPUThread& spu, spu_opcode_t op); - void FNMS(SPUThread& spu, spu_opcode_t op); - void FMA(SPUThread& spu, spu_opcode_t op); - void FMS(SPUThread& spu, spu_opcode_t op); - } -} +struct spu_interpreter_precise final : spu_interpreter +{ + static void FREST(SPUThread&, spu_opcode_t); + static void FRSQEST(SPUThread&, spu_opcode_t); + static void FCGT(SPUThread&, spu_opcode_t); + static void FA(SPUThread&, spu_opcode_t); + static void FS(SPUThread&, spu_opcode_t); + static void FM(SPUThread&, spu_opcode_t); + static void FCMGT(SPUThread&, spu_opcode_t); + static void DFA(SPUThread&, spu_opcode_t); + static void DFS(SPUThread&, spu_opcode_t); + static void DFM(SPUThread&, spu_opcode_t); + static void DFMA(SPUThread&, spu_opcode_t); + static void DFMS(SPUThread&, spu_opcode_t); + static void DFNMS(SPUThread&, spu_opcode_t); + static void DFNMA(SPUThread&, spu_opcode_t); + static void FSCRRD(SPUThread&, spu_opcode_t); + static void FESD(SPUThread&, spu_opcode_t); + static void FRDS(SPUThread&, spu_opcode_t); + static void FSCRWR(SPUThread&, spu_opcode_t); + static void FCEQ(SPUThread&, spu_opcode_t); + static void FCMEQ(SPUThread&, spu_opcode_t); + static void FI(SPUThread&, spu_opcode_t); + static void CFLTS(SPUThread&, spu_opcode_t); + static void CFLTU(SPUThread&, spu_opcode_t); + static void CSFLT(SPUThread&, spu_opcode_t); + static void CUFLT(SPUThread&, spu_opcode_t); + static void FNMS(SPUThread&, spu_opcode_t); + static void FMA(SPUThread&, spu_opcode_t); + static void FMS(SPUThread&, spu_opcode_t); +}; diff --git a/rpcs3/Emu/Cell/SPUOpcodes.h b/rpcs3/Emu/Cell/SPUOpcodes.h index 25c02fb604..e3f3618f71 100644 --- a/rpcs3/Emu/Cell/SPUOpcodes.h +++ b/rpcs3/Emu/Cell/SPUOpcodes.h @@ -1,5 +1,7 @@ #pragma once +#include "../../../Utilities/BitField.h" + union spu_opcode_t { u32 opcode; @@ -23,246 +25,6 @@ union spu_opcode_t bf_t i18; // 7..24 }; -#define DEFINE_SPU_OPCODES(ns) { \ - { 10, 0x0, ns STOP }, \ - { 10, 0x1, ns LNOP }, \ - { 10, 0x2, ns SYNC }, \ - { 10, 0x3, ns DSYNC }, \ - { 10, 0xc, ns MFSPR }, \ - { 10, 0xd, ns RDCH }, \ - { 10, 0xf, ns RCHCNT }, \ - { 10, 0x40, ns SF }, \ - { 10, 0x41, ns OR }, \ - { 10, 0x42, ns BG }, \ - { 10, 0x48, ns SFH }, \ - { 10, 0x49, ns NOR }, \ - { 10, 0x53, ns ABSDB }, \ - { 10, 0x58, ns ROT }, \ - { 10, 0x59, ns ROTM }, \ - { 10, 0x5a, ns ROTMA }, \ - { 10, 0x5b, ns SHL }, \ - { 10, 0x5c, ns ROTH }, \ - { 10, 0x5d, ns ROTHM }, \ - { 10, 0x5e, ns ROTMAH }, \ - { 10, 0x5f, ns SHLH }, \ - { 10, 0x78, ns ROTI }, \ - { 10, 0x79, ns ROTMI }, \ - { 10, 0x7a, ns ROTMAI }, \ - { 10, 0x7b, ns SHLI }, \ - { 10, 0x7c, ns ROTHI }, \ - { 10, 0x7d, ns ROTHMI }, \ - { 10, 0x7e, ns ROTMAHI }, \ - { 10, 0x7f, ns SHLHI }, \ - { 10, 0xc0, ns A }, \ - { 10, 0xc1, ns AND }, \ - { 10, 0xc2, ns CG }, \ - { 10, 0xc8, ns AH }, \ - { 10, 0xc9, ns NAND }, \ - { 10, 0xd3, ns AVGB }, \ - { 10, 0x10c, ns MTSPR }, \ - { 10, 0x10d, ns WRCH }, \ - { 10, 0x128, ns BIZ }, \ - { 10, 0x129, ns BINZ }, \ - { 10, 0x12a, ns BIHZ }, \ - { 10, 0x12b, ns BIHNZ }, \ - { 10, 0x140, ns STOPD }, \ - { 10, 0x144, ns STQX }, \ - { 10, 0x1a8, ns BI }, \ - { 10, 0x1a9, ns BISL }, \ - { 10, 0x1aa, ns IRET }, \ - { 10, 0x1ab, ns BISLED }, \ - { 10, 0x1ac, ns HBR }, \ - { 10, 0x1b0, ns GB }, \ - { 10, 0x1b1, ns GBH }, \ - { 10, 0x1b2, ns GBB }, \ - { 10, 0x1b4, ns FSM }, \ - { 10, 0x1b5, ns FSMH }, \ - { 10, 0x1b6, ns FSMB }, \ - { 10, 0x1b8, ns FREST }, \ - { 10, 0x1b9, ns FRSQEST }, \ - { 10, 0x1c4, ns LQX }, \ - { 10, 0x1cc, ns ROTQBYBI }, \ - { 10, 0x1cd, ns ROTQMBYBI }, \ - { 10, 0x1cf, ns SHLQBYBI }, \ - { 10, 0x1d4, ns CBX }, \ - { 10, 0x1d5, ns CHX }, \ - { 10, 0x1d6, ns CWX }, \ - { 10, 0x1d7, ns CDX }, \ - { 10, 0x1d8, ns ROTQBI }, \ - { 10, 0x1d9, ns ROTQMBI }, \ - { 10, 0x1db, ns SHLQBI }, \ - { 10, 0x1dc, ns ROTQBY }, \ - { 10, 0x1dd, ns ROTQMBY }, \ - { 10, 0x1df, ns SHLQBY }, \ - { 10, 0x1f0, ns ORX }, \ - { 10, 0x1f4, ns CBD }, \ - { 10, 0x1f5, ns CHD }, \ - { 10, 0x1f6, ns CWD }, \ - { 10, 0x1f7, ns CDD }, \ - { 10, 0x1f8, ns ROTQBII }, \ - { 10, 0x1f9, ns ROTQMBII }, \ - { 10, 0x1fb, ns SHLQBII }, \ - { 10, 0x1fc, ns ROTQBYI }, \ - { 10, 0x1fd, ns ROTQMBYI }, \ - { 10, 0x1ff, ns SHLQBYI }, \ - { 10, 0x201, ns NOP }, \ - { 10, 0x240, ns CGT }, \ - { 10, 0x241, ns XOR }, \ - { 10, 0x248, ns CGTH }, \ - { 10, 0x249, ns EQV }, \ - { 10, 0x250, ns CGTB }, \ - { 10, 0x253, ns SUMB }, \ - { 10, 0x258, ns HGT }, \ - { 10, 0x2a5, ns CLZ }, \ - { 10, 0x2a6, ns XSWD }, \ - { 10, 0x2ae, ns XSHW }, \ - { 10, 0x2b4, ns CNTB }, \ - { 10, 0x2b6, ns XSBH }, \ - { 10, 0x2c0, ns CLGT }, \ - { 10, 0x2c1, ns ANDC }, \ - { 10, 0x2c2, ns FCGT }, \ - { 10, 0x2c3, ns DFCGT }, \ - { 10, 0x2c4, ns FA }, \ - { 10, 0x2c5, ns FS }, \ - { 10, 0x2c6, ns FM }, \ - { 10, 0x2c8, ns CLGTH }, \ - { 10, 0x2c9, ns ORC }, \ - { 10, 0x2ca, ns FCMGT }, \ - { 10, 0x2cb, ns DFCMGT }, \ - { 10, 0x2cc, ns DFA }, \ - { 10, 0x2cd, ns DFS }, \ - { 10, 0x2ce, ns DFM }, \ - { 10, 0x2d0, ns CLGTB }, \ - { 10, 0x2d8, ns HLGT }, \ - { 10, 0x35c, ns DFMA }, \ - { 10, 0x35d, ns DFMS }, \ - { 10, 0x35e, ns DFNMS }, \ - { 10, 0x35f, ns DFNMA }, \ - { 10, 0x3c0, ns CEQ }, \ - { 10, 0x3ce, ns MPYHHU }, \ - { 10, 0x340, ns ADDX }, \ - { 10, 0x341, ns SFX }, \ - { 10, 0x342, ns CGX }, \ - { 10, 0x343, ns BGX }, \ - { 10, 0x346, ns MPYHHA }, \ - { 10, 0x34e, ns MPYHHAU }, \ - { 10, 0x398, ns FSCRRD }, \ - { 10, 0x3b8, ns FESD }, \ - { 10, 0x3b9, ns FRDS }, \ - { 10, 0x3ba, ns FSCRWR }, \ - { 10, 0x3bf, ns DFTSV }, \ - { 10, 0x3c2, ns FCEQ }, \ - { 10, 0x3c3, ns DFCEQ }, \ - { 10, 0x3c4, ns MPY }, \ - { 10, 0x3c5, ns MPYH }, \ - { 10, 0x3c6, ns MPYHH }, \ - { 10, 0x3c7, ns MPYS }, \ - { 10, 0x3c8, ns CEQH }, \ - { 10, 0x3ca, ns FCMEQ }, \ - { 10, 0x3cb, ns DFCMEQ }, \ - { 10, 0x3cc, ns MPYU }, \ - { 10, 0x3d0, ns CEQB }, \ - { 10, 0x3d4, ns FI }, \ - { 10, 0x3d8, ns HEQ }, \ - { 9, 0x1d8, ns CFLTS }, \ - { 9, 0x1d9, ns CFLTU }, \ - { 9, 0x1da, ns CSFLT }, \ - { 9, 0x1db, ns CUFLT }, \ - { 8, 0x40, ns BRZ }, \ - { 8, 0x41, ns STQA }, \ - { 8, 0x42, ns BRNZ }, \ - { 8, 0x44, ns BRHZ }, \ - { 8, 0x46, ns BRHNZ }, \ - { 8, 0x47, ns STQR }, \ - { 8, 0x60, ns BRA }, \ - { 8, 0x61, ns LQA }, \ - { 8, 0x62, ns BRASL }, \ - { 8, 0x64, ns BR }, \ - { 8, 0x65, ns FSMBI }, \ - { 8, 0x66, ns BRSL }, \ - { 8, 0x67, ns LQR }, \ - { 8, 0x81, ns IL }, \ - { 8, 0x82, ns ILHU }, \ - { 8, 0x83, ns ILH }, \ - { 8, 0xc1, ns IOHL }, \ - { 7, 0x4, ns ORI }, \ - { 7, 0x5, ns ORHI }, \ - { 7, 0x6, ns ORBI }, \ - { 7, 0xc, ns SFI }, \ - { 7, 0xd, ns SFHI }, \ - { 7, 0x14, ns ANDI }, \ - { 7, 0x15, ns ANDHI }, \ - { 7, 0x16, ns ANDBI }, \ - { 7, 0x1c, ns AI }, \ - { 7, 0x1d, ns AHI }, \ - { 7, 0x24, ns STQD }, \ - { 7, 0x34, ns LQD }, \ - { 7, 0x44, ns XORI }, \ - { 7, 0x45, ns XORHI }, \ - { 7, 0x46, ns XORBI }, \ - { 7, 0x4c, ns CGTI }, \ - { 7, 0x4d, ns CGTHI }, \ - { 7, 0x4e, ns CGTBI }, \ - { 7, 0x4f, ns HGTI }, \ - { 7, 0x5c, ns CLGTI }, \ - { 7, 0x5d, ns CLGTHI }, \ - { 7, 0x5e, ns CLGTBI }, \ - { 7, 0x5f, ns HLGTI }, \ - { 7, 0x74, ns MPYI }, \ - { 7, 0x75, ns MPYUI }, \ - { 7, 0x7c, ns CEQI }, \ - { 7, 0x7d, ns CEQHI }, \ - { 7, 0x7e, ns CEQBI }, \ - { 7, 0x7f, ns HEQI }, \ - { 6, 0x8, ns HBRA }, \ - { 6, 0x9, ns HBRR }, \ - { 6, 0x21, ns ILA }, \ - { 3, 0x8, ns SELB }, \ - { 3, 0xb, ns SHUFB }, \ - { 3, 0xc, ns MPYA }, \ - { 3, 0xd, ns FNMS }, \ - { 3, 0xe, ns FMA }, \ - { 3, 0xf, ns FMS }, \ -} - -template class spu_opcode_table_t -{ - std::array m_data; - - struct opcode_entry_t - { - u32 group; - u32 value; - T pointer; - }; - -public: - // opcode table initialization (TODO: optimize it a bit) - spu_opcode_table_t(std::initializer_list opcodes, T default_value = {}) - { - for (u32 i = 0; i < 2048; i++) - { - m_data[i] = default_value; - - for (auto& op : opcodes) - { - if (((i << 21) & (INT_MIN >> op.group)) == (op.value << (31 - op.group))) - { - m_data[i] = op.pointer; - break; - } - } - } - } - - // access opcode table - 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, u32 imm = 0) { return (pc + (imm << 2)) & 0x3fffc; @@ -272,3 +34,250 @@ inline u32 spu_ls_target(u32 pc, u32 imm = 0) { return (pc + (imm << 2)) & 0x3fff0; } + +static u32 spu_decode(u32 inst) +{ + return inst >> 21; +} + +// SPU decoder object. D provides functions. T is function pointer type returned. +template +class spu_decoder +{ + // Fast lookup table + std::array m_table; + + struct instruction_info + { + u32 magn; // Count = 2 ^ magn + u32 value; + T pointer; + }; + +public: + spu_decoder() + { + const std::initializer_list instructions + { + { 0, 0x0, &D::STOP }, + { 0, 0x1, &D::LNOP }, + { 0, 0x2, &D::SYNC }, + { 0, 0x3, &D::DSYNC }, + { 0, 0xc, &D::MFSPR }, + { 0, 0xd, &D::RDCH }, + { 0, 0xf, &D::RCHCNT }, + { 0, 0x40, &D::SF }, + { 0, 0x41, &D::OR }, + { 0, 0x42, &D::BG }, + { 0, 0x48, &D::SFH }, + { 0, 0x49, &D::NOR }, + { 0, 0x53, &D::ABSDB }, + { 0, 0x58, &D::ROT }, + { 0, 0x59, &D::ROTM }, + { 0, 0x5a, &D::ROTMA }, + { 0, 0x5b, &D::SHL }, + { 0, 0x5c, &D::ROTH }, + { 0, 0x5d, &D::ROTHM }, + { 0, 0x5e, &D::ROTMAH }, + { 0, 0x5f, &D::SHLH }, + { 0, 0x78, &D::ROTI }, + { 0, 0x79, &D::ROTMI }, + { 0, 0x7a, &D::ROTMAI }, + { 0, 0x7b, &D::SHLI }, + { 0, 0x7c, &D::ROTHI }, + { 0, 0x7d, &D::ROTHMI }, + { 0, 0x7e, &D::ROTMAHI }, + { 0, 0x7f, &D::SHLHI }, + { 0, 0xc0, &D::A }, + { 0, 0xc1, &D::AND }, + { 0, 0xc2, &D::CG }, + { 0, 0xc8, &D::AH }, + { 0, 0xc9, &D::NAND }, + { 0, 0xd3, &D::AVGB }, + { 0, 0x10c, &D::MTSPR }, + { 0, 0x10d, &D::WRCH }, + { 0, 0x128, &D::BIZ }, + { 0, 0x129, &D::BINZ }, + { 0, 0x12a, &D::BIHZ }, + { 0, 0x12b, &D::BIHNZ }, + { 0, 0x140, &D::STOPD }, + { 0, 0x144, &D::STQX }, + { 0, 0x1a8, &D::BI }, + { 0, 0x1a9, &D::BISL }, + { 0, 0x1aa, &D::IRET }, + { 0, 0x1ab, &D::BISLED }, + { 0, 0x1ac, &D::HBR }, + { 0, 0x1b0, &D::GB }, + { 0, 0x1b1, &D::GBH }, + { 0, 0x1b2, &D::GBB }, + { 0, 0x1b4, &D::FSM }, + { 0, 0x1b5, &D::FSMH }, + { 0, 0x1b6, &D::FSMB }, + { 0, 0x1b8, &D::FREST }, + { 0, 0x1b9, &D::FRSQEST }, + { 0, 0x1c4, &D::LQX }, + { 0, 0x1cc, &D::ROTQBYBI }, + { 0, 0x1cd, &D::ROTQMBYBI }, + { 0, 0x1cf, &D::SHLQBYBI }, + { 0, 0x1d4, &D::CBX }, + { 0, 0x1d5, &D::CHX }, + { 0, 0x1d6, &D::CWX }, + { 0, 0x1d7, &D::CDX }, + { 0, 0x1d8, &D::ROTQBI }, + { 0, 0x1d9, &D::ROTQMBI }, + { 0, 0x1db, &D::SHLQBI }, + { 0, 0x1dc, &D::ROTQBY }, + { 0, 0x1dd, &D::ROTQMBY }, + { 0, 0x1df, &D::SHLQBY }, + { 0, 0x1f0, &D::ORX }, + { 0, 0x1f4, &D::CBD }, + { 0, 0x1f5, &D::CHD }, + { 0, 0x1f6, &D::CWD }, + { 0, 0x1f7, &D::CDD }, + { 0, 0x1f8, &D::ROTQBII }, + { 0, 0x1f9, &D::ROTQMBII }, + { 0, 0x1fb, &D::SHLQBII }, + { 0, 0x1fc, &D::ROTQBYI }, + { 0, 0x1fd, &D::ROTQMBYI }, + { 0, 0x1ff, &D::SHLQBYI }, + { 0, 0x201, &D::NOP }, + { 0, 0x240, &D::CGT }, + { 0, 0x241, &D::XOR }, + { 0, 0x248, &D::CGTH }, + { 0, 0x249, &D::EQV }, + { 0, 0x250, &D::CGTB }, + { 0, 0x253, &D::SUMB }, + { 0, 0x258, &D::HGT }, + { 0, 0x2a5, &D::CLZ }, + { 0, 0x2a6, &D::XSWD }, + { 0, 0x2ae, &D::XSHW }, + { 0, 0x2b4, &D::CNTB }, + { 0, 0x2b6, &D::XSBH }, + { 0, 0x2c0, &D::CLGT }, + { 0, 0x2c1, &D::ANDC }, + { 0, 0x2c2, &D::FCGT }, + { 0, 0x2c3, &D::DFCGT }, + { 0, 0x2c4, &D::FA }, + { 0, 0x2c5, &D::FS }, + { 0, 0x2c6, &D::FM }, + { 0, 0x2c8, &D::CLGTH }, + { 0, 0x2c9, &D::ORC }, + { 0, 0x2ca, &D::FCMGT }, + { 0, 0x2cb, &D::DFCMGT }, + { 0, 0x2cc, &D::DFA }, + { 0, 0x2cd, &D::DFS }, + { 0, 0x2ce, &D::DFM }, + { 0, 0x2d0, &D::CLGTB }, + { 0, 0x2d8, &D::HLGT }, + { 0, 0x35c, &D::DFMA }, + { 0, 0x35d, &D::DFMS }, + { 0, 0x35e, &D::DFNMS }, + { 0, 0x35f, &D::DFNMA }, + { 0, 0x3c0, &D::CEQ }, + { 0, 0x3ce, &D::MPYHHU }, + { 0, 0x340, &D::ADDX }, + { 0, 0x341, &D::SFX }, + { 0, 0x342, &D::CGX }, + { 0, 0x343, &D::BGX }, + { 0, 0x346, &D::MPYHHA }, + { 0, 0x34e, &D::MPYHHAU }, + { 0, 0x398, &D::FSCRRD }, + { 0, 0x3b8, &D::FESD }, + { 0, 0x3b9, &D::FRDS }, + { 0, 0x3ba, &D::FSCRWR }, + { 0, 0x3bf, &D::DFTSV }, + { 0, 0x3c2, &D::FCEQ }, + { 0, 0x3c3, &D::DFCEQ }, + { 0, 0x3c4, &D::MPY }, + { 0, 0x3c5, &D::MPYH }, + { 0, 0x3c6, &D::MPYHH }, + { 0, 0x3c7, &D::MPYS }, + { 0, 0x3c8, &D::CEQH }, + { 0, 0x3ca, &D::FCMEQ }, + { 0, 0x3cb, &D::DFCMEQ }, + { 0, 0x3cc, &D::MPYU }, + { 0, 0x3d0, &D::CEQB }, + { 0, 0x3d4, &D::FI }, + { 0, 0x3d8, &D::HEQ }, + { 1, 0x1d8, &D::CFLTS }, + { 1, 0x1d9, &D::CFLTU }, + { 1, 0x1da, &D::CSFLT }, + { 1, 0x1db, &D::CUFLT }, + { 2, 0x40, &D::BRZ }, + { 2, 0x41, &D::STQA }, + { 2, 0x42, &D::BRNZ }, + { 2, 0x44, &D::BRHZ }, + { 2, 0x46, &D::BRHNZ }, + { 2, 0x47, &D::STQR }, + { 2, 0x60, &D::BRA }, + { 2, 0x61, &D::LQA }, + { 2, 0x62, &D::BRASL }, + { 2, 0x64, &D::BR }, + { 2, 0x65, &D::FSMBI }, + { 2, 0x66, &D::BRSL }, + { 2, 0x67, &D::LQR }, + { 2, 0x81, &D::IL }, + { 2, 0x82, &D::ILHU }, + { 2, 0x83, &D::ILH }, + { 2, 0xc1, &D::IOHL }, + { 3, 0x4, &D::ORI }, + { 3, 0x5, &D::ORHI }, + { 3, 0x6, &D::ORBI }, + { 3, 0xc, &D::SFI }, + { 3, 0xd, &D::SFHI }, + { 3, 0x14, &D::ANDI }, + { 3, 0x15, &D::ANDHI }, + { 3, 0x16, &D::ANDBI }, + { 3, 0x1c, &D::AI }, + { 3, 0x1d, &D::AHI }, + { 3, 0x24, &D::STQD }, + { 3, 0x34, &D::LQD }, + { 3, 0x44, &D::XORI }, + { 3, 0x45, &D::XORHI }, + { 3, 0x46, &D::XORBI }, + { 3, 0x4c, &D::CGTI }, + { 3, 0x4d, &D::CGTHI }, + { 3, 0x4e, &D::CGTBI }, + { 3, 0x4f, &D::HGTI }, + { 3, 0x5c, &D::CLGTI }, + { 3, 0x5d, &D::CLGTHI }, + { 3, 0x5e, &D::CLGTBI }, + { 3, 0x5f, &D::HLGTI }, + { 3, 0x74, &D::MPYI }, + { 3, 0x75, &D::MPYUI }, + { 3, 0x7c, &D::CEQI }, + { 3, 0x7d, &D::CEQHI }, + { 3, 0x7e, &D::CEQBI }, + { 3, 0x7f, &D::HEQI }, + { 4, 0x8, &D::HBRA }, + { 4, 0x9, &D::HBRR }, + { 4, 0x21, &D::ILA }, + { 7, 0x8, &D::SELB }, + { 7, 0xb, &D::SHUFB }, + { 7, 0xc, &D::MPYA }, + { 7, 0xd, &D::FNMS }, + { 7, 0xe, &D::FMA }, + { 7, 0xf, &D::FMS }, + }; + + m_table.fill(&D::UNK); + + for (auto& entry : instructions) + { + for (u32 i = 0; i < 1u << entry.magn; i++) + { + m_table[entry.value << entry.magn | i] = entry.pointer; + } + } + } + + const std::array& get_table() const + { + return m_table; + } + + T decode(u32 inst) const + { + return m_table[spu_decode(inst)]; + } +}; diff --git a/rpcs3/Emu/Cell/SPURecompiler.cpp b/rpcs3/Emu/Cell/SPURecompiler.cpp index c490b187ea..b6e635bfb2 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.cpp +++ b/rpcs3/Emu/Cell/SPURecompiler.cpp @@ -8,39 +8,36 @@ extern u64 get_system_time(); -SPURecompilerDecoder::SPURecompilerDecoder(SPUThread& spu) - : db(fxm::get_always()) - , rec(fxm::get_always()) - , spu(spu) +void spu_recompiler_base::enter(SPUThread& spu) { -} - -u32 SPURecompilerDecoder::DecodeMemory(const u32 address) -{ - if (spu.offset != address - spu.pc || spu.pc >= 0x40000 || spu.pc % 4) + if (spu.pc >= 0x40000 || spu.pc % 4) { - throw EXCEPTION("Invalid address or PC (address=0x%x, PC=0x%05x)", address, spu.pc); + throw fmt::exception("Invalid PC: 0x%05x", spu.pc); } - // get SPU LS pointer + // Get SPU LS pointer const auto _ls = vm::ps3::_ptr(spu.offset); - // always validate (TODO) - const auto func = db->analyse(_ls, spu.pc); + // Always validate (TODO) + const auto func = spu.spu_db->analyse(_ls, spu.pc); - // reset callstack if necessary + // Reset callstack if necessary if (func->does_reset_stack && spu.recursion_level) { - spu.m_state |= CPU_STATE_RETURN; - - return 0; + spu.state += cpu_state::ret; + return; } if (!func->compiled) { - rec->compile(*func); + if (!spu.spu_rec) + { + spu.spu_rec = fxm::get_always(); + } - if (!func->compiled) throw EXCEPTION("Compilation failed"); + spu.spu_rec->compile(*func); + + if (!func->compiled) throw std::runtime_error("Compilation failed" HERE); } const u32 res = func->compiled(&spu, _ls); @@ -64,7 +61,7 @@ u32 SPURecompilerDecoder::DecodeMemory(const u32 address) { if (res & 0x8000000) { - throw EXCEPTION("Undefined behaviour"); + throw std::logic_error("Invalid interrupt status set" HERE); } spu.set_interrupt_status(true); @@ -75,6 +72,4 @@ u32 SPURecompilerDecoder::DecodeMemory(const u32 address) } spu.pc = res & 0x3fffc; - - return 0; } diff --git a/rpcs3/Emu/Cell/SPURecompiler.h b/rpcs3/Emu/Cell/SPURecompiler.h index 5ef15efc55..ed9b9aae64 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.h +++ b/rpcs3/Emu/Cell/SPURecompiler.h @@ -1,12 +1,9 @@ #pragma once -#include "Emu/CPU/CPUDecoder.h" #include "SPUAnalyser.h" -class SPUThread; - // SPU Recompiler instance base (must be global or PS3 process-local) -class SPURecompilerBase +class spu_recompiler_base { protected: std::mutex m_mutex; // must be locked in compile() @@ -16,21 +13,11 @@ protected: u32 m_pos; // current position public: - virtual void compile(spu_function_t& f) = 0; // compile specified function - virtual ~SPURecompilerBase() {}; -}; - -// SPU Decoder instance (created per SPU thread) -class SPURecompilerDecoder final : public CPUDecoder -{ -public: - const std::shared_ptr db; // associated SPU Analyser instance - - const std::shared_ptr rec; // assiciated SPU Recompiler instance - - SPUThread& spu; // associated SPU Thread - - SPURecompilerDecoder(SPUThread& spu); - - u32 DecodeMemory(const u32 address) override; // non-virtual override (to avoid virtual call whenever possible) + virtual ~spu_recompiler_base() = default; + + // Compile specified function + virtual void compile(spu_function_t& f) = 0; + + // Run + static void enter(class SPUThread&); }; diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 5c92fae5f5..9bb9fdc4b6 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -1,15 +1,15 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/state.h" #include "Emu/IdManager.h" #include "Emu/Cell/PPUThread.h" -#include "Emu/SysCalls/ErrorCodes.h" -#include "Emu/SysCalls/lv2/sys_spu.h" -#include "Emu/SysCalls/lv2/sys_event_flag.h" -#include "Emu/SysCalls/lv2/sys_event.h" -#include "Emu/SysCalls/lv2/sys_interrupt.h" +#include "Emu/Cell/ErrorCodes.h" +#include "Emu/Cell/lv2/sys_spu.h" +#include "Emu/Cell/lv2/sys_event_flag.h" +#include "Emu/Cell/lv2/sys_event.h" +#include "Emu/Cell/lv2/sys_interrupt.h" #include "Emu/Cell/SPUDisAsm.h" #include "Emu/Cell/SPUThread.h" @@ -20,8 +20,24 @@ extern u64 get_timebased_time(); -// defined here since SPUDisAsm.cpp doesn't exist -const spu_opcode_table_t SPUDisAsm::opcodes{ DEFINE_SPU_OPCODES(&SPUDisAsm::), &SPUDisAsm::UNK }; +enum class spu_decoder_type +{ + precise, + fast, + asmjit, + llvm, +}; + +cfg::map_entry g_cfg_spu_decoder(cfg::root.core, "SPU Decoder", 2, +{ + { "Interpreter (precise)", spu_decoder_type::precise }, + { "Interpreter (fast)", spu_decoder_type::fast }, + { "Recompiler (ASMJIT)", spu_decoder_type::asmjit }, + { "Recompiler (LLVM)", spu_decoder_type::llvm }, +}); + +const spu_decoder s_spu_interpreter_precise; +const spu_decoder s_spu_interpreter_fast; thread_local bool spu_channel_t::notification_required; @@ -31,7 +47,7 @@ void spu_int_ctrl_t::set(u64 ints) ints &= mask; // notify if at least 1 bit was set - if (ints && ~stat._or(ints) & ints && tag) + if (ints && ~stat.fetch_or(ints) & ints && tag) { LV2_LOCK; @@ -44,112 +60,23 @@ void spu_int_ctrl_t::set(u64 ints) } } -void spu_int_ctrl_t::clear(u64 ints) -{ - stat &= ~ints; -} - const spu_imm_table_t g_spu_imm; -SPUThread::SPUThread(CPUThreadType type, const std::string& name, u32 index, u32 offset) - : CPUThread(type, name) - , index(index) - , offset(offset) -{ -} - -SPUThread::SPUThread(const std::string& name, u32 index) - : CPUThread(CPU_THREAD_SPU, name) - , index(index) - , offset(vm::alloc(0x40000, vm::main)) -{ - CHECK_ASSERTION(offset); -} - -SPUThread::~SPUThread() -{ - // Deallocate Local Storage - vm::dealloc_verbose_nothrow(offset); -} - -bool SPUThread::is_paused() const -{ - if (CPUThread::is_paused()) - { - return true; - } - - if (const auto group = tg.lock()) - { - if (group->state >= SPU_THREAD_GROUP_STATUS_WAITING && group->state <= SPU_THREAD_GROUP_STATUS_SUSPENDED) - { - return true; - } - } - - return false; -} - std::string SPUThread::get_name() const { - return fmt::format("%s[0x%x] Thread (%s)[0x%05x]", CPUThread::GetTypeString(), m_id, CPUThread::get_name(), pc); + return fmt::format("%sSPU[0x%x] Thread (%s)", offset > RAW_SPU_BASE_ADDR ? "Raw" : "", id, name); } -void SPUThread::dump_info() const +std::string SPUThread::dump() const { - CPUThread::dump_info(); + std::string ret = "Registers:\n=========\n"; + + for (uint i = 0; i<128; ++i) ret += fmt::format("GPR[%d] = 0x%s\n", i, gpr[i].to_hex().c_str()); + + return ret; } -void SPUThread::cpu_task() -{ - std::fesetround(FE_TOWARDZERO); - - if (!custom_task && !m_dec) - { - // Select opcode table (TODO) - const auto& table = rpcs3::state.config.core.spu_decoder.value() == spu_decoder_type::interpreter_precise ? spu_interpreter::precise::g_spu_opcode_table : spu_interpreter::fast::g_spu_opcode_table; - - // LS base address - const auto base = vm::_ptr(offset); - - while (true) - { - if (!m_state) - { - // read opcode - const u32 opcode = base[pc / 4]; - - // call interpreter function - table[opcode](*this, { opcode }); - - // next instruction - pc += 4; - - continue; - } - - if (check_status()) - { - return; - } - } - } - - if (custom_task) - { - if (check_status()) return; - - return custom_task(*this); - } - - while (!m_state || !check_status()) - { - // decode instruction using specified decoder - pc += m_dec->DecodeMemory(pc + offset); - } -} - -void SPUThread::init_regs() +void SPUThread::cpu_init() { gpr = {}; fpscr.Reset(); @@ -190,75 +117,96 @@ void SPUThread::init_regs() gpr[1]._u32[3] = 0x3FFF0; // initial stack frame pointer } -void SPUThread::init_stack() +void SPUThread::cpu_task() { - // nothing to do -} + std::fesetround(FE_TOWARDZERO); -void SPUThread::close_stack() -{ - // nothing to do here -} - -void SPUThread::do_run() -{ - m_dec.reset(); - - switch (auto mode = rpcs3::state.config.core.spu_decoder.value()) + if (custom_task) { - case spu_decoder_type::interpreter_precise: // Interpreter 1 (Precise) - case spu_decoder_type::interpreter_fast: // Interpreter 2 (Fast) - { - break; + if (check_status()) return; + + return custom_task(*this); } - case spu_decoder_type::recompiler_asmjit: + _log::g_tls_make_prefix = [](const auto&, auto, const auto&) { - m_dec.reset(new SPURecompilerDecoder(*this)); - break; + const auto cpu = static_cast(get_current_cpu_thread()); + + return fmt::format("%s [0x%05x]", cpu->get_name(), cpu->pc); + }; + + if (g_cfg_spu_decoder.get() == spu_decoder_type::asmjit) + { + if (!spu_db) spu_db = fxm::get_always(); + return spu_recompiler_base::enter(*this); } - default: + // Select opcode table + const auto& table = *( + g_cfg_spu_decoder.get() == spu_decoder_type::precise ? &s_spu_interpreter_precise.get_table() : + g_cfg_spu_decoder.get() == spu_decoder_type::fast ? &s_spu_interpreter_fast.get_table() : + throw std::logic_error("Invalid SPU decoder")); + + // LS base address + const auto base = vm::_ptr(offset); + + while (true) { - LOG_ERROR(SPU, "Invalid SPU decoder mode: %d", (u8)mode); - Emu.Pause(); - } + if (!state.load()) + { + // Read opcode + const u32 op = base[pc / 4]; + + // Call interpreter function + table[spu_decode(op)](*this, { op }); + + // Next instruction + pc += 4; + continue; + } + + if (check_status()) return; } } -void SPUThread::fast_call(u32 ls_addr) +SPUThread::SPUThread(const std::string & name, u32 index) + : cpu_thread(cpu_type::spu, name) + , index(index) + , offset(vm::alloc(0x40000, vm::main)) { - if (!is_current()) + Ensures(offset); +} + +SPUThread::~SPUThread() +{ + // Deallocate Local Storage + vm::dealloc_verbose_nothrow(offset); +} + +void SPUThread::push_snr(u32 number, u32 value) +{ + // get channel + const auto channel = + number == 0 ? &ch_snr1 : + number == 1 ? &ch_snr2 : throw EXCEPTION("Unexpected"); + + // check corresponding SNR register settings + if ((snr_config >> number) & 1) { - throw EXCEPTION("Called from the wrong thread"); + channel->push_or(value); + } + else + { + channel->push(value); } - // LS:0x0: this is originally the entry point of the interrupt handler, but interrupts are not implemented - _ref(0) = 0x00000002; // STOP 2 - - auto old_pc = pc; - auto old_lr = gpr[0]._u32[3]; - auto old_stack = gpr[1]._u32[3]; // only saved and restored (may be wrong) - auto old_task = std::move(custom_task); - - pc = ls_addr; - gpr[0]._u32[3] = 0x0; - custom_task = nullptr; - - try + if (channel->notification_required) { - cpu_task(); - } - catch (CPUThreadReturn) - { - } + // lock for reliable notification + std::lock_guard lock(mutex); - m_state &= ~CPU_STATE_RETURN; - - pc = old_pc; - gpr[0]._u32[3] = old_lr; - gpr[1]._u32[3] = old_stack; - custom_task = std::move(old_task); + cv.notify_one(); + } } void SPUThread::do_dma_transfer(u32 cmd, spu_mfc_arg_t args) @@ -268,9 +216,9 @@ void SPUThread::do_dma_transfer(u32 cmd, spu_mfc_arg_t args) _mm_mfence(); } - u32 eal = VM_CAST(args.ea); + u32 eal = vm::cast(args.ea, HERE); - if (eal >= SYS_SPU_THREAD_BASE_LOW && m_type == CPU_THREAD_SPU) // SPU Thread Group MMIO (LS and SNR) + if (eal >= SYS_SPU_THREAD_BASE_LOW && offset >= RAW_SPU_BASE_ADDR) // SPU Thread Group MMIO (LS and SNR) { const u32 index = (eal - SYS_SPU_THREAD_BASE_LOW) / SYS_SPU_THREAD_OFFSET; // thread number in group const u32 offset = (eal - SYS_SPU_THREAD_BASE_LOW) % SYS_SPU_THREAD_OFFSET; // LS offset or MMIO register @@ -413,7 +361,7 @@ void SPUThread::process_mfc_cmd(u32 cmd) break; } - const u32 raddr = VM_CAST(ch_mfc_args.ea); + const u32 raddr = vm::cast(ch_mfc_args.ea, HERE); vm::reservation_acquire(vm::base(offset + ch_mfc_args.lsa), raddr, 128); @@ -434,7 +382,7 @@ void SPUThread::process_mfc_cmd(u32 cmd) break; } - if (vm::reservation_update(VM_CAST(ch_mfc_args.ea), vm::base(offset + ch_mfc_args.lsa), 128)) + if (vm::reservation_update(vm::cast(ch_mfc_args.ea, HERE), vm::base(offset + ch_mfc_args.lsa), 128)) { if (last_raddr == 0) { @@ -466,9 +414,9 @@ void SPUThread::process_mfc_cmd(u32 cmd) break; } - vm::reservation_op(VM_CAST(ch_mfc_args.ea), 128, [this]() + vm::reservation_op(vm::cast(ch_mfc_args.ea, HERE), 128, [this]() { - std::memcpy(vm::base_priv(VM_CAST(ch_mfc_args.ea)), vm::base(offset + ch_mfc_args.lsa), 128); + std::memcpy(vm::base_priv(vm::cast(ch_mfc_args.ea, HERE)), vm::base(offset + ch_mfc_args.lsa), 128); }); if (last_raddr != 0 && vm::g_tls_did_break_reservation) @@ -539,7 +487,7 @@ void SPUThread::set_events(u32 mask) } // set new events, get old event mask - const u32 old_stat = ch_event_stat._or(mask); + const u32 old_stat = ch_event_stat.fetch_or(mask); // notify if some events were set if (~old_stat & mask && old_stat & SPU_EVENT_WAITING) @@ -617,7 +565,10 @@ u32 SPUThread::get_ch_value(u32 ch) CHECK_EMU_STATUS; - if (is_stopped()) throw CPUThreadStop{}; + if (state & cpu_state::stop) + { + throw cpu_state::stop; + } if (!lock) { @@ -658,7 +609,10 @@ u32 SPUThread::get_ch_value(u32 ch) CHECK_EMU_STATUS; - if (is_stopped()) throw CPUThreadStop{}; + if (state & cpu_state::stop) + { + throw cpu_state::stop; + } if (!lock) { @@ -723,14 +677,14 @@ u32 SPUThread::get_ch_value(u32 ch) if (ch_event_mask & SPU_EVENT_LR) { // register waiter if polling reservation status is required - vm::wait_op(*this, last_raddr, 128, WRAP_EXPR(get_events(true) || is_stopped())); + vm::wait_op(*this, last_raddr, 128, WRAP_EXPR(get_events(true) || state & cpu_state::stop)); } else { lock.lock(); // simple waiting loop otherwise - while (!get_events(true) && !is_stopped()) + while (!get_events(true) && !(state & cpu_state::stop)) { CHECK_EMU_STATUS; @@ -740,7 +694,10 @@ u32 SPUThread::get_ch_value(u32 ch) ch_event_stat &= ~SPU_EVENT_WAITING; - if (is_stopped()) throw CPUThreadStop{}; + if (state & cpu_state::stop) + { + throw cpu_state::stop; + } return get_events(); } @@ -767,7 +724,7 @@ void SPUThread::set_ch_value(u32 ch, u32 value) // break; case SPU_WrOutIntrMbox: { - if (m_type == CPU_THREAD_RAW_SPU) + if (offset >= RAW_SPU_BASE_ADDR) { std::unique_lock lock(mutex, std::defer_lock); @@ -775,7 +732,10 @@ void SPUThread::set_ch_value(u32 ch, u32 value) { CHECK_EMU_STATUS; - if (is_stopped()) throw CPUThreadStop{}; + if (state & cpu_state::stop) + { + throw cpu_state::stop; + } if (!lock) { @@ -824,12 +784,12 @@ void SPUThread::set_ch_value(u32 ch, u32 value) return ch_in_mbox.set_values(1, CELL_ENOTCONN); // TODO: check error passing } - if (queue->events.size() >= queue->size) + if (queue->events() >= queue->size) { return ch_in_mbox.set_values(1, CELL_EBUSY); } - queue->push(lv2_lock, SYS_SPU_THREAD_EVENT_USER_KEY, m_id, ((u64)spup << 32) | (value & 0x00ffffff), data); + queue->push(lv2_lock, SYS_SPU_THREAD_EVENT_USER_KEY, id, ((u64)spup << 32) | (value & 0x00ffffff), data); return ch_in_mbox.set_values(1, CELL_OK); } @@ -861,13 +821,13 @@ void SPUThread::set_ch_value(u32 ch, u32 value) } // TODO: check passing spup value - if (queue->events.size() >= queue->size) + if (queue->events() >= queue->size) { LOG_WARNING(SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x) failed (queue is full)", spup, (value & 0x00ffffff), data); return; } - queue->push(lv2_lock, SYS_SPU_THREAD_EVENT_USER_KEY, m_id, ((u64)spup << 32) | (value & 0x00ffffff), data); + queue->push(lv2_lock, SYS_SPU_THREAD_EVENT_USER_KEY, id, ((u64)spup << 32) | (value & 0x00ffffff), data); return; } else if (code == 128) @@ -979,7 +939,10 @@ void SPUThread::set_ch_value(u32 ch, u32 value) { CHECK_EMU_STATUS; - if (is_stopped()) throw CPUThreadStop{}; + if (state & cpu_state::stop) + { + throw cpu_state::stop; + } if (!lock) { @@ -1136,7 +1099,7 @@ void SPUThread::stop_and_signal(u32 code) { LOG_TRACE(SPU, "stop_and_signal(code=0x%x)", code); - if (m_type == CPU_THREAD_RAW_SPU) + if (offset >= RAW_SPU_BASE_ADDR) { status.atomic_op([code](u32& status) { @@ -1146,8 +1109,7 @@ void SPUThread::stop_and_signal(u32 code) }); int_ctrl[2].set(SPU_INT2_STAT_SPU_STOP_AND_SIGNAL_INT); - - return stop(); + throw cpu_state::stop; } switch (code) @@ -1160,7 +1122,7 @@ void SPUThread::stop_and_signal(u32 code) case 0x002: { - m_state |= CPU_STATE_RETURN; + state += cpu_state::ret; return; } @@ -1241,7 +1203,10 @@ void SPUThread::stop_and_signal(u32 code) { CHECK_EMU_STATUS; - if (is_stopped()) throw CPUThreadStop{}; + if (state & cpu_state::stop) + { + throw cpu_state::stop; + } group->cv.wait_for(lv2_lock, std::chrono::milliseconds(1)); } @@ -1253,7 +1218,10 @@ void SPUThread::stop_and_signal(u32 code) for (auto& thread : group->threads) { - if (thread) thread->sleep(); // trigger status check + if (thread) + { + thread->state += cpu_state::suspend; + } } } else @@ -1261,24 +1229,25 @@ void SPUThread::stop_and_signal(u32 code) throw EXCEPTION("Unexpected SPU Thread Group state (%d)", group->state); } - if (queue->events.size()) + if (queue->events()) { - auto& event = queue->events.front(); + const auto event = queue->pop(lv2_lock); ch_in_mbox.set_values(4, CELL_OK, static_cast(std::get<1>(event)), static_cast(std::get<2>(event)), static_cast(std::get<3>(event))); - - queue->events.pop_front(); } else { // add waiter; protocol is ignored in current implementation - sleep_queue_entry_t waiter(*this, queue->sq); + sleep_entry waiter(queue->thread_queue(lv2_lock), *this); // wait on the event queue - while (!unsignal()) + while (!state.test_and_reset(cpu_state::signal)) { CHECK_EMU_STATUS; - if (is_stopped()) throw CPUThreadStop{}; + if (state & cpu_state::stop) + { + throw cpu_state::stop; + } cv.wait(lv2_lock); } @@ -1302,9 +1271,14 @@ void SPUThread::stop_and_signal(u32 code) for (auto& thread : group->threads) { - if (thread) thread->awake(); // untrigger status check + if (thread && thread.get() != this) + { + thread->state -= cpu_state::suspend; + thread->safe_notify(); + } } + state -= cpu_state::suspend; group->cv.notify_all(); return; @@ -1338,7 +1312,8 @@ void SPUThread::stop_and_signal(u32 code) { if (thread && thread.get() != this) { - thread->stop(); + thread->state += cpu_state::stop; + thread->safe_notify(); } } @@ -1347,7 +1322,7 @@ void SPUThread::stop_and_signal(u32 code) group->join_state |= SPU_TGJSF_GROUP_EXIT; group->cv.notify_one(); - return stop(); + throw cpu_state::stop; } case 0x102: @@ -1373,7 +1348,7 @@ void SPUThread::stop_and_signal(u32 code) status |= SPU_STATUS_STOPPED_BY_STOP; group->cv.notify_one(); - return stop(); + throw cpu_state::stop; } } @@ -1391,7 +1366,7 @@ void SPUThread::halt() { LOG_TRACE(SPU, "halt()"); - if (m_type == CPU_THREAD_RAW_SPU) + if (offset >= RAW_SPU_BASE_ADDR) { status.atomic_op([](u32& status) { @@ -1401,18 +1376,41 @@ void SPUThread::halt() int_ctrl[2].set(SPU_INT2_STAT_SPU_HALT_OR_STEP_INT); - return stop(); + throw cpu_state::stop; } status |= SPU_STATUS_STOPPED_BY_HALT; throw EXCEPTION("Halt"); } -spu_thread::spu_thread(u32 entry, const std::string& name, u32 stack_size, u32 prio) +void SPUThread::fast_call(u32 ls_addr) { - auto spu = idm::make_ptr(name, 0x13370666); + // LS:0x0: this is originally the entry point of the interrupt handler, but interrupts are not implemented + _ref(0) = 0x00000002; // STOP 2 - spu->pc = entry; + auto old_pc = pc; + auto old_lr = gpr[0]._u32[3]; + auto old_stack = gpr[1]._u32[3]; // only saved and restored (may be wrong) + auto old_task = std::move(custom_task); - thread = std::move(spu); + pc = ls_addr; + gpr[0]._u32[3] = 0x0; + custom_task = nullptr; + + try + { + cpu_task(); + } + catch (cpu_state _s) + { + state += _s; + if (_s != cpu_state::ret) throw; + } + + state -= cpu_state::ret; + + pc = old_pc; + gpr[0]._u32[3] = old_lr; + gpr[1]._u32[3] = old_stack; + custom_task = std::move(old_task); } diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index c16547f3d6..7da16bfc7a 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -2,10 +2,10 @@ #include "Emu/Cell/Common.h" #include "Emu/CPU/CPUThread.h" -#include "Emu/Cell/SPUContext.h" +#include "Emu/Cell/SPUInterpreter.h" #include "MFC.h" -struct lv2_event_queue_t; +class lv2_event_queue_t; struct lv2_spu_group_t; struct lv2_int_tag_t; @@ -135,12 +135,20 @@ enum SPU_RdSigNotify2_offs = 0x1C00C, }; +enum : u32 +{ + RAW_SPU_BASE_ADDR = 0xE0000000, + RAW_SPU_OFFSET = 0x00100000, + RAW_SPU_LS_OFFSET = 0x00000000, + RAW_SPU_PROB_OFFSET = 0x00040000, +}; + struct spu_channel_t { // set to true if SPU thread must be notified after SPU channel operation thread_local static bool notification_required; - struct sync_var_t + struct alignas(8) sync_var_t { bool count; // value available bool wait; // notification required @@ -153,7 +161,7 @@ public: // returns true on success bool try_push(u32 value) { - const auto old = data.atomic_op([=](sync_var_t& data) + const auto old = data.fetch_op([=](sync_var_t& data) { if ((data.wait = data.count) == false) { @@ -168,7 +176,7 @@ public: // push performing bitwise OR with previous value, may require notification void push_or(u32 value) { - const auto old = data.atomic_op([=](sync_var_t& data) + const auto old = data.fetch_op([=](sync_var_t& data) { data.count = true; data.wait = false; @@ -181,7 +189,7 @@ public: // push unconditionally (overwriting previous value), may require notification void push(u32 value) { - const auto old = data.atomic_op([=](sync_var_t& data) + const auto old = data.fetch_op([=](sync_var_t& data) { data.count = true; data.wait = false; @@ -194,7 +202,7 @@ public: // returns true on success and loaded value std::tuple try_pop() { - const auto old = data.atomic_op([](sync_var_t& data) + const auto old = data.fetch_op([](sync_var_t& data) { data.wait = !data.count; data.count = false; @@ -207,7 +215,7 @@ public: // pop unconditionally (loading last value), may require notification u32 pop() { - const auto old = data.atomic_op([](sync_var_t& data) + const auto old = data.fetch_op([](sync_var_t& data) { data.wait = false; data.count = false; @@ -237,7 +245,7 @@ public: struct spu_channel_4_t { - struct sync_var_t + struct alignas(16) sync_var_t { struct { @@ -256,7 +264,7 @@ struct spu_channel_4_t public: void clear() { - values = sync_var_t{}; + values.store({}); value3 = 0; } @@ -333,7 +341,10 @@ struct spu_int_ctrl_t void set(u64 ints); - void clear(u64 ints); + void clear(u64 ints) + { + stat &= ~ints; + } void clear() { @@ -526,12 +537,27 @@ public: } }; -class SPUThread : public CPUThread +class SPUThread : public cpu_thread { - friend class SPURecompilerDecoder; - friend class spu_recompiler; +public: + virtual std::string get_name() const override; + virtual std::string dump() const override; + virtual void cpu_init() override; + virtual void cpu_task() override; + +protected: + SPUThread(const std::string& name) + : cpu_thread(cpu_type::spu, name) + , index(0) + , offset(0) + { + } public: + SPUThread(const std::string& name, u32 index); + + virtual ~SPUThread() override; + std::array gpr; // General-Purpose Registers SPU_FPSCR fpscr; @@ -578,32 +604,14 @@ public: const u32 index; // SPU index const u32 offset; // SPU LS offset - void push_snr(u32 number, u32 value) - { - // get channel - const auto channel = - number == 0 ? &ch_snr1 : - number == 1 ? &ch_snr2 : throw EXCEPTION("Unexpected"); + std::function custom_task; + std::exception_ptr pending_exception; - // check corresponding SNR register settings - if ((snr_config >> number) & 1) - { - channel->push_or(value); - } - else - { - channel->push(value); - } - - if (channel->notification_required) - { - // lock for reliable notification - std::lock_guard lock(mutex); - - cv.notify_one(); - } - } + std::shared_ptr spu_db; + std::shared_ptr spu_rec; + u32 recursion_level = 0; + void push_snr(u32 number, u32 value); void do_dma_transfer(u32 cmd, spu_mfc_arg_t args); void do_dma_list_cmd(u32 cmd, spu_mfc_arg_t args); void process_mfc_cmd(u32 cmd); @@ -618,14 +626,18 @@ public: void stop_and_signal(u32 code); void halt(); + void fast_call(u32 ls_addr); + // Convert specified SPU LS address to a pointer of specified (possibly converted to BE) type - template inline to_be_t* _ptr(u32 lsa) + template + inline to_be_t* _ptr(u32 lsa) { return static_cast*>(vm::base(offset + lsa)); } // Convert specified SPU LS address to a reference of specified (possibly converted to BE) type - template inline to_be_t& _ref(u32 lsa) + template + inline to_be_t& _ref(u32 lsa) { return *_ptr(lsa); } @@ -655,100 +667,4 @@ public: } } } - - std::function custom_task; - std::exception_ptr pending_exception; - u32 recursion_level = 0; - -protected: - SPUThread(CPUThreadType type, const std::string& name, u32 index, u32 offset); - -public: - SPUThread(const std::string& name, u32 index); - virtual ~SPUThread() override; - - virtual bool is_paused() const override; - - virtual std::string get_name() const override; - virtual void dump_info() const override; - virtual u32 get_pc() const override { return pc; } - virtual u32 get_offset() const override { return offset; } - virtual void do_run() override; - virtual void cpu_task() override; - - virtual void init_regs() override; - virtual void init_stack() override; - virtual void close_stack() override; - - void fast_call(u32 ls_addr); - - virtual std::string RegsToString() const override - { - std::string ret = "Registers:\n=========\n"; - - for(uint i=0; i<128; ++i) ret += fmt::format("GPR[%d] = 0x%s\n", i, gpr[i].to_hex().c_str()); - - return ret; - } - - virtual std::string ReadRegString(const std::string& reg) const override - { - std::string::size_type first_brk = reg.find('['); - if (first_brk != std::string::npos) - { - long reg_index; - reg_index = atol(reg.substr(first_brk + 1, reg.length()-2).c_str()); - if (reg.find("GPR")==0) return fmt::format("%016llx%016llx", gpr[reg_index]._u64[1], gpr[reg_index]._u64[0]); - } - return ""; - } - - bool WriteRegString(const std::string& reg, std::string value) override - { - while (value.length() < 32) value = "0"+value; - std::string::size_type first_brk = reg.find('['); - if (first_brk != std::string::npos) - { - long reg_index; - reg_index = atol(reg.substr(first_brk + 1, reg.length() - 2).c_str()); - if (reg.find("GPR")==0) - { - unsigned long long reg_value0; - unsigned long long reg_value1; - try - { - reg_value0 = std::stoull(value.substr(16, 31), 0, 16); - reg_value1 = std::stoull(value.substr(0, 15), 0, 16); - } - catch (std::invalid_argument& /*e*/) - { - return false; - } - gpr[reg_index]._u64[0] = (u64)reg_value0; - gpr[reg_index]._u64[1] = (u64)reg_value1; - return true; - } - } - return false; - } -}; - -class spu_thread : cpu_thread -{ -public: - spu_thread(u32 entry, const std::string& name = "", u32 stack_size = 0, u32 prio = 0); - - cpu_thread& args(std::initializer_list values) override - { - return *this; - } - - cpu_thread& run() override - { - auto& spu = static_cast(*thread); - - spu.run(); - - return *this; - } }; diff --git a/rpcs3/Emu/SysCalls/SysCalls.cpp b/rpcs3/Emu/Cell/lv2/lv2.cpp similarity index 97% rename from rpcs3/Emu/SysCalls/SysCalls.cpp rename to rpcs3/Emu/Cell/lv2/lv2.cpp index bb3ebdde99..771302c551 100644 --- a/rpcs3/Emu/SysCalls/SysCalls.cpp +++ b/rpcs3/Emu/Cell/lv2/lv2.cpp @@ -1,42 +1,39 @@ #include "stdafx.h" #include "Utilities/AutoPause.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/state.h" -#include "Modules.h" -#include "lv2/sys_lwmutex.h" -#include "lv2/sys_lwcond.h" -#include "lv2/sys_mutex.h" -#include "lv2/sys_cond.h" -#include "lv2/sys_event.h" -#include "lv2/sys_event_flag.h" -#include "lv2/sys_interrupt.h" -#include "lv2/sys_memory.h" -#include "lv2/sys_mmapper.h" -#include "lv2/sys_ppu_thread.h" -#include "lv2/sys_process.h" -#include "lv2/sys_prx.h" -#include "lv2/sys_rsx.h" -#include "lv2/sys_rwlock.h" -#include "lv2/sys_semaphore.h" -#include "lv2/sys_spu.h" -#include "lv2/sys_time.h" -#include "lv2/sys_timer.h" -#include "lv2/sys_trace.h" -#include "lv2/sys_tty.h" -#include "lv2/sys_vm.h" -#include "lv2/sys_fs.h" -#include "lv2/sys_dbg.h" +#include "Emu/Cell/PPUFunction.h" +#include "Emu/Cell/ErrorCodes.h" +#include "sys_sync.h" +#include "sys_lwmutex.h" +#include "sys_lwcond.h" +#include "sys_mutex.h" +#include "sys_cond.h" +#include "sys_event.h" +#include "sys_event_flag.h" +#include "sys_interrupt.h" +#include "sys_memory.h" +#include "sys_mmapper.h" +#include "sys_ppu_thread.h" +#include "sys_process.h" +#include "sys_prx.h" +#include "sys_rsx.h" +#include "sys_rwlock.h" +#include "sys_semaphore.h" +#include "sys_spu.h" +#include "sys_time.h" +#include "sys_timer.h" +#include "sys_trace.h" +#include "sys_tty.h" +#include "sys_vm.h" +#include "sys_fs.h" +#include "sys_dbg.h" -#include "Emu/SysCalls/Modules/cellGcmSys.h" +extern std::string ppu_get_syscall_name(u64 code); -#include "SysCalls.h" - -void null_func(PPUThread& ppu) +static void null_func(PPUThread& ppu) { - const u64 code = ppu.GPR[11]; - LOG_TODO(HLE, "Unimplemented syscall %lld: %s -> CELL_OK", code, get_ps3_function_name(~code)); + LOG_TODO(HLE, "Unimplemented syscall %s -> CELL_OK", ppu_get_syscall_name(ppu.GPR[11])); ppu.GPR[3] = 0; } @@ -45,7 +42,7 @@ void null_func(PPUThread& ppu) // DBG = Debug // PM = Product Mode // AuthID = Authentication ID -const ppu_func_caller g_sc_table[1024] = +std::array g_ppu_syscall_table { null_func, BIND_FUNC(sys_process_getpid), //1 (0x001) @@ -887,24 +884,34 @@ const ppu_func_caller g_sc_table[1024] = null_func, null_func, null_func, null_func, null_func, //1009 UNS null_func, null_func, null_func, null_func, null_func, //1014 UNS null_func, null_func, null_func, null_func, null_func, //1019 UNS - null_func, null_func, null_func, BIND_FUNC(cellGcmCallback), //1023 UNS + null_func, null_func, null_func, null_func, //1023 UNS }; -void execute_syscall_by_index(PPUThread& ppu, u64 code) +extern void ppu_execute_syscall(PPUThread& ppu, u64 code) { - if (code >= 1024) + if (code >= g_ppu_syscall_table.size()) { - throw EXCEPTION("Invalid syscall number (0x%llx)", code); + throw fmt::exception("Invalid syscall number (%llu)", code); } + + // If autopause occures, check_status() will hold the thread till unpaused. + if (debug::autopause::pause_syscall(code) && ppu.check_status()) throw cpu_state::ret; + + const auto previous_function = ppu.last_function; // TODO: use gsl::finally or something - auto last_code = ppu.hle_code; - ppu.hle_code = ~code; + try + { + g_ppu_syscall_table[code](ppu); + } + catch (...) + { + LOG_WARNING(PPU, "Syscall '%s' (%llu) aborted", ppu_get_syscall_name(code), code); + ppu.last_function = previous_function; + throw; + } - LOG_TRACE(PPU, "Syscall %lld called: %s", code, get_ps3_function_name(~code)); - - g_sc_table[code](ppu); - - LOG_TRACE(PPU, "Syscall %lld finished: %s -> 0x%llx", code, get_ps3_function_name(~code), ppu.GPR[3]); - - ppu.hle_code = last_code; + LOG_TRACE(PPU, "Syscall '%s' (%llu) finished, r3=0x%llx", ppu_get_syscall_name(code), code, ppu.GPR[3]); + ppu.last_function = previous_function; } + +lv2_lock_t::type::mutex_type lv2_lock_t::mutex; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp b/rpcs3/Emu/Cell/lv2/sys_cond.cpp similarity index 87% rename from rpcs3/Emu/SysCalls/lv2/sys_cond.cpp rename to rpcs3/Emu/Cell/lv2/sys_cond.cpp index ceda3643e2..845a3ec097 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_cond.cpp @@ -1,22 +1,20 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" -#include "sys_sync.h" #include "sys_mutex.h" #include "sys_cond.h" -SysCallBase sys_cond("sys_cond"); +LOG_CHANNEL(sys_cond); extern u64 get_system_time(); -void lv2_cond_t::notify(lv2_lock_t& lv2_lock, sleep_queue_t::value_type& thread) +void lv2_cond_t::notify(lv2_lock_t, cpu_thread* thread) { - CHECK_LV2_LOCK(lv2_lock); - if (mutex->owner) { // add thread to the mutex sleep queue if cannot lock immediately @@ -24,12 +22,10 @@ void lv2_cond_t::notify(lv2_lock_t& lv2_lock, sleep_queue_t::value_type& thread) } else { - mutex->owner = thread; + mutex->owner = std::static_pointer_cast(thread->shared_from_this()); - if (!thread->signal()) - { - throw EXCEPTION("Thread already signaled"); - } + ASSERT(!thread->state.test_and_set(cpu_state::signal)); + thread->cv.notify_one(); } } @@ -150,9 +146,9 @@ s32 sys_cond_signal_to(u32 cond_id, u32 thread_id) return CELL_ESRCH; } - const auto found = std::find_if(cond->sq.begin(), cond->sq.end(), [=](sleep_queue_t::value_type& thread) + const auto found = std::find_if(cond->sq.begin(), cond->sq.end(), [=](cpu_thread* thread) { - return thread->get_id() == thread_id; + return thread->id == thread_id; }); // TODO: check if CELL_ESRCH is returned if thread_id is invalid @@ -196,12 +192,12 @@ s32 sys_cond_wait(PPUThread& ppu, u32 cond_id, u64 timeout) cond->mutex->unlock(lv2_lock); // add waiter; protocol is ignored in current implementation - sleep_queue_entry_t waiter(ppu, cond->sq); + sleep_entry waiter(cond->sq, ppu); // potential mutex waiter (not added immediately) - sleep_queue_entry_t mutex_waiter(ppu, cond->mutex->sq, defer_sleep); + sleep_entry mutex_waiter(cond->mutex->sq, ppu, defer_sleep); - while (!ppu.unsignal()) + while (!ppu.state.test_and_reset(cpu_state::signal)) { CHECK_EMU_STATUS; @@ -215,7 +211,7 @@ s32 sys_cond_wait(PPUThread& ppu, u32 cond_id, u64 timeout) // try to reown mutex and exit if timed out if (!cond->mutex->owner) { - cond->mutex->owner = std::static_pointer_cast(ppu.shared_from_this()); + cond->mutex->owner = std::static_pointer_cast(ppu.shared_from_this()); break; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_cond.h b/rpcs3/Emu/Cell/lv2/sys_cond.h similarity index 81% rename from rpcs3/Emu/SysCalls/lv2/sys_cond.h rename to rpcs3/Emu/Cell/lv2/sys_cond.h index 2b0583cd1e..24b4012c7c 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_cond.h +++ b/rpcs3/Emu/Cell/lv2/sys_cond.h @@ -1,8 +1,6 @@ #pragma once -#include "Utilities/SleepQueue.h" - -namespace vm { using namespace ps3; } +#include "sys_sync.h" struct lv2_mutex_t; @@ -24,7 +22,7 @@ struct lv2_cond_t const u64 name; const std::shared_ptr mutex; // associated mutex - sleep_queue_t sq; + sleep_queue sq; lv2_cond_t(const std::shared_ptr& mutex, u64 name) : mutex(mutex) @@ -32,7 +30,7 @@ struct lv2_cond_t { } - void notify(lv2_lock_t& lv2_lock, sleep_queue_t::value_type& thread); + void notify(lv2_lock_t, cpu_thread* thread); }; class PPUThread; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_dbg.cpp b/rpcs3/Emu/Cell/lv2/sys_dbg.cpp similarity index 59% rename from rpcs3/Emu/SysCalls/lv2/sys_dbg.cpp rename to rpcs3/Emu/Cell/lv2/sys_dbg.cpp index bfa9445bb0..3890fc906f 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_dbg.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_dbg.cpp @@ -1,9 +1,10 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "sys_dbg.h" -SysCallBase sys_dbg("sys_dbg"); +LOG_CHANNEL(sys_dbg); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_dbg.h b/rpcs3/Emu/Cell/lv2/sys_dbg.h similarity index 100% rename from rpcs3/Emu/SysCalls/lv2/sys_dbg.h rename to rpcs3/Emu/Cell/lv2/sys_dbg.h diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event.cpp b/rpcs3/Emu/Cell/lv2/sys_event.cpp similarity index 72% rename from rpcs3/Emu/SysCalls/lv2/sys_event.cpp rename to rpcs3/Emu/Cell/lv2/sys_event.cpp index a0cdd9b182..81a71bdc5d 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_event.cpp @@ -1,49 +1,65 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" #include "Emu/Cell/SPUThread.h" -#include "Emu/Event.h" -#include "sys_sync.h" #include "sys_process.h" #include "sys_event.h" -SysCallBase sys_event("sys_event"); +LOG_CHANNEL(sys_event); extern u64 get_system_time(); -lv2_event_queue_t::lv2_event_queue_t(u32 protocol, s32 type, u64 name, u64 key, s32 size) - : id(idm::get_last_id()) - , protocol(protocol) - , type(type) - , name(name) - , key(key) - , size(size) +static ipc_manager& get_ipc_manager() { + // Use magic static + static ipc_manager instance; + return instance; } -void lv2_event_queue_t::push(lv2_lock_t& lv2_lock, u64 source, u64 data1, u64 data2, u64 data3) +std::shared_ptr lv2_event_queue_t::make(u32 protocol, s32 type, u64 name, u64 ipc_key, s32 size) { - CHECK_LV2_LOCK(lv2_lock); + auto make_expr = WRAP_EXPR(idm::import(WRAP_EXPR(std::make_shared(protocol, type, name, ipc_key, size)))); - // save event if no waiters - if (sq.empty()) + if (ipc_key == SYS_EVENT_QUEUE_LOCAL) { - return events.emplace_back(source, data1, data2, data3); + // Not an IPC queue + return make_expr(); } - if (events.size()) + // IPC queue + return get_ipc_manager().add(ipc_key, make_expr); +} + +std::shared_ptr lv2_event_queue_t::find(u64 ipc_key) +{ + if (ipc_key == SYS_EVENT_QUEUE_LOCAL) { - throw EXCEPTION("Unexpected"); + // Invalid IPC key + return{}; + } + + return get_ipc_manager().get(ipc_key); +} + +void lv2_event_queue_t::push(lv2_lock_t, u64 source, u64 data1, u64 data2, u64 data3) +{ + Expects(m_sq.empty() || m_events.empty()); + + // save event if no waiters + if (m_sq.empty()) + { + return m_events.emplace_back(source, data1, data2, data3); } // notify waiter; protocol is ignored in current implementation - auto& thread = sq.front(); + auto& thread = m_sq.front(); - if (type == SYS_PPU_QUEUE && thread->get_type() == CPU_THREAD_PPU) + if (type == SYS_PPU_QUEUE && thread->type == cpu_type::ppu) { // store event data in registers auto& ppu = static_cast(*thread); @@ -53,7 +69,7 @@ void lv2_event_queue_t::push(lv2_lock_t& lv2_lock, u64 source, u64 data1, u64 da ppu.GPR[6] = data2; ppu.GPR[7] = data3; } - else if (type == SYS_SPU_QUEUE && thread->get_type() == CPU_THREAD_SPU) + else if (type == SYS_SPU_QUEUE && thread->type == cpu_type::spu) { // store event data in In_MBox auto& spu = static_cast(*thread); @@ -62,15 +78,21 @@ void lv2_event_queue_t::push(lv2_lock_t& lv2_lock, u64 source, u64 data1, u64 da } else { - throw EXCEPTION("Unexpected (queue_type=%d, thread_type=%d)", type, thread->get_type()); + throw fmt::exception("Unexpected (queue.type=%d, thread.type=%d)" HERE, type, thread->type); } - if (!sq.front()->signal()) - { - throw EXCEPTION("Thread already signaled"); - } + ASSERT(!thread->state.test_and_set(cpu_state::signal)); + thread->cv.notify_one(); - return sq.pop_front(); + return m_sq.pop_front(); +} + +lv2_event_queue_t::event_type lv2_event_queue_t::pop(lv2_lock_t) +{ + Expects(m_events.size()); + auto result = m_events.front(); + m_events.pop_front(); + return result; } s32 sys_event_queue_create(vm::ptr equeue_id, vm::ptr attr, u64 event_queue_key, s32 size) @@ -98,7 +120,7 @@ s32 sys_event_queue_create(vm::ptr equeue_id, vm::ptr(attr->name), event_queue_key, size); + const auto queue = lv2_event_queue_t::make(protocol, type, reinterpret_cast(attr->name), event_queue_key, size); if (!queue) { @@ -128,32 +150,32 @@ s32 sys_event_queue_destroy(u32 equeue_id, s32 mode) return CELL_EINVAL; } - if (!mode && queue->sq.size()) + if (!mode && queue->waiters()) { return CELL_EBUSY; } // cleanup - Emu.GetEventManager().UnregisterKey(queue->key); idm::remove(equeue_id); // signal all threads to return CELL_ECANCELED - for (auto& thread : queue->sq) + for (auto& thread : queue->thread_queue(lv2_lock)) { - if (queue->type == SYS_PPU_QUEUE && thread->get_type() == CPU_THREAD_PPU) + if (queue->type == SYS_PPU_QUEUE && thread->type == cpu_type::ppu) { static_cast(*thread).GPR[3] = 1; } - else if (queue->type == SYS_SPU_QUEUE && thread->get_type() == CPU_THREAD_SPU) + else if (queue->type == SYS_SPU_QUEUE && thread->type == cpu_type::spu) { static_cast(*thread).ch_in_mbox.set_values(1, CELL_ECANCELED); } else { - throw EXCEPTION("Unexpected (queue_type=%d, thread_type=%d)", queue->type, thread->get_type()); + throw fmt::exception("Unexpected (queue.type=%d, thread.type=%d)" HERE, queue->type, thread->type); } - thread->signal(); + thread->state += cpu_state::signal; + thread->cv.notify_one(); } return CELL_OK; @@ -174,7 +196,7 @@ s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr event_array, if (size < 0) { - throw EXCEPTION("Negative size"); + throw fmt::exception("Negative size (%d)" HERE, size); } if (queue->type != SYS_PPU_QUEUE) @@ -184,13 +206,11 @@ s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr event_array, s32 count = 0; - while (queue->sq.empty() && count < size && queue->events.size()) + while (queue->waiters() == 0 && count < size && queue->events()) { auto& dest = event_array[count++]; - std::tie(dest.source, dest.data1, dest.data2, dest.data3) = queue->events.front(); - - queue->events.pop_front(); + std::tie(dest.source, dest.data1, dest.data2, dest.data3) = queue->pop(lv2_lock); } *number = count; @@ -218,13 +238,10 @@ s32 sys_event_queue_receive(PPUThread& ppu, u32 equeue_id, vm::ptr return CELL_EINVAL; } - if (queue->events.size()) + if (queue->events()) { // event data is returned in registers (dummy_event is not used) - std::tie(ppu.GPR[4], ppu.GPR[5], ppu.GPR[6], ppu.GPR[7]) = queue->events.front(); - - queue->events.pop_front(); - + std::tie(ppu.GPR[4], ppu.GPR[5], ppu.GPR[6], ppu.GPR[7]) = queue->pop(lv2_lock); return CELL_OK; } @@ -232,9 +249,9 @@ s32 sys_event_queue_receive(PPUThread& ppu, u32 equeue_id, vm::ptr ppu.GPR[3] = 0; // add waiter; protocol is ignored in current implementation - sleep_queue_entry_t waiter(ppu, queue->sq); + sleep_entry waiter(queue->thread_queue(lv2_lock), ppu); - while (!ppu.unsignal()) + while (!ppu.state.test_and_reset(cpu_state::signal)) { CHECK_EMU_STATUS; @@ -257,11 +274,7 @@ s32 sys_event_queue_receive(PPUThread& ppu, u32 equeue_id, vm::ptr if (ppu.GPR[3]) { - if (idm::check(equeue_id)) - { - throw EXCEPTION("Unexpected"); - } - + Ensures(!idm::check(equeue_id)); return CELL_ECANCELED; } @@ -282,7 +295,7 @@ s32 sys_event_queue_drain(u32 equeue_id) return CELL_ESRCH; } - queue->events.clear(); + queue->clear(lv2_lock); return CELL_OK; } @@ -401,7 +414,7 @@ s32 sys_event_port_send(u32 eport_id, u64 data1, u64 data2, u64 data3) return CELL_ENOTCONN; } - if (queue->events.size() >= queue->size) + if (queue->events() >= queue->size) { return CELL_EBUSY; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event.h b/rpcs3/Emu/Cell/lv2/sys_event.h similarity index 65% rename from rpcs3/Emu/SysCalls/lv2/sys_event.h rename to rpcs3/Emu/Cell/lv2/sys_event.h index 5326e6cff8..e1c088870c 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event.h +++ b/rpcs3/Emu/Cell/lv2/sys_event.h @@ -1,8 +1,6 @@ #pragma once -#include "Utilities/SleepQueue.h" - -namespace vm { using namespace ps3; } +#include "sys_sync.h" // Event Queue Type enum : u32 @@ -65,23 +63,58 @@ struct sys_event_t be_t data3; }; -struct lv2_event_queue_t +class lv2_event_queue_t final { - const u32 id; + // Tuple elements: source, data1, data2, data3 + using event_type = std::tuple; + + std::deque m_events; + + sleep_queue m_sq; + +public: + // Try to make an event queue with specified global key + static std::shared_ptr make(u32 protocol, s32 type, u64 name, u64 ipc_key, s32 size); + + // Get event queue by its global key + static std::shared_ptr find(u64 ipc_key); + const u32 protocol; const s32 type; const u64 name; - const u64 key; + const u64 ipc_key; const s32 size; + const u32 id{}; - // tuple elements: source, data1, data2, data3 - std::deque> events; + lv2_event_queue_t(u32 protocol, s32 type, u64 name, u64 ipc_key, s32 size) + : protocol(protocol) + , type(type) + , name(name) + , ipc_key(ipc_key) + , size(size) + { + } - sleep_queue_t sq; + // Send an event + void push(lv2_lock_t, u64 source, u64 data1, u64 data2, u64 data3); - lv2_event_queue_t(u32 protocol, s32 type, u64 name, u64 key, s32 size); + // Receive an event (queue shouldn't be empty) + event_type pop(lv2_lock_t); - void push(lv2_lock_t& lv2_lock, u64 source, u64 data1, u64 data2, u64 data3); + // Remove all events + void clear(lv2_lock_t) + { + m_events.clear(); + } + + // Get event count + std::size_t events() const { return m_events.size(); } + + // Get waiter count + std::size_t waiters() const { return m_sq.size(); } + + // Get threads (TODO) + auto& thread_queue(lv2_lock_t) { return m_sq; } }; struct lv2_event_port_t diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp b/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp similarity index 92% rename from rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp rename to rpcs3/Emu/Cell/lv2/sys_event_flag.cpp index da3b58edc2..443cc55de3 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp @@ -1,22 +1,20 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" -#include "sys_sync.h" #include "sys_event_flag.h" -SysCallBase sys_event_flag("sys_event_flag"); +LOG_CHANNEL(sys_event_flag); extern u64 get_system_time(); -void lv2_event_flag_t::notify_all(lv2_lock_t& lv2_lock) +void lv2_event_flag_t::notify_all(lv2_lock_t) { - CHECK_LV2_LOCK(lv2_lock); - - auto pred = [this](sleep_queue_t::value_type& thread) -> bool + auto pred = [this](cpu_thread* thread) -> bool { auto& ppu = static_cast(*thread); @@ -30,10 +28,8 @@ void lv2_event_flag_t::notify_all(lv2_lock_t& lv2_lock) // save pattern ppu.GPR[4] = clear_pattern(bitptn, mode); - if (!ppu.signal()) - { - throw EXCEPTION("Thread already signaled"); - } + ASSERT(!thread->state.test_and_set(cpu_state::signal)); + thread->cv.notify_one(); return true; } @@ -147,9 +143,9 @@ s32 sys_event_flag_wait(PPUThread& ppu, u32 id, u64 bitptn, u32 mode, vm::ptrsq); + sleep_entry waiter(eflag->sq, ppu); - while (!ppu.unsignal()) + while (!ppu.state.test_and_reset(cpu_state::signal)) { CHECK_EMU_STATUS; @@ -295,10 +291,8 @@ s32 sys_event_flag_cancel(u32 id, vm::ptr num) // clear "mode" as a sign of cancellation ppu.GPR[5] = 0; - if (!thread->signal()) - { - throw EXCEPTION("Thread already signaled"); - } + ASSERT(!thread->state.test_and_set(cpu_state::signal)); + thread->cv.notify_one(); } eflag->sq.clear(); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.h b/rpcs3/Emu/Cell/lv2/sys_event_flag.h similarity index 93% rename from rpcs3/Emu/SysCalls/lv2/sys_event_flag.h rename to rpcs3/Emu/Cell/lv2/sys_event_flag.h index 35da424583..31b27947c5 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.h +++ b/rpcs3/Emu/Cell/lv2/sys_event_flag.h @@ -1,8 +1,6 @@ #pragma once -#include "Utilities/SleepQueue.h" - -namespace vm { using namespace ps3; } +#include "sys_sync.h" enum { @@ -37,9 +35,9 @@ struct lv2_event_flag_t const s32 type; const u64 name; - std::atomic pattern; + atomic_t pattern; - sleep_queue_t sq; + sleep_queue sq; lv2_event_flag_t(u64 pattern, u32 protocol, s32 type, u64 name) : pattern(pattern) @@ -105,7 +103,7 @@ struct lv2_event_flag_t } } - void notify_all(lv2_lock_t& lv2_lock); + void notify_all(lv2_lock_t); }; // Aux diff --git a/rpcs3/Emu/SysCalls/lv2/sys_fs.cpp b/rpcs3/Emu/Cell/lv2/sys_fs.cpp similarity index 76% rename from rpcs3/Emu/SysCalls/lv2/sys_fs.cpp rename to rpcs3/Emu/Cell/lv2/sys_fs.cpp index 9b2fef1ae0..f9dc481f4b 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_fs.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_fs.cpp @@ -1,17 +1,13 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" - -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsFile.h" -#include "Emu/FS/vfsLocalFile.h" -#include "Emu/FS/vfsDir.h" +#include "Emu/Cell/ErrorCodes.h" #include "sys_fs.h" -SysCallBase sys_fs("sys_fs"); +LOG_CHANNEL(sys_fs); s32 sys_fs_test(u32 arg1, u32 arg2, vm::ptr arg3, u32 arg4, vm::ptr arg5, u32 arg6) { @@ -31,11 +27,8 @@ s32 sys_fs_open(vm::cptr path, s32 flags, vm::ptr fd, s32 mode, vm::c return CELL_FS_EINVAL; } - std::string local_path; - - const auto device = Emu.GetVFS().GetDevice(path.get_ptr(), local_path); - - if (!device) + const std::string& local_path = vfs::get(path.get_ptr()); + if (local_path.empty()) { sys_fs.error("sys_fs_open('%s') failed: device not mounted", path.get_ptr()); return CELL_FS_ENOTMOUNTED; @@ -49,50 +42,50 @@ s32 sys_fs_open(vm::cptr path, s32 flags, vm::ptr fd, s32 mode, vm::c return CELL_FS_EISDIR; } - u32 open_mode = 0; + mset open_mode{}; switch (flags & CELL_FS_O_ACCMODE) { - case CELL_FS_O_RDONLY: open_mode |= fom::read; break; - case CELL_FS_O_WRONLY: open_mode |= fom::write; break; - case CELL_FS_O_RDWR: open_mode |= fom::read | fom::write; break; + case CELL_FS_O_RDONLY: open_mode += fs::read; break; + case CELL_FS_O_WRONLY: open_mode += fs::write; break; + case CELL_FS_O_RDWR: open_mode += fs::read + fs::write; break; } if (flags & CELL_FS_O_CREAT) { - open_mode |= fom::create; + open_mode += fs::create; } if (flags & CELL_FS_O_TRUNC) { - open_mode |= fom::trunc; + open_mode += fs::trunc; } if (flags & CELL_FS_O_APPEND) { - open_mode |= fom::append; + open_mode += fs::append; } if (flags & CELL_FS_O_EXCL) { if (flags & CELL_FS_O_CREAT) { - open_mode |= fom::excl; + open_mode += fs::excl; } else { - open_mode = 0; // error + open_mode = {}; // error } } if (flags & ~(CELL_FS_O_ACCMODE | CELL_FS_O_CREAT | CELL_FS_O_TRUNC | CELL_FS_O_APPEND | CELL_FS_O_EXCL)) { - open_mode = 0; // error + open_mode = {}; // error } if ((flags & CELL_FS_O_ACCMODE) == CELL_FS_O_ACCMODE) { - open_mode = 0; // error + open_mode = {}; // error } if (!open_mode) @@ -100,13 +93,13 @@ s32 sys_fs_open(vm::cptr path, s32 flags, vm::ptr fd, s32 mode, vm::c throw EXCEPTION("Invalid or unimplemented flags (%#o): '%s'", flags, path.get_ptr()); } - std::shared_ptr file(Emu.GetVFS().OpenFile(path.get_ptr(), open_mode)); + fs::file file(local_path, open_mode); - if (!file || !file->IsOpened()) + if (!file) { sys_fs.error("sys_fs_open('%s'): failed to open file (flags=%#o, mode=%#o)", path.get_ptr(), flags, mode); - if (open_mode & fom::excl) + if (open_mode & fs::excl) { return CELL_FS_EEXIST; // approximation } @@ -122,7 +115,7 @@ s32 sys_fs_open(vm::cptr path, s32 flags, vm::ptr fd, s32 mode, vm::c return CELL_FS_EMFILE; } - *fd = idm::get_last_id(); + *fd = _file->id; return CELL_OK; } @@ -140,7 +133,7 @@ s32 sys_fs_read(u32 fd, vm::ptr buf, u64 nbytes, vm::ptr nread) std::lock_guard lock(file->mutex); - *nread = file->file->Read(buf.get_ptr(), nbytes); + *nread = file->file.read(buf.get_ptr(), nbytes); return CELL_OK; } @@ -160,7 +153,7 @@ s32 sys_fs_write(u32 fd, vm::cptr buf, u64 nbytes, vm::ptr nwrite) std::lock_guard lock(file->mutex); - *nwrite = file->file->Write(buf.get_ptr(), nbytes); + *nwrite = file->file.write(buf.get_ptr(), nbytes); return CELL_OK; } @@ -188,9 +181,9 @@ s32 sys_fs_opendir(vm::cptr path, vm::ptr fd) sys_fs.warning("sys_fs_opendir(path=*0x%x, fd=*0x%x)", path, fd); sys_fs.warning("*** path = '%s'", path.get_ptr()); - std::shared_ptr dir(Emu.GetVFS().OpenDir(path.get_ptr())); + fs::dir dir(vfs::get(path.get_ptr())); - if (!dir || !dir->IsOpened()) + if (!dir) { sys_fs.error("sys_fs_opendir('%s'): failed to open directory", path.get_ptr()); return CELL_FS_ENOENT; @@ -204,7 +197,7 @@ s32 sys_fs_opendir(vm::cptr path, vm::ptr fd) return CELL_FS_EMFILE; } - *fd = idm::get_last_id(); + *fd = _dir->id; return CELL_OK; } @@ -220,13 +213,13 @@ s32 sys_fs_readdir(u32 fd, vm::ptr dir, vm::ptr nread) return CELL_FS_EBADF; } - const DirEntryInfo* info = directory->dir->Read(); + fs::dir_entry info; - if (info) + if (directory->dir.read(info)) { - dir->d_type = (info->flags & DirEntry_TypeFile) ? CELL_FS_TYPE_REGULAR : CELL_FS_TYPE_DIRECTORY; - dir->d_namlen = u8(std::min(info->name.length(), CELL_FS_MAX_FS_FILE_NAME_LENGTH)); - strcpy_trunc(dir->d_name, info->name); + dir->d_type = info.is_directory ? CELL_FS_TYPE_DIRECTORY : CELL_FS_TYPE_REGULAR; + dir->d_namlen = u8(std::min(info.name.size(), CELL_FS_MAX_FS_FILE_NAME_LENGTH)); + strcpy_trunc(dir->d_name, info.name); *nread = sizeof(CellFsDirent); } else @@ -258,9 +251,9 @@ s32 sys_fs_stat(vm::cptr path, vm::ptr sb) sys_fs.warning("sys_fs_stat(path=*0x%x, sb=*0x%x)", path, sb); sys_fs.warning("*** path = '%s'", path.get_ptr()); - std::string local_path; + const std::string& local_path = vfs::get(path.get_ptr()); - if (!Emu.GetVFS().GetDevice(path.get_ptr(), local_path)) + if (local_path.empty()) { sys_fs.warning("sys_fs_stat('%s') failed: not mounted", path.get_ptr()); return CELL_FS_ENOTMOUNTED; @@ -299,20 +292,7 @@ s32 sys_fs_fstat(u32 fd, vm::ptr sb) std::lock_guard lock(file->mutex); - const auto local_file = dynamic_cast(file->file.get()); - - if (!local_file) - { - sys_fs.error("sys_fs_fstat(fd=0x%x): not a local file"); - return CELL_FS_ENOTSUP; - } - - fs::stat_t info; - - if (!local_file->GetFile().stat(info)) - { - return CELL_FS_EIO; // ??? - } + const fs::stat_t& info = file->file.stat(); sb->mode = info.is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666; sb->uid = 1; // ??? @@ -331,14 +311,14 @@ s32 sys_fs_mkdir(vm::cptr path, s32 mode) sys_fs.warning("sys_fs_mkdir(path=*0x%x, mode=%#o)", path, mode); sys_fs.warning("*** path = '%s'", path.get_ptr()); - std::string ps3_path = path.get_ptr(); + const std::string& local_path = vfs::get(path.get_ptr()); - if (Emu.GetVFS().ExistsDir(ps3_path)) + if (fs::is_dir(local_path)) { return CELL_FS_EEXIST; } - if (!Emu.GetVFS().CreatePath(ps3_path)) + if (!fs::create_path(local_path)) { return CELL_FS_EIO; // ??? } @@ -353,7 +333,7 @@ s32 sys_fs_rename(vm::cptr from, vm::cptr to) sys_fs.warning("*** from = '%s'", from.get_ptr()); sys_fs.warning("*** to = '%s'", to.get_ptr()); - if (!Emu.GetVFS().Rename(from.get_ptr(), to.get_ptr())) + if (!fs::rename(vfs::get(from.get_ptr()), vfs::get(to.get_ptr()))) { return CELL_FS_ENOENT; // ??? } @@ -367,15 +347,14 @@ s32 sys_fs_rmdir(vm::cptr path) sys_fs.warning("sys_fs_rmdir(path=*0x%x)", path); sys_fs.warning("*** path = '%s'", path.get_ptr()); - std::string ps3_path = path.get_ptr(); - - if (!Emu.GetVFS().ExistsDir(ps3_path)) + if (!fs::remove_dir(vfs::get(path.get_ptr()))) { - return CELL_FS_ENOENT; - } + switch (auto error = errno) + { + case ENOENT: return CELL_FS_ENOENT; + default: sys_fs.error("sys_fs_rmdir(): unknown error %d", error); + } - if (!Emu.GetVFS().RemoveDir(ps3_path)) - { return CELL_FS_EIO; // ??? } @@ -388,15 +367,14 @@ s32 sys_fs_unlink(vm::cptr path) sys_fs.warning("sys_fs_unlink(path=*0x%x)", path); sys_fs.warning("*** path = '%s'", path.get_ptr()); - std::string ps3_path = path.get_ptr(); - - if (!Emu.GetVFS().ExistsFile(ps3_path)) + if (!fs::remove_file(vfs::get(path.get_ptr()))) { - return CELL_FS_ENOENT; - } + switch (auto error = errno) + { + case ENOENT: return CELL_FS_ENOENT; + default: sys_fs.error("sys_fs_unlink(): unknown error %d", error); + } - if (!Emu.GetVFS().RemoveFile(ps3_path)) - { return CELL_FS_EIO; // ??? } @@ -417,7 +395,7 @@ s32 sys_fs_lseek(u32 fd, s64 offset, s32 whence, vm::ptr pos) if (whence >= 3) { - sys_fs.error("sys_fs_lseek(): unknown seek whence (%d)", whence); + sys_fs.error("sys_fs_lseek(): invalid seek whence (%d)", whence); return CELL_FS_EINVAL; } @@ -430,7 +408,7 @@ s32 sys_fs_lseek(u32 fd, s64 offset, s32 whence, vm::ptr pos) std::lock_guard lock(file->mutex); - *pos = file->file->Seek(offset, (fs::seek_mode)whence); + *pos = file->file.seek(offset, static_cast(whence)); return CELL_OK; } @@ -468,15 +446,14 @@ s32 sys_fs_truncate(vm::cptr path, u64 size) sys_fs.warning("sys_fs_truncate(path=*0x%x, size=0x%llx)", path, size); sys_fs.warning("*** path = '%s'", path.get_ptr()); - std::string ps3_path = path.get_ptr(); - - if (!Emu.GetVFS().ExistsFile(ps3_path)) + if (!fs::truncate_file(vfs::get(path.get_ptr()), size)) { - return CELL_FS_ENOENT; - } + switch (auto error = errno) + { + case ENOENT: return CELL_FS_ENOENT; + default: sys_fs.error("sys_fs_truncate(): unknown error %d", error); + } - if (!Emu.GetVFS().TruncateFile(ps3_path, size)) - { return CELL_FS_EIO; // ??? } @@ -496,16 +473,14 @@ s32 sys_fs_ftruncate(u32 fd, u64 size) std::lock_guard lock(file->mutex); - const auto local_file = dynamic_cast(file->file.get()); - - if (!local_file) + if (!file->file.trunc(size)) { - sys_fs.error("sys_fs_ftruncate(fd=0x%x): not a local file"); - return CELL_FS_ENOTSUP; - } + switch (auto error = errno) + { + case 0: + default: sys_fs.error("sys_fs_ftruncate(): unknown error %d", error); + } - if (!local_file->GetFile().trunc(size)) - { return CELL_FS_EIO; // ??? } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_fs.h b/rpcs3/Emu/Cell/lv2/sys_fs.h similarity index 87% rename from rpcs3/Emu/SysCalls/lv2/sys_fs.h rename to rpcs3/Emu/Cell/lv2/sys_fs.h index 324958a54a..e943697325 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_fs.h +++ b/rpcs3/Emu/Cell/lv2/sys_fs.h @@ -148,8 +148,6 @@ struct CellFsUtimbuf #pragma pack(pop) -struct vfsStream; - // Stream Support Status (st_status) enum : u32 { @@ -161,16 +159,26 @@ enum : u32 using fs_st_cb_t = vm::ptr; -struct fs_st_cb_rec_t +struct alignas(16) fs_st_cb_rec_t { u64 size; fs_st_cb_t func; u32 pad; }; -struct lv2_file_t +struct lv2_fs_object_t { - const std::shared_ptr file; + using id_base = lv2_fs_object_t; + + static constexpr u32 id_min = 3; + static constexpr u32 id_max = 255; + + const u32 id{}; +}; + +struct lv2_file_t : lv2_fs_object_t +{ + const fs::file file; const s32 mode; const s32 flags; @@ -188,12 +196,12 @@ struct lv2_file_t u32 st_buffer; u64 st_read_size; - std::atomic st_total_read; - std::atomic st_copied; + atomic_t st_total_read; + atomic_t st_copied; atomic_t st_callback; - lv2_file_t(std::shared_ptr file, s32 mode, s32 flags) + lv2_file_t(fs::file file, s32 mode, s32 flags) : file(std::move(file)) , mode(mode) , flags(flags) @@ -203,42 +211,16 @@ struct lv2_file_t } }; -template<> struct id_traits +struct lv2_dir_t : lv2_fs_object_t { - static const u32 base = 0xfddd0000, max = 255; + const fs::dir dir; - static u32 next_id(u32 raw_id) - { - return - raw_id < 0x80000000 ? base + 3 : - raw_id - base < max ? raw_id + 1 : 0; - } - - static u32 in_id(u32 id) - { - return id + base; - } - - static u32 out_id(u32 raw_id) - { - return raw_id - base; - } -}; - -class vfsDirBase; - -struct lv2_dir_t -{ - const std::shared_ptr dir; - - lv2_dir_t(std::shared_ptr dir) + lv2_dir_t(fs::dir dir) : dir(std::move(dir)) { } }; -template<> struct id_traits : public id_traits {}; - // SysCalls s32 sys_fs_test(u32 arg1, u32 arg2, vm::ptr arg3, u32 arg4, vm::ptr arg5, u32 arg6); s32 sys_fs_open(vm::cptr path, s32 flags, vm::ptr fd, s32 mode, vm::cptr arg, u64 size); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_interrupt.cpp b/rpcs3/Emu/Cell/lv2/sys_interrupt.cpp similarity index 85% rename from rpcs3/Emu/SysCalls/lv2/sys_interrupt.cpp rename to rpcs3/Emu/Cell/lv2/sys_interrupt.cpp index 6251f33d00..21c873cc3c 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_interrupt.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_interrupt.cpp @@ -1,36 +1,24 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" #include "sys_interrupt.h" -SysCallBase sys_interrupt("sys_interrupt"); +LOG_CHANNEL(sys_interrupt); -lv2_int_tag_t::lv2_int_tag_t() - : id(idm::get_last_id()) +void lv2_int_serv_t::join(PPUThread& ppu, lv2_lock_t lv2_lock) { -} - -lv2_int_serv_t::lv2_int_serv_t(const std::shared_ptr& thread) - : thread(thread) - , id(idm::get_last_id()) -{ -} - -void lv2_int_serv_t::join(PPUThread& ppu, lv2_lock_t& lv2_lock) -{ - CHECK_LV2_LOCK(lv2_lock); - // Use is_joining to stop interrupt thread and signal thread->is_joining = true; thread->cv.notify_one(); // Start joining - while (thread->is_alive()) + while (!(thread->state & cpu_state::exit)) { CHECK_EMU_STATUS; @@ -39,7 +27,7 @@ void lv2_int_serv_t::join(PPUThread& ppu, lv2_lock_t& lv2_lock) // Cleanup idm::remove(id); - idm::remove(thread->get_id()); + idm::remove(thread->id); } s32 sys_interrupt_tag_destroy(u32 intrtag) @@ -88,7 +76,7 @@ s32 _sys_interrupt_thread_establish(vm::ptr ih, u32 intrtag, u32 intrthread } // If interrupt thread is running, it's already established on another interrupt tag - if (!it->is_stopped()) + if (!(it->state & cpu_state::stop)) { return CELL_EAGAIN; } @@ -137,10 +125,11 @@ s32 _sys_interrupt_thread_establish(vm::ptr ih, u32 intrtag, u32 intrthread ppu.cv.wait(lv2_lock); } - ppu.exit(); + ppu.state += cpu_state::exit; }; - it->exec(); + it->state -= cpu_state::stop; + it->safe_notify(); *ih = handler->id; @@ -177,5 +166,5 @@ void sys_interrupt_thread_eoi(PPUThread& ppu) ppu.GPR[1] = align(ppu.stack_addr + ppu.stack_size, 0x200) - 0x200; // supercrutch to bypass stack check - ppu.fast_stop(); + ppu.state += cpu_state::ret; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_interrupt.h b/rpcs3/Emu/Cell/lv2/sys_interrupt.h similarity index 65% rename from rpcs3/Emu/SysCalls/lv2/sys_interrupt.h rename to rpcs3/Emu/Cell/lv2/sys_interrupt.h index fef802d89d..558aede372 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_interrupt.h +++ b/rpcs3/Emu/Cell/lv2/sys_interrupt.h @@ -1,28 +1,29 @@ #pragma once -namespace vm { using namespace ps3; } +#include "sys_sync.h" class PPUThread; struct lv2_int_tag_t { - const u32 id; + const u32 id{}; std::shared_ptr handler; - - lv2_int_tag_t(); }; struct lv2_int_serv_t { const std::shared_ptr thread; - const u32 id; + const u32 id{}; - std::atomic signal{ 0 }; // signal count + atomic_t signal{ 0 }; // signal count - lv2_int_serv_t(const std::shared_ptr& thread); + lv2_int_serv_t(const std::shared_ptr& thread) + : thread(thread) + { + } - void join(PPUThread& ppu, lv2_lock_t& lv2_lock); + void join(PPUThread& ppu, lv2_lock_t); }; // SysCalls diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp b/rpcs3/Emu/Cell/lv2/sys_lwcond.cpp similarity index 88% rename from rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp rename to rpcs3/Emu/Cell/lv2/sys_lwcond.cpp index ad843cae93..cb77b4b479 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_lwcond.cpp @@ -1,21 +1,20 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" #include "sys_lwmutex.h" #include "sys_lwcond.h" -SysCallBase sys_lwcond("sys_lwcond"); +LOG_CHANNEL(sys_lwcond); extern u64 get_system_time(); -void lv2_lwcond_t::notify(lv2_lock_t & lv2_lock, sleep_queue_t::value_type& thread, const std::shared_ptr& mutex, bool mode2) +void lv2_lwcond_t::notify(lv2_lock_t, cpu_thread* thread, const std::shared_ptr& mutex, bool mode2) { - CHECK_LV2_LOCK(lv2_lock); - auto& ppu = static_cast(*thread); ppu.GPR[3] = mode2; // set to return CELL_EBUSY @@ -30,10 +29,8 @@ void lv2_lwcond_t::notify(lv2_lock_t & lv2_lock, sleep_queue_t::value_type& thre mutex->signaled--; } - if (!ppu.signal()) - { - throw EXCEPTION("Thread already signaled"); - } + ASSERT(!thread->state.test_and_set(cpu_state::signal)); + thread->cv.notify_one(); } s32 _sys_lwcond_create(vm::ptr lwcond_id, u32 lwmutex_id, vm::ptr control, u64 name, u32 arg5) @@ -92,9 +89,9 @@ s32 _sys_lwcond_signal(u32 lwcond_id, u32 lwmutex_id, u32 ppu_thread_id, u32 mod // mode 3: lightweight mutex was forcefully owned by the calling thread // pick waiter; protocol is ignored in current implementation - const auto found = !~ppu_thread_id ? cond->sq.begin() : std::find_if(cond->sq.begin(), cond->sq.end(), [=](sleep_queue_t::value_type& thread) + const auto found = !~ppu_thread_id ? cond->sq.begin() : std::find_if(cond->sq.begin(), cond->sq.end(), [=](cpu_thread* thread) { - return thread->get_id() == ppu_thread_id; + return thread->id == ppu_thread_id; }); if (found == cond->sq.end()) @@ -177,12 +174,12 @@ s32 _sys_lwcond_queue_wait(PPUThread& ppu, u32 lwcond_id, u32 lwmutex_id, u64 ti mutex->unlock(lv2_lock); // add waiter; protocol is ignored in current implementation - sleep_queue_entry_t waiter(ppu, cond->sq); + sleep_entry waiter(cond->sq, ppu); // potential mutex waiter (not added immediately) - sleep_queue_entry_t mutex_waiter(ppu, cond->sq, defer_sleep); + sleep_entry mutex_waiter(cond->sq, ppu, defer_sleep); - while (!ppu.unsignal()) + while (!ppu.state.test_and_reset(cpu_state::signal)) { CHECK_EMU_STATUS; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.h b/rpcs3/Emu/Cell/lv2/sys_lwcond.h similarity index 84% rename from rpcs3/Emu/SysCalls/lv2/sys_lwcond.h rename to rpcs3/Emu/Cell/lv2/sys_lwcond.h index 552210ce34..8633318c03 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.h +++ b/rpcs3/Emu/Cell/lv2/sys_lwcond.h @@ -21,14 +21,14 @@ struct lv2_lwcond_t { const u64 name; - sleep_queue_t sq; + sleep_queue sq; lv2_lwcond_t(u64 name) : name(name) { } - void notify(lv2_lock_t& lv2_lock, sleep_queue_t::value_type& thread, const std::shared_ptr& mutex, bool mode2); + void notify(lv2_lock_t, cpu_thread* thread, const std::shared_ptr& mutex, bool mode2); }; // Aux diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp b/rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp similarity index 88% rename from rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp rename to rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp index 746f87464b..76833e1a93 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp @@ -1,21 +1,19 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" -#include "sys_sync.h" #include "sys_lwmutex.h" -SysCallBase sys_lwmutex("sys_lwmutex"); +LOG_CHANNEL(sys_lwmutex); extern u64 get_system_time(); -void lv2_lwmutex_t::unlock(lv2_lock_t& lv2_lock) +void lv2_lwmutex_t::unlock(lv2_lock_t) { - CHECK_LV2_LOCK(lv2_lock); - if (signaled) { throw EXCEPTION("Unexpected"); @@ -23,10 +21,9 @@ void lv2_lwmutex_t::unlock(lv2_lock_t& lv2_lock) if (sq.size()) { - if (!sq.front()->signal()) - { - throw EXCEPTION("Thread already signaled"); - } + auto& thread = sq.front(); + ASSERT(!thread->state.test_and_set(cpu_state::signal)); + thread->cv.notify_one(); sq.pop_front(); } @@ -102,9 +99,9 @@ s32 _sys_lwmutex_lock(PPUThread& ppu, u32 lwmutex_id, u64 timeout) } // add waiter; protocol is ignored in current implementation - sleep_queue_entry_t waiter(ppu, mutex->sq); + sleep_entry waiter(mutex->sq, ppu); - while (!ppu.unsignal()) + while (!ppu.state.test_and_reset(cpu_state::signal)) { CHECK_EMU_STATUS; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h b/rpcs3/Emu/Cell/lv2/sys_lwmutex.h similarity index 86% rename from rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h rename to rpcs3/Emu/Cell/lv2/sys_lwmutex.h index 4386c83650..775bd11ff6 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h +++ b/rpcs3/Emu/Cell/lv2/sys_lwmutex.h @@ -1,8 +1,6 @@ #pragma once -#include "Utilities/SleepQueue.h" - -namespace vm { using namespace ps3; } +#include "sys_sync.h" struct sys_lwmutex_attribute_t { @@ -20,7 +18,7 @@ enum : u32 struct sys_lwmutex_t { - struct sync_var_t + struct alignas(8) sync_var_t { be_t owner; be_t waiter; @@ -52,9 +50,9 @@ struct lv2_lwmutex_t const u64 name; // this object is not truly a mutex and its syscall names may be wrong, it's probably a sleep queue or something - std::atomic signaled{ 0 }; + atomic_t signaled{ 0 }; - sleep_queue_t sq; + sleep_queue sq; lv2_lwmutex_t(u32 protocol, u64 name) : protocol(protocol) @@ -62,7 +60,7 @@ struct lv2_lwmutex_t { } - void unlock(lv2_lock_t& lv2_lock); + void unlock(lv2_lock_t); }; // Aux diff --git a/rpcs3/Emu/SysCalls/lv2/sys_memory.cpp b/rpcs3/Emu/Cell/lv2/sys_memory.cpp similarity index 97% rename from rpcs3/Emu/SysCalls/lv2/sys_memory.cpp rename to rpcs3/Emu/Cell/lv2/sys_memory.cpp index 3141092f9f..47a7fc79cc 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_memory.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_memory.cpp @@ -1,18 +1,13 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "sys_memory.h" -SysCallBase sys_memory("sys_memory"); - -lv2_memory_container_t::lv2_memory_container_t(u32 size) - : size(size) - , id(idm::get_last_id()) -{ -} +LOG_CHANNEL(sys_memory); s32 sys_memory_allocate(u32 size, u64 flags, vm::ptr alloc_addr) { diff --git a/rpcs3/Emu/SysCalls/lv2/sys_memory.h b/rpcs3/Emu/Cell/lv2/sys_memory.h similarity index 92% rename from rpcs3/Emu/SysCalls/lv2/sys_memory.h rename to rpcs3/Emu/Cell/lv2/sys_memory.h index da73297264..e99580083d 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_memory.h +++ b/rpcs3/Emu/Cell/lv2/sys_memory.h @@ -1,6 +1,6 @@ #pragma once -namespace vm { using namespace ps3; } +#include "sys_sync.h" enum : u32 { @@ -42,18 +42,23 @@ struct sys_page_attr_t be_t pad; }; +#include + struct lv2_memory_container_t { const u32 size; // amount of "physical" memory in this container - const u32 id; + const u32 id{}; // amount of memory allocated - std::atomic used{ 0 }; + atomic_t used{ 0 }; // allocations (addr -> size) std::map allocs; - lv2_memory_container_t(u32 size); + lv2_memory_container_t(u32 size) + : size(size) + { + } }; // SysCalls diff --git a/rpcs3/Emu/SysCalls/lv2/sys_mmapper.cpp b/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp similarity index 96% rename from rpcs3/Emu/SysCalls/lv2/sys_mmapper.cpp rename to rpcs3/Emu/Cell/lv2/sys_mmapper.cpp index 5ec9fc02ac..c8e70246cd 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_mmapper.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp @@ -1,21 +1,13 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "sys_mmapper.h" -SysCallBase sys_mmapper("sys_mmapper"); - -lv2_memory_t::lv2_memory_t(u32 size, u32 align, u64 flags, const std::shared_ptr ct) - : size(size) - , align(align) - , id(idm::get_last_id()) - , flags(flags) - , ct(ct) -{ -} +LOG_CHANNEL(sys_mmapper); s32 sys_mmapper_allocate_address(u64 size, u64 flags, u64 alignment, vm::ptr alloc_addr) { diff --git a/rpcs3/Emu/SysCalls/lv2/sys_mmapper.h b/rpcs3/Emu/Cell/lv2/sys_mmapper.h similarity index 86% rename from rpcs3/Emu/SysCalls/lv2/sys_mmapper.h rename to rpcs3/Emu/Cell/lv2/sys_mmapper.h index 684ac0fdc8..e8d9d9a265 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_mmapper.h +++ b/rpcs3/Emu/Cell/lv2/sys_mmapper.h @@ -2,19 +2,23 @@ #include "sys_memory.h" -namespace vm { using namespace ps3; } - struct lv2_memory_t { const u32 size; // memory size const u32 align; // required alignment - const u32 id; const u64 flags; const std::shared_ptr ct; // memory container the physical memory is taken from + const u32 id{}; - std::atomic addr{ 0 }; // actual mapping address + atomic_t addr{ 0 }; // actual mapping address - lv2_memory_t(u32 size, u32 align, u64 flags, const std::shared_ptr ct); + lv2_memory_t(u32 size, u32 align, u64 flags, const std::shared_ptr ct) + : size(size) + , align(align) + , flags(flags) + , ct(ct) + { + } }; // SysCalls diff --git a/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp b/rpcs3/Emu/Cell/lv2/sys_mutex.cpp similarity index 88% rename from rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp rename to rpcs3/Emu/Cell/lv2/sys_mutex.cpp index f2d50747ee..faf3f21b99 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_mutex.cpp @@ -1,32 +1,28 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" -#include "sys_sync.h" #include "sys_mutex.h" -SysCallBase sys_mutex("sys_mutex"); +LOG_CHANNEL(sys_mutex); extern u64 get_system_time(); -void lv2_mutex_t::unlock(lv2_lock_t& lv2_lock) +void lv2_mutex_t::unlock(lv2_lock_t) { - CHECK_LV2_LOCK(lv2_lock); - owner.reset(); if (sq.size()) { // pick new owner; protocol is ignored in current implementation - owner = sq.front(); + owner = std::static_pointer_cast(sq.front()->shared_from_this()); - if (!owner->signal()) - { - throw EXCEPTION("Mutex owner already signaled"); - } + ASSERT(!owner->state.test_and_set(cpu_state::signal)); + owner->cv.notify_one(); } } @@ -132,15 +128,15 @@ s32 sys_mutex_lock(PPUThread& ppu, u32 mutex_id, u64 timeout) // lock immediately if not locked if (!mutex->owner) { - mutex->owner = std::static_pointer_cast(ppu.shared_from_this()); + mutex->owner = std::static_pointer_cast(ppu.shared_from_this()); return CELL_OK; } // add waiter; protocol is ignored in current implementation - sleep_queue_entry_t waiter(ppu, mutex->sq); + sleep_entry waiter(mutex->sq, ppu); - while (!ppu.unsignal()) + while (!ppu.state.test_and_reset(cpu_state::signal)) { CHECK_EMU_STATUS; @@ -207,7 +203,7 @@ s32 sys_mutex_trylock(PPUThread& ppu, u32 mutex_id) } // own the mutex if free - mutex->owner = std::static_pointer_cast(ppu.shared_from_this()); + mutex->owner = std::static_pointer_cast(ppu.shared_from_this()); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_mutex.h b/rpcs3/Emu/Cell/lv2/sys_mutex.h similarity index 72% rename from rpcs3/Emu/SysCalls/lv2/sys_mutex.h rename to rpcs3/Emu/Cell/lv2/sys_mutex.h index 8e736b5ea9..97f9d7d858 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_mutex.h +++ b/rpcs3/Emu/Cell/lv2/sys_mutex.h @@ -1,8 +1,6 @@ #pragma once -#include "Utilities/SleepQueue.h" - -namespace vm { using namespace ps3; } +#include "sys_sync.h" struct sys_mutex_attribute_t { @@ -27,11 +25,11 @@ struct lv2_mutex_t const u32 protocol; const u64 name; - std::atomic cond_count{ 0 }; // count of condition variables associated - std::atomic recursive_count{ 0 }; // count of recursive locks - std::shared_ptr owner; // current mutex owner + atomic_t cond_count{ 0 }; // count of condition variables associated + atomic_t recursive_count{ 0 }; // count of recursive locks + std::shared_ptr owner; // current mutex owner - sleep_queue_t sq; + sleep_queue sq; lv2_mutex_t(bool recursive, u32 protocol, u64 name) : recursive(recursive) @@ -40,7 +38,7 @@ struct lv2_mutex_t { } - void unlock(lv2_lock_t& lv2_lock); + void unlock(lv2_lock_t); }; class PPUThread; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp similarity index 90% rename from rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp rename to rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp index 51cff30866..f895072977 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp @@ -1,14 +1,15 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" #include "sys_mutex.h" #include "sys_ppu_thread.h" -SysCallBase sys_ppu_thread("sys_ppu_thread"); +LOG_CHANNEL(sys_ppu_thread); void _sys_ppu_thread_exit(PPUThread& ppu, u64 errorcode) { @@ -28,17 +29,17 @@ void _sys_ppu_thread_exit(PPUThread& ppu, u64 errorcode) if (!ppu.is_joinable) { - idm::remove(ppu.get_id()); + idm::remove(ppu.id); } else { - ppu.exit(); + ppu.state += cpu_state::exit; } - // Throw if this syscall was not called directly by the SC instruction - if (~ppu.hle_code != 41) + // Throw if this syscall was not called directly by the SC instruction (hack) + if (ppu.GPR[11] != 41 || ppu.custom_task) { - throw CPUThreadExit{}; + throw cpu_state::exit; } } @@ -76,7 +77,7 @@ s32 sys_ppu_thread_join(PPUThread& ppu, u32 thread_id, vm::ptr vptr) thread->is_joining = true; // join thread - while (thread->is_alive()) + while (!(thread->state & cpu_state::exit)) { CHECK_EMU_STATUS; @@ -84,10 +85,10 @@ s32 sys_ppu_thread_join(PPUThread& ppu, u32 thread_id, vm::ptr vptr) } // get exit status from the register - *vptr = thread->GPR[3]; + if (vptr) *vptr = thread->GPR[3]; // cleanup - idm::remove(thread->get_id()); + idm::remove(thread->id); return CELL_OK; } @@ -225,7 +226,7 @@ u32 ppu_thread_create(u32 entry, u64 arg, s32 prio, u32 stacksize, const std::st ppu->prio = prio; ppu->stack_size = stacksize; ppu->custom_task = std::move(task); - ppu->run(); + ppu->cpu_init(); if (entry) { @@ -234,9 +235,10 @@ u32 ppu_thread_create(u32 entry, u64 arg, s32 prio, u32 stacksize, const std::st } ppu->GPR[3] = arg; - ppu->exec(); + ppu->state -= cpu_state::stop; + ppu->safe_notify(); - return ppu->get_id(); + return ppu->id; } s32 _sys_ppu_thread_create(vm::ptr thread_id, vm::ptr param, u64 arg, u64 unk, s32 prio, u32 stacksize, u64 flags, vm::cptr threadname) @@ -263,21 +265,17 @@ s32 _sys_ppu_thread_create(vm::ptr thread_id, vm::ptr p ppu->prio = prio; ppu->stack_size = std::max(stacksize, 0x4000); - ppu->run(); + ppu->cpu_init(); ppu->PC = vm::read32(param->entry); ppu->GPR[2] = vm::read32(param->entry + 4); // rtoc ppu->GPR[3] = arg; ppu->GPR[4] = unk; // actually unknown + ppu->GPR[13] = param->tls; ppu->is_joinable = is_joinable; - if (u32 tls = param->tls) // hack - { - ppu->GPR[13] = tls; - } - - *thread_id = ppu->get_id(); + *thread_id = ppu->id; return CELL_OK; } @@ -295,7 +293,8 @@ s32 sys_ppu_thread_start(u32 thread_id) return CELL_ESRCH; } - thread->exec(); + thread->state -= cpu_state::stop; + thread->safe_notify(); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.h b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.h similarity index 100% rename from rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.h rename to rpcs3/Emu/Cell/lv2/sys_ppu_thread.h diff --git a/rpcs3/Emu/SysCalls/lv2/sys_process.cpp b/rpcs3/Emu/Cell/lv2/sys_process.cpp similarity index 97% rename from rpcs3/Emu/SysCalls/lv2/sys_process.cpp rename to rpcs3/Emu/Cell/lv2/sys_process.cpp index 9de2ae7dbc..8291849120 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_process.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_process.cpp @@ -1,12 +1,10 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsFile.h" -#include "Loader/PSF.h" +#include "Emu/Cell/ErrorCodes.h" #include "sys_lwmutex.h" #include "sys_lwcond.h" #include "sys_mutex.h" @@ -24,7 +22,7 @@ #include "sys_fs.h" #include "sys_process.h" -SysCallBase sys_process("sys_process"); +LOG_CHANNEL(sys_process); s32 process_getpid() { diff --git a/rpcs3/Emu/SysCalls/lv2/sys_process.h b/rpcs3/Emu/Cell/lv2/sys_process.h similarity index 100% rename from rpcs3/Emu/SysCalls/lv2/sys_process.h rename to rpcs3/Emu/Cell/lv2/sys_process.h diff --git a/rpcs3/Emu/SysCalls/lv2/sys_prx.cpp b/rpcs3/Emu/Cell/lv2/sys_prx.cpp similarity index 62% rename from rpcs3/Emu/SysCalls/lv2/sys_prx.cpp rename to rpcs3/Emu/Cell/lv2/sys_prx.cpp index 4f39c3059f..99ec5b9ac5 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_prx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_prx.cpp @@ -1,142 +1,32 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" -#include "Emu/SysCalls/CB_FUNC.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/SysCalls/ModuleManager.h" -#include "Emu/Cell/PPUInstrTable.h" - -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsFile.h" #include "Crypto/unself.h" -#include "Loader/ELF64.h" +#include "Loader/ELF.h" + +#include "Emu/Cell/ErrorCodes.h" #include "sys_prx.h" -SysCallBase sys_prx("sys_prx"); - -lv2_prx_t::lv2_prx_t() - : id(idm::get_last_id()) -{ -} +LOG_CHANNEL(sys_prx); s32 prx_load_module(std::string path, u64 flags, vm::ptr pOpt) { sys_prx.warning("prx_load_module(path='%s', flags=0x%llx, pOpt=*0x%x)", path.c_str(), flags, pOpt); - loader::handlers::elf64 loader; + const ppu_prx_loader loader = fs::file(vfs::get(path)); - vfsFile f(path); - if (!f.IsOpened()) - { - return CELL_PRX_ERROR_UNKNOWN_MODULE; - } - - if (loader.init(f) != loader::handler::error_code::ok || !loader.is_sprx()) + if (loader != elf_error::ok) { return CELL_PRX_ERROR_ILLEGAL_LIBRARY; } - loader::handlers::elf64::sprx_info info; - loader.load_sprx(info); + const auto prx = loader.load(); - auto prx = idm::make_ptr(); - - auto meta = info.modules[""]; - prx->start.set(meta.exports[0xBC9A0086]); - prx->stop.set(meta.exports[0xAB779874]); - prx->exit.set(meta.exports[0x3AB9A95E]); - - for (auto &module_ : info.modules) + if (!prx) { - if (module_.first == "") - continue; - - Module<>* module = Emu.GetModuleManager().GetModuleByName(module_.first.c_str()); - - if (!module) - { - sys_prx.error("Unknown module '%s'", module_.first.c_str()); - } - - for (auto& f : module_.second.exports) - { - const u32 nid = f.first; - const u32 addr = f.second; - - u32 index; - - auto func = get_ppu_func_by_nid(nid, &index); - - if (!func) - { - index = add_ppu_func(ModuleFunc(nid, 0, module, nullptr, nullptr, vm::ptr::make(addr))); - } - else - { - func->lle_func.set(addr); - - if (func->flags & MFF_FORCED_HLE) - { - u32 i_addr = 0; - - if (!vm::check_addr(addr, 8) || !vm::check_addr(i_addr = vm::read32(addr), 4)) - { - sys_prx.error("Failed to inject code for exported function '%s' (opd=0x%x, 0x%x)", get_ps3_function_name(nid), addr, i_addr); - } - else - { - vm::write32(i_addr, PPU_instr::HACK(index | EIF_PERFORM_BLR)); - } - } - } - } - - for (auto &import : module_.second.imports) - { - u32 nid = import.first; - u32 addr = import.second; - - u32 index; - - auto func = get_ppu_func_by_nid(nid, &index); - - if (!func) - { - sys_prx.error("Unknown function '%s' in '%s' module (0x%x)", get_ps3_function_name(nid), module_.first); - - index = add_ppu_func(ModuleFunc(nid, 0, module, nullptr, nullptr)); - } - else - { - const bool is_lle = func->lle_func && !(func->flags & MFF_FORCED_HLE); - - sys_prx.error("Imported %sfunction '%s' in '%s' module (0x%x)", (is_lle ? "LLE " : ""), get_ps3_function_name(nid), module_.first, addr); - } - - if (!patch_ppu_import(addr, index)) - { - sys_prx.error("Failed to inject code at address 0x%x", addr); - } - } - } - - const auto decoder_cache = fxm::get(); - - for (auto& seg : info.segments) - { - const u32 addr = seg.begin.addr(); - const u32 size = align(seg.size, 4096); - - if (vm::check_addr(addr, size)) - { - decoder_cache->initialize(addr, size); - } - else - { - sys_prx.error("Failed to process executable area (addr=0x%x, size=0x%x)", addr, size); - } + return CELL_PRX_ERROR_ILLEGAL_LIBRARY; } return prx->id; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_prx.h b/rpcs3/Emu/Cell/lv2/sys_prx.h similarity index 69% rename from rpcs3/Emu/SysCalls/lv2/sys_prx.h rename to rpcs3/Emu/Cell/lv2/sys_prx.h index 89371e63ed..4d513b03b3 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_prx.h +++ b/rpcs3/Emu/Cell/lv2/sys_prx.h @@ -30,114 +30,21 @@ enum CELL_PRX_ERROR_ELF_IS_REGISTERED = 0x80011910, // Fixed ELF is already registered }; -struct sys_stub -{ - u8 s_size; // = 0x2c - u8 s_unk0; - be_t s_version; // = 0x1 - be_t s_unk1; // = 0x9 // flags? - be_t s_imports; - be_t s_unk2; // = 0x0 - be_t s_unk3; // = 0x0 - vm::bcptr s_modulename; - vm::bptr s_nid; - vm::bptr s_text; - be_t s_unk4; // = 0x0 - be_t s_unk5; // = 0x0 - be_t s_unk6; // = 0x0 - be_t s_unk7; // = 0x0 -}; - -struct sys_proc_prx_param -{ - be_t size; - be_t magic; - be_t version; - be_t pad0; - be_t libentstart; - be_t libentend; - vm::bptr libstubstart; - vm::bptr libstubend; - be_t ver; - be_t pad1; - be_t pad2; -}; - -// Information about imported or exported libraries in PRX modules -struct sys_prx_library_info_t -{ - u8 size; - u8 unk0; - be_t version; - be_t attributes; - be_t num_func; - be_t num_var; - be_t num_tlsvar; - u8 info_hash; - u8 info_tlshash; - u8 unk1[2]; - be_t name_addr; - be_t fnid_addr; - be_t fstub_addr; - be_t unk4; - be_t unk5; - be_t unk6; - be_t unk7; -}; - -// ELF file headers -struct sys_prx_param_t -{ - be_t size; - be_t magic; - be_t version; - be_t unk0; - be_t libentstart; - be_t libentend; - vm::bptr libstubstart; - vm::bptr libstubend; - be_t ver; - be_t unk1; - be_t unk2; -}; - struct sys_prx_get_module_id_by_name_option_t { be_t size; vm::ptr base; }; -// PRX file headers -struct sys_prx_module_info_t -{ - be_t attributes; - be_t version; - char name[28]; - be_t toc; - vm::bptr exports_start; - vm::bptr exports_end; - be_t imports_start; - be_t imports_end; -}; - -// Relocation information of the SCE_PPURELA segment -struct sys_prx_relocation_info_t -{ - be_t offset; - be_t unk0; - u8 index_value; - u8 index_addr; - be_t type; - vm::bptr ptr; -}; - -// Data types struct sys_prx_load_module_option_t { be_t size; vm::bptr base_addr; }; +struct sys_prx_segment_info_t;// TODO +struct sys_prx_module_info_t;// TODO + struct sys_prx_start_module_option_t { be_t size; @@ -165,18 +72,17 @@ struct sys_prx_get_module_list_t vm::bptr idlist; }; -// Auxiliary data types struct lv2_prx_t { - const u32 id; + const u32 id{}; bool is_started = false; + std::unordered_map specials; + vm::ptr argv)> start = vm::null; vm::ptr argv)> stop = vm::null; vm::ptr exit = vm::null; - - lv2_prx_t(); }; // SysCalls diff --git a/rpcs3/Emu/SysCalls/lv2/sys_rsx.cpp b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/lv2/sys_rsx.cpp rename to rpcs3/Emu/Cell/lv2/sys_rsx.cpp index eb25345942..5d4d8ee83d 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_rsx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp @@ -1,11 +1,12 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "sys_rsx.h" -SysCallBase sys_rsx("sys_rsx"); +LOG_CHANNEL(sys_rsx); s32 sys_rsx_device_open() { diff --git a/rpcs3/Emu/SysCalls/lv2/sys_rsx.h b/rpcs3/Emu/Cell/lv2/sys_rsx.h similarity index 100% rename from rpcs3/Emu/SysCalls/lv2/sys_rsx.h rename to rpcs3/Emu/Cell/lv2/sys_rsx.h diff --git a/rpcs3/Emu/SysCalls/lv2/sys_rwlock.cpp b/rpcs3/Emu/Cell/lv2/sys_rwlock.cpp similarity index 87% rename from rpcs3/Emu/SysCalls/lv2/sys_rwlock.cpp rename to rpcs3/Emu/Cell/lv2/sys_rwlock.cpp index 1145e6cb31..0188cf7ac6 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_rwlock.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_rwlock.cpp @@ -1,30 +1,26 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" -#include "sys_sync.h" #include "sys_rwlock.h" -SysCallBase sys_rwlock("sys_rwlock"); +LOG_CHANNEL(sys_rwlock); extern u64 get_system_time(); -void lv2_rwlock_t::notify_all(lv2_lock_t& lv2_lock) +void lv2_rwlock_t::notify_all(lv2_lock_t) { - CHECK_LV2_LOCK(lv2_lock); - // pick a new writer if possible; protocol is ignored in current implementation if (!readers && !writer && wsq.size()) { - writer = wsq.front(); + writer = std::static_pointer_cast(wsq.front()->shared_from_this()); - if (!writer->signal()) - { - throw EXCEPTION("Writer already signaled"); - } + ASSERT(!writer->state.test_and_set(cpu_state::signal)); + writer->cv.notify_one(); return wsq.pop_front(); } @@ -36,10 +32,8 @@ void lv2_rwlock_t::notify_all(lv2_lock_t& lv2_lock) for (auto& thread : rsq) { - if (!thread->signal()) - { - throw EXCEPTION("Reader already signaled"); - } + ASSERT(!thread->state.test_and_set(cpu_state::signal)); + thread->cv.notify_one(); } return rsq.clear(); @@ -123,9 +117,9 @@ s32 sys_rwlock_rlock(PPUThread& ppu, u32 rw_lock_id, u64 timeout) } // add waiter; protocol is ignored in current implementation - sleep_queue_entry_t waiter(ppu, rwlock->rsq); + sleep_entry waiter(rwlock->rsq, ppu); - while (!ppu.unsignal()) + while (!ppu.state.test_and_reset(cpu_state::signal)) { CHECK_EMU_STATUS; @@ -228,15 +222,15 @@ s32 sys_rwlock_wlock(PPUThread& ppu, u32 rw_lock_id, u64 timeout) if (!rwlock->readers && !rwlock->writer) { - rwlock->writer = std::static_pointer_cast(ppu.shared_from_this()); + rwlock->writer = std::static_pointer_cast(ppu.shared_from_this()); return CELL_OK; } // add waiter; protocol is ignored in current implementation - sleep_queue_entry_t waiter(ppu, rwlock->wsq); + sleep_entry waiter(rwlock->wsq, ppu); - while (!ppu.unsignal()) + while (!ppu.state.test_and_reset(cpu_state::signal)) { CHECK_EMU_STATUS; @@ -249,7 +243,7 @@ s32 sys_rwlock_wlock(PPUThread& ppu, u32 rw_lock_id, u64 timeout) // if the last waiter quit the writer sleep queue, readers must acquire the lock if (!rwlock->writer && rwlock->wsq.size() == 1) { - if (rwlock->wsq.front().get() != &ppu) + if (rwlock->wsq.front() != &ppu) { throw EXCEPTION("Unexpected"); } @@ -300,7 +294,7 @@ s32 sys_rwlock_trywlock(PPUThread& ppu, u32 rw_lock_id) return CELL_EBUSY; } - rwlock->writer = std::static_pointer_cast(ppu.shared_from_this()); + rwlock->writer = std::static_pointer_cast(ppu.shared_from_this()); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_rwlock.h b/rpcs3/Emu/Cell/lv2/sys_rwlock.h similarity index 70% rename from rpcs3/Emu/SysCalls/lv2/sys_rwlock.h rename to rpcs3/Emu/Cell/lv2/sys_rwlock.h index ea9f19f138..596f1ad010 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_rwlock.h +++ b/rpcs3/Emu/Cell/lv2/sys_rwlock.h @@ -1,8 +1,6 @@ #pragma once -#include "Utilities/SleepQueue.h" - -namespace vm { using namespace ps3; } +#include "sys_sync.h" struct sys_rwlock_attribute_t { @@ -24,11 +22,11 @@ struct lv2_rwlock_t const u64 name; const u32 protocol; - std::atomic readers{ 0 }; // reader lock count - std::shared_ptr writer; // writer lock owner + atomic_t readers{ 0 }; // reader lock count + std::shared_ptr writer; // writer lock owner - sleep_queue_t rsq; // threads trying to acquire readed lock - sleep_queue_t wsq; // threads trying to acquire writer lock + sleep_queue rsq; // threads trying to acquire readed lock + sleep_queue wsq; // threads trying to acquire writer lock lv2_rwlock_t(u32 protocol, u64 name) : protocol(protocol) @@ -36,7 +34,7 @@ struct lv2_rwlock_t { } - void notify_all(lv2_lock_t& lv2_lock); + void notify_all(lv2_lock_t); }; // Aux diff --git a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp b/rpcs3/Emu/Cell/lv2/sys_semaphore.cpp similarity index 92% rename from rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp rename to rpcs3/Emu/Cell/lv2/sys_semaphore.cpp index 089c38f814..04c4a59c9c 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_semaphore.cpp @@ -1,14 +1,14 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" -#include "sys_sync.h" #include "sys_semaphore.h" -SysCallBase sys_semaphore("sys_semaphore"); +LOG_CHANNEL(sys_semaphore); extern u64 get_system_time(); @@ -92,9 +92,9 @@ s32 sys_semaphore_wait(PPUThread& ppu, u32 sem_id, u64 timeout) } // add waiter; protocol is ignored in current implementation - sleep_queue_entry_t waiter(ppu, sem->sq); + sleep_entry waiter(sem->sq, ppu); - while (!ppu.unsignal()) + while (!ppu.state.test_and_reset(cpu_state::signal)) { CHECK_EMU_STATUS; @@ -173,10 +173,9 @@ s32 sys_semaphore_post(u32 sem_id, s32 count) { count--; - if (!sem->sq.front()->signal()) - { - throw EXCEPTION("Thread already signaled"); - } + auto& thread = sem->sq.front(); + ASSERT(!thread->state.test_and_set(cpu_state::signal)); + thread->cv.notify_one(); sem->sq.pop_front(); } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.h b/rpcs3/Emu/Cell/lv2/sys_semaphore.h similarity index 87% rename from rpcs3/Emu/SysCalls/lv2/sys_semaphore.h rename to rpcs3/Emu/Cell/lv2/sys_semaphore.h index f179b072cd..9885b1a2eb 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.h +++ b/rpcs3/Emu/Cell/lv2/sys_semaphore.h @@ -1,8 +1,6 @@ #pragma once -#include "Utilities/SleepQueue.h" - -namespace vm { using namespace ps3; } +#include "sys_sync.h" struct sys_semaphore_attribute_t { @@ -25,9 +23,9 @@ struct lv2_sema_t const s32 max; const u64 name; - std::atomic value; + atomic_t value; - sleep_queue_t sq; + sleep_queue sq; lv2_sema_t(u32 protocol, s32 max, u64 name, s32 value) : protocol(protocol) diff --git a/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp b/rpcs3/Emu/Cell/lv2/sys_spu.cpp similarity index 91% rename from rpcs3/Emu/SysCalls/lv2/sys_spu.cpp rename to rpcs3/Emu/Cell/lv2/sys_spu.cpp index 470c644dc1..fde8c1320b 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_spu.cpp @@ -1,30 +1,40 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" - -#include "Emu/CPU/CPUThreadManager.h" -#include "Emu/Cell/RawSPUThread.h" -#include "Emu/FS/vfsStreamMemory.h" -#include "Emu/FS/vfsFile.h" -#include "Loader/ELF32.h" #include "Crypto/unself.h" +#include "Loader/ELF.h" + +#include "Emu/Cell/ErrorCodes.h" +#include "Emu/Cell/RawSPUThread.h" #include "sys_interrupt.h" #include "sys_event.h" #include "sys_spu.h" -SysCallBase sys_spu("sys_spu"); +LOG_CHANNEL(sys_spu); -void LoadSpuImage(vfsStream& stream, u32& spu_ep, u32 addr) +void LoadSpuImage(const fs::file& stream, u32& spu_ep, u32 addr) { - loader::handlers::elf32 h; - h.init(stream); - h.load_data(addr); - spu_ep = h.m_ehdr.data_be.e_entry; + const spu_exec_loader loader = stream; + + if (loader != elf_error::ok) + { + throw fmt::exception("Failed to load SPU image: %s" HERE, bijective_find(loader, "???")); + } + + for (const auto& prog : loader.progs) + { + if (prog.p_type == 0x1 /* LOAD */) + { + std::memcpy(vm::base(addr + prog.p_vaddr), prog.bin.data(), prog.p_filesz); + } + } + + spu_ep = loader.header.e_entry; } -u32 LoadSpuImage(vfsStream& stream, u32& spu_ep) +u32 LoadSpuImage(const fs::file& stream, u32& spu_ep) { const u32 alloc_size = 256 * 1024; u32 spu_offset = (u32)vm::alloc(alloc_size, vm::main); @@ -33,20 +43,6 @@ u32 LoadSpuImage(vfsStream& stream, u32& spu_ep) return spu_offset; } -s32 spu_image_import(sys_spu_image& img, u32 src, u32 type) -{ - vfsStreamMemory f(src); - u32 entry; - u32 offset = LoadSpuImage(f, entry); - - img.type = SYS_SPU_IMAGE_TYPE_USER; - img.entry_point = entry; - img.addr = offset; // TODO: writing actual segment info - img.nsegs = 1; // wrong value - - return CELL_OK; -} - s32 sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu) { sys_spu.warning("sys_spu_initialize(max_usable_spu=%d, max_raw_spu=%d)", max_usable_spu, max_raw_spu); @@ -59,14 +55,14 @@ s32 sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu) return CELL_OK; } -s32 sys_spu_image_open(vm::ptr img, vm::cptr path) +s32 sys_spu_image_open(vm::ptr img, vm::cptr path) { sys_spu.warning("sys_spu_image_open(img=*0x%x, path=*0x%x)", img, path); - vfsFile f(path.get_ptr()); - if(!f.IsOpened()) + const fs::file f(vfs::get(path.get_ptr())); + if (!f) { - sys_spu.error("sys_spu_image_open error: '%s' not found!", path.get_ptr()); + sys_spu.error("sys_spu_image_open() error: '%s' not found!", path.get_ptr()); return CELL_ENOENT; } @@ -75,25 +71,23 @@ s32 sys_spu_image_open(vm::ptr img, vm::cptr path) if (hdr.CheckMagic()) { - sys_spu.error("sys_spu_image_open error: '%s' is encrypted! Decrypt SELF and try again.", path.get_ptr()); - Emu.Pause(); - return CELL_ENOENT; + throw fmt::exception("sys_spu_image_open() error: '%s' is encrypted! Try to decrypt it manually and try again.", path.get_ptr()); } - f.Seek(0); + f.seek(0); u32 entry; u32 offset = LoadSpuImage(f, entry); img->type = SYS_SPU_IMAGE_TYPE_USER; img->entry_point = entry; - img->addr = offset; // TODO: writing actual segment info + img->segs.set(offset); // TODO: writing actual segment info img->nsegs = 1; // wrong value return CELL_OK; } -u32 spu_thread_initialize(u32 group_id, u32 spu_num, vm::ptr img, const std::string& name, u32 option, u64 a1, u64 a2, u64 a3, u64 a4, std::function task = nullptr) +u32 spu_thread_initialize(u32 group_id, u32 spu_num, vm::ptr img, const std::string& name, u32 option, u64 a1, u64 a2, u64 a3, u64 a4, std::function task = nullptr) { if (option) { @@ -131,10 +125,10 @@ u32 spu_thread_initialize(u32 group_id, u32 spu_num, vm::ptr img, group->state = SPU_THREAD_GROUP_STATUS_INITIALIZED; } - return spu->get_id(); + return spu->id; } -s32 sys_spu_thread_initialize(vm::ptr thread, u32 group_id, u32 spu_num, vm::ptr img, vm::ptr attr, vm::ptr arg) +s32 sys_spu_thread_initialize(vm::ptr thread, u32 group_id, u32 spu_num, vm::ptr img, vm::ptr attr, vm::ptr arg) { sys_spu.warning("sys_spu_thread_initialize(thread=*0x%x, group=0x%x, spu_num=%d, img=*0x%x, attr=*0x%x, arg=*0x%x)", thread, group_id, spu_num, img, attr, arg); @@ -263,7 +257,7 @@ s32 sys_spu_thread_group_destroy(u32 id) { if (t) { - idm::remove(t->get_id()); + idm::remove(t->id); t.reset(); } @@ -312,10 +306,10 @@ s32 sys_spu_thread_group_start(u32 id) // Copy SPU image: // TODO: use segment info - std::memcpy(vm::base(t->offset), vm::base(image->addr), 256 * 1024); + std::memcpy(vm::base(t->offset), image->segs.get_ptr(), 256 * 1024); t->pc = image->entry_point; - t->run(); + t->cpu_init(); t->gpr[3] = v128::from64(0, args.arg1); t->gpr[4] = v128::from64(0, args.arg2); t->gpr[5] = v128::from64(0, args.arg3); @@ -329,9 +323,13 @@ s32 sys_spu_thread_group_start(u32 id) group->send_run_event(lv2_lock, id, 0, 0); // TODO: check data2 and data3 - for (auto& t : group->threads) + for (auto& thread : group->threads) { - if (t) t->exec(); + if (thread) + { + thread->state -= cpu_state::stop; + thread->safe_notify(); + } } return CELL_OK; @@ -379,9 +377,12 @@ s32 sys_spu_thread_group_suspend(u32 id) return CELL_ESTAT; } - for (auto& t : group->threads) + for (auto& thread : group->threads) { - if (t) t->sleep(); // trigger status check + if (thread) + { + thread->state += cpu_state::suspend; + } } return CELL_OK; @@ -420,9 +421,13 @@ s32 sys_spu_thread_group_resume(u32 id) return CELL_ESTAT; } - for (auto& t : group->threads) + for (auto& thread : group->threads) { - if (t) t->awake(); // untrigger status check + if (thread) + { + thread->state -= cpu_state::suspend; + thread->safe_notify(); + } } group->cv.notify_all(); @@ -499,9 +504,13 @@ s32 sys_spu_thread_group_terminate(u32 id, s32 value) return CELL_ESTAT; } - for (auto& t : group->threads) + for (auto& thread : group->threads) { - if (t) t->stop(); + if (thread) + { + thread->state += cpu_state::stop; + thread->safe_notify(); + } } group->state = SPU_THREAD_GROUP_STATUS_INITIALIZED; @@ -1143,14 +1152,14 @@ s32 sys_raw_spu_create(vm::ptr id, vm::ptr attr) // TODO: check number set by sys_spu_initialize() - const auto thread = Emu.GetCPU().NewRawSPUThread(); + const auto thread = idm::make_ptr(""); if (!thread) { return CELL_EAGAIN; } - thread->run(); + thread->cpu_init(); *id = thread->index; @@ -1163,7 +1172,7 @@ s32 sys_raw_spu_destroy(PPUThread& ppu, u32 id) LV2_LOCK; - const auto thread = Emu.GetCPU().GetRawSPUThread(id); + const auto thread = idm::get(id); if (!thread) { @@ -1173,7 +1182,7 @@ s32 sys_raw_spu_destroy(PPUThread& ppu, u32 id) // TODO: CELL_EBUSY is not returned // Stop thread - thread->stop(); + thread->state += cpu_state::stop; // Clear interrupt handlers for (auto& intr : thread->int_ctrl) @@ -1189,7 +1198,7 @@ s32 sys_raw_spu_destroy(PPUThread& ppu, u32 id) } } - idm::remove(thread->get_id()); + idm::remove(thread->id); return CELL_OK; } @@ -1200,7 +1209,7 @@ s32 sys_raw_spu_create_interrupt_tag(u32 id, u32 class_id, u32 hwthread, vm::ptr LV2_LOCK; - const auto thread = Emu.GetCPU().GetRawSPUThread(id); + const auto thread = idm::get(id); if (!thread) { @@ -1235,7 +1244,7 @@ s32 sys_raw_spu_set_int_mask(u32 id, u32 class_id, u64 mask) return CELL_EINVAL; } - const auto thread = Emu.GetCPU().GetRawSPUThread(id); + const auto thread = idm::get(id); if (!thread) { @@ -1256,7 +1265,7 @@ s32 sys_raw_spu_get_int_mask(u32 id, u32 class_id, vm::ptr mask) return CELL_EINVAL; } - const auto thread = Emu.GetCPU().GetRawSPUThread(id); + const auto thread = idm::get(id); if (!thread) { @@ -1277,7 +1286,7 @@ s32 sys_raw_spu_set_int_stat(u32 id, u32 class_id, u64 stat) return CELL_EINVAL; } - const auto thread = Emu.GetCPU().GetRawSPUThread(id); + const auto thread = idm::get(id); if (!thread) { @@ -1298,7 +1307,7 @@ s32 sys_raw_spu_get_int_stat(u32 id, u32 class_id, vm::ptr stat) return CELL_EINVAL; } - const auto thread = Emu.GetCPU().GetRawSPUThread(id); + const auto thread = idm::get(id); if (!thread) { @@ -1314,7 +1323,7 @@ s32 sys_raw_spu_read_puint_mb(u32 id, vm::ptr value) { sys_spu.trace("sys_raw_spu_read_puint_mb(id=%d, value=*0x%x)", id, value); - const auto thread = Emu.GetCPU().GetRawSPUThread(id); + const auto thread = idm::get(id); if (!thread) { @@ -1343,7 +1352,7 @@ s32 sys_raw_spu_set_spu_cfg(u32 id, u32 value) throw EXCEPTION("Unexpected value (0x%x)", value); } - const auto thread = Emu.GetCPU().GetRawSPUThread(id); + const auto thread = idm::get(id); if (!thread) { @@ -1359,7 +1368,7 @@ s32 sys_raw_spu_get_spu_cfg(u32 id, vm::ptr value) { sys_spu.trace("sys_raw_spu_get_spu_afg(id=%d, value=*0x%x)", id, value); - const auto thread = Emu.GetCPU().GetRawSPUThread(id); + const auto thread = idm::get(id); if (!thread) { diff --git a/rpcs3/Emu/SysCalls/lv2/sys_spu.h b/rpcs3/Emu/Cell/lv2/sys_spu.h similarity index 86% rename from rpcs3/Emu/SysCalls/lv2/sys_spu.h rename to rpcs3/Emu/Cell/lv2/sys_spu.h index 1b720448de..cc6475447b 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_spu.h +++ b/rpcs3/Emu/Cell/lv2/sys_spu.h @@ -1,7 +1,5 @@ #pragma once -namespace vm { using namespace ps3; } - #include "sys_event.h" enum : s32 @@ -107,15 +105,11 @@ enum : u32 SYS_SPU_IMAGE_TYPE_KERNEL = 1, }; -struct sys_spu_image +struct sys_spu_image_t { be_t type; // user, kernel be_t entry_point; - union - { - be_t addr; // temporarily used as offset of the whole LS image (should be removed) - vm::bptr segs; - }; + vm::bptr segs; be_t nsegs; }; @@ -151,14 +145,14 @@ struct lv2_spu_group_t const u32 ct; // Memory Container Id std::array, 256> threads; // SPU Threads - std::array, 256> images; // SPU Images + std::array, 256> images; // SPU Images std::array args; // SPU Thread Arguments s32 prio; // SPU Thread Group Priority volatile u32 state; // SPU Thread Group State s32 exit_status; // SPU Thread Group Exit Status - std::atomic join_state; // flags used to detect exit cause + atomic_t join_state; // flags used to detect exit cause std::condition_variable cv; // used to signal waiting PPU thread std::weak_ptr ep_run; // port for SYS_SPU_THREAD_GROUP_EVENT_RUN events @@ -177,30 +171,24 @@ struct lv2_spu_group_t { } - void send_run_event(lv2_lock_t& lv2_lock, u64 data1, u64 data2, u64 data3) + void send_run_event(lv2_lock_t lv2_lock, u64 data1, u64 data2, u64 data3) { - CHECK_LV2_LOCK(lv2_lock); - if (const auto queue = ep_run.lock()) { queue->push(lv2_lock, SYS_SPU_THREAD_GROUP_EVENT_RUN_KEY, data1, data2, data3); } } - void send_exception_event(lv2_lock_t& lv2_lock, u64 data1, u64 data2, u64 data3) + void send_exception_event(lv2_lock_t lv2_lock, u64 data1, u64 data2, u64 data3) { - CHECK_LV2_LOCK(lv2_lock); - if (const auto queue = ep_exception.lock()) { queue->push(lv2_lock, SYS_SPU_THREAD_GROUP_EVENT_EXCEPTION_KEY, data1, data2, data3); } } - void send_sysmodule_event(lv2_lock_t& lv2_lock, u64 data1, u64 data2, u64 data3) + void send_sysmodule_event(lv2_lock_t lv2_lock, u64 data1, u64 data2, u64 data3) { - CHECK_LV2_LOCK(lv2_lock); - if (const auto queue = ep_sysmodule.lock()) { queue->push(lv2_lock, SYS_SPU_THREAD_GROUP_EVENT_SYSTEM_MODULE_KEY, data1, data2, data3); @@ -208,20 +196,17 @@ struct lv2_spu_group_t } }; -struct vfsStream; class PPUThread; -void LoadSpuImage(vfsStream& stream, u32& spu_ep, u32 addr); -u32 LoadSpuImage(vfsStream& stream, u32& spu_ep); - // Aux -s32 spu_image_import(sys_spu_image& img, u32 src, u32 type); +void LoadSpuImage(const fs::file& stream, u32& spu_ep, u32 addr); +u32 LoadSpuImage(const fs::file& stream, u32& spu_ep); // SysCalls s32 sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu); -s32 sys_spu_image_open(vm::ptr img, vm::cptr path); -s32 sys_spu_image_close(vm::ptr img); -s32 sys_spu_thread_initialize(vm::ptr thread, u32 group, u32 spu_num, vm::ptr img, vm::ptr attr, vm::ptr arg); +s32 sys_spu_image_open(vm::ptr img, vm::cptr path); +s32 sys_spu_image_close(vm::ptr img); +s32 sys_spu_thread_initialize(vm::ptr thread, u32 group, u32 spu_num, vm::ptr img, vm::ptr attr, vm::ptr arg); s32 sys_spu_thread_set_argument(u32 id, vm::ptr arg); s32 sys_spu_thread_group_create(vm::ptr id, u32 num, s32 prio, vm::ptr attr); s32 sys_spu_thread_group_destroy(u32 id); diff --git a/rpcs3/Emu/Cell/lv2/sys_sync.h b/rpcs3/Emu/Cell/lv2/sys_sync.h new file mode 100644 index 0000000000..37b147e472 --- /dev/null +++ b/rpcs3/Emu/Cell/lv2/sys_sync.h @@ -0,0 +1,113 @@ +#pragma once + +#include "Utilities/SharedMutex.h" +#include "Utilities/SleepQueue.h" + +namespace vm { using namespace ps3; } + +// attr_protocol (waiting scheduling policy) +enum +{ + // First In, First Out + SYS_SYNC_FIFO = 1, + // Priority Order + SYS_SYNC_PRIORITY = 2, + // Basic Priority Inheritance Protocol (probably not implemented) + SYS_SYNC_PRIORITY_INHERIT = 3, + // Not selected while unlocking + SYS_SYNC_RETRY = 4, + // + SYS_SYNC_ATTR_PROTOCOL_MASK = 0xF, +}; + +// attr_recursive (recursive locks policy) +enum +{ + // Recursive locks are allowed + SYS_SYNC_RECURSIVE = 0x10, + // Recursive locks are NOT allowed + SYS_SYNC_NOT_RECURSIVE = 0x20, + // + SYS_SYNC_ATTR_RECURSIVE_MASK = 0xF0, //??? +}; + +// attr_pshared +enum +{ + SYS_SYNC_NOT_PROCESS_SHARED = 0x200, +}; + +// attr_adaptive +enum +{ + SYS_SYNC_ADAPTIVE = 0x1000, + SYS_SYNC_NOT_ADAPTIVE = 0x2000, +}; + +// IPC manager collection for lv2 objects of type T +template +class ipc_manager final +{ + mutable shared_mutex m_mutex; + std::unordered_map> m_map; + +public: + // Add new object if specified ipc_key is not used + template + auto add(u64 ipc_key, F&& provider) -> decltype(static_cast>(provider())) + { + std::lock_guard lock(m_mutex); + + // Get object location + std::weak_ptr& wptr = m_map[ipc_key]; + + if (wptr.expired()) + { + // Call a function which must return the object + std::shared_ptr&& result = provider(); + wptr = result; + return result; + } + + return{}; + } + + // Get existing object with specified ipc_key + std::shared_ptr get(u64 ipc_key) const + { + reader_lock lock(m_mutex); + + const auto found = m_map.find(ipc_key); + + if (found != m_map.end()) + { + return found->second.lock(); + } + + return{}; + } +}; + +// Simple class for global mutex to pass unique_lock and check it +struct lv2_lock_t +{ + using type = std::unique_lock; + + type& ref; + + lv2_lock_t(type& lv2_lock) + : ref(lv2_lock) + { + Expects(ref.owns_lock()); + Expects(ref.mutex() == &mutex); + } + + operator type&() const + { + return ref; + } + + static type::mutex_type mutex; +}; + +#define LV2_LOCK lv2_lock_t::type lv2_lock(lv2_lock_t::mutex) diff --git a/rpcs3/Emu/SysCalls/lv2/sys_time.cpp b/rpcs3/Emu/Cell/lv2/sys_time.cpp similarity index 97% rename from rpcs3/Emu/SysCalls/lv2/sys_time.cpp rename to rpcs3/Emu/Cell/lv2/sys_time.cpp index bdaed94974..39f4b1a156 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_time.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_time.cpp @@ -1,8 +1,9 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "sys_time.h" #ifdef _WIN32 @@ -44,7 +45,7 @@ const g_time_aux_info = []() -> time_aux_info_t // initialize time-related value #endif -SysCallBase sys_time("sys_time"); +LOG_CHANNEL(sys_time); static const u64 g_timebase_freq = /*79800000*/ 80000000; // 80 Mhz diff --git a/rpcs3/Emu/SysCalls/lv2/sys_time.h b/rpcs3/Emu/Cell/lv2/sys_time.h similarity index 100% rename from rpcs3/Emu/SysCalls/lv2/sys_time.h rename to rpcs3/Emu/Cell/lv2/sys_time.h diff --git a/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp b/rpcs3/Emu/Cell/lv2/sys_timer.cpp similarity index 94% rename from rpcs3/Emu/SysCalls/lv2/sys_timer.cpp rename to rpcs3/Emu/Cell/lv2/sys_timer.cpp index 6fa2ba5001..3f8c8f78fc 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_timer.cpp @@ -1,15 +1,15 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" -#include "Utilities/Thread.h" +#include "Emu/Cell/ErrorCodes.h" #include "sys_event.h" #include "sys_process.h" #include "sys_timer.h" -SysCallBase sys_timer("sys_timer"); +LOG_CHANNEL(sys_timer); extern u64 get_system_time(); @@ -59,11 +59,6 @@ void lv2_timer_t::on_task() } } -lv2_timer_t::lv2_timer_t() - : id(idm::get_last_id()) -{ -} - s32 sys_timer_create(vm::ptr timer_id) { sys_timer.warning("sys_timer_create(timer_id=*0x%x)", timer_id); @@ -199,8 +194,8 @@ s32 sys_timer_connect_event_queue(u32 timer_id, u32 queue_id, u64 name, u64 data LV2_LOCK; - const auto timer(idm::get(timer_id)); - const auto queue(idm::get(queue_id)); + const auto timer = idm::get(timer_id); + const auto queue = idm::get(queue_id); if (!timer || !queue) { @@ -269,7 +264,7 @@ s32 sys_timer_sleep(u32 sleep_time) return CELL_OK; } -s32 sys_timer_usleep(u64 sleep_time) +s32 sys_timer_usleep(const u64 sleep_time) { sys_timer.trace("sys_timer_usleep(sleep_time=0x%llx)", sleep_time); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_timer.h b/rpcs3/Emu/Cell/lv2/sys_timer.h similarity index 63% rename from rpcs3/Emu/SysCalls/lv2/sys_timer.h rename to rpcs3/Emu/Cell/lv2/sys_timer.h index 5d1e32c68c..a0bcbba701 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_timer.h +++ b/rpcs3/Emu/Cell/lv2/sys_timer.h @@ -19,35 +19,36 @@ struct sys_timer_information_t be_t pad; }; -class lv2_timer_t final : public named_thread_t +class lv2_timer_t final : public named_thread { void on_task() override; - void on_id_aux_finalize() override +public: + std::string get_name() const override + { + return fmt::format("Timer Thread[0x%x]", id); + } + + void on_stop() override { // Signal thread using invalid state and join - { std::lock_guard{mutex}, state = -1; } + std::lock_guard{ mutex }, state = -1; cv.notify_one(); join(); } -public: - lv2_timer_t(); + const u32 id{}; // Timer id - std::string get_name() const override { return fmt::format("Timer Thread[0x%x]", id); } + atomic_t state{ SYS_TIMER_STATE_RUN }; // Timer state - const u32 id; - - std::weak_ptr port; // event queue - u64 source; // event source - u64 data1; // event arg 1 - u64 data2; // event arg 2 + std::weak_ptr port; // Event queue + u64 source; // Event source + u64 data1; // Event arg 1 + u64 data2; // Event arg 2 - u64 expire = 0; // next expiration time - u64 period = 0; // period (oneshot if 0) - - std::atomic state{ SYS_TIMER_STATE_RUN }; // timer state + u64 expire = 0; // Next expiration time + u64 period = 0; // Period (oneshot if 0) }; s32 sys_timer_create(vm::ptr timer_id); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_trace.cpp b/rpcs3/Emu/Cell/lv2/sys_trace.cpp similarity index 91% rename from rpcs3/Emu/SysCalls/lv2/sys_trace.cpp rename to rpcs3/Emu/Cell/lv2/sys_trace.cpp index f7b3d29c7e..78a10eb063 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_trace.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_trace.cpp @@ -1,11 +1,12 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "sys_trace.h" -SysCallBase sys_trace("sys_trace"); +LOG_CHANNEL(sys_trace); s32 sys_trace_create() { diff --git a/rpcs3/Emu/SysCalls/lv2/sys_trace.h b/rpcs3/Emu/Cell/lv2/sys_trace.h similarity index 100% rename from rpcs3/Emu/SysCalls/lv2/sys_trace.h rename to rpcs3/Emu/Cell/lv2/sys_trace.h diff --git a/rpcs3/Emu/SysCalls/lv2/sys_tty.cpp b/rpcs3/Emu/Cell/lv2/sys_tty.cpp similarity index 89% rename from rpcs3/Emu/SysCalls/lv2/sys_tty.cpp rename to rpcs3/Emu/Cell/lv2/sys_tty.cpp index 8dadf61685..bdbe5fa49f 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_tty.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_tty.cpp @@ -1,11 +1,12 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "sys_tty.h" -SysCallBase sys_tty("sys_tty"); +LOG_CHANNEL(sys_tty); s32 sys_tty_read(s32 ch, vm::ptr buf, u32 len, vm::ptr preadlen) { diff --git a/rpcs3/Emu/SysCalls/lv2/sys_tty.h b/rpcs3/Emu/Cell/lv2/sys_tty.h similarity index 100% rename from rpcs3/Emu/SysCalls/lv2/sys_tty.h rename to rpcs3/Emu/Cell/lv2/sys_tty.h diff --git a/rpcs3/Emu/SysCalls/lv2/sys_vm.cpp b/rpcs3/Emu/Cell/lv2/sys_vm.cpp similarity index 96% rename from rpcs3/Emu/SysCalls/lv2/sys_vm.cpp rename to rpcs3/Emu/Cell/lv2/sys_vm.cpp index 3e9361bedb..22492efb6e 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_vm.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_vm.cpp @@ -1,13 +1,14 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "sys_memory.h" #include "sys_vm.h" -SysCallBase sys_vm("sys_vm"); +LOG_CHANNEL(sys_vm); s32 sys_vm_memory_map(u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr addr) { diff --git a/rpcs3/Emu/SysCalls/lv2/sys_vm.h b/rpcs3/Emu/Cell/lv2/sys_vm.h similarity index 97% rename from rpcs3/Emu/SysCalls/lv2/sys_vm.h rename to rpcs3/Emu/Cell/lv2/sys_vm.h index cce3134611..5c03b588d1 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_vm.h +++ b/rpcs3/Emu/Cell/lv2/sys_vm.h @@ -1,6 +1,6 @@ #pragma once -namespace vm { using namespace ps3; } +#include "sys_sync.h" enum : u64 { diff --git a/rpcs3/Emu/Event.cpp b/rpcs3/Emu/Event.cpp deleted file mode 100644 index 8c9ceae8cc..0000000000 --- a/rpcs3/Emu/Event.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/System.h" - -#include "Emu/SysCalls/lv2/sys_event.h" -#include "Event.h" - -void EventManager::Init() -{ -} - -void EventManager::Clear() -{ - m_map.clear(); -} - -bool EventManager::UnregisterKey(u64 key) -{ - if (!key) - { - // always ok - return true; - } - - std::lock_guard lock(m_mutex); - - auto f = m_map.find(key); - if (f != m_map.end()) - { - m_map.erase(f); - return true; - } - - return false; -} - -std::shared_ptr EventManager::GetEventQueue(u64 key) -{ - if (!key) - { - // never exists - return nullptr; - } - - std::lock_guard lock(m_mutex); - - auto f = m_map.find(key); - if (f != m_map.end()) - { - return f->second; - } - - return nullptr; -} diff --git a/rpcs3/Emu/Event.h b/rpcs3/Emu/Event.h deleted file mode 100644 index 754b526bad..0000000000 --- a/rpcs3/Emu/Event.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include "Emu/IdManager.h" - -struct lv2_event_queue_t; - -class EventManager -{ - std::mutex m_mutex; - std::unordered_map> m_map; - -public: - void Init(); - void Clear(); - bool UnregisterKey(u64 key); - - template::value>> std::shared_ptr MakeEventQueue(u64 key, Args&&... args) - { - std::lock_guard lock(m_mutex); - - if (key && m_map.find(key) != m_map.end()) - { - return nullptr; - } - - auto queue = idm::make_ptr(std::forward(args)...); - - if (key) - { - m_map[key] = queue; - } - - return queue; - } - - std::shared_ptr GetEventQueue(u64 key); -}; diff --git a/rpcs3/Emu/FS/VFS.cpp b/rpcs3/Emu/FS/VFS.cpp deleted file mode 100644 index fdcfa4a37d..0000000000 --- a/rpcs3/Emu/FS/VFS.cpp +++ /dev/null @@ -1,568 +0,0 @@ -#include "stdafx.h" -#include "VFS.h" -#include "vfsDir.h" -#include "vfsFile.h" -#include "vfsDirBase.h" -#include "Emu/HDD/HDD.h" -#include "vfsDeviceLocalFile.h" -#include "Emu/System.h" -#include "Emu/state.h" - -std::vector simplify_path_blocks(const std::string& path) -{ - // fmt::tolower() removed - std::vector path_blocks = std::move(fmt::split(path, { "/", "\\" })); - - for (s32 i = 0; i < path_blocks.size(); ++i) - { - if (path_blocks[i] == "." || (i > 0 && path_blocks[i].empty())) - { - path_blocks.erase(path_blocks.begin() + i); - i--; - } - else if (i > 0 && path_blocks[i] == "..") - { - path_blocks.erase(path_blocks.begin() + (i - 1), path_blocks.begin() + (i + 1)); - i--; - } - } - - return path_blocks; -} - -std::string simplify_path(const std::string& path, bool is_dir, bool is_ps3) -{ - std::vector path_blocks = simplify_path_blocks(path); - - if (path_blocks.empty()) - return ""; - - std::string result = fmt::merge(path_blocks, "/"); - -#ifdef _WIN32 - if (is_ps3) -#endif - { - result = "/" + result; - } - - if (is_dir) result = result + "/"; - - return result; -} - -VFS::~VFS() -{ - UnMountAll(); -} - -void VFS::Mount(const std::string& ps3_path, const std::string& local_path, vfsDevice* device) -{ - std::string simpl_ps3_path = simplify_path(ps3_path, true, true); - - UnMount(simpl_ps3_path); - - device->SetPath(simpl_ps3_path, simplify_path(local_path, true, false)); - m_devices.push_back(device); - - if (m_devices.size() > 1) - { - std::sort(m_devices.begin(), m_devices.end(), [](vfsDevice *a, vfsDevice *b) { return b->GetPs3Path().length() < a->GetPs3Path().length(); }); - } -} - -void VFS::Link(const std::string& mount_point, const std::string& ps3_path) -{ - links[simplify_path_blocks(mount_point)] = simplify_path_blocks(ps3_path); -} - -std::string VFS::GetLinked(const std::string& ps3_path) const -{ - // fmt::tolower removed - auto path_blocks = fmt::split(ps3_path, { "/", "\\" }); - - for (auto link : links) - { - if (path_blocks.size() < link.first.size()) - continue; - - bool is_ok = true; - - for (size_t i = 0; i < link.first.size(); ++i) - { - if (link.first[i] != path_blocks[i]) - { - is_ok = false; - break; - } - } - - if (is_ok) - return fmt::merge({ link.second, std::vector(path_blocks.begin() + link.first.size(), path_blocks.end()) }, "/"); - } - - return ps3_path; -} - -void VFS::UnMount(const std::string& ps3_path) -{ - std::string simpl_ps3_path = simplify_path(ps3_path, true, true); - - for (u32 i = 0; i < m_devices.size(); ++i) - { - if (!strcmp(m_devices[i]->GetPs3Path().c_str(), simpl_ps3_path.c_str())) - { - delete m_devices[i]; - - m_devices.erase(m_devices.begin() +i); - - return; - } - } -} - -void VFS::UnMountAll() -{ - for(u32 i=0; iGetNewFileStream()) - { - res->Open(path, mode); - return res; - } - } - - return nullptr; -} - -vfsDirBase* VFS::OpenDir(const std::string& ps3_path) const -{ - std::string path; - - if (vfsDevice* dev = GetDevice(ps3_path, path)) - { - if (vfsDirBase* res = dev->GetNewDirStream()) - { - res->Open(path); - return res; - } - } - - return nullptr; -} - -bool VFS::CreateDir(const std::string& ps3_path) const -{ - std::string path; - - if (vfsDevice* dev = GetDevice(ps3_path, path)) - { - // return dev->create_dir(path); - return fs::create_dir(path); - } - - return false; -} - -bool VFS::CreatePath(const std::string& ps3_path) const -{ - std::string path; - - if (vfsDevice* dev = GetDevice(ps3_path, path)) - { - // return dev->create_path(path); - return fs::create_path(path); - } - - return false; -} - -bool VFS::RemoveFile(const std::string& ps3_path) const -{ - std::string path; - - if (vfsDevice* dev = GetDevice(ps3_path, path)) - { - // return dev->remove_file(path); - return fs::remove_file(path); - } - - return false; -} - -bool VFS::RemoveDir(const std::string& ps3_path) const -{ - std::string path; - - if (vfsDevice* dev = GetDevice(ps3_path, path)) - { - // return dev->remove_dir(path); - return fs::remove_dir(path); - } - - return false; -} - -void VFS::DeleteAll(const std::string& ps3_path) const -{ - // Delete directory and all its contents recursively - for (const auto entry : vfsDir(ps3_path)) - { - if (entry->name == "." || entry->name == "..") - { - continue; - } - - if (entry->flags & DirEntry_TypeFile) - { - RemoveFile(ps3_path + "/" + entry->name); - } - - if (entry->flags & DirEntry_TypeDir) - { - DeleteAll(ps3_path + "/" + entry->name); - } - } - - RemoveDir(ps3_path); -} - -u64 VFS::GetDirSize(const std::string& ps3_path) const -{ - u64 result = 0; - - for (const auto entry : vfsDir(ps3_path)) - { - if (entry->name == "." || entry->name == "..") - { - continue; - } - - if (entry->flags & DirEntry_TypeFile) - { - result += entry->size; - } - - if (entry->flags & DirEntry_TypeDir) - { - result += GetDirSize(ps3_path + "/" + entry->name); - } - } - - return result; -} - -bool VFS::ExistsFile(const std::string& ps3_path) const -{ - std::string path; - - if (vfsDevice* dev = GetDevice(ps3_path, path)) - { - // return dev->is_file(path); - return fs::is_file(path); - } - - return false; -} - -bool VFS::ExistsDir(const std::string& ps3_path) const -{ - std::string path; - - if (vfsDevice* dev = GetDevice(ps3_path, path)) - { - // return dev->is_dir(path); - return fs::is_dir(path); - } - - return false; -} - -bool VFS::Exists(const std::string& ps3_path) const -{ - std::string path; - - if (vfsDevice* dev = GetDevice(ps3_path, path)) - { - // return dev->exists(path); - return fs::exists(path); - } - - return false; -} - -bool VFS::Rename(const std::string& ps3_path_from, const std::string& ps3_path_to) const -{ - std::string path_from, path_to; - - if (vfsDevice* dev = GetDevice(ps3_path_from, path_from)) - { - if (vfsDevice* dev_ = GetDevice(ps3_path_to, path_to)) - { - // return dev->rename(dev_, path_from, path_to); - return fs::rename(path_from, path_to); - } - } - - return false; -} - -bool VFS::CopyFile(const std::string& ps3_path_from, const std::string& ps3_path_to, bool overwrite) const -{ - std::string path_from, path_to; - - if (vfsDevice* dev = GetDevice(ps3_path_from, path_from)) - { - if (vfsDevice* dev_ = GetDevice(ps3_path_to, path_to)) - { - // return dev->copy_file(dev_, path_from, path_to, overwrite); - return fs::copy_file(path_from, path_to, overwrite); - } - } - - return false; -} - -bool VFS::TruncateFile(const std::string& ps3_path, u64 length) const -{ - std::string path; - - if (vfsDevice* dev = GetDevice(ps3_path, path)) - { - // return dev->truncate_file(path, length); - return fs::truncate_file(path, length); - } - - return false; -} - -vfsDevice* VFS::GetDevice(const std::string& ps3_path, std::string& path) const -{ - auto try_get_device = [this, &path](const std::string& ps3_path) -> vfsDevice* - { - std::vector ps3_path_blocks = simplify_path_blocks(ps3_path); - size_t max_eq = 0; - int max_i = -1; - - for (u32 i = 0; i < m_devices.size(); ++i) - { - std::vector dev_ps3_path_blocks = simplify_path_blocks(m_devices[i]->GetPs3Path()); - - if (ps3_path_blocks.size() < dev_ps3_path_blocks.size()) - continue; - - size_t eq = 0; - for (; eq < dev_ps3_path_blocks.size(); ++eq) - { - if (strcmp(ps3_path_blocks[eq].c_str(), dev_ps3_path_blocks[eq].c_str())) - { - break; - } - } - - if (eq > max_eq) - { - max_eq = eq; - max_i = i; - } - } - - if (max_i < 0) - return nullptr; - - path = m_devices[max_i]->GetLocalPath(); - - for (size_t i = max_eq; i < ps3_path_blocks.size(); i++) - { - path += "/" + ps3_path_blocks[i]; - } - - path = simplify_path(path, false, false); - - return m_devices[max_i]; - }; - - if (!ps3_path.size() || ps3_path[0] != '/') - { - return nullptr; - } - - return try_get_device(GetLinked(ps3_path)); - - // What is it? cwd is real path, ps3_path is ps3 path, but GetLinked accepts ps3 path - //if (auto res = try_get_device(GetLinked(cwd + ps3_path))) - // return res; -} - -vfsDevice* VFS::GetDeviceLocal(const std::string& local_path, std::string& path) const -{ - int max_eq = -1; - int max_i = -1; - - std::vector local_path_blocks = simplify_path_blocks(local_path); - - for (u32 i = 0; i < m_devices.size(); ++i) - { - std::vector dev_local_path_blocks = simplify_path_blocks(m_devices[i]->GetLocalPath()); - - if (local_path_blocks.size() < dev_local_path_blocks.size()) - continue; - - int dev_blocks = dev_local_path_blocks.size(); - - bool prefix_equal = std::equal( - std::begin(dev_local_path_blocks), - std::end(dev_local_path_blocks), - std::begin(local_path_blocks), - [](const std::string& a, const std::string& b){ return strcmp(a.c_str(), b.c_str()) == 0; } - ); - - if (prefix_equal && dev_blocks > max_eq) - { - max_eq = dev_blocks; - max_i = i; - } - } - - if (max_i < 0) - return nullptr; - - path = m_devices[max_i]->GetPs3Path(); - - for (size_t i = max_eq; i < local_path_blocks.size(); i++) - { - path += "/" + local_path_blocks[i]; - } - - path = simplify_path(path, false, true); - - return m_devices[max_i]; -} - -void VFS::Init(const std::string& path) -{ - cwd = simplify_path(path, true, false); - - UnMountAll(); - - std::vector entries; - SaveLoadDevices(entries, true); - - for(const VFSManagerEntry& entry : entries) - { - vfsDevice* dev; - - switch(entry.device) - { - case vfsDevice_LocalFile: - dev = new vfsDeviceLocalFile(); - break; - - case vfsDevice_HDD: - dev = new vfsDeviceHDD(entry.device_path); - break; - - default: - continue; - } - - std::string mpath = entry.path; - // If no value assigned to SysEmulationDirPath in INI, use the path that with executable. - if (rpcs3::config.system.emulation_dir_path_enable.value()) - { - fmt::Replace(mpath, "$(EmulatorDir)", rpcs3::config.system.emulation_dir_path.value()); - } - else - { - fmt::Replace(mpath, "$(EmulatorDir)", fs::get_executable_dir()); - } - fmt::Replace(mpath, "$(GameDir)", cwd); - Mount(entry.mount, mpath, dev); - } - - Link("/app_home/", "/host_root/" + cwd); -} - -void VFS::SaveLoadDevices(std::vector& res, bool is_load) -{ - int count = 0; - if (is_load) - { - count = rpcs3::config.vfs.count.value(); - - if (!count) - { - res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_hdd0/", "/dev_hdd0/"); - res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_hdd1/", "/dev_hdd1/"); - res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_flash/", "/dev_flash/"); - res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_usb000/", "/dev_usb000/"); - res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_usb000/", "/dev_usb/"); - res.emplace_back(vfsDevice_LocalFile, "", "/host_root/"); - - return; - } - - res.resize(count); - } - else - { - count = (int)res.size(); - rpcs3::config.vfs.count = count; - } - - // Custom EmulationDir - if (rpcs3::config.system.emulation_dir_path_enable.value()) - { - std::string dir = rpcs3::config.system.emulation_dir_path.value(); - - if (dir.empty()) - { - rpcs3::config.system.emulation_dir_path = fs::get_executable_dir(); - } - - if (!fs::is_dir(dir)) - { - LOG_ERROR(GENERAL, "Custom EmulationDir: directory '%s' not found", dir); - } - else - { - LOG_NOTICE(GENERAL, "Custom EmulationDir: $(EmulatorDir) bound to '%s'", dir); - } - } - - for(int i=0; i(fmt::format("path[%d]", i), std::string{}); - res[i].device_path = rpcs3::config.vfs.get_entry_value(fmt::format("device_path[%d]", i), std::string{}); - res[i].mount = rpcs3::config.vfs.get_entry_value(fmt::format("mount[%d]", i), std::string{}); - res[i].device = (vfsDeviceType)rpcs3::config.vfs.get_entry_value(fmt::format("device[%d]", i), 0); - } - else - { - rpcs3::config.vfs.set_entry_value(fmt::format("path[%d]", i), res[i].path); - rpcs3::config.vfs.set_entry_value(fmt::format("device_path[%d]", i), res[i].device_path); - rpcs3::config.vfs.set_entry_value(fmt::format("mount[%d]", i), res[i].mount); - rpcs3::config.vfs.set_entry_value(fmt::format("device[%d]", i), (int)res[i].device); - } - } -} diff --git a/rpcs3/Emu/FS/VFS.h b/rpcs3/Emu/FS/VFS.h deleted file mode 100644 index 4418ea33f1..0000000000 --- a/rpcs3/Emu/FS/VFS.h +++ /dev/null @@ -1,98 +0,0 @@ -#pragma once -#include - -class vfsDevice; -struct vfsFileBase; -class vfsDirBase; - -enum vfsDeviceType -{ - vfsDevice_LocalFile, - vfsDevice_HDD, -}; - -static const char* vfsDeviceTypeNames[] = -{ - "Local", - "HDD", -}; - -struct VFSManagerEntry -{ - vfsDeviceType device; - std::string device_path; - std::string path; - std::string mount; - - VFSManagerEntry() - : device(vfsDevice_LocalFile) - , device_path("") - , path("") - , mount("") - { - } - - VFSManagerEntry(const vfsDeviceType& device, const std::string& path, const std::string& mount) - : device(device) - , device_path("") - , path(path) - , mount(mount) - - { - } -}; - -std::vector simplify_path_blocks(const std::string& path); -std::string simplify_path(const std::string& path, bool is_dir, bool is_ps3); - -struct VFS -{ - ~VFS(); - - std::string cwd; - - //TODO: find out where these are supposed to be deleted or just make it shared_ptr - //and also make GetDevice and GetDeviceLocal return shared_ptr then. - // A vfsDevice will be deleted when they're unmounted or the VFS struct is destroyed. - // This will cause problems if other code stores the pointer returned by GetDevice/GetDeviceLocal - // and tries to use it after the device is unmounted. - std::vector m_devices; - - struct links_sorter - { - bool operator()(const std::vector& a, const std::vector& b) const - { - return b.size() < a.size(); - } - }; - - std::map, std::vector, links_sorter> links; - - void Mount(const std::string& ps3_path, const std::string& local_path, vfsDevice* device); - void Link(const std::string& mount_point, const std::string& ps3_path); - void UnMount(const std::string& ps3_path); - void UnMountAll(); - - std::string GetLinked(const std::string& ps3_path) const; - - vfsFileBase* OpenFile(const std::string& ps3_path, u32 mode) const; - vfsDirBase* OpenDir(const std::string& ps3_path) const; - bool CreateDir(const std::string& ps3_path) const; - bool CreatePath(const std::string& ps3_path) const; - bool RemoveFile(const std::string& ps3_path) const; - bool RemoveDir(const std::string& ps3_path) const; - void DeleteAll(const std::string& ps3_path) const; - u64 GetDirSize(const std::string& ps3_path) const; - bool ExistsFile(const std::string& ps3_path) const; - bool ExistsDir(const std::string& ps3_path) const; - bool Exists(const std::string& ps3_path) const; - bool Rename(const std::string& ps3_path_from, const std::string& ps3_path_to) const; - bool CopyFile(const std::string& ps3_path_from, const std::string& ps3_path_to, bool overwrite = true) const; - bool TruncateFile(const std::string& ps3_path, u64 length) const; - - vfsDevice* GetDevice(const std::string& ps3_path, std::string& path) const; - vfsDevice* GetDeviceLocal(const std::string& local_path, std::string& path) const; - - void Init(const std::string& path); - void SaveLoadDevices(std::vector& res, bool is_load); -}; diff --git a/rpcs3/Emu/FS/vfsDevice.cpp b/rpcs3/Emu/FS/vfsDevice.cpp deleted file mode 100644 index 652c6f4f55..0000000000 --- a/rpcs3/Emu/FS/vfsDevice.cpp +++ /dev/null @@ -1,249 +0,0 @@ -#include "stdafx.h" -#include "vfsDevice.h" - -vfsDevice::vfsDevice(const std::string& ps3_path, const std::string& local_path) - : m_ps3_path(ps3_path) - , m_local_path(GetWinPath(local_path)) -{ -} - -std::string vfsDevice::GetLocalPath() const -{ - return m_local_path; -} - -std::string vfsDevice::GetPs3Path() const -{ - return m_ps3_path; -} - -void vfsDevice::SetPath(const std::string& ps3_path, const std::string& local_path) -{ - m_ps3_path = ps3_path; - m_local_path = local_path; -} - -u32 vfsDevice::CmpPs3Path(const std::string& ps3_path) -{ - const u32 lim = (u32)std::min(m_ps3_path.length(), ps3_path.length()); - u32 ret = 0; - - for(u32 i=0; i arr0 = fmt::rSplit(m_local_path, DL); - std::vector arr1 = fmt::rSplit(local_path, DL); - - const u32 lim = (u32)std::min(arr0.size(), arr1.size()); - u32 ret = 0; - - for(u32 i=0; i= 0; --i) - { - if(path[i] == '\\' || path[i] == '/' || i == 0) - { - if(dir++ == end_dir_count) - { - to = i; - break; - } - } - } - - return path.substr(from, to - from); -} - -std::string vfsDevice::GetRoot(const std::string& path) -{ - //return fmt::ToUTF8(wxFileName(fmt::FromUTF8(path), wxPATH_UNIX).GetPath()); - if(path.empty()) return ""; - - u32 first_dir = (u32)path.length() - 1; - - for(int i = (int)path.length() - 1, dir = 0, li = (int)path.length() - 1; i >= 0 && dir < 2; --i) - { - if(path[i] == '\\' || path[i] == '/' || i == 0) - { - switch(dir++) - { - case 0: - first_dir = i; - break; - - case 1: - if(!path.substr(i + 1, li - i).compare("USRDIR")) return path.substr(0, i + 1); - continue; - } - - li = i - 1; - } - } - - return path.substr(0, first_dir + 1); -} - -std::string vfsDevice::GetRootPs3(const std::string& path) -{ - if(path.empty()) return ""; - - static const std::string home = "/dev_hdd0/game/"; - u32 last_dir = 0; - u32 first_dir = (u32)path.length() - 1; - - for(int i = (int)path.length() - 1, dir = 0; i >= 0; --i) - { - if(path[i] == '\\' || path[i] == '/' || i == 0) - { - switch(dir++) - { - case 1: - if(path.substr(i + 1, last_dir - i - 1) == "USRDIR") return ""; - break; - - case 2: - return GetPs3Path(home + path.substr(i + 1, last_dir - i - 1)); - } - - last_dir = i; - } - } - - return GetPs3Path(home + path.substr(0, last_dir - 1)); -} - -std::string vfsDevice::GetWinPath(const std::string& p, bool is_dir) -{ - if(p.empty()) return ""; - - std::string ret; - bool is_ls = false; - - for(u32 i=0; iIsOpened() ? m_stream->GetPath() : path), true, true); - - auto blocks = simplify_path_blocks(GetPath()); - - for (auto dev : Emu.GetVFS().m_devices) - { - auto dev_blocks = simplify_path_blocks(dev->GetPs3Path()); - - if (dev_blocks.size() < (blocks.size() + 1)) - { - continue; - } - - bool is_ok = true; - - for (size_t i = 0; i < blocks.size(); ++i) - { - if (strcmp(dev_blocks[i].c_str(), blocks[i].c_str())) - { - is_ok = false; - break; - } - } - - if (is_ok) - { - info.name = dev_blocks[blocks.size()]; - m_entries.push_back(info); - } - } - - if (m_stream && m_stream->IsOpened()) - { - m_entries.insert(m_entries.begin(), m_stream->GetEntries().begin(), m_stream->GetEntries().end()); - } - - return !m_entries.empty(); -} - -void vfsDir::Close() -{ - m_stream.reset(); -} - -bool vfsDir::IsOpened() const -{ - return !m_entries.empty(); -} diff --git a/rpcs3/Emu/FS/vfsDir.h b/rpcs3/Emu/FS/vfsDir.h deleted file mode 100644 index 61a2004875..0000000000 --- a/rpcs3/Emu/FS/vfsDir.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include "vfsDirBase.h" - -class vfsDir : public vfsDirBase -{ -private: - std::shared_ptr m_stream; - -public: - vfsDir(); - vfsDir(const std::string& path); - - virtual bool Open(const std::string& path) override; - virtual bool IsOpened() const override; - virtual void Close() override; - //virtual std::string GetPath() const override; -}; diff --git a/rpcs3/Emu/FS/vfsDirBase.cpp b/rpcs3/Emu/FS/vfsDirBase.cpp deleted file mode 100644 index 8e4cccc327..0000000000 --- a/rpcs3/Emu/FS/vfsDirBase.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "stdafx.h" -#include "vfsDirBase.h" - -vfsDirBase::vfsDirBase(vfsDevice* device) - : m_pos(0) - , m_device(device) -{ -} - -vfsDirBase::~vfsDirBase() -{ -} - -bool vfsDirBase::Open(const std::string& path) -{ - if (IsOpened()) - { - Close(); - } - - m_pos = 0; - m_cwd += '/' + path; - return true; -} - -bool vfsDirBase::IsOpened() const -{ - return !m_cwd.empty(); -} - -const std::vector& vfsDirBase::GetEntries() const -{ - return m_entries; -} - -void vfsDirBase::Close() -{ - m_cwd = ""; - m_entries.clear(); -} - -std::string vfsDirBase::GetPath() const -{ - return m_cwd; -} - -const DirEntryInfo* vfsDirBase::Read() -{ - if (m_pos >= m_entries.size()) - return nullptr; - - return &m_entries[m_pos++]; -} - -const DirEntryInfo* vfsDirBase::First() -{ - m_pos = 0; - return Read(); -} diff --git a/rpcs3/Emu/FS/vfsDirBase.h b/rpcs3/Emu/FS/vfsDirBase.h deleted file mode 100644 index ee43cb602d..0000000000 --- a/rpcs3/Emu/FS/vfsDirBase.h +++ /dev/null @@ -1,106 +0,0 @@ -#pragma once - -class vfsDevice; - -enum DirEntryFlags -{ - DirEntry_TypeDir = 0x1, - DirEntry_TypeFile = 0x2, - DirEntry_TypeMask = 0x3, - DirEntry_PermWritable = 0x20, - DirEntry_PermReadable = 0x40, - DirEntry_PermExecutable = 0x80, -}; - -struct DirEntryInfo -{ - std::string name; - u32 flags; - u64 size; - time_t create_time; - time_t access_time; - time_t modify_time; - - DirEntryInfo() - : flags(0) - , size(0) - , create_time(0) - , access_time(0) - , modify_time(0) - { - } -}; - -class vfsDirBase -{ -protected: - std::string m_cwd; - std::vector m_entries; - uint m_pos; - vfsDevice* m_device; - -public: - vfsDirBase(vfsDevice* device); - virtual ~vfsDirBase(); - - virtual bool Open(const std::string& path); - virtual bool IsOpened() const; - virtual const std::vector& GetEntries() const; - virtual void Close(); - virtual std::string GetPath() const; - - virtual const DirEntryInfo* Read(); - virtual const DirEntryInfo* First(); - - class iterator - { - vfsDirBase *parent; - const DirEntryInfo* data; - - public: - iterator(vfsDirBase* parent) - : parent(parent) - , data(parent->First()) - { - } - - iterator(vfsDirBase* parent, const DirEntryInfo* data) - : parent(parent) - , data(data) - { - } - - iterator& operator++() - { - data = parent->Read(); - return *this; - } - - iterator operator++(int) - { - const DirEntryInfo* olddata = data; - data = parent->Read(); - return iterator(parent, olddata); - } - - const DirEntryInfo* operator *() - { - return data; - } - - bool operator !=(iterator other) const - { - return data != other.data; - } - }; - - iterator begin() - { - return iterator(this); - } - - iterator end() - { - return iterator(this, nullptr); - } -}; diff --git a/rpcs3/Emu/FS/vfsFile.cpp b/rpcs3/Emu/FS/vfsFile.cpp deleted file mode 100644 index cded25282c..0000000000 --- a/rpcs3/Emu/FS/vfsFile.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "stdafx.h" -#include "Emu/System.h" - -#include "VFS.h" -#include "vfsFile.h" - -vfsFile::vfsFile() - : vfsFileBase(nullptr) - , m_stream(nullptr) -{ -} - -vfsFile::vfsFile(const std::string& path, u32 mode) - : vfsFileBase(nullptr) - , m_stream(nullptr) -{ - Open(path, mode); -} - -bool vfsFile::Open(const std::string& path, u32 mode) -{ - Close(); - - m_stream.reset(Emu.GetVFS().OpenFile(path, mode)); - - return m_stream && m_stream->IsOpened(); -} - -void vfsFile::Close() -{ - m_stream.reset(); -} - -u64 vfsFile::GetSize() const -{ - return m_stream->GetSize(); -} - -u64 vfsFile::Write(const void* src, u64 size) -{ - return m_stream->Write(src, size); -} - -u64 vfsFile::Read(void* dst, u64 size) -{ - return m_stream->Read(dst, size); -} - -u64 vfsFile::Seek(s64 offset, fs::seek_mode whence) -{ - return m_stream->Seek(offset, whence); -} - -u64 vfsFile::Tell() const -{ - return m_stream->Tell(); -} - -bool vfsFile::IsOpened() const -{ - return m_stream && m_stream->IsOpened(); -} diff --git a/rpcs3/Emu/FS/vfsFile.h b/rpcs3/Emu/FS/vfsFile.h deleted file mode 100644 index 74f538abc5..0000000000 --- a/rpcs3/Emu/FS/vfsFile.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include "vfsFileBase.h" - -class vfsFile : public vfsFileBase -{ -private: - std::shared_ptr m_stream; - -public: - vfsFile(); - vfsFile(const std::string& path, u32 mode = fom::read); - - virtual bool Open(const std::string& path, u32 mode = fom::read) override; - virtual void Close() override; - - virtual u64 GetSize() const override; - - virtual u64 Write(const void* src, u64 size) override; - virtual u64 Read(void* dst, u64 size) override; - - virtual u64 Seek(s64 offset, fs::seek_mode whence = fs::seek_set) override; - virtual u64 Tell() const override; - - virtual bool IsOpened() const override; -}; diff --git a/rpcs3/Emu/FS/vfsFileBase.cpp b/rpcs3/Emu/FS/vfsFileBase.cpp deleted file mode 100644 index b3cc967246..0000000000 --- a/rpcs3/Emu/FS/vfsFileBase.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "stdafx.h" -#include "vfsFileBase.h" - -vfsFileBase::vfsFileBase(vfsDevice* device) - : vfsStream() - , m_device(device) -{ -} - -vfsFileBase::~vfsFileBase() -{ - Close(); -} - -bool vfsFileBase::Open(const std::string& path, u32 mode) -{ - m_path = path; - m_mode = mode; - - return true; -} - -void vfsFileBase::Close() -{ - m_path = ""; - vfsStream::Close(); -} - -std::string vfsFileBase::GetPath() const -{ - return m_path; -} - -u32 vfsFileBase::GetOpenMode() const -{ - return m_mode; -} diff --git a/rpcs3/Emu/FS/vfsFileBase.h b/rpcs3/Emu/FS/vfsFileBase.h deleted file mode 100644 index 0b4f00b4b2..0000000000 --- a/rpcs3/Emu/FS/vfsFileBase.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include "vfsStream.h" - -class vfsDevice; - -struct vfsFileBase : public vfsStream -{ -protected: - std::string m_path; - u32 m_mode; - vfsDevice* m_device; - -public: - vfsFileBase(vfsDevice* device); - virtual ~vfsFileBase() override; - - virtual bool Open(const std::string& path, u32 mode); - virtual void Close() override; - virtual bool IsOpened() const override { return !m_path.empty(); } - - std::string GetPath() const; - u32 GetOpenMode() const; -}; diff --git a/rpcs3/Emu/FS/vfsLocalDir.cpp b/rpcs3/Emu/FS/vfsLocalDir.cpp deleted file mode 100644 index 95062193cb..0000000000 --- a/rpcs3/Emu/FS/vfsLocalDir.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "stdafx.h" -#include "vfsDevice.h" -#include "vfsLocalDir.h" - -vfsLocalDir::vfsLocalDir(vfsDevice* device) : vfsDirBase(device) -{ -} - -vfsLocalDir::~vfsLocalDir() -{ -} - -bool vfsLocalDir::Open(const std::string& path) -{ - if (!vfsDirBase::Open(path) || !m_dir.open(path)) - { - return false; - } - - std::string name; - fs::stat_t file_info; - - while (m_dir.read(name, file_info) && name.size()) - { - m_entries.emplace_back(); - - DirEntryInfo& info = m_entries.back(); - - info.name = name; - info.flags |= file_info.is_directory ? DirEntry_TypeDir | DirEntry_PermExecutable : DirEntry_TypeFile; - info.flags |= file_info.is_writable ? DirEntry_PermWritable | DirEntry_PermReadable : DirEntry_PermReadable; - info.size = file_info.size; - info.access_time = file_info.atime; - info.modify_time = file_info.mtime; - info.create_time = file_info.ctime; - } - - return true; -} - -bool vfsLocalDir::IsOpened() const -{ - return m_dir && vfsDirBase::IsOpened(); -} diff --git a/rpcs3/Emu/FS/vfsLocalDir.h b/rpcs3/Emu/FS/vfsLocalDir.h deleted file mode 100644 index f64ae9a768..0000000000 --- a/rpcs3/Emu/FS/vfsLocalDir.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include "vfsDirBase.h" - -class vfsLocalDir : public vfsDirBase -{ -private: - u32 m_pos; - fs::dir m_dir; - -public: - vfsLocalDir(vfsDevice* device); - virtual ~vfsLocalDir(); - - virtual bool Open(const std::string& path) override; - virtual bool IsOpened() const override; -}; diff --git a/rpcs3/Emu/FS/vfsLocalFile.cpp b/rpcs3/Emu/FS/vfsLocalFile.cpp deleted file mode 100644 index 573fc9db47..0000000000 --- a/rpcs3/Emu/FS/vfsLocalFile.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "stdafx.h" -#include "vfsLocalFile.h" - -vfsLocalFile::vfsLocalFile(vfsDevice* device) : vfsFileBase(device) -{ -} - -bool vfsLocalFile::Open(const std::string& path, u32 mode) -{ - Close(); - - return m_file.open(path, mode) && vfsFileBase::Open(path, mode); -} - -void vfsLocalFile::Close() -{ - m_file.close(); - vfsFileBase::Close(); -} - -u64 vfsLocalFile::GetSize() const -{ - return m_file.size(); -} - -u64 vfsLocalFile::Write(const void* src, u64 size) -{ - return m_file.write(src, size); -} - -u64 vfsLocalFile::Read(void* dst, u64 size) -{ - return m_file.read(dst, size); -} - -u64 vfsLocalFile::Seek(s64 offset, fs::seek_mode whence) -{ - return m_file.seek(offset, whence); -} - -u64 vfsLocalFile::Tell() const -{ - return m_file.seek(0, fs::seek_cur); -} - -bool vfsLocalFile::IsOpened() const -{ - return m_file && vfsFileBase::IsOpened(); -} diff --git a/rpcs3/Emu/FS/vfsLocalFile.h b/rpcs3/Emu/FS/vfsLocalFile.h deleted file mode 100644 index dc56074b71..0000000000 --- a/rpcs3/Emu/FS/vfsLocalFile.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include "vfsFileBase.h" - -class vfsLocalFile : public vfsFileBase -{ -private: - fs::file m_file; - -public: - vfsLocalFile(vfsDevice* device); - - virtual bool Open(const std::string& path, u32 mode = fom::read) override; - virtual void Close() override; - - virtual u64 GetSize() const override; - - virtual u64 Write(const void* src, u64 size) override; - virtual u64 Read(void* dst, u64 size) override; - - virtual u64 Seek(s64 offset, fs::seek_mode whence = fs::seek_set) override; - virtual u64 Tell() const override; - - virtual bool IsOpened() const override; - - virtual const fs::file& GetFile() const { return m_file; } -}; diff --git a/rpcs3/Emu/FS/vfsStream.cpp b/rpcs3/Emu/FS/vfsStream.cpp deleted file mode 100644 index a1fe0ffc0e..0000000000 --- a/rpcs3/Emu/FS/vfsStream.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "stdafx.h" -#include "vfsStream.h" diff --git a/rpcs3/Emu/FS/vfsStream.h b/rpcs3/Emu/FS/vfsStream.h deleted file mode 100644 index 74839c7fab..0000000000 --- a/rpcs3/Emu/FS/vfsStream.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -struct vfsStream -{ - vfsStream() = default; - - virtual ~vfsStream() - { - Close(); - } - - virtual void Close() - { - } - - virtual u64 GetSize() const = 0; - - virtual u64 Write(const void* src, u64 count) = 0; - - template - force_inline bool SWrite(const T& data, u64 count = sizeof(T)) - { - return Write(&data, count) == count; - } - - virtual u64 Read(void* dst, u64 count) = 0; - - template - force_inline bool SRead(T& data, u64 count = sizeof(T)) - { - return Read(&data, count) == count; - } - - template - bool VWrite(const std::vector& vec) - { - return IsOpened() && Write(vec.data(), vec.size() * sizeof(T)) == vec.size() * sizeof(T); - } - - template - std::vector VRead() - { - std::vector result; - if (IsOpened() == false) - { - return result; - } - - result.resize(GetSize() / sizeof(T)); - - if (Seek(0) == -1 || Read(result.data(), result.size() * sizeof(T)) != result.size() * sizeof(T)) - { - result.clear(); - } - - return result; - } - - virtual u64 Seek(s64 offset, fs::seek_mode whence = fs::seek_set) = 0; - - virtual u64 Tell() const = 0; - - virtual bool Eof() const - { - return Tell() >= GetSize(); - } - - virtual bool IsOpened() const = 0; -}; diff --git a/rpcs3/Emu/FS/vfsStreamMemory.cpp b/rpcs3/Emu/FS/vfsStreamMemory.cpp deleted file mode 100644 index 35dd1830af..0000000000 --- a/rpcs3/Emu/FS/vfsStreamMemory.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "vfsStreamMemory.h" - -u64 vfsStreamMemory::Write(const void* src, u64 count) -{ - assert(m_pos < m_size); - if (m_pos + count > m_size) - { - count = m_size - m_pos; - } - - std::memcpy(vm::base(VM_CAST(m_addr + m_pos)), src, count); - m_pos += count; - return count; -} - -u64 vfsStreamMemory::Read(void* dst, u64 count) -{ - assert(m_pos < m_size); - if (m_pos + count > m_size) - { - count = m_size - m_pos; - } - - std::memcpy(dst, vm::base(VM_CAST(m_addr + m_pos)), count); - m_pos += count; - return count; -} diff --git a/rpcs3/Emu/FS/vfsStreamMemory.h b/rpcs3/Emu/FS/vfsStreamMemory.h deleted file mode 100644 index d5dd22c0db..0000000000 --- a/rpcs3/Emu/FS/vfsStreamMemory.h +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once -#include "vfsStream.h" - -class vfsStreamMemory : public vfsStream -{ - u64 m_pos = 0; - u32 m_addr = 0; - u64 m_size = 0; - -public: - vfsStreamMemory() = default; - - vfsStreamMemory(u32 addr, u32 size = 0) - { - Open(addr, size); - } - - void Open(u32 addr, u32 size = 0) - { - m_pos = 0; - m_addr = addr; - m_size = size ? size : 0x100000000ull - addr; // determine max possible size - } - - virtual u64 GetSize() const override - { - return m_size; - } - - virtual u64 Write(const void* src, u64 count) override; - - virtual u64 Read(void* dst, u64 count) override; - - virtual u64 Seek(s64 offset, fs::seek_mode whence) override - { - switch (whence) - { - case fs::seek_set: return m_pos = offset; - case fs::seek_cur: return m_pos += offset; - case fs::seek_end: return m_pos = m_size + offset; - } - - throw EXCEPTION("Unknown seek_mode (0x%x)", whence); - } - - virtual u64 Tell() const override - { - return m_pos; - } - - virtual bool IsOpened() const override - { - return true; - } -}; diff --git a/rpcs3/Emu/HDD/HDD.cpp b/rpcs3/Emu/HDD/HDD.cpp deleted file mode 100644 index 5c4cf61145..0000000000 --- a/rpcs3/Emu/HDD/HDD.cpp +++ /dev/null @@ -1,820 +0,0 @@ -#include "stdafx.h" -#include "HDD.h" - -void vfsHDDManager::CreateBlock(vfsHDD_Block& block) -{ - block.is_used = true; - block.next_block = 0; -} - -void vfsHDDManager::CreateEntry(vfsHDD_Entry& entry) -{ - memset(&entry, 0, sizeof(vfsHDD_Entry)); - u64 ctime = time(nullptr); - entry.atime = ctime; - entry.ctime = ctime; - entry.mtime = ctime; - entry.access = 0666; - CreateBlock(entry); -} - -void vfsHDDManager::CreateHDD(const std::string& path, u64 size, u64 block_size) -{ - fs::file f(path, fom::rewrite); - - static const u64 cur_dir_block = 1; - - vfsHDD_Hdr hdr; - CreateBlock(hdr); - hdr.next_block = cur_dir_block; - hdr.magic = g_hdd_magic; - hdr.version = g_hdd_version; - hdr.block_count = (size + block_size) / block_size; - hdr.block_size = block_size; - f.write(&hdr, sizeof(vfsHDD_Hdr)); - - { - vfsHDD_Entry entry; - CreateEntry(entry); - entry.type = vfsHDD_Entry_Dir; - entry.data_block = hdr.next_block; - entry.next_block = 0; - - f.seek(cur_dir_block * hdr.block_size); - f.write(&entry, sizeof(vfsHDD_Entry)); - f.write(".", 1); - } - - u8 null = 0; - - CHECK_ASSERTION(f.seek(hdr.block_count * hdr.block_size - sizeof(null)) != -1); - - f.write(&null, sizeof(null)); -} - -void vfsHDDManager::Format() -{ -} - -void vfsHDDManager::AppendEntry(vfsHDD_Entry entry) -{ -} - -bool vfsHDDFile::goto_block(u64 n) -{ - vfsHDD_Block block_info; - - if (m_info.data_block >= m_hdd_info.block_count) - { - return false; - } - - CHECK_ASSERTION(m_hdd.Seek(m_info.data_block * m_hdd_info.block_size) != -1); - - block_info.next_block = m_info.data_block; - - for (u64 i = 0; i < n; ++i) - { - if (!block_info.next_block || !block_info.is_used || block_info.next_block >= m_hdd_info.block_count) - { - return false; - } - - CHECK_ASSERTION(m_hdd.Seek(block_info.next_block * m_hdd_info.block_size) != -1); - - m_hdd.Read(&block_info, sizeof(vfsHDD_Block)); - } - - return true; -} - -void vfsHDDFile::RemoveBlocks(u64 start_block) -{ - vfsHDD_Block block_info; - block_info.next_block = start_block; - - while (block_info.next_block && block_info.is_used) - { - u64 offset = block_info.next_block * m_hdd_info.block_size; - - ReadBlock(offset, block_info); - WriteBlock(offset, g_null_block); - } -} - -void vfsHDDFile::WriteBlock(u64 block, const vfsHDD_Block& data) -{ - CHECK_ASSERTION(m_hdd.Seek(block * m_hdd_info.block_size) != -1); - - m_hdd.Write(&data, sizeof(vfsHDD_Block)); -} - -void vfsHDDFile::ReadBlock(u64 block, vfsHDD_Block& data) -{ - CHECK_ASSERTION(m_hdd.Seek(block * m_hdd_info.block_size) != -1); - - m_hdd.Read(&data, sizeof(vfsHDD_Block)); -} - -void vfsHDDFile::WriteEntry(u64 block, const vfsHDD_Entry& data) -{ - CHECK_ASSERTION(m_hdd.Seek(block * m_hdd_info.block_size) != -1); - - m_hdd.Write(&data, sizeof(vfsHDD_Entry)); -} - -void vfsHDDFile::ReadEntry(u64 block, vfsHDD_Entry& data) -{ - CHECK_ASSERTION(m_hdd.Seek(block * m_hdd_info.block_size) != -1); - - m_hdd.Read(&data, sizeof(vfsHDD_Entry)); -} - -void vfsHDDFile::ReadEntry(u64 block, vfsHDD_Entry& data, std::string& name) -{ - CHECK_ASSERTION(m_hdd.Seek(block * m_hdd_info.block_size) != -1); - - m_hdd.Read(&data, sizeof(vfsHDD_Entry)); - name.resize(GetMaxNameLen()); - m_hdd.Read(&name.front(), GetMaxNameLen()); -} - -void vfsHDDFile::ReadEntry(u64 block, std::string& name) -{ - CHECK_ASSERTION(m_hdd.Seek(block * m_hdd_info.block_size + sizeof(vfsHDD_Entry)) != -1); - - name.resize(GetMaxNameLen()); - m_hdd.Read(&name.front(), GetMaxNameLen()); -} - -void vfsHDDFile::WriteEntry(u64 block, const vfsHDD_Entry& data, const std::string& name) -{ - CHECK_ASSERTION(m_hdd.Seek(block * m_hdd_info.block_size) != -1); - - m_hdd.Write(&data, sizeof(vfsHDD_Entry)); - m_hdd.Write(name.c_str(), std::min(GetMaxNameLen() - 1, name.length() + 1)); -} - -void vfsHDDFile::Open(u64 info_block) -{ - m_info_block = info_block; - ReadEntry(m_info_block, m_info); - m_position = 0; - m_cur_block = m_info.data_block; -} - -u64 vfsHDDFile::FindFreeBlock() -{ - vfsHDD_Block block_info; - - for (u64 i = 0; i < m_hdd_info.block_count; ++i) - { - ReadBlock(i, block_info); - - if (!block_info.is_used) - { - return i; - } - } - - return 0; -} - -bool vfsHDDFile::Seek(u64 pos) -{ - if (!goto_block(pos / m_hdd_info.block_size)) - { - return false; - } - - m_position = pos % m_hdd_info.block_size; - return true; -} - -void vfsHDDFile::SaveInfo() -{ - CHECK_ASSERTION(m_hdd.Seek(m_info_block * m_hdd_info.block_size) != -1); - - CHECK_ASSERTION(m_hdd.Seek(m_info_block * m_hdd_info.block_size) != -1); - - m_hdd.Write(&m_info, sizeof(vfsHDD_Entry)); -} - -u64 vfsHDDFile::Read(void* dst, u64 size) -{ - if (!size) - return 0; - - //vfsDeviceLocker lock(m_hdd); - - const u32 block_size = m_hdd_info.block_size - sizeof(vfsHDD_Block); - u64 rsize = std::min(block_size - m_position, size); - - vfsHDD_Block cur_block_info; - - CHECK_ASSERTION(m_hdd.Seek(m_cur_block * m_hdd_info.block_size) != -1); - - m_hdd.Read(&cur_block_info, sizeof(vfsHDD_Block)); - - CHECK_ASSERTION(m_hdd.Seek(m_cur_block * m_hdd_info.block_size + sizeof(vfsHDD_Block) + m_position) != -1); - - m_hdd.Read(dst, rsize); - size -= rsize; - m_position += rsize; - if (!size) - { - return rsize; - } - - u64 offset = rsize; - - for (; size; size -= rsize, offset += rsize) - { - if (!cur_block_info.is_used || !cur_block_info.next_block || cur_block_info.next_block >= m_hdd_info.block_count) - { - return offset; - } - - m_cur_block = cur_block_info.next_block; - rsize = std::min(block_size, size); - - CHECK_ASSERTION(m_hdd.Seek(cur_block_info.next_block * m_hdd_info.block_size) != -1); - - m_hdd.Read(&cur_block_info, sizeof(vfsHDD_Block)); - - if (m_hdd.Read((u8*)dst + offset, rsize) != rsize) - { - return offset; - } - } - - m_position = rsize; - - return offset; -} - -u64 vfsHDDFile::Write(const void* src, u64 size) -{ - if (!size) - return 0; - - //vfsDeviceLocker lock(m_hdd); - - const u32 block_size = m_hdd_info.block_size - sizeof(vfsHDD_Block); - - if (!m_cur_block) - { - if (!m_info.data_block) - { - u64 new_block = FindFreeBlock(); - - if (!new_block) - { - return 0; - } - - WriteBlock(new_block, g_used_block); - m_info.data_block = new_block; - m_info.size = 0; - SaveInfo(); - } - - m_cur_block = m_info.data_block; - m_position = 0; - } - - u64 wsize = std::min(block_size - m_position, size); - - vfsHDD_Block block_info; - ReadBlock(m_cur_block, block_info); - - if (wsize) - { - CHECK_ASSERTION(m_hdd.Seek(m_cur_block * m_hdd_info.block_size + sizeof(vfsHDD_Block) + m_position) != -1); - - m_hdd.Write(src, wsize); - size -= wsize; - m_info.size += wsize; - m_position += wsize; - SaveInfo(); - - if (!size) - return wsize; - } - - u64 last_block = m_cur_block; - block_info.is_used = true; - u64 offset = wsize; - - for (; size; size -= wsize, offset += wsize, m_info.size += wsize) - { - u64 new_block = FindFreeBlock(); - - if (!new_block) - { - m_position = 0; - SaveInfo(); - return offset; - } - - m_cur_block = new_block; - wsize = std::min(block_size, size); - - block_info.next_block = m_cur_block; - - CHECK_ASSERTION(m_hdd.Seek(last_block * m_hdd_info.block_size) != -1); - - if (m_hdd.Write(&block_info, sizeof(vfsHDD_Block)) != sizeof(vfsHDD_Block)) - { - m_position = 0; - SaveInfo(); - return offset; - } - - block_info.next_block = 0; - - CHECK_ASSERTION(m_hdd.Seek(m_cur_block * m_hdd_info.block_size) != -1); - - if (m_hdd.Write(&block_info, sizeof(vfsHDD_Block)) != sizeof(vfsHDD_Block)) - { - m_position = 0; - SaveInfo(); - return offset; - } - - if ((m_position = m_hdd.Write((u8*)src + offset, wsize)) != wsize) - { - m_info.size += wsize; - SaveInfo(); - return offset; - } - - last_block = m_cur_block; - } - - SaveInfo(); - m_position = wsize; - return offset; -} - -vfsDeviceHDD::vfsDeviceHDD(const std::string& hdd_path) : m_hdd_path(hdd_path) -{ -} - -vfsFileBase* vfsDeviceHDD::GetNewFileStream() -{ - return new vfsHDD(this, m_hdd_path); -} - -vfsDirBase* vfsDeviceHDD::GetNewDirStream() -{ - return nullptr; -} - -vfsHDD::vfsHDD(vfsDevice* device, const std::string& hdd_path) - : m_hdd_file(device) - , m_file(m_hdd_file, m_hdd_info) - , m_hdd_path(hdd_path) - , vfsFileBase(device) -{ - m_hdd_file.Open(hdd_path, fom::read | fom::write); - m_hdd_file.Read(&m_hdd_info, sizeof(vfsHDD_Hdr)); - m_cur_dir_block = m_hdd_info.next_block; - if (!m_hdd_info.block_size) - { - LOG_ERROR(HLE, "Bad block size!"); - m_hdd_info.block_size = 2048; - } - - CHECK_ASSERTION(m_hdd_file.Seek(m_cur_dir_block * m_hdd_info.block_size) != -1); - - m_hdd_file.Read(&m_cur_dir, sizeof(vfsHDD_Entry)); -} - -bool vfsHDD::SearchEntry(const std::string& name, u64& entry_block, u64* parent_block) -{ - u64 last_block = 0; - u64 block = m_cur_dir_block; - vfsHDD_Entry entry; - std::string buf; - - while (block) - { - ReadEntry(block, entry, buf); - - if (fmt::CmpNoCase(name, buf) == 0) - { - entry_block = block; - if (parent_block) - *parent_block = last_block; - - return true; - } - - last_block = block; - block = entry.is_used ? entry.next_block : 0ULL; - } - - return false; -} - -s32 vfsHDD::OpenDir(const std::string& name) -{ - LOG_WARNING(HLE, "OpenDir(%s)", name.c_str()); - u64 entry_block; - - if (!SearchEntry(name, entry_block)) - { - return -1; - } - - CHECK_ASSERTION(m_hdd_file.Seek(entry_block * m_hdd_info.block_size) != -1); - - vfsHDD_Entry entry; - m_hdd_file.Read(&entry, sizeof(vfsHDD_Entry)); - - if (entry.type == vfsHDD_Entry_File) - { - return 1; - } - - m_cur_dir_block = entry.data_block; - ReadEntry(m_cur_dir_block, m_cur_dir); - - return 0; -} - -bool vfsHDD::Rename(const std::string& from, const std::string& to) -{ - u64 entry_block; - if (!SearchEntry(from, entry_block)) - { - return false; - } - - vfsHDD_Entry entry; - ReadEntry(entry_block, entry); - WriteEntry(entry_block, entry, to); - - return true; -} - -u64 vfsHDD::FindFreeBlock() -{ - vfsHDD_Block block_info; - - for (u64 i = 0; i < m_hdd_info.block_count; ++i) - { - ReadBlock(i, block_info); - - if (!block_info.is_used) - { - return i; - } - } - - return 0; -} - -void vfsHDD::WriteBlock(u64 block, const vfsHDD_Block& data) -{ - CHECK_ASSERTION(m_hdd_file.Seek(block * m_hdd_info.block_size) != -1); - - m_hdd_file.Write(&data, sizeof(vfsHDD_Block)); -} - -void vfsHDD::ReadBlock(u64 block, vfsHDD_Block& data) -{ - CHECK_ASSERTION(m_hdd_file.Seek(block * m_hdd_info.block_size) != -1); - - m_hdd_file.Read(&data, sizeof(vfsHDD_Block)); -} - -void vfsHDD::WriteEntry(u64 block, const vfsHDD_Entry& data) -{ - CHECK_ASSERTION(m_hdd_file.Seek(block * m_hdd_info.block_size) != -1); - - m_hdd_file.Write(&data, sizeof(vfsHDD_Entry)); -} - -void vfsHDD::ReadEntry(u64 block, vfsHDD_Entry& data) -{ - CHECK_ASSERTION(m_hdd_file.Seek(block * m_hdd_info.block_size) != -1); - - m_hdd_file.Read(&data, sizeof(vfsHDD_Entry)); -} - -void vfsHDD::ReadEntry(u64 block, vfsHDD_Entry& data, std::string& name) -{ - CHECK_ASSERTION(m_hdd_file.Seek(block * m_hdd_info.block_size) != -1); - - m_hdd_file.Read(&data, sizeof(vfsHDD_Entry)); - name.resize(GetMaxNameLen()); - m_hdd_file.Read(&name.front(), GetMaxNameLen()); -} - -void vfsHDD::ReadEntry(u64 block, std::string& name) -{ - CHECK_ASSERTION(m_hdd_file.Seek(block * m_hdd_info.block_size + sizeof(vfsHDD_Entry)) != -1); - - name.resize(GetMaxNameLen()); - m_hdd_file.Read(&name.front(), GetMaxNameLen()); -} - -void vfsHDD::WriteEntry(u64 block, const vfsHDD_Entry& data, const std::string& name) -{ - CHECK_ASSERTION(m_hdd_file.Seek(block * m_hdd_info.block_size) != -1); - - m_hdd_file.Write(&data, sizeof(vfsHDD_Entry)); - m_hdd_file.Write(name.c_str(), std::min(GetMaxNameLen() - 1, name.length() + 1)); -} - -bool vfsHDD::Create(vfsHDD_EntryType type, const std::string& name) -{ - if (HasEntry(name)) - { - return false; - } - - u64 new_block = FindFreeBlock(); - if (!new_block) - { - return false; - } - - LOG_NOTICE(HLE, "CREATING ENTRY AT 0x%llx", new_block); - WriteBlock(new_block, g_used_block); - - { - vfsHDD_Entry new_entry; - vfsHDDManager::CreateEntry(new_entry); - new_entry.next_block = 0; - new_entry.type = type; - - if (type == vfsHDD_Entry_Dir) - { - u64 block_cur = FindFreeBlock(); - - if (!block_cur) - { - return false; - } - - WriteBlock(block_cur, g_used_block); - - u64 block_last = FindFreeBlock(); - - if (!block_last) - { - return false; - } - - WriteBlock(block_last, g_used_block); - - vfsHDD_Entry entry_cur, entry_last; - vfsHDDManager::CreateEntry(entry_cur); - vfsHDDManager::CreateEntry(entry_last); - - entry_cur.type = vfsHDD_Entry_Dir; - entry_cur.data_block = block_cur; - entry_cur.next_block = block_last; - - entry_last.type = vfsHDD_Entry_Dir; - entry_last.data_block = m_cur_dir_block; - entry_last.next_block = 0; - - new_entry.data_block = block_cur; - - WriteEntry(block_cur, entry_cur, "."); - WriteEntry(block_last, entry_last, ".."); - } - - WriteEntry(new_block, new_entry, name); - } - - { - u64 block = m_cur_dir_block; - - vfsHDD_Block tmp; - while (block) - { - ReadBlock(block, tmp); - - if (!tmp.next_block) - break; - - block = tmp.next_block; - } - - tmp.next_block = new_block; - WriteBlock(block, tmp); - } - - return true; -} - -bool vfsHDD::GetFirstEntry(u64& block, vfsHDD_Entry& entry, std::string& name) -{ - if (!m_cur_dir_block) - { - return false; - } - - ReadEntry(m_cur_dir_block, entry, name); - block = entry.is_used ? entry.next_block : 0; - - return true; -} - -bool vfsHDD::GetNextEntry(u64& block, vfsHDD_Entry& entry, std::string& name) -{ - if (!block) - { - return false; - } - - ReadEntry(block, entry, name); - - block = entry.is_used ? entry.next_block : 0; - return true; -} - -bool vfsHDD::Open(const std::string& path, u32 mode) -{ - const char* s = path.c_str(); - u64 from = 0; - u64 pos = 0; - u64 file_pos = -1; - - do - { - if (s[pos] == '\\' || s[pos] == '/' || s[pos] == '\0') // ??? - { - if (file_pos != -1) - { - return false; - } - - if (from != -1) - { - if (pos - from > 1) - { - s32 res = OpenDir(std::string(s + from, pos)); - - if (res == -1) - { - return false; - } - else if (res == 1) - { - file_pos = from; - } - } - - from = pos; - } - else - { - from = pos; - } - } - } while (s[pos++] != '\0'); - - if (file_pos == -1) - { - return false; - } - - u64 file_block; - if (!SearchEntry(std::string(s + file_pos), file_block)) - { - return false; - } - - LOG_NOTICE(HLE, "ENTRY FOUND AT 0x%llx", file_block); - m_file.Open(file_block); - - return vfsFileBase::Open(path, mode); -} - -bool vfsHDD::HasEntry(const std::string& name) -{ - u64 file_block; - if (!SearchEntry(name, file_block)) - { - return false; - } - - return true; -} - -void vfsHDD::RemoveBlocksDir(u64 start_block) -{ - std::string name; - u64 block = start_block; - vfsHDD_Entry entry; - - while (block) - { - ReadEntry(block, entry, name); - WriteBlock(block, g_null_block); - - if (entry.type == vfsHDD_Entry_Dir && name != "." && name != "..") - { - LOG_WARNING(HLE, "Removing sub folder '%s'", name.c_str()); - RemoveBlocksDir(entry.data_block); - } - else if (entry.type == vfsHDD_Entry_File) - { - RemoveBlocksFile(entry.data_block); - } - - block = entry.next_block; - } -} - -void vfsHDD::RemoveBlocksFile(u64 start_block) -{ - u64 block = start_block; - vfsHDD_Block block_data; - - while (block) - { - ReadBlock(block, block_data); - WriteBlock(block, g_null_block); - - block = block_data.next_block; - } -} - -bool vfsHDD::RemoveEntry(const std::string& name) -{ - u64 entry_block, parent_entry; - if (!SearchEntry(name, entry_block, &parent_entry)) - { - return false; - } - - vfsHDD_Entry entry; - ReadEntry(entry_block, entry); - if (entry.type == vfsHDD_Entry_Dir) - { - RemoveBlocksDir(entry.data_block); - } - else if (entry.type == vfsHDD_Entry_File) - { - RemoveBlocksFile(entry.data_block); - } - - if (parent_entry) - { - u64 next = entry.next_block; - ReadEntry(parent_entry, entry); - entry.next_block = next; - WriteEntry(parent_entry, entry); - } - WriteBlock(entry_block, g_null_block); - return true; -} - -u64 vfsHDD::Write(const void* src, u64 size) -{ - return m_file.Write(src, size); // ??? -} - -u64 vfsHDD::Read(void* dst, u64 size) -{ - return m_file.Read(dst, size); // ??? -} - -u64 vfsHDD::Seek(s64 offset, fs::seek_mode whence) -{ - switch (whence) - { - case fs::seek_set: return m_file.Seek(offset); - case fs::seek_cur: return m_file.Seek(Tell() + offset); - case fs::seek_end: return m_file.Seek(m_file.GetSize() + offset); - } - - throw EXCEPTION("Unknown whence (0x%x)", whence); -} - -u64 vfsHDD::Tell() const -{ - return m_file.Tell(); // ??? -} - -bool vfsHDD::Eof() const -{ - return m_file.Eof(); -} - -bool vfsHDD::IsOpened() const -{ - return true; // ??? -} - -u64 vfsHDD::GetSize() const -{ - return m_file.GetSize(); -} diff --git a/rpcs3/Emu/HDD/HDD.h b/rpcs3/Emu/HDD/HDD.h deleted file mode 100644 index a192de41e5..0000000000 --- a/rpcs3/Emu/HDD/HDD.h +++ /dev/null @@ -1,208 +0,0 @@ -#pragma once -#include "Emu/FS/vfsDevice.h" -#include "Emu/FS/vfsLocalFile.h" - -static const u64 g_hdd_magic = *(u64*)"PS3eHDD\0"; -static const u16 g_hdd_version = 0x0001; - -struct vfsHDD_Block -{ - struct - { - u64 is_used : 1; - u64 next_block : 63; - }; -} static const g_null_block = {0}, g_used_block = {1}; - -struct vfsHDD_Hdr : public vfsHDD_Block -{ - u64 magic; - u16 version; - u64 block_count; - u32 block_size; -}; - -enum vfsHDD_EntryType : u8 -{ - vfsHDD_Entry_Dir = 0, - vfsHDD_Entry_File = 1, - vfsHDD_Entry_Link = 2, -}; - -struct vfsHDD_Entry : public vfsHDD_Block -{ - u64 data_block; - u32 access; - vfsHDD_EntryType type; - u64 size; - u64 ctime; - u64 mtime; - u64 atime; -}; - -class vfsHDDManager -{ -public: - static void CreateBlock(vfsHDD_Block& block); - - static void CreateEntry(vfsHDD_Entry& entry); - - static void CreateHDD(const std::string& path, u64 size, u64 block_size); - - void Format(); - - void AppendEntry(vfsHDD_Entry entry); -}; - - -class vfsHDDFile -{ - u64 m_info_block; - vfsHDD_Entry m_info; - const vfsHDD_Hdr& m_hdd_info; - vfsLocalFile& m_hdd; - u32 m_position; - u64 m_cur_block; - - bool goto_block(u64 n); - - void RemoveBlocks(u64 start_block); - - void WriteBlock(u64 block, const vfsHDD_Block& data); - - void ReadBlock(u64 block, vfsHDD_Block& data); - - void WriteEntry(u64 block, const vfsHDD_Entry& data); - - void ReadEntry(u64 block, vfsHDD_Entry& data); - - void ReadEntry(u64 block, vfsHDD_Entry& data, std::string& name); - - void ReadEntry(u64 block, std::string& name); - - void WriteEntry(u64 block, const vfsHDD_Entry& data, const std::string& name); - - force_inline u32 GetMaxNameLen() const - { - return m_hdd_info.block_size - sizeof(vfsHDD_Entry); - } - -public: - vfsHDDFile(vfsLocalFile& hdd, const vfsHDD_Hdr& hdd_info) - : m_hdd(hdd) - , m_hdd_info(hdd_info) - { - } - - ~vfsHDDFile() - { - } - - void Open(u64 info_block); - - u64 FindFreeBlock(); - - u64 GetSize() const - { - return m_info.size; - } - - bool Seek(u64 pos); - - u64 Tell() const - { - return m_cur_block * m_hdd_info.block_size + m_position; // ??? - } - - void SaveInfo(); - - u64 Read(void* dst, u64 size); - - u64 Write(const void* src, u64 size); - - bool Eof() const - { - return m_info.size <= (m_cur_block * m_hdd_info.block_size + m_position); - } -}; - -class vfsDeviceHDD : public vfsDevice -{ - std::string m_hdd_path; - -public: - vfsDeviceHDD(const std::string& hdd_path); - - virtual vfsFileBase* GetNewFileStream() override; - virtual vfsDirBase* GetNewDirStream() override; -}; - -class vfsHDD : public vfsFileBase -{ - vfsHDD_Hdr m_hdd_info; - vfsLocalFile m_hdd_file; - const std::string& m_hdd_path; - vfsHDD_Entry m_cur_dir; - u64 m_cur_dir_block; - vfsHDDFile m_file; - -public: - vfsHDD(vfsDevice* device, const std::string& hdd_path); - - force_inline u32 GetMaxNameLen() const - { - return m_hdd_info.block_size - sizeof(vfsHDD_Entry); - } - - bool SearchEntry(const std::string& name, u64& entry_block, u64* parent_block = nullptr); - - s32 OpenDir(const std::string& name); - - bool Rename(const std::string& from, const std::string& to); - - u64 FindFreeBlock(); - - void WriteBlock(u64 block, const vfsHDD_Block& data); - - void ReadBlock(u64 block, vfsHDD_Block& data); - - void WriteEntry(u64 block, const vfsHDD_Entry& data); - - void ReadEntry(u64 block, vfsHDD_Entry& data); - - void ReadEntry(u64 block, vfsHDD_Entry& data, std::string& name); - - void ReadEntry(u64 block, std::string& name); - - void WriteEntry(u64 block, const vfsHDD_Entry& data, const std::string& name); - - bool Create(vfsHDD_EntryType type, const std::string& name); - - bool GetFirstEntry(u64& block, vfsHDD_Entry& entry, std::string& name); - - bool GetNextEntry(u64& block, vfsHDD_Entry& entry, std::string& name); - - virtual bool Open(const std::string& path, u32 mode = fom::read) override; - - bool HasEntry(const std::string& name); - - void RemoveBlocksDir(u64 start_block); - - void RemoveBlocksFile(u64 start_block); - - bool RemoveEntry(const std::string& name); - - virtual u64 Write(const void* src, u64 count) override; - - virtual u64 Read(void* dst, u64 count) override; - - virtual u64 Seek(s64 offset, fs::seek_mode whence = fs::seek_set) override; - - virtual u64 Tell() const override; - - virtual bool Eof() const override; - - virtual bool IsOpened() const override; - - virtual u64 GetSize() const override; -}; diff --git a/rpcs3/Emu/IdManager.cpp b/rpcs3/Emu/IdManager.cpp deleted file mode 100644 index 1f7dc195f7..0000000000 --- a/rpcs3/Emu/IdManager.cpp +++ /dev/null @@ -1,156 +0,0 @@ -#include "stdafx.h" -#include "IdManager.h" - -namespace idm -{ - shared_mutex g_mutex; - - idm::map_t g_map; - - u32 g_last_raw_id = 0; - - thread_local u32 g_tls_last_id = 0xdeadbeef; -} - -namespace fxm -{ - shared_mutex g_mutex; - - fxm::map_t g_map; -} - -void idm::clear() -{ - std::lock_guard lock(g_mutex); - - // Call recorded finalization functions for all IDs - for (auto& id : idm::map_t(std::move(g_map))) - { - (*id.second.type_index)(id.second.data.get()); - } - - g_last_raw_id = 0; -} - -bool idm::check(u32 in_id, id_type_index_t type) -{ - reader_lock lock(g_mutex); - - const auto found = g_map.find(in_id); - - return found != g_map.end() && found->second.type_index == type; -} - -const std::type_info* idm::get_type(u32 raw_id) -{ - reader_lock lock(g_mutex); - - const auto found = g_map.find(raw_id); - - return found == g_map.end() ? nullptr : found->second.info; -} - -std::shared_ptr idm::get(u32 in_id, id_type_index_t type) -{ - reader_lock lock(g_mutex); - - const auto found = g_map.find(in_id); - - if (found == g_map.end() || found->second.type_index != type) - { - return nullptr; - } - - return found->second.data; -} - -idm::map_t idm::get_all(id_type_index_t type) -{ - reader_lock lock(g_mutex); - - idm::map_t result; - - for (auto& id : g_map) - { - if (id.second.type_index == type) - { - result.insert(id); - } - } - - return result; -} - -std::shared_ptr idm::withdraw(u32 in_id, id_type_index_t type) -{ - std::lock_guard lock(g_mutex); - - const auto found = g_map.find(in_id); - - if (found == g_map.end() || found->second.type_index != type) - { - return nullptr; - } - - auto ptr = std::move(found->second.data); - - g_map.erase(found); - - return ptr; -} - -u32 idm::get_count(id_type_index_t type) -{ - reader_lock lock(g_mutex); - - u32 result = 0; - - for (auto& id : g_map) - { - if (id.second.type_index == type) - { - result++; - } - } - - return result; -} - - -void fxm::clear() -{ - std::lock_guard lock(g_mutex); - - // Call recorded finalization functions for all IDs - for (auto& id : fxm::map_t(std::move(g_map))) - { - if (id.second) (*id.first)(id.second.get()); - } -} - -bool fxm::check(id_type_index_t type) -{ - reader_lock lock(g_mutex); - - const auto found = g_map.find(type); - - return found != g_map.end() && found->second; -} - -std::shared_ptr fxm::get(id_type_index_t type) -{ - reader_lock lock(g_mutex); - - const auto found = g_map.find(type); - - return found != g_map.end() ? found->second : nullptr; -} - -std::shared_ptr fxm::withdraw(id_type_index_t type) -{ - std::unique_lock lock(g_mutex); - - const auto found = g_map.find(type); - - return found != g_map.end() ? std::move(found->second) : nullptr; -} diff --git a/rpcs3/Emu/IdManager.h b/rpcs3/Emu/IdManager.h index 347fa2b5b1..25604293ee 100644 --- a/rpcs3/Emu/IdManager.h +++ b/rpcs3/Emu/IdManager.h @@ -2,86 +2,154 @@ #include "Utilities/SharedMutex.h" -#define ID_MANAGER_INCLUDED +#include +#include -// TODO: make id_aux_initialize and id_aux_finalize safer against a possible ODR violation - -// Function called after the successfull creation of an ID (does nothing by default, provide an overload) -inline void id_aux_initialize(void*) +// Mostly helper namespace +namespace id_manager { - ; -} - -// Function called after the ID removal (does nothing by default, provide an overload) -inline void id_aux_finalize(void*) -{ - ; -} - -// Type-erased id_aux_* function type -using id_aux_func_t = void(*)(void*); - -template -struct id_type_info_t -{ - static const auto size = sizeof(T); // forbid forward declarations - - static const id_aux_func_t on_remove; -}; - -// Type-erased finalization function -template -const id_aux_func_t id_type_info_t::on_remove = [](void* ptr) -{ - return id_aux_finalize(static_cast(ptr)); -}; - -using id_type_index_t = const id_aux_func_t*; - -// Get a unique pointer to the on_remove value (will be unique for each type) -template -inline constexpr id_type_index_t get_id_type_index() -{ - return &id_type_info_t::on_remove; -} - -// Default ID traits for any arbitrary type -template -struct id_traits -{ - static const auto size = sizeof(T); // forbid forward declarations - - // Get next mapped id (may return 0 if out of IDs) - static u32 next_id(u32 raw_id) { return raw_id < 0x80000000 ? (raw_id + 1) & 0x7fffffff : 0; } - - // Convert "public" id to mapped id (may return 0 if invalid) - static u32 in_id(u32 id) { return id; } - - // Convert mapped id to "public" id - static u32 out_id(u32 raw_id) { return raw_id; } -}; - -// ID Manager -// 0 is invalid ID -// 1..0x7fffffff : general purpose IDs -// 0x80000000+ : reserved (may be used through id_traits specializations) -namespace idm -{ - struct id_data_t final + // Optional ID traits + template + struct id_traits { - std::shared_ptr data; - const std::type_info* info; - id_type_index_t type_index; + using tag = void; - template id_data_t(const std::shared_ptr& data) - : data(data) - , info(&typeid(T)) - , type_index(get_id_type_index()) + static constexpr u32 min = 1; + static constexpr u32 max = 0x7fffffff; + }; + + template + struct id_traits> + { + using tag = typename T::id_base; + + static constexpr u32 min = T::id_min; + static constexpr u32 max = T::id_max; + }; + + // Optional ID storage + template + struct id_storage + { + static const u32* get(T*) + { + return nullptr; + } + }; + + template + struct id_storage> + { + static const u32* get(T* ptr) + { + return &ptr->id; + } + }; + + // Optional object initialization function (called after ID registration) + template + struct on_init + { + static void func(T*) { } }; - // Custom hasher for ID values (map to itself) + template + struct on_init().on_init())> + { + static void func(T* ptr) + { + ptr->on_init(); + } + }; + + // Optional object finalization function (called after ID removal) + template + struct on_stop + { + static void func(T*) + { + } + }; + + template + struct on_stop().on_stop())> + { + static void func(T* ptr) + { + ptr->on_stop(); + } + }; + + template + class typeinfo + { + // Global variable for each registered type + template + struct registered + { + static const u32 index; + }; + + // Access global type list + static never_inline auto& access() + { + static std::vector list; + + return list; + } + + static never_inline u32 add_type(typeinfo info) + { + auto& list = access(); + + list.emplace_back(info); + + return ::size32(list) - 1; + } + + public: + const std::type_info* info; + void(*on_init)(void*); + void(*on_stop)(void*); + + // Get type index + template + static inline u32 get_index() + { + // Forbid forward declarations (It'd be better to allow them sometimes but it seems too dangerous) + static constexpr auto size = sizeof(std::conditional_t::value, void*, T>); + + return registered::index; + } + + // Read all registered types + static inline const auto& get() + { + return access(); + } + }; + + template template + const u32 typeinfo::registered::index = typeinfo::add_type( + { + &typeid(T), + PURE_EXPR(id_manager::on_init::func(static_cast(ptr)), void* ptr), + PURE_EXPR(id_manager::on_stop::func(static_cast(ptr)), void* ptr), + }); +} + +// Object manager for emulated process. Multiple objects of specified arbitrary type are given unique IDs. +class idm +{ + // Rules for ID allocation: + // 0) Individual ID counter may be specified for each type by defining 'using id_base = ...;' + // 1) If no id_base specified, void is assumed. + // 2) g_id[id_base] indicates next ID allocated in g_map. + // 3) g_map[id_base] contains the additional copy of object pointer. + + // Custom hasher for ID values struct id_hash_t final { std::size_t operator ()(u32 value) const @@ -90,82 +158,157 @@ namespace idm } }; - using map_t = std::unordered_map; + using map_type = std::unordered_map, id_hash_t>; - // Can be called from the constructor called through make() or make_ptr() to get the ID of the object being created - inline u32 get_last_id() + // Type Index -> ID -> Object. Use global since only one process is supported atm. + static std::vector g_map; + + // Next ID for each category + static std::vector g_id; + + static shared_mutex g_mutex; + + static const auto& get_types() { - extern thread_local u32 g_tls_last_id; - - return g_tls_last_id; + return id_manager::typeinfo::get(); } - // Remove all objects - void clear(); - - // Internal - bool check(u32 in_id, id_type_index_t type); - - // Check if an ID of specified type exists template - bool check(u32 id) + static inline u32 get_type() { - return check(id_traits::in_id(id), get_id_type_index()); + return id_manager::typeinfo::get_index(); } - // Check if an ID exists and return its type or nullptr - const std::type_info* get_type(u32 raw_id); - - // Internal - template - std::shared_ptr add(Ptr&& get_ptr) + template + static inline u32 get_tag() { - extern shared_mutex g_mutex; - extern idm::map_t g_map; - extern u32 g_last_raw_id; - extern thread_local u32 g_tls_last_id; + return get_type::tag>(); + } + // Prepares new ID, returns nullptr if out of resources + static map_type::pointer allocate_id(u32 tag, u32 min, u32 max) + { + // Check all IDs starting from "next id" + for (u32 i = 0; i <= max - min; i++) + { + // Fix current ID (wrap around) + if (g_id[tag] < min || g_id[tag] > max) g_id[tag] = min; + + // Get ID + const auto r = g_map[tag].emplace(g_id[tag]++, nullptr); + + if (r.second) + { + return &*r.first; + } + } + + // Nothing found + return nullptr; + } + + // Deallocate ID, returns object + static std::shared_ptr deallocate_id(u32 tag, u32 id) + { + const auto found = g_map[tag].find(id); + + if (found == g_map[tag].end()) return nullptr; + + auto ptr = std::move(found->second); + + g_map[tag].erase(found); + + return ptr; + } + + // Allocate new ID and construct it from the provider() + template> + static map_type::pointer create_id(F&& provider) + { std::lock_guard lock(g_mutex); - for (u32 raw_id = g_last_raw_id; (raw_id = id_traits::next_id(raw_id)); /**/) + if (auto place = allocate_id(get_tag(), id_manager::id_traits::min, id_manager::id_traits::max)) { - if (g_map.find(raw_id) != g_map.end()) continue; + try + { + // Get object, write it + place->second = provider(); + + // Update ID storage if available + if (const u32* id = id_manager::id_storage::get(static_cast(place->second.get()))) + { + *const_cast(id) = place->first; + } - g_tls_last_id = id_traits::out_id(raw_id); - - std::shared_ptr ptr = get_ptr(); - - g_map.emplace(raw_id, id_data_t(ptr)); - - if (raw_id < 0x80000000) g_last_raw_id = raw_id; - - return ptr; + return &*g_map[get_type()].emplace(*place).first; + } + catch (...) + { + deallocate_id(get_tag(), place->first); + throw; + } } return nullptr; } - // Add a new ID of specified type with specified constructor arguments (returns object or nullptr) - template - std::enable_if_t::value, std::shared_ptr> make_ptr(Args&&... args) + // Remove ID and return object + static std::shared_ptr delete_id(u32 type, u32 tag, u32 id) { - if (auto ptr = add(WRAP_EXPR(std::make_shared(std::forward(args)...)))) + std::lock_guard lock(g_mutex); + + auto&& ptr = deallocate_id(tag, id); + + g_map[type].erase(id); + + return ptr; + } + +public: + // Initialize object manager + static void init() + { + g_map.resize(get_types().size(), {}); + g_id.resize(get_types().size(), 0); + } + + // Remove all objects + static void clear() + { + // Call recorded finalization functions for all IDs + for (std::size_t i = 0; i < g_map.size(); i++) { - id_aux_initialize(ptr.get()); - return ptr; + for (auto& id : g_map[i]) + { + get_types()[i].on_stop(id.second.get()); + } + + g_map[i].clear(); + g_id[i] = 0; + } + } + + // Add a new ID of specified type with specified constructor arguments (returns object or nullptr) + template + static std::enable_if_t::value, std::shared_ptr> make_ptr(Args&&... args) + { + if (auto pair = create_id(WRAP_EXPR(std::make_shared(std::forward(args)...)))) + { + id_manager::on_init::func(static_cast(pair->second.get())); + return{ pair->second, static_cast(pair->second.get()) }; } return nullptr; } // Add a new ID of specified type with specified constructor arguments (returns id) - template - std::enable_if_t::value, u32> make(Args&&... args) + template + static std::enable_if_t::value, u32> make(Args&&... args) { - if (auto ptr = add(WRAP_EXPR(std::make_shared(std::forward(args)...)))) + if (auto pair = create_id(WRAP_EXPR(std::make_shared(std::forward(args)...)))) { - id_aux_initialize(ptr.get()); - return get_last_id(); + id_manager::on_init::func(static_cast(pair->second.get())); + return pair->first; } throw EXCEPTION("Out of IDs ('%s')", typeid(T).name()); @@ -173,93 +316,118 @@ namespace idm // Add a new ID for an existing object provided (returns new id) template - u32 import(const std::shared_ptr& ptr) + static u32 import_existing(const std::shared_ptr& ptr) { - static const auto size = sizeof(T); // forbid forward declarations - - if (add(WRAP_EXPR(ptr))) + if (auto pair = create_id(WRAP_EXPR(ptr))) { - id_aux_initialize(ptr.get()); - return get_last_id(); + id_manager::on_init::func(static_cast(pair->second.get())); + return pair->first; } throw EXCEPTION("Out of IDs ('%s')", typeid(T).name()); } - // Internal - std::shared_ptr get(u32 in_id, id_type_index_t type); - - // Get ID of specified type - template - std::shared_ptr get(u32 id) + // Add a new ID for an object returned by provider() + template> + static std::shared_ptr import(F&& provider) { - return std::static_pointer_cast(get(id_traits::in_id(id), get_id_type_index())); - } - - // Internal - idm::map_t get_all(id_type_index_t type); - - // Get all IDs of specified type T (unsorted) - template - std::vector> get_all() - { - std::vector> result; - - for (auto& id : get_all(get_id_type_index())) + if (auto pair = create_id(std::forward(provider))) { - result.emplace_back(std::static_pointer_cast(id.second.data)); - } - - return result; - } - - std::shared_ptr withdraw(u32 in_id, id_type_index_t type); - - // Remove the ID created with type T - template - bool remove(u32 id) - { - if (auto ptr = withdraw(id_traits::in_id(id), get_id_type_index())) - { - id_aux_finalize(static_cast(ptr.get())); - - return true; - } - - return false; - } - - // Remove the ID created with type T and return it - template - std::shared_ptr withdraw(u32 id) - { - if (auto ptr = std::static_pointer_cast(withdraw(id_traits::in_id(id), get_id_type_index()))) - { - id_aux_finalize(ptr.get()); - - return ptr; + id_manager::on_init::func(static_cast(pair->second.get())); + return { pair->second, static_cast(pair->second.get()) }; } return nullptr; } - u32 get_count(id_type_index_t type); + // Check whether ID exists + template + static bool check(u32 id) + { + reader_lock lock(g_mutex); + + return g_map[get_type()].count(id) != 0; + } + + // Get ID + template + static std::shared_ptr get(u32 id) + { + reader_lock lock(g_mutex); + + const auto found = g_map[get_type()].find(id); + + if (found == g_map[get_type()].end()) + { + return nullptr; + } + + return{ found->second, static_cast(found->second.get()) }; + } + + // Get all IDs (unsorted) + template + static std::vector> get_all() + { + reader_lock lock(g_mutex); + + std::vector> result; + + for (auto& id : g_map[get_type()]) + { + result.emplace_back(id.second, static_cast(id.second.get())); + } + + return result; + } + + // Remove the ID + template + static bool remove(u32 id) + { + auto&& ptr = delete_id(get_type(), get_tag(), id); + + if (ptr) + { + id_manager::on_stop::func(static_cast(ptr.get())); + } + + return ptr.operator bool(); + } + + // Remove the ID and return it + template + static std::shared_ptr withdraw(u32 id) + { + auto&& ptr = delete_id(get_type(), get_tag(), id); + + if (ptr) + { + id_manager::on_stop::func(static_cast(ptr.get())); + } + + return{ ptr, static_cast(ptr.get()) }; + } template - u32 get_count() + static u32 get_count() { - return get_count(get_id_type_index()); + reader_lock lock(g_mutex); + + return ::size32(g_map[get_type()]); } // Get sorted list of all IDs of specified type template - std::set get_set() + static std::set get_set() { + reader_lock lock(g_mutex); + std::set result; - for (auto& id : get_all(get_id_type_index())) + for (auto& id : g_map[get_type()]) { - result.emplace(id_traits::out_id(id.first)); + result.emplace(id.first); } return result; @@ -267,188 +435,234 @@ namespace idm // Get sorted map (ID value -> ID data) of all IDs of specified type template - std::map> get_map() + static std::map> get_map() { + reader_lock lock(g_mutex); + std::map> result; - for (auto& id : get_all(get_id_type_index())) + for (auto& id : g_map[get_type()]) { - result[id_traits::out_id(id.first)] = std::static_pointer_cast(id.second.data); + result[id.first] = { id.second, static_cast(id.second.get()) }; } return result; } -} +}; -// Fixed Object Manager -// allows to manage shared objects of any specified type, but only one object per type; -// object are deleted when the emulation is stopped -namespace fxm +// Object manager for emulated process. One unique object per type, or zero. +class fxm { - // Custom hasher for aligned pointer values - struct hash_t final + // Type Index -> Object. Use global since only one process is supported atm. + static std::vector> g_map; + + static shared_mutex g_mutex; + + static inline const auto& get_types() { - std::size_t operator()(id_type_index_t value) const - { - return reinterpret_cast(value) >> 3; - } - }; + return id_manager::typeinfo::get(); + } - using map_t = std::unordered_map, hash_t>; - - // Remove all objects - void clear(); - - // Internal (returns old and new pointers) - template - std::pair, std::shared_ptr> add(Ptr&& get_ptr) + template + static inline u32 get_type() { - extern shared_mutex g_mutex; - extern fxm::map_t g_map; + return id_manager::typeinfo::get_index(); + } + static std::shared_ptr remove(u32 type) + { std::lock_guard lock(g_mutex); - auto& item = g_map[get_id_type_index()]; + return std::move(g_map[type]); + } - if (Always || !item) +public: + // Initialize object manager + static void init() + { + g_map.resize(get_types().size(), {}); + } + + // Remove all objects + static void clear() + { + // Call recorded finalization functions for all IDs + for (std::size_t i = 0; i < g_map.size(); i++) { - std::shared_ptr old = std::static_pointer_cast(std::move(item)); - std::shared_ptr ptr = get_ptr(); + if (g_map[i]) + { + get_types()[i].on_stop(g_map[i].get()); + } - // Set new object - item = ptr; - - return{ std::move(old), std::move(ptr) }; - } - else - { - return{ std::static_pointer_cast(item), nullptr }; + g_map[i].reset(); } } // Create the object (returns nullptr if it already exists) - template - std::enable_if_t::value, std::shared_ptr> make(Args&&... args) + template + static std::enable_if_t::value, std::shared_ptr> make(Args&&... args) { - auto pair = add(WRAP_EXPR(std::make_shared(std::forward(args)...))); - - if (pair.second) + std::shared_ptr ptr; { - id_aux_initialize(pair.second.get()); + std::lock_guard lock(g_mutex); + + if (!g_map[get_type()]) + { + ptr = std::make_shared(std::forward(args)...); + + g_map[get_type()] = ptr; + } } - return std::move(pair.second); + if (ptr) + { + id_manager::on_init::func(ptr.get()); + } + + return ptr; } // Create the object unconditionally (old object will be removed if it exists) - template - std::enable_if_t::value, std::shared_ptr> make_always(Args&&... args) + template + static std::enable_if_t::value, std::shared_ptr> make_always(Args&&... args) { - auto pair = add(WRAP_EXPR(std::make_shared(std::forward(args)...))); - - if (pair.first) + std::shared_ptr ptr; + std::shared_ptr old; { - id_aux_finalize(pair.first.get()); + std::lock_guard lock(g_mutex); + + old = std::move(g_map[get_type()]); + ptr = std::make_shared(std::forward(args)...); + + g_map[get_type()] = ptr; } - id_aux_initialize(pair.second.get()); - return std::move(pair.second); + if (old) + { + id_manager::on_stop::func(static_cast(old.get())); + } + + id_manager::on_init::func(ptr.get()); + return ptr; } // Emplace the object returned by provider() and return it if no object exists template - auto import(F&& provider) -> decltype(static_cast>(provider())) + static auto import(F&& provider) -> decltype(static_cast>(provider())) { - static const auto size = sizeof(T); // forbid forward declarations - - auto pair = add(std::forward(provider)); - - if (pair.second) + std::shared_ptr ptr; { - id_aux_initialize(pair.second.get()); + std::lock_guard lock(g_mutex); + + if (!g_map[get_type()]) + { + ptr = provider(); + + g_map[get_type()] = ptr; + } } - return std::move(pair.second); + if (ptr) + { + id_manager::on_init::func(ptr.get()); + } + + return ptr; } // Emplace the object return by provider() (old object will be removed if it exists) template - auto import_always(F&& provider) -> decltype(static_cast>(provider())) + static auto import_always(F&& provider) -> decltype(static_cast>(provider())) { - static const auto size = sizeof(T); // forbid forward declarations - - auto pair = add(std::forward(provider)); - - if (pair.first) + std::shared_ptr ptr; + std::shared_ptr old; { - id_aux_finalize(pair.first.get()); + std::lock_guard lock(g_mutex); + + old = std::move(g_map[get_type()]); + ptr = provider(); + + g_map[get_type()] = ptr; } - id_aux_initialize(pair.second.get()); - return std::move(pair.second); + if (old) + { + id_manager::on_stop::func(static_cast(old.get())); + } + + id_manager::on_init::func(ptr.get()); + return ptr; } // Get the object unconditionally (create an object if it doesn't exist) - template - std::enable_if_t::value, std::shared_ptr> get_always(Args&&... args) + template + static std::enable_if_t::value, std::shared_ptr> get_always(Args&&... args) { - auto pair = add(WRAP_EXPR(std::make_shared(std::forward(args)...))); - - if (pair.second) + std::shared_ptr ptr; { - id_aux_initialize(pair.second.get()); - return std::move(pair.second); + std::lock_guard lock(g_mutex); + + if (auto& value = g_map[get_type()]) + { + return{ value, static_cast(value.get()) }; + } + else + { + ptr = std::make_shared(std::forward(args)...); + + g_map[get_type()] = ptr; + } } - return std::move(pair.first); + id_manager::on_init::func(ptr.get()); + return ptr; } - // Internal - bool check(id_type_index_t type); - // Check whether the object exists template - bool check() + static bool check() { - return check(get_id_type_index()); - } + reader_lock lock(g_mutex); - // Internal - std::shared_ptr get(id_type_index_t type); + return g_map[get_type()].operator bool(); + } // Get the object (returns nullptr if it doesn't exist) template - std::shared_ptr get() + static std::shared_ptr get() { - return std::static_pointer_cast(get(get_id_type_index())); - } + reader_lock lock(g_mutex); - // Internal - std::shared_ptr withdraw(id_type_index_t type); + auto& ptr = g_map[get_type()]; + + return{ ptr, static_cast(ptr.get()) }; + } // Delete the object template - bool remove() + static bool remove() { - if (auto ptr = withdraw(get_id_type_index())) + auto&& ptr = remove(get_type()); + + if (ptr) { - id_aux_finalize(static_cast(ptr.get())); - return true; + id_manager::on_stop::func(static_cast(ptr.get())); } - return false; + return ptr.operator bool(); } // Delete the object and return it template - std::shared_ptr withdraw() + static std::shared_ptr withdraw() { - if (auto ptr = std::static_pointer_cast(withdraw(get_id_type_index()))) + auto&& ptr = remove(get_type()); + + if (ptr) { - id_aux_finalize(ptr.get()); - return ptr; + id_manager::on_stop::func(static_cast(ptr.get())); } - return nullptr; + return{ ptr, static_cast(ptr.get()) }; } -} +}; diff --git a/rpcs3/Emu/Io/Keyboard.cpp b/rpcs3/Emu/Io/Keyboard.cpp deleted file mode 100644 index 052cb2d843..0000000000 --- a/rpcs3/Emu/Io/Keyboard.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "stdafx.h" -#include "Emu/System.h" - -#include "Keyboard.h" - -void KeyboardManager::Init(u32 max_connect) -{ - m_keyboard_handler = Emu.GetCallbacks().get_kb_handler(); - m_keyboard_handler->Init(max_connect); -} - -void KeyboardManager::Close() -{ - m_keyboard_handler.reset(); -} diff --git a/rpcs3/Emu/Io/Keyboard.h b/rpcs3/Emu/Io/Keyboard.h deleted file mode 100644 index c61916dc3b..0000000000 --- a/rpcs3/Emu/Io/Keyboard.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include "KeyboardHandler.h" - -class KeyboardManager -{ - std::unique_ptr m_keyboard_handler; - -public: - void Init(u32 max_connect); - void Close(); - - std::vector& GetKeyboards() { return m_keyboard_handler->GetKeyboards(); } - KbInfo& GetInfo() { return m_keyboard_handler->GetInfo(); } - std::vector& GetButtons(const u32 keyboard) { return m_keyboard_handler->GetButtons(keyboard); } - KbData& GetData(const u32 keyboard) { return m_keyboard_handler->GetData(keyboard); } - KbConfig& GetConfig(const u32 keyboard) { return m_keyboard_handler->GetConfig(keyboard); } - - bool IsInited() const { return m_keyboard_handler.operator bool(); } -}; diff --git a/rpcs3/Emu/Io/KeyboardHandler.h b/rpcs3/Emu/Io/KeyboardHandler.h index 04d143dd01..06065a5bed 100644 --- a/rpcs3/Emu/Io/KeyboardHandler.h +++ b/rpcs3/Emu/Io/KeyboardHandler.h @@ -1,5 +1,7 @@ #pragma once +// TODO: HLE info (constants, structs, etc.) should not be available here + extern u16 cellKbCnvRawCode(u32 arrange, u32 mkey, u32 led, u16 rawcode); // (TODO: Can it be problematic to place SysCalls in middle of nowhere?) enum KbPortStatus @@ -263,8 +265,7 @@ protected: std::vector m_keyboards; public: - virtual void Init(const u32 max_connect)=0; - virtual void Close()=0; + virtual void Init(const u32 max_connect) = 0; virtual ~KeyboardHandlerBase() = default; void Key(const u32 code, bool pressed) diff --git a/rpcs3/Emu/Io/Mouse.cpp b/rpcs3/Emu/Io/Mouse.cpp deleted file mode 100644 index e07534e3c8..0000000000 --- a/rpcs3/Emu/Io/Mouse.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "stdafx.h" -#include "Emu/System.h" - -#include "Mouse.h" - -void MouseManager::Init(u32 max_connect) -{ - m_mouse_handler = Emu.GetCallbacks().get_mouse_handler(); - m_mouse_handler->Init(max_connect); -} - -void MouseManager::Close() -{ - m_mouse_handler.reset(); -} diff --git a/rpcs3/Emu/Io/Mouse.h b/rpcs3/Emu/Io/Mouse.h deleted file mode 100644 index 98d86185c4..0000000000 --- a/rpcs3/Emu/Io/Mouse.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include "MouseHandler.h" - -class MouseManager -{ - std::unique_ptr m_mouse_handler; - -public: - void Init(u32 max_connect); - void Close(); - - std::vector& GetMice() { return m_mouse_handler->GetMice(); } - MouseInfo& GetInfo() { return m_mouse_handler->GetInfo(); } - MouseData& GetData(const u32 mouse) { return m_mouse_handler->GetData(mouse); } - MouseRawData& GetRawData(const u32 mouse) { return m_mouse_handler->GetRawData(mouse); } - - bool IsInited() const { return m_mouse_handler.operator bool(); } -}; diff --git a/rpcs3/Emu/Io/MouseHandler.h b/rpcs3/Emu/Io/MouseHandler.h index 7c472c9d5e..8d82d33aa8 100644 --- a/rpcs3/Emu/Io/MouseHandler.h +++ b/rpcs3/Emu/Io/MouseHandler.h @@ -1,5 +1,7 @@ #pragma once +// TODO: HLE info (constants, structs, etc.) should not be available here + enum MousePortStatus { CELL_MOUSE_STATUS_DISCONNECTED = 0x00000000, @@ -104,8 +106,7 @@ protected: std::vector m_mice; public: - virtual void Init(const u32 max_connect)=0; - virtual void Close()=0; + virtual void Init(const u32 max_connect) = 0; virtual ~MouseHandlerBase() = default; void Button(u8 button, bool pressed) diff --git a/rpcs3/Emu/Io/Null/NullKeyboardHandler.h b/rpcs3/Emu/Io/Null/NullKeyboardHandler.h index 78d25be2b3..e26688e042 100644 --- a/rpcs3/Emu/Io/Null/NullKeyboardHandler.h +++ b/rpcs3/Emu/Io/Null/NullKeyboardHandler.h @@ -5,11 +5,7 @@ class NullKeyboardHandler final : public KeyboardHandlerBase { public: - NullKeyboardHandler() - { - } - - virtual void Init(const u32 max_connect) + void Init(const u32 max_connect) override { memset(&m_info, 0, sizeof(KbInfo)); m_info.max_connect = max_connect; @@ -19,10 +15,4 @@ public: m_keyboards.emplace_back(Keyboard()); } } - - virtual void Close() - { - memset(&m_info, 0, sizeof(KbInfo)); - m_keyboards.clear(); - } -}; \ No newline at end of file +}; diff --git a/rpcs3/Emu/Io/Null/NullMouseHandler.h b/rpcs3/Emu/Io/Null/NullMouseHandler.h index 883bca01ef..4be6fb8445 100644 --- a/rpcs3/Emu/Io/Null/NullMouseHandler.h +++ b/rpcs3/Emu/Io/Null/NullMouseHandler.h @@ -5,20 +5,10 @@ class NullMouseHandler final : public MouseHandlerBase { public: - NullMouseHandler() - { - } - - virtual void Init(const u32 max_connect) + void Init(const u32 max_connect) override { memset(&m_info, 0, sizeof(MouseInfo)); m_info.max_connect = max_connect; m_mice.clear(); } - - virtual void Close() - { - memset(&m_info, 0, sizeof(MouseInfo)); - m_mice.clear(); - } -}; \ No newline at end of file +}; diff --git a/rpcs3/Emu/Io/Null/NullPadHandler.h b/rpcs3/Emu/Io/Null/NullPadHandler.h index d770bf4a00..2f72cf7607 100644 --- a/rpcs3/Emu/Io/Null/NullPadHandler.h +++ b/rpcs3/Emu/Io/Null/NullPadHandler.h @@ -5,20 +5,10 @@ class NullPadHandler final : public PadHandlerBase { public: - NullPadHandler() - { - } - - virtual void Init(const u32 max_connect) + void Init(const u32 max_connect) override { memset(&m_info, 0, sizeof(PadInfo)); m_info.max_connect = max_connect; m_pads.clear(); } - - virtual void Close() - { - memset(&m_info, 0, sizeof(PadInfo)); - m_pads.clear(); - } -}; \ No newline at end of file +}; diff --git a/rpcs3/Emu/Io/Pad.cpp b/rpcs3/Emu/Io/Pad.cpp deleted file mode 100644 index 5c3328337d..0000000000 --- a/rpcs3/Emu/Io/Pad.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "stdafx.h" -#include "Emu/System.h" - -#include "Pad.h" - -void PadManager::Init(u32 max_connect) -{ - m_pad_handler = Emu.GetCallbacks().get_pad_handler(); - m_pad_handler->Init(max_connect); -} - -void PadManager::Close() -{ - m_pad_handler.reset(); -} diff --git a/rpcs3/Emu/Io/Pad.h b/rpcs3/Emu/Io/Pad.h deleted file mode 100644 index 8bbb3a01f3..0000000000 --- a/rpcs3/Emu/Io/Pad.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include "PadHandler.h" - -class PadManager -{ - std::unique_ptr m_pad_handler; - -public: - void Init(u32 max_connect); - void Close(); - - std::vector& GetPads() { return m_pad_handler->GetPads(); } - PadInfo& GetInfo() { return m_pad_handler->GetInfo(); } - std::vector