/**************************************************************************** * * * Project 64 - A Nintendo 64 emulator. * * http://www.pj64-emu.com/ * * Copyright (C) 2012 Project64. All rights reserved. * * * * License: * * GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html * * * ****************************************************************************/ #include "stdafx.h" #include "Debugger UI.h" CDebugMemoryView::CDebugMemoryView(CDebugger * debugger) : CDebugDialog(debugger), m_MemoryList(NULL) { if (m_MemoryList== NULL) { m_MemoryList = new CListCtrl; m_MemoryList->RegisterClass(); } } CDebugMemoryView::~CDebugMemoryView() { } LRESULT CDebugMemoryView::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { m_DataStartLoc = (DWORD)-1; m_CompareStartLoc = (DWORD)-1; memset(m_CompareData,0,sizeof(m_CompareData)); memset(m_CompareValid,0,sizeof(m_CompareValid)); HWND hScrlBar = GetDlgItem(IDC_SCRL_BAR); if (hScrlBar) { SCROLLINFO si; si.cbSize = sizeof(si); si.fMask = SIF_RANGE | SIF_POS | SIF_PAGE; si.nMin = 0; si.nMax = 0xFFFF; si.nPos = 0x8000; si.nPage = 100; ::SetScrollInfo(hScrlBar,SB_CTL,&si,TRUE); } m_MemAddr.Attach(GetDlgItem(IDC_ADDR_EDIT)); m_MemAddr.SetDisplayType(CEditNumber::DisplayHex); m_MemAddr.SetValue(0x80000000,true,true); SendDlgItemMessage( IDC_CHK_VADDR, BM_SETCHECK, BST_CHECKED,0); if (m_MemoryList== NULL) { m_MemoryList = new CListCtrl; m_MemoryList->RegisterClass(); } m_MemoryList->SubclassWindow( GetDlgItem( IDC_MEM_DETAILS ) ); m_MemoryList->ShowHeader(false); m_MemoryList->SetSortEnabled(FALSE); m_MemoryList->AddColumn( _T( "Address" ), 90 ); m_MemoryList->AddColumn( _T( "1" ), 20 ); m_MemoryList->AddColumn( _T( "2" ), 20 ); m_MemoryList->AddColumn( _T( "3" ), 20 ); m_MemoryList->AddColumn( _T( "4" ), 20 ); m_MemoryList->AddColumn( _T( "-" ), 10 ); m_MemoryList->AddColumn( _T( "5" ), 20 ); m_MemoryList->AddColumn( _T( "6" ), 20 ); m_MemoryList->AddColumn( _T( "7" ), 20 ); m_MemoryList->AddColumn( _T( "8" ), 20 ); m_MemoryList->AddColumn( _T( "-" ), 10 ); m_MemoryList->AddColumn( _T( "9" ), 20 ); m_MemoryList->AddColumn( _T( "10" ), 20 ); m_MemoryList->AddColumn( _T( "11" ), 20 ); m_MemoryList->AddColumn( _T( "12" ), 20 ); m_MemoryList->AddColumn( _T( "-" ), 10 ); m_MemoryList->AddColumn( _T( "13" ), 20 ); m_MemoryList->AddColumn( _T( "14" ), 20 ); m_MemoryList->AddColumn( _T( "15" ), 20 ); m_MemoryList->AddColumn( _T( "16" ), 35 ); m_MemoryList->AddColumn( _T( "Memory Ascii" ), 140 ); ::SetWindowLongPtr(m_MemoryList->m_hWnd, GWL_EXSTYLE, WS_EX_CLIENTEDGE); RefreshMemory(false); int height = m_MemoryList->GetTotalHeight(); RECT MemoryListRect = {0}; ::GetClientRect(GetDlgItem( IDC_MEM_DETAILS ), &MemoryListRect); if (height > MemoryListRect.bottom) { RECT MemoryListWindow = {0}; GetWindowRect(&MemoryListWindow); SetWindowPos(NULL,0,0,MemoryListWindow.right - MemoryListWindow.left,(MemoryListWindow.bottom - MemoryListWindow.top) + (height - MemoryListRect.bottom), SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOZORDER); RECT DlgItemRect = {0}; ::GetWindowRect(GetDlgItem( IDC_BORDER ), &DlgItemRect); ::SetWindowPos(GetDlgItem( IDC_BORDER ), NULL,0,0,DlgItemRect.right - DlgItemRect.left,(DlgItemRect.bottom - DlgItemRect.top) + (height - MemoryListRect.bottom), SWP_NOMOVE); ::GetWindowRect(GetDlgItem( IDC_MEM_DETAILS ), &DlgItemRect); ::SetWindowPos(GetDlgItem( IDC_MEM_DETAILS ), NULL,0,0,DlgItemRect.right - DlgItemRect.left,(DlgItemRect.bottom - DlgItemRect.top) + (height - MemoryListRect.bottom), SWP_NOMOVE); ::GetWindowRect(GetDlgItem( IDC_SCRL_BAR ), &DlgItemRect); ::SetWindowPos(GetDlgItem( IDC_SCRL_BAR ), NULL,0,0,DlgItemRect.right - DlgItemRect.left,(DlgItemRect.bottom - DlgItemRect.top) + (height - MemoryListRect.bottom), SWP_NOMOVE); } WindowCreated(); return TRUE; } LRESULT CDebugMemoryView::OnDestroy ( void ) { if (m_MemoryList) { m_MemoryList->UnsubclassWindow(); delete m_MemoryList; m_MemoryList = NULL; } return 0; } LRESULT CDebugMemoryView::OnClicked (WORD /*wNotifyCode*/, WORD wID, HWND , BOOL& /*bHandled*/) { switch(wID) { case IDC_REFRSH_MEM: RefreshMemory(true); break; case IDC_CHK_VADDR: RefreshMemory(false); break; case IDC_DUMP_MEM: m_Debugger->Debug_ShowMemoryDump(); break; case IDC_SEARCH_MEM: m_Debugger->Debug_ShowMemorySearch(); break; case IDCANCEL: EndDialog(0); break; } return FALSE; } LRESULT CDebugMemoryView::OnMemoryModified ( LPNMHDR lpNMHDR ) { CListNotify *pListNotify = reinterpret_cast( lpNMHDR ); int LineNumber = pListNotify->m_nItem; int Pos = ((LineNumber << 4) + (pListNotify->m_nSubItem - 1)); if (pListNotify->m_nSubItem >= 6 && pListNotify->m_nSubItem < 10) { Pos = ((LineNumber << 4) + (pListNotify->m_nSubItem - 2)); } if (pListNotify->m_nSubItem >= 11 && pListNotify->m_nSubItem < 15) { Pos = ((LineNumber << 4) + (pListNotify->m_nSubItem - 3)); } if (pListNotify->m_nSubItem >= 16 && pListNotify->m_nSubItem < 20) { Pos = ((LineNumber << 4) + (pListNotify->m_nSubItem - 4)); } LPCSTR strValue = m_MemoryList->GetItemText(pListNotify->m_nItem,pListNotify->m_nSubItem); int Finish = strlen(strValue); if (Finish > 8) { Finish = 8; } DWORD Value = 0; for (int i = 0; i < Finish; i++) { Value = (Value << 4); if (strValue[i] <= '9' && strValue[i] >= '0') { Value |= strValue[i] - '0'; } else if (strValue[i] <= 'f' && strValue[i] >= 'a') { Value |= strValue[i] - 'a' + 10; } else if (strValue[i] <= 'F' && strValue[i] >= 'A') { Value |= strValue[i] - 'A' + 10; } } if (m_CurrentData[Pos] == Value) { return 0; } if (m_CompareStartLoc != m_DataStartLoc || m_CompareVAddrr != m_DataVAddrr) { // copy current data for change comparison m_CompareStartLoc = m_DataStartLoc; m_CompareVAddrr = m_DataVAddrr; memcpy(m_CompareData,m_CurrentData,sizeof(m_CurrentData)); memcpy(m_CompareValid,m_DataValid,sizeof(m_CompareValid)); } m_CompareData[Pos] = m_CurrentData[Pos]; m_CurrentData[Pos] = (BYTE)Value; //sb if ( m_DataVAddrr ) { if (!g_MMU->SB_VAddr(m_DataStartLoc + Pos,(BYTE)Value)) { WriteTraceF(TraceError,__FUNCTION__ ": failed to store at %X",m_DataStartLoc + Pos); } } else { if (!g_MMU->SB_PAddr(m_DataStartLoc + Pos,(BYTE)Value)) { WriteTraceF(TraceError,__FUNCTION__ ": failed to store at %X",m_DataStartLoc + Pos); } } Insert_MemoryLineDump(LineNumber); return 0; } void CDebugMemoryView::ShowAddress(DWORD Address, bool VAddr) { if (m_hWnd == NULL) { return; } SendDlgItemMessage( IDC_CHK_VADDR, BM_SETCHECK, VAddr ? BST_CHECKED : BST_UNCHECKED,0); m_MemAddr.SetValue(Address,true,true); RefreshMemory (true); } void CDebugMemoryView::Insert_MemoryLineDump ( int LineNumber ) { if (m_MemoryList == NULL || m_MemoryList->GetColumnCount() == 0) { return; } char Output[20], Hex[60], Ascii[20], AsciiAddOn[15]; sprintf(Output,"0x%08X",m_DataStartLoc + (LineNumber << 4)); if (m_MemoryList->GetItemCount() <= LineNumber) { HFONT hFont = (HFONT)GetStockObject(ANSI_FIXED_FONT); m_MemoryList->AddItemAt( LineNumber, Output); for (int i = 0; i < m_MemoryList->GetColumnCount(); i++) { m_MemoryList->SetItemFont( LineNumber, i, hFont ); if (i == 5 || i == 10 || i == 15) { m_MemoryList->SetItemText(LineNumber,i,"-"); } } } else { if ( strcmp( Output, m_MemoryList->GetItemText(LineNumber, 0) ) != 0 ) { m_MemoryList->SetItemText(LineNumber,0,Output); } } Hex[0] = 0; Ascii[0] = 0; int CompareStartPos = m_DataStartLoc - m_CompareStartLoc; for (int i = 0, col = 1; i < 0x10; i ++, col ++) { int Pos = ((LineNumber << 4) + i); if (m_DataValid[Pos]) { int ComparePos = CompareStartPos + Pos; bool Changed = false; if (ComparePos >= 0 && ComparePos < MemoryToDisplay && m_DataVAddrr == m_CompareVAddrr && m_DataValid[ComparePos] && m_CurrentData[Pos] != m_CompareData[ComparePos]) { Changed = true; } sprintf(Hex,"%02X",m_CurrentData[Pos]); m_MemoryList->SetItemText(LineNumber,col,Hex); m_MemoryList->SetItemFormat( LineNumber,col, ITEM_FORMAT_EDIT, ITEM_FLAGS_EDIT_HEX ); m_MemoryList->SetItemMaxEditLen( LineNumber,col , 2); m_MemoryList->SetItemColours( LineNumber, col, GetSysColor( COLOR_WINDOW ), Changed ? RGB( 255, 0, 0 ) : GetSysColor( COLOR_WINDOWTEXT ) ); m_MemoryList->SetItemHighlightColours( LineNumber, col, Changed ? RGB( 255, 0, 0 ) : GetSysColor( COLOR_HIGHLIGHTTEXT ) ); if (m_CurrentData[Pos] < 30) { strcat(Ascii,"."); } else { sprintf(AsciiAddOn,"%c",m_CurrentData[Pos]); strcat(Ascii,AsciiAddOn); } } else { m_MemoryList->SetItemText(LineNumber,col,"**"); m_MemoryList->SetItemFormat( LineNumber,col, ITEM_FORMAT_NONE, ITEM_FLAGS_NONE ); m_MemoryList->SetItemColours( LineNumber, col, GetSysColor( COLOR_WINDOW ), GetSysColor( COLOR_WINDOWTEXT ) ); strcat(Ascii,"*"); } if (i != 0xF) { if ((i & 3) == 3) { col += 1; } } } if ( strcmp( Ascii, m_MemoryList->GetItemText(LineNumber, 20) ) != 0 ) { m_MemoryList->SetItemText(LineNumber,20,Ascii); } } void CDebugMemoryView::OnAddrChanged( UINT /*Code*/, int /*id*/, HWND /*ctl*/ ) { RefreshMemory(false); } void CDebugMemoryView::OnVScroll(int request, short Pos, HWND ctrl ) { if (ctrl != GetDlgItem(IDC_SCRL_BAR)) { return; } DWORD Location = m_MemAddr.GetValue(); switch (request) { case SB_LINEDOWN: m_MemAddr.SetValue(Location < 0xFFFFFFEF ? Location + 0x10 : 0xFFFFFFFF,true,true); break; case SB_LINEUP: m_MemAddr.SetValue(Location > 0x10 ? Location - 0x10 : 0,true,true); break; case SB_PAGEDOWN: m_MemAddr.SetValue(Location < 0xFFFFFEFF ? Location + 0x100 : 0xFFFFFFFF,true,true); break; case SB_PAGEUP: m_MemAddr.SetValue(Location > 0x100 ? Location - 0x100 : 0,true,true); break; case SB_THUMBPOSITION: m_MemAddr.SetValue((DWORD)Pos << 0x10,true,true); break; default: break; } } void CDebugMemoryView::RefreshMemory ( bool ResetCompare ) { if (m_MemoryList && m_MemoryList->GetHasEditItem()) { m_MemoryList->SetFocus(); } DWORD NewAddress = m_MemAddr.GetValue(); if (NewAddress != m_DataStartLoc) { HWND hScrlBar = GetDlgItem(IDC_SCRL_BAR); if (hScrlBar) { SCROLLINFO si; si.cbSize = sizeof(si); si.fMask = SIF_POS; si.nPos = NewAddress >> 0x10; ::SetScrollInfo(hScrlBar,SB_CTL,&si,TRUE); } } if (ResetCompare) { // copy current data for change comparison m_CompareStartLoc = m_DataStartLoc; m_CompareVAddrr = m_DataVAddrr; memcpy(m_CompareData,m_CurrentData,sizeof(m_CurrentData)); memcpy(m_CompareValid,m_DataValid,sizeof(m_CompareValid)); } m_DataStartLoc = m_MemAddr.GetValue(); if (m_DataStartLoc > 0xFFFFFF00) { m_DataStartLoc = 0xFFFFFF00; } int WritePos = 0; m_DataVAddrr = (SendDlgItemMessage( IDC_CHK_VADDR, BM_GETCHECK, 0,0) & BST_CHECKED) != 0; if ((m_DataStartLoc & 3) != 0) { MIPS_WORD word; bool ValidData = true; if ( m_DataVAddrr ) { if (!g_MMU->LW_VAddr(m_DataStartLoc & ~3, word.UW)) { ValidData = false; } } else { if (!g_MMU->LW_PAddr(m_DataStartLoc & ~3, word.UW)) { ValidData = false; } } int Offset = (m_DataStartLoc & 3); for (int i = 0; i < (4 - Offset); i++) { if (WritePos >= MemoryToDisplay) { break; } m_DataValid[WritePos + i] = ValidData; if (ValidData) { m_CurrentData[WritePos + i] = word.UB[3 - (i + Offset)]; } } WritePos = 4 - Offset; } for (DWORD Pos = ((m_DataStartLoc + 3) & ~3); Pos < (m_DataStartLoc + MemoryToDisplay); WritePos += 4, Pos += 4) { MIPS_WORD word; bool ValidData = true; if ( m_DataVAddrr ) { if (!g_MMU->LW_VAddr(Pos, word.UW)) { ValidData = false; } } else { if (!g_MMU->LW_PAddr(Pos, word.UW)) { ValidData = false; } } for (int i = 0; i < 4; i++) { if ((WritePos + i)>= MemoryToDisplay) { break; } m_DataValid[WritePos + i] = ValidData; if (ValidData) { m_CurrentData[WritePos + i] = word.UB[3 - i]; } } } for (int count = 0 ; count < 16;count ++ ){ Insert_MemoryLineDump ( count ); } }