|
|
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.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 root 189: dsp_disasm_addr = DSP_DisasmAddress(dsp_disasm_addr, dsp_disasm_addr);
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:
296:
297: /**
1.1.1.2 root 298: * DSP wrapper for BreakAddr_Command().
1.1 root 299: */
300: static int DebugDsp_BreakAddr(int nArgc, char *psArgs[])
301: {
302: BreakAddr_Command(psArgs[1], true);
303: return DEBUGGER_CMDDONE;
304: }
305:
306: /**
1.1.1.2 root 307: * DSP wrapper for BreakCond_Command().
1.1 root 308: */
309: static int DebugDsp_BreakCond(int nArgc, char *psArgs[])
310: {
311: BreakCond_Command(psArgs[1], true);
312: return DEBUGGER_CMDDONE;
313: }
314:
1.1.1.2 root 315: /**
316: * DSP wrapper for Profile_Command().
317: */
318: static int DebugDsp_Profile(int nArgc, char *psArgs[])
319: {
320: Profile_Command(nArgc, psArgs, true);
321: return DEBUGGER_CMDDONE;
322: }
323:
1.1 root 324:
325: /**
326: * This function is called after each DSP instruction when debugging is enabled.
327: */
328: void DebugDsp_Check(void)
329: {
1.1.1.2 root 330: if (bDspProfiling)
331: {
332: Profile_DspUpdate();
333: }
1.1.1.4 ! root 334: if (LOG_TRACE_LEVEL((TRACE_DSP_DISASM|TRACE_DSP_SYMBOLS)))
! 335: {
! 336: DebugDsp_ShowAddressInfo(DSP_GetPC());
! 337: }
1.1 root 338: if (nDspActiveCBs)
339: {
340: if (BreakCond_MatchDsp())
1.1.1.3 root 341: DebugUI(REASON_DSP_BREAKPOINT);
1.1 root 342: }
343: if (nDspSteps)
344: {
345: nDspSteps -= 1;
346: if (nDspSteps == 0)
1.1.1.3 root 347: DebugUI(REASON_DSP_STEPS);
348: }
349: if (bHistoryEnabled)
350: {
351: History_AddDsp();
1.1 root 352: }
353: }
354:
355:
356: /**
357: * Should be called before returning back emulation to tell the DSP core
358: * to call us after each instruction if "real-time" debugging like
359: * breakpoints has been set.
360: */
361: void DebugDsp_SetDebugging(void)
362: {
1.1.1.2 root 363: bDspProfiling = Profile_DspStart();
1.1 root 364: nDspActiveCBs = BreakCond_BreakPointCount(true);
1.1.1.2 root 365:
1.1.1.4 ! root 366: if (nDspActiveCBs || nDspSteps || bDspProfiling || bHistoryEnabled
! 367: || LOG_TRACE_LEVEL((TRACE_DSP_DISASM|TRACE_DSP_SYMBOLS)))
1.1 root 368: DSP_SetDebugging(true);
369: else
370: DSP_SetDebugging(false);
371: }
372:
373:
374: static const dbgcommand_t dspcommands[] =
375: {
376: { NULL, NULL, "DSP commands", NULL, NULL, NULL, false },
377: { DebugDsp_BreakAddr, Symbols_MatchDspCodeAddress,
378: "dspaddress", "da",
379: "set DSP PC address breakpoints",
380: BreakAddr_Description,
381: true },
382: { DebugDsp_BreakCond, BreakCond_MatchDspVariable,
383: "dspbreak", "db",
384: "set/remove/list conditional DSP breakpoints",
385: BreakCond_Description,
386: true },
387: { DebugDsp_DisAsm, Symbols_MatchDspCodeAddress,
388: "dspdisasm", "dd",
389: "disassemble DSP code",
390: "[<start address>[-<end address>]]\n"
391: "\tDisassemble from DSP-PC, otherwise at given address.",
392: false },
393: { DebugDsp_MemDump, Symbols_MatchDspDataAddress,
394: "dspmemdump", "dm",
395: "dump DSP memory",
396: "[<x|y|p> <start address>[-<end address>]]\n"
397: "\tdump DSP memory from given memory space and address, or\n"
398: "\tcontinue from previous address if not specified.",
399: false },
400: { Symbols_Command, NULL,
401: "dspsymbols", "",
402: "load DSP symbols & their addresses",
403: Symbols_Description,
404: false },
1.1.1.2 root 405: { DebugDsp_Profile, Profile_Match,
406: "dspprofile", "dp",
407: "profile DSP code",
408: Profile_Description,
409: false },
1.1 root 410: { DebugDsp_Register, DebugDsp_MatchRegister,
411: "dspreg", "dr",
412: "read/write DSP registers",
413: "[REG=value]"
414: "\tSet or dump contents of DSP registers.",
415: true },
416: { DebugDsp_Continue, NULL,
417: "dspcont", "dc",
418: "continue emulation / DSP single-stepping",
419: "[steps]\n"
420: "\tLeave debugger and continue emulation for <steps> DSP instructions\n"
421: "\tor forever if no steps have been specified.",
422: false }
423: };
424:
425:
426: /**
427: * Should be called when debugger is first entered to initialize
428: * DSP debugging variables.
429: *
430: * if you want disassembly or memdumping to start/continue from
431: * specific address, you can set them here. If disassembly
432: * address is zero, disassembling starts from PC.
433: *
434: * returns number of DSP commands and pointer to array of them.
435: */
436: int DebugDsp_Init(const dbgcommand_t **table)
437: {
438: dsp_disasm_addr = 0;
439: dsp_memdump_addr = 0;
440: dsp_mem_space = 'P';
441:
442: *table = dspcommands;
443: return ARRAYSIZE(dspcommands);
444: }
445:
446: /**
447: * Should be called when debugger is re-entered to reset
448: * relevant DSP debugging variables.
449: */
450: void DebugDsp_InitSession(void)
451: {
452: dsp_disasm_addr = DSP_GetPC();
1.1.1.2 root 453: Profile_DspStop();
1.1 root 454: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.