From 9ad5fc8a08c402559389f068ecfa306933aaf99a Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Sun, 15 Apr 2018 15:37:34 +0300 Subject: [PATCH] SPU: rewrite spu_channel_t --- rpcs3/Emu/Cell/SPUThread.cpp | 2 +- rpcs3/Emu/Cell/SPUThread.h | 124 +++++++++++++++++------------------ 2 files changed, 61 insertions(+), 65 deletions(-) diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index be2a05fd6f..26fbc2771f 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -1494,7 +1494,7 @@ bool SPUThread::get_ch_value(u32 ch, u32& out) { LOG_TRACE(SPU, "get_ch_value(ch=%d [%s])", ch, ch < 128 ? spu_ch_name[ch] : "???"); - auto read_channel = [&](spu_channel_t& channel) + auto read_channel = [&](spu_channel& channel) { for (int i = 0; i < 10 && channel.get_count() == 0; i++) { diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index a2c45b4a54..b4ba66269b 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -153,119 +153,115 @@ enum : u32 RAW_SPU_PROB_OFFSET = 0x00040000, }; -struct spu_channel_t +struct spu_channel { - struct alignas(8) sync_var_t - { - bool count; // value available - bool wait; // notification required - u32 value; - }; - - atomic_t data; + // Low 32 bits contain value + atomic_t data; public: - // returns true on success + static const u32 off_wait = 32; + static const u32 off_count = 63; + static const u64 bit_wait = 1ull << off_wait; + static const u64 bit_count = 1ull << off_count; + + // Returns true on success bool try_push(u32 value) { - const auto old = data.fetch_op([=](sync_var_t& data) + const u64 old = data.fetch_op([=](u64& data) { - if ((data.wait = data.count) == false) + if (UNLIKELY(data & bit_count)) { - data.count = true; - data.value = value; + data |= bit_wait; + } + else + { + data = bit_count | value; } }); - return !old.count; + return !(old & bit_count); } - // push performing bitwise OR with previous value, may require notification + // Push performing bitwise OR with previous value, may require notification void push_or(cpu_thread& spu, u32 value) { - const auto old = data.fetch_op([=](sync_var_t& data) + const u64 old = data.fetch_op([=](u64& data) { - data.count = true; - data.wait = false; - data.value |= value; + data &= ~bit_wait; + data |= bit_count | value; }); - if (old.wait) spu.notify(); + if (old & bit_wait) + { + spu.notify(); + } } bool push_and(u32 value) { - const auto old = data.fetch_op([=](sync_var_t& data) - { - data.value &= ~value; - }); - - return (old.value & value) != 0; + return (data.fetch_and(~u64{value}) & value) != 0; } - // push unconditionally (overwriting previous value), may require notification + // Push unconditionally (overwriting previous value), may require notification void push(cpu_thread& spu, u32 value) { - const auto old = data.fetch_op([=](sync_var_t& data) + if (data.exchange(bit_count | value) & bit_wait) { - data.count = true; - data.wait = false; - data.value = value; - }); - - if (old.wait) spu.notify(); + spu.notify(); + } } - // returns true on success + // Returns true on success bool try_pop(u32& out) { - const auto old = data.fetch_op([&](sync_var_t& data) + const u64 old = data.fetch_op([&](u64& data) { - if (data.count) + if (LIKELY(data & bit_count)) { - data.wait = false; - out = data.value; + out = static_cast(data); + data = 0; } else { - data.wait = true; + data |= bit_wait; } - - data.count = false; - data.value = 0; // ??? }); - return old.count; + return (old & bit_count) != 0; } - // pop unconditionally (loading last value), may require notification + // Pop unconditionally (loading last value), may require notification u32 pop(cpu_thread& spu) { - const auto old = data.fetch_op([](sync_var_t& data) + // Value is not cleared and may be read again + const u64 old = data.fetch_and(~(bit_count | bit_wait)); + + if (old & bit_wait) { - data.wait = false; - data.count = false; - // value is not cleared and may be read again - }); + spu.notify(); + } - if (old.wait) spu.notify(); - - return old.value; + return static_cast(old); } void set_value(u32 value, bool count = true) { - data.store({ count, false, value }); + const u64 new_data = u64{count} << off_count | value; +#ifdef _MSC_VER + const_cast(data.raw()) = new_data; +#else + __atomic_store_n(&data.raw(), new_data, __ATOMIC_RELAXED); +#endif } u32 get_value() { - return data.load().value; + return static_cast(data); } u32 get_count() { - return data.load().count; + return static_cast(data >> off_count); } }; @@ -551,20 +547,20 @@ public: u32 srr0; u32 ch_tag_upd; u32 ch_tag_mask; - spu_channel_t ch_tag_stat; + spu_channel ch_tag_stat; u32 ch_stall_mask; - spu_channel_t ch_stall_stat; - spu_channel_t ch_atomic_stat; + spu_channel ch_stall_stat; + spu_channel ch_atomic_stat; spu_channel_4_t ch_in_mbox; - spu_channel_t ch_out_mbox; - spu_channel_t ch_out_intr_mbox; + spu_channel ch_out_mbox; + spu_channel ch_out_intr_mbox; u64 snr_config; // SPU SNR Config Register - spu_channel_t ch_snr1; // SPU Signal Notification Register 1 - spu_channel_t ch_snr2; // SPU Signal Notification Register 2 + spu_channel ch_snr1; // SPU Signal Notification Register 1 + spu_channel ch_snr2; // SPU Signal Notification Register 2 atomic_t ch_event_mask; atomic_t ch_event_stat;