From f8719c12308d61fecb426e23326f6049d1feb008 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Thu, 28 Jul 2016 00:43:22 +0300 Subject: [PATCH] PPUThread refactoring `CallbackManager` removed, added _gcm_intr_thread for cellGcmSys `PPUThread` renamed to `ppu_thread`, inheritance allowed Added lightweight command queue for `ppu_thread` Implemented call stack dump for PPU `get_current_thread_mutex` removed `thread_ctrl::spawn`: minor initialization fix `thread_ctrl::wait_for` added `named_thread`: some methods added `cpu_thread::run` added Some bugs fixes, including SPU channels --- Utilities/Atomic.h | 57 +- Utilities/SleepQueue.h | 2 +- Utilities/Thread.cpp | 7 +- Utilities/Thread.h | 79 +- rpcs3/Emu/CPU/CPUThread.cpp | 29 +- rpcs3/Emu/CPU/CPUThread.h | 53 +- rpcs3/Emu/Cell/Modules/cellAdec.cpp | 740 +++--- rpcs3/Emu/Cell/Modules/cellAdec.h | 57 +- rpcs3/Emu/Cell/Modules/cellDmux.cpp | 1138 +++++---- rpcs3/Emu/Cell/Modules/cellDmux.h | 193 -- rpcs3/Emu/Cell/Modules/cellFont.cpp | 4 +- rpcs3/Emu/Cell/Modules/cellFs.cpp | 97 +- rpcs3/Emu/Cell/Modules/cellGame.cpp | 6 +- rpcs3/Emu/Cell/Modules/cellGcmSys.cpp | 10 +- rpcs3/Emu/Cell/Modules/cellL10n.cpp | 1 + rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp | 4 +- rpcs3/Emu/Cell/Modules/cellMusic.cpp | 3 +- rpcs3/Emu/Cell/Modules/cellNetCtl.cpp | 6 +- rpcs3/Emu/Cell/Modules/cellPngDec.cpp | 26 +- rpcs3/Emu/Cell/Modules/cellResc.cpp | 2 +- rpcs3/Emu/Cell/Modules/cellRudp.cpp | 8 +- rpcs3/Emu/Cell/Modules/cellSail.cpp | 46 +- rpcs3/Emu/Cell/Modules/cellSaveData.cpp | 71 +- rpcs3/Emu/Cell/Modules/cellSpurs.cpp | 222 +- rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp | 8 +- rpcs3/Emu/Cell/Modules/cellSync.cpp | 20 +- rpcs3/Emu/Cell/Modules/cellSysutil.cpp | 69 +- rpcs3/Emu/Cell/Modules/cellSysutil.h | 3 +- rpcs3/Emu/Cell/Modules/cellVdec.cpp | 855 +++---- rpcs3/Emu/Cell/Modules/cellVdec.h | 80 +- rpcs3/Emu/Cell/Modules/libmixer.cpp | 131 +- rpcs3/Emu/Cell/Modules/libmixer.h | 36 - rpcs3/Emu/Cell/Modules/sceNp2.cpp | 2 +- rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp | 2 +- rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp | 8 +- rpcs3/Emu/Cell/Modules/sysPrxForUser.h | 18 +- rpcs3/Emu/Cell/Modules/sys_libc_.cpp | 6 +- rpcs3/Emu/Cell/Modules/sys_lwcond_.cpp | 8 +- rpcs3/Emu/Cell/Modules/sys_lwmutex_.cpp | 8 +- rpcs3/Emu/Cell/Modules/sys_net.cpp | 1 + rpcs3/Emu/Cell/Modules/sys_ppu_thread_.cpp | 12 +- rpcs3/Emu/Cell/Modules/sys_spu_.cpp | 10 +- rpcs3/Emu/Cell/PPUAnalyser.cpp | 8 +- rpcs3/Emu/Cell/PPUCallback.cpp | 103 - rpcs3/Emu/Cell/PPUCallback.h | 80 +- rpcs3/Emu/Cell/PPUFunction.cpp | 4 +- rpcs3/Emu/Cell/PPUFunction.h | 60 +- rpcs3/Emu/Cell/PPUInterpreter.cpp | 2492 ++++++++++---------- rpcs3/Emu/Cell/PPUInterpreter.h | 764 +++--- rpcs3/Emu/Cell/PPUModule.cpp | 153 +- rpcs3/Emu/Cell/PPUModule.h | 2 +- rpcs3/Emu/Cell/PPUThread.cpp | 380 +-- rpcs3/Emu/Cell/PPUThread.h | 221 +- rpcs3/Emu/Cell/PPUTranslator.cpp | 12 +- rpcs3/Emu/Cell/PPUTranslator.h | 14 +- rpcs3/Emu/Cell/RawSPUThread.cpp | 16 +- rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp | 4 +- rpcs3/Emu/Cell/SPUThread.cpp | 37 +- rpcs3/Emu/Cell/SPUThread.h | 18 +- rpcs3/Emu/Cell/lv2/lv2.cpp | 8 +- rpcs3/Emu/Cell/lv2/sys_cond.cpp | 8 +- rpcs3/Emu/Cell/lv2/sys_cond.h | 4 +- rpcs3/Emu/Cell/lv2/sys_event.cpp | 24 +- rpcs3/Emu/Cell/lv2/sys_event.h | 4 +- rpcs3/Emu/Cell/lv2/sys_event_flag.cpp | 28 +- rpcs3/Emu/Cell/lv2/sys_event_flag.h | 4 +- rpcs3/Emu/Cell/lv2/sys_interrupt.cpp | 84 +- rpcs3/Emu/Cell/lv2/sys_interrupt.h | 18 +- rpcs3/Emu/Cell/lv2/sys_lwcond.cpp | 10 +- rpcs3/Emu/Cell/lv2/sys_lwcond.h | 4 +- rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp | 4 +- rpcs3/Emu/Cell/lv2/sys_lwmutex.h | 4 +- rpcs3/Emu/Cell/lv2/sys_mutex.cpp | 14 +- rpcs3/Emu/Cell/lv2/sys_mutex.h | 8 +- rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp | 100 +- rpcs3/Emu/Cell/lv2/sys_ppu_thread.h | 10 +- rpcs3/Emu/Cell/lv2/sys_process.cpp | 2 +- rpcs3/Emu/Cell/lv2/sys_rwlock.cpp | 18 +- rpcs3/Emu/Cell/lv2/sys_rwlock.h | 10 +- rpcs3/Emu/Cell/lv2/sys_semaphore.cpp | 4 +- rpcs3/Emu/Cell/lv2/sys_semaphore.h | 4 +- rpcs3/Emu/Cell/lv2/sys_spu.cpp | 9 +- rpcs3/Emu/Cell/lv2/sys_spu.h | 4 +- rpcs3/Emu/Cell/lv2/sys_timer.cpp | 13 +- rpcs3/Emu/Memory/vm.cpp | 20 +- rpcs3/Emu/Memory/vm_ptr.h | 4 +- rpcs3/Emu/PSP2/ARMv7Thread.cpp | 2 +- rpcs3/Emu/PSP2/Modules/sceLibKernel.cpp | 25 +- rpcs3/Emu/RSX/RSXThread.cpp | 11 +- rpcs3/Emu/RSX/RSXThread.h | 2 + rpcs3/Emu/RSX/rsx_methods.cpp | 18 +- rpcs3/Emu/System.cpp | 23 +- rpcs3/Emu/System.h | 9 - rpcs3/Gui/InterpreterDisAsm.cpp | 4 +- rpcs3/Gui/KernelExplorer.cpp | 4 +- rpcs3/Gui/MainFrame.cpp | 6 +- rpcs3/Gui/RegisterEditor.cpp | 30 +- rpcs3/emucore.vcxproj | 2 +- rpcs3/emucore.vcxproj.filters | 6 +- 99 files changed, 4480 insertions(+), 4592 deletions(-) delete mode 100644 rpcs3/Emu/Cell/PPUCallback.cpp diff --git a/Utilities/Atomic.h b/Utilities/Atomic.h index 4022164be4..2b03bfae0e 100644 --- a/Utilities/Atomic.h +++ b/Utilities/Atomic.h @@ -143,22 +143,34 @@ struct atomic_storage return atomic_storage::sub_fetch(dest, 1); } + static inline bool test_and_set(T& dest, T mask) + { + return (atomic_storage::fetch_or(dest, mask) & mask) != 0; + } + + static inline bool test_and_reset(T& dest, T mask) + { + return (atomic_storage::fetch_and(dest, ~mask) & mask) != 0; + } + + static inline bool test_and_complement(T& dest, T mask) + { + return (atomic_storage::fetch_xor(dest, mask) & mask) != 0; + } + static inline bool bts(T& dest, uint bit) { - const T mask = static_cast(1) << bit; - return (atomic_storage::fetch_or(dest, mask) & mask) != 0; + return atomic_storage::test_and_set(dest, static_cast(1) << bit); } static inline bool btr(T& dest, uint bit) { - const T mask = static_cast(1) << bit; - return (atomic_storage::fetch_and(dest, ~mask) & mask) != 0; + return atomic_storage::test_and_reset(dest, static_cast(1) << bit); } static inline bool btc(T& dest, uint bit) { - const T mask = static_cast(1) << bit; - return (atomic_storage::fetch_xor(dest, mask) & mask) != 0; + return atomic_storage::test_and_complement(dest, static_cast(1) << bit); } }; @@ -637,14 +649,9 @@ struct atomic_test_and_set 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; - } - - static constexpr auto fetch_op = &op; - static constexpr auto op_fetch = &op; - static constexpr auto atomic_op = &op; + static constexpr auto fetch_op = &atomic_storage::test_and_set; + static constexpr auto op_fetch = &atomic_storage::test_and_set; + static constexpr auto atomic_op = &atomic_storage::test_and_set; }; template @@ -659,14 +666,9 @@ struct atomic_test_and_reset 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; + static constexpr auto fetch_op = &atomic_storage::test_and_reset; + static constexpr auto op_fetch = &atomic_storage::test_and_reset; + static constexpr auto atomic_op = &atomic_storage::test_and_reset; }; template @@ -681,14 +683,9 @@ struct atomic_test_and_complement 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; + static constexpr auto fetch_op = &atomic_storage::test_and_complement; + static constexpr auto op_fetch = &atomic_storage::test_and_complement; + static constexpr auto atomic_op = &atomic_storage::test_and_complement; }; // Atomic type with lock-free and standard layout guarantees (and appropriate limitations) diff --git a/Utilities/SleepQueue.h b/Utilities/SleepQueue.h index aa5120bb78..e11c5417df 100644 --- a/Utilities/SleepQueue.h +++ b/Utilities/SleepQueue.h @@ -12,7 +12,7 @@ template using sleep_queue = std::deque; // 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 +template class sleep_entry final { sleep_queue& m_queue; diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index 95e2282f51..2bcde23bd7 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -1830,11 +1830,6 @@ struct thread_ctrl::internal thread_local thread_ctrl::internal* g_tls_internal = nullptr; -extern std::mutex& get_current_thread_mutex() -{ - return g_tls_internal->mutex; -} - extern std::condition_variable& get_current_thread_cv() { return g_tls_internal->cond; @@ -2244,7 +2239,7 @@ void named_thread::start_thread(const std::shared_ptr& _this) ENSURES(_this.get() == this); // Run thread - m_thread = thread_ctrl::spawn(get_name(), [this, _this]() + thread_ctrl::spawn(m_thread, get_name(), [this, _this]() { try { diff --git a/Utilities/Thread.h b/Utilities/Thread.h index fecf418bc6..ffa3ef63bb 100644 --- a/Utilities/Thread.h +++ b/Utilities/Thread.h @@ -233,9 +233,12 @@ public: // Wait until pred(). Abortable, may throw. Thread must be locked. // Timeout in microseconds (zero means infinite). template - static inline auto wait(u64 useconds, F&& pred) + static inline auto wait_for(u64 useconds, F&& pred) { - g_tls_this_thread->wait_start(useconds); + if (useconds) + { + g_tls_this_thread->wait_start(useconds); + } while (true) { @@ -252,6 +255,26 @@ public: } } + // Wait once. Abortable, may throw. Thread must be locked. + // Timeout in microseconds (zero means infinite). + static inline bool wait_for(u64 useconds = 0) + { + if (useconds) + { + g_tls_this_thread->wait_start(useconds); + } + + g_tls_this_thread->test(); + + if (!g_tls_this_thread->wait_wait(useconds) && useconds) + { + return false; + } + + g_tls_this_thread->test(); + return true; + } + // Wait until pred(). Abortable, may throw. Thread must be locked. template static inline auto wait(F&& pred) @@ -269,7 +292,7 @@ public: } } - // Wait once. Thread must be locked. + // Wait once. Abortable, may throw. Thread must be locked. static inline void wait() { g_tls_this_thread->test(); @@ -277,7 +300,7 @@ public: g_tls_this_thread->test(); } - // Wait unconditionally until aborted. Thread must be locked. + // Wait eternally. Abortable, may throw. Thread must be locked. [[noreturn]] static inline void eternalize() { while (true) @@ -302,13 +325,20 @@ public: // Named thread factory template - static inline std::shared_ptr spawn(N&& name, F&& func) + static inline void spawn(N&& name, F&& func) { - auto ctrl = std::make_shared(std::forward(name)); + auto&& out = std::make_shared(std::forward(name)); - thread_ctrl::start(ctrl, std::forward(func)); + thread_ctrl::start(out, std::forward(func)); + } - return ctrl; + // Named thread factory + template + static inline void spawn(std::shared_ptr& out, N&& name, F&& func) + { + out = std::make_shared(std::forward(name)); + + thread_ctrl::start(out, std::forward(func)); } }; @@ -356,6 +386,31 @@ public: { return m_thread.get(); } + + void join() const + { + return m_thread->join(); + } + + void lock() const + { + return m_thread->lock(); + } + + void unlock() const + { + return m_thread->unlock(); + } + + void lock_notify() const + { + return m_thread->lock_notify(); + } + + void notify() const + { + return m_thread->notify(); + } }; // Simple thread mutex locker @@ -429,8 +484,8 @@ class scope_thread final public: template scope_thread(N&& name, F&& func) - : m_thread(thread_ctrl::spawn(std::forward(name), std::forward(func))) { + thread_ctrl::spawn(m_thread, std::forward(name), std::forward(func)); } // Deleted copy/move constructors + copy/move operators @@ -441,4 +496,10 @@ public: { m_thread->join(); } + + // Access thread_ctrl + thread_ctrl* operator->() const + { + return m_thread.get(); + } }; diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index 7be23e9849..39dda7a011 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -3,13 +3,9 @@ #include "CPUThread.h" #include -#include thread_local cpu_thread* g_tls_current_cpu_thread = nullptr; -extern std::mutex& get_current_thread_mutex(); -extern std::condition_variable& get_current_thread_cv(); - void cpu_thread::on_task() { state -= cpu_state::exit; @@ -18,7 +14,7 @@ void cpu_thread::on_task() Emu.SendDbgCommand(DID_CREATE_THREAD, this); - std::unique_lock lock(get_current_thread_mutex()); + std::unique_lock lock(*this); // Check thread status while (!(state & cpu_state::exit)) @@ -54,14 +50,14 @@ void cpu_thread::on_task() continue; } - get_current_thread_cv().wait(lock); + thread_ctrl::wait(); } } void cpu_thread::on_stop() { state += cpu_state::exit; - (*this)->lock_notify(); + lock_notify(); } cpu_thread::~cpu_thread() @@ -73,9 +69,9 @@ cpu_thread::cpu_thread(cpu_type type) { } -bool cpu_thread::check_status() +bool cpu_thread::check_state() { - std::unique_lock lock(get_current_thread_mutex(), std::defer_lock); + std::unique_lock lock(*this, std::defer_lock); while (true) { @@ -86,7 +82,7 @@ bool cpu_thread::check_status() return true; } - if (!state.test(cpu_state_pause) && !state.test(cpu_state::interrupt)) + if (!state.test(cpu_state_pause)) { break; } @@ -97,12 +93,7 @@ bool cpu_thread::check_status() continue; } - if (!state.test(cpu_state_pause) && state & cpu_state::interrupt && handle_interrupt()) - { - continue; - } - - get_current_thread_cv().wait(lock); + thread_ctrl::wait(); } const auto state_ = state.load(); @@ -120,3 +111,9 @@ bool cpu_thread::check_status() return false; } + +void cpu_thread::run() +{ + state -= cpu_state::stop; + lock_notify(); +} diff --git a/rpcs3/Emu/CPU/CPUThread.h b/rpcs3/Emu/CPU/CPUThread.h index 3dd21a1aee..9280b0d78c 100644 --- a/rpcs3/Emu/CPU/CPUThread.h +++ b/rpcs3/Emu/CPU/CPUThread.h @@ -3,7 +3,7 @@ #include "../Utilities/Thread.h" #include "../Utilities/BitSet.h" -// CPU Thread Type +// CPU Thread Type (TODO: probably remove, use id and idm to classify threads) enum class cpu_type : u8 { ppu, // PPU Thread @@ -11,7 +11,7 @@ enum class cpu_type : u8 arm, // ARMv7 Thread }; -// CPU Thread State flags +// CPU Thread State flags (TODO: use u32 once cpu_type is removed) enum struct cpu_state : u16 { stop, // Thread not running (HLE, initial state) @@ -19,7 +19,6 @@ enum struct cpu_state : u16 suspend, // Thread paused ret, // Callback return requested signal, // Thread received a signal (HLE) - interrupt, // Thread interrupted dbg_global_pause, // Emulation paused dbg_global_stop, // Emulation stopped @@ -43,9 +42,6 @@ public: cpu_thread(cpu_type type); - // Public recursive sleep state counter - atomic_t sleep_counter{}; - // Public thread state atomic_t> state{ cpu_state::stop }; @@ -53,25 +49,14 @@ public: atomic_t owner{}; // Process thread state, return true if the checker must return - bool check_status(); + bool check_state(); - // Increse sleep counter - void sleep() - { - if (!sleep_counter++) return; //handle_interrupt(); - } + // Run thread + void run(); - // Decrese sleep counter - void awake() - { - if (!--sleep_counter) owner = nullptr; - } - - // Print CPU state - virtual std::string dump() const = 0; - virtual void cpu_init() {} + virtual std::string dump() const = 0; // Print CPU state + virtual void cpu_init() {} // Obsolete, must be removed virtual void cpu_task() = 0; - virtual bool handle_interrupt() { return false; } }; inline cpu_thread* get_current_cpu_thread() noexcept @@ -80,27 +65,3 @@ inline cpu_thread* get_current_cpu_thread() noexcept return g_tls_current_cpu_thread; } - -// Helper for cpu_thread. -// 1) Calls sleep() and locks the thread in the constructor. -// 2) Calls awake() and unlocks the thread in the destructor. -class cpu_thread_lock final -{ - cpu_thread& m_thread; - -public: - cpu_thread_lock(const cpu_thread_lock&) = delete; - - cpu_thread_lock(cpu_thread& thread) - : m_thread(thread) - { - m_thread.sleep(); - m_thread->lock(); - } - - ~cpu_thread_lock() - { - m_thread.awake(); - m_thread->unlock(); - } -}; diff --git a/rpcs3/Emu/Cell/Modules/cellAdec.cpp b/rpcs3/Emu/Cell/Modules/cellAdec.cpp index 6214c8fb41..dc241932fe 100644 --- a/rpcs3/Emu/Cell/Modules/cellAdec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAdec.cpp @@ -3,8 +3,6 @@ #include "Emu/IdManager.h" #include "Emu/Cell/PPUModule.h" -extern std::mutex g_mutex_avcodec_open2; - extern "C" { #include "libavcodec/avcodec.h" @@ -15,97 +13,391 @@ extern "C" #include "cellPamf.h" #include "cellAdec.h" +#include #include +extern std::mutex g_mutex_avcodec_open2; + logs::channel cellAdec("cellAdec", logs::level::notice); -AudioDecoder::AudioDecoder(s32 type, u32 addr, u32 size, vm::ptr func, u32 arg) - : type(type) - , memAddr(addr) - , memSize(size) - , memBias(0) - , cbFunc(func) - , cbArg(arg) - , is_closed(false) - , is_finished(false) - , just_started(false) - , just_finished(false) - , codec(nullptr) - , input_format(nullptr) - , ctx(nullptr) - , fmt(nullptr) +class AudioDecoder : public ppu_thread { - av_register_all(); - avcodec_register_all(); +public: + squeue_t job; + volatile bool is_closed; + volatile bool is_finished; + bool just_started; + bool just_finished; - switch (type) - { - case CELL_ADEC_TYPE_ATRACX: - case CELL_ADEC_TYPE_ATRACX_2CH: - case CELL_ADEC_TYPE_ATRACX_6CH: - case CELL_ADEC_TYPE_ATRACX_8CH: - { - codec = avcodec_find_decoder(AV_CODEC_ID_ATRAC3P); - input_format = av_find_input_format("oma"); - break; - } - case CELL_ADEC_TYPE_MP3: - { - codec = avcodec_find_decoder(AV_CODEC_ID_MP3); - input_format = av_find_input_format("mp3"); - break; - } - default: - { - throw EXCEPTION("Unknown type (0x%x)", type); - } - } - - if (!codec) - { - throw EXCEPTION("avcodec_find_decoder() failed"); - } - if (!input_format) - { - throw EXCEPTION("av_find_input_format() failed"); - } - fmt = avformat_alloc_context(); - if (!fmt) - { - throw EXCEPTION("avformat_alloc_context() failed"); - } - io_buf = (u8*)av_malloc(4096); - fmt->pb = avio_alloc_context(io_buf, 256, 0, this, adecRead, NULL, NULL); - if (!fmt->pb) - { - throw EXCEPTION("avio_alloc_context() failed"); - } -} + AVCodec* codec; + AVInputFormat* input_format; + AVCodecContext* ctx; + AVFormatContext* fmt; + u8* io_buf; -AudioDecoder::~AudioDecoder() -{ - // TODO: check finalization - AdecFrame af; - while (frames.try_pop(af)) + struct AudioReader { - av_frame_unref(af.data); - av_frame_free(&af.data); - } - if (ctx) - { - avcodec_close(ctx); - avformat_close_input(&fmt); - } - if (fmt) - { - if (io_buf) + u32 addr; + u32 size; + bool init; + bool has_ats; + + AudioReader() + : init(false) { - av_free(io_buf); } - if (fmt->pb) av_free(fmt->pb); - avformat_free_context(fmt); + + } reader; + + squeue_t frames; + + const s32 type; + const u32 memAddr; + const u32 memSize; + const vm::ptr cbFunc; + const u32 cbArg; + u32 memBias; + + AdecTask task; + u64 last_pts, first_pts; + + u32 ch_out; + u32 ch_cfg; + u32 frame_size; + u32 sample_rate; + bool use_ats_headers; + + AudioDecoder(s32 type, u32 addr, u32 size, vm::ptr func, u32 arg) + : ppu_thread("HLE Audio Decoder") + , type(type) + , memAddr(addr) + , memSize(size) + , memBias(0) + , cbFunc(func) + , cbArg(arg) + , is_closed(false) + , is_finished(false) + , just_started(false) + , just_finished(false) + , codec(nullptr) + , input_format(nullptr) + , ctx(nullptr) + , fmt(nullptr) + { + av_register_all(); + avcodec_register_all(); + + switch (type) + { + case CELL_ADEC_TYPE_ATRACX: + case CELL_ADEC_TYPE_ATRACX_2CH: + case CELL_ADEC_TYPE_ATRACX_6CH: + case CELL_ADEC_TYPE_ATRACX_8CH: + { + codec = avcodec_find_decoder(AV_CODEC_ID_ATRAC3P); + input_format = av_find_input_format("oma"); + break; + } + case CELL_ADEC_TYPE_MP3: + { + codec = avcodec_find_decoder(AV_CODEC_ID_MP3); + input_format = av_find_input_format("mp3"); + break; + } + default: + { + throw EXCEPTION("Unknown type (0x%x)", type); + } + } + + if (!codec) + { + throw EXCEPTION("avcodec_find_decoder() failed"); + } + if (!input_format) + { + throw EXCEPTION("av_find_input_format() failed"); + } + fmt = avformat_alloc_context(); + if (!fmt) + { + throw EXCEPTION("avformat_alloc_context() failed"); + } + io_buf = (u8*)av_malloc(4096); + fmt->pb = avio_alloc_context(io_buf, 256, 0, this, adecRead, NULL, NULL); + if (!fmt->pb) + { + throw EXCEPTION("avio_alloc_context() failed"); + } } -} + + ~AudioDecoder() + { + // TODO: check finalization + AdecFrame af; + while (frames.try_pop(af)) + { + av_frame_unref(af.data); + av_frame_free(&af.data); + } + if (ctx) + { + avcodec_close(ctx); + avformat_close_input(&fmt); + } + if (fmt) + { + if (io_buf) + { + av_free(io_buf); + } + if (fmt->pb) av_free(fmt->pb); + avformat_free_context(fmt); + } + } + + virtual void cpu_task() override + { + while (true) + { + if (Emu.IsStopped() || is_closed) + { + break; + } + + if (!job.pop(task, &is_closed)) + { + break; + } + + switch (task.type) + { + case adecStartSeq: + { + // TODO: reset data + cellAdec.warning("adecStartSeq:"); + + reader.addr = 0; + reader.size = 0; + reader.init = false; + reader.has_ats = false; + just_started = true; + + if (adecIsAtracX(type)) + { + ch_cfg = task.at3p.channel_config; + ch_out = task.at3p.channels; + frame_size = task.at3p.frame_size; + sample_rate = task.at3p.sample_rate; + use_ats_headers = task.at3p.ats_header == 1; + } + break; + } + + case adecEndSeq: + { + // TODO: finalize + cellAdec.warning("adecEndSeq:"); + cbFunc(*this, id, CELL_ADEC_MSG_TYPE_SEQDONE, CELL_OK, cbArg); + + just_finished = true; + break; + } + + case adecDecodeAu: + { + int err = 0; + + reader.addr = task.au.addr; + reader.size = task.au.size; + reader.has_ats = use_ats_headers; + //LOG_NOTICE(HLE, "Audio AU: size = 0x%x, pts = 0x%llx", task.au.size, task.au.pts); + + if (just_started) + { + first_pts = task.au.pts; + last_pts = task.au.pts; + if (adecIsAtracX(type)) last_pts -= 0x10000; // hack + } + + struct AVPacketHolder : AVPacket + { + AVPacketHolder(u32 size) + { + av_init_packet(this); + + if (size) + { + data = (u8*)av_calloc(1, size + FF_INPUT_BUFFER_PADDING_SIZE); + this->size = size + FF_INPUT_BUFFER_PADDING_SIZE; + } + else + { + data = NULL; + size = 0; + } + } + + ~AVPacketHolder() + { + av_free(data); + } + + } au(0); + + if (just_started && just_finished) + { + avcodec_flush_buffers(ctx); + + reader.init = true; // wrong + just_finished = false; + just_started = false; + } + else if (just_started) // deferred initialization + { + AVDictionary* opts = nullptr; + av_dict_set(&opts, "probesize", "96", 0); + err = avformat_open_input(&fmt, NULL, input_format, &opts); + if (err || opts) + { + throw EXCEPTION("avformat_open_input() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0); + } + //err = avformat_find_stream_info(fmt, NULL); + //if (err || !fmt->nb_streams) + //{ + // ADEC_ERROR("adecDecodeAu: avformat_find_stream_info() failed (err=0x%x, nb_streams=%d)", err, fmt->nb_streams); + //} + if (!avformat_new_stream(fmt, codec)) + { + throw EXCEPTION("avformat_new_stream() failed"); + } + ctx = fmt->streams[0]->codec; // TODO: check data + + opts = nullptr; + av_dict_set(&opts, "refcounted_frames", "1", 0); + { + std::lock_guard lock(g_mutex_avcodec_open2); + // not multithread-safe (???) + err = avcodec_open2(ctx, codec, &opts); + } + if (err || opts) + { + throw EXCEPTION("avcodec_open2() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0); + } + just_started = false; + } + + bool last_frame = false; + + while (true) + { + if (Emu.IsStopped() || is_closed) + { + if (Emu.IsStopped()) cellAdec.warning("adecDecodeAu: aborted"); + break; + } + + last_frame = av_read_frame(fmt, &au) < 0; + if (last_frame) + { + //break; + av_free(au.data); + au.data = NULL; + au.size = 0; + } + + struct AdecFrameHolder : AdecFrame + { + AdecFrameHolder() + { + data = av_frame_alloc(); + } + + ~AdecFrameHolder() + { + if (data) + { + av_frame_unref(data); + av_frame_free(&data); + } + } + + } frame; + + if (!frame.data) + { + throw EXCEPTION("av_frame_alloc() failed"); + } + + int got_frame = 0; + + int decode = avcodec_decode_audio4(ctx, frame.data, &got_frame, &au); + + if (decode <= 0) + { + if (decode < 0) + { + cellAdec.error("adecDecodeAu: AU decoding error(0x%x)", decode); + } + if (!got_frame && reader.size == 0) break; + } + + if (got_frame) + { + //u64 ts = av_frame_get_best_effort_timestamp(frame.data); + //if (ts != AV_NOPTS_VALUE) + //{ + // frame.pts = ts/* - first_pts*/; + // last_pts = frame.pts; + //} + last_pts += ((u64)frame.data->nb_samples) * 90000 / frame.data->sample_rate; + frame.pts = last_pts; + + s32 nbps = av_get_bytes_per_sample((AVSampleFormat)frame.data->format); + switch (frame.data->format) + { + case AV_SAMPLE_FMT_FLTP: break; + case AV_SAMPLE_FMT_S16P: break; + default: + { + throw EXCEPTION("Unsupported frame format(%d)", frame.data->format); + } + } + frame.auAddr = task.au.addr; + frame.auSize = task.au.size; + frame.userdata = task.au.userdata; + frame.size = frame.data->nb_samples * frame.data->channels * nbps; + + //LOG_NOTICE(HLE, "got audio frame (pts=0x%llx, nb_samples=%d, ch=%d, sample_rate=%d, nbps=%d)", + //frame.pts, frame.data->nb_samples, frame.data->channels, frame.data->sample_rate, nbps); + + if (frames.push(frame, &is_closed)) + { + frame.data = nullptr; // to prevent destruction + cbFunc(*this, id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, cbArg); + } + } + } + + cbFunc(*this, id, CELL_ADEC_MSG_TYPE_AUDONE, task.au.auInfo_addr, cbArg); + break; + } + + case adecClose: + { + break; + } + + default: + { + throw EXCEPTION("Unknown task(%d)", task.type); + } + } + } + + is_finished = true; + } +}; int adecRead(void* opaque, u8* buf, int buf_size) { @@ -162,16 +454,16 @@ next: buf_size = adec.reader.size; } break; - + case adecDecodeAu: { std::memcpy(buf, vm::base(adec.reader.addr), adec.reader.size); - + buf += adec.reader.size; buf_size -= adec.reader.size; res += adec.reader.size; - adec.cbFunc(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_AUDONE, adec.task.au.auInfo_addr, adec.cbArg); + adec.cbFunc(adec, adec.id, CELL_ADEC_MSG_TYPE_AUDONE, adec.task.au.auInfo_addr, adec.cbArg); adec.job.pop(adec.task); @@ -181,7 +473,7 @@ next: //LOG_NOTICE(HLE, "Audio AU: size = 0x%x, pts = 0x%llx", adec.task.au.size, adec.task.au.pts); } break; - + default: { cellAdec.error("adecRawRead(): unknown task (%d)", task.type); @@ -212,267 +504,6 @@ next: } } -void adecOpen(u32 adec_id) // TODO: call from the constructor -{ - const auto sptr = idm::get(adec_id); - AudioDecoder& adec = *sptr; - - adec.id = adec_id; - - adec.adecCb = idm::make_ptr(fmt::format("Demuxer[0x%x] Thread", adec_id)); - adec.adecCb->prio = 1001; - adec.adecCb->stack_size = 0x10000; - adec.adecCb->custom_task = [sptr](PPUThread& CPU) - { - AudioDecoder& adec = *sptr; - AdecTask& task = adec.task; - - while (true) - { - if (Emu.IsStopped() || adec.is_closed) - { - break; - } - - if (!adec.job.pop(task, &adec.is_closed)) - { - break; - } - - switch (task.type) - { - case adecStartSeq: - { - // TODO: reset data - cellAdec.warning("adecStartSeq:"); - - adec.reader.addr = 0; - adec.reader.size = 0; - adec.reader.init = false; - adec.reader.has_ats = false; - adec.just_started = true; - - if (adecIsAtracX(adec.type)) - { - adec.ch_cfg = task.at3p.channel_config; - adec.ch_out = task.at3p.channels; - adec.frame_size = task.at3p.frame_size; - adec.sample_rate = task.at3p.sample_rate; - adec.use_ats_headers = task.at3p.ats_header == 1; - } - break; - } - - case adecEndSeq: - { - // TODO: finalize - cellAdec.warning("adecEndSeq:"); - adec.cbFunc(CPU, adec.id, CELL_ADEC_MSG_TYPE_SEQDONE, CELL_OK, adec.cbArg); - - adec.just_finished = true; - break; - } - - case adecDecodeAu: - { - int err = 0; - - adec.reader.addr = task.au.addr; - adec.reader.size = task.au.size; - adec.reader.has_ats = adec.use_ats_headers; - //LOG_NOTICE(HLE, "Audio AU: size = 0x%x, pts = 0x%llx", task.au.size, task.au.pts); - - if (adec.just_started) - { - adec.first_pts = task.au.pts; - adec.last_pts = task.au.pts; - if (adecIsAtracX(adec.type)) adec.last_pts -= 0x10000; // hack - } - - struct AVPacketHolder : AVPacket - { - AVPacketHolder(u32 size) - { - av_init_packet(this); - - if (size) - { - data = (u8*)av_calloc(1, size + FF_INPUT_BUFFER_PADDING_SIZE); - this->size = size + FF_INPUT_BUFFER_PADDING_SIZE; - } - else - { - data = NULL; - size = 0; - } - } - - ~AVPacketHolder() - { - av_free(data); - } - - } au(0); - - if (adec.just_started && adec.just_finished) - { - avcodec_flush_buffers(adec.ctx); - - adec.reader.init = true; // wrong - adec.just_finished = false; - adec.just_started = false; - } - else if (adec.just_started) // deferred initialization - { - AVDictionary* opts = nullptr; - av_dict_set(&opts, "probesize", "96", 0); - err = avformat_open_input(&adec.fmt, NULL, adec.input_format, &opts); - if (err || opts) - { - throw EXCEPTION("avformat_open_input() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0); - } - //err = avformat_find_stream_info(adec.fmt, NULL); - //if (err || !adec.fmt->nb_streams) - //{ - // ADEC_ERROR("adecDecodeAu: avformat_find_stream_info() failed (err=0x%x, nb_streams=%d)", err, adec.fmt->nb_streams); - //} - if (!avformat_new_stream(adec.fmt, adec.codec)) - { - throw EXCEPTION("avformat_new_stream() failed"); - } - adec.ctx = adec.fmt->streams[0]->codec; // TODO: check data - - opts = nullptr; - av_dict_set(&opts, "refcounted_frames", "1", 0); - { - std::lock_guard lock(g_mutex_avcodec_open2); - // not multithread-safe (???) - err = avcodec_open2(adec.ctx, adec.codec, &opts); - } - if (err || opts) - { - throw EXCEPTION("avcodec_open2() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0); - } - adec.just_started = false; - } - - bool last_frame = false; - - while (true) - { - if (Emu.IsStopped() || adec.is_closed) - { - if (Emu.IsStopped()) cellAdec.warning("adecDecodeAu: aborted"); - break; - } - - last_frame = av_read_frame(adec.fmt, &au) < 0; - if (last_frame) - { - //break; - av_free(au.data); - au.data = NULL; - au.size = 0; - } - - struct AdecFrameHolder : AdecFrame - { - AdecFrameHolder() - { - data = av_frame_alloc(); - } - - ~AdecFrameHolder() - { - if (data) - { - av_frame_unref(data); - av_frame_free(&data); - } - } - - } frame; - - if (!frame.data) - { - throw EXCEPTION("av_frame_alloc() failed"); - } - - int got_frame = 0; - - int decode = avcodec_decode_audio4(adec.ctx, frame.data, &got_frame, &au); - - if (decode <= 0) - { - if (decode < 0) - { - cellAdec.error("adecDecodeAu: AU decoding error(0x%x)", decode); - } - if (!got_frame && adec.reader.size == 0) break; - } - - if (got_frame) - { - //u64 ts = av_frame_get_best_effort_timestamp(frame.data); - //if (ts != AV_NOPTS_VALUE) - //{ - // frame.pts = ts/* - adec.first_pts*/; - // adec.last_pts = frame.pts; - //} - adec.last_pts += ((u64)frame.data->nb_samples) * 90000 / frame.data->sample_rate; - frame.pts = adec.last_pts; - - s32 nbps = av_get_bytes_per_sample((AVSampleFormat)frame.data->format); - switch (frame.data->format) - { - case AV_SAMPLE_FMT_FLTP: break; - case AV_SAMPLE_FMT_S16P: break; - default: - { - throw EXCEPTION("Unsupported frame format(%d)", frame.data->format); - } - } - frame.auAddr = task.au.addr; - frame.auSize = task.au.size; - frame.userdata = task.au.userdata; - frame.size = frame.data->nb_samples * frame.data->channels * nbps; - - //LOG_NOTICE(HLE, "got audio frame (pts=0x%llx, nb_samples=%d, ch=%d, sample_rate=%d, nbps=%d)", - //frame.pts, frame.data->nb_samples, frame.data->channels, frame.data->sample_rate, nbps); - - if (adec.frames.push(frame, &adec.is_closed)) - { - frame.data = nullptr; // to prevent destruction - adec.cbFunc(CPU, adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg); - } - } - } - - adec.cbFunc(CPU, adec.id, CELL_ADEC_MSG_TYPE_AUDONE, task.au.auInfo_addr, adec.cbArg); - break; - } - - case adecClose: - { - break; - } - - default: - { - throw EXCEPTION("Unknown task(%d)", task.type); - } - } - } - - adec.is_finished = true; - - }; - - adec.adecCb->cpu_init(); - adec.adecCb->state -= cpu_state::stop; - (*adec.adecCb)->lock_notify(); -} - bool adecCheckType(s32 type) { switch (type) @@ -527,7 +558,11 @@ s32 cellAdecOpen(vm::ptr type, vm::ptr res, vm:: return CELL_ADEC_ERROR_ARG; } - adecOpen(*handle = idm::make(type->audioCodecType, res->startAddr, res->totalMemSize, cb->cbFunc, cb->cbArg)); + auto&& adec = std::make_shared(type->audioCodecType, res->startAddr, res->totalMemSize, cb->cbFunc, cb->cbArg); + + *handle = idm::import_existing(adec); + + adec->run(); return CELL_OK; } @@ -541,7 +576,11 @@ s32 cellAdecOpenEx(vm::ptr type, vm::ptr res, return CELL_ADEC_ERROR_ARG; } - adecOpen(*handle = idm::make(type->audioCodecType, res->startAddr, res->totalMemSize, cb->cbFunc, cb->cbArg)); + auto&& adec = std::make_shared(type->audioCodecType, res->startAddr, res->totalMemSize, cb->cbFunc, cb->cbArg); + + *handle = idm::import_existing(adec); + + adec->run(); return CELL_OK; } @@ -574,8 +613,7 @@ s32 cellAdecClose(u32 handle) std::this_thread::sleep_for(1ms); // hack } - idm::remove(adec->adecCb->id); - idm::remove(handle); + idm::remove(handle); return CELL_OK; } diff --git a/rpcs3/Emu/Cell/Modules/cellAdec.h b/rpcs3/Emu/Cell/Modules/cellAdec.h index 97ef2c834d..ba5d0c16be 100644 --- a/rpcs3/Emu/Cell/Modules/cellAdec.h +++ b/rpcs3/Emu/Cell/Modules/cellAdec.h @@ -1043,7 +1043,7 @@ struct AdecTask struct AdecFrame { - AVFrame* data; + struct AVFrame* data; u64 pts; u64 userdata; u32 auAddr; @@ -1096,58 +1096,3 @@ struct OMAHeader // OMA Header }; CHECK_SIZE(OMAHeader, 96); - -class AudioDecoder -{ -public: - squeue_t job; - u32 id; - volatile bool is_closed; - volatile bool is_finished; - bool just_started; - bool just_finished; - - AVCodec* codec; - AVInputFormat* input_format; - AVCodecContext* ctx; - AVFormatContext* fmt; - u8* io_buf; - - struct AudioReader - { - u32 addr; - u32 size; - bool init; - bool has_ats; - - AudioReader() - : init(false) - { - } - - } reader; - - squeue_t frames; - - const s32 type; - const u32 memAddr; - const u32 memSize; - const vm::ptr cbFunc; - const u32 cbArg; - u32 memBias; - - AdecTask task; - u64 last_pts, first_pts; - - u32 ch_out; - u32 ch_cfg; - u32 frame_size; - u32 sample_rate; - bool use_ats_headers; - - std::shared_ptr adecCb; - - AudioDecoder(s32 type, u32 addr, u32 size, vm::ptr func, u32 arg); - - ~AudioDecoder(); -}; diff --git a/rpcs3/Emu/Cell/Modules/cellDmux.cpp b/rpcs3/Emu/Cell/Modules/cellDmux.cpp index 7ea8c97263..e367af6b8a 100644 --- a/rpcs3/Emu/Cell/Modules/cellDmux.cpp +++ b/rpcs3/Emu/Cell/Modules/cellDmux.cpp @@ -10,6 +10,654 @@ logs::channel cellDmux("cellDmux", logs::level::notice); +/* Demuxer Thread Classes */ + +enum +{ + /* http://dvd.sourceforge.net/dvdinfo/mpeghdrs.html */ + + PACKET_START_CODE_MASK = 0xffffff00, + PACKET_START_CODE_PREFIX = 0x00000100, + + PACK_START_CODE = 0x000001ba, + SYSTEM_HEADER_START_CODE = 0x000001bb, + PRIVATE_STREAM_1 = 0x000001bd, + PADDING_STREAM = 0x000001be, + PRIVATE_STREAM_2 = 0x000001bf, +}; + +struct DemuxerStream +{ + u32 addr; + u32 size; + u64 userdata; + bool discontinuity; + + template + bool get(T& out) + { + if (sizeof(T) > size) return false; + + out = vm::_ref(addr); + addr += sizeof(T); + size -= sizeof(T); + + return true; + } + + template + bool peek(T& out, u32 shift = 0) + { + if (sizeof(T) + shift > size) return false; + + out = vm::_ref(addr + shift); + return true; + } + + void skip(u32 count) + { + addr += count; + size = size > count ? size - count : 0; + } + + bool check(u32 count) const + { + return count <= size; + } + + u64 get_ts(u8 c) + { + u8 v[4]; get((u32&)v); + return + (((u64)c & 0x0e) << 29) | + (((u64)v[0]) << 21) | + (((u64)v[1] & 0x7e) << 15) | + (((u64)v[2]) << 7) | ((u64)v[3] >> 1); + } +}; + +struct PesHeader +{ + u64 pts; + u64 dts; + u8 size; + bool has_ts; + bool is_ok; + + PesHeader(DemuxerStream& stream); +}; + +class ElementaryStream; +class Demuxer; + +enum DemuxerJobType +{ + dmuxSetStream, + dmuxResetStream, + dmuxResetStreamAndWaitDone, + dmuxEnableEs, + dmuxDisableEs, + dmuxResetEs, + dmuxFlushEs, + dmuxClose, +}; + +struct DemuxerTask +{ + DemuxerJobType type; + + union + { + DemuxerStream stream; + + struct + { + u32 es; + u32 auInfo_ptr_addr; + u32 auSpec_ptr_addr; + ElementaryStream* es_ptr; + } es; + }; + + DemuxerTask() + { + } + + DemuxerTask(DemuxerJobType type) + : type(type) + { + } +}; + +class ElementaryStream +{ + std::mutex m_mutex; + + squeue_t entries; // AU starting addresses + u32 put_count; // number of AU written + u32 got_count; // number of AU obtained by GetAu(Ex) + u32 released; // number of AU released + + u32 put; // AU that is being written now + + bool is_full(u32 space); + +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 id_value<> id{}; + const u32 memAddr; + const u32 memSize; + const u32 fidMajor; + const u32 fidMinor; + const u32 sup1; + const u32 sup2; + const vm::ptr cbFunc; + const u32 cbArg; + const u32 spec; //addr + + std::vector raw_data; // demultiplexed data stream (managed by demuxer thread) + size_t raw_pos; // should be <= raw_data.size() + u64 last_dts; + u64 last_pts; + + void push(DemuxerStream& stream, u32 size); // called by demuxer thread (not multithread-safe) + + bool isfull(u32 space); + + void push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool rap, u32 specific); + + bool release(); + + bool peek(u32& out_data, bool no_ex, u32& out_spec, bool update_index); + + void reset(); +}; + +class Demuxer : public ppu_thread +{ +public: + squeue_t job; + const u32 memAddr; + const u32 memSize; + const vm::ptr cbFunc; + const u32 cbArg; + volatile bool is_finished; + volatile bool is_closed; + atomic_t is_running; + atomic_t is_working; + + Demuxer(u32 addr, u32 size, vm::ptr func, u32 arg) + : ppu_thread("HLE Demuxer") + , is_finished(false) + , is_closed(false) + , is_running(false) + , is_working(false) + , memAddr(addr) + , memSize(size) + , cbFunc(func) + , cbArg(arg) + { + } + + virtual void cpu_task() override + { + DemuxerTask task; + DemuxerStream stream = {}; + ElementaryStream* esALL[96]; memset(esALL, 0, sizeof(esALL)); + ElementaryStream** esAVC = &esALL[0]; // AVC (max 16 minus M2V count) + ElementaryStream** esM2V = &esALL[16]; // M2V (max 16 minus AVC count) + ElementaryStream** esDATA = &esALL[32]; // user data (max 16) + ElementaryStream** esATX = &esALL[48]; // ATRAC3+ (max 16) + ElementaryStream** esAC3 = &esALL[64]; // AC3 (max 16) + ElementaryStream** esPCM = &esALL[80]; // LPCM (max 16) + + u32 cb_add = 0; + + while (true) + { + if (Emu.IsStopped() || is_closed) + { + break; + } + + if (!job.try_peek(task) && is_running && stream.addr) + { + // default task (demuxing) (if there is no other work) + be_t code; + be_t len; + + if (!stream.peek(code)) + { + // demuxing finished + is_running = false; + + // callback + auto dmuxMsg = vm::ptr::make(memAddr + (cb_add ^= 16)); + dmuxMsg->msgType = CELL_DMUX_MSG_TYPE_DEMUX_DONE; + dmuxMsg->supplementalInfo = stream.userdata; + cbFunc(*this, id, dmuxMsg, cbArg); + + is_working = false; + + stream = {}; + + continue; + } + + switch (code) + { + case PACK_START_CODE: + { + if (!stream.check(14)) + { + throw EXCEPTION("End of stream (PACK_START_CODE)"); + } + stream.skip(14); + break; + } + + case SYSTEM_HEADER_START_CODE: + { + if (!stream.check(18)) + { + throw EXCEPTION("End of stream (SYSTEM_HEADER_START_CODE)"); + } + stream.skip(18); + break; + } + + case PADDING_STREAM: + { + if (!stream.check(6)) + { + throw EXCEPTION("End of stream (PADDING_STREAM)"); + } + stream.skip(4); + stream.get(len); + + if (!stream.check(len)) + { + throw EXCEPTION("End of stream (PADDING_STREAM, len=%d)", len); + } + stream.skip(len); + break; + } + + case PRIVATE_STREAM_2: + { + if (!stream.check(6)) + { + throw EXCEPTION("End of stream (PRIVATE_STREAM_2)"); + } + stream.skip(4); + stream.get(len); + + cellDmux.notice("PRIVATE_STREAM_2 (%d)", len); + + if (!stream.check(len)) + { + throw EXCEPTION("End of stream (PRIVATE_STREAM_2, len=%d)", len); + } + stream.skip(len); + break; + } + + case PRIVATE_STREAM_1: + { + // audio and user data stream + DemuxerStream backup = stream; + + if (!stream.check(6)) + { + throw EXCEPTION("End of stream (PRIVATE_STREAM_1)"); + } + stream.skip(4); + stream.get(len); + + if (!stream.check(len)) + { + throw EXCEPTION("End of stream (PRIVATE_STREAM_1, len=%d)", len); + } + + const PesHeader pes(stream); + if (!pes.is_ok) + { + throw EXCEPTION("PesHeader error (PRIVATE_STREAM_1, len=%d)", len); + } + + if (len < pes.size + 4) + { + throw EXCEPTION("End of block (PRIVATE_STREAM_1, PesHeader + fid_minor, len=%d)", len); + } + len -= pes.size + 4; + + u8 fid_minor; + if (!stream.get(fid_minor)) + { + throw EXCEPTION("End of stream (PRIVATE_STREAM1, fid_minor)"); + } + + const u32 ch = fid_minor % 16; + if ((fid_minor & -0x10) == 0 && esATX[ch]) + { + ElementaryStream& es = *esATX[ch]; + if (es.raw_data.size() > 1024 * 1024) + { + stream = backup; + std::this_thread::sleep_for(1ms); // hack + continue; + } + + if (len < 3 || !stream.check(3)) + { + throw EXCEPTION("End of block (ATX, unknown header, len=%d)", len); + } + len -= 3; + stream.skip(3); + + if (pes.has_ts) + { + es.last_dts = pes.dts; + es.last_pts = pes.pts; + } + + es.push(stream, len); + + while (true) + { + auto const size = es.raw_data.size() - es.raw_pos; // size of available new data + auto const data = es.raw_data.data() + es.raw_pos; // pointer to available data + + if (size < 8) break; // skip if cannot read ATS header + + if (data[0] != 0x0f || data[1] != 0xd0) + { + throw EXCEPTION("ATX: 0x0fd0 header not found (ats=0x%llx)", *(be_t*)data); + } + + u32 frame_size = ((((u32)data[2] & 0x3) << 8) | (u32)data[3]) * 8 + 8; + + if (size < frame_size + 8) break; // skip non-complete AU + + if (es.isfull(frame_size + 8)) break; // skip if cannot push AU + + es.push_au(frame_size + 8, es.last_dts, es.last_pts, stream.userdata, false /* TODO: set correct value */, 0); + + //cellDmux.notice("ATX AU pushed (ats=0x%llx, frame_size=%d)", *(be_t*)data, frame_size); + + auto esMsg = vm::ptr::make(memAddr + (cb_add ^= 16)); + esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND; + esMsg->supplementalInfo = stream.userdata; + es.cbFunc(*this, id, es.id, esMsg, es.cbArg); + } + } + else + { + cellDmux.notice("PRIVATE_STREAM_1 (len=%d, fid_minor=0x%x)", len, fid_minor); + stream.skip(len); + } + break; + } + + case 0x1e0: case 0x1e1: case 0x1e2: case 0x1e3: + case 0x1e4: case 0x1e5: case 0x1e6: case 0x1e7: + case 0x1e8: case 0x1e9: case 0x1ea: case 0x1eb: + case 0x1ec: case 0x1ed: case 0x1ee: case 0x1ef: + { + // video stream (AVC or M2V) + DemuxerStream backup = stream; + + if (!stream.check(6)) + { + throw EXCEPTION("End of stream (video, code=0x%x)", code); + } + stream.skip(4); + stream.get(len); + + if (!stream.check(len)) + { + throw EXCEPTION("End of stream (video, code=0x%x, len=%d)", code, len); + } + + const PesHeader pes(stream); + if (!pes.is_ok) + { + throw EXCEPTION("PesHeader error (video, code=0x%x, len=%d)", code, len); + } + + if (len < pes.size + 3) + { + throw EXCEPTION("End of block (video, code=0x%x, PesHeader)", code); + } + len -= pes.size + 3; + + const u32 ch = code % 16; + if (esAVC[ch]) + { + ElementaryStream& es = *esAVC[ch]; + + const u32 old_size = (u32)es.raw_data.size(); + if (es.isfull(old_size)) + { + stream = backup; + std::this_thread::sleep_for(1ms); // hack + continue; + } + + if ((pes.has_ts && old_size) || old_size >= 0x69800) + { + // push AU if it becomes too big or the next packet contains PTS/DTS + es.push_au(old_size, es.last_dts, es.last_pts, stream.userdata, false /* TODO: set correct value */, 0); + + // callback + auto esMsg = vm::ptr::make(memAddr + (cb_add ^= 16)); + esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND; + esMsg->supplementalInfo = stream.userdata; + es.cbFunc(*this, id, es.id, esMsg, es.cbArg); + } + + if (pes.has_ts) + { + // preserve dts/pts for next AU + es.last_dts = pes.dts; + es.last_pts = pes.pts; + } + + // reconstruction of MPEG2-PS stream for vdec module + const u32 size = len + pes.size + 9; + stream = backup; + es.push(stream, size); + } + else + { + cellDmux.notice("Video stream (code=0x%x, len=%d)", code, len); + stream.skip(len); + } + break; + } + + default: + { + if ((code & PACKET_START_CODE_MASK) == PACKET_START_CODE_PREFIX) + { + throw EXCEPTION("Unknown code found (0x%x)", code); + } + + // search + stream.skip(1); + } + } + + continue; + } + + // wait for task if no work + if (!job.pop(task, &is_closed)) + { + break; // Emu is stopped + } + + switch (task.type) + { + case dmuxSetStream: + { + if (task.stream.discontinuity) + { + cellDmux.warning("dmuxSetStream (beginning)"); + for (u32 i = 0; i < sizeof(esALL) / sizeof(esALL[0]); i++) + { + if (esALL[i]) + { + esALL[i]->reset(); + } + } + } + + stream = task.stream; + //LOG_NOTICE(HLE, "*** stream updated(addr=0x%x, size=0x%x, discont=%d, userdata=0x%llx)", + //stream.addr, stream.size, stream.discontinuity, stream.userdata); + break; + } + + case dmuxResetStream: + case dmuxResetStreamAndWaitDone: + { + // demuxing stopped + if (is_running.exchange(false)) + { + // callback + auto dmuxMsg = vm::ptr::make(memAddr + (cb_add ^= 16)); + dmuxMsg->msgType = CELL_DMUX_MSG_TYPE_DEMUX_DONE; + dmuxMsg->supplementalInfo = stream.userdata; + cbFunc(*this, id, dmuxMsg, cbArg); + + stream = {}; + + is_working = false; + } + + break; + } + + case dmuxEnableEs: + { + ElementaryStream& es = *task.es.es_ptr; + + // TODO: uncomment when ready to use + //if ((es.fidMajor & -0x10) == 0xe0 && es.fidMinor == 0 && es.sup1 == 1 && !es.sup2) + //{ + // esAVC[es.fidMajor % 16] = task.es.es_ptr; + //} + //else if ((es.fidMajor & -0x10) == 0xe0 && es.fidMinor == 0 && !es.sup1 && !es.sup2) + //{ + // esM2V[es.fidMajor % 16] = task.es.es_ptr; + //} + //else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0 && !es.sup1 && !es.sup2) + //{ + // esATX[es.fidMinor % 16] = task.es.es_ptr; + //} + //else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0x20 && !es.sup1 && !es.sup2) + //{ + // esDATA[es.fidMinor % 16] = task.es.es_ptr; + //} + //else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0x30 && !es.sup1 && !es.sup2) + //{ + // esAC3[es.fidMinor % 16] = task.es.es_ptr; + //} + //else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0x40 && !es.sup1 && !es.sup2) + //{ + // esPCM[es.fidMinor % 16] = task.es.es_ptr; + //} + //else + { + throw EXCEPTION("dmuxEnableEs: unknown filter (0x%x, 0x%x, 0x%x, 0x%x)", es.fidMajor, es.fidMinor, es.sup1, es.sup2); + } + es.dmux = this; + break; + } + + case dmuxDisableEs: + { + ElementaryStream& es = *task.es.es_ptr; + if (es.dmux != this) + { + throw EXCEPTION("dmuxDisableEs: invalid elementary stream"); + } + + for (u32 i = 0; i < sizeof(esALL) / sizeof(esALL[0]); i++) + { + if (esALL[i] == &es) + { + esALL[i] = nullptr; + } + } + es.dmux = nullptr; + idm::remove(task.es.es); + break; + } + + case dmuxFlushEs: + { + ElementaryStream& es = *task.es.es_ptr; + + const u32 old_size = (u32)es.raw_data.size(); + if (old_size && (es.fidMajor & -0x10) == 0xe0) + { + // TODO (it's only for AVC, some ATX data may be lost) + while (es.isfull(old_size)) + { + if (Emu.IsStopped() || is_closed) break; + + std::this_thread::sleep_for(1ms); // hack + } + + es.push_au(old_size, es.last_dts, es.last_pts, stream.userdata, false, 0); + + // callback + auto esMsg = vm::ptr::make(memAddr + (cb_add ^= 16)); + esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND; + esMsg->supplementalInfo = stream.userdata; + es.cbFunc(*this, id, es.id, esMsg, es.cbArg); + } + + if (es.raw_data.size()) + { + cellDmux.error("dmuxFlushEs: 0x%x bytes lost (es_id=%d)", (u32)es.raw_data.size(), es.id); + } + + // callback + auto esMsg = vm::ptr::make(memAddr + (cb_add ^= 16)); + esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_FLUSH_DONE; + esMsg->supplementalInfo = stream.userdata; + es.cbFunc(*this, id, es.id, esMsg, es.cbArg); + break; + } + + case dmuxResetEs: + { + task.es.es_ptr->reset(); + break; + } + + case dmuxClose: + { + break; + } + + default: + { + throw EXCEPTION("Demuxer thread error: unknown task (0x%x)", task.type); + } + } + } + + is_finished = true; + } +}; + + PesHeader::PesHeader(DemuxerStream& stream) : pts(CODEC_TS_INVALID) , dts(CODEC_TS_INVALID) @@ -292,478 +940,6 @@ void dmuxQueryEsAttr(u32 info /* may be 0 */, vm::cptr esFi cellDmux.warning("*** filter(0x%x, 0x%x, 0x%x, 0x%x)", esFilterId->filterIdMajor, esFilterId->filterIdMinor, esFilterId->supplementalInfo1, esFilterId->supplementalInfo2); } -void dmuxOpen(u32 dmux_id) // TODO: call from the constructor -{ - const auto sptr = idm::get(dmux_id); - Demuxer& dmux = *sptr; - - dmux.id = dmux_id; - - dmux.dmuxCb = idm::make_ptr(fmt::format("Demuxer[0x%x] Thread", dmux_id)); - dmux.dmuxCb->prio = 1001; - dmux.dmuxCb->stack_size = 0x10000; - dmux.dmuxCb->custom_task = [sptr](PPUThread& CPU) - { - Demuxer& dmux = *sptr; - - DemuxerTask task; - DemuxerStream stream = {}; - ElementaryStream* esALL[96]; memset(esALL, 0, sizeof(esALL)); - ElementaryStream** esAVC = &esALL[0]; // AVC (max 16 minus M2V count) - ElementaryStream** esM2V = &esALL[16]; // M2V (max 16 minus AVC count) - ElementaryStream** esDATA = &esALL[32]; // user data (max 16) - ElementaryStream** esATX = &esALL[48]; // ATRAC3+ (max 16) - ElementaryStream** esAC3 = &esALL[64]; // AC3 (max 16) - ElementaryStream** esPCM = &esALL[80]; // LPCM (max 16) - - u32 cb_add = 0; - - while (true) - { - if (Emu.IsStopped() || dmux.is_closed) - { - break; - } - - if (!dmux.job.try_peek(task) && dmux.is_running && stream.addr) - { - // default task (demuxing) (if there is no other work) - be_t code; - be_t len; - - if (!stream.peek(code)) - { - // demuxing finished - dmux.is_running = false; - - // callback - auto dmuxMsg = vm::ptr::make(dmux.memAddr + (cb_add ^= 16)); - dmuxMsg->msgType = CELL_DMUX_MSG_TYPE_DEMUX_DONE; - dmuxMsg->supplementalInfo = stream.userdata; - dmux.cbFunc(CPU, dmux.id, dmuxMsg, dmux.cbArg); - - dmux.is_working = false; - - stream = {}; - - continue; - } - - switch (code) - { - case PACK_START_CODE: - { - if (!stream.check(14)) - { - throw EXCEPTION("End of stream (PACK_START_CODE)"); - } - stream.skip(14); - break; - } - - case SYSTEM_HEADER_START_CODE: - { - if (!stream.check(18)) - { - throw EXCEPTION("End of stream (SYSTEM_HEADER_START_CODE)"); - } - stream.skip(18); - break; - } - - case PADDING_STREAM: - { - if (!stream.check(6)) - { - throw EXCEPTION("End of stream (PADDING_STREAM)"); - } - stream.skip(4); - stream.get(len); - - if (!stream.check(len)) - { - throw EXCEPTION("End of stream (PADDING_STREAM, len=%d)", len); - } - stream.skip(len); - break; - } - - case PRIVATE_STREAM_2: - { - if (!stream.check(6)) - { - throw EXCEPTION("End of stream (PRIVATE_STREAM_2)"); - } - stream.skip(4); - stream.get(len); - - cellDmux.notice("PRIVATE_STREAM_2 (%d)", len); - - if (!stream.check(len)) - { - throw EXCEPTION("End of stream (PRIVATE_STREAM_2, len=%d)", len); - } - stream.skip(len); - break; - } - - case PRIVATE_STREAM_1: - { - // audio and user data stream - DemuxerStream backup = stream; - - if (!stream.check(6)) - { - throw EXCEPTION("End of stream (PRIVATE_STREAM_1)"); - } - stream.skip(4); - stream.get(len); - - if (!stream.check(len)) - { - throw EXCEPTION("End of stream (PRIVATE_STREAM_1, len=%d)", len); - } - - const PesHeader pes(stream); - if (!pes.is_ok) - { - throw EXCEPTION("PesHeader error (PRIVATE_STREAM_1, len=%d)", len); - } - - if (len < pes.size + 4) - { - throw EXCEPTION("End of block (PRIVATE_STREAM_1, PesHeader + fid_minor, len=%d)", len); - } - len -= pes.size + 4; - - u8 fid_minor; - if (!stream.get(fid_minor)) - { - throw EXCEPTION("End of stream (PRIVATE_STREAM1, fid_minor)"); - } - - const u32 ch = fid_minor % 16; - if ((fid_minor & -0x10) == 0 && esATX[ch]) - { - ElementaryStream& es = *esATX[ch]; - if (es.raw_data.size() > 1024 * 1024) - { - stream = backup; - std::this_thread::sleep_for(1ms); // hack - continue; - } - - if (len < 3 || !stream.check(3)) - { - throw EXCEPTION("End of block (ATX, unknown header, len=%d)", len); - } - len -= 3; - stream.skip(3); - - if (pes.has_ts) - { - es.last_dts = pes.dts; - es.last_pts = pes.pts; - } - - es.push(stream, len); - - while (true) - { - auto const size = es.raw_data.size() - es.raw_pos; // size of available new data - auto const data = es.raw_data.data() + es.raw_pos; // pointer to available data - - if (size < 8) break; // skip if cannot read ATS header - - if (data[0] != 0x0f || data[1] != 0xd0) - { - throw EXCEPTION("ATX: 0x0fd0 header not found (ats=0x%llx)", *(be_t*)data); - } - - u32 frame_size = ((((u32)data[2] & 0x3) << 8) | (u32)data[3]) * 8 + 8; - - if (size < frame_size + 8) break; // skip non-complete AU - - if (es.isfull(frame_size + 8)) break; // skip if cannot push AU - - es.push_au(frame_size + 8, es.last_dts, es.last_pts, stream.userdata, false /* TODO: set correct value */, 0); - - //cellDmux.notice("ATX AU pushed (ats=0x%llx, frame_size=%d)", *(be_t*)data, frame_size); - - auto esMsg = vm::ptr::make(dmux.memAddr + (cb_add ^= 16)); - esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND; - esMsg->supplementalInfo = stream.userdata; - es.cbFunc(CPU, dmux.id, es.id, esMsg, es.cbArg); - } - } - else - { - cellDmux.notice("PRIVATE_STREAM_1 (len=%d, fid_minor=0x%x)", len, fid_minor); - stream.skip(len); - } - break; - } - - case 0x1e0: case 0x1e1: case 0x1e2: case 0x1e3: - case 0x1e4: case 0x1e5: case 0x1e6: case 0x1e7: - case 0x1e8: case 0x1e9: case 0x1ea: case 0x1eb: - case 0x1ec: case 0x1ed: case 0x1ee: case 0x1ef: - { - // video stream (AVC or M2V) - DemuxerStream backup = stream; - - if (!stream.check(6)) - { - throw EXCEPTION("End of stream (video, code=0x%x)", code); - } - stream.skip(4); - stream.get(len); - - if (!stream.check(len)) - { - throw EXCEPTION("End of stream (video, code=0x%x, len=%d)", code, len); - } - - const PesHeader pes(stream); - if (!pes.is_ok) - { - throw EXCEPTION("PesHeader error (video, code=0x%x, len=%d)", code, len); - } - - if (len < pes.size + 3) - { - throw EXCEPTION("End of block (video, code=0x%x, PesHeader)", code); - } - len -= pes.size + 3; - - const u32 ch = code % 16; - if (esAVC[ch]) - { - ElementaryStream& es = *esAVC[ch]; - - const u32 old_size = (u32)es.raw_data.size(); - if (es.isfull(old_size)) - { - stream = backup; - std::this_thread::sleep_for(1ms); // hack - continue; - } - - if ((pes.has_ts && old_size) || old_size >= 0x69800) - { - // push AU if it becomes too big or the next packet contains PTS/DTS - es.push_au(old_size, es.last_dts, es.last_pts, stream.userdata, false /* TODO: set correct value */, 0); - - // callback - auto esMsg = vm::ptr::make(dmux.memAddr + (cb_add ^= 16)); - esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND; - esMsg->supplementalInfo = stream.userdata; - es.cbFunc(CPU, dmux.id, es.id, esMsg, es.cbArg); - } - - if (pes.has_ts) - { - // preserve dts/pts for next AU - es.last_dts = pes.dts; - es.last_pts = pes.pts; - } - - // reconstruction of MPEG2-PS stream for vdec module - const u32 size = len + pes.size + 9; - stream = backup; - es.push(stream, size); - } - else - { - cellDmux.notice("Video stream (code=0x%x, len=%d)", code, len); - stream.skip(len); - } - break; - } - - default: - { - if ((code & PACKET_START_CODE_MASK) == PACKET_START_CODE_PREFIX) - { - throw EXCEPTION("Unknown code found (0x%x)", code); - } - - // search - stream.skip(1); - } - } - - continue; - } - - // wait for task if no work - if (!dmux.job.pop(task, &dmux.is_closed)) - { - break; // Emu is stopped - } - - switch (task.type) - { - case dmuxSetStream: - { - if (task.stream.discontinuity) - { - cellDmux.warning("dmuxSetStream (beginning)"); - for (u32 i = 0; i < sizeof(esALL) / sizeof(esALL[0]); i++) - { - if (esALL[i]) - { - esALL[i]->reset(); - } - } - } - - stream = task.stream; - //LOG_NOTICE(HLE, "*** stream updated(addr=0x%x, size=0x%x, discont=%d, userdata=0x%llx)", - //stream.addr, stream.size, stream.discontinuity, stream.userdata); - break; - } - - case dmuxResetStream: - case dmuxResetStreamAndWaitDone: - { - // demuxing stopped - if (dmux.is_running.exchange(false)) - { - // callback - auto dmuxMsg = vm::ptr::make(dmux.memAddr + (cb_add ^= 16)); - dmuxMsg->msgType = CELL_DMUX_MSG_TYPE_DEMUX_DONE; - dmuxMsg->supplementalInfo = stream.userdata; - dmux.cbFunc(CPU, dmux.id, dmuxMsg, dmux.cbArg); - - stream = {}; - - dmux.is_working = false; - } - - break; - } - - case dmuxEnableEs: - { - ElementaryStream& es = *task.es.es_ptr; - - // TODO: uncomment when ready to use - if ((es.fidMajor & -0x10) == 0xe0 && es.fidMinor == 0 && es.sup1 == 1 && !es.sup2) - { - esAVC[es.fidMajor % 16] = task.es.es_ptr; - } - //else if ((es.fidMajor & -0x10) == 0xe0 && es.fidMinor == 0 && !es.sup1 && !es.sup2) - //{ - // esM2V[es.fidMajor % 16] = task.es.es_ptr; - //} - else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0 && !es.sup1 && !es.sup2) - { - esATX[es.fidMinor % 16] = task.es.es_ptr; - } - //else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0x20 && !es.sup1 && !es.sup2) - //{ - // esDATA[es.fidMinor % 16] = task.es.es_ptr; - //} - //else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0x30 && !es.sup1 && !es.sup2) - //{ - // esAC3[es.fidMinor % 16] = task.es.es_ptr; - //} - //else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0x40 && !es.sup1 && !es.sup2) - //{ - // esPCM[es.fidMinor % 16] = task.es.es_ptr; - //} - else - { - throw EXCEPTION("dmuxEnableEs: unknown filter (0x%x, 0x%x, 0x%x, 0x%x)", es.fidMajor, es.fidMinor, es.sup1, es.sup2); - } - es.dmux = &dmux; - break; - } - - case dmuxDisableEs: - { - ElementaryStream& es = *task.es.es_ptr; - if (es.dmux != &dmux) - { - throw EXCEPTION("dmuxDisableEs: invalid elementary stream"); - } - - for (u32 i = 0; i < sizeof(esALL) / sizeof(esALL[0]); i++) - { - if (esALL[i] == &es) - { - esALL[i] = nullptr; - } - } - es.dmux = nullptr; - idm::remove(task.es.es); - break; - } - - case dmuxFlushEs: - { - ElementaryStream& es = *task.es.es_ptr; - - const u32 old_size = (u32)es.raw_data.size(); - if (old_size && (es.fidMajor & -0x10) == 0xe0) - { - // TODO (it's only for AVC, some ATX data may be lost) - while (es.isfull(old_size)) - { - if (Emu.IsStopped() || dmux.is_closed) break; - - std::this_thread::sleep_for(1ms); // hack - } - - es.push_au(old_size, es.last_dts, es.last_pts, stream.userdata, false, 0); - - // callback - auto esMsg = vm::ptr::make(dmux.memAddr + (cb_add ^= 16)); - esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND; - esMsg->supplementalInfo = stream.userdata; - es.cbFunc(CPU, dmux.id, es.id, esMsg, es.cbArg); - } - - if (es.raw_data.size()) - { - cellDmux.error("dmuxFlushEs: 0x%x bytes lost (es_id=%d)", (u32)es.raw_data.size(), es.id); - } - - // callback - auto esMsg = vm::ptr::make(dmux.memAddr + (cb_add ^= 16)); - esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_FLUSH_DONE; - esMsg->supplementalInfo = stream.userdata; - es.cbFunc(CPU, dmux.id, es.id, esMsg, es.cbArg); - break; - } - - case dmuxResetEs: - { - task.es.es_ptr->reset(); - break; - } - - case dmuxClose: - { - break; - } - - default: - { - throw EXCEPTION("Demuxer thread error: unknown task (0x%x)", task.type); - } - } - } - - dmux.is_finished = true; - }; - - dmux.dmuxCb->cpu_init(); - dmux.dmuxCb->state -= cpu_state::stop; - (*dmux.dmuxCb)->lock_notify(); -} - s32 cellDmuxQueryAttr(vm::cptr type, vm::ptr attr) { cellDmux.warning("cellDmuxQueryAttr(type=*0x%x, attr=*0x%x)", type, attr); @@ -800,8 +976,11 @@ s32 cellDmuxOpen(vm::cptr type, vm::cptr res, vm } // TODO: check demuxerResource and demuxerCb arguments + auto&& dmux = std::make_shared(res->memAddr, res->memSize, cb->cbMsgFunc, cb->cbArg); - dmuxOpen(*handle = idm::make(res->memAddr, res->memSize, cb->cbMsgFunc, cb->cbArg)); + *handle = idm::import_existing(dmux); + + dmux->run(); return CELL_OK; } @@ -816,8 +995,11 @@ s32 cellDmuxOpenEx(vm::cptr type, vm::cptr res } // TODO: check demuxerResourceEx and demuxerCb arguments + auto&& dmux = std::make_shared(resEx->memAddr, resEx->memSize, cb->cbMsgFunc, cb->cbArg); - dmuxOpen(*handle = idm::make(resEx->memAddr, resEx->memSize, cb->cbMsgFunc, cb->cbArg)); + *handle = idm::import_existing(dmux); + + dmux->run(); return CELL_OK; } @@ -839,8 +1021,11 @@ s32 cellDmuxOpen2(vm::cptr type2, vm::cptr res } // TODO: check demuxerType2, demuxerResource2 and demuxerCb arguments + auto&& dmux = std::make_shared(res2->memAddr, res2->memSize, cb->cbMsgFunc, cb->cbArg); - dmuxOpen(*handle = idm::make(res2->memAddr, res2->memSize, cb->cbMsgFunc, cb->cbArg)); + *handle = idm::import_existing(dmux); + + dmux->run(); return CELL_OK; } @@ -870,8 +1055,7 @@ s32 cellDmuxClose(u32 handle) std::this_thread::sleep_for(1ms); // hack } - idm::remove(dmux->dmuxCb->id); - idm::remove(handle); + idm::remove(handle); return CELL_OK; } diff --git a/rpcs3/Emu/Cell/Modules/cellDmux.h b/rpcs3/Emu/Cell/Modules/cellDmux.h index dd93bad2dd..fd32643dba 100644 --- a/rpcs3/Emu/Cell/Modules/cellDmux.h +++ b/rpcs3/Emu/Cell/Modules/cellDmux.h @@ -275,196 +275,3 @@ struct CellDmuxAuInfoEx CellCodecTimeStamp pts; CellCodecTimeStamp dts; }; - -/* Demuxer Thread Classes */ - -enum -{ - /* http://dvd.sourceforge.net/dvdinfo/mpeghdrs.html */ - - PACKET_START_CODE_MASK = 0xffffff00, - PACKET_START_CODE_PREFIX = 0x00000100, - - PACK_START_CODE = 0x000001ba, - SYSTEM_HEADER_START_CODE = 0x000001bb, - PRIVATE_STREAM_1 = 0x000001bd, - PADDING_STREAM = 0x000001be, - PRIVATE_STREAM_2 = 0x000001bf, -}; - -struct DemuxerStream -{ - u32 addr; - u32 size; - u64 userdata; - bool discontinuity; - - template - bool get(T& out) - { - if (sizeof(T) > size) return false; - - out = vm::_ref(addr); - addr += sizeof(T); - size -= sizeof(T); - - return true; - } - - template - bool peek(T& out, u32 shift = 0) - { - if (sizeof(T) + shift > size) return false; - - out = vm::_ref(addr + shift); - return true; - } - - void skip(u32 count) - { - addr += count; - size = size > count ? size - count : 0; - } - - bool check(u32 count) const - { - return count <= size; - } - - u64 get_ts(u8 c) - { - u8 v[4]; get((u32&)v); - return - (((u64)c & 0x0e) << 29) | - (((u64)v[0]) << 21) | - (((u64)v[1] & 0x7e) << 15) | - (((u64)v[2]) << 7) | ((u64)v[3] >> 1); - } -}; - -struct PesHeader -{ - u64 pts; - u64 dts; - u8 size; - bool has_ts; - bool is_ok; - - PesHeader(DemuxerStream& stream); -}; - -class ElementaryStream; - -enum DemuxerJobType -{ - dmuxSetStream, - dmuxResetStream, - dmuxResetStreamAndWaitDone, - dmuxEnableEs, - dmuxDisableEs, - dmuxResetEs, - dmuxFlushEs, - dmuxClose, -}; - -struct DemuxerTask -{ - DemuxerJobType type; - - union - { - DemuxerStream stream; - - struct - { - u32 es; - u32 auInfo_ptr_addr; - u32 auSpec_ptr_addr; - ElementaryStream* es_ptr; - } es; - }; - - DemuxerTask() - { - } - - DemuxerTask(DemuxerJobType type) - : type(type) - { - } -}; - -class Demuxer -{ -public: - squeue_t job; - const u32 memAddr; - const u32 memSize; - const vm::ptr cbFunc; - const u32 cbArg; - u32 id; - volatile bool is_finished; - volatile bool is_closed; - atomic_t is_running; - atomic_t is_working; - - std::shared_ptr dmuxCb; - - Demuxer(u32 addr, u32 size, vm::ptr func, u32 arg) - : is_finished(false) - , is_closed(false) - , is_running(false) - , is_working(false) - , memAddr(addr) - , memSize(size) - , cbFunc(func) - , cbArg(arg) - { - } -}; - -class ElementaryStream -{ - std::mutex m_mutex; - - squeue_t entries; // AU starting addresses - u32 put_count; // number of AU written - u32 got_count; // number of AU obtained by GetAu(Ex) - u32 released; // number of AU released - - u32 put; // AU that is being written now - - bool is_full(u32 space); - -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 id_value<> id{}; - const u32 memAddr; - const u32 memSize; - const u32 fidMajor; - const u32 fidMinor; - const u32 sup1; - const u32 sup2; - const vm::ptr cbFunc; - const u32 cbArg; - const u32 spec; //addr - - std::vector raw_data; // demultiplexed data stream (managed by demuxer thread) - size_t raw_pos; // should be <= raw_data.size() - u64 last_dts; - u64 last_pts; - - void push(DemuxerStream& stream, u32 size); // called by demuxer thread (not multithread-safe) - - bool isfull(u32 space); - - void push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool rap, u32 specific); - - bool release(); - - bool peek(u32& out_data, bool no_ex, u32& out_spec, bool update_index); - - void reset(); -}; diff --git a/rpcs3/Emu/Cell/Modules/cellFont.cpp b/rpcs3/Emu/Cell/Modules/cellFont.cpp index cc3df1b933..28bf5953a4 100644 --- a/rpcs3/Emu/Cell/Modules/cellFont.cpp +++ b/rpcs3/Emu/Cell/Modules/cellFont.cpp @@ -82,7 +82,7 @@ s32 cellFontOpenFontFile(vm::ptr library, vm::cptr fontPa return ret; } -s32 cellFontOpenFontset(PPUThread& ppu, vm::ptr library, vm::ptr fontType, vm::ptr font) +s32 cellFontOpenFontset(ppu_thread& ppu, vm::ptr library, vm::ptr fontType, vm::ptr font) { cellFont.warning("cellFontOpenFontset(library=*0x%x, fontType=*0x%x, font=*0x%x)", library, fontType, font); @@ -423,7 +423,7 @@ s32 cellFontGraphicsSetFontRGBA() return CELL_OK; } -s32 cellFontOpenFontsetOnMemory(PPUThread& ppu, vm::ptr library, vm::ptr fontType, vm::ptr font) +s32 cellFontOpenFontsetOnMemory(ppu_thread& ppu, vm::ptr library, vm::ptr fontType, vm::ptr font) { cellFont.todo("cellFontOpenFontsetOnMemory(library=*0x%x, fontType=*0x%x, font=*0x%x)", library, fontType, font); diff --git a/rpcs3/Emu/Cell/Modules/cellFs.cpp b/rpcs3/Emu/Cell/Modules/cellFs.cpp index 56ca4a3524..238c0ad06f 100644 --- a/rpcs3/Emu/Cell/Modules/cellFs.cpp +++ b/rpcs3/Emu/Cell/Modules/cellFs.cpp @@ -8,6 +8,8 @@ #include "Utilities/StrUtil.h" +#include + logs::channel cellFs("cellFs", logs::level::notice); s32 cellFsOpen(vm::cptr path, s32 flags, vm::ptr fd, vm::cptr arg, u64 size) @@ -691,38 +693,58 @@ struct lv2_fs_mount_point std::mutex mutex; }; -void fsAio(vm::ptr aio, bool write, s32 xid, fs_aio_cb_t func) +struct fs_aio_thread : ppu_thread { - cellFs.notice("FS AIO Request(%d): fd=%d, offset=0x%llx, buf=*0x%x, size=0x%llx, user_data=0x%llx", xid, aio->fd, aio->offset, aio->buf, aio->size, aio->user_data); + using ppu_thread::ppu_thread; - s32 error = CELL_OK; - u64 result = 0; - - const auto file = idm::get(aio->fd); - - if (!file || (!write && file->flags & CELL_FS_O_WRONLY) || (write && !(file->flags & CELL_FS_O_ACCMODE))) + virtual void cpu_task() override { - error = CELL_EBADF; + while (ppu_cmd cmd = cmd_wait()) + { + const u32 type = cmd.arg1(); + const s32 xid = cmd.arg2(); + const ppu_cmd cmd2 = cmd_queue[cmd_queue.peek() + 1]; + const auto aio = cmd2.arg1>(); + const auto func = cmd2.arg2(); + cmd_pop(1); + + s32 error = CELL_OK; + u64 result = 0; + + const auto file = idm::get(aio->fd); + + if (!file || (type == 1 && file->flags & CELL_FS_O_WRONLY) || (type == 2 && !(file->flags & CELL_FS_O_ACCMODE))) + { + error = CELL_EBADF; + } + else + { + std::lock_guard lock(file->mp->mutex); + + const auto old_pos = file->file.pos(); file->file.seek(aio->offset); + + result = type == 2 + ? file->op_write(aio->buf, aio->size) + : file->op_read(aio->buf, aio->size); + + file->file.seek(old_pos); + } + + func(*this, aio, error, xid, result); + } } - else +}; + +struct fs_aio_manager +{ + std::shared_ptr t = std::make_shared("FS AIO Thread", 500); + + fs_aio_manager() { - std::lock_guard lock(file->mp->mutex); - - const auto old_pos = file->file.pos(); file->file.seek(aio->offset); - - result = write - ? file->op_write(aio->buf, aio->size) - : file->op_read(aio->buf, aio->size); - - file->file.seek(old_pos); + idm::import_existing(t); + t->run(); } - - // should be executed directly by FS AIO thread - Emu.GetCallbackManager().Async([=](PPUThread& ppu) - { - func(ppu, aio, error, xid, result); - }); -} +}; s32 cellFsAioInit(vm::cptr mount_point) { @@ -730,6 +752,7 @@ s32 cellFsAioInit(vm::cptr mount_point) cellFs.warning("*** mount_point = '%s'", mount_point.get_ptr()); // TODO: create AIO thread (if not exists) for specified mount point + fxm::get_always(); return CELL_OK; } @@ -754,7 +777,15 @@ s32 cellFsAioRead(vm::ptr aio, vm::ptr id, fs_aio_cb_t func) const s32 xid = (*id = ++g_fs_aio_id); - thread_ctrl::spawn("FS AIO Read Thread", COPY_EXPR(fsAio(aio, false, xid, func))); + const auto m = fxm::get_always(); + + m->t->cmd_list + ({ + { 1, xid }, + { aio, func }, + }); + + m->t->lock_notify(); return CELL_OK; } @@ -767,14 +798,22 @@ s32 cellFsAioWrite(vm::ptr aio, vm::ptr id, fs_aio_cb_t func) const s32 xid = (*id = ++g_fs_aio_id); - thread_ctrl::spawn("FS AIO Write Thread", COPY_EXPR(fsAio(aio, true, xid, func))); + const auto m = fxm::get_always(); + + m->t->cmd_list + ({ + { 2, xid }, + { aio, func }, + }); + + m->t->lock_notify(); return CELL_OK; } s32 cellFsAioCancel(s32 id) { - cellFs.warning("cellFsAioCancel(id=%d) -> CELL_EINVAL", id); + cellFs.todo("cellFsAioCancel(id=%d) -> CELL_EINVAL", id); // TODO: cancelled requests return CELL_ECANCELED through their own callbacks diff --git a/rpcs3/Emu/Cell/Modules/cellGame.cpp b/rpcs3/Emu/Cell/Modules/cellGame.cpp index 682f1568ad..d2bd32dad0 100644 --- a/rpcs3/Emu/Cell/Modules/cellGame.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGame.cpp @@ -50,7 +50,7 @@ struct content_permission final } }; -s32 cellHddGameCheck(PPUThread& ppu, u32 version, vm::cptr dirName, u32 errDialog, vm::ptr funcStat, u32 container) +s32 cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr dirName, u32 errDialog, vm::ptr funcStat, u32 container) { cellGame.error("cellHddGameCheck(version=%d, dirName=*0x%x, errDialog=%d, funcStat=*0x%x, container=%d)", version, dirName, errDialog, funcStat, container); @@ -332,7 +332,7 @@ ppu_error_code cellGameContentPermit(vm::ptr contentIn return CELL_OK; } -ppu_error_code cellGameDataCheckCreate2(PPUThread& ppu, u32 version, vm::cptr dirName, u32 errDialog, vm::ptr funcStat, u32 container) +ppu_error_code cellGameDataCheckCreate2(ppu_thread& ppu, u32 version, vm::cptr dirName, u32 errDialog, vm::ptr funcStat, u32 container) { cellGame.error("cellGameDataCheckCreate2(version=0x%x, dirName=*0x%x, errDialog=0x%x, funcStat=*0x%x, container=%d)", version, dirName, errDialog, funcStat, container); @@ -420,7 +420,7 @@ ppu_error_code cellGameDataCheckCreate2(PPUThread& ppu, u32 version, vm::cptr dirName, u32 errDialog, vm::ptr funcStat, u32 container) +s32 cellGameDataCheckCreate(ppu_thread& ppu, u32 version, vm::cptr dirName, u32 errDialog, vm::ptr funcStat, u32 container) { cellGame.warning("cellGameDataCheckCreate(version=0x%x, dirName=*0x%x, errDialog=0x%x, funcStat=*0x%x, container=%d)", version, dirName, errDialog, funcStat, container); diff --git a/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp b/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp index 5331465f4b..3e8112aa95 100644 --- a/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp @@ -396,6 +396,8 @@ s32 _cellGcmInitBody(vm::pptr context, u32 cmdSize, u32 ioSi ctrl.ref = -1; const auto render = fxm::get(); + render->intr_thread = idm::make_ptr("_gcm_intr_thread", 1, 0x4000); + render->intr_thread->run(); 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); @@ -496,7 +498,7 @@ void cellGcmSetFlipStatus() fxm::get()->flip_status = 0; } -s32 cellGcmSetPrepareFlip(PPUThread& ppu, vm::ptr ctxt, u32 id) +s32 cellGcmSetPrepareFlip(ppu_thread& ppu, vm::ptr ctxt, u32 id) { cellGcmSys.trace("cellGcmSetPrepareFlip(ctx=*0x%x, id=0x%x)", ctxt, id); @@ -525,7 +527,7 @@ s32 cellGcmSetPrepareFlip(PPUThread& ppu, vm::ptr ctxt, u32 return id; } -s32 cellGcmSetFlip(PPUThread& ppu, vm::ptr ctxt, u32 id) +s32 cellGcmSetFlip(ppu_thread& ppu, vm::ptr ctxt, u32 id) { cellGcmSys.trace("cellGcmSetFlip(ctxt=*0x%x, id=0x%x)", ctxt, id); @@ -1141,14 +1143,14 @@ s32 cellGcmSetDefaultCommandBufferAndSegmentWordSize() // Other //------------------------------------------------------------------------ -s32 _cellGcmSetFlipCommand(PPUThread& ppu, vm::ptr ctx, u32 id) +s32 _cellGcmSetFlipCommand(ppu_thread& ppu, vm::ptr ctx, u32 id) { cellGcmSys.trace("cellGcmSetFlipCommand(ctx=*0x%x, id=0x%x)", ctx, id); return cellGcmSetPrepareFlip(ppu, ctx, id); } -s32 _cellGcmSetFlipCommandWithWaitLabel(PPUThread& ppu, vm::ptr ctx, u32 id, u32 label_index, u32 label_value) +s32 _cellGcmSetFlipCommandWithWaitLabel(ppu_thread& ppu, vm::ptr ctx, u32 id, u32 label_index, u32 label_value) { cellGcmSys.trace("cellGcmSetFlipCommandWithWaitLabel(ctx=*0x%x, id=0x%x, label_index=0x%x, label_value=0x%x)", ctx, id, label_index, label_value); diff --git a/rpcs3/Emu/Cell/Modules/cellL10n.cpp b/rpcs3/Emu/Cell/Modules/cellL10n.cpp index 7dbc9c3da5..d534e90a54 100644 --- a/rpcs3/Emu/Cell/Modules/cellL10n.cpp +++ b/rpcs3/Emu/Cell/Modules/cellL10n.cpp @@ -9,6 +9,7 @@ typedef int HostCode; #else #include +#include typedef const char *HostCode; #endif diff --git a/rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp b/rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp index e4c7fe221c..a4bd28430c 100644 --- a/rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp +++ b/rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp @@ -92,7 +92,7 @@ s32 cellMsgDialogOpen2(u32 type, vm::cptr msgString, vm::ptr s32 + sysutil_register_cb([=](ppu_thread& ppu) -> s32 { callback(ppu, status, userData); return CELL_OK; @@ -121,7 +121,7 @@ s32 cellMsgDialogOpen2(u32 type, vm::cptr msgString, vm::ptr callback, vm::ptr userData, vm::ptr extParam) +s32 cellMsgDialogOpenErrorCode(ppu_thread& ppu, u32 errorCode, vm::ptr callback, vm::ptr userData, vm::ptr extParam) { cellSysutil.warning("cellMsgDialogOpenErrorCode(errorCode=0x%x, callback=*0x%x, userData=*0x%x, extParam=*0x%x)", errorCode, callback, userData, extParam); diff --git a/rpcs3/Emu/Cell/Modules/cellMusic.cpp b/rpcs3/Emu/Cell/Modules/cellMusic.cpp index 7cd839bfdd..f2b61e49bc 100644 --- a/rpcs3/Emu/Cell/Modules/cellMusic.cpp +++ b/rpcs3/Emu/Cell/Modules/cellMusic.cpp @@ -4,6 +4,7 @@ #include "Emu/Cell/PPUModule.h" #include "cellMusic.h" +#include "cellSysutil.h" logs::channel cellMusic("cellMusic", logs::level::notice); @@ -122,7 +123,7 @@ s32 cellMusicInitialize2(s32 mode, s32 spuPriority, vm::ptr music->func = func; music->userData = userData; - Emu.GetCallbackManager().Register([=](PPUThread& ppu) -> s32 + sysutil_register_cb([=](ppu_thread& ppu) -> s32 { func(ppu, CELL_MUSIC2_EVENT_INITIALIZE_RESULT, vm::make_var(CELL_OK), userData); return CELL_OK; diff --git a/rpcs3/Emu/Cell/Modules/cellNetCtl.cpp b/rpcs3/Emu/Cell/Modules/cellNetCtl.cpp index 4114c89444..b1e2a21363 100644 --- a/rpcs3/Emu/Cell/Modules/cellNetCtl.cpp +++ b/rpcs3/Emu/Cell/Modules/cellNetCtl.cpp @@ -101,8 +101,8 @@ s32 cellNetCtlNetStartDialogLoadAsync(vm::ptr par // 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); + sysutil_send_system_cmd(CELL_SYSUTIL_NET_CTL_NETSTART_LOADED, 0); + sysutil_send_system_cmd(CELL_SYSUTIL_NET_CTL_NETSTART_FINISHED, 0); return CELL_OK; } @@ -119,7 +119,7 @@ s32 cellNetCtlNetStartDialogUnloadAsync(vm::ptr cellNetCtl.warning("cellNetCtlNetStartDialogUnloadAsync(result=*0x%x)", result); result->result = CELL_NET_CTL_ERROR_DIALOG_CANCELED; - sysutilSendSystemCommand(CELL_SYSUTIL_NET_CTL_NETSTART_UNLOADED, 0); + sysutil_send_system_cmd(CELL_SYSUTIL_NET_CTL_NETSTART_UNLOADED, 0); return CELL_OK; } diff --git a/rpcs3/Emu/Cell/Modules/cellPngDec.cpp b/rpcs3/Emu/Cell/Modules/cellPngDec.cpp index 79991b56f9..a15af64369 100644 --- a/rpcs3/Emu/Cell/Modules/cellPngDec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPngDec.cpp @@ -244,7 +244,7 @@ be_t pngDecGetChunkInformation(PStream stream, bool IDAT = false) return chunk_information; } -s32 pngDecCreate(PPUThread& ppu, PPHandle png_handle, PThreadInParam thread_in_param, PThreadOutParam thread_out_param, PExtThreadInParam extra_thread_in_param = vm::null, PExtThreadOutParam extra_thread_out_param = vm::null) +s32 pngDecCreate(ppu_thread& ppu, PPHandle png_handle, PThreadInParam thread_in_param, PThreadOutParam thread_out_param, PExtThreadInParam extra_thread_in_param = vm::null, PExtThreadOutParam extra_thread_out_param = vm::null) { // Check if partial image decoding is used if (extra_thread_out_param) @@ -277,7 +277,7 @@ s32 pngDecCreate(PPUThread& ppu, PPHandle png_handle, PThreadInParam thread_in_p return CELL_OK; } -s32 pngDecDestroy(PPUThread& ppu, PHandle handle) +s32 pngDecDestroy(ppu_thread& ppu, PHandle handle) { // Deallocate the decoder handle memory if (handle->free(ppu, handle, handle->free_arg) != 0) @@ -289,7 +289,7 @@ s32 pngDecDestroy(PPUThread& ppu, PHandle handle) return CELL_OK; } -s32 pngDecOpen(PPUThread& ppu, PHandle handle, PPStream png_stream, PSrc source, POpenInfo open_info, PCbControlStream control_stream = vm::null, POpenParam open_param = vm::null) +s32 pngDecOpen(ppu_thread& ppu, PHandle handle, PPStream png_stream, PSrc source, POpenInfo open_info, PCbControlStream control_stream = vm::null, POpenParam open_param = vm::null) { // Check if partial image decoding is used if (control_stream || open_param) @@ -442,7 +442,7 @@ s32 pngDecOpen(PPUThread& ppu, PHandle handle, PPStream png_stream, PSrc source, return CELL_OK; } -s32 pngDecClose(PPUThread& ppu, PHandle handle, PStream stream) +s32 pngDecClose(ppu_thread& ppu, PHandle handle, PStream stream) { // Remove the file descriptor, if a file descriptor was used for decoding if (stream->buffer->file) @@ -555,7 +555,7 @@ s32 pngDecSetParameter(PStream stream, PInParam in_param, POutParam out_param, P return CELL_OK; } -s32 pngDecodeData(PPUThread& ppu, PHandle handle, PStream stream, vm::ptr data, PDataControlParam data_control_param, PDataOutInfo data_out_info, PCbControlDisp cb_control_disp = vm::null, PDispParam disp_param = vm::null) +s32 pngDecodeData(ppu_thread& ppu, PHandle handle, PStream stream, vm::ptr data, PDataControlParam data_control_param, PDataOutInfo data_out_info, PCbControlDisp cb_control_disp = vm::null, PDispParam disp_param = vm::null) { if (cb_control_disp || disp_param) { @@ -703,37 +703,37 @@ s32 pngDecodeData(PPUThread& ppu, PHandle handle, PStream stream, vm::ptr da return CELL_OK; } -s32 cellPngDecCreate(PPUThread& ppu, PPHandle handle, PThreadInParam threadInParam, PThreadOutParam threadOutParam) +s32 cellPngDecCreate(ppu_thread& ppu, PPHandle handle, PThreadInParam threadInParam, PThreadOutParam threadOutParam) { cellPngDec.warning("cellPngDecCreate(handle=**0x%x, threadInParam=*0x%x, threadOutParam=*0x%x)", handle, threadInParam, threadOutParam); return pngDecCreate(ppu, handle, threadInParam, threadOutParam); } -s32 cellPngDecExtCreate(PPUThread& ppu, PPHandle handle, PThreadInParam threadInParam, PThreadOutParam threadOutParam, PExtThreadInParam extThreadInParam, PExtThreadOutParam extThreadOutParam) +s32 cellPngDecExtCreate(ppu_thread& ppu, PPHandle handle, PThreadInParam threadInParam, PThreadOutParam threadOutParam, PExtThreadInParam extThreadInParam, PExtThreadOutParam extThreadOutParam) { cellPngDec.warning("cellPngDecCreate(mainHandle=**0x%x, threadInParam=*0x%x, threadOutParam=*0x%x, extThreadInParam=*0x%x, extThreadOutParam=*0x%x)", handle, threadInParam, threadOutParam, extThreadInParam, extThreadOutParam); return pngDecCreate(ppu, handle, threadInParam, threadOutParam, extThreadInParam, extThreadOutParam); } -s32 cellPngDecDestroy(PPUThread& ppu, PHandle handle) +s32 cellPngDecDestroy(ppu_thread& ppu, PHandle handle) { cellPngDec.warning("cellPngDecDestroy(mainHandle=*0x%x)", handle); return pngDecDestroy(ppu, handle); } -s32 cellPngDecOpen(PPUThread& ppu, PHandle handle, PPStream stream, PSrc src, POpenInfo openInfo) +s32 cellPngDecOpen(ppu_thread& ppu, PHandle handle, PPStream stream, PSrc src, POpenInfo openInfo) { cellPngDec.warning("cellPngDecOpen(handle=*0x%x, stream=**0x%x, src=*0x%x, openInfo=*0x%x)", handle, stream, src, openInfo); return pngDecOpen(ppu, handle, stream, src, openInfo); } -s32 cellPngDecExtOpen(PPUThread& ppu, PHandle handle, PPStream stream, PSrc src, POpenInfo openInfo, PCbControlStream cbCtrlStrm, POpenParam opnParam) +s32 cellPngDecExtOpen(ppu_thread& ppu, PHandle handle, PPStream stream, PSrc src, POpenInfo openInfo, PCbControlStream cbCtrlStrm, POpenParam opnParam) { cellPngDec.warning("cellPngDecExtOpen(handle=*0x%x, stream=**0x%x, src=*0x%x, openInfo=*0x%x, cbCtrlStrm=*0x%x, opnParam=*0x%x)", handle, stream, src, openInfo, cbCtrlStrm, opnParam); return pngDecOpen(ppu, handle, stream, src, openInfo, cbCtrlStrm, opnParam); } -s32 cellPngDecClose(PPUThread& ppu, PHandle handle, PStream stream) +s32 cellPngDecClose(ppu_thread& ppu, PHandle handle, PStream stream) { cellPngDec.warning("cellPngDecClose(handle=*0x%x, stream=*0x%x)", handle, stream); return pngDecClose(ppu, handle, stream); @@ -763,13 +763,13 @@ s32 cellPngDecExtSetParameter(PHandle handle, PStream stream, PInParam inParam, return pngDecSetParameter(stream, inParam, outParam, extInParam, extOutParam); } -s32 cellPngDecDecodeData(PPUThread& ppu, PHandle handle, PStream stream, vm::ptr data, PDataControlParam dataCtrlParam, PDataOutInfo dataOutInfo) +s32 cellPngDecDecodeData(ppu_thread& ppu, PHandle handle, PStream stream, vm::ptr data, PDataControlParam dataCtrlParam, PDataOutInfo dataOutInfo) { cellPngDec.warning("cellPngDecDecodeData(handle=*0x%x, stream=*0x%x, data=*0x%x, dataCtrlParam=*0x%x, dataOutInfo=*0x%x)", handle, stream, data, dataCtrlParam, dataOutInfo); return pngDecodeData(ppu, handle, stream, data, dataCtrlParam, dataOutInfo); } -s32 cellPngDecExtDecodeData(PPUThread& ppu, PHandle handle, PStream stream, vm::ptr data, PDataControlParam dataCtrlParam, PDataOutInfo dataOutInfo, PCbControlDisp cbCtrlDisp, PDispParam dispParam) +s32 cellPngDecExtDecodeData(ppu_thread& ppu, PHandle handle, PStream stream, vm::ptr data, PDataControlParam dataCtrlParam, PDataOutInfo dataOutInfo, PCbControlDisp cbCtrlDisp, PDispParam dispParam) { cellPngDec.warning("cellPngDecExtDecodeData(handle=*0x%x, stream=*0x%x, data=*0x%x, dataCtrlParam=*0x%x, dataOutInfo=*0x%x, cbCtrlDisp=*0x%x, dispParam=*0x%x)", handle, stream, data, dataCtrlParam, dataOutInfo, cbCtrlDisp, dispParam); return pngDecodeData(ppu, handle, stream, data, dataCtrlParam, dataOutInfo, cbCtrlDisp, dispParam); diff --git a/rpcs3/Emu/Cell/Modules/cellResc.cpp b/rpcs3/Emu/Cell/Modules/cellResc.cpp index 182bfd0e14..14df3537e5 100644 --- a/rpcs3/Emu/Cell/Modules/cellResc.cpp +++ b/rpcs3/Emu/Cell/Modules/cellResc.cpp @@ -83,7 +83,7 @@ s32 cellRescSetSrc(s32 idx, vm::ptr src) return CELL_OK; } -s32 cellRescSetConvertAndFlip(PPUThread& ppu, vm::ptr cntxt, s32 idx) +s32 cellRescSetConvertAndFlip(ppu_thread& ppu, vm::ptr cntxt, s32 idx) { cellResc.todo("cellRescSetConvertAndFlip(cntxt=*0x%x, idx=0x%x)", cntxt, idx); diff --git a/rpcs3/Emu/Cell/Modules/cellRudp.cpp b/rpcs3/Emu/Cell/Modules/cellRudp.cpp index c7ae11dfda..d3c3195db3 100644 --- a/rpcs3/Emu/Cell/Modules/cellRudp.cpp +++ b/rpcs3/Emu/Cell/Modules/cellRudp.cpp @@ -10,8 +10,8 @@ logs::channel cellRudp("cellRudp", logs::level::notice); struct rudp_t { // allocator functions - std::function(PPUThread& ppu, u32 size)> malloc; - std::function ptr)> free; + std::function(ppu_thread& ppu, u32 size)> malloc; + std::function ptr)> free; // event handler function vm::ptr handler = vm::null; @@ -36,12 +36,12 @@ s32 cellRudpInit(vm::ptr allocator) } else { - rudp->malloc = [](PPUThread& ppu, u32 size) + rudp->malloc = [](ppu_thread& ppu, u32 size) { return vm::ptr::make(vm::alloc(size, vm::main)); }; - rudp->free = [](PPUThread& ppu, vm::ptr ptr) + rudp->free = [](ppu_thread& ppu, vm::ptr ptr) { if (!vm::dealloc(ptr.addr(), vm::main)) { diff --git a/rpcs3/Emu/Cell/Modules/cellSail.cpp b/rpcs3/Emu/Cell/Modules/cellSail.cpp index 970bd2a324..63acd78d40 100644 --- a/rpcs3/Emu/Cell/Modules/cellSail.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSail.cpp @@ -7,28 +7,6 @@ logs::channel cellSail("cellSail", logs::level::notice); -void playerBoot(vm::ptr pSelf, u64 userParam) -{ - Emu.GetCallbackManager().Async([=](PPUThread& ppu) - { - CellSailEvent event; - event.u32x2.major = CELL_SAIL_EVENT_PLAYER_STATE_CHANGED; - event.u32x2.minor = 0; - pSelf->callback(ppu, pSelf->callbackArg, event, CELL_SAIL_PLAYER_STATE_BOOT_TRANSITION, 0); - }); - - // TODO: Do stuff here - pSelf->booted = true; - - Emu.GetCallbackManager().Async([=](PPUThread& ppu) - { - CellSailEvent event; - event.u32x2.major = CELL_SAIL_EVENT_PLAYER_CALL_COMPLETED; - event.u32x2.minor = CELL_SAIL_PLAYER_CALL_BOOT; - pSelf->callback(ppu, pSelf->callbackArg, event, 0, 0); - }); -} - s32 cellSailMemAllocatorInitialize(vm::ptr pSelf, vm::ptr pCallbacks) { cellSail.warning("cellSailMemAllocatorInitialize(pSelf=*0x%x, pCallbacks=*0x%x)", pSelf, pCallbacks); @@ -611,7 +589,7 @@ s32 cellSailPlayerInitialize() return CELL_OK; } -s32 cellSailPlayerInitialize2( +s32 cellSailPlayerInitialize2(ppu_thread& ppu, vm::ptr pSelf, vm::ptr pAllocator, vm::ptr pCallback, @@ -630,13 +608,12 @@ s32 cellSailPlayerInitialize2( pSelf->booted = false; pSelf->paused = true; - Emu.GetCallbackManager().Async([=](PPUThread& ppu) { CellSailEvent event; event.u32x2.major = CELL_SAIL_EVENT_PLAYER_STATE_CHANGED; event.u32x2.minor = 0; pSelf->callback(ppu, pSelf->callbackArg, event, CELL_SAIL_PLAYER_STATE_INITIALIZED, 0); - }); + }; return CELL_OK; } @@ -765,11 +742,26 @@ s32 cellSailPlayerReplaceEventHandler() return CELL_OK; } -s32 cellSailPlayerBoot(PPUThread& ppu, vm::ptr pSelf, u64 userParam) +s32 cellSailPlayerBoot(ppu_thread& ppu, vm::ptr pSelf, u64 userParam) { cellSail.warning("cellSailPlayerBoot(pSelf=*0x%x, userParam=%d)", pSelf, userParam); - playerBoot(pSelf, userParam); + { + CellSailEvent event; + event.u32x2.major = CELL_SAIL_EVENT_PLAYER_STATE_CHANGED; + event.u32x2.minor = 0; + pSelf->callback(ppu, pSelf->callbackArg, event, CELL_SAIL_PLAYER_STATE_BOOT_TRANSITION, 0); + }; + + // TODO: Do stuff here + pSelf->booted = true; + + { + CellSailEvent event; + event.u32x2.major = CELL_SAIL_EVENT_PLAYER_CALL_COMPLETED; + event.u32x2.minor = CELL_SAIL_PLAYER_CALL_BOOT; + pSelf->callback(ppu, pSelf->callbackArg, event, 0, 0); + }; return CELL_OK; } diff --git a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp index 313a2ac90f..6388e65150 100644 --- a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp @@ -7,6 +7,7 @@ #include "Loader/PSF.h" #include "Utilities/StrUtil.h" +#include #include logs::channel cellSaveData("cellSaveData", logs::level::notice); @@ -36,7 +37,7 @@ enum : u32 std::mutex g_savedata_mutex; -static never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cptr dirName, +static never_inline s32 savedata_op(ppu_thread& 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) { @@ -618,7 +619,7 @@ static never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, } // Functions -s32 cellSaveDataListSave2(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncList funcList, +s32 cellSaveDataListSave2(ppu_thread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { 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)", @@ -627,7 +628,7 @@ s32 cellSaveDataListSave2(PPUThread& ppu, u32 version, PSetList setList, PSetBuf 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); } -s32 cellSaveDataListLoad2(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncList funcList, +s32 cellSaveDataListLoad2(ppu_thread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { 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)", @@ -636,7 +637,7 @@ s32 cellSaveDataListLoad2(PPUThread& ppu, u32 version, PSetList setList, PSetBuf 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); } -s32 cellSaveDataListSave(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncList funcList, +s32 cellSaveDataListSave(ppu_thread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncStat funcStat, PFuncFile funcFile, u32 container) { cellSaveData.warning("cellSaveDataListSave(version=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", @@ -645,7 +646,7 @@ s32 cellSaveDataListSave(PPUThread& ppu, u32 version, PSetList setList, PSetBuf 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); } -s32 cellSaveDataListLoad(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncList funcList, +s32 cellSaveDataListLoad(ppu_thread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncStat funcStat, PFuncFile funcFile, u32 container) { cellSaveData.warning("cellSaveDataListLoad(version=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", @@ -655,7 +656,7 @@ s32 cellSaveDataListLoad(PPUThread& ppu, u32 version, PSetList setList, PSetBuf } -s32 cellSaveDataFixedSave2(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, +s32 cellSaveDataFixedSave2(ppu_thread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { 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)", @@ -664,7 +665,7 @@ s32 cellSaveDataFixedSave2(PPUThread& ppu, u32 version, PSetList setList, PSetBu 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); } -s32 cellSaveDataFixedLoad2(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, +s32 cellSaveDataFixedLoad2(ppu_thread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { 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)", @@ -673,7 +674,7 @@ s32 cellSaveDataFixedLoad2(PPUThread& ppu, u32 version, PSetList setList, PSetBu 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); } -s32 cellSaveDataFixedSave(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, +s32 cellSaveDataFixedSave(ppu_thread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container) { cellSaveData.warning("cellSaveDataFixedSave(version=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", @@ -683,7 +684,7 @@ s32 cellSaveDataFixedSave(PPUThread& ppu, u32 version, PSetList setList, PSetBuf } -s32 cellSaveDataFixedLoad(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, +s32 cellSaveDataFixedLoad(ppu_thread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container) { cellSaveData.warning("cellSaveDataFixedLoad(version=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", @@ -692,7 +693,7 @@ s32 cellSaveDataFixedLoad(PPUThread& ppu, u32 version, PSetList setList, PSetBuf 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); } -s32 cellSaveDataAutoSave2(PPUThread& ppu, u32 version, vm::cptr dirName, u32 errDialog, PSetBuf setBuf, +s32 cellSaveDataAutoSave2(ppu_thread& ppu, u32 version, vm::cptr dirName, u32 errDialog, PSetBuf setBuf, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { 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)", @@ -701,7 +702,7 @@ s32 cellSaveDataAutoSave2(PPUThread& ppu, u32 version, vm::cptr dirName, u 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); } -s32 cellSaveDataAutoLoad2(PPUThread& ppu, u32 version, vm::cptr dirName, u32 errDialog, PSetBuf setBuf, +s32 cellSaveDataAutoLoad2(ppu_thread& ppu, u32 version, vm::cptr dirName, u32 errDialog, PSetBuf setBuf, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { 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)", @@ -710,7 +711,7 @@ s32 cellSaveDataAutoLoad2(PPUThread& ppu, u32 version, vm::cptr dirName, u 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); } -s32 cellSaveDataAutoSave(PPUThread& ppu, u32 version, vm::cptr dirName, u32 errDialog, PSetBuf setBuf, +s32 cellSaveDataAutoSave(ppu_thread& ppu, u32 version, vm::cptr dirName, u32 errDialog, PSetBuf setBuf, PFuncStat funcStat, PFuncFile funcFile, u32 container) { cellSaveData.warning("cellSaveDataAutoSave(version=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", @@ -719,7 +720,7 @@ s32 cellSaveDataAutoSave(PPUThread& ppu, u32 version, vm::cptr dirName, u3 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); } -s32 cellSaveDataAutoLoad(PPUThread& ppu, u32 version, vm::cptr dirName, u32 errDialog, PSetBuf setBuf, +s32 cellSaveDataAutoLoad(ppu_thread& ppu, u32 version, vm::cptr dirName, u32 errDialog, PSetBuf setBuf, PFuncStat funcStat, PFuncFile funcFile, u32 container) { cellSaveData.warning("cellSaveDataAutoLoad(version=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", @@ -728,7 +729,7 @@ s32 cellSaveDataAutoLoad(PPUThread& ppu, u32 version, vm::cptr dirName, u3 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); } -s32 cellSaveDataListAutoSave(PPUThread& ppu, u32 version, u32 errDialog, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) +s32 cellSaveDataListAutoSave(ppu_thread& ppu, u32 version, u32 errDialog, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { 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); @@ -736,7 +737,7 @@ s32 cellSaveDataListAutoSave(PPUThread& ppu, u32 version, u32 errDialog, PSetLis 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); } -s32 cellSaveDataListAutoLoad(PPUThread& ppu, u32 version, u32 errDialog, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) +s32 cellSaveDataListAutoLoad(ppu_thread& ppu, u32 version, u32 errDialog, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { 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); @@ -758,7 +759,7 @@ s32 cellSaveDataDelete(u32 container) return CELL_SAVEDATA_RET_CANCEL; } -s32 cellSaveDataFixedDelete(PPUThread& ppu, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncDone funcDone, u32 container, vm::ptr userdata) +s32 cellSaveDataFixedDelete(ppu_thread& ppu, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncDone funcDone, u32 container, vm::ptr userdata) { 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); @@ -766,7 +767,7 @@ s32 cellSaveDataFixedDelete(PPUThread& ppu, PSetList setList, PSetBuf setBuf, PF return CELL_OK; } -s32 cellSaveDataUserListSave(PPUThread& ppu, u32 version, u32 userId, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) +s32 cellSaveDataUserListSave(ppu_thread& ppu, u32 version, u32 userId, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { 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); @@ -774,7 +775,7 @@ s32 cellSaveDataUserListSave(PPUThread& ppu, u32 version, u32 userId, PSetList s 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); } -s32 cellSaveDataUserListLoad(PPUThread& ppu, u32 version, u32 userId, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) +s32 cellSaveDataUserListLoad(ppu_thread& ppu, u32 version, u32 userId, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { 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); @@ -782,7 +783,7 @@ s32 cellSaveDataUserListLoad(PPUThread& ppu, u32 version, u32 userId, PSetList s 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); } -s32 cellSaveDataUserFixedSave(PPUThread& ppu, u32 version, u32 userId, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) +s32 cellSaveDataUserFixedSave(ppu_thread& ppu, u32 version, u32 userId, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { 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); @@ -790,7 +791,7 @@ s32 cellSaveDataUserFixedSave(PPUThread& ppu, u32 version, u32 userId, PSetList 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); } -s32 cellSaveDataUserFixedLoad(PPUThread& ppu, u32 version, u32 userId, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) +s32 cellSaveDataUserFixedLoad(ppu_thread& ppu, u32 version, u32 userId, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { 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); @@ -798,7 +799,7 @@ s32 cellSaveDataUserFixedLoad(PPUThread& ppu, u32 version, u32 userId, PSetList 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); } -s32 cellSaveDataUserAutoSave(PPUThread& ppu, u32 version, u32 userId, vm::cptr dirName, u32 errDialog, PSetBuf setBuf, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) +s32 cellSaveDataUserAutoSave(ppu_thread& ppu, u32 version, u32 userId, vm::cptr dirName, u32 errDialog, PSetBuf setBuf, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { 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); @@ -806,7 +807,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) +s32 cellSaveDataUserAutoLoad(ppu_thread& ppu, u32 version, u32 userId, vm::cptr dirName, u32 errDialog, PSetBuf setBuf, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { 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); @@ -814,7 +815,7 @@ s32 cellSaveDataUserAutoLoad(PPUThread& ppu, u32 version, u32 userId, vm::cptr userdata) +s32 cellSaveDataUserListAutoSave(ppu_thread& ppu, u32 version, u32 userId, u32 errDialog, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { 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); @@ -822,7 +823,7 @@ s32 cellSaveDataUserListAutoSave(PPUThread& ppu, u32 version, u32 userId, u32 er 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); } -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) +s32 cellSaveDataUserListAutoLoad(ppu_thread& ppu, u32 version, u32 userId, u32 errDialog, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { 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); @@ -830,7 +831,7 @@ s32 cellSaveDataUserListAutoLoad(PPUThread& ppu, u32 version, u32 userId, u32 er 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); } -s32 cellSaveDataUserFixedDelete(PPUThread& ppu, u32 userId, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncDone funcDone, u32 container, vm::ptr userdata) +s32 cellSaveDataUserFixedDelete(ppu_thread& ppu, u32 userId, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncDone funcDone, u32 container, vm::ptr userdata) { 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); @@ -847,35 +848,35 @@ void cellSaveDataEnableOverlay(s32 enable) // Functions (Extensions) -s32 cellSaveDataListDelete(PPUThread& ppu, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncDone funcDone, u32 container, vm::ptr userdata) +s32 cellSaveDataListDelete(ppu_thread& ppu, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncDone funcDone, u32 container, vm::ptr userdata) { UNIMPLEMENTED_FUNC(cellSaveData); return CELL_OK; } -s32 cellSaveDataListImport(PPUThread& ppu, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) +s32 cellSaveDataListImport(ppu_thread& ppu, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) { UNIMPLEMENTED_FUNC(cellSaveData); return CELL_OK; } -s32 cellSaveDataListExport(PPUThread& ppu, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) +s32 cellSaveDataListExport(ppu_thread& ppu, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) { UNIMPLEMENTED_FUNC(cellSaveData); return CELL_OK; } -s32 cellSaveDataFixedImport(PPUThread& ppu, vm::cptr dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) +s32 cellSaveDataFixedImport(ppu_thread& ppu, vm::cptr dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) { UNIMPLEMENTED_FUNC(cellSaveData); return CELL_OK; } -s32 cellSaveDataFixedExport(PPUThread& ppu, vm::cptr dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) +s32 cellSaveDataFixedExport(ppu_thread& ppu, vm::cptr dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) { UNIMPLEMENTED_FUNC(cellSaveData); @@ -889,35 +890,35 @@ s32 cellSaveDataGetListItem(vm::cptr dirName, vm::ptr return CELL_OK; } -s32 cellSaveDataUserListDelete(PPUThread& ppu, u32 userId, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncDone funcDone, u32 container, vm::ptr userdata) +s32 cellSaveDataUserListDelete(ppu_thread& ppu, u32 userId, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncDone funcDone, u32 container, vm::ptr userdata) { UNIMPLEMENTED_FUNC(cellSaveData); return CELL_OK; } -s32 cellSaveDataUserListImport(PPUThread& ppu, u32 userId, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) +s32 cellSaveDataUserListImport(ppu_thread& ppu, u32 userId, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) { UNIMPLEMENTED_FUNC(cellSaveData); return CELL_OK; } -s32 cellSaveDataUserListExport(PPUThread& ppu, u32 userId, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) +s32 cellSaveDataUserListExport(ppu_thread& ppu, u32 userId, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) { UNIMPLEMENTED_FUNC(cellSaveData); return CELL_OK; } -s32 cellSaveDataUserFixedImport(PPUThread& ppu, u32 userId, vm::cptr dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) +s32 cellSaveDataUserFixedImport(ppu_thread& ppu, u32 userId, vm::cptr dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) { UNIMPLEMENTED_FUNC(cellSaveData); return CELL_OK; } -s32 cellSaveDataUserFixedExport(PPUThread& ppu, u32 userId, vm::cptr dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) +s32 cellSaveDataUserFixedExport(ppu_thread& ppu, u32 userId, vm::cptr dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) { UNIMPLEMENTED_FUNC(cellSaveData); diff --git a/rpcs3/Emu/Cell/Modules/cellSpurs.cpp b/rpcs3/Emu/Cell/Modules/cellSpurs.cpp index e4946f9d88..a07623d74f 100644 --- a/rpcs3/Emu/Cell/Modules/cellSpurs.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSpurs.cpp @@ -30,28 +30,6 @@ struct cell_error_t #define CHECK_SUCCESS(expr) if (cell_error_t error{expr}) throw fmt::exception("Failure: %s -> 0x%x" HERE, #expr, error.value) -static u32 ppu_thread_create(u32 entry, u64 arg, s32 prio, u32 stacksize, const std::string& name, std::function task) -{ - const auto ppu = idm::make_ptr(name); - - ppu->prio = prio; - ppu->stack_size = stacksize; - ppu->custom_task = std::move(task); - ppu->cpu_init(); - - if (entry) - { - ppu->pc = vm::read32(entry); - ppu->GPR[2] = vm::read32(entry + 4); // rtoc - } - - ppu->GPR[3] = arg; - ppu->state -= cpu_state::stop; - (*ppu)->lock_notify(); - - return ppu->id; -} - //---------------------------------------------------------------------------- // Function prototypes //---------------------------------------------------------------------------- @@ -68,34 +46,34 @@ namespace _spurs bool is_libprof_loaded(); // Create an LV2 event queue and attach it to the SPURS instance - s32 create_lv2_eq(PPUThread& ppu, vm::ptr spurs, vm::ptr queueId, vm::ptr port, s32 size, const sys_event_queue_attribute_t& name); + s32 create_lv2_eq(ppu_thread& ppu, vm::ptr spurs, vm::ptr queueId, vm::ptr port, s32 size, const sys_event_queue_attribute_t& name); // Attach an LV2 event queue to the SPURS instance - s32 attach_lv2_eq(PPUThread& ppu, vm::ptr spurs, u32 queue, vm::ptr port, s32 isDynamic, bool spursCreated); + s32 attach_lv2_eq(ppu_thread& ppu, vm::ptr spurs, u32 queue, vm::ptr port, s32 isDynamic, bool spursCreated); // Detach an LV2 event queue from the SPURS instance s32 detach_lv2_eq(vm::ptr spurs, u8 spuPort, bool spursCreated); // Wait until a workload in the SPURS instance becomes ready - void handler_wait_ready(PPUThread& ppu, vm::ptr spurs); + void handler_wait_ready(ppu_thread& ppu, vm::ptr spurs); // Entry point of the SPURS handler thread. This thread is responsible for starting the SPURS SPU thread group. - void handler_entry(PPUThread& ppu, vm::ptr spurs); + void handler_entry(ppu_thread& ppu, vm::ptr spurs); // Create the SPURS handler thread s32 create_handler(vm::ptr spurs, u32 ppuPriority); // Invoke event handlers - s32 invoke_event_handlers(PPUThread& ppu, vm::ptr eventPortMux); + s32 invoke_event_handlers(ppu_thread& ppu, vm::ptr eventPortMux); // Invoke workload shutdown completion callbacks - s32 wakeup_shutdown_completion_waiter(PPUThread& ppu, vm::ptr spurs, u32 wid); + s32 wakeup_shutdown_completion_waiter(ppu_thread& ppu, vm::ptr spurs, u32 wid); // Entry point of the SPURS event helper thread - void event_helper_entry(PPUThread& ppu, vm::ptr spurs); + void event_helper_entry(ppu_thread& ppu, vm::ptr spurs); // Create the SPURS event helper thread - s32 create_event_helper(PPUThread& ppu, vm::ptr spurs, u32 ppuPriority); + s32 create_event_helper(ppu_thread& ppu, vm::ptr spurs, u32 ppuPriority); // Initialise the event port multiplexor structure void init_event_port_mux(vm::ptr eventPortMux, u8 spuPort, u32 eventPort, u32 unknown); @@ -107,25 +85,25 @@ namespace _spurs s32 finalize_spu(vm::ptr spurs); // Stop the event helper thread - s32 stop_event_helper(PPUThread& ppu, vm::ptr spurs); + s32 stop_event_helper(ppu_thread& ppu, vm::ptr spurs); // Signal to the SPURS handler thread - s32 signal_to_handler_thread(PPUThread& ppu, vm::ptr spurs); + s32 signal_to_handler_thread(ppu_thread& ppu, vm::ptr spurs); // Join the SPURS handler thread - s32 join_handler_thread(PPUThread& ppu, vm::ptr spurs); + s32 join_handler_thread(ppu_thread& ppu, vm::ptr spurs); // Initialise SPURS - s32 initialize(PPUThread& ppu, vm::ptr spurs, u32 revision, u32 sdkVersion, s32 nSpus, s32 spuPriority, s32 ppuPriority, u32 flags, vm::cptr prefix, u32 prefixSize, u32 container, vm::cptr swlPriority, u32 swlMaxSpu, u32 swlIsPreem); + s32 initialize(ppu_thread& ppu, vm::ptr spurs, u32 revision, u32 sdkVersion, s32 nSpus, s32 spuPriority, s32 ppuPriority, u32 flags, vm::cptr prefix, u32 prefixSize, u32 container, vm::cptr swlPriority, u32 swlMaxSpu, u32 swlIsPreem); } // // SPURS Core Functions // -//s32 cellSpursInitialize(PPUThread& ppu, vm::ptr spurs, s32 nSpus, s32 spuPriority, s32 ppuPriority, b8 exitIfNoWork); -//s32 cellSpursInitializeWithAttribute(PPUThread& ppu, vm::ptr spurs, vm::cptr attr); -//s32 cellSpursInitializeWithAttribute2(PPUThread& ppu, vm::ptr spurs, vm::cptr attr); +//s32 cellSpursInitialize(ppu_thread& ppu, vm::ptr spurs, s32 nSpus, s32 spuPriority, s32 ppuPriority, b8 exitIfNoWork); +//s32 cellSpursInitializeWithAttribute(ppu_thread& ppu, vm::ptr spurs, vm::cptr attr); +//s32 cellSpursInitializeWithAttribute2(ppu_thread& ppu, vm::ptr spurs, vm::cptr attr); //s32 _cellSpursAttributeInitialize(vm::ptr attr, u32 revision, u32 sdkVersion, u32 nSpus, s32 spuPriority, s32 ppuPriority, b8 exitIfNoWork); //s32 cellSpursAttributeSetMemoryContainerForSpuThread(vm::ptr attr, u32 container); //s32 cellSpursAttributeSetNamePrefix(vm::ptr attr, vm::cptr prefix, u32 size); @@ -139,7 +117,7 @@ namespace _spurs //s32 cellSpursSetMaxContention(vm::ptr spurs, u32 wid, u32 maxContention); //s32 cellSpursSetPriorities(vm::ptr spurs, u32 wid, vm::cptr priorities); //s32 cellSpursSetPreemptionVictimHints(vm::ptr spurs, vm::cptr isPreemptible); -//s32 cellSpursAttachLv2EventQueue(PPUThread& ppu, vm::ptr spurs, u32 queue, vm::ptr port, s32 isDynamic); +//s32 cellSpursAttachLv2EventQueue(ppu_thread& ppu, vm::ptr spurs, u32 queue, vm::ptr port, s32 isDynamic); //s32 cellSpursDetachLv2EventQueue(vm::ptr spurs, u8 port); // Enable the SPU exception event handler @@ -162,22 +140,22 @@ s32 cellSpursEnableExceptionEventHandler(vm::ptr spurs, b8 flag); namespace _spurs { // Signal SPUs to update trace status - void trace_status_update(PPUThread& ppu, vm::ptr spurs); + void trace_status_update(ppu_thread& ppu, vm::ptr spurs); // Initialize SPURS trace - s32 trace_initialize(PPUThread& ppu, vm::ptr spurs, vm::ptr buffer, u32 size, u32 mode, u32 updateStatus); + s32 trace_initialize(ppu_thread& ppu, vm::ptr spurs, vm::ptr buffer, u32 size, u32 mode, u32 updateStatus); // Start SPURS trace - s32 trace_start(PPUThread& ppu, vm::ptr spurs, u32 updateStatus); + s32 trace_start(ppu_thread& ppu, vm::ptr spurs, u32 updateStatus); // Stop SPURS trace - s32 trace_stop(PPUThread& ppu, vm::ptr spurs, u32 updateStatus); + s32 trace_stop(ppu_thread& ppu, vm::ptr spurs, u32 updateStatus); } -//s32 cellSpursTraceInitialize(PPUThread& ppu, vm::ptr spurs, vm::ptr buffer, u32 size, u32 mode); -//s32 cellSpursTraceFinalize(PPUThread& ppu, vm::ptr spurs); -//s32 cellSpursTraceStart(PPUThread& ppu, vm::ptr spurs); -//s32 cellSpursTraceStop(PPUThread& ppu, vm::ptr spurs); +//s32 cellSpursTraceInitialize(ppu_thread& ppu, vm::ptr spurs, vm::ptr buffer, u32 size, u32 mode); +//s32 cellSpursTraceFinalize(ppu_thread& ppu, vm::ptr spurs); +//s32 cellSpursTraceStart(ppu_thread& ppu, vm::ptr spurs); +//s32 cellSpursTraceStop(ppu_thread& ppu, vm::ptr spurs); // // SPURS policy module functions @@ -199,7 +177,7 @@ namespace _spurs //s32 cellSpursRemoveWorkload(); // Activate the SPURS kernel -s32 cellSpursWakeUp(PPUThread& ppu, vm::ptr spurs); +s32 cellSpursWakeUp(ppu_thread& ppu, vm::ptr spurs); //s32 cellSpursSendWorkloadSignal(vm::ptr spurs, u32 wid); //s32 cellSpursGetWorkloadFlag(vm::ptr spurs, vm::pptr flag); @@ -222,11 +200,11 @@ s32 cellSpursWakeUp(PPUThread& ppu, vm::ptr spurs); namespace _spurs { // Create taskset - s32 create_taskset(PPUThread& ppu, vm::ptr spurs, vm::ptr taskset, u64 args, vm::cptr priority, u32 max_contention, vm::cptr name, u32 size, s32 enable_clear_ls); + s32 create_taskset(ppu_thread& ppu, vm::ptr spurs, vm::ptr taskset, u64 args, vm::cptr priority, u32 max_contention, vm::cptr name, u32 size, s32 enable_clear_ls); } -//s32 cellSpursCreateTasksetWithAttribute(PPUThread& ppu, vm::ptr spurs, vm::ptr taskset, vm::ptr attr); -//s32 cellSpursCreateTaskset(PPUThread& ppu, vm::ptr spurs, vm::ptr taskset, u64 args, vm::cptr priority, u32 maxContention); +//s32 cellSpursCreateTasksetWithAttribute(ppu_thread& ppu, vm::ptr spurs, vm::ptr taskset, vm::ptr attr); +//s32 cellSpursCreateTaskset(ppu_thread& ppu, vm::ptr spurs, vm::ptr taskset, u64 args, vm::cptr priority, u32 maxContention); //s32 cellSpursJoinTaskset(vm::ptr taskset); //s32 cellSpursGetTasksetId(vm::ptr taskset, vm::ptr wid); //s32 cellSpursShutdownTaskset(vm::ptr taskset); @@ -234,13 +212,13 @@ namespace _spurs //s32 cellSpursTasksetAttributeSetTasksetSize(vm::ptr attr, u32 size); //s32 cellSpursTasksetAttributeEnableClearLS(vm::ptr attr, s32 enable); //s32 _cellSpursTasksetAttribute2Initialize(vm::ptr attribute, u32 revision); -//s32 cellSpursCreateTaskset2(PPUThread& ppu, vm::ptr spurs, vm::ptr taskset, vm::ptr attr); +//s32 cellSpursCreateTaskset2(ppu_thread& ppu, vm::ptr spurs, vm::ptr taskset, vm::ptr attr); //s32 cellSpursDestroyTaskset2(); //s32 cellSpursTasksetSetExceptionEventHandler(vm::ptr taskset, vm::ptr handler, vm::ptr arg); //s32 cellSpursTasksetUnsetExceptionEventHandler(vm::ptr taskset); // Get taskset instance from the workload ID -s32 cellSpursLookUpTasksetAddress(PPUThread& ppu, vm::ptr spurs, vm::pptr taskset, u32 id); +s32 cellSpursLookUpTasksetAddress(ppu_thread& ppu, vm::ptr spurs, vm::pptr taskset, u32 id); //s32 cellSpursTasksetGetSpursAddress(vm::cptr taskset, vm::ptr spurs); //s32 cellSpursGetTasksetInfo(); @@ -256,13 +234,13 @@ namespace _spurs s32 create_task(vm::ptr taskset, vm::ptr task_id, vm::cptr elf, vm::cptr context, u32 size, vm::ptr ls_pattern, vm::ptr arg); // Start task - s32 task_start(PPUThread& ppu, vm::ptr taskset, u32 taskId); + s32 task_start(ppu_thread& ppu, vm::ptr taskset, u32 taskId); } -//s32 cellSpursCreateTask(PPUThread& ppu, vm::ptr taskset, vm::ptr taskId, vm::cptr elf, vm::cptr context, u32 size, vm::ptr lsPattern, vm::ptr argument); +//s32 cellSpursCreateTask(ppu_thread& ppu, vm::ptr taskset, vm::ptr taskId, vm::cptr elf, vm::cptr context, u32 size, vm::ptr lsPattern, vm::ptr argument); // Sends a signal to the task -s32 _cellSpursSendSignal(PPUThread& ppu, vm::ptr taskset, u32 taskId); +s32 _cellSpursSendSignal(ppu_thread& ppu, vm::ptr taskset, u32 taskId); //s32 cellSpursCreateTaskWithAttribute(); //s32 cellSpursTaskExitCodeGet(); @@ -287,15 +265,15 @@ s32 _cellSpursSendSignal(PPUThread& ppu, vm::ptr taskset, u32 namespace _spurs { // Wait for SPURS event flag - s32 event_flag_wait(PPUThread& ppu, vm::ptr eventFlag, vm::ptr mask, u32 mode, u32 block); + s32 event_flag_wait(ppu_thread& ppu, vm::ptr eventFlag, vm::ptr mask, u32 mode, u32 block); } //s32 _cellSpursEventFlagInitialize(vm::ptr spurs, vm::ptr taskset, vm::ptr eventFlag, u32 flagClearMode, u32 flagDirection); //s32 cellSpursEventFlagClear(vm::ptr eventFlag, u16 bits); -//s32 cellSpursEventFlagSet(PPUThread& ppu, vm::ptr eventFlag, u16 bits); -//s32 cellSpursEventFlagWait(PPUThread& ppu, vm::ptr eventFlag, vm::ptr mask, u32 mode); -//s32 cellSpursEventFlagTryWait(PPUThread& ppu, vm::ptr eventFlag, vm::ptr mask, u32 mode); -//s32 cellSpursEventFlagAttachLv2EventQueue(PPUThread& ppu, vm::ptr eventFlag); +//s32 cellSpursEventFlagSet(ppu_thread& ppu, vm::ptr eventFlag, u16 bits); +//s32 cellSpursEventFlagWait(ppu_thread& ppu, vm::ptr eventFlag, vm::ptr mask, u32 mode); +//s32 cellSpursEventFlagTryWait(ppu_thread& ppu, vm::ptr eventFlag, vm::ptr mask, u32 mode); +//s32 cellSpursEventFlagAttachLv2EventQueue(ppu_thread& ppu, vm::ptr eventFlag); //s32 cellSpursEventFlagDetachLv2EventQueue(vm::ptr eventFlag); //s32 cellSpursEventFlagGetDirection(vm::ptr eventFlag, vm::ptr direction); //s32 cellSpursEventFlagGetClearMode(vm::ptr eventFlag, vm::ptr clear_mode); @@ -391,7 +369,7 @@ bool _spurs::is_libprof_loaded() // SPURS core functions //---------------------------------------------------------------------------- -s32 _spurs::create_lv2_eq(PPUThread& ppu, vm::ptr spurs, vm::ptr queueId, vm::ptr port, s32 size, const sys_event_queue_attribute_t& attr) +s32 _spurs::create_lv2_eq(ppu_thread& ppu, vm::ptr spurs, vm::ptr queueId, vm::ptr port, s32 size, const sys_event_queue_attribute_t& attr) { if (s32 rc = sys_event_queue_create(queueId, vm::make_var(attr), SYS_EVENT_QUEUE_LOCAL, size)) { @@ -406,7 +384,7 @@ s32 _spurs::create_lv2_eq(PPUThread& ppu, vm::ptr spurs, vm::ptr return CELL_OK; } -s32 _spurs::attach_lv2_eq(PPUThread& ppu, vm::ptr spurs, u32 queue, vm::ptr port, s32 isDynamic, bool spursCreated) +s32 _spurs::attach_lv2_eq(ppu_thread& ppu, vm::ptr spurs, u32 queue, vm::ptr port, s32 isDynamic, bool spursCreated) { if (!spurs || !port) { @@ -503,7 +481,7 @@ s32 _spurs::detach_lv2_eq(vm::ptr spurs, u8 spuPort, bool spursCreate return CELL_OK; } -void _spurs::handler_wait_ready(PPUThread& ppu, vm::ptr spurs) +void _spurs::handler_wait_ready(ppu_thread& ppu, vm::ptr spurs) { CHECK_SUCCESS(sys_lwmutex_lock(ppu, spurs.ptr(&CellSpurs::mutex), 0)); @@ -580,7 +558,7 @@ void _spurs::handler_wait_ready(PPUThread& ppu, vm::ptr spurs) CHECK_SUCCESS(sys_lwmutex_unlock(ppu, spurs.ptr(&CellSpurs::mutex))); } -void _spurs::handler_entry(PPUThread& ppu, vm::ptr spurs) +void _spurs::handler_entry(ppu_thread& ppu, vm::ptr spurs) { if (spurs->flags & SAF_UNKNOWN_FLAG_30) { @@ -619,12 +597,27 @@ void _spurs::handler_entry(PPUThread& ppu, vm::ptr spurs) s32 _spurs::create_handler(vm::ptr spurs, u32 ppuPriority) { - spurs->ppu0 = ppu_thread_create(0, spurs.addr(), ppuPriority, 0x4000, std::string(spurs->prefix, spurs->prefixSize) + "SpursHdlr0", BIND_FUNC(_spurs::handler_entry)); + struct handler_thread : ppu_thread + { + using ppu_thread::ppu_thread; + + virtual void cpu_task() override + { + BIND_FUNC(_spurs::handler_entry)(*this); + } + }; + + auto&& eht = std::make_shared(std::string(spurs->prefix, spurs->prefixSize) + "SpursHdlr0", ppuPriority, 0x4000); + + spurs->ppu0 = idm::import_existing(eht); + + eht->gpr[3] = spurs.addr(); + eht->run(); return CELL_OK; } -s32 _spurs::invoke_event_handlers(PPUThread& ppu, vm::ptr eventPortMux) +s32 _spurs::invoke_event_handlers(ppu_thread& ppu, vm::ptr eventPortMux) { if (eventPortMux->reqPending.exchange(0)) { @@ -637,7 +630,7 @@ s32 _spurs::invoke_event_handlers(PPUThread& ppu, vm::ptr spurs, u32 wid) +s32 _spurs::wakeup_shutdown_completion_waiter(ppu_thread& ppu, vm::ptr spurs, u32 wid) { if (!spurs) { @@ -689,21 +682,19 @@ s32 _spurs::wakeup_shutdown_completion_waiter(PPUThread& ppu, vm::ptr return rc; } -void _spurs::event_helper_entry(PPUThread& ppu, vm::ptr spurs) +void _spurs::event_helper_entry(ppu_thread& ppu, vm::ptr spurs) { - bool terminate = false; - vm::var events(8); vm::var count; - while (!terminate) + while (true) { CHECK_SUCCESS(sys_event_queue_receive(ppu, spurs->eventQueue, vm::null, 0)); - const u64 event_src = ppu.GPR[4]; - const u64 event_data1 = ppu.GPR[5]; - const u64 event_data2 = ppu.GPR[6]; - const u64 event_data3 = ppu.GPR[7]; + const u64 event_src = ppu.gpr[4]; + const u64 event_data1 = ppu.gpr[5]; + const u64 event_data2 = ppu.gpr[6]; + const u64 event_data3 = ppu.gpr[7]; if (event_src == SYS_SPU_THREAD_EVENT_EXCEPTION_KEY) { @@ -737,7 +728,7 @@ void _spurs::event_helper_entry(PPUThread& ppu, vm::ptr spurs) if (data0 == 1) { - terminate = true; + return; } else if (data0 < 1) { @@ -772,7 +763,7 @@ void _spurs::event_helper_entry(PPUThread& ppu, vm::ptr spurs) } } -s32 _spurs::create_event_helper(PPUThread& ppu, vm::ptr spurs, u32 ppuPriority) +s32 _spurs::create_event_helper(ppu_thread& ppu, vm::ptr spurs, u32 ppuPriority) { if (s32 rc = _spurs::create_lv2_eq(ppu, spurs, spurs.ptr(&CellSpurs::eventQueue), spurs.ptr(&CellSpurs::spuPort), 0x2A, sys_event_queue_attribute_t{ SYS_SYNC_PRIORITY, SYS_PPU_QUEUE, "_spuPrv" })) { @@ -803,7 +794,19 @@ s32 _spurs::create_event_helper(PPUThread& ppu, vm::ptr spurs, u32 pp return CELL_SPURS_CORE_ERROR_STAT; } - const u32 tid = ppu_thread_create(0, spurs.addr(), ppuPriority, 0x8000, std::string(spurs->prefix, spurs->prefixSize) + "SpursHdlr1", BIND_FUNC(_spurs::event_helper_entry)); + struct event_helper_thread : ppu_thread + { + using ppu_thread::ppu_thread; + + virtual void cpu_task() override + { + BIND_FUNC(_spurs::event_helper_entry)(*this); + } + }; + + auto&& eht = std::make_shared(std::string(spurs->prefix, spurs->prefixSize) + "SpursHdlr1", ppuPriority, 0x8000); + + const u32 tid = idm::import_existing(eht); if (tid == 0) { @@ -819,6 +822,9 @@ s32 _spurs::create_event_helper(PPUThread& ppu, vm::ptr spurs, u32 pp return CELL_SPURS_CORE_ERROR_STAT; } + eht->gpr[3] = spurs.addr(); + eht->run(); + spurs->ppu1 = tid; return CELL_OK; } @@ -871,7 +877,7 @@ s32 _spurs::finalize_spu(vm::ptr spurs) return CELL_OK; } -s32 _spurs::stop_event_helper(PPUThread& ppu, vm::ptr spurs) +s32 _spurs::stop_event_helper(ppu_thread& ppu, vm::ptr spurs) { if (spurs->ppu1 == 0xFFFFFFFF) { @@ -898,7 +904,7 @@ s32 _spurs::stop_event_helper(PPUThread& ppu, vm::ptr spurs) return CELL_OK; } -s32 _spurs::signal_to_handler_thread(PPUThread& ppu, vm::ptr spurs) +s32 _spurs::signal_to_handler_thread(ppu_thread& ppu, vm::ptr spurs) { CHECK_SUCCESS(sys_lwmutex_lock(ppu, spurs.ptr(&CellSpurs::mutex), 0)); CHECK_SUCCESS(sys_lwcond_signal(ppu, spurs.ptr(&CellSpurs::cond))); @@ -907,7 +913,7 @@ s32 _spurs::signal_to_handler_thread(PPUThread& ppu, vm::ptr spurs) return CELL_OK; } -s32 _spurs::join_handler_thread(PPUThread& ppu, vm::ptr spurs) +s32 _spurs::join_handler_thread(ppu_thread& ppu, vm::ptr spurs) { if (spurs->ppu0 == 0xFFFFFFFF) { @@ -920,7 +926,7 @@ s32 _spurs::join_handler_thread(PPUThread& ppu, vm::ptr spurs) return CELL_OK; } -s32 _spurs::initialize(PPUThread& ppu, vm::ptr spurs, u32 revision, u32 sdkVersion, s32 nSpus, s32 spuPriority, s32 ppuPriority, u32 flags, vm::cptr prefix, u32 prefixSize, u32 container, vm::cptr swlPriority, u32 swlMaxSpu, u32 swlIsPreem) +s32 _spurs::initialize(ppu_thread& ppu, vm::ptr spurs, u32 revision, u32 sdkVersion, s32 nSpus, s32 spuPriority, s32 ppuPriority, u32 flags, vm::cptr prefix, u32 prefixSize, u32 container, vm::cptr swlPriority, u32 swlMaxSpu, u32 swlIsPreem) { vm::var sem; vm::var semAttr; @@ -1211,7 +1217,7 @@ s32 _spurs::initialize(PPUThread& ppu, vm::ptr spurs, u32 revision, u } /// Initialize SPURS -s32 cellSpursInitialize(PPUThread& ppu, vm::ptr spurs, s32 nSpus, s32 spuPriority, s32 ppuPriority, b8 exitIfNoWork) +s32 cellSpursInitialize(ppu_thread& ppu, vm::ptr spurs, s32 nSpus, s32 spuPriority, s32 ppuPriority, b8 exitIfNoWork) { cellSpurs.warning("cellSpursInitialize(spurs=*0x%x, nSpus=%d, spuPriority=%d, ppuPriority=%d, exitIfNoWork=%d)", spurs, nSpus, spuPriority, ppuPriority, exitIfNoWork); @@ -1219,7 +1225,7 @@ s32 cellSpursInitialize(PPUThread& ppu, vm::ptr spurs, s32 nSpus, s32 } /// Initialise SPURS -s32 cellSpursInitializeWithAttribute(PPUThread& ppu, vm::ptr spurs, vm::cptr attr) +s32 cellSpursInitializeWithAttribute(ppu_thread& ppu, vm::ptr spurs, vm::cptr attr) { cellSpurs.warning("cellSpursInitializeWithAttribute(spurs=*0x%x, attr=*0x%x)", spurs, attr); @@ -1256,7 +1262,7 @@ s32 cellSpursInitializeWithAttribute(PPUThread& ppu, vm::ptr spurs, v } /// Initialise SPURS -s32 cellSpursInitializeWithAttribute2(PPUThread& ppu, vm::ptr spurs, vm::cptr attr) +s32 cellSpursInitializeWithAttribute2(ppu_thread& ppu, vm::ptr spurs, vm::cptr attr) { cellSpurs.warning("cellSpursInitializeWithAttribute2(spurs=*0x%x, attr=*0x%x)", spurs, attr); @@ -1697,7 +1703,7 @@ s32 cellSpursSetPreemptionVictimHints(vm::ptr spurs, vm::cptr isP } /// Attach an LV2 event queue to a SPURS instance -s32 cellSpursAttachLv2EventQueue(PPUThread& ppu, vm::ptr spurs, u32 queue, vm::ptr port, s32 isDynamic) +s32 cellSpursAttachLv2EventQueue(ppu_thread& ppu, vm::ptr spurs, u32 queue, vm::ptr port, s32 isDynamic) { cellSpurs.warning("cellSpursAttachLv2EventQueue(spurs=*0x%x, queue=0x%x, port=*0x%x, isDynamic=%d)", spurs, queue, port, isDynamic); @@ -1810,7 +1816,7 @@ s32 cellSpursGetSpuGuid() // SPURS trace functions //---------------------------------------------------------------------------- -void _spurs::trace_status_update(PPUThread& ppu, vm::ptr spurs) +void _spurs::trace_status_update(ppu_thread& ppu, vm::ptr spurs) { u8 init; @@ -1830,7 +1836,7 @@ void _spurs::trace_status_update(PPUThread& ppu, vm::ptr spurs) } } -s32 _spurs::trace_initialize(PPUThread& ppu, vm::ptr spurs, vm::ptr buffer, u32 size, u32 mode, u32 updateStatus) +s32 _spurs::trace_initialize(ppu_thread& ppu, vm::ptr spurs, vm::ptr buffer, u32 size, u32 mode, u32 updateStatus) { if (!spurs || !buffer) { @@ -1881,7 +1887,7 @@ s32 _spurs::trace_initialize(PPUThread& ppu, vm::ptr spurs, vm::ptr spurs, vm::ptr buffer, u32 size, u32 mode) +s32 cellSpursTraceInitialize(ppu_thread& ppu, vm::ptr spurs, vm::ptr buffer, u32 size, u32 mode) { cellSpurs.warning("cellSpursTraceInitialize(spurs=*0x%x, buffer=*0x%x, size=0x%x, mode=0x%x)", spurs, buffer, size, mode); @@ -1894,7 +1900,7 @@ s32 cellSpursTraceInitialize(PPUThread& ppu, vm::ptr spurs, vm::ptr spurs) +s32 cellSpursTraceFinalize(ppu_thread& ppu, vm::ptr spurs) { cellSpurs.warning("cellSpursTraceFinalize(spurs=*0x%x)", spurs); @@ -1922,7 +1928,7 @@ s32 cellSpursTraceFinalize(PPUThread& ppu, vm::ptr spurs) return CELL_OK; } -s32 _spurs::trace_start(PPUThread& ppu, vm::ptr spurs, u32 updateStatus) +s32 _spurs::trace_start(ppu_thread& ppu, vm::ptr spurs, u32 updateStatus) { if (!spurs) { @@ -1949,7 +1955,7 @@ s32 _spurs::trace_start(PPUThread& ppu, vm::ptr spurs, u32 updateStat } /// Start SPURS trace -s32 cellSpursTraceStart(PPUThread& ppu, vm::ptr spurs) +s32 cellSpursTraceStart(ppu_thread& ppu, vm::ptr spurs) { cellSpurs.warning("cellSpursTraceStart(spurs=*0x%x)", spurs); @@ -1966,7 +1972,7 @@ s32 cellSpursTraceStart(PPUThread& ppu, vm::ptr spurs) return _spurs::trace_start(ppu, spurs, spurs->traceMode & CELL_SPURS_TRACE_MODE_FLAG_SYNCHRONOUS_START_STOP); } -s32 _spurs::trace_stop(PPUThread& ppu, vm::ptr spurs, u32 updateStatus) +s32 _spurs::trace_stop(ppu_thread& ppu, vm::ptr spurs, u32 updateStatus) { if (!spurs) { @@ -1993,7 +1999,7 @@ s32 _spurs::trace_stop(PPUThread& ppu, vm::ptr spurs, u32 updateStatu } /// Stop SPURS trace -s32 cellSpursTraceStop(PPUThread& ppu, vm::ptr spurs) +s32 cellSpursTraceStop(ppu_thread& ppu, vm::ptr spurs) { cellSpurs.warning("cellSpursTraceStop(spurs=*0x%x)", spurs); @@ -2315,7 +2321,7 @@ s32 cellSpursRemoveWorkload() return CELL_OK; } -s32 cellSpursWakeUp(PPUThread& ppu, vm::ptr spurs) +s32 cellSpursWakeUp(ppu_thread& ppu, vm::ptr spurs) { cellSpurs.warning("cellSpursWakeUp(spurs=*0x%x)", spurs); @@ -2692,7 +2698,7 @@ s32 cellSpursEventFlagClear(vm::ptr eventFlag, u16 bits) } /// Set a SPURS event flag -s32 cellSpursEventFlagSet(PPUThread& ppu, vm::ptr eventFlag, u16 bits) +s32 cellSpursEventFlagSet(ppu_thread& ppu, vm::ptr eventFlag, u16 bits) { cellSpurs.warning("cellSpursEventFlagSet(eventFlag=*0x%x, bits=0x%x)", eventFlag, bits); @@ -2820,7 +2826,7 @@ s32 cellSpursEventFlagSet(PPUThread& ppu, vm::ptr eventFlag, return CELL_OK; } -s32 _spurs::event_flag_wait(PPUThread& ppu, vm::ptr eventFlag, vm::ptr mask, u32 mode, u32 block) +s32 _spurs::event_flag_wait(ppu_thread& ppu, vm::ptr eventFlag, vm::ptr mask, u32 mode, u32 block) { if (!eventFlag || !mask) { @@ -2975,7 +2981,7 @@ s32 _spurs::event_flag_wait(PPUThread& ppu, vm::ptr eventFla } /// Wait for SPURS event flag -s32 cellSpursEventFlagWait(PPUThread& ppu, vm::ptr eventFlag, vm::ptr mask, u32 mode) +s32 cellSpursEventFlagWait(ppu_thread& ppu, vm::ptr eventFlag, vm::ptr mask, u32 mode) { cellSpurs.warning("cellSpursEventFlagWait(eventFlag=*0x%x, mask=*0x%x, mode=%d)", eventFlag, mask, mode); @@ -2983,7 +2989,7 @@ s32 cellSpursEventFlagWait(PPUThread& ppu, vm::ptr eventFlag } /// Check SPURS event flag -s32 cellSpursEventFlagTryWait(PPUThread& ppu, vm::ptr eventFlag, vm::ptr mask, u32 mode) +s32 cellSpursEventFlagTryWait(ppu_thread& ppu, vm::ptr eventFlag, vm::ptr mask, u32 mode) { cellSpurs.warning("cellSpursEventFlagTryWait(eventFlag=*0x%x, mask=*0x%x, mode=0x%x)", eventFlag, mask, mode); @@ -2991,7 +2997,7 @@ s32 cellSpursEventFlagTryWait(PPUThread& ppu, vm::ptr eventF } /// Attach an LV2 event queue to a SPURS event flag -s32 cellSpursEventFlagAttachLv2EventQueue(PPUThread& ppu, vm::ptr eventFlag) +s32 cellSpursEventFlagAttachLv2EventQueue(ppu_thread& ppu, vm::ptr eventFlag) { cellSpurs.warning("cellSpursEventFlagAttachLv2EventQueue(eventFlag=*0x%x)", eventFlag); @@ -3300,7 +3306,7 @@ s32 cellSpursQueueGetDirection() return CELL_OK; } -s32 _spurs::create_taskset(PPUThread& ppu, vm::ptr spurs, vm::ptr taskset, u64 args, vm::cptr priority, u32 max_contention, vm::cptr name, u32 size, s32 enable_clear_ls) +s32 _spurs::create_taskset(ppu_thread& ppu, vm::ptr spurs, vm::ptr taskset, u64 args, vm::cptr priority, u32 max_contention, vm::cptr name, u32 size, s32 enable_clear_ls) { if (!spurs || !taskset) { @@ -3342,7 +3348,7 @@ s32 _spurs::create_taskset(PPUThread& ppu, vm::ptr spurs, vm::ptr spurs, vm::ptr taskset, vm::ptr attr) +s32 cellSpursCreateTasksetWithAttribute(ppu_thread& ppu, vm::ptr spurs, vm::ptr taskset, vm::ptr attr) { cellSpurs.warning("cellSpursCreateTasksetWithAttribute(spurs=*0x%x, taskset=*0x%x, attr=*0x%x)", spurs, taskset, attr); @@ -3371,7 +3377,7 @@ s32 cellSpursCreateTasksetWithAttribute(PPUThread& ppu, vm::ptr spurs return rc; } -s32 cellSpursCreateTaskset(PPUThread& ppu, vm::ptr spurs, vm::ptr taskset, u64 args, vm::cptr priority, u32 maxContention) +s32 cellSpursCreateTaskset(ppu_thread& ppu, vm::ptr spurs, vm::ptr taskset, u64 args, vm::cptr priority, u32 maxContention) { cellSpurs.warning("cellSpursCreateTaskset(spurs=*0x%x, taskset=*0x%x, args=0x%llx, priority=*0x%x, maxContention=%d)", spurs, taskset, args, priority, maxContention); @@ -3513,7 +3519,7 @@ s32 _spurs::create_task(vm::ptr taskset, vm::ptr task_id, return CELL_OK; } -s32 _spurs::task_start(PPUThread& ppu, vm::ptr taskset, u32 taskId) +s32 _spurs::task_start(ppu_thread& ppu, vm::ptr taskset, u32 taskId) { auto pendingReady = taskset->pending_ready.value(); pendingReady._bit[taskId] = true; @@ -3536,7 +3542,7 @@ s32 _spurs::task_start(PPUThread& ppu, vm::ptr taskset, u32 ta return CELL_OK; } -s32 cellSpursCreateTask(PPUThread& ppu, vm::ptr taskset, vm::ptr taskId, vm::cptr elf, vm::cptr context, u32 size, vm::ptr lsPattern, vm::ptr argument) +s32 cellSpursCreateTask(ppu_thread& ppu, vm::ptr taskset, vm::ptr taskId, vm::cptr elf, vm::cptr context, u32 size, vm::ptr lsPattern, vm::ptr argument) { cellSpurs.warning("cellSpursCreateTask(taskset=*0x%x, taskID=*0x%x, elf=*0x%x, context=*0x%x, size=0x%x, lsPattern=*0x%x, argument=*0x%x)", taskset, taskId, elf, context, size, lsPattern, argument); @@ -3565,7 +3571,7 @@ s32 cellSpursCreateTask(PPUThread& ppu, vm::ptr taskset, vm::p return CELL_OK; } -s32 _cellSpursSendSignal(PPUThread& ppu, vm::ptr taskset, u32 taskId) +s32 _cellSpursSendSignal(ppu_thread& ppu, vm::ptr taskset, u32 taskId) { if (!taskset) { @@ -3768,7 +3774,7 @@ s32 cellSpursTaskGetContextSaveAreaSize() return CELL_OK; } -s32 cellSpursCreateTaskset2(PPUThread& ppu, vm::ptr spurs, vm::ptr taskset, vm::ptr attr) +s32 cellSpursCreateTaskset2(ppu_thread& ppu, vm::ptr spurs, vm::ptr taskset, vm::ptr attr) { cellSpurs.warning("cellSpursCreateTaskset2(spurs=*0x%x, taskset=*0x%x, attr=*0x%x)", spurs, taskset, attr); @@ -3877,7 +3883,7 @@ s32 cellSpursTasksetUnsetExceptionEventHandler(vm::ptr taskset return CELL_OK; } -s32 cellSpursLookUpTasksetAddress(PPUThread& ppu, vm::ptr spurs, vm::pptr taskset, u32 id) +s32 cellSpursLookUpTasksetAddress(ppu_thread& ppu, vm::ptr spurs, vm::pptr taskset, u32 id) { cellSpurs.warning("cellSpursLookUpTasksetAddress(spurs=*0x%x, taskset=**0x%x, id=0x%x)", spurs, taskset, id); diff --git a/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp b/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp index 956dc733cf..8f177b0d01 100644 --- a/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp @@ -17,8 +17,6 @@ extern logs::channel cellSpurs; -extern std::mutex& get_current_thread_mutex(); - //---------------------------------------------------------------------------- // Function prototypes //---------------------------------------------------------------------------- @@ -774,7 +772,7 @@ void spursSysServiceIdleHandler(SPUThread& spu, SpursKernelContext* ctxt) { bool shouldExit; - std::unique_lock lock(get_current_thread_mutex(), std::defer_lock); + std::unique_lock lock(spu, std::defer_lock); while (true) { @@ -864,8 +862,8 @@ void spursSysServiceIdleHandler(SPUThread& spu, SpursKernelContext* ctxt) { // The system service blocks by making a reservation and waiting on the lock line reservation lost event. CHECK_EMU_STATUS; - if (!lock) lock.lock(); - get_current_thread_cv().wait_for(lock, 1ms); + if (!lock) { lock.lock(); continue; } + thread_ctrl::wait_for(1000); continue; } diff --git a/rpcs3/Emu/Cell/Modules/cellSync.cpp b/rpcs3/Emu/Cell/Modules/cellSync.cpp index 1dc29dfb85..c6397e9545 100644 --- a/rpcs3/Emu/Cell/Modules/cellSync.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSync.cpp @@ -820,7 +820,7 @@ ppu_error_code cellSyncLFQueueInitialize(vm::ptr queue, vm::cpt return CELL_OK; } -ppu_error_code _cellSyncLFQueueGetPushPointer(PPUThread& ppu, vm::ptr queue, vm::ptr pointer, u32 isBlocking, u32 useEventQueue) +ppu_error_code _cellSyncLFQueueGetPushPointer(ppu_thread& 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); @@ -913,7 +913,7 @@ ppu_error_code _cellSyncLFQueueGetPushPointer(PPUThread& ppu, vm::ptr queue, vm::ptr pointer, u32 isBlocking, u32 useEventQueue) +ppu_error_code _cellSyncLFQueueGetPushPointer2(ppu_thread& 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); @@ -921,7 +921,7 @@ ppu_error_code _cellSyncLFQueueGetPushPointer2(PPUThread& ppu, vm::ptr queue, s32 pointer, vm::ptr fpSendSignal) +ppu_error_code _cellSyncLFQueueCompletePushPointer(ppu_thread& ppu, vm::ptr queue, s32 pointer, vm::ptr fpSendSignal) { cellSync.warning("_cellSyncLFQueueCompletePushPointer(queue=*0x%x, pointer=%d, fpSendSignal=*0x%x)", queue, pointer, fpSendSignal); @@ -1053,7 +1053,7 @@ ppu_error_code _cellSyncLFQueueCompletePushPointer(PPUThread& ppu, vm::ptr queue, s32 pointer, vm::ptr fpSendSignal) +ppu_error_code _cellSyncLFQueueCompletePushPointer2(ppu_thread& 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); @@ -1061,7 +1061,7 @@ ppu_error_code _cellSyncLFQueueCompletePushPointer2(PPUThread& ppu, vm::ptr queue, vm::cptr buffer, u32 isBlocking) +ppu_error_code _cellSyncLFQueuePushBody(ppu_thread& 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); @@ -1119,7 +1119,7 @@ ppu_error_code _cellSyncLFQueuePushBody(PPUThread& ppu, vm::ptr } } -ppu_error_code _cellSyncLFQueueGetPopPointer(PPUThread& ppu, vm::ptr queue, vm::ptr pointer, u32 isBlocking, u32 arg4, u32 useEventQueue) +ppu_error_code _cellSyncLFQueueGetPopPointer(ppu_thread& 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); @@ -1212,7 +1212,7 @@ ppu_error_code _cellSyncLFQueueGetPopPointer(PPUThread& ppu, vm::ptr queue, vm::ptr pointer, u32 isBlocking, u32 useEventQueue) +ppu_error_code _cellSyncLFQueueGetPopPointer2(ppu_thread& 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); @@ -1220,7 +1220,7 @@ ppu_error_code _cellSyncLFQueueGetPopPointer2(PPUThread& ppu, vm::ptr queue, s32 pointer, vm::ptr fpSendSignal, u32 noQueueFull) +ppu_error_code _cellSyncLFQueueCompletePopPointer(ppu_thread& 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); @@ -1352,7 +1352,7 @@ ppu_error_code _cellSyncLFQueueCompletePopPointer(PPUThread& ppu, vm::ptr queue, s32 pointer, vm::ptr fpSendSignal, u32 noQueueFull) +ppu_error_code _cellSyncLFQueueCompletePopPointer2(ppu_thread& 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); @@ -1360,7 +1360,7 @@ ppu_error_code _cellSyncLFQueueCompletePopPointer2(PPUThread& ppu, vm::ptr queue, vm::ptr buffer, u32 isBlocking) +ppu_error_code _cellSyncLFQueuePopBody(ppu_thread& 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); diff --git a/rpcs3/Emu/Cell/Modules/cellSysutil.cpp b/rpcs3/Emu/Cell/Modules/cellSysutil.cpp index ce21bcb7dc..910c9eaa18 100644 --- a/rpcs3/Emu/Cell/Modules/cellSysutil.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSysutil.cpp @@ -8,20 +8,40 @@ #include "Utilities/StrUtil.h" +#include +#include + logs::channel cellSysutil("cellSysutil", logs::level::notice); -// Temporarily -using sys_callbacks_t = std::array, vm::ptr>, 4>; - -void sysutilSendSystemCommand(u64 status, u64 param) +struct sysutil_cb_manager { - if (const auto g_sys_callback = fxm::get()) + std::mutex mutex; + + std::array, vm::ptr>, 4> callbacks; + + std::queue> registered; +}; + +extern void sysutil_register_cb(std::function&& cb) +{ + const auto cbm = fxm::get_always(); + + std::lock_guard lock(cbm->mutex); + + cbm->registered.push(std::move(cb)); +} + +extern void sysutil_send_system_cmd(u64 status, u64 param) +{ + if (const auto cbm = fxm::get()) { - for (auto& cb : *g_sys_callback) + for (auto& cb : cbm->callbacks) { if (cb.first) { - Emu.GetCallbackManager().Register([=](PPUThread& ppu) -> s32 + std::lock_guard lock(cbm->mutex); + + cbm->registered.push([=](ppu_thread& 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); @@ -196,15 +216,26 @@ s32 cellSysutilGetSystemParamString(s32 id, vm::ptr buf, u32 bufsize) return CELL_OK; } -s32 cellSysutilCheckCallback(PPUThread& CPU) +s32 cellSysutilCheckCallback(ppu_thread& ppu) { cellSysutil.trace("cellSysutilCheckCallback()"); - while (auto func = Emu.GetCallbackManager().Check()) - { - CHECK_EMU_STATUS; + const auto cbm = fxm::get_always(); - if (s32 res = func(CPU)) + while (true) + { + std::lock_guard lock(cbm->mutex); + + if (cbm->registered.empty()) + { + break; + } + + const auto func = std::move(cbm->registered.front()); + + cbm->registered.pop(); + + if (s32 res = func(ppu)) { return res; } @@ -217,12 +248,15 @@ s32 cellSysutilRegisterCallback(s32 slot, vm::ptr func, vm: { cellSysutil.warning("cellSysutilRegisterCallback(slot=%d, func=*0x%x, userdata=*0x%x)", slot, func, userdata); - if (slot >= sys_callbacks_t{}.size()) + if (slot >= 4) { return CELL_SYSUTIL_ERROR_VALUE; } - fxm::get_always()->at(slot) = std::make_pair(func, userdata); + const auto cbm = fxm::get_always(); + + cbm->callbacks[slot] = std::make_pair(func, userdata); + return CELL_OK; } @@ -230,12 +264,15 @@ s32 cellSysutilUnregisterCallback(u32 slot) { cellSysutil.warning("cellSysutilUnregisterCallback(slot=%d)", slot); - if (slot >= sys_callbacks_t{}.size()) + if (slot >= 4) { return CELL_SYSUTIL_ERROR_VALUE; } - fxm::get_always()->at(slot) = std::make_pair(vm::null, vm::null); + const auto cbm = fxm::get_always(); + + cbm->callbacks[slot] = std::make_pair(vm::null, vm::null); + return CELL_OK; } diff --git a/rpcs3/Emu/Cell/Modules/cellSysutil.h b/rpcs3/Emu/Cell/Modules/cellSysutil.h index 69d9c2917d..6257ddae46 100644 --- a/rpcs3/Emu/Cell/Modules/cellSysutil.h +++ b/rpcs3/Emu/Cell/Modules/cellSysutil.h @@ -195,4 +195,5 @@ struct CellSysCacheParam vm::ptr reserved; }; -extern void sysutilSendSystemCommand(u64 status, u64 param); +extern void sysutil_register_cb(std::function&&); +extern void sysutil_send_system_cmd(u64 status, u64 param); diff --git a/rpcs3/Emu/Cell/Modules/cellVdec.cpp b/rpcs3/Emu/Cell/Modules/cellVdec.cpp index 9d9891a884..72132772e7 100644 --- a/rpcs3/Emu/Cell/Modules/cellVdec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellVdec.cpp @@ -3,8 +3,6 @@ #include "Emu/IdManager.h" #include "Emu/Cell/PPUModule.h" -std::mutex g_mutex_avcodec_open2; - extern "C" { #include "libavcodec/avcodec.h" @@ -15,90 +13,354 @@ extern "C" #include "cellPamf.h" #include "cellVdec.h" +#include #include +#include + +std::mutex g_mutex_avcodec_open2; logs::channel cellVdec("cellVdec", logs::level::notice); vm::gvar _cell_vdec_prx_ver; // ??? -VideoDecoder::VideoDecoder(s32 type, u32 profile, u32 addr, u32 size, vm::ptr func, u32 arg) - : type(type) - , profile(profile) - , memAddr(addr) - , memSize(size) - , memBias(0) - , cbFunc(func) - , cbArg(arg) - , is_finished(false) - , is_closed(false) - , frc_set(0) - , codec(nullptr) - , ctx(nullptr) +enum class vdec_cmd : u32 { - avcodec_register_all(); + none = 0, - switch (type) - { - case CELL_VDEC_CODEC_TYPE_MPEG2: - { - codec = avcodec_find_decoder(AV_CODEC_ID_MPEG2VIDEO); - break; - } - case CELL_VDEC_CODEC_TYPE_AVC: - { - codec = avcodec_find_decoder(AV_CODEC_ID_H264); - break; - } - case CELL_VDEC_CODEC_TYPE_DIVX: - { - codec = avcodec_find_decoder(AV_CODEC_ID_MPEG4); - break; - } - default: - { - throw fmt::exception("Unknown video decoder type (0x%x)" HERE, type); - } - } + start_seq, + end_seq, + decode, + set_frc, + close, +}; - if (!codec) - { - throw fmt::exception("avcodec_find_decoder() failed (type=0x%x)" HERE, type); - } - - ctx = avcodec_alloc_context3(codec); - - if (!ctx) - { - throw fmt::exception("avcodec_alloc_context3() failed (type=0x%x)" HERE, type); - } - - AVDictionary* opts{}; - av_dict_set(&opts, "refcounted_frames", "1", 0); - - std::lock_guard lock(g_mutex_avcodec_open2); - - int err = avcodec_open2(ctx, codec, &opts); - if (err || opts) - { - throw fmt::exception("avcodec_open2() failed (err=0x%x, opts=%d)" HERE, err, opts ? 1 : 0); - } -} - -VideoDecoder::~VideoDecoder() +struct vdec_frame { - VdecFrame vf; - while (frames.try_pop(vf)) + struct frame_dtor { - av_frame_unref(vf.data); - av_frame_free(&vf.data); + void operator()(AVFrame* data) const + { + av_frame_unref(data); + av_frame_free(&data); + } + }; + + std::unique_ptr avf; + u64 dts; + u64 pts; + u64 userdata; + u32 frc; + + AVFrame* operator ->() const + { + return avf.get(); + } +}; + +struct vdec_thread : ppu_thread +{ + AVCodec* codec{}; + AVCodecContext* ctx{}; + + const s32 type; + const u32 profile; + const u32 mem_addr; + const u32 mem_size; + const vm::ptr cb_func; + const u32 cb_arg; + u32 mem_bias{}; + + u32 frc_set{}; // Frame Rate Override + u64 last_pts{}; + u64 last_dts{}; + + std::queue out; + std::queue user_data; // TODO + + vdec_thread(s32 type, u32 profile, u32 addr, u32 size, vm::ptr func, u32 arg) + : ppu_thread("HLE Video Decoder") + , type(type) + , profile(profile) + , mem_addr(addr) + , mem_size(size) + , cb_func(func) + , cb_arg(arg) + { + avcodec_register_all(); + + switch (type) + { + case CELL_VDEC_CODEC_TYPE_MPEG2: + { + codec = avcodec_find_decoder(AV_CODEC_ID_MPEG2VIDEO); + break; + } + case CELL_VDEC_CODEC_TYPE_AVC: + { + codec = avcodec_find_decoder(AV_CODEC_ID_H264); + break; + } + case CELL_VDEC_CODEC_TYPE_DIVX: + { + codec = avcodec_find_decoder(AV_CODEC_ID_MPEG4); + break; + } + default: + { + throw fmt::exception("Unknown video decoder type (0x%x)" HERE, type); + } + } + + if (!codec) + { + throw fmt::exception("avcodec_find_decoder() failed (type=0x%x)" HERE, type); + } + + ctx = avcodec_alloc_context3(codec); + + if (!ctx) + { + throw fmt::exception("avcodec_alloc_context3() failed (type=0x%x)" HERE, type); + } + + AVDictionary* opts{}; + av_dict_set(&opts, "refcounted_frames", "1", 0); + + std::lock_guard lock(g_mutex_avcodec_open2); + + int err = avcodec_open2(ctx, codec, &opts); + if (err || opts) + { + avcodec_free_context(&ctx); + throw fmt::exception("avcodec_open2() failed (err=0x%x, opts=%d)" HERE, err, opts ? 1 : 0); + } } - if (ctx) + virtual ~vdec_thread() override { avcodec_close(ctx); avcodec_free_context(&ctx); } -} + + virtual std::string dump() const override + { + // TODO + return ppu_thread::dump(); + } + + virtual void cpu_task() override + { + while (ppu_cmd cmd = cmd_wait()) + { + switch (vdec_cmd vcmd = cmd.arg1()) + { + case vdec_cmd::start_seq: + { + cmd_pop(); + avcodec_flush_buffers(ctx); + + frc_set = 0; // TODO: ??? + last_pts = 0; + last_dts = 0; + cellVdec.trace("Start sequence..."); + break; + } + + case vdec_cmd::decode: + case vdec_cmd::end_seq: + { + AVPacket packet{}; + packet.pos = -1; + + u32 au_type{}; + u32 au_addr{}; + u32 au_size{}; + u64 au_pts{}; + u64 au_dts{}; + u64 au_usrd{}; + u64 au_spec{}; + + if (vcmd == vdec_cmd::decode) + { + const u32 pos = cmd_queue.peek(); + au_type = cmd.arg2(); // TODO + au_addr = cmd_queue[pos + 1].load().arg1(); + au_size = cmd_queue[pos + 1].load().arg2(); + au_pts = cmd_queue[pos + 2].load().as(); + au_dts = cmd_queue[pos + 3].load().as(); + au_usrd = cmd_queue[pos + 4].load().as(); // TODO + au_spec = cmd_queue[pos + 5].load().as(); // TODO + cmd_pop(5); + + packet.data = vm::_ptr(au_addr); + packet.size = au_size; + packet.pts = au_pts != -1 ? au_pts : AV_NOPTS_VALUE; + packet.dts = au_dts != -1 ? au_dts : AV_NOPTS_VALUE; + cellVdec.trace("AU decoding: size=0x%x, pts=0x%llx, dts=0x%llx, userdata=0x%llx", au_size, au_pts, au_dts, au_usrd); + } + else + { + cmd_pop(); + + packet.pts = AV_NOPTS_VALUE; + packet.dts = AV_NOPTS_VALUE; + cellVdec.trace("End sequence..."); + } + + while (true) + { + vdec_frame frame; + frame.avf.reset(av_frame_alloc()); + + if (!frame.avf) + { + throw fmt::exception("av_frame_alloc() failed" HERE); + } + + int got_picture = 0; + + int decode = avcodec_decode_video2(ctx, frame.avf.get(), &got_picture, &packet); + + if (decode < 0) + { + throw fmt::exception("vdecDecodeAu: AU decoding error(0x%x)" HERE, decode); + } + + if (got_picture == 0) + { + break; + } + + if (decode != packet.size) + { + cellVdec.error("vdecDecodeAu: incorrect AU size (0x%x, decoded 0x%x)", packet.size, decode); + } + + if (got_picture) + { + if (frame->interlaced_frame) + { + throw fmt::exception("Interlaced frames not supported (0x%x)", frame->interlaced_frame); + } + + if (frame->repeat_pict) + { + throw fmt::exception("Repeated frames not supported (0x%x)", frame->repeat_pict); + } + + if (frc_set) + { + u64 amend = 0; + + switch (frc_set) + { + case CELL_VDEC_FRC_24000DIV1001: amend = 1001 * 90000 / 24000; break; + case CELL_VDEC_FRC_24: amend = 90000 / 24; break; + case CELL_VDEC_FRC_25: amend = 90000 / 25; break; + case CELL_VDEC_FRC_30000DIV1001: amend = 1001 * 90000 / 30000; break; + case CELL_VDEC_FRC_30: amend = 90000 / 30; break; + case CELL_VDEC_FRC_50: amend = 90000 / 50; break; + case CELL_VDEC_FRC_60000DIV1001: amend = 1001 * 90000 / 60000; break; + case CELL_VDEC_FRC_60: amend = 90000 / 60; break; + default: + { + throw EXCEPTION("Invalid frame rate code set (0x%x)", frc_set); + } + } + + last_pts += amend; + last_dts += amend; + frame.frc = frc_set; + } + else + { + const u64 amend = ctx->time_base.num * 90000 * ctx->ticks_per_frame / ctx->time_base.den; + last_pts += amend; + last_dts += amend; + + if (ctx->time_base.num == 1) + { + switch ((u64)ctx->time_base.den + (u64)(ctx->ticks_per_frame - 1) * 0x100000000ull) + { + case 24: case 0x100000000ull + 48: frame.frc = CELL_VDEC_FRC_24; break; + case 25: case 0x100000000ull + 50: frame.frc = CELL_VDEC_FRC_25; break; + case 30: case 0x100000000ull + 60: frame.frc = CELL_VDEC_FRC_30; break; + case 50: case 0x100000000ull + 100: frame.frc = CELL_VDEC_FRC_50; break; + case 60: case 0x100000000ull + 120: frame.frc = CELL_VDEC_FRC_60; break; + default: + { + throw EXCEPTION("Unsupported time_base.den (%d/1, tpf=%d)", ctx->time_base.den, ctx->ticks_per_frame); + } + } + } + else if (ctx->time_base.num == 1001) + { + if (ctx->time_base.den / ctx->ticks_per_frame == 24000) + { + frame.frc = CELL_VDEC_FRC_24000DIV1001; + } + else if (ctx->time_base.den / ctx->ticks_per_frame == 30000) + { + frame.frc = CELL_VDEC_FRC_30000DIV1001; + } + else if (ctx->time_base.den / ctx->ticks_per_frame == 60000) + { + frame.frc = CELL_VDEC_FRC_60000DIV1001; + } + else + { + throw EXCEPTION("Unsupported time_base.den (%d/1001, tpf=%d)", ctx->time_base.den, ctx->ticks_per_frame); + } + } + else + { + throw EXCEPTION("Unsupported time_base.num (%d)", ctx->time_base.num); + } + } + + frame.pts = last_pts = frame->pkt_pts != AV_NOPTS_VALUE ? frame->pkt_pts : last_pts; + frame.dts = last_dts = frame->pkt_dts != AV_NOPTS_VALUE ? frame->pkt_dts : last_dts; + frame.userdata = au_usrd; + + cellVdec.trace("got picture (pts=0x%llx, dts=0x%llx)", frame.pts, frame.dts); + + thread_lock{*this}, out.push(std::move(frame)); + + cb_func(*this, id, CELL_VDEC_MSG_TYPE_PICOUT, CELL_OK, cb_arg); + } + + if (vcmd == vdec_cmd::decode) + { + break; + } + } + + cb_func(*this, id, vcmd == vdec_cmd::decode ? CELL_VDEC_MSG_TYPE_AUDONE : CELL_VDEC_MSG_TYPE_SEQDONE, CELL_OK, cb_arg); + break; + } + + case vdec_cmd::set_frc: + { + cmd_pop(); + frc_set = cmd.arg2(); + break; + } + + case vdec_cmd::close: + { + cmd_pop(); + state += cpu_state::exit; + return; + } + + default: + { + throw fmt::exception("Unknown command (0x%x)" HERE, vcmd); + } + } + } + } +}; u32 vdecQueryAttr(s32 type, u32 profile, u32 spec_addr /* may be 0 */, vm::ptr attr) { @@ -118,253 +380,6 @@ u32 vdecQueryAttr(s32 type, u32 profile, u32 spec_addr /* may be 0 */, vm::ptr(vdec_id); - - VideoDecoder& vdec = *sptr; - - vdec.id = vdec_id; - - vdec.vdecCb = idm::make_ptr(fmt::format("VideoDecoder[0x%x] Thread", vdec_id)); - vdec.vdecCb->prio = 1001; - vdec.vdecCb->stack_size = 0x10000; - vdec.vdecCb->custom_task = [sptr](PPUThread& ppu) - { - VideoDecoder& vdec = *sptr; - VdecTask& task = vdec.task; - - while (true) - { - if (Emu.IsStopped() || vdec.is_closed) - { - break; - } - - if (!vdec.job.pop(task, &vdec.is_closed)) - { - break; - } - - switch (task.type) - { - case vdecStartSeq: - { - cellVdec.warning("vdecStartSeq:"); - avcodec_flush_buffers(vdec.ctx); - - vdec.frc_set = 0; // TODO: ??? - vdec.last_pts = 0; - vdec.last_dts = 0; - break; - } - - case vdecDecodeAu: - case vdecEndSeq: - { - AVPacket packet{}; - - if (task.type == vdecDecodeAu) - { - packet.pts = vdec.task.pts != -1 ? vdec.task.pts : AV_NOPTS_VALUE; - packet.dts = vdec.task.dts != -1 ? vdec.task.dts : AV_NOPTS_VALUE; - packet.data = vm::_ptr(vdec.task.addr); - packet.size = vdec.task.size; - cellVdec.trace("vdecDecodeAu: size = 0x%x, pts = 0x%llx, dts = 0x%llx", task.size, task.pts, task.dts); - } - else - { - packet.pts = AV_NOPTS_VALUE; - packet.dts = AV_NOPTS_VALUE; - packet.data = nullptr; - packet.size = 0; - cellVdec.warning("vdecEndSeq"); - } - - while (true) - { - struct VdecFrameHolder : VdecFrame - { - VdecFrameHolder() - { - data = av_frame_alloc(); - } - - ~VdecFrameHolder() - { - if (data) - { - av_frame_unref(data); - av_frame_free(&data); - } - } - - } frame; - - if (!frame.data) - { - throw fmt::exception("av_frame_alloc() failed" HERE); - } - - int got_picture = 0; - - int decode = avcodec_decode_video2(vdec.ctx, frame.data, &got_picture, &packet); - - if (decode < 0) - { - throw fmt::exception("vdecDecodeAu: AU decoding error(0x%x)" HERE, decode); - } - - if (got_picture == 0) - { - break; - } - - if (decode != packet.size) - { - cellVdec.error("vdecDecodeAu: incorrect AU size (0x%x, decoded 0x%x)", packet.size, decode); - } - - if (got_picture) - { - if (frame.data->interlaced_frame) - { - throw EXCEPTION("Interlaced frames not supported (0x%x)", frame.data->interlaced_frame); - } - - if (frame.data->repeat_pict) - { - throw EXCEPTION("Repeated frames not supported (0x%x)", frame.data->repeat_pict); - } - - if (vdec.frc_set) - { - u64 amend = 0; - - switch (vdec.frc_set) - { - case CELL_VDEC_FRC_24000DIV1001: amend = 1001 * 90000 / 24000; break; - case CELL_VDEC_FRC_24: amend = 90000 / 24; break; - case CELL_VDEC_FRC_25: amend = 90000 / 25; break; - case CELL_VDEC_FRC_30000DIV1001: amend = 1001 * 90000 / 30000; break; - case CELL_VDEC_FRC_30: amend = 90000 / 30; break; - case CELL_VDEC_FRC_50: amend = 90000 / 50; break; - case CELL_VDEC_FRC_60000DIV1001: amend = 1001 * 90000 / 60000; break; - case CELL_VDEC_FRC_60: amend = 90000 / 60; break; - default: - { - throw EXCEPTION("Invalid frame rate code set (0x%x)", vdec.frc_set); - } - } - - vdec.last_pts += amend; - vdec.last_dts += amend; - frame.frc = vdec.frc_set; - } - else - { - const u64 amend = vdec.ctx->time_base.num * 90000 * vdec.ctx->ticks_per_frame / vdec.ctx->time_base.den; - vdec.last_pts += amend; - vdec.last_dts += amend; - - if (vdec.ctx->time_base.num == 1) - { - switch ((u64)vdec.ctx->time_base.den + (u64)(vdec.ctx->ticks_per_frame - 1) * 0x100000000ull) - { - case 24: case 0x100000000ull + 48: frame.frc = CELL_VDEC_FRC_24; break; - case 25: case 0x100000000ull + 50: frame.frc = CELL_VDEC_FRC_25; break; - case 30: case 0x100000000ull + 60: frame.frc = CELL_VDEC_FRC_30; break; - case 50: case 0x100000000ull + 100: frame.frc = CELL_VDEC_FRC_50; break; - case 60: case 0x100000000ull + 120: frame.frc = CELL_VDEC_FRC_60; break; - default: - { - throw EXCEPTION("Unsupported time_base.den (%d/1, tpf=%d)", vdec.ctx->time_base.den, vdec.ctx->ticks_per_frame); - } - } - } - else if (vdec.ctx->time_base.num == 1001) - { - if (vdec.ctx->time_base.den / vdec.ctx->ticks_per_frame == 24000) - { - frame.frc = CELL_VDEC_FRC_24000DIV1001; - } - else if (vdec.ctx->time_base.den / vdec.ctx->ticks_per_frame == 30000) - { - frame.frc = CELL_VDEC_FRC_30000DIV1001; - } - else if (vdec.ctx->time_base.den / vdec.ctx->ticks_per_frame == 60000) - { - frame.frc = CELL_VDEC_FRC_60000DIV1001; - } - else - { - throw EXCEPTION("Unsupported time_base.den (%d/1001, tpf=%d)", vdec.ctx->time_base.den, vdec.ctx->ticks_per_frame); - } - } - else - { - throw EXCEPTION("Unsupported time_base.num (%d)", vdec.ctx->time_base.num); - } - } - - frame.pts = vdec.last_pts = frame.data->pkt_pts != AV_NOPTS_VALUE ? frame.data->pkt_pts : vdec.last_pts; - frame.dts = vdec.last_dts = frame.data->pkt_dts != AV_NOPTS_VALUE ? frame.data->pkt_dts : vdec.last_dts; - frame.userdata = task.userData; - - cellVdec.trace("got picture (pts=0x%llx, dts=0x%llx)", frame.pts, frame.dts); - - if (vdec.frames.push(frame, &vdec.is_closed)) - { - frame.data = nullptr; // to prevent destruction - vdec.cbFunc(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_PICOUT, CELL_OK, vdec.cbArg); - } - } - - if (task.type == vdecDecodeAu) - { - break; - } - } - - if (task.type == vdecDecodeAu) - { - vdec.cbFunc(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, vdec.cbArg); - } - else - { - vdec.cbFunc(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_SEQDONE, CELL_OK, vdec.cbArg); - } - - break; - } - - case vdecSetFrameRate: - { - cellVdec.warning("vdecSetFrameRate(0x%x)", task.frc); - vdec.frc_set = task.frc; - break; - } - - case vdecClose: - { - break; - } - - default: - { - throw fmt::exception("Unknown task(%d)" HERE, task.type); - } - } - } - - vdec.is_finished = true; - }; - - vdec.vdecCb->cpu_init(); - vdec.vdecCb->state -= cpu_state::stop; - (*vdec.vdecCb)->lock_notify(); -} - s32 cellVdecQueryAttr(vm::cptr type, vm::ptr attr) { cellVdec.warning("cellVdecQueryAttr(type=*0x%x, attr=*0x%x)", type, attr); @@ -383,7 +398,13 @@ s32 cellVdecOpen(vm::cptr type, vm::cptr res, vm { cellVdec.warning("cellVdecOpen(type=*0x%x, res=*0x%x, cb=*0x%x, handle=*0x%x)", type, res, cb, handle); - vdecOpen(*handle = idm::make(type->codecType, type->profileLevel, res->memAddr, res->memSize, cb->cbFunc, cb->cbArg)); + // Create decoder thread + auto&& vdec = std::make_shared(type->codecType, type->profileLevel, res->memAddr, res->memSize, cb->cbFunc, cb->cbArg); + + // Hack: store thread id (normally it should be pointer) + *handle = idm::import_existing(vdec); + + vdec->run(); return CELL_OK; } @@ -392,7 +413,13 @@ s32 cellVdecOpenEx(vm::cptr type, vm::cptr r { cellVdec.warning("cellVdecOpenEx(type=*0x%x, res=*0x%x, cb=*0x%x, handle=*0x%x)", type, res, cb, handle); - vdecOpen(*handle = idm::make(type->codecType, type->profileLevel, res->memAddr, res->memSize, cb->cbFunc, cb->cbArg)); + // Create decoder thread + auto&& vdec = std::make_shared(type->codecType, type->profileLevel, res->memAddr, res->memSize, cb->cbFunc, cb->cbArg); + + // Hack: store thread id (normally it should be pointer) + *handle = idm::import_existing(vdec); + + vdec->run(); return CELL_OK; } @@ -401,25 +428,17 @@ s32 cellVdecClose(u32 handle) { cellVdec.warning("cellVdecClose(handle=0x%x)", handle); - const auto vdec = idm::get(handle); + const auto vdec = std::dynamic_pointer_cast(idm::get(handle)); // TODO: avoid RTTI if (!vdec) { return CELL_VDEC_ERROR_ARG; } - vdec->is_closed = true; - vdec->job.try_push(VdecTask(vdecClose)); - - while (!vdec->is_finished) - { - CHECK_EMU_STATUS; - - std::this_thread::sleep_for(1ms); // hack - } - - idm::remove(vdec->vdecCb->id); - idm::remove(handle); + vdec->cmd_push({vdec_cmd::close, 0}); + vdec->lock_notify(); + vdec->join(); + idm::remove(handle); return CELL_OK; } @@ -427,14 +446,15 @@ s32 cellVdecStartSeq(u32 handle) { cellVdec.trace("cellVdecStartSeq(handle=0x%x)", handle); - const auto vdec = idm::get(handle); + const auto vdec = std::dynamic_pointer_cast(idm::get(handle)); // TODO: avoid RTTI if (!vdec) { return CELL_VDEC_ERROR_ARG; } - vdec->job.push(VdecTask(vdecStartSeq), &vdec->is_closed); + vdec->cmd_push({vdec_cmd::start_seq, 0}); + vdec->lock_notify(); return CELL_OK; } @@ -442,14 +462,15 @@ s32 cellVdecEndSeq(u32 handle) { cellVdec.warning("cellVdecEndSeq(handle=0x%x)", handle); - const auto vdec = idm::get(handle); + const auto vdec = std::dynamic_pointer_cast(idm::get(handle)); // TODO: avoid RTTI if (!vdec) { return CELL_VDEC_ERROR_ARG; } - vdec->job.push(VdecTask(vdecEndSeq), &vdec->is_closed); + vdec->cmd_push({vdec_cmd::end_seq, 0}); + vdec->lock_notify(); return CELL_OK; } @@ -457,9 +478,9 @@ s32 cellVdecDecodeAu(u32 handle, CellVdecDecodeMode mode, vm::cptr(handle); + const auto vdec = std::dynamic_pointer_cast(idm::get(handle)); // TODO: avoid RTTI - if (!vdec || mode > CELL_VDEC_DEC_MODE_PB_SKIP) + if (mode > CELL_VDEC_DEC_MODE_PB_SKIP || !vdec) { return CELL_VDEC_ERROR_ARG; } @@ -470,16 +491,17 @@ s32 cellVdecDecodeAu(u32 handle, CellVdecDecodeMode mode, vm::cptrstartAddr; - task.size = auInfo->size; - task.dts = (u64)auInfo->dts.lower | ((u64)auInfo->dts.upper << 32); - task.pts = (u64)auInfo->pts.lower | ((u64)auInfo->pts.upper << 32); - task.userData = auInfo->userData; - task.specData = auInfo->codecSpecificData; + vdec->cmd_list + ({ + { vdec_cmd::decode, mode }, + { auInfo->startAddr, auInfo->size }, + u64{auInfo->pts.upper} << 32 | auInfo->pts.lower, + u64{auInfo->dts.upper} << 32 | auInfo->dts.lower, + auInfo->userData, + auInfo->codecSpecificData, + }); - vdec->job.push(task, &vdec->is_closed); + vdec->lock_notify(); return CELL_OK; } @@ -487,39 +509,35 @@ s32 cellVdecGetPicture(u32 handle, vm::cptr format, vm::ptr(handle); + const auto vdec = std::dynamic_pointer_cast(idm::get(handle)); // TODO: avoid RTTI - if (!vdec || !format) + if (!format || !vdec) { return CELL_VDEC_ERROR_ARG; } - VdecFrame vf; - if (!vdec->frames.try_pop(vf)) + vdec_frame frame; { - //std::this_thread::sleep_for(1ms); // hack - return CELL_VDEC_ERROR_EMPTY; + thread_lock lock(*vdec); + + if (vdec->out.empty()) + { + return CELL_VDEC_ERROR_EMPTY; + } + + frame = std::move(vdec->out.front()); + + vdec->out.pop(); } - if (!vf.data) - { - // hack - return CELL_OK; - } - - std::unique_ptr frame(vf.data, [](AVFrame* frame) - { - av_frame_unref(frame); - av_frame_free(&frame); - }); - + vdec->notify(); + if (outBuff) { - const auto f = vdec->ctx->pix_fmt; - const auto w = vdec->ctx->width; - const auto h = vdec->ctx->height; + const int w = frame->width; + const int h = frame->height; - auto out_f = AV_PIX_FMT_YUV420P; + AVPixelFormat out_f = AV_PIX_FMT_YUV420P; std::unique_ptr alpha_plane; @@ -532,29 +550,29 @@ s32 cellVdecGetPicture(u32 handle, vm::cptr format, vm::ptrcolorMatrixType != CELL_VDEC_COLOR_MATRIX_TYPE_BT709) { - throw EXCEPTION("Unknown colorMatrixType(%d)", format->colorMatrixType); + throw fmt::exception("Unknown colorMatrixType (%d)" HERE, format->colorMatrixType); } if (alpha_plane) { - memset(alpha_plane.get(), format->alpha, w * h); + std::memset(alpha_plane.get(), format->alpha, w * h); } - auto in_f = AV_PIX_FMT_YUV420P; + AVPixelFormat in_f = AV_PIX_FMT_YUV420P; - switch (f) + switch (frame->format) { case AV_PIX_FMT_YUV420P: in_f = alpha_plane ? AV_PIX_FMT_YUVA420P : AV_PIX_FMT_YUV420P; break; default: { - throw EXCEPTION("Unknown pix_fmt(%d)", f); + throw fmt::exception("Unknown format (%d)" HERE, frame->format); } } @@ -611,43 +629,54 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr picItem) { cellVdec.trace("cellVdecGetPicItem(handle=0x%x, picItem=**0x%x)", handle, picItem); - const auto vdec = idm::get(handle); + const auto vdec = std::dynamic_pointer_cast(idm::get(handle)); // TODO: avoid RTTI if (!vdec) { return CELL_VDEC_ERROR_ARG; } - VdecFrame vf; - if (!vdec->frames.try_peek(vf)) + AVFrame* frame{}; + u64 pts; + u64 dts; + u64 usrd; + u32 frc; { - //std::this_thread::sleep_for(1ms); // hack - return CELL_VDEC_ERROR_EMPTY; + thread_lock lock(*vdec); + + if (vdec->out.empty()) + { + return CELL_VDEC_ERROR_EMPTY; + } + + frame = vdec->out.front().avf.get(); + pts = vdec->out.front().pts; + dts = vdec->out.front().dts; + usrd = vdec->out.front().userdata; + frc = vdec->out.front().frc; } - AVFrame& frame = *vf.data; + const vm::ptr info = vm::cast(vdec->mem_addr + vdec->mem_bias); - const vm::ptr info = vm::cast(vdec->memAddr + vdec->memBias); - - vdec->memBias += 512; - if (vdec->memBias + 512 > vdec->memSize) + vdec->mem_bias += 512; + if (vdec->mem_bias + 512 > vdec->mem_size) { - vdec->memBias = 0; + vdec->mem_bias = 0; } info->codecType = vdec->type; info->startAddr = 0x00000123; // invalid value (no address for picture) info->size = align(av_image_get_buffer_size(vdec->ctx->pix_fmt, vdec->ctx->width, vdec->ctx->height, 1), 128); info->auNum = 1; - info->auPts[0].lower = (u32)(vf.pts); - info->auPts[0].upper = (u32)(vf.pts >> 32); + info->auPts[0].lower = (u32)(pts); + info->auPts[0].upper = (u32)(pts >> 32); info->auPts[1].lower = (u32)CODEC_TS_INVALID; info->auPts[1].upper = (u32)CODEC_TS_INVALID; - info->auDts[0].lower = (u32)(vf.dts); - info->auDts[0].upper = (u32)(vf.dts >> 32); + info->auDts[0].lower = (u32)(dts); + info->auDts[0].upper = (u32)(dts >> 32); info->auDts[1].lower = (u32)CODEC_TS_INVALID; info->auDts[1].upper = (u32)CODEC_TS_INVALID; - info->auUserData[0] = vf.userdata; + info->auUserData[0] = usrd; info->auUserData[1] = 0; info->status = CELL_OK; info->attr = CELL_VDEC_PICITEM_ATTR_NORMAL; @@ -657,15 +686,15 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr picItem) { const vm::ptr avc = vm::cast(info.addr() + SIZE_32(CellVdecPicItem)); - avc->horizontalSize = frame.width; - avc->verticalSize = frame.height; + avc->horizontalSize = frame->width; + avc->verticalSize = frame->height; - switch (frame.pict_type) + switch (frame->pict_type) { case AV_PICTURE_TYPE_I: avc->pictureType[0] = CELL_VDEC_AVC_PCT_I; break; case AV_PICTURE_TYPE_P: avc->pictureType[0] = CELL_VDEC_AVC_PCT_P; break; case AV_PICTURE_TYPE_B: avc->pictureType[0] = CELL_VDEC_AVC_PCT_B; break; - default: cellVdec.error("cellVdecGetPicItem(AVC): unknown pict_type value (0x%x)", frame.pict_type); + default: cellVdec.error("cellVdecGetPicItem(AVC): unknown pict_type value (0x%x)", frame->pict_type); } avc->pictureType[1] = CELL_VDEC_AVC_PCT_UNKNOWN; // ??? @@ -687,7 +716,7 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr picItem) avc->matrix_coefficients = CELL_VDEC_AVC_MXC_ITU_R_BT_709_5; // important avc->timing_info_present_flag = true; - switch (vf.frc) + switch (frc) { case CELL_VDEC_FRC_24000DIV1001: avc->frameRateCode = CELL_VDEC_AVC_FRC_24000DIV1001; break; case CELL_VDEC_FRC_24: avc->frameRateCode = CELL_VDEC_AVC_FRC_24; break; @@ -697,7 +726,7 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr picItem) case CELL_VDEC_FRC_50: avc->frameRateCode = CELL_VDEC_AVC_FRC_50; break; case CELL_VDEC_FRC_60000DIV1001: avc->frameRateCode = CELL_VDEC_AVC_FRC_60000DIV1001; break; case CELL_VDEC_FRC_60: avc->frameRateCode = CELL_VDEC_AVC_FRC_60; break; - default: cellVdec.error("cellVdecGetPicItem(AVC): unknown frc value (0x%x)", vf.frc); + default: cellVdec.error("cellVdecGetPicItem(AVC): unknown frc value (0x%x)", frc); } avc->fixed_frame_rate_flag = true; @@ -713,16 +742,16 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr picItem) { const vm::ptr dvx = vm::cast(info.addr() + SIZE_32(CellVdecPicItem)); - switch (frame.pict_type) + switch (frame->pict_type) { case AV_PICTURE_TYPE_I: dvx->pictureType = CELL_VDEC_DIVX_VCT_I; break; case AV_PICTURE_TYPE_P: dvx->pictureType = CELL_VDEC_DIVX_VCT_P; break; case AV_PICTURE_TYPE_B: dvx->pictureType = CELL_VDEC_DIVX_VCT_B; break; - default: cellVdec.error("cellVdecGetPicItem(DivX): unknown pict_type value (0x%x)", frame.pict_type); + default: cellVdec.error("cellVdecGetPicItem(DivX): unknown pict_type value (0x%x)", frame->pict_type); } - dvx->horizontalSize = frame.width; - dvx->verticalSize = frame.height; + dvx->horizontalSize = frame->width; + dvx->verticalSize = frame->height; dvx->pixelAspectRatio = CELL_VDEC_DIVX_ARI_PAR_1_1; // ??? dvx->parHeight = 0; dvx->parWidth = 0; @@ -732,7 +761,7 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr picItem) dvx->matrixCoefficients = CELL_VDEC_DIVX_MXC_ITU_R_BT_709; // ??? dvx->pictureStruct = CELL_VDEC_DIVX_PSTR_FRAME; // ??? - switch (vf.frc) + switch (frc) { case CELL_VDEC_FRC_24000DIV1001: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_24000DIV1001; break; case CELL_VDEC_FRC_24: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_24; break; @@ -742,7 +771,7 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr picItem) case CELL_VDEC_FRC_50: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_50; break; case CELL_VDEC_FRC_60000DIV1001: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_60000DIV1001; break; case CELL_VDEC_FRC_60: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_60; break; - default: cellVdec.error("cellVdecGetPicItem(DivX): unknown frc value (0x%x)", vf.frc); + default: cellVdec.error("cellVdecGetPicItem(DivX): unknown frc value (0x%x)", frc); } } else if (vdec->type == CELL_VDEC_CODEC_TYPE_MPEG2) @@ -750,11 +779,11 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr picItem) const vm::ptr mp2 = vm::cast(info.addr() + SIZE_32(CellVdecPicItem)); std::memset(mp2.get_ptr(), 0, sizeof(CellVdecMpeg2Info)); - mp2->horizontal_size = frame.width; - mp2->vertical_size = frame.height; + mp2->horizontal_size = frame->width; + mp2->vertical_size = frame->height; mp2->aspect_ratio_information = CELL_VDEC_MPEG2_ARI_SAR_1_1; // ??? - switch (vf.frc) + switch (frc) { case CELL_VDEC_FRC_24000DIV1001: mp2->frame_rate_code = CELL_VDEC_MPEG2_FRC_24000DIV1001; break; case CELL_VDEC_FRC_24: mp2->frame_rate_code = CELL_VDEC_MPEG2_FRC_24; break; @@ -764,7 +793,7 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr picItem) case CELL_VDEC_FRC_50: mp2->frame_rate_code = CELL_VDEC_MPEG2_FRC_50; break; case CELL_VDEC_FRC_60000DIV1001: mp2->frame_rate_code = CELL_VDEC_MPEG2_FRC_60000DIV1001; break; case CELL_VDEC_FRC_60: mp2->frame_rate_code = CELL_VDEC_MPEG2_FRC_60; break; - default: cellVdec.error("cellVdecGetPicItem(MPEG2): unknown frc value (0x%x)", vf.frc); + default: cellVdec.error("cellVdecGetPicItem(MPEG2): unknown frc value (0x%x)", frc); } mp2->progressive_sequence = true; // ??? @@ -772,12 +801,12 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr picItem) mp2->video_format = CELL_VDEC_MPEG2_VF_UNSPECIFIED; // ??? mp2->colour_description = false; // ??? - switch (frame.pict_type) + switch (frame->pict_type) { case AV_PICTURE_TYPE_I: mp2->picture_coding_type[0] = CELL_VDEC_MPEG2_PCT_I; break; case AV_PICTURE_TYPE_P: mp2->picture_coding_type[0] = CELL_VDEC_MPEG2_PCT_P; break; case AV_PICTURE_TYPE_B: mp2->picture_coding_type[0] = CELL_VDEC_MPEG2_PCT_B; break; - default: cellVdec.error("cellVdecGetPicItem(MPEG2): unknown pict_type value (0x%x)", frame.pict_type); + default: cellVdec.error("cellVdecGetPicItem(MPEG2): unknown pict_type value (0x%x)", frame->pict_type); } mp2->picture_coding_type[1] = CELL_VDEC_MPEG2_PCT_FORBIDDEN; // ??? @@ -795,18 +824,16 @@ s32 cellVdecSetFrameRate(u32 handle, CellVdecFrameRate frc) { cellVdec.trace("cellVdecSetFrameRate(handle=0x%x, frc=0x%x)", handle, frc); - const auto vdec = idm::get(handle); + const auto vdec = std::dynamic_pointer_cast(idm::get(handle)); // TODO: avoid RTTI if (!vdec) { return CELL_VDEC_ERROR_ARG; } - // TODO: check frc value and set frame rate - VdecTask task(vdecSetFrameRate); - task.frc = frc; - - vdec->job.push(task, &vdec->is_closed); + // TODO: check frc value + vdec->cmd_push({vdec_cmd::set_frc, frc}); + vdec->lock_notify(); return CELL_OK; } diff --git a/rpcs3/Emu/Cell/Modules/cellVdec.h b/rpcs3/Emu/Cell/Modules/cellVdec.h index 7709139e1a..8a8ce8193f 100644 --- a/rpcs3/Emu/Cell/Modules/cellVdec.h +++ b/rpcs3/Emu/Cell/Modules/cellVdec.h @@ -61,7 +61,7 @@ enum CellVdecPicAttr : s32 }; // Universal Frame Rate Code -enum CellVdecFrameRate : u8 +enum CellVdecFrameRate : s32 { CELL_VDEC_FRC_24000DIV1001 = 0x80, CELL_VDEC_FRC_24 = 0x81, @@ -644,81 +644,3 @@ struct CellVdecMpeg2Info u8 ccData[2][128]; be_t reserved[2]; }; - -/* Video Decoder Thread Classes */ - -enum VdecJobType : u32 -{ - vdecStartSeq, - vdecEndSeq, - vdecDecodeAu, - vdecSetFrameRate, - vdecClose, -}; - -struct VdecTask -{ - VdecJobType type; - union - { - u32 frc; - CellVdecDecodeMode mode; - }; - u32 addr; - u32 size; - u64 pts; - u64 dts; - u64 userData; - u64 specData; - - VdecTask(VdecJobType type) - : type(type) - { - } - - VdecTask() - { - } -}; - -struct VdecFrame -{ - AVFrame* data; - u64 dts; - u64 pts; - u64 userdata; - u32 frc; -}; - -class VideoDecoder -{ -public: - squeue_t job; - u32 id; - volatile bool is_closed; - volatile bool is_finished; - - struct AVCodec* codec; - struct AVCodecContext* ctx; - - squeue_t frames; - - const s32 type; - const u32 profile; - const u32 memAddr; - const u32 memSize; - const vm::ptr cbFunc; - const u32 cbArg; - u32 memBias; - - VdecTask task; // current task variable - u32 frc_set; // frame rate overwriting - u64 last_pts; - u64 last_dts; - - std::shared_ptr vdecCb; - - VideoDecoder(s32 type, u32 profile, u32 addr, u32 size, vm::ptr func, u32 arg); - - ~VideoDecoder(); -}; diff --git a/rpcs3/Emu/Cell/Modules/libmixer.cpp b/rpcs3/Emu/Cell/Modules/libmixer.cpp index 932d20e67e..e129cfda2c 100644 --- a/rpcs3/Emu/Cell/Modules/libmixer.cpp +++ b/rpcs3/Emu/Cell/Modules/libmixer.cpp @@ -8,9 +8,46 @@ #include #include +#include logs::channel libmixer("libmixer", logs::level::notice); +struct SurMixerConfig +{ + std::mutex mutex; + + u32 audio_port; + s32 priority; + u32 ch_strips_1; + u32 ch_strips_2; + u32 ch_strips_6; + u32 ch_strips_8; + + vm::ptr cb; + vm::ptr cb_arg; + + f32 mixdata[8 * 256]; + u64 mixcount; +}; + +struct SSPlayer +{ + bool m_created; // SSPlayerCreate/Remove + bool m_connected; // AANConnect/Disconnect + bool m_active; // SSPlayerPlay/Stop + u32 m_channels; // 1 or 2 + u32 m_addr; + u32 m_samples; + u32 m_loop_start; + u32 m_loop_mode; + u32 m_position; + float m_level; + float m_speed; + float m_x; + float m_y; + float m_z; +}; + // TODO: use fxm SurMixerConfig g_surmx; @@ -284,48 +321,14 @@ s32 cellSSPlayerGetState(u32 handle) return CELL_SSPLAYER_STATE_OFF; } -s32 cellSurMixerCreate(vm::cptr config) +struct surmixer_thread : ppu_thread { - libmixer.warning("cellSurMixerCreate(config=*0x%x)", config); + using ppu_thread::ppu_thread; - const auto g_audio = fxm::get(); - - const auto port = g_audio->open_port(); - - if (!port) + virtual void cpu_task() override { - return CELL_LIBMIXER_ERROR_FULL; - } + const auto g_audio = fxm::get(); - 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) @@ -345,7 +348,7 @@ s32 cellSurMixerCreate(vm::cptr config) 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); + g_surmx.cb(*this, g_surmx.cb_arg, (u32)g_surmx.mixcount, 256); } //u64 stamp1 = get_system_time(); @@ -445,12 +448,52 @@ s32 cellSurMixerCreate(vm::cptr config) g_surmx.mixcount++; } - idm::remove(ppu.id); - }; + idm::remove(id); + } +}; - ppu->cpu_init(); - ppu->state -= cpu_state::stop; - (*ppu)->lock_notify(); +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); + + auto&& thread = std::make_shared("Surmixer Thread"); + + idm::import_existing(thread); + + thread->run(); return CELL_OK; } diff --git a/rpcs3/Emu/Cell/Modules/libmixer.h b/rpcs3/Emu/Cell/Modules/libmixer.h index 87487b761b..404826902d 100644 --- a/rpcs3/Emu/Cell/Modules/libmixer.h +++ b/rpcs3/Emu/Cell/Modules/libmixer.h @@ -166,39 +166,3 @@ struct CellSurMixerChStripParam be_t floatVal; be_t intVal; }; - -struct SurMixerConfig -{ - std::mutex mutex; - - u32 audio_port; - s32 priority; - u32 ch_strips_1; - u32 ch_strips_2; - u32 ch_strips_6; - u32 ch_strips_8; - - vm::ptr cb; - vm::ptr cb_arg; - - f32 mixdata[8 * 256]; - u64 mixcount; -}; - -struct SSPlayer -{ - bool m_created; // SSPlayerCreate/Remove - bool m_connected; // AANConnect/Disconnect - bool m_active; // SSPlayerPlay/Stop - u32 m_channels; // 1 or 2 - u32 m_addr; - u32 m_samples; - u32 m_loop_start; - u32 m_loop_mode; - u32 m_position; - float m_level; - float m_speed; - float m_x; - float m_y; - float m_z; -}; diff --git a/rpcs3/Emu/Cell/Modules/sceNp2.cpp b/rpcs3/Emu/Cell/Modules/sceNp2.cpp index 653c4a5295..6b0b42caf1 100644 --- a/rpcs3/Emu/Cell/Modules/sceNp2.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNp2.cpp @@ -53,7 +53,7 @@ s32 sceNp2Term() return CELL_OK; } -s32 sceNpMatching2Term(PPUThread& ppu) +s32 sceNpMatching2Term(ppu_thread& ppu) { sceNp2.warning("sceNpMatching2Term()"); diff --git a/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp b/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp index 1f011f2b2b..a743a953cb 100644 --- a/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp @@ -136,7 +136,7 @@ s32 sceNpTrophyDestroyContext(u32 context) return CELL_OK; } -s32 sceNpTrophyRegisterContext(PPUThread& CPU, u32 context, u32 handle, vm::ptr statusCb, vm::ptr arg, u64 options) +s32 sceNpTrophyRegisterContext(ppu_thread& CPU, u32 context, u32 handle, vm::ptr statusCb, vm::ptr arg, u64 options) { sceNpTrophy.error("sceNpTrophyRegisterContext(context=0x%x, handle=0x%x, statusCb=*0x%x, arg=*0x%x, options=0x%llx)", context, handle, statusCb, arg, options); diff --git a/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp b/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp index 91b075b393..036555bee3 100644 --- a/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp @@ -58,12 +58,12 @@ void ppu_free_tls(u32 addr) } } -void sys_initialize_tls(PPUThread& ppu, u64 main_thread_id, u32 tls_seg_addr, u32 tls_seg_size, u32 tls_mem_size) +void sys_initialize_tls(ppu_thread& 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; + if (ppu.gpr[13] != 0) return; // Initialize TLS memory s_tls_addr = tls_seg_addr; @@ -75,7 +75,7 @@ void sys_initialize_tls(PPUThread& ppu, u64 main_thread_id, u32 tls_seg_addr, u3 s_tls_map = std::make_unique[]>(s_tls_max); // Allocate TLS for main thread - ppu.GPR[13] = ppu_alloc_tls() + 0x7000 + 0x30; + ppu.gpr[13] = ppu_alloc_tls() + 0x7000 + 0x30; sysPrxForUser.notice("TLS initialized (addr=0x%x, size=0x%x, max=0x%x)", s_tls_area - 0x30, s_tls_size, s_tls_max); @@ -105,7 +105,7 @@ s64 _sys_process_at_Exitspawn() return CELL_OK; } -s32 sys_interrupt_thread_disestablish(PPUThread& ppu, u32 ih) +s32 sys_interrupt_thread_disestablish(ppu_thread& ppu, u32 ih) { sysPrxForUser.notice("sys_interrupt_thread_disestablish(ih=0x%x)", ih); diff --git a/rpcs3/Emu/Cell/Modules/sysPrxForUser.h b/rpcs3/Emu/Cell/Modules/sysPrxForUser.h index d430f7cddc..dc146a43c4 100644 --- a/rpcs3/Emu/Cell/Modules/sysPrxForUser.h +++ b/rpcs3/Emu/Cell/Modules/sysPrxForUser.h @@ -17,19 +17,19 @@ struct sys_lwmutex_t; struct sys_lwmutex_attribute_t; s32 sys_lwmutex_create(vm::ptr lwmutex, vm::ptr attr); -s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr lwmutex, u64 timeout); -s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr lwmutex); -s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr lwmutex); -s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr lwmutex); +s32 sys_lwmutex_lock(ppu_thread& CPU, vm::ptr lwmutex, u64 timeout); +s32 sys_lwmutex_trylock(ppu_thread& CPU, vm::ptr lwmutex); +s32 sys_lwmutex_unlock(ppu_thread& CPU, vm::ptr lwmutex); +s32 sys_lwmutex_destroy(ppu_thread& CPU, vm::ptr lwmutex); struct sys_lwcond_t; struct sys_lwcond_attribute_t; s32 sys_lwcond_create(vm::ptr lwcond, vm::ptr lwmutex, vm::ptr attr); s32 sys_lwcond_destroy(vm::ptr lwcond); -s32 sys_lwcond_signal(PPUThread& CPU, vm::ptr lwcond); -s32 sys_lwcond_signal_all(PPUThread& CPU, vm::ptr lwcond); -s32 sys_lwcond_signal_to(PPUThread& CPU, vm::ptr lwcond, u32 ppu_thread_id); -s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr lwcond, u64 timeout); +s32 sys_lwcond_signal(ppu_thread& CPU, vm::ptr lwcond); +s32 sys_lwcond_signal_all(ppu_thread& CPU, vm::ptr lwcond); +s32 sys_lwcond_signal_to(ppu_thread& CPU, vm::ptr lwcond, u32 ppu_thread_id); +s32 sys_lwcond_wait(ppu_thread& CPU, vm::ptr lwcond, u64 timeout); -void sys_ppu_thread_exit(PPUThread& CPU, u64 val); +void sys_ppu_thread_exit(ppu_thread& CPU, u64 val); diff --git a/rpcs3/Emu/Cell/Modules/sys_libc_.cpp b/rpcs3/Emu/Cell/Modules/sys_libc_.cpp index 97b1045823..c7ea6fed01 100644 --- a/rpcs3/Emu/Cell/Modules/sys_libc_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_libc_.cpp @@ -6,7 +6,7 @@ extern logs::channel sysPrxForUser; extern fs::file g_tty; // TODO -static std::string ps3_fmt(PPUThread& context, vm::cptr fmt, u32 g_count) +static std::string ps3_fmt(ppu_thread& context, vm::cptr fmt, u32 g_count) { std::string result; @@ -312,7 +312,7 @@ s32 _sys_free(u32 addr) return CELL_OK; } -s32 _sys_snprintf(PPUThread& ppu, vm::ptr dst, u32 count, vm::cptr fmt, ppu_va_args_t va_args) +s32 _sys_snprintf(ppu_thread& ppu, vm::ptr dst, u32 count, vm::cptr fmt, ppu_va_args_t va_args) { sysPrxForUser.warning("_sys_snprintf(dst=*0x%x, count=%d, fmt=*0x%x, ...)", dst, count, fmt); @@ -334,7 +334,7 @@ s32 _sys_snprintf(PPUThread& ppu, vm::ptr dst, u32 count, vm::cptr f } } -s32 _sys_printf(PPUThread& ppu, vm::cptr fmt, ppu_va_args_t va_args) +s32 _sys_printf(ppu_thread& ppu, vm::cptr fmt, ppu_va_args_t va_args) { sysPrxForUser.warning("_sys_printf(fmt=*0x%x, ...)", fmt); diff --git a/rpcs3/Emu/Cell/Modules/sys_lwcond_.cpp b/rpcs3/Emu/Cell/Modules/sys_lwcond_.cpp index 4d3e0e5518..d505e07f68 100644 --- a/rpcs3/Emu/Cell/Modules/sys_lwcond_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_lwcond_.cpp @@ -33,7 +33,7 @@ s32 sys_lwcond_destroy(vm::ptr lwcond) return res; } -s32 sys_lwcond_signal(PPUThread& ppu, vm::ptr lwcond) +s32 sys_lwcond_signal(ppu_thread& ppu, vm::ptr lwcond) { sysPrxForUser.trace("sys_lwcond_signal(lwcond=*0x%x)", lwcond); @@ -91,7 +91,7 @@ s32 sys_lwcond_signal(PPUThread& ppu, vm::ptr lwcond) return CELL_OK; } -s32 sys_lwcond_signal_all(PPUThread& ppu, vm::ptr lwcond) +s32 sys_lwcond_signal_all(ppu_thread& ppu, vm::ptr lwcond) { sysPrxForUser.trace("sys_lwcond_signal_all(lwcond=*0x%x)", lwcond); @@ -148,7 +148,7 @@ s32 sys_lwcond_signal_all(PPUThread& ppu, vm::ptr lwcond) return res; } -s32 sys_lwcond_signal_to(PPUThread& ppu, vm::ptr lwcond, u32 ppu_thread_id) +s32 sys_lwcond_signal_to(ppu_thread& ppu, vm::ptr lwcond, u32 ppu_thread_id) { sysPrxForUser.trace("sys_lwcond_signal_to(lwcond=*0x%x, ppu_thread_id=0x%x)", lwcond, ppu_thread_id); @@ -206,7 +206,7 @@ s32 sys_lwcond_signal_to(PPUThread& ppu, vm::ptr lwcond, u32 ppu_t return CELL_OK; } -s32 sys_lwcond_wait(PPUThread& ppu, vm::ptr lwcond, u64 timeout) +s32 sys_lwcond_wait(ppu_thread& ppu, vm::ptr lwcond, u64 timeout) { sysPrxForUser.trace("sys_lwcond_wait(lwcond=*0x%x, timeout=0x%llx)", lwcond, timeout); diff --git a/rpcs3/Emu/Cell/Modules/sys_lwmutex_.cpp b/rpcs3/Emu/Cell/Modules/sys_lwmutex_.cpp index 7050e97aa5..6edc64ea9e 100644 --- a/rpcs3/Emu/Cell/Modules/sys_lwmutex_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_lwmutex_.cpp @@ -39,7 +39,7 @@ s32 sys_lwmutex_create(vm::ptr lwmutex, vm::ptr lwmutex) +s32 sys_lwmutex_destroy(ppu_thread& ppu, vm::ptr lwmutex) { sysPrxForUser.trace("sys_lwmutex_destroy(lwmutex=*0x%x)", lwmutex); @@ -70,7 +70,7 @@ s32 sys_lwmutex_destroy(PPUThread& ppu, vm::ptr lwmutex) return CELL_OK; } -s32 sys_lwmutex_lock(PPUThread& ppu, vm::ptr lwmutex, u64 timeout) +s32 sys_lwmutex_lock(ppu_thread& ppu, vm::ptr lwmutex, u64 timeout) { sysPrxForUser.trace("sys_lwmutex_lock(lwmutex=*0x%x, timeout=0x%llx)", lwmutex, timeout); @@ -164,7 +164,7 @@ s32 sys_lwmutex_lock(PPUThread& ppu, vm::ptr lwmutex, u64 timeout return res; } -s32 sys_lwmutex_trylock(PPUThread& ppu, vm::ptr lwmutex) +s32 sys_lwmutex_trylock(ppu_thread& ppu, vm::ptr lwmutex) { sysPrxForUser.trace("sys_lwmutex_trylock(lwmutex=*0x%x)", lwmutex); @@ -231,7 +231,7 @@ s32 sys_lwmutex_trylock(PPUThread& ppu, vm::ptr lwmutex) return CELL_EBUSY; } -s32 sys_lwmutex_unlock(PPUThread& ppu, vm::ptr lwmutex) +s32 sys_lwmutex_unlock(ppu_thread& ppu, vm::ptr lwmutex) { sysPrxForUser.trace("sys_lwmutex_unlock(lwmutex=*0x%x)", lwmutex); diff --git a/rpcs3/Emu/Cell/Modules/sys_net.cpp b/rpcs3/Emu/Cell/Modules/sys_net.cpp index 990b2bd14d..23272d49ff 100644 --- a/rpcs3/Emu/Cell/Modules/sys_net.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_net.cpp @@ -8,6 +8,7 @@ #include #include #else +#include #include #include #include diff --git a/rpcs3/Emu/Cell/Modules/sys_ppu_thread_.cpp b/rpcs3/Emu/Cell/Modules/sys_ppu_thread_.cpp index 7078ff70c8..08cd2f3dc8 100644 --- a/rpcs3/Emu/Cell/Modules/sys_ppu_thread_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_ppu_thread_.cpp @@ -57,7 +57,7 @@ s32 sys_ppu_thread_create(vm::ptr thread_id, u32 entry, u64 arg, s32 prio, return CELL_OK; } -s32 sys_ppu_thread_get_id(PPUThread& ppu, vm::ptr thread_id) +s32 sys_ppu_thread_get_id(ppu_thread& ppu, vm::ptr thread_id) { sysPrxForUser.trace("sys_ppu_thread_get_id(thread_id=*0x%x)", thread_id); @@ -66,7 +66,7 @@ s32 sys_ppu_thread_get_id(PPUThread& ppu, vm::ptr thread_id) return CELL_OK; } -void sys_ppu_thread_exit(PPUThread& ppu, u64 val) +void sys_ppu_thread_exit(ppu_thread& ppu, u64 val) { sysPrxForUser.trace("sys_ppu_thread_exit(val=0x%llx)", val); @@ -74,12 +74,12 @@ void sys_ppu_thread_exit(PPUThread& ppu, u64 val) // ... // Deallocate TLS - ppu_free_tls(vm::cast(ppu.GPR[13], HERE) - 0x7030); + ppu_free_tls(vm::cast(ppu.gpr[13], HERE) - 0x7030); - if (ppu.GPR[3] == val && !ppu.custom_task) + if (ppu.gpr[3] == val) { // Change sys_ppu_thread_exit code to the syscall code (hack) - ppu.GPR[11] = 41; + ppu.gpr[11] = 41; } // Call the syscall @@ -88,7 +88,7 @@ void sys_ppu_thread_exit(PPUThread& ppu, u64 val) std::mutex g_once_mutex; -void sys_ppu_thread_once(PPUThread& ppu, vm::ptr> once_ctrl, vm::ptr init) +void sys_ppu_thread_once(ppu_thread& ppu, vm::ptr> once_ctrl, vm::ptr init) { sysPrxForUser.warning("sys_ppu_thread_once(once_ctrl=*0x%x, init=*0x%x)", once_ctrl, init); diff --git a/rpcs3/Emu/Cell/Modules/sys_spu_.cpp b/rpcs3/Emu/Cell/Modules/sys_spu_.cpp index 111ce221de..397c3a331f 100644 --- a/rpcs3/Emu/Cell/Modules/sys_spu_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_spu_.cpp @@ -93,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(ppu_thread& ppu, s32 id, vm::ptr img) { sysPrxForUser.warning("sys_raw_spu_image_load(id=%d, img=*0x%x)", id, img); @@ -140,7 +140,7 @@ s32 _sys_spu_printf_finalize() return CELL_OK; } -s32 _sys_spu_printf_attach_group(PPUThread& ppu, u32 group) +s32 _sys_spu_printf_attach_group(ppu_thread& ppu, u32 group) { sysPrxForUser.warning("_sys_spu_printf_attach_group(group=0x%x)", group); @@ -152,7 +152,7 @@ s32 _sys_spu_printf_attach_group(PPUThread& ppu, u32 group) return g_spu_printf_agcb(ppu, group); } -s32 _sys_spu_printf_detach_group(PPUThread& ppu, u32 group) +s32 _sys_spu_printf_detach_group(ppu_thread& ppu, u32 group) { sysPrxForUser.warning("_sys_spu_printf_detach_group(group=0x%x)", group); @@ -164,7 +164,7 @@ s32 _sys_spu_printf_detach_group(PPUThread& ppu, u32 group) return g_spu_printf_dgcb(ppu, group); } -s32 _sys_spu_printf_attach_thread(PPUThread& ppu, u32 thread) +s32 _sys_spu_printf_attach_thread(ppu_thread& ppu, u32 thread) { sysPrxForUser.warning("_sys_spu_printf_attach_thread(thread=0x%x)", thread); @@ -176,7 +176,7 @@ s32 _sys_spu_printf_attach_thread(PPUThread& ppu, u32 thread) return g_spu_printf_atcb(ppu, thread); } -s32 _sys_spu_printf_detach_thread(PPUThread& ppu, u32 thread) +s32 _sys_spu_printf_detach_thread(ppu_thread& ppu, u32 thread) { sysPrxForUser.warning("_sys_spu_printf_detach_thread(thread=0x%x)", thread); diff --git a/rpcs3/Emu/Cell/PPUAnalyser.cpp b/rpcs3/Emu/Cell/PPUAnalyser.cpp index 4df9e91edf..5759921c1a 100644 --- a/rpcs3/Emu/Cell/PPUAnalyser.cpp +++ b/rpcs3/Emu/Cell/PPUAnalyser.cpp @@ -403,6 +403,10 @@ std::vector ppu_analyse(const std::vector>& se const u32 addr = ptr[0]; const u32 _toc = ptr[1]; + // Rough Table of Contents borders + const u32 _toc_begin = _toc - 0x8000; + const u32 _toc_end = _toc + 0x8000; + // TODO: improve TOC constraints if (_toc % 4 || _toc == 0 || _toc >= 0x40000000 || (_toc >= start && _toc < end)) { @@ -436,8 +440,8 @@ std::vector ppu_analyse(const std::vector>& se } } - // Secondary attempt (TODO) - if (secs.empty() && lib_toc) + // Secondary attempt (TODO, needs better strategy) + if (/*secs.empty() &&*/ lib_toc) { add_toc(lib_toc); } diff --git a/rpcs3/Emu/Cell/PPUCallback.cpp b/rpcs3/Emu/Cell/PPUCallback.cpp deleted file mode 100644 index 3f29de1945..0000000000 --- a/rpcs3/Emu/Cell/PPUCallback.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/System.h" -#include "Emu/IdManager.h" - -#include "PPUThread.h" -#include "PPUCallback.h" - -#include - -void CallbackManager::Register(check_cb_t func) -{ - std::lock_guard lock(m_mutex); - - m_check_cb.emplace(std::move(func)); -} - -void CallbackManager::Async(async_cb_t func) -{ - std::lock_guard lock(m_mutex); - - if (!m_cb_thread) - { - throw EXCEPTION("Callback thread not found"); - } - - m_async_cb.emplace(std::move(func)); - - (*m_cb_thread)->notify(); -} - -extern std::condition_variable& get_current_thread_cv(); - -CallbackManager::check_cb_t CallbackManager::Check() -{ - std::lock_guard lock(m_mutex); - - if (m_check_cb.size()) - { - check_cb_t func = std::move(m_check_cb.front()); - - m_check_cb.pop(); - - return func; - } - - return nullptr; -} - -void CallbackManager::Init() -{ - std::lock_guard lock(m_mutex); - - auto task = [this](PPUThread& ppu) - { - std::unique_lock lock(m_mutex); - - while (true) - { - CHECK_EMU_STATUS; - - if (!lock) - { - lock.lock(); - continue; - } - - if (m_async_cb.size()) - { - async_cb_t func = std::move(m_async_cb.front()); - - m_async_cb.pop(); - - if (lock) lock.unlock(); - - func(ppu); - - continue; - } - - get_current_thread_cv().wait(lock); - } - }; - - auto thread = idm::make_ptr("Callback Thread"); - - thread->prio = 1001; - thread->stack_size = 0x10000; - thread->custom_task = task; - thread->cpu_init(); - - m_cb_thread = thread; -} - -void CallbackManager::Clear() -{ - std::lock_guard lock(m_mutex); - - m_check_cb = decltype(m_check_cb){}; - m_async_cb = decltype(m_async_cb){}; - - m_cb_thread.reset(); -} diff --git a/rpcs3/Emu/Cell/PPUCallback.h b/rpcs3/Emu/Cell/PPUCallback.h index 42fe061830..1797556b27 100644 --- a/rpcs3/Emu/Cell/PPUCallback.h +++ b/rpcs3/Emu/Cell/PPUCallback.h @@ -27,9 +27,9 @@ namespace ppu_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"); - static inline void set_value(PPUThread& CPU, const T& arg) + static inline void set_value(ppu_thread& CPU, const T& arg) { - CPU.GPR[g_count + 2] = ppu_gpr_cast(arg); + CPU.gpr[g_count + 2] = ppu_gpr_cast(arg); } }; @@ -38,9 +38,9 @@ namespace ppu_cb_detail { static_assert(sizeof(T) <= 8, "Invalid callback argument type for ARG_FLOAT"); - static inline void set_value(PPUThread& CPU, const T& arg) + static inline void set_value(ppu_thread& CPU, const T& arg) { - CPU.FPR[f_count] = static_cast(arg); + CPU.fpr[f_count] = static_cast(arg); } }; @@ -49,9 +49,9 @@ namespace ppu_cb_detail { static_assert(std::is_same::value, "Invalid callback argument type for ARG_VECTOR"); - static inline void set_value(PPUThread& CPU, const T& arg) + static inline void set_value(ppu_thread& CPU, const T& arg) { - CPU.VR[v_count + 1] = arg; + CPU.vr[v_count + 1] = arg; } }; @@ -60,37 +60,37 @@ namespace ppu_cb_detail { static_assert(alignof(T) <= 16, "Unsupported callback argument type alignment for ARG_STACK"); - static inline void set_value(PPUThread& CPU, const T& arg) + static inline void set_value(ppu_thread& CPU, const T& 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 + vm::ps3::write64(CPU.gpr[1] + stack_pos, ppu_gpr_cast(arg)); // TODO } }; template struct _func_arg { - static_assert(std::is_same::value, "Invalid callback argument type for ARG_CONTEXT"); + static_assert(std::is_same::value, "Invalid callback argument type for ARG_CONTEXT"); - force_inline static void set_value(PPUThread& CPU, const T& arg) + force_inline static void set_value(ppu_thread& CPU, const T& arg) { } }; template - force_inline static bool _bind_func_args(PPUThread& CPU) + force_inline static bool _bind_func_args(ppu_thread& CPU) { // terminator return false; } template - force_inline static bool _bind_func_args(PPUThread& CPU, T1 arg1, T... args) + force_inline static bool _bind_func_args(ppu_thread& CPU, T1 arg1, T... args) { const bool is_float = std::is_floating_point::value; const bool is_vector = std::is_same::value; - const bool is_context = std::is_same::value; + const bool is_context = std::is_same::value; const bool is_general = !is_float && !is_vector && !is_context; const _func_arg_type t = @@ -116,9 +116,9 @@ namespace ppu_cb_detail static_assert(type == ARG_GENERAL, "Unknown callback result type"); static_assert(sizeof(T) <= 8, "Invalid callback result type for ARG_GENERAL"); - force_inline static T get_value(const PPUThread& CPU) + force_inline static T get_value(const ppu_thread& CPU) { - return ppu_gpr_cast(CPU.GPR[3]); + return ppu_gpr_cast(CPU.gpr[3]); } }; @@ -127,9 +127,9 @@ namespace ppu_cb_detail { static_assert(sizeof(T) <= 8, "Invalid callback result type for ARG_FLOAT"); - force_inline static T get_value(const PPUThread& CPU) + force_inline static T get_value(const ppu_thread& CPU) { - return static_cast(CPU.FPR[1]); + return static_cast(CPU.fpr[1]); } }; @@ -138,16 +138,16 @@ namespace ppu_cb_detail { static_assert(std::is_same::value, "Invalid callback result type for ARG_VECTOR"); - force_inline static T get_value(const PPUThread& CPU) + force_inline static T get_value(const ppu_thread& CPU) { - return CPU.VR[2]; + return CPU.vr[2]; } }; template struct _func_caller { - force_inline static RT call(PPUThread& CPU, u32 pc, u32 rtoc, T... args) + force_inline static RT call(ppu_thread& CPU, u32 pc, u32 rtoc, T... args) { _func_caller::call(CPU, pc, rtoc, args...); @@ -164,12 +164,12 @@ namespace ppu_cb_detail template struct _func_caller { - force_inline static void call(PPUThread& CPU, u32 pc, u32 rtoc, T... args) + force_inline static void call(ppu_thread& CPU, u32 pc, u32 rtoc, T... args) { const bool stack = _bind_func_args<0, 0, 0, T...>(CPU, args...); - CPU.GPR[1] -= stack ? FIXED_STACK_FRAME_SIZE : 0x30; // create reserved area + CPU.gpr[1] -= stack ? FIXED_STACK_FRAME_SIZE : 0x30; // create reserved area CPU.fast_call(pc, rtoc); - CPU.GPR[1] += stack ? FIXED_STACK_FRAME_SIZE : 0x30; + CPU.gpr[1] += stack ? FIXED_STACK_FRAME_SIZE : 0x30; } }; } @@ -177,7 +177,7 @@ namespace ppu_cb_detail namespace vm { template - force_inline RT _ptr_base::operator()(PPUThread& CPU, T... args) const + force_inline RT _ptr_base::operator()(ppu_thread& CPU, T... args) const { const auto data = vm::ps3::_ptr(vm::cast(m_addr, HERE)); const u32 pc = data[0]; @@ -187,37 +187,7 @@ namespace vm } } -template inline RT cb_call(PPUThread& CPU, u32 pc, u32 rtoc, T... args) +template inline RT cb_call(ppu_thread& CPU, u32 pc, u32 rtoc, T... args) { return ppu_cb_detail::_func_caller::call(CPU, pc, rtoc, args...); } - -#include -#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/PPUFunction.cpp b/rpcs3/Emu/Cell/PPUFunction.cpp index 7ec4bb34f3..ebee4e9916 100644 --- a/rpcs3/Emu/Cell/PPUFunction.cpp +++ b/rpcs3/Emu/Cell/PPUFunction.cpp @@ -2361,7 +2361,7 @@ s32 ppu_error_code::report(s32 error, const char* text) { if (thread->type == cpu_type::ppu) { - if (auto func = static_cast(thread)->last_function) + if (auto func = static_cast(thread)->last_function) { LOG_ERROR(PPU, "'%s' failed with 0x%08x : %s", func, error, text); } @@ -2383,7 +2383,7 @@ std::vector& ppu_function_manager::access() static std::vector list { nullptr, - [](PPUThread& ppu) { ppu.state += cpu_state::ret; }, + [](ppu_thread& ppu) { ppu.state += cpu_state::ret; }, }; return list; diff --git a/rpcs3/Emu/Cell/PPUFunction.h b/rpcs3/Emu/Cell/PPUFunction.h index 02c24490be..b69910da07 100644 --- a/rpcs3/Emu/Cell/PPUFunction.h +++ b/rpcs3/Emu/Cell/PPUFunction.h @@ -2,14 +2,14 @@ #include "PPUThread.h" -using ppu_function_t = void(*)(PPUThread&); +using ppu_function_t = void(*)(ppu_thread&); // BIND_FUNC macro "converts" any appropriate HLE function to ppu_function_t, binding it to PPU thread context. // If function already has type ppu_function_t, it's handled specially and classified as "low-level HLE function". // 1) Low-level functions are bound directly so they don't save their name to ppu.last_function variable. // 2) Low-level functions don't install thread_guar, so they are very limited, and may be dangerous. -// If you don't need "low-level function", be sure it's either `void()` or `void(PPUThread& ppu, PPUThread&)` for example. -#define BIND_FUNC(func) (std::is_same::value ? reinterpret_cast(func) : static_cast([](PPUThread& ppu){\ +// If you don't need "low-level function", be sure it's either `void()` or `void(ppu_thread& ppu, ppu_thread&)` for example. +#define BIND_FUNC(func) (std::is_same::value ? reinterpret_cast(func) : static_cast([](ppu_thread& ppu){\ const thread_guard guard(ppu);\ const auto old_f = ppu.last_function;\ ppu.last_function = #func;\ @@ -27,11 +27,11 @@ namespace ppu_func_detail // argument type classification enum arg_class : u32 { - 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_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_CONTEXT, // ppu_thread& passed, doesn't affect g/f/v_count ARG_VARIADIC, // argument count at specific position, doesn't affect g/f/v_count ARG_UNKNOWN, }; @@ -44,9 +44,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 inline T get_arg(PPUThread& ppu) + static inline T get_arg(ppu_thread& ppu) { - return ppu_gpr_cast(ppu.GPR[g_count + 2]); + return ppu_gpr_cast(ppu.gpr[g_count + 2]); } }; @@ -55,9 +55,9 @@ namespace ppu_func_detail { static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_FLOAT"); - static inline T get_arg(PPUThread& ppu) + static inline T get_arg(ppu_thread& ppu) { - return static_cast(ppu.FPR[f_count]); + return static_cast(ppu.fpr[f_count]); } }; @@ -66,9 +66,9 @@ namespace ppu_func_detail { static_assert(std::is_same::value, "Invalid function argument type for ARG_VECTOR"); - static force_inline T get_arg(PPUThread& ppu) + static force_inline T get_arg(ppu_thread& ppu) { - return ppu.VR[v_count + 1]; + return ppu.vr[v_count + 1]; } }; @@ -77,7 +77,7 @@ namespace ppu_func_detail { static_assert(alignof(T) <= 16, "Unsupported type alignment for ARG_STACK"); - static force_inline T get_arg(PPUThread& ppu) + static force_inline T get_arg(ppu_thread& ppu) { return ppu_gpr_cast(*ppu.get_stack_arg(g_count, alignof(T))); // TODO } @@ -86,9 +86,9 @@ namespace ppu_func_detail template struct bind_arg { - static_assert(std::is_same::value, "Invalid function argument type for ARG_CONTEXT"); + static_assert(std::is_same::value, "Invalid function argument type for ARG_CONTEXT"); - static force_inline PPUThread& get_arg(PPUThread& ppu) + static force_inline ppu_thread& get_arg(ppu_thread& ppu) { return ppu; } @@ -99,7 +99,7 @@ namespace ppu_func_detail { static_assert(std::is_same::value, "Invalid function argument type for ARG_VARIADIC"); - static force_inline ppu_va_args_t get_arg(PPUThread& ppu) + static force_inline ppu_va_args_t get_arg(ppu_thread& ppu) { return{ g_count }; } @@ -111,9 +111,9 @@ namespace ppu_func_detail static_assert(type == ARG_GENERAL, "Unknown function result type"); static_assert(sizeof(T) <= 8, "Invalid function result type for ARG_GENERAL"); - static force_inline void put_result(PPUThread& ppu, const T& result) + static force_inline void put_result(ppu_thread& ppu, const T& result) { - ppu.GPR[3] = ppu_gpr_cast(result); + ppu.gpr[3] = ppu_gpr_cast(result); } }; @@ -122,9 +122,9 @@ namespace ppu_func_detail { static_assert(sizeof(T) <= 8, "Invalid function result type for ARG_FLOAT"); - static force_inline void put_result(PPUThread& ppu, const T& result) + static force_inline void put_result(ppu_thread& ppu, const T& result) { - ppu.FPR[1] = static_cast(result); + ppu.fpr[1] = static_cast(result); } }; @@ -133,9 +133,9 @@ namespace ppu_func_detail { static_assert(std::is_same::value, "Invalid function result type for ARG_VECTOR"); - static force_inline void put_result(PPUThread& ppu, const T& result) + static force_inline void put_result(ppu_thread& ppu, const T& result) { - ppu.VR[2] = result; + ppu.vr[2] = result; } }; @@ -160,21 +160,21 @@ namespace ppu_func_detail // argument type + g/f/v_count unpacker template struct bind_arg_packed { - static force_inline T get_arg(PPUThread& ppu) + static force_inline T get_arg(ppu_thread& ppu) { return bind_arg(type_pack & 0xff), (type_pack >> 8) & 0xff, (type_pack >> 16) & 0xff, (type_pack >> 24)>::get_arg(ppu); } }; template - force_inline RT call(PPUThread& ppu, RT(*func)(Args...), arg_info_pack_t) + force_inline RT call(ppu_thread& ppu, RT(*func)(Args...), arg_info_pack_t) { // do the actual function call when all arguments are prepared (simultaneous unpacking of Args... and Info...) return func(bind_arg_packed::get_arg(ppu)...); } template - force_inline RT call(PPUThread& ppu, RT(*func)(Args...), arg_info_pack_t info) + force_inline RT call(ppu_thread& ppu, 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; @@ -184,7 +184,7 @@ namespace ppu_func_detail // TODO: check calculations const bool is_float = std::is_floating_point::value; const bool is_vector = std::is_same::value; - const bool is_context = std::is_same::value; + const bool is_context = std::is_same::value; const bool is_variadic = std::is_same::value; const bool is_general = !is_float && !is_vector && !is_context && !is_variadic; @@ -220,7 +220,7 @@ namespace ppu_func_detail { using func_t = void(*)(T...); - static force_inline void do_call(PPUThread& ppu, func_t func) + static force_inline void do_call(ppu_thread& ppu, func_t func) { call(ppu, func, arg_info_pack_t<>{}); } @@ -231,14 +231,14 @@ namespace ppu_func_detail { using func_t = RT(*)(T...); - static force_inline void do_call(PPUThread& ppu, func_t func) + static force_inline void do_call(ppu_thread& ppu, func_t func) { bind_result::value>::put_result(ppu, call(ppu, func, arg_info_pack_t<>{})); } }; template - force_inline void do_call(PPUThread& ppu, RT(*func)(T...)) + force_inline void do_call(ppu_thread& ppu, RT(*func)(T...)) { func_binder::do_call(ppu, func); } diff --git a/rpcs3/Emu/Cell/PPUInterpreter.cpp b/rpcs3/Emu/Cell/PPUInterpreter.cpp index daf0c2fdc9..33a14448e3 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.cpp +++ b/rpcs3/Emu/Cell/PPUInterpreter.cpp @@ -33,6 +33,29 @@ inline s64 MULH64(s64 a, s64 b) #define MULH64 __mulh #endif +// Write values to CR field +inline void ppu_cr_set(ppu_thread& ppu, u32 field, bool le, bool gt, bool eq, bool so) +{ + ppu.cr[field * 4 + 0] = le; + ppu.cr[field * 4 + 1] = gt; + ppu.cr[field * 4 + 2] = eq; + ppu.cr[field * 4 + 3] = so; +} + +// Write comparison results to CR field +template +inline void ppu_cr_set(ppu_thread& ppu, u32 field, const T& a, const T& b) +{ + ppu_cr_set(ppu, field, a < b, a > b, a == b, ppu.xer.so); +} + +// Set XER.OV bit (overflow) +inline void ppu_ov_set(ppu_thread& ppu, bool bit) +{ + ppu.xer.ov = bit; + ppu.xer.so |= bit; +} + // Compare 16 packed unsigned bytes (greater than) inline __m128i sse_cmpgt_epu8(__m128i A, __m128i B) { @@ -242,8 +265,8 @@ static add_flags_result_t add64_flags(u64 a, u64 b, bool c) } extern u64 get_timebased_time(); -extern void ppu_execute_syscall(PPUThread& ppu, u64 code); -extern void ppu_execute_function(PPUThread& ppu, u32 index); +extern void ppu_execute_syscall(ppu_thread& ppu, u64 code); +extern void ppu_execute_function(ppu_thread& ppu, u32 index); namespace vm { using namespace ps3; } @@ -267,498 +290,498 @@ public: } const g_ppu_scale_table; -bool ppu_interpreter::MFVSCR(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::MFVSCR(ppu_thread& ppu, ppu_opcode_t op) { throw std::runtime_error("MFVSCR" HERE); } -bool ppu_interpreter::MTVSCR(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::MTVSCR(ppu_thread& ppu, ppu_opcode_t op) { LOG_WARNING(PPU, "MTVSCR"); return true; } -bool ppu_interpreter::VADDCUW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VADDCUW(ppu_thread& ppu, ppu_opcode_t op) { - 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); + 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); return true; } -bool ppu_interpreter::VADDFP(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VADDFP(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd] = v128::addfs(ppu.VR[op.va], ppu.VR[op.vb]); + ppu.vr[op.vd] = v128::addfs(ppu.vr[op.va], ppu.vr[op.vb]); return true; } -bool ppu_interpreter::VADDSBS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VADDSBS(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vi = _mm_adds_epi8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); + ppu.vr[op.vd].vi = _mm_adds_epi8(ppu.vr[op.va].vi, ppu.vr[op.vb].vi); return true; } -bool ppu_interpreter::VADDSHS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VADDSHS(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vi = _mm_adds_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); + ppu.vr[op.vd].vi = _mm_adds_epi16(ppu.vr[op.va].vi, ppu.vr[op.vb].vi); return true; } -bool ppu_interpreter::VADDSWS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VADDSWS(ppu_thread& ppu, ppu_opcode_t op) { - const auto a = ppu.VR[op.va]; - const auto b = ppu.VR[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 - ppu.VR[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)); return true; } -bool ppu_interpreter::VADDUBM(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VADDUBM(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd] = v128::add8(ppu.VR[op.va], ppu.VR[op.vb]); + ppu.vr[op.vd] = v128::add8(ppu.vr[op.va], ppu.vr[op.vb]); return true; } -bool ppu_interpreter::VADDUBS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VADDUBS(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vi = _mm_adds_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); + ppu.vr[op.vd].vi = _mm_adds_epu8(ppu.vr[op.va].vi, ppu.vr[op.vb].vi); return true; } -bool ppu_interpreter::VADDUHM(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VADDUHM(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd] = v128::add16(ppu.VR[op.va], ppu.VR[op.vb]); + ppu.vr[op.vd] = v128::add16(ppu.vr[op.va], ppu.vr[op.vb]); return true; } -bool ppu_interpreter::VADDUHS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VADDUHS(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vi = _mm_adds_epu16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); + ppu.vr[op.vd].vi = _mm_adds_epu16(ppu.vr[op.va].vi, ppu.vr[op.vb].vi); return true; } -bool ppu_interpreter::VADDUWM(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VADDUWM(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd] = v128::add32(ppu.VR[op.va], ppu.VR[op.vb]); + ppu.vr[op.vd] = v128::add32(ppu.vr[op.va], ppu.vr[op.vb]); return true; } -bool ppu_interpreter::VADDUWS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VADDUWS(ppu_thread& ppu, ppu_opcode_t op) { - 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)))); + 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)))); return true; } -bool ppu_interpreter::VAND(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VAND(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd] = ppu.VR[op.va] & ppu.VR[op.vb]; + ppu.vr[op.vd] = ppu.vr[op.va] & ppu.vr[op.vb]; return true; } -bool ppu_interpreter::VANDC(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VANDC(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd] = v128::andnot(ppu.VR[op.vb], ppu.VR[op.va]); + ppu.vr[op.vd] = v128::andnot(ppu.vr[op.vb], ppu.vr[op.va]); return true; } -bool ppu_interpreter::VAVGSB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VAVGSB(ppu_thread& ppu, ppu_opcode_t op) { - const auto a = ppu.VR[op.va]; - const auto b = v128::add8(ppu.VR[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 - ppu.VR[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)); return true; } -bool ppu_interpreter::VAVGSH(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VAVGSH(ppu_thread& ppu, ppu_opcode_t op) { - const auto a = ppu.VR[op.va]; - const auto b = v128::add16(ppu.VR[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 - ppu.VR[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)); return true; } -bool ppu_interpreter::VAVGSW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VAVGSW(ppu_thread& ppu, ppu_opcode_t op) { - const auto a = ppu.VR[op.va]; - const auto b = v128::add32(ppu.VR[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 - ppu.VR[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)); return true; } -bool ppu_interpreter::VAVGUB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VAVGUB(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vi = _mm_avg_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); + ppu.vr[op.vd].vi = _mm_avg_epu8(ppu.vr[op.va].vi, ppu.vr[op.vb].vi); return true; } -bool ppu_interpreter::VAVGUH(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VAVGUH(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vi = _mm_avg_epu16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); + ppu.vr[op.vd].vi = _mm_avg_epu16(ppu.vr[op.va].vi, ppu.vr[op.vb].vi); return true; } -bool ppu_interpreter::VAVGUW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VAVGUW(ppu_thread& ppu, ppu_opcode_t op) { - const auto a = ppu.VR[op.va]; - const auto b = ppu.VR[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)); - ppu.VR[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)); return true; } -bool ppu_interpreter::VCFSX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VCFSX(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vf = _mm_mul_ps(_mm_cvtepi32_ps(ppu.VR[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]); return true; } -bool ppu_interpreter::VCFUX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VCFUX(ppu_thread& ppu, ppu_opcode_t op) { - const auto b = ppu.VR[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)); - 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]); + 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]); return true; } -bool ppu_interpreter::VCMPBFP(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VCMPBFP(ppu_thread& ppu, ppu_opcode_t op) { - const auto a = ppu.VR[op.va].vf; - const auto b = ppu.VR[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 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 (UNLIKELY(op.oe)) ppu.SetCR(6, false, false, _mm_movemask_ps(_mm_or_ps(cmp1, cmp2)) == 0, false); + 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 (UNLIKELY(op.oe)) ppu_cr_set(ppu, 6, false, false, _mm_movemask_ps(_mm_or_ps(cmp1, cmp2)) == 0, false); return true; } -bool ppu_interpreter::VCMPEQFP(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VCMPEQFP(ppu_thread& ppu, ppu_opcode_t op) { - 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 (UNLIKELY(op.oe)) ppu.SetCR(6, rmask == 0xf, false, rmask == 0, false); + 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 (UNLIKELY(op.oe)) ppu_cr_set(ppu, 6, rmask == 0xf, false, rmask == 0, false); return true; } -bool ppu_interpreter::VCMPEQUB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VCMPEQUB(ppu_thread& ppu, ppu_opcode_t op) { - const auto rmask = _mm_movemask_epi8((ppu.VR[op.vd] = v128::eq8(ppu.VR[op.va], ppu.VR[op.vb])).vi); - if (UNLIKELY(op.oe)) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); + const auto rmask = _mm_movemask_epi8((ppu.vr[op.vd] = v128::eq8(ppu.vr[op.va], ppu.vr[op.vb])).vi); + if (UNLIKELY(op.oe)) ppu_cr_set(ppu, 6, rmask == 0xffff, false, rmask == 0, false); return true; } -bool ppu_interpreter::VCMPEQUH(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VCMPEQUH(ppu_thread& ppu, ppu_opcode_t op) { - const auto rmask = _mm_movemask_epi8((ppu.VR[op.vd] = v128::eq16(ppu.VR[op.va], ppu.VR[op.vb])).vi); - if (UNLIKELY(op.oe)) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); + const auto rmask = _mm_movemask_epi8((ppu.vr[op.vd] = v128::eq16(ppu.vr[op.va], ppu.vr[op.vb])).vi); + if (UNLIKELY(op.oe)) ppu_cr_set(ppu, 6, rmask == 0xffff, false, rmask == 0, false); return true; } -bool ppu_interpreter::VCMPEQUW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VCMPEQUW(ppu_thread& ppu, ppu_opcode_t op) { - const auto rmask = _mm_movemask_epi8((ppu.VR[op.vd] = v128::eq32(ppu.VR[op.va], ppu.VR[op.vb])).vi); - if (UNLIKELY(op.oe)) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); + const auto rmask = _mm_movemask_epi8((ppu.vr[op.vd] = v128::eq32(ppu.vr[op.va], ppu.vr[op.vb])).vi); + if (UNLIKELY(op.oe)) ppu_cr_set(ppu, 6, rmask == 0xffff, false, rmask == 0, false); return true; } -bool ppu_interpreter::VCMPGEFP(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VCMPGEFP(ppu_thread& ppu, ppu_opcode_t op) { - 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 (UNLIKELY(op.oe)) ppu.SetCR(6, rmask == 0xf, false, rmask == 0, false); + 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 (UNLIKELY(op.oe)) ppu_cr_set(ppu, 6, rmask == 0xf, false, rmask == 0, false); return true; } -bool ppu_interpreter::VCMPGTFP(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VCMPGTFP(ppu_thread& ppu, ppu_opcode_t op) { - 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 (UNLIKELY(op.oe)) ppu.SetCR(6, rmask == 0xf, false, rmask == 0, false); + 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 (UNLIKELY(op.oe)) ppu_cr_set(ppu, 6, rmask == 0xf, false, rmask == 0, false); return true; } -bool ppu_interpreter::VCMPGTSB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VCMPGTSB(ppu_thread& ppu, ppu_opcode_t op) { - 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 (UNLIKELY(op.oe)) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); + 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 (UNLIKELY(op.oe)) ppu_cr_set(ppu, 6, rmask == 0xffff, false, rmask == 0, false); return true; } -bool ppu_interpreter::VCMPGTSH(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VCMPGTSH(ppu_thread& ppu, ppu_opcode_t op) { - 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 (UNLIKELY(op.oe)) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); + 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 (UNLIKELY(op.oe)) ppu_cr_set(ppu, 6, rmask == 0xffff, false, rmask == 0, false); return true; } -bool ppu_interpreter::VCMPGTSW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VCMPGTSW(ppu_thread& ppu, ppu_opcode_t op) { - 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 (UNLIKELY(op.oe)) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); + 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 (UNLIKELY(op.oe)) ppu_cr_set(ppu, 6, rmask == 0xffff, false, rmask == 0, false); return true; } -bool ppu_interpreter::VCMPGTUB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VCMPGTUB(ppu_thread& ppu, ppu_opcode_t op) { - 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 (UNLIKELY(op.oe)) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); + 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 (UNLIKELY(op.oe)) ppu_cr_set(ppu, 6, rmask == 0xffff, false, rmask == 0, false); return true; } -bool ppu_interpreter::VCMPGTUH(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VCMPGTUH(ppu_thread& ppu, ppu_opcode_t op) { - 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 (UNLIKELY(op.oe)) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); + 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 (UNLIKELY(op.oe)) ppu_cr_set(ppu, 6, rmask == 0xffff, false, rmask == 0, false); return true; } -bool ppu_interpreter::VCMPGTUW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VCMPGTUW(ppu_thread& ppu, ppu_opcode_t op) { - 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 (UNLIKELY(op.oe)) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); + 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 (UNLIKELY(op.oe)) ppu_cr_set(ppu, 6, rmask == 0xffff, false, rmask == 0, false); return true; } -bool ppu_interpreter::VCTSXS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VCTSXS(ppu_thread& ppu, ppu_opcode_t op) { - 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)))); + 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)))); return true; } -bool ppu_interpreter::VCTUXS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VCTUXS(ppu_thread& ppu, ppu_opcode_t op) { - 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 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))); - 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)))); + 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)))); return true; } -bool ppu_interpreter::VEXPTEFP(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VEXPTEFP(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vf = sse_exp2_ps(ppu.VR[op.vb].vf); + ppu.vr[op.vd].vf = sse_exp2_ps(ppu.vr[op.vb].vf); return true; } -bool ppu_interpreter::VLOGEFP(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VLOGEFP(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vf = sse_log2_ps(ppu.VR[op.vb].vf); + ppu.vr[op.vd].vf = sse_log2_ps(ppu.vr[op.vb].vf); return true; } -bool ppu_interpreter::VMADDFP(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMADDFP(ppu_thread& ppu, ppu_opcode_t op) { - 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); + 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); return true; } -bool ppu_interpreter::VMAXFP(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMAXFP(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vf = _mm_max_ps(ppu.VR[op.va].vf, ppu.VR[op.vb].vf); + ppu.vr[op.vd].vf = _mm_max_ps(ppu.vr[op.va].vf, ppu.vr[op.vb].vf); return true; } -bool ppu_interpreter::VMAXSB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMAXSB(ppu_thread& ppu, ppu_opcode_t op) { - const auto a = ppu.VR[op.va].vi; - const auto b = ppu.VR[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); - ppu.VR[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)); return true; } -bool ppu_interpreter::VMAXSH(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMAXSH(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vi = _mm_max_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); + ppu.vr[op.vd].vi = _mm_max_epi16(ppu.vr[op.va].vi, ppu.vr[op.vb].vi); return true; } -bool ppu_interpreter::VMAXSW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMAXSW(ppu_thread& ppu, ppu_opcode_t op) { - const auto a = ppu.VR[op.va].vi; - const auto b = ppu.VR[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); - ppu.VR[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)); return true; } -bool ppu_interpreter::VMAXUB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMAXUB(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vi = _mm_max_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); + ppu.vr[op.vd].vi = _mm_max_epu8(ppu.vr[op.va].vi, ppu.vr[op.vb].vi); return true; } -bool ppu_interpreter::VMAXUH(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMAXUH(ppu_thread& ppu, ppu_opcode_t op) { const auto mask = _mm_set1_epi32(0x80008000); - 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); + 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); return true; } -bool ppu_interpreter::VMAXUW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMAXUW(ppu_thread& ppu, ppu_opcode_t op) { - const auto a = ppu.VR[op.va].vi; - const auto b = ppu.VR[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); - ppu.VR[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)); return true; } -bool ppu_interpreter::VMHADDSHS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMHADDSHS(ppu_thread& ppu, ppu_opcode_t op) { - 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 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) - ppu.VR[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)); return true; } -bool ppu_interpreter::VMHRADDSHS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMHRADDSHS(ppu_thread& ppu, ppu_opcode_t op) { - 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 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) - ppu.VR[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)); return true; } -bool ppu_interpreter::VMINFP(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMINFP(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vf = _mm_min_ps(ppu.VR[op.va].vf, ppu.VR[op.vb].vf); + ppu.vr[op.vd].vf = _mm_min_ps(ppu.vr[op.va].vf, ppu.vr[op.vb].vf); return true; } -bool ppu_interpreter::VMINSB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMINSB(ppu_thread& ppu, ppu_opcode_t op) { - const auto a = ppu.VR[op.va].vi; - const auto b = ppu.VR[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); - ppu.VR[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)); return true; } -bool ppu_interpreter::VMINSH(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMINSH(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vi = _mm_min_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); + ppu.vr[op.vd].vi = _mm_min_epi16(ppu.vr[op.va].vi, ppu.vr[op.vb].vi); return true; } -bool ppu_interpreter::VMINSW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMINSW(ppu_thread& ppu, ppu_opcode_t op) { - const auto a = ppu.VR[op.va].vi; - const auto b = ppu.VR[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); - ppu.VR[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)); return true; } -bool ppu_interpreter::VMINUB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMINUB(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vi = _mm_min_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); + ppu.vr[op.vd].vi = _mm_min_epu8(ppu.vr[op.va].vi, ppu.vr[op.vb].vi); return true; } -bool ppu_interpreter::VMINUH(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMINUH(ppu_thread& ppu, ppu_opcode_t op) { const auto mask = _mm_set1_epi32(0x80008000); - 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); + 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); return true; } -bool ppu_interpreter::VMINUW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMINUW(ppu_thread& ppu, ppu_opcode_t op) { - const auto a = ppu.VR[op.va].vi; - const auto b = ppu.VR[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); - ppu.VR[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)); return true; } -bool ppu_interpreter::VMLADDUHM(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMLADDUHM(ppu_thread& ppu, ppu_opcode_t op) { - 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); + 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); return true; } -bool ppu_interpreter::VMRGHB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMRGHB(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vi = _mm_unpackhi_epi8(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); + ppu.vr[op.vd].vi = _mm_unpackhi_epi8(ppu.vr[op.vb].vi, ppu.vr[op.va].vi); return true; } -bool ppu_interpreter::VMRGHH(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMRGHH(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vi = _mm_unpackhi_epi16(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); + ppu.vr[op.vd].vi = _mm_unpackhi_epi16(ppu.vr[op.vb].vi, ppu.vr[op.va].vi); return true; } -bool ppu_interpreter::VMRGHW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMRGHW(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vi = _mm_unpackhi_epi32(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); + ppu.vr[op.vd].vi = _mm_unpackhi_epi32(ppu.vr[op.vb].vi, ppu.vr[op.va].vi); return true; } -bool ppu_interpreter::VMRGLB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMRGLB(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vi = _mm_unpacklo_epi8(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); + ppu.vr[op.vd].vi = _mm_unpacklo_epi8(ppu.vr[op.vb].vi, ppu.vr[op.va].vi); return true; } -bool ppu_interpreter::VMRGLH(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMRGLH(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vi = _mm_unpacklo_epi16(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); + ppu.vr[op.vd].vi = _mm_unpacklo_epi16(ppu.vr[op.vb].vi, ppu.vr[op.va].vi); return true; } -bool ppu_interpreter::VMRGLW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMRGLW(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vi = _mm_unpacklo_epi32(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); + ppu.vr[op.vd].vi = _mm_unpacklo_epi32(ppu.vr[op.vb].vi, ppu.vr[op.va].vi); return true; } -bool ppu_interpreter::VMSUMMBM(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMSUMMBM(ppu_thread& ppu, ppu_opcode_t op) { - 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 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); - ppu.VR[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); return true; } -bool ppu_interpreter::VMSUMSHM(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMSUMSHM(ppu_thread& ppu, ppu_opcode_t op) { - 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); + 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); return true; } -bool ppu_interpreter::VMSUMSHS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMSUMSHS(ppu_thread& 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]; + 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++) { @@ -788,11 +811,11 @@ bool ppu_interpreter::VMSUMSHS(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VMSUMUBM(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMSUMUBM(ppu_thread& ppu, ppu_opcode_t op) { - 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 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); @@ -800,29 +823,29 @@ bool ppu_interpreter::VMSUMUBM(PPUThread& ppu, 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); - ppu.VR[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); return true; } -bool ppu_interpreter::VMSUMUHM(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMSUMUHM(ppu_thread& ppu, ppu_opcode_t op) { - 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 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))); - ppu.VR[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); return true; } -bool ppu_interpreter::VMSUMUHS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMSUMUHS(ppu_thread& 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]; + 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++) { @@ -848,93 +871,93 @@ bool ppu_interpreter::VMSUMUHS(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VMULESB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMULESB(ppu_thread& ppu, ppu_opcode_t op) { - 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)); + 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)); return true; } -bool ppu_interpreter::VMULESH(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMULESH(ppu_thread& ppu, ppu_opcode_t op) { - 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)); + 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)); return true; } -bool ppu_interpreter::VMULEUB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMULEUB(ppu_thread& ppu, ppu_opcode_t op) { - 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)); + 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)); return true; } -bool ppu_interpreter::VMULEUH(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMULEUH(ppu_thread& ppu, ppu_opcode_t op) { - const auto a = ppu.VR[op.va].vi; - const auto b = ppu.VR[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); - ppu.VR[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))); return true; } -bool ppu_interpreter::VMULOSB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMULOSB(ppu_thread& ppu, ppu_opcode_t op) { - 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)); + 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)); return true; } -bool ppu_interpreter::VMULOSH(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMULOSH(ppu_thread& ppu, ppu_opcode_t op) { const auto mask = _mm_set1_epi32(0x0000ffff); - 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)); + 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)); return true; } -bool ppu_interpreter::VMULOUB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMULOUB(ppu_thread& ppu, ppu_opcode_t op) { const auto mask = _mm_set1_epi16(0x00ff); - 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)); + 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)); return true; } -bool ppu_interpreter::VMULOUH(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VMULOUH(ppu_thread& ppu, ppu_opcode_t op) { - const auto a = ppu.VR[op.va].vi; - const auto b = ppu.VR[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); - ppu.VR[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))); return true; } -bool ppu_interpreter::VNMSUBFP(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VNMSUBFP(ppu_thread& ppu, ppu_opcode_t op) { - 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)); + 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)); return true; } -bool ppu_interpreter::VNOR(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VNOR(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd] = ~(ppu.VR[op.va] | ppu.VR[op.vb]); + ppu.vr[op.vd] = ~(ppu.vr[op.va] | ppu.vr[op.vb]); return true; } -bool ppu_interpreter::VOR(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VOR(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd] = ppu.VR[op.va] | ppu.VR[op.vb]; + ppu.vr[op.vd] = ppu.vr[op.va] | ppu.vr[op.vb]; return true; } -bool ppu_interpreter::VPERM(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VPERM(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vi = sse_altivec_vperm(ppu.VR[op.va].vi, ppu.VR[op.vb].vi, ppu.VR[op.vc].vi); + ppu.vr[op.vd].vi = sse_altivec_vperm(ppu.vr[op.va].vi, ppu.vr[op.vb].vi, ppu.vr[op.vc].vi); return true; } -bool ppu_interpreter::VPKPX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VPKPX(ppu_thread& ppu, ppu_opcode_t op) { - auto& d = ppu.VR[op.vd]; - v128 VA = ppu.VR[op.va]; - v128 VB = ppu.VR[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; @@ -952,30 +975,30 @@ bool ppu_interpreter::VPKPX(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VPKSHSS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VPKSHSS(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vi = _mm_packs_epi16(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); + ppu.vr[op.vd].vi = _mm_packs_epi16(ppu.vr[op.vb].vi, ppu.vr[op.va].vi); return true; } -bool ppu_interpreter::VPKSHUS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VPKSHUS(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vi = _mm_packus_epi16(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); + ppu.vr[op.vd].vi = _mm_packus_epi16(ppu.vr[op.vb].vi, ppu.vr[op.va].vi); return true; } -bool ppu_interpreter::VPKSWSS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VPKSWSS(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vi = _mm_packs_epi32(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); + ppu.vr[op.vd].vi = _mm_packs_epi32(ppu.vr[op.vb].vi, ppu.vr[op.va].vi); return true; } -bool ppu_interpreter::VPKSWUS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VPKSWUS(ppu_thread& ppu, ppu_opcode_t op) { - //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]; + //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]; @@ -1007,11 +1030,11 @@ bool ppu_interpreter::VPKSWUS(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VPKUHUM(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VPKUHUM(ppu_thread& ppu, ppu_opcode_t op) { - auto& d = ppu.VR[op.vd]; - v128 VA = ppu.VR[op.va]; - v128 VB = ppu.VR[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++) { d._u8[b + 8] = VA._u8[b * 2]; @@ -1020,11 +1043,11 @@ bool ppu_interpreter::VPKUHUM(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VPKUHUS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VPKUHUS(ppu_thread& ppu, ppu_opcode_t op) { - auto& d = ppu.VR[op.vd]; - v128 VA = ppu.VR[op.va]; - v128 VB = ppu.VR[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]; @@ -1048,11 +1071,11 @@ bool ppu_interpreter::VPKUHUS(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VPKUWUM(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VPKUWUM(ppu_thread& ppu, ppu_opcode_t op) { - auto& d = ppu.VR[op.vd]; - v128 VA = ppu.VR[op.va]; - v128 VB = ppu.VR[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++) { d._u16[h + 4] = VA._u16[h * 2]; @@ -1061,11 +1084,11 @@ bool ppu_interpreter::VPKUWUM(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VPKUWUS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VPKUWUS(ppu_thread& ppu, ppu_opcode_t op) { - auto& d = ppu.VR[op.vd]; - v128 VA = ppu.VR[op.va]; - v128 VB = ppu.VR[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]; @@ -1089,16 +1112,16 @@ bool ppu_interpreter::VPKUWUS(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VREFP(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VREFP(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vf = _mm_rcp_ps(ppu.VR[op.vb].vf); + ppu.vr[op.vd].vf = _mm_rcp_ps(ppu.vr[op.vb].vf); return true; } -bool ppu_interpreter::VRFIM(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VRFIM(ppu_thread& ppu, ppu_opcode_t op) { - auto& d = ppu.VR[op.vd]; - const auto& b = ppu.VR[op.vb]; + auto& d = ppu.vr[op.vd]; + const auto& b = ppu.vr[op.vb]; for (uint w = 0; w < 4; w++) { @@ -1107,10 +1130,10 @@ bool ppu_interpreter::VRFIM(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VRFIN(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VRFIN(ppu_thread& ppu, ppu_opcode_t op) { - auto& d = ppu.VR[op.vd]; - const auto& b = ppu.VR[op.vb]; + auto& d = ppu.vr[op.vd]; + const auto& b = ppu.vr[op.vb]; for (uint w = 0; w < 4; w++) { @@ -1119,10 +1142,10 @@ bool ppu_interpreter::VRFIN(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VRFIP(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VRFIP(ppu_thread& ppu, ppu_opcode_t op) { - auto& d = ppu.VR[op.vd]; - const auto& b = ppu.VR[op.vb]; + auto& d = ppu.vr[op.vd]; + const auto& b = ppu.vr[op.vb]; for (uint w = 0; w < 4; w++) { @@ -1131,10 +1154,10 @@ bool ppu_interpreter::VRFIP(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VRFIZ(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VRFIZ(ppu_thread& ppu, ppu_opcode_t op) { - auto& d = ppu.VR[op.vd]; - const auto& b = ppu.VR[op.vb]; + auto& d = ppu.vr[op.vd]; + const auto& b = ppu.vr[op.vb]; for (uint w = 0; w < 4; w++) { @@ -1143,11 +1166,11 @@ bool ppu_interpreter::VRFIZ(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VRLB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VRLB(ppu_thread& 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]; + 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++) { @@ -1156,11 +1179,11 @@ bool ppu_interpreter::VRLB(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VRLH(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VRLH(ppu_thread& 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]; + 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++) { @@ -1169,11 +1192,11 @@ bool ppu_interpreter::VRLH(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VRLW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VRLW(ppu_thread& 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]; + 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++) { @@ -1182,28 +1205,28 @@ bool ppu_interpreter::VRLW(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VRSQRTEFP(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VRSQRTEFP(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vf = _mm_rsqrt_ps(ppu.VR[op.vb].vf); + ppu.vr[op.vd].vf = _mm_rsqrt_ps(ppu.vr[op.vb].vf); return true; } -bool ppu_interpreter::VSEL(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSEL(ppu_thread& 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]; + 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); return true; } -bool ppu_interpreter::VSL(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSL(ppu_thread& 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; + auto& d = ppu.vr[op.vd]; + v128 VA = ppu.vr[op.va]; + u8 sh = ppu.vr[op.vb]._u8[0] & 0x7; d._u8[0] = VA._u8[0] << sh; for (uint b = 1; b < 16; b++) @@ -1213,11 +1236,11 @@ bool ppu_interpreter::VSL(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VSLB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSLB(ppu_thread& 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]; + 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++) { @@ -1226,12 +1249,12 @@ bool ppu_interpreter::VSLB(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VSLDOI(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSLDOI(ppu_thread& ppu, ppu_opcode_t op) { - auto& d = ppu.VR[op.vd]; + auto& d = ppu.vr[op.vd]; u8 tmpSRC[32]; - std::memcpy(tmpSRC, &ppu.VR[op.vb], 16); - std::memcpy(tmpSRC + 16, &ppu.VR[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++) { @@ -1240,11 +1263,11 @@ bool ppu_interpreter::VSLDOI(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VSLH(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSLH(ppu_thread& 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]; + 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++) { @@ -1253,11 +1276,11 @@ bool ppu_interpreter::VSLH(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VSLO(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSLO(ppu_thread& ppu, ppu_opcode_t op) { - auto& d = ppu.VR[op.vd]; - v128 VA = ppu.VR[op.va]; - u8 nShift = (ppu.VR[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; d.clear(); @@ -1268,11 +1291,11 @@ bool ppu_interpreter::VSLO(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VSLW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSLW(ppu_thread& 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]; + 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++) { @@ -1281,10 +1304,10 @@ bool ppu_interpreter::VSLW(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VSPLTB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSPLTB(ppu_thread& ppu, ppu_opcode_t op) { - auto& d = ppu.VR[op.vd]; - u8 byte = ppu.VR[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++) { @@ -1293,12 +1316,12 @@ bool ppu_interpreter::VSPLTB(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VSPLTH(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSPLTH(ppu_thread& ppu, ppu_opcode_t op) { - auto& d = ppu.VR[op.vd]; + auto& d = ppu.vr[op.vd]; EXPECTS(op.vuimm < 8); - u16 hword = ppu.VR[op.vb]._u16[7 - op.vuimm]; + u16 hword = ppu.vr[op.vb]._u16[7 - op.vuimm]; for (uint h = 0; h < 8; h++) { @@ -1307,9 +1330,9 @@ bool ppu_interpreter::VSPLTH(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VSPLTISB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSPLTISB(ppu_thread& ppu, ppu_opcode_t op) { - auto& d = ppu.VR[op.vd]; + auto& d = ppu.vr[op.vd]; const s8 imm = op.vsimm; for (uint b = 0; b < 16; b++) @@ -1319,9 +1342,9 @@ bool ppu_interpreter::VSPLTISB(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VSPLTISH(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSPLTISH(ppu_thread& ppu, ppu_opcode_t op) { - auto& d = ppu.VR[op.vd]; + auto& d = ppu.vr[op.vd]; const s16 imm = op.vsimm; for (uint h = 0; h < 8; h++) @@ -1331,9 +1354,9 @@ bool ppu_interpreter::VSPLTISH(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VSPLTISW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSPLTISW(ppu_thread& ppu, ppu_opcode_t op) { - auto& d = ppu.VR[op.vd]; + auto& d = ppu.vr[op.vd]; const s32 imm = op.vsimm; for (uint w = 0; w < 4; w++) @@ -1343,12 +1366,12 @@ bool ppu_interpreter::VSPLTISW(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VSPLTW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSPLTW(ppu_thread& ppu, ppu_opcode_t op) { - auto& d = ppu.VR[op.vd]; + auto& d = ppu.vr[op.vd]; EXPECTS(op.vuimm < 4); - u32 word = ppu.VR[op.vb]._u32[3 - op.vuimm]; + u32 word = ppu.vr[op.vb]._u32[3 - op.vuimm]; for (uint w = 0; w < 4; w++) { @@ -1357,11 +1380,11 @@ bool ppu_interpreter::VSPLTW(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VSR(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSR(ppu_thread& 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; + 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--) @@ -1371,11 +1394,11 @@ bool ppu_interpreter::VSR(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VSRAB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSRAB(ppu_thread& 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]; + 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++) { @@ -1384,11 +1407,11 @@ bool ppu_interpreter::VSRAB(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VSRAH(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSRAH(ppu_thread& 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]; + 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++) { @@ -1397,11 +1420,11 @@ bool ppu_interpreter::VSRAH(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VSRAW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSRAW(ppu_thread& 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]; + 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++) { @@ -1410,11 +1433,11 @@ bool ppu_interpreter::VSRAW(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VSRB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSRB(ppu_thread& 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]; + 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++) { @@ -1423,11 +1446,11 @@ bool ppu_interpreter::VSRB(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VSRH(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSRH(ppu_thread& 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]; + 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++) { @@ -1436,11 +1459,11 @@ bool ppu_interpreter::VSRH(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VSRO(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSRO(ppu_thread& ppu, ppu_opcode_t op) { - auto& d = ppu.VR[op.vd]; - v128 VA = ppu.VR[op.va]; - u8 nShift = (ppu.VR[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; d.clear(); @@ -1451,11 +1474,11 @@ bool ppu_interpreter::VSRO(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VSRW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSRW(ppu_thread& 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]; + 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++) { @@ -1464,11 +1487,11 @@ bool ppu_interpreter::VSRW(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VSUBCUW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSUBCUW(ppu_thread& 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]; + 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++) { @@ -1477,29 +1500,29 @@ bool ppu_interpreter::VSUBCUW(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VSUBFP(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSUBFP(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd] = v128::subfs(ppu.VR[op.va], ppu.VR[op.vb]); + ppu.vr[op.vd] = v128::subfs(ppu.vr[op.va], ppu.vr[op.vb]); return true; } -bool ppu_interpreter::VSUBSBS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSUBSBS(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vi = _mm_subs_epi8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); + ppu.vr[op.vd].vi = _mm_subs_epi8(ppu.vr[op.va].vi, ppu.vr[op.vb].vi); return true; } -bool ppu_interpreter::VSUBSHS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSUBSHS(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vi = _mm_subs_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); + ppu.vr[op.vd].vi = _mm_subs_epi16(ppu.vr[op.va].vi, ppu.vr[op.vb].vi); return true; } -bool ppu_interpreter::VSUBSWS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSUBSWS(ppu_thread& 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]; + 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++) { @@ -1519,41 +1542,41 @@ bool ppu_interpreter::VSUBSWS(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VSUBUBM(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSUBUBM(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd] = v128::sub8(ppu.VR[op.va], ppu.VR[op.vb]); + ppu.vr[op.vd] = v128::sub8(ppu.vr[op.va], ppu.vr[op.vb]); return true; } -bool ppu_interpreter::VSUBUBS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSUBUBS(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vi = _mm_subs_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); + ppu.vr[op.vd].vi = _mm_subs_epu8(ppu.vr[op.va].vi, ppu.vr[op.vb].vi); return true; } -bool ppu_interpreter::VSUBUHM(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSUBUHM(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd] = v128::sub16(ppu.VR[op.va], ppu.VR[op.vb]); + ppu.vr[op.vd] = v128::sub16(ppu.vr[op.va], ppu.vr[op.vb]); return true; } -bool ppu_interpreter::VSUBUHS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSUBUHS(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd].vi = _mm_subs_epu16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); + ppu.vr[op.vd].vi = _mm_subs_epu16(ppu.vr[op.va].vi, ppu.vr[op.vb].vi); return true; } -bool ppu_interpreter::VSUBUWM(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSUBUWM(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd] = v128::sub32(ppu.VR[op.va], ppu.VR[op.vb]); + ppu.vr[op.vd] = v128::sub32(ppu.vr[op.va], ppu.vr[op.vb]); return true; } -bool ppu_interpreter::VSUBUWS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSUBUWS(ppu_thread& 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]; + 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++) { @@ -1569,11 +1592,11 @@ bool ppu_interpreter::VSUBUWS(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VSUMSWS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSUMSWS(ppu_thread& 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]; + 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]; @@ -1596,11 +1619,11 @@ bool ppu_interpreter::VSUMSWS(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VSUM2SWS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSUM2SWS(ppu_thread& 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]; + 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++) { @@ -1622,11 +1645,11 @@ bool ppu_interpreter::VSUM2SWS(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VSUM4SBS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSUM4SBS(ppu_thread& 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]; + 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++) { @@ -1651,11 +1674,11 @@ bool ppu_interpreter::VSUM4SBS(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VSUM4SHS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSUM4SHS(ppu_thread& 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]; + 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++) { @@ -1680,11 +1703,11 @@ bool ppu_interpreter::VSUM4SHS(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VSUM4UBS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VSUM4UBS(ppu_thread& 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]; + 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++) { @@ -1705,10 +1728,10 @@ bool ppu_interpreter::VSUM4UBS(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VUPKHPX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VUPKHPX(ppu_thread& ppu, ppu_opcode_t op) { - auto& d = ppu.VR[op.vd]; - v128 VB = ppu.VR[op.vb]; + auto& d = ppu.vr[op.vd]; + v128 VB = ppu.vr[op.vb]; for (uint w = 0; w < 4; w++) { d._s8[w * 4 + 3] = VB._s8[8 + w * 2 + 1] >> 7; // signed shift sign extends @@ -1719,10 +1742,10 @@ bool ppu_interpreter::VUPKHPX(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VUPKHSB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VUPKHSB(ppu_thread& ppu, ppu_opcode_t op) { - auto& d = ppu.VR[op.vd]; - v128 VB = ppu.VR[op.vb]; + auto& d = ppu.vr[op.vd]; + v128 VB = ppu.vr[op.vb]; for (uint h = 0; h < 8; h++) { d._s16[h] = VB._s8[8 + h]; @@ -1730,10 +1753,10 @@ bool ppu_interpreter::VUPKHSB(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VUPKHSH(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VUPKHSH(ppu_thread& ppu, ppu_opcode_t op) { - auto& d = ppu.VR[op.vd]; - v128 VB = ppu.VR[op.vb]; + auto& d = ppu.vr[op.vd]; + v128 VB = ppu.vr[op.vb]; for (uint w = 0; w < 4; w++) { d._s32[w] = VB._s16[4 + w]; @@ -1741,10 +1764,10 @@ bool ppu_interpreter::VUPKHSH(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VUPKLPX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VUPKLPX(ppu_thread& ppu, ppu_opcode_t op) { - auto& d = ppu.VR[op.vd]; - v128 VB = ppu.VR[op.vb]; + auto& d = ppu.vr[op.vd]; + v128 VB = ppu.vr[op.vb]; for (uint w = 0; w < 4; w++) { d._s8[w * 4 + 3] = VB._s8[w * 2 + 1] >> 7; // signed shift sign extends @@ -1755,10 +1778,10 @@ bool ppu_interpreter::VUPKLPX(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VUPKLSB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VUPKLSB(ppu_thread& ppu, ppu_opcode_t op) { - auto& d = ppu.VR[op.vd]; - v128 VB = ppu.VR[op.vb]; + auto& d = ppu.vr[op.vd]; + v128 VB = ppu.vr[op.vb]; for (uint h = 0; h < 8; h++) { d._s16[h] = VB._s8[h]; @@ -1766,10 +1789,10 @@ bool ppu_interpreter::VUPKLSB(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VUPKLSH(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VUPKLSH(ppu_thread& ppu, ppu_opcode_t op) { - auto& d = ppu.VR[op.vd]; - v128 VB = ppu.VR[op.vb]; + auto& d = ppu.vr[op.vd]; + v128 VB = ppu.vr[op.vb]; for (uint w = 0; w < 4; w++) { d._s32[w] = VB._s16[w]; @@ -1777,15 +1800,15 @@ bool ppu_interpreter::VUPKLSH(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::VXOR(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::VXOR(ppu_thread& ppu, ppu_opcode_t op) { - ppu.VR[op.vd] = ppu.VR[op.va] ^ ppu.VR[op.vb]; + ppu.vr[op.vd] = ppu.vr[op.va] ^ ppu.vr[op.vb]; return true; } -bool ppu_interpreter::TDI(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::TDI(ppu_thread& ppu, ppu_opcode_t op) { - const s64 a = ppu.GPR[op.ra], b = op.simm16; + const s64 a = ppu.gpr[op.ra], b = op.simm16; const u64 a_ = a, b_ = b; if (((op.bo & 0x10) && a < b) || @@ -1800,9 +1823,9 @@ bool ppu_interpreter::TDI(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::TWI(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::TWI(ppu_thread& ppu, ppu_opcode_t op) { - const s32 a = u32(ppu.GPR[op.ra]), b = op.simm16; + const s32 a = u32(ppu.gpr[op.ra]), b = op.simm16; const u32 a_ = a, b_ = b; if (((op.bo & 0x10) && a < b) || @@ -1817,88 +1840,88 @@ bool ppu_interpreter::TWI(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::MULLI(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::MULLI(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.rd] = (s64)ppu.GPR[op.ra] * op.simm16; + ppu.gpr[op.rd] = (s64)ppu.gpr[op.ra] * op.simm16; return true; } -bool ppu_interpreter::SUBFIC(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::SUBFIC(ppu_thread& ppu, ppu_opcode_t op) { - const u64 a = ppu.GPR[op.ra]; + 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; + ppu.gpr[op.rd] = r.result; + ppu.xer.ca = r.carry; return true; } -bool ppu_interpreter::CMPLI(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::CMPLI(ppu_thread& ppu, ppu_opcode_t op) { if (op.l10) { - ppu.SetCR(op.crfd, ppu.GPR[op.ra], op.uimm16); + ppu_cr_set(ppu, op.crfd, ppu.gpr[op.ra], op.uimm16); } else { - ppu.SetCR(op.crfd, u32(ppu.GPR[op.ra]), op.uimm16); + ppu_cr_set(ppu, op.crfd, u32(ppu.gpr[op.ra]), op.uimm16); } return true; } -bool ppu_interpreter::CMPI(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::CMPI(ppu_thread& ppu, ppu_opcode_t op) { if (op.l10) { - ppu.SetCR(op.crfd, ppu.GPR[op.ra], op.simm16); + ppu_cr_set(ppu, op.crfd, ppu.gpr[op.ra], op.simm16); } else { - ppu.SetCR(op.crfd, u32(ppu.GPR[op.ra]), op.simm16); + ppu_cr_set(ppu, op.crfd, u32(ppu.gpr[op.ra]), op.simm16); } return true; } -bool ppu_interpreter::ADDIC(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::ADDIC(ppu_thread& ppu, ppu_opcode_t op) { - const s64 a = ppu.GPR[op.ra]; + 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 (UNLIKELY(op.main & 1)) ppu.SetCR(0, r.result, 0); + ppu.gpr[op.rd] = r.result; + ppu.xer.ca = r.carry; + if (UNLIKELY(op.main & 1)) ppu_cr_set(ppu, 0, r.result, 0); return true; } -bool ppu_interpreter::ADDI(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::ADDI(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.rd] = op.ra ? ((s64)ppu.GPR[op.ra] + op.simm16) : op.simm16; + ppu.gpr[op.rd] = op.ra ? ((s64)ppu.gpr[op.ra] + op.simm16) : op.simm16; return true; } -bool ppu_interpreter::ADDIS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::ADDIS(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.rd] = op.ra ? ((s64)ppu.GPR[op.ra] + (op.simm16 << 16)) : (op.simm16 << 16); + ppu.gpr[op.rd] = op.ra ? ((s64)ppu.gpr[op.ra] + (op.simm16 << 16)) : (op.simm16 << 16); return true; } -bool ppu_interpreter::BC(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::BC(ppu_thread& ppu, ppu_opcode_t op) { 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; - ppu.CTR -= (bo2 ^ true); + ppu.ctr -= (bo2 ^ true); - const bool ctr_ok = bo2 | ((ppu.CTR != 0) ^ bo3); - const bool cond_ok = bo0 | (ppu.CR[op.bi] ^ (bo1 ^ true)); + 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 = ppu.pc + 4; - ppu.pc = (op.aa ? 0 : ppu.pc) + op.bt14; - if (op.lk) ppu.LR = nextLR; + const u32 link = ppu.cia + 4; + ppu.cia = (op.aa ? 0 : ppu.cia) + op.bt14; + if (op.lk) ppu.lr = link; return false; } else @@ -1907,55 +1930,55 @@ bool ppu_interpreter::BC(PPUThread& ppu, ppu_opcode_t op) } } -bool ppu_interpreter::HACK(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::HACK(ppu_thread& ppu, ppu_opcode_t op) { ppu_execute_function(ppu, op.opcode & 0x3ffffff); return true; } -bool ppu_interpreter::SC(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::SC(ppu_thread& ppu, ppu_opcode_t op) { switch (u32 lv = op.lev) { - case 0x0: ppu_execute_syscall(ppu, ppu.GPR[11]); break; + case 0x0: ppu_execute_syscall(ppu, ppu.gpr[11]); break; default: throw fmt::exception("SC lv%u", lv); } return true; } -bool ppu_interpreter::B(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::B(ppu_thread& ppu, ppu_opcode_t op) { - const u32 nextLR = ppu.pc + 4; - ppu.pc = (op.aa ? 0 : ppu.pc) + op.bt24; - if (op.lk) ppu.LR = nextLR; + const u32 link = ppu.cia + 4; + ppu.cia = (op.aa ? 0 : ppu.cia) + op.bt24; + if (op.lk) ppu.lr = link; return false; } -bool ppu_interpreter::MCRF(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::MCRF(ppu_thread& ppu, ppu_opcode_t op) { - CHECK_SIZE(PPUThread::CR, 32); - reinterpret_cast(ppu.CR)[op.crfd] = reinterpret_cast(ppu.CR)[op.crfs]; + CHECK_SIZE(ppu_thread::cr, 32); + reinterpret_cast(ppu.cr)[op.crfd] = reinterpret_cast(ppu.cr)[op.crfs]; return true; } -bool ppu_interpreter::BCLR(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::BCLR(ppu_thread& ppu, ppu_opcode_t op) { 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; - ppu.CTR -= (bo2 ^ true); + ppu.ctr -= (bo2 ^ true); - const bool ctr_ok = bo2 | ((ppu.CTR != 0) ^ bo3); - const bool cond_ok = bo0 | (ppu.CR[op.bi] ^ (bo1 ^ true)); + 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 = ppu.pc + 4; - ppu.pc = (u32)ppu.LR & ~3; - if (op.lk) ppu.LR = nextLR; + const u32 link = ppu.cia + 4; + ppu.cia = (u32)ppu.lr & ~3; + if (op.lk) ppu.lr = link; return false; } else @@ -1964,193 +1987,193 @@ bool ppu_interpreter::BCLR(PPUThread& ppu, ppu_opcode_t op) } } -bool ppu_interpreter::CRNOR(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::CRNOR(ppu_thread& ppu, ppu_opcode_t op) { - ppu.CR[op.crbd] = (ppu.CR[op.crba] | ppu.CR[op.crbb]) ^ true; + ppu.cr[op.crbd] = (ppu.cr[op.crba] | ppu.cr[op.crbb]) ^ true; return true; } -bool ppu_interpreter::CRANDC(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::CRANDC(ppu_thread& ppu, ppu_opcode_t op) { - ppu.CR[op.crbd] = ppu.CR[op.crba] & (ppu.CR[op.crbb] ^ true); + ppu.cr[op.crbd] = ppu.cr[op.crba] & (ppu.cr[op.crbb] ^ true); return true; } -bool ppu_interpreter::ISYNC(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::ISYNC(ppu_thread& ppu, ppu_opcode_t op) { _mm_mfence(); return true; } -bool ppu_interpreter::CRXOR(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::CRXOR(ppu_thread& ppu, ppu_opcode_t op) { - ppu.CR[op.crbd] = ppu.CR[op.crba] ^ ppu.CR[op.crbb]; + ppu.cr[op.crbd] = ppu.cr[op.crba] ^ ppu.cr[op.crbb]; return true; } -bool ppu_interpreter::CRNAND(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::CRNAND(ppu_thread& ppu, ppu_opcode_t op) { - ppu.CR[op.crbd] = (ppu.CR[op.crba] & ppu.CR[op.crbb]) ^ true; + ppu.cr[op.crbd] = (ppu.cr[op.crba] & ppu.cr[op.crbb]) ^ true; return true; } -bool ppu_interpreter::CRAND(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::CRAND(ppu_thread& ppu, ppu_opcode_t op) { - ppu.CR[op.crbd] = ppu.CR[op.crba] & ppu.CR[op.crbb]; + ppu.cr[op.crbd] = ppu.cr[op.crba] & ppu.cr[op.crbb]; return true; } -bool ppu_interpreter::CREQV(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::CREQV(ppu_thread& ppu, ppu_opcode_t op) { - ppu.CR[op.crbd] = (ppu.CR[op.crba] ^ ppu.CR[op.crbb]) ^ true; + ppu.cr[op.crbd] = (ppu.cr[op.crba] ^ ppu.cr[op.crbb]) ^ true; return true; } -bool ppu_interpreter::CRORC(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::CRORC(ppu_thread& ppu, ppu_opcode_t op) { - ppu.CR[op.crbd] = ppu.CR[op.crba] | (ppu.CR[op.crbb] ^ true); + ppu.cr[op.crbd] = ppu.cr[op.crba] | (ppu.cr[op.crbb] ^ true); return true; } -bool ppu_interpreter::CROR(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::CROR(ppu_thread& ppu, ppu_opcode_t op) { - ppu.CR[op.crbd] = ppu.CR[op.crba] | ppu.CR[op.crbb]; + ppu.cr[op.crbd] = ppu.cr[op.crba] | ppu.cr[op.crbb]; return true; } -bool ppu_interpreter::BCCTR(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::BCCTR(ppu_thread& ppu, ppu_opcode_t op) { - if (op.bo & 0x10 || ppu.CR[op.bi] == ((op.bo & 0x8) != 0)) + if (op.bo & 0x10 || ppu.cr[op.bi] == ((op.bo & 0x8) != 0)) { - const u32 nextLR = ppu.pc + 4; - ppu.pc = (u32)ppu.CTR & ~3; - if (op.lk) ppu.LR = nextLR; + const u32 link = ppu.cia + 4; + ppu.cia = (u32)ppu.ctr & ~3; + if (op.lk) ppu.lr = link; return false; } return true; } -bool ppu_interpreter::RLWIMI(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::RLWIMI(ppu_thread& ppu, ppu_opcode_t op) { 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 (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + ppu.gpr[op.ra] = (ppu.gpr[op.ra] & ~mask) | (dup32(rol32(u32(ppu.gpr[op.rs]), op.sh32)) & mask); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::RLWINM(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::RLWINM(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.ra] = dup32(rol32(u32(ppu.GPR[op.rs]), op.sh32)) & ppu_rotate_mask(32 + op.mb32, 32 + op.me32); - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + ppu.gpr[op.ra] = dup32(rol32(u32(ppu.gpr[op.rs]), op.sh32)) & ppu_rotate_mask(32 + op.mb32, 32 + op.me32); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::RLWNM(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::RLWNM(ppu_thread& ppu, ppu_opcode_t op) { - 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 (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + 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 (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::ORI(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::ORI(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.ra] = ppu.GPR[op.rs] | op.uimm16; + ppu.gpr[op.ra] = ppu.gpr[op.rs] | op.uimm16; return true; } -bool ppu_interpreter::ORIS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::ORIS(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.ra] = ppu.GPR[op.rs] | ((u64)op.uimm16 << 16); + ppu.gpr[op.ra] = ppu.gpr[op.rs] | ((u64)op.uimm16 << 16); return true; } -bool ppu_interpreter::XORI(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::XORI(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.ra] = ppu.GPR[op.rs] ^ op.uimm16; + ppu.gpr[op.ra] = ppu.gpr[op.rs] ^ op.uimm16; return true; } -bool ppu_interpreter::XORIS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::XORIS(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.ra] = ppu.GPR[op.rs] ^ ((u64)op.uimm16 << 16); + ppu.gpr[op.ra] = ppu.gpr[op.rs] ^ ((u64)op.uimm16 << 16); return true; } -bool ppu_interpreter::ANDI(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::ANDI(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.ra] = ppu.GPR[op.rs] & op.uimm16; - ppu.SetCR(0, ppu.GPR[op.ra], 0); + ppu.gpr[op.ra] = ppu.gpr[op.rs] & op.uimm16; + ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::ANDIS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::ANDIS(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.ra] = ppu.GPR[op.rs] & ((u64)op.uimm16 << 16); - ppu.SetCR(0, ppu.GPR[op.ra], 0); + ppu.gpr[op.ra] = ppu.gpr[op.rs] & ((u64)op.uimm16 << 16); + ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::RLDICL(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::RLDICL(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.ra] = rol64(ppu.GPR[op.rs], op.sh64) & (~0ull >> op.mbe64); - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + ppu.gpr[op.ra] = rol64(ppu.gpr[op.rs], op.sh64) & (~0ull >> op.mbe64); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::RLDICR(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::RLDICR(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.ra] = rol64(ppu.GPR[op.rs], op.sh64) & (~0ull << (op.mbe64 ^ 63)); - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + ppu.gpr[op.ra] = rol64(ppu.gpr[op.rs], op.sh64) & (~0ull << (op.mbe64 ^ 63)); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::RLDIC(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::RLDIC(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.ra] = rol64(ppu.GPR[op.rs], op.sh64) & ppu_rotate_mask(op.mbe64, op.sh64 ^ 63); - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + ppu.gpr[op.ra] = rol64(ppu.gpr[op.rs], op.sh64) & ppu_rotate_mask(op.mbe64, op.sh64 ^ 63); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::RLDIMI(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::RLDIMI(ppu_thread& ppu, ppu_opcode_t op) { 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 (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + ppu.gpr[op.ra] = (ppu.gpr[op.ra] & ~mask) | (rol64(ppu.gpr[op.rs], op.sh64) & mask); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::RLDCL(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::RLDCL(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.ra] = rol64(ppu.GPR[op.rs], ppu.GPR[op.rb] & 0x3f) & (~0ull >> op.mbe64); - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + ppu.gpr[op.ra] = rol64(ppu.gpr[op.rs], ppu.gpr[op.rb] & 0x3f) & (~0ull >> op.mbe64); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::RLDCR(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::RLDCR(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.ra] = rol64(ppu.GPR[op.rs], ppu.GPR[op.rb] & 0x3f) & (~0ull << (op.mbe64 ^ 63)); - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + ppu.gpr[op.ra] = rol64(ppu.gpr[op.rs], ppu.gpr[op.rb] & 0x3f) & (~0ull << (op.mbe64 ^ 63)); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::CMP(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::CMP(ppu_thread& ppu, ppu_opcode_t op) { if (op.l10) { - ppu.SetCR(op.crfd, ppu.GPR[op.ra], ppu.GPR[op.rb]); + ppu_cr_set(ppu, 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])); + ppu_cr_set(ppu, op.crfd, u32(ppu.gpr[op.ra]), u32(ppu.gpr[op.rb])); } return true; } -bool ppu_interpreter::TW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::TW(ppu_thread& ppu, ppu_opcode_t op) { - s32 a = (s32)ppu.GPR[op.ra]; - s32 b = (s32)ppu.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)) || @@ -2164,212 +2187,213 @@ bool ppu_interpreter::TW(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::LVSL(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LVSL(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; - ppu.VR[op.vd].vi = sse_altivec_lvsl(addr); + const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]; + ppu.vr[op.vd].vi = sse_altivec_lvsl(addr); return true; } -bool ppu_interpreter::LVEBX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LVEBX(ppu_thread& ppu, ppu_opcode_t op) { - 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)); + 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)); return true; } -bool ppu_interpreter::SUBFC(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::SUBFC(ppu_thread& ppu, ppu_opcode_t op) { - const u64 RA = ppu.GPR[op.ra]; - const u64 RB = ppu.GPR[op.rb]; + 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 (UNLIKELY(op.oe)) ppu.SetOV((~RA >> 63 == RB >> 63) && (~RA >> 63 != ppu.GPR[op.rd] >> 63)); - if (UNLIKELY(op.rc)) ppu.SetCR(0, r.result, 0); + ppu.gpr[op.rd] = r.result; + ppu.xer.ca = r.carry; + if (UNLIKELY(op.oe)) ppu_ov_set(ppu, (~RA >> 63 == RB >> 63) && (~RA >> 63 != ppu.gpr[op.rd] >> 63)); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, r.result, 0); return true; } -bool ppu_interpreter::MULHDU(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::MULHDU(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.rd] = UMULH64(ppu.GPR[op.ra], ppu.GPR[op.rb]); - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.rd], 0); + ppu.gpr[op.rd] = UMULH64(ppu.gpr[op.ra], ppu.gpr[op.rb]); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.rd], 0); return true; } -bool ppu_interpreter::ADDC(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::ADDC(ppu_thread& ppu, ppu_opcode_t op) { - const u64 RA = ppu.GPR[op.ra]; - const u64 RB = ppu.GPR[op.rb]; + 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 (UNLIKELY(op.oe)) ppu.SetOV((RA >> 63 == RB >> 63) && (RA >> 63 != ppu.GPR[op.rd] >> 63)); - if (UNLIKELY(op.rc)) ppu.SetCR(0, r.result, 0); + ppu.gpr[op.rd] = r.result; + ppu.xer.ca = r.carry; + if (UNLIKELY(op.oe)) ppu_ov_set(ppu, (RA >> 63 == RB >> 63) && (RA >> 63 != ppu.gpr[op.rd] >> 63)); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, r.result, 0); return true; } -bool ppu_interpreter::MULHWU(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::MULHWU(ppu_thread& ppu, ppu_opcode_t op) { - u32 a = (u32)ppu.GPR[op.ra]; - u32 b = (u32)ppu.GPR[op.rb]; - ppu.GPR[op.rd] = ((u64)a * (u64)b) >> 32; - if (UNLIKELY(op.rc)) ppu.SetCR(0, false, false, false, ppu.SO); + u32 a = (u32)ppu.gpr[op.ra]; + u32 b = (u32)ppu.gpr[op.rb]; + ppu.gpr[op.rd] = ((u64)a * (u64)b) >> 32; + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, false, false, false, ppu.xer.so); return true; } -bool ppu_interpreter::MFOCRF(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::MFOCRF(ppu_thread& ppu, ppu_opcode_t op) { 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; + 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); + ppu.gpr[op.rd] = v << (p ^ 0x1c); } else { // MFCR - auto* lanes = reinterpret_cast*>(ppu.CR); + 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; + ppu.gpr[op.rd] = (mh << 16) | ml; } + return true; } -bool ppu_interpreter::LWARX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LWARX(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.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, HERE), SIZE_32(value)); - ppu.GPR[op.rd] = value; + ppu.gpr[op.rd] = value; return true; } -bool ppu_interpreter::LDX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LDX(ppu_thread& 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] = vm::read64(vm::cast(addr, HERE)); + 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)); return true; } -bool ppu_interpreter::LWZX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LWZX(ppu_thread& 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] = vm::read32(vm::cast(addr, HERE)); + 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)); return true; } -bool ppu_interpreter::SLW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::SLW(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.ra] = u32(ppu.GPR[op.rs] << (ppu.GPR[op.rb] & 0x3f)); - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + ppu.gpr[op.ra] = u32(ppu.gpr[op.rs] << (ppu.gpr[op.rb] & 0x3f)); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::CNTLZW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::CNTLZW(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.ra] = cntlz32(u32(ppu.GPR[op.rs])); - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + ppu.gpr[op.ra] = cntlz32(u32(ppu.gpr[op.rs])); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::SLD(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::SLD(ppu_thread& ppu, ppu_opcode_t op) { - const u32 n = ppu.GPR[op.rb]; - ppu.GPR[op.ra] = UNLIKELY(n & 0x40) ? 0 : ppu.GPR[op.rs] << n; - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + const u32 n = ppu.gpr[op.rb]; + ppu.gpr[op.ra] = UNLIKELY(n & 0x40) ? 0 : ppu.gpr[op.rs] << n; + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::AND(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::AND(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.ra] = ppu.GPR[op.rs] & ppu.GPR[op.rb]; - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + ppu.gpr[op.ra] = ppu.gpr[op.rs] & ppu.gpr[op.rb]; + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::CMPL(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::CMPL(ppu_thread& ppu, ppu_opcode_t op) { if (op.l10) { - ppu.SetCR(op.crfd, ppu.GPR[op.ra], ppu.GPR[op.rb]); + ppu_cr_set(ppu, 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])); + ppu_cr_set(ppu, op.crfd, u32(ppu.gpr[op.ra]), u32(ppu.gpr[op.rb])); } return true; } -bool ppu_interpreter::LVSR(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LVSR(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; - ppu.VR[op.vd].vi = sse_altivec_lvsr(addr); + const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]; + ppu.vr[op.vd].vi = sse_altivec_lvsr(addr); return true; } -bool ppu_interpreter::LVEHX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LVEHX(ppu_thread& ppu, ppu_opcode_t op) { - 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)); + 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)); return true; } -bool ppu_interpreter::SUBF(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::SUBF(ppu_thread& ppu, ppu_opcode_t op) { - const u64 RA = ppu.GPR[op.ra]; - const u64 RB = ppu.GPR[op.rb]; - ppu.GPR[op.rd] = RB - RA; - if (UNLIKELY(op.oe)) ppu.SetOV((~RA >> 63 == RB >> 63) && (~RA >> 63 != ppu.GPR[op.rd] >> 63)); - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.rd], 0); + const u64 RA = ppu.gpr[op.ra]; + const u64 RB = ppu.gpr[op.rb]; + ppu.gpr[op.rd] = RB - RA; + if (UNLIKELY(op.oe)) ppu_ov_set(ppu, (~RA >> 63 == RB >> 63) && (~RA >> 63 != ppu.gpr[op.rd] >> 63)); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.rd], 0); return true; } -bool ppu_interpreter::LDUX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LDUX(ppu_thread& ppu, ppu_opcode_t op) { - 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; + 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; return true; } -bool ppu_interpreter::DCBST(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::DCBST(ppu_thread& ppu, ppu_opcode_t op) { return true; } -bool ppu_interpreter::LWZUX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LWZUX(ppu_thread& ppu, ppu_opcode_t op) { - 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; + 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; return true; } -bool ppu_interpreter::CNTLZD(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::CNTLZD(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.ra] = cntlz64(ppu.GPR[op.rs]); - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + ppu.gpr[op.ra] = cntlz64(ppu.gpr[op.rs]); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::ANDC(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::ANDC(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.ra] = ppu.GPR[op.rs] & ~ppu.GPR[op.rb]; - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + ppu.gpr[op.ra] = ppu.gpr[op.rs] & ~ppu.gpr[op.rb]; + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::TD(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::TD(ppu_thread& ppu, ppu_opcode_t op) { - const s64 a = ppu.GPR[op.ra], b = ppu.GPR[op.rb]; + const s64 a = ppu.gpr[op.ra], b = ppu.gpr[op.rb]; const u64 a_ = a, b_ = b; if (((op.bo & 0x10) && a < b) || @@ -2384,118 +2408,118 @@ bool ppu_interpreter::TD(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::LVEWX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LVEWX(ppu_thread& ppu, ppu_opcode_t op) { - 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)); + 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)); return true; } -bool ppu_interpreter::MULHD(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::MULHD(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.rd] = MULH64(ppu.GPR[op.ra], ppu.GPR[op.rb]); - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.rd], 0); + ppu.gpr[op.rd] = MULH64(ppu.gpr[op.ra], ppu.gpr[op.rb]); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.rd], 0); return true; } -bool ppu_interpreter::MULHW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::MULHW(ppu_thread& ppu, ppu_opcode_t op) { - s32 a = (s32)ppu.GPR[op.ra]; - s32 b = (s32)ppu.GPR[op.rb]; - ppu.GPR[op.rd] = ((s64)a * (s64)b) >> 32; - if (UNLIKELY(op.rc)) ppu.SetCR(0, false, false, false, ppu.SO); + s32 a = (s32)ppu.gpr[op.ra]; + s32 b = (s32)ppu.gpr[op.rb]; + ppu.gpr[op.rd] = ((s64)a * (s64)b) >> 32; + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, false, false, false, ppu.xer.so); return true; } -bool ppu_interpreter::LDARX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LDARX(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.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, HERE), SIZE_32(value)); - ppu.GPR[op.rd] = value; + ppu.gpr[op.rd] = value; return true; } -bool ppu_interpreter::DCBF(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::DCBF(ppu_thread& ppu, ppu_opcode_t op) { return true; } -bool ppu_interpreter::LBZX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LBZX(ppu_thread& 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] = vm::read8(vm::cast(addr, HERE)); + 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)); return true; } -bool ppu_interpreter::LVX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LVX(ppu_thread& ppu, ppu_opcode_t op) { - 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)); + 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)); return true; } -bool ppu_interpreter::NEG(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::NEG(ppu_thread& ppu, ppu_opcode_t op) { - const u64 RA = ppu.GPR[op.ra]; - ppu.GPR[op.rd] = 0 - RA; - if (UNLIKELY(op.oe)) ppu.SetOV((~RA >> 63 == 0) && (~RA >> 63 != ppu.GPR[op.rd] >> 63)); - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.rd], 0); + const u64 RA = ppu.gpr[op.ra]; + ppu.gpr[op.rd] = 0 - RA; + if (UNLIKELY(op.oe)) ppu_ov_set(ppu, (~RA >> 63 == 0) && (~RA >> 63 != ppu.gpr[op.rd] >> 63)); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.rd], 0); return true; } -bool ppu_interpreter::LBZUX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LBZUX(ppu_thread& ppu, ppu_opcode_t op) { - 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; + 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; return true; } -bool ppu_interpreter::NOR(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::NOR(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.ra] = ~(ppu.GPR[op.rs] | ppu.GPR[op.rb]); - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + ppu.gpr[op.ra] = ~(ppu.gpr[op.rs] | ppu.gpr[op.rb]); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::STVEBX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STVEBX(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.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, HERE), ppu.VR[op.vs]._u8[15 - eb]); + vm::write8(vm::cast(addr, HERE), ppu.vr[op.vs]._u8[15 - eb]); return true; } -bool ppu_interpreter::SUBFE(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::SUBFE(ppu_thread& ppu, ppu_opcode_t op) { - 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 (UNLIKELY(op.oe)) ppu.SetOV((~RA >> 63 == RB >> 63) && (~RA >> 63 != ppu.GPR[op.rd] >> 63)); - if (UNLIKELY(op.rc)) ppu.SetCR(0, r.result, 0); + const u64 RA = ppu.gpr[op.ra]; + const u64 RB = ppu.gpr[op.rb]; + const auto r = add64_flags(~RA, RB, ppu.xer.ca); + ppu.gpr[op.rd] = r.result; + ppu.xer.ca = r.carry; + if (UNLIKELY(op.oe)) ppu_ov_set(ppu, (~RA >> 63 == RB >> 63) && (~RA >> 63 != ppu.gpr[op.rd] >> 63)); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, r.result, 0); return true; } -bool ppu_interpreter::ADDE(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::ADDE(ppu_thread& ppu, ppu_opcode_t op) { - 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 (UNLIKELY(op.oe)) ppu.SetOV((RA >> 63 == RB >> 63) && (RA >> 63 != ppu.GPR[op.rd] >> 63)); - if (UNLIKELY(op.rc)) ppu.SetCR(0, r.result, 0); + const u64 RA = ppu.gpr[op.ra]; + const u64 RB = ppu.gpr[op.rb]; + const auto r = add64_flags(RA, RB, ppu.xer.ca); + ppu.gpr[op.rd] = r.result; + ppu.xer.ca = r.carry; + if (UNLIKELY(op.oe)) ppu_ov_set(ppu, (RA >> 63 == RB >> 63) && (RA >> 63 != ppu.gpr[op.rd] >> 63)); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, r.result, 0); return true; } -bool ppu_interpreter::MTOCRF(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::MTOCRF(ppu_thread& ppu, ppu_opcode_t op) { - const u64 s = ppu.GPR[op.rs]; + const u64 s = ppu.gpr[op.rs]; if (op.l11) { @@ -2504,10 +2528,10 @@ bool ppu_interpreter::MTOCRF(PPUThread& ppu, ppu_opcode_t op) 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; + 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 { @@ -2520,357 +2544,357 @@ bool ppu_interpreter::MTOCRF(PPUThread& ppu, ppu_opcode_t op) if (op.crm & (128 >> i)) { - 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; + 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; } } } return true; } -bool ppu_interpreter::STDX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STDX(ppu_thread& ppu, ppu_opcode_t op) { - 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]); + 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]); return true; } -bool ppu_interpreter::STWCX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STWCX(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.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)ppu.GPR[op.rs]; - ppu.SetCR(0, false, false, vm::reservation_update(vm::cast(addr, HERE), &value, SIZE_32(value)), ppu.SO); + const be_t value = (u32)ppu.gpr[op.rs]; + ppu_cr_set(ppu, 0, false, false, vm::reservation_update(vm::cast(addr, HERE), &value, SIZE_32(value)), ppu.xer.so); return true; } -bool ppu_interpreter::STWX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STWX(ppu_thread& ppu, ppu_opcode_t op) { - 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]); + 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]); return true; } -bool ppu_interpreter::STVEHX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STVEHX(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.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, HERE), ppu.VR[op.vs]._u16[7 - eb]); + vm::write16(vm::cast(addr, HERE), ppu.vr[op.vs]._u16[7 - eb]); return true; } -bool ppu_interpreter::STDUX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STDUX(ppu_thread& ppu, ppu_opcode_t op) { - 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; + 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; return true; } -bool ppu_interpreter::STWUX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STWUX(ppu_thread& ppu, ppu_opcode_t op) { - 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; + 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; return true; } -bool ppu_interpreter::STVEWX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STVEWX(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.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, HERE), ppu.VR[op.vs]._u32[3 - eb]); + vm::write32(vm::cast(addr, HERE), ppu.vr[op.vs]._u32[3 - eb]); return true; } -bool ppu_interpreter::SUBFZE(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::SUBFZE(ppu_thread& ppu, ppu_opcode_t op) { - 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 (UNLIKELY(op.oe)) ppu.SetOV((~RA >> 63 == 0) && (~RA >> 63 != ppu.GPR[op.rd] >> 63)); - if (UNLIKELY(op.rc)) ppu.SetCR(0, r.result, 0); + const u64 RA = ppu.gpr[op.ra]; + const auto r = add64_flags(~RA, 0, ppu.xer.ca); + ppu.gpr[op.rd] = r.result; + ppu.xer.ca = r.carry; + if (UNLIKELY(op.oe)) ppu_ov_set(ppu, (~RA >> 63 == 0) && (~RA >> 63 != ppu.gpr[op.rd] >> 63)); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, r.result, 0); return true; } -bool ppu_interpreter::ADDZE(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::ADDZE(ppu_thread& ppu, ppu_opcode_t op) { - 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 (UNLIKELY(op.oe)) ppu.SetOV((RA >> 63 == 0) && (RA >> 63 != ppu.GPR[op.rd] >> 63)); - if (UNLIKELY(op.rc)) ppu.SetCR(0, r.result, 0); + const u64 RA = ppu.gpr[op.ra]; + const auto r = add64_flags(RA, 0, ppu.xer.ca); + ppu.gpr[op.rd] = r.result; + ppu.xer.ca = r.carry; + if (UNLIKELY(op.oe)) ppu_ov_set(ppu, (RA >> 63 == 0) && (RA >> 63 != ppu.gpr[op.rd] >> 63)); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, r.result, 0); return true; } -bool ppu_interpreter::STDCX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STDCX(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]; - 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); + const be_t value = ppu.gpr[op.rs]; + ppu_cr_set(ppu, 0, false, false, vm::reservation_update(vm::cast(addr, HERE), &value, SIZE_32(value)), ppu.xer.so); return true; } -bool ppu_interpreter::STBX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STBX(ppu_thread& ppu, ppu_opcode_t op) { - 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]); + 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]); return true; } -bool ppu_interpreter::STVX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STVX(ppu_thread& 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]; + 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]; return true; } -bool ppu_interpreter::MULLD(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::MULLD(ppu_thread& ppu, ppu_opcode_t op) { - const s64 RA = ppu.GPR[op.ra]; - const s64 RB = ppu.GPR[op.rb]; - ppu.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 (UNLIKELY(op.oe)) { const s64 high = MULH64(RA, RB); - ppu.SetOV(high != s64(ppu.GPR[op.rd]) >> 63); + ppu_ov_set(ppu, high != s64(ppu.gpr[op.rd]) >> 63); } - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.rd], 0); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.rd], 0); return true; } -bool ppu_interpreter::SUBFME(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::SUBFME(ppu_thread& ppu, ppu_opcode_t op) { - 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 (UNLIKELY(op.oe)) ppu.SetOV((~RA >> 63 == 1) && (~RA >> 63 != ppu.GPR[op.rd] >> 63)); - if (UNLIKELY(op.rc)) ppu.SetCR(0, r.result, 0); + const u64 RA = ppu.gpr[op.ra]; + const auto r = add64_flags(~RA, ~0ull, ppu.xer.ca); + ppu.gpr[op.rd] = r.result; + ppu.xer.ca = r.carry; + if (UNLIKELY(op.oe)) ppu_ov_set(ppu, (~RA >> 63 == 1) && (~RA >> 63 != ppu.gpr[op.rd] >> 63)); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, r.result, 0); return true; } -bool ppu_interpreter::ADDME(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::ADDME(ppu_thread& ppu, ppu_opcode_t op) { - 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 (UNLIKELY(op.oe)) ppu.SetOV((u64(RA) >> 63 == 1) && (u64(RA) >> 63 != ppu.GPR[op.rd] >> 63)); - if (UNLIKELY(op.rc)) ppu.SetCR(0, r.result, 0); + const s64 RA = ppu.gpr[op.ra]; + const auto r = add64_flags(RA, ~0ull, ppu.xer.ca); + ppu.gpr[op.rd] = r.result; + ppu.xer.ca = r.carry; + if (UNLIKELY(op.oe)) ppu_ov_set(ppu, (u64(RA) >> 63 == 1) && (u64(RA) >> 63 != ppu.gpr[op.rd] >> 63)); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, r.result, 0); return true; } -bool ppu_interpreter::MULLW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::MULLW(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.rd] = (s64)((s64)(s32)ppu.GPR[op.ra] * (s64)(s32)ppu.GPR[op.rb]); - if (UNLIKELY(op.oe)) ppu.SetOV(s64(ppu.GPR[op.rd]) < s64(-1) << 31 || s64(ppu.GPR[op.rd]) >= s64(1) << 31); - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + ppu.gpr[op.rd] = (s64)((s64)(s32)ppu.gpr[op.ra] * (s64)(s32)ppu.gpr[op.rb]); + if (UNLIKELY(op.oe)) ppu_ov_set(ppu, s64(ppu.gpr[op.rd]) < s64(-1) << 31 || s64(ppu.gpr[op.rd]) >= s64(1) << 31); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::DCBTST(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::DCBTST(ppu_thread& ppu, ppu_opcode_t op) { return true; } -bool ppu_interpreter::STBUX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STBUX(ppu_thread& ppu, ppu_opcode_t op) { - 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; + 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; return true; } -bool ppu_interpreter::ADD(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::ADD(ppu_thread& ppu, ppu_opcode_t op) { - const u64 RA = ppu.GPR[op.ra]; - const u64 RB = ppu.GPR[op.rb]; - ppu.GPR[op.rd] = RA + RB; - if (UNLIKELY(op.oe)) ppu.SetOV((RA >> 63 == RB >> 63) && (RA >> 63 != ppu.GPR[op.rd] >> 63)); - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.rd], 0); + const u64 RA = ppu.gpr[op.ra]; + const u64 RB = ppu.gpr[op.rb]; + ppu.gpr[op.rd] = RA + RB; + if (UNLIKELY(op.oe)) ppu_ov_set(ppu, (RA >> 63 == RB >> 63) && (RA >> 63 != ppu.gpr[op.rd] >> 63)); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.rd], 0); return true; } -bool ppu_interpreter::DCBT(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::DCBT(ppu_thread& ppu, ppu_opcode_t op) { return true; } -bool ppu_interpreter::LHZX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LHZX(ppu_thread& 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] = vm::read16(vm::cast(addr, HERE)); + 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)); return true; } -bool ppu_interpreter::EQV(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::EQV(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.ra] = ~(ppu.GPR[op.rs] ^ ppu.GPR[op.rb]); - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + ppu.gpr[op.ra] = ~(ppu.gpr[op.rs] ^ ppu.gpr[op.rb]); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::ECIWX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::ECIWX(ppu_thread& ppu, ppu_opcode_t op) { throw std::runtime_error("ECIWX" HERE); } -bool ppu_interpreter::LHZUX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LHZUX(ppu_thread& 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] = vm::read16(vm::cast(addr, HERE)); - ppu.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; return true; } -bool ppu_interpreter::XOR(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::XOR(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.ra] = ppu.GPR[op.rs] ^ ppu.GPR[op.rb]; - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + ppu.gpr[op.ra] = ppu.gpr[op.rs] ^ ppu.gpr[op.rb]; + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::MFSPR(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::MFSPR(ppu_thread& ppu, ppu_opcode_t op) { const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5); switch (n) { - case 0x001: ppu.GPR[op.rd] = u32{ ppu.SO } << 31 | ppu.OV << 30 | ppu.CA << 29 | ppu.XCNT; break; - case 0x008: ppu.GPR[op.rd] = ppu.LR; break; - case 0x009: ppu.GPR[op.rd] = ppu.CTR; break; - case 0x100: ppu.GPR[op.rd] = ppu.VRSAVE; break; + case 0x001: ppu.gpr[op.rd] = u32{ppu.xer.so} << 31 | ppu.xer.ov << 30 | ppu.xer.ca << 29 | ppu.xer.cnt; break; + case 0x008: ppu.gpr[op.rd] = ppu.lr; break; + case 0x009: ppu.gpr[op.rd] = ppu.ctr; break; + case 0x100: ppu.gpr[op.rd] = ppu.vrsave; break; - case 0x10C: ppu.GPR[op.rd] = get_timebased_time() & 0xffffffff; break; - case 0x10D: ppu.GPR[op.rd] = get_timebased_time() >> 32; break; + 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); } return true; } -bool ppu_interpreter::LWAX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LWAX(ppu_thread& 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)); + 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)); return true; } -bool ppu_interpreter::DST(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::DST(ppu_thread& ppu, ppu_opcode_t op) { return true; } -bool ppu_interpreter::LHAX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LHAX(ppu_thread& 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)(s16)vm::read16(vm::cast(addr, HERE)); + 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)); return true; } -bool ppu_interpreter::LVXL(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LVXL(ppu_thread& ppu, ppu_opcode_t op) { - 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)); + 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)); return true; } -bool ppu_interpreter::MFTB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::MFTB(ppu_thread& ppu, ppu_opcode_t op) { const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5); switch (n) { - case 0x10C: ppu.GPR[op.rd] = get_timebased_time() & 0xffffffff; break; - case 0x10D: ppu.GPR[op.rd] = get_timebased_time() >> 32; break; + 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); } return true; } -bool ppu_interpreter::LWAUX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LWAUX(ppu_thread& 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; + 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; return true; } -bool ppu_interpreter::DSTST(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::DSTST(ppu_thread& ppu, ppu_opcode_t op) { return true; } -bool ppu_interpreter::LHAUX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LHAUX(ppu_thread& 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)(s16)vm::read16(vm::cast(addr, HERE)); - ppu.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] = (s64)(s16)vm::read16(vm::cast(addr, HERE)); + ppu.gpr[op.ra] = addr; return true; } -bool ppu_interpreter::STHX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STHX(ppu_thread& ppu, ppu_opcode_t op) { - 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]); + 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]); return true; } -bool ppu_interpreter::ORC(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::ORC(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.ra] = ppu.GPR[op.rs] | ~ppu.GPR[op.rb]; - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + ppu.gpr[op.ra] = ppu.gpr[op.rs] | ~ppu.gpr[op.rb]; + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::ECOWX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::ECOWX(ppu_thread& ppu, ppu_opcode_t op) { throw std::runtime_error("ECOWX" HERE); } -bool ppu_interpreter::STHUX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STHUX(ppu_thread& 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; + 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; return true; } -bool ppu_interpreter::OR(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::OR(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.ra] = ppu.GPR[op.rs] | ppu.GPR[op.rb]; - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + ppu.gpr[op.ra] = ppu.gpr[op.rs] | ppu.gpr[op.rb]; + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::DIVDU(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::DIVDU(ppu_thread& 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 (UNLIKELY(op.oe)) ppu.SetOV(RB == 0); - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.rd], 0); + const u64 RA = ppu.gpr[op.ra]; + const u64 RB = ppu.gpr[op.rb]; + ppu.gpr[op.rd] = RB == 0 ? 0 : RA / RB; + if (UNLIKELY(op.oe)) ppu_ov_set(ppu, RB == 0); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.rd], 0); return true; } -bool ppu_interpreter::DIVWU(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::DIVWU(ppu_thread& 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 (UNLIKELY(op.oe)) ppu.SetOV(RB == 0); - if (UNLIKELY(op.rc)) ppu.SetCR(0, false, false, false, ppu.SO); + 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 (UNLIKELY(op.oe)) ppu_ov_set(ppu, RB == 0); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, false, false, false, ppu.xer.so); return true; } -bool ppu_interpreter::MTSPR(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::MTSPR(ppu_thread& ppu, ppu_opcode_t op) { const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5); @@ -2878,84 +2902,84 @@ bool ppu_interpreter::MTSPR(PPUThread& ppu, ppu_opcode_t op) { case 0x001: { - 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; + const u64 value = ppu.gpr[op.rs]; + ppu.xer.so = (value & 0x80000000) != 0; + ppu.xer.ov = (value & 0x40000000) != 0; + ppu.xer.ca = (value & 0x20000000) != 0; + ppu.xer.cnt = value & 0x7f; break; } - case 0x008: ppu.LR = ppu.GPR[op.rs]; break; - case 0x009: ppu.CTR = ppu.GPR[op.rs]; break; - case 0x100: ppu.VRSAVE = (u32)ppu.GPR[op.rs]; break; + case 0x008: ppu.lr = ppu.gpr[op.rs]; break; + case 0x009: ppu.ctr = ppu.gpr[op.rs]; break; + case 0x100: ppu.vrsave = (u32)ppu.gpr[op.rs]; break; default: throw fmt::exception("MTSPR 0x%x" HERE, n); } return true; } -bool ppu_interpreter::DCBI(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::DCBI(ppu_thread& ppu, ppu_opcode_t op) { return true; } -bool ppu_interpreter::NAND(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::NAND(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.ra] = ~(ppu.GPR[op.rs] & ppu.GPR[op.rb]); - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + ppu.gpr[op.ra] = ~(ppu.gpr[op.rs] & ppu.gpr[op.rb]); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::STVXL(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STVXL(ppu_thread& 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]; + 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]; return true; } -bool ppu_interpreter::DIVD(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::DIVD(ppu_thread& ppu, ppu_opcode_t op) { - const s64 RA = ppu.GPR[op.ra]; - const s64 RB = ppu.GPR[op.rb]; + 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 (UNLIKELY(op.oe)) ppu.SetOV(o); - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.rd], 0); + ppu.gpr[op.rd] = o ? 0 : RA / RB; + if (UNLIKELY(op.oe)) ppu_ov_set(ppu, o); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.rd], 0); return true; } -bool ppu_interpreter::DIVW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::DIVW(ppu_thread& ppu, ppu_opcode_t op) { - const s32 RA = (s32)ppu.GPR[op.ra]; - const s32 RB = (s32)ppu.GPR[op.rb]; + 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 (UNLIKELY(op.oe)) ppu.SetOV(o); - if (UNLIKELY(op.rc)) ppu.SetCR(0, false, false, false, ppu.SO); + ppu.gpr[op.rd] = o ? 0 : u32(RA / RB); + if (UNLIKELY(op.oe)) ppu_ov_set(ppu, o); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, false, false, false, ppu.xer.so); return true; } -bool ppu_interpreter::LVLX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LVLX(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; - ppu.VR[op.vd].vi = sse_cellbe_lvlx(addr); + const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]; + ppu.vr[op.vd].vi = sse_cellbe_lvlx(addr); return true; } -bool ppu_interpreter::LDBRX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LDBRX(ppu_thread& 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] = vm::_ref>(vm::cast(addr, HERE)); + 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)); return true; } -bool ppu_interpreter::LSWX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LSWX(ppu_thread& ppu, ppu_opcode_t op) { - u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; - u32 count = ppu.XCNT & 0x7f; + u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]; + u32 count = ppu.xer.cnt & 0x7f; for (; count >= 4; count -= 4, addr += 4, op.rd = (op.rd + 1) & 31) { - ppu.GPR[op.rd] = vm::_ref(vm::cast(addr, HERE)); + ppu.gpr[op.rd] = vm::_ref(vm::cast(addr, HERE)); } if (count) { @@ -2965,50 +2989,50 @@ bool ppu_interpreter::LSWX(PPUThread& ppu, ppu_opcode_t op) u32 byte_value = vm::_ref(vm::cast(addr + byte, HERE)); value |= byte_value << ((3 ^ byte) * 8); } - ppu.GPR[op.rd] = value; + ppu.gpr[op.rd] = value; } return true; } -bool ppu_interpreter::LWBRX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LWBRX(ppu_thread& 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] = vm::_ref>(vm::cast(addr, HERE)); + 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)); return true; } -bool ppu_interpreter::LFSX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LFSX(ppu_thread& ppu, ppu_opcode_t op) { - 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)); + 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)); return true; } -bool ppu_interpreter::SRW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::SRW(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.ra] = (ppu.GPR[op.rs] & 0xffffffff) >> (ppu.GPR[op.rb] & 0x3f); - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + ppu.gpr[op.ra] = (ppu.gpr[op.rs] & 0xffffffff) >> (ppu.gpr[op.rb] & 0x3f); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::SRD(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::SRD(ppu_thread& ppu, ppu_opcode_t op) { - const u32 n = ppu.GPR[op.rb]; - ppu.GPR[op.ra] = UNLIKELY(n & 0x40) ? 0 : ppu.GPR[op.rs] >> n; - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + const u32 n = ppu.gpr[op.rb]; + ppu.gpr[op.ra] = UNLIKELY(n & 0x40) ? 0 : ppu.gpr[op.rs] >> n; + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::LVRX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LVRX(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; - ppu.VR[op.vd].vi = sse_cellbe_lvrx(addr); + const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]; + ppu.vr[op.vd].vi = sse_cellbe_lvrx(addr); return true; } -bool ppu_interpreter::LSWI(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LSWI(ppu_thread& ppu, ppu_opcode_t op) { - u64 addr = op.ra ? ppu.GPR[op.ra] : 0; + u64 addr = op.ra ? ppu.gpr[op.ra] : 0; u64 N = op.rb ? op.rb : 32; u8 reg = op.rd; @@ -3016,7 +3040,7 @@ bool ppu_interpreter::LSWI(PPUThread& ppu, ppu_opcode_t op) { if (N > 3) { - ppu.GPR[reg] = vm::read32(vm::cast(addr, HERE)); + ppu.gpr[reg] = vm::read32(vm::cast(addr, HERE)); addr += 4; N -= 4; } @@ -3031,67 +3055,67 @@ bool ppu_interpreter::LSWI(PPUThread& ppu, ppu_opcode_t op) addr++; i--; } - ppu.GPR[reg] = buf; + ppu.gpr[reg] = buf; } reg = (reg + 1) % 32; } return true; } -bool ppu_interpreter::LFSUX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LFSUX(ppu_thread& ppu, ppu_opcode_t op) { - 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; + 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; return true; } -bool ppu_interpreter::SYNC(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::SYNC(ppu_thread& ppu, ppu_opcode_t op) { _mm_mfence(); return true; } -bool ppu_interpreter::LFDX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LFDX(ppu_thread& ppu, ppu_opcode_t op) { - 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)); + 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)); return true; } -bool ppu_interpreter::LFDUX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LFDUX(ppu_thread& ppu, ppu_opcode_t op) { - 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; + 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; return true; } -bool ppu_interpreter::STVLX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STVLX(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; - sse_cellbe_stvlx(addr, ppu.VR[op.vs].vi); + const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]; + sse_cellbe_stvlx(addr, ppu.vr[op.vs].vi); return true; } -bool ppu_interpreter::STDBRX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STDBRX(ppu_thread& ppu, ppu_opcode_t op) { - 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]; + 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]; return true; } -bool ppu_interpreter::STSWX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STSWX(ppu_thread& ppu, ppu_opcode_t op) { - u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; - u32 count = ppu.XCNT & 0x7F; + u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]; + u32 count = ppu.xer.cnt & 0x7F; for (; count >= 4; count -= 4, addr += 4, op.rs = (op.rs + 1) & 31) { - vm::write32(vm::cast(addr, HERE), (u32)ppu.GPR[op.rs]); + vm::write32(vm::cast(addr, HERE), (u32)ppu.gpr[op.rs]); } if (count) { - u32 value = (u32)ppu.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)); @@ -3101,38 +3125,38 @@ bool ppu_interpreter::STSWX(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::STWBRX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STWBRX(ppu_thread& ppu, ppu_opcode_t op) { - 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]; + 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]; return true; } -bool ppu_interpreter::STFSX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STFSX(ppu_thread& ppu, ppu_opcode_t op) { - 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]); + 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]); return true; } -bool ppu_interpreter::STVRX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STVRX(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; - sse_cellbe_stvrx(addr, ppu.VR[op.vs].vi); + const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]; + sse_cellbe_stvrx(addr, ppu.vr[op.vs].vi); return true; } -bool ppu_interpreter::STFSUX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STFSUX(ppu_thread& ppu, ppu_opcode_t op) { - 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; + 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; return true; } -bool ppu_interpreter::STSWI(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STSWI(ppu_thread& ppu, ppu_opcode_t op) { - u64 addr = op.ra ? ppu.GPR[op.ra] : 0; + u64 addr = op.ra ? ppu.gpr[op.ra] : 0; u64 N = op.rb ? op.rb : 32; u8 reg = op.rd; @@ -3140,13 +3164,13 @@ bool ppu_interpreter::STSWI(PPUThread& ppu, ppu_opcode_t op) { if (N > 3) { - vm::write32(vm::cast(addr, HERE), (u32)ppu.GPR[reg]); + vm::write32(vm::cast(addr, HERE), (u32)ppu.gpr[reg]); addr += 4; N -= 4; } else { - u32 buf = (u32)ppu.GPR[reg]; + u32 buf = (u32)ppu.gpr[reg]; while (N > 0) { N = N - 1; @@ -3160,671 +3184,671 @@ bool ppu_interpreter::STSWI(PPUThread& ppu, ppu_opcode_t op) return true; } -bool ppu_interpreter::STFDX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STFDX(ppu_thread& ppu, ppu_opcode_t op) { - 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]; + 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]; return true; } -bool ppu_interpreter::STFDUX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STFDUX(ppu_thread& ppu, ppu_opcode_t op) { - 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; + 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; return true; } -bool ppu_interpreter::LVLXL(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LVLXL(ppu_thread& ppu, ppu_opcode_t op) { return LVLX(ppu, op); } -bool ppu_interpreter::LHBRX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LHBRX(ppu_thread& 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] = vm::_ref>(vm::cast(addr, HERE)); + 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)); return true; } -bool ppu_interpreter::SRAW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::SRAW(ppu_thread& ppu, ppu_opcode_t op) { - s32 RS = (s32)ppu.GPR[op.rs]; - u8 shift = ppu.GPR[op.rb] & 63; + s32 RS = (s32)ppu.gpr[op.rs]; + u8 shift = ppu.gpr[op.rb] & 63; if (shift > 31) { - ppu.GPR[op.ra] = 0 - (RS < 0); - ppu.CA = (RS < 0); + ppu.gpr[op.ra] = 0 - (RS < 0); + ppu.xer.ca = (RS < 0); } else { - ppu.GPR[op.ra] = RS >> shift; - ppu.CA = (RS < 0) && ((ppu.GPR[op.ra] << shift) != RS); + ppu.gpr[op.ra] = RS >> shift; + ppu.xer.ca = (RS < 0) && ((ppu.gpr[op.ra] << shift) != RS); } - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::SRAD(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::SRAD(ppu_thread& ppu, ppu_opcode_t op) { - s64 RS = ppu.GPR[op.rs]; - u8 shift = ppu.GPR[op.rb] & 127; + s64 RS = ppu.gpr[op.rs]; + u8 shift = ppu.gpr[op.rb] & 127; if (shift > 63) { - ppu.GPR[op.ra] = 0 - (RS < 0); - ppu.CA = (RS < 0); + ppu.gpr[op.ra] = 0 - (RS < 0); + ppu.xer.ca = (RS < 0); } else { - ppu.GPR[op.ra] = RS >> shift; - ppu.CA = (RS < 0) && ((ppu.GPR[op.ra] << shift) != RS); + ppu.gpr[op.ra] = RS >> shift; + ppu.xer.ca = (RS < 0) && ((ppu.gpr[op.ra] << shift) != RS); } - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::LVRXL(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LVRXL(ppu_thread& ppu, ppu_opcode_t op) { return LVRX(ppu, op); } -bool ppu_interpreter::DSS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::DSS(ppu_thread& ppu, ppu_opcode_t op) { return true; } -bool ppu_interpreter::SRAWI(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::SRAWI(ppu_thread& ppu, ppu_opcode_t op) { - 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); + s32 RS = (u32)ppu.gpr[op.rs]; + ppu.gpr[op.ra] = RS >> op.sh32; + ppu.xer.ca = (RS < 0) && ((u32)(ppu.gpr[op.ra] << op.sh32) != RS); - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::SRADI(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::SRADI(ppu_thread& ppu, ppu_opcode_t op) { 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); + s64 RS = ppu.gpr[op.rs]; + ppu.gpr[op.ra] = RS >> sh; + ppu.xer.ca = (RS < 0) && ((ppu.gpr[op.ra] << sh) != RS); - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::EIEIO(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::EIEIO(ppu_thread& ppu, ppu_opcode_t op) { _mm_mfence(); return true; } -bool ppu_interpreter::STVLXL(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STVLXL(ppu_thread& ppu, ppu_opcode_t op) { return STVLX(ppu, op); } -bool ppu_interpreter::STHBRX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STHBRX(ppu_thread& ppu, ppu_opcode_t op) { - 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]; + 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]; return true; } -bool ppu_interpreter::EXTSH(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::EXTSH(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.ra] = (s64)(s16)ppu.GPR[op.rs]; - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + ppu.gpr[op.ra] = (s64)(s16)ppu.gpr[op.rs]; + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::STVRXL(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STVRXL(ppu_thread& ppu, ppu_opcode_t op) { return STVRX(ppu, op); } -bool ppu_interpreter::EXTSB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::EXTSB(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.ra] = (s64)(s8)ppu.GPR[op.rs]; - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + ppu.gpr[op.ra] = (s64)(s8)ppu.gpr[op.rs]; + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::STFIWX(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STFIWX(ppu_thread& ppu, ppu_opcode_t op) { - 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]); + 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]); return true; } -bool ppu_interpreter::EXTSW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::EXTSW(ppu_thread& ppu, ppu_opcode_t op) { - ppu.GPR[op.ra] = (s64)(s32)ppu.GPR[op.rs]; - if (UNLIKELY(op.rc)) ppu.SetCR(0, ppu.GPR[op.ra], 0); + ppu.gpr[op.ra] = (s64)(s32)ppu.gpr[op.rs]; + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 0, ppu.gpr[op.ra], 0); return true; } -bool ppu_interpreter::ICBI(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::ICBI(ppu_thread& ppu, ppu_opcode_t op) { return true; } -bool ppu_interpreter::DCBZ(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::DCBZ(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.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, HERE) & ~127), 0, 128); return true; } -bool ppu_interpreter::LWZ(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LWZ(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; - ppu.GPR[op.rd] = vm::read32(vm::cast(addr, HERE)); + const u64 addr = op.ra ? ppu.gpr[op.ra] + op.simm16 : op.simm16; + ppu.gpr[op.rd] = vm::read32(vm::cast(addr, HERE)); return true; } -bool ppu_interpreter::LWZU(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LWZU(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = ppu.GPR[op.ra] + op.simm16; - ppu.GPR[op.rd] = vm::read32(vm::cast(addr, HERE)); - ppu.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; return true; } -bool ppu_interpreter::LBZ(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LBZ(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; - ppu.GPR[op.rd] = vm::read8(vm::cast(addr, HERE)); + const u64 addr = op.ra ? ppu.gpr[op.ra] + op.simm16 : op.simm16; + ppu.gpr[op.rd] = vm::read8(vm::cast(addr, HERE)); return true; } -bool ppu_interpreter::LBZU(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LBZU(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = ppu.GPR[op.ra] + op.simm16; - ppu.GPR[op.rd] = vm::read8(vm::cast(addr, HERE)); - ppu.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; return true; } -bool ppu_interpreter::STW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STW(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; - vm::write32(vm::cast(addr, HERE), (u32)ppu.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]); return true; } -bool ppu_interpreter::STWU(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STWU(ppu_thread& ppu, ppu_opcode_t op) { - 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; + 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; return true; } -bool ppu_interpreter::STB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STB(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; - vm::write8(vm::cast(addr, HERE), (u8)ppu.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]); return true; } -bool ppu_interpreter::STBU(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STBU(ppu_thread& ppu, ppu_opcode_t op) { - 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; + 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; return true; } -bool ppu_interpreter::LHZ(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LHZ(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; - ppu.GPR[op.rd] = vm::read16(vm::cast(addr, HERE)); + const u64 addr = op.ra ? ppu.gpr[op.ra] + op.simm16 : op.simm16; + ppu.gpr[op.rd] = vm::read16(vm::cast(addr, HERE)); return true; } -bool ppu_interpreter::LHZU(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LHZU(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = ppu.GPR[op.ra] + op.simm16; - ppu.GPR[op.rd] = vm::read16(vm::cast(addr, HERE)); - ppu.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; return true; } -bool ppu_interpreter::LHA(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LHA(ppu_thread& ppu, ppu_opcode_t op) { - 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)); + 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)); return true; } -bool ppu_interpreter::LHAU(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LHAU(ppu_thread& ppu, ppu_opcode_t op) { - 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; + 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; return true; } -bool ppu_interpreter::STH(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STH(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; - vm::write16(vm::cast(addr, HERE), (u16)ppu.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]); return true; } -bool ppu_interpreter::STHU(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STHU(ppu_thread& ppu, ppu_opcode_t op) { - 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; + 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; return true; } -bool ppu_interpreter::LMW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LMW(ppu_thread& ppu, ppu_opcode_t op) { - u64 addr = op.ra ? ppu.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) { - ppu.GPR[i] = vm::read32(vm::cast(addr, HERE)); + ppu.gpr[i] = vm::read32(vm::cast(addr, HERE)); } return true; } -bool ppu_interpreter::STMW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STMW(ppu_thread& ppu, ppu_opcode_t op) { - u64 addr = op.ra ? ppu.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, HERE), (u32)ppu.GPR[i]); + vm::write32(vm::cast(addr, HERE), (u32)ppu.gpr[i]); } return true; } -bool ppu_interpreter::LFS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LFS(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; - ppu.FPR[op.frd] = vm::_ref(vm::cast(addr, HERE)); + const u64 addr = op.ra ? ppu.gpr[op.ra] + op.simm16 : op.simm16; + ppu.fpr[op.frd] = vm::_ref(vm::cast(addr, HERE)); return true; } -bool ppu_interpreter::LFSU(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LFSU(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = ppu.GPR[op.ra] + op.simm16; - ppu.FPR[op.frd] = vm::_ref(vm::cast(addr, HERE)); - ppu.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; return true; } -bool ppu_interpreter::LFD(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LFD(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; - ppu.FPR[op.frd] = vm::_ref(vm::cast(addr, HERE)); + const u64 addr = op.ra ? ppu.gpr[op.ra] + op.simm16 : op.simm16; + ppu.fpr[op.frd] = vm::_ref(vm::cast(addr, HERE)); return true; } -bool ppu_interpreter::LFDU(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LFDU(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = ppu.GPR[op.ra] + op.simm16; - ppu.FPR[op.frd] = vm::_ref(vm::cast(addr, HERE)); - ppu.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; return true; } -bool ppu_interpreter::STFS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STFS(ppu_thread& ppu, ppu_opcode_t op) { - 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]); + 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]); return true; } -bool ppu_interpreter::STFSU(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STFSU(ppu_thread& ppu, ppu_opcode_t op) { - 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; + 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; return true; } -bool ppu_interpreter::STFD(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STFD(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; - vm::_ref(vm::cast(addr, HERE)) = ppu.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]; return true; } -bool ppu_interpreter::STFDU(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STFDU(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = ppu.GPR[op.ra] + op.simm16; - vm::_ref(vm::cast(addr, HERE)) = ppu.FPR[op.frs]; - ppu.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; return true; } -bool ppu_interpreter::LD(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LD(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = (op.simm16 & ~3) + (op.ra ? ppu.GPR[op.ra] : 0); - ppu.GPR[op.rd] = vm::read64(vm::cast(addr, HERE)); + const u64 addr = (op.simm16 & ~3) + (op.ra ? ppu.gpr[op.ra] : 0); + ppu.gpr[op.rd] = vm::read64(vm::cast(addr, HERE)); return true; } -bool ppu_interpreter::LDU(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LDU(ppu_thread& ppu, ppu_opcode_t op) { - 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; + 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; return true; } -bool ppu_interpreter::LWA(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::LWA(ppu_thread& ppu, ppu_opcode_t op) { - 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)); + 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)); return true; } -bool ppu_interpreter::STD(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STD(ppu_thread& ppu, ppu_opcode_t op) { - const u64 addr = (op.simm16 & ~3) + (op.ra ? ppu.GPR[op.ra] : 0); - vm::write64(vm::cast(addr, HERE), ppu.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]); return true; } -bool ppu_interpreter::STDU(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::STDU(ppu_thread& ppu, ppu_opcode_t op) { - 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; + 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; return true; } -bool ppu_interpreter::FDIVS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FDIVS(ppu_thread& ppu, ppu_opcode_t op) { - ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] / ppu.FPR[op.frb]); - VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + ppu.fpr[op.frd] = f32(ppu.fpr[op.fra] / ppu.fpr[op.frb]); + VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FSUBS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FSUBS(ppu_thread& ppu, ppu_opcode_t op) { - ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] - ppu.FPR[op.frb]); - VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + ppu.fpr[op.frd] = f32(ppu.fpr[op.fra] - ppu.fpr[op.frb]); + VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FADDS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FADDS(ppu_thread& ppu, ppu_opcode_t op) { - ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] + ppu.FPR[op.frb]); - VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + ppu.fpr[op.frd] = f32(ppu.fpr[op.fra] + ppu.fpr[op.frb]); + VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FSQRTS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FSQRTS(ppu_thread& ppu, ppu_opcode_t op) { - ppu.FPR[op.frd] = f32(std::sqrt(ppu.FPR[op.frb])); - VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + ppu.fpr[op.frd] = f32(std::sqrt(ppu.fpr[op.frb])); + VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FRES(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FRES(ppu_thread& ppu, ppu_opcode_t op) { - f32 value = f32(ppu.FPR[op.frb]); + f32 value = f32(ppu.fpr[op.frb]); _mm_store_ss(&value, _mm_rcp_ss(_mm_load_ss(&value))); - ppu.FPR[op.frd] = value; - VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + ppu.fpr[op.frd] = value; + VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FMULS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FMULS(ppu_thread& ppu, ppu_opcode_t op) { - ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] * ppu.FPR[op.frc]); - VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + ppu.fpr[op.frd] = f32(ppu.fpr[op.fra] * ppu.fpr[op.frc]); + VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FMADDS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FMADDS(ppu_thread& ppu, ppu_opcode_t op) { - ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] * ppu.FPR[op.frc] + ppu.FPR[op.frb]); - VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + ppu.fpr[op.frd] = f32(ppu.fpr[op.fra] * ppu.fpr[op.frc] + ppu.fpr[op.frb]); + VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FMSUBS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FMSUBS(ppu_thread& ppu, ppu_opcode_t op) { - ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] * ppu.FPR[op.frc] - ppu.FPR[op.frb]); - VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + ppu.fpr[op.frd] = f32(ppu.fpr[op.fra] * ppu.fpr[op.frc] - ppu.fpr[op.frb]); + VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FNMSUBS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FNMSUBS(ppu_thread& ppu, ppu_opcode_t op) { - ppu.FPR[op.frd] = f32(-(ppu.FPR[op.fra] * ppu.FPR[op.frc]) + ppu.FPR[op.frb]); - VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + ppu.fpr[op.frd] = f32(-(ppu.fpr[op.fra] * ppu.fpr[op.frc]) + ppu.fpr[op.frb]); + VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FNMADDS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FNMADDS(ppu_thread& ppu, ppu_opcode_t op) { - ppu.FPR[op.frd] = f32(-(ppu.FPR[op.fra] * ppu.FPR[op.frc]) - ppu.FPR[op.frb]); - VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + ppu.fpr[op.frd] = f32(-(ppu.fpr[op.fra] * ppu.fpr[op.frc]) - ppu.fpr[op.frb]); + VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::MTFSB1(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::MTFSB1(ppu_thread& ppu, ppu_opcode_t op) { LOG_WARNING(PPU, "MTFSB1"); - if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::MCRFS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::MCRFS(ppu_thread& ppu, ppu_opcode_t op) { LOG_WARNING(PPU, "MCRFS"); - ppu.SetCR(op.crfd, false, false, false, false); + ppu_cr_set(ppu, op.crfd, false, false, false, false); return true; } -bool ppu_interpreter::MTFSB0(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::MTFSB0(ppu_thread& ppu, ppu_opcode_t op) { LOG_WARNING(PPU, "MTFSB0"); - if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::MTFSFI(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::MTFSFI(ppu_thread& ppu, ppu_opcode_t op) { LOG_WARNING(PPU, "MTFSFI"); - if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::MFFS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::MFFS(ppu_thread& ppu, ppu_opcode_t op) { LOG_WARNING(PPU, "MFFS"); - ppu.FPR[op.frd] = 0.0; - if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + ppu.fpr[op.frd] = 0.0; + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::MTFSF(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::MTFSF(ppu_thread& ppu, ppu_opcode_t op) { LOG_WARNING(PPU, "MTFSF"); - if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FCMPU(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FCMPU(ppu_thread& 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); + const f64 a = ppu.fpr[op.fra]; + const f64 b = ppu.fpr[op.frb]; + ppu.fpscr.fg = a > b; + ppu.fpscr.fl = a < b; + ppu.fpscr.fe = a == b; + //ppu.fpscr.fu = a != a || b != b; + ppu_cr_set(ppu, op.crfd, ppu.fpscr.fl, ppu.fpscr.fg, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FRSP(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FRSP(ppu_thread& ppu, ppu_opcode_t op) { - ppu.FPR[op.frd] = f32(ppu.FPR[op.frb]); - VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + ppu.fpr[op.frd] = f32(ppu.fpr[op.frb]); + VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FCTIW(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FCTIW(ppu_thread& ppu, ppu_opcode_t op) { - (s32&)ppu.FPR[op.frd] = s32(ppu.FPR[op.frb]); - VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + (s32&)ppu.fpr[op.frd] = s32(ppu.fpr[op.frb]); + VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FCTIWZ(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FCTIWZ(ppu_thread& ppu, ppu_opcode_t op) { - (s32&)ppu.FPR[op.frd] = _mm_cvttsd_si32(_mm_load_sd(&ppu.FPR[op.frb])); - VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + (s32&)ppu.fpr[op.frd] = _mm_cvttsd_si32(_mm_load_sd(&ppu.fpr[op.frb])); + VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FDIV(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FDIV(ppu_thread& ppu, ppu_opcode_t op) { - ppu.FPR[op.frd] = ppu.FPR[op.fra] / ppu.FPR[op.frb]; - VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + ppu.fpr[op.frd] = ppu.fpr[op.fra] / ppu.fpr[op.frb]; + VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FSUB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FSUB(ppu_thread& ppu, ppu_opcode_t op) { - ppu.FPR[op.frd] = ppu.FPR[op.fra] - ppu.FPR[op.frb]; - VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + ppu.fpr[op.frd] = ppu.fpr[op.fra] - ppu.fpr[op.frb]; + VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FADD(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FADD(ppu_thread& ppu, ppu_opcode_t op) { - ppu.FPR[op.frd] = ppu.FPR[op.fra] + ppu.FPR[op.frb]; - VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + ppu.fpr[op.frd] = ppu.fpr[op.fra] + ppu.fpr[op.frb]; + VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FSQRT(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FSQRT(ppu_thread& ppu, ppu_opcode_t op) { - ppu.FPR[op.frd] = std::sqrt(ppu.FPR[op.frb]); - VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + ppu.fpr[op.frd] = std::sqrt(ppu.fpr[op.frb]); + VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FSEL(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FSEL(ppu_thread& ppu, ppu_opcode_t op) { - ppu.FPR[op.frd] = ppu.FPR[op.fra] >= 0.0 ? ppu.FPR[op.frc] : ppu.FPR[op.frb]; - if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + ppu.fpr[op.frd] = ppu.fpr[op.fra] >= 0.0 ? ppu.fpr[op.frc] : ppu.fpr[op.frb]; + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FMUL(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FMUL(ppu_thread& ppu, ppu_opcode_t op) { - ppu.FPR[op.frd] = ppu.FPR[op.fra] * ppu.FPR[op.frc]; - VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + ppu.fpr[op.frd] = ppu.fpr[op.fra] * ppu.fpr[op.frc]; + VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FRSQRTE(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FRSQRTE(ppu_thread& ppu, ppu_opcode_t op) { - f32 value = f32(ppu.FPR[op.frb]); + f32 value = f32(ppu.fpr[op.frb]); _mm_store_ss(&value, _mm_rsqrt_ss(_mm_load_ss(&value))); - ppu.FPR[op.frd] = value; - VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + ppu.fpr[op.frd] = value; + VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FMSUB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FMSUB(ppu_thread& ppu, ppu_opcode_t op) { - ppu.FPR[op.frd] = ppu.FPR[op.fra] * ppu.FPR[op.frc] - ppu.FPR[op.frb]; - VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + ppu.fpr[op.frd] = ppu.fpr[op.fra] * ppu.fpr[op.frc] - ppu.fpr[op.frb]; + VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FMADD(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FMADD(ppu_thread& ppu, ppu_opcode_t op) { - ppu.FPR[op.frd] = ppu.FPR[op.fra] * ppu.FPR[op.frc] + ppu.FPR[op.frb]; - VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + ppu.fpr[op.frd] = ppu.fpr[op.fra] * ppu.fpr[op.frc] + ppu.fpr[op.frb]; + VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FNMSUB(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FNMSUB(ppu_thread& ppu, ppu_opcode_t op) { - ppu.FPR[op.frd] = -(ppu.FPR[op.fra] * ppu.FPR[op.frc]) + ppu.FPR[op.frb]; - VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + ppu.fpr[op.frd] = -(ppu.fpr[op.fra] * ppu.fpr[op.frc]) + ppu.fpr[op.frb]; + VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FNMADD(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FNMADD(ppu_thread& ppu, ppu_opcode_t op) { - ppu.FPR[op.frd] = -(ppu.FPR[op.fra] * ppu.FPR[op.frc]) - ppu.FPR[op.frb]; - VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + ppu.fpr[op.frd] = -(ppu.fpr[op.fra] * ppu.fpr[op.frc]) - ppu.fpr[op.frb]; + VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FCMPO(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FCMPO(ppu_thread& ppu, ppu_opcode_t op) { return FCMPU(ppu, op); return true; } -bool ppu_interpreter::FNEG(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FNEG(ppu_thread& ppu, ppu_opcode_t op) { - ppu.FPR[op.frd] = -ppu.FPR[op.frb]; - if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + ppu.fpr[op.frd] = -ppu.fpr[op.frb]; + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FMR(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FMR(ppu_thread& ppu, ppu_opcode_t op) { - ppu.FPR[op.frd] = ppu.FPR[op.frb]; - if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + ppu.fpr[op.frd] = ppu.fpr[op.frb]; + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FNABS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FNABS(ppu_thread& ppu, ppu_opcode_t op) { - ppu.FPR[op.frd] = -std::fabs(ppu.FPR[op.frb]); - if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + ppu.fpr[op.frd] = -std::fabs(ppu.fpr[op.frb]); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FABS(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FABS(ppu_thread& ppu, ppu_opcode_t op) { - ppu.FPR[op.frd] = std::fabs(ppu.FPR[op.frb]); - if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + ppu.fpr[op.frd] = std::fabs(ppu.fpr[op.frb]); + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FCTID(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FCTID(ppu_thread& ppu, ppu_opcode_t op) { - (s64&)ppu.FPR[op.frd] = s64(ppu.FPR[op.frb]); - VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + (s64&)ppu.fpr[op.frd] = s64(ppu.fpr[op.frb]); + VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FCTIDZ(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FCTIDZ(ppu_thread& ppu, ppu_opcode_t op) { - (s64&)ppu.FPR[op.frd] = _mm_cvttsd_si64(_mm_load_sd(&ppu.FPR[op.frb])); - VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + (s64&)ppu.fpr[op.frd] = _mm_cvttsd_si64(_mm_load_sd(&ppu.fpr[op.frb])); + VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::FCFID(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::FCFID(ppu_thread& ppu, ppu_opcode_t op) { - ppu.FPR[op.frd] = static_cast((s64&)ppu.FPR[op.frb]); - VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); + ppu.fpr[op.frd] = static_cast((s64&)ppu.fpr[op.frb]); + VERIFY(!op.rc); //if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } -bool ppu_interpreter::UNK(PPUThread& ppu, ppu_opcode_t op) +bool ppu_interpreter::UNK(ppu_thread& ppu, ppu_opcode_t op) { - throw fmt::exception("Unknown/Illegal opcode: 0x%08x (pc=0x%x)" HERE, op.opcode, ppu.pc); + throw fmt::exception("Unknown/Illegal opcode: 0x%08x at 0x%x" HERE, op.opcode, ppu.cia); } diff --git a/rpcs3/Emu/Cell/PPUInterpreter.h b/rpcs3/Emu/Cell/PPUInterpreter.h index e1c54db3cc..2478f497cb 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.h +++ b/rpcs3/Emu/Cell/PPUInterpreter.h @@ -2,392 +2,392 @@ #include "PPUOpcodes.h" -class PPUThread; +class ppu_thread; struct ppu_interpreter { - static bool MFVSCR(PPUThread&, ppu_opcode_t); - static bool MTVSCR(PPUThread&, ppu_opcode_t); - static bool VADDCUW(PPUThread&, ppu_opcode_t); - static bool VADDFP(PPUThread&, ppu_opcode_t); - static bool VADDSBS(PPUThread&, ppu_opcode_t); - static bool VADDSHS(PPUThread&, ppu_opcode_t); - static bool VADDSWS(PPUThread&, ppu_opcode_t); - static bool VADDUBM(PPUThread&, ppu_opcode_t); - static bool VADDUBS(PPUThread&, ppu_opcode_t); - static bool VADDUHM(PPUThread&, ppu_opcode_t); - static bool VADDUHS(PPUThread&, ppu_opcode_t); - static bool VADDUWM(PPUThread&, ppu_opcode_t); - static bool VADDUWS(PPUThread&, ppu_opcode_t); - static bool VAND(PPUThread&, ppu_opcode_t); - static bool VANDC(PPUThread&, ppu_opcode_t); - static bool VAVGSB(PPUThread&, ppu_opcode_t); - static bool VAVGSH(PPUThread&, ppu_opcode_t); - static bool VAVGSW(PPUThread&, ppu_opcode_t); - static bool VAVGUB(PPUThread&, ppu_opcode_t); - static bool VAVGUH(PPUThread&, ppu_opcode_t); - static bool VAVGUW(PPUThread&, ppu_opcode_t); - static bool VCFSX(PPUThread&, ppu_opcode_t); - static bool VCFUX(PPUThread&, ppu_opcode_t); - static bool VCMPBFP(PPUThread&, ppu_opcode_t); - static bool VCMPEQFP(PPUThread&, ppu_opcode_t); - static bool VCMPEQUB(PPUThread&, ppu_opcode_t); - static bool VCMPEQUH(PPUThread&, ppu_opcode_t); - static bool VCMPEQUW(PPUThread&, ppu_opcode_t); - static bool VCMPGEFP(PPUThread&, ppu_opcode_t); - static bool VCMPGTFP(PPUThread&, ppu_opcode_t); - static bool VCMPGTSB(PPUThread&, ppu_opcode_t); - static bool VCMPGTSH(PPUThread&, ppu_opcode_t); - static bool VCMPGTSW(PPUThread&, ppu_opcode_t); - static bool VCMPGTUB(PPUThread&, ppu_opcode_t); - static bool VCMPGTUH(PPUThread&, ppu_opcode_t); - static bool VCMPGTUW(PPUThread&, ppu_opcode_t); - static bool VCTSXS(PPUThread&, ppu_opcode_t); - static bool VCTUXS(PPUThread&, ppu_opcode_t); - static bool VEXPTEFP(PPUThread&, ppu_opcode_t); - static bool VLOGEFP(PPUThread&, ppu_opcode_t); - static bool VMADDFP(PPUThread&, ppu_opcode_t); - static bool VMAXFP(PPUThread&, ppu_opcode_t); - static bool VMAXSB(PPUThread&, ppu_opcode_t); - static bool VMAXSH(PPUThread&, ppu_opcode_t); - static bool VMAXSW(PPUThread&, ppu_opcode_t); - static bool VMAXUB(PPUThread&, ppu_opcode_t); - static bool VMAXUH(PPUThread&, ppu_opcode_t); - static bool VMAXUW(PPUThread&, ppu_opcode_t); - static bool VMHADDSHS(PPUThread&, ppu_opcode_t); - static bool VMHRADDSHS(PPUThread&, ppu_opcode_t); - static bool VMINFP(PPUThread&, ppu_opcode_t); - static bool VMINSB(PPUThread&, ppu_opcode_t); - static bool VMINSH(PPUThread&, ppu_opcode_t); - static bool VMINSW(PPUThread&, ppu_opcode_t); - static bool VMINUB(PPUThread&, ppu_opcode_t); - static bool VMINUH(PPUThread&, ppu_opcode_t); - static bool VMINUW(PPUThread&, ppu_opcode_t); - static bool VMLADDUHM(PPUThread&, ppu_opcode_t); - static bool VMRGHB(PPUThread&, ppu_opcode_t); - static bool VMRGHH(PPUThread&, ppu_opcode_t); - static bool VMRGHW(PPUThread&, ppu_opcode_t); - static bool VMRGLB(PPUThread&, ppu_opcode_t); - static bool VMRGLH(PPUThread&, ppu_opcode_t); - static bool VMRGLW(PPUThread&, ppu_opcode_t); - static bool VMSUMMBM(PPUThread&, ppu_opcode_t); - static bool VMSUMSHM(PPUThread&, ppu_opcode_t); - static bool VMSUMSHS(PPUThread&, ppu_opcode_t); - static bool VMSUMUBM(PPUThread&, ppu_opcode_t); - static bool VMSUMUHM(PPUThread&, ppu_opcode_t); - static bool VMSUMUHS(PPUThread&, ppu_opcode_t); - static bool VMULESB(PPUThread&, ppu_opcode_t); - static bool VMULESH(PPUThread&, ppu_opcode_t); - static bool VMULEUB(PPUThread&, ppu_opcode_t); - static bool VMULEUH(PPUThread&, ppu_opcode_t); - static bool VMULOSB(PPUThread&, ppu_opcode_t); - static bool VMULOSH(PPUThread&, ppu_opcode_t); - static bool VMULOUB(PPUThread&, ppu_opcode_t); - static bool VMULOUH(PPUThread&, ppu_opcode_t); - static bool VNMSUBFP(PPUThread&, ppu_opcode_t); - static bool VNOR(PPUThread&, ppu_opcode_t); - static bool VOR(PPUThread&, ppu_opcode_t); - static bool VPERM(PPUThread&, ppu_opcode_t); - static bool VPKPX(PPUThread&, ppu_opcode_t); - static bool VPKSHSS(PPUThread&, ppu_opcode_t); - static bool VPKSHUS(PPUThread&, ppu_opcode_t); - static bool VPKSWSS(PPUThread&, ppu_opcode_t); - static bool VPKSWUS(PPUThread&, ppu_opcode_t); - static bool VPKUHUM(PPUThread&, ppu_opcode_t); - static bool VPKUHUS(PPUThread&, ppu_opcode_t); - static bool VPKUWUM(PPUThread&, ppu_opcode_t); - static bool VPKUWUS(PPUThread&, ppu_opcode_t); - static bool VREFP(PPUThread&, ppu_opcode_t); - static bool VRFIM(PPUThread&, ppu_opcode_t); - static bool VRFIN(PPUThread&, ppu_opcode_t); - static bool VRFIP(PPUThread&, ppu_opcode_t); - static bool VRFIZ(PPUThread&, ppu_opcode_t); - static bool VRLB(PPUThread&, ppu_opcode_t); - static bool VRLH(PPUThread&, ppu_opcode_t); - static bool VRLW(PPUThread&, ppu_opcode_t); - static bool VRSQRTEFP(PPUThread&, ppu_opcode_t); - static bool VSEL(PPUThread&, ppu_opcode_t); - static bool VSL(PPUThread&, ppu_opcode_t); - static bool VSLB(PPUThread&, ppu_opcode_t); - static bool VSLDOI(PPUThread&, ppu_opcode_t); - static bool VSLH(PPUThread&, ppu_opcode_t); - static bool VSLO(PPUThread&, ppu_opcode_t); - static bool VSLW(PPUThread&, ppu_opcode_t); - static bool VSPLTB(PPUThread&, ppu_opcode_t); - static bool VSPLTH(PPUThread&, ppu_opcode_t); - static bool VSPLTISB(PPUThread&, ppu_opcode_t); - static bool VSPLTISH(PPUThread&, ppu_opcode_t); - static bool VSPLTISW(PPUThread&, ppu_opcode_t); - static bool VSPLTW(PPUThread&, ppu_opcode_t); - static bool VSR(PPUThread&, ppu_opcode_t); - static bool VSRAB(PPUThread&, ppu_opcode_t); - static bool VSRAH(PPUThread&, ppu_opcode_t); - static bool VSRAW(PPUThread&, ppu_opcode_t); - static bool VSRB(PPUThread&, ppu_opcode_t); - static bool VSRH(PPUThread&, ppu_opcode_t); - static bool VSRO(PPUThread&, ppu_opcode_t); - static bool VSRW(PPUThread&, ppu_opcode_t); - static bool VSUBCUW(PPUThread&, ppu_opcode_t); - static bool VSUBFP(PPUThread&, ppu_opcode_t); - static bool VSUBSBS(PPUThread&, ppu_opcode_t); - static bool VSUBSHS(PPUThread&, ppu_opcode_t); - static bool VSUBSWS(PPUThread&, ppu_opcode_t); - static bool VSUBUBM(PPUThread&, ppu_opcode_t); - static bool VSUBUBS(PPUThread&, ppu_opcode_t); - static bool VSUBUHM(PPUThread&, ppu_opcode_t); - static bool VSUBUHS(PPUThread&, ppu_opcode_t); - static bool VSUBUWM(PPUThread&, ppu_opcode_t); - static bool VSUBUWS(PPUThread&, ppu_opcode_t); - static bool VSUMSWS(PPUThread&, ppu_opcode_t); - static bool VSUM2SWS(PPUThread&, ppu_opcode_t); - static bool VSUM4SBS(PPUThread&, ppu_opcode_t); - static bool VSUM4SHS(PPUThread&, ppu_opcode_t); - static bool VSUM4UBS(PPUThread&, ppu_opcode_t); - static bool VUPKHPX(PPUThread&, ppu_opcode_t); - static bool VUPKHSB(PPUThread&, ppu_opcode_t); - static bool VUPKHSH(PPUThread&, ppu_opcode_t); - static bool VUPKLPX(PPUThread&, ppu_opcode_t); - static bool VUPKLSB(PPUThread&, ppu_opcode_t); - static bool VUPKLSH(PPUThread&, ppu_opcode_t); - static bool VXOR(PPUThread&, ppu_opcode_t); - static bool TDI(PPUThread&, ppu_opcode_t); - static bool TWI(PPUThread&, ppu_opcode_t); - static bool MULLI(PPUThread&, ppu_opcode_t); - static bool SUBFIC(PPUThread&, ppu_opcode_t); - static bool CMPLI(PPUThread&, ppu_opcode_t); - static bool CMPI(PPUThread&, ppu_opcode_t); - static bool ADDIC(PPUThread&, ppu_opcode_t); - static bool ADDI(PPUThread&, ppu_opcode_t); - static bool ADDIS(PPUThread&, ppu_opcode_t); - static bool BC(PPUThread&, ppu_opcode_t); - static bool HACK(PPUThread&, ppu_opcode_t); - static bool SC(PPUThread&, ppu_opcode_t); - static bool B(PPUThread&, ppu_opcode_t); - static bool MCRF(PPUThread&, ppu_opcode_t); - static bool BCLR(PPUThread&, ppu_opcode_t); - static bool CRNOR(PPUThread&, ppu_opcode_t); - static bool CRANDC(PPUThread&, ppu_opcode_t); - static bool ISYNC(PPUThread&, ppu_opcode_t); - static bool CRXOR(PPUThread&, ppu_opcode_t); - static bool CRNAND(PPUThread&, ppu_opcode_t); - static bool CRAND(PPUThread&, ppu_opcode_t); - static bool CREQV(PPUThread&, ppu_opcode_t); - static bool CRORC(PPUThread&, ppu_opcode_t); - static bool CROR(PPUThread&, ppu_opcode_t); - static bool BCCTR(PPUThread&, ppu_opcode_t); - static bool RLWIMI(PPUThread&, ppu_opcode_t); - static bool RLWINM(PPUThread&, ppu_opcode_t); - static bool RLWNM(PPUThread&, ppu_opcode_t); - static bool ORI(PPUThread&, ppu_opcode_t); - static bool ORIS(PPUThread&, ppu_opcode_t); - static bool XORI(PPUThread&, ppu_opcode_t); - static bool XORIS(PPUThread&, ppu_opcode_t); - static bool ANDI(PPUThread&, ppu_opcode_t); - static bool ANDIS(PPUThread&, ppu_opcode_t); - static bool RLDICL(PPUThread&, ppu_opcode_t); - static bool RLDICR(PPUThread&, ppu_opcode_t); - static bool RLDIC(PPUThread&, ppu_opcode_t); - static bool RLDIMI(PPUThread&, ppu_opcode_t); - static bool RLDCL(PPUThread&, ppu_opcode_t); - static bool RLDCR(PPUThread&, ppu_opcode_t); - static bool CMP(PPUThread&, ppu_opcode_t); - static bool TW(PPUThread&, ppu_opcode_t); - static bool LVSL(PPUThread&, ppu_opcode_t); - static bool LVEBX(PPUThread&, ppu_opcode_t); - static bool SUBFC(PPUThread&, ppu_opcode_t); - static bool MULHDU(PPUThread&, ppu_opcode_t); - static bool ADDC(PPUThread&, ppu_opcode_t); - static bool MULHWU(PPUThread&, ppu_opcode_t); - static bool MFOCRF(PPUThread&, ppu_opcode_t); - static bool LWARX(PPUThread&, ppu_opcode_t); - static bool LDX(PPUThread&, ppu_opcode_t); - static bool LWZX(PPUThread&, ppu_opcode_t); - static bool SLW(PPUThread&, ppu_opcode_t); - static bool CNTLZW(PPUThread&, ppu_opcode_t); - static bool SLD(PPUThread&, ppu_opcode_t); - static bool AND(PPUThread&, ppu_opcode_t); - static bool CMPL(PPUThread&, ppu_opcode_t); - static bool LVSR(PPUThread&, ppu_opcode_t); - static bool LVEHX(PPUThread&, ppu_opcode_t); - static bool SUBF(PPUThread&, ppu_opcode_t); - static bool LDUX(PPUThread&, ppu_opcode_t); - static bool DCBST(PPUThread&, ppu_opcode_t); - static bool LWZUX(PPUThread&, ppu_opcode_t); - static bool CNTLZD(PPUThread&, ppu_opcode_t); - static bool ANDC(PPUThread&, ppu_opcode_t); - static bool TD(PPUThread&, ppu_opcode_t); - static bool LVEWX(PPUThread&, ppu_opcode_t); - static bool MULHD(PPUThread&, ppu_opcode_t); - static bool MULHW(PPUThread&, ppu_opcode_t); - static bool LDARX(PPUThread&, ppu_opcode_t); - static bool DCBF(PPUThread&, ppu_opcode_t); - static bool LBZX(PPUThread&, ppu_opcode_t); - static bool LVX(PPUThread&, ppu_opcode_t); - static bool NEG(PPUThread&, ppu_opcode_t); - static bool LBZUX(PPUThread&, ppu_opcode_t); - static bool NOR(PPUThread&, ppu_opcode_t); - static bool STVEBX(PPUThread&, ppu_opcode_t); - static bool SUBFE(PPUThread&, ppu_opcode_t); - static bool ADDE(PPUThread&, ppu_opcode_t); - static bool MTOCRF(PPUThread&, ppu_opcode_t); - static bool STDX(PPUThread&, ppu_opcode_t); - static bool STWCX(PPUThread&, ppu_opcode_t); - static bool STWX(PPUThread&, ppu_opcode_t); - static bool STVEHX(PPUThread&, ppu_opcode_t); - static bool STDUX(PPUThread&, ppu_opcode_t); - static bool STWUX(PPUThread&, ppu_opcode_t); - static bool STVEWX(PPUThread&, ppu_opcode_t); - static bool SUBFZE(PPUThread&, ppu_opcode_t); - static bool ADDZE(PPUThread&, ppu_opcode_t); - static bool STDCX(PPUThread&, ppu_opcode_t); - static bool STBX(PPUThread&, ppu_opcode_t); - static bool STVX(PPUThread&, ppu_opcode_t); - static bool MULLD(PPUThread&, ppu_opcode_t); - static bool SUBFME(PPUThread&, ppu_opcode_t); - static bool ADDME(PPUThread&, ppu_opcode_t); - static bool MULLW(PPUThread&, ppu_opcode_t); - static bool DCBTST(PPUThread&, ppu_opcode_t); - static bool STBUX(PPUThread&, ppu_opcode_t); - static bool ADD(PPUThread&, ppu_opcode_t); - static bool DCBT(PPUThread&, ppu_opcode_t); - static bool LHZX(PPUThread&, ppu_opcode_t); - static bool EQV(PPUThread&, ppu_opcode_t); - static bool ECIWX(PPUThread&, ppu_opcode_t); - static bool LHZUX(PPUThread&, ppu_opcode_t); - static bool XOR(PPUThread&, ppu_opcode_t); - static bool MFSPR(PPUThread&, ppu_opcode_t); - static bool LWAX(PPUThread&, ppu_opcode_t); - static bool DST(PPUThread&, ppu_opcode_t); - static bool LHAX(PPUThread&, ppu_opcode_t); - static bool LVXL(PPUThread&, ppu_opcode_t); - static bool MFTB(PPUThread&, ppu_opcode_t); - static bool LWAUX(PPUThread&, ppu_opcode_t); - static bool DSTST(PPUThread&, ppu_opcode_t); - static bool LHAUX(PPUThread&, ppu_opcode_t); - static bool STHX(PPUThread&, ppu_opcode_t); - static bool ORC(PPUThread&, ppu_opcode_t); - static bool ECOWX(PPUThread&, ppu_opcode_t); - static bool STHUX(PPUThread&, ppu_opcode_t); - static bool OR(PPUThread&, ppu_opcode_t); - static bool DIVDU(PPUThread&, ppu_opcode_t); - static bool DIVWU(PPUThread&, ppu_opcode_t); - static bool MTSPR(PPUThread&, ppu_opcode_t); - static bool DCBI(PPUThread&, ppu_opcode_t); - static bool NAND(PPUThread&, ppu_opcode_t); - static bool STVXL(PPUThread&, ppu_opcode_t); - static bool DIVD(PPUThread&, ppu_opcode_t); - static bool DIVW(PPUThread&, ppu_opcode_t); - static bool LVLX(PPUThread&, ppu_opcode_t); - static bool LDBRX(PPUThread&, ppu_opcode_t); - static bool LSWX(PPUThread&, ppu_opcode_t); - static bool LWBRX(PPUThread&, ppu_opcode_t); - static bool LFSX(PPUThread&, ppu_opcode_t); - static bool SRW(PPUThread&, ppu_opcode_t); - static bool SRD(PPUThread&, ppu_opcode_t); - static bool LVRX(PPUThread&, ppu_opcode_t); - static bool LSWI(PPUThread&, ppu_opcode_t); - static bool LFSUX(PPUThread&, ppu_opcode_t); - static bool SYNC(PPUThread&, ppu_opcode_t); - static bool LFDX(PPUThread&, ppu_opcode_t); - static bool LFDUX(PPUThread&, ppu_opcode_t); - static bool STVLX(PPUThread&, ppu_opcode_t); - static bool STDBRX(PPUThread&, ppu_opcode_t); - static bool STSWX(PPUThread&, ppu_opcode_t); - static bool STWBRX(PPUThread&, ppu_opcode_t); - static bool STFSX(PPUThread&, ppu_opcode_t); - static bool STVRX(PPUThread&, ppu_opcode_t); - static bool STFSUX(PPUThread&, ppu_opcode_t); - static bool STSWI(PPUThread&, ppu_opcode_t); - static bool STFDX(PPUThread&, ppu_opcode_t); - static bool STFDUX(PPUThread&, ppu_opcode_t); - static bool LVLXL(PPUThread&, ppu_opcode_t); - static bool LHBRX(PPUThread&, ppu_opcode_t); - static bool SRAW(PPUThread&, ppu_opcode_t); - static bool SRAD(PPUThread&, ppu_opcode_t); - static bool LVRXL(PPUThread&, ppu_opcode_t); - static bool DSS(PPUThread&, ppu_opcode_t); - static bool SRAWI(PPUThread&, ppu_opcode_t); - static bool SRADI(PPUThread&, ppu_opcode_t); - static bool EIEIO(PPUThread&, ppu_opcode_t); - static bool STVLXL(PPUThread&, ppu_opcode_t); - static bool STHBRX(PPUThread&, ppu_opcode_t); - static bool EXTSH(PPUThread&, ppu_opcode_t); - static bool STVRXL(PPUThread&, ppu_opcode_t); - static bool EXTSB(PPUThread&, ppu_opcode_t); - static bool STFIWX(PPUThread&, ppu_opcode_t); - static bool EXTSW(PPUThread&, ppu_opcode_t); - static bool ICBI(PPUThread&, ppu_opcode_t); - static bool DCBZ(PPUThread&, ppu_opcode_t); - static bool LWZ(PPUThread&, ppu_opcode_t); - static bool LWZU(PPUThread&, ppu_opcode_t); - static bool LBZ(PPUThread&, ppu_opcode_t); - static bool LBZU(PPUThread&, ppu_opcode_t); - static bool STW(PPUThread&, ppu_opcode_t); - static bool STWU(PPUThread&, ppu_opcode_t); - static bool STB(PPUThread&, ppu_opcode_t); - static bool STBU(PPUThread&, ppu_opcode_t); - static bool LHZ(PPUThread&, ppu_opcode_t); - static bool LHZU(PPUThread&, ppu_opcode_t); - static bool LHA(PPUThread&, ppu_opcode_t); - static bool LHAU(PPUThread&, ppu_opcode_t); - static bool STH(PPUThread&, ppu_opcode_t); - static bool STHU(PPUThread&, ppu_opcode_t); - static bool LMW(PPUThread&, ppu_opcode_t); - static bool STMW(PPUThread&, ppu_opcode_t); - static bool LFS(PPUThread&, ppu_opcode_t); - static bool LFSU(PPUThread&, ppu_opcode_t); - static bool LFD(PPUThread&, ppu_opcode_t); - static bool LFDU(PPUThread&, ppu_opcode_t); - static bool STFS(PPUThread&, ppu_opcode_t); - static bool STFSU(PPUThread&, ppu_opcode_t); - static bool STFD(PPUThread&, ppu_opcode_t); - static bool STFDU(PPUThread&, ppu_opcode_t); - static bool LD(PPUThread&, ppu_opcode_t); - static bool LDU(PPUThread&, ppu_opcode_t); - static bool LWA(PPUThread&, ppu_opcode_t); - static bool STD(PPUThread&, ppu_opcode_t); - static bool STDU(PPUThread&, ppu_opcode_t); - static bool FDIVS(PPUThread&, ppu_opcode_t); - static bool FSUBS(PPUThread&, ppu_opcode_t); - static bool FADDS(PPUThread&, ppu_opcode_t); - static bool FSQRTS(PPUThread&, ppu_opcode_t); - static bool FRES(PPUThread&, ppu_opcode_t); - static bool FMULS(PPUThread&, ppu_opcode_t); - static bool FMADDS(PPUThread&, ppu_opcode_t); - static bool FMSUBS(PPUThread&, ppu_opcode_t); - static bool FNMSUBS(PPUThread&, ppu_opcode_t); - static bool FNMADDS(PPUThread&, ppu_opcode_t); - static bool MTFSB1(PPUThread&, ppu_opcode_t); - static bool MCRFS(PPUThread&, ppu_opcode_t); - static bool MTFSB0(PPUThread&, ppu_opcode_t); - static bool MTFSFI(PPUThread&, ppu_opcode_t); - static bool MFFS(PPUThread&, ppu_opcode_t); - static bool MTFSF(PPUThread&, ppu_opcode_t); - static bool FCMPU(PPUThread&, ppu_opcode_t); - static bool FRSP(PPUThread&, ppu_opcode_t); - static bool FCTIW(PPUThread&, ppu_opcode_t); - static bool FCTIWZ(PPUThread&, ppu_opcode_t); - static bool FDIV(PPUThread&, ppu_opcode_t); - static bool FSUB(PPUThread&, ppu_opcode_t); - static bool FADD(PPUThread&, ppu_opcode_t); - static bool FSQRT(PPUThread&, ppu_opcode_t); - static bool FSEL(PPUThread&, ppu_opcode_t); - static bool FMUL(PPUThread&, ppu_opcode_t); - static bool FRSQRTE(PPUThread&, ppu_opcode_t); - static bool FMSUB(PPUThread&, ppu_opcode_t); - static bool FMADD(PPUThread&, ppu_opcode_t); - static bool FNMSUB(PPUThread&, ppu_opcode_t); - static bool FNMADD(PPUThread&, ppu_opcode_t); - static bool FCMPO(PPUThread&, ppu_opcode_t); - static bool FNEG(PPUThread&, ppu_opcode_t); - static bool FMR(PPUThread&, ppu_opcode_t); - static bool FNABS(PPUThread&, ppu_opcode_t); - static bool FABS(PPUThread&, ppu_opcode_t); - static bool FCTID(PPUThread&, ppu_opcode_t); - static bool FCTIDZ(PPUThread&, ppu_opcode_t); - static bool FCFID(PPUThread&, ppu_opcode_t); + static bool MFVSCR(ppu_thread&, ppu_opcode_t); + static bool MTVSCR(ppu_thread&, ppu_opcode_t); + static bool VADDCUW(ppu_thread&, ppu_opcode_t); + static bool VADDFP(ppu_thread&, ppu_opcode_t); + static bool VADDSBS(ppu_thread&, ppu_opcode_t); + static bool VADDSHS(ppu_thread&, ppu_opcode_t); + static bool VADDSWS(ppu_thread&, ppu_opcode_t); + static bool VADDUBM(ppu_thread&, ppu_opcode_t); + static bool VADDUBS(ppu_thread&, ppu_opcode_t); + static bool VADDUHM(ppu_thread&, ppu_opcode_t); + static bool VADDUHS(ppu_thread&, ppu_opcode_t); + static bool VADDUWM(ppu_thread&, ppu_opcode_t); + static bool VADDUWS(ppu_thread&, ppu_opcode_t); + static bool VAND(ppu_thread&, ppu_opcode_t); + static bool VANDC(ppu_thread&, ppu_opcode_t); + static bool VAVGSB(ppu_thread&, ppu_opcode_t); + static bool VAVGSH(ppu_thread&, ppu_opcode_t); + static bool VAVGSW(ppu_thread&, ppu_opcode_t); + static bool VAVGUB(ppu_thread&, ppu_opcode_t); + static bool VAVGUH(ppu_thread&, ppu_opcode_t); + static bool VAVGUW(ppu_thread&, ppu_opcode_t); + static bool VCFSX(ppu_thread&, ppu_opcode_t); + static bool VCFUX(ppu_thread&, ppu_opcode_t); + static bool VCMPBFP(ppu_thread&, ppu_opcode_t); + static bool VCMPEQFP(ppu_thread&, ppu_opcode_t); + static bool VCMPEQUB(ppu_thread&, ppu_opcode_t); + static bool VCMPEQUH(ppu_thread&, ppu_opcode_t); + static bool VCMPEQUW(ppu_thread&, ppu_opcode_t); + static bool VCMPGEFP(ppu_thread&, ppu_opcode_t); + static bool VCMPGTFP(ppu_thread&, ppu_opcode_t); + static bool VCMPGTSB(ppu_thread&, ppu_opcode_t); + static bool VCMPGTSH(ppu_thread&, ppu_opcode_t); + static bool VCMPGTSW(ppu_thread&, ppu_opcode_t); + static bool VCMPGTUB(ppu_thread&, ppu_opcode_t); + static bool VCMPGTUH(ppu_thread&, ppu_opcode_t); + static bool VCMPGTUW(ppu_thread&, ppu_opcode_t); + static bool VCTSXS(ppu_thread&, ppu_opcode_t); + static bool VCTUXS(ppu_thread&, ppu_opcode_t); + static bool VEXPTEFP(ppu_thread&, ppu_opcode_t); + static bool VLOGEFP(ppu_thread&, ppu_opcode_t); + static bool VMADDFP(ppu_thread&, ppu_opcode_t); + static bool VMAXFP(ppu_thread&, ppu_opcode_t); + static bool VMAXSB(ppu_thread&, ppu_opcode_t); + static bool VMAXSH(ppu_thread&, ppu_opcode_t); + static bool VMAXSW(ppu_thread&, ppu_opcode_t); + static bool VMAXUB(ppu_thread&, ppu_opcode_t); + static bool VMAXUH(ppu_thread&, ppu_opcode_t); + static bool VMAXUW(ppu_thread&, ppu_opcode_t); + static bool VMHADDSHS(ppu_thread&, ppu_opcode_t); + static bool VMHRADDSHS(ppu_thread&, ppu_opcode_t); + static bool VMINFP(ppu_thread&, ppu_opcode_t); + static bool VMINSB(ppu_thread&, ppu_opcode_t); + static bool VMINSH(ppu_thread&, ppu_opcode_t); + static bool VMINSW(ppu_thread&, ppu_opcode_t); + static bool VMINUB(ppu_thread&, ppu_opcode_t); + static bool VMINUH(ppu_thread&, ppu_opcode_t); + static bool VMINUW(ppu_thread&, ppu_opcode_t); + static bool VMLADDUHM(ppu_thread&, ppu_opcode_t); + static bool VMRGHB(ppu_thread&, ppu_opcode_t); + static bool VMRGHH(ppu_thread&, ppu_opcode_t); + static bool VMRGHW(ppu_thread&, ppu_opcode_t); + static bool VMRGLB(ppu_thread&, ppu_opcode_t); + static bool VMRGLH(ppu_thread&, ppu_opcode_t); + static bool VMRGLW(ppu_thread&, ppu_opcode_t); + static bool VMSUMMBM(ppu_thread&, ppu_opcode_t); + static bool VMSUMSHM(ppu_thread&, ppu_opcode_t); + static bool VMSUMSHS(ppu_thread&, ppu_opcode_t); + static bool VMSUMUBM(ppu_thread&, ppu_opcode_t); + static bool VMSUMUHM(ppu_thread&, ppu_opcode_t); + static bool VMSUMUHS(ppu_thread&, ppu_opcode_t); + static bool VMULESB(ppu_thread&, ppu_opcode_t); + static bool VMULESH(ppu_thread&, ppu_opcode_t); + static bool VMULEUB(ppu_thread&, ppu_opcode_t); + static bool VMULEUH(ppu_thread&, ppu_opcode_t); + static bool VMULOSB(ppu_thread&, ppu_opcode_t); + static bool VMULOSH(ppu_thread&, ppu_opcode_t); + static bool VMULOUB(ppu_thread&, ppu_opcode_t); + static bool VMULOUH(ppu_thread&, ppu_opcode_t); + static bool VNMSUBFP(ppu_thread&, ppu_opcode_t); + static bool VNOR(ppu_thread&, ppu_opcode_t); + static bool VOR(ppu_thread&, ppu_opcode_t); + static bool VPERM(ppu_thread&, ppu_opcode_t); + static bool VPKPX(ppu_thread&, ppu_opcode_t); + static bool VPKSHSS(ppu_thread&, ppu_opcode_t); + static bool VPKSHUS(ppu_thread&, ppu_opcode_t); + static bool VPKSWSS(ppu_thread&, ppu_opcode_t); + static bool VPKSWUS(ppu_thread&, ppu_opcode_t); + static bool VPKUHUM(ppu_thread&, ppu_opcode_t); + static bool VPKUHUS(ppu_thread&, ppu_opcode_t); + static bool VPKUWUM(ppu_thread&, ppu_opcode_t); + static bool VPKUWUS(ppu_thread&, ppu_opcode_t); + static bool VREFP(ppu_thread&, ppu_opcode_t); + static bool VRFIM(ppu_thread&, ppu_opcode_t); + static bool VRFIN(ppu_thread&, ppu_opcode_t); + static bool VRFIP(ppu_thread&, ppu_opcode_t); + static bool VRFIZ(ppu_thread&, ppu_opcode_t); + static bool VRLB(ppu_thread&, ppu_opcode_t); + static bool VRLH(ppu_thread&, ppu_opcode_t); + static bool VRLW(ppu_thread&, ppu_opcode_t); + static bool VRSQRTEFP(ppu_thread&, ppu_opcode_t); + static bool VSEL(ppu_thread&, ppu_opcode_t); + static bool VSL(ppu_thread&, ppu_opcode_t); + static bool VSLB(ppu_thread&, ppu_opcode_t); + static bool VSLDOI(ppu_thread&, ppu_opcode_t); + static bool VSLH(ppu_thread&, ppu_opcode_t); + static bool VSLO(ppu_thread&, ppu_opcode_t); + static bool VSLW(ppu_thread&, ppu_opcode_t); + static bool VSPLTB(ppu_thread&, ppu_opcode_t); + static bool VSPLTH(ppu_thread&, ppu_opcode_t); + static bool VSPLTISB(ppu_thread&, ppu_opcode_t); + static bool VSPLTISH(ppu_thread&, ppu_opcode_t); + static bool VSPLTISW(ppu_thread&, ppu_opcode_t); + static bool VSPLTW(ppu_thread&, ppu_opcode_t); + static bool VSR(ppu_thread&, ppu_opcode_t); + static bool VSRAB(ppu_thread&, ppu_opcode_t); + static bool VSRAH(ppu_thread&, ppu_opcode_t); + static bool VSRAW(ppu_thread&, ppu_opcode_t); + static bool VSRB(ppu_thread&, ppu_opcode_t); + static bool VSRH(ppu_thread&, ppu_opcode_t); + static bool VSRO(ppu_thread&, ppu_opcode_t); + static bool VSRW(ppu_thread&, ppu_opcode_t); + static bool VSUBCUW(ppu_thread&, ppu_opcode_t); + static bool VSUBFP(ppu_thread&, ppu_opcode_t); + static bool VSUBSBS(ppu_thread&, ppu_opcode_t); + static bool VSUBSHS(ppu_thread&, ppu_opcode_t); + static bool VSUBSWS(ppu_thread&, ppu_opcode_t); + static bool VSUBUBM(ppu_thread&, ppu_opcode_t); + static bool VSUBUBS(ppu_thread&, ppu_opcode_t); + static bool VSUBUHM(ppu_thread&, ppu_opcode_t); + static bool VSUBUHS(ppu_thread&, ppu_opcode_t); + static bool VSUBUWM(ppu_thread&, ppu_opcode_t); + static bool VSUBUWS(ppu_thread&, ppu_opcode_t); + static bool VSUMSWS(ppu_thread&, ppu_opcode_t); + static bool VSUM2SWS(ppu_thread&, ppu_opcode_t); + static bool VSUM4SBS(ppu_thread&, ppu_opcode_t); + static bool VSUM4SHS(ppu_thread&, ppu_opcode_t); + static bool VSUM4UBS(ppu_thread&, ppu_opcode_t); + static bool VUPKHPX(ppu_thread&, ppu_opcode_t); + static bool VUPKHSB(ppu_thread&, ppu_opcode_t); + static bool VUPKHSH(ppu_thread&, ppu_opcode_t); + static bool VUPKLPX(ppu_thread&, ppu_opcode_t); + static bool VUPKLSB(ppu_thread&, ppu_opcode_t); + static bool VUPKLSH(ppu_thread&, ppu_opcode_t); + static bool VXOR(ppu_thread&, ppu_opcode_t); + static bool TDI(ppu_thread&, ppu_opcode_t); + static bool TWI(ppu_thread&, ppu_opcode_t); + static bool MULLI(ppu_thread&, ppu_opcode_t); + static bool SUBFIC(ppu_thread&, ppu_opcode_t); + static bool CMPLI(ppu_thread&, ppu_opcode_t); + static bool CMPI(ppu_thread&, ppu_opcode_t); + static bool ADDIC(ppu_thread&, ppu_opcode_t); + static bool ADDI(ppu_thread&, ppu_opcode_t); + static bool ADDIS(ppu_thread&, ppu_opcode_t); + static bool BC(ppu_thread&, ppu_opcode_t); + static bool HACK(ppu_thread&, ppu_opcode_t); + static bool SC(ppu_thread&, ppu_opcode_t); + static bool B(ppu_thread&, ppu_opcode_t); + static bool MCRF(ppu_thread&, ppu_opcode_t); + static bool BCLR(ppu_thread&, ppu_opcode_t); + static bool CRNOR(ppu_thread&, ppu_opcode_t); + static bool CRANDC(ppu_thread&, ppu_opcode_t); + static bool ISYNC(ppu_thread&, ppu_opcode_t); + static bool CRXOR(ppu_thread&, ppu_opcode_t); + static bool CRNAND(ppu_thread&, ppu_opcode_t); + static bool CRAND(ppu_thread&, ppu_opcode_t); + static bool CREQV(ppu_thread&, ppu_opcode_t); + static bool CRORC(ppu_thread&, ppu_opcode_t); + static bool CROR(ppu_thread&, ppu_opcode_t); + static bool BCCTR(ppu_thread&, ppu_opcode_t); + static bool RLWIMI(ppu_thread&, ppu_opcode_t); + static bool RLWINM(ppu_thread&, ppu_opcode_t); + static bool RLWNM(ppu_thread&, ppu_opcode_t); + static bool ORI(ppu_thread&, ppu_opcode_t); + static bool ORIS(ppu_thread&, ppu_opcode_t); + static bool XORI(ppu_thread&, ppu_opcode_t); + static bool XORIS(ppu_thread&, ppu_opcode_t); + static bool ANDI(ppu_thread&, ppu_opcode_t); + static bool ANDIS(ppu_thread&, ppu_opcode_t); + static bool RLDICL(ppu_thread&, ppu_opcode_t); + static bool RLDICR(ppu_thread&, ppu_opcode_t); + static bool RLDIC(ppu_thread&, ppu_opcode_t); + static bool RLDIMI(ppu_thread&, ppu_opcode_t); + static bool RLDCL(ppu_thread&, ppu_opcode_t); + static bool RLDCR(ppu_thread&, ppu_opcode_t); + static bool CMP(ppu_thread&, ppu_opcode_t); + static bool TW(ppu_thread&, ppu_opcode_t); + static bool LVSL(ppu_thread&, ppu_opcode_t); + static bool LVEBX(ppu_thread&, ppu_opcode_t); + static bool SUBFC(ppu_thread&, ppu_opcode_t); + static bool MULHDU(ppu_thread&, ppu_opcode_t); + static bool ADDC(ppu_thread&, ppu_opcode_t); + static bool MULHWU(ppu_thread&, ppu_opcode_t); + static bool MFOCRF(ppu_thread&, ppu_opcode_t); + static bool LWARX(ppu_thread&, ppu_opcode_t); + static bool LDX(ppu_thread&, ppu_opcode_t); + static bool LWZX(ppu_thread&, ppu_opcode_t); + static bool SLW(ppu_thread&, ppu_opcode_t); + static bool CNTLZW(ppu_thread&, ppu_opcode_t); + static bool SLD(ppu_thread&, ppu_opcode_t); + static bool AND(ppu_thread&, ppu_opcode_t); + static bool CMPL(ppu_thread&, ppu_opcode_t); + static bool LVSR(ppu_thread&, ppu_opcode_t); + static bool LVEHX(ppu_thread&, ppu_opcode_t); + static bool SUBF(ppu_thread&, ppu_opcode_t); + static bool LDUX(ppu_thread&, ppu_opcode_t); + static bool DCBST(ppu_thread&, ppu_opcode_t); + static bool LWZUX(ppu_thread&, ppu_opcode_t); + static bool CNTLZD(ppu_thread&, ppu_opcode_t); + static bool ANDC(ppu_thread&, ppu_opcode_t); + static bool TD(ppu_thread&, ppu_opcode_t); + static bool LVEWX(ppu_thread&, ppu_opcode_t); + static bool MULHD(ppu_thread&, ppu_opcode_t); + static bool MULHW(ppu_thread&, ppu_opcode_t); + static bool LDARX(ppu_thread&, ppu_opcode_t); + static bool DCBF(ppu_thread&, ppu_opcode_t); + static bool LBZX(ppu_thread&, ppu_opcode_t); + static bool LVX(ppu_thread&, ppu_opcode_t); + static bool NEG(ppu_thread&, ppu_opcode_t); + static bool LBZUX(ppu_thread&, ppu_opcode_t); + static bool NOR(ppu_thread&, ppu_opcode_t); + static bool STVEBX(ppu_thread&, ppu_opcode_t); + static bool SUBFE(ppu_thread&, ppu_opcode_t); + static bool ADDE(ppu_thread&, ppu_opcode_t); + static bool MTOCRF(ppu_thread&, ppu_opcode_t); + static bool STDX(ppu_thread&, ppu_opcode_t); + static bool STWCX(ppu_thread&, ppu_opcode_t); + static bool STWX(ppu_thread&, ppu_opcode_t); + static bool STVEHX(ppu_thread&, ppu_opcode_t); + static bool STDUX(ppu_thread&, ppu_opcode_t); + static bool STWUX(ppu_thread&, ppu_opcode_t); + static bool STVEWX(ppu_thread&, ppu_opcode_t); + static bool SUBFZE(ppu_thread&, ppu_opcode_t); + static bool ADDZE(ppu_thread&, ppu_opcode_t); + static bool STDCX(ppu_thread&, ppu_opcode_t); + static bool STBX(ppu_thread&, ppu_opcode_t); + static bool STVX(ppu_thread&, ppu_opcode_t); + static bool MULLD(ppu_thread&, ppu_opcode_t); + static bool SUBFME(ppu_thread&, ppu_opcode_t); + static bool ADDME(ppu_thread&, ppu_opcode_t); + static bool MULLW(ppu_thread&, ppu_opcode_t); + static bool DCBTST(ppu_thread&, ppu_opcode_t); + static bool STBUX(ppu_thread&, ppu_opcode_t); + static bool ADD(ppu_thread&, ppu_opcode_t); + static bool DCBT(ppu_thread&, ppu_opcode_t); + static bool LHZX(ppu_thread&, ppu_opcode_t); + static bool EQV(ppu_thread&, ppu_opcode_t); + static bool ECIWX(ppu_thread&, ppu_opcode_t); + static bool LHZUX(ppu_thread&, ppu_opcode_t); + static bool XOR(ppu_thread&, ppu_opcode_t); + static bool MFSPR(ppu_thread&, ppu_opcode_t); + static bool LWAX(ppu_thread&, ppu_opcode_t); + static bool DST(ppu_thread&, ppu_opcode_t); + static bool LHAX(ppu_thread&, ppu_opcode_t); + static bool LVXL(ppu_thread&, ppu_opcode_t); + static bool MFTB(ppu_thread&, ppu_opcode_t); + static bool LWAUX(ppu_thread&, ppu_opcode_t); + static bool DSTST(ppu_thread&, ppu_opcode_t); + static bool LHAUX(ppu_thread&, ppu_opcode_t); + static bool STHX(ppu_thread&, ppu_opcode_t); + static bool ORC(ppu_thread&, ppu_opcode_t); + static bool ECOWX(ppu_thread&, ppu_opcode_t); + static bool STHUX(ppu_thread&, ppu_opcode_t); + static bool OR(ppu_thread&, ppu_opcode_t); + static bool DIVDU(ppu_thread&, ppu_opcode_t); + static bool DIVWU(ppu_thread&, ppu_opcode_t); + static bool MTSPR(ppu_thread&, ppu_opcode_t); + static bool DCBI(ppu_thread&, ppu_opcode_t); + static bool NAND(ppu_thread&, ppu_opcode_t); + static bool STVXL(ppu_thread&, ppu_opcode_t); + static bool DIVD(ppu_thread&, ppu_opcode_t); + static bool DIVW(ppu_thread&, ppu_opcode_t); + static bool LVLX(ppu_thread&, ppu_opcode_t); + static bool LDBRX(ppu_thread&, ppu_opcode_t); + static bool LSWX(ppu_thread&, ppu_opcode_t); + static bool LWBRX(ppu_thread&, ppu_opcode_t); + static bool LFSX(ppu_thread&, ppu_opcode_t); + static bool SRW(ppu_thread&, ppu_opcode_t); + static bool SRD(ppu_thread&, ppu_opcode_t); + static bool LVRX(ppu_thread&, ppu_opcode_t); + static bool LSWI(ppu_thread&, ppu_opcode_t); + static bool LFSUX(ppu_thread&, ppu_opcode_t); + static bool SYNC(ppu_thread&, ppu_opcode_t); + static bool LFDX(ppu_thread&, ppu_opcode_t); + static bool LFDUX(ppu_thread&, ppu_opcode_t); + static bool STVLX(ppu_thread&, ppu_opcode_t); + static bool STDBRX(ppu_thread&, ppu_opcode_t); + static bool STSWX(ppu_thread&, ppu_opcode_t); + static bool STWBRX(ppu_thread&, ppu_opcode_t); + static bool STFSX(ppu_thread&, ppu_opcode_t); + static bool STVRX(ppu_thread&, ppu_opcode_t); + static bool STFSUX(ppu_thread&, ppu_opcode_t); + static bool STSWI(ppu_thread&, ppu_opcode_t); + static bool STFDX(ppu_thread&, ppu_opcode_t); + static bool STFDUX(ppu_thread&, ppu_opcode_t); + static bool LVLXL(ppu_thread&, ppu_opcode_t); + static bool LHBRX(ppu_thread&, ppu_opcode_t); + static bool SRAW(ppu_thread&, ppu_opcode_t); + static bool SRAD(ppu_thread&, ppu_opcode_t); + static bool LVRXL(ppu_thread&, ppu_opcode_t); + static bool DSS(ppu_thread&, ppu_opcode_t); + static bool SRAWI(ppu_thread&, ppu_opcode_t); + static bool SRADI(ppu_thread&, ppu_opcode_t); + static bool EIEIO(ppu_thread&, ppu_opcode_t); + static bool STVLXL(ppu_thread&, ppu_opcode_t); + static bool STHBRX(ppu_thread&, ppu_opcode_t); + static bool EXTSH(ppu_thread&, ppu_opcode_t); + static bool STVRXL(ppu_thread&, ppu_opcode_t); + static bool EXTSB(ppu_thread&, ppu_opcode_t); + static bool STFIWX(ppu_thread&, ppu_opcode_t); + static bool EXTSW(ppu_thread&, ppu_opcode_t); + static bool ICBI(ppu_thread&, ppu_opcode_t); + static bool DCBZ(ppu_thread&, ppu_opcode_t); + static bool LWZ(ppu_thread&, ppu_opcode_t); + static bool LWZU(ppu_thread&, ppu_opcode_t); + static bool LBZ(ppu_thread&, ppu_opcode_t); + static bool LBZU(ppu_thread&, ppu_opcode_t); + static bool STW(ppu_thread&, ppu_opcode_t); + static bool STWU(ppu_thread&, ppu_opcode_t); + static bool STB(ppu_thread&, ppu_opcode_t); + static bool STBU(ppu_thread&, ppu_opcode_t); + static bool LHZ(ppu_thread&, ppu_opcode_t); + static bool LHZU(ppu_thread&, ppu_opcode_t); + static bool LHA(ppu_thread&, ppu_opcode_t); + static bool LHAU(ppu_thread&, ppu_opcode_t); + static bool STH(ppu_thread&, ppu_opcode_t); + static bool STHU(ppu_thread&, ppu_opcode_t); + static bool LMW(ppu_thread&, ppu_opcode_t); + static bool STMW(ppu_thread&, ppu_opcode_t); + static bool LFS(ppu_thread&, ppu_opcode_t); + static bool LFSU(ppu_thread&, ppu_opcode_t); + static bool LFD(ppu_thread&, ppu_opcode_t); + static bool LFDU(ppu_thread&, ppu_opcode_t); + static bool STFS(ppu_thread&, ppu_opcode_t); + static bool STFSU(ppu_thread&, ppu_opcode_t); + static bool STFD(ppu_thread&, ppu_opcode_t); + static bool STFDU(ppu_thread&, ppu_opcode_t); + static bool LD(ppu_thread&, ppu_opcode_t); + static bool LDU(ppu_thread&, ppu_opcode_t); + static bool LWA(ppu_thread&, ppu_opcode_t); + static bool STD(ppu_thread&, ppu_opcode_t); + static bool STDU(ppu_thread&, ppu_opcode_t); + static bool FDIVS(ppu_thread&, ppu_opcode_t); + static bool FSUBS(ppu_thread&, ppu_opcode_t); + static bool FADDS(ppu_thread&, ppu_opcode_t); + static bool FSQRTS(ppu_thread&, ppu_opcode_t); + static bool FRES(ppu_thread&, ppu_opcode_t); + static bool FMULS(ppu_thread&, ppu_opcode_t); + static bool FMADDS(ppu_thread&, ppu_opcode_t); + static bool FMSUBS(ppu_thread&, ppu_opcode_t); + static bool FNMSUBS(ppu_thread&, ppu_opcode_t); + static bool FNMADDS(ppu_thread&, ppu_opcode_t); + static bool MTFSB1(ppu_thread&, ppu_opcode_t); + static bool MCRFS(ppu_thread&, ppu_opcode_t); + static bool MTFSB0(ppu_thread&, ppu_opcode_t); + static bool MTFSFI(ppu_thread&, ppu_opcode_t); + static bool MFFS(ppu_thread&, ppu_opcode_t); + static bool MTFSF(ppu_thread&, ppu_opcode_t); + static bool FCMPU(ppu_thread&, ppu_opcode_t); + static bool FRSP(ppu_thread&, ppu_opcode_t); + static bool FCTIW(ppu_thread&, ppu_opcode_t); + static bool FCTIWZ(ppu_thread&, ppu_opcode_t); + static bool FDIV(ppu_thread&, ppu_opcode_t); + static bool FSUB(ppu_thread&, ppu_opcode_t); + static bool FADD(ppu_thread&, ppu_opcode_t); + static bool FSQRT(ppu_thread&, ppu_opcode_t); + static bool FSEL(ppu_thread&, ppu_opcode_t); + static bool FMUL(ppu_thread&, ppu_opcode_t); + static bool FRSQRTE(ppu_thread&, ppu_opcode_t); + static bool FMSUB(ppu_thread&, ppu_opcode_t); + static bool FMADD(ppu_thread&, ppu_opcode_t); + static bool FNMSUB(ppu_thread&, ppu_opcode_t); + static bool FNMADD(ppu_thread&, ppu_opcode_t); + static bool FCMPO(ppu_thread&, ppu_opcode_t); + static bool FNEG(ppu_thread&, ppu_opcode_t); + static bool FMR(ppu_thread&, ppu_opcode_t); + static bool FNABS(ppu_thread&, ppu_opcode_t); + static bool FABS(ppu_thread&, ppu_opcode_t); + static bool FCTID(ppu_thread&, ppu_opcode_t); + static bool FCTIDZ(ppu_thread&, ppu_opcode_t); + static bool FCFID(ppu_thread&, ppu_opcode_t); - static bool UNK(PPUThread&, ppu_opcode_t); + static bool UNK(ppu_thread&, ppu_opcode_t); }; struct ppu_interpreter_precise final : ppu_interpreter diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index d4abcf07cd..dda1c48914 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -114,9 +114,9 @@ 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); +extern void sys_initialize_tls(ppu_thread&, u64, u32, u32, u32); -extern void ppu_initialize(const std::string& name, const std::vector& set, u32 entry); +extern void ppu_initialize(const std::string& name, const std::vector& set); extern u32 g_ps3_sdk_version; @@ -139,17 +139,17 @@ extern std::string ppu_get_module_function_name(u32 index) return fmt::format(".%u", index); } -extern void ppu_execute_function(PPUThread& ppu, u32 index) +extern void ppu_execute_function(ppu_thread& 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 (debug::autopause::pause_function(g_ppu_fnid_cache[index]) && ppu.check_state()) throw cpu_state::ret; if (const auto func = g_ppu_function_cache[index]) { func(ppu); - LOG_TRACE(HLE, "'%s' finished, r3=0x%llx", ppu_get_module_function_name(index), ppu.GPR[3]); + LOG_TRACE(HLE, "'%s' finished, r3=0x%llx", ppu_get_module_function_name(index), ppu.gpr[3]); return; } } @@ -783,7 +783,7 @@ std::shared_ptr ppu_load_prx(const ppu_prx_object& elf) const u32 addr = vm::cast(s.sh_addr); const u32 size = vm::cast(s.sh_size); - if (s.sh_type == 1 && addr && size) + if (s.sh_type == 1 && addr && size) // TODO: some sections with addr=0 are valid { for (auto i = 0; i < segments.size(); i++) { @@ -1138,7 +1138,15 @@ void ppu_load_exec(const ppu_exec_object& elf) // Add functions exec_set.insert(exec_set.end(), prx->funcs.begin(), prx->funcs.end()); - ppu_validate(lle_dir + '/' + name, prx->funcs, prx->funcs[0].addr); + if (prx->funcs.empty()) + { + LOG_FATAL(LOADER, "Module %s has no functions!", name); + } + else + { + // TODO: fix arguments + ppu_validate(lle_dir + '/' + name, prx->funcs, prx->funcs[0].addr); + } } else { @@ -1279,100 +1287,19 @@ void ppu_load_exec(const ppu_exec_object& elf) exec_set.emplace_back(pair); } - // TODO: adjust for liblv2 loading option - using namespace ppu_instructions; - - static const int branch_size = 10 * 4; - - auto make_branch = [](vm::ptr& ptr, u32 addr, bool last) - { - 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++ = last ? BCTR() : 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, false); - } - - // 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, static_cast(elf.header.e_entry), false); - - // Register entry function (addr, size) - ppu_function entry_func; - entry_func.addr = entry.addr() & -0x1000; - entry_func.size = entry.addr() & 0xfff; - entry_func.attr += ppu_attr::entry_point; - exec_set.emplace_back(entry_func); - - // Initialize recompiler - ppu_initialize("", exec_set, static_cast(elf.header.e_entry)); + // Initialize interpreter/recompiler + ppu_initialize("", exec_set); // Set SDK version g_ps3_sdk_version = sdk_version; - auto ppu = idm::make_ptr("main_thread"); - - ppu->pc = entry.addr() & -0x1000; - ppu->stack_size = std::max(primary_stacksize, 0x4000); - ppu->prio = primary_prio; - ppu->cpu_init(); - - ppu->GPR[2] = 0xdeadbeef; // rtoc - ppu->GPR[11] = 0xabadcafe; // OPD ??? - ppu->GPR[12] = malloc_pagesize; - + // Initialize process arguments 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); @@ -1383,15 +1310,43 @@ void ppu_load_exec(const ppu_exec_object& elf) *argv++ = arg_addr; } - // Arguments for sys_initialize_tls() - ppu->GPR[7] = ppu->id; - ppu->GPR[8] = tls_vaddr; - ppu->GPR[9] = tls_fsize; - ppu->GPR[10] = tls_vsize; + argv -= args.size(); - //ppu->state += cpu_state::interrupt; + // Initialize main thread + auto ppu = idm::make_ptr("main_thread", primary_prio, primary_stacksize); - // Set memory protection + // TODO: adjust for liblv2 loading option + if (!g_cfg_load_liblv2) + { + // Set TLS args, call sys_initialize_tls + ppu->cmd_list + ({ + { ppu_cmd::set_args, 4 }, u64{ppu->id}, u64{tls_vaddr}, u64{tls_fsize}, u64{tls_vsize}, + { ppu_cmd::hle_call, FIND_FUNC(sys_initialize_tls) }, + }); + } + + // Run start functions + for (u32 func : start_funcs) + { + // Reset arguments, run module entry point function + ppu->cmd_list + ({ + { ppu_cmd::set_args, 2 }, u64{0}, u64{0}, + { ppu_cmd::lle_call, func }, + }); + } + + // Set command line arguments, run entry function + ppu->cmd_list + ({ + { ppu_cmd::set_args, 8 }, u64{args.size()}, u64{argv.addr()}, u64{envp.addr()}, u64{0}, u64{ppu->id}, u64{tls_vaddr}, u64{tls_fsize}, u64{tls_vsize}, + { ppu_cmd::set_gpr, 11 }, u64{0xabadcafe}, + { ppu_cmd::set_gpr, 12 }, u64{malloc_pagesize}, + { ppu_cmd::lle_call, static_cast(elf.header.e_entry) }, + }); + + // Set actual memory protection (experimental) for (const auto& prog : elf.progs) { const u32 addr = static_cast(prog.p_vaddr); @@ -1399,7 +1354,7 @@ void ppu_load_exec(const ppu_exec_object& elf) if (prog.p_type == 0x1 /* LOAD */ && prog.p_memsz && (prog.p_flags & 0x2) == 0 /* W */) { - // Set memory protection to read-only where necessary + // Set memory protection to read-only when necessary VERIFY(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 index 9dbc922cf3..7e641dd207 100644 --- a/rpcs3/Emu/Cell/PPUModule.h +++ b/rpcs3/Emu/Cell/PPUModule.h @@ -197,7 +197,7 @@ public: // 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) +inline RT ppu_execute_function_or_callback(const char* name, ppu_thread& ppu, Args&&... args) { return Func(std::forward(args)...); } diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 20f273569c..6a2889a221 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -57,6 +57,9 @@ cfg::map_entry g_cfg_ppu_decoder(cfg::root.core, "PPU Decoder" const ppu_decoder s_ppu_interpreter_precise; const ppu_decoder s_ppu_interpreter_fast; +extern void ppu_execute_syscall(ppu_thread& ppu, u64 code); +extern void ppu_execute_function(ppu_thread& ppu, u32 index); + const auto s_ppu_compiled = static_cast(memory_helper::reserve_memory(0x100000000)); extern void ppu_register_function_at(u32 addr, ppu_function_t ptr) @@ -68,82 +71,117 @@ extern void ppu_register_function_at(u32 addr, ppu_function_t ptr) } } -std::string PPUThread::get_name() const +std::string ppu_thread::get_name() const { return fmt::format("PPU[0x%x] Thread (%s)", id, m_name); } -std::string PPUThread::dump() const +std::string ppu_thread::dump() const { - std::string ret = "Registers:\n=========\n"; + std::string ret; - 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 }); + ret += fmt::format("State: 0x%08x\n", state.load()); + ret += fmt::format("Priority: %d\n", prio); + + ret += "\nRegisters:\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, 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()); + + if (g_cfg_ppu_decoder.get() != ppu_decoder_type::llvm) + { + ret += fmt::format("CR = 0x%08x\n", cr_pack()); + ret += fmt::format("LR = 0x%llx\n", lr); + ret += fmt::format("CTR = 0x%llx\n", ctr); + ret += fmt::format("VRSAVE = 0x%08x\n", vrsave); + ret += fmt::format("XER = [CA=%u | OV=%u | SO=%u | CNT=%u]\n", xer.ca, xer.ov, xer.so, xer.cnt); + ret += fmt::format("VSCR = [SAT=%u | NJ=%u]\n", sat, nj); + ret += fmt::format("FPSCR = [FL=%u | FG=%u | FE=%u | FU=%u]\n", fpscr.fl, fpscr.fg, fpscr.fe, fpscr.fu); + + ret += "\nCall stack:\n=========\n"; + ret += fmt::format("0x%08x (0x0) called\n", cia); + const u32 stack_max = ::align(stack_addr + stack_size, 0x200) - 0x200; + for (u64 sp = vm::read64(static_cast(gpr[1])); sp >= stack_addr && sp < stack_max; sp = vm::read64(static_cast(sp))) + { + // TODO: print also function addresses + ret += fmt::format("> from 0x%08llx (0x0)\n", vm::read64(static_cast(sp + 16))); + } + } return ret; } -void PPUThread::cpu_init() -{ - if (!stack_addr) - { - if (!stack_size) - { - throw EXCEPTION("Invalid stack size"); - } - - stack_addr = vm::alloc(stack_size, vm::stack); - - if (!stack_addr) - { - throw EXCEPTION("Out of stack memory"); - } - } - - GPR[1] = align(stack_addr + stack_size, 0x200) - 0x200; -} - extern thread_local std::string(*g_tls_log_prefix)(); -void PPUThread::cpu_task() +void ppu_thread::cpu_task() { //SetHostRoundingMode(FPSCR_RN_NEAR); - return custom_task ? custom_task(*this) : fast_call(pc, static_cast(GPR[2])); + // Execute cmd_queue + while (ppu_cmd cmd = cmd_wait()) + { + const u32 pos = cmd_queue.peek() + 1; // Additional arguments start from [pos] + const u32 arg = cmd.arg2(); // 32-bit arg extracted + + switch (u32 type = cmd.arg1()) + { + case ppu_cmd::opcode: + { + cmd_pop(), s_ppu_interpreter_fast.decode(arg)(*this, {arg}); + break; + } + case ppu_cmd::set_gpr: + { + if (arg >= 32) + { + throw fmt::exception("Invalid ppu_cmd::set_gpr arg (0x%x)" HERE, arg); + } + + gpr[arg % 32] = cmd_queue[pos].load().as(); + cmd_pop(1); + break; + } + case ppu_cmd::set_args: + { + if (arg > 8) + { + throw fmt::exception("Unsupported ppu_cmd::set_args size (0x%x)" HERE, arg); + } + + for (u32 i = 0; i < arg; i++) + { + gpr[i + 3] = cmd_queue[pos + i].load().as(); + } + + cmd_pop(arg); + break; + } + case ppu_cmd::lle_call: + { + const vm::ptr opd(arg < 32 ? vm::cast(gpr[arg]) : vm::cast(arg)); + cmd_pop(), fast_call(opd[0], opd[1]); + break; + } + case ppu_cmd::hle_call: + { + cmd_pop(), ppu_execute_function(*this, arg); + break; + } + default: + { + throw fmt::exception("Unknown ppu_cmd(0x%x)" HERE, type); + } + } + } } -void PPUThread::cpu_task_main() +void ppu_thread::exec_task() { if (g_cfg_ppu_decoder.get() == ppu_decoder_type::llvm) { - return reinterpret_cast((std::uintptr_t)s_ppu_compiled[pc / 4])(*this); + return reinterpret_cast((std::uintptr_t)s_ppu_compiled[cia / 4])(*this); } - g_tls_log_prefix = [] - { - 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 @@ -159,12 +197,12 @@ void PPUThread::cpu_task_main() { if (UNLIKELY(state.load())) { - if (check_status()) return; + if (check_state()) return; } // Reinitialize { - const auto _ops = _mm_shuffle_epi8(_mm_lddqu_si128(reinterpret_cast(base + pc)), _mm_set_epi8(12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3)); + const auto _ops = _mm_shuffle_epi8(_mm_lddqu_si128(reinterpret_cast(base + cia)), _mm_set_epi8(12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3)); _op.vi = _ops; const v128 _i = v128::fromV(_mm_and_si128(_mm_or_si128(_mm_slli_epi32(_op.vi, 6), _mm_srli_epi32(_op.vi, 26)), _mm_set1_epi32(0x1ffff))); func0 = table[_i._u32[0]]; @@ -175,14 +213,14 @@ void PPUThread::cpu_task_main() while (LIKELY(func0(*this, { _op._u32[0] }))) { - if (pc += 4, LIKELY(func1(*this, { _op._u32[1] }))) + if (cia += 4, LIKELY(func1(*this, { _op._u32[1] }))) { - if (pc += 4, LIKELY(func2(*this, { _op._u32[2] }))) + if (cia += 4, LIKELY(func2(*this, { _op._u32[2] }))) { - pc += 4; + cia += 4; func0 = func3; - const auto _ops = _mm_shuffle_epi8(_mm_lddqu_si128(reinterpret_cast(base + pc + 4)), _mm_set_epi8(12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3)); + const auto _ops = _mm_shuffle_epi8(_mm_lddqu_si128(reinterpret_cast(base + cia + 4)), _mm_set_epi8(12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3)); _op.vi = _mm_alignr_epi8(_ops, _op.vi, 12); const v128 _i = v128::fromV(_mm_and_si128(_mm_or_si128(_mm_slli_epi32(_op.vi, 6), _mm_srli_epi32(_op.vi, 26)), _mm_set1_epi32(0x1ffff))); func1 = table[_i._u32[1]]; @@ -204,87 +242,7 @@ void PPUThread::cpu_task_main() constexpr auto stop_state = make_bitset(cpu_state::stop, cpu_state::exit, cpu_state::suspend); -atomic_t g_ppu_core[2]{}; - -bool PPUThread::handle_interrupt() -{ - // Reschedule and wake up a new thread, possibly this one as well. - return false; - - // Check virtual core allocation - if (g_ppu_core[0] != id && g_ppu_core[1] != id) - { - auto cpu0 = idm::get(g_ppu_core[0]); - auto cpu1 = idm::get(g_ppu_core[1]); - - if (cpu0 && cpu1) - { - if (cpu1->prio > cpu0->prio) - { - cpu0 = std::move(cpu1); - } - - // Preempt thread with the lowest priority - if (prio < cpu0->prio) - { - cpu0->state += cpu_state::interrupt; - } - } - else - { - // Try to obtain a virtual core in optimistic way - if (g_ppu_core[0].compare_and_swap_test(0, id) || g_ppu_core[1].compare_and_swap_test(0, id)) - { - state -= cpu_state::interrupt; - return true; - } - } - - return false; - } - - // Select appropriate thread - u32 top_prio = -1; - u32 selected = -1; - - idm::select([&](u32 id, PPUThread& ppu) - { - // Exclude suspended and low-priority threads - if (!ppu.state.test(stop_state) && ppu.prio < top_prio /*&& (!ppu.is_sleep() || ppu.state & cpu_state::signal)*/) - { - top_prio = ppu.prio; - selected = id; - } - }); - - // If current thread selected - if (selected == id) - { - state -= cpu_state::interrupt; - VERIFY(g_ppu_core[0] == id || g_ppu_core[1] == id); - return true; - } - - // If another thread selected - const auto thread = idm::get(selected); - - // Lend virtual core to another thread - if (thread && thread->state.test_and_reset(cpu_state::interrupt)) - { - g_ppu_core[0].compare_and_swap(id, thread->id); - g_ppu_core[1].compare_and_swap(id, thread->id); - (*thread)->lock_notify(); - } - else - { - g_ppu_core[0].compare_and_swap(id, 0); - g_ppu_core[1].compare_and_swap(id, 0); - } - - return false; -} - -PPUThread::~PPUThread() +ppu_thread::~ppu_thread() { if (stack_addr) { @@ -292,40 +250,126 @@ PPUThread::~PPUThread() } } -PPUThread::PPUThread(const std::string& name) +ppu_thread::ppu_thread(const std::string& name, u32 prio, u32 stack) : cpu_thread(cpu_type::ppu) + , prio(prio) + , stack_size(std::max(stack, 0x4000)) + , stack_addr(vm::alloc(stack_size, vm::stack)) , m_name(name) { + if (!stack_addr) + { + throw fmt::exception("Out of stack memory (size=0x%x)" HERE, stack_size); + } + + gpr[1] = ::align(stack_addr + stack_size, 0x200) - 0x200; } -be_t* PPUThread::get_stack_arg(s32 i, u64 align) +void ppu_thread::cmd_push(ppu_cmd cmd) +{ + // Reserve queue space + const u32 pos = cmd_queue.push_begin(); + + // Write single command + cmd_queue[pos] = cmd; +} + +void ppu_thread::cmd_list(std::initializer_list list) +{ + // Reserve queue space + const u32 pos = cmd_queue.push_begin(static_cast(list.size())); + + // Write command tail in relaxed manner + for (u32 i = 1; i < list.size(); i++) + { + cmd_queue[pos + i].raw() = list.begin()[i]; + } + + // Write command head after all + cmd_queue[pos] = *list.begin(); +} + +void ppu_thread::cmd_pop(u32 count) +{ + // Get current position + const u32 pos = cmd_queue.peek(); + + // Clean command buffer for command tail + for (u32 i = 1; i <= count; i++) + { + cmd_queue[pos + i].raw() = ppu_cmd{}; + } + + // Free + cmd_queue.pop_end(count + 1); +} + +ppu_cmd ppu_thread::cmd_wait() +{ + std::unique_lock lock(*this, std::defer_lock); + + while (true) + { + if (UNLIKELY(state.load())) + { + if (lock) lock.unlock(); + + if (check_state()) // check_status() requires unlocked mutex + { + return ppu_cmd{}; + } + } + + // Lightweight queue doesn't care about mutex state + if (ppu_cmd result = cmd_queue[cmd_queue.peek()].exchange(ppu_cmd{})) + { + return result; + } + + if (!lock) + { + lock.lock(); + continue; + } + + thread_ctrl::wait(); // Waiting requires locked mutex + } +} + +be_t* ppu_thread::get_stack_arg(s32 i, u64 align) { 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)); + return vm::_ptr(vm::cast((gpr[1] + 0x30 + 0x8 * (i - 1)) & (0 - align), HERE)); } -void PPUThread::fast_call(u32 addr, u32 rtoc) +void ppu_thread::fast_call(u32 addr, u32 rtoc) { - const auto old_PC = pc; - const auto old_stack = GPR[1]; - const auto old_rtoc = GPR[2]; - const auto old_LR = LR; - const auto old_task = std::move(custom_task); + const auto old_pc = cia; + const auto old_stack = gpr[1]; + const auto old_rtoc = gpr[2]; + const auto old_lr = lr; const auto old_func = last_function; + const auto old_fmt = g_tls_log_prefix; - pc = addr; - GPR[2] = rtoc; - LR = Emu.GetCPUThreadStop(); - custom_task = nullptr; + cia = addr; + gpr[2] = rtoc; + lr = Emu.GetCPUThreadStop(); last_function = nullptr; + g_tls_log_prefix = [] + { + const auto ppu = static_cast(get_current_cpu_thread()); + + return fmt::format("%s [0x%08x]", ppu->get_name(), ppu->cia); + }; + try { - cpu_task_main(); + exec_task(); - if (GPR[1] != old_stack && !state.test(cpu_state::ret) && !state.test(cpu_state::exit)) // GPR[1] shouldn't change + if (gpr[1] != old_stack && !state.test(cpu_state::ret) && !state.test(cpu_state::exit)) // gpr[1] shouldn't change { - throw fmt::exception("Stack inconsistency (addr=0x%x, rtoc=0x%x, SP=0x%llx, old=0x%llx)", addr, rtoc, GPR[1], old_stack); + throw fmt::exception("Stack inconsistency (addr=0x%x, rtoc=0x%x, SP=0x%llx, old=0x%llx)", addr, rtoc, gpr[1], old_stack); } } catch (cpu_state _s) @@ -348,25 +392,17 @@ void PPUThread::fast_call(u32 addr, u32 rtoc) state -= cpu_state::ret; - pc = old_PC; - GPR[1] = old_stack; - GPR[2] = old_rtoc; - LR = old_LR; - custom_task = std::move(old_task); + cia = old_pc; + gpr[1] = old_stack; + gpr[2] = old_rtoc; + lr = old_lr; last_function = old_func; - - //if (custom_task) - //{ - // state += cpu_state::interrupt; - // handle_interrupt(); - //} + g_tls_log_prefix = old_fmt; } const ppu_decoder s_ppu_itype; extern u64 get_timebased_time(); -extern void ppu_execute_syscall(PPUThread& ppu, u64 code); -extern void ppu_execute_function(PPUThread& ppu, u32 index); extern ppu_function_t ppu_get_syscall(u64 code); extern std::string ppu_get_syscall_name(u64 code); extern ppu_function_t ppu_get_function(u32 index); @@ -434,7 +470,7 @@ static bool adde_carry(u64 a, u64 b, bool c) #endif } -extern void ppu_initialize(const std::string& name, const std::vector& funcs, u32 entry) +extern void ppu_initialize(const std::string& name, const std::vector& funcs) { if (g_cfg_ppu_decoder.get() != ppu_decoder_type::llvm || funcs.empty()) { @@ -485,7 +521,7 @@ extern void ppu_initialize(const std::string& name, const std::vectorsetTargetTriple(Triple::normalize(sys::getProcessTriple())); // Initialize translator - std::unique_ptr translator = std::make_unique(g_llvm_ctx, module.get(), 0, entry); + std::unique_ptr translator = std::make_unique(g_llvm_ctx, module.get(), 0); // Define some types const auto _void = Type::getVoidTy(g_llvm_ctx); diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h index 4303090c0e..7bf4f1e82b 100644 --- a/rpcs3/Emu/Cell/PPUThread.h +++ b/rpcs3/Emu/Cell/PPUThread.h @@ -3,29 +3,124 @@ #include "Common.h" #include "../CPU/CPUThread.h" #include "../Memory/vm.h" +#include "Utilities/lockless.h" -class PPUThread final : public cpu_thread +// Lightweight PPU command queue element +struct ppu_cmd : any64 +{ + enum : u32 + { + none = 0, + + opcode, // Execute PPU instruction from arg + set_gpr, // Set gpr[arg] (+1 cmd) + set_args, // Set general-purpose args (+arg cmd) + lle_call, // Load addr and rtoc at *arg or *gpr[arg] and execute + hle_call, // Execute function by index (arg) + }; + + struct pair_t + { + any32 arg1; + any32 arg2; + }; + + ppu_cmd() = default; + + template + ppu_cmd(const T& value) + : any64(value) + { + } + + template + ppu_cmd(const T1& arg1, const T2& arg2) + : any64(pair_t{arg1, arg2}) + { + } + + explicit operator bool() const + { + return as() != 0; + } + + template + decltype(auto) arg1() + { + return as().arg1.as(); + } + + template + decltype(auto) arg1() const + { + return as().arg1.as(); + } + + template + decltype(auto) arg2() + { + return as().arg2.as(); + } + + template + decltype(auto) arg2() const + { + return as().arg2.as(); + } +}; + +static_assert(sizeof(ppu_cmd) == 8 && std::is_pod::value, "Incorrect ppu_cmd struct"); + +class ppu_thread : public cpu_thread { public: virtual std::string get_name() const override; virtual std::string dump() const override; - virtual void cpu_init() override; + virtual void cpu_init() override final {} virtual void cpu_task() override; - virtual void cpu_task_main(); - virtual bool handle_interrupt() override; - virtual ~PPUThread() override; + virtual ~ppu_thread() override; - PPUThread(const std::string& name); + ppu_thread(const std::string& name, u32 prio = 0, u32 stack = 0x10000); - 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 + u64 gpr[32] = {}; // General-Purpose Registers + f64 fpr[32] = {}; // Floating Point Registers + v128 vr[32] = {}; // Vector Registers + alignas(16) bool cr[32] = {}; // Condition Registers (abstract representation) + + // Pack CR bits + u32 cr_pack() const + { + u32 result{}; + + for (u32 bit : cr) + { + result = (result << 1) | bit; + } + + return result; + } + + // Unpack CR bits + void cr_unpack(u32 value) + { + for (bool& b : cr) + { + b = (value & 0x1) != 0; + value >>= 1; + } + } + + // Fixed-Point Exception Register (abstract representation) + struct + { + bool so{}; // Summary Overflow + bool ov{}; // Overflow + bool ca{}; // Carry + u8 cnt{}; // 0..6 + } + xer; + /* 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 @@ -45,7 +140,7 @@ public: Vector Convert to Fixed-Point with Saturation (vctuxs, vctsxs) 0 Indicates no saturation occurred; mtvscr can explicitly clear this bit. */ - bool SAT{}; + bool sat{}; /* Non-Java. A mode control bit that determines whether vector floating-point operations will be performed @@ -54,88 +149,47 @@ public: by Java, IEEE, and C9X standard. 1 The non-Java/non-IEEE-compliant mode is selected. If an element in a source vector register 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' + 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. */ - bool NJ{ true }; + bool nj = true; - bool FL{}; // FPSCR.FPCC.FL - bool FG{}; // FPSCR.FPCC.FG - bool FE{}; // FPSCR.FPCC.FE - bool FU{}; // FPSCR.FPCC.FU + struct // Floating-Point Status and Control Register (abstract representation) + { + bool fl{}; // FPCC.FL + bool fg{}; // FPCC.FG + bool fe{}; // FPCC.FE + bool fu{}; // FPCC.FU + } + fpscr; - u64 LR{}; // Link Register - u64 CTR{}; // Counter Register - u32 VRSAVE{}; + u32 cia{}; // Current Instruction Address + u64 lr{}; // Link Register + u64 ctr{}; // Counter Register + u32 vrsave{0xffffffff}; // VR Save Register (almost unused) - u32 pc = 0; - u32 prio = -1; // Thread priority - u32 stack_addr = 0; // Stack address - u32 stack_size = 0; // Stack size + u32 prio = 0; // Thread priority (0..3071) + const u32 stack_size; // Stack size + const u32 stack_addr; // Stack address bool is_joinable = true; bool is_joining = false; + lf_fifo, 255> cmd_queue; // Command queue for asynchronous operations. + + void cmd_push(ppu_cmd); + void cmd_list(std::initializer_list); + void cmd_pop(u32 = 0); + ppu_cmd cmd_wait(); // Empty command means caller must return, like true from cpu_thread::check_status(). + + const char* last_function{}; // Last function name for diagnosis, optimized for speed. + const std::string m_name; // Thread name - 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; - - // Pack CR bits - u32 GetCR() const - { - u32 result{}; - - for (u32 bit : CR) - { - result = (result << 1) | bit; - } - - return result; - } - - // Unpack CR bits - void SetCR(u32 value) - { - for (bool& b : CR) - { - b = (value & 0x1) != 0; - value >>= 1; - } - } - - // Set CR field - void SetCR(u32 field, bool le, bool gt, bool eq, bool so) - { - CR[field * 4 + 0] = le; - CR[field * 4 + 1] = gt; - CR[field * 4 + 2] = eq; - CR[field * 4 + 3] = so; - } - - // Set CR field for comparison - template - void SetCR(u32 field, const T& a, const T& b) - { - SetCR(field, a < b, a > b, a == b, SO); - } - - // Set overflow bit - void SetOV(const bool set) - { - OV = set; - SO |= set; - } - u64 get_next_arg(u32& g_count) { if (g_count < 8) { - return GPR[g_count++ + 3]; + return gpr[g_count++ + 3]; } else { @@ -144,6 +198,7 @@ public: } be_t* get_stack_arg(s32 i, u64 align = alignof(u64)); + void exec_task(); void fast_call(u32 addr, u32 rtoc); }; diff --git a/rpcs3/Emu/Cell/PPUTranslator.cpp b/rpcs3/Emu/Cell/PPUTranslator.cpp index d80e506a9c..3d87f8baa1 100644 --- a/rpcs3/Emu/Cell/PPUTranslator.cpp +++ b/rpcs3/Emu/Cell/PPUTranslator.cpp @@ -63,7 +63,7 @@ const ppu_decoder s_ppu_decoder; GetGpr(op.ra),\ GetGpr(op.rb))) -PPUTranslator::PPUTranslator(LLVMContext& context, Module* module, u64 base, u64 entry) +PPUTranslator::PPUTranslator(LLVMContext& context, Module* module, u64 base) : m_context(context) , m_module(module) , m_base_addr(base) @@ -74,12 +74,12 @@ PPUTranslator::PPUTranslator(LLVMContext& context, Module* module, u64 base, u64 m_base = new GlobalVariable(*module, ArrayType::get(GetType(), 0x100000000)->getPointerTo(), true, GlobalValue::ExternalLinkage, 0, "__mptr"); // Thread context struct (TODO: safer member access) - std::vector thread_struct{ArrayType::get(GetType(), OFFSET_32(PPUThread, GPR))}; + std::vector thread_struct{ArrayType::get(GetType(), OFFSET_32(ppu_thread, gpr))}; - thread_struct.insert(thread_struct.end(), 32, GetType()); // GPR[0..31] - thread_struct.insert(thread_struct.end(), 32, GetType()); // FPR[0..31] - thread_struct.insert(thread_struct.end(), 32, GetType()); // VR[0..31] - thread_struct.insert(thread_struct.end(), 32, GetType()); // CR[0..31] + thread_struct.insert(thread_struct.end(), 32, GetType()); // gpr[0..31] + thread_struct.insert(thread_struct.end(), 32, GetType()); // fpr[0..31] + thread_struct.insert(thread_struct.end(), 32, GetType()); // vr[0..31] + thread_struct.insert(thread_struct.end(), 32, GetType()); // cr[0..31] m_thread_type = StructType::create(m_context, thread_struct, "context_t"); diff --git a/rpcs3/Emu/Cell/PPUTranslator.h b/rpcs3/Emu/Cell/PPUTranslator.h index 780e9e7e81..d57925af09 100644 --- a/rpcs3/Emu/Cell/PPUTranslator.h +++ b/rpcs3/Emu/Cell/PPUTranslator.h @@ -238,16 +238,16 @@ public: // Get the basic block for the specified address llvm::BasicBlock* GetBasicBlock(u64 addr); - // Load GPR + // Load gpr llvm::Value* GetGpr(u32 r, u32 num_bits = 64); - // Set GPR + // Set gpr void SetGpr(u32 r, llvm::Value* value); - // Get FPR + // Get fpr llvm::Value* GetFpr(u32 r, u32 bits = 64, bool as_int = false); - // Set FPR + // Set fpr void SetFpr(u32 r, llvm::Value* val); // Vector register type @@ -260,7 +260,7 @@ public: i128, // Solid 128-bit integer }; - // Load VR + // Load vr llvm::Value* GetVr(u32 vr, VrType); // Load VRs @@ -271,7 +271,7 @@ public: return{ GetVr(regs, type)... }; } - // Set VR to the specified value + // Set vr to the specified value void SetVr(u32 vr, llvm::Value*); // Bitcast to scalar integer value @@ -431,7 +431,7 @@ public: // Handle compilation errors void CompilationError(const std::string& error); - PPUTranslator(llvm::LLVMContext& context, llvm::Module* module, u64 base, u64 entry); + PPUTranslator(llvm::LLVMContext& context, llvm::Module* module, u64 base); ~PPUTranslator(); // Get thread context struct type diff --git a/rpcs3/Emu/Cell/RawSPUThread.cpp b/rpcs3/Emu/Cell/RawSPUThread.cpp index 2003b47f32..ba503b9ba3 100644 --- a/rpcs3/Emu/Cell/RawSPUThread.cpp +++ b/rpcs3/Emu/Cell/RawSPUThread.cpp @@ -87,21 +87,9 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value) { auto try_start = [this]() { - if (status.atomic_op([](u32& status) -> bool + if (!status.test_and_set(SPU_STATUS_RUNNING)) { - if (status & SPU_STATUS_RUNNING) - { - return false; - } - else - { - status = SPU_STATUS_RUNNING; - return true; - } - })) - { - state -= cpu_state::stop; - (*this)->lock_notify(); + run(); } }; diff --git a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp index aae3547b7b..e6525200fd 100644 --- a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp @@ -269,7 +269,7 @@ void spu_recompiler::InterpreterCall(spu_opcode_t op) const u32 old_pc = _spu->pc; - if (_spu->state.load() && _spu->check_status()) + if (_spu->state.load() && _spu->check_state()) { return 0x2000000 | _spu->pc; } @@ -340,7 +340,7 @@ void spu_recompiler::FunctionCall() LOG_ERROR(SPU, "Branch-to-self"); } - while (!_spu->state.load() || !_spu->check_status()) + while (!_spu->state.load() || !_spu->check_state()) { // Proceed recursively spu_recompiler_base::enter(*_spu); diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 1317779ac8..73c1880e84 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -24,8 +24,6 @@ extern u64 get_timebased_time(); -extern std::mutex& get_current_thread_mutex(); - enum class spu_decoder_type { precise, @@ -57,8 +55,7 @@ void spu_int_ctrl_t::set(u64 ints) if (tag && tag->handler) { - tag->handler->signal++; - (*tag->handler->thread)->notify(); + tag->handler->exec(); } } } @@ -126,7 +123,7 @@ spu_imm_table_t::spu_imm_table_t() std::string SPUThread::get_name() const { - return fmt::format("%sSPU[0x%x] Thread (%s)", offset > RAW_SPU_BASE_ADDR ? "Raw" : "", id, m_name); + return fmt::format("%sSPU[0x%x] Thread (%s)", offset >= RAW_SPU_BASE_ADDR ? "Raw" : "", id, m_name); } std::string SPUThread::dump() const @@ -187,7 +184,7 @@ void SPUThread::cpu_task() if (custom_task) { - if (check_status()) return; + if (check_state()) return; return custom_task(*this); } @@ -229,7 +226,7 @@ void SPUThread::cpu_task() continue; } - if (check_status()) return; + if (check_state()) return; } } @@ -281,7 +278,7 @@ void SPUThread::do_dma_transfer(u32 cmd, spu_mfc_arg_t args) u32 eal = vm::cast(args.ea, HERE); - if (eal >= SYS_SPU_THREAD_BASE_LOW && offset >= RAW_SPU_BASE_ADDR) // 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 @@ -548,7 +545,7 @@ void SPUThread::set_events(u32 mask) // Notify if some events were set if (~old_stat & mask && old_stat & SPU_EVENT_WAITING && ch_event_stat & SPU_EVENT_WAITING) { - (*this)->lock_notify(); + lock_notify(); } } @@ -602,7 +599,7 @@ bool SPUThread::get_ch_value(u32 ch, u32& out) { if (!channel.try_pop(out)) { - cpu_thread_lock{*this}, thread_ctrl::wait(WRAP_EXPR(state & cpu_state::stop || channel.try_pop(out))); + thread_lock{*this}, thread_ctrl::wait(WRAP_EXPR(state & cpu_state::stop || channel.try_pop(out))); return !state.test(cpu_state::stop); } @@ -617,7 +614,7 @@ bool SPUThread::get_ch_value(u32 ch, u32& out) // break; case SPU_RdInMbox: { - std::unique_lock lock(get_current_thread_mutex(), std::defer_lock); + std::unique_lock lock(*this, std::defer_lock); while (true) { @@ -644,7 +641,7 @@ bool SPUThread::get_ch_value(u32 ch, u32& out) continue; } - get_current_thread_cv().wait(lock); + thread_ctrl::wait(); } } @@ -693,7 +690,7 @@ bool SPUThread::get_ch_value(u32 ch, u32& out) case SPU_RdEventStat: { - std::unique_lock lock(get_current_thread_mutex(), std::defer_lock); + std::unique_lock lock(*this, std::defer_lock); // start waiting or return immediately if (u32 res = get_events(true)) @@ -716,7 +713,7 @@ bool SPUThread::get_ch_value(u32 ch, u32& out) { CHECK_EMU_STATUS; - get_current_thread_cv().wait(lock); + thread_ctrl::wait(); } } @@ -756,7 +753,7 @@ bool SPUThread::set_ch_value(u32 ch, u32 value) { if (offset >= RAW_SPU_BASE_ADDR) { - std::unique_lock lock(get_current_thread_mutex(), std::defer_lock); + std::unique_lock lock(*this, std::defer_lock); while (!ch_out_intr_mbox.try_push(value)) { @@ -773,7 +770,7 @@ bool SPUThread::set_ch_value(u32 ch, u32 value) continue; } - get_current_thread_cv().wait(lock); + thread_ctrl::wait(); } int_ctrl[2].set(SPU_INT2_STAT_MAILBOX_INT); @@ -963,7 +960,7 @@ bool SPUThread::set_ch_value(u32 ch, u32 value) case SPU_WrOutMbox: { - std::unique_lock lock(get_current_thread_mutex(), std::defer_lock); + std::unique_lock lock(*this, std::defer_lock); while (!ch_out_mbox.try_push(value)) { @@ -980,7 +977,7 @@ bool SPUThread::set_ch_value(u32 ch, u32 value) continue; } - get_current_thread_cv().wait(lock); + thread_ctrl::wait(); } return true; @@ -1305,7 +1302,7 @@ bool SPUThread::stop_and_signal(u32 code) if (thread && thread.get() != this) { thread->state -= cpu_state::suspend; - (*thread)->lock_notify(); + thread->lock_notify(); } } @@ -1344,7 +1341,7 @@ bool SPUThread::stop_and_signal(u32 code) if (thread && thread.get() != this) { thread->state += cpu_state::stop; - (*thread)->lock_notify(); + thread->lock_notify(); } } diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index 9e2354f8fb..def1d0472e 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -180,7 +180,7 @@ public: data.value |= value; }); - if (old.wait) spu->lock_notify(); + if (old.wait) spu.lock_notify(); } // push unconditionally (overwriting previous value), may require notification @@ -193,7 +193,7 @@ public: data.value = value; }); - if (old.wait) spu->lock_notify(); + if (old.wait) spu.lock_notify(); } // returns true on success @@ -228,7 +228,7 @@ public: // value is not cleared and may be read again }); - if (old.wait) spu->lock_notify(); + if (old.wait) spu.lock_notify(); return old.value; } @@ -253,12 +253,8 @@ struct spu_channel_4_t { struct alignas(16) sync_var_t { - struct - { - u32 waiting : 1; - u32 count : 3; - }; - + u8 waiting; + u8 count; u32 value0; u32 value1; u32 value2; @@ -299,7 +295,7 @@ public: return false; })) { - spu->lock_notify(); + spu.lock_notify(); } } @@ -337,7 +333,7 @@ public: void set_values(u32 count, u32 value0, u32 value1 = 0, u32 value2 = 0, u32 value3 = 0) { - this->values.raw() = { 0, count, value0, value1, value2 }; + this->values.raw() = { 0, static_cast(count), value0, value1, value2 }; this->value3 = value3; } }; diff --git a/rpcs3/Emu/Cell/lv2/lv2.cpp b/rpcs3/Emu/Cell/lv2/lv2.cpp index 3b6ab8a1ef..3f05d43aed 100644 --- a/rpcs3/Emu/Cell/lv2/lv2.cpp +++ b/rpcs3/Emu/Cell/lv2/lv2.cpp @@ -908,22 +908,22 @@ std::array g_ppu_syscall_table null_func, null_func, null_func, null_func, //1023 UNS }; -extern void ppu_execute_syscall(PPUThread& ppu, u64 code) +extern void ppu_execute_syscall(ppu_thread& ppu, u64 code) { if (code < g_ppu_syscall_table.size()) { // If autopause occures, check_status() will hold the thread till unpaused. - if (debug::autopause::pause_syscall(code) && ppu.check_status()) throw cpu_state::ret; + if (debug::autopause::pause_syscall(code) && ppu.check_state()) throw cpu_state::ret; if (auto func = g_ppu_syscall_table[code]) { func(ppu); - LOG_TRACE(PPU, "Syscall '%s' (%llu) finished, r3=0x%llx", ppu_get_syscall_name(code), code, ppu.GPR[3]); + LOG_TRACE(PPU, "Syscall '%s' (%llu) finished, r3=0x%llx", ppu_get_syscall_name(code), code, ppu.gpr[3]); } else { LOG_TODO(HLE, "Unimplemented syscall %s -> CELL_OK", ppu_get_syscall_name(code)); - ppu.GPR[3] = 0; + ppu.gpr[3] = 0; } return; diff --git a/rpcs3/Emu/Cell/lv2/sys_cond.cpp b/rpcs3/Emu/Cell/lv2/sys_cond.cpp index cbab40e538..46e84e667a 100644 --- a/rpcs3/Emu/Cell/lv2/sys_cond.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_cond.cpp @@ -23,10 +23,10 @@ void lv2_cond_t::notify(lv2_lock_t, cpu_thread* thread) } else { - mutex->owner = idm::get(thread->id); + mutex->owner = idm::get(thread->id); VERIFY(!thread->state.test_and_set(cpu_state::signal)); - (*thread)->notify(); + thread->notify(); } } @@ -165,7 +165,7 @@ s32 sys_cond_signal_to(u32 cond_id, u32 thread_id) return CELL_OK; } -s32 sys_cond_wait(PPUThread& ppu, u32 cond_id, u64 timeout) +s32 sys_cond_wait(ppu_thread& ppu, u32 cond_id, u64 timeout) { sys_cond.trace("sys_cond_wait(cond_id=0x%x, timeout=%lld)", cond_id, timeout); @@ -212,7 +212,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 = idm::get(ppu.id); + cond->mutex->owner = idm::get(ppu.id); break; } diff --git a/rpcs3/Emu/Cell/lv2/sys_cond.h b/rpcs3/Emu/Cell/lv2/sys_cond.h index 24b4012c7c..a891f0de41 100644 --- a/rpcs3/Emu/Cell/lv2/sys_cond.h +++ b/rpcs3/Emu/Cell/lv2/sys_cond.h @@ -33,12 +33,12 @@ struct lv2_cond_t void notify(lv2_lock_t, cpu_thread* thread); }; -class PPUThread; +class ppu_thread; // SysCalls s32 sys_cond_create(vm::ptr cond_id, u32 mutex_id, vm::ptr attr); s32 sys_cond_destroy(u32 cond_id); -s32 sys_cond_wait(PPUThread& ppu, u32 cond_id, u64 timeout); +s32 sys_cond_wait(ppu_thread& ppu, u32 cond_id, u64 timeout); s32 sys_cond_signal(u32 cond_id); s32 sys_cond_signal_all(u32 cond_id); s32 sys_cond_signal_to(u32 cond_id, u32 thread_id); diff --git a/rpcs3/Emu/Cell/lv2/sys_event.cpp b/rpcs3/Emu/Cell/lv2/sys_event.cpp index 2c1994419b..da82fc9a2e 100644 --- a/rpcs3/Emu/Cell/lv2/sys_event.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_event.cpp @@ -64,12 +64,12 @@ void lv2_event_queue_t::push(lv2_lock_t, u64 source, u64 data1, u64 data2, u64 d if (type == SYS_PPU_QUEUE && thread->type == cpu_type::ppu) { // store event data in registers - auto& ppu = static_cast(*thread); + auto& ppu = static_cast(*thread); - ppu.GPR[4] = source; - ppu.GPR[5] = data1; - ppu.GPR[6] = data2; - ppu.GPR[7] = data3; + ppu.gpr[4] = source; + ppu.gpr[5] = data1; + ppu.gpr[6] = data2; + ppu.gpr[7] = data3; } else if (type == SYS_SPU_QUEUE && thread->type == cpu_type::spu) { @@ -84,7 +84,7 @@ void lv2_event_queue_t::push(lv2_lock_t, u64 source, u64 data1, u64 data2, u64 d } VERIFY(!thread->state.test_and_set(cpu_state::signal)); - (*thread)->notify(); + thread->notify(); return m_sq.pop_front(); } @@ -165,7 +165,7 @@ s32 sys_event_queue_destroy(u32 equeue_id, s32 mode) { if (queue->type == SYS_PPU_QUEUE && thread->type == cpu_type::ppu) { - static_cast(*thread).GPR[3] = 1; + static_cast(*thread).gpr[3] = 1; } else if (queue->type == SYS_SPU_QUEUE && thread->type == cpu_type::spu) { @@ -177,7 +177,7 @@ s32 sys_event_queue_destroy(u32 equeue_id, s32 mode) } thread->state += cpu_state::signal; - (*thread)->notify(); + thread->notify(); } return CELL_OK; @@ -220,7 +220,7 @@ s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr event_array, return CELL_OK; } -s32 sys_event_queue_receive(PPUThread& ppu, u32 equeue_id, vm::ptr dummy_event, u64 timeout) +s32 sys_event_queue_receive(ppu_thread& ppu, u32 equeue_id, vm::ptr dummy_event, u64 timeout) { sys_event.trace("sys_event_queue_receive(equeue_id=0x%x, *0x%x, timeout=0x%llx)", equeue_id, dummy_event, timeout); @@ -243,12 +243,12 @@ s32 sys_event_queue_receive(PPUThread& ppu, u32 equeue_id, vm::ptr 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->pop(lv2_lock); + std::tie(ppu.gpr[4], ppu.gpr[5], ppu.gpr[6], ppu.gpr[7]) = queue->pop(lv2_lock); return CELL_OK; } // cause (if cancelled) will be returned in r3 - ppu.GPR[3] = 0; + ppu.gpr[3] = 0; // add waiter; protocol is ignored in current implementation sleep_entry waiter(queue->thread_queue(lv2_lock), ppu); @@ -274,7 +274,7 @@ s32 sys_event_queue_receive(PPUThread& ppu, u32 equeue_id, vm::ptr } } - if (ppu.GPR[3]) + if (ppu.gpr[3]) { ENSURES(!idm::check(equeue_id)); return CELL_ECANCELED; diff --git a/rpcs3/Emu/Cell/lv2/sys_event.h b/rpcs3/Emu/Cell/lv2/sys_event.h index ba9d22b038..fc8936f40a 100644 --- a/rpcs3/Emu/Cell/lv2/sys_event.h +++ b/rpcs3/Emu/Cell/lv2/sys_event.h @@ -132,12 +132,12 @@ struct lv2_event_port_t } }; -class PPUThread; +class ppu_thread; // SysCalls s32 sys_event_queue_create(vm::ptr equeue_id, vm::ptr attr, u64 event_queue_key, s32 size); s32 sys_event_queue_destroy(u32 equeue_id, s32 mode); -s32 sys_event_queue_receive(PPUThread& ppu, u32 equeue_id, vm::ptr dummy_event, u64 timeout); +s32 sys_event_queue_receive(ppu_thread& ppu, u32 equeue_id, vm::ptr dummy_event, u64 timeout); s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr event_array, s32 size, vm::ptr number); s32 sys_event_queue_drain(u32 event_queue_id); diff --git a/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp b/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp index d39ba434d0..c5eb2b887d 100644 --- a/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp @@ -17,20 +17,20 @@ void lv2_event_flag_t::notify_all(lv2_lock_t) { auto pred = [this](cpu_thread* thread) -> bool { - auto& ppu = static_cast(*thread); + auto& ppu = static_cast(*thread); // load pattern and mode from registers - const u64 bitptn = ppu.GPR[4]; - const u32 mode = static_cast(ppu.GPR[5]); + const u64 bitptn = ppu.gpr[4]; + const u32 mode = static_cast(ppu.gpr[5]); // check specific pattern if (check_pattern(bitptn, mode)) { // save pattern - ppu.GPR[4] = clear_pattern(bitptn, mode); + ppu.gpr[4] = clear_pattern(bitptn, mode); VERIFY(!thread->state.test_and_set(cpu_state::signal)); - (*thread)->notify(); + thread->notify(); return true; } @@ -101,7 +101,7 @@ s32 sys_event_flag_destroy(u32 id) return CELL_OK; } -s32 sys_event_flag_wait(PPUThread& ppu, u32 id, u64 bitptn, u32 mode, vm::ptr result, u64 timeout) +s32 sys_event_flag_wait(ppu_thread& ppu, u32 id, u64 bitptn, u32 mode, vm::ptr result, u64 timeout) { sys_event_flag.trace("sys_event_flag_wait(id=0x%x, bitptn=0x%llx, mode=0x%x, result=*0x%x, timeout=0x%llx)", id, bitptn, mode, result, timeout); @@ -109,8 +109,8 @@ s32 sys_event_flag_wait(PPUThread& ppu, u32 id, u64 bitptn, u32 mode, vm::ptr num) // signal all threads to return CELL_ECANCELED for (auto& thread : eflag->sq) { - auto& ppu = static_cast(*thread); + auto& ppu = static_cast(*thread); // save existing pattern - ppu.GPR[4] = pattern; + ppu.gpr[4] = pattern; // clear "mode" as a sign of cancellation - ppu.GPR[5] = 0; + ppu.gpr[5] = 0; VERIFY(!thread->state.test_and_set(cpu_state::signal)); - (*thread)->notify(); + thread->notify(); } eflag->sq.clear(); diff --git a/rpcs3/Emu/Cell/lv2/sys_event_flag.h b/rpcs3/Emu/Cell/lv2/sys_event_flag.h index 31b27947c5..4a74176b0d 100644 --- a/rpcs3/Emu/Cell/lv2/sys_event_flag.h +++ b/rpcs3/Emu/Cell/lv2/sys_event_flag.h @@ -107,12 +107,12 @@ struct lv2_event_flag_t }; // Aux -class PPUThread; +class ppu_thread; // SysCalls s32 sys_event_flag_create(vm::ptr id, vm::ptr attr, u64 init); s32 sys_event_flag_destroy(u32 id); -s32 sys_event_flag_wait(PPUThread& ppu, u32 id, u64 bitptn, u32 mode, vm::ptr result, u64 timeout); +s32 sys_event_flag_wait(ppu_thread& ppu, u32 id, u64 bitptn, u32 mode, vm::ptr result, u64 timeout); s32 sys_event_flag_trywait(u32 id, u64 bitptn, u32 mode, vm::ptr result); s32 sys_event_flag_set(u32 id, u64 bitptn); s32 sys_event_flag_clear(u32 id, u64 bitptn); diff --git a/rpcs3/Emu/Cell/lv2/sys_interrupt.cpp b/rpcs3/Emu/Cell/lv2/sys_interrupt.cpp index de8acf544e..57f04ed0c3 100644 --- a/rpcs3/Emu/Cell/lv2/sys_interrupt.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_interrupt.cpp @@ -5,17 +5,35 @@ #include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" +#include "Emu/Cell/PPUOpcodes.h" #include "sys_interrupt.h" logs::channel sys_interrupt("sys_interrupt", logs::level::notice); -void lv2_int_serv_t::join(PPUThread& ppu, lv2_lock_t lv2_lock) +void lv2_int_serv_t::exec() { - // Use is_joining to stop interrupt thread and signal - thread->is_joining = true; - (*thread)->notify(); + thread->cmd_list + ({ + { ppu_cmd::set_args, 2 }, arg1, arg2, + { ppu_cmd::lle_call, 2 }, + }); - // Start joining + thread->lock_notify(); +} + +void lv2_int_serv_t::join(ppu_thread& ppu, lv2_lock_t lv2_lock) +{ + // Enqueue _sys_ppu_thread_exit call + thread->cmd_list + ({ + { ppu_cmd::set_args, 1 }, u64{0}, + { ppu_cmd::set_gpr, 11 }, u64{41}, + { ppu_cmd::opcode, ppu_instructions::SC(0) }, + }); + + thread->lock_notify(); + + // Join thread (TODO) while (!(thread->state & cpu_state::exit)) { CHECK_EMU_STATUS; @@ -25,7 +43,6 @@ void lv2_int_serv_t::join(PPUThread& ppu, lv2_lock_t lv2_lock) // Cleanup idm::remove(id); - idm::remove(thread->id); } s32 sys_interrupt_tag_destroy(u32 intrtag) @@ -66,7 +83,7 @@ s32 _sys_interrupt_thread_establish(vm::ptr ih, u32 intrtag, u32 intrthread } // Get interrupt thread - const auto it = idm::get(intrthread); + const auto it = idm::get(intrthread); if (!it) { @@ -86,55 +103,16 @@ s32 _sys_interrupt_thread_establish(vm::ptr ih, u32 intrtag, u32 intrthread return CELL_ESTAT; } - const auto handler = idm::make_ptr(it); + tag->handler = idm::make_ptr(it, arg1, arg2); - tag->handler = handler; + it->run(); - it->custom_task = [handler, arg1, arg2](PPUThread& ppu) - { - const u32 pc = ppu.pc; - const u32 rtoc = ppu.GPR[2]; - - LV2_LOCK; - - while (!ppu.is_joining) - { - CHECK_EMU_STATUS; - - // call interrupt handler until int status is clear - if (handler->signal) - { - if (lv2_lock) lv2_lock.unlock(); - - ppu.GPR[3] = arg1; - ppu.GPR[4] = arg2; - ppu.fast_call(pc, rtoc); - - handler->signal--; - continue; - } - - if (!lv2_lock) - { - lv2_lock.lock(); - continue; - } - - get_current_thread_cv().wait(lv2_lock); - } - - ppu.state += cpu_state::exit; - }; - - it->state -= cpu_state::stop; - (*it)->lock_notify(); - - *ih = handler->id; + *ih = tag->handler->id; return CELL_OK; } -s32 _sys_interrupt_thread_disestablish(PPUThread& ppu, u32 ih, vm::ptr r13) +s32 _sys_interrupt_thread_disestablish(ppu_thread& ppu, u32 ih, vm::ptr r13) { sys_interrupt.warning("_sys_interrupt_thread_disestablish(ih=0x%x, r13=*0x%x)", ih, r13); @@ -151,12 +129,12 @@ s32 _sys_interrupt_thread_disestablish(PPUThread& ppu, u32 ih, vm::ptr r13) handler->join(ppu, lv2_lock); // Save TLS base - *r13 = handler->thread->GPR[13]; + *r13 = handler->thread->gpr[13]; return CELL_OK; } -void sys_interrupt_thread_eoi(PPUThread& ppu) // Low-level PPU function example +void sys_interrupt_thread_eoi(ppu_thread& ppu) // Low-level PPU function example { // Low-level function body must guard all C++-ish calls and all objects with non-trivial destructors thread_guard{ppu}, sys_interrupt.trace("sys_interrupt_thread_eoi()"); @@ -164,7 +142,7 @@ void sys_interrupt_thread_eoi(PPUThread& ppu) // Low-level PPU function example ppu.state += cpu_state::ret; // Throw if this syscall was not called directly by the SC instruction (hack) - if (ppu.LR == 0 || ppu.GPR[11] != 88 || ppu.custom_task) + if (ppu.lr == 0 || ppu.gpr[11] != 88) { // Low-level function must disable interrupts before throwing (not related to sys_interrupt_*, it's rather coincidence) ppu->interrupt_disable(); diff --git a/rpcs3/Emu/Cell/lv2/sys_interrupt.h b/rpcs3/Emu/Cell/lv2/sys_interrupt.h index b440852af0..71edca0104 100644 --- a/rpcs3/Emu/Cell/lv2/sys_interrupt.h +++ b/rpcs3/Emu/Cell/lv2/sys_interrupt.h @@ -2,7 +2,7 @@ #include "sys_sync.h" -class PPUThread; +class ppu_thread; struct lv2_int_tag_t { @@ -13,22 +13,26 @@ struct lv2_int_tag_t struct lv2_int_serv_t { - const std::shared_ptr thread; + const std::shared_ptr thread; const id_value<> id{}; - atomic_t signal{ 0 }; // signal count + const u64 arg1; + const u64 arg2; - lv2_int_serv_t(const std::shared_ptr& thread) + lv2_int_serv_t(const std::shared_ptr& thread, u64 arg1, u64 arg2) : thread(thread) + , arg1(arg1) + , arg2(arg2) { } - void join(PPUThread& ppu, lv2_lock_t); + void exec(); + void join(ppu_thread& ppu, lv2_lock_t); }; // SysCalls s32 sys_interrupt_tag_destroy(u32 intrtag); s32 _sys_interrupt_thread_establish(vm::ptr ih, u32 intrtag, u32 intrthread, u64 arg1, u64 arg2); -s32 _sys_interrupt_thread_disestablish(PPUThread& ppu, u32 ih, vm::ptr r13); -void sys_interrupt_thread_eoi(PPUThread& ppu); +s32 _sys_interrupt_thread_disestablish(ppu_thread& ppu, u32 ih, vm::ptr r13); +void sys_interrupt_thread_eoi(ppu_thread& ppu); diff --git a/rpcs3/Emu/Cell/lv2/sys_lwcond.cpp b/rpcs3/Emu/Cell/lv2/sys_lwcond.cpp index eaea8482bc..3ceba748dc 100644 --- a/rpcs3/Emu/Cell/lv2/sys_lwcond.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_lwcond.cpp @@ -16,9 +16,9 @@ extern u64 get_system_time(); void lv2_lwcond_t::notify(lv2_lock_t, cpu_thread* thread, const std::shared_ptr& mutex, bool mode2) { - auto& ppu = static_cast(*thread); + auto& ppu = static_cast(*thread); - ppu.GPR[3] = mode2; // set to return CELL_EBUSY + ppu.gpr[3] = mode2; // set to return CELL_EBUSY if (!mode2) { @@ -31,7 +31,7 @@ void lv2_lwcond_t::notify(lv2_lock_t, cpu_thread* thread, const std::shared_ptr< } VERIFY(!thread->state.test_and_set(cpu_state::signal)); - (*thread)->notify(); + thread->notify(); } s32 _sys_lwcond_create(vm::ptr lwcond_id, u32 lwmutex_id, vm::ptr control, u64 name, u32 arg5) @@ -155,7 +155,7 @@ s32 _sys_lwcond_signal_all(u32 lwcond_id, u32 lwmutex_id, u32 mode) return result; } -s32 _sys_lwcond_queue_wait(PPUThread& ppu, u32 lwcond_id, u32 lwmutex_id, u64 timeout) +s32 _sys_lwcond_queue_wait(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id, u64 timeout) { sys_lwcond.trace("_sys_lwcond_queue_wait(lwcond_id=0x%x, lwmutex_id=0x%x, timeout=0x%llx)", lwcond_id, lwmutex_id, timeout); @@ -212,5 +212,5 @@ s32 _sys_lwcond_queue_wait(PPUThread& ppu, u32 lwcond_id, u32 lwmutex_id, u64 ti } // return cause - return ppu.GPR[3] ? CELL_EBUSY : CELL_OK; + return ppu.gpr[3] ? CELL_EBUSY : CELL_OK; } diff --git a/rpcs3/Emu/Cell/lv2/sys_lwcond.h b/rpcs3/Emu/Cell/lv2/sys_lwcond.h index 8633318c03..f0867ba2a1 100644 --- a/rpcs3/Emu/Cell/lv2/sys_lwcond.h +++ b/rpcs3/Emu/Cell/lv2/sys_lwcond.h @@ -32,11 +32,11 @@ struct lv2_lwcond_t }; // Aux -class PPUThread; +class ppu_thread; // SysCalls s32 _sys_lwcond_create(vm::ptr lwcond_id, u32 lwmutex_id, vm::ptr control, u64 name, u32 arg5); s32 _sys_lwcond_destroy(u32 lwcond_id); s32 _sys_lwcond_signal(u32 lwcond_id, u32 lwmutex_id, u32 ppu_thread_id, u32 mode); s32 _sys_lwcond_signal_all(u32 lwcond_id, u32 lwmutex_id, u32 mode); -s32 _sys_lwcond_queue_wait(PPUThread& ppu, u32 lwcond_id, u32 lwmutex_id, u64 timeout); +s32 _sys_lwcond_queue_wait(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id, u64 timeout); diff --git a/rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp b/rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp index 9178bda26d..2454f93f16 100644 --- a/rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp @@ -22,7 +22,7 @@ void lv2_lwmutex_t::unlock(lv2_lock_t) { auto& thread = sq.front(); VERIFY(!thread->state.test_and_set(cpu_state::signal)); - (*thread)->notify(); + thread->notify(); sq.pop_front(); } @@ -75,7 +75,7 @@ s32 _sys_lwmutex_destroy(u32 lwmutex_id) return CELL_OK; } -s32 _sys_lwmutex_lock(PPUThread& ppu, u32 lwmutex_id, u64 timeout) +s32 _sys_lwmutex_lock(ppu_thread& ppu, u32 lwmutex_id, u64 timeout) { sys_lwmutex.trace("_sys_lwmutex_lock(lwmutex_id=0x%x, timeout=0x%llx)", lwmutex_id, timeout); diff --git a/rpcs3/Emu/Cell/lv2/sys_lwmutex.h b/rpcs3/Emu/Cell/lv2/sys_lwmutex.h index 775bd11ff6..7d1b88763d 100644 --- a/rpcs3/Emu/Cell/lv2/sys_lwmutex.h +++ b/rpcs3/Emu/Cell/lv2/sys_lwmutex.h @@ -64,11 +64,11 @@ struct lv2_lwmutex_t }; // Aux -class PPUThread; +class ppu_thread; // SysCalls s32 _sys_lwmutex_create(vm::ptr lwmutex_id, u32 protocol, vm::ptr control, u32 arg4, u64 name, u32 arg6); s32 _sys_lwmutex_destroy(u32 lwmutex_id); -s32 _sys_lwmutex_lock(PPUThread& ppu, u32 lwmutex_id, u64 timeout); +s32 _sys_lwmutex_lock(ppu_thread& ppu, u32 lwmutex_id, u64 timeout); s32 _sys_lwmutex_trylock(u32 lwmutex_id); s32 _sys_lwmutex_unlock(u32 lwmutex_id); diff --git a/rpcs3/Emu/Cell/lv2/sys_mutex.cpp b/rpcs3/Emu/Cell/lv2/sys_mutex.cpp index 88d00bfe4b..1a2a722625 100644 --- a/rpcs3/Emu/Cell/lv2/sys_mutex.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_mutex.cpp @@ -18,10 +18,10 @@ void lv2_mutex_t::unlock(lv2_lock_t) if (sq.size()) { // pick new owner; protocol is ignored in current implementation - owner = idm::get(sq.front()->id); + owner = idm::get(sq.front()->id); VERIFY(!owner->state.test_and_set(cpu_state::signal)); - (*owner)->notify(); + owner->notify(); } } @@ -91,7 +91,7 @@ s32 sys_mutex_destroy(u32 mutex_id) return CELL_OK; } -s32 sys_mutex_lock(PPUThread& ppu, u32 mutex_id, u64 timeout) +s32 sys_mutex_lock(ppu_thread& ppu, u32 mutex_id, u64 timeout) { sys_mutex.trace("sys_mutex_lock(mutex_id=0x%x, timeout=0x%llx)", mutex_id, timeout); @@ -127,7 +127,7 @@ s32 sys_mutex_lock(PPUThread& ppu, u32 mutex_id, u64 timeout) // lock immediately if not locked if (!mutex->owner) { - mutex->owner = idm::get(ppu.id); + mutex->owner = idm::get(ppu.id); return CELL_OK; } @@ -165,7 +165,7 @@ s32 sys_mutex_lock(PPUThread& ppu, u32 mutex_id, u64 timeout) return CELL_OK; } -s32 sys_mutex_trylock(PPUThread& ppu, u32 mutex_id) +s32 sys_mutex_trylock(ppu_thread& ppu, u32 mutex_id) { sys_mutex.trace("sys_mutex_trylock(mutex_id=0x%x)", mutex_id); @@ -202,12 +202,12 @@ s32 sys_mutex_trylock(PPUThread& ppu, u32 mutex_id) } // own the mutex if free - mutex->owner = idm::get(ppu.id); + mutex->owner = idm::get(ppu.id); return CELL_OK; } -s32 sys_mutex_unlock(PPUThread& ppu, u32 mutex_id) +s32 sys_mutex_unlock(ppu_thread& ppu, u32 mutex_id) { sys_mutex.trace("sys_mutex_unlock(mutex_id=0x%x)", mutex_id); diff --git a/rpcs3/Emu/Cell/lv2/sys_mutex.h b/rpcs3/Emu/Cell/lv2/sys_mutex.h index 97f9d7d858..aa628068b9 100644 --- a/rpcs3/Emu/Cell/lv2/sys_mutex.h +++ b/rpcs3/Emu/Cell/lv2/sys_mutex.h @@ -41,11 +41,11 @@ struct lv2_mutex_t void unlock(lv2_lock_t); }; -class PPUThread; +class ppu_thread; // SysCalls s32 sys_mutex_create(vm::ptr mutex_id, vm::ptr attr); s32 sys_mutex_destroy(u32 mutex_id); -s32 sys_mutex_lock(PPUThread& ppu, u32 mutex_id, u64 timeout); -s32 sys_mutex_trylock(PPUThread& ppu, u32 mutex_id); -s32 sys_mutex_unlock(PPUThread& ppu, u32 mutex_id); +s32 sys_mutex_lock(ppu_thread& ppu, u32 mutex_id, u64 timeout); +s32 sys_mutex_trylock(ppu_thread& ppu, u32 mutex_id); +s32 sys_mutex_unlock(ppu_thread& ppu, u32 mutex_id); diff --git a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp index 81c273d083..1b896b9a29 100644 --- a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp @@ -11,37 +11,24 @@ logs::channel sys_ppu_thread("sys_ppu_thread", logs::level::notice); -void _sys_ppu_thread_exit(PPUThread& ppu, u64 errorcode) +void _sys_ppu_thread_exit(ppu_thread& ppu, u64 errorcode) { sys_ppu_thread.warning("_sys_ppu_thread_exit(errorcode=0x%llx)", errorcode); - // TODO: Should we really unlock mutexes? + // TODO: shall sys_mutex objects be unlocked? - //// get all sys_mutex objects - //for (auto& mutex : idm::get_all()) - //{ - // // unlock mutex if locked by this thread - // if (mutex->owner.get() == &ppu) - // { - // mutex->unlock(lv2_lock); - // } - //} + LV2_LOCK; + ppu.state += cpu_state::exit; + + // Delete detached thread + if (!ppu.is_joinable) { - LV2_LOCK; - - ppu.state += cpu_state::exit; - //ppu.handle_interrupt(); - - // Delete detached thread - if (!ppu.is_joinable) - { - idm::remove(ppu.id); - } + idm::remove(ppu.id); } // Throw if this syscall was not called directly by the SC instruction (hack) - if (ppu.LR == 0 || ppu.GPR[11] != 41 || ppu.custom_task) + if (ppu.lr == 0 || ppu.gpr[11] != 41) { throw cpu_state::exit; } @@ -54,13 +41,13 @@ void sys_ppu_thread_yield() std::this_thread::yield(); } -s32 sys_ppu_thread_join(PPUThread& ppu, u32 thread_id, vm::ptr vptr) +s32 sys_ppu_thread_join(ppu_thread& ppu, u32 thread_id, vm::ptr vptr) { sys_ppu_thread.warning("sys_ppu_thread_join(thread_id=0x%x, vptr=*0x%x)", thread_id, vptr); LV2_LOCK; - const auto thread = idm::get(thread_id); + const auto thread = idm::get(thread_id); if (!thread) { @@ -77,8 +64,6 @@ s32 sys_ppu_thread_join(PPUThread& ppu, u32 thread_id, vm::ptr vptr) return CELL_EDEADLK; } - ppu.sleep(); - // mark joining thread->is_joining = true; @@ -90,13 +75,11 @@ s32 sys_ppu_thread_join(PPUThread& ppu, u32 thread_id, vm::ptr vptr) get_current_thread_cv().wait_for(lv2_lock, 1ms); } - ppu.awake(); - // get exit status from the register - if (vptr) *vptr = thread->GPR[3]; + if (vptr) *vptr = thread->gpr[3]; // cleanup - idm::remove(thread->id); + idm::remove(thread->id); return CELL_OK; } @@ -107,7 +90,7 @@ s32 sys_ppu_thread_detach(u32 thread_id) LV2_LOCK; - const auto thread = idm::get(thread_id); + const auto thread = idm::get(thread_id); if (!thread) { @@ -130,7 +113,7 @@ s32 sys_ppu_thread_detach(u32 thread_id) return CELL_OK; } -void sys_ppu_thread_get_join_state(PPUThread& ppu, vm::ptr isjoinable) +void sys_ppu_thread_get_join_state(ppu_thread& ppu, vm::ptr isjoinable) { sys_ppu_thread.warning("sys_ppu_thread_get_join_state(isjoinable=*0x%x)", isjoinable); @@ -145,7 +128,7 @@ s32 sys_ppu_thread_set_priority(u32 thread_id, s32 prio) LV2_LOCK; - const auto thread = idm::get(thread_id); + const auto thread = idm::get(thread_id); if (!thread) { @@ -168,7 +151,7 @@ s32 sys_ppu_thread_get_priority(u32 thread_id, vm::ptr priop) LV2_LOCK; - const auto thread = idm::get(thread_id); + const auto thread = idm::get(thread_id); if (!thread) { @@ -180,7 +163,7 @@ s32 sys_ppu_thread_get_priority(u32 thread_id, vm::ptr priop) return CELL_OK; } -s32 sys_ppu_thread_get_stack_information(PPUThread& ppu, vm::ptr sp) +s32 sys_ppu_thread_get_stack_information(ppu_thread& ppu, vm::ptr sp) { sys_ppu_thread.trace("sys_ppu_thread_get_stack_information(sp=*0x%x)", sp); @@ -196,7 +179,7 @@ s32 sys_ppu_thread_stop(u32 thread_id) LV2_LOCK; - const auto thread = idm::get(thread_id); + const auto thread = idm::get(thread_id); if (!thread) { @@ -214,7 +197,7 @@ s32 sys_ppu_thread_restart(u32 thread_id) LV2_LOCK; - const auto thread = idm::get(thread_id); + const auto thread = idm::get(thread_id); if (!thread) { @@ -239,28 +222,30 @@ s32 _sys_ppu_thread_create(vm::ptr thread_id, vm::ptr p return CELL_EINVAL; } - const bool is_joinable = (flags & SYS_PPU_THREAD_CREATE_JOINABLE) != 0; - const bool is_interrupt = (flags & SYS_PPU_THREAD_CREATE_INTERRUPT) != 0; - - if (is_joinable && is_interrupt) + if ((flags & 3) == 3) // Check two flags: joinable + interrupt not allowed { return CELL_EPERM; } - const auto ppu = idm::make_ptr(threadname ? threadname.get_ptr() : ""); + const auto ppu = idm::make_ptr(threadname ? threadname.get_ptr() : "", prio, stacksize); - ppu->prio = prio; - ppu->stack_size = std::max(stacksize, 0x4000); - 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; - //ppu->state += cpu_state::interrupt; + ppu->is_joinable = (flags & SYS_PPU_THREAD_CREATE_JOINABLE) != 0; + ppu->gpr[13] = param->tls.value(); + + if ((flags & SYS_PPU_THREAD_CREATE_INTERRUPT) == 0) + { + // Initialize thread entry point + ppu->cmd_list + ({ + { ppu_cmd::set_args, 2 }, arg, unk, // Actually unknown + { ppu_cmd::lle_call, param->entry.value() }, + }); + } + else + { + // Save entry for further use + ppu->gpr[2] = param->entry.value(); + } *thread_id = ppu->id; @@ -273,15 +258,14 @@ s32 sys_ppu_thread_start(u32 thread_id) LV2_LOCK; - const auto thread = idm::get(thread_id); + const auto thread = idm::get(thread_id); if (!thread) { return CELL_ESRCH; } - thread->state -= cpu_state::stop; - (*thread)->lock_notify(); + thread->run(); return CELL_OK; } @@ -292,7 +276,7 @@ s32 sys_ppu_thread_rename(u32 thread_id, vm::cptr name) LV2_LOCK; - const auto thread = idm::get(thread_id); + const auto thread = idm::get(thread_id); if (!thread) { diff --git a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.h b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.h index eefd4d047b..4c74ea0b68 100644 --- a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.h +++ b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.h @@ -2,7 +2,7 @@ #include "sys_sync.h" -class PPUThread; +class ppu_thread; enum : u32 { @@ -42,14 +42,14 @@ enum : u32 }; // SysCalls -void _sys_ppu_thread_exit(PPUThread& ppu, u64 errorcode); +void _sys_ppu_thread_exit(ppu_thread& ppu, u64 errorcode); void sys_ppu_thread_yield(); -s32 sys_ppu_thread_join(PPUThread& ppu, u32 thread_id, vm::ptr vptr); +s32 sys_ppu_thread_join(ppu_thread& ppu, u32 thread_id, vm::ptr vptr); s32 sys_ppu_thread_detach(u32 thread_id); -void sys_ppu_thread_get_join_state(PPUThread& ppu, vm::ptr isjoinable); +void sys_ppu_thread_get_join_state(ppu_thread& ppu, vm::ptr isjoinable); s32 sys_ppu_thread_set_priority(u32 thread_id, s32 prio); s32 sys_ppu_thread_get_priority(u32 thread_id, vm::ptr priop); -s32 sys_ppu_thread_get_stack_information(PPUThread& ppu, vm::ptr sp); +s32 sys_ppu_thread_get_stack_information(ppu_thread& ppu, vm::ptr sp); s32 sys_ppu_thread_stop(u32 thread_id); s32 sys_ppu_thread_restart(u32 thread_id); s32 _sys_ppu_thread_create(vm::ptr thread_id, vm::ptr param, u64 arg, u64 arg4, s32 prio, u32 stacksize, u64 flags, vm::cptr threadname); diff --git a/rpcs3/Emu/Cell/lv2/sys_process.cpp b/rpcs3/Emu/Cell/lv2/sys_process.cpp index 323d466f23..b7062ed581 100644 --- a/rpcs3/Emu/Cell/lv2/sys_process.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_process.cpp @@ -241,7 +241,7 @@ s32 sys_process_wait_for_child2(u64 unk1, u64 unk2, u64 unk3, u64 unk4, u64 unk5 s32 sys_process_get_status(u64 unk) { sys_process.todo("sys_process_get_status(unk=0x%llx)", unk); - //vm::write32(CPU.GPR[4], GetPPUThreadStatus(CPU)); + //vm::write32(CPU.gpr[4], GetPPUThreadStatus(CPU)); return CELL_OK; } diff --git a/rpcs3/Emu/Cell/lv2/sys_rwlock.cpp b/rpcs3/Emu/Cell/lv2/sys_rwlock.cpp index 90893d916b..776e23d52c 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rwlock.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_rwlock.cpp @@ -16,10 +16,10 @@ void lv2_rwlock_t::notify_all(lv2_lock_t) // pick a new writer if possible; protocol is ignored in current implementation if (!readers && !writer && wsq.size()) { - writer = idm::get(wsq.front()->id); + writer = idm::get(wsq.front()->id); VERIFY(!writer->state.test_and_set(cpu_state::signal)); - (*writer)->notify(); + writer->notify(); return wsq.pop_front(); } @@ -32,7 +32,7 @@ void lv2_rwlock_t::notify_all(lv2_lock_t) for (auto& thread : rsq) { VERIFY(!thread->state.test_and_set(cpu_state::signal)); - (*thread)->notify(); + thread->notify(); } return rsq.clear(); @@ -90,7 +90,7 @@ s32 sys_rwlock_destroy(u32 rw_lock_id) return CELL_OK; } -s32 sys_rwlock_rlock(PPUThread& ppu, u32 rw_lock_id, u64 timeout) +s32 sys_rwlock_rlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout) { sys_rwlock.trace("sys_rwlock_rlock(rw_lock_id=0x%x, timeout=0x%llx)", rw_lock_id, timeout); @@ -199,7 +199,7 @@ s32 sys_rwlock_runlock(u32 rw_lock_id) return CELL_OK; } -s32 sys_rwlock_wlock(PPUThread& ppu, u32 rw_lock_id, u64 timeout) +s32 sys_rwlock_wlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout) { sys_rwlock.trace("sys_rwlock_wlock(rw_lock_id=0x%x, timeout=0x%llx)", rw_lock_id, timeout); @@ -221,7 +221,7 @@ s32 sys_rwlock_wlock(PPUThread& ppu, u32 rw_lock_id, u64 timeout) if (!rwlock->readers && !rwlock->writer) { - rwlock->writer = idm::get(ppu.id); + rwlock->writer = idm::get(ppu.id); return CELL_OK; } @@ -270,7 +270,7 @@ s32 sys_rwlock_wlock(PPUThread& ppu, u32 rw_lock_id, u64 timeout) return CELL_OK; } -s32 sys_rwlock_trywlock(PPUThread& ppu, u32 rw_lock_id) +s32 sys_rwlock_trywlock(ppu_thread& ppu, u32 rw_lock_id) { sys_rwlock.trace("sys_rwlock_trywlock(rw_lock_id=0x%x)", rw_lock_id); @@ -293,12 +293,12 @@ s32 sys_rwlock_trywlock(PPUThread& ppu, u32 rw_lock_id) return CELL_EBUSY; } - rwlock->writer = idm::get(ppu.id); + rwlock->writer = idm::get(ppu.id); return CELL_OK; } -s32 sys_rwlock_wunlock(PPUThread& ppu, u32 rw_lock_id) +s32 sys_rwlock_wunlock(ppu_thread& ppu, u32 rw_lock_id) { sys_rwlock.trace("sys_rwlock_wunlock(rw_lock_id=0x%x)", rw_lock_id); diff --git a/rpcs3/Emu/Cell/lv2/sys_rwlock.h b/rpcs3/Emu/Cell/lv2/sys_rwlock.h index 596f1ad010..adf7bb707f 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rwlock.h +++ b/rpcs3/Emu/Cell/lv2/sys_rwlock.h @@ -38,14 +38,14 @@ struct lv2_rwlock_t }; // Aux -class PPUThread; +class ppu_thread; // SysCalls s32 sys_rwlock_create(vm::ptr rw_lock_id, vm::ptr attr); s32 sys_rwlock_destroy(u32 rw_lock_id); -s32 sys_rwlock_rlock(PPUThread& ppu, u32 rw_lock_id, u64 timeout); +s32 sys_rwlock_rlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout); s32 sys_rwlock_tryrlock(u32 rw_lock_id); s32 sys_rwlock_runlock(u32 rw_lock_id); -s32 sys_rwlock_wlock(PPUThread& ppu, u32 rw_lock_id, u64 timeout); -s32 sys_rwlock_trywlock(PPUThread& ppu, u32 rw_lock_id); -s32 sys_rwlock_wunlock(PPUThread& ppu, u32 rw_lock_id); +s32 sys_rwlock_wlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout); +s32 sys_rwlock_trywlock(ppu_thread& ppu, u32 rw_lock_id); +s32 sys_rwlock_wunlock(ppu_thread& ppu, u32 rw_lock_id); diff --git a/rpcs3/Emu/Cell/lv2/sys_semaphore.cpp b/rpcs3/Emu/Cell/lv2/sys_semaphore.cpp index c22bfa8a17..e73e9886bb 100644 --- a/rpcs3/Emu/Cell/lv2/sys_semaphore.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_semaphore.cpp @@ -68,7 +68,7 @@ s32 sys_semaphore_destroy(u32 sem_id) return CELL_OK; } -s32 sys_semaphore_wait(PPUThread& ppu, u32 sem_id, u64 timeout) +s32 sys_semaphore_wait(ppu_thread& ppu, u32 sem_id, u64 timeout) { sys_semaphore.trace("sys_semaphore_wait(sem_id=0x%x, timeout=0x%llx)", sem_id, timeout); @@ -174,7 +174,7 @@ s32 sys_semaphore_post(u32 sem_id, s32 count) auto& thread = sem->sq.front(); VERIFY(!thread->state.test_and_set(cpu_state::signal)); - (*thread)->notify(); + thread->notify(); sem->sq.pop_front(); } diff --git a/rpcs3/Emu/Cell/lv2/sys_semaphore.h b/rpcs3/Emu/Cell/lv2/sys_semaphore.h index 9885b1a2eb..694ec67b3d 100644 --- a/rpcs3/Emu/Cell/lv2/sys_semaphore.h +++ b/rpcs3/Emu/Cell/lv2/sys_semaphore.h @@ -37,12 +37,12 @@ struct lv2_sema_t }; // Aux -class PPUThread; +class ppu_thread; // SysCalls s32 sys_semaphore_create(vm::ptr sem_id, vm::ptr attr, s32 initial_val, s32 max_val); s32 sys_semaphore_destroy(u32 sem_id); -s32 sys_semaphore_wait(PPUThread& ppu, u32 sem_id, u64 timeout); +s32 sys_semaphore_wait(ppu_thread& ppu, u32 sem_id, u64 timeout); s32 sys_semaphore_trywait(u32 sem_id); s32 sys_semaphore_post(u32 sem_id, s32 count); s32 sys_semaphore_get_value(u32 sem_id, vm::ptr count); diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.cpp b/rpcs3/Emu/Cell/lv2/sys_spu.cpp index ad06d482dd..78629998c5 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_spu.cpp @@ -321,8 +321,7 @@ s32 sys_spu_thread_group_start(u32 id) { if (thread) { - thread->state -= cpu_state::stop; - (*thread)->lock_notify(); + thread->run(); } } @@ -420,7 +419,7 @@ s32 sys_spu_thread_group_resume(u32 id) if (thread) { thread->state -= cpu_state::suspend; - (*thread)->lock_notify(); + thread->lock_notify(); } } @@ -503,7 +502,7 @@ s32 sys_spu_thread_group_terminate(u32 id, s32 value) if (thread) { thread->state += cpu_state::stop; - (*thread)->lock_notify(); + thread->lock_notify(); } } @@ -1154,7 +1153,7 @@ s32 sys_raw_spu_create(vm::ptr id, vm::ptr attr) return CELL_OK; } -s32 sys_raw_spu_destroy(PPUThread& ppu, u32 id) +s32 sys_raw_spu_destroy(ppu_thread& ppu, u32 id) { sys_spu.warning("sys_raw_spu_destroy(id=%d)", id); diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.h b/rpcs3/Emu/Cell/lv2/sys_spu.h index 6405879318..7b89348636 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.h +++ b/rpcs3/Emu/Cell/lv2/sys_spu.h @@ -196,7 +196,7 @@ struct lv2_spu_group_t } }; -class PPUThread; +class ppu_thread; // Aux void LoadSpuImage(const fs::file& stream, u32& spu_ep, u32 addr); @@ -233,7 +233,7 @@ s32 sys_spu_thread_unbind_queue(u32 id, u32 spuq_num); s32 sys_spu_thread_get_exit_status(u32 id, vm::ptr status); s32 sys_raw_spu_create(vm::ptr id, vm::ptr attr); -s32 sys_raw_spu_destroy(PPUThread& ppu, u32 id); +s32 sys_raw_spu_destroy(ppu_thread& ppu, u32 id); s32 sys_raw_spu_create_interrupt_tag(u32 id, u32 class_id, u32 hwthread, vm::ptr intrtag); s32 sys_raw_spu_set_int_mask(u32 id, u32 class_id, u64 mask); s32 sys_raw_spu_get_int_mask(u32 id, u32 class_id, vm::ptr mask); diff --git a/rpcs3/Emu/Cell/lv2/sys_timer.cpp b/rpcs3/Emu/Cell/lv2/sys_timer.cpp index d0ccbf2c1c..e749d07316 100644 --- a/rpcs3/Emu/Cell/lv2/sys_timer.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_timer.cpp @@ -8,17 +8,13 @@ #include "sys_process.h" #include "sys_timer.h" -#include - logs::channel sys_timer("sys_timer", logs::level::notice); extern u64 get_system_time(); -extern std::mutex& get_current_thread_mutex(); - void lv2_timer_t::on_task() { - std::unique_lock lock(get_current_thread_mutex()); + thread_lock lock(*this); while (state <= SYS_TIMER_STATE_RUN) { @@ -54,7 +50,7 @@ void lv2_timer_t::on_task() continue; } - get_current_thread_cv().wait_for(lock, 1ms); + thread_ctrl::wait_for(100); } } @@ -67,7 +63,7 @@ void lv2_timer_t::on_stop() { // Signal thread using invalid state and join state = -1; - (*this)->lock_notify(); + this->lock_notify(); named_thread::on_stop(); } @@ -172,8 +168,7 @@ s32 _sys_timer_start(u32 timer_id, u64 base_time, u64 period) timer->expire = base_time ? base_time : start_time + period; timer->period = period; timer->state = SYS_TIMER_STATE_RUN; - - (*timer)->lock_notify(); + timer->lock_notify(); return CELL_OK; } diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index 9c65309214..9914ed024e 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -823,19 +823,19 @@ namespace vm { case cpu_type::ppu: { - PPUThread& context = static_cast(*cpu); + ppu_thread& context = static_cast(*cpu); - const u32 old_pos = vm::cast(context.GPR[1], HERE); - context.GPR[1] -= align(size + 4, 8); // room minimal possible size - context.GPR[1] &= ~(align_v - 1); // fix stack alignment + const u32 old_pos = vm::cast(context.gpr[1], HERE); + context.gpr[1] -= align(size + 4, 8); // room minimal possible size + context.gpr[1] &= ~(align_v - 1); // fix stack alignment - if (context.GPR[1] < context.stack_addr) + if (context.gpr[1] < context.stack_addr) { throw EXCEPTION("Stack overflow (size=0x%x, align=0x%x, SP=0x%llx, stack=*0x%x)", size, align_v, old_pos, context.stack_addr); } else { - const u32 addr = static_cast(context.GPR[1]); + const u32 addr = static_cast(context.gpr[1]); vm::ps3::_ref>(addr + size) = old_pos; std::memset(vm::base(addr), 0, size); return addr; @@ -896,15 +896,15 @@ namespace vm { case cpu_type::ppu: { - PPUThread& context = static_cast(*cpu); + ppu_thread& context = static_cast(*cpu); - if (context.GPR[1] != addr) + if (context.gpr[1] != addr) { - LOG_ERROR(MEMORY, "Stack inconsistency (addr=0x%x, SP=0x%llx, size=0x%x)", addr, context.GPR[1], size); + LOG_ERROR(MEMORY, "Stack inconsistency (addr=0x%x, SP=0x%llx, size=0x%x)", addr, context.gpr[1], size); return; } - context.GPR[1] = vm::ps3::_ref>(context.GPR[1] + size); + context.gpr[1] = vm::ps3::_ref>(context.gpr[1] + size); return; } diff --git a/rpcs3/Emu/Memory/vm_ptr.h b/rpcs3/Emu/Memory/vm_ptr.h index 3667d7a015..36f7f8adac 100644 --- a/rpcs3/Emu/Memory/vm_ptr.h +++ b/rpcs3/Emu/Memory/vm_ptr.h @@ -2,7 +2,7 @@ #include "vm_ref.h" -class PPUThread; +class ppu_thread; class ARMv7Thread; namespace vm @@ -264,7 +264,7 @@ namespace vm } // Callback; defined in PPUCallback.h, passing context is mandatory - RT operator()(PPUThread& ppu, T... args) const; + RT operator()(ppu_thread& ppu, T... args) const; // Callback; defined in ARMv7Callback.h, passing context is mandatory RT operator()(ARMv7Thread& cpu, T... args) const; diff --git a/rpcs3/Emu/PSP2/ARMv7Thread.cpp b/rpcs3/Emu/PSP2/ARMv7Thread.cpp index 8d1c458c4e..f83320bdbc 100644 --- a/rpcs3/Emu/PSP2/ARMv7Thread.cpp +++ b/rpcs3/Emu/PSP2/ARMv7Thread.cpp @@ -77,7 +77,7 @@ void ARMv7Thread::cpu_task_main() return fmt::format("%s [0x%08x]", cpu->get_name(), cpu->PC); }; - while (!state.load() || !check_status()) + while (!state.load() || !check_state()) { if (ISET == Thumb) { diff --git a/rpcs3/Emu/PSP2/Modules/sceLibKernel.cpp b/rpcs3/Emu/PSP2/Modules/sceLibKernel.cpp index e0a51eed28..882a195e49 100644 --- a/rpcs3/Emu/PSP2/Modules/sceLibKernel.cpp +++ b/rpcs3/Emu/PSP2/Modules/sceLibKernel.cpp @@ -129,9 +129,7 @@ arm_error_code sceKernelStartThread(s32 threadId, u32 argSize, vm::cptr pA // set SceKernelThreadEntry function arguments thread->GPR[0] = argSize; thread->GPR[1] = pos; - - thread->state -= cpu_state::stop; - (*thread)->lock_notify(); + thread->run(); return SCE_OK; } @@ -308,7 +306,7 @@ arm_error_code sceKernelWaitThreadEnd(s32 threadId, vm::ptr pExitStatus, vm { } - (*thread)->join(); + thread->join(); if (pExitStatus) { @@ -480,23 +478,20 @@ struct psp2_event_flag final // Returns true if the command has been completed immediately. Its status is unknown otherwise. bool exec(task type, u32 arg) { - // Acquire position in the queue + // Allocate position in the queue const u32 push_pos = m_workload.push_begin(); // Make the command cmd_t cmd{type, arg}; + // Get queue head u32 pos = m_workload.peek(); - // Check optimistic case + // Check non-optimistic case if (UNLIKELY(pos != push_pos)) { - // Write the command - m_workload[push_pos] = cmd; - pos = m_workload.peek(); // ??? - - // Try to acquire a command - cmd = m_workload[pos].exchange({task::null}); + // Try to acquire first command in the queue, *then* write current command + m_workload[push_pos] = std::exchange(cmd, m_workload[pos].exchange({task::null})); } while (true) @@ -523,7 +518,7 @@ struct psp2_event_flag final idm::get(cmd.arg, [&](u32, ARMv7Thread& cpu) { cpu.state += cpu_state::signal; - cpu->lock_notify(); + cpu.lock_notify(); }); break; @@ -869,9 +864,9 @@ arm_error_code sceKernelWaitEventFlag(ARMv7Thread& cpu, s32 evfId, u32 bitPatter return SCE_OK; } - cpu_thread_lock entry(cpu); + thread_lock entry(cpu); - if (!thread_ctrl::wait(timeout, WRAP_EXPR(cpu.state.test_and_reset(cpu_state::signal)))) + if (!thread_ctrl::wait_for(timeout, WRAP_EXPR(cpu.state.test_and_reset(cpu_state::signal)))) { // Timeout cleanup cpu.owner = nullptr; diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 50722c3799..dc6b596418 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -375,7 +375,7 @@ namespace rsx last_flip_time = get_system_time() - 1000000; - m_vblank_thread = thread_ctrl::spawn("VBlank Thread", [this]() + thread_ctrl::spawn(m_vblank_thread, "VBlank Thread", [this]() { const u64 start_time = get_system_time(); @@ -390,10 +390,13 @@ namespace rsx if (vblank_handler) { - Emu.GetCallbackManager().Async([func = vblank_handler](PPUThread& ppu) - { - func(ppu, 1); + intr_thread->cmd_list + ({ + { ppu_cmd::set_args, 1 }, u64{1}, + { ppu_cmd::lle_call, vblank_handler }, }); + + intr_thread->lock_notify(); } continue; diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index 83429098c6..77cb887e8c 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -196,6 +196,8 @@ namespace rsx void capture_frame(const std::string &name); public: + std::shared_ptr intr_thread; + u32 ioAddress, ioSize; int flip_status; int flip_mode; diff --git a/rpcs3/Emu/RSX/rsx_methods.cpp b/rpcs3/Emu/RSX/rsx_methods.cpp index 6a020089f8..973241592a 100644 --- a/rpcs3/Emu/RSX/rsx_methods.cpp +++ b/rpcs3/Emu/RSX/rsx_methods.cpp @@ -746,10 +746,13 @@ namespace rsx if (rsx->flip_handler) { - Emu.GetCallbackManager().Async([func = rsx->flip_handler](PPUThread& ppu) - { - func(ppu, 1); + rsx->intr_thread->cmd_list + ({ + { ppu_cmd::set_args, 1 }, u64{1}, + { ppu_cmd::lle_call, rsx->flip_handler }, }); + + rsx->intr_thread->lock_notify(); } } @@ -757,10 +760,13 @@ namespace rsx { if (rsx->user_handler) { - Emu.GetCallbackManager().Async([func = rsx->user_handler, arg](PPUThread& ppu) - { - func(ppu, arg); + rsx->intr_thread->cmd_list + ({ + { ppu_cmd::set_args, 1 }, u64{arg}, + { ppu_cmd::lle_call, rsx->user_handler }, }); + + rsx->intr_thread->lock_notify(); } } diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 0d35763385..4a96ceb908 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -42,8 +42,6 @@ std::string g_cfg_defaults; extern atomic_t g_thread_count; -extern atomic_t g_ppu_core[2]; - extern u64 get_system_time(); extern void ppu_load_exec(const ppu_exec_object&); @@ -64,7 +62,6 @@ namespace rpcs3 Emulator::Emulator() : m_status(Stopped) , m_cpu_thr_stop(0) - , m_callback_manager(new CallbackManager()) { } @@ -78,9 +75,6 @@ void Emulator::Init() idm::init(); fxm::init(); - g_ppu_core[0] = 0; - g_ppu_core[1] = 0; - // Reset defaults, cache them cfg::root.from_default(); g_cfg_defaults = cfg::root.to_string(); @@ -277,7 +271,6 @@ void Emulator::Load() ppu_load_exec(ppu_exec); - Emu.GetCallbackManager().Init(); fxm::import(PURE_EXPR(Emu.GetCallbacks().get_gs_render())); // TODO: must be created in appropriate sys_rsx syscall } else if (ppu_prx.open(elf_file) == elf_error::ok) @@ -286,7 +279,6 @@ void Emulator::Load() m_status = Ready; vm::ps3::init(); ppu_load_prx(ppu_prx); - GetCallbackManager().Init(); } else if (spu_exec.open(elf_file) == elf_error::ok) { @@ -348,10 +340,9 @@ void Emulator::Run() m_pause_amend_time = 0; m_status = Running; - idm::select([](u32, cpu_thread& cpu) + idm::select([](u32, cpu_thread& cpu) { - cpu.state -= cpu_state::stop; - cpu->lock_notify(); + cpu.run(); }); SendDbgCommand(DID_STARTED_EMU); @@ -377,7 +368,7 @@ bool Emulator::Pause() SendDbgCommand(DID_PAUSE_EMU); - idm::select([](u32, cpu_thread& cpu) + idm::select([](u32, cpu_thread& cpu) { cpu.state += cpu_state::dbg_global_pause; }); @@ -411,10 +402,10 @@ void Emulator::Resume() SendDbgCommand(DID_RESUME_EMU); - idm::select([](u32, cpu_thread& cpu) + idm::select([](u32, cpu_thread& cpu) { cpu.state -= cpu_state::dbg_global_pause; - cpu->lock_notify(); + cpu.lock_notify(); }); rpcs3::on_resume()(); @@ -437,7 +428,7 @@ void Emulator::Stop() { LV2_LOCK; - idm::select([](u32, cpu_thread& cpu) + idm::select([](u32, cpu_thread& cpu) { cpu.state += cpu_state::dbg_global_stop; cpu->lock(); @@ -463,8 +454,6 @@ void Emulator::Stop() LOG_NOTICE(GENERAL, "Objects cleared..."); - GetCallbackManager().Clear(); - RSXIOMem.Clear(); vm::close(); diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index 1d46cf0d03..f5fc00bf19 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -32,8 +32,6 @@ enum Status : u32 // Emulation Stopped exception event class EmulationStopped {}; -class CallbackManager; - class Emulator final { atomic_t m_status; @@ -45,8 +43,6 @@ class Emulator final u32 m_cpu_thr_stop; - std::unique_ptr m_callback_manager; - std::string m_path; std::string m_elf_path; std::string m_title_id; @@ -107,11 +103,6 @@ public: return m_pause_amend_time; } - CallbackManager& GetCallbackManager() - { - return *m_callback_manager; - } - void SetCPUThreadStop(u32 addr) { m_cpu_thr_stop = addr; diff --git a/rpcs3/Gui/InterpreterDisAsm.cpp b/rpcs3/Gui/InterpreterDisAsm.cpp index c593d9e376..dcb4b0e3a8 100644 --- a/rpcs3/Gui/InterpreterDisAsm.cpp +++ b/rpcs3/Gui/InterpreterDisAsm.cpp @@ -25,7 +25,7 @@ u32 InterpreterDisAsmFrame::GetPc() const { switch (cpu->type) { - case cpu_type::ppu: return static_cast(cpu)->pc; + case cpu_type::ppu: return static_cast(cpu)->cia; case cpu_type::spu: return static_cast(cpu)->pc; case cpu_type::arm: return static_cast(cpu)->PC; } @@ -123,7 +123,7 @@ void InterpreterDisAsmFrame::UpdateUnitList() m_choice_units->Freeze(); m_choice_units->Clear(); - idm::select([&](u32, cpu_thread& cpu) + idm::select([&](u32, cpu_thread& cpu) { m_choice_units->Append(cpu.get_name(), &cpu); }); diff --git a/rpcs3/Gui/KernelExplorer.cpp b/rpcs3/Gui/KernelExplorer.cpp index 48dc5f64e3..634546b9d8 100644 --- a/rpcs3/Gui/KernelExplorer.cpp +++ b/rpcs3/Gui/KernelExplorer.cpp @@ -220,11 +220,11 @@ void KernelExplorer::Update() } // PPU Threads - if (const u32 count = idm::get_count()) + if (const u32 count = idm::get_count()) { const auto& node = m_tree->AppendItem(root, fmt::format("PPU Threads (%zu)", count)); - idm::select([&](u32 id, PPUThread& ppu) + idm::select([&](u32 id, ppu_thread& ppu) { m_tree->AppendItem(node, fmt::format("PPU Thread: ID = 0x%08x '%s'", id, ppu.get_name())); }); diff --git a/rpcs3/Gui/MainFrame.cpp b/rpcs3/Gui/MainFrame.cpp index 798974f13b..84b6fe6750 100644 --- a/rpcs3/Gui/MainFrame.cpp +++ b/rpcs3/Gui/MainFrame.cpp @@ -414,16 +414,16 @@ void MainFrame::Stop(wxCommandEvent& WXUNUSED(event)) } // This is ugly, but PS3 headers shall not be included there. -extern void sysutilSendSystemCommand(u64 status, u64 param); +extern void sysutil_send_system_cmd(u64 status, u64 param); void MainFrame::SendExit(wxCommandEvent& event) { - sysutilSendSystemCommand(0x0101 /* CELL_SYSUTIL_REQUEST_EXITGAME */, 0); + sysutil_send_system_cmd(0x0101 /* CELL_SYSUTIL_REQUEST_EXITGAME */, 0); } void MainFrame::SendOpenCloseSysMenu(wxCommandEvent& event) { - sysutilSendSystemCommand(m_sys_menu_opened ? 0x0132 /* CELL_SYSUTIL_SYSTEM_MENU_CLOSE */ : 0x0131 /* CELL_SYSUTIL_SYSTEM_MENU_OPEN */, 0); + sysutil_send_system_cmd(m_sys_menu_opened ? 0x0132 /* CELL_SYSUTIL_SYSTEM_MENU_CLOSE */ : 0x0131 /* CELL_SYSUTIL_SYSTEM_MENU_OPEN */, 0); m_sys_menu_opened = !m_sys_menu_opened; wxCommandEvent ce; UpdateUI(ce); diff --git a/rpcs3/Gui/RegisterEditor.cpp b/rpcs3/Gui/RegisterEditor.cpp index 184a5f6f4b..5e2ddc2731 100644 --- a/rpcs3/Gui/RegisterEditor.cpp +++ b/rpcs3/Gui/RegisterEditor.cpp @@ -86,7 +86,7 @@ RegisterEditorDialog::RegisterEditorDialog(wxPanel *parent, u32 _pc, cpu_thread* { case cpu_type::ppu: { - auto& ppu = *static_cast(cpu); + auto& ppu = *static_cast(cpu); while (value.length() < 32) value = "0" + value; std::string::size_type first_brk = reg.find('['); @@ -99,8 +99,8 @@ RegisterEditorDialog::RegisterEditorDialog(wxPanel *parent, u32 _pc, cpu_thread* { unsigned long long reg_value; reg_value = std::stoull(value.substr(16, 31), 0, 16); - if (reg.find("GPR") == 0) ppu.GPR[reg_index] = (u64)reg_value; - if (reg.find("FPR") == 0) (u64&)ppu.FPR[reg_index] = (u64)reg_value; + if (reg.find("GPR") == 0) ppu.gpr[reg_index] = (u64)reg_value; + if (reg.find("FPR") == 0) (u64&)ppu.fpr[reg_index] = (u64)reg_value; return; } if (reg.find("VR") == 0) @@ -109,8 +109,8 @@ RegisterEditorDialog::RegisterEditorDialog(wxPanel *parent, u32 _pc, cpu_thread* 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); - ppu.VR[reg_index]._u64[0] = (u64)reg_value0; - ppu.VR[reg_index]._u64[1] = (u64)reg_value1; + ppu.vr[reg_index]._u64[0] = (u64)reg_value0; + ppu.vr[reg_index]._u64[1] = (u64)reg_value1; return; } } @@ -118,15 +118,15 @@ RegisterEditorDialog::RegisterEditorDialog(wxPanel *parent, u32 _pc, cpu_thread* { unsigned long long reg_value; reg_value = std::stoull(value.substr(16, 31), 0, 16); - if (reg == "LR") ppu.LR = (u64)reg_value; - if (reg == "CTR") ppu.CTR = (u64)reg_value; + if (reg == "LR") ppu.lr = (u64)reg_value; + if (reg == "CTR") ppu.ctr = (u64)reg_value; return; } if (reg == "CR") { unsigned long long reg_value; reg_value = std::stoull(value.substr(24, 31), 0, 16); - if (reg == "CR") ppu.SetCR((u32)reg_value); + if (reg == "CR") ppu.cr_unpack((u32)reg_value); return; } } @@ -183,19 +183,19 @@ void RegisterEditorDialog::updateRegister(wxCommandEvent& event) { case cpu_type::ppu: { - auto& ppu = *static_cast(cpu); + auto& ppu = *static_cast(cpu); std::size_t first_brk = reg.find('['); if (first_brk != -1) { long reg_index = std::atol(reg.substr(first_brk + 1, reg.length() - first_brk - 2).c_str()); - if (reg.find("GPR") == 0) str = fmt::format("%016llx", ppu.GPR[reg_index]); - if (reg.find("FPR") == 0) str = fmt::format("%016llx", ppu.FPR[reg_index]); - if (reg.find("VR") == 0) str = fmt::format("%016llx%016llx", ppu.VR[reg_index]._u64[1], ppu.VR[reg_index]._u64[0]); + if (reg.find("GPR") == 0) str = fmt::format("%016llx", ppu.gpr[reg_index]); + if (reg.find("FPR") == 0) str = fmt::format("%016llx", ppu.fpr[reg_index]); + if (reg.find("VR") == 0) str = fmt::format("%016llx%016llx", ppu.vr[reg_index]._u64[1], ppu.vr[reg_index]._u64[0]); } - if (reg == "CR") str = fmt::format("%08x", ppu.GetCR()); - if (reg == "LR") str = fmt::format("%016llx", ppu.LR); - if (reg == "CTR") str = fmt::format("%016llx", ppu.CTR); + if (reg == "CR") str = fmt::format("%08x", ppu.cr_pack()); + if (reg == "LR") str = fmt::format("%016llx", ppu.lr); + if (reg == "CTR") str = fmt::format("%016llx", ppu.ctr); break; } case cpu_type::spu: diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 7cd1cedfaf..0afd13d522 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -240,7 +240,6 @@ - @@ -390,6 +389,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 9a74222c91..3d9f73ceb2 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -632,9 +632,6 @@ Emu\Cell\Modules - - Emu\Cell - Emu\Cell @@ -1696,5 +1693,8 @@ Emu\GPU\RSX + + Utilities + \ No newline at end of file