From 1d7167610a609f91b5003a98c921446445f63b75 Mon Sep 17 00:00:00 2001 From: skidau Date: Sun, 19 Oct 2014 21:45:40 +1100 Subject: [PATCH] Added a RAM Watch window to the debugger Conflicts: Source/Core/Core/HW/Memmap.cpp Source/Core/Core/HW/Memmap.h Source/Core/DolphinWX/Debugger/CodeWindow.h --- Source/Core/Common/BreakPoints.cpp | 83 +++++++ Source/Core/Common/BreakPoints.h | 37 +++ Source/Core/Common/DebugInterface.h | 1 + .../Core/Core/Debugger/PPCDebugInterface.cpp | 5 + Source/Core/Core/Debugger/PPCDebugInterface.h | 1 + Source/Core/Core/PowerPC/PowerPC.cpp | 1 + Source/Core/Core/PowerPC/PowerPC.h | 1 + Source/Core/DolphinWX/CMakeLists.txt | 2 + Source/Core/DolphinWX/Debugger/CodeWindow.cpp | 3 + Source/Core/DolphinWX/Debugger/CodeWindow.h | 209 ++++++++--------- .../Debugger/CodeWindowFunctions.cpp | 21 ++ Source/Core/DolphinWX/Debugger/MemoryView.cpp | 7 + Source/Core/DolphinWX/Debugger/WatchView.cpp | 212 ++++++++++++++++++ Source/Core/DolphinWX/Debugger/WatchView.h | 50 +++++ .../Core/DolphinWX/Debugger/WatchWindow.cpp | 46 ++++ Source/Core/DolphinWX/Debugger/WatchWindow.h | 42 ++++ Source/Core/DolphinWX/DolphinWX.vcxproj | 4 + .../Core/DolphinWX/DolphinWX.vcxproj.filters | 14 +- Source/Core/DolphinWX/FrameAui.cpp | 6 + Source/Core/DolphinWX/FrameTools.cpp | 1 + Source/Core/DolphinWX/Globals.h | 1 + 21 files changed, 643 insertions(+), 104 deletions(-) create mode 100644 Source/Core/DolphinWX/Debugger/WatchView.cpp create mode 100644 Source/Core/DolphinWX/Debugger/WatchView.h create mode 100644 Source/Core/DolphinWX/Debugger/WatchWindow.cpp create mode 100644 Source/Core/DolphinWX/Debugger/WatchWindow.h diff --git a/Source/Core/Common/BreakPoints.cpp b/Source/Core/Common/BreakPoints.cpp index 6014eae776b2..50b4d56be5fe 100644 --- a/Source/Core/Common/BreakPoints.cpp +++ b/Source/Core/Common/BreakPoints.cpp @@ -217,3 +217,86 @@ void TMemCheck::Action(DebugInterface *debug_interface, u32 iValue, u32 addr, bo debug_interface->BreakNow(); } } + + +bool Watches::IsAddressWatch(u32 _iAddress) +{ + for (const TWatch& bp : m_Watches) + if (bp.iAddress == _iAddress) + return true; + + return false; +} + +Watches::TWatchesStr Watches::GetStrings() const +{ + TWatchesStr bps; + for (const TWatch& bp : m_Watches) + { + std::stringstream ss; + ss << std::hex << bp.iAddress << " " << (bp.bOn ? "n" : ""); + bps.push_back(ss.str()); + } + + return bps; +} + +void Watches::AddFromStrings(const TWatchesStr& bpstrs) +{ + for (const std::string& bpstr : bpstrs) + { + TWatch bp; + std::stringstream ss; + ss << std::hex << bpstr; + ss >> bp.iAddress; + bp.bOn = bpstr.find("n") != bpstr.npos; + Add(bp); + } +} + +void Watches::Add(const TWatch& bp) +{ + if (!IsAddressWatch(bp.iAddress)) + { + m_Watches.push_back(bp); + } +} + +void Watches::Add(u32 em_address) +{ + if (!IsAddressWatch(em_address)) // only add new addresses + { + TWatch pt; // breakpoint settings + pt.bOn = true; + pt.iAddress = em_address; + + m_Watches.push_back(pt); + } +} + +void Watches::Update(int count, u32 em_address) +{ + m_Watches.at(count).iAddress = em_address; +} + +void Watches::UpdateName(int count, std::string name) +{ + m_Watches.at(count).name = name; +} + +void Watches::Remove(u32 em_address) +{ + for (auto i = m_Watches.begin(); i != m_Watches.end(); ++i) + { + if (i->iAddress == em_address) + { + m_Watches.erase(i); + return; + } + } +} + +void Watches::Clear() +{ + m_Watches.clear(); +} diff --git a/Source/Core/Common/BreakPoints.h b/Source/Core/Common/BreakPoints.h index 3d656b12e815..cd18eedd604c 100644 --- a/Source/Core/Common/BreakPoints.h +++ b/Source/Core/Common/BreakPoints.h @@ -44,6 +44,13 @@ struct TMemCheck bool write, int size, u32 pc); }; +struct TWatch +{ + std::string name = ""; + u32 iAddress; + bool bOn; +}; + // Code breakpoints. class BreakPoints { @@ -99,3 +106,33 @@ class MemChecks void Clear() { m_MemChecks.clear(); } }; + +class Watches +{ +public: + typedef std::vector TWatches; + typedef std::vector TWatchesStr; + + const TWatches& GetWatches() { return m_Watches; } + + TWatchesStr GetStrings() const; + void AddFromStrings(const TWatchesStr& bps); + + bool IsAddressWatch(u32 _iAddress); + + // Add BreakPoint + void Add(u32 em_address); + void Add(const TWatch& bp); + + void Update(int count, u32 em_address); + void UpdateName(int count, std::string name); + + // Remove Breakpoint + void Remove(u32 _iAddress); + void Clear(); + + void DeleteByAddress(u32 _Address); + +private: + TWatches m_Watches; +}; \ No newline at end of file diff --git a/Source/Core/Common/DebugInterface.h b/Source/Core/Common/DebugInterface.h index 5bee2f7951dd..a21921d49688 100644 --- a/Source/Core/Common/DebugInterface.h +++ b/Source/Core/Common/DebugInterface.h @@ -18,6 +18,7 @@ class DebugInterface virtual void ClearBreakpoint(unsigned int /*address*/){} virtual void ClearAllBreakpoints() {} virtual void ToggleBreakpoint(unsigned int /*address*/){} + virtual void AddWatch(unsigned int /*address*/){} virtual void ClearAllMemChecks() {} virtual bool IsMemCheck(unsigned int /*address*/) {return false;} virtual void ToggleMemCheck(unsigned int /*address*/){} diff --git a/Source/Core/Core/Debugger/PPCDebugInterface.cpp b/Source/Core/Core/Debugger/PPCDebugInterface.cpp index 84e2cb687944..988d0de20dee 100644 --- a/Source/Core/Core/Debugger/PPCDebugInterface.cpp +++ b/Source/Core/Core/Debugger/PPCDebugInterface.cpp @@ -131,6 +131,11 @@ void PPCDebugInterface::ToggleBreakpoint(unsigned int address) PowerPC::breakpoints.Add(address); } +void PPCDebugInterface::AddWatch(unsigned int address) +{ + PowerPC::watches.Add(address); +} + void PPCDebugInterface::ClearAllMemChecks() { PowerPC::memchecks.Clear(); diff --git a/Source/Core/Core/Debugger/PPCDebugInterface.h b/Source/Core/Core/Debugger/PPCDebugInterface.h index 3675c9f9cfb2..0cecef0ea676 100644 --- a/Source/Core/Core/Debugger/PPCDebugInterface.h +++ b/Source/Core/Core/Debugger/PPCDebugInterface.h @@ -22,6 +22,7 @@ class PPCDebugInterface final : public DebugInterface virtual void SetBreakpoint(unsigned int address) override; virtual void ClearBreakpoint(unsigned int address) override; virtual void ClearAllBreakpoints() override; + virtual void AddWatch(unsigned int address) override; virtual void ToggleBreakpoint(unsigned int address) override; virtual void ClearAllMemChecks() override; virtual bool IsMemCheck(unsigned int address) override; diff --git a/Source/Core/Core/PowerPC/PowerPC.cpp b/Source/Core/Core/PowerPC/PowerPC.cpp index 858fced5d942..c78c021a3deb 100644 --- a/Source/Core/Core/PowerPC/PowerPC.cpp +++ b/Source/Core/Core/PowerPC/PowerPC.cpp @@ -35,6 +35,7 @@ static volatile CPUState state = CPU_POWERDOWN; Interpreter * const interpreter = Interpreter::getInstance(); static CoreMode mode; +Watches watches; BreakPoints breakpoints; MemChecks memchecks; PPCDebugInterface debug_interface; diff --git a/Source/Core/Core/PowerPC/PowerPC.h b/Source/Core/Core/PowerPC/PowerPC.h index a4c2fc4af1e6..e9f3aee36771 100644 --- a/Source/Core/Core/PowerPC/PowerPC.h +++ b/Source/Core/Core/PowerPC/PowerPC.h @@ -114,6 +114,7 @@ enum CPUState extern PowerPCState ppcState; +extern Watches watches; extern BreakPoints breakpoints; extern MemChecks memchecks; extern PPCDebugInterface debug_interface; diff --git a/Source/Core/DolphinWX/CMakeLists.txt b/Source/Core/DolphinWX/CMakeLists.txt index 8d179653f03b..c0dd0f6cc0ab 100644 --- a/Source/Core/DolphinWX/CMakeLists.txt +++ b/Source/Core/DolphinWX/CMakeLists.txt @@ -45,6 +45,8 @@ set(GUI_SRCS Debugger/MemoryWindow.cpp Debugger/RegisterView.cpp Debugger/RegisterWindow.cpp + Debugger/WatchView.cpp + Debugger/WatchWindow.cpp FifoPlayerDlg.cpp Frame.cpp FrameAui.cpp diff --git a/Source/Core/DolphinWX/Debugger/CodeWindow.cpp b/Source/Core/DolphinWX/Debugger/CodeWindow.cpp index c6ad04e8b70c..b34dfa29b518 100644 --- a/Source/Core/DolphinWX/Debugger/CodeWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/CodeWindow.cpp @@ -52,6 +52,7 @@ #include "DolphinWX/Debugger/DebuggerUIUtil.h" #include "DolphinWX/Debugger/JitWindow.h" #include "DolphinWX/Debugger/RegisterWindow.h" +#include "DolphinWX/Debugger/WatchWindow.h" extern "C" // Bitmaps { @@ -93,6 +94,7 @@ CCodeWindow::CCodeWindow(const SCoreStartupParameter& _LocalCoreStartupParameter : wxPanel(parent, id, position, size, style, name) , Parent(parent) , m_RegisterWindow(nullptr) + , m_WatchWindow(nullptr) , m_BreakpointWindow(nullptr) , m_MemoryWindow(nullptr) , m_JitWindow(nullptr) @@ -152,6 +154,7 @@ void CCodeWindow::OnHostMessage(wxCommandEvent& event) Update(); if (codeview) codeview->Center(PC); if (m_RegisterWindow) m_RegisterWindow->NotifyUpdate(); + if (m_WatchWindow) m_WatchWindow->NotifyUpdate(); break; case IDM_UPDATEBREAKPOINTS: diff --git a/Source/Core/DolphinWX/Debugger/CodeWindow.h b/Source/Core/DolphinWX/Debugger/CodeWindow.h index dfe2ed018879..26322b1b902a 100644 --- a/Source/Core/DolphinWX/Debugger/CodeWindow.h +++ b/Source/Core/DolphinWX/Debugger/CodeWindow.h @@ -19,6 +19,7 @@ class CFrame; class CRegisterWindow; +class CWatchWindow; class CBreakPointWindow; class CMemoryWindow; class CJitWindow; @@ -35,111 +36,113 @@ class wxMenuBar; class CCodeWindow : public wxPanel { public: - CCodeWindow(const SCoreStartupParameter& _LocalCoreStartupParameter, - CFrame * parent, - wxWindowID id = wxID_ANY, - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - long style = wxTAB_TRAVERSAL | wxBORDER_NONE, + CCodeWindow(const SCoreStartupParameter& _LocalCoreStartupParameter, + CFrame * parent, + wxWindowID id = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxTAB_TRAVERSAL | wxBORDER_NONE, const wxString& name = _("Code")); - void Load(); - void Save(); - - // Parent interaction - CFrame *Parent; - wxMenuBar * GetMenuBar(); - wxToolBar * GetToolBar(); - wxBitmap m_Bitmaps[ToolbarDebugBitmapMax]; - - bool UseInterpreter(); - bool BootToPause(); - bool AutomaticStart(); - bool JITNoBlockCache(); - bool JITNoBlockLinking(); - bool JumpToAddress(u32 address); - - void Update() override; - void NotifyMapLoaded(); - void CreateMenu(const SCoreStartupParameter& _LocalCoreStartupParameter, wxMenuBar *pMenuBar); - void CreateMenuOptions(wxMenu *pMenu); - void CreateMenuSymbols(wxMenuBar *pMenuBar); - void RecreateToolbar(wxToolBar*); - void PopulateToolbar(wxToolBar* toolBar); - void UpdateButtonStates(); - void OpenPages(); - void UpdateManager(); - - // Menu bar - // ------------------- - void OnCPUMode(wxCommandEvent& event); // CPU Mode menu - void OnJITOff(wxCommandEvent& event); - - void ToggleCodeWindow(bool bShow); - void ToggleRegisterWindow(bool bShow); - void ToggleBreakPointWindow(bool bShow); - void ToggleMemoryWindow(bool bShow); - void ToggleJitWindow(bool bShow); - void ToggleSoundWindow(bool bShow); - void ToggleVideoWindow(bool bShow); - - void OnChangeFont(wxCommandEvent& event); - - void OnCodeStep(wxCommandEvent& event); - void OnAddrBoxChange(wxCommandEvent& event); - void OnSymbolsMenu(wxCommandEvent& event); - void OnJitMenu(wxCommandEvent& event); - void OnProfilerMenu(wxCommandEvent& event); - - // Sub dialogs - CRegisterWindow* m_RegisterWindow; - CBreakPointWindow* m_BreakpointWindow; - CMemoryWindow* m_MemoryWindow; - CJitWindow* m_JitWindow; - DSPDebuggerLLE* m_SoundWindow; - GFXDebuggerPanel* m_VideoWindow; - - // Settings - bool bAutomaticStart; bool bBootToPause; - bool bShowOnStart[IDM_VIDEOWINDOW - IDM_LOGWINDOW + 1]; - int iNbAffiliation[IDM_CODEWINDOW - IDM_LOGWINDOW + 1]; + void Load(); + void Save(); + + // Parent interaction + CFrame *Parent; + wxMenuBar * GetMenuBar(); + wxToolBar * GetToolBar(); + wxBitmap m_Bitmaps[ToolbarDebugBitmapMax]; + + bool UseInterpreter(); + bool BootToPause(); + bool AutomaticStart(); + bool JITNoBlockCache(); + bool JITNoBlockLinking(); + bool JumpToAddress(u32 address); + + void Update() override; + void NotifyMapLoaded(); + void CreateMenu(const SCoreStartupParameter& _LocalCoreStartupParameter, wxMenuBar *pMenuBar); + void CreateMenuOptions(wxMenu *pMenu); + void CreateMenuSymbols(wxMenuBar *pMenuBar); + void RecreateToolbar(wxToolBar*); + void PopulateToolbar(wxToolBar* toolBar); + void UpdateButtonStates(); + void OpenPages(); + void UpdateManager(); + + // Menu bar + // ------------------- + void OnCPUMode(wxCommandEvent& event); // CPU Mode menu + void OnJITOff(wxCommandEvent& event); + + void ToggleCodeWindow(bool bShow); + void ToggleRegisterWindow(bool bShow); + void ToggleWatchWindow(bool bShow); + void ToggleBreakPointWindow(bool bShow); + void ToggleMemoryWindow(bool bShow); + void ToggleJitWindow(bool bShow); + void ToggleSoundWindow(bool bShow); + void ToggleVideoWindow(bool bShow); + + void OnChangeFont(wxCommandEvent& event); + + void OnCodeStep(wxCommandEvent& event); + void OnAddrBoxChange(wxCommandEvent& event); + void OnSymbolsMenu(wxCommandEvent& event); + void OnJitMenu(wxCommandEvent& event); + void OnProfilerMenu(wxCommandEvent& event); + + // Sub dialogs + CRegisterWindow* m_RegisterWindow; + CWatchWindow* m_WatchWindow; + CBreakPointWindow* m_BreakpointWindow; + CMemoryWindow* m_MemoryWindow; + CJitWindow* m_JitWindow; + DSPDebuggerLLE* m_SoundWindow; + GFXDebuggerPanel* m_VideoWindow; + + // Settings + bool bAutomaticStart; bool bBootToPause; + bool bShowOnStart[IDM_VIDEOWINDOW - IDM_LOGWINDOW + 1]; + int iNbAffiliation[IDM_CODEWINDOW - IDM_LOGWINDOW + 1]; private: - enum - { - // Debugger GUI Objects - ID_CODEVIEW, - ID_CALLSTACKLIST, - ID_CALLERSLIST, - ID_CALLSLIST, - ID_SYMBOLLIST - }; - - void OnSymbolListChange(wxCommandEvent& event); - void OnSymbolListContextMenu(wxContextMenuEvent& event); - void OnCallstackListChange(wxCommandEvent& event); - void OnCallersListChange(wxCommandEvent& event); - void OnCallsListChange(wxCommandEvent& event); - void OnCodeViewChange(wxCommandEvent &event); - void OnHostMessage(wxCommandEvent& event); - - // Debugger functions - void SingleStep(); - void StepOver(); - void StepOut(); - void ToggleBreakpoint(); - - void UpdateLists(); - void UpdateCallstack(); - - void InitBitmaps(); - - CCodeView* codeview; - wxListBox* callstack; - wxListBox* symbols; - wxListBox* callers; - wxListBox* calls; - Common::Event sync_event; - - DECLARE_EVENT_TABLE() + enum + { + // Debugger GUI Objects + ID_CODEVIEW, + ID_CALLSTACKLIST, + ID_CALLERSLIST, + ID_CALLSLIST, + ID_SYMBOLLIST + }; + + void OnSymbolListChange(wxCommandEvent& event); + void OnSymbolListContextMenu(wxContextMenuEvent& event); + void OnCallstackListChange(wxCommandEvent& event); + void OnCallersListChange(wxCommandEvent& event); + void OnCallsListChange(wxCommandEvent& event); + void OnCodeViewChange(wxCommandEvent &event); + void OnHostMessage(wxCommandEvent& event); + + // Debugger functions + void SingleStep(); + void StepOver(); + void StepOut(); + void ToggleBreakpoint(); + + void UpdateLists(); + void UpdateCallstack(); + + void InitBitmaps(); + + CCodeView* codeview; + wxListBox* callstack; + wxListBox* symbols; + wxListBox* callers; + wxListBox* calls; + Common::Event sync_event; + + DECLARE_EVENT_TABLE() }; diff --git a/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp b/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp index fbf5820c0a55..099d184bee13 100644 --- a/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp +++ b/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp @@ -51,6 +51,7 @@ #include "DolphinWX/Debugger/JitWindow.h" #include "DolphinWX/Debugger/MemoryWindow.h" #include "DolphinWX/Debugger/RegisterWindow.h" +#include "DolphinWX/Debugger/WatchWindow.h" // Save and load settings @@ -421,6 +422,8 @@ void CCodeWindow::OpenPages() Parent->ToggleLogConfigWindow(true); if (bShowOnStart[IDM_REGISTERWINDOW - IDM_LOGWINDOW]) ToggleRegisterWindow(true); + if (bShowOnStart[IDM_WATCHWINDOW - IDM_LOGWINDOW]) + ToggleWatchWindow(true); if (bShowOnStart[IDM_BREAKPOINTWINDOW - IDM_LOGWINDOW]) ToggleBreakPointWindow(true); if (bShowOnStart[IDM_MEMORYWINDOW - IDM_LOGWINDOW]) @@ -461,6 +464,24 @@ void CCodeWindow::ToggleRegisterWindow(bool bShow) } } +void CCodeWindow::ToggleWatchWindow(bool bShow) +{ + GetMenuBar()->FindItem(IDM_WATCHWINDOW)->Check(bShow); + if (bShow) + { + if (!m_WatchWindow) + m_WatchWindow = new CWatchWindow(Parent, IDM_WATCHWINDOW); + Parent->DoAddPage(m_WatchWindow, + iNbAffiliation[IDM_WATCHWINDOW - IDM_LOGWINDOW], + Parent->bFloatWindow[IDM_WATCHWINDOW - IDM_LOGWINDOW]); + } + else // Close + { + Parent->DoRemovePage(m_WatchWindow, false); + m_WatchWindow = nullptr; + } +} + void CCodeWindow::ToggleBreakPointWindow(bool bShow) { GetMenuBar()->FindItem(IDM_BREAKPOINTWINDOW)->Check(bShow); diff --git a/Source/Core/DolphinWX/Debugger/MemoryView.cpp b/Source/Core/DolphinWX/Debugger/MemoryView.cpp index 0fd8f48746b4..f05c1b96fa94 100644 --- a/Source/Core/DolphinWX/Debugger/MemoryView.cpp +++ b/Source/Core/DolphinWX/Debugger/MemoryView.cpp @@ -38,6 +38,7 @@ enum IDM_COPYCODE, IDM_RUNTOHERE, IDM_DYNARECRESULTS, + IDM_WATCHADDRESS, IDM_TOGGLEMEMORY, IDM_VIEWASFP, IDM_VIEWASASCII, @@ -180,6 +181,11 @@ void CMemoryView::OnPopupMenu(wxCommandEvent& event) break; #endif + case IDM_WATCHADDRESS: + debugger->AddWatch(selection); + Refresh(); + break; + case IDM_TOGGLEMEMORY: memory ^= 1; Refresh(); @@ -215,6 +221,7 @@ void CMemoryView::OnMouseDownR(wxMouseEvent& event) menu->Append(IDM_COPYADDRESS, _("Copy &address")); menu->Append(IDM_COPYHEX, _("Copy &hex")); #endif + menu->Append(IDM_WATCHADDRESS, _("Add to &watch")); menu->Append(IDM_TOGGLEMEMORY, _("Toggle &memory")); wxMenu* viewAsSubMenu = new wxMenu; diff --git a/Source/Core/DolphinWX/Debugger/WatchView.cpp b/Source/Core/DolphinWX/Debugger/WatchView.cpp new file mode 100644 index 000000000000..6982dd8816e2 --- /dev/null +++ b/Source/Core/DolphinWX/Debugger/WatchView.cpp @@ -0,0 +1,212 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include +#include +#include +#include +#include +#include + +#include "Common/GekkoDisassembler.h" +#include "Core/HW/Memmap.h" +#include "Core/PowerPC/PowerPC.h" +#include "DolphinWX/WxUtils.h" +#include "DolphinWX/Debugger/DebuggerUIUtil.h" +#include "DolphinWX/Debugger/WatchView.h" + +class wxWindow; + +static std::string GetWatchName(int count) +{ + return PowerPC::watches.GetWatches().at(count - 1).name; +} + +static u32 GetWatchAddr(int count) +{ + return PowerPC::watches.GetWatches().at(count - 1).iAddress; +} + +static u32 GetWatchValue(int count) +{ + return Memory::ReadUnchecked_U32(GetWatchAddr(count)); +} + +static void AddWatchAddr(int count, u32 value) +{ + PowerPC::watches.Add(value); +} + +static void UpdateWatchAddr(int count, u32 value) +{ + PowerPC::watches.Update(count - 1, value); +} + +static void SetWatchName(int count, std::string value) +{ + PowerPC::watches.UpdateName(count - 1, value); +} + +static void SetWatchValue(int count, u32 value) +{ + Memory::WriteUnchecked_U32(value, GetWatchAddr(count)); +} + +wxString CWatchTable::GetValue(int row, int col) +{ + if (row == 0) + { + // Column Labels + switch (col) + { + case 0: return wxString::Format("Label"); + case 1: return wxString::Format("Addr"); + case 2: return wxString::Format("Hex"); + case 3: return wxString::Format("Dec"); + case 4: return wxString::Format("Str"); + default: return wxEmptyString; + } + } + else if (row <= PowerPC::watches.GetWatches().size()) + { + if (PowerPC::GetState() != PowerPC::CPU_POWERDOWN) + { + switch (col) + { + case 0: return wxString::Format("%s", GetWatchName(row)); + case 1: return wxString::Format("%08x", GetWatchAddr(row)); + case 2: return wxString::Format("%08x", GetWatchValue(row)); + case 3: return wxString::Format("%lu", GetWatchValue(row)); + case 4: + { + u32 addr = GetWatchAddr(row); + if (Memory::IsRAMAddress(addr)) + return Memory::GetString(addr, 32).c_str(); + else + return wxEmptyString; + } + default: return wxEmptyString; + } + } + } + return wxEmptyString; +} + +void CWatchTable::SetValue(int row, int col, const wxString& strNewVal) +{ + u32 newVal = 0; + if (col == 0 || TryParse("0x" + WxStrToStr(strNewVal), &newVal)) + { + if (row > 0) + { + switch (col) + { + case 0: + { + SetWatchName(row, std::string(WxStrToStr(strNewVal))); + break; + } + case 1: + { + if (row > (int)PowerPC::watches.GetWatches().size()) + { + AddWatchAddr(row, newVal); + row = (int)PowerPC::watches.GetWatches().size(); + } + else + { + UpdateWatchAddr(row, newVal); + } + break; + } + case 2: + { + SetWatchValue(row, newVal); + break; + } + default: + break; + } + } + } +} + +void CWatchTable::UpdateWatch() +{ + for (int i = 0; i < (int)PowerPC::watches.GetWatches().size(); ++i) + { + m_CachedWatchHasChanged[i] = (m_CachedWatch[i] != GetWatchValue(i + 1)); + m_CachedWatch[i] = GetWatchValue(i + 1); + } +} + +wxGridCellAttr *CWatchTable::GetAttr(int row, int col, wxGridCellAttr::wxAttrKind) +{ + wxGridCellAttr *attr = new wxGridCellAttr(); + + attr->SetBackgroundColour(*wxWHITE); + attr->SetFont(DebuggerFont); + + switch (col) + { + case 1: + attr->SetAlignment(wxALIGN_LEFT, wxALIGN_CENTER); + break; + case 3: + case 4: + attr->SetAlignment(wxALIGN_LEFT, wxALIGN_CENTER); + break; + default: + attr->SetAlignment(wxALIGN_LEFT, wxALIGN_CENTER); + break; + } + + if (row == 0) + { + attr->SetReadOnly(true); + attr->SetBackgroundColour(*wxBLACK); + attr->SetTextColour(*wxWHITE); + } + else + { + bool red = false; + switch (col) + { + case 1: red = m_CachedWatchHasChanged[row]; break; + } + + attr->SetTextColour(red ? *wxRED : *wxBLACK); + + if (row > (int)(PowerPC::watches.GetWatches().size() + 1)) + { + attr->SetReadOnly(true); + attr->SetBackgroundColour(*wxLIGHT_GREY); + } + } + attr->IncRef(); + return attr; +} + +CWatchView::CWatchView(wxWindow *parent, wxWindowID id) + : wxGrid(parent, id) +{ + SetTable(new CWatchTable(), false); + SetRowLabelSize(0); + SetColLabelSize(0); + DisableDragRowSize(); + + if (PowerPC::GetState() != PowerPC::CPU_POWERDOWN) + { + AutoSizeColumns(); + } +} + +void CWatchView::Update() +{ + if (PowerPC::GetState() != PowerPC::CPU_POWERDOWN) + { + ForceRefresh(); + ((CWatchTable *)GetTable())->UpdateWatch(); + } +} diff --git a/Source/Core/DolphinWX/Debugger/WatchView.h b/Source/Core/DolphinWX/Debugger/WatchView.h new file mode 100644 index 000000000000..4f093624a0cd --- /dev/null +++ b/Source/Core/DolphinWX/Debugger/WatchView.h @@ -0,0 +1,50 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "Common/CommonTypes.h" + +class wxWindow; + +class CWatchTable : public wxGridTableBase +{ + enum + { + NUM_SPECIALS = 1, + MAX_SPECIALS = 256, + }; + +public: + CWatchTable() + { + } + + int GetNumberCols() override { return 5; } + int GetNumberRows() override { return MAX_SPECIALS; } + wxString GetValue(int row, int col) override; + void SetValue(int row, int col, const wxString &) override; + wxGridCellAttr *GetAttr(int, int, wxGridCellAttr::wxAttrKind) override; + void UpdateWatch(); + +private: + std::array m_CachedWatch; + std::array m_CachedWatchHasChanged; + + DECLARE_NO_COPY_CLASS(CWatchTable); +}; + +class CWatchView : public wxGrid +{ +public: + CWatchView(wxWindow* parent, wxWindowID id); + void Update() override; +}; diff --git a/Source/Core/DolphinWX/Debugger/WatchWindow.cpp b/Source/Core/DolphinWX/Debugger/WatchWindow.cpp new file mode 100644 index 000000000000..8f6f578b013c --- /dev/null +++ b/Source/Core/DolphinWX/Debugger/WatchWindow.cpp @@ -0,0 +1,46 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "DolphinWX/Debugger/WatchView.h" +#include "DolphinWX/Debugger/WatchWindow.h" + +class wxWindow; + +BEGIN_EVENT_TABLE(CWatchWindow, wxPanel) +END_EVENT_TABLE() + + +CWatchWindow::CWatchWindow(wxWindow* parent, wxWindowID id, + const wxPoint& position, const wxSize& size, + long style, const wxString& name) + : wxPanel(parent, id, position, size, style, name) + , m_GPRGridView(nullptr) +{ + CreateGUIControls(); +} + +void CWatchWindow::CreateGUIControls() +{ + wxBoxSizer *sGrid = new wxBoxSizer(wxVERTICAL); + m_GPRGridView = new CWatchView(this, ID_GPR); + sGrid->Add(m_GPRGridView, 1, wxGROW); + SetSizer(sGrid); + + NotifyUpdate(); +} + +void CWatchWindow::NotifyUpdate() +{ + if (m_GPRGridView != nullptr) + m_GPRGridView->Update(); +} diff --git a/Source/Core/DolphinWX/Debugger/WatchWindow.h b/Source/Core/DolphinWX/Debugger/WatchWindow.h new file mode 100644 index 000000000000..9a3b9c4d6721 --- /dev/null +++ b/Source/Core/DolphinWX/Debugger/WatchWindow.h @@ -0,0 +1,42 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +class CWatchView; +class wxWindow; + +class CWatchWindow + : public wxPanel +{ +public: + CWatchWindow(wxWindow* parent, + wxWindowID id = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxTAB_TRAVERSAL | wxNO_BORDER, + const wxString& name = _("Watch")); + + void NotifyUpdate(); + + +private: + DECLARE_EVENT_TABLE(); + + enum + { + ID_GPR = 1002 + }; + + CWatchView* m_GPRGridView; + void CreateGUIControls(); +}; diff --git a/Source/Core/DolphinWX/DolphinWX.vcxproj b/Source/Core/DolphinWX/DolphinWX.vcxproj index 124315d86373..51026da88e0c 100644 --- a/Source/Core/DolphinWX/DolphinWX.vcxproj +++ b/Source/Core/DolphinWX/DolphinWX.vcxproj @@ -71,6 +71,8 @@ + + @@ -124,6 +126,8 @@ + + diff --git a/Source/Core/DolphinWX/DolphinWX.vcxproj.filters b/Source/Core/DolphinWX/DolphinWX.vcxproj.filters index b01a58d3f372..8e46985a83a4 100644 --- a/Source/Core/DolphinWX/DolphinWX.vcxproj.filters +++ b/Source/Core/DolphinWX/DolphinWX.vcxproj.filters @@ -90,6 +90,12 @@ GUI\Debugger + + GUI\Debugger + + + GUI\Debugger + GUI\InputConfig @@ -222,6 +228,12 @@ GUI\Debugger + + GUI\Debugger + + + GUI\Debugger + GUI\InputConfig @@ -303,4 +315,4 @@ - \ No newline at end of file + diff --git a/Source/Core/DolphinWX/FrameAui.cpp b/Source/Core/DolphinWX/FrameAui.cpp index 34d52068c144..3c44ab592041 100644 --- a/Source/Core/DolphinWX/FrameAui.cpp +++ b/Source/Core/DolphinWX/FrameAui.cpp @@ -179,6 +179,9 @@ void CFrame::OnToggleWindow(wxCommandEvent& event) case IDM_REGISTERWINDOW: g_pCodeWindow->ToggleRegisterWindow(bShow); break; + case IDM_WATCHWINDOW: + g_pCodeWindow->ToggleWatchWindow(bShow); + break; case IDM_BREAKPOINTWINDOW: g_pCodeWindow->ToggleBreakPointWindow(bShow); break; @@ -208,6 +211,7 @@ void CFrame::ClosePages() { g_pCodeWindow->ToggleCodeWindow(false); g_pCodeWindow->ToggleRegisterWindow(false); + g_pCodeWindow->ToggleWatchWindow(false); g_pCodeWindow->ToggleBreakPointWindow(false); g_pCodeWindow->ToggleMemoryWindow(false); g_pCodeWindow->ToggleJitWindow(false); @@ -247,6 +251,8 @@ void CFrame::OnNotebookPageClose(wxAuiNotebookEvent& event) ToggleLogConfigWindow(false); if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_REGISTERWINDOW) g_pCodeWindow->ToggleRegisterWindow(false); + if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_WATCHWINDOW) + g_pCodeWindow->ToggleWatchWindow(false); if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_BREAKPOINTWINDOW) g_pCodeWindow->ToggleBreakPointWindow(false); if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_JITWINDOW) diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp index de080a858795..eb9c6632a73c 100644 --- a/Source/Core/DolphinWX/FrameTools.cpp +++ b/Source/Core/DolphinWX/FrameTools.cpp @@ -285,6 +285,7 @@ wxMenuBar* CFrame::CreateMenu() const wxString MenuText[] = { wxTRANSLATE("&Registers"), + wxTRANSLATE("&Watch"), wxTRANSLATE("&Breakpoints"), wxTRANSLATE("&Memory"), wxTRANSLATE("&JIT"), diff --git a/Source/Core/DolphinWX/Globals.h b/Source/Core/DolphinWX/Globals.h index 84b046f9ef24..d8b83bd400f4 100644 --- a/Source/Core/DolphinWX/Globals.h +++ b/Source/Core/DolphinWX/Globals.h @@ -150,6 +150,7 @@ enum IDM_LOGWINDOW, IDM_LOGCONFIGWINDOW, IDM_REGISTERWINDOW, + IDM_WATCHWINDOW, IDM_BREAKPOINTWINDOW, IDM_MEMORYWINDOW, IDM_JITWINDOW,