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