|
|
1.1 ! root 1: /* ! 2: Hatari - debugdsp.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: debugdsp.c - function needed for the DSP debugging tasks like memory ! 8: and register dumps. ! 9: */ ! 10: const char DebugDsp_fileid[] = "Hatari debugdsp.c : " __DATE__ " " __TIME__; ! 11: ! 12: #include <stdio.h> ! 13: ! 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 "debugdsp.h" ! 22: #include "dsp.h" ! 23: #include "evaluate.h" ! 24: #include "memorySnapShot.h" ! 25: #include "str.h" ! 26: #include "symbols.h" ! 27: ! 28: static Uint16 dsp_disasm_addr; /* DSP disasm address */ ! 29: static Uint16 dsp_memdump_addr; /* DSP memdump address */ ! 30: static char dsp_mem_space = 'P'; /* X, Y, P */ ! 31: ! 32: static int nDspActiveCBs = 0; /* Amount of active conditional breakpoints */ ! 33: static int nDspSteps = 0; /* Amount of steps for DSP single-stepping */ ! 34: ! 35: ! 36: /** ! 37: * Readline match callback to list register names usable within debugger. ! 38: * STATE = 0 -> different text from previous one. ! 39: * Return next match or NULL if no matches. ! 40: */ ! 41: static char *DebugDsp_MatchRegister(const char *text, int state) ! 42: { ! 43: static const char regs[][4] = { ! 44: "a0", "a1", "a2", "b0", "b1", "b2", "la", "lc", ! 45: "m0", "m1", "m2", "m3", "m4", "m5", "m6", "m7", ! 46: "n0", "n1", "n2", "n3", "n4", "n5", "n6", "n7", ! 47: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", ! 48: "omr", "pc", "sp", "sr", "ssh", "ssl", ! 49: "x0", "x1", "y0", "y1", ! 50: }; ! 51: static int i, len; ! 52: ! 53: if (!state) ! 54: { ! 55: /* first match */ ! 56: i = 0; ! 57: len = strlen(text); ! 58: if (len > 2) ! 59: return NULL; ! 60: } ! 61: /* next match */ ! 62: while (i < ARRAYSIZE(regs)) { ! 63: if (strncasecmp(regs[i++], text, len) == 0) ! 64: return (strdup(regs[i-1])); ! 65: } ! 66: return NULL; ! 67: } ! 68: ! 69: /** ! 70: * Command: Dump or set a DSP register ! 71: */ ! 72: int DebugDsp_Register(int nArgc, char *psArgs[]) ! 73: { ! 74: char *assign; ! 75: Uint32 value; ! 76: char *arg; ! 77: ! 78: if (!bDspEnabled) ! 79: { ! 80: fprintf(stderr, "DSP isn't present or initialized.\n"); ! 81: return DEBUGGER_CMDDONE; ! 82: } ! 83: ! 84: if (nArgc == 1) ! 85: { ! 86: /* No parameter - dump all registers */ ! 87: DSP_DisasmRegisters(); ! 88: return DEBUGGER_CMDDONE; ! 89: } ! 90: arg = psArgs[1]; ! 91: ! 92: assign = strchr(arg, '='); ! 93: if (!assign) ! 94: goto error_msg; ! 95: ! 96: *assign++ = '\0'; ! 97: if (!Eval_Number(Str_Trim(assign), &value)) ! 98: goto error_msg; ! 99: ! 100: if (DSP_Disasm_SetRegister(Str_Trim(arg), value)) ! 101: return DEBUGGER_CMDDONE; ! 102: ! 103: error_msg: ! 104: fprintf(stderr,"\tError, usage: dr or dr xx=yyyy\n" ! 105: "\tWhere: xx=A0-A2, B0-B2, X0, X1, Y0, Y1, R0-R7,\n" ! 106: "\t N0-N7, M0-M7, LA, LC, PC, SR, SP, OMR, SSH, SSL\n"); ! 107: ! 108: return DEBUGGER_CMDDONE; ! 109: } ! 110: ! 111: ! 112: /** ! 113: * Check whether given address matches any DSP symbol, if yes, ! 114: * show the matching symbol information. ! 115: */ ! 116: static void DebugDsp_ShowMatchedSymbol(Uint32 addr) ! 117: { ! 118: const char *symbol = Symbols_GetByDspAddress(addr); ! 119: if (symbol) ! 120: fprintf(debugOutput, "%s:\n", symbol); ! 121: } ! 122: ! 123: ! 124: /** ! 125: * DSP dissassemble - arg = starting address/range, or PC. ! 126: */ ! 127: int DebugDsp_DisAsm(int nArgc, char *psArgs[]) ! 128: { ! 129: Uint32 lower, upper; ! 130: Uint16 dsp_disasm_upper = 0; ! 131: ! 132: if (!bDspEnabled) ! 133: { ! 134: fprintf(stderr, "DSP isn't present or initialized.\n"); ! 135: return DEBUGGER_CMDDONE; ! 136: } ! 137: ! 138: if (nArgc > 1) ! 139: { ! 140: switch (Eval_Range(psArgs[1], &lower, &upper)) ! 141: { ! 142: case -1: ! 143: /* invalid value(s) */ ! 144: return DEBUGGER_CMDDONE; ! 145: case 0: ! 146: /* single value */ ! 147: break; ! 148: case 1: ! 149: /* range */ ! 150: if (upper > 0xFFFF) ! 151: { ! 152: fprintf(stderr,"Invalid address 0x%x!\n", upper); ! 153: return DEBUGGER_CMDDONE; ! 154: } ! 155: dsp_disasm_upper = upper; ! 156: break; ! 157: } ! 158: ! 159: if (lower > 0xFFFF) ! 160: { ! 161: fprintf(stderr,"Invalid address 0x%x!\n", lower); ! 162: return DEBUGGER_CMDDONE; ! 163: } ! 164: dsp_disasm_addr = lower; ! 165: } ! 166: else ! 167: { ! 168: /* continue */ ! 169: if(!dsp_disasm_addr) ! 170: { ! 171: dsp_disasm_addr = DSP_GetPC(); ! 172: } ! 173: } ! 174: if (!dsp_disasm_upper) ! 175: { ! 176: int lines = ConfigureParams.Debugger.nDisasmLines; ! 177: if ( dsp_disasm_addr < (0xFFFF - lines)) ! 178: dsp_disasm_upper = dsp_disasm_addr + lines; ! 179: else ! 180: dsp_disasm_upper = 0xFFFF; ! 181: } ! 182: printf("DSP disasm 0x%hx-0x%hx:\n", dsp_disasm_addr, dsp_disasm_upper); ! 183: while (dsp_disasm_addr < dsp_disasm_upper) { ! 184: DebugDsp_ShowMatchedSymbol(dsp_disasm_addr); ! 185: dsp_disasm_addr = DSP_DisasmAddress(dsp_disasm_addr, dsp_disasm_addr); ! 186: } ! 187: ! 188: return DEBUGGER_CMDCONT; ! 189: } ! 190: ! 191: ! 192: /** ! 193: * Do a DSP memory dump, args = starting address or range. ! 194: * <x|y|p> <address>: dump from X, Y or P, starting from given address, ! 195: * e.g. "x 200" or "p 200-300" ! 196: */ ! 197: int DebugDsp_MemDump(int nArgc, char *psArgs[]) ! 198: { ! 199: Uint32 lower, upper; ! 200: Uint16 dsp_memdump_upper = 0; ! 201: char space; ! 202: ! 203: if (!bDspEnabled) ! 204: { ! 205: fprintf(stderr, "DSP isn't present or initialized.\n"); ! 206: return DEBUGGER_CMDDONE; ! 207: } ! 208: if (nArgc != 1 && nArgc != 3) ! 209: { ! 210: DebugUI_PrintCmdHelp(psArgs[0]); ! 211: return DEBUGGER_CMDDONE; ! 212: } ! 213: ! 214: if (nArgc == 3) ! 215: { ! 216: space = toupper(psArgs[1][0]); ! 217: switch (space) ! 218: { ! 219: case 'X': ! 220: case 'Y': ! 221: case 'P': ! 222: break; ! 223: default: ! 224: fprintf(stderr,"Invalid DSP address space '%c'!\n", space); ! 225: return DEBUGGER_CMDDONE; ! 226: } ! 227: switch (Eval_Range(psArgs[2], &lower, &upper)) ! 228: { ! 229: case -1: ! 230: /* invalid value(s) */ ! 231: return DEBUGGER_CMDDONE; ! 232: case 0: ! 233: /* single value */ ! 234: break; ! 235: case 1: ! 236: /* range */ ! 237: if (upper > 0xFFFF) ! 238: { ! 239: fprintf(stderr,"Invalid address 0x%x!\n", upper); ! 240: return DEBUGGER_CMDDONE; ! 241: } ! 242: dsp_memdump_upper = upper; ! 243: break; ! 244: } ! 245: if (lower > 0xFFFF) ! 246: { ! 247: fprintf(stderr,"Invalid address 0x%x!\n", lower); ! 248: return DEBUGGER_CMDDONE; ! 249: } ! 250: dsp_memdump_addr = lower; ! 251: dsp_mem_space = space; ! 252: } /* continue */ ! 253: ! 254: if (!dsp_memdump_upper) ! 255: { ! 256: int lines = ConfigureParams.Debugger.nMemdumpLines; ! 257: if ( dsp_memdump_addr < (0xFFFF - lines)) ! 258: dsp_memdump_upper = dsp_memdump_addr + lines; ! 259: else ! 260: dsp_memdump_upper = 0xFFFF; ! 261: } ! 262: ! 263: printf("DSP memdump from 0x%hx in '%c' address space:\n", dsp_memdump_addr, dsp_mem_space); ! 264: dsp_memdump_addr = DSP_DisasmMemory(dsp_memdump_addr, dsp_memdump_upper, dsp_mem_space); ! 265: ! 266: return DEBUGGER_CMDCONT; ! 267: } ! 268: ! 269: ! 270: /** ! 271: * Command: Continue DSP emulation / single-stepping ! 272: */ ! 273: static int DebugDsp_Continue(int nArgc, char *psArgv[]) ! 274: { ! 275: int steps = 0; ! 276: ! 277: if (nArgc > 1) ! 278: { ! 279: steps = atoi(psArgv[1]); ! 280: } ! 281: if (steps <= 0) ! 282: { ! 283: nDspSteps = 0; ! 284: fprintf(stderr,"Returning to emulation...\n"); ! 285: return DEBUGGER_END; ! 286: } ! 287: nDspSteps = steps; ! 288: fprintf(stderr,"Returning to emulation for %i DSP instructions...\n", steps); ! 289: return DEBUGGER_END; ! 290: } ! 291: ! 292: ! 293: /** ! 294: * DSP wrapper for BreakAddr_Command/BreakPointCount, returns DEBUGGER_END ! 295: */ ! 296: static int DebugDsp_BreakAddr(int nArgc, char *psArgs[]) ! 297: { ! 298: BreakAddr_Command(psArgs[1], true); ! 299: return DEBUGGER_CMDDONE; ! 300: } ! 301: ! 302: /** ! 303: * DSP wrapper for BreakCond_Command/BreakPointCount, returns DEBUGGER_END ! 304: */ ! 305: static int DebugDsp_BreakCond(int nArgc, char *psArgs[]) ! 306: { ! 307: BreakCond_Command(psArgs[1], true); ! 308: return DEBUGGER_CMDDONE; ! 309: } ! 310: ! 311: ! 312: /** ! 313: * This function is called after each DSP instruction when debugging is enabled. ! 314: */ ! 315: void DebugDsp_Check(void) ! 316: { ! 317: /* TODO: show symbols while disassembling DSP instructions */ ! 318: if (nDspActiveCBs) ! 319: { ! 320: if (BreakCond_MatchDsp()) ! 321: DebugUI(); ! 322: } ! 323: if (nDspSteps) ! 324: { ! 325: nDspSteps -= 1; ! 326: if (nDspSteps == 0) ! 327: DebugUI(); ! 328: } ! 329: } ! 330: ! 331: ! 332: /** ! 333: * Should be called before returning back emulation to tell the DSP core ! 334: * to call us after each instruction if "real-time" debugging like ! 335: * breakpoints has been set. ! 336: */ ! 337: void DebugDsp_SetDebugging(void) ! 338: { ! 339: nDspActiveCBs = BreakCond_BreakPointCount(true); ! 340: if (nDspActiveCBs || nDspSteps) ! 341: DSP_SetDebugging(true); ! 342: else ! 343: DSP_SetDebugging(false); ! 344: } ! 345: ! 346: ! 347: static const dbgcommand_t dspcommands[] = ! 348: { ! 349: { NULL, NULL, "DSP commands", NULL, NULL, NULL, false }, ! 350: { DebugDsp_BreakAddr, Symbols_MatchDspCodeAddress, ! 351: "dspaddress", "da", ! 352: "set DSP PC address breakpoints", ! 353: BreakAddr_Description, ! 354: true }, ! 355: { DebugDsp_BreakCond, BreakCond_MatchDspVariable, ! 356: "dspbreak", "db", ! 357: "set/remove/list conditional DSP breakpoints", ! 358: BreakCond_Description, ! 359: true }, ! 360: { DebugDsp_DisAsm, Symbols_MatchDspCodeAddress, ! 361: "dspdisasm", "dd", ! 362: "disassemble DSP code", ! 363: "[<start address>[-<end address>]]\n" ! 364: "\tDisassemble from DSP-PC, otherwise at given address.", ! 365: false }, ! 366: { DebugDsp_MemDump, Symbols_MatchDspDataAddress, ! 367: "dspmemdump", "dm", ! 368: "dump DSP memory", ! 369: "[<x|y|p> <start address>[-<end address>]]\n" ! 370: "\tdump DSP memory from given memory space and address, or\n" ! 371: "\tcontinue from previous address if not specified.", ! 372: false }, ! 373: { Symbols_Command, NULL, ! 374: "dspsymbols", "", ! 375: "load DSP symbols & their addresses", ! 376: Symbols_Description, ! 377: false }, ! 378: { DebugDsp_Register, DebugDsp_MatchRegister, ! 379: "dspreg", "dr", ! 380: "read/write DSP registers", ! 381: "[REG=value]" ! 382: "\tSet or dump contents of DSP registers.", ! 383: true }, ! 384: { DebugDsp_Continue, NULL, ! 385: "dspcont", "dc", ! 386: "continue emulation / DSP single-stepping", ! 387: "[steps]\n" ! 388: "\tLeave debugger and continue emulation for <steps> DSP instructions\n" ! 389: "\tor forever if no steps have been specified.", ! 390: false } ! 391: }; ! 392: ! 393: ! 394: /** ! 395: * Should be called when debugger is first entered to initialize ! 396: * DSP debugging variables. ! 397: * ! 398: * if you want disassembly or memdumping to start/continue from ! 399: * specific address, you can set them here. If disassembly ! 400: * address is zero, disassembling starts from PC. ! 401: * ! 402: * returns number of DSP commands and pointer to array of them. ! 403: */ ! 404: int DebugDsp_Init(const dbgcommand_t **table) ! 405: { ! 406: dsp_disasm_addr = 0; ! 407: dsp_memdump_addr = 0; ! 408: dsp_mem_space = 'P'; ! 409: ! 410: *table = dspcommands; ! 411: return ARRAYSIZE(dspcommands); ! 412: } ! 413: ! 414: /** ! 415: * Should be called when debugger is re-entered to reset ! 416: * relevant DSP debugging variables. ! 417: */ ! 418: void DebugDsp_InitSession(void) ! 419: { ! 420: dsp_disasm_addr = DSP_GetPC(); ! 421: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.