summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Source/Core/Core/PowerPC/BreakPoints.cpp14
-rw-r--r--Source/Core/Core/PowerPC/BreakPoints.h10
-rw-r--r--Source/Core/Core/PowerPC/PowerPC.cpp3
-rw-r--r--Source/Core/DolphinQt/Debugger/BreakpointWidget.cpp55
-rw-r--r--Source/Core/DolphinQt/Debugger/BreakpointWidget.h2
-rw-r--r--Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp3
6 files changed, 82 insertions, 5 deletions
diff --git a/Source/Core/Core/PowerPC/BreakPoints.cpp b/Source/Core/Core/PowerPC/BreakPoints.cpp
index 3cf564663e..e5dca73989 100644
--- a/Source/Core/Core/PowerPC/BreakPoints.cpp
+++ b/Source/Core/Core/PowerPC/BreakPoints.cpp
@@ -34,6 +34,9 @@ bool BreakPoints::IsAddressBreakPoint(u32 address) const
bool BreakPoints::IsBreakPointEnable(u32 address) const
{
+ if (!m_breaking_enabled)
+ return false;
+
const TBreakPoint* bp = GetBreakpoint(address);
return bp != nullptr && bp->is_enabled;
}
@@ -184,6 +187,11 @@ bool BreakPoints::ToggleEnable(u32 address)
return true;
}
+void BreakPoints::EnableBreaking(bool enable)
+{
+ m_breaking_enabled = enable;
+}
+
bool BreakPoints::Remove(u32 address)
{
const auto iter = std::ranges::find(m_breakpoints, address, &TBreakPoint::address);
@@ -318,6 +326,12 @@ bool MemChecks::ToggleEnable(u32 address)
return true;
}
+void MemChecks::EnableBreaking(bool enabled)
+{
+ m_breaking_enabled = enabled;
+ Update();
+}
+
DelayedMemCheckUpdate MemChecks::Remove(u32 address)
{
const auto iter = std::ranges::find(m_mem_checks, address, &TMemCheck::start_address);
diff --git a/Source/Core/Core/PowerPC/BreakPoints.h b/Source/Core/Core/PowerPC/BreakPoints.h
index de22192f7a..da5e755dd3 100644
--- a/Source/Core/Core/PowerPC/BreakPoints.h
+++ b/Source/Core/Core/PowerPC/BreakPoints.h
@@ -87,6 +87,9 @@ public:
bool ToggleBreakPoint(u32 address);
bool ToggleEnable(u32 address);
+ void EnableBreaking(bool enable);
+ bool IsBreakingEnabled() const { return m_breaking_enabled; }
+
// Remove Breakpoint. Returns whether it was removed.
bool Remove(u32 address);
void Clear();
@@ -96,6 +99,7 @@ private:
TBreakPoints m_breakpoints;
std::optional<TBreakPoint> m_temp_breakpoint;
Core::System& m_system;
+ bool m_breaking_enabled = true;
};
class DelayedMemCheckUpdate;
@@ -126,9 +130,12 @@ public:
bool OverlapsMemcheck(u32 address, u32 length) const;
DelayedMemCheckUpdate Remove(u32 address);
+ void EnableBreaking(bool enable);
+ bool IsBreakingEnabled() const { return m_breaking_enabled; }
+
void Update();
void Clear();
- bool HasAny() const { return !m_mem_checks.empty(); }
+ bool HasAny() const { return !m_mem_checks.empty() && m_breaking_enabled; }
BitSet32 GetGPRsUsedInConditions() { return m_gprs_used_in_conditions; }
BitSet32 GetFPRsUsedInConditions() { return m_fprs_used_in_conditions; }
@@ -142,6 +149,7 @@ private:
BitSet32 m_gprs_used_in_conditions;
BitSet32 m_fprs_used_in_conditions;
bool m_mem_breakpoints_set = false;
+ bool m_breaking_enabled = true;
};
class DelayedMemCheckUpdate final
diff --git a/Source/Core/Core/PowerPC/PowerPC.cpp b/Source/Core/Core/PowerPC/PowerPC.cpp
index e5ce8ffcdb..7939b6d4bc 100644
--- a/Source/Core/Core/PowerPC/PowerPC.cpp
+++ b/Source/Core/Core/PowerPC/PowerPC.cpp
@@ -639,7 +639,8 @@ bool PowerPCManager::CheckBreakPoints()
{
const TBreakPoint* bp = m_breakpoints.GetBreakpoint(m_ppc_state.pc);
- if (!bp || !bp->is_enabled || !EvaluateCondition(m_system, bp->condition))
+ if (!m_breakpoints.IsBreakingEnabled() || !bp || !bp->is_enabled ||
+ !EvaluateCondition(m_system, bp->condition))
return false;
if (bp->log_on_hit)
diff --git a/Source/Core/DolphinQt/Debugger/BreakpointWidget.cpp b/Source/Core/DolphinQt/Debugger/BreakpointWidget.cpp
index 09b045688c..fbb5c38d9b 100644
--- a/Source/Core/DolphinQt/Debugger/BreakpointWidget.cpp
+++ b/Source/Core/DolphinQt/Debugger/BreakpointWidget.cpp
@@ -173,6 +173,7 @@ void BreakpointWidget::CreateWidgets()
layout->setContentsMargins(2, 2, 2, 2);
layout->setSpacing(0);
+ m_enabled = m_toolbar->addAction(tr("Disable"), this, &BreakpointWidget::OnToggleBreaking);
m_new = m_toolbar->addAction(tr("New"), this, &BreakpointWidget::OnNewBreakpoint);
m_clear = m_toolbar->addAction(tr("Clear"), this, &BreakpointWidget::OnClear);
@@ -190,6 +191,10 @@ void BreakpointWidget::CreateWidgets()
void BreakpointWidget::UpdateIcons()
{
+ if (m_system.GetPowerPC().GetBreakPoints().IsBreakingEnabled())
+ m_enabled->setIcon(Resources::GetThemeIcon("pause"));
+ else
+ m_enabled->setIcon(Resources::GetThemeIcon("play"));
m_new->setIcon(Resources::GetThemeIcon("debugger_add_breakpoint"));
m_clear->setIcon(Resources::GetThemeIcon("debugger_clear"));
m_load->setIcon(Resources::GetThemeIcon("debugger_load"));
@@ -289,6 +294,24 @@ void BreakpointWidget::Update()
QPixmap enabled_icon =
Resources::GetThemeIcon("debugger_breakpoint").pixmap(QSize(downscale, downscale));
+ auto& power_pc = m_system.GetPowerPC();
+ auto& breakpoints = power_pc.GetBreakPoints();
+
+ if (!breakpoints.IsBreakingEnabled())
+ {
+ // Use QPainter to draw a transparent hole in the center
+ QImage image = enabled_icon.toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied);
+ QPainter painter(&image);
+ painter.setCompositionMode(QPainter::CompositionMode_Source);
+ painter.setRenderHint(QPainter::Antialiasing, true);
+ painter.setPen(Qt::NoPen);
+ painter.setBrush(Qt::transparent);
+ // Center and radius
+ painter.drawEllipse(QPoint(downscale / 2, downscale / 2), downscale / 4, downscale / 4);
+ painter.end();
+ enabled_icon = QPixmap::fromImage(image);
+ }
+
const auto create_item = [](const QString& string = {}) {
QTableWidgetItem* item = new QTableWidgetItem(string);
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
@@ -306,8 +329,6 @@ void BreakpointWidget::Update()
Settings::Instance().IsThemeDark() ? QColor(75, 75, 75) : QColor(225, 225, 225);
disabled_item.setBackground(disabled_color);
- auto& power_pc = m_system.GetPowerPC();
- auto& breakpoints = power_pc.GetBreakPoints();
auto& memchecks = power_pc.GetMemChecks();
auto& ppc_symbol_db = power_pc.GetSymbolDB();
@@ -466,6 +487,36 @@ void BreakpointWidget::OnEditBreakpoint(u32 address, bool is_instruction_bp)
emit Host::GetInstance()->PPCBreakpointsChanged();
}
+void BreakpointWidget::OnToggleBreaking()
+{
+ auto& breakpoints = m_system.GetPowerPC().GetBreakPoints();
+ auto& memchecks = m_system.GetPowerPC().GetMemChecks();
+ // Memcheck's HasAny() will report no memchecks while breaking is disabled, so only check when
+ // breaking is true.
+ bool has_memory_bp;
+
+ // Currently toggles all code and memory breakpoints. Could be split if needed.
+ if (breakpoints.IsBreakingEnabled())
+ {
+ has_memory_bp = memchecks.HasAny();
+ breakpoints.EnableBreaking(false);
+ memchecks.EnableBreaking(false);
+ m_enabled->setText(tr("Enable"));
+ m_enabled->setIcon(Resources::GetThemeIcon("play"));
+ }
+ else
+ {
+ breakpoints.EnableBreaking(true);
+ memchecks.EnableBreaking(true);
+ has_memory_bp = memchecks.HasAny();
+ m_enabled->setText(tr("Disable"));
+ m_enabled->setIcon(Resources::GetThemeIcon("pause"));
+ }
+
+ if (has_memory_bp || !breakpoints.GetBreakPoints().empty())
+ emit Host::GetInstance()->PPCBreakpointsChanged();
+}
+
void BreakpointWidget::OnLoad()
{
Common::IniFile ini;
diff --git a/Source/Core/DolphinQt/Debugger/BreakpointWidget.h b/Source/Core/DolphinQt/Debugger/BreakpointWidget.h
index f48570f449..64dfcf1283 100644
--- a/Source/Core/DolphinQt/Debugger/BreakpointWidget.h
+++ b/Source/Core/DolphinQt/Debugger/BreakpointWidget.h
@@ -58,6 +58,7 @@ private:
void OnClear();
void OnClicked(QTableWidgetItem* item);
+ void OnToggleBreaking();
void OnNewBreakpoint();
void OnEditBreakpoint(u32 address, bool is_instruction_bp);
void OnLoad();
@@ -70,6 +71,7 @@ private:
QToolBar* m_toolbar;
QTableWidget* m_table;
+ QAction* m_enabled;
QAction* m_new;
QAction* m_clear;
QAction* m_load;
diff --git a/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp b/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp
index ce02b6baa5..c7a74ee29d 100644
--- a/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp
+++ b/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp
@@ -319,6 +319,7 @@ void CodeViewWidget::Update(const Core::CPUThreadGuard* guard)
guard ? std::make_optional(power_pc.GetPPCState().pc) : std::nullopt;
const bool dark_theme = Settings::Instance().IsThemeDark();
+ const bool breaking_enabled = power_pc.GetBreakPoints().IsBreakingEnabled();
m_branches.clear();
@@ -400,7 +401,7 @@ void CodeViewWidget::Update(const Core::CPUThreadGuard* guard)
if (bp != nullptr)
{
auto icon = Resources::GetThemeIcon("debugger_breakpoint").pixmap(QSize(rowh - 2, rowh - 2));
- if (!bp->is_enabled)
+ if (!breaking_enabled || !bp->is_enabled)
{
QPixmap disabled_icon(icon.size());
disabled_icon.fill(Qt::transparent);