SPU: Fix events ACK, minor optimizations (#8771)

This commit is contained in:
Eladash 2020-08-27 23:36:54 +03:00 committed by GitHub
parent 190822c2b2
commit 47b545282e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 30 additions and 39 deletions

View file

@ -1329,15 +1329,7 @@ void spu_recompiler::get_events()
{ {
auto sub = [](spu_thread* _spu) auto sub = [](spu_thread* _spu)
{ {
if (const u64 res = (_spu->ch_dec_value - (get_timebased_time() - _spu->ch_dec_start_timestamp)) >> 32) _spu->get_events(SPU_EVENT_TM);
{
_spu->ch_dec_start_timestamp -= res << 32;
if (!(_spu->ch_event_stat & SPU_EVENT_TM))
{
_spu->ch_event_stat |= SPU_EVENT_TM;
}
}
}; };
c->bind(tcheck); c->bind(tcheck);

View file

@ -5387,7 +5387,7 @@ public:
static u32 exec_read_events(spu_thread* _spu) 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; return events;
} }
@ -5522,9 +5522,9 @@ public:
return _spu->get_ch_count(ch); 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) llvm::Value* get_rchcnt(u32 off, u64 inv = 0)
@ -5602,7 +5602,7 @@ public:
} }
case SPU_RdEventStat: 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<u32>(&spu_thread::ch_event_mask)));
res.value = m_ir->CreateICmpNE(res.value, m_ir->getInt32(0)); res.value = m_ir->CreateICmpNE(res.value, m_ir->getInt32(0));
res.value = m_ir->CreateZExt(res.value, get_type<u32>()); res.value = m_ir->CreateZExt(res.value, get_type<u32>());
break; break;
@ -6092,6 +6092,7 @@ public:
} }
case SPU_WrDec: 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<u64>(&spu_thread::ch_dec_start_timestamp)); m_ir->CreateStore(call("get_timebased_time", &get_timebased_time), spu_ptr<u64>(&spu_thread::ch_dec_start_timestamp));
m_ir->CreateStore(val.value, spu_ptr<u32>(&spu_thread::ch_dec_value)); m_ir->CreateStore(val.value, spu_ptr<u32>(&spu_thread::ch_dec_value));
return; return;
@ -6103,6 +6104,8 @@ public:
} }
case SPU_WrEventAck: 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<u32>(&spu_thread::ch_event_stat), eval(~val).value, llvm::AtomicOrdering::Release); m_ir->CreateAtomicRMW(llvm::AtomicRMWInst::And, spu_ptr<u32>(&spu_thread::ch_event_stat), eval(~val).value, llvm::AtomicOrdering::Release);
return; return;
} }
@ -8583,7 +8586,7 @@ public:
if (m_block) m_block->block_end = m_ir->GetInsertBlock(); if (m_block) m_block->block_end = m_ir->GetInsertBlock();
const auto addr = eval(extract(get_vr(op.ra), 3) & 0x3fffc); const auto addr = eval(extract(get_vr(op.ra), 3) & 0x3fffc);
set_link(op); 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<u32>(&spu_thread::ch_event_mask)));
const auto target = add_block_indirect(op, addr); const auto target = add_block_indirect(op, addr);
m_ir->CreateCondBr(m_ir->CreateICmpNE(res, m_ir->getInt32(0)), target, add_block_next()); m_ir->CreateCondBr(m_ir->CreateICmpNE(res, m_ir->getInt32(0)), target, add_block_next());
} }

View file

@ -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); 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; 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 // 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<decltype(rdata)>(raddr)))) if (mask_hint & SPU_EVENT_LR && raddr && ((vm::reservation_acquire(raddr, sizeof(rdata)) & -128) != rtime || !cmp_rdata(rdata, vm::_ref<decltype(rdata)>(raddr))))
{ {
ch_event_stat |= SPU_EVENT_LR; ch_event_stat |= SPU_EVENT_LR;
raddr = 0; raddr = 0;
} }
// SPU Decrementer Event on underflow (use the upper 32-bits to determine it) // 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 if (const u64 res = (ch_dec_value - (get_timebased_time() - ch_dec_start_timestamp)) >> 32)
ch_dec_start_timestamp -= res << 32;
if ((ch_event_stat & SPU_EVENT_TM) == 0)
{ {
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 // 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 return ch_event_stat & mask1;
{
if (u32 res = stat & mask1)
{
stat &= ~SPU_EVENT_WAITING;
return res;
}
stat |= SPU_EVENT_WAITING;
return 0;
});
} }
void spu_thread::set_events(u32 mask) void spu_thread::set_events(u32 mask)
@ -2580,7 +2573,9 @@ s64 spu_thread::get_ch_value(u32 ch)
case SPU_RdEventStat: case SPU_RdEventStat:
{ {
u32 res = get_events(); const u32 mask1 = ch_event_mask;
u32 res = get_events(mask1);
if (res) if (res)
{ {
@ -2589,8 +2584,6 @@ s64 spu_thread::get_ch_value(u32 ch)
spu_function_logger logger(*this, "MFC Events read"); 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 && raddr)
{ {
if (mask1 != SPU_EVENT_LR && mask1 != SPU_EVENT_LR + SPU_EVENT_TM) 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); 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; state += cpu_flag::wait;
@ -2615,7 +2608,7 @@ s64 spu_thread::get_ch_value(u32 ch)
return res; return res;
} }
while (res = get_events(true), !res) while (res = get_events(mask1), !res)
{ {
state += cpu_flag::wait; state += cpu_flag::wait;
@ -2928,6 +2921,7 @@ bool spu_thread::set_ch_value(u32 ch, u32 value)
case SPU_WrDec: case SPU_WrDec:
{ {
get_events(SPU_EVENT_TM); // Don't discard possibly occured old event
ch_dec_start_timestamp = get_timebased_time(); ch_dec_start_timestamp = get_timebased_time();
ch_dec_value = value; ch_dec_value = value;
return true; return true;
@ -2941,6 +2935,8 @@ bool spu_thread::set_ch_value(u32 ch, u32 value)
case SPU_WrEventAck: case SPU_WrEventAck:
{ {
// "Collect" events before final acknowledgment
get_events(value);
ch_event_stat &= ~value; ch_event_stat &= ~value;
return true; return true;
} }

View file

@ -750,7 +750,7 @@ public:
u32 get_mfc_completed(); u32 get_mfc_completed();
bool process_mfc_cmd(); bool process_mfc_cmd();
u32 get_events(bool waiting = false); u32 get_events(u32 mask_hint = -1);
void set_events(u32 mask); void set_events(u32 mask);
void set_interrupt_status(bool enable); void set_interrupt_status(bool enable);
bool check_mfc_interrupts(u32 nex_pc); bool check_mfc_interrupts(u32 nex_pc);