/* This file is part of UKNCBTL. UKNCBTL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. UKNCBTL 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with UKNCBTL. If not, see . */ // DebugView.cpp #include "stdafx.h" #include #include #include "Main.h" #include "Views.h" #include "ToolWindow.h" #include "Emulator.h" #include "emubase/Emubase.h" ////////////////////////////////////////////////////////////////////// HWND g_hwndDebug = (HWND)INVALID_HANDLE_VALUE; // Debug View window handle WNDPROC m_wndprocDebugToolWindow = NULL; // Old window proc address of the ToolWindow HWND m_hwndDebugToolbar = (HWND)INVALID_HANDLE_VALUE; HWND m_hwndDebugProcViewer = (HWND)INVALID_HANDLE_VALUE; HWND m_hwndDebugStackViewer = (HWND)INVALID_HANDLE_VALUE; HWND m_hwndDebugPortsViewer = (HWND)INVALID_HANDLE_VALUE; HWND m_hwndDebugBreaksViewer = (HWND)INVALID_HANDLE_VALUE; HWND m_hwndDebugMemoryViewer = (HWND)INVALID_HANDLE_VALUE; BOOL m_okDebugProcessor = FALSE; // TRUE - CPU, FALSE - PPU WORD m_wDebugCpuR[11]; // Saved register values - R0..R7, PSW, CPC, CPSW WORD m_wDebugPpuR[11]; // Saved register values - R0..R7, PSW, CPC, CPSW BOOL m_okDebugCpuRChanged[11]; // Register change flags BOOL m_okDebugPpuRChanged[11]; // Register change flags WORD m_wDebugCpuPswOld; // PSW value on previous step WORD m_wDebugPpuPswOld; // PSW value on previous step WORD m_wDebugCpuR6Old; // SP value on previous step WORD m_wDebugPpuR6Old; // SP value on previous step int m_cyDebugLine = 10; // cyLine for the current font DebugCtrlHitTest m_DebugLastHitTest; // For context menu ////////////////////////////////////////////////////////////////////// void DebugView_UpdateWindowText(); BOOL DebugView_OnKeyDown(WPARAM vkey, LPARAM lParam); DebugCtrlHitTest DebugView_BaseHitTest(int x, int y); void DebugProcView_DoDraw(HDC hdc); void DebugView_DrawProcessor(HDC hdc, const CProcessor* pProc, int x, int y, WORD* arrR, BOOL* arrRChanged, WORD oldPsw); DebugCtrlHitTest DebugProcView_HitTest(int x, int y); void DebugProcView_OnRButtonDown(int mousex, int mousey); void DebugStackView_DoDraw(HDC hdc); void DebugView_DrawMemoryForRegister(HDC hdc, int reg, CProcessor* pProc, int x, int y, WORD oldValue); //DebugCtrlHitTest DebugStackView_HitTest(int x, int y); //void DebugStackView_OnRButtonDown(int mousex, int mousey); void DebugPortsView_DoDraw(HDC hdc); void DebugView_DrawPorts(HDC hdc, BOOL okProcessor, const CMemoryController* pMemCtl, CMotherboard* pBoard, int x, int y); void DebugView_DrawChannels(HDC hdc, int x, int y); void DebugBreaksView_DoDraw(HDC hdc); void DebugBreaksView_OnRButtonDown(int mousex, int mousey); void DebugMemoryView_DoDraw(HDC hdc); void DebugView_DrawCPUMemoryMap(HDC hdc, int x, int y, const CProcessor* pDebugPU); void DebugView_DrawPPUMemoryMap(HDC hdc, int x, int y, const CProcessor* pDebugPU, const CMemoryController* pMemCtl); ////////////////////////////////////////////////////////////////////// void DebugView_RegisterClasses() { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = g_hInst; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wcex.lpszMenuName = NULL; wcex.hIconSm = NULL; wcex.lpszClassName = CLASSNAME_DEBUGPROCVIEW; wcex.lpfnWndProc = DebugProcViewViewerWndProc; RegisterClassEx(&wcex); wcex.lpszClassName = CLASSNAME_DEBUGSTACKVIEW; wcex.lpfnWndProc = DebugStackViewViewerWndProc; RegisterClassEx(&wcex); wcex.lpszClassName = CLASSNAME_DEBUGPORTSVIEW; wcex.lpfnWndProc = DebugPortsViewViewerWndProc; RegisterClassEx(&wcex); wcex.lpszClassName = CLASSNAME_DEBUGBREAKSVIEW; wcex.lpfnWndProc = DebugBreaksViewViewerWndProc; RegisterClassEx(&wcex); wcex.lpszClassName = CLASSNAME_DEBUGMEMORYVIEW; wcex.lpfnWndProc = DebugMemoryViewViewerWndProc; RegisterClassEx(&wcex); } void DebugView_Init() { memset(m_wDebugCpuR, 255, sizeof(m_wDebugCpuR)); memset(m_okDebugCpuRChanged, 1, sizeof(m_okDebugCpuRChanged)); memset(m_wDebugPpuR, 255, sizeof(m_wDebugPpuR)); memset(m_okDebugPpuRChanged, 1, sizeof(m_okDebugPpuRChanged)); m_wDebugCpuPswOld = m_wDebugPpuPswOld = 0; m_wDebugCpuR6Old = m_wDebugPpuR6Old = 0; m_okDebugProcessor = Settings_GetDebugCpuPpu(); } void DebugView_Create(HWND hwndParent, int x, int y, int width, int height) { ASSERT(hwndParent != NULL); g_hwndDebug = CreateWindow( CLASSNAME_TOOLWINDOW, NULL, WS_CHILD | WS_VISIBLE, x, y, width, height, hwndParent, NULL, g_hInst, NULL); DebugView_UpdateWindowText(); // ToolWindow subclassing m_wndprocDebugToolWindow = (WNDPROC)LongToPtr( SetWindowLongPtr( g_hwndDebug, GWLP_WNDPROC, PtrToLong(DebugViewWndProc)) ); RECT rcClient; GetClientRect(g_hwndDebug, &rcClient); m_hwndDebugProcViewer = CreateWindowEx( 0, CLASSNAME_DEBUGPROCVIEW, NULL, WS_CHILD | WS_VISIBLE, 0, 0, rcClient.right, rcClient.bottom, g_hwndDebug, NULL, g_hInst, NULL); m_hwndDebugStackViewer = CreateWindowEx( 0, CLASSNAME_DEBUGSTACKVIEW, NULL, WS_CHILD | WS_VISIBLE, 0, 0, rcClient.right, rcClient.bottom, g_hwndDebug, NULL, g_hInst, NULL); m_hwndDebugPortsViewer = CreateWindowEx( 0, CLASSNAME_DEBUGPORTSVIEW, NULL, WS_CHILD | WS_VISIBLE, 0, 0, rcClient.right, rcClient.bottom, g_hwndDebug, NULL, g_hInst, NULL); m_hwndDebugBreaksViewer = CreateWindowEx( 0, CLASSNAME_DEBUGBREAKSVIEW, NULL, WS_CHILD | WS_VISIBLE, 0, 0, rcClient.right, rcClient.bottom, g_hwndDebug, NULL, g_hInst, NULL); m_hwndDebugMemoryViewer = CreateWindowEx( 0, CLASSNAME_DEBUGMEMORYVIEW, NULL, WS_CHILD | WS_VISIBLE, 0, 0, rcClient.right, rcClient.bottom, g_hwndDebug, NULL, g_hInst, NULL); m_hwndDebugToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | TBSTYLE_TRANSPARENT | TBSTYLE_TOOLTIPS | CCS_NOPARENTALIGN | CCS_NODIVIDER | CCS_VERT, 4, 4, 32, rcClient.bottom, m_hwndDebugProcViewer, (HMENU)102, g_hInst, NULL); TBADDBITMAP addbitmap; addbitmap.hInst = g_hInst; addbitmap.nID = IDB_TOOLBAR; SendMessage(m_hwndDebugToolbar, TB_ADDBITMAP, 2, (LPARAM)&addbitmap); SendMessage(m_hwndDebugToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0); SendMessage(m_hwndDebugToolbar, TB_SETBUTTONSIZE, 0, (LPARAM) MAKELONG (26, 26)); TBBUTTON buttons[6]; ZeroMemory(buttons, sizeof(buttons)); for (int i = 0; i < sizeof(buttons) / sizeof(TBBUTTON); i++) { buttons[i].fsState = TBSTATE_ENABLED | TBSTATE_WRAP; buttons[i].fsStyle = BTNS_BUTTON; buttons[i].iString = -1; } buttons[0].idCommand = ID_VIEW_DEBUG; buttons[0].iBitmap = ToolbarImageDebugger; buttons[0].fsState = TBSTATE_ENABLED | TBSTATE_WRAP | TBSTATE_CHECKED; buttons[1].idCommand = ID_DEBUG_CPUPPU; buttons[1].iBitmap = ToolbarImageCpuPpu; buttons[2].idCommand = ID_DEBUG_SPRITES; buttons[2].iBitmap = ToolbarImageSpriteViewer; buttons[3].fsStyle = BTNS_SEP; buttons[4].idCommand = ID_DEBUG_STEPINTO; buttons[4].iBitmap = ToolbarImageStepInto; buttons[5].idCommand = ID_DEBUG_STEPOVER; buttons[5].iBitmap = ToolbarImageStepOver; SendMessage(m_hwndDebugToolbar, TB_ADDBUTTONS, (WPARAM) sizeof(buttons) / sizeof(TBBUTTON), (LPARAM)&buttons); } void DebugView_Redraw() { RedrawWindow(g_hwndDebug, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN); } // Adjust position of client windows void DebugView_AdjustWindowLayout() { RECT rc; GetClientRect(g_hwndDebug, &rc); // Get cxChar, cyLine HDC hdc = ::GetDC(g_hwndDebug); HFONT hFont = CreateMonospacedFont(); HGDIOBJ hOldFont = SelectObject(hdc, hFont); int cxChar, cyLine; GetFontWidthAndHeight(hdc, &cxChar, &cyLine); SelectObject(hdc, hOldFont); VERIFY(::DeleteObject(hFont)); ::ReleaseDC(g_hwndDebug, hdc); m_cyDebugLine = cyLine; int cxDebug = 32 + 4 + cxChar * 33; int cxStack = cxChar * 17 + cxChar / 2; int cxPorts = cxChar * 15; int cxBreaks = cxChar * 9; int cxMemory = cxChar * 26; int xDebug = 0; if (m_hwndDebugProcViewer != (HWND)INVALID_HANDLE_VALUE) SetWindowPos(m_hwndDebugProcViewer, NULL, xDebug, 0, cxDebug, rc.bottom, SWP_NOZORDER); int xStack = xDebug + cxDebug + 4; if (m_hwndDebugStackViewer != (HWND)INVALID_HANDLE_VALUE) SetWindowPos(m_hwndDebugStackViewer, NULL, xStack, 0, cxStack, rc.bottom, SWP_NOZORDER); int xPorts = xStack + cxStack + 4; if (m_hwndDebugPortsViewer != (HWND)INVALID_HANDLE_VALUE) SetWindowPos(m_hwndDebugPortsViewer, NULL, xPorts, 0, cxPorts, rc.bottom, SWP_NOZORDER); int xBreaks = xPorts + cxPorts + 4; if (m_hwndDebugBreaksViewer != (HWND)INVALID_HANDLE_VALUE) SetWindowPos(m_hwndDebugBreaksViewer, NULL, xBreaks, 0, cxBreaks, rc.bottom, SWP_NOZORDER); int xMemory = xBreaks + cxBreaks + 4; if (m_hwndDebugMemoryViewer != (HWND)INVALID_HANDLE_VALUE) SetWindowPos(m_hwndDebugMemoryViewer, NULL, xMemory, 0, cxMemory, rc.bottom, SWP_NOZORDER); } LRESULT CALLBACK DebugViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); LRESULT lResult; switch (message) { case WM_DESTROY: g_hwndDebug = (HWND)INVALID_HANDLE_VALUE; // We are closed! Bye-bye!.. return CallWindowProc(m_wndprocDebugToolWindow, hWnd, message, wParam, lParam); case WM_SIZE: lResult = CallWindowProc(m_wndprocDebugToolWindow, hWnd, message, wParam, lParam); DebugView_AdjustWindowLayout(); return lResult; default: return CallWindowProc(m_wndprocDebugToolWindow, hWnd, message, wParam, lParam); } //return (LRESULT)FALSE; } BOOL DebugView_OnKeyDown(WPARAM vkey, LPARAM /*lParam*/) { switch (vkey) { case VK_SPACE: DebugView_SwitchCpuPpu(); break; case VK_ESCAPE: ConsoleView_Activate(); break; default: return TRUE; } return FALSE; } void DebugView_UpdateWindowText() { CProcessor* pDebugPU = (m_okDebugProcessor) ? g_pBoard->GetCPU() : g_pBoard->GetPPU(); ASSERT(pDebugPU != NULL); LPCTSTR sProcName = pDebugPU->GetName(); TCHAR buffer[64]; _sntprintf(buffer, sizeof(buffer) / sizeof(TCHAR) - 1, _T("Debug - %s"), sProcName); ::SetWindowText(g_hwndDebug, buffer); } void DebugView_SwitchCpuPpu() { m_okDebugProcessor = ! m_okDebugProcessor; InvalidateRect(m_hwndDebugProcViewer, NULL, TRUE); DebugView_UpdateWindowText(); DisasmView_SetCurrentProc(m_okDebugProcessor); ConsoleView_SetCurrentProc(m_okDebugProcessor); Settings_SetDebugCpuPpu(m_okDebugProcessor); } // Update after Run or Step void DebugView_OnUpdate() { CProcessor* pCPU = g_pBoard->GetCPU(); ASSERT(pCPU != nullptr); // Get new register values and set change flags m_wDebugCpuR6Old = m_wDebugCpuR[6]; for (int r = 0; r < 8; r++) { WORD value = pCPU->GetReg(r); m_okDebugCpuRChanged[r] = (m_wDebugCpuR[r] != value); m_wDebugCpuR[r] = value; } WORD pswCPU = pCPU->GetPSW(); m_okDebugCpuRChanged[8] = (m_wDebugCpuR[8] != pswCPU); m_wDebugCpuPswOld = m_wDebugCpuR[8]; m_wDebugCpuR[8] = pswCPU; WORD cpcCPU = pCPU->GetCPC(); m_okDebugCpuRChanged[9] = (m_wDebugCpuR[9] != cpcCPU); m_wDebugCpuR[9] = cpcCPU; WORD cpswCPU = pCPU->GetCPSW(); m_okDebugCpuRChanged[10] = (m_wDebugCpuR[10] != cpswCPU); m_wDebugCpuR[10] = cpswCPU; CProcessor* pPPU = g_pBoard->GetPPU(); ASSERT(pPPU != NULL); // Get new register values and set change flags m_wDebugPpuR6Old = m_wDebugPpuR[6]; for (int r = 0; r < 8; r++) { WORD value = pPPU->GetReg(r); m_okDebugPpuRChanged[r] = (m_wDebugPpuR[r] != value); m_wDebugPpuR[r] = value; } WORD pswPPU = pPPU->GetPSW(); m_okDebugPpuRChanged[8] = (m_wDebugPpuR[8] != pswPPU); m_wDebugPpuPswOld = m_wDebugPpuR[8]; m_wDebugPpuR[8] = pswPPU; WORD cpcPPU = pPPU->GetCPC(); m_okDebugPpuRChanged[9] = (m_wDebugPpuR[9] != cpcPPU); m_wDebugPpuR[9] = cpcPPU; WORD cpswPPU = pPPU->GetCPSW(); m_okDebugPpuRChanged[10] = (m_wDebugPpuR[10] != cpswPPU); m_wDebugPpuR[10] = cpswPPU; } void DebugView_SetCurrentProc(BOOL okCPU) { m_okDebugProcessor = okCPU; InvalidateRect(m_hwndDebugProcViewer, NULL, TRUE); DebugView_UpdateWindowText(); Settings_SetDebugCpuPpu(m_okDebugProcessor); } void DebugView_DrawAddressAndValue(HDC hdc, const CProcessor* pProc, const CMemoryController* pMemCtl, uint16_t address, int x, int y, int cxChar) { COLORREF colorText = Settings_GetColor(ColorDebugText); SetTextColor(hdc, colorText); DrawOctalValue(hdc, x, y, address); x += 7 * cxChar; int addrtype = ADDRTYPE_NONE; uint16_t value = pMemCtl->GetWordView(address, pProc->IsHaltMode(), FALSE, &addrtype); if (addrtype == ADDRTYPE_RAM0 || (addrtype & ADDRTYPE_MASK_RAM) != 0) { uint16_t wChanged = Emulator_GetChangeRamStatus(addrtype, address); if (wChanged != 0) SetTextColor(hdc, Settings_GetColor(ColorDebugValueChanged)); DrawOctalValue(hdc, x, y, value); } else if (addrtype == ADDRTYPE_ROM || addrtype == ADDRTYPE_ROMCART1 || addrtype == ADDRTYPE_ROMCART2) { SetTextColor(hdc, Settings_GetColor(ColorDebugMemoryRom)); DrawOctalValue(hdc, x, y, value); } else if (addrtype == ADDRTYPE_IO) { value = pMemCtl->GetPortView(address); SetTextColor(hdc, Settings_GetColor(ColorDebugMemoryIO)); DrawOctalValue(hdc, x, y, value); } else //if (addrtype == ADDRTYPE_DENY || addrtype == ADDRTYPE_NONE) { SetTextColor(hdc, Settings_GetColor(ColorDebugMemoryNA)); TextOut(hdc, x, y, _T(" NA "), 6); } SetTextColor(hdc, colorText); } DebugCtrlHitTest DebugView_BaseHitTest(int /*x*/, int y) { DebugCtrlHitTest hit; hit.isValid = false; hit.address = hit.value = 0; hit.line = (y - m_cyDebugLine / 2) / m_cyDebugLine; m_DebugLastHitTest = hit; return hit; } ////////////////////////////////////////////////////////////////////// LRESULT CALLBACK DebugProcViewViewerWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_COMMAND: if (wParam == ID_DEBUG_COPY_VALUE) // Copy command from context menu CopyOctalValueToClipboard(m_DebugLastHitTest.value); else if (wParam == ID_DEBUG_COPY_VALUE_HEX) // Copy command from context menu CopyHexValueToClipboard(m_DebugLastHitTest.value); else ::PostMessage(g_hwnd, WM_COMMAND, wParam, lParam); // Forward commands to the main window break; case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); DebugProcView_DoDraw(hdc); EndPaint(hWnd, &ps); } break; case WM_LBUTTONDOWN: ::SetFocus(hWnd); break; case WM_RBUTTONDOWN: ::SetFocus(hWnd); DebugProcView_OnRButtonDown(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); break; case WM_KEYDOWN: return (LRESULT)DebugView_OnKeyDown(wParam, lParam); case WM_SETFOCUS: case WM_KILLFOCUS: ::InvalidateRect(hWnd, NULL, TRUE); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return (LRESULT)FALSE; } void DebugProcView_OnRButtonDown(int mousex, int mousey) { DebugCtrlHitTest hit = DebugProcView_HitTest(mousex, mousey); m_DebugLastHitTest = hit; POINT pt = { mousex, mousey }; HMENU hMenu = ::CreatePopupMenu(); if (hit.isValid) { TCHAR buffer[20]; _sntprintf(buffer, sizeof(buffer) / sizeof(TCHAR) - 1, _T("Copy Value: %06ho"), hit.value); ::AppendMenu(hMenu, 0, ID_DEBUG_COPY_VALUE, buffer); _sntprintf(buffer, sizeof(buffer) / sizeof(TCHAR) - 1, _T("Copy Value: %04hx"), hit.value); ::AppendMenu(hMenu, 0, ID_DEBUG_COPY_VALUE_HEX, buffer); ::AppendMenu(hMenu, MF_SEPARATOR, 0, NULL); pt.y = m_cyDebugLine / 2 + (hit.line + 1) * m_cyDebugLine; } ::AppendMenu(hMenu, 0, ID_DEBUG_CPUPPU, m_okDebugProcessor ? _T("Swith to PPU") : _T("Swith to CPU")); ::ClientToScreen(m_hwndDebugProcViewer, &pt); ::TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, m_hwndDebugProcViewer, NULL); VERIFY(::DestroyMenu(hMenu)); } void DebugProcView_DoDraw(HDC hdc) { ASSERT(g_pBoard != nullptr); // Create and select font HFONT hFont = CreateMonospacedFont(); HGDIOBJ hOldFont = SelectObject(hdc, hFont); int cxChar, cyLine; GetFontWidthAndHeight(hdc, &cxChar, &cyLine); int cyHeight = cyLine * 17; COLORREF colorOld = SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); COLORREF colorBkOld = SetBkColor(hdc, GetSysColor(COLOR_WINDOW)); CProcessor* pDebugPU = (m_okDebugProcessor) ? g_pBoard->GetCPU() : g_pBoard->GetPPU(); ASSERT(pDebugPU != nullptr); WORD* arrR = (m_okDebugProcessor) ? m_wDebugCpuR : m_wDebugPpuR; BOOL* arrRChanged = (m_okDebugProcessor) ? m_okDebugCpuRChanged : m_okDebugPpuRChanged; WORD oldPsw = (m_okDebugProcessor) ? m_wDebugCpuPswOld : m_wDebugPpuPswOld; HGDIOBJ hOldBrush = ::SelectObject(hdc, ::GetSysColorBrush(COLOR_BTNFACE)); int x = 32; ::PatBlt(hdc, x, 0, 4, cyHeight, PATCOPY); x += 4; int xProc = x; ::SelectObject(hdc, hOldBrush); DebugView_DrawProcessor(hdc, pDebugPU, xProc + cxChar, cyLine / 2, arrR, arrRChanged, oldPsw); SetTextColor(hdc, colorOld); SetBkColor(hdc, colorBkOld); SelectObject(hdc, hOldFont); VERIFY(::DeleteObject(hFont)); if (::GetFocus() == m_hwndDebugProcViewer) { RECT rcClient; GetClientRect(m_hwndDebugProcViewer, &rcClient); rcClient.left += 32 + 4; DrawFocusRect(hdc, &rcClient); } } void DebugView_DrawProcessor(HDC hdc, const CProcessor* pProc, int x, int y, WORD* arrR, BOOL* arrRChanged, WORD oldPsw) { int cxChar, cyLine; GetFontWidthAndHeight(hdc, &cxChar, &cyLine); COLORREF colorText = Settings_GetColor(ColorDebugText); COLORREF colorChanged = Settings_GetColor(ColorDebugValueChanged); ::SetTextColor(hdc, colorText); // Registers for (int r = 0; r < 8; r++) { ::SetTextColor(hdc, arrRChanged[r] ? colorChanged : colorText); LPCTSTR strRegName = REGISTER_NAME[r]; TextOut(hdc, x, y + r * cyLine, strRegName, (int)_tcsnlen(strRegName, 2)); WORD value = arrR[r]; //pProc->GetReg(r); DrawOctalValue(hdc, x + cxChar * 3, y + r * cyLine, value); DrawHexValue(hdc, x + cxChar * 10, y + r * cyLine, value); DrawBinaryValue(hdc, x + cxChar * 15, y + r * cyLine, value); } ::SetTextColor(hdc, colorText); // CPC value ::SetTextColor(hdc, arrRChanged[9] ? colorChanged : colorText); TextOut(hdc, x, y + 8 * cyLine, _T("PC'"), 3); WORD cpc = arrR[9]; DrawOctalValue(hdc, x + cxChar * 3, y + 8 * cyLine, cpc); DrawHexValue(hdc, x + cxChar * 10, y + 8 * cyLine, cpc); DrawBinaryValue(hdc, x + cxChar * 15, y + 8 * cyLine, cpc); // PSW value ::SetTextColor(hdc, arrRChanged[8] ? colorChanged : colorText); TextOut(hdc, x, y + 10 * cyLine, _T("PS"), 2); WORD psw = arrR[8]; // pProc->GetPSW(); DrawOctalValue(hdc, x + cxChar * 3, y + 10 * cyLine, psw); //DrawHexValue(hdc, x + cxChar * 10, y + 10 * cyLine, psw); ::SetTextColor(hdc, colorText); TextOut(hdc, x + cxChar * 15, y + 9 * cyLine, _T(" HP TNZVC"), 16); // PSW value bits colored bit-by-bit TCHAR buffera[2]; buffera[1] = 0; for (int i = 0; i < 16; i++) { WORD bitpos = 1 << i; buffera[0] = (psw & bitpos) ? '1' : '0'; ::SetTextColor(hdc, ((psw & bitpos) != (oldPsw & bitpos)) ? colorChanged : colorText); TextOut(hdc, x + cxChar * (15 + 15 - i), y + 10 * cyLine, buffera, 1); } // CPSW value ::SetTextColor(hdc, arrRChanged[10] ? colorChanged : colorText); TextOut(hdc, x, y + 11 * cyLine, _T("PS'"), 3); WORD cpsw = arrR[10]; DrawOctalValue(hdc, x + cxChar * 3, y + 11 * cyLine, cpsw); //DrawHexValue(hdc, x + cxChar * 10, y + 11 * cyLine, cpsw); DrawBinaryValue(hdc, x + cxChar * 15, y + 11 * cyLine, cpsw); ::SetTextColor(hdc, colorText); // Processor mode - HALT or USER BOOL okHaltMode = pProc->IsHaltMode(); TextOut(hdc, x, y + 13 * cyLine, okHaltMode ? _T("HALT") : _T("USER"), 4); // "Stopped" flag BOOL okStopped = pProc->IsStopped(); if (okStopped) TextOut(hdc, x + 6 * cxChar, y + 13 * cyLine, _T("STOP"), 4); } DebugCtrlHitTest DebugProcView_HitTest(int x, int y) { DebugCtrlHitTest hit = DebugView_BaseHitTest(x, y); if (hit.line < 0 || hit.line == 9 || hit.line > 11) return hit; // Invalid line number hit.isValid = true; const CProcessor* pDebugPU = (m_okDebugProcessor) ? g_pBoard->GetCPU() : g_pBoard->GetPPU(); if (hit.line >= 0 && hit.line < 8) hit.value = pDebugPU->GetReg(hit.line); else if (hit.line == 8) hit.value = pDebugPU->GetCPC(); else if (hit.line == 10) hit.value = pDebugPU->GetPSW(); else if (hit.line == 11) hit.value = pDebugPU->GetCPSW(); return hit; } ////////////////////////////////////////////////////////////////////// LRESULT CALLBACK DebugStackViewViewerWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_COMMAND: ::PostMessage(g_hwnd, WM_COMMAND, wParam, lParam); break; case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); DebugStackView_DoDraw(hdc); EndPaint(hWnd, &ps); } break; case WM_LBUTTONDOWN: ::SetFocus(hWnd); break; case WM_RBUTTONDOWN: ::SetFocus(hWnd); //DebugStackView_OnRButtonDown(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); break; case WM_KEYDOWN: return (LRESULT)DebugView_OnKeyDown(wParam, lParam); case WM_SETFOCUS: case WM_KILLFOCUS: ::InvalidateRect(hWnd, NULL, TRUE); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return (LRESULT)FALSE; } void DebugStackView_DoDraw(HDC hdc) { ASSERT(g_pBoard != nullptr); // Create and select font HFONT hFont = CreateMonospacedFont(); HGDIOBJ hOldFont = SelectObject(hdc, hFont); int cxChar, cyLine; GetFontWidthAndHeight(hdc, &cxChar, &cyLine); CProcessor* pDebugPU = (m_okDebugProcessor) ? g_pBoard->GetCPU() : g_pBoard->GetPPU(); ASSERT(pDebugPU != nullptr); WORD oldSP = (m_okDebugProcessor) ? m_wDebugCpuR6Old : m_wDebugPpuR6Old; // Draw stack for the current processor DebugView_DrawMemoryForRegister(hdc, 6, pDebugPU, cxChar / 2, cyLine / 2, oldSP); SelectObject(hdc, hOldFont); VERIFY(::DeleteObject(hFont)); if (::GetFocus() == m_hwndDebugStackViewer) { RECT rcClient; GetClientRect(m_hwndDebugStackViewer, &rcClient); DrawFocusRect(hdc, &rcClient); } } void DebugView_DrawMemoryForRegister(HDC hdc, int reg, CProcessor* pProc, int x, int y, WORD oldValue) { int cxChar, cyLine; GetFontWidthAndHeight(hdc, &cxChar, &cyLine); COLORREF colorText = Settings_GetColor(ColorDebugText); COLORREF colorChanged = Settings_GetColor(ColorDebugValueChanged); COLORREF colorPrev = Settings_GetColor(ColorDebugPrevious); COLORREF colorOld = SetTextColor(hdc, colorText); uint16_t current = pProc->GetReg(reg) & ~1; uint16_t previous = oldValue; bool okExec = (reg == 7); // Reading from memory into the buffer uint16_t memory[16]; int addrtype[16]; const CMemoryController* pMemCtl = pProc->GetMemoryController(); for (int idx = 0; idx < 16; idx++) { memory[idx] = pMemCtl->GetWordView( (uint16_t)(current + idx * 2 - 16), pProc->IsHaltMode(), okExec, addrtype + idx); } WORD address = current - 16; for (int index = 0; index < 16; index++) { DebugView_DrawAddressAndValue(hdc, pProc, pMemCtl, address, x + 3 * cxChar, y, cxChar); if (address == current) // Current position { SetTextColor(hdc, colorText); TextOut(hdc, x + 2 * cxChar, y, _T(">"), 1); if (current != previous) SetTextColor(hdc, colorChanged); TextOut(hdc, x, y, REGISTER_NAME[reg], 2); } else if (address == previous) { SetTextColor(hdc, colorPrev); TextOut(hdc, x + 2 * cxChar, y, _T(">"), 1); } address += 2; y += cyLine; } SetTextColor(hdc, colorOld); } ////////////////////////////////////////////////////////////////////// LRESULT CALLBACK DebugPortsViewViewerWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_COMMAND: ::PostMessage(g_hwnd, WM_COMMAND, wParam, lParam); break; case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); DebugPortsView_DoDraw(hdc); EndPaint(hWnd, &ps); } break; case WM_LBUTTONDOWN: ::SetFocus(hWnd); break; case WM_RBUTTONDOWN: ::SetFocus(hWnd); //DebugPortsView_OnRButtonDown(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); break; case WM_KEYDOWN: return (LRESULT)DebugView_OnKeyDown(wParam, lParam); case WM_SETFOCUS: case WM_KILLFOCUS: ::InvalidateRect(hWnd, NULL, TRUE); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return (LRESULT)FALSE; } void DebugPortsView_DoDraw(HDC hdc) { ASSERT(g_pBoard != nullptr); // Create and select font HFONT hFont = CreateMonospacedFont(); HGDIOBJ hOldFont = SelectObject(hdc, hFont); int cxChar, cyLine; GetFontWidthAndHeight(hdc, &cxChar, &cyLine); CProcessor* pDebugPU = (m_okDebugProcessor) ? g_pBoard->GetCPU() : g_pBoard->GetPPU(); ASSERT(pDebugPU != nullptr); CMemoryController* pDebugMemCtl = pDebugPU->GetMemoryController(); DebugView_DrawPorts(hdc, m_okDebugProcessor, pDebugMemCtl, g_pBoard, 0, cyLine / 2); SelectObject(hdc, hOldFont); VERIFY(::DeleteObject(hFont)); if (::GetFocus() == m_hwndDebugPortsViewer) { RECT rcClient; GetClientRect(m_hwndDebugPortsViewer, &rcClient); DrawFocusRect(hdc, &rcClient); } } uint16_t m_DebugViewCPUPorts[] = { 0176640, 0176642 }; uint16_t m_DebugViewPPUPorts[] = { 0177010, 0177012, 0177014, 0177016, 0177020, 0177022, 0177024, 0177026, 0177054, 0177700, 0177716 }; void DebugView_DrawPorts(HDC hdc, BOOL okProcessor, const CMemoryController* pMemCtl, CMotherboard* pBoard, int x, int y) { int cxChar, cyLine; GetFontWidthAndHeight(hdc, &cxChar, &cyLine); x += cxChar; TextOut(hdc, x, y, _T("Ports"), 5); uint16_t* addresses = okProcessor ? m_DebugViewCPUPorts : m_DebugViewPPUPorts; int addrcount = okProcessor ? sizeof(m_DebugViewCPUPorts) / sizeof(m_DebugViewCPUPorts[0]) : sizeof(m_DebugViewPPUPorts) / sizeof(m_DebugViewPPUPorts[0]); for (int i = 0; i < addrcount; i++) { uint16_t address = addresses[i]; DebugView_DrawAddressAndValue(hdc, pBoard->GetCPU(), pMemCtl, address, x, y + (i + 1) * cyLine, cxChar); } if (!okProcessor) // PPU timer { WORD value177710 = pBoard->GetTimerStateView(); DrawOctalValue(hdc, x + 0 * cxChar, y + 13 * cyLine, 0177710); DrawOctalValue(hdc, x + 7 * cxChar, y + 13 * cyLine, value177710); WORD value177712 = pBoard->GetTimerReloadView(); DrawOctalValue(hdc, x + 0 * cxChar, y + 14 * cyLine, 0177712); DrawOctalValue(hdc, x + 7 * cxChar, y + 14 * cyLine, value177712); WORD value177714 = pBoard->GetTimerValueView(); DrawOctalValue(hdc, x + 0 * cxChar, y + 15 * cyLine, 0177714); DrawOctalValue(hdc, x + 7 * cxChar, y + 15 * cyLine, value177714); } } void DebugView_DrawChannels(HDC hdc, int x, int y) { int cxChar, cyLine; GetFontWidthAndHeight(hdc, &cxChar, &cyLine); TextOut(hdc, x, y, _T("Channels:"), 9); TCHAR bufData[7]; const size_t buffersize = 32; TCHAR buffer[buffersize]; chan_stc tmpstc; tmpstc = g_pBoard->GetChannelStruct(0, 0, 0); PrintOctalValue(bufData, tmpstc.data); _sntprintf(buffer, buffersize - 1, _T("PPU CH:0 RX D:%s RDY:%d IRQ:%d"), bufData + 3, tmpstc.ready, tmpstc.irq); TextOut(hdc, x, y + 1 * cyLine, buffer, lstrlen(buffer)); tmpstc = g_pBoard->GetChannelStruct(0, 1, 0); PrintOctalValue(bufData, tmpstc.data); _sntprintf(buffer, buffersize - 1, _T("PPU CH:1 RX D:%s RDY:%d IRQ:%d"), bufData + 3, tmpstc.ready, tmpstc.irq); TextOut(hdc, x, y + 2 * cyLine, buffer, lstrlen(buffer)); tmpstc = g_pBoard->GetChannelStruct(0, 2, 0); PrintOctalValue(bufData, tmpstc.data); _sntprintf(buffer, buffersize - 1, _T("PPU CH:2 RX D:%s RDY:%d IRQ:%d"), bufData + 3, tmpstc.ready, tmpstc.irq); TextOut(hdc, x, y + 3 * cyLine, buffer, lstrlen(buffer)); tmpstc = g_pBoard->GetChannelStruct(0, 0, 1); _sntprintf(buffer, buffersize - 1, _T("PPU CH:0 TX RDY:%d IRQ:%d"), tmpstc.ready, tmpstc.irq); TextOut(hdc, x, y + 4 * cyLine, buffer, lstrlen(buffer)); tmpstc = g_pBoard->GetChannelStruct(0, 1, 1); _sntprintf(buffer, buffersize - 1, _T("PPU CH:1 TX RDY:%d IRQ:%d"), tmpstc.ready, tmpstc.irq); TextOut(hdc, x, y + 5 * cyLine, buffer, lstrlen(buffer)); tmpstc = g_pBoard->GetChannelStruct(1, 0, 0); PrintOctalValue(bufData, tmpstc.data); _sntprintf(buffer, buffersize - 1, _T("CPU CH:0 RX D:%s RDY:%d IRQ:%d"), bufData + 3, tmpstc.ready, tmpstc.irq); TextOut(hdc, x, y + 6 * cyLine, buffer, lstrlen(buffer)); tmpstc = g_pBoard->GetChannelStruct(1, 1, 0); PrintOctalValue(bufData, tmpstc.data); _sntprintf(buffer, buffersize - 1, _T("CPU CH:1 RX D:%s RDY:%d IRQ:%d"), bufData + 3, tmpstc.ready, tmpstc.irq); TextOut(hdc, x, y + 7 * cyLine, buffer, lstrlen(buffer)); tmpstc = g_pBoard->GetChannelStruct(1, 0, 1); _sntprintf(buffer, buffersize - 1, _T("CPU CH:0 TX RDY:%d IRQ:%d"), tmpstc.ready, tmpstc.irq); TextOut(hdc, x, y + 8 * cyLine, buffer, lstrlen(buffer)); tmpstc = g_pBoard->GetChannelStruct(1, 1, 1); _sntprintf(buffer, buffersize - 1, _T("CPU CH:1 TX RDY:%d IRQ:%d"), tmpstc.ready, tmpstc.irq); TextOut(hdc, x, y + 9 * cyLine, buffer, lstrlen(buffer)); tmpstc = g_pBoard->GetChannelStruct(1, 2, 1); _sntprintf(buffer, buffersize - 1, _T("CPU CH:2 TX RDY:%d IRQ:%d"), tmpstc.ready, tmpstc.irq); TextOut(hdc, x, y + 10 * cyLine, buffer, lstrlen(buffer)); } ////////////////////////////////////////////////////////////////////// LRESULT CALLBACK DebugBreaksViewViewerWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_COMMAND: ::PostMessage(g_hwnd, WM_COMMAND, wParam, lParam); break; case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); DebugBreaksView_DoDraw(hdc); EndPaint(hWnd, &ps); } break; case WM_LBUTTONDOWN: ::SetFocus(hWnd); break; case WM_RBUTTONDOWN: ::SetFocus(hWnd); DebugBreaksView_OnRButtonDown(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); break; case WM_KEYDOWN: return (LRESULT)DebugView_OnKeyDown(wParam, lParam); case WM_SETFOCUS: case WM_KILLFOCUS: ::InvalidateRect(hWnd, NULL, TRUE); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return (LRESULT)FALSE; } void DebugBreaksView_DoDraw(HDC hdc) { ASSERT(g_pBoard != nullptr); // Create and select font HFONT hFont = CreateMonospacedFont(); HGDIOBJ hOldFont = SelectObject(hdc, hFont); int cxChar, cyLine; GetFontWidthAndHeight(hdc, &cxChar, &cyLine); int x = cxChar / 2, y = cyLine / 2; TextOut(hdc, x, y, _T("Breakpts"), 8); const uint16_t* pbps = m_okDebugProcessor ? Emulator_GetCPUBreakpointList() : Emulator_GetPPUBreakpointList(); if (*pbps != 0177777) { x += cxChar; y += cyLine; while (*pbps != 0177777) { DrawOctalValue(hdc, x, y, *pbps); y += cyLine; pbps++; } } SelectObject(hdc, hOldFont); VERIFY(::DeleteObject(hFont)); if (::GetFocus() == m_hwndDebugBreaksViewer) { RECT rcClient; GetClientRect(m_hwndDebugBreaksViewer, &rcClient); DrawFocusRect(hdc, &rcClient); } } void DebugBreaksView_OnRButtonDown(int mousex, int mousey) { HMENU hMenu = ::CreatePopupMenu(); //::AppendMenu(hMenu, 0, ID_DEBUG_CPUPPU, m_okDebugProcessor ? _T("Swith to PPU") : _T("Swith to CPU")); //::AppendMenu(hMenu, MF_SEPARATOR, 0, NULL); ::AppendMenu(hMenu, 0, ID_DEBUG_DELETEALLBREAKPTS, _T("Delete All Breakpoints")); POINT pt = { mousex, mousey }; ::ClientToScreen(m_hwndDebugBreaksViewer, &pt); ::TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, m_hwndDebugBreaksViewer, NULL); VERIFY(::DestroyMenu(hMenu)); } ////////////////////////////////////////////////////////////////////// LRESULT CALLBACK DebugMemoryViewViewerWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_COMMAND: ::PostMessage(g_hwnd, WM_COMMAND, wParam, lParam); break; case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); DebugMemoryView_DoDraw(hdc); EndPaint(hWnd, &ps); } break; case WM_LBUTTONDOWN: ::SetFocus(hWnd); break; case WM_RBUTTONDOWN: ::SetFocus(hWnd); //DebugView_OnRButtonDown(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); break; case WM_KEYDOWN: return (LRESULT)DebugView_OnKeyDown(wParam, lParam); case WM_SETFOCUS: case WM_KILLFOCUS: ::InvalidateRect(hWnd, NULL, TRUE); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return (LRESULT)FALSE; } void DebugMemoryView_DoDraw(HDC hdc) { ASSERT(g_pBoard != nullptr); // Create and select font HFONT hFont = CreateMonospacedFont(); HGDIOBJ hOldFont = SelectObject(hdc, hFont); int cxChar, cyLine; GetFontWidthAndHeight(hdc, &cxChar, &cyLine); COLORREF colorOld = SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); COLORREF colorBkOld = SetBkColor(hdc, GetSysColor(COLOR_WINDOW)); CProcessor* pDebugPU = (m_okDebugProcessor) ? g_pBoard->GetCPU() : g_pBoard->GetPPU(); ASSERT(pDebugPU != nullptr); CMemoryController* pDebugMemCtl = pDebugPU->GetMemoryController(); HGDIOBJ hOldBrush = ::SelectObject(hdc, ::GetSysColorBrush(COLOR_BTNFACE)); ::SelectObject(hdc, hOldBrush); if (m_okDebugProcessor) DebugView_DrawCPUMemoryMap(hdc, cxChar, 0 * cyLine, pDebugPU); else DebugView_DrawPPUMemoryMap(hdc, cxChar, 0 * cyLine, pDebugPU, pDebugMemCtl); SetTextColor(hdc, colorOld); SetBkColor(hdc, colorBkOld); SelectObject(hdc, hOldFont); VERIFY(::DeleteObject(hFont)); if (::GetFocus() == m_hwndDebugMemoryViewer) { RECT rcClient; GetClientRect(m_hwndDebugMemoryViewer, &rcClient); DrawFocusRect(hdc, &rcClient); } } void DebugView_DrawCPUMemoryMap(HDC hdc, int x, int y, const CProcessor* pDebugPU) { int cxChar, cyLine; GetFontWidthAndHeight(hdc, &cxChar, &cyLine); int x1 = x + cxChar * 7; int y1 = y + cxChar / 2; int x2 = x1 + cxChar * 14; int y2 = y1 + cyLine * 16; int xtype = x1 + cxChar * 3; int ybase = y + cyLine * 16; HGDIOBJ hOldBrush = ::SelectObject(hdc, ::GetSysColorBrush(COLOR_BTNSHADOW)); PatBlt(hdc, x1, y1, 1, y2 - y1, PATCOPY); PatBlt(hdc, x2, y1, 1, y2 - y1 + 1, PATCOPY); PatBlt(hdc, x1, y1, x2 - x1, 1, PATCOPY); PatBlt(hdc, x1, y2, x2 - x1, 1, PATCOPY); TextOut(hdc, x, ybase - cyLine / 2, _T("000000"), 6); for (int i = 1; i < 8; i++) { if (i < 7) PatBlt(hdc, x1, y2 - cyLine * i * 2, 8, 1, PATCOPY); else PatBlt(hdc, x1, y2 - cyLine * i * 2, x2 - x1, 1, PATCOPY); WORD addr = (WORD)i * 020000; DrawOctalValue(hdc, x, y2 - cyLine * i * 2 - 4, addr); } TextOut(hdc, xtype, ybase - cyLine * 7, _T("RAM12"), 5); if (pDebugPU->IsHaltMode()) TextOut(hdc, xtype, ybase - cyLine * 15, _T("RAM12"), 5); else TextOut(hdc, xtype, ybase - cyLine * 15, _T("I/O"), 3); uint16_t sp = pDebugPU->GetSP(); int ysp = y2 - ((y2 - y1) * sp / 65536); PatBlt(hdc, x2, ysp, cxChar, 1, PATCOPY); TextOut(hdc, x2 + cxChar, ysp - cyLine / 2, _T("SP"), 2); uint16_t pc = pDebugPU->GetPC(); int ypc = y2 - ((y2 - y1) * pc / 65536); PatBlt(hdc, x2, ypc, cxChar, 1, PATCOPY); TextOut(hdc, x2 + cxChar, ypc - cyLine / 2, _T("PC"), 2); ::SelectObject(hdc, hOldBrush); } void DebugView_DrawPPUMemoryMap(HDC hdc, int x, int y, const CProcessor* pDebugPU, const CMemoryController* pMemCtl) { WORD value177054 = pMemCtl->GetPortView(0177054); int cxChar, cyLine; GetFontWidthAndHeight(hdc, &cxChar, &cyLine); int x1 = x + cxChar * 7; int y1 = y + cxChar / 2; int x2 = x1 + cxChar * 14; int y2 = y1 + cyLine * 16; int xtype = x1 + cxChar * 3; int ybase = y + cyLine * 16; HGDIOBJ hOldBrush = ::SelectObject(hdc, ::GetSysColorBrush(COLOR_BTNSHADOW)); PatBlt(hdc, x1, y1, 1, y2 - y1, PATCOPY); PatBlt(hdc, x2, y1, 1, y2 - y1 + 1, PATCOPY); PatBlt(hdc, x1, y1, x2 - x1, 1, PATCOPY); PatBlt(hdc, x1, y2, x2 - x1, 1, PATCOPY); TextOut(hdc, x, ybase - cyLine / 2, _T("000000"), 6); for (int i = 1; i < 8; i++) { if (i < 4) PatBlt(hdc, x1, y2 - cyLine * i * 2, 8, 1, PATCOPY); else PatBlt(hdc, x1, y2 - cyLine * i * 2, x2 - x1, 1, PATCOPY); WORD addr = (WORD)i * 020000; DrawOctalValue(hdc, x, y2 - cyLine * i * 2 - 4, addr); } PatBlt(hdc, x1, y1 + cyLine / 4, x2 - x1, 1, PATCOPY); TextOut(hdc, x, ybase - cyLine * 16 + cyLine / 4, _T("177000"), 6); TextOut(hdc, xtype, ybase - cyLine * 4, _T("RAM0"), 4); // 100000-117777 - Window block 0 if ((value177054 & 16) != 0) // Port 177054 bit 4 set => RAM selected TextOut(hdc, xtype, ybase - cyLine * 9, _T("RAM0"), 4); else if ((value177054 & 1) != 0) // ROM selected TextOut(hdc, xtype, ybase - cyLine * 9, _T("ROM"), 3); else if ((value177054 & 14) != 0) // ROM cartridge selected { int slot = ((value177054 & 8) == 0) ? 1 : 2; int bank = (value177054 & 6) >> 1; const size_t buffersize = 10; TCHAR buffer[10]; _sntprintf(buffer, buffersize - 1, _T("Cart %d/%d"), slot, bank); TextOut(hdc, xtype, ybase - cyLine * 9, buffer, _tcsnlen(buffer, buffersize)); } // 120000-137777 - Window block 1 if ((value177054 & 32) != 0) // Port 177054 bit 5 set => RAM selected TextOut(hdc, xtype, ybase - cyLine * 11, _T("RAM0"), 4); else TextOut(hdc, xtype, ybase - cyLine * 11, _T("ROM"), 3); // 140000-157777 - Window block 2 if ((value177054 & 64) != 0) // Port 177054 bit 6 set => RAM selected TextOut(hdc, xtype, ybase - cyLine * 13, _T("RAM0"), 4); else TextOut(hdc, xtype, ybase - cyLine * 13, _T("ROM"), 3); // 160000-176777 - Window block 3 if ((value177054 & 128) != 0) // Port 177054 bit 7 set => RAM selected TextOut(hdc, xtype, ybase - cyLine * 15, _T("RAM0"), 4); else TextOut(hdc, xtype, ybase - cyLine * 15, _T("ROM"), 3); uint16_t sp = pDebugPU->GetSP(); int ysp = y2 - ((y2 - y1) * sp / 65536); PatBlt(hdc, x2, ysp, cxChar, 1, PATCOPY); TextOut(hdc, x2 + cxChar, ysp - cyLine / 2, _T("SP"), 2); uint16_t pc = pDebugPU->GetPC(); int ypc = y2 - ((y2 - y1) * pc / 65536); PatBlt(hdc, x2, ypc, cxChar, 1, PATCOPY); TextOut(hdc, x2 + cxChar, ypc - cyLine / 2, _T("PC"), 2); ::SelectObject(hdc, hOldBrush); } //////////////////////////////////////////////////////////////////////