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