SPU: Implement S1/S2 (SNR) events (closes #8789)

Add TSX path in push_snr()
Add locks bits in ch_events
This commit is contained in:
Nekotekina 2020-10-12 17:19:06 +03:00
parent b57a9c31f0
commit a806be8bc4
2 changed files with 92 additions and 13 deletions

View File

@ -1248,15 +1248,79 @@ void spu_thread::push_snr(u32 number, u32 value)
// Get channel
const auto channel = number & 1 ? &ch_snr2 : &ch_snr1;
// Check corresponding SNR register settings
if ((snr_config >> number) & 1)
// Prepare some data
const u32 event_bit = SPU_EVENT_S1 >> (number & 1);
const u32 bitor_bit = (snr_config >> number) & 1;
if (g_use_rtm)
{
channel->push_or(value);
bool channel_notify = false;
bool thread_notify = false;
const bool ok = utils::tx_start([&]
{
channel_notify = (channel->data.raw() & spu_channel::bit_wait) != 0;
thread_notify = (channel->data.raw() & spu_channel::bit_count) == 0;
if (bitor_bit)
{
channel->data.raw() &= ~spu_channel::bit_wait;
channel->data.raw() |= spu_channel::bit_count | value;
}
else
{
channel->data.raw() = spu_channel::bit_count | value;
}
if (thread_notify)
{
ch_events.raw().events |= event_bit;
if (ch_events.raw().mask & event_bit)
{
ch_events.raw().count = 1;
thread_notify = ch_events.raw().waiting != 0;
}
else
{
thread_notify = false;
}
}
});
if (ok)
{
if (channel_notify)
channel->data.notify_one();
if (thread_notify)
this->notify();
return;
}
}
// Lock event channel in case it needs event notification
ch_events.atomic_op([](ch_events_t& ev)
{
ev.locks++;
});
// Check corresponding SNR register settings
if (bitor_bit)
{
if (channel->push_or(value))
set_events(event_bit);
}
else
{
channel->push(value);
if (channel->push(value))
set_events(event_bit);
}
ch_events.atomic_op([](ch_events_t& ev)
{
ev.locks--;
});
}
void spu_thread::do_dma_transfer(const spu_mfc_cmd& args)
@ -1389,7 +1453,7 @@ void spu_thread::do_dma_transfer(const spu_mfc_cmd& args)
cpu->set_events(SPU_EVENT_LR);
cpu->raddr = 0;
}
switch (size0)
{
case 1:
@ -2465,6 +2529,7 @@ spu_thread::ch_events_t spu_thread::get_events(u32 mask_hint, bool waiting, bool
fmt::throw_exception("SPU Events not implemented (mask=0x%x)" HERE, mask1);
}
retry:
u32 collect = 0;
// Check reservation status and set SPU_EVENT_LR if lost
@ -2490,7 +2555,7 @@ spu_thread::ch_events_t spu_thread::get_events(u32 mask_hint, bool waiting, bool
set_events(collect);
}
return ch_events.fetch_op([&](ch_events_t& events)
auto [res, ok] = ch_events.fetch_op([&](ch_events_t& events)
{
if (!reading)
return false;
@ -2499,7 +2564,15 @@ spu_thread::ch_events_t spu_thread::get_events(u32 mask_hint, bool waiting, bool
events.count = false;
return true;
}).first;
});
if (reading && res.locks && mask_hint & (SPU_EVENT_S1 | SPU_EVENT_S2))
{
busy_wait(100);
goto retry;
}
return res;
}
void spu_thread::set_events(u32 bits)
@ -2520,8 +2593,7 @@ void spu_thread::set_events(u32 bits)
return false;
}))
{
// Preserved for external events implementation
//notify();
notify();
}
}

View File

@ -75,7 +75,7 @@ enum : u32
SPU_EVENT_SN = 0x2, // MFC List Command stall-and-notify event
SPU_EVENT_TG = 0x1, // MFC Tag Group status update event
SPU_EVENT_IMPLEMENTED = SPU_EVENT_LR | SPU_EVENT_TM | SPU_EVENT_SN, // Mask of implemented events
SPU_EVENT_IMPLEMENTED = SPU_EVENT_LR | SPU_EVENT_TM | SPU_EVENT_SN | SPU_EVENT_S1 | SPU_EVENT_S2, // Mask of implemented events
SPU_EVENT_INTR_IMPLEMENTED = SPU_EVENT_SN,
SPU_EVENT_INTR_TEST = SPU_EVENT_INTR_IMPLEMENTED,
@ -187,7 +187,7 @@ public:
}
// Push performing bitwise OR with previous value, may require notification
void push_or(u32 value)
bool push_or(u32 value)
{
const u64 old = data.fetch_op([value](u64& data)
{
@ -199,6 +199,8 @@ public:
{
data.notify_one();
}
return (old & bit_count) == 0;
}
bool push_and(u32 value)
@ -207,12 +209,16 @@ public:
}
// Push unconditionally (overwriting previous value), may require notification
void push(u32 value)
bool push(u32 value)
{
if (data.exchange(bit_count | value) & bit_wait)
const u64 old = data.exchange(bit_count | value);
if (old & bit_wait)
{
data.notify_one();
}
return (old & bit_count) == 0;
}
// Returns true on success
@ -694,6 +700,7 @@ public:
{
u64 all;
bf_t<u64, 0, 16> events;
bf_t<u64, 16, 8> locks;
bf_t<u64, 30, 1> waiting;
bf_t<u64, 31, 1> count;
bf_t<u64, 32, 32> mask;