From 47b545282e9815d9b842beebdcf649b77b6b6956 Mon Sep 17 00:00:00 2001 From: Eladash Date: Thu, 27 Aug 2020 23:36:54 +0300 Subject: [PATCH] SPU: Fix events ACK, minor optimizations (#8771) --- rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp | 10 +----- rpcs3/Emu/Cell/SPURecompiler.cpp | 13 +++++--- rpcs3/Emu/Cell/SPUThread.cpp | 44 ++++++++++++-------------- rpcs3/Emu/Cell/SPUThread.h | 2 +- 4 files changed, 30 insertions(+), 39 deletions(-) diff --git a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp index e8f3df2afc..e8e392db99 100644 --- a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp @@ -1329,15 +1329,7 @@ void spu_recompiler::get_events() { auto sub = [](spu_thread* _spu) { - if (const u64 res = (_spu->ch_dec_value - (get_timebased_time() - _spu->ch_dec_start_timestamp)) >> 32) - { - _spu->ch_dec_start_timestamp -= res << 32; - - if (!(_spu->ch_event_stat & SPU_EVENT_TM)) - { - _spu->ch_event_stat |= SPU_EVENT_TM; - } - } + _spu->get_events(SPU_EVENT_TM); }; c->bind(tcheck); diff --git a/rpcs3/Emu/Cell/SPURecompiler.cpp b/rpcs3/Emu/Cell/SPURecompiler.cpp index b7136217ba..20397f27ba 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.cpp +++ b/rpcs3/Emu/Cell/SPURecompiler.cpp @@ -5387,7 +5387,7 @@ public: static u32 exec_read_events(spu_thread* _spu) { - if (const u32 events = _spu->get_events()) + if (const u32 events = _spu->get_events(_spu->ch_event_mask)) { return events; } @@ -5522,9 +5522,9 @@ public: return _spu->get_ch_count(ch); } - static u32 exec_get_events(spu_thread* _spu) + static u32 exec_get_events(spu_thread* _spu, u32 mask) { - return _spu->get_events(); + return _spu->get_events(mask); } llvm::Value* get_rchcnt(u32 off, u64 inv = 0) @@ -5602,7 +5602,7 @@ public: } case SPU_RdEventStat: { - res.value = call("spu_get_events", &exec_get_events, m_thread); + res.value = call("spu_get_events", &exec_get_events, m_thread, m_ir->CreateLoad(spu_ptr(&spu_thread::ch_event_mask))); res.value = m_ir->CreateICmpNE(res.value, m_ir->getInt32(0)); res.value = m_ir->CreateZExt(res.value, get_type()); break; @@ -6092,6 +6092,7 @@ public: } case SPU_WrDec: { + call("spu_get_events", &exec_get_events, m_thread, m_ir->getInt32(SPU_EVENT_TM)); m_ir->CreateStore(call("get_timebased_time", &get_timebased_time), spu_ptr(&spu_thread::ch_dec_start_timestamp)); m_ir->CreateStore(val.value, spu_ptr(&spu_thread::ch_dec_value)); return; @@ -6103,6 +6104,8 @@ public: } case SPU_WrEventAck: { + // "Collect" events before final acknowledgment + call("spu_get_events", &exec_get_events, m_thread, val.value); m_ir->CreateAtomicRMW(llvm::AtomicRMWInst::And, spu_ptr(&spu_thread::ch_event_stat), eval(~val).value, llvm::AtomicOrdering::Release); return; } @@ -8583,7 +8586,7 @@ public: if (m_block) m_block->block_end = m_ir->GetInsertBlock(); const auto addr = eval(extract(get_vr(op.ra), 3) & 0x3fffc); set_link(op); - const auto res = call("spu_get_events", &exec_get_events, m_thread); + const auto res = call("spu_get_events", &exec_get_events, m_thread, m_ir->CreateLoad(spu_ptr(&spu_thread::ch_event_mask))); const auto target = add_block_indirect(op, addr); m_ir->CreateCondBr(m_ir->CreateICmpNE(res, m_ir->getInt32(0)), target, add_block_next()); } diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 8e7ebc043b..4db17d05ba 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -2346,7 +2346,7 @@ bool spu_thread::process_mfc_cmd() ch_mfc_cmd.cmd, ch_mfc_cmd.lsa, ch_mfc_cmd.eal, ch_mfc_cmd.tag, ch_mfc_cmd.size); } -u32 spu_thread::get_events(bool waiting) +u32 spu_thread::get_events(u32 mask_hint) { const u32 mask1 = ch_event_mask; @@ -2356,36 +2356,29 @@ u32 spu_thread::get_events(bool waiting) } // Check reservation status and set SPU_EVENT_LR if lost - if (raddr && ((vm::reservation_acquire(raddr, sizeof(rdata)) & -128) != rtime || !cmp_rdata(rdata, vm::_ref(raddr)))) + if (mask_hint & SPU_EVENT_LR && raddr && ((vm::reservation_acquire(raddr, sizeof(rdata)) & -128) != rtime || !cmp_rdata(rdata, vm::_ref(raddr)))) { ch_event_stat |= SPU_EVENT_LR; raddr = 0; } // SPU Decrementer Event on underflow (use the upper 32-bits to determine it) - if (const u64 res = (ch_dec_value - (get_timebased_time() - ch_dec_start_timestamp)) >> 32) + if (mask_hint & SPU_EVENT_TM) { - // Set next event to the next time the decrementer underflows - ch_dec_start_timestamp -= res << 32; - - if ((ch_event_stat & SPU_EVENT_TM) == 0) + if (const u64 res = (ch_dec_value - (get_timebased_time() - ch_dec_start_timestamp)) >> 32) { - ch_event_stat |= SPU_EVENT_TM; + // Set next event to the next time the decrementer underflows + ch_dec_start_timestamp -= res << 32; + + if ((ch_event_stat & SPU_EVENT_TM) == 0) + { + ch_event_stat |= SPU_EVENT_TM; + } } } // Simple polling or polling with atomically set/removed SPU_EVENT_WAITING flag - return !waiting ? ch_event_stat & mask1 : ch_event_stat.atomic_op([&](u32& stat) -> u32 - { - if (u32 res = stat & mask1) - { - stat &= ~SPU_EVENT_WAITING; - return res; - } - - stat |= SPU_EVENT_WAITING; - return 0; - }); + return ch_event_stat & mask1; } void spu_thread::set_events(u32 mask) @@ -2580,7 +2573,9 @@ s64 spu_thread::get_ch_value(u32 ch) case SPU_RdEventStat: { - u32 res = get_events(); + const u32 mask1 = ch_event_mask; + + u32 res = get_events(mask1); if (res) { @@ -2589,8 +2584,6 @@ s64 spu_thread::get_ch_value(u32 ch) spu_function_logger logger(*this, "MFC Events read"); - const u32 mask1 = ch_event_mask; - if (mask1 & SPU_EVENT_LR && raddr) { if (mask1 != SPU_EVENT_LR && mask1 != SPU_EVENT_LR + SPU_EVENT_TM) @@ -2599,7 +2592,7 @@ s64 spu_thread::get_ch_value(u32 ch) fmt::throw_exception("Not supported: event mask 0x%x" HERE, mask1); } - while (res = get_events(), !res) + while (res = get_events(mask1), !res) { state += cpu_flag::wait; @@ -2615,7 +2608,7 @@ s64 spu_thread::get_ch_value(u32 ch) return res; } - while (res = get_events(true), !res) + while (res = get_events(mask1), !res) { state += cpu_flag::wait; @@ -2928,6 +2921,7 @@ bool spu_thread::set_ch_value(u32 ch, u32 value) case SPU_WrDec: { + get_events(SPU_EVENT_TM); // Don't discard possibly occured old event ch_dec_start_timestamp = get_timebased_time(); ch_dec_value = value; return true; @@ -2941,6 +2935,8 @@ bool spu_thread::set_ch_value(u32 ch, u32 value) case SPU_WrEventAck: { + // "Collect" events before final acknowledgment + get_events(value); ch_event_stat &= ~value; return true; } diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index 034109f440..8d4b227ee1 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -750,7 +750,7 @@ public: u32 get_mfc_completed(); bool process_mfc_cmd(); - u32 get_events(bool waiting = false); + u32 get_events(u32 mask_hint = -1); void set_events(u32 mask); void set_interrupt_status(bool enable); bool check_mfc_interrupts(u32 nex_pc);