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)
{
if (const u64 res = (_spu->ch_dec_value - (get_timebased_time() - _spu->ch_dec_start_timestamp)) >> 32)
{
_spu->ch_dec_start_timestamp -= res << 32;
if (!(_spu->ch_event_stat & SPU_EVENT_TM))
{
_spu->ch_event_stat |= SPU_EVENT_TM;
}
}
_spu->get_events(SPU_EVENT_TM);
};
c->bind(tcheck);

View File

@ -5387,7 +5387,7 @@ public:
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;
}
@ -5522,9 +5522,9 @@ public:
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)
@ -5602,7 +5602,7 @@ public:
}
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->CreateZExt(res.value, get_type<u32>());
break;
@ -6092,6 +6092,7 @@ public:
}
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(val.value, spu_ptr<u32>(&spu_thread::ch_dec_value));
return;
@ -6103,6 +6104,8 @@ public:
}
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);
return;
}
@ -8583,7 +8586,7 @@ public:
if (m_block) m_block->block_end = m_ir->GetInsertBlock();
const auto addr = eval(extract(get_vr(op.ra), 3) & 0x3fffc);
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);
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);
}
u32 spu_thread::get_events(bool waiting)
u32 spu_thread::get_events(u32 mask_hint)
{
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
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;
raddr = 0;
}
// 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
ch_dec_start_timestamp -= res << 32;
if ((ch_event_stat & SPU_EVENT_TM) == 0)
if (const u64 res = (ch_dec_value - (get_timebased_time() - ch_dec_start_timestamp)) >> 32)
{
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
return !waiting ? ch_event_stat & mask1 : ch_event_stat.atomic_op([&](u32& stat) -> u32
{
if (u32 res = stat & mask1)
{
stat &= ~SPU_EVENT_WAITING;
return res;
}
stat |= SPU_EVENT_WAITING;
return 0;
});
return ch_event_stat & mask1;
}
void spu_thread::set_events(u32 mask)
@ -2580,7 +2573,9 @@ s64 spu_thread::get_ch_value(u32 ch)
case SPU_RdEventStat:
{
u32 res = get_events();
const u32 mask1 = ch_event_mask;
u32 res = get_events(mask1);
if (res)
{
@ -2589,8 +2584,6 @@ s64 spu_thread::get_ch_value(u32 ch)
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 && 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);
}
while (res = get_events(), !res)
while (res = get_events(mask1), !res)
{
state += cpu_flag::wait;
@ -2615,7 +2608,7 @@ s64 spu_thread::get_ch_value(u32 ch)
return res;
}
while (res = get_events(true), !res)
while (res = get_events(mask1), !res)
{
state += cpu_flag::wait;
@ -2928,6 +2921,7 @@ bool spu_thread::set_ch_value(u32 ch, u32 value)
case SPU_WrDec:
{
get_events(SPU_EVENT_TM); // Don't discard possibly occured old event
ch_dec_start_timestamp = get_timebased_time();
ch_dec_value = value;
return true;
@ -2941,6 +2935,8 @@ bool spu_thread::set_ch_value(u32 ch, u32 value)
case SPU_WrEventAck:
{
// "Collect" events before final acknowledgment
get_events(value);
ch_event_stat &= ~value;
return true;
}

View File

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