From 745d30bc089e20c34b059d70e2efa446fda46759 Mon Sep 17 00:00:00 2001 From: Swift <85366980+Swiftshine@users.noreply.github.com> Date: Tue, 9 Jun 2026 15:04:33 -0500 Subject: [PATCH] debugger: Tweaks + add context menu to write different value types (#1950) --- src/gui/wxgui/debugger/DumpCtrl.cpp | 199 +++++++++++++++++++--- src/gui/wxgui/debugger/DumpCtrl.h | 10 +- src/gui/wxgui/debugger/RegisterWindow.cpp | 21 ++- 3 files changed, 200 insertions(+), 30 deletions(-) diff --git a/src/gui/wxgui/debugger/DumpCtrl.cpp b/src/gui/wxgui/debugger/DumpCtrl.cpp index 16167e39..8bfb2dff 100644 --- a/src/gui/wxgui/debugger/DumpCtrl.cpp +++ b/src/gui/wxgui/debugger/DumpCtrl.cpp @@ -12,6 +12,14 @@ #define OFFSET_ADDRESS_RELATIVE (90) #define OFFSET_MEMORY (450) +enum { + ID_WRITE_U8 = wxID_HIGHEST + 1, + ID_WRITE_U16, + ID_WRITE_U32, + ID_WRITE_FLOAT, + ID_WRITE_STRING +}; + DumpCtrl::DumpCtrl(wxWindow* parent, const wxWindowID& id, const wxPoint& pos, const wxSize& size, long style) : TextList(parent, id, pos, size, style) { @@ -28,6 +36,8 @@ DumpCtrl::DumpCtrl(wxWindow* parent, const wxWindowID& id, const wxPoint& pos, c m_memoryRegion.size = 0x1000; Init(); } + + Bind(wxEVT_MENU, &DumpCtrl::OnMenuSelected, this); } void DumpCtrl::Init() @@ -163,31 +173,36 @@ void DumpCtrl::OnMouseMove(const wxPoint& start_position, uint32 line) position.x -= OFFSET_MEMORY; } +uint32 DumpCtrl::PositionToAddress(const wxPoint& position, uint32 line) +{ + wxPoint pos = position; + + if (pos.x <= OFFSET_ADDRESS + OFFSET_ADDRESS_RELATIVE) + return MPTR_NULL; + + pos.x -= OFFSET_ADDRESS + OFFSET_ADDRESS_RELATIVE; + + if (pos.x > OFFSET_MEMORY) + return MPTR_NULL; + + const uint32 byteIndex = (pos.x / m_char_width) / 3; + return LineToOffset(line) + byteIndex; +} + void DumpCtrl::OnMouseDClick(const wxPoint& position, uint32 line) { - wxPoint pos = position; - if (pos.x <= OFFSET_ADDRESS + OFFSET_ADDRESS_RELATIVE) + uint32 address = PositionToAddress(position, line); + + if (address == MPTR_NULL) return; - - pos.x -= OFFSET_ADDRESS + OFFSET_ADDRESS_RELATIVE; - if(pos.x <= OFFSET_MEMORY) + + if (!memory_isAddressRangeAccessible(address, 1)) + return; + + if (WriteNumericDialog(address)) { - const uint32 byte_index = (pos.x / m_char_width) / 3; - const uint32 offset = LineToOffset(line) + byte_index; - if (!memory_isAddressRangeAccessible(offset, 1)) - return; - const uint8 value = memory_readU8(offset); - - wxTextEntryDialog set_value_dialog(this, _("Enter a new value."), wxString::Format(_("Set byte at address %08x"), offset), wxString::Format("%02x", value)); - if (set_value_dialog.ShowModal() == wxID_OK) - { - const uint8 new_value = std::stoul(set_value_dialog.GetValue().ToStdString(), nullptr, 16); - memory_writeU8(offset, new_value); - wxRect update_rect(0, line * m_line_height, GetSize().x, m_line_height); - RefreshControl(&update_rect); - } - - return; + wxRect updateRect(0, line * m_line_height, GetSize().x, m_line_height); + RefreshControl(&updateRect); } } @@ -264,7 +279,6 @@ uint32 DumpCtrl::OffsetToLine(uint32 offset) return (offset - m_memoryRegion.baseAddress) / 0x10; } - void DumpCtrl::OnKeyPressed(sint32 key_code, const wxPoint& position) { switch (key_code) @@ -284,3 +298,144 @@ wxSize DumpCtrl::DoGetBestSize() const { return TextList::DoGetBestSize(); } + +void DumpCtrl::OnContextMenu(const wxPoint& position, uint32 line) +{ + const uint32 address = PositionToAddress(position, line); + + if (!memory_isAddressRangeAccessible(address, 1)) + return; + + m_writerContextAddress = address; + m_writerContextLine = line; + + wxMenu menu; + + menu.Append(ID_WRITE_U8, _("Write Byte")); + menu.Append(ID_WRITE_U16, _("Write Int16")); + menu.Append(ID_WRITE_U32, _("Write Int32")); + menu.Append(ID_WRITE_FLOAT, _("Write Float")); + menu.Append(ID_WRITE_STRING, _("Write String")); + + PopupMenu(&menu); +} + +void DumpCtrl::OnMenuSelected(wxCommandEvent& event) +{ + bool update = false; + switch (event.GetId()) + { + case ID_WRITE_U8: + update = WriteNumericDialog(m_writerContextAddress); + break; + case ID_WRITE_U16: + update = WriteNumericDialog(m_writerContextAddress); + break; + case ID_WRITE_U32: + update = WriteNumericDialog(m_writerContextAddress); + break; + case ID_WRITE_FLOAT: + update = WriteNumericDialog(m_writerContextAddress); + break; + case ID_WRITE_STRING: + update = WriteString(m_writerContextAddress); + break; + } + + if (update) + { + wxRect updateRect(0, m_writerContextLine * m_line_height, GetSize().x, m_line_height); + RefreshControl(&updateRect); + } +} + +template +bool DumpCtrl::WriteNumericDialog(uint32 address) +{ + static_assert( + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value, + "Unsupported type" + ); + + T value; + const char* dataType; + wxString label; + + if constexpr (std::is_same::value) + { + value = memory_readU8(address); + dataType = "byte"; + label = wxString::Format("0x%02x", value); + } + else if constexpr (std::is_same::value) + { + value = memory_readU16(address); + dataType = "int16"; + label = wxString::Format("0x%04x", value); + } + else if constexpr (std::is_same::value) + { + value = memory_readU32(address); + dataType = "int32"; + label = wxString::Format("0x%08x", value); + } + else if constexpr (std::is_same::value) + { + value = memory_readFloat(address); + dataType = "float"; + label = wxString::Format("%f", value); + } + + wxTextEntryDialog dialog( + this, + _("Enter a new value."), + wxString::Format(_("Write %s at address 0x%08x"), dataType, address), + label + ); + + if (dialog.ShowModal() != wxID_OK) + return false; + + + const T newValue = ConvertString(dialog.GetValue().ToStdString()); + + if constexpr (std::is_same::value) + memory_writeU8(address, newValue); + else if constexpr (std::is_same::value) + memory_writeU16(address, newValue); + else if constexpr (std::is_same::value) + memory_writeU32(address, newValue); + else if constexpr (std::is_same::value) + memory_writeFloat(address, newValue); + + return true; +} + +bool DumpCtrl::WriteString(uint32 address) +{ + wxTextEntryDialog dialog( + this, + _("Enter string"), + wxString::Format(_("Write string at address 0x%08x"), address), + "" + ); + + if (dialog.ShowModal() != wxID_OK) + return false; + + std::string text = dialog.GetValue().ToStdString(); + + if (text.empty()) + return false; + + for (size_t i = 0; i < text.size(); i++) + memory_writeU8(address + i, static_cast(text[i])); + + // null-terminator + memory_writeU8(address + text.size(), 0); + + return true; +} diff --git a/src/gui/wxgui/debugger/DumpCtrl.h b/src/gui/wxgui/debugger/DumpCtrl.h index eb7fc53b..b63bbc85 100644 --- a/src/gui/wxgui/debugger/DumpCtrl.h +++ b/src/gui/wxgui/debugger/DumpCtrl.h @@ -1,7 +1,6 @@ #pragma once #include "wxgui/components/TextList.h" - class DumpCtrl : public TextList { public: @@ -15,11 +14,18 @@ protected: void CenterOffset(uint32 offset); uint32 LineToOffset(uint32 line); uint32 OffsetToLine(uint32 offset); + uint32 PositionToAddress(const wxPoint& position, uint32 line); void OnDraw(wxDC& dc, sint32 start, sint32 count, const wxPoint& start_position) override; void OnMouseMove(const wxPoint& position, uint32 line) override; void OnMouseDClick(const wxPoint& position, uint32 line) override; void OnKeyPressed(sint32 key_code, const wxPoint& position) override; + void OnContextMenu(const wxPoint& position, uint32 line) override; + void OnMenuSelected(wxCommandEvent& event); + + template + bool WriteNumericDialog(uint32 address); + bool WriteString(uint32 address); private: struct { @@ -27,4 +33,6 @@ private: uint32 size; }m_memoryRegion; uint32 m_lastGotoOffset{0}; + uint32 m_writerContextAddress {0}; + uint32 m_writerContextLine {0}; }; diff --git a/src/gui/wxgui/debugger/RegisterWindow.cpp b/src/gui/wxgui/debugger/RegisterWindow.cpp index e8a136b9..d9241bef 100644 --- a/src/gui/wxgui/debugger/RegisterWindow.cpp +++ b/src/gui/wxgui/debugger/RegisterWindow.cpp @@ -8,6 +8,7 @@ #include "Cafe/OS/RPL/rpl.h" #include "Cafe/OS/RPL/rpl_structs.h" #include "Cafe/HW/Espresso/EspressoISA.h" +#include "util/helpers/helpers.h" enum { @@ -355,15 +356,17 @@ void RegisterWindow::OnMouseDClickEvent(wxMouseEvent& event) { const uint32 register_index = id - kRegisterValueR0; const uint32 register_value = ppcSnapshot.gpr[register_index]; - wxTextEntryDialog set_value_dialog(this, _("Enter a new value."), wxString::Format(_("Set R%d value"), register_index), wxString::Format("%08x", register_value)); + wxTextEntryDialog set_value_dialog(this, _("Enter a new value."), wxString::Format(_("Set R%d value"), register_index), wxString::Format("0x%08x", register_value)); if (set_value_dialog.ShowModal() == wxID_OK) { - const uint32 new_value = std::stoul(set_value_dialog.GetValue().ToStdString(), nullptr, 16); + const uint32 value = ConvertString(set_value_dialog.GetValue().ToStdString()); + if (debugSession = debugger_lockDebugSession(); debugSession) { - debugSession->gpr[register_index] = new_value; + debugSession->gpr[register_index] = value; debugger_unlockDebugSession(debugSession); } + OnUpdateView(); } return; @@ -376,12 +379,14 @@ void RegisterWindow::OnMouseDClickEvent(wxMouseEvent& event) wxTextEntryDialog set_value_dialog(this, _("Enter a new value."), wxString::Format(_("Set FP0_%d value"), register_index), wxString::Format("%lf", register_value)); if (set_value_dialog.ShowModal() == wxID_OK) { - const double new_value = std::stod(set_value_dialog.GetValue().ToStdString()); + const double value = ConvertString(set_value_dialog.GetValue().ToStdString()); + if (debugSession = debugger_lockDebugSession(); debugSession) { - debugSession->fpr[register_index].fp0 = new_value; + debugSession->fpr[register_index].fp0 = value; debugger_unlockDebugSession(debugSession); } + OnUpdateView(); } @@ -395,12 +400,14 @@ void RegisterWindow::OnMouseDClickEvent(wxMouseEvent& event) wxTextEntryDialog set_value_dialog(this, _("Enter a new value."), wxString::Format(_("Set FP1_%d value"), register_index), wxString::Format("%lf", register_value)); if (set_value_dialog.ShowModal() == wxID_OK) { - const double new_value = std::stod(set_value_dialog.GetValue().ToStdString()); + const double value = ConvertString(set_value_dialog.GetValue().ToStdString()); + if (debugSession = debugger_lockDebugSession(); debugSession) { - debugSession->fpr[register_index].fp1 = new_value; + debugSession->fpr[register_index].fp1 = value; debugger_unlockDebugSession(debugSession); } + OnUpdateView(); } return;