2015-05-24 04:55:12 +00:00
|
|
|
// Copyright 2008 Dolphin Emulator Project
|
2015-05-17 23:08:10 +00:00
|
|
|
// Licensed under GPLv2+
|
2013-04-18 03:43:35 +00:00
|
|
|
// Refer to the license.txt file included.
|
2008-12-08 05:30:24 +00:00
|
|
|
|
2016-10-03 07:29:50 +00:00
|
|
|
#include <algorithm>
|
|
|
|
#include <array>
|
2014-02-22 22:36:30 +00:00
|
|
|
#include <cstddef>
|
|
|
|
#include <cstdio>
|
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
2008-12-08 05:30:24 +00:00
|
|
|
#include <wx/button.h>
|
2014-02-22 22:36:30 +00:00
|
|
|
#include <wx/checkbox.h>
|
|
|
|
#include <wx/listbox.h>
|
|
|
|
#include <wx/msgdlg.h>
|
|
|
|
#include <wx/panel.h>
|
2016-10-03 07:29:50 +00:00
|
|
|
#include <wx/radiobox.h>
|
2016-08-18 20:08:26 +00:00
|
|
|
#include <wx/radiobut.h>
|
2014-02-22 22:36:30 +00:00
|
|
|
#include <wx/sizer.h>
|
2015-08-03 08:39:06 +00:00
|
|
|
#include <wx/srchctrl.h>
|
2016-10-03 07:29:50 +00:00
|
|
|
#include <wx/stattext.h>
|
2014-02-19 01:56:29 +00:00
|
|
|
#include <wx/textctrl.h>
|
2016-10-03 07:29:50 +00:00
|
|
|
#include <wx/utils.h>
|
2013-02-28 04:37:38 +00:00
|
|
|
|
2014-09-08 01:06:58 +00:00
|
|
|
#include "Common/CommonTypes.h"
|
2014-02-17 10:18:15 +00:00
|
|
|
#include "Common/FileUtil.h"
|
2014-02-22 22:36:30 +00:00
|
|
|
#include "Common/IniFile.h"
|
|
|
|
#include "Common/StringUtil.h"
|
|
|
|
#include "Common/SymbolDB.h"
|
2014-02-17 10:18:15 +00:00
|
|
|
#include "Core/ConfigManager.h"
|
|
|
|
#include "Core/Debugger/PPCDebugInterface.h"
|
|
|
|
#include "Core/HW/DSP.h"
|
|
|
|
#include "Core/HW/Memmap.h"
|
|
|
|
#include "Core/PowerPC/PowerPC.h"
|
2016-08-11 18:24:10 +00:00
|
|
|
#include "DolphinWX/Debugger/BreakpointWindow.h"
|
|
|
|
#include "DolphinWX/Debugger/CodeWindow.h"
|
2014-02-22 22:36:30 +00:00
|
|
|
#include "DolphinWX/Debugger/MemoryView.h"
|
2014-02-17 10:18:15 +00:00
|
|
|
#include "DolphinWX/Debugger/MemoryWindow.h"
|
2016-06-24 08:43:46 +00:00
|
|
|
#include "DolphinWX/Globals.h"
|
|
|
|
#include "DolphinWX/WxUtils.h"
|
2008-12-08 05:30:24 +00:00
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
IDM_MEM_ADDRBOX,
|
|
|
|
IDM_SYMBOLLIST,
|
|
|
|
IDM_SETVALBUTTON,
|
|
|
|
IDM_DUMP_MEMORY,
|
|
|
|
IDM_DUMP_MEM2,
|
|
|
|
IDM_DUMP_FAKEVMEM,
|
|
|
|
IDM_VALBOX,
|
2016-10-03 07:29:50 +00:00
|
|
|
IDM_DATA_TYPE_RBOX,
|
2016-06-24 08:43:46 +00:00
|
|
|
IDM_SEARCH,
|
|
|
|
IDM_ASCII,
|
2016-08-18 20:08:26 +00:00
|
|
|
IDM_HEX,
|
|
|
|
IDM_MEMCHECK_OPTIONS_CHANGE
|
2008-12-08 05:30:24 +00:00
|
|
|
};
|
|
|
|
|
2009-09-07 20:51:02 +00:00
|
|
|
BEGIN_EVENT_TABLE(CMemoryWindow, wxPanel)
|
2016-06-24 08:43:46 +00:00
|
|
|
EVT_BUTTON(IDM_SETVALBUTTON, CMemoryWindow::SetMemoryValue)
|
|
|
|
EVT_BUTTON(IDM_DUMP_MEMORY, CMemoryWindow::OnDumpMemory)
|
|
|
|
EVT_BUTTON(IDM_DUMP_MEM2, CMemoryWindow::OnDumpMem2)
|
|
|
|
EVT_BUTTON(IDM_DUMP_FAKEVMEM, CMemoryWindow::OnDumpFakeVMEM)
|
2016-10-03 07:29:50 +00:00
|
|
|
EVT_RADIOBOX(IDM_DATA_TYPE_RBOX, CMemoryWindow::OnDataTypeChanged)
|
|
|
|
EVT_BUTTON(IDM_SEARCH, CMemoryWindow::OnSearch)
|
|
|
|
EVT_RADIOBUTTON(IDM_MEMCHECK_OPTIONS_CHANGE, CMemoryWindow::OnMemCheckOptionChange)
|
|
|
|
EVT_CHECKBOX(IDM_MEMCHECK_OPTIONS_CHANGE, CMemoryWindow::OnMemCheckOptionChange)
|
2008-12-08 05:30:24 +00:00
|
|
|
END_EVENT_TABLE()
|
|
|
|
|
2016-10-03 07:29:50 +00:00
|
|
|
CMemoryWindow::CMemoryWindow(wxWindow* parent, wxWindowID id, const wxPoint& pos,
|
|
|
|
const wxSize& size, long style, const wxString& name)
|
|
|
|
: wxPanel(parent, id, pos, size, style, name)
|
2010-07-24 02:36:22 +00:00
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
DebugInterface* di = &PowerPC::debug_interface;
|
|
|
|
|
|
|
|
memview = new CMemoryView(di, this);
|
2016-10-03 07:29:50 +00:00
|
|
|
memview->Bind(DOLPHIN_EVT_MEMORY_VIEW_DATA_TYPE_CHANGED, &CMemoryWindow::OnDataTypeChanged, this);
|
2016-06-24 08:43:46 +00:00
|
|
|
|
|
|
|
addrbox = new wxSearchCtrl(this, IDM_MEM_ADDRBOX);
|
|
|
|
addrbox->Bind(wxEVT_TEXT, &CMemoryWindow::OnAddrBoxChange, this);
|
|
|
|
addrbox->SetDescriptiveText(_("Search Address"));
|
|
|
|
|
|
|
|
valbox =
|
|
|
|
new wxTextCtrl(this, IDM_VALBOX, "", wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);
|
|
|
|
valbox->Bind(wxEVT_TEXT_ENTER, &CMemoryWindow::SetMemoryValueFromValBox, this);
|
2016-10-03 07:29:50 +00:00
|
|
|
valbox->Bind(wxEVT_TEXT, &CMemoryWindow::OnValueChanged, this);
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2016-10-03 07:29:50 +00:00
|
|
|
const int space3 = FromDIP(3);
|
|
|
|
const int space5 = FromDIP(5);
|
|
|
|
|
|
|
|
wxBoxSizer* const search_sizer = new wxBoxSizer(wxVERTICAL);
|
|
|
|
search_sizer->Add(addrbox, 0, wxEXPAND);
|
2016-06-24 08:43:46 +00:00
|
|
|
search_sizer->Add(valbox, 0, wxEXPAND);
|
|
|
|
search_sizer->Add(new wxButton(this, IDM_SETVALBUTTON, _("Set Value")));
|
|
|
|
|
2016-10-03 07:29:50 +00:00
|
|
|
wxBoxSizer* const dump_sizer = new wxBoxSizer(wxVERTICAL);
|
2016-06-24 08:43:46 +00:00
|
|
|
dump_sizer->Add(new wxButton(this, IDM_DUMP_MEMORY, _("Dump MRAM")), 0, wxEXPAND);
|
|
|
|
dump_sizer->Add(new wxButton(this, IDM_DUMP_MEM2, _("Dump EXRAM")), 0, wxEXPAND);
|
|
|
|
if (!SConfig::GetInstance().bMMU)
|
|
|
|
dump_sizer->Add(new wxButton(this, IDM_DUMP_FAKEVMEM, _("Dump FakeVMEM")), 0, wxEXPAND);
|
|
|
|
|
|
|
|
wxStaticBoxSizer* const sizerSearchType = new wxStaticBoxSizer(wxVERTICAL, this, _("Search"));
|
|
|
|
sizerSearchType->Add(btnSearch = new wxButton(this, IDM_SEARCH, _("Search")));
|
2016-10-03 07:29:50 +00:00
|
|
|
sizerSearchType->Add(m_rb_ascii = new wxRadioButton(this, IDM_ASCII, "Ascii", wxDefaultPosition,
|
|
|
|
wxDefaultSize, wxRB_GROUP));
|
|
|
|
sizerSearchType->Add(m_rb_hex = new wxRadioButton(this, IDM_HEX, _("Hex")));
|
|
|
|
m_search_result_msg =
|
|
|
|
new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
|
|
|
|
wxST_NO_AUTORESIZE | wxALIGN_CENTER_HORIZONTAL);
|
|
|
|
sizerSearchType->Add(m_search_result_msg, 0, wxEXPAND);
|
|
|
|
|
|
|
|
wxArrayString data_type_options;
|
|
|
|
data_type_options.Add("U8");
|
|
|
|
data_type_options.Add("U16");
|
|
|
|
data_type_options.Add("U32");
|
|
|
|
data_type_options.Add("ASCII");
|
|
|
|
data_type_options.Add("Float32");
|
|
|
|
m_rbox_data_type = new wxRadioBox(this, IDM_DATA_TYPE_RBOX, _("Data Type"), wxDefaultPosition,
|
|
|
|
wxDefaultSize, data_type_options, 1);
|
|
|
|
|
|
|
|
wxStaticBoxSizer* const memcheck_options_sizer =
|
2016-10-06 14:46:09 +00:00
|
|
|
new wxStaticBoxSizer(wxVERTICAL, this, "Memory breakpoint options");
|
2016-10-03 07:29:50 +00:00
|
|
|
memcheck_options_sizer->Add(rdbReadWrite = new wxRadioButton(this, IDM_MEMCHECK_OPTIONS_CHANGE,
|
|
|
|
"Read and Write", wxDefaultPosition,
|
|
|
|
wxDefaultSize, wxRB_GROUP));
|
|
|
|
memcheck_options_sizer->Add(
|
|
|
|
rdbRead = new wxRadioButton(this, IDM_MEMCHECK_OPTIONS_CHANGE, "Read only"));
|
|
|
|
memcheck_options_sizer->Add(
|
|
|
|
rdbWrite = new wxRadioButton(this, IDM_MEMCHECK_OPTIONS_CHANGE, "Write only"));
|
|
|
|
memcheck_options_sizer->Add(chkLog = new wxCheckBox(this, IDM_MEMCHECK_OPTIONS_CHANGE, "Log"));
|
2016-08-18 20:08:26 +00:00
|
|
|
|
2016-06-24 08:43:46 +00:00
|
|
|
wxBoxSizer* const sizerRight = new wxBoxSizer(wxVERTICAL);
|
|
|
|
sizerRight->Add(search_sizer);
|
2016-10-03 07:29:50 +00:00
|
|
|
sizerRight->AddSpacer(space5);
|
|
|
|
sizerRight->Add(dump_sizer, 0, wxEXPAND);
|
|
|
|
sizerRight->Add(sizerSearchType, 0, wxEXPAND);
|
|
|
|
sizerRight->Add(m_rbox_data_type, 0, wxEXPAND);
|
|
|
|
sizerRight->Add(memcheck_options_sizer, 0, wxEXPAND);
|
2016-06-24 08:43:46 +00:00
|
|
|
|
|
|
|
wxBoxSizer* const sizerBig = new wxBoxSizer(wxHORIZONTAL);
|
|
|
|
sizerBig->Add(memview, 20, wxEXPAND);
|
2016-10-03 07:29:50 +00:00
|
|
|
sizerBig->AddSpacer(space3);
|
|
|
|
sizerBig->Add(sizerRight, 0, wxEXPAND | wxTOP | wxBOTTOM, space3);
|
|
|
|
sizerBig->AddSpacer(space3);
|
2016-06-24 08:43:46 +00:00
|
|
|
|
|
|
|
SetSizer(sizerBig);
|
2016-10-03 07:29:50 +00:00
|
|
|
m_rb_hex->SetValue(true); // Set defaults
|
|
|
|
chkLog->SetValue(true);
|
|
|
|
m_rbox_data_type->SetSelection(static_cast<int>(memview->GetDataType()));
|
2016-06-24 08:43:46 +00:00
|
|
|
|
|
|
|
sizerRight->Fit(this);
|
|
|
|
sizerBig->Fit(this);
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CMemoryWindow::JumpToAddress(u32 _Address)
|
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
memview->Center(_Address);
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
|
|
|
|
2015-04-25 02:19:21 +00:00
|
|
|
void CMemoryWindow::SetMemoryValueFromValBox(wxCommandEvent& event)
|
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
SetMemoryValue(event);
|
|
|
|
valbox->SetFocus();
|
2015-04-25 02:19:21 +00:00
|
|
|
}
|
|
|
|
|
2008-12-08 05:30:24 +00:00
|
|
|
void CMemoryWindow::SetMemoryValue(wxCommandEvent& event)
|
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
if (!Memory::IsInitialized())
|
|
|
|
{
|
|
|
|
WxUtils::ShowErrorDialog(_("Cannot set uninitialized memory."));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string str_addr = WxStrToStr(addrbox->GetValue());
|
|
|
|
std::string str_val = WxStrToStr(valbox->GetValue());
|
|
|
|
u32 addr;
|
|
|
|
u32 val;
|
|
|
|
|
|
|
|
if (!TryParse(std::string("0x") + str_addr, &addr))
|
|
|
|
{
|
|
|
|
WxUtils::ShowErrorDialog(wxString::Format(_("Invalid address: %s"), str_addr.c_str()));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!TryParse(std::string("0x") + str_val, &val))
|
|
|
|
{
|
|
|
|
WxUtils::ShowErrorDialog(wxString::Format(_("Invalid value: %s"), str_val.c_str()));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
PowerPC::HostWrite_U32(val, addr);
|
|
|
|
memview->Refresh();
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
2009-06-17 19:50:59 +00:00
|
|
|
|
2008-12-08 05:30:24 +00:00
|
|
|
void CMemoryWindow::OnAddrBoxChange(wxCommandEvent& event)
|
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
wxString txt = addrbox->GetValue();
|
|
|
|
if (txt.size())
|
|
|
|
{
|
|
|
|
u32 addr;
|
|
|
|
sscanf(WxStrToStr(txt).c_str(), "%08x", &addr);
|
|
|
|
memview->Center(addr & ~3);
|
|
|
|
}
|
|
|
|
|
|
|
|
event.Skip();
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
|
|
|
|
2016-10-03 07:29:50 +00:00
|
|
|
void CMemoryWindow::Repopulate()
|
2008-12-08 05:30:24 +00:00
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
memview->Center(PC);
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
|
|
|
|
2016-10-03 07:29:50 +00:00
|
|
|
void CMemoryWindow::OnValueChanged(wxCommandEvent&)
|
2008-12-08 05:30:24 +00:00
|
|
|
{
|
2016-10-03 07:29:50 +00:00
|
|
|
m_continue_search = false;
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
|
|
|
|
2014-07-08 12:29:26 +00:00
|
|
|
static void DumpArray(const std::string& filename, const u8* data, size_t length)
|
2009-01-21 17:02:01 +00:00
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
if (data)
|
|
|
|
{
|
|
|
|
File::IOFile f(filename, "wb");
|
|
|
|
f.WriteBytes(data, length);
|
|
|
|
}
|
2010-10-14 04:07:04 +00:00
|
|
|
}
|
|
|
|
|
2011-03-11 10:21:46 +00:00
|
|
|
// Write mram to file
|
2016-06-24 08:43:46 +00:00
|
|
|
void CMemoryWindow::OnDumpMemory(wxCommandEvent& event)
|
2011-03-11 10:21:46 +00:00
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
DumpArray(File::GetUserPath(F_RAMDUMP_IDX), Memory::m_pRAM, Memory::REALRAM_SIZE);
|
2011-03-11 10:21:46 +00:00
|
|
|
}
|
|
|
|
|
2010-10-14 04:07:04 +00:00
|
|
|
// Write exram (aram or mem2) to file
|
2016-06-24 08:43:46 +00:00
|
|
|
void CMemoryWindow::OnDumpMem2(wxCommandEvent& event)
|
2013-10-29 05:23:17 +00:00
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
if (SConfig::GetInstance().bWii)
|
|
|
|
{
|
|
|
|
DumpArray(File::GetUserPath(F_ARAMDUMP_IDX), Memory::m_pEXRAM, Memory::EXRAM_SIZE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DumpArray(File::GetUserPath(F_ARAMDUMP_IDX), DSP::GetARAMPtr(), DSP::ARAM_SIZE);
|
|
|
|
}
|
2009-06-30 21:11:39 +00:00
|
|
|
}
|
2009-11-25 10:07:56 +00:00
|
|
|
|
2012-06-19 11:51:29 +00:00
|
|
|
// Write fake vmem to file
|
2016-06-24 08:43:46 +00:00
|
|
|
void CMemoryWindow::OnDumpFakeVMEM(wxCommandEvent& event)
|
2012-06-19 11:51:29 +00:00
|
|
|
{
|
2016-06-24 08:43:46 +00:00
|
|
|
DumpArray(File::GetUserPath(F_FAKEVMEMDUMP_IDX), Memory::m_pFakeVMEM, Memory::FAKEVMEM_SIZE);
|
2012-06-19 11:51:29 +00:00
|
|
|
}
|
|
|
|
|
2016-10-03 07:29:50 +00:00
|
|
|
void CMemoryWindow::OnDataTypeChanged(wxCommandEvent& ev)
|
2010-07-24 02:36:22 +00:00
|
|
|
{
|
2016-10-03 07:29:50 +00:00
|
|
|
static constexpr std::array<MemoryDataType, 5> map{{MemoryDataType::U8, MemoryDataType::U16,
|
|
|
|
MemoryDataType::U32, MemoryDataType::ASCII,
|
|
|
|
MemoryDataType::FloatingPoint}};
|
|
|
|
if (ev.GetId() == IDM_DATA_TYPE_RBOX)
|
|
|
|
{
|
|
|
|
memview->SetDataType(map.at(ev.GetSelection()));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Event from the CMemoryView indicating type was changed.
|
|
|
|
auto itr = std::find(map.begin(), map.end(), static_cast<MemoryDataType>(ev.GetInt()));
|
|
|
|
int idx = -1;
|
|
|
|
if (itr != map.end())
|
|
|
|
idx = static_cast<int>(itr - map.begin());
|
|
|
|
m_rbox_data_type->SetSelection(idx);
|
|
|
|
}
|
2009-11-25 10:07:56 +00:00
|
|
|
}
|
|
|
|
|
2016-10-03 07:29:50 +00:00
|
|
|
void CMemoryWindow::OnSearch(wxCommandEvent& event)
|
2010-07-24 02:36:22 +00:00
|
|
|
{
|
2016-10-03 07:29:50 +00:00
|
|
|
wxBusyCursor hourglass_cursor;
|
|
|
|
u8* ram_ptr = nullptr;
|
|
|
|
u32 ram_size = 0;
|
|
|
|
// NOTE: We're assuming the base address is zero.
|
2016-06-24 08:43:46 +00:00
|
|
|
switch (memview->GetMemoryType())
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
default:
|
|
|
|
if (Memory::m_pRAM)
|
|
|
|
{
|
2016-10-03 07:29:50 +00:00
|
|
|
ram_ptr = Memory::m_pRAM;
|
|
|
|
ram_size = Memory::REALRAM_SIZE;
|
2016-06-24 08:43:46 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
{
|
|
|
|
u8* aram = DSP::GetARAMPtr();
|
|
|
|
if (aram)
|
|
|
|
{
|
2016-10-03 07:29:50 +00:00
|
|
|
ram_ptr = aram;
|
|
|
|
ram_size = DSP::ARAM_SIZE;
|
2016-06-24 08:43:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2016-10-03 07:29:50 +00:00
|
|
|
if (!ram_ptr)
|
2016-06-24 08:43:46 +00:00
|
|
|
{
|
2016-10-03 07:29:50 +00:00
|
|
|
m_search_result_msg->SetLabel(_("Memory Not Ready"));
|
|
|
|
return;
|
|
|
|
}
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2016-10-03 07:29:50 +00:00
|
|
|
std::vector<u8> search_bytes;
|
|
|
|
wxString search_val = valbox->GetValue();
|
|
|
|
|
|
|
|
if (m_rb_hex->GetValue())
|
|
|
|
{
|
|
|
|
search_val.Trim(true).Trim(false);
|
|
|
|
// If there's a trailing nybble, stick a zero in front to make it a byte
|
|
|
|
if (search_val.size() & 1)
|
|
|
|
search_val.insert(0, 1, '0');
|
|
|
|
search_bytes.reserve(search_val.size() / 2);
|
|
|
|
|
|
|
|
wxString conversion_buffer(2, ' ');
|
|
|
|
for (std::size_t i = 0; i < search_val.size(); i += 2)
|
2016-06-24 08:43:46 +00:00
|
|
|
{
|
2016-10-03 07:29:50 +00:00
|
|
|
unsigned long byte = 0;
|
|
|
|
conversion_buffer[0] = search_val[i];
|
|
|
|
conversion_buffer[1] = search_val[i + 1];
|
|
|
|
if (!conversion_buffer.ToULong(&byte, 16))
|
|
|
|
{
|
|
|
|
m_search_result_msg->SetLabel(_("Not Valid Hex"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
search_bytes.push_back(static_cast<u8>(byte));
|
2016-06-24 08:43:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-10-03 07:29:50 +00:00
|
|
|
const auto& bytes = search_val.ToUTF8();
|
|
|
|
search_bytes.assign(bytes.data(), bytes.data() + bytes.length());
|
|
|
|
}
|
|
|
|
search_val.Clear();
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2016-10-03 07:29:50 +00:00
|
|
|
// For completeness
|
|
|
|
if (search_bytes.size() > ram_size)
|
|
|
|
{
|
|
|
|
m_search_result_msg->SetLabel(_("Value Too Large"));
|
|
|
|
return;
|
|
|
|
}
|
2016-06-24 08:43:46 +00:00
|
|
|
|
2016-10-03 07:29:50 +00:00
|
|
|
if (search_bytes.empty())
|
|
|
|
{
|
|
|
|
m_search_result_msg->SetLabel(_("No Value Given"));
|
|
|
|
return;
|
2016-06-24 08:43:46 +00:00
|
|
|
}
|
|
|
|
|
2016-10-03 07:29:50 +00:00
|
|
|
// Search starting from specified address if there is one.
|
|
|
|
u32 addr = 0; // Base address
|
2016-06-24 08:43:46 +00:00
|
|
|
{
|
2016-10-03 07:29:50 +00:00
|
|
|
wxString addr_val = addrbox->GetValue();
|
|
|
|
addr_val.Trim(true).Trim(false);
|
|
|
|
if (!addr_val.empty())
|
2016-06-24 08:43:46 +00:00
|
|
|
{
|
2016-10-03 07:29:50 +00:00
|
|
|
unsigned long addr_ul = 0;
|
|
|
|
if (addr_val.ToULong(&addr_ul, 16))
|
2016-06-24 08:43:46 +00:00
|
|
|
{
|
2016-10-03 07:29:50 +00:00
|
|
|
addr = static_cast<u32>(addr_ul);
|
|
|
|
// Don't find the result we're already looking at
|
|
|
|
if (m_continue_search && addr == m_last_search_address)
|
|
|
|
addr += 1;
|
2016-06-24 08:43:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-11-25 10:07:56 +00:00
|
|
|
|
2016-10-03 07:29:50 +00:00
|
|
|
// If the current address doesn't leave enough bytes to search then we're done.
|
|
|
|
if (addr >= ram_size - search_bytes.size())
|
|
|
|
{
|
|
|
|
m_search_result_msg->SetLabel(_("Address Out of Range"));
|
|
|
|
return;
|
|
|
|
}
|
2009-11-25 10:07:56 +00:00
|
|
|
|
2016-10-03 07:29:50 +00:00
|
|
|
u8* end = &ram_ptr[ram_size - search_bytes.size() + 1];
|
|
|
|
u8* ptr = &ram_ptr[addr];
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
ptr = std::find(ptr, end, search_bytes[0]);
|
|
|
|
if (ptr == end)
|
|
|
|
{
|
|
|
|
m_search_result_msg->SetLabel(_("No Match"));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (std::equal(search_bytes.begin(), search_bytes.end(), ptr))
|
|
|
|
{
|
|
|
|
m_search_result_msg->SetLabel(_("Match Found"));
|
|
|
|
u32 offset = static_cast<u32>(ptr - ram_ptr);
|
|
|
|
// NOTE: SetValue() generates a synthetic wxEVT_TEXT
|
|
|
|
addrbox->SetValue(wxString::Format("%08x", offset));
|
|
|
|
m_last_search_address = offset;
|
|
|
|
m_continue_search = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
++ptr;
|
|
|
|
}
|
2009-12-15 14:40:03 +00:00
|
|
|
}
|
2016-08-18 20:08:26 +00:00
|
|
|
|
2016-10-03 07:29:50 +00:00
|
|
|
void CMemoryWindow::OnMemCheckOptionChange(wxCommandEvent& event)
|
2016-08-18 20:08:26 +00:00
|
|
|
{
|
|
|
|
if (rdbReadWrite->GetValue())
|
|
|
|
memview->SetMemCheckOptions(true, true, chkLog->GetValue());
|
|
|
|
else
|
|
|
|
memview->SetMemCheckOptions(rdbRead->GetValue(), rdbWrite->GetValue(), chkLog->GetValue());
|
|
|
|
}
|