CPU: Flush load delays before PCDrv calls

This commit is contained in:
Stenzek 2023-11-28 18:24:42 +10:00
parent c482dfd27a
commit 08fcee2f56
No known key found for this signature in database
2 changed files with 20 additions and 10 deletions

View file

@ -27,6 +27,7 @@ namespace CPU {
static void SetPC(u32 new_pc);
static void UpdateLoadDelay();
static void Branch(u32 target);
static void FlushLoadDelay();
static void FlushPipeline();
static u32 GetExceptionVector(bool debug_exception = false);
@ -362,12 +363,19 @@ void CPU::RaiseException(Exception excode)
void CPU::RaiseBreakException(u32 CAUSE_bits, u32 EPC, u32 instruction_bits)
{
if (PCDrv::HandleSyscall(instruction_bits, g_state.regs))
if (g_settings.pcdrv_enable)
{
// immediately return
g_state.npc = EPC + 4;
FlushPipeline();
return;
// Load delays need to be flushed, because the break HLE might read a register which
// is currently being loaded, and on real hardware there isn't a hazard here.
FlushLoadDelay();
if (PCDrv::HandleSyscall(instruction_bits, g_state.regs))
{
// immediately return
g_state.npc = EPC + 4;
FlushPipeline();
return;
}
}
// normal exception
@ -394,12 +402,17 @@ ALWAYS_INLINE_RELEASE void CPU::UpdateLoadDelay()
g_state.next_load_delay_reg = Reg::count;
}
ALWAYS_INLINE_RELEASE void CPU::FlushPipeline()
ALWAYS_INLINE_RELEASE void CPU::FlushLoadDelay()
{
// loads are flushed
g_state.next_load_delay_reg = Reg::count;
g_state.regs.r[static_cast<u8>(g_state.load_delay_reg)] = g_state.load_delay_value;
g_state.load_delay_reg = Reg::count;
}
ALWAYS_INLINE_RELEASE void CPU::FlushPipeline()
{
// loads are flushed
FlushLoadDelay();
// not in a branch delay slot
g_state.branch_was_taken = false;

View file

@ -121,9 +121,6 @@ bool PCDrv::HandleSyscall(u32 instruction_bits, CPU::Registers& regs)
regs.v0 = 0xffffffff; \
regs.v1 = 0xffffffff; // error code
if (!g_settings.pcdrv_enable)
return false;
const u32 code = (instruction_bits >> 6) & 0xfffff; // 20 bits, funct = 0
switch (code)
{