/* 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 . */ // ConsoleView.cpp #include "stdafx.h" #include "Main.h" #include "Views.h" #include "ToolWindow.h" #include "Emulator.h" #include "emubase/Emubase.h" ////////////////////////////////////////////////////////////////////// COLORREF COLOR_COMMANDFOCUS = RGB(255, 242, 157); HWND g_hwndConsole = (HWND)INVALID_HANDLE_VALUE; // Console View window handle WNDPROC m_wndprocConsoleToolWindow = NULL; // Old window proc address of the ToolWindow HWND m_hwndConsoleLog = (HWND)INVALID_HANDLE_VALUE; // Console log window - read-only edit control HWND m_hwndConsoleEdit = (HWND)INVALID_HANDLE_VALUE; // Console line - edit control HWND m_hwndConsolePrompt = (HWND)INVALID_HANDLE_VALUE; // Console prompt - static control HFONT m_hfontConsole = NULL; WNDPROC m_wndprocConsoleEdit = NULL; // Old window proc address of the console prompt HBRUSH m_hbrConsoleFocused = NULL; CProcessor* ConsoleView_GetCurrentProcessor(); void ConsoleView_AdjustWindowLayout(); LRESULT CALLBACK ConsoleEditWndProc(HWND, UINT, WPARAM, LPARAM); void ConsoleView_DoConsoleCommand(); void ConsoleView_PrintConsolePrompt(); void ConsoleView_PrintRegister(LPCTSTR strName, WORD value); void ConsoleView_PrintMemoryDump(const CProcessor* pProc, WORD address, int lines); BOOL ConsoleView_SaveMemoryDump(); const LPCTSTR MESSAGE_UNKNOWN_COMMAND = _T(" Unknown command.\r\n"); const LPCTSTR MESSAGE_WRONG_VALUE = _T(" Wrong value.\r\n"); const LPCTSTR MESSAGE_INVALID_REGNUM = _T(" Invalid register number, 0..7 expected.\r\n"); ////////////////////////////////////////////////////////////////////// void ConsoleView_RegisterClass() { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = ConsoleViewWndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = g_hInst; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); wcex.lpszMenuName = NULL; wcex.lpszClassName = CLASSNAME_CONSOLEVIEW; wcex.hIconSm = NULL; RegisterClassEx(&wcex); } // Create Console View as child of Main Window void ConsoleView_Create(HWND hwndParent, int x, int y, int width, int height) { ASSERT(hwndParent != NULL); g_hwndConsole = CreateWindow( CLASSNAME_TOOLWINDOW, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN, x, y, width, height, hwndParent, NULL, g_hInst, NULL); SetWindowText(g_hwndConsole, _T("Debug Console")); // ToolWindow subclassing m_wndprocConsoleToolWindow = (WNDPROC)LongToPtr( SetWindowLongPtr( g_hwndConsole, GWLP_WNDPROC, PtrToLong(ConsoleViewWndProc)) ); RECT rcConsole; GetClientRect(g_hwndConsole, &rcConsole); m_hwndConsoleEdit = CreateWindowEx( WS_EX_CLIENTEDGE, _T("EDIT"), NULL, WS_CHILD | WS_VISIBLE, 90, rcConsole.bottom - 20, rcConsole.right - 90, 20, g_hwndConsole, NULL, g_hInst, NULL); m_hwndConsoleLog = CreateWindowEx( WS_EX_CLIENTEDGE, _T("EDIT"), NULL, WS_CHILD | WS_VSCROLL | WS_VISIBLE | ES_READONLY | ES_MULTILINE, 0, 0, rcConsole.right, rcConsole.bottom - 20, g_hwndConsole, NULL, g_hInst, NULL); m_hwndConsolePrompt = CreateWindowEx( 0, _T("STATIC"), NULL, WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE | SS_CENTER | SS_NOPREFIX, 0, rcConsole.bottom - 20, 90, 20, g_hwndConsole, NULL, g_hInst, NULL); m_hfontConsole = CreateMonospacedFont(); SendMessage(m_hwndConsolePrompt, WM_SETFONT, (WPARAM)m_hfontConsole, 0); SendMessage(m_hwndConsoleEdit, WM_SETFONT, (WPARAM)m_hfontConsole, 0); SendMessage(m_hwndConsoleLog, WM_SETFONT, (WPARAM)m_hfontConsole, 0); // Edit box subclassing m_wndprocConsoleEdit = (WNDPROC)LongToPtr( SetWindowLongPtr( m_hwndConsoleEdit, GWLP_WNDPROC, PtrToLong(ConsoleEditWndProc)) ); ShowWindow(g_hwndConsole, SW_SHOW); UpdateWindow(g_hwndConsole); ConsoleView_Print(_T("Use 'h' command to show help.\r\n\r\n")); ConsoleView_PrintConsolePrompt(); SetFocus(m_hwndConsoleEdit); } // Adjust position of client windows void ConsoleView_AdjustWindowLayout() { RECT rc; GetClientRect(g_hwndConsole, &rc); int promptWidth = 65; if (m_hwndConsolePrompt != (HWND)INVALID_HANDLE_VALUE) SetWindowPos(m_hwndConsolePrompt, NULL, 0, rc.bottom - 20, promptWidth, 20, SWP_NOZORDER); if (m_hwndConsoleEdit != (HWND)INVALID_HANDLE_VALUE) SetWindowPos(m_hwndConsoleEdit, NULL, promptWidth, rc.bottom - 20, rc.right - promptWidth, 20, SWP_NOZORDER); if (m_hwndConsoleLog != (HWND)INVALID_HANDLE_VALUE) SetWindowPos(m_hwndConsoleLog, NULL, 0, 0, rc.right, rc.bottom - 24, SWP_NOZORDER); } LRESULT CALLBACK ConsoleViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); LRESULT lResult; switch (message) { case WM_DESTROY: g_hwndConsole = (HWND)INVALID_HANDLE_VALUE; // We are closed! Bye-bye!.. break; case WM_CTLCOLORSTATIC: if (((HWND)lParam) == m_hwndConsoleLog) { SetBkColor((HDC)wParam, ::GetSysColor(COLOR_WINDOW)); return (LRESULT)::GetSysColorBrush(COLOR_WINDOW); } break; case WM_CTLCOLOREDIT: if (((HWND)lParam) == m_hwndConsoleEdit && ::GetFocus() == m_hwndConsoleEdit) { if (m_hbrConsoleFocused == NULL) m_hbrConsoleFocused = ::CreateSolidBrush(COLOR_COMMANDFOCUS); SetBkColor((HDC)wParam, COLOR_COMMANDFOCUS); return (LRESULT)m_hbrConsoleFocused; } return CallWindowProc(m_wndprocConsoleToolWindow, hWnd, message, wParam, lParam); case WM_SIZE: lResult = CallWindowProc(m_wndprocConsoleToolWindow, hWnd, message, wParam, lParam); ConsoleView_AdjustWindowLayout(); return lResult; } return CallWindowProc(m_wndprocConsoleToolWindow, hWnd, message, wParam, lParam); } LRESULT CALLBACK ConsoleEditWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CHAR: if (wParam == 13) { ConsoleView_DoConsoleCommand(); return 0; } if (wParam == VK_ESCAPE) { TCHAR command[32]; GetWindowText(m_hwndConsoleEdit, command, 32); if (*command == 0) // If command is empty SetFocus(g_hwndScreen); else SendMessage(m_hwndConsoleEdit, WM_SETTEXT, 0, (LPARAM)_T("")); // Clear command return 0; } break; } return CallWindowProc(m_wndprocConsoleEdit, hWnd, message, wParam, lParam); } void ConsoleView_Activate() { if (g_hwndConsole == INVALID_HANDLE_VALUE) return; SetFocus(m_hwndConsoleEdit); } CProcessor* ConsoleView_GetCurrentProcessor() { return g_pBoard->GetCPU(); } void ConsoleView_PrintFormat(LPCTSTR pszFormat, ...) { const size_t buffersize = 512; TCHAR buffer[buffersize]; va_list ptr; va_start(ptr, pszFormat); _vsntprintf_s(buffer, buffersize, buffersize - 1, pszFormat, ptr); va_end(ptr); ConsoleView_Print(buffer); } void ConsoleView_Print(LPCTSTR message) { if (m_hwndConsoleLog == INVALID_HANDLE_VALUE) return; // Put selection to the end of text SendMessage(m_hwndConsoleLog, EM_SETSEL, 0x100000, 0x100000); // Insert the message SendMessage(m_hwndConsoleLog, EM_REPLACESEL, (WPARAM)FALSE, (LPARAM)message); // Scroll to caret SendMessage(m_hwndConsoleLog, EM_SCROLLCARET, 0, 0); } void ConsoleView_ClearConsole() { if (m_hwndConsoleLog == INVALID_HANDLE_VALUE) return; SendMessage(m_hwndConsoleLog, WM_SETTEXT, 0, (LPARAM)_T("")); } void ConsoleView_PrintConsolePrompt() { CProcessor* pProc = ConsoleView_GetCurrentProcessor(); TCHAR bufferAddr[7]; PrintOctalValue(bufferAddr, pProc->GetPC()); TCHAR buffer[14]; _sntprintf(buffer, sizeof(buffer) / sizeof(TCHAR) - 1, _T("%s> "), bufferAddr); ::SetWindowText(m_hwndConsolePrompt, buffer); } // Print register name, octal value and binary value void ConsoleView_PrintRegister(LPCTSTR strName, WORD value) { TCHAR buffer[36]; TCHAR* p = buffer; *p++ = _T(' '); *p++ = _T(' '); lstrcpy(p, strName); p += 2; *p++ = _T(' '); PrintOctalValue(p, value); p += 6; *p++ = _T(' '); PrintHexValue(p, value); p += 4; *p++ = _T(' '); PrintBinaryValue(p, value); p += 16; *p++ = _T('\r'); *p++ = _T('\n'); *p++ = 0; ConsoleView_Print(buffer); } void ConsoleView_StepInto() { // Put command to console prompt SendMessage(m_hwndConsoleEdit, WM_SETTEXT, 0, (LPARAM)_T("s")); // Execute command ConsoleView_DoConsoleCommand(); } void ConsoleView_StepOver() { // Put command to console prompt SendMessage(m_hwndConsoleEdit, WM_SETTEXT, 0, (LPARAM)_T("so")); // Execute command ConsoleView_DoConsoleCommand(); } void ConsoleView_DeleteAllBreakpoints() { // Put command to console prompt SendMessage(m_hwndConsoleEdit, WM_SETTEXT, 0, (LPARAM)_T("bc")); // Execute command ConsoleView_DoConsoleCommand(); } BOOL ConsoleView_SaveMemoryDump() { BYTE buf[65536]; for (int i = 0; i < 65536; i++) { buf[i] = g_pBoard->GetByte((uint16_t)i, 1); } const TCHAR fname[] = _T("memdump.bin"); HANDLE file = ::CreateFile(fname, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); DWORD dwBytesWritten = 0; ::WriteFile(file, buf, 65536, &dwBytesWritten, NULL); ::CloseHandle(file); if (dwBytesWritten != 65536) return FALSE; return TRUE; } // Print memory dump void ConsoleView_PrintMemoryDump(const CProcessor* pProc, WORD address, int lines = 8) { address &= ~1; // Line up to even address bool okHaltMode = pProc->IsHaltMode(); for (int line = 0; line < lines; line++) { WORD dump[8]; int addrtype; for (int i = 0; i < 8; i++) dump[i] = g_pBoard->GetWordView((uint16_t)(address + i * 2), okHaltMode, false, &addrtype); TCHAR buffer[2 + 6 + 2 + 7 * 8 + 1 + 16 + 1 + 2]; TCHAR* pBuf = buffer; *pBuf = _T(' '); pBuf++; *pBuf = _T(' '); pBuf++; PrintOctalValue(pBuf, address); pBuf += 6; *pBuf = _T(' '); pBuf++; *pBuf = _T(' '); pBuf++; for (int i = 0; i < 8; i++) { PrintOctalValue(pBuf, dump[i]); pBuf += 6; *pBuf = _T(' '); pBuf++; } *pBuf = _T(' '); pBuf++; for (int i = 0; i < 8; i++) { WORD word = dump[i]; BYTE ch1 = LOBYTE(word); TCHAR wch1 = Translate_BK_Unicode(ch1); if (ch1 < 32) wch1 = _T('·'); *pBuf = wch1; pBuf++; BYTE ch2 = HIBYTE(word); TCHAR wch2 = Translate_BK_Unicode(ch2); if (ch2 < 32) wch2 = _T('·'); *pBuf = wch2; pBuf++; } *pBuf++ = _T('\r'); *pBuf++ = _T('\n'); *pBuf = 0; ConsoleView_Print(buffer); address += 16; } } // Print disassembled instructions // Return value: number of words in the last instruction int ConsoleView_PrintDisassemble(CProcessor* pProc, WORD address, BOOL okOneInstr, BOOL okShort) { bool okHaltMode = pProc->IsHaltMode(); const int nWindowSize = 30; WORD memory[nWindowSize + 2]; int addrtype; for (int i = 0; i < nWindowSize + 2; i++) memory[i] = g_pBoard->GetWordView((uint16_t)(address + i * 2), okHaltMode, TRUE, &addrtype); TCHAR bufaddr[7]; TCHAR bufvalue[7]; TCHAR buffer[64]; int lastLength = 0; int length = 0; for (int index = 0; index < nWindowSize; index++) // Рисуем строки { PrintOctalValue(bufaddr, address); WORD value = memory[index]; PrintOctalValue(bufvalue, value); if (length > 0) { if (!okShort) { _sntprintf(buffer, sizeof(buffer) / sizeof(TCHAR) - 1, _T(" %s %s\r\n"), bufaddr, bufvalue); ConsoleView_Print(buffer); } } else { if (okOneInstr && index > 0) break; TCHAR instr[8]; TCHAR args[32]; length = DisassembleInstruction(memory + index, address, instr, args); lastLength = length; if (index + length > nWindowSize) break; if (okShort) _sntprintf(buffer, sizeof(buffer) / sizeof(TCHAR) - 1, _T(" %s %-7s %s\r\n"), bufaddr, instr, args); else _sntprintf(buffer, sizeof(buffer) / sizeof(TCHAR) - 1, _T(" %s %s %-7s %s\r\n"), bufaddr, bufvalue, instr, args); ConsoleView_Print(buffer); } length--; address += 2; } return lastLength; } void ConsoleView_GotoMonitor() { if ((g_nEmulatorConfiguration & BK_COPT_ROM_BASIC) != 0) { ScreenView_KeyEvent(0115, TRUE); // M ScreenView_KeyEvent(0115, FALSE); ScreenView_KeyEvent(0117, TRUE); // O ScreenView_KeyEvent(0117, FALSE); //ScreenView_KeyEvent(0012, TRUE); // ENTER //ScreenView_KeyEvent(0012, FALSE); } else if ((g_nEmulatorConfiguration & BK_COPT_ROM_FOCAL) != 0) { ScreenView_KeyEvent(0120, TRUE); // P ScreenView_KeyEvent(0120, FALSE); ScreenView_KeyEvent(0040, TRUE); // SPACE ScreenView_KeyEvent(0040, FALSE); ScreenView_KeyEvent(0115, TRUE); // M ScreenView_KeyEvent(0115, FALSE); //ScreenView_KeyEvent(0012, TRUE); // ENTER //ScreenView_KeyEvent(0012, FALSE); } SetFocus(g_hwndScreen); // Move focus to the screen } #if !defined(PRODUCT) void ConsoleView_TraceLog(DWORD value) { g_pBoard->SetTrace(value); if (value != TRACE_NONE) ConsoleView_PrintFormat(_T(" Trace ON, trace flags %06o\r\n"), (uint16_t)g_pBoard->GetTrace()); else { ConsoleView_Print(_T(" Trace OFF.\r\n")); DebugLogCloseFile(); } } #endif ////////////////////////////////////////////////////////////////////// // Console commands handlers struct ConsoleCommandParams { LPCTSTR commandText; int paramReg1; uint16_t paramOct1, paramOct2; }; void ConsoleView_CmdShowHelp(const ConsoleCommandParams& /*params*/) { ConsoleView_Print(_T("Console command list:\r\n") _T(" c Clear console log\r\n") _T(" d Disassemble from PC; use D for short format\r\n") _T(" dXXXXXX Disassemble from address XXXXXX\r\n") _T(" g Go; free run\r\n") _T(" gXXXXXX Go; run and stop at address XXXXXX\r\n") _T(" m Memory dump at current address\r\n") _T(" mXXXXXX Memory dump at address XXXXXX\r\n") _T(" mrN Memory dump at address from register N; N=0..7\r\n") _T(" r Show register values\r\n") _T(" rN Show value of register N; N=0..7,ps\r\n") _T(" rN XXXXXX Set register N to value XXXXXX; N=0..7,ps\r\n") _T(" s Step Into; executes one instruction\r\n") _T(" so Step Over; executes and stops after the current instruction\r\n") _T(" b List all breakpoints\r\n") _T(" bXXXXXX Set breakpoint at address XXXXXX\r\n") _T(" bcXXXXXX Remove breakpoint at address XXXXXX\r\n") _T(" bc Remove all breakpoints\r\n") _T(" w List all watches\r\n") _T(" wXXXXXX Set watch at address XXXXXX\r\n") _T(" wcXXXXXX Remove watch at address XXXXXX\r\n") _T(" wc Remove all watches\r\n") _T(" u Save memory dump to file memdump.bin\r\n") _T(" mo Type MO (BASIC) or P M (FOCAL) to exit to Monitor\r\n") #if !defined(PRODUCT) _T(" t Tracing on/off to trace.log file\r\n") _T(" tXXXXXX Set tracing flags\r\n") _T(" tc Clear trace.log file\r\n") #endif ); } void ConsoleView_CmdClearConsoleLog(const ConsoleCommandParams& /*params*/) { ConsoleView_ClearConsole(); } void ConsoleView_CmdPrintRegister(const ConsoleCommandParams& params) { int r = params.paramReg1; LPCTSTR name = REGISTER_NAME[r]; const CProcessor* pProc = ConsoleView_GetCurrentProcessor(); uint16_t value = pProc->GetReg(r); ConsoleView_PrintRegister(name, value); } void ConsoleView_CmdPrintRegisterPSW(const ConsoleCommandParams& /*params*/) { const CProcessor* pProc = ConsoleView_GetCurrentProcessor(); WORD value = pProc->GetPSW(); ConsoleView_PrintRegister(_T("PS"), value); } void ConsoleView_CmdSetRegisterValue(const ConsoleCommandParams& params) { int r = params.paramReg1; uint16_t value = params.paramOct1; CProcessor* pProc = ConsoleView_GetCurrentProcessor(); pProc->SetReg(r, value); MainWindow_UpdateAllViews(); } void ConsoleView_CmdSetRegisterPSW(const ConsoleCommandParams& params) { uint16_t value = params.paramOct1; CProcessor* pProc = ConsoleView_GetCurrentProcessor(); pProc->SetPSW(value); MainWindow_UpdateAllViews(); } void ConsoleView_CmdSaveMemoryDump(const ConsoleCommandParams& /*params*/) { ConsoleView_SaveMemoryDump(); } void ConsoleView_CmdPrintMemoryDumpAtPC(const ConsoleCommandParams& /*params*/) { CProcessor* pProc = ConsoleView_GetCurrentProcessor(); uint16_t address = pProc->GetPC(); ConsoleView_PrintMemoryDump(pProc, address); } void ConsoleView_CmdPrintMemoryDumpAtAddress(const ConsoleCommandParams& params) { uint16_t address = params.paramOct1; CProcessor* pProc = ConsoleView_GetCurrentProcessor(); ConsoleView_PrintMemoryDump(pProc, address); } void ConsoleView_CmdPrintMemoryDumpAtRegister(const ConsoleCommandParams& params) { int r = params.paramReg1; CProcessor* pProc = ConsoleView_GetCurrentProcessor(); uint16_t address = pProc->GetReg(r); ConsoleView_PrintMemoryDump(pProc, address); } void ConsoleView_CmdPrintDisassembleAtPC(const ConsoleCommandParams& params) { BOOL okShort = (params.commandText[0] == _T('D')); CProcessor* pProc = ConsoleView_GetCurrentProcessor(); uint16_t address = pProc->GetPC(); ConsoleView_PrintDisassemble(pProc, address, FALSE, okShort); } void ConsoleView_CmdPrintDisassembleAtAddress(const ConsoleCommandParams& params) { uint16_t address = params.paramOct1; BOOL okShort = (params.commandText[0] == _T('D')); CProcessor* pProc = ConsoleView_GetCurrentProcessor(); ConsoleView_PrintDisassemble(pProc, address, FALSE, okShort); } void ConsoleView_CmdPrintAllRegisters(const ConsoleCommandParams& /*params*/) { CProcessor* pProc = ConsoleView_GetCurrentProcessor(); for (int r = 0; r < 8; r++) { LPCTSTR name = REGISTER_NAME[r]; WORD value = pProc->GetReg(r); ConsoleView_PrintRegister(name, value); } ConsoleView_PrintRegister(_T("PS"), pProc->GetPSW()); } void ConsoleView_CmdStepInto(const ConsoleCommandParams& /*params*/) { CProcessor* pProc = ConsoleView_GetCurrentProcessor(); ConsoleView_PrintDisassemble(pProc, pProc->GetPC(), TRUE, FALSE); g_pBoard->DebugTicks(); MainWindow_UpdateAllViews(); } void ConsoleView_CmdStepOver(const ConsoleCommandParams& /*params*/) { CProcessor* pProc = ConsoleView_GetCurrentProcessor(); int instrLength = ConsoleView_PrintDisassemble(pProc, pProc->GetPC(), TRUE, FALSE); int addrtype; uint16_t instr = g_pBoard->GetWordView(pProc->GetPC(), pProc->IsHaltMode(), true, &addrtype); // For JMP and BR use Step Into logic, not Step Over if ((instr & ~(uint16_t)077) == PI_JMP || (instr & ~(uint16_t)0377) == PI_BR) { g_pBoard->DebugTicks(); MainWindow_UpdateAllViews(); return; } uint16_t bpaddress = (uint16_t)(pProc->GetPC() + instrLength * 2); Emulator_SetTempCPUBreakpoint(bpaddress); Emulator_Start(); } void ConsoleView_CmdRun(const ConsoleCommandParams& /*params*/) { Emulator_Start(); } void ConsoleView_CmdRunToAddress(const ConsoleCommandParams& params) { uint16_t address = params.paramOct1; Emulator_SetTempCPUBreakpoint(address); Emulator_Start(); } void ConsoleView_CmdGotoMonitor(const ConsoleCommandParams& /*params*/) { ConsoleView_GotoMonitor(); } void ConsoleView_CmdPrintAllBreakpoints(const ConsoleCommandParams& /*params*/) { const uint16_t* pbps = Emulator_GetCPUBreakpointList(); if (pbps == nullptr || *pbps == 0177777) { ConsoleView_Print(_T(" No breakpoints.\r\n")); } else { while (*pbps != 0177777) { ConsoleView_PrintFormat(_T(" %06ho\r\n"), *pbps); pbps++; } } } void ConsoleView_CmdRemoveAllBreakpoints(const ConsoleCommandParams& /*params*/) { Emulator_RemoveAllBreakpoints(); DebugView_Redraw(); DisasmView_Redraw(); } void ConsoleView_CmdSetBreakpointAtAddress(const ConsoleCommandParams& params) { uint16_t address = params.paramOct1; bool result = Emulator_AddCPUBreakpoint(address); if (!result) ConsoleView_Print(_T(" Failed to add breakpoint.\r\n")); DebugView_Redraw(); DisasmView_Redraw(); } void ConsoleView_CmdRemoveBreakpointAtAddress(const ConsoleCommandParams& params) { uint16_t address = params.paramOct1; bool result = Emulator_RemoveCPUBreakpoint(address); if (!result) ConsoleView_Print(_T(" Failed to remove breakpoint.\r\n")); DebugView_Redraw(); DisasmView_Redraw(); } void ConsoleView_CmdPrintAllWatches(const ConsoleCommandParams& /*params*/) { CProcessor* pProc = ConsoleView_GetCurrentProcessor(); bool okHaltMode = pProc->IsHaltMode(); const uint16_t* pws = Emulator_GetWatchList(); if (pws == nullptr || *pws == 0177777) { ConsoleView_Print(_T(" No watches defined.\r\n")); } else { while (*pws != 0177777) { uint16_t address = *pws; int addrtype; uint16_t value = g_pBoard->GetWordView(address, okHaltMode, false, &addrtype); ConsoleView_PrintFormat(_T(" %06ho %06ho\r\n"), address, value); pws++; } } } void ConsoleView_CmdSetWatchAtAddress(const ConsoleCommandParams& params) { uint16_t address = params.paramOct1; bool result = Emulator_AddWatch(address); if (!result) ConsoleView_Print(_T(" Failed to add the watch.\r\n")); DebugView_Redraw(); } void ConsoleView_CmdRemoveWatchAtAddress(const ConsoleCommandParams& params) { uint16_t address = params.paramOct1; bool result = Emulator_RemoveWatch(address); if (!result) ConsoleView_Print(_T(" Failed to remove the watch.\r\n")); DebugView_Redraw(); } void ConsoleView_CmdRemoveAllWatches(const ConsoleCommandParams& /*params*/) { Emulator_RemoveAllWatches(); DebugView_Redraw(); } #if !defined(PRODUCT) void ConsoleView_CmdClearTraceLog(const ConsoleCommandParams& /*params*/) { DebugLogClear(); ConsoleView_Print(_T(" Trace log cleared.\r\n")); } void ConsoleView_CmdTraceLogWithMask(const ConsoleCommandParams& params) { ConsoleView_TraceLog(params.paramOct1); } void ConsoleView_CmdTraceLogOnOff(const ConsoleCommandParams& /*params*/) { DWORD dwTrace = (g_pBoard->GetTrace() == TRACE_NONE ? TRACE_ALL : TRACE_NONE); ConsoleView_TraceLog(dwTrace); } #endif ////////////////////////////////////////////////////////////////////// enum ConsoleCommandArgInfo { ARGINFO_NONE, // No parameters ARGINFO_REG, // Register number 0..7 ARGINFO_OCT, // Octal value ARGINFO_REG_OCT, // Register number, octal value ARGINFO_OCT_OCT, // Octal value, octal value }; typedef void(*CONSOLE_COMMAND_CALLBACK)(const ConsoleCommandParams& params); struct ConsoleCommandStruct { LPCTSTR pattern; ConsoleCommandArgInfo arginfo; CONSOLE_COMMAND_CALLBACK callback; } static ConsoleCommands[] = { // IMPORTANT! First list more complex forms with more arguments, then less complex forms { _T("h"), ARGINFO_NONE, ConsoleView_CmdShowHelp }, { _T("c"), ARGINFO_NONE, ConsoleView_CmdClearConsoleLog }, { _T("r%d=%ho"), ARGINFO_REG_OCT, ConsoleView_CmdSetRegisterValue }, { _T("r%d %ho"), ARGINFO_REG_OCT, ConsoleView_CmdSetRegisterValue }, { _T("r%d"), ARGINFO_REG, ConsoleView_CmdPrintRegister }, { _T("r"), ARGINFO_NONE, ConsoleView_CmdPrintAllRegisters }, { _T("rps=%ho"), ARGINFO_OCT, ConsoleView_CmdSetRegisterPSW }, { _T("rps %ho"), ARGINFO_OCT, ConsoleView_CmdSetRegisterPSW }, { _T("rps"), ARGINFO_NONE, ConsoleView_CmdPrintRegisterPSW }, { _T("s"), ARGINFO_NONE, ConsoleView_CmdStepInto }, { _T("so"), ARGINFO_NONE, ConsoleView_CmdStepOver }, { _T("d%ho"), ARGINFO_OCT, ConsoleView_CmdPrintDisassembleAtAddress }, { _T("D%ho"), ARGINFO_OCT, ConsoleView_CmdPrintDisassembleAtAddress }, { _T("d"), ARGINFO_NONE, ConsoleView_CmdPrintDisassembleAtPC }, { _T("D"), ARGINFO_NONE, ConsoleView_CmdPrintDisassembleAtPC }, { _T("u"), ARGINFO_NONE, ConsoleView_CmdSaveMemoryDump }, { _T("m%ho"), ARGINFO_OCT, ConsoleView_CmdPrintMemoryDumpAtAddress }, { _T("mr%d"), ARGINFO_REG, ConsoleView_CmdPrintMemoryDumpAtRegister }, { _T("m"), ARGINFO_NONE, ConsoleView_CmdPrintMemoryDumpAtPC }, { _T("mo"), ARGINFO_NONE, ConsoleView_CmdGotoMonitor }, { _T("g%ho"), ARGINFO_OCT, ConsoleView_CmdRunToAddress }, { _T("g"), ARGINFO_NONE, ConsoleView_CmdRun }, { _T("b%ho"), ARGINFO_OCT, ConsoleView_CmdSetBreakpointAtAddress }, { _T("b"), ARGINFO_NONE, ConsoleView_CmdPrintAllBreakpoints }, { _T("bc%ho"), ARGINFO_OCT, ConsoleView_CmdRemoveBreakpointAtAddress }, { _T("bc"), ARGINFO_NONE, ConsoleView_CmdRemoveAllBreakpoints }, { _T("w%ho"), ARGINFO_OCT, ConsoleView_CmdSetWatchAtAddress }, { _T("w"), ARGINFO_NONE, ConsoleView_CmdPrintAllWatches }, { _T("wc%ho"), ARGINFO_OCT, ConsoleView_CmdRemoveWatchAtAddress }, { _T("wc"), ARGINFO_NONE, ConsoleView_CmdRemoveAllWatches }, #if !defined(PRODUCT) { _T("t%ho"), ARGINFO_OCT, ConsoleView_CmdTraceLogWithMask }, { _T("t"), ARGINFO_NONE, ConsoleView_CmdTraceLogOnOff }, { _T("tc"), ARGINFO_NONE, ConsoleView_CmdClearTraceLog }, #endif }; const size_t ConsoleCommandsCount = sizeof(ConsoleCommands) / sizeof(ConsoleCommands[0]); void ConsoleView_DoConsoleCommand() { // Get command text TCHAR command[32]; GetWindowText(m_hwndConsoleEdit, command, 32); SendMessage(m_hwndConsoleEdit, WM_SETTEXT, 0, (LPARAM)_T("")); // Clear command if (command[0] == 0) return; // Nothing to do // Echo command to the log TCHAR buffer[36]; ::GetWindowText(m_hwndConsolePrompt, buffer, 14); ConsoleView_Print(buffer); _sntprintf(buffer, sizeof(buffer) / sizeof(TCHAR) - 1, _T(" %s\r\n"), command); ConsoleView_Print(buffer); ConsoleCommandParams params; params.commandText = command; params.paramReg1 = -1; params.paramOct1 = 0; params.paramOct2 = 0; // Find matching console command from the list, parse and execute the command bool parsedOkay = false, parseError = false; for (size_t i = 0; i < ConsoleCommandsCount; i++) { ConsoleCommandStruct& cmd = ConsoleCommands[i]; int paramsParsed = 0; switch (cmd.arginfo) { case ARGINFO_NONE: parsedOkay = (_tcscmp(command, cmd.pattern) == 0); break; case ARGINFO_REG: paramsParsed = _sntscanf_s(command, 32, cmd.pattern, ¶ms.paramReg1); parsedOkay = (paramsParsed == 1); if (parsedOkay && params.paramReg1 < 0 || params.paramReg1 > 7) { ConsoleView_Print(MESSAGE_INVALID_REGNUM); parseError = true; } break; case ARGINFO_OCT: paramsParsed = _sntscanf_s(command, 32, cmd.pattern, ¶ms.paramOct1); parsedOkay = (paramsParsed == 1); break; case ARGINFO_REG_OCT: paramsParsed = _sntscanf_s(command, 32, cmd.pattern, ¶ms.paramReg1, ¶ms.paramOct1); parsedOkay = (paramsParsed == 2); if (parsedOkay && params.paramReg1 < 0 || params.paramReg1 > 7) { ConsoleView_Print(MESSAGE_INVALID_REGNUM); parseError = true; } break; case ARGINFO_OCT_OCT: paramsParsed = _sntscanf_s(command, 32, cmd.pattern, ¶ms.paramOct1, ¶ms.paramOct2); parsedOkay = (paramsParsed == 2); break; } if (parseError) break; // Validation detected error and printed the message already if (parsedOkay) { cmd.callback(params); // Execute the command break; } } if (!parsedOkay && !parseError) ConsoleView_Print(MESSAGE_UNKNOWN_COMMAND); ConsoleView_PrintConsolePrompt(); } //////////////////////////////////////////////////////////////////////