mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-01-30 12:32:43 +00:00
SPU: rewrite spu_channel_t
This commit is contained in:
parent
3ffafb741c
commit
9ad5fc8a08
@ -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] : "???");
|
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++)
|
for (int i = 0; i < 10 && channel.get_count() == 0; i++)
|
||||||
{
|
{
|
||||||
|
@ -153,119 +153,115 @@ enum : u32
|
|||||||
RAW_SPU_PROB_OFFSET = 0x00040000,
|
RAW_SPU_PROB_OFFSET = 0x00040000,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct spu_channel_t
|
struct spu_channel
|
||||||
{
|
{
|
||||||
struct alignas(8) sync_var_t
|
// Low 32 bits contain value
|
||||||
{
|
atomic_t<u64> data;
|
||||||
bool count; // value available
|
|
||||||
bool wait; // notification required
|
|
||||||
u32 value;
|
|
||||||
};
|
|
||||||
|
|
||||||
atomic_t<sync_var_t> data;
|
|
||||||
|
|
||||||
public:
|
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)
|
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 |= bit_wait;
|
||||||
data.value = value;
|
}
|
||||||
|
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)
|
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 &= ~bit_wait;
|
||||||
data.wait = false;
|
data |= bit_count | value;
|
||||||
data.value |= value;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (old.wait) spu.notify();
|
if (old & bit_wait)
|
||||||
|
{
|
||||||
|
spu.notify();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool push_and(u32 value)
|
bool push_and(u32 value)
|
||||||
{
|
{
|
||||||
const auto old = data.fetch_op([=](sync_var_t& data)
|
return (data.fetch_and(~u64{value}) & value) != 0;
|
||||||
{
|
|
||||||
data.value &= ~value;
|
|
||||||
});
|
|
||||||
|
|
||||||
return (old.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)
|
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;
|
spu.notify();
|
||||||
data.wait = false;
|
}
|
||||||
data.value = value;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (old.wait) spu.notify();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns true on success
|
// Returns true on success
|
||||||
bool try_pop(u32& out)
|
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 = static_cast<u32>(data);
|
||||||
out = data.value;
|
data = 0;
|
||||||
}
|
}
|
||||||
else
|
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)
|
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;
|
spu.notify();
|
||||||
data.count = false;
|
}
|
||||||
// value is not cleared and may be read again
|
|
||||||
});
|
|
||||||
|
|
||||||
if (old.wait) spu.notify();
|
return static_cast<u32>(old);
|
||||||
|
|
||||||
return old.value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_value(u32 value, bool count = true)
|
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()
|
u32 get_value()
|
||||||
{
|
{
|
||||||
return data.load().value;
|
return static_cast<u32>(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 get_count()
|
u32 get_count()
|
||||||
{
|
{
|
||||||
return data.load().count;
|
return static_cast<u32>(data >> off_count);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -551,20 +547,20 @@ public:
|
|||||||
u32 srr0;
|
u32 srr0;
|
||||||
u32 ch_tag_upd;
|
u32 ch_tag_upd;
|
||||||
u32 ch_tag_mask;
|
u32 ch_tag_mask;
|
||||||
spu_channel_t ch_tag_stat;
|
spu_channel ch_tag_stat;
|
||||||
u32 ch_stall_mask;
|
u32 ch_stall_mask;
|
||||||
spu_channel_t ch_stall_stat;
|
spu_channel ch_stall_stat;
|
||||||
spu_channel_t ch_atomic_stat;
|
spu_channel ch_atomic_stat;
|
||||||
|
|
||||||
spu_channel_4_t ch_in_mbox;
|
spu_channel_4_t ch_in_mbox;
|
||||||
|
|
||||||
spu_channel_t ch_out_mbox;
|
spu_channel ch_out_mbox;
|
||||||
spu_channel_t ch_out_intr_mbox;
|
spu_channel ch_out_intr_mbox;
|
||||||
|
|
||||||
u64 snr_config; // SPU SNR Config Register
|
u64 snr_config; // SPU SNR Config Register
|
||||||
|
|
||||||
spu_channel_t ch_snr1; // SPU Signal Notification Register 1
|
spu_channel ch_snr1; // SPU Signal Notification Register 1
|
||||||
spu_channel_t ch_snr2; // SPU Signal Notification Register 2
|
spu_channel ch_snr2; // SPU Signal Notification Register 2
|
||||||
|
|
||||||
atomic_t<u32> ch_event_mask;
|
atomic_t<u32> ch_event_mask;
|
||||||
atomic_t<u32> ch_event_stat;
|
atomic_t<u32> ch_event_stat;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user