mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-01-30 12:32:43 +00:00
SPU: Implement timer freezing ability
This commit is contained in:
parent
f2920bc30d
commit
2ba437b6dc
@ -1461,7 +1461,7 @@ void spu_recompiler::RDCH(spu_opcode_t op)
|
||||
|
||||
auto sub2 = [](spu_thread* _spu, v128* _res)
|
||||
{
|
||||
const u32 out = _spu->ch_dec_value - static_cast<u32>(get_timebased_time() - _spu->ch_dec_start_timestamp);
|
||||
const u32 out = _spu->read_dec().first;
|
||||
|
||||
*_res = v128::from32r(out);
|
||||
};
|
||||
@ -2467,6 +2467,7 @@ void spu_recompiler::WRCH(spu_opcode_t op)
|
||||
{
|
||||
auto sub = [](spu_thread* _spu)
|
||||
{
|
||||
_spu->get_events(SPU_EVENT_TM);
|
||||
_spu->ch_dec_start_timestamp = get_timebased_time();
|
||||
};
|
||||
|
||||
@ -2474,6 +2475,7 @@ void spu_recompiler::WRCH(spu_opcode_t op)
|
||||
c->call(+sub);
|
||||
c->mov(qw0->r32(), SPU_OFF_32(gpr, op.rt, &v128::_u32, 3));
|
||||
c->mov(SPU_OFF_32(ch_dec_value), qw0->r32());
|
||||
c->mov(SPU_OFF_8(is_dec_frozen), 0);
|
||||
return;
|
||||
}
|
||||
case SPU_WrEventMask:
|
||||
|
@ -5579,7 +5579,7 @@ public:
|
||||
|
||||
static u32 exec_read_dec(spu_thread* _spu)
|
||||
{
|
||||
const u32 res = _spu->ch_dec_value - static_cast<u32>(get_timebased_time() - _spu->ch_dec_start_timestamp);
|
||||
const u32 res = _spu->read_dec().first;
|
||||
|
||||
if (res > 1500 && g_cfg.core.spu_loop_detection)
|
||||
{
|
||||
@ -6331,6 +6331,7 @@ public:
|
||||
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));
|
||||
m_ir->CreateStore(m_ir->getInt8(0), spu_ptr<u8>(&spu_thread::is_dec_frozen));
|
||||
return;
|
||||
}
|
||||
case SPU_Set_Bkmk_Tag:
|
||||
|
@ -1309,6 +1309,7 @@ void spu_thread::cpu_init()
|
||||
|
||||
ch_dec_start_timestamp = get_timebased_time();
|
||||
ch_dec_value = option & SYS_SPU_THREAD_OPTION_DEC_SYNC_TB_ENABLE ? ~static_cast<u32>(ch_dec_start_timestamp) : 0;
|
||||
is_dec_frozen = false;
|
||||
|
||||
if (get_type() >= spu_type::raw)
|
||||
{
|
||||
@ -3641,6 +3642,12 @@ bool spu_thread::reservation_check(u32 addr, const decltype(rdata)& data) const
|
||||
return !res;
|
||||
}
|
||||
|
||||
std::pair<u32, u32> spu_thread::read_dec() const
|
||||
{
|
||||
const u64 res = ch_dec_value - (is_dec_frozen ? 0 : (get_timebased_time() - ch_dec_start_timestamp));
|
||||
return {static_cast<u32>(res), static_cast<u32>(res >> 32)};
|
||||
}
|
||||
|
||||
spu_thread::ch_events_t spu_thread::get_events(u32 mask_hint, bool waiting, bool reading)
|
||||
{
|
||||
if (auto mask1 = ch_events.load().mask; mask1 & ~SPU_EVENT_IMPLEMENTED)
|
||||
@ -3664,7 +3671,7 @@ retry:
|
||||
// SPU Decrementer Event on underflow (use the upper 32-bits to determine it)
|
||||
if (mask_hint & SPU_EVENT_TM)
|
||||
{
|
||||
if (const u64 res = (ch_dec_value - (get_timebased_time() - ch_dec_start_timestamp)) >> 32)
|
||||
if (const u64 res = read_dec().second)
|
||||
{
|
||||
// Set next event to the next time the decrementer underflows
|
||||
ch_dec_start_timestamp -= res << 32;
|
||||
@ -3921,7 +3928,7 @@ s64 spu_thread::get_ch_value(u32 ch)
|
||||
|
||||
case SPU_RdDec:
|
||||
{
|
||||
u32 out = ch_dec_value - static_cast<u32>(get_timebased_time() - ch_dec_start_timestamp);
|
||||
u32 out = read_dec().first;
|
||||
|
||||
//Polling: We might as well hint to the scheduler to slot in another thread since this one is counting down
|
||||
if (g_cfg.core.spu_loop_detection && out > spu::scheduler::native_jiffy_duration_us)
|
||||
@ -4337,6 +4344,7 @@ bool spu_thread::set_ch_value(u32 ch, u32 value)
|
||||
get_events(SPU_EVENT_TM); // Don't discard possibly occured old event
|
||||
ch_dec_start_timestamp = get_timebased_time();
|
||||
ch_dec_value = value;
|
||||
is_dec_frozen = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -4372,10 +4380,14 @@ bool spu_thread::set_ch_value(u32 ch, u32 value)
|
||||
// "Collect" events before final acknowledgment
|
||||
get_events(value);
|
||||
|
||||
if (ch_events.atomic_op([&](ch_events_t& events)
|
||||
bool freeze_dec = false;
|
||||
|
||||
const bool check_intr = ch_events.atomic_op([&](ch_events_t& events)
|
||||
{
|
||||
events.events &= ~value;
|
||||
|
||||
freeze_dec = !!((value & SPU_EVENT_TM) & ~events.mask);
|
||||
|
||||
if (events.events & events.mask)
|
||||
{
|
||||
events.count = true;
|
||||
@ -4383,7 +4395,16 @@ bool spu_thread::set_ch_value(u32 ch, u32 value)
|
||||
}
|
||||
|
||||
return false;
|
||||
}))
|
||||
});
|
||||
|
||||
if (!is_dec_frozen && freeze_dec)
|
||||
{
|
||||
// Save current time, this will be the reported value until the decrementer resumes
|
||||
ch_dec_value = read_dec().first;
|
||||
is_dec_frozen = true;
|
||||
}
|
||||
|
||||
if (check_intr)
|
||||
{
|
||||
// Check interrupts in case count is 1
|
||||
if (check_mfc_interrupts(pc + 4))
|
||||
|
@ -733,6 +733,8 @@ public:
|
||||
|
||||
u64 ch_dec_start_timestamp; // timestamp of writing decrementer value
|
||||
u32 ch_dec_value; // written decrementer value
|
||||
bool is_dec_frozen = false;
|
||||
std::pair<u32, u32> read_dec() const; // Read decrementer
|
||||
|
||||
atomic_t<u32> run_ctrl; // SPU Run Control register (only provided to get latest data written)
|
||||
shared_mutex run_ctrl_mtx;
|
||||
|
Loading…
x
Reference in New Issue
Block a user