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