SPU LLVM: Fix RCHCNT write channel looping

This commit is contained in:
Elad 2026-04-15 22:20:42 +03:00
parent 1ca8ab393a
commit 7d0df300ea
3 changed files with 28 additions and 8 deletions

View File

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

View File

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

View File

@ -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<atomic_t<u32>>(&data)[1].notify_one();