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