|
|
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.