CPU/Recompiler: Exit block early on DCIC/BPCM change

Fixes booting Xplorer cartridge with recompiler.
This commit is contained in:
Stenzek 2024-12-23 23:10:20 +10:00
parent 307bd86b72
commit 18c509a679
No known key found for this signature in database
5 changed files with 43 additions and 16 deletions

View File

@ -105,6 +105,8 @@ protected:
FLUSH_FOR_BRANCH = (FLUSH_FLUSH_MIPS_REGISTERS), FLUSH_FOR_BRANCH = (FLUSH_FLUSH_MIPS_REGISTERS),
FLUSH_FOR_EXCEPTION = FLUSH_FOR_EXCEPTION =
(FLUSH_CYCLES | FLUSH_GTE_DONE_CYCLE), // GTE cycles needed because it stalls when a GTE instruction is next. (FLUSH_CYCLES | FLUSH_GTE_DONE_CYCLE), // GTE cycles needed because it stalls when a GTE instruction is next.
FLUSH_FOR_EARLY_BLOCK_EXIT =
(FLUSH_FLUSH_MIPS_REGISTERS | FLUSH_CYCLES | FLUSH_GTE_DONE_CYCLE | FLUSH_PC | FLUSH_LOAD_DELAY),
FLUSH_FOR_INTERPRETER = (FLUSH_FLUSH_MIPS_REGISTERS | FLUSH_INVALIDATE_MIPS_REGISTERS | FLUSH_FOR_INTERPRETER = (FLUSH_FLUSH_MIPS_REGISTERS | FLUSH_INVALIDATE_MIPS_REGISTERS |
FLUSH_FREE_CALLER_SAVED_REGISTERS | FLUSH_PC | FLUSH_CYCLES | FLUSH_INSTRUCTION_BITS | FLUSH_FREE_CALLER_SAVED_REGISTERS | FLUSH_PC | FLUSH_CYCLES | FLUSH_INSTRUCTION_BITS |
FLUSH_LOAD_DELAY | FLUSH_GTE_DONE_CYCLE | FLUSH_INVALIDATE_SPECULATIVE_CONSTANTS), FLUSH_LOAD_DELAY | FLUSH_GTE_DONE_CYCLE | FLUSH_INVALIDATE_SPECULATIVE_CONSTANTS),

View File

@ -2286,11 +2286,17 @@ void CPU::ARM32Recompiler::Compile_mtc0(CompileFlags cf)
armAsm->ldr(RARG1, PTR(&g_state.cop0_regs.sr.bits)); armAsm->ldr(RARG1, PTR(&g_state.cop0_regs.sr.bits));
TestInterrupts(RARG1); TestInterrupts(RARG1);
} }
else if (reg == Cop0Reg::DCIC || reg == Cop0Reg::BPCM)
if (reg == Cop0Reg::DCIC && g_settings.cpu_recompiler_memory_exceptions)
{ {
// TODO: DCIC handling for debug breakpoints // need to check whether we're switching to debug mode
WARNING_LOG("TODO: DCIC handling for debug breakpoints"); Flush(FLUSH_FOR_C_CALL);
EmitCall(reinterpret_cast<const void*>(&CPU::UpdateDebugDispatcherFlag));
SwitchToFarCodeIfRegZeroOrNonZero(RRET, true);
BackupHostState();
Flush(FLUSH_FOR_EARLY_BLOCK_EXIT);
EmitCall(reinterpret_cast<const void*>(&CPU::ExitExecution)); // does not return
RestoreHostState();
SwitchToNearCode(false);
} }
} }

View File

@ -2443,11 +2443,17 @@ void CPU::ARM64Recompiler::Compile_mtc0(CompileFlags cf)
armAsm->ldr(RWARG1, PTR(&g_state.cop0_regs.sr.bits)); armAsm->ldr(RWARG1, PTR(&g_state.cop0_regs.sr.bits));
TestInterrupts(RWARG1); TestInterrupts(RWARG1);
} }
else if (reg == Cop0Reg::DCIC || reg == Cop0Reg::BPCM)
if (reg == Cop0Reg::DCIC && g_settings.cpu_recompiler_memory_exceptions)
{ {
// TODO: DCIC handling for debug breakpoints // need to check whether we're switching to debug mode
WARNING_LOG("TODO: DCIC handling for debug breakpoints"); Flush(FLUSH_FOR_C_CALL);
EmitCall(reinterpret_cast<const void*>(&CPU::UpdateDebugDispatcherFlag));
SwitchToFarCodeIfRegZeroOrNonZero(RWRET, true);
BackupHostState();
Flush(FLUSH_FOR_EARLY_BLOCK_EXIT);
EmitCall(reinterpret_cast<const void*>(&CPU::ExitExecution)); // does not return
RestoreHostState();
SwitchToNearCode(false);
} }
} }

View File

@ -2300,11 +2300,17 @@ void CPU::RISCV64Recompiler::Compile_mtc0(CompileFlags cf)
rvAsm->LW(RARG1, PTR(&g_state.cop0_regs.sr.bits)); rvAsm->LW(RARG1, PTR(&g_state.cop0_regs.sr.bits));
TestInterrupts(RARG1); TestInterrupts(RARG1);
} }
else if (reg == Cop0Reg::DCIC || reg == Cop0Reg::BPCM)
if (reg == Cop0Reg::DCIC && g_settings.cpu_recompiler_memory_exceptions)
{ {
// TODO: DCIC handling for debug breakpoints // need to check whether we're switching to debug mode
WARNING_LOG("TODO: DCIC handling for debug breakpoints"); Flush(FLUSH_FOR_C_CALL);
EmitCall(reinterpret_cast<const void*>(&CPU::UpdateDebugDispatcherFlag));
SwitchToFarCode(true, &Assembler::BEQ, RRET, zero);
BackupHostState();
Flush(FLUSH_FOR_EARLY_BLOCK_EXIT);
EmitCall(reinterpret_cast<const void*>(&CPU::ExitExecution)); // does not return
RestoreHostState();
SwitchToNearCode(false);
} }
} }

View File

@ -2259,11 +2259,18 @@ void CPU::X64Recompiler::Compile_mtc0(CompileFlags cf)
cg->mov(RWARG1, cg->dword[PTR(&g_state.cop0_regs.sr.bits)]); cg->mov(RWARG1, cg->dword[PTR(&g_state.cop0_regs.sr.bits)]);
TestInterrupts(RWARG1); TestInterrupts(RWARG1);
} }
else if (reg == Cop0Reg::DCIC || reg == Cop0Reg::BPCM)
if (reg == Cop0Reg::DCIC && g_settings.cpu_recompiler_memory_exceptions)
{ {
// TODO: DCIC handling for debug breakpoints // need to check whether we're switching to debug mode
WARNING_LOG("TODO: DCIC handling for debug breakpoints"); Flush(FLUSH_FOR_C_CALL);
cg->call(&CPU::UpdateDebugDispatcherFlag);
cg->test(cg->al, cg->al);
SwitchToFarCode(true, &Xbyak::CodeGenerator::jnz);
BackupHostState();
Flush(FLUSH_FOR_EARLY_BLOCK_EXIT);
cg->call(&CPU::ExitExecution); // does not return
RestoreHostState();
SwitchToNearCode(false);
} }
} }