From 7d0df300ea04b644677f26e431330556b22ea176 Mon Sep 17 00:00:00 2001 From: Elad <18193363+elad335@users.noreply.github.com> Date: Wed, 15 Apr 2026 22:20:42 +0300 Subject: [PATCH] SPU LLVM: Fix RCHCNT write channel looping --- rpcs3/Emu/Cell/SPULLVMRecompiler.cpp | 10 ++++++++++ rpcs3/Emu/Cell/SPUThread.cpp | 6 ++++++ rpcs3/Emu/Cell/SPUThread.h | 20 ++++++++++++-------- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp index d3c4a6a8f9..5b63ca80cc 100644 --- a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp @@ -4353,6 +4353,16 @@ public: { switch (op.ra) { + case SPU_WrOutMbox: + { + res.value = wait_rchcnt(::offset32(&spu_thread::ch_out_mbox), true); + break; + } + case SPU_WrOutIntrMbox: + { + res.value = wait_rchcnt(::offset32(&spu_thread::ch_out_intr_mbox), true); + break; + } case SPU_RdSigNotify1: { res.value = wait_rchcnt(::offset32(&spu_thread::ch_snr1)); diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 60e0f99cca..855d95a44e 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -7219,6 +7219,12 @@ s64 spu_channel::pop_wait(cpu_thread& spu, bool pop) { if (u64 v = jostling_value.exchange(0); !(v & bit_occupy)) { + while (data & bit_wait) + { + // Wait until notifying thread finishes operation + busy_wait(500); + } + return static_cast(v); } diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index 889d6f291c..eb4e936c3b 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -197,11 +197,12 @@ struct alignas(16) spu_channel public: static constexpr u32 off_wait = 32; - static constexpr u32 off_occupy = 32; + static constexpr u32 off_occupy = 33; static constexpr u32 off_count = 63; static constexpr u64 bit_wait = 1ull << off_wait; static constexpr u64 bit_occupy = 1ull << off_occupy; static constexpr u64 bit_count = 1ull << off_count; + static constexpr u64 occupy_ored_wait = bit_wait | bit_occupy; // Returns true on success bool try_push(u32 value) @@ -252,17 +253,20 @@ public: // Other thread has inserted a value through jostling_value, retry continue; } + + // Turn off waiting bit manually (must succeed because waiting bit can only be resetted by the thread pushed to jostling_value) + if (~this->data.fetch_and(~occupy_ored_wait) & bit_wait) + { + // Could be fatal or at emulation stopping, to be checked by the caller + ensure(false); + } + + // Fallthrough to notification + ensure(old & bit_wait); } if (old & bit_wait) { - // Turn off waiting bit manually (must succeed because waiting bit can only be resetted by the thread pushed to jostling_value) - if (!this->data.bit_test_reset(off_wait)) - { - // Could be fatal or at emulation stopping, to be checked by the caller - return { (old & bit_count) == 0, 0, false, false }; - } - if (!postpone_notify) { utils::bless>(&data)[1].notify_one();