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