2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
15 #include "vm/device.h"
16 #include "vm/debugger.h"
20 #include "emu_thread.h"
25 #ifndef FOREGROUND_BLUE
26 #define FOREGROUND_BLUE 0x0001 // text color contains blue.
28 #ifndef FOREGROUND_GREEN
29 #define FOREGROUND_GREEN 0x0002 // text color contains green.
31 #ifndef FOREGROUND_RED
32 #define FOREGROUND_RED 0x0004 // text color contains red.
34 #ifndef FOREGROUND_INTENSITY
35 #define FOREGROUND_INTENSITY 0x0008 // text color is intensified.
38 static FILEIO* logfile = NULL;
40 void my_printf(OSD *osd, const _TCHAR *format, ...)
46 my_vstprintf_s(buffer, 1024, format, ap);
49 if(logfile != NULL && logfile->IsOpened()) {
50 logfile->Fwrite(buffer, lstrlen(buffer) * sizeof(_TCHAR), 1);
53 if(logfile != NULL && logfile->IsOpened()) {
54 logfile->Fwrite(buffer, strlen(buffer) * sizeof(_TCHAR), 1);
57 osd->write_console(buffer, _tcslen(buffer));
60 void my_putch(OSD *osd, _TCHAR c)
62 if(logfile != NULL && logfile->IsOpened()) {
63 logfile->Fwrite(&c, sizeof(_TCHAR), 1);
65 osd->write_console(&c, 1);
68 uint32_t my_hexatoi(const _TCHAR *str)
72 if(str == NULL || _tcslen(str) == 0) {
75 my_tcscpy_s(tmp, 1024, str);
77 if(_tcslen(tmp) == 3 && tmp[0] == _T('\'') && tmp[2] == _T('\'')) {
80 } else if((s = _tcsstr(tmp, _T(":"))) != NULL) {
83 return (my_hexatoi(tmp) << 4) + my_hexatoi(s + 1);
84 } else if(tmp[0] == _T('%')) {
86 #if defined(__MINGW32__)
89 return _tstoi(tmp + 1);
92 return _tcstoul(tmp, NULL, 16);
95 uint8_t my_hexatob(char *value)
101 return (uint8_t)strtoul(tmp, NULL, 16);
104 uint16_t my_hexatow(char *value)
112 return (uint16_t)strtoul(tmp, NULL, 16);
115 break_point_t *get_break_point(DEBUGGER *debugger, const _TCHAR *command)
117 if(command[0] == _T('B') || command[0] == _T('b')) {
118 return &debugger->bp;
119 } else if(command[0] == _T('R') || command[0] == _T('r')) {
120 return &debugger->rbp;
121 } else if(command[0] == _T('W') || command[0] == _T('w')) {
122 return &debugger->wbp;
123 } else if(command[0] == _T('I') || command[0] == _T('i')) {
124 return &debugger->ibp;
125 } else if(command[0] == _T('O') || command[0] == _T('o')) {
126 return &debugger->obp;
131 static uint32_t dump_addr;
132 static uint32_t dasm_addr;
134 int debugger_command(debugger_thread_t *p, _TCHAR *command, _TCHAR *prev_command, bool cp932)
136 DEVICE *cpu = p->vm->get_cpu(p->cpu_index);
137 DEBUGGER *debugger = (DEBUGGER *)cpu->get_debugger();
138 uint32_t prog_addr_mask = cpu->debug_prog_addr_mask();
139 uint32_t data_addr_mask = cpu->debug_data_addr_mask();
140 //while(!debugger->now_suspended) {
141 // p->osd->sleep(10);
144 // initialize console
146 if(strlen(command) > 0) {
147 _TCHAR *params[32], *token = NULL, *context = NULL;
150 if((token = my_tcstok_s(command, _T(" "), &context)) != NULL) {
151 params[num++] = token;
152 while(num < 32 && (token = my_tcstok_s(NULL, _T(" "), &context)) != NULL) {
153 params[num++] = token;
156 if(_tcsicmp(params[0], _T("D")) == 0) {
158 uint32_t start_addr = dump_addr;
160 start_addr = my_hexatoi(params[1]);
162 start_addr &= data_addr_mask;
164 uint32_t end_addr = start_addr + 8 * 16 - 1;
166 end_addr = my_hexatoi(params[2]);
168 end_addr &= data_addr_mask;
170 if(start_addr > end_addr) {
171 end_addr = data_addr_mask;
173 for(uint64_t addr = start_addr & ~0x0f; addr <= end_addr; addr++) {
174 if(addr > data_addr_mask) {
175 end_addr = data_addr_mask;
178 if((addr & 0x0f) == 0) {
179 my_printf(p->osd, _T("%08X "), addr & data_addr_mask);
180 memset(buffer, 0, sizeof(buffer));
182 if(addr < start_addr) {
183 my_printf(p->osd, _T(" "));
184 buffer[addr & 0x0f] = _T(' ');
186 uint32_t data = cpu->read_debug_data8(addr & data_addr_mask);
187 my_printf(p->osd, _T(" %02X"), data);
188 buffer[addr & 0x0f] = ((data >= 0x20 && data <= 0x7e) || (cp932 && data >= 0xa1 && data <= 0xdf)) ? data : _T('.');
190 if((addr & 0x0f) == 0x0f) {
191 my_printf(p->osd, _T(" %s\n"), buffer);
194 if((end_addr & 0x0f) != 0x0f) {
195 for(uint32_t addr = (end_addr & 0x0f) + 1; addr <= 0x0f; addr++) {
196 my_printf(p->osd, _T(" "));
198 my_printf(p->osd, _T(" %s\n"), buffer);
200 dump_addr = (end_addr + 1) & data_addr_mask;
201 prev_command[1] = _T('\0'); // remove parameters to dump continuously
203 my_printf(p->osd, _T("invalid parameter number\n"));
205 } else if(_tcsicmp(params[0], _T("E")) == 0 || _tcsicmp(params[0], _T("EB")) == 0) {
207 uint32_t addr = my_hexatoi(params[1]) & data_addr_mask;
208 for(int i = 2; i < num; i++) {
209 cpu->write_debug_data8(addr, my_hexatoi(params[i]) & 0xff);
210 addr = (addr + 1) & data_addr_mask;
213 my_printf(p->osd, _T("invalid parameter number\n"));
215 } else if(_tcsicmp(params[0], _T("EW")) == 0) {
217 uint32_t addr = my_hexatoi(params[1]) & data_addr_mask;
218 for(int i = 2; i < num; i++) {
219 cpu->write_debug_data16(addr, my_hexatoi(params[i]) & 0xffff);
220 addr = (addr + 2) & data_addr_mask;
223 my_printf(p->osd, _T("invalid parameter number\n"));
225 } else if(_tcsicmp(params[0], _T("ED")) == 0) {
227 uint32_t addr = my_hexatoi(params[1]) & data_addr_mask;
228 for(int i = 2; i < num; i++) {
229 cpu->write_debug_data32(addr, my_hexatoi(params[i]));
230 addr = (addr + 4) & data_addr_mask;
233 my_printf(p->osd, _T("invalid parameter number\n"));
235 } else if(_tcsicmp(params[0], _T("EA")) == 0) {
237 uint32_t addr = my_hexatoi(params[1]) & data_addr_mask;
238 my_tcscpy_s(buffer, 1024, prev_command);
239 if((token = my_tcstok_s(buffer, _T("\""), &context)) != NULL && (token = my_tcstok_s(NULL, _T("\""), &context)) != NULL) {
240 int len = _tcslen(token);
241 for(int i = 0; i < len; i++) {
242 cpu->write_debug_data8(addr, token[i] & 0xff);
243 addr = (addr + 1) & data_addr_mask;
246 my_printf(p->osd, _T("invalid parameter\n"));
249 my_printf(p->osd, _T("invalid parameter number\n"));
251 } else if(_tcsicmp(params[0], _T("I")) == 0 || _tcsicmp(params[0], _T("IB")) == 0) {
253 my_printf(p->osd, _T("%02X\n"), cpu->read_debug_io8(my_hexatoi(params[1])) & 0xff);
255 my_printf(p->osd, _T("invalid parameter number\n"));
257 } else if(_tcsicmp(params[0], _T("IW")) == 0) {
259 my_printf(p->osd, _T("%02X\n"), cpu->read_debug_io16(my_hexatoi(params[1])) & 0xffff);
261 my_printf(p->osd, _T("invalid parameter number\n"));
263 } else if(_tcsicmp(params[0], _T("ID")) == 0) {
265 my_printf(p->osd, _T("%02X\n"), cpu->read_debug_io32(my_hexatoi(params[1])));
267 my_printf(p->osd, _T("invalid parameter number\n"));
269 } else if(_tcsicmp(params[0], _T("O")) == 0 || _tcsicmp(params[0], _T("OB")) == 0) {
271 cpu->write_debug_io8(my_hexatoi(params[1]), my_hexatoi(params[2]) & 0xff);
273 my_printf(p->osd, _T("invalid parameter number\n"));
275 } else if(_tcsicmp(params[0], _T("OW")) == 0) {
277 cpu->write_debug_io16(my_hexatoi(params[1]), my_hexatoi(params[2]) & 0xffff);
279 my_printf(p->osd, _T("invalid parameter number\n"));
281 } else if(_tcsicmp(params[0], _T("OD")) == 0) {
283 cpu->write_debug_io32(my_hexatoi(params[1]), my_hexatoi(params[2]));
285 my_printf(p->osd, _T("invalid parameter number\n"));
287 } else if(_tcsicmp(params[0], _T("R")) == 0) {
289 cpu->debug_regs_info(buffer, 1024);
290 my_printf(p->osd, _T("%s\n"), buffer);
291 } else if(num == 3) {
292 if(!cpu->write_debug_reg(params[1], my_hexatoi(params[2]))) {
293 my_printf(p->osd, _T("unknown register %s\n"), params[1]);
296 my_printf(p->osd, _T("invalid parameter number\n"));
298 } else if(_tcsicmp(params[0], _T("S")) == 0) {
300 uint32_t start_addr = my_hexatoi(params[1]) & data_addr_mask;
301 uint32_t end_addr = my_hexatoi(params[2]) & data_addr_mask;
303 for(int i = 3, j = 0; i < num; i++, j++) {
304 list[j] = my_hexatoi(params[i]);
306 for(uint64_t addr = start_addr; addr <= end_addr; addr++) {
308 for(int i = 3, j = 0; i < num; i++, j++) {
309 if(cpu->read_debug_data8((addr + j) & data_addr_mask) != list[j]) {
315 my_printf(p->osd, _T("%08X\n"), addr);
319 my_printf(p->osd, _T("invalid parameter number\n"));
321 } else if(_tcsicmp(params[0], _T("U")) == 0) {
324 dasm_addr = my_hexatoi(params[1]) & prog_addr_mask;
327 uint32_t end_addr = my_hexatoi(params[2]) & prog_addr_mask;
328 while(dasm_addr <= end_addr) {
329 int len = cpu->debug_dasm(dasm_addr, buffer, 1024);
330 my_printf(p->osd, _T("%08X "), dasm_addr);
331 for(int i = 0; i < len; i++) {
332 my_printf(p->osd, _T("%02X"), cpu->read_debug_data8((dasm_addr + i) & data_addr_mask));
334 for(int i = len; i < 8; i++) {
335 my_printf(p->osd, _T(" "));
337 my_printf(p->osd, _T(" %s\n"), buffer);
338 dasm_addr = (dasm_addr + len) & prog_addr_mask;
341 for(int i = 0; i < 16; i++) {
342 int len = cpu->debug_dasm(dasm_addr, buffer, 1024);
343 my_printf(p->osd, _T("%08X "), dasm_addr);
344 for(int i = 0; i < len; i++) {
345 my_printf(p->osd, _T("%02X"), cpu->read_debug_data8((dasm_addr + i) & data_addr_mask));
347 for(int i = len; i < 8; i++) {
348 my_printf(p->osd, _T(" "));
350 my_printf(p->osd, _T(" %s\n"), buffer);
351 dasm_addr = (dasm_addr + len) & prog_addr_mask;
354 prev_command[1] = _T('\0'); // remove parameters to disassemble continuously
356 my_printf(p->osd, _T("invalid parameter number\n"));
358 } else if(_tcsicmp(params[0], _T("H")) == 0) {
360 uint32_t l = my_hexatoi(params[1]);
361 uint32_t r = my_hexatoi(params[2]);
362 my_printf(p->osd, _T("%08X %08X\n"), l + r, l - r);
364 my_printf(p->osd, _T("invalid parameter number\n"));
366 } else if(_tcsicmp(params[0], _T("N")) == 0) {
367 if(num >= 2 && params[1][0] == _T('\"')) {
368 my_tcscpy_s(buffer, 1024, prev_command);
369 if((token = my_tcstok_s(buffer, _T("\""), &context)) != NULL && (token = my_tcstok_s(NULL, _T("\""), &context)) != NULL) {
370 my_tcscpy_s(debugger->file_path, _MAX_PATH, token);
372 my_printf(p->osd, _T("invalid parameter\n"));
374 } else if(num == 2) {
375 my_tcscpy_s(debugger->file_path, _MAX_PATH, params[1]);
377 my_printf(p->osd, _T("invalid parameter number\n"));
379 } else if(_tcsicmp(params[0], _T("L")) == 0) {
380 FILEIO* fio = new FILEIO();
381 if(check_file_extension(debugger->file_path, _T(".hex"))) {
382 if(fio->Fopen(debugger->file_path, FILEIO_READ_ASCII)) {
383 uint32_t start_addr = 0, linear = 0, segment = 0;
385 start_addr = my_hexatoi(params[1]);
388 while(fio->Fgets(line, sizeof(line)) != NULL) {
389 if(line[0] != ':') continue;
390 int type = my_hexatob(line + 7);
392 uint32_t bytes = my_hexatob(line + 1);
393 uint32_t addr = my_hexatow(line + 3) + start_addr + linear + segment;
394 for(uint32_t i = 0; i < bytes; i++) {
395 cpu->write_debug_data8((addr + i) & data_addr_mask, my_hexatob(line + 9 + 2 * i));
397 } else if(type == 0x01) {
399 } else if(type == 0x02) {
400 segment = my_hexatow(line + 9) << 4;
402 } else if(type == 0x04) {
403 linear = my_hexatow(line + 9) << 16;
409 my_printf(p->osd, _T("can't open %s\n"), debugger->file_path);
412 if(fio->Fopen(debugger->file_path, FILEIO_READ_BINARY)) {
413 uint32_t start_addr = 0x100, end_addr = data_addr_mask;
415 start_addr = my_hexatoi(params[1]) & data_addr_mask;
418 end_addr = my_hexatoi(params[2]) & data_addr_mask;
420 for(uint32_t addr = start_addr; addr <= end_addr; addr++) {
421 int data = fio->Fgetc();
425 cpu->write_debug_data8(addr & data_addr_mask, data);
429 my_printf(p->osd, _T("can't open %s\n"), debugger->file_path);
433 } else if(_tcsicmp(params[0], _T("W")) == 0) {
435 uint32_t start_addr = my_hexatoi(params[1]) & data_addr_mask, end_addr = my_hexatoi(params[2]) & data_addr_mask;
436 FILEIO* fio = new FILEIO();
437 if(check_file_extension(debugger->file_path, _T(".hex"))) {
438 // write intel hex format file
439 if(fio->Fopen(debugger->file_path, FILEIO_WRITE_ASCII)) {
440 uint32_t addr = start_addr;
441 while(addr <= end_addr) {
442 uint32_t len = min(end_addr - addr + 1, (uint32_t)16);
443 uint32_t sum = len + ((addr >> 8) & 0xff) + (addr & 0xff) + 0x00;
444 fio->Fprintf(":%02X%04X%02X", len, addr & 0xffff, 0x00);
445 for(uint32_t i = 0; i < len; i++) {
446 uint8_t data = cpu->read_debug_data8((addr++) & data_addr_mask);
448 fio->Fprintf("%02X", data);
450 fio->Fprintf("%02X\n", (0x100 - (sum & 0xff)) & 0xff);
452 fio->Fprintf(":00000001FF\n");
455 my_printf(p->osd, _T("can't open %s\n"), debugger->file_path);
458 if(fio->Fopen(debugger->file_path, FILEIO_WRITE_BINARY)) {
459 for(uint32_t addr = start_addr; addr <= end_addr; addr++) {
460 fio->Fputc(cpu->read_debug_data8(addr & data_addr_mask));
464 my_printf(p->osd, _T("can't open %s\n"), debugger->file_path);
469 my_printf(p->osd, _T("invalid parameter number\n"));
471 } else if(_tcsicmp(params[0], _T( "BP")) == 0 || _tcsicmp(params[0], _T("RBP")) == 0 || _tcsicmp(params[0], _T("WBP")) == 0) {
472 break_point_t *bp = get_break_point(debugger, params[0]);
474 uint32_t addr = my_hexatoi(params[1]);
476 for(int i = 0; i < MAX_BREAK_POINTS && !found; i++) {
477 if(bp->table[i].status == 0 || (bp->table[i].addr == addr && bp->table[i].mask == prog_addr_mask)) {
478 bp->table[i].addr = addr;
479 bp->table[i].mask = prog_addr_mask;
480 bp->table[i].status = 1;
485 my_printf(p->osd, _T("too many break points\n"));
488 my_printf(p->osd, _T("invalid parameter number\n"));
490 } else if(_tcsicmp(params[0], _T("IBP")) == 0 || _tcsicmp(params[0], _T("OBP")) == 0) {
491 break_point_t *bp = get_break_point(debugger, params[0]);
492 if(num == 2 || num == 3) {
493 uint32_t addr = my_hexatoi(params[1]), mask = 0xff;
495 mask = my_hexatoi(params[2]);
498 for(int i = 0; i < MAX_BREAK_POINTS && !found; i++) {
499 if(bp->table[i].status == 0 || (bp->table[i].addr == addr && bp->table[i].mask == mask)) {
500 bp->table[i].addr = addr;
501 bp->table[i].mask = mask;
502 bp->table[i].status = 1;
507 my_printf(p->osd, _T("too many break points\n"));
510 my_printf(p->osd, _T("invalid parameter number\n"));
512 } else if(_tcsicmp(params[0], _T("BC")) == 0 || _tcsicmp(params[0], _T("RBC")) == 0 || _tcsicmp(params[0], _T("WBC")) == 0 || _tcsicmp(params[0], _T("IBC")) == 0 || _tcsicmp(params[0], _T("OBC")) == 0) {
513 break_point_t *bp = get_break_point(debugger, params[0]);
514 if(num == 2 && (_tcsicmp(params[1], _T("*")) == 0 || _tcsicmp(params[1], _T("ALL")) == 0)) {
515 memset(bp->table, 0, sizeof(bp->table));
516 } else if(num >= 2) {
517 for(int i = 1; i < num; i++) {
518 int index = my_hexatoi(params[i]);
519 if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
520 my_printf(p->osd, _T("invalid index %x\n"), index);
522 bp->table[index - 1].addr = bp->table[index - 1].mask = 0;
523 bp->table[index - 1].status = 0;
527 my_printf(p->osd, _T("invalid parameter number\n"));
529 } else if(_tcsicmp(params[0], _T("BD")) == 0 || _tcsicmp(params[0], _T("RBD")) == 0 || _tcsicmp(params[0], _T("WBD")) == 0 || _tcsicmp(params[0], _T("IBD")) == 0 || _tcsicmp(params[0], _T("OBD")) == 0 ||
530 _tcsicmp(params[0], _T("BE")) == 0 || _tcsicmp(params[0], _T("RBE")) == 0 || _tcsicmp(params[0], _T("WBE")) == 0 || _tcsicmp(params[0], _T("IBE")) == 0 || _tcsicmp(params[0], _T("OBE")) == 0) {
531 break_point_t *bp = get_break_point(debugger, params[0]);
532 bool enabled = (params[0][1] == _T('E') || params[0][1] == _T('e') || params[0][2] == _T('E') || params[0][2] == _T('e'));
533 if(num == 2 && (_tcsicmp(params[1], _T("*")) == 0 || _tcsicmp(params[1], _T("ALL")) == 0)) {
534 for(int i = 0; i < MAX_BREAK_POINTS; i++) {
535 if(bp->table[i].status != 0) {
536 bp->table[i].status = enabled ? 1 : -1;
539 } else if(num >= 2) {
540 for(int i = 1; i < num; i++) {
541 int index = my_hexatoi(params[i]);
542 if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
543 my_printf(p->osd, _T("invalid index %x\n"), index);
544 } else if(bp->table[index - 1].status == 0) {
545 my_printf(p->osd, _T("break point %x is null\n"), index);
547 bp->table[index - 1].status = enabled ? 1 : -1;
551 my_printf(p->osd, _T("invalid parameter number\n"));
553 } else if(_tcsicmp(params[0], _T("BL")) == 0 || _tcsicmp(params[0], _T("RBL")) == 0 || _tcsicmp(params[0], _T("WBL")) == 0) {
555 break_point_t *bp = get_break_point(debugger, params[0]);
556 for(int i = 0; i < MAX_BREAK_POINTS; i++) {
557 if(bp->table[i].status) {
558 my_printf(p->osd, _T("%d %c %08X\n"), i + 1, bp->table[i].status == 1 ? _T('e') : _T('d'), bp->table[i].addr);
562 my_printf(p->osd, _T("invalid parameter number\n"));
564 } else if(_tcsicmp(params[0], _T("IBL")) == 0 || _tcsicmp(params[0], _T("OBL")) == 0) {
566 break_point_t *bp = get_break_point(debugger, params[0]);
567 for(int i = 0; i < MAX_BREAK_POINTS; i++) {
568 if(bp->table[i].status) {
569 my_printf(p->osd, _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);
573 my_printf(p->osd, _T("invalid parameter number\n"));
575 } else if(_tcsicmp(params[0], _T("G")) == 0) {
576 if(num == 1 || num == 2) {
578 debugger->store_break_points();
579 debugger->bp.table[0].addr = my_hexatoi(params[1]) & prog_addr_mask;
580 debugger->bp.table[0].mask = prog_addr_mask;
581 debugger->bp.table[0].status = 1;
583 debugger->now_going = true;
584 debugger->now_suspended = false;
585 #if defined(_MSC_VER)
586 while(!p->request_terminate && !debugger->now_suspended) {
587 if(p->osd->is_console_key_pressed(VK_ESCAPE) && p->osd->is_console_active()) {
592 #elif defined(OSD_QT)
593 while(!p->request_terminate && !debugger->now_suspended) {
594 if(p->osd->console_input_string() != NULL && p->osd->is_console_active()) {
595 p->osd->clear_console_input_string();
602 debugger->now_going = false;
603 while(!p->request_terminate && !debugger->now_suspended) {
606 dasm_addr = cpu->get_next_pc();
608 p->osd->set_console_text_attribute(FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
609 cpu->debug_dasm(cpu->get_pc(), buffer, 1024);
610 my_printf(p->osd, _T("done\t%08X %s\n"), cpu->get_pc(), buffer);
612 p->osd->set_console_text_attribute(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
613 cpu->debug_regs_info(buffer, 1024);
614 my_printf(p->osd, _T("%s\n"), buffer);
616 if(debugger->hit()) {
617 p->osd->set_console_text_attribute(FOREGROUND_RED | FOREGROUND_INTENSITY);
618 if(debugger->bp.hit) {
619 my_printf(p->osd, _T("breaked at %08X\n"), cpu->get_next_pc());
620 } else if(debugger->rbp.hit) {
621 my_printf(p->osd, _T("breaked at %08X: memory %08X was read at %08X\n"), cpu->get_next_pc(), debugger->rbp.hit_addr, cpu->get_pc());
622 } else if(debugger->wbp.hit) {
623 my_printf(p->osd, _T("breaked at %08X: memory %08X was written at %08X\n"), cpu->get_next_pc(), debugger->wbp.hit_addr, cpu->get_pc());
624 } else if(debugger->ibp.hit) {
625 my_printf(p->osd, _T("breaked at %08X: port %08X was read at %08X\n"), cpu->get_next_pc(), debugger->ibp.hit_addr, cpu->get_pc());
626 } else if(debugger->obp.hit) {
627 my_printf(p->osd, _T("breaked at %08X: port %08X was written at %08X\n"), cpu->get_next_pc(), debugger->obp.hit_addr, cpu->get_pc());
629 debugger->bp.hit = debugger->rbp.hit = debugger->wbp.hit = debugger->ibp.hit = debugger->obp.hit = false;
631 p->osd->set_console_text_attribute(FOREGROUND_RED | FOREGROUND_INTENSITY);
632 my_printf(p->osd, _T("breaked at %08X: esc key was pressed\n"), cpu->get_next_pc());
635 debugger->restore_break_points();
637 p->osd->set_console_text_attribute(FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
638 cpu->debug_dasm(cpu->get_next_pc(), buffer, 1024);
639 my_printf(p->osd, _T("next\t%08X %s\n"), cpu->get_next_pc(), buffer);
640 p->osd->set_console_text_attribute(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
642 my_printf(p->osd, _T("invalid parameter number\n"));
644 } else if(_tcsicmp(params[0], _T("T")) == 0) {
645 if(num == 1 || num == 2) {
648 steps = my_hexatoi(params[1]);
650 for(int i = 0; i < steps; i++) {
651 debugger->now_going = false;
652 debugger->now_suspended = false;
653 while(!p->request_terminate && !debugger->now_suspended) {
656 dasm_addr = cpu->get_next_pc();
658 p->osd->set_console_text_attribute(FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
659 cpu->debug_dasm(cpu->get_pc(), buffer, 1024);
660 my_printf(p->osd, _T("done\t%08X %s\n"), cpu->get_pc(), buffer);
662 p->osd->set_console_text_attribute(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
663 cpu->debug_regs_info(buffer, 1024);
664 my_printf(p->osd, _T("%s\n"), buffer);
665 if(debugger->hit() || (p->osd->is_console_key_pressed(VK_ESCAPE) && p->osd->is_console_active())) {
666 //p->osd->clear_console_input_string();
670 if(debugger->hit()) {
671 p->osd->set_console_text_attribute(FOREGROUND_RED | FOREGROUND_INTENSITY);
672 if(debugger->bp.hit) {
673 my_printf(p->osd, _T("breaked at %08X\n"), cpu->get_next_pc());
674 } else if(debugger->rbp.hit) {
675 my_printf(p->osd, _T("breaked at %08X: memory %08X was read at %08X\n"), cpu->get_next_pc(), debugger->rbp.hit_addr, cpu->get_pc());
676 } else if(debugger->wbp.hit) {
677 my_printf(p->osd, _T("breaked at %08X: memory %08X was written at %08X\n"), cpu->get_next_pc(), debugger->wbp.hit_addr, cpu->get_pc());
678 } else if(debugger->ibp.hit) {
679 my_printf(p->osd, _T("breaked at %08X: port %08X was read at %08X\n"), cpu->get_next_pc(), debugger->ibp.hit_addr, cpu->get_pc());
680 } else if(debugger->obp.hit) {
681 my_printf(p->osd, _T("breaked at %08X: port %08X was written at %08X\n"), cpu->get_next_pc(), debugger->obp.hit_addr, cpu->get_pc());
683 debugger->bp.hit = debugger->rbp.hit = debugger->wbp.hit = debugger->ibp.hit = debugger->obp.hit = false;
685 p->osd->set_console_text_attribute(FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
686 cpu->debug_dasm(cpu->get_next_pc(), buffer, 1024);
687 my_printf(p->osd, _T("next\t%08X %s\n"), cpu->get_next_pc(), buffer);
688 p->osd->set_console_text_attribute(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
690 my_printf(p->osd, _T("invalid parameter number\n"));
692 } else if(_tcsicmp(params[0], _T("Q")) == 0) {
693 p->osd->close_debugger_console();
695 } else if(_tcsicmp(params[0], _T(">")) == 0) {
697 if(logfile != NULL) {
698 if(logfile->IsOpened()) {
704 logfile = new FILEIO();
705 logfile->Fopen(params[1], FILEIO_WRITE_ASCII);
707 my_printf(p->osd, _T("invalid parameter number\n"));
709 } else if(_tcsicmp(params[0], _T("!")) == 0) {
711 my_printf(p->osd, _T("invalid parameter number\n"));
712 } else if(_tcsicmp(params[1], _T("RESET")) == 0) {
715 } else if(num == 3) {
716 if(_tcsicmp(params[2], _T("ALL")) == 0) {
718 } if(_tcsicmp(params[2], _T("CPU")) == 0) {
721 my_printf(p->osd, _T("unknown device %s\n"), params[2]);
724 my_printf(p->osd, _T("invalid parameter number\n"));
726 } else if(_tcsicmp(params[1], _T("KEY")) == 0) {
727 if(num == 3 || num == 4) {
728 int code = my_hexatoi(params[2]) & 0xff, msec = 100;
730 msec = my_hexatoi(params[3]);
732 #ifdef SUPPORT_VARIABLE_TIMING
733 p->osd->modify_key_buffer(code, max((int)(p->vm->get_frame_rate() * (double)msec / 1000.0 + 0.5), 1));
735 p->osd->modify_key_buffer(code, max((int)(FRAMES_PER_SEC * (double)msec / 1000.0 + 0.5), 1));
737 #ifdef NOTIFY_KEY_DOWN
738 p->vm->key_down(code, false);
741 my_printf(p->osd, _T("invalid parameter number\n"));
744 my_printf(p->osd, _T("unknown command ! %s\n"), params[1]);
746 } else if(_tcsicmp(params[0], _T("?")) == 0) {
747 my_printf(p->osd, _T("D [<range>] - dump memory\n"));
748 my_printf(p->osd, _T("E[{B,W,D}] <address> <list> - edit memory (byte,word,dword)\n"));
749 my_printf(p->osd, _T("EA <address> \"<value>\" - edit memory (ascii)\n"));
750 my_printf(p->osd, _T("I[{B,W,D}] <port> - input port (byte,word,dword)\n"));
751 my_printf(p->osd, _T("O[{B,W,D}] <port> <value> - output port (byte,word,dword)\n"));
752 my_printf(p->osd, _T("R - show register(s)\n"));
753 my_printf(p->osd, _T("R <reg> <value> - edit register\n"));
754 my_printf(p->osd, _T("S <range> <list> - search\n"));
755 my_printf(p->osd, _T("U [<range>] - unassemble\n"));
757 my_printf(p->osd, _T("H <value> <value> - hexadd\n"));
758 my_printf(p->osd, _T("N <filename> - name\n"));
759 my_printf(p->osd, _T("L [<range>] - load file\n"));
760 my_printf(p->osd, _T("W <range> - write file\n"));
762 my_printf(p->osd, _T("BP <address> - set breakpoint\n"));
763 my_printf(p->osd, _T("{R,W}BP <address> - set breakpoint (break at memory access)\n"));
764 my_printf(p->osd, _T("{I,O}BP <port> [<mask>] - set breakpoint (break at i/o access)\n"));
765 my_printf(p->osd, _T("[{R,W,I,O}]B{C,D,E} {*,<list>} - clear/disable/enable breakpoint(s)\n"));
766 my_printf(p->osd, _T("[{R,W,I,O}]BL - list breakpoint(s)\n"));
768 my_printf(p->osd, _T("G - go (press esc key to break)\n"));
769 my_printf(p->osd, _T("G <address> - go and break at address\n"));
770 my_printf(p->osd, _T("T [<count>] - trace\n"));
771 my_printf(p->osd, _T("Q - quit\n"));
773 my_printf(p->osd, _T("> <filename> - output logfile\n"));
775 my_printf(p->osd, _T("! reset [cpu] - reset\n"));
776 my_printf(p->osd, _T("! key <code> [<msec>] - press key\n"));
778 my_printf(p->osd, _T("<value> - hexa, decimal(%%d), ascii('a')\n"));
780 my_printf(p->osd, _T("unknown command %s\n"), params[0]);
787 unsigned __stdcall debugger_thread(void *lpx)
789 int debugger_thread(void *lpx)
792 volatile debugger_thread_t *p = (debugger_thread_t *)lpx;
795 DEVICE *cpu = p->vm->get_cpu(p->cpu_index);
796 DEBUGGER *debugger = (DEBUGGER *)cpu->get_debugger();
798 debugger->now_going = false;
799 debugger->now_debugging = true;
800 while(!debugger->now_suspended) {
804 uint32_t prog_addr_mask = cpu->debug_prog_addr_mask();
805 uint32_t data_addr_mask = cpu->debug_data_addr_mask();
807 dasm_addr = cpu->get_next_pc();
809 // initialize console
811 bool cp932 = (p->osd->get_console_code_page() == 932);
813 p->osd->open_console((_TCHAR *)create_string(_T("Debugger - %s"), _T(DEVICE_NAME)));
814 p->osd->set_console_text_attribute(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
815 cpu->debug_regs_info(buffer, 1024);
816 my_printf(p->osd, _T("%s\n"), buffer);
818 p->osd->set_console_text_attribute(FOREGROUND_RED | FOREGROUND_INTENSITY);
819 my_printf(p->osd, _T("breaked at %08X\n"), cpu->get_next_pc());
821 p->osd->set_console_text_attribute(FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
822 cpu->debug_dasm(cpu->get_next_pc(), buffer, 1024);
823 my_printf(p->osd, _T("next\t%08X %s\n"), cpu->get_next_pc(), buffer);
824 p->osd->set_console_text_attribute(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
826 // initialize logfile
829 #define MAX_COMMAND_LEN 64
831 _TCHAR command[MAX_COMMAND_LEN + 1];
832 _TCHAR prev_command[MAX_COMMAND_LEN + 1];
834 memset(prev_command, 0, sizeof(prev_command));
835 while(!p->request_terminate) {
836 my_printf(p->osd, _T("- "));
840 bool enter_done = false;
842 while(!p->request_terminate && !enter_done) {
844 int count = p->osd->read_console_input(ir);
846 for(int i = 0; i < count; i++) {
849 if(chr == '\n' || chr == '\r') {
850 if(ptr == 0 && prev_command[0] != _T('\0')) {
851 memcpy(command, prev_command, sizeof(command));
852 my_printf(p->osd, _T("%s\n"), command);
856 command[ptr] = _T('\0');
857 memcpy(prev_command, command, sizeof(command));
858 my_printf(p->osd, _T("\n"));
862 } else if(chr == 0x08) {
865 my_putch(p->osd, chr);
866 my_putch(p->osd, _T(' '));
867 my_putch(p->osd, chr);
869 } else if(chr >= 0x20 && chr <= 0x7e && ptr < MAX_COMMAND_LEN && !(chr == 0x20 && ptr == 0)) {
870 command[ptr++] = chr;
871 my_putch(p->osd, chr);
877 if(!p->request_terminate && enter_done) {
878 if(debugger_command((debugger_thread_t *)p, command, prev_command, cp932) < 0) break;
884 debugger->now_debugging = debugger->now_going = debugger->now_suspended = false;
889 if(logfile != NULL) {
890 if(logfile->IsOpened()) {
898 p->osd->close_console();
909 void EMU::initialize_debugger()
911 now_debugging = false;
914 void EMU::release_debugger()
919 void EMU::open_debugger(int cpu_index)
921 if(!(now_debugging && debugger_thread_param.cpu_index == cpu_index)) {
923 if(vm->get_cpu(cpu_index) != NULL && vm->get_cpu(cpu_index)->get_debugger() != NULL) {
924 // debugger_thread_param.emu = this;
925 debugger_thread_param.osd = osd;
926 debugger_thread_param.vm = vm;
927 debugger_thread_param.cpu_index = cpu_index;
928 debugger_thread_param.request_terminate = false;
930 if((hDebuggerThread = (HANDLE)_beginthreadex(NULL, 0, debugger_thread, &debugger_thread_param, 0, NULL)) != (HANDLE)0) {
931 #elif !defined(_USE_QT)
932 if((debugger_thread_id = SDL_CreateThread(debugger_thread, "DebuggerThread", (void *)&debugger_thread_param)) != 0) {
935 volatile debugger_thread_t *p = (debugger_thread_t *)(&debugger_thread_param);
938 DEVICE *cpu = p->vm->get_cpu(p->cpu_index);
939 DEBUGGER *debugger = (DEBUGGER *)cpu->get_debugger();
941 debugger->now_going = false;
942 debugger->now_debugging = true;
943 //while(!debugger->now_suspended) {
944 // p->osd->sleep(10);
947 uint32_t prog_addr_mask = cpu->debug_prog_addr_mask();
948 uint32_t data_addr_mask = cpu->debug_data_addr_mask();
950 dasm_addr = cpu->get_next_pc();
952 // initialize console
954 my_stprintf_s(buffer, 1024, _T("Debugger - %s"), _T(DEVICE_NAME));
956 p->osd->open_console(buffer);
958 bool cp932 = (p->osd->get_console_code_page() == 932);
960 p->osd->set_console_text_attribute(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
961 cpu->debug_regs_info(buffer, 1024);
962 my_printf(p->osd, _T("%s\n"), buffer);
964 p->osd->set_console_text_attribute(FOREGROUND_RED | FOREGROUND_INTENSITY);
965 my_printf(p->osd, _T("breaked at %08X\n"), cpu->get_next_pc());
967 p->osd->set_console_text_attribute(FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
968 cpu->debug_dasm(cpu->get_next_pc(), buffer, 1024);
969 my_printf(p->osd, _T("next\t%08X %s\n"), cpu->get_next_pc(), buffer);
970 p->osd->set_console_text_attribute(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
972 // initialize logfile
973 if(logfile != NULL && logfile->IsOpened()) {
980 now_debugging = true;
986 void EMU::close_debugger()
989 if(debugger_thread_param.running) {
990 debugger_thread_param.request_terminate = true;
993 WaitForSingleObject(hDebuggerThread, INFINITE);
994 CloseHandle(hDebuggerThread);
995 #elif !defined(_USE_QT)
996 //pthread_join(debugger_thread_id, NULL);
997 SDL_DetachThread(debugger_thread_id);
999 volatile debugger_thread_t *p = (debugger_thread_t *)(&debugger_thread_param);
1002 if(logfile != NULL && logfile->IsOpened()) {
1005 // initialize logfile
1009 now_debugging = false;
1013 bool EMU::is_debugger_enabled(int cpu_index)
1015 return (vm->get_cpu(cpu_index) != NULL && vm->get_cpu(cpu_index)->get_debugger() != NULL);