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 SetPC(u32 new_pc);
static void UpdateLoadDelay(); static void UpdateLoadDelay();
static void Branch(u32 target); static void Branch(u32 target);
static void FlushLoadDelay();
static void FlushPipeline(); static void FlushPipeline();
static u32 GetExceptionVector(bool debug_exception = false); 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) 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 // Load delays need to be flushed, because the break HLE might read a register which
g_state.npc = EPC + 4; // is currently being loaded, and on real hardware there isn't a hazard here.
FlushPipeline(); FlushLoadDelay();
return;
if (PCDrv::HandleSyscall(instruction_bits, g_state.regs))
{
// immediately return
g_state.npc = EPC + 4;
FlushPipeline();
return;
}
} }
// normal exception // normal exception
@ -394,12 +402,17 @@ ALWAYS_INLINE_RELEASE void CPU::UpdateLoadDelay()
g_state.next_load_delay_reg = Reg::count; 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.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.regs.r[static_cast<u8>(g_state.load_delay_reg)] = g_state.load_delay_value;
g_state.load_delay_reg = Reg::count; g_state.load_delay_reg = Reg::count;
}
ALWAYS_INLINE_RELEASE void CPU::FlushPipeline()
{
// loads are flushed
FlushLoadDelay();
// not in a branch delay slot // not in a branch delay slot
g_state.branch_was_taken = false; 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.v0 = 0xffffffff; \
regs.v1 = 0xffffffff; // error code regs.v1 = 0xffffffff; // error code
if (!g_settings.pcdrv_enable)
return false;
const u32 code = (instruction_bits >> 6) & 0xfffff; // 20 bits, funct = 0 const u32 code = (instruction_bits >> 6) & 0xfffff; // 20 bits, funct = 0
switch (code) switch (code)
{ {