// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. // Copyright (C) 1999-2003 Forgotten // Copyright (C) 2004 Forgotten and the VBA development team // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2, or(at your option) // any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // MemoryViewerDlg.cpp : implementation file // #include "stdafx.h" #include "vba.h" #include "FileDlg.h" #include "MemoryViewerAddressSize.h" #include "MemoryViewerDlg.h" #include "Reg.h" #include "WinResUtil.h" #include "../System.h" #include "../GBA.h" #include "../Globals.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif extern int emulating; #define CPUReadByteQuick(addr) \ ::map[(addr)>>24].address[(addr) & ::map[(addr)>>24].mask] #define CPUWriteByteQuick(addr, b) \ ::map[(addr)>>24].address[(addr) & ::map[(addr)>>24].mask] = (b) #define CPUReadHalfWordQuick(addr) \ *((u16 *)&::map[(addr)>>24].address[(addr) & ::map[(addr)>>24].mask]) #define CPUWriteHalfWordQuick(addr, b) \ *((u16 *)&::map[(addr)>>24].address[(addr) & ::map[(addr)>>24].mask]) = (b) #define CPUReadMemoryQuick(addr) \ *((u32 *)&::map[(addr)>>24].address[(addr) & ::map[(addr)>>24].mask]) #define CPUWriteMemoryQuick(addr, b) \ *((u32 *)&::map[(addr)>>24].address[(addr) & ::map[(addr)>>24].mask]) = (b) ///////////////////////////////////////////////////////////////////////////// // GBAMemoryViewer control GBAMemoryViewer::GBAMemoryViewer() : MemoryViewer() { setAddressSize(0); } void GBAMemoryViewer::readData(u32 address, int len, u8 *data) { if(emulating && rom != NULL) { for(int i = 0; i < len; i++) { *data++ = CPUReadByteQuick(address); address++; } } else { for(int i = 0; i < len; i++) { *data++ = 0; address++; } } } void GBAMemoryViewer::editData(u32 address, int size, int mask, u32 value) { u32 oldValue; switch(size) { case 8: oldValue = (CPUReadByteQuick(address) & mask) | value; CPUWriteByteQuick(address, oldValue); break; case 16: oldValue = (CPUReadHalfWordQuick(address) & mask) | value; CPUWriteHalfWordQuick(address, oldValue); break; case 32: oldValue = (CPUReadMemoryQuick(address) & mask) | value; CPUWriteMemoryQuick(address, oldValue); break; } } ///////////////////////////////////////////////////////////////////////////// // MemoryViewerDlg dialog MemoryViewerDlg::MemoryViewerDlg(CWnd* pParent /*=NULL*/) : ResizeDlg(MemoryViewerDlg::IDD, pParent) { //{{AFX_DATA_INIT(MemoryViewerDlg) m_size = -1; //}}AFX_DATA_INIT autoUpdate = false; } void MemoryViewerDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(MemoryViewerDlg) DDX_Control(pDX, IDC_CURRENT_ADDRESS, m_current); DDX_Control(pDX, IDC_ADDRESS, m_address); DDX_Control(pDX, IDC_ADDRESSES, m_addresses); DDX_Radio(pDX, IDC_8_BIT, m_size); //}}AFX_DATA_MAP DDX_Control(pDX, IDC_VIEWER, m_viewer); } BEGIN_MESSAGE_MAP(MemoryViewerDlg, CDialog) //{{AFX_MSG_MAP(MemoryViewerDlg) ON_BN_CLICKED(IDC_CLOSE, OnClose) ON_BN_CLICKED(IDC_REFRESH, OnRefresh) ON_BN_CLICKED(IDC_8_BIT, On8Bit) ON_BN_CLICKED(IDC_16_BIT, On16Bit) ON_BN_CLICKED(IDC_32_BIT, On32Bit) ON_BN_CLICKED(IDC_AUTO_UPDATE, OnAutoUpdate) ON_BN_CLICKED(IDC_GO, OnGo) ON_CBN_SELCHANGE(IDC_ADDRESSES, OnSelchangeAddresses) ON_BN_CLICKED(IDC_SAVE, OnSave) ON_BN_CLICKED(IDC_LOAD, OnLoad) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // MemoryViewerDlg message handlers BOOL MemoryViewerDlg::OnInitDialog() { CDialog::OnInitDialog(); DIALOG_SIZER_START( sz ) DIALOG_SIZER_ENTRY( IDC_VIEWER, DS_SizeX | DS_SizeY ) DIALOG_SIZER_ENTRY( IDC_REFRESH, DS_MoveY) DIALOG_SIZER_ENTRY( IDC_CLOSE, DS_MoveY) DIALOG_SIZER_ENTRY( IDC_LOAD, DS_MoveY) DIALOG_SIZER_ENTRY( IDC_SAVE, DS_MoveY) DIALOG_SIZER_ENTRY( IDC_AUTO_UPDATE, DS_MoveY) DIALOG_SIZER_ENTRY( IDC_CURRENT_ADDRESS_LABEL, DS_MoveY | DS_MoveX) DIALOG_SIZER_ENTRY( IDC_CURRENT_ADDRESS, DS_MoveY | DS_MoveX) DIALOG_SIZER_END() SetData(sz, TRUE, HKEY_CURRENT_USER, "Software\\Emulators\\VisualBoyAdvance\\Viewer\\MemoryView", NULL); m_viewer.setDialog(this); m_viewer.ShowScrollBar(SB_VERT, TRUE); m_viewer.EnableScrollBar(SB_VERT, ESB_ENABLE_BOTH); LPCTSTR s[] = { "0x00000000 - BIOS", "0x02000000 - WRAM", "0x03000000 - IRAM", "0x04000000 - I/O", "0x05000000 - PALETTE", "0x06000000 - VRAM", "0x07000000 - OAM", "0x08000000 - ROM" }; for(int i = 0; i < 8; i++) m_addresses.AddString(s[i]); m_addresses.SetCurSel(0); RECT cbSize; int Height; m_addresses.GetClientRect(&cbSize); Height = m_addresses.GetItemHeight(-1); Height += m_addresses.GetItemHeight(0) * (9); // Note: The use of SM_CYEDGE assumes that we're using Windows '95 // Now add on the height of the border of the edit box Height += GetSystemMetrics(SM_CYEDGE) * 2; // top & bottom edges // The height of the border of the drop-down box Height += GetSystemMetrics(SM_CYEDGE) * 2; // top & bottom edges // now set the size of the window m_addresses.SetWindowPos(NULL, 0, 0, cbSize.right, Height, SWP_NOMOVE | SWP_NOZORDER); m_address.LimitText(8); m_size = regQueryDwordValue("memViewerDataSize", 0); if(m_size < 0 || m_size > 2) m_size = 0; m_viewer.setSize(m_size); UpdateData(FALSE); m_current.SetFont(CFont::FromHandle((HFONT)GetStockObject(SYSTEM_FIXED_FONT))); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } void MemoryViewerDlg::OnClose() { theApp.winRemoveUpdateListener(this); DestroyWindow(); } void MemoryViewerDlg::OnRefresh() { m_viewer.Invalidate(); } void MemoryViewerDlg::update() { OnRefresh(); } void MemoryViewerDlg::On8Bit() { m_viewer.setSize(0); regSetDwordValue("memViewerDataSize", 0); } void MemoryViewerDlg::On16Bit() { m_viewer.setSize(1); regSetDwordValue("memViewerDataSize", 1); } void MemoryViewerDlg::On32Bit() { m_viewer.setSize(2); regSetDwordValue("memViewerDataSize", 2); } void MemoryViewerDlg::OnAutoUpdate() { autoUpdate = !autoUpdate; if(autoUpdate) { theApp.winAddUpdateListener(this); } else { theApp.winRemoveUpdateListener(this); } } void MemoryViewerDlg::OnGo() { CString buffer; m_address.GetWindowText(buffer); u32 address; sscanf(buffer, "%x", &address); if(m_viewer.getSize() == 1) address &= ~1; else if(m_viewer.getSize() == 2) address &= ~3; m_viewer.setAddress(address); } void MemoryViewerDlg::OnSelchangeAddresses() { int cur = m_addresses.GetCurSel(); switch(cur) { case 0: m_viewer.setAddress(0); break; case 1: m_viewer.setAddress(0x2000000); break; case 2: m_viewer.setAddress(0x3000000); break; case 3: m_viewer.setAddress(0x4000000); break; case 4: m_viewer.setAddress(0x5000000); break; case 5: m_viewer.setAddress(0x6000000); break; case 6: m_viewer.setAddress(0x7000000); break; case 7: m_viewer.setAddress(0x8000000); break; } } void MemoryViewerDlg::setCurrentAddress(u32 address) { CString buffer; buffer.Format("0x%08X", address); m_current.SetWindowText(buffer); } void MemoryViewerDlg::OnSave() { MemoryViewerAddressSize dlg; CString buffer; dlg.setAddress(m_viewer.getCurrentAddress()); LPCTSTR exts[] = { ".dmp" }; if(dlg.DoModal() == IDOK) { CString filter = theApp.winLoadFilter(IDS_FILTER_DUMP); CString title = winResLoadString(IDS_SELECT_DUMP_FILE); FileDlg file(this, buffer, filter, 0, "DMP", exts, "", title, true); if(file.DoModal() == IDOK) { buffer = file.GetPathName(); FILE *f = fopen(buffer, "wb"); if(f == NULL) { systemMessage(IDS_ERROR_CREATING_FILE, buffer); return; } int size = dlg.getSize(); u32 addr = dlg.getAddress(); for(int i = 0; i < size; i++) { fputc(CPUReadByteQuick(addr), f); addr++; } fclose(f); } } } void MemoryViewerDlg::OnLoad() { CString buffer; LPCTSTR exts[] = { ".dmp" }; CString filter = theApp.winLoadFilter(IDS_FILTER_DUMP); CString title = winResLoadString(IDS_SELECT_DUMP_FILE); FileDlg file(this, buffer, filter, 0, "DMP", exts, "", title, false); if(file.DoModal() == IDOK) { buffer = file.GetPathName(); FILE *f = fopen(buffer, "rb"); if(f == NULL) { systemMessage(IDS_CANNOT_OPEN_FILE, "Cannot open file %s", buffer); return; } MemoryViewerAddressSize dlg; fseek(f, 0, SEEK_END); int size = ftell(f); fseek(f, 0, SEEK_SET); dlg.setAddress(m_viewer.getCurrentAddress()); dlg.setSize(size); if(dlg.DoModal() == IDOK) { int size = dlg.getSize(); u32 addr = dlg.getAddress(); for(int i = 0; i < size; i++) { int c = fgetc(f); if(c == -1) break; CPUWriteByteQuick(addr, c); addr++; } OnRefresh(); } fclose(f); } } void MemoryViewerDlg::PostNcDestroy() { delete this; }