mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-15 13:57:57 -07:00
ac54c6a4e2
The PowerPC CPU has bits in MSR (DR and IR) which control whether addresses are translated. We should respect these instead of mixing physical addresses and translated addresses into the same address space. This is mostly mass-renaming calls to memory accesses APIs from places which expect address translation to use a different version from those which do not expect address translation. This does very little on its own, but it's the first step to a correct BAT implementation.
446 lines
11 KiB
C++
446 lines
11 KiB
C++
// Copyright 2013 Dolphin Emulator Project
|
|
// Licensed under GPLv2
|
|
// Refer to the license.txt file included.
|
|
|
|
#include <cstddef>
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <wx/button.h>
|
|
#include <wx/chartype.h>
|
|
#include <wx/checkbox.h>
|
|
#include <wx/defs.h>
|
|
#include <wx/event.h>
|
|
#include <wx/gdicmn.h>
|
|
#include <wx/listbox.h>
|
|
#include <wx/msgdlg.h>
|
|
#include <wx/panel.h>
|
|
#include <wx/sizer.h>
|
|
#include <wx/string.h>
|
|
#include <wx/textctrl.h>
|
|
#include <wx/translation.h>
|
|
#include <wx/window.h>
|
|
#include <wx/windowid.h>
|
|
#include <wx/wxcrtvararg.h>
|
|
|
|
#include "Common/CommonTypes.h"
|
|
#include "Common/FileUtil.h"
|
|
#include "Common/IniFile.h"
|
|
#include "Common/StringUtil.h"
|
|
#include "Common/SymbolDB.h"
|
|
#include "Core/ConfigManager.h"
|
|
#include "Core/CoreParameter.h"
|
|
#include "Core/Debugger/PPCDebugInterface.h"
|
|
#include "Core/HW/DSP.h"
|
|
#include "Core/HW/Memmap.h"
|
|
#include "Core/PowerPC/PowerPC.h"
|
|
#include "DolphinWX/Globals.h"
|
|
#include "DolphinWX/WxUtils.h"
|
|
#include "DolphinWX/Debugger/MemoryView.h"
|
|
#include "DolphinWX/Debugger/MemoryWindow.h"
|
|
|
|
enum
|
|
{
|
|
IDM_MEM_ADDRBOX,
|
|
IDM_SYMBOLLIST,
|
|
IDM_SETVALBUTTON,
|
|
IDM_DUMP_MEMORY,
|
|
IDM_DUMP_MEM2,
|
|
IDM_DUMP_FAKEVMEM,
|
|
IDM_VALBOX,
|
|
IDM_U8,
|
|
IDM_U16,
|
|
IDM_U32,
|
|
IDM_SEARCH,
|
|
IDM_ASCII,
|
|
IDM_HEX
|
|
};
|
|
|
|
BEGIN_EVENT_TABLE(CMemoryWindow, wxPanel)
|
|
EVT_TEXT(IDM_MEM_ADDRBOX, CMemoryWindow::OnAddrBoxChange)
|
|
EVT_LISTBOX(IDM_SYMBOLLIST, CMemoryWindow::OnSymbolListChange)
|
|
EVT_HOST_COMMAND(wxID_ANY, CMemoryWindow::OnHostMessage)
|
|
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)
|
|
EVT_CHECKBOX(IDM_U8, CMemoryWindow::U8)
|
|
EVT_CHECKBOX(IDM_U16, CMemoryWindow::U16)
|
|
EVT_CHECKBOX(IDM_U32, CMemoryWindow::U32)
|
|
EVT_BUTTON(IDM_SEARCH, CMemoryWindow::onSearch)
|
|
EVT_CHECKBOX(IDM_ASCII, CMemoryWindow::onAscii)
|
|
EVT_CHECKBOX(IDM_HEX, CMemoryWindow::onHex)
|
|
END_EVENT_TABLE()
|
|
|
|
CMemoryWindow::CMemoryWindow(wxWindow* parent, wxWindowID id,
|
|
const wxPoint& pos, const wxSize& size, long style, const wxString& name)
|
|
: wxPanel(parent, id, pos, size, style, name)
|
|
{
|
|
wxBoxSizer* sizerBig = new wxBoxSizer(wxHORIZONTAL);
|
|
wxBoxSizer* sizerRight = new wxBoxSizer(wxVERTICAL);
|
|
// Didn't see anything useful in the left part
|
|
//wxBoxSizer* sizerLeft = new wxBoxSizer(wxVERTICAL);
|
|
|
|
DebugInterface* di = &PowerPC::debug_interface;
|
|
|
|
//symbols = new wxListBox(this, IDM_SYMBOLLIST, wxDefaultPosition,
|
|
// wxSize(20, 100), 0, nullptr, wxLB_SORT);
|
|
//sizerLeft->Add(symbols, 1, wxEXPAND);
|
|
memview = new CMemoryView(di, this);
|
|
memview->dataType = 0;
|
|
//sizerBig->Add(sizerLeft, 1, wxEXPAND);
|
|
sizerBig->Add(memview, 20, wxEXPAND);
|
|
sizerBig->Add(sizerRight, 0, wxEXPAND | wxALL, 3);
|
|
sizerRight->Add(addrbox = new wxTextCtrl(this, IDM_MEM_ADDRBOX, ""));
|
|
sizerRight->Add(valbox = new wxTextCtrl(this, IDM_VALBOX, ""));
|
|
sizerRight->Add(new wxButton(this, IDM_SETVALBUTTON, _("Set &Value")));
|
|
|
|
sizerRight->AddSpacer(5);
|
|
sizerRight->Add(new wxButton(this, IDM_DUMP_MEMORY, _("&Dump MRAM")));
|
|
sizerRight->Add(new wxButton(this, IDM_DUMP_MEM2, _("&Dump EXRAM")));
|
|
|
|
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bMMU)
|
|
sizerRight->Add(new wxButton(this, IDM_DUMP_FAKEVMEM, _("&Dump FakeVMEM")));
|
|
|
|
wxStaticBoxSizer* sizerSearchType = new wxStaticBoxSizer(wxVERTICAL, this, _("Search"));
|
|
|
|
sizerSearchType->Add(btnSearch = new wxButton(this, IDM_SEARCH, _("Search")));
|
|
sizerSearchType->Add(chkAscii = new wxCheckBox(this, IDM_ASCII, "&Ascii "));
|
|
sizerSearchType->Add(chkHex = new wxCheckBox(this, IDM_HEX, _("&Hex")));
|
|
sizerRight->Add(sizerSearchType);
|
|
wxStaticBoxSizer* sizerDataTypes = new wxStaticBoxSizer(wxVERTICAL, this, _("Data Type"));
|
|
|
|
sizerDataTypes->SetMinSize(74, 40);
|
|
sizerDataTypes->Add(chk8 = new wxCheckBox(this, IDM_U8, "&U8"));
|
|
sizerDataTypes->Add(chk16 = new wxCheckBox(this, IDM_U16, "&U16"));
|
|
sizerDataTypes->Add(chk32 = new wxCheckBox(this, IDM_U32, "&U32"));
|
|
sizerRight->Add(sizerDataTypes);
|
|
SetSizer(sizerBig);
|
|
chkHex->SetValue(1); //Set defaults
|
|
chk8->SetValue(1);
|
|
|
|
//sizerLeft->Fit(this);
|
|
sizerRight->Fit(this);
|
|
sizerBig->Fit(this);
|
|
}
|
|
|
|
void CMemoryWindow::Save(IniFile& ini) const
|
|
{
|
|
// Prevent these bad values that can happen after a crash or hanging
|
|
if (GetPosition().x != -32000 && GetPosition().y != -32000)
|
|
{
|
|
IniFile::Section* mem_window = ini.GetOrCreateSection("MemoryWindow");
|
|
mem_window->Set("x", GetPosition().x);
|
|
mem_window->Set("y", GetPosition().y);
|
|
mem_window->Set("w", GetSize().GetWidth());
|
|
mem_window->Set("h", GetSize().GetHeight());
|
|
}
|
|
}
|
|
|
|
void CMemoryWindow::Load(IniFile& ini)
|
|
{
|
|
int x, y, w, h;
|
|
|
|
IniFile::Section* mem_window = ini.GetOrCreateSection("MemoryWindow");
|
|
mem_window->Get("x", &x, GetPosition().x);
|
|
mem_window->Get("y", &y, GetPosition().y);
|
|
mem_window->Get("w", &w, GetSize().GetWidth());
|
|
mem_window->Get("h", &h, GetSize().GetHeight());
|
|
|
|
SetSize(x, y, w, h);
|
|
}
|
|
|
|
void CMemoryWindow::JumpToAddress(u32 _Address)
|
|
{
|
|
memview->Center(_Address);
|
|
}
|
|
|
|
void CMemoryWindow::SetMemoryValue(wxCommandEvent& event)
|
|
{
|
|
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();
|
|
}
|
|
|
|
void CMemoryWindow::OnAddrBoxChange(wxCommandEvent& event)
|
|
{
|
|
wxString txt = addrbox->GetValue();
|
|
if (txt.size())
|
|
{
|
|
u32 addr;
|
|
sscanf(WxStrToStr(txt).c_str(), "%08x", &addr);
|
|
memview->Center(addr & ~3);
|
|
}
|
|
|
|
event.Skip();
|
|
}
|
|
|
|
void CMemoryWindow::Update()
|
|
{
|
|
memview->Refresh();
|
|
memview->Center(PC);
|
|
}
|
|
|
|
void CMemoryWindow::NotifyMapLoaded()
|
|
{
|
|
symbols->Show(false); // hide it for faster filling
|
|
symbols->Clear();
|
|
#if 0
|
|
#ifdef _WIN32
|
|
const FunctionDB::XFuncMap &syms = g_symbolDB.Symbols();
|
|
for (FuntionDB::XFuncMap::iterator iter = syms.begin(); iter != syms.end(); ++iter)
|
|
{
|
|
int idx = symbols->Append(iter->second.name.c_str());
|
|
symbols->SetClientData(idx, (void*)&iter->second);
|
|
}
|
|
#endif
|
|
#endif
|
|
symbols->Show(true);
|
|
Update();
|
|
}
|
|
|
|
void CMemoryWindow::OnSymbolListChange(wxCommandEvent& event)
|
|
{
|
|
int index = symbols->GetSelection();
|
|
if (index >= 0)
|
|
{
|
|
Symbol* pSymbol = static_cast<Symbol *>(symbols->GetClientData(index));
|
|
if (pSymbol != nullptr)
|
|
{
|
|
memview->Center(pSymbol->address);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CMemoryWindow::OnHostMessage(wxCommandEvent& event)
|
|
{
|
|
switch (event.GetId())
|
|
{
|
|
case IDM_NOTIFY_MAP_LOADED:
|
|
NotifyMapLoaded();
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void DumpArray(const std::string& filename, const u8* data, size_t length)
|
|
{
|
|
if (data)
|
|
{
|
|
File::IOFile f(filename, "wb");
|
|
f.WriteBytes(data, length);
|
|
}
|
|
}
|
|
|
|
// Write mram to file
|
|
void CMemoryWindow::OnDumpMemory( wxCommandEvent& event )
|
|
{
|
|
DumpArray(File::GetUserPath(F_RAMDUMP_IDX), Memory::m_pRAM, Memory::REALRAM_SIZE);
|
|
}
|
|
|
|
// Write exram (aram or mem2) to file
|
|
void CMemoryWindow::OnDumpMem2( wxCommandEvent& event )
|
|
{
|
|
if (SConfig::GetInstance().m_LocalCoreStartupParameter.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);
|
|
}
|
|
}
|
|
|
|
// Write fake vmem to file
|
|
void CMemoryWindow::OnDumpFakeVMEM( wxCommandEvent& event )
|
|
{
|
|
DumpArray(File::GetUserPath(F_FAKEVMEMDUMP_IDX), Memory::m_pFakeVMEM, Memory::FAKEVMEM_SIZE);
|
|
}
|
|
|
|
void CMemoryWindow::U8(wxCommandEvent& event)
|
|
{
|
|
chk16->SetValue(0);
|
|
chk32->SetValue(0);
|
|
memview->dataType = 0;
|
|
memview->Refresh();
|
|
}
|
|
|
|
void CMemoryWindow::U16(wxCommandEvent& event)
|
|
{
|
|
chk8->SetValue(0);
|
|
chk32->SetValue(0);
|
|
memview->dataType = 1;
|
|
memview->Refresh();
|
|
}
|
|
|
|
void CMemoryWindow::U32(wxCommandEvent& event)
|
|
{
|
|
chk16->SetValue(0);
|
|
chk8->SetValue(0);
|
|
memview->dataType = 2;
|
|
memview->Refresh();
|
|
}
|
|
|
|
void CMemoryWindow::onSearch(wxCommandEvent& event)
|
|
{
|
|
u8* TheRAM = nullptr;
|
|
u32 szRAM = 0;
|
|
switch (memview->GetMemoryType())
|
|
{
|
|
case 0:
|
|
default:
|
|
if (Memory::m_pRAM)
|
|
{
|
|
TheRAM = Memory::m_pRAM;
|
|
szRAM = Memory::REALRAM_SIZE;
|
|
}
|
|
break;
|
|
case 1:
|
|
{
|
|
u8* aram = DSP::GetARAMPtr();
|
|
if (aram)
|
|
{
|
|
TheRAM = aram;
|
|
szRAM = DSP::ARAM_SIZE;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
//Now we have memory to look in
|
|
//Are we looking for ASCII string, or hex?
|
|
//memview->cu
|
|
wxString rawData = valbox->GetValue();
|
|
std::vector<u8> Dest; //May need a better name
|
|
u32 size = 0;
|
|
int pad = rawData.size()%2; //If it's uneven
|
|
unsigned int i = 0;
|
|
long count = 0;
|
|
char copy[3] = {0};
|
|
long newsize = 0;
|
|
unsigned char *tmp2 = nullptr;
|
|
char* tmpstr = nullptr;
|
|
|
|
if (chkHex->GetValue())
|
|
{
|
|
//We are looking for hex
|
|
//If it's uneven
|
|
size = (rawData.size()/2) + pad;
|
|
Dest.resize(size+32);
|
|
newsize = rawData.size();
|
|
|
|
if (pad)
|
|
{
|
|
tmpstr = new char[newsize + 2];
|
|
memset(tmpstr, 0, newsize + 2);
|
|
tmpstr[0] = '0';
|
|
}
|
|
else
|
|
{
|
|
tmpstr = new char[newsize + 1];
|
|
memset(tmpstr, 0, newsize + 1);
|
|
}
|
|
strcat(tmpstr, WxStrToStr(rawData).c_str());
|
|
tmp2 = &Dest.front();
|
|
count = 0;
|
|
for (i = 0; i < strlen(tmpstr); i++)
|
|
{
|
|
copy[0] = tmpstr[i];
|
|
copy[1] = tmpstr[i+1];
|
|
copy[2] = 0;
|
|
int tmpint;
|
|
sscanf(copy, "%02x", &tmpint);
|
|
tmp2[count++] = tmpint;
|
|
// Dest[count] should now be the hex of what the two chars were!
|
|
// Also should add a check to make sure it's A-F only
|
|
//sscanf(copy, "%02x", &tmp2[count++]);
|
|
i += 1;
|
|
}
|
|
delete[] tmpstr;
|
|
}
|
|
else
|
|
{
|
|
//Looking for an ascii string
|
|
size = rawData.size();
|
|
Dest.resize(size+1);
|
|
tmpstr = new char[size+1];
|
|
|
|
tmp2 = &Dest.front();
|
|
sprintf(tmpstr, "%s", WxStrToStr(rawData).c_str());
|
|
|
|
for (i = 0; i < size; i++)
|
|
tmp2[i] = tmpstr[i];
|
|
|
|
delete[] tmpstr;
|
|
}
|
|
|
|
if (size)
|
|
{
|
|
unsigned char* pnt = &Dest.front();
|
|
unsigned int k = 0;
|
|
//grab
|
|
wxString txt = addrbox->GetValue();
|
|
u32 addr = 0;
|
|
if (txt.size())
|
|
{
|
|
sscanf(WxStrToStr(txt).c_str(), "%08x", &addr);
|
|
}
|
|
i = addr+4;
|
|
for ( ; i < szRAM; ++i)
|
|
{
|
|
for (k = 0; k < size; ++k)
|
|
{
|
|
if (i + k > szRAM) break;
|
|
if (k > size) break;
|
|
if (pnt[k] != TheRAM[i+k])
|
|
{
|
|
k = 0;
|
|
break;
|
|
}
|
|
}
|
|
if (k == size)
|
|
{
|
|
//Match was found
|
|
wxMessageBox(_("A match was found. Placing viewer at the offset."));
|
|
addrbox->SetValue(wxString::Format("%08x", i));
|
|
//memview->curAddress = i;
|
|
//memview->Refresh();
|
|
OnAddrBoxChange(event);
|
|
return;
|
|
}
|
|
}
|
|
wxMessageBox(_("No match was found."));
|
|
}
|
|
}
|
|
|
|
void CMemoryWindow::onAscii(wxCommandEvent& event)
|
|
{
|
|
chkHex->SetValue(0);
|
|
}
|
|
|
|
void CMemoryWindow::onHex(wxCommandEvent& event)
|
|
{
|
|
chkAscii->SetValue(0);
|
|
}
|