1 #include "stdafx.h"
2 #include "qconsoleview.h"
3 #include <QLabel>
4 #include <QLineEdit>
5 #include <QTextEdit>
6 #include <QHBoxLayout>
7 #include <QVBoxLayout>
8 #include "main.h"
9 #include "Emulator.h"
10 #include "emubase/Emubase.h"
11
12 QString QConsoleView::MESSAGE_UNKNOWN_COMMAND;
13 QString QConsoleView::MESSAGE_WRONG_VALUE;
14
QConsoleView()15 QConsoleView::QConsoleView()
16 {
17 MESSAGE_UNKNOWN_COMMAND = QConsoleView::tr(" Unknown command.\r\n");
18 MESSAGE_WRONG_VALUE = QConsoleView::tr(" Wrong value.\r\n");
19
20 m_okCurrentProc = Settings_GetDebugCpuPpu();
21
22 setMinimumSize(320, 120);
23
24 m_log = new QTextEdit();
25 m_prompt = new QLabel();
26 m_edit = new QLineEdit();
27
28 QVBoxLayout *vboxlayout = new QVBoxLayout;
29 vboxlayout->setMargin(0);
30 vboxlayout->setSpacing(4);
31 vboxlayout->addWidget(m_log);
32 QHBoxLayout *hboxlayout = new QHBoxLayout;
33 hboxlayout->addWidget(m_prompt);
34 hboxlayout->addWidget(m_edit);
35 vboxlayout->addLayout(hboxlayout);
36 this->setLayout(vboxlayout);
37
38 QFont font = Common_GetMonospacedFont();
39 m_log->setReadOnly(true);
40 m_log->setFont(font);
41 m_edit->setFont(font);
42
43 QObject::connect(m_edit, SIGNAL(returnPressed()), this, SLOT(execConsoleCommand()));
44
45 this->print(tr("Use 'h' command to show help.\r\n\r\n"));
46 }
47
~QConsoleView()48 QConsoleView::~QConsoleView()
49 {
50 delete m_log;
51 delete m_prompt;
52 delete m_edit;
53 }
54
getCurrentProcessor()55 CProcessor* QConsoleView::getCurrentProcessor()
56 {
57 if (m_okCurrentProc)
58 return g_pBoard->GetCPU();
59 else
60 return g_pBoard->GetPPU();
61 }
62
clear()63 void QConsoleView::clear()
64 {
65 m_log->clear();
66 }
67
setCurrentProc(bool okProc)68 void QConsoleView::setCurrentProc(bool okProc)
69 {
70 m_okCurrentProc = okProc;
71
72 Settings_SetDebugCpuPpu(m_okCurrentProc);
73 }
74
updatePrompt()75 void QConsoleView::updatePrompt()
76 {
77 CProcessor* pProc = this->getCurrentProcessor();
78 if (pProc == nullptr) return;
79 char buffer[15];
80 _snprintf(buffer, 15, " %s:%06o> ", pProc->GetName(), pProc->GetPC());
81 m_prompt->setText(buffer);
82 }
83
print(const QString & message)84 void QConsoleView::print(const QString &message)
85 {
86 m_log->moveCursor(QTextCursor::End);
87 m_log->insertPlainText(message);
88 m_log->moveCursor(QTextCursor::End);
89 }
printLine(const QString & message)90 void QConsoleView::printLine(const QString &message)
91 {
92 m_log->moveCursor(QTextCursor::End);
93 m_log->insertPlainText(message);
94 m_log->insertPlainText("\r\n");
95 m_log->moveCursor(QTextCursor::End);
96 }
97
printConsolePrompt()98 void QConsoleView::printConsolePrompt()
99 {
100 CProcessor* pProc = this->getCurrentProcessor();
101 char buffer[14];
102 _snprintf(buffer, 14, "%s:%06o> ", pProc->GetName(), pProc->GetPC());
103 this->print(buffer);
104 }
105
printRegister(LPCTSTR strName,quint16 value)106 void QConsoleView::printRegister(LPCTSTR strName, quint16 value)
107 {
108 char buffer[31];
109 char* p = buffer;
110 *p++ = ' ';
111 *p++ = ' ';
112 strcpy(p, strName); p += 2;
113 *p++ = ' ';
114 PrintOctalValue(p, value); p += 6;
115 *p++ = ' ';
116 PrintBinaryValue(p, value); p += 16;
117 *p++ = '\r';
118 *p++ = '\n';
119 *p++ = 0;
120 this->print(buffer);
121 }
122
123 // Print memory dump
printMemoryDump(CProcessor * pProc,quint16 address,int lines)124 void QConsoleView::printMemoryDump(CProcessor *pProc, quint16 address, int lines)
125 {
126 address &= ~1; // Line up to even address
127
128 CMemoryController* pMemCtl = pProc->GetMemoryController();
129 bool okHaltMode = pProc->IsHaltMode();
130
131 for (int line = 0; line < lines; line++)
132 {
133 quint16 dump[8];
134 for (int i = 0; i < 8; i++)
135 dump[i] = pMemCtl->GetWord(address + i * 2, okHaltMode, false);
136
137 char buffer[2 + 6 + 2 + 7 * 8 + 1 + 16 + 1 + 2];
138 char* pBuf = buffer;
139 *pBuf = ' '; pBuf++;
140 *pBuf = ' '; pBuf++;
141 PrintOctalValue(pBuf, address); pBuf += 6;
142 *pBuf = ' '; pBuf++;
143 *pBuf = ' '; pBuf++;
144 for (int i = 0; i < 8; i++)
145 {
146 PrintOctalValue(pBuf, dump[i]); pBuf += 6;
147 *pBuf = ' '; pBuf++;
148 }
149 *pBuf = ' '; pBuf++;
150 // for (int i = 0; i < 8; i++) {
151 // quint16 word = dump[i];
152 // quint8 ch1 = LOBYTE(word);
153 // char wch1 = Translate_BK_Unicode(ch1);
154 // if (ch1 < 32) wch1 = '·';
155 // *pBuf = wch1; pBuf++;
156 // quint8 ch2 = HIBYTE(word);
157 // char wch2 = Translate_BK_Unicode(ch2);
158 // if (ch2 < 32) wch2 = '·';
159 // *pBuf = wch2; pBuf++;
160 // }
161 *pBuf++ = '\r';
162 *pBuf++ = '\n';
163 *pBuf = 0;
164
165 this->print(buffer);
166
167 address += 16;
168 }
169 }
170
171 // Print disassembled instructions
172 // Return value: number of words disassembled
printDisassemble(CProcessor * pProc,quint16 address,bool okOneInstr,bool okShort)173 int QConsoleView::printDisassemble(CProcessor* pProc, quint16 address, bool okOneInstr, bool okShort)
174 {
175 CMemoryController* pMemCtl = pProc->GetMemoryController();
176 bool okHaltMode = pProc->IsHaltMode();
177
178 const int nWindowSize = 30;
179 quint16 memory[nWindowSize + 2];
180 int addrtype;
181 for (int i = 0; i < nWindowSize + 2; i++)
182 memory[i] = pMemCtl->GetWordView(address + i * 2, okHaltMode, true, &addrtype);
183
184 char bufaddr[7];
185 char bufvalue[7];
186 char buffer[64];
187
188 int totalLength = 0;
189 int lastLength = 0;
190 int length = 0;
191 for (int index = 0; index < nWindowSize; index++) // Draw strings
192 {
193 PrintOctalValue(bufaddr, address);
194 quint16 value = memory[index];
195 PrintOctalValue(bufvalue, value);
196
197 if (length > 0)
198 {
199 if (!okShort)
200 {
201 _snprintf(buffer, 64, " %s %s\r\n", bufaddr, bufvalue);
202 this->print(buffer);
203 }
204 }
205 else
206 {
207 if (okOneInstr && index > 0)
208 break;
209 char instr[8];
210 char args[32];
211 length = DisassembleInstruction(memory + index, address, instr, args);
212 lastLength = length;
213 if (index + length > nWindowSize)
214 break;
215 if (okShort)
216 _snprintf(buffer, 64, " %s %-7s %s\r\n", bufaddr, instr, args);
217 else
218 _snprintf(buffer, 64, " %s %s %-7s %s\r\n", bufaddr, bufvalue, instr, args);
219 this->print(buffer);
220 }
221 length--;
222 address += 2;
223 totalLength++;
224 }
225
226 return totalLength;
227 }
228
printHelp()229 void QConsoleView::printHelp()
230 {
231 this->print(tr("Console command list:\r\n"
232 " c Clear console log\r\n"
233 " dXXXXXX Disassemble from address XXXXXX\r\n"
234 " g Go; free run\r\n"
235 " gXXXXXX Go; run processor until breakpoint at address XXXXXX\r\n"
236 " m Memory dump at current address\r\n"
237 " mXXXXXX Memory dump at address XXXXXX\r\n"
238 " mrN Memory dump at address from register N; N=0..7\r\n"
239 " p Switch to other processor\r\n"
240 " r Show register values\r\n"
241 " rN Show value of register N; N=0..7,ps\r\n"
242 " rN XXXXXX Set register N to value XXXXXX; N=0..7,ps\r\n"
243 " s Step Into; executes one instruction\r\n"
244 " so Step Over; executes and stops after the current instruction\r\n"
245 " b List breakpoints set for the current processor\r\n"
246 " bXXXXXX Set breakpoint at address XXXXXX\r\n"
247 " bcXXXXXX Remove breakpoint at address XXXXXX\r\n"
248 " bc Remove all breakpoints for the current processor\r\n"
249 // " u Save memory dump to file memdumpXPU.bin\r\n"
250 ));
251 }
252
execConsoleCommand()253 void QConsoleView::execConsoleCommand()
254 {
255 QString command = m_edit->text();
256 m_edit->clear();
257 this->execConsoleCommand(command);
258 }
259
execConsoleCommand(const QString & command)260 void QConsoleView::execConsoleCommand(const QString &command)
261 {
262 if (command.isNull() || command.isEmpty()) return; // Nothing to do
263 if (g_okEmulatorRunning) return;
264
265 // Echo command to the log
266 this->printConsolePrompt();
267 this->printLine(command);
268
269 bool okUpdateAllViews = false; // Flag - need to update all debug views
270 bool okUpdateMenu = false; // Flag - need to update main menu
271 CProcessor* pProc = this->getCurrentProcessor();
272
273 // Execute the command
274 if (command == "h")
275 {
276 this->printHelp();
277 }
278 else if (command == "c") // Clear log
279 {
280 this->clear();
281 }
282 else if (command == "p") // Switch CPU/PPU
283 {
284 Global_SetCurrentProc(! m_okCurrentProc);
285 okUpdateAllViews = true;
286 }
287 else if (command.startsWith("r")) // Register operations
288 {
289 if (command.length() == 1) // Print all registers
290 {
291 for (int r = 0; r < 8; r++)
292 {
293 LPCTSTR name = REGISTER_NAME[r];
294 quint16 value = pProc->GetReg(r);
295 this->printRegister(name, value);
296 }
297 }
298 else if (command[1].toLatin1() >= '0' && command[1].toLatin1() <= '7') // "r0".."r7"
299 {
300 int r = command[1].toLatin1() - '0';
301 LPCTSTR name = REGISTER_NAME[r];
302 if (command.length() == 2) // "rN" - show register N
303 {
304 quint16 value = pProc->GetReg(r);
305 this->printRegister(name, value);
306 }
307 else if (command[2].toLatin1() == '=' || command[2].toLatin1() == ' ') // "rN=XXXXXX" - set register N to value XXXXXX
308 {
309 quint16 value;
310 if (! ParseOctalValue(command.mid(3), &value))
311 this->print(MESSAGE_WRONG_VALUE);
312 else
313 {
314 pProc->SetReg(r, value);
315 this->printRegister(name, value);
316 okUpdateAllViews = true;
317 }
318 }
319 else
320 this->print(MESSAGE_UNKNOWN_COMMAND);
321 }
322 else if (command.startsWith("rps")) // "rps"
323 {
324 if (command.length() == 3) // "rps" - show PSW
325 {
326 quint16 value = pProc->GetPSW();
327 this->printRegister("PS", value);
328 }
329 else if (command[3].toLatin1() == '=' || command[3].toLatin1() == ' ') // "rps=XXXXXX" - set PSW to value XXXXXX
330 {
331 quint16 value;
332 if (! ParseOctalValue(command.mid(4), &value))
333 this->print(MESSAGE_WRONG_VALUE);
334 else
335 {
336 pProc->SetPSW(value);
337 this->printRegister("PS", value);
338 okUpdateAllViews = true;
339 }
340 }
341 else
342 this->print(MESSAGE_UNKNOWN_COMMAND);
343 }
344 else
345 this->print(MESSAGE_UNKNOWN_COMMAND);
346 }
347 else if (command == "s") // "s" - Step Into, execute one instruction
348 {
349 this->printDisassemble(pProc, pProc->GetPC(), true, false);
350
351 //pProc->Execute();
352 g_pBoard->DebugTicks();
353
354 okUpdateAllViews = true;
355 }
356 else if (command == "so") // "so" - Step Over
357 {
358 int instrLength = this->printDisassemble(pProc, pProc->GetPC(), true, false);
359 quint16 bpaddress = pProc->GetPC() + instrLength * 2;
360
361 if (m_okCurrentProc)
362 Emulator_SetTempCPUBreakpoint(bpaddress);
363 else
364 Emulator_SetTempPPUBreakpoint(bpaddress);
365 Emulator_Start();
366
367 okUpdateMenu = true;
368 }
369 else if (command.startsWith("d") || // Disassemble
370 command.startsWith("D")) // Disassemble, short format
371 {
372 bool okShort = (command[0] == 'D');
373 quint16 address = 0;
374 bool okValidAddress = false;
375 if (command.length() == 1) // "d" - disassemble at current address
376 {
377 address = pProc->GetPC();
378 okValidAddress = true;
379 }
380 else if (command[1].toLatin1() >= '0' && command[1].toLatin1() <= '7') // "dXXXXXX" - disassemble at address XXXXXX
381 {
382 if (! ParseOctalValue(command.mid(1), &address))
383 this->print(MESSAGE_WRONG_VALUE);
384 else
385 okValidAddress = true;
386 }
387 else
388 {
389 this->print(MESSAGE_UNKNOWN_COMMAND);
390 }
391
392 if (okValidAddress)
393 {
394 int length = this->printDisassemble(pProc, address, false, okShort);
395 address += length * 2;
396 QString prompt; prompt.sprintf("%c%06o", command[0], address);
397 m_edit->setText(prompt);
398 }
399 }
400 else if (command.startsWith("m"))
401 {
402 if (command.length() == 1) // "m" - dump memory at current address
403 {
404 this->printMemoryDump(pProc, pProc->GetPC(), 8);
405 }
406 else if (command[1].toLatin1() >= '0' && command[1].toLatin1() <= '7') // "mXXXXXX" - dump memory at address XXXXXX
407 {
408 quint16 value;
409 if (! ParseOctalValue(command.mid(1), &value))
410 this->print(MESSAGE_WRONG_VALUE);
411 else
412 this->printMemoryDump(pProc, value, 8);
413 }
414 else if (command[1].toLatin1() == 'r' && command.length() >= 3 &&
415 command[2].toLatin1() >= '0' && command[2].toLatin1() <= '7') // "mrN" - dump memory at address from register N
416 {
417 int r = command[2].toLatin1() - '0';
418 quint16 address = pProc->GetReg(r);
419 this->printMemoryDump(pProc, address, 8);
420 }
421 else
422 this->print(MESSAGE_UNKNOWN_COMMAND);
423 //TODO: "mXXXXXX YYYYYY" - set memory cell at XXXXXX to value YYYYYY
424 //TODO: "mrN YYYYYY" - set memory cell at address from rN to value YYYYYY
425 }
426 else if (command == "g") // Go
427 {
428 Emulator_Start();
429 okUpdateAllViews = true;
430 }
431 else if (command.startsWith("g")) // Go
432 {
433 quint16 value;
434 if (! ParseOctalValue(command.mid(1), &value))
435 this->print(MESSAGE_WRONG_VALUE);
436 else
437 {
438 if (m_okCurrentProc)
439 Emulator_SetTempCPUBreakpoint(value);
440 else
441 Emulator_SetTempPPUBreakpoint(value);
442 Emulator_Start();
443
444 okUpdateMenu = true;
445 }
446 }
447 else if (command == "b") // b - list breakpoints
448 {
449 const quint16* pbps = m_okCurrentProc ? Emulator_GetCPUBreakpointList() : Emulator_GetPPUBreakpointList();
450 if (pbps == nullptr || *pbps == 0177777)
451 {
452 this->print(" No breakpoints.\r\n");
453 }
454 else
455 {
456 while (*pbps != 0177777)
457 {
458 QString line; line.sprintf(" %06ho\r\n", *pbps);
459 this->print(line);
460 pbps++;
461 }
462 }
463 }
464 else if (command == "bc") // bc - remove all breakpoints
465 {
466 Emulator_RemoveAllBreakpoints(m_okCurrentProc);
467 Global_RedrawDebugView();
468 Global_RedrawDisasmView();
469 }
470 else if (command.startsWith("bc")) // bcXXXXXX - remove breakpoint
471 {
472 quint16 value;
473 if (! ParseOctalValue(command.mid(2), &value))
474 this->print(MESSAGE_WRONG_VALUE);
475 else
476 {
477 bool result = m_okCurrentProc ? Emulator_RemoveCPUBreakpoint(value) : Emulator_RemovePPUBreakpoint(value);
478 if (!result)
479 this->print(" Failed to remove breakpoint.\r\n");
480 Global_RedrawDebugView();
481 Global_RedrawDisasmView();
482 }
483 }
484 else if (command.startsWith("b")) // bXXXXXX - add breakpoint
485 {
486 quint16 value;
487 if (! ParseOctalValue(command.mid(1), &value))
488 this->print(MESSAGE_WRONG_VALUE);
489 else
490 {
491 bool result = m_okCurrentProc ? Emulator_AddCPUBreakpoint(value) : Emulator_AddPPUBreakpoint(value);
492 if (!result)
493 this->print(" Failed to add breakpoint.\r\n");
494 Global_RedrawDebugView();
495 Global_RedrawDisasmView();
496 }
497 }
498 else
499 {
500 this->print(MESSAGE_UNKNOWN_COMMAND);
501 }
502
503 if (okUpdateAllViews)
504 Global_UpdateAllViews();
505 else if (okUpdateMenu)
506 Global_UpdateMenu();
507 }
508