diff --git a/Source/Core/DolphinWX/Debugger/CodeWindow.cpp b/Source/Core/DolphinWX/Debugger/CodeWindow.cpp index 2f1ba3aaa7..aff5d48577 100644 --- a/Source/Core/DolphinWX/Debugger/CodeWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/CodeWindow.cpp @@ -149,8 +149,6 @@ void CCodeWindow::OnHostMessage(wxCommandEvent& event) case IDM_UPDATE_DISASM_DIALOG: Update(); - if (codeview) - codeview->Center(PC); if (CPU::IsStepping()) Parent->UpdateGUI(); if (m_RegisterWindow) @@ -160,7 +158,6 @@ void CCodeWindow::OnHostMessage(wxCommandEvent& event) break; case IDM_UPDATE_BREAKPOINTS: - Update(); if (m_BreakpointWindow) m_BreakpointWindow->NotifyUpdate(); break; @@ -296,13 +293,13 @@ void CCodeWindow::SingleStep() { if (CPU::IsStepping()) { + PowerPC::CoreMode old_mode = PowerPC::GetMode(); + PowerPC::SetMode(PowerPC::MODE_INTERPRETER); PowerPC::breakpoints.ClearAllTemporary(); - JitInterface::InvalidateICache(PC, 4, true); CPU::StepOpcode(&sync_event); - wxThread::Sleep(20); - // need a short wait here - JumpToAddress(PC); - Update(); + sync_event.WaitFor(std::chrono::milliseconds(20)); + PowerPC::SetMode(old_mode); + // Will get a IDM_UPDATE_DISASM_DIALOG. Don't update the GUI here. } } @@ -316,20 +313,23 @@ void CCodeWindow::StepOver() PowerPC::breakpoints.ClearAllTemporary(); PowerPC::breakpoints.Add(PC + 4, true); CPU::EnableStepping(false); - JumpToAddress(PC); - Update(); } else { SingleStep(); } - - UpdateButtonStates(); - // Update all toolbars in the aui manager - Parent->UpdateGUI(); } } +// Returns true on a blr or on a bclr that evaluates to true. +static bool WillInstructionReturn(UGeckoInstruction inst) +{ + bool counter = (inst.BO_2 >> 2 & 1) != 0 || (CTR != 0) != ((inst.BO_2 >> 1 & 1) != 0); + bool condition = inst.BO_2 >> 4 != 0 || GetCRBit(inst.BI_2) == (inst.BO_2 >> 3 & 1); + bool isBclr = inst.OPCD_7 == 0b010011 && (inst.hex >> 1 & 0b10000) != 0; + return isBclr && counter && condition && !inst.LK_3; +} + void CCodeWindow::StepOut() { if (CPU::IsStepping()) @@ -337,13 +337,16 @@ void CCodeWindow::StepOut() CPU::PauseAndLock(true, false); PowerPC::breakpoints.ClearAllTemporary(); - // Keep stepping until the next blr or timeout after one second + // Keep stepping until the next return instruction or timeout after one second u64 timeout = SystemTimers::GetTicksPerSecond(); u64 steps = 0; - PowerPC::CoreMode oldMode = PowerPC::GetMode(); + PowerPC::CoreMode old_mode = PowerPC::GetMode(); PowerPC::SetMode(PowerPC::MODE_INTERPRETER); UGeckoInstruction inst = PowerPC::HostRead_Instruction(PC); - while (inst.hex != 0x4e800020 && steps < timeout) // check for blr + // Loop until either the current instruction is a return instruction with no Link flag + // or a breakpoint is detected so it can step at the breakpoint. + while (!(WillInstructionReturn(inst)) && steps < timeout && + !PowerPC::breakpoints.IsAddressBreakPoint(PC)) { if (inst.LK) { @@ -362,15 +365,14 @@ void CCodeWindow::StepOut() } inst = PowerPC::HostRead_Instruction(PC); } - - PowerPC::SingleStep(); - PowerPC::SetMode(oldMode); + // If the loop stopped because of a breakpoint, we do not want to step to + // an instruction after it. + if (!PowerPC::breakpoints.IsAddressBreakPoint(PC)) + PowerPC::SingleStep(); + PowerPC::SetMode(old_mode); CPU::PauseAndLock(false, false); - JumpToAddress(PC); - Update(); Host_UpdateDisasmDialog(); - UpdateButtonStates(); // Update all toolbars in the aui manager Parent->UpdateGUI(); @@ -698,7 +700,7 @@ void CCodeWindow::Update() if (!codeview) return; - codeview->Refresh(); + codeview->Center(PC); UpdateCallstack(); UpdateButtonStates();