|
|
1.1 root 1: /***************************************************************************
2:
3: i860dbg.cpp
4:
5: Debugger for the Intel i860 emulator.
6:
7: Copyright (C) 1995-present Jason Eckhardt ([email protected])
8: Released for general non-commercial use under the MAME license
9: with the additional requirement that you are free to use and
10: redistribute this code in modified or unmodified form, provided
11: you list me in the credits.
12: Visit http://mamedev.org for licensing and usage restrictions.
13:
14: Changes for previous/NeXTdimension by Simon Schubiger (SC)
15:
16: ***************************************************************************/
17:
18: extern int i860_disassembler(UINT32 pc, UINT32 insn, char* buffer);
19:
20: /* A simple internal debugger. */
21: void i860_cpu_device::debugger() {
22: debugger(0, "");
23: }
24:
25: void i860_cpu_device::debugger(char cmd, const char* format, ...) {
26: if(!(isatty(fileno(stdin)))) return;
27:
28: char buf[256];
29: UINT32 curr_disasm = m_pc;
30: UINT32 curr_dumpdb = 0;
31: int c = 0;
32:
33: if(format)
34: m_single_stepping = 0;
35:
36: if (m_single_stepping > 1 && m_single_stepping != m_pc)
37: return;
38:
39: lock(&m_debugger_lock);
40:
41: if(format) {
42: va_list ap;
43: va_start (ap, format);
44: fprintf(stderr, "\n[i860]");
45: if(format[0]) {
46: fprintf(stderr, " (");
47: vfprintf (stderr, format, ap);
48: }
49: va_end (ap);
50: if(format[0])
51: fprintf(stderr, ")");
52: fprintf(stderr, " debugger started (? for help).\n");
53: }
54:
55: if(!(cmd))
56: disasm (m_pc, (m_dim ? 2 : 1) + delay_slots(ifetch_notrap(m_pc)));
57:
58: buf[0] = 0;
59: fflush (stdin);
60:
61: m_single_stepping = 0;
62:
63: while(!m_single_stepping) {
64: if(cmd) {
65: m_lastcmd = cmd;
66: buf[0] = cmd;
67: buf[1] = 0;
68: cmd = 0;
69: } else {
70: fprintf (stderr, ">");
71: for(;;) {
72: char it = 0;
73: if (read(STDIN_FILENO, &it, 1) == 1) {
74: if (it == '\n') {
75: buf[c] = 0;
76: c = 0;
77: break;
78: }
79: buf[c++] = it;
80: }
81: }
82: if(buf[0] == 0) {
83: buf[0] = m_lastcmd;
84: buf[1] = 0;
85: } else {
86: m_lastcmd = buf[0];
87: }
88: }
89: switch(buf[0]) {
90: case 'g':
91: if (buf[1] == '0')
92: sscanf (buf + 1, "%x", &m_single_stepping);
93: else {
94: m_single_stepping = 2;
95: break;
96: }
97: buf[1] = 0;
98: fprintf (stderr, "go until pc = 0x%08x.\n", m_single_stepping);
99: break;
100: case 'h':
101: halt(true);
102: m_single_stepping = 2;
103: break;
104: case 'c':
105: halt(false);
106: m_single_stepping = 2;
107: break;
108: case 'r':
109: dump_state();
110: break;
111: case 'd':
112: if (buf[1] == '0')
113: sscanf (buf + 1, "%x", &curr_disasm);
114: curr_disasm = disasm (curr_disasm, 10);
115: buf[1] = 0;
116: break;
117: case 'p':
118: if (buf[1] >= '0' && buf[1] <= '4')
119: dump_pipe (buf[1] - 0x30);
120: buf[1] = 0;
121: break;
122: case 's':
123: m_single_stepping = 1;
124: break;
125: case 'w':
126: nd_dbg_cmd(buf);
127: break;
128: case 'k':
129: m_console[m_console_idx] = 0;
130: fputs(m_console, stderr);
131: fflush(stderr);
132: break;
133: case 'b':
134: SET_PSR_IT (1);
135: m_flow |= TRAP_NORMAL;
136: m_single_stepping = 2;
137: break;
138: case 'm':
139: if (buf[1] == '0')
140: sscanf (buf + 1, "%x", &curr_dumpdb);
141: dbg_db (curr_dumpdb, 32);
142: curr_dumpdb += 32;
143: break;
144: case 't': {
145: int bufsz = sizeof(m_traceback) / sizeof(m_traceback[0]);
146: int count = bufsz;
147: if(buf[1])
148: sscanf(buf + 1, "%d", &count);
149: if(count >= bufsz) count = bufsz;
150: fprintf (stderr, "Traceback of last %d instructions:\n", count);
151: int before = m_traceback_idx;
152: m_traceback_idx += bufsz;
153: m_traceback_idx -= count;
154: while(count--)
155: disasm(m_traceback[m_traceback_idx++ % bufsz], 1);
156: m_traceback_idx = before;
157: break;}
158: case 'x':
159: if(buf[1] == '0') {
160: UINT32 v;
161: sscanf (buf + 1, "%x", &v);
162: if (GET_DIRBASE_ATE ())
163: fprintf (stderr, "vma 0x%08x ==> phys 0x%08x\n", v, get_address_translation (v, 1, 0));
164: else
165: fprintf (stderr, "not in virtual address mode.\n");
166: break;
167: }
168: case '?':
169: fprintf (stderr,
170: " m: dump bytes (m[0xaddress])\n"
171: " r: dump registers\n"
172: " s: single-step\n"
173: " h: halt i860\n"
174: " c: continue i860\n"
175: " g: go back to emulator (g[0xaddress])\n"
176: " k: print console buffer\n"
177: " d: disassemble (u[0xaddress])\n"
178: " p: dump pipelines (p{0-4} for all, add, mul, load, graphics)\n"
179: " b: break - set trap on next instruction\n"
180: " t: dump traceback buffer (t[count])\n"
181: " x: give virt->phys translation (x{0xaddress})\n");
182: nd_dbg_cmd(0);
183: break;
184: default:
185: if(!(nd_dbg_cmd(buf)))
186: fprintf (stderr, "Bad command '%s'. Type '?' for help.\n", buf);
187: break;
188: }
189: }
190:
191: /* Less noise when single-stepping. */
192: if(m_single_stepping != 1) {
193: fprintf (stderr, "Debugger done, continuing emulation.\n");
194: if(m_single_stepping == 2) m_single_stepping = 0;
195: }
196:
197: unlock(&m_debugger_lock);
198: }
199:
200: /* Disassemble `len' instructions starting at `addr'. */
201: UINT32 i860_cpu_device::disasm (UINT32 addr, int len)
202: {
203: UINT32 insn;
204: int j;
205: for (j = 0; j < len; j++) {
206: char buf[256];
207: /* Note that we print the incoming (possibly virtual) address as the
208: PC rather than the translated address. */
209: fprintf (stderr, " [i860] %08X: ", addr);
210: insn = ifetch_notrap(addr);
211: i860_disassembler(addr, insn, buf);
212: fprintf (stderr, "%s\n", buf);
213: addr += 4;
214: }
215: return addr;
216: }
217:
218:
219: /* Dump `len' bytes starting at `addr'. */
220: void i860_cpu_device::dbg_db (UINT32 addr, int len)
221: {
222: UINT8 b[16];
223: int i;
224: /* This will always dump a multiple of 16 bytes, even if 'len' isn't. */
225: while (len > 0)
226: {
227: /* Note that we print the incoming (possibly virtual) address
228: rather than the translated address. */
229: fprintf (stderr, "0x%08x: ", addr);
230: for (i = 0; i < 16; i++)
231: {
232: UINT32 phys_addr = addr;
233: if (GET_DIRBASE_ATE ())
234: phys_addr = get_address_translation (addr, 1 /* is_dataref */, 0 /* is_write */);
235:
236: rdmem[1](phys_addr, (UINT32*)&b[i]);
237: fprintf (stderr, "%02x ", b[i]);
238: addr++;
239: }
240: fprintf (stderr, "| ");
241: for (i = 0; i < 16; i++)
242: {
243: if (isprint (b[i]))
244: fprintf (stderr, "%c", b[i]);
245: else
246: fprintf (stderr, ".");
247: }
248: fprintf (stderr, "\n");
249: len -= 16;
250: }
251: }
252:
253: /* Do a pipeline dump.
254: type: 0 (all), 1 (add), 2 (mul), 3 (load), 4 (graphics). */
255: void i860_cpu_device::dump_pipe (int type)
256: {
257: int i = 0;
258:
259: fprintf (stderr, "pipeline state:\n");
260: /* Dump the adder pipeline, if requested. */
261: if (type == 0 || type == 1)
262: {
263: fprintf (stderr, " A: ");
264: for (i = 0; i < 3; i++)
265: {
266: if (m_A[i].stat.arp)
267: fprintf (stderr, "[%dd] 0x%016llx ", i + 1,
268: *(UINT64 *)(&m_A[i].val.d));
269: else
270: fprintf (stderr, "[%ds] 0x%08x ", i + 1,
271: *(UINT32 *)(&m_A[i].val.s));
272: }
273: fprintf (stderr, "\n");
274: }
275:
276:
277: /* Dump the multiplier pipeline, if requested. */
278: if (type == 0 || type == 2)
279: {
280: fprintf (stderr, " M: ");
281: for (i = 0; i < 3; i++)
282: {
283: if (m_M[i].stat.mrp)
284: fprintf (stderr, "[%dd] 0x%016llx ", i + 1,
285: *(UINT64 *)(&m_M[i].val.d));
286: else
287: fprintf (stderr, "[%ds] 0x%08x ", i + 1,
288: *(UINT32 *)(&m_M[i].val.s));
289: }
290: fprintf (stderr, "\n");
291: }
292:
293: /* Dump the load pipeline, if requested. */
294: if (type == 0 || type == 3)
295: {
296: fprintf (stderr, " L: ");
297: for (i = 0; i < 3; i++)
298: {
299: if (m_L[i].stat.lrp)
300: fprintf (stderr, "[%dd] 0x%016llx ", i + 1,
301: *(UINT64 *)(&m_L[i].val.d));
302: else
303: fprintf (stderr, "[%ds] 0x%08x ", i + 1,
304: *(UINT32 *)(&m_L[i].val.s));
305: }
306: fprintf (stderr, "\n");
307: }
308:
309: /* Dump the graphics pipeline, if requested. */
310: if (type == 0 || type == 4)
311: {
312: fprintf (stderr, " I: ");
313: if (m_G.stat.irp)
314: fprintf (stderr, "[1d] 0x%016llx\n",
315: *(UINT64 *)(&m_G.val.d));
316: else
317: fprintf (stderr, "[1s] 0x%08x\n",
318: *(UINT32 *)(&m_G.val.s));
319: }
320: }
321:
322:
323: /* Do a register/state dump. */
324: void i860_cpu_device::dump_state()
325: {
326: int rn;
327:
328: /* GR's first, 4 per line. */
329: for (rn = 0; rn < 32; rn++)
330: {
331: if ((rn % 4) == 0)
332: fprintf (stderr, "\n");
333: fprintf (stderr, "%%r%-3d: 0x%08x ", rn, get_iregval (rn));
334: }
335: fprintf (stderr, "\n");
336:
337: /* FR's (as 32-bits), 4 per line. */
338: for (rn = 0; rn < 32; rn++)
339: {
340: float ff = get_fregval_s (rn);
341: if ((rn % 4) == 0)
342: fprintf (stderr, "\n");
343: fprintf (stderr, "%%f%-3d: 0x%08x ", rn, *(UINT32 *)&ff);
344: }
345: fprintf (stderr, "\n");
346: fprintf(stderr, " psr: CC=%d LCC=%d SC=%d IM=%d U=%d IT=%d FT=%d IAT=%d DAT=%d IN=%d PS=%d PM=%08X\n",
347: GET_PSR_CC (), GET_PSR_LCC (), GET_PSR_SC (), GET_PSR_IM (), GET_PSR_U (),
348: GET_PSR_IT (), GET_PSR_FT (), GET_PSR_IAT (), GET_PSR_DAT (), GET_PSR_IN (), GET_PSR_PS(), GET_PSR_PM());
349: fprintf(stderr, " epsr: INT=%d, OF=%d BE=%d WP=%d\n", GET_EPSR_INT (), GET_EPSR_OF (), GET_EPSR_BE (), GET_EPSR_WP());
350: fprintf(stderr, "dirbase: CS8=%d ATE=%d 0x%08x", GET_DIRBASE_CS8(), GET_DIRBASE_ATE(), m_cregs[CR_DIRBASE]);
351: fprintf(stderr, " fir: 0x%08x fsr: 0x%08x pc:0x%08x\n", m_cregs[CR_FIR], m_cregs[CR_FSR], m_pc);
352: fprintf(stderr, " merge: 0x%016llx\n", m_merge);
353: }
354:
355: void i860_cpu_device::halt(bool state) {
356: if(state) {
357: m_halt = true;
358: Log_Printf(LOG_WARN, "[i860] **** HALTED ****");
359: Statusbar_SetNdLed(0);
360: } else {
361: Log_Printf(LOG_WARN, "[i860] **** RESTARTED ****");
362: m_halt = false;
363: Statusbar_SetNdLed(1);
364: }
365: }
366:
367: void i860_cpu_device::dbg_check_wr(UINT32 addr, int size, UINT8* data) {
368: if(addr == 0xF83FE800 || addr == 0xF80FF800) {
369: switch(*((UINT32*)data)) {
370: case 0:
371: case 4: {
372: // catch ND console writes
373: UINT32 ptr = addr + 4;
374: int count; readmem_emu(ptr, 4, (UINT8*)&count);
375: int col = 0;
376: ptr += 4;
377: if(count < 1024) { // sanity check
378: for(int i = 0; i < count; i++) {
379: char ch; readmem_emu(ptr++, 1, (UINT8*)&ch);
380: switch(ch) { // msg cleanup & tab expand for debugger console
381: case '\r': continue;
382: case '\t': while(col++ % 16) m_console[m_console_idx++] = ' '; continue;
383: case '\n':
384: col = -1;
385: // fall-through
386: default:
387: m_console[m_console_idx++] = ch;
388: col++;
389: break;
390: }
391: }
392: m_console[m_console_idx] = 0;
393: if(strstr(m_console, "NeXTdimension Trap:"))
394: m_break_on_next_msg = true;
395: if(*((UINT32*)data) == 4) {
396: char exit_code; readmem_emu(addr + 8, 1, (UINT8*)&exit_code);
397: debugger('k', "NeXTdimension exit(%d)", exit_code);
398: }
399: }
400: break;
401: }
402: case 5:
403: if(m_break_on_next_msg) {
404: m_break_on_next_msg = false;
405: debugger('k', "NeXTdimension Trap");
406: }
407: break;
408: }
409: }
410: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.