|
|
1.1 ! root 1: /* ! 2: Hatari - debugcpu.c ! 3: ! 4: This file is distributed under the GNU Public License, version 2 or at ! 5: your option any later version. Read the file gpl.txt for details. ! 6: ! 7: debugcpu.c - function needed for the CPU debugging tasks like memory ! 8: and register dumps. ! 9: */ ! 10: const char DebugCpu_fileid[] = "Hatari debugcpu.c : " __DATE__ " " __TIME__; ! 11: ! 12: #include <stdio.h> ! 13: #include <ctype.h> ! 14: #include "config.h" ! 15: ! 16: #include "main.h" ! 17: #include "breakcond.h" ! 18: #include "configuration.h" ! 19: #include "debugui.h" ! 20: #include "debug_priv.h" ! 21: #include "debugcpu.h" ! 22: #include "evaluate.h" ! 23: #include "hatari-glue.h" ! 24: #include "log.h" ! 25: #include "m68000.h" ! 26: #include "profile.h" ! 27: #include "str.h" ! 28: #include "symbols.h" ! 29: #include "68kDisass.h" ! 30: #include "cpummu.h" ! 31: #include "cpummu030.h" ! 32: ! 33: #define MEMDUMP_COLS 16 /* memdump, number of bytes per row */ ! 34: #define NON_PRINT_CHAR '.' /* character to display for non-printables */ ! 35: ! 36: static Uint32 disasm_addr=0; /* disasm address */ ! 37: static Uint32 memdump_addr=0; /* memdump address */ ! 38: ! 39: static bool bCpuProfiling; /* Whether CPU profiling is activated */ ! 40: static int nCpuActiveCBs = 0; /* Amount of active conditional breakpoints */ ! 41: static int nCpuSteps = 0; /* Amount of steps for CPU single-stepping */ ! 42: ! 43: Uint32 DBGMemory_ReadLong(Uint32 addr) { ! 44: switch (ConfigureParams.System.nCpuLevel) { ! 45: case 3: return get_long_mmu030(addr); ! 46: case 4: return get_long_mmu040(addr); ! 47: default: return 0; ! 48: } ! 49: } ! 50: ! 51: Uint16 DBGMemory_ReadWord(Uint32 addr) { ! 52: switch (ConfigureParams.System.nCpuLevel) { ! 53: case 3: return get_word_mmu030(addr); ! 54: case 4: return get_word_mmu040(addr); ! 55: default: return 0; ! 56: } ! 57: } ! 58: ! 59: Uint8 DBGMemory_ReadByte(Uint32 addr) { ! 60: switch (ConfigureParams.System.nCpuLevel) { ! 61: case 3: return get_byte_mmu030(addr); ! 62: case 4: return get_byte_mmu040(addr); ! 63: default: return 0; ! 64: } ! 65: } ! 66: ! 67: void DBGMemory_WriteLong(Uint32 addr, Uint32 val) { ! 68: switch (ConfigureParams.System.nCpuLevel) { ! 69: case 3: put_long_mmu030(addr, val); break; ! 70: case 4: put_long_mmu040(addr, val); break; ! 71: default: break; ! 72: } ! 73: } ! 74: ! 75: void DBGMemory_WriteWord(Uint32 addr, Uint16 val) { ! 76: switch (ConfigureParams.System.nCpuLevel) { ! 77: case 3: put_word_mmu030(addr, val); break; ! 78: case 4: put_word_mmu040(addr, val); break; ! 79: default: break; ! 80: } ! 81: } ! 82: ! 83: void DBGMemory_WriteByte(Uint32 addr, Uint8 val) { ! 84: switch (ConfigureParams.System.nCpuLevel) { ! 85: case 3: put_byte_mmu030(addr, val); break; ! 86: case 4: put_byte_mmu040(addr, val); break; ! 87: default: break; ! 88: } ! 89: } ! 90: ! 91: /** ! 92: * Load a binary file to a memory address. ! 93: */ ! 94: static int DebugCpu_LoadBin(int nArgc, char *psArgs[]) ! 95: { ! 96: FILE *fp; ! 97: unsigned char c; ! 98: Uint32 address; ! 99: int i=0; ! 100: ! 101: if (nArgc < 3) ! 102: { ! 103: DebugUI_PrintCmdHelp(psArgs[0]); ! 104: return DEBUGGER_CMDDONE; ! 105: } ! 106: ! 107: if (!Eval_Number(psArgs[2], &address)) ! 108: { ! 109: fprintf(stderr, "Invalid address!\n"); ! 110: return DEBUGGER_CMDDONE; ! 111: } ! 112: ! 113: if ((fp = fopen(psArgs[1], "rb")) == NULL) ! 114: { ! 115: fprintf(stderr, "Cannot open file '%s'!\n", psArgs[1]); ! 116: return DEBUGGER_CMDDONE; ! 117: } ! 118: ! 119: c = fgetc(fp); ! 120: while (!feof(fp)) ! 121: { ! 122: i++; ! 123: DBGMemory_WriteByte(address++, c); ! 124: c = fgetc(fp); ! 125: } ! 126: fprintf(stderr," Read 0x%x bytes.\n", i); ! 127: fclose(fp); ! 128: ! 129: return DEBUGGER_CMDDONE; ! 130: } ! 131: ! 132: ! 133: /** ! 134: * Dump memory from an address to a binary file. ! 135: */ ! 136: static int DebugCpu_SaveBin(int nArgc, char *psArgs[]) ! 137: { ! 138: FILE *fp; ! 139: unsigned char c; ! 140: Uint32 address; ! 141: Uint32 bytes, i = 0; ! 142: ! 143: if (nArgc < 4) ! 144: { ! 145: DebugUI_PrintCmdHelp(psArgs[0]); ! 146: return DEBUGGER_CMDDONE; ! 147: } ! 148: ! 149: if (!Eval_Number(psArgs[2], &address)) ! 150: { ! 151: fprintf(stderr, " Invalid address!\n"); ! 152: return DEBUGGER_CMDDONE; ! 153: } ! 154: ! 155: if (!Eval_Number(psArgs[3], &bytes)) ! 156: { ! 157: fprintf(stderr, " Invalid length!\n"); ! 158: return DEBUGGER_CMDDONE; ! 159: } ! 160: ! 161: if ((fp = fopen(psArgs[1], "wb")) == NULL) ! 162: { ! 163: fprintf(stderr," Cannot open file '%s'!\n", psArgs[1]); ! 164: return DEBUGGER_CMDDONE; ! 165: } ! 166: ! 167: while (i < bytes) ! 168: { ! 169: c = DBGMemory_ReadByte(address++); ! 170: fputc(c, fp); ! 171: i++; ! 172: } ! 173: fclose(fp); ! 174: fprintf(stderr, " Wrote 0x%x bytes.\n", bytes); ! 175: ! 176: return DEBUGGER_CMDDONE; ! 177: } ! 178: ! 179: ! 180: /** ! 181: * Check whether given address matches any CPU symbol and whether ! 182: * there's profiling information available for it. If yes, show it. ! 183: */ ! 184: static void DebugCpu_ShowAddressInfo(Uint32 addr) ! 185: { ! 186: Uint32 count, cycles; ! 187: const char *symbol; ! 188: bool shown = false; ! 189: ! 190: symbol = Symbols_GetByCpuAddress(addr); ! 191: if (symbol) ! 192: { ! 193: fprintf(debugOutput, "%s", symbol); ! 194: shown = true; ! 195: } ! 196: if (Profile_CpuAddressData(addr, &count, &cycles)) ! 197: { ! 198: fprintf(debugOutput, "%s%d/%d times/cycles", ! 199: (shown ? ", " : ""), count, cycles); ! 200: shown = true; ! 201: } ! 202: if (shown) ! 203: fprintf(debugOutput, ":\n"); ! 204: } ! 205: ! 206: /** ! 207: * Dissassemble - arg = starting address, or PC. ! 208: */ ! 209: int DebugCpu_DisAsm(int nArgc, char *psArgs[]) ! 210: { ! 211: Uint32 disasm_upper = 0; ! 212: int insts, max_insts; ! 213: uaecptr nextpc; ! 214: FILE* mydebugOutput=debugOutput; ! 215: ! 216: if (nArgc > 1) ! 217: { ! 218: switch (Eval_Range(psArgs[1], &disasm_addr, &disasm_upper, false)) ! 219: { ! 220: case -1: ! 221: /* invalid value(s) */ ! 222: return DEBUGGER_CMDDONE; ! 223: case 0: ! 224: /* single value */ ! 225: break; ! 226: case 1: ! 227: /* range */ ! 228: break; ! 229: } ! 230: if (nArgc > 2) { ! 231: mydebugOutput=fopen(psArgs[2],"w"); ! 232: if (mydebugOutput==NULL) ! 233: { ! 234: fprintf(debugOutput,"Cannot open %s abort\n",psArgs[2]); ! 235: return DEBUGGER_CMDDONE; ! 236: } ! 237: } ! 238: } ! 239: else ! 240: { ! 241: /* continue */ ! 242: if(!disasm_addr) ! 243: disasm_addr = M68000_GetPC(); ! 244: } ! 245: ! 246: /* limit is topmost address or instruction count */ ! 247: if (disasm_upper) { ! 248: max_insts = INT_MAX; ! 249: } else { ! 250: // max_insts = ConfigureParams.Debugger.nDisasmLines; ! 251: max_insts = 5; ! 252: disasm_upper = 0xFFFFFFFF; ! 253: } ! 254: ! 255: /* output a range */ ! 256: for (insts = 0; insts < max_insts && disasm_addr < disasm_upper; insts++) ! 257: { ! 258: DebugCpu_ShowAddressInfo(disasm_addr); ! 259: Disasm(debugOutput, (uaecptr)disasm_addr, &nextpc, 1, DISASM_ENGINE_UAE); ! 260: disasm_addr = nextpc; ! 261: } ! 262: fflush(mydebugOutput); ! 263: if (mydebugOutput!=debugOutput) {fclose(mydebugOutput);} ! 264: ! 265: return DEBUGGER_CMDCONT; ! 266: } ! 267: ! 268: ! 269: /** ! 270: * Readline match callback to list register names usable within debugger. ! 271: * STATE = 0 -> different text from previous one. ! 272: * Return next match or NULL if no matches. ! 273: */ ! 274: static char *DebugCpu_MatchRegister(const char *text, int state) ! 275: { ! 276: static const char regs[][3] = { ! 277: "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", ! 278: "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", ! 279: "pc", "sr" ! 280: }; ! 281: static int i, len; ! 282: ! 283: if (!state) ! 284: { ! 285: /* first match */ ! 286: i = 0; ! 287: len = strlen(text); ! 288: if (len > 2) ! 289: return NULL; ! 290: } ! 291: /* next match */ ! 292: while (i < ARRAYSIZE(regs)) { ! 293: if (strncasecmp(regs[i++], text, len) == 0) ! 294: return (strdup(regs[i-1])); ! 295: } ! 296: return NULL; ! 297: } ! 298: ! 299: ! 300: /** ! 301: * Set address of the named register to given argument. ! 302: * Return register size in bits or zero for uknown register name. ! 303: * Handles D0-7 data and A0-7 address registers, but not PC & SR ! 304: * registers as they need to be accessed using UAE accessors. ! 305: */ ! 306: int DebugCpu_GetRegisterAddress(const char *reg, Uint32 **addr) ! 307: { ! 308: char r0, r1; ! 309: if (!reg[0] || !reg[1] || reg[2]) ! 310: return 0; ! 311: ! 312: r0 = toupper(reg[0]); ! 313: r1 = toupper(reg[1]); ! 314: ! 315: if (r0 == 'D') /* Data regs? */ ! 316: { ! 317: if (r1 >= '0' && r1 <= '7') ! 318: { ! 319: *addr = &(Regs[REG_D0 + r1 - '0']); ! 320: return 32; ! 321: } ! 322: fprintf(stderr,"\tBad data register, valid values are 0-7\n"); ! 323: return 0; ! 324: } ! 325: if(r0 == 'A') /* Address regs? */ ! 326: { ! 327: if (r1 >= '0' && r1 <= '7') ! 328: { ! 329: *addr = &(Regs[REG_A0 + r1 - '0']); ! 330: return 32; ! 331: } ! 332: fprintf(stderr,"\tBad address register, valid values are 0-7\n"); ! 333: return 0; ! 334: } ! 335: return 0; ! 336: } ! 337: ! 338: ! 339: /** ! 340: * Dump or set CPU registers ! 341: */ ! 342: int DebugCpu_Register(int nArgc, char *psArgs[]) ! 343: { ! 344: char reg[3], *assign; ! 345: Uint32 value; ! 346: char *arg; ! 347: ! 348: /* If no parameter has been given, simply dump all registers */ ! 349: if (nArgc == 1) ! 350: { ! 351: uaecptr nextpc; ! 352: /* use the UAE function instead */ ! 353: m68k_dumpstate(&nextpc); ! 354: fflush(debugOutput); ! 355: return DEBUGGER_CMDDONE; ! 356: } ! 357: ! 358: arg = psArgs[1]; ! 359: ! 360: assign = strchr(arg, '='); ! 361: if (!assign) ! 362: { ! 363: goto error_msg; ! 364: } ! 365: ! 366: *assign++ = '\0'; ! 367: if (!Eval_Number(Str_Trim(assign), &value)) ! 368: { ! 369: goto error_msg; ! 370: } ! 371: ! 372: arg = Str_Trim(arg); ! 373: if (strlen(arg) != 2) ! 374: { ! 375: goto error_msg; ! 376: } ! 377: reg[0] = toupper(arg[0]); ! 378: reg[1] = toupper(arg[1]); ! 379: reg[2] = '\0'; ! 380: ! 381: /* set SR and update conditional flags for the UAE CPU core. */ ! 382: if (reg[0] == 'S' && reg[1] == 'R') ! 383: { ! 384: M68000_SetSR(value); ! 385: } ! 386: else if (reg[0] == 'P' && reg[1] == 'C') /* set PC? */ ! 387: { ! 388: M68000_SetPC(value); ! 389: } ! 390: else ! 391: { ! 392: Uint32 *regaddr; ! 393: /* check&set data and address registers */ ! 394: if (DebugCpu_GetRegisterAddress(reg, ®addr)) ! 395: { ! 396: *regaddr = value; ! 397: } ! 398: else ! 399: { ! 400: goto error_msg; ! 401: } ! 402: } ! 403: return DEBUGGER_CMDDONE; ! 404: ! 405: error_msg: ! 406: fprintf(stderr,"\tError, usage: r or r xx=yyyy\n\tWhere: xx=A0-A7, D0-D7, PC or SR.\n"); ! 407: return DEBUGGER_CMDDONE; ! 408: } ! 409: ! 410: ! 411: /** ! 412: * CPU wrapper for BreakAddr_Command(). ! 413: */ ! 414: static int DebugCpu_BreakAddr(int nArgc, char *psArgs[]) ! 415: { ! 416: BreakAddr_Command(psArgs[1], false); ! 417: return DEBUGGER_CMDDONE; ! 418: } ! 419: ! 420: /** ! 421: * CPU wrapper for BreakCond_Command(). ! 422: */ ! 423: static int DebugCpu_BreakCond(int nArgc, char *psArgs[]) ! 424: { ! 425: BreakCond_Command(psArgs[1], false); ! 426: return DEBUGGER_CMDDONE; ! 427: } ! 428: ! 429: /** ! 430: * CPU wrapper for Profile_Command(). ! 431: */ ! 432: static int DebugCpu_Profile(int nArgc, char *psArgs[]) ! 433: { ! 434: Profile_Command(nArgc, psArgs, false); ! 435: return DEBUGGER_CMDDONE; ! 436: } ! 437: ! 438: /** ! 439: * Do a memory dump, args = starting address. ! 440: */ ! 441: int DebugCpu_MemDump(int nArgc, char *psArgs[]) ! 442: { ! 443: int i; ! 444: char c; ! 445: Uint32 memdump_upper = 0; ! 446: ! 447: if (nArgc > 1) ! 448: { ! 449: switch (Eval_Range(psArgs[1], &memdump_addr, &memdump_upper, false)) ! 450: { ! 451: case -1: ! 452: /* invalid value(s) */ ! 453: return DEBUGGER_CMDDONE; ! 454: case 0: ! 455: /* single value */ ! 456: break; ! 457: case 1: ! 458: /* range */ ! 459: break; ! 460: } ! 461: } /* continue */ ! 462: ! 463: if (!memdump_upper) ! 464: { ! 465: memdump_upper = memdump_addr + MEMDUMP_COLS * ConfigureParams.Debugger.nMemdumpLines; ! 466: } ! 467: ! 468: while (memdump_addr < memdump_upper) ! 469: { ! 470: fprintf(debugOutput, "%6.6X: ", memdump_addr); /* print address */ ! 471: for (i = 0; i < MEMDUMP_COLS; i++) /* print hex data */ ! 472: fprintf(debugOutput, "%2.2x ", DBGMemory_ReadByte(memdump_addr++)); ! 473: fprintf(debugOutput, " "); /* print ASCII data */ ! 474: for (i = 0; i < MEMDUMP_COLS; i++) ! 475: { ! 476: c = DBGMemory_ReadByte(memdump_addr-MEMDUMP_COLS+i); ! 477: if(!isprint((unsigned)c)) ! 478: c = NON_PRINT_CHAR; /* non-printable as dots */ ! 479: fprintf(debugOutput,"%c", c); ! 480: } ! 481: fprintf(debugOutput, "\n"); /* newline */ ! 482: } /* while */ ! 483: fflush(debugOutput); ! 484: ! 485: return DEBUGGER_CMDCONT; ! 486: } ! 487: ! 488: ! 489: /** ! 490: * Command: Write to memory, arg = starting address, followed by bytes. ! 491: */ ! 492: static int DebugCpu_MemWrite(int nArgc, char *psArgs[]) ! 493: { ! 494: int i, numBytes; ! 495: Uint32 write_addr, d; ! 496: unsigned char bytes[256]; /* store bytes */ ! 497: ! 498: if (nArgc < 3) ! 499: { ! 500: DebugUI_PrintCmdHelp(psArgs[0]); ! 501: return DEBUGGER_CMDDONE; ! 502: } ! 503: ! 504: /* Read address */ ! 505: if (!Eval_Number(psArgs[1], &write_addr)) ! 506: { ! 507: fprintf(stderr, "Bad address!\n"); ! 508: return DEBUGGER_CMDDONE; ! 509: } ! 510: ! 511: numBytes = 0; ! 512: ! 513: /* get bytes data */ ! 514: for (i = 2; i < nArgc; i++) ! 515: { ! 516: if (!Eval_Number(psArgs[i], &d) || d > 255) ! 517: { ! 518: fprintf(stderr, "Bad byte argument: '%s'!\n", psArgs[i]); ! 519: return DEBUGGER_CMDDONE; ! 520: } ! 521: ! 522: bytes[numBytes] = d & 0x0FF; ! 523: numBytes++; ! 524: } ! 525: ! 526: /* write the data */ ! 527: for (i = 0; i < numBytes; i++) ! 528: DBGMemory_WriteByte(write_addr + i, bytes[i]); ! 529: ! 530: return DEBUGGER_CMDDONE; ! 531: } ! 532: ! 533: ! 534: /** ! 535: * Command: Continue CPU emulation / single-stepping ! 536: */ ! 537: static int DebugCpu_Continue(int nArgc, char *psArgv[]) ! 538: { ! 539: int steps = 0; ! 540: ! 541: if (nArgc > 1) ! 542: { ! 543: steps = atoi(psArgv[1]); ! 544: } ! 545: if (steps <= 0) ! 546: { ! 547: nCpuSteps = 0; ! 548: fprintf(stderr,"Returning to emulation...\n"); ! 549: return DEBUGGER_END; ! 550: } ! 551: nCpuSteps = steps; ! 552: fprintf(stderr,"Returning to emulation for %i CPU instructions...\n", steps); ! 553: return DEBUGGER_END; ! 554: } ! 555: ! 556: ! 557: /** ! 558: * This function is called after each CPU instruction when debugging is enabled. ! 559: */ ! 560: void DebugCpu_Check(void) ! 561: { ! 562: if (bCpuProfiling) ! 563: { ! 564: Profile_CpuUpdate(); ! 565: } ! 566: if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM)) ! 567: { ! 568: DebugCpu_ShowAddressInfo(M68000_GetPC()); ! 569: } ! 570: if (nCpuActiveCBs) ! 571: { ! 572: if (BreakCond_MatchCpu()) ! 573: DebugUI(); ! 574: } ! 575: if (nCpuSteps) ! 576: { ! 577: nCpuSteps -= 1; ! 578: if (nCpuSteps == 0) ! 579: DebugUI(); ! 580: } ! 581: } ! 582: ! 583: /** ! 584: * Should be called before returning back emulation to tell the CPU core ! 585: * to call us after each instruction if "real-time" debugging like ! 586: * breakpoints has been set. ! 587: */ ! 588: void DebugCpu_SetDebugging(void) ! 589: { ! 590: bCpuProfiling = Profile_CpuStart(); ! 591: nCpuActiveCBs = BreakCond_BreakPointCount(false); ! 592: ! 593: if (nCpuActiveCBs || nCpuSteps || bCpuProfiling) ! 594: M68000_SetSpecial(SPCFLAG_DEBUGGER); ! 595: else ! 596: M68000_UnsetSpecial(SPCFLAG_DEBUGGER); ! 597: } ! 598: ! 599: ! 600: static const dbgcommand_t cpucommands[] = ! 601: { ! 602: { NULL, NULL, "CPU commands", NULL, NULL, NULL, false }, ! 603: /* NULL as match function will complete file names */ ! 604: { DebugCpu_BreakAddr, Symbols_MatchCpuCodeAddress, ! 605: "address", "a", ! 606: "set CPU PC address breakpoints", ! 607: BreakAddr_Description, ! 608: true }, ! 609: { DebugCpu_BreakCond, BreakCond_MatchCpuVariable, ! 610: "breakpoint", "b", ! 611: "set/remove/list conditional CPU breakpoints", ! 612: BreakCond_Description, ! 613: true }, ! 614: { DebugCpu_DisAsm, Symbols_MatchCpuCodeAddress, ! 615: "disasm", "d", ! 616: "disassemble from PC, or given address", ! 617: "[<start address>[-<end address>]]\n" ! 618: "\tIf no address is given, this command disassembles from the last\n" ! 619: "\tposition or from current PC if no last position is available.", ! 620: false }, ! 621: { DebugCpu_Profile, Profile_Match, ! 622: "profile", "", ! 623: "profile CPU code", ! 624: Profile_Description, ! 625: false }, ! 626: { DebugCpu_Register, DebugCpu_MatchRegister, ! 627: "cpureg", "r", ! 628: "dump register values or set register to value", ! 629: "[REG=value]\n" ! 630: "\tSet CPU register to value or dumps all register if no parameter\n" ! 631: "\thas been specified.", ! 632: true }, ! 633: { DebugCpu_MemDump, Symbols_MatchCpuDataAddress, ! 634: "memdump", "m", ! 635: "dump memory", ! 636: "[<start address>[-<end address>]]\n" ! 637: "\tdump memory at address or continue dump from previous address.", ! 638: false }, ! 639: { DebugCpu_MemWrite, Symbols_MatchCpuAddress, ! 640: "memwrite", "w", ! 641: "write bytes to memory", ! 642: "address byte1 [byte2 ...]\n" ! 643: "\tWrite bytes to a memory address, bytes are space separated\n" ! 644: "\thexadecimals.", ! 645: false }, ! 646: { DebugCpu_LoadBin, NULL, ! 647: "loadbin", "l", ! 648: "load a file into memory", ! 649: "filename address\n" ! 650: "\tLoad the file <filename> into memory starting at <address>.", ! 651: false }, ! 652: { DebugCpu_SaveBin, NULL, ! 653: "savebin", "s", ! 654: "save memory to a file", ! 655: "filename address length\n" ! 656: "\tSave the memory block at <address> with given <length> to\n" ! 657: "\tthe file <filename>.", ! 658: false }, ! 659: { Symbols_Command, NULL, ! 660: "symbols", "", ! 661: "load CPU symbols & their addresses", ! 662: Symbols_Description, ! 663: false }, ! 664: { DebugCpu_Continue, NULL, ! 665: "cont", "c", ! 666: "continue emulation / CPU single-stepping", ! 667: "[steps]\n" ! 668: "\tLeave debugger and continue emulation for <steps> CPU instructions\n" ! 669: "\tor forever if no steps have been specified.", ! 670: false } ! 671: }; ! 672: ! 673: ! 674: /** ! 675: * Should be called when debugger is first entered to initialize ! 676: * CPU debugging variables. ! 677: * ! 678: * if you want disassembly or memdumping to start/continue from ! 679: * specific address, you can set them here. If disassembly ! 680: * address is zero, disassembling starts from PC. ! 681: * ! 682: * returns number of CPU commands and pointer to array of them. ! 683: */ ! 684: int DebugCpu_Init(const dbgcommand_t **table) ! 685: { ! 686: memdump_addr = 0; ! 687: disasm_addr = 0; ! 688: ! 689: *table = cpucommands; ! 690: return ARRAYSIZE(cpucommands); ! 691: } ! 692: ! 693: /** ! 694: * Should be called when debugger is re-entered to reset ! 695: * relevant CPU debugging variables. ! 696: */ ! 697: void DebugCpu_InitSession(void) ! 698: { ! 699: disasm_addr = M68000_GetPC(); ! 700: Profile_CpuStop(); ! 701: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.