603 lines
20 KiB
C++
603 lines
20 KiB
C++
/* This file is part of BKBTL.
|
|
BKBTL 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.
|
|
BKBTL 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
|
|
BKBTL. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
// DebugView.cpp
|
|
|
|
#include "stdafx.h"
|
|
#include <windowsx.h>
|
|
#include <CommCtrl.h>
|
|
#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_hwndDebugViewer = (HWND)INVALID_HANDLE_VALUE;
|
|
HWND m_hwndDebugToolbar = (HWND)INVALID_HANDLE_VALUE;
|
|
|
|
WORD m_wDebugCpuR[9]; // Old register values - R0..R7, PSW
|
|
BOOL m_okDebugCpuRChanged[9]; // Register change flags
|
|
WORD m_wDebugCpuPswOld; // PSW value on previous step
|
|
WORD m_wDebugCpuR6Old; // SP value on previous step
|
|
|
|
void DebugView_OnRButtonDown(int mousex, int mousey);
|
|
void DebugView_DoDraw(HDC hdc);
|
|
BOOL DebugView_OnKeyDown(WPARAM vkey, LPARAM lParam);
|
|
void DebugView_DrawProcessor(HDC hdc, const CProcessor* pProc, int x, int y, WORD* arrR, BOOL* arrRChanged, WORD oldPsw);
|
|
void DebugView_DrawMemoryForRegister(HDC hdc, int reg, const CProcessor* pProc, int x, int y, WORD oldValue);
|
|
int DebugView_DrawWatchpoints(HDC hdc, int x, int y);
|
|
void DebugView_DrawPorts(HDC hdc, int x, int y);
|
|
void DebugView_DrawBreakpoints(HDC hdc, int x, int y);
|
|
void DebugView_DrawMemoryMap(HDC hdc, int x, int y, const CProcessor* pProc);
|
|
void DebugView_UpdateWindowText();
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
void DebugView_RegisterClass()
|
|
{
|
|
WNDCLASSEX wcex;
|
|
wcex.cbSize = sizeof(WNDCLASSEX);
|
|
|
|
wcex.style = CS_HREDRAW | CS_VREDRAW;
|
|
wcex.lpfnWndProc = DebugViewViewerWndProc;
|
|
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.lpszClassName = CLASSNAME_DEBUGVIEW;
|
|
wcex.hIconSm = NULL;
|
|
|
|
RegisterClassEx(&wcex);
|
|
}
|
|
|
|
void DebugView_Init()
|
|
{
|
|
memset(m_wDebugCpuR, 255, sizeof(m_wDebugCpuR));
|
|
memset(m_okDebugCpuRChanged, 1, sizeof(m_okDebugCpuRChanged));
|
|
m_wDebugCpuPswOld = 0;
|
|
m_wDebugCpuR6Old = 0;
|
|
}
|
|
|
|
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_hwndDebugViewer = CreateWindowEx(
|
|
WS_EX_STATICEDGE,
|
|
CLASSNAME_DEBUGVIEW, 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_hwndDebugViewer,
|
|
(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[5];
|
|
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_SPRITES;
|
|
buttons[1].iBitmap = ToolbarImageSpriteViewer;
|
|
buttons[2].fsStyle = BTNS_SEP;
|
|
buttons[3].idCommand = ID_DEBUG_STEPINTO;
|
|
buttons[3].iBitmap = ToolbarImageStepInto;
|
|
buttons[4].idCommand = ID_DEBUG_STEPOVER;
|
|
buttons[4].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);
|
|
|
|
if (m_hwndDebugViewer != (HWND)INVALID_HANDLE_VALUE)
|
|
SetWindowPos(m_hwndDebugViewer, NULL, 0, 0, rc.right, 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;
|
|
}
|
|
|
|
LRESULT CALLBACK DebugViewViewerWndProc(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);
|
|
|
|
DebugView_DoDraw(hdc);
|
|
|
|
EndPaint(hWnd, &ps);
|
|
}
|
|
break;
|
|
case WM_LBUTTONDOWN:
|
|
::SetFocus(hWnd);
|
|
break;
|
|
case WM_RBUTTONDOWN:
|
|
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 DebugView_OnRButtonDown(int mousex, int mousey)
|
|
{
|
|
::SetFocus(m_hwndDebugViewer);
|
|
|
|
HMENU hMenu = ::CreatePopupMenu();
|
|
::AppendMenu(hMenu, 0, ID_DEBUG_DELETEALLBREAKPTS, _T("Delete All Breakpoints"));
|
|
|
|
POINT pt = { mousex, mousey };
|
|
::ClientToScreen(m_hwndDebugViewer, &pt);
|
|
::TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, m_hwndDebugViewer, NULL);
|
|
|
|
VERIFY(::DestroyMenu(hMenu));
|
|
}
|
|
|
|
BOOL DebugView_OnKeyDown(WPARAM vkey, LPARAM /*lParam*/)
|
|
{
|
|
switch (vkey)
|
|
{
|
|
case VK_ESCAPE:
|
|
ConsoleView_Activate();
|
|
break;
|
|
default:
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void DebugView_UpdateWindowText()
|
|
{
|
|
::SetWindowText(g_hwndDebug, _T("Debug"));
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// 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;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Draw functions
|
|
|
|
void DebugView_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 = g_pBoard->GetCPU();
|
|
ASSERT(pDebugPU != nullptr);
|
|
WORD* arrR = m_wDebugCpuR;
|
|
BOOL* arrRChanged = m_okDebugCpuRChanged;
|
|
WORD oldPsw = m_wDebugCpuPswOld;
|
|
WORD oldSP = m_wDebugCpuR6Old;
|
|
|
|
HGDIOBJ hOldBrush = ::SelectObject(hdc, ::GetSysColorBrush(COLOR_BTNFACE));
|
|
int x = 32;
|
|
::PatBlt(hdc, x, 0, 4, cyHeight, PATCOPY);
|
|
x += 4;
|
|
int xProc = x;
|
|
x += cxChar * 33;
|
|
::PatBlt(hdc, x, 0, 4, cyHeight, PATCOPY);
|
|
x += 4;
|
|
int xStack = x;
|
|
x += cxChar * 17 + cxChar / 2;
|
|
::PatBlt(hdc, x, 0, 4, cyHeight, PATCOPY);
|
|
x += 4;
|
|
int xPorts = x;
|
|
x += cxChar * 25;
|
|
::PatBlt(hdc, x, 0, 4, cyHeight, PATCOPY);
|
|
x += 4;
|
|
int xBreaks = x;
|
|
x += cxChar * 9;
|
|
::PatBlt(hdc, x, 0, 4, cyHeight, PATCOPY);
|
|
x += 4;
|
|
int xMemmap = x;
|
|
::SelectObject(hdc, hOldBrush);
|
|
|
|
DebugView_DrawProcessor(hdc, pDebugPU, xProc + cxChar, cyLine / 2, arrR, arrRChanged, oldPsw);
|
|
|
|
// Draw stack for the current processor
|
|
DebugView_DrawMemoryForRegister(hdc, 6, pDebugPU, xStack + cxChar / 2, cyLine / 2, oldSP);
|
|
|
|
int nWatches = DebugView_DrawWatchpoints(hdc, xPorts + cxChar, cyLine / 2);
|
|
DebugView_DrawPorts(hdc, xPorts + cxChar, cyLine / 2 + (nWatches > 0 ? 2 + nWatches : 0) * cyLine);
|
|
|
|
DebugView_DrawBreakpoints(hdc, xBreaks + cxChar / 2, cyLine / 2);
|
|
|
|
DebugView_DrawMemoryMap(hdc, xMemmap + cxChar, 0, pDebugPU);
|
|
|
|
SetTextColor(hdc, colorOld);
|
|
SetBkColor(hdc, colorBkOld);
|
|
SelectObject(hdc, hOldFont);
|
|
VERIFY(::DeleteObject(hFont));
|
|
|
|
if (::GetFocus() == m_hwndDebugViewer)
|
|
{
|
|
RECT rcClient;
|
|
GetClientRect(m_hwndDebugViewer, &rcClient);
|
|
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) _tcslen(strRegName));
|
|
|
|
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);
|
|
|
|
// 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);
|
|
}
|
|
|
|
::SetTextColor(hdc, colorText);
|
|
|
|
// Processor mode - HALT or USER
|
|
BOOL okHaltMode = pProc->IsHaltMode();
|
|
TextOut(hdc, x, y + 12 * cyLine, okHaltMode ? _T("HALT") : _T("USER"), 4);
|
|
|
|
// "Stopped" flag
|
|
BOOL okStopped = pProc->IsStopped();
|
|
if (okStopped)
|
|
TextOut(hdc, x + 6 * cxChar, y + 12 * cyLine, _T("STOP"), 4);
|
|
}
|
|
|
|
void DebugView_DrawAddressAndValue(HDC hdc, uint16_t address, int x, int y, int cxChar)
|
|
{
|
|
ASSERT(g_pBoard != nullptr);
|
|
|
|
COLORREF colorText = Settings_GetColor(ColorDebugText);
|
|
SetTextColor(hdc, colorText);
|
|
DrawOctalValue(hdc, x, y, address);
|
|
x += 7 * cxChar;
|
|
|
|
bool okHaltMode = g_pBoard->GetCPU()->IsHaltMode();
|
|
int addrtype = ADDRTYPE_DENY;
|
|
uint16_t value = g_pBoard->GetWordView(address, okHaltMode, FALSE, &addrtype);
|
|
if (addrtype == ADDRTYPE_RAM)
|
|
{
|
|
uint16_t wChanged = Emulator_GetChangeRamStatus(address);
|
|
if (wChanged != 0) SetTextColor(hdc, Settings_GetColor(ColorDebugValueChanged));
|
|
DrawOctalValue(hdc, x, y, value);
|
|
}
|
|
else if (addrtype == ADDRTYPE_ROM)
|
|
{
|
|
SetTextColor(hdc, Settings_GetColor(ColorDebugMemoryRom));
|
|
DrawOctalValue(hdc, x, y, value);
|
|
}
|
|
else if (addrtype == ADDRTYPE_IO)
|
|
{
|
|
value = g_pBoard->GetPortView(address);
|
|
SetTextColor(hdc, Settings_GetColor(ColorDebugMemoryIO));
|
|
DrawOctalValue(hdc, x, y, value);
|
|
}
|
|
else //if (addrtype == ADDRTYPE_DENY)
|
|
{
|
|
SetTextColor(hdc, Settings_GetColor(ColorDebugMemoryNA));
|
|
TextOut(hdc, x, y, _T(" NA "), 6);
|
|
}
|
|
|
|
SetTextColor(hdc, colorText);
|
|
}
|
|
|
|
void DebugView_DrawMemoryForRegister(HDC hdc, int reg, const 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];
|
|
for (int idx = 0; idx < 16; idx++)
|
|
{
|
|
memory[idx] = g_pBoard->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, 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);
|
|
}
|
|
|
|
int DebugView_DrawWatchpoints(HDC hdc, int x, int y)
|
|
{
|
|
const uint16_t* pws = Emulator_GetWatchList();
|
|
if (*pws == 0177777)
|
|
return 0;
|
|
|
|
int cxChar, cyLine; GetFontWidthAndHeight(hdc, &cxChar, &cyLine);
|
|
|
|
int nWatches = 0;
|
|
TextOut(hdc, x, y, _T("Watches"), 7);
|
|
y += cyLine;
|
|
while (*pws != 0177777)
|
|
{
|
|
uint16_t address = *pws;
|
|
DebugView_DrawAddressAndValue(hdc, address, x, y, cxChar);
|
|
y += cyLine;
|
|
pws++; nWatches++;
|
|
}
|
|
|
|
return nWatches;
|
|
}
|
|
|
|
struct DebugViewPortWatch
|
|
{
|
|
uint16_t address;
|
|
LPCTSTR description;
|
|
}
|
|
m_DebugViewPorts[] =
|
|
{
|
|
{ 0177660, _T("kbd state") },
|
|
{ 0177662, _T("kbd data") },
|
|
{ 0177664, _T("scroll") },
|
|
{ 0177706, _T("timer rel") },
|
|
{ 0177710, _T("timer val") },
|
|
{ 0177712, _T("timer ctl") },
|
|
{ 0177714, _T("parallel") },
|
|
{ 0177716, _T("system") },
|
|
{ 0177130, _T("fdd state") },
|
|
{ 0177132, _T("fdd data") },
|
|
};
|
|
|
|
void DebugView_DrawPorts(HDC hdc, int x, int y)
|
|
{
|
|
int cxChar, cyLine; GetFontWidthAndHeight(hdc, &cxChar, &cyLine);
|
|
|
|
TextOut(hdc, x, y, _T("Ports"), 5);
|
|
|
|
int portsCount = sizeof(m_DebugViewPorts) / sizeof(m_DebugViewPorts[0]);
|
|
for (int i = 0; i < portsCount; i++)
|
|
{
|
|
y += cyLine;
|
|
const DebugViewPortWatch& watch = m_DebugViewPorts[i];
|
|
DebugView_DrawAddressAndValue(hdc, watch.address, x, y, cxChar);
|
|
TextOut(hdc, x + 14 * cxChar, y, watch.description, _tcslen(watch.description));
|
|
}
|
|
}
|
|
|
|
void DebugView_DrawBreakpoints(HDC hdc, int x, int y)
|
|
{
|
|
TextOut(hdc, x, y, _T("Breakpts"), 8);
|
|
|
|
const uint16_t* pbps = Emulator_GetCPUBreakpointList();
|
|
if (*pbps == 0177777)
|
|
return;
|
|
|
|
int cxChar, cyLine; GetFontWidthAndHeight(hdc, &cxChar, &cyLine);
|
|
|
|
x += cxChar;
|
|
y += cyLine;
|
|
while (*pbps != 0177777)
|
|
{
|
|
DrawOctalValue(hdc, x, y, *pbps);
|
|
y += cyLine;
|
|
pbps++;
|
|
}
|
|
}
|
|
|
|
void DebugView_DrawMemoryMap(HDC hdc, int x, int y, const CProcessor* pProc)
|
|
{
|
|
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;
|
|
|
|
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);
|
|
|
|
for (uint16_t window = 0; window < 8; window++)
|
|
{
|
|
int yp = y2 - window * cyLine * 2;
|
|
uint16_t address = window << 13;
|
|
DrawOctalValue(hdc, x, yp - cyLine / 2, address);
|
|
PatBlt(hdc, x1, yp, x2 - x1, 1, PATCOPY);
|
|
|
|
int addrtype;
|
|
g_pBoard->GetWordView(address, pProc->GetHALT(), FALSE, &addrtype);
|
|
LPCTSTR addrtypestr;
|
|
switch (addrtype & (ADDRTYPE_RAM | ADDRTYPE_ROM | ADDRTYPE_IO | ADDRTYPE_DENY))
|
|
{
|
|
case ADDRTYPE_ROM: addrtypestr = _T("ROM"); break;
|
|
case ADDRTYPE_RAM: addrtypestr = _T("RAM"); break;
|
|
case ADDRTYPE_IO: addrtypestr = _T("I/O"); break;
|
|
case ADDRTYPE_DENY: addrtypestr = _T("N/A"); break;
|
|
default:
|
|
addrtypestr = nullptr;
|
|
}
|
|
if (addrtypestr != nullptr)
|
|
TextOut(hdc, x1 + cxChar * 2, yp - (cyLine * 4) / 3, addrtypestr, 3);
|
|
}
|
|
|
|
PatBlt(hdc, x1, y1 + cyLine / 4, x2 - x1, 1, PATCOPY);
|
|
|
|
uint16_t sp = pProc->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 = pProc->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);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|