From 8f76a32be4af4ecd02839e05acfe1519deb36551 Mon Sep 17 00:00:00 2001 From: mitaclaw <140017135+mitaclaw@users.noreply.github.com> Date: Tue, 6 Aug 2024 05:04:50 -0700 Subject: [PATCH] Branch Watch Tool: New Conditional Branch Inspection Tools Invert conditions, invert decrement checks, and make conditional branches unconditional. USnapshotMetadata in prior versions of Dolphin is forward-compatible with these changes (tested on x86_64). --- Source/Core/Core/Debugger/BranchWatch.cpp | 4 +- Source/Core/Core/Debugger/BranchWatch.h | 2 + Source/Core/Core/PowerPC/Gekko.h | 8 ++ .../DolphinQt/Debugger/BranchWatchDialog.cpp | 128 +++++++++++++++--- .../DolphinQt/Debugger/BranchWatchDialog.h | 12 +- .../Debugger/BranchWatchTableModel.cpp | 127 +++++++++-------- .../Debugger/BranchWatchTableModel.h | 5 + 7 files changed, 199 insertions(+), 87 deletions(-) diff --git a/Source/Core/Core/Debugger/BranchWatch.cpp b/Source/Core/Core/Debugger/BranchWatch.cpp index 73e6892258..4ea0559cd9 100644 --- a/Source/Core/Core/Debugger/BranchWatch.cpp +++ b/Source/Core/Core/Debugger/BranchWatch.cpp @@ -38,14 +38,14 @@ union USnapshotMetadata using Inspection = BranchWatch::SelectionInspection; using StorageType = unsigned long long; - static_assert(Inspection::EndOfEnumeration == Inspection{(1u << 3) + 1}); + static_assert(Inspection::EndOfEnumeration == Inspection{(1u << 5) + 1}); StorageType hex; BitField<0, 1, bool, StorageType> is_virtual; BitField<1, 1, bool, StorageType> condition; BitField<2, 1, bool, StorageType> is_selected; - BitField<3, 4, Inspection, StorageType> inspection; + BitField<3, 6, Inspection, StorageType> inspection; USnapshotMetadata() : hex(0) {} explicit USnapshotMetadata(bool is_virtual_, bool condition_, bool is_selected_, diff --git a/Source/Core/Core/Debugger/BranchWatch.h b/Source/Core/Core/Debugger/BranchWatch.h index 32dc28853d..5644a979ba 100644 --- a/Source/Core/Core/Debugger/BranchWatch.h +++ b/Source/Core/Core/Debugger/BranchWatch.h @@ -63,6 +63,8 @@ enum class BranchWatchSelectionInspection : u8 SetDestinBLR = 1u << 1, SetOriginSymbolBLR = 1u << 2, SetDestinSymbolBLR = 1u << 3, + InvertBranchOption = 1u << 4, // Used for both conditions and decrement checks. + MakeUnconditional = 1u << 5, EndOfEnumeration, }; diff --git a/Source/Core/Core/PowerPC/Gekko.h b/Source/Core/Core/PowerPC/Gekko.h index 86c6dd8632..12d6a6bcc8 100644 --- a/Source/Core/Core/PowerPC/Gekko.h +++ b/Source/Core/Core/PowerPC/Gekko.h @@ -294,6 +294,14 @@ union UGeckoInstruction }; }; +// Precondition: inst is a bx, bcx, bclrx, or bcctrx instruction. +constexpr bool BranchIsConditional(UGeckoInstruction inst) +{ + if (inst.OPCD == 18) // bx + return false; + return (inst.BO & 0b10100) != 0b10100; // 1z1zz - Branch always +} + // Used in implementations of rlwimi, rlwinm, and rlwnm inline u32 MakeRotationMask(u32 mb, u32 me) { diff --git a/Source/Core/DolphinQt/Debugger/BranchWatchDialog.cpp b/Source/Core/DolphinQt/Debugger/BranchWatchDialog.cpp index aef6f18cc3..8e740daffd 100644 --- a/Source/Core/DolphinQt/Debugger/BranchWatchDialog.cpp +++ b/Source/Core/DolphinQt/Debugger/BranchWatchDialog.cpp @@ -105,6 +105,8 @@ public: bool IsBranchTypeAllowed(UGeckoInstruction inst) const; void SetInspected(const QModelIndex& index) const; + const Core::BranchWatchSelectionValueType& + GetBranchWatchSelection(const QModelIndex& index) const; private: const Core::BranchWatch& m_branch_watch; @@ -157,34 +159,25 @@ bool BranchWatchProxyModel::filterAcceptsRow(int source_row, const QModelIndex&) return true; } -static constexpr bool BranchSavesLR(UGeckoInstruction inst) -{ - DEBUG_ASSERT(inst.OPCD == 18 || inst.OPCD == 16 || - (inst.OPCD == 19 && (inst.SUBOP10 == 16 || inst.SUBOP10 == 528))); - // Every branch instruction uses the same LK field. - return inst.LK; -} - bool BranchWatchProxyModel::IsBranchTypeAllowed(UGeckoInstruction inst) const { - const bool lr_saved = BranchSavesLR(inst); switch (inst.OPCD) { case 18: - return lr_saved ? m_bl : m_b; + return inst.LK ? m_bl : m_b; case 16: - return lr_saved ? m_bcl : m_bc; + return inst.LK ? m_bcl : m_bc; case 19: switch (inst.SUBOP10) { case 16: if ((inst.BO & 0b10100) == 0b10100) // 1z1zz - Branch always - return lr_saved ? m_blrl : m_blr; - return lr_saved ? m_bclrl : m_bclr; + return inst.LK ? m_blrl : m_blr; + return inst.LK ? m_bclrl : m_bclr; case 528: if ((inst.BO & 0b10100) == 0b10100) // 1z1zz - Branch always - return lr_saved ? m_bctrl : m_bctr; - return lr_saved ? m_bcctrl : m_bcctr; + return inst.LK ? m_bctrl : m_bctr; + return inst.LK ? m_bcctrl : m_bcctr; } } return false; @@ -195,6 +188,12 @@ void BranchWatchProxyModel::SetInspected(const QModelIndex& index) const sourceModel()->SetInspected(mapToSource(index)); } +const Core::BranchWatchSelectionValueType& +BranchWatchProxyModel::GetBranchWatchSelection(const QModelIndex& index) const +{ + return sourceModel()->GetBranchWatchSelection(mapToSource(index)); +} + BranchWatchDialog::BranchWatchDialog(Core::System& system, Core::BranchWatch& branch_watch, PPCSymbolDB& ppc_symbol_db, CodeWidget* code_widget, QWidget* parent) @@ -419,6 +418,18 @@ BranchWatchDialog::BranchWatchDialog(Core::System& system, Core::BranchWatch& br auto* const delete_action = new QAction(tr("&Delete"), this); connect(delete_action, &QAction::triggered, this, &BranchWatchDialog::OnTableDelete); + m_act_invert_condition = new QAction(tr("Invert &Condition"), this); + connect(m_act_invert_condition, &QAction::triggered, this, + &BranchWatchDialog::OnTableInvertCondition); + + m_act_invert_decrement_check = new QAction(tr("Invert &Decrement Check"), this); + connect(m_act_invert_decrement_check, &QAction::triggered, this, + &BranchWatchDialog::OnTableInvertDecrementCheck); + + m_act_make_unconditional = new QAction(tr("Make &Unconditional"), this); + connect(m_act_make_unconditional, &QAction::triggered, this, + &BranchWatchDialog::OnTableMakeUnconditional); + m_act_copy_address = new QAction(tr("&Copy Address"), this); connect(m_act_copy_address, &QAction::triggered, this, &BranchWatchDialog::OnTableCopyAddress); @@ -436,6 +447,13 @@ BranchWatchDialog::BranchWatchDialog(Core::System& system, Core::BranchWatch& br m_act_both_on_hit = m_mnu_set_breakpoint->addAction(tr("Break &and Log on Hit"), this, &BranchWatchDialog::OnTableSetBreakpointBoth); + m_mnu_table_context_instruction = new QMenu(this); + m_mnu_table_context_instruction->addActions( + {delete_action, m_act_invert_condition, m_act_invert_decrement_check}); + + m_mnu_table_context_condition = new QMenu(this); + m_mnu_table_context_condition->addActions({delete_action, m_act_make_unconditional}); + m_mnu_table_context_origin = new QMenu(this); m_mnu_table_context_origin->addActions( {delete_action, m_act_insert_nop, m_act_copy_address, m_mnu_set_breakpoint->menuAction()}); @@ -734,6 +752,15 @@ void BranchWatchDialog::OnHelp() "destination symbol columns, these actions will only be enabled if every row in the " "selection has a symbol." "\n\n" + "If the instruction column of a row selection is right-clicked, an action to invert the " + "branch instruction's condition and an action to invert the branch instruction's " + "decrement check will be available, but only if the branch instruction is a conditional " + "one." + "\n\n" + "If the condition column of a row selection is right-clicked, an action to make the " + "branch instruction unconditional will be available, but only if the branch instruction " + "is a conditional one." + "\n\n" "If the origin column of a row selection is right-clicked, an action to replace the " "branch instruction at the origin(s) with a NOP instruction (No Operation) will be " "available." @@ -851,6 +878,33 @@ void BranchWatchDialog::OnTableSetNOP() const SetStubPatches(0x60000000); } +void BranchWatchDialog::OnTableInvertCondition() const +{ + SetEditPatches([](u32 hex) { + UGeckoInstruction inst = hex; + inst.BO ^= 0b01000; + return inst.hex; + }); +} + +void BranchWatchDialog::OnTableInvertDecrementCheck() const +{ + SetEditPatches([](u32 hex) { + UGeckoInstruction inst = hex; + inst.BO ^= 0b00010; + return inst.hex; + }); +} + +void BranchWatchDialog::OnTableMakeUnconditional() const +{ + SetEditPatches([](u32 hex) { + UGeckoInstruction inst = hex; + inst.BO = 0b10100; // 1z1zz - Branch always + return inst.hex; + }); +} + void BranchWatchDialog::OnTableCopyAddress() const { auto iter = m_index_list_temp.begin(); @@ -1047,6 +1101,21 @@ void BranchWatchDialog::SetStubPatches(u32 value) const m_code_widget->Update(); } +void BranchWatchDialog::SetEditPatches(u32 (*transform)(u32)) const +{ + auto& debug_interface = m_system.GetPowerPC().GetDebugInterface(); + for (const Core::CPUThreadGuard guard(m_system); const QModelIndex& index : m_index_list_temp) + { + const Core::BranchWatchCollectionKey& k = + m_table_proxy->GetBranchWatchSelection(index).collection_ptr->first; + // This function assumes patches apply to the origin address, unlike SetStubPatches. + debug_interface.SetPatch(guard, k.origin_addr, transform(k.original_inst.hex)); + m_table_proxy->SetInspected(index); + } + // TODO: Same issue as SetStubPatches. + m_code_widget->Update(); +} + void BranchWatchDialog::SetBreakpoints(bool break_on_hit, bool log_on_hit) const { auto& breakpoints = m_system.GetPowerPC().GetBreakPoints(); @@ -1092,8 +1161,9 @@ QMenu* BranchWatchDialog::GetTableContextMenu(const QModelIndex& index) const switch (index.column()) { case Column::Instruction: + return GetTableContextMenu_Instruction(core_initialized); case Column::Condition: - return m_mnu_table_context_other; + return GetTableContextMenu_Condition(core_initialized); case Column::Origin: return GetTableContextMenu_Origin(core_initialized); case Column::Destination: @@ -1109,6 +1179,29 @@ QMenu* BranchWatchDialog::GetTableContextMenu(const QModelIndex& index) const Common::Unreachable(); } +QMenu* BranchWatchDialog::GetTableContextMenu_Instruction(bool core_initialized) const +{ + const bool all_branches_conditional = // Taking advantage of short-circuit evaluation here. + core_initialized && std::ranges::all_of(m_index_list_temp, [this](const QModelIndex& index) { + return BranchIsConditional( + m_table_proxy->GetBranchWatchSelection(index).collection_ptr->first.original_inst); + }); + m_act_invert_condition->setEnabled(all_branches_conditional); + m_act_invert_decrement_check->setEnabled(all_branches_conditional); + return m_mnu_table_context_instruction; +} + +QMenu* BranchWatchDialog::GetTableContextMenu_Condition(bool core_initialized) const +{ + const bool all_branches_conditional = // Taking advantage of short-circuit evaluation here. + core_initialized && std::ranges::all_of(m_index_list_temp, [this](const QModelIndex& index) { + return BranchIsConditional( + m_table_proxy->GetBranchWatchSelection(index).collection_ptr->first.original_inst); + }); + m_act_make_unconditional->setEnabled(all_branches_conditional); + return m_mnu_table_context_condition; +} + QMenu* BranchWatchDialog::GetTableContextMenu_Origin(bool core_initialized) const { SetBreakpointMenuActionsIcons(); @@ -1123,8 +1216,7 @@ QMenu* BranchWatchDialog::GetTableContextMenu_Destin(bool core_initialized) cons SetBreakpointMenuActionsIcons(); const bool all_branches_save_lr = // Taking advantage of short-circuit evaluation here. core_initialized && std::ranges::all_of(m_index_list_temp, [this](const QModelIndex& index) { - const QModelIndex sibling = index.siblingAtColumn(Column::Instruction); - return BranchSavesLR(m_table_proxy->data(sibling, UserRole::ClickRole).value()); + return m_table_proxy->GetBranchWatchSelection(index).collection_ptr->first.original_inst.LK; }); m_act_insert_blr->setEnabled(all_branches_save_lr); m_act_copy_address->setEnabled(true); diff --git a/Source/Core/DolphinQt/Debugger/BranchWatchDialog.h b/Source/Core/DolphinQt/Debugger/BranchWatchDialog.h index 0c9eee8433..9d7d08833e 100644 --- a/Source/Core/DolphinQt/Debugger/BranchWatchDialog.h +++ b/Source/Core/DolphinQt/Debugger/BranchWatchDialog.h @@ -93,6 +93,9 @@ private: void OnTableDeleteKeypress() const; void OnTableSetBLR() const; void OnTableSetNOP() const; + void OnTableInvertCondition() const; + void OnTableInvertDecrementCheck() const; + void OnTableMakeUnconditional() const; void OnTableCopyAddress() const; void OnTableSetBreakpointBreak() const; void OnTableSetBreakpointLog() const; @@ -116,10 +119,13 @@ private: void Load(const Core::CPUThreadGuard& guard, const std::string& filepath); void AutoSave(const Core::CPUThreadGuard& guard); void SetStubPatches(u32 value) const; + void SetEditPatches(u32 (*transform)(u32)) const; void SetBreakpoints(bool break_on_hit, bool log_on_hit) const; void SetBreakpointMenuActionsIcons() const; QMenu* GetTableContextMenu(const QModelIndex& index) const; + QMenu* GetTableContextMenu_Instruction(bool core_initialized) const; + QMenu* GetTableContextMenu_Condition(bool core_initialized) const; QMenu* GetTableContextMenu_Origin(bool core_initialized) const; QMenu* GetTableContextMenu_Destin(bool core_initialized) const; QMenu* GetTableContextMenu_Symbol(bool core_initialized) const; @@ -131,6 +137,9 @@ private: QPushButton *m_btn_start_pause, *m_btn_clear_watch, *m_btn_path_was_taken, *m_btn_path_not_taken, *m_btn_was_overwritten, *m_btn_not_overwritten, *m_btn_wipe_recent_hits; QAction* m_act_autosave; + QAction* m_act_invert_condition; + QAction* m_act_invert_decrement_check; + QAction* m_act_make_unconditional; QAction* m_act_insert_nop; QAction* m_act_insert_blr; QAction* m_act_copy_address; @@ -138,7 +147,8 @@ private: QAction* m_act_break_on_hit; QAction* m_act_log_on_hit; QAction* m_act_both_on_hit; - QMenu *m_mnu_table_context_origin, *m_mnu_table_context_destin_or_symbol, + QMenu *m_mnu_table_context_instruction, *m_mnu_table_context_condition, + *m_mnu_table_context_origin, *m_mnu_table_context_destin_or_symbol, *m_mnu_table_context_other; QMenu* m_mnu_column_visibility; diff --git a/Source/Core/DolphinQt/Debugger/BranchWatchTableModel.cpp b/Source/Core/DolphinQt/Debugger/BranchWatchTableModel.cpp index be0c095d53..2a3f4cb3d1 100644 --- a/Source/Core/DolphinQt/Debugger/BranchWatchTableModel.cpp +++ b/Source/Core/DolphinQt/Debugger/BranchWatchTableModel.cpp @@ -195,6 +195,12 @@ void BranchWatchTableModel::SetInspected(const QModelIndex& index) const int row = index.row(); switch (index.column()) { + case Column::Instruction: + SetInspected(index, Core::BranchWatchSelectionInspection::InvertBranchOption); + return; + case Column::Condition: + SetInspected(index, Core::BranchWatchSelectionInspection::MakeUnconditional); + return; case Column::Origin: SetOriginInspected(m_branch_watch.GetSelection()[row].collection_ptr->first.origin_addr); return; @@ -210,35 +216,35 @@ void BranchWatchTableModel::SetInspected(const QModelIndex& index) } } +void BranchWatchTableModel::SetInspected(const QModelIndex& index, + Core::BranchWatchSelectionInspection inspection) +{ + static const QList roles = {Qt::FontRole, Qt::ForegroundRole}; + m_branch_watch.SetSelectedInspected(index.row(), inspection); + emit dataChanged(index, index, roles); +} + void BranchWatchTableModel::SetOriginInspected(u32 origin_addr) { - using Inspection = Core::BranchWatchSelectionInspection; - static const QList roles = {Qt::FontRole, Qt::ForegroundRole}; - const Core::BranchWatch::Selection& selection = m_branch_watch.GetSelection(); for (std::size_t i = 0; i < selection.size(); ++i) { if (selection[i].collection_ptr->first.origin_addr != origin_addr) continue; - m_branch_watch.SetSelectedInspected(i, Inspection::SetOriginNOP); - const QModelIndex index = createIndex(static_cast(i), Column::Origin); - emit dataChanged(index, index, roles); + SetInspected(createIndex(static_cast(i), Column::Origin), + Core::BranchWatchSelectionInspection::SetOriginNOP); } } void BranchWatchTableModel::SetDestinInspected(u32 destin_addr, bool nested) { - using Inspection = Core::BranchWatchSelectionInspection; - static const QList roles = {Qt::FontRole, Qt::ForegroundRole}; - const Core::BranchWatch::Selection& selection = m_branch_watch.GetSelection(); for (std::size_t i = 0; i < selection.size(); ++i) { if (selection[i].collection_ptr->first.destin_addr != destin_addr) continue; - m_branch_watch.SetSelectedInspected(i, Inspection::SetDestinBLR); - const QModelIndex index = createIndex(static_cast(i), Column::Destination); - emit dataChanged(index, index, roles); + SetInspected(createIndex(static_cast(i), Column::Destination), + Core::BranchWatchSelectionInspection::SetDestinBLR); } if (nested) @@ -248,23 +254,18 @@ void BranchWatchTableModel::SetDestinInspected(u32 destin_addr, bool nested) void BranchWatchTableModel::SetSymbolInspected(u32 symbol_addr, bool nested) { - using Inspection = Core::BranchWatchSelectionInspection; - static const QList roles = {Qt::FontRole, Qt::ForegroundRole}; - for (qsizetype i = 0; i < m_symbol_list.size(); ++i) { const SymbolListValueType& value = m_symbol_list[i]; if (value.origin_addr.isValid() && value.origin_addr.value() == symbol_addr) { - m_branch_watch.SetSelectedInspected(i, Inspection::SetOriginSymbolBLR); - const QModelIndex index = createIndex(i, Column::OriginSymbol); - emit dataChanged(index, index, roles); + SetInspected(createIndex(static_cast(i), Column::OriginSymbol), + Core::BranchWatchSelectionInspection::SetOriginSymbolBLR); } if (value.destin_addr.isValid() && value.destin_addr.value() == symbol_addr) { - m_branch_watch.SetSelectedInspected(i, Inspection::SetDestinSymbolBLR); - const QModelIndex index = createIndex(i, Column::DestinSymbol); - emit dataChanged(index, index, roles); + SetInspected(createIndex(static_cast(i), Column::DestinSymbol), + Core::BranchWatchSelectionInspection::SetDestinSymbolBLR); } } @@ -273,6 +274,13 @@ void BranchWatchTableModel::SetSymbolInspected(u32 symbol_addr, bool nested) SetDestinInspected(symbol_addr, true); } +const Core::BranchWatchSelectionValueType& +BranchWatchTableModel::GetBranchWatchSelection(const QModelIndex& index) const +{ + ASSERT(index.isValid()); + return m_branch_watch.GetSelection()[index.row()]; +} + void BranchWatchTableModel::PrefetchSymbols() { if (m_branch_watch.GetRecordingPhase() != Core::BranchWatch::Phase::Reduction) @@ -306,25 +314,14 @@ static QString GetInstructionMnemonic(u32 hex) return QString::fromLatin1(disas.data(), split); } -static bool BranchIsUnconditional(UGeckoInstruction inst) -{ - if (inst.OPCD == 18) // bx - return true; - // If BranchWatch is doing its job, the input will be only bcx, bclrx, and bcctrx instructions. - DEBUG_ASSERT(inst.OPCD == 16 || (inst.OPCD == 19 && (inst.SUBOP10 == 16 || inst.SUBOP10 == 528))); - if ((inst.BO & 0b10100) == 0b10100) // 1z1zz - Branch always - return true; - return false; -} - static QString GetConditionString(const Core::BranchWatch::Selection::value_type& value, const Core::BranchWatch::Collection::value_type* kv) { if (value.condition == false) return BranchWatchTableModel::tr("false"); - if (BranchIsUnconditional(kv->first.original_inst)) - return QStringLiteral(""); - return BranchWatchTableModel::tr("true"); + if (BranchIsConditional(kv->first.original_inst)) + return BranchWatchTableModel::tr("true"); + return QStringLiteral(""); } QVariant BranchWatchTableModel::DisplayRoleData(const QModelIndex& index) const @@ -361,21 +358,25 @@ QVariant BranchWatchTableModel::DisplayRoleData(const QModelIndex& index) const QVariant BranchWatchTableModel::FontRoleData(const QModelIndex& index) const { m_font.setBold([&]() -> bool { + using Inspection = Core::BranchWatchSelectionInspection; + const auto get_bit_test = [this, &index](Inspection inspection_mask) -> bool { + const Inspection inspection = m_branch_watch.GetSelection()[index.row()].inspection; + return (inspection & inspection_mask) != Inspection{}; + }; switch (index.column()) { - using Inspection = Core::BranchWatchSelectionInspection; + case Column::Instruction: + return get_bit_test(Inspection::InvertBranchOption); + case Column::Condition: + return get_bit_test(Inspection::MakeUnconditional); case Column::Origin: - return (m_branch_watch.GetSelection()[index.row()].inspection & Inspection::SetOriginNOP) != - Inspection{}; + return get_bit_test(Inspection::SetOriginNOP); case Column::Destination: - return (m_branch_watch.GetSelection()[index.row()].inspection & Inspection::SetDestinBLR) != - Inspection{}; + return get_bit_test(Inspection::SetDestinBLR); case Column::OriginSymbol: - return (m_branch_watch.GetSelection()[index.row()].inspection & - Inspection::SetOriginSymbolBLR) != Inspection{}; + return get_bit_test(Inspection::SetOriginSymbolBLR); case Column::DestinSymbol: - return (m_branch_watch.GetSelection()[index.row()].inspection & - Inspection::SetDestinSymbolBLR) != Inspection{}; + return get_bit_test(Inspection::SetDestinSymbolBLR); } // Importantly, this code path avoids subscripting the selection to get an inspection value. return false; @@ -406,31 +407,25 @@ QVariant BranchWatchTableModel::TextAlignmentRoleData(const QModelIndex& index) QVariant BranchWatchTableModel::ForegroundRoleData(const QModelIndex& index) const { + using Inspection = Core::BranchWatchSelectionInspection; + const auto get_brush_v = [this, &index](Inspection inspection_mask) -> QVariant { + const Inspection inspection = m_branch_watch.GetSelection()[index.row()].inspection; + return (inspection & inspection_mask) != Inspection{} ? QBrush(Qt::red) : QVariant(); + }; switch (index.column()) { - using Inspection = Core::BranchWatchSelectionInspection; + case Column::Instruction: + return get_brush_v(Inspection::InvertBranchOption); + case Column::Condition: + return get_brush_v(Inspection::MakeUnconditional); case Column::Origin: - { - const Inspection inspection = m_branch_watch.GetSelection()[index.row()].inspection; - return (inspection & Inspection::SetOriginNOP) != Inspection{} ? QBrush(Qt::red) : QVariant(); - } + return get_brush_v(Inspection::SetOriginNOP); case Column::Destination: - { - const Inspection inspection = m_branch_watch.GetSelection()[index.row()].inspection; - return (inspection & Inspection::SetDestinBLR) != Inspection{} ? QBrush(Qt::red) : QVariant(); - } + return get_brush_v(Inspection::SetDestinBLR); case Column::OriginSymbol: - { - const Inspection inspection = m_branch_watch.GetSelection()[index.row()].inspection; - return (inspection & Inspection::SetOriginSymbolBLR) != Inspection{} ? QBrush(Qt::red) : - QVariant(); - } + return get_brush_v(Inspection::SetOriginSymbolBLR); case Column::DestinSymbol: - { - const Inspection inspection = m_branch_watch.GetSelection()[index.row()].inspection; - return (inspection & Inspection::SetDestinSymbolBLR) != Inspection{} ? QBrush(Qt::red) : - QVariant(); - } + return get_brush_v(Inspection::SetDestinSymbolBLR); } // Importantly, this code path avoids subscripting the selection to get an inspection value. return QVariant(); @@ -465,9 +460,9 @@ static int GetConditionInteger(const Core::BranchWatch::Selection::value_type& v { if (value.condition == false) return 0; - if (BranchIsUnconditional(kv->first.original_inst)) - return 2; - return 1; + if (BranchIsConditional(kv->first.original_inst)) + return 1; + return 2; } QVariant BranchWatchTableModel::SortRoleData(const QModelIndex& index) const diff --git a/Source/Core/DolphinQt/Debugger/BranchWatchTableModel.h b/Source/Core/DolphinQt/Debugger/BranchWatchTableModel.h index 616c2da023..c1cfca2415 100644 --- a/Source/Core/DolphinQt/Debugger/BranchWatchTableModel.h +++ b/Source/Core/DolphinQt/Debugger/BranchWatchTableModel.h @@ -15,6 +15,8 @@ namespace Core { class BranchWatch; +enum class BranchWatchSelectionInspection : u8; +struct BranchWatchSelectionValueType; class CPUThreadGuard; class System; } // namespace Core @@ -106,9 +108,12 @@ public: void UpdateHits(); void SetInspected(const QModelIndex& index); + const Core::BranchWatchSelectionValueType& + GetBranchWatchSelection(const QModelIndex& index) const; const SymbolList& GetSymbolList() const { return m_symbol_list; } private: + void SetInspected(const QModelIndex& index, Core::BranchWatchSelectionInspection inspection); void SetOriginInspected(u32 origin_addr); void SetDestinInspected(u32 destin_addr, bool nested); void SetSymbolInspected(u32 symbol_addr, bool nested);