diff --git a/src/core/cpu_recompiler.h b/src/core/cpu_recompiler.h index db61d5a85..b3f37a7e2 100644 --- a/src/core/cpu_recompiler.h +++ b/src/core/cpu_recompiler.h @@ -105,6 +105,8 @@ protected: FLUSH_FOR_BRANCH = (FLUSH_FLUSH_MIPS_REGISTERS), FLUSH_FOR_EXCEPTION = (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_FREE_CALLER_SAVED_REGISTERS | FLUSH_PC | FLUSH_CYCLES | FLUSH_INSTRUCTION_BITS | FLUSH_LOAD_DELAY | FLUSH_GTE_DONE_CYCLE | FLUSH_INVALIDATE_SPECULATIVE_CONSTANTS), diff --git a/src/core/cpu_recompiler_arm32.cpp b/src/core/cpu_recompiler_arm32.cpp index 03a0bf902..85c0e4915 100644 --- a/src/core/cpu_recompiler_arm32.cpp +++ b/src/core/cpu_recompiler_arm32.cpp @@ -2286,11 +2286,17 @@ void CPU::ARM32Recompiler::Compile_mtc0(CompileFlags cf) armAsm->ldr(RARG1, PTR(&g_state.cop0_regs.sr.bits)); TestInterrupts(RARG1); } - - if (reg == Cop0Reg::DCIC && g_settings.cpu_recompiler_memory_exceptions) + else if (reg == Cop0Reg::DCIC || reg == Cop0Reg::BPCM) { - // TODO: DCIC handling for debug breakpoints - WARNING_LOG("TODO: DCIC handling for debug breakpoints"); + // need to check whether we're switching to debug mode + Flush(FLUSH_FOR_C_CALL); + EmitCall(reinterpret_cast(&CPU::UpdateDebugDispatcherFlag)); + SwitchToFarCodeIfRegZeroOrNonZero(RRET, true); + BackupHostState(); + Flush(FLUSH_FOR_EARLY_BLOCK_EXIT); + EmitCall(reinterpret_cast(&CPU::ExitExecution)); // does not return + RestoreHostState(); + SwitchToNearCode(false); } } diff --git a/src/core/cpu_recompiler_arm64.cpp b/src/core/cpu_recompiler_arm64.cpp index a2a961ef7..02a5773c1 100644 --- a/src/core/cpu_recompiler_arm64.cpp +++ b/src/core/cpu_recompiler_arm64.cpp @@ -2443,11 +2443,17 @@ void CPU::ARM64Recompiler::Compile_mtc0(CompileFlags cf) armAsm->ldr(RWARG1, PTR(&g_state.cop0_regs.sr.bits)); TestInterrupts(RWARG1); } - - if (reg == Cop0Reg::DCIC && g_settings.cpu_recompiler_memory_exceptions) + else if (reg == Cop0Reg::DCIC || reg == Cop0Reg::BPCM) { - // TODO: DCIC handling for debug breakpoints - WARNING_LOG("TODO: DCIC handling for debug breakpoints"); + // need to check whether we're switching to debug mode + Flush(FLUSH_FOR_C_CALL); + EmitCall(reinterpret_cast(&CPU::UpdateDebugDispatcherFlag)); + SwitchToFarCodeIfRegZeroOrNonZero(RWRET, true); + BackupHostState(); + Flush(FLUSH_FOR_EARLY_BLOCK_EXIT); + EmitCall(reinterpret_cast(&CPU::ExitExecution)); // does not return + RestoreHostState(); + SwitchToNearCode(false); } } diff --git a/src/core/cpu_recompiler_riscv64.cpp b/src/core/cpu_recompiler_riscv64.cpp index 2ac93ecb3..e6045fa88 100644 --- a/src/core/cpu_recompiler_riscv64.cpp +++ b/src/core/cpu_recompiler_riscv64.cpp @@ -2300,11 +2300,17 @@ void CPU::RISCV64Recompiler::Compile_mtc0(CompileFlags cf) rvAsm->LW(RARG1, PTR(&g_state.cop0_regs.sr.bits)); TestInterrupts(RARG1); } - - if (reg == Cop0Reg::DCIC && g_settings.cpu_recompiler_memory_exceptions) + else if (reg == Cop0Reg::DCIC || reg == Cop0Reg::BPCM) { - // TODO: DCIC handling for debug breakpoints - WARNING_LOG("TODO: DCIC handling for debug breakpoints"); + // need to check whether we're switching to debug mode + Flush(FLUSH_FOR_C_CALL); + EmitCall(reinterpret_cast(&CPU::UpdateDebugDispatcherFlag)); + SwitchToFarCode(true, &Assembler::BEQ, RRET, zero); + BackupHostState(); + Flush(FLUSH_FOR_EARLY_BLOCK_EXIT); + EmitCall(reinterpret_cast(&CPU::ExitExecution)); // does not return + RestoreHostState(); + SwitchToNearCode(false); } } diff --git a/src/core/cpu_recompiler_x64.cpp b/src/core/cpu_recompiler_x64.cpp index 1d3495640..b4c45e9af 100644 --- a/src/core/cpu_recompiler_x64.cpp +++ b/src/core/cpu_recompiler_x64.cpp @@ -2259,11 +2259,18 @@ void CPU::X64Recompiler::Compile_mtc0(CompileFlags cf) cg->mov(RWARG1, cg->dword[PTR(&g_state.cop0_regs.sr.bits)]); TestInterrupts(RWARG1); } - - if (reg == Cop0Reg::DCIC && g_settings.cpu_recompiler_memory_exceptions) + else if (reg == Cop0Reg::DCIC || reg == Cop0Reg::BPCM) { - // TODO: DCIC handling for debug breakpoints - WARNING_LOG("TODO: DCIC handling for debug breakpoints"); + // need to check whether we're switching to debug mode + 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); } }