CPU: Move interrupt check out of inner-most exec loop

This commit is contained in:
Connor McLaughlin
2020-10-17 01:28:08 +10:00
parent 0afdc04d88
commit cb351a7dbd
5 changed files with 66 additions and 51 deletions

View File

@ -229,7 +229,16 @@ void RaiseException(u32 CAUSE_bits, u32 EPC)
void SetExternalInterrupt(u8 bit)
{
g_state.cop0_regs.cause.Ip |= static_cast<u8>(1u << bit);
g_state.interrupt_delay = 1;
if (g_settings.cpu_execution_mode == CPUExecutionMode::Interpreter)
{
g_state.interrupt_delay = 1;
}
else
{
g_state.interrupt_delay = 0;
CheckForPendingInterrupt();
}
}
void ClearExternalInterrupt(u8 bit)
@ -395,6 +404,7 @@ ALWAYS_INLINE_RELEASE static void WriteCop0Reg(Cop0Reg reg, u32 value)
g_state.cop0_regs.sr.bits =
(g_state.cop0_regs.sr.bits & ~Cop0Registers::SR::WRITE_MASK) | (value & Cop0Registers::SR::WRITE_MASK);
Log_DebugPrintf("COP0 SR <- %08X (now %08X)", value, g_state.cop0_regs.sr.bits);
CheckForPendingInterrupt();
}
break;
@ -403,6 +413,7 @@ ALWAYS_INLINE_RELEASE static void WriteCop0Reg(Cop0Reg reg, u32 value)
g_state.cop0_regs.cause.bits =
(g_state.cop0_regs.cause.bits & ~Cop0Registers::CAUSE::WRITE_MASK) | (value & Cop0Registers::CAUSE::WRITE_MASK);
Log_DebugPrintf("COP0 CAUSE <- %08X (now %08X)", value, g_state.cop0_regs.cause.bits);
CheckForPendingInterrupt();
}
break;
@ -1216,6 +1227,7 @@ restart_instruction:
// restore mode
g_state.cop0_regs.sr.mode_bits =
(g_state.cop0_regs.sr.mode_bits & UINT32_C(0b110000)) | (g_state.cop0_regs.sr.mode_bits >> 2);
CheckForPendingInterrupt();
}
break;
@ -1365,6 +1377,20 @@ restart_instruction:
}
}
void DispatchInterrupt()
{
// If the instruction we're about to execute is a GTE instruction, delay dispatching the interrupt until the next
// instruction. For some reason, if we don't do this, we end up with incorrectly sorted polygons and flickering..
if (g_state.next_instruction.op == InstructionOp::cop2 && !g_state.next_instruction.cop.IsCommonInstruction())
GTE::ExecuteInstruction(g_state.next_instruction.bits);
// Interrupt raising occurs before the start of the instruction.
RaiseException(
Cop0Registers::CAUSE::MakeValueForException(Exception::INT, g_state.next_instruction_is_branch_delay_slot,
g_state.branch_was_taken, g_state.next_instruction.cop.cop_n),
g_state.regs.pc);
}
template<PGXPMode pgxp_mode>
static void ExecuteImpl()
{
@ -1375,9 +1401,10 @@ static void ExecuteImpl()
while (g_state.pending_ticks < g_state.downcount)
{
if (HasPendingInterrupt())
if (HasPendingInterrupt() && !g_state.interrupt_delay)
DispatchInterrupt();
g_state.interrupt_delay = false;
g_state.pending_ticks++;
// now executing the instruction we previously fetched