SPU: rewrite spu_channel_t

This commit is contained in:
Nekotekina 2018-04-15 15:37:34 +03:00
parent 3ffafb741c
commit 9ad5fc8a08
2 changed files with 61 additions and 65 deletions

View File

@ -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++)
{

View File

@ -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<sync_var_t> data;
// Low 32 bits contain value
atomic_t<u64> 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<u32>(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<u32>(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<volatile u64&>(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<u32>(data);
}
u32 get_count()
{
return data.load().count;
return static_cast<u32>(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<u32> ch_event_mask;
atomic_t<u32> ch_event_stat;