2 Skelton for retropc emulator
4 Author : K.Ohta <whatisthis.sowhat _at_ gmail.com>
6 History: 09 Apr, 2015 : Initial from Takeda.Toshiya's w32_debugger.cpp.
13 //#include "res/resource.h"
14 #include "../../emu.h"
15 #include "../../vm/device.h"
16 #include "../../vm/debugger.h"
17 #include "../../vm/vm.h"
18 #include "../../fileio.h"
20 #include "qt_debugger.h"
22 #include <QMainWindow>
23 #include "../../qt/3rdparty/qtermwidget/lib/qtermwidget.h"
27 void my_printf(FILE *hStdOut, const _TCHAR *format, ...)
34 _vstprintf_s(buffer, 4096, format, ap);
37 fputs(buffer, hStdOut);
40 void my_putch(FILE *hStdOut, _TCHAR c)
47 uint32 my_hexatoi(_TCHAR *str)
51 if(str == NULL || strlen(str) == 0) {
53 } else if(strlen(str) == 3 && str[0] == _T('\'') && str[2] == _T('\'')) {
56 } else if((s = strstr(str, _T(":"))) != NULL) {
59 return (my_hexatoi(str) << 4) + my_hexatoi(s + 1);
60 } else if(str[0] == _T('%')) {
64 return strtol(str, NULL, 16);
67 break_point_t *get_break_point(DEBUGGER *debugger, _TCHAR *command)
69 if(command[0] == _T('B') || command[0] == _T('b')) {
71 } else if(command[0] == _T('R') || command[0] == _T('r')) {
72 return &debugger->rbp;
73 } else if(command[0] == _T('W') || command[0] == _T('w')) {
74 return &debugger->wbp;
75 } else if(command[0] == _T('I') || command[0] == _T('i')) {
76 return &debugger->ibp;
77 } else if(command[0] == _T('O') || command[0] == _T('o')) {
78 return &debugger->obp;
84 void Sleep(uint32_t tick)
86 QThread::msleep(tick);
89 int debugger_main(void *debugger_)
92 volatile debugger_thread_t *p = (debugger_thread_t *)debugger_;
95 DEVICE *cpu = p->vm->get_cpu(p->cpu_index);
96 DEBUGGER *debugger = (DEBUGGER *)cpu->get_debugger();
98 debugger->now_going = false;
99 debugger->now_debugging = true;
100 //while(!debugger->now_suspended) {
104 uint32 prog_addr_mask = cpu->debug_prog_addr_mask();
105 uint32 data_addr_mask = cpu->debug_data_addr_mask();
106 uint32 dump_addr = 0;
107 uint32 dasm_addr = cpu->get_next_pc();
109 // initialize console
111 snprintf(buffer, 1024, _T("Debugger - %s"), _T(DEVICE_NAME));
113 //SetConsoleTitle(buffer);
115 FILE *hStdIn = stdin;
116 FILE *hStdOut = stdout;
117 bool cp932 = false; //(GetConsoleCP() == 932);
123 // Now, pure write to stdin / stdout. Will implement with Qt widget. (20150409)
124 //SetConsoleScreenBufferSize(hStdOut, coord);
125 //SetConsoleTextAttribute(hStdOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
126 //RemoveMenu(GetSystemMenu(GetConsoleWindow(), FALSE), SC_CLOSE, MF_BYCOMMAND);
128 //SetConsoleTextAttribute(hStdOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
129 cpu->debug_regs_info(buffer, 1024);
130 my_printf(hStdOut, _T("%s\n"), buffer);
132 //SetConsoleTextAttribute(hStdOut, FOREGROUND_RED | FOREGROUND_INTENSITY);
133 my_printf(hStdOut, _T("breaked at %08X\n"), cpu->get_next_pc());
135 //SetConsoleTextAttribute(hStdOut, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
136 cpu->debug_dasm(cpu->get_next_pc(), buffer, 1024);
137 my_printf(hStdOut, _T("next\t%08X %s\n"), cpu->get_next_pc(), buffer);
138 //SetConsoleTextAttribute(hStdOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
140 #define MAX_COMMAND_LEN 64
142 _TCHAR command[MAX_COMMAND_LEN + 1];
143 _TCHAR prev_command[MAX_COMMAND_LEN + 1];
145 memset(prev_command, 0, sizeof(prev_command));
148 while(!p->request_terminate) {
149 my_printf(hStdOut, _T("- "));
153 bool enter_done = false;
155 while(!p->request_terminate && !enter_done) {
160 if(fgets(ir, 32, hStdIn) != NULL) {
162 for(unsigned int i = 0; i < dwRead; i++) {
164 if(chr == 0x0d || chr == 0x0a) {
165 if(ptr == 0 && prev_command[0] != _T('\0')) {
166 memcpy(command, prev_command, sizeof(command));
167 my_printf(hStdOut, _T("%s\n"), command);
171 command[ptr] = _T('\0');
172 memcpy(prev_command, command, sizeof(command));
173 my_printf(hStdOut, _T("\n"));
177 } else if(chr == 0x08) {
180 my_putch(hStdOut, chr);
181 my_putch(hStdOut, _T(' '));
182 my_putch(hStdOut, chr);
184 } else if(chr >= 0x20 && chr <= 0x7e && ptr < MAX_COMMAND_LEN && !(chr == 0x20 && ptr == 0)) {
185 command[ptr++] = chr;
186 my_putch(hStdOut, chr);
198 if(!p->request_terminate && enter_done) {
199 _TCHAR *params[32], *token = NULL, *context = NULL;
202 if((token = strtok_r(command, _T(" "), &context)) != NULL) {
203 params[num++] = token;
204 while(num < 32 && (token = strtok_r(NULL, _T(" "), &context)) != NULL) {
205 params[num++] = token;
208 if(strcasecmp(params[0], _T("D")) == 0) {
210 uint32 start_addr = dump_addr;
212 start_addr = my_hexatoi(params[1]);
214 start_addr &= data_addr_mask;
216 uint32 end_addr = start_addr + 8 * 16 - 1;
218 end_addr = my_hexatoi(params[2]);
220 end_addr &= data_addr_mask;
222 if(start_addr > end_addr) {
223 end_addr = data_addr_mask;
225 for(uint64 addr = start_addr & ~0x0f; addr <= end_addr; addr++) {
226 if(addr > data_addr_mask) {
227 end_addr = data_addr_mask;
230 if((addr & 0x0f) == 0) {
231 my_printf(hStdOut, _T("%08X "), addr & data_addr_mask);
232 memset(buffer, 0, sizeof(buffer));
234 if(addr < start_addr) {
235 my_printf(hStdOut, _T(" "));
236 buffer[addr & 0x0f] = _T(' ');
238 uint32 data = cpu->debug_read_data8(addr & data_addr_mask);
239 my_printf(hStdOut, _T(" %02X"), data);
240 buffer[addr & 0x0f] = ((data >= 0x20 && data <= 0x7e) || (cp932 && data >= 0xa1 && data <= 0xdf)) ? data : _T('.');
242 if((addr & 0x0f) == 0x0f) {
243 my_printf(hStdOut, _T(" %s\n"), buffer);
246 if((end_addr & 0x0f) != 0x0f) {
247 for(uint32 addr = (end_addr & 0x0f) + 1; addr <= 0x0f; addr++) {
248 my_printf(hStdOut, _T(" "));
250 my_printf(hStdOut, _T(" %s\n"), buffer);
252 dump_addr = (end_addr + 1) & data_addr_mask;
253 prev_command[1] = _T('\0'); // remove parameters to dump continuously
255 my_printf(hStdOut, _T("invalid parameter number\n"));
257 } else if(strcasecmp(params[0], _T("E")) == 0 || strcasecmp(params[0], _T("EB")) == 0) {
259 uint32 addr = my_hexatoi(params[1]) & data_addr_mask;
260 for(int i = 2; i < num; i++) {
261 cpu->debug_write_data8(addr, my_hexatoi(params[i]) & 0xff);
262 addr = (addr + 1) & data_addr_mask;
265 my_printf(hStdOut, _T("invalid parameter number\n"));
267 } else if(strcasecmp(params[0], _T("EW")) == 0) {
269 uint32 addr = my_hexatoi(params[1]) & data_addr_mask;
270 for(int i = 2; i < num; i++) {
271 cpu->debug_write_data16(addr, my_hexatoi(params[i]) & 0xffff);
272 addr = (addr + 2) & data_addr_mask;
275 my_printf(hStdOut, _T("invalid parameter number\n"));
277 } else if(strcasecmp(params[0], _T("ED")) == 0) {
279 uint32 addr = my_hexatoi(params[1]) & data_addr_mask;
280 for(int i = 2; i < num; i++) {
281 cpu->debug_write_data32(addr, my_hexatoi(params[i]));
282 addr = (addr + 4) & data_addr_mask;
285 my_printf(hStdOut, _T("invalid parameter number\n"));
287 } else if(strcasecmp(params[0], _T("EA")) == 0) {
289 uint32 addr = my_hexatoi(params[1]) & data_addr_mask;
290 strncpy(buffer, prev_command, 1024);
291 if((token = strtok_r(buffer, _T("\""), &context)) != NULL && (token = strtok_r(NULL, _T("\""), &context)) != NULL) {
292 int len = strlen(token);
293 for(int i = 0; i < len; i++) {
294 cpu->debug_write_data8(addr, token[i] & 0xff);
295 addr = (addr + 1) & data_addr_mask;
298 my_printf(hStdOut, _T("invalid parameter\n"));
301 my_printf(hStdOut, _T("invalid parameter number\n"));
303 } else if(strcasecmp(params[0], _T("I")) == 0 || strcasecmp(params[0], _T("IB")) == 0) {
305 my_printf(hStdOut, _T("%02X\n"), cpu->debug_read_io8(my_hexatoi(params[1])) & 0xff);
307 my_printf(hStdOut, _T("invalid parameter number\n"));
309 } else if(strcasecmp(params[0], _T("IW")) == 0) {
311 my_printf(hStdOut, _T("%02X\n"), cpu->debug_read_io16(my_hexatoi(params[1])) & 0xffff);
313 my_printf(hStdOut, _T("invalid parameter number\n"));
315 } else if(strcasecmp(params[0], _T("ID")) == 0) {
317 my_printf(hStdOut, _T("%02X\n"), cpu->debug_read_io32(my_hexatoi(params[1])));
319 my_printf(hStdOut, _T("invalid parameter number\n"));
321 } else if(strcasecmp(params[0], _T("O")) == 0 || strcasecmp(params[0], _T("OB")) == 0) {
323 cpu->debug_write_io8(my_hexatoi(params[1]), my_hexatoi(params[2]) & 0xff);
325 my_printf(hStdOut, _T("invalid parameter number\n"));
327 } else if(strcasecmp(params[0], _T("OW")) == 0) {
329 cpu->debug_write_io16(my_hexatoi(params[1]), my_hexatoi(params[2]) & 0xffff);
331 my_printf(hStdOut, _T("invalid parameter number\n"));
333 } else if(strcasecmp(params[0], _T("OD")) == 0) {
335 cpu->debug_write_io32(my_hexatoi(params[1]), my_hexatoi(params[2]));
337 my_printf(hStdOut, _T("invalid parameter number\n"));
339 } else if(strcasecmp(params[0], _T("R")) == 0) {
341 cpu->debug_regs_info(buffer, 1024);
342 my_printf(hStdOut, _T("%s\n"), buffer);
343 } else if(num == 3) {
344 if(!cpu->debug_write_reg(params[1], my_hexatoi(params[2]))) {
345 my_printf(hStdOut, _T("unknown register %s\n"), params[1]);
348 my_printf(hStdOut, _T("invalid parameter number\n"));
350 } else if(strcasecmp(params[0], _T("S")) == 0) {
352 uint32 start_addr = my_hexatoi(params[1]) & data_addr_mask;
353 uint32 end_addr = my_hexatoi(params[2]) & data_addr_mask;
355 for(int i = 3, j = 0; i < num; i++, j++) {
356 list[j] = my_hexatoi(params[i]);
358 for(uint64 addr = start_addr; addr <= end_addr; addr++) {
360 for(int i = 3, j = 0; i < num; i++, j++) {
361 if(cpu->debug_read_data8((addr + j) & data_addr_mask) != list[j]) {
367 my_printf(hStdOut, _T("%08X\n"), addr);
371 my_printf(hStdOut, _T("invalid parameter number\n"));
373 } else if(strcasecmp(params[0], _T("U")) == 0) {
376 dasm_addr = my_hexatoi(params[1]) & prog_addr_mask;
379 uint32 end_addr = my_hexatoi(params[2]) & prog_addr_mask;
380 while(dasm_addr <= end_addr) {
381 int len = cpu->debug_dasm(dasm_addr, buffer, 1024);
382 my_printf(hStdOut, _T("%08X %s\n"), dasm_addr, buffer);
383 dasm_addr = (dasm_addr + len) & prog_addr_mask;
386 for(int i = 0; i < 16; i++) {
387 int len = cpu->debug_dasm(dasm_addr, buffer, 1024);
388 my_printf(hStdOut, _T("%08X %s\n"), dasm_addr, buffer);
389 dasm_addr = (dasm_addr + len) & prog_addr_mask;
392 prev_command[1] = _T('\0'); // remove parameters to disassemble continuously
394 my_printf(hStdOut, _T("invalid parameter number\n"));
396 } else if(strcasecmp(params[0], _T("H")) == 0) {
398 uint32 l = my_hexatoi(params[1]);
399 uint32 r = my_hexatoi(params[2]);
400 my_printf(hStdOut, _T("%08X %08X\n"), l + r, l - r);
402 my_printf(hStdOut, _T("invalid parameter number\n"));
404 } else if(strcasecmp(params[0], _T("N")) == 0) {
405 if(num >= 2 && params[1][0] == _T('\"')) {
406 strncpy(buffer, prev_command, 1024);
407 if((token = strtok_r(buffer, _T("\""), &context)) != NULL && (token = strtok_r(NULL, _T("\""), &context)) != NULL) {
408 strncpy(debugger->file_path, token, _MAX_PATH);
410 my_printf(hStdOut, _T("invalid parameter\n"));
412 } else if(num == 2) {
413 strncpy(debugger->file_path, params[1], _MAX_PATH);
415 my_printf(hStdOut, _T("invalid parameter number\n"));
417 } else if(strcasecmp(params[0], _T("L")) == 0) {
419 uint32 start_addr = my_hexatoi(params[1]) & data_addr_mask, end_addr = my_hexatoi(params[2]) & data_addr_mask;
420 FILEIO* fio = new FILEIO();
421 if(fio->Fopen(debugger->file_path, FILEIO_READ_BINARY)) {
422 for(uint32 addr = start_addr; addr <= end_addr; addr++) {
423 int data = fio->Fgetc();
427 cpu->debug_write_data8(addr & data_addr_mask, data);
431 my_printf(hStdOut, _T("can't open %s\n"), debugger->file_path);
435 my_printf(hStdOut, _T("invalid parameter number\n"));
437 } else if(strcasecmp(params[0], _T("W")) == 0) {
439 uint32 start_addr = my_hexatoi(params[1]) & data_addr_mask, end_addr = my_hexatoi(params[2]) & data_addr_mask;
440 FILEIO* fio = new FILEIO();
441 if(fio->Fopen(debugger->file_path, FILEIO_WRITE_BINARY)) {
442 for(uint32 addr = start_addr; addr <= end_addr; addr++) {
443 fio->Fputc(cpu->debug_read_data8(addr & data_addr_mask));
447 my_printf(hStdOut, _T("can't open %s\n"), debugger->file_path);
451 my_printf(hStdOut, _T("invalid parameter number\n"));
453 } else if(strcasecmp(params[0], _T( "BP")) == 0 || strcasecmp(params[0], _T("RBP")) == 0 || strcasecmp(params[0], _T("WBP")) == 0) {
454 break_point_t *bp = get_break_point(debugger, params[0]);
456 uint32 addr = my_hexatoi(params[1]);
458 for(int i = 0; i < MAX_BREAK_POINTS && !found; i++) {
459 if(bp->table[i].status == 0 || (bp->table[i].addr == addr && bp->table[i].mask == prog_addr_mask)) {
460 bp->table[i].addr = addr;
461 bp->table[i].mask = prog_addr_mask;
462 bp->table[i].status = 1;
467 my_printf(hStdOut, _T("too many break points\n"));
470 my_printf(hStdOut, _T("invalid parameter number\n"));
472 } else if(strcasecmp(params[0], _T("IBP")) == 0 || strcasecmp(params[0], _T("OBP")) == 0) {
473 break_point_t *bp = get_break_point(debugger, params[0]);
474 if(num == 2 || num == 3) {
475 uint32 addr = my_hexatoi(params[1]), mask = 0xff;
477 mask = my_hexatoi(params[2]);
480 for(int i = 0; i < MAX_BREAK_POINTS && !found; i++) {
481 if(bp->table[i].status == 0 || (bp->table[i].addr == addr && bp->table[i].mask == mask)) {
482 bp->table[i].addr = addr;
483 bp->table[i].mask = mask;
484 bp->table[i].status = 1;
489 my_printf(hStdOut, _T("too many break points\n"));
492 my_printf(hStdOut, _T("invalid parameter number\n"));
494 } else if(strcasecmp(params[0], _T("BC")) == 0 || strcasecmp(params[0], _T("RBC")) == 0 || strcasecmp(params[0], _T("WBC")) == 0 || strcasecmp(params[0], _T("IBC")) == 0 || strcasecmp(params[0], _T("OBC")) == 0) {
495 break_point_t *bp = get_break_point(debugger, params[0]);
496 if(num == 2 && strcasecmp(params[1], _T("ALL")) == 0) {
497 memset(bp->table, 0, sizeof(bp->table));
498 } else if(num >= 2) {
499 for(int i = 1; i < num; i++) {
500 int index = my_hexatoi(params[i]);
501 if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
502 my_printf(hStdOut, _T("invalid index %x\n"), index);
504 bp->table[index - 1].addr = bp->table[index - 1].mask = 0;
505 bp->table[index - 1].status = 0;
509 my_printf(hStdOut, _T("invalid parameter number\n"));
511 } else if(strcasecmp(params[0], _T("BD")) == 0 || strcasecmp(params[0], _T("RBD")) == 0 || strcasecmp(params[0], _T("WBD")) == 0 || strcasecmp(params[0], _T("IBD")) == 0 || strcasecmp(params[0], _T("OBD")) == 0 ||
512 strcasecmp(params[0], _T("BE")) == 0 || strcasecmp(params[0], _T("RBE")) == 0 || strcasecmp(params[0], _T("WBE")) == 0 || strcasecmp(params[0], _T("IBE")) == 0 || strcasecmp(params[0], _T("OBE")) == 0) {
513 break_point_t *bp = get_break_point(debugger, params[0]);
514 bool enabled = (params[0][1] == _T('E') || params[0][1] == _T('e') || params[0][2] == _T('E') || params[0][2] == _T('e'));
515 if(num == 2 && strcasecmp(params[1], _T("ALL")) == 0) {
516 for(int i = 0; i < MAX_BREAK_POINTS; i++) {
517 if(bp->table[i].status != 0) {
518 bp->table[i].status = enabled ? 1 : -1;
521 } else if(num >= 2) {
522 for(int i = 1; i < num; i++) {
523 int index = my_hexatoi(params[i]);
524 if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
525 my_printf(hStdOut, _T("invalid index %x\n"), index);
526 } else if(bp->table[index - 1].status == 0) {
527 my_printf(hStdOut, _T("break point %x is null\n"), index);
529 bp->table[index - 1].status = enabled ? 1 : -1;
533 my_printf(hStdOut, _T("invalid parameter number\n"));
535 } else if(strcasecmp(params[0], _T("BL")) == 0 || strcasecmp(params[0], _T("RBL")) == 0 || strcasecmp(params[0], _T("WBL")) == 0) {
537 break_point_t *bp = get_break_point(debugger, params[0]);
538 for(int i = 0; i < MAX_BREAK_POINTS; i++) {
539 if(bp->table[i].status) {
540 my_printf(hStdOut, _T("%d %c %08X\n"), i + 1, bp->table[i].status == 1 ? _T('e') : _T('d'), bp->table[i].addr);
544 my_printf(hStdOut, _T("invalid parameter number\n"));
546 } else if(strcasecmp(params[0], _T("IBL")) == 0 || strcasecmp(params[0], _T("OBL")) == 0) {
548 break_point_t *bp = get_break_point(debugger, params[0]);
549 for(int i = 0; i < MAX_BREAK_POINTS; i++) {
550 if(bp->table[i].status) {
551 my_printf(hStdOut, _T("%d %c %08X %08X\n"), i + 1, bp->table[i].status == 1 ? _T('e') : _T('d'), bp->table[i].addr, bp->table[i].mask);
555 my_printf(hStdOut, _T("invalid parameter number\n"));
557 } else if(strcasecmp(params[0], _T("G")) == 0) {
558 if(num == 1 || num == 2) {
560 debugger->store_break_points();
561 debugger->bp.table[0].addr = my_hexatoi(params[1]) & prog_addr_mask;
562 debugger->bp.table[0].mask = prog_addr_mask;
563 debugger->bp.table[0].status = 1;
565 debugger->now_going = true;
566 debugger->now_suspended = false;
567 while(!p->request_terminate && !debugger->now_suspended) {
568 // if((GetAsyncKeyState(VK_ESCAPE) & 0x8000) != 0) {
574 debugger->now_going = false;
575 while(!p->request_terminate && !debugger->now_suspended) {
578 dasm_addr = cpu->get_next_pc();
580 ////SetConsoleTextAttribute(hStdOut, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
581 cpu->debug_dasm(cpu->get_pc(), buffer, 1024);
582 my_printf(hStdOut, _T("done\t%08X %s\n"), cpu->get_pc(), buffer);
584 ////SetConsoleTextAttribute(hStdOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
585 cpu->debug_regs_info(buffer, 1024);
586 my_printf(hStdOut, _T("%s\n"), buffer);
588 if(debugger->hit()) {
589 ////SetConsoleTextAttribute(hStdOut, FOREGROUND_RED | FOREGROUND_INTENSITY);
590 if(debugger->bp.hit) {
591 my_printf(hStdOut, _T("breaked at %08X\n"), cpu->get_next_pc());
592 } else if(debugger->rbp.hit) {
593 my_printf(hStdOut, _T("breaked at %08X: memory %08X was read at %08X\n"), cpu->get_next_pc(), debugger->rbp.hit_addr, cpu->get_pc());
594 } else if(debugger->wbp.hit) {
595 my_printf(hStdOut, _T("breaked at %08X: memory %08X was written at %08X\n"), cpu->get_next_pc(), debugger->wbp.hit_addr, cpu->get_pc());
596 } else if(debugger->ibp.hit) {
597 my_printf(hStdOut, _T("breaked at %08X: port %08X was read at %08X\n"), cpu->get_next_pc(), debugger->ibp.hit_addr, cpu->get_pc());
598 } else if(debugger->obp.hit) {
599 my_printf(hStdOut, _T("breaked at %08X: port %08X was written at %08X\n"), cpu->get_next_pc(), debugger->obp.hit_addr, cpu->get_pc());
601 debugger->bp.hit = debugger->rbp.hit = debugger->wbp.hit = debugger->ibp.hit = debugger->obp.hit = false;
603 ////SetConsoleTextAttribute(hStdOut, FOREGROUND_RED | FOREGROUND_INTENSITY);
604 my_printf(hStdOut, _T("breaked at %08X: esc key was pressed\n"), cpu->get_next_pc());
607 debugger->restore_break_points();
609 ////SetConsoleTextAttribute(hStdOut, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
610 cpu->debug_dasm(cpu->get_next_pc(), buffer, 1024);
611 my_printf(hStdOut, _T("next\t%08X %s\n"), cpu->get_next_pc(), buffer);
612 ////SetConsoleTextAttribute(hStdOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
614 my_printf(hStdOut, _T("invalid parameter number\n"));
616 } else if(strcasecmp(params[0], _T("T")) == 0) {
617 if(num == 1 || num == 2) {
620 steps = my_hexatoi(params[1]);
622 for(int i = 0; i < steps; i++) {
623 debugger->now_going = false;
624 debugger->now_suspended = false;
625 while(!p->request_terminate && !debugger->now_suspended) {
628 dasm_addr = cpu->get_next_pc();
630 ////SetConsoleTextAttribute(hStdOut, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
631 cpu->debug_dasm(cpu->get_pc(), buffer, 1024);
632 my_printf(hStdOut, _T("done\t%08X %s\n"), cpu->get_pc(), buffer);
634 ////SetConsoleTextAttribute(hStdOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
635 cpu->debug_regs_info(buffer, 1024);
636 my_printf(hStdOut, _T("%s\n"), buffer);
638 //if(debugger->hit() || (GetAsyncKeyState(VK_ESCAPE) & 0x8000) != 0) {
639 if(debugger->hit()) {
643 if(debugger->hit()) {
644 //SetConsoleTextAttribute(hStdOut, FOREGROUND_RED | FOREGROUND_INTENSITY);
645 if(debugger->bp.hit) {
646 my_printf(hStdOut, _T("breaked at %08X\n"), cpu->get_next_pc());
647 } else if(debugger->rbp.hit) {
648 my_printf(hStdOut, _T("breaked at %08X: memory %08X was read at %08X\n"), cpu->get_next_pc(), debugger->rbp.hit_addr, cpu->get_pc());
649 } else if(debugger->wbp.hit) {
650 my_printf(hStdOut, _T("breaked at %08X: memory %08X was written at %08X\n"), cpu->get_next_pc(), debugger->wbp.hit_addr, cpu->get_pc());
651 } else if(debugger->ibp.hit) {
652 my_printf(hStdOut, _T("breaked at %08X: port %08X was read at %08X\n"), cpu->get_next_pc(), debugger->ibp.hit_addr, cpu->get_pc());
653 } else if(debugger->obp.hit) {
654 my_printf(hStdOut, _T("breaked at %08X: port %08X was written at %08X\n"), cpu->get_next_pc(), debugger->obp.hit_addr, cpu->get_pc());
656 debugger->bp.hit = debugger->rbp.hit = debugger->wbp.hit = debugger->ibp.hit = debugger->obp.hit = false;
658 //SetConsoleTextAttribute(hStdOut, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
659 cpu->debug_dasm(cpu->get_next_pc(), buffer, 1024);
660 my_printf(hStdOut, _T("next\t%08X %s\n"), cpu->get_next_pc(), buffer);
661 //SetConsoleTextAttribute(hStdOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
663 my_printf(hStdOut, _T("invalid parameter number\n"));
665 } else if(strcasecmp(params[0], _T("Q")) == 0) {
666 //PostMessage(p->emu->main_window_handle, WM_COMMAND, ID_CLOSE_DEBUGGER, 0L);
668 } else if(strcasecmp(params[0], _T("!")) == 0) {
670 my_printf(hStdOut, _T("invalid parameter number\n"));
671 } else if(strcasecmp(params[1], _T("RESET")) == 0) {
674 } else if(num == 3) {
675 if(strcasecmp(params[2], _T("ALL")) == 0) {
677 } if(strcasecmp(params[2], _T("CPU")) == 0) {
680 my_printf(hStdOut, _T("unknown device %s\n"), params[2]);
683 my_printf(hStdOut, _T("invalid parameter number\n"));
685 } else if(strcasecmp(params[1], _T("KEY")) == 0) {
686 if(num == 3 || num == 4) {
687 int code = my_hexatoi(params[2]) & 0xff, msec = 100;
689 msec = my_hexatoi(params[3]);
691 #ifdef SUPPORT_VARIABLE_TIMING
692 p->emu->key_buffer()[code] = (int)fmax(p->vm->frame_rate() * (double)msec / 1000.0 + 0.5, 1.0);
694 p->emu->key_buffer()[code] = (int)fmax(FRAMES_PER_SEC * (double)msec / 1000.0 + 0.5, 1.0);
696 #ifdef NOTIFY_KEY_DOWN
697 p->vm->key_down(code, false);
700 my_printf(hStdOut, _T("invalid parameter number\n"));
703 my_printf(hStdOut, _T("unknown command ! %s\n"), params[1]);
705 } else if(strcasecmp(params[0], _T("?")) == 0) {
706 my_printf(hStdOut, _T("D [<range>] - dump memory\n"));
707 my_printf(hStdOut, _T("E[{B,W,D}] <address> <list> - edit memory (byte,word,dword)\n"));
708 my_printf(hStdOut, _T("EA <address> \"<value>\" - edit memory (ascii)\n"));
709 my_printf(hStdOut, _T("I[{B,W,D}] <port> - input port (byte,word,dword)\n"));
710 my_printf(hStdOut, _T("O[{B,W,D}] <port> <value> - output port (byte,word,dword)\n"));
711 my_printf(hStdOut, _T("R - show register(s)\n"));
712 my_printf(hStdOut, _T("R <reg> <value> - edit register\n"));
713 my_printf(hStdOut, _T("S <range> <list> - search\n"));
714 my_printf(hStdOut, _T("U [<range>] - unassemble\n"));
716 my_printf(hStdOut, _T("H <value> <value> - hexadd\n"));
717 my_printf(hStdOut, _T("N <filename> - name\n"));
718 my_printf(hStdOut, _T("L <range> - load file\n"));
719 my_printf(hStdOut, _T("W <range> - write file\n"));
721 my_printf(hStdOut, _T("BP <address> - set breakpoint\n"));
722 my_printf(hStdOut, _T("{R,W}BP <address> - set breakpoint (break at memory access)\n"));
723 my_printf(hStdOut, _T("{I,O}BP <port> [<mask>] - set breakpoint (break at i/o access)\n"));
724 my_printf(hStdOut, _T("[{R,W,I,O}]B{C,D,E} {all,<list>} - clear/disable/enable breakpoint(s)\n"));
725 my_printf(hStdOut, _T("[{R,W,I,O}]BL - list breakpoint(s)\n"));
727 my_printf(hStdOut, _T("G - go (press esc key to break)\n"));
728 my_printf(hStdOut, _T("G <address> - go and break at address\n"));
729 my_printf(hStdOut, _T("T [<count>] - trace\n"));
730 my_printf(hStdOut, _T("Q - quit\n"));
732 my_printf(hStdOut, _T("! reset [cpu] - reset\n"));
733 my_printf(hStdOut, _T("! key <code> [<msec>] - press key\n"));
735 my_printf(hStdOut, _T("<value> - hexa, decimal(%%d), ascii('a')\n"));
737 my_printf(hStdOut, _T("unknown command %s\n"), params[0]);
745 debugger->now_debugging = debugger->now_going = debugger->now_suspended = false;
758 void CSP_Debugger::doWork(QObject *parent)
761 SDL_DetachThread(thread);
763 thread = SDL_CreateThread(debugger_main, "CSP:DEBUGGER", &debugger_thread_param);
766 void CSP_Debugger::doExit(void)
768 debugger_thread_param.request_terminate = true;
770 SDL_DetachThread(thread);
776 CSP_Debugger::~CSP_Debugger()
779 // delete debug_window;
782 CSP_Debugger::CSP_Debugger(QObject *parent) : QObject(parent)
784 // debug_window = new QMainWindow();
785 // hConsole = new QTermWidget(0);
788 font.setFamily("Monaco");
789 #elif defined(Q_WS_QWS)
790 font.setFamily("fixed");
792 font.setFamily("Monospace");
794 font.setPointSize(14);
795 // hConsole->setTerminalFont(font);
796 // hConsole->setScrollBarPosition(QTermWidget::ScrollBarRight);
797 // debug_window->setCentralWidget(hConsole);
798 // debug_window->resize(600, 400);
799 // QObject::connect(hConsole, SIGNAL(finished()), debug_window, SLOT(close()));
800 // debug_window->show();
804 void EMU::initialize_debugger()
806 now_debugging = false;
807 hDebuggerThread = NULL;
811 void EMU::release_debugger()
816 void EMU::open_debugger(int cpu_index)
818 if(!(now_debugging && debugger_thread_param.cpu_index == cpu_index)) {
820 if(vm->get_cpu(cpu_index) != NULL && vm->get_cpu(cpu_index)->get_debugger() != NULL) {
822 hDebugger = new CSP_Debugger(NULL);
823 hDebuggerThread = new QThread;
824 hDebugger->debugger_thread_param.emu = this;
825 hDebugger->debugger_thread_param.vm = vm;
826 hDebugger->debugger_thread_param.cpu_index = cpu_index;
827 hDebugger->debugger_thread_param.request_terminate = false;
830 now_debugging = true;
831 //hDebugger->moveToThread(hDebuggerThread);
832 //QMetaObject::invokeMethod(hDebugger, "start", Qt::QueuedConnection);
833 hDebugger->doWork(NULL);
838 void EMU::close_debugger()
841 if(hDebugger->debugger_thread_param.running && (hDebugger->thread != NULL)) {
842 hDebugger->debugger_thread_param.request_terminate = true;
843 SDL_WaitThread(hDebugger->thread, NULL);
844 //WaitForSingleObject(hDebuggerThread, INFINITE);
846 delete hDebuggerThread;
848 hDebuggerThread = NULL;
850 now_debugging = false;
854 bool EMU::debugger_enabled(int cpu_index)
856 return (vm->get_cpu(cpu_index) != NULL && vm->get_cpu(cpu_index)->get_debugger() != NULL);