spu: Fix interrupt jump check - also change interrupt variable to atomic bool for ease of setting/checking

This commit is contained in:
Jake 2017-11-30 20:50:01 -06:00 committed by kd-11
parent 34e01ba3d8
commit d17093e65b
6 changed files with 15 additions and 14 deletions

View File

@ -21,7 +21,7 @@ void RawSPUThread::cpu_task()
SPUThread::cpu_task(); SPUThread::cpu_task();
// save next PC and current SPU Interrupt status // save next PC and current SPU Interrupt status
npc = pc | ((ch_event_stat & SPU_EVENT_INTR_ENABLED) != 0); npc = pc | (interrupts_enabled);
} }
void RawSPUThread::on_init(const std::shared_ptr<void>& _this) void RawSPUThread::on_init(const std::shared_ptr<void>& _this)

View File

@ -376,12 +376,12 @@ void spu_recompiler::FunctionCall()
fmt::throw_exception("Undefined behaviour" HERE); fmt::throw_exception("Undefined behaviour" HERE);
} }
_spu->set_interrupt_status(true); _spu->interrupts_enabled = true;
_spu->pc &= ~0x4000000; _spu->pc &= ~0x4000000;
} }
else if (_spu->pc & 0x8000000) else if (_spu->pc & 0x8000000)
{ {
_spu->set_interrupt_status(false); _spu->interrupts_enabled = false;
_spu->pc &= ~0x8000000; _spu->pc &= ~0x8000000;
} }

View File

@ -50,9 +50,9 @@ void spu_interpreter::set_interrupt_status(SPUThread& spu, spu_opcode_t op)
spu.set_interrupt_status(false); spu.set_interrupt_status(false);
} }
if ((spu.ch_event_stat & SPU_EVENT_INTR_TEST & spu.ch_event_mask) > SPU_EVENT_INTR_ENABLED) if (spu.interrupts_enabled && (spu.ch_event_mask & spu.ch_event_stat & SPU_EVENT_INTR_IMPLEMENTED) > 0)
{ {
spu.ch_event_stat &= ~SPU_EVENT_INTR_ENABLED; spu.interrupts_enabled = false;
spu.srr0 = std::exchange(spu.pc, -4) + 4; spu.srr0 = std::exchange(spu.pc, -4) + 4;
} }
} }

View File

@ -86,9 +86,9 @@ void spu_recompiler_base::enter(SPUThread& spu)
spu.pc = res & 0x3fffc; spu.pc = res & 0x3fffc;
if ((spu.ch_event_stat & SPU_EVENT_INTR_TEST & spu.ch_event_mask) > SPU_EVENT_INTR_ENABLED) if (spu.interrupts_enabled && (spu.ch_event_mask & spu.ch_event_stat & SPU_EVENT_INTR_IMPLEMENTED) > 0)
{ {
spu.ch_event_stat &= ~SPU_EVENT_INTR_ENABLED; spu.interrupts_enabled = false;
spu.srr0 = std::exchange(spu.pc, 0); spu.srr0 = std::exchange(spu.pc, 0);
} }
} }

View File

@ -292,6 +292,7 @@ void SPUThread::cpu_init()
ch_event_mask = 0; ch_event_mask = 0;
ch_event_stat = 0; ch_event_stat = 0;
interrupts_enabled = false;
raddr = 0; raddr = 0;
ch_dec_start_timestamp = get_timebased_time(); // ??? ch_dec_start_timestamp = get_timebased_time(); // ???
@ -974,12 +975,11 @@ void SPUThread::set_interrupt_status(bool enable)
{ {
fmt::throw_exception("SPU Interrupts not implemented (mask=0x%x)" HERE, mask); fmt::throw_exception("SPU Interrupts not implemented (mask=0x%x)" HERE, mask);
} }
interrupts_enabled = true;
ch_event_stat |= SPU_EVENT_INTR_ENABLED;
} }
else else
{ {
ch_event_stat &= ~SPU_EVENT_INTR_ENABLED; interrupts_enabled = false;
} }
} }
@ -1165,7 +1165,7 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
{ {
// HACK: "Not isolated" status // HACK: "Not isolated" status
// Return SPU Interrupt status in LSB // Return SPU Interrupt status in LSB
out = (ch_event_stat & SPU_EVENT_INTR_ENABLED) != 0; out = interrupts_enabled == true;
return true; return true;
} }
} }
@ -1467,7 +1467,7 @@ bool SPUThread::set_ch_value(u32 ch, u32 value)
case SPU_WrEventMask: case SPU_WrEventMask:
{ {
// detect masking events with enabled interrupt status // detect masking events with enabled interrupt status
if (value & ~SPU_EVENT_INTR_IMPLEMENTED && ch_event_stat & SPU_EVENT_INTR_ENABLED) if (value & ~SPU_EVENT_INTR_IMPLEMENTED && interrupts_enabled)
{ {
fmt::throw_exception("SPU Interrupts not implemented (mask=0x%x)" HERE, value); fmt::throw_exception("SPU Interrupts not implemented (mask=0x%x)" HERE, value);
} }

View File

@ -68,9 +68,9 @@ enum : u32
SPU_EVENT_WAITING = 0x80000000, // Originally unused, set when SPU thread starts waiting on ch_event_stat SPU_EVENT_WAITING = 0x80000000, // Originally unused, set when SPU thread starts waiting on ch_event_stat
//SPU_EVENT_AVAILABLE = 0x40000000, // Originally unused, channel count of the SPU_RdEventStat channel //SPU_EVENT_AVAILABLE = 0x40000000, // Originally unused, channel count of the SPU_RdEventStat channel
SPU_EVENT_INTR_ENABLED = 0x20000000, // Originally unused, represents "SPU Interrupts Enabled" status //SPU_EVENT_INTR_ENABLED = 0x20000000, // Originally unused, represents "SPU Interrupts Enabled" status
SPU_EVENT_INTR_TEST = SPU_EVENT_INTR_ENABLED | SPU_EVENT_INTR_IMPLEMENTED SPU_EVENT_INTR_TEST = SPU_EVENT_INTR_IMPLEMENTED
}; };
// SPU Class 0 Interrupts // SPU Class 0 Interrupts
@ -562,6 +562,7 @@ public:
atomic_t<u32> ch_event_mask; atomic_t<u32> ch_event_mask;
atomic_t<u32> ch_event_stat; atomic_t<u32> ch_event_stat;
atomic_t<bool> interrupts_enabled;
u64 ch_dec_start_timestamp; // timestamp of writing decrementer value u64 ch_dec_start_timestamp; // timestamp of writing decrementer value
u32 ch_dec_value; // written decrementer value u32 ch_dec_value; // written decrementer value