1 // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
2 // Copyright (C) 1999-2003 Forgotten
3 // Copyright (C) 2004 Forgotten and the VBA development team
4 
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2, or(at your option)
8 // any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 
19 // GBMemoryViewerDlg.cpp : implementation file
20 //
21 
22 #include "stdafx.h"
23 #include "vba.h"
24 #include "FileDlg.h"
25 #include "GBMemoryViewerDlg.h"
26 #include "MemoryViewerAddressSize.h"
27 #include "Reg.h"
28 #include "WinResUtil.h"
29 
30 #include "../System.h"
31 #include "../gb/gbGlobals.h"
32 
33 #ifdef _DEBUG
34 #define new DEBUG_NEW
35 #undef THIS_FILE
36 static char THIS_FILE[] = __FILE__;
37 #endif
38 
GBMemoryViewer()39 GBMemoryViewer::GBMemoryViewer()
40   : MemoryViewer()
41 {
42   setAddressSize(1);
43 }
44 
readData(u32 address,int len,u8 * data)45 void GBMemoryViewer::readData(u32 address, int len, u8 *data)
46 {
47   u16 addr = address & 0xffff;
48   if(emulating && gbRom != NULL) {
49     for(int i = 0; i < len; i++) {
50       *data++ = gbMemoryMap[addr >> 12][addr & 0xfff];
51       addr++;
52     }
53   } else {
54     for(int i = 0; i < len; i++) {
55       *data++ = 0;
56       addr++;
57     }
58   }
59 }
60 
61 #define GB_READBYTE_QUICK(addr) \
62   gbMemoryMap[(addr) >> 12][(addr) & 0xfff]
63 
64 #define GB_WRITEBYTE_QUICK(addr,v) \
65   gbMemoryMap[(addr) >> 12][(addr) & 0xfff] = (v)
66 
editData(u32 address,int size,int mask,u32 value)67 void GBMemoryViewer::editData(u32 address, int size, int mask, u32 value)
68 {
69   u32 oldValue;
70   u16 addr = (u16)address & 0xffff;
71   switch(size) {
72   case 8:
73     oldValue = GB_READBYTE_QUICK(addr);
74     oldValue &= mask;
75     oldValue |= (u8)value;
76     GB_WRITEBYTE_QUICK(addr, oldValue);
77     break;
78   case 16:
79     oldValue = GB_READBYTE_QUICK(addr) |
80       (GB_READBYTE_QUICK(addr + 1) << 8);
81     oldValue &= mask;
82     oldValue |= (u16)value;
83     GB_WRITEBYTE_QUICK(addr, (oldValue & 255));
84     GB_WRITEBYTE_QUICK(addr+1, (oldValue >> 8));
85     break;
86   case 32:
87     oldValue = GB_READBYTE_QUICK(addr) |
88       (GB_READBYTE_QUICK(addr + 1) << 8) |
89       (GB_READBYTE_QUICK(addr + 2) << 16) |
90       (GB_READBYTE_QUICK(addr + 3) << 24);
91     oldValue &= mask;
92     oldValue |= (u32)value;
93     GB_WRITEBYTE_QUICK(addr, (oldValue & 255));
94     GB_WRITEBYTE_QUICK(addr+1, (oldValue >> 8));
95     GB_WRITEBYTE_QUICK(addr+2, (oldValue >> 16));
96     GB_WRITEBYTE_QUICK(addr+3, (oldValue >> 24));
97     break;
98   }
99 }
100 
101 /////////////////////////////////////////////////////////////////////////////
102 // GBMemoryViewerDlg dialog
103 
104 
GBMemoryViewerDlg(CWnd * pParent)105 GBMemoryViewerDlg::GBMemoryViewerDlg(CWnd* pParent /*=NULL*/)
106   : ResizeDlg(GBMemoryViewerDlg::IDD, pParent)
107 {
108   //{{AFX_DATA_INIT(GBMemoryViewerDlg)
109   m_size = -1;
110   //}}AFX_DATA_INIT
111   autoUpdate = false;
112 }
113 
114 
DoDataExchange(CDataExchange * pDX)115 void GBMemoryViewerDlg::DoDataExchange(CDataExchange* pDX)
116 {
117   CDialog::DoDataExchange(pDX);
118   //{{AFX_DATA_MAP(GBMemoryViewerDlg)
119   DDX_Control(pDX, IDC_CURRENT_ADDRESS, m_current);
120   DDX_Control(pDX, IDC_ADDRESS, m_address);
121   DDX_Control(pDX, IDC_ADDRESSES, m_addresses);
122   DDX_Radio(pDX, IDC_8_BIT, m_size);
123   //}}AFX_DATA_MAP
124   DDX_Control(pDX, IDC_VIEWER, m_viewer);
125 }
126 
127 
BEGIN_MESSAGE_MAP(GBMemoryViewerDlg,CDialog)128 BEGIN_MESSAGE_MAP(GBMemoryViewerDlg, CDialog)
129   //{{AFX_MSG_MAP(GBMemoryViewerDlg)
130   ON_BN_CLICKED(IDC_CLOSE, OnClose)
131   ON_BN_CLICKED(IDC_REFRESH, OnRefresh)
132   ON_BN_CLICKED(IDC_8_BIT, On8Bit)
133   ON_BN_CLICKED(IDC_16_BIT, On16Bit)
134   ON_BN_CLICKED(IDC_32_BIT, On32Bit)
135   ON_BN_CLICKED(IDC_AUTO_UPDATE, OnAutoUpdate)
136   ON_BN_CLICKED(IDC_GO, OnGo)
137   ON_CBN_SELCHANGE(IDC_ADDRESSES, OnSelchangeAddresses)
138   ON_BN_CLICKED(IDC_SAVE, OnSave)
139   ON_BN_CLICKED(IDC_LOAD, OnLoad)
140   //}}AFX_MSG_MAP
141   END_MESSAGE_MAP()
142 
143   /////////////////////////////////////////////////////////////////////////////
144 // GBMemoryViewerDlg message handlers
145 
146 BOOL GBMemoryViewerDlg::OnInitDialog()
147 {
148   CDialog::OnInitDialog();
149 
150   DIALOG_SIZER_START( sz )
151     DIALOG_SIZER_ENTRY( IDC_VIEWER, DS_SizeX | DS_SizeY )
152     DIALOG_SIZER_ENTRY( IDC_REFRESH, DS_MoveY)
153     DIALOG_SIZER_ENTRY( IDC_CLOSE, DS_MoveY)
154     DIALOG_SIZER_ENTRY( IDC_LOAD, DS_MoveY)
155     DIALOG_SIZER_ENTRY( IDC_SAVE, DS_MoveY)
156     DIALOG_SIZER_ENTRY( IDC_AUTO_UPDATE, DS_MoveY)
157     DIALOG_SIZER_ENTRY( IDC_CURRENT_ADDRESS_LABEL, DS_MoveY | DS_MoveX)
158     DIALOG_SIZER_ENTRY( IDC_CURRENT_ADDRESS, DS_MoveY | DS_MoveX)
159     DIALOG_SIZER_END()
160     SetData(sz,
161             TRUE,
162             HKEY_CURRENT_USER,
163             "Software\\Emulators\\VisualBoyAdvance\\Viewer\\GBMemoryView",
164             NULL);
165 
166   m_viewer.setDialog(this);
167   m_viewer.ShowScrollBar(SB_VERT, TRUE);
168   m_viewer.EnableScrollBar(SB_VERT, ESB_ENABLE_BOTH);
169 
170   LPCTSTR s[] = {
171     "0x0000 - ROM",
172     "0x4000 - ROM",
173     "0x8000 - VRAM",
174     "0xA000 - SRAM",
175     "0xC000 - RAM",
176     "0xD000 - WRAM",
177     "0xFF00 - I/O",
178     "0xFF80 - RAM"
179   };
180 
181   for(int i = 0; i < 8; i++)
182     m_addresses.AddString(s[i]);
183 
184   m_addresses.SetCurSel(0);
185 
186   RECT cbSize;
187   int Height;
188 
189   m_addresses.GetClientRect(&cbSize);
190   Height = m_addresses.GetItemHeight(-1);
191   Height += m_addresses.GetItemHeight(0) * (9);
192 
193   // Note: The use of SM_CYEDGE assumes that we're using Windows '95
194   // Now add on the height of the border of the edit box
195   Height += GetSystemMetrics(SM_CYEDGE) * 2;  // top & bottom edges
196 
197   // The height of the border of the drop-down box
198   Height += GetSystemMetrics(SM_CYEDGE) * 2;  // top & bottom edges
199 
200   // now set the size of the window
201   m_addresses.SetWindowPos(NULL,
202                            0, 0,
203                            cbSize.right, Height,
204                            SWP_NOMOVE | SWP_NOZORDER);
205 
206   m_address.LimitText(8);
207 
208   m_size = regQueryDwordValue("memViewerDataSize", 0);
209   if(m_size < 0 || m_size > 2)
210     m_size = 0;
211   m_viewer.setSize(m_size);
212   UpdateData(FALSE);
213 
214   m_current.SetFont(CFont::FromHandle((HFONT)GetStockObject(SYSTEM_FIXED_FONT)));
215 
216   return TRUE;  // return TRUE unless you set the focus to a control
217                 // EXCEPTION: OCX Property Pages should return FALSE
218 }
219 
OnClose()220 void GBMemoryViewerDlg::OnClose()
221 {
222   theApp.winRemoveUpdateListener(this);
223 
224   DestroyWindow();
225 }
226 
OnRefresh()227 void GBMemoryViewerDlg::OnRefresh()
228 {
229   m_viewer.Invalidate();
230 }
231 
update()232 void GBMemoryViewerDlg::update()
233 {
234   OnRefresh();
235 }
236 
On8Bit()237 void GBMemoryViewerDlg::On8Bit()
238 {
239   m_viewer.setSize(0);
240   regSetDwordValue("memViewerDataSize", 0);
241 }
242 
On16Bit()243 void GBMemoryViewerDlg::On16Bit()
244 {
245   m_viewer.setSize(1);
246   regSetDwordValue("memViewerDataSize", 1);
247 }
248 
On32Bit()249 void GBMemoryViewerDlg::On32Bit()
250 {
251   m_viewer.setSize(2);
252   regSetDwordValue("memViewerDataSize", 2);
253 }
254 
OnAutoUpdate()255 void GBMemoryViewerDlg::OnAutoUpdate()
256 {
257   autoUpdate = !autoUpdate;
258   if(autoUpdate) {
259     theApp.winAddUpdateListener(this);
260   } else {
261     theApp.winRemoveUpdateListener(this);
262   }
263 }
264 
OnGo()265 void GBMemoryViewerDlg::OnGo()
266 {
267   CString buffer;
268 
269   m_address.GetWindowText(buffer);
270 
271   u32 address;
272   sscanf(buffer, "%x", &address);
273   if(m_viewer.getSize() == 1)
274     address &= ~1;
275   else if(m_viewer.getSize() == 2)
276     address &= ~3;
277   m_viewer.setAddress(address);
278 }
279 
OnSelchangeAddresses()280 void GBMemoryViewerDlg::OnSelchangeAddresses()
281 {
282   int cur = m_addresses.GetCurSel();
283 
284   switch(cur) {
285   case 0:
286     m_viewer.setAddress(0x0000);
287     break;
288   case 1:
289     m_viewer.setAddress(0x4000);
290     break;
291   case 2:
292     m_viewer.setAddress(0x8000);
293     break;
294   case 3:
295     m_viewer.setAddress(0xa000);
296     break;
297   case 4:
298     m_viewer.setAddress(0xc000);
299     break;
300   case 5:
301     m_viewer.setAddress(0xd000);
302     break;
303   case 6:
304     m_viewer.setAddress(0xff00);
305     break;
306   case 7:
307     m_viewer.setAddress(0xff80);
308     break;
309   }
310 }
311 
setCurrentAddress(u32 address)312 void GBMemoryViewerDlg::setCurrentAddress(u32 address)
313 {
314   CString buffer;
315 
316   buffer.Format("0x%08X", address);
317   m_current.SetWindowText(buffer);
318 }
319 
OnSave()320 void GBMemoryViewerDlg::OnSave()
321 {
322   MemoryViewerAddressSize dlg;
323   CString buffer;
324 
325   dlg.setAddress(m_viewer.getCurrentAddress());
326 
327   LPCTSTR exts[] = { ".dmp" };
328 
329   CString filter = theApp.winLoadFilter(IDS_FILTER_DUMP);
330   CString title = winResLoadString(IDS_SELECT_DUMP_FILE);
331 
332   if(dlg.DoModal() == IDOK) {
333     FileDlg file(this,
334                  buffer,
335                  filter,
336                  0,
337                  "DMP",
338                  exts,
339                  "",
340                  title,
341                  true);
342     if(file.DoModal() == IDOK) {
343       buffer = file.GetPathName();
344       FILE *f = fopen(buffer, "wb");
345 
346       if(f == NULL) {
347         systemMessage(IDS_ERROR_CREATING_FILE, buffer);
348         return;
349       }
350 
351       int size = dlg.getSize();
352       u16 addr = dlg.getAddress() & 0xffff;
353 
354       for(int i = 0; i < size; i++) {
355         fputc(gbMemoryMap[addr >> 12][addr & 0xfff], f);
356         addr++;
357       }
358 
359       fclose(f);
360     }
361   }
362 }
363 
OnLoad()364 void GBMemoryViewerDlg::OnLoad()
365 {
366   CString buffer;
367   LPCTSTR exts[] = { ".dmp" };
368   CString filter = theApp.winLoadFilter(IDS_FILTER_DUMP);
369   CString title = winResLoadString(IDS_SELECT_DUMP_FILE);
370 
371   FileDlg file(this,
372                buffer,
373                filter,
374                0,
375                "DMP",
376                exts,
377                "",
378                title,
379                false);
380 
381   if(file.DoModal() == IDOK) {
382     buffer = file.GetPathName();
383     FILE *f = fopen(buffer, "rb");
384     if(f == NULL) {
385       systemMessage(IDS_CANNOT_OPEN_FILE,
386                     "Cannot open file %s",
387                     buffer);
388       return;
389     }
390 
391     MemoryViewerAddressSize dlg;
392 
393     fseek(f, 0, SEEK_END);
394     int size = ftell(f);
395 
396     fseek(f, 0, SEEK_SET);
397 
398     dlg.setAddress(m_viewer.getCurrentAddress());
399     dlg.setSize(size);
400 
401     if(dlg.DoModal() == IDOK) {
402       int size = dlg.getSize();
403       u16 addr = dlg.getAddress() & 0xffff;
404 
405       for(int i = 0; i < size; i++) {
406         int c = fgetc(f);
407         if(c == -1)
408           break;
409         gbMemoryMap[addr >> 12][addr & 0xfff] = c;
410         addr++;
411       }
412       OnRefresh();
413     }
414     fclose(f);
415   }
416 }
417 
PostNcDestroy()418 void GBMemoryViewerDlg::PostNcDestroy()
419 {
420   delete this;
421 }
422