|
|
1.1 ! root 1: /*************************************************************************** ! 2: ! 3: i860.c ! 4: ! 5: Interface file 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: #include <stdio.h> ! 19: #include <stdlib.h> ! 20: #include <string.h> ! 21: #include <math.h> ! 22: #include <assert.h> ! 23: #include "i860.hpp" ! 24: ! 25: static i860_cpu_device nd_i860; ! 26: ! 27: extern "C" { ! 28: void nd_i860_init() { ! 29: nd_i860.init(); ! 30: } ! 31: ! 32: void nd_i860_uninit() { ! 33: nd_i860.uninit(); ! 34: } ! 35: ! 36: int nd_speed_hack; ! 37: ! 38: void nd_set_speed_hack(int state) { ! 39: nd_speed_hack = state; ! 40: } ! 41: ! 42: void nd_start_debugger(void) { ! 43: nd_i860.send_msg(MSG_DBG_BREAK); ! 44: } ! 45: ! 46: static int checklock_cnt = 0; ! 47: void i860_Run(int nHostCycles) { ! 48: #if ENABLE_PERF_COUNTERS ! 49: nd_i860.m_m68k_cylces += nHostCycles; ! 50: #endif ! 51: #if ENABLE_I860_THREAD ! 52: if(nd_speed_hack) { ! 53: // while spped-hack is on, slow down m68k a bit ! 54: for(int i = 10; --i >= 0;) ! 55: checklock(&nd_i860.m_debugger_lock); ! 56: } ! 57: if(checklock_cnt <= 0) { ! 58: checklock(&nd_i860.m_debugger_lock); ! 59: // optimzation: check the debugger lock only all 10000 cycles ! 60: checklock_cnt = 10000; ! 61: } ! 62: else ! 63: checklock_cnt -= nHostCycles; ! 64: #else ! 65: nd_i860.handle_msgs(); ! 66: ! 67: if(nd_i860.is_halted()) return; ! 68: ! 69: if (nd_speed_hack) { ! 70: while(nHostCycles) { ! 71: nd_i860.run_cycle(); ! 72: nHostCycles -= 2; ! 73: } ! 74: } else ! 75: nd_i860.run_cycle(); ! 76: #endif ! 77: nd_nbic_interrupt(); ! 78: } ! 79: ! 80: int i860_thread(void* data) { ! 81: ((i860_cpu_device*)data)->run(); ! 82: return 0; ! 83: } ! 84: ! 85: void i860_reset() { ! 86: nd_i860.send_msg(MSG_I860_RESET); ! 87: } ! 88: ! 89: void i860_tick(bool intr) { ! 90: nd_i860.tick(intr); ! 91: } ! 92: } ! 93: ! 94: i860_cpu_device::i860_cpu_device() { ! 95: #if ENABLE_I860_THREAD ! 96: m_thread = NULL; ! 97: #endif ! 98: #if ENABLE_PERF_COUNTERS ! 99: dump_reset_perfc(); ! 100: #endif ! 101: m_halt = true; ! 102: } ! 103: ! 104: void i860_cpu_device::set_mem_access(bool be) { ! 105: if(be) { ! 106: rdmem[1] = nd_board_rd8_be; ! 107: rdmem[2] = nd_board_rd16_be; ! 108: rdmem[4] = nd_board_rd32_be; ! 109: rdmem[8] = nd_board_rd64_be; ! 110: rdmem[16] = nd_board_rd128_be; ! 111: ! 112: wrmem[1] = nd_board_wr8_be; ! 113: wrmem[2] = nd_board_wr16_be; ! 114: wrmem[4] = nd_board_wr32_be; ! 115: wrmem[8] = nd_board_wr64_be; ! 116: wrmem[16] = nd_board_wr128_be; ! 117: } else { ! 118: rdmem[1] = nd_board_rd8_le; ! 119: rdmem[2] = nd_board_rd16_le; ! 120: rdmem[4] = nd_board_rd32_le; ! 121: rdmem[8] = nd_board_rd64_le; ! 122: rdmem[16] = nd_board_rd128_le; ! 123: ! 124: wrmem[1] = nd_board_wr8_le; ! 125: wrmem[2] = nd_board_wr16_le; ! 126: wrmem[4] = nd_board_wr32_le; ! 127: wrmem[8] = nd_board_wr64_le; ! 128: wrmem[16] = nd_board_wr128_le; ! 129: } ! 130: } ! 131: ! 132: inline UINT8 i860_cpu_device::rdcs8(UINT32 addr) { ! 133: return nd_board_cs8get(addr); ! 134: } ! 135: ! 136: inline UINT32 i860_cpu_device::get_iregval(int gr) { ! 137: return m_iregs[gr]; ! 138: } ! 139: ! 140: inline void i860_cpu_device::set_iregval(int gr, UINT32 val) { ! 141: m_iregs[gr] = val; ! 142: m_iregs[0] = 0; // make sure r0 is always 0 ! 143: } ! 144: ! 145: inline float i860_cpu_device::get_fregval_s (int fr) { ! 146: return *(float*)(&m_fregs[fr * 4]); ! 147: } ! 148: ! 149: inline void i860_cpu_device::set_fregval_s (int fr, float s) { ! 150: if(fr > 1) ! 151: *(float*)(&m_fregs[fr * 4]) = s; ! 152: } ! 153: ! 154: inline double i860_cpu_device::get_fregval_d (int fr) { ! 155: return *(double*)(&m_fregs[fr * 4]); ! 156: } ! 157: ! 158: inline void i860_cpu_device::set_fregval_d (int fr, double d) { ! 159: if(fr > 1) ! 160: *(double*)(&m_fregs[fr * 4]) = d; ! 161: } ! 162: ! 163: inline void i860_cpu_device::SET_PSR_CC(int val) { ! 164: if(!(m_dim_cc_valid)) ! 165: m_cregs[CR_PSR] = (m_cregs[CR_PSR] & ~(1 << 2)) | ((val & 1) << 2); ! 166: } ! 167: ! 168: void i860_cpu_device::send_msg(int msg) { ! 169: lock(&m_port_lock); ! 170: m_port |= msg; ! 171: unlock(&m_port_lock); ! 172: } ! 173: ! 174: void i860_cpu_device::handle_trap(UINT32 savepc) { ! 175: static char buffer[256]; ! 176: buffer[0] = 0; ! 177: strcat(buffer, "TRAP"); ! 178: if(m_flow & TRAP_NORMAL) strcat(buffer, " [Normal]"); ! 179: if(m_flow & TRAP_IN_DELAY_SLOT) strcat(buffer, " [Delay Slot]"); ! 180: if(m_flow & TRAP_WAS_EXTERNAL) strcat(buffer, " [External]"); ! 181: if(!(GET_PSR_IT() || GET_PSR_FT() || GET_PSR_IAT() || GET_PSR_DAT() || GET_PSR_IN())) ! 182: strcat(buffer, " >Reset<"); ! 183: else { ! 184: if(GET_PSR_IT()) strcat(buffer, " >Instruction Fault<"); ! 185: if(GET_PSR_FT()) strcat(buffer, " >Floating Point Fault<"); ! 186: if(GET_PSR_IAT()) strcat(buffer, " >Instruction Access Fault<"); ! 187: if(GET_PSR_DAT()) strcat(buffer, " >Data Access Fault<"); ! 188: if(GET_PSR_IN()) strcat(buffer, " >Interrupt<"); ! 189: } ! 190: ! 191: if(!(m_single_stepping) && !((GET_PSR_IAT() || GET_PSR_DAT() || GET_PSR_IN()))) ! 192: debugger('d', buffer); ! 193: ! 194: if(m_dim) ! 195: Log_Printf(LOG_WARN, "[i860] Trap while DIM %s pc=%08X m_flow=%08X", buffer, savepc, m_flow); ! 196: ! 197: /* If we need to trap, change PC to trap address. ! 198: Also set supervisor mode, copy U and IM to their ! 199: previous versions, clear IM. */ ! 200: if(m_flow & TRAP_WAS_EXTERNAL) { ! 201: if (GET_PC_UPDATED()) { ! 202: m_cregs[CR_FIR] = m_pc; ! 203: } else { ! 204: m_cregs[CR_FIR] = savepc + 4; ! 205: } ! 206: } ! 207: else if (m_flow & TRAP_IN_DELAY_SLOT) { ! 208: m_cregs[CR_FIR] = savepc + 4; ! 209: } ! 210: else ! 211: m_cregs[CR_FIR] = savepc; ! 212: ! 213: m_flow |= FIR_GETS_TRAP; ! 214: SET_PSR_PU (GET_PSR_U ()); ! 215: SET_PSR_PIM (GET_PSR_IM ()); ! 216: SET_PSR_U (0); ! 217: SET_PSR_IM (0); ! 218: SET_PSR_DIM (0); ! 219: SET_PSR_DS (0); ! 220: ! 221: m_save_flow = m_flow & DIM_OP; ! 222: m_save_dim = m_dim; ! 223: m_save_cc = m_dim_cc; ! 224: m_save_cc_valid = m_dim_cc_valid; ! 225: ! 226: m_dim = DIM_NONE; ! 227: m_dim_cc = false; ! 228: m_dim_cc_valid = false; ! 229: ! 230: m_pc = 0xffffff00; ! 231: } ! 232: ! 233: void i860_cpu_device::ret_from_trap() { ! 234: m_flow |= m_save_flow & ~DIM_OP; ! 235: m_dim = m_save_dim; ! 236: m_flow &= ~FIR_GETS_TRAP; ! 237: m_dim_cc = m_save_cc; ! 238: m_dim_cc_valid = m_save_cc_valid; ! 239: } ! 240: ! 241: void i860_cpu_device::run_cycle() { ! 242: CLEAR_FLOW(); ! 243: m_dim_cc_valid = false; ! 244: m_flow &= ~DIM_OP; ! 245: UINT64 insn64 = ifetch64(m_pc); ! 246: ! 247: if(!(m_pc & 4)) { ! 248: UINT32 savepc = m_pc; ! 249: ! 250: #if ENABLE_DEBUGGER ! 251: if(m_single_stepping) debugger(0,0); ! 252: #endif ! 253: ! 254: UINT32 insnLow = insn64; ! 255: if(insnLow == INSN_FNOP_DIM) { ! 256: if(m_dim) m_flow |= DIM_OP; ! 257: else m_flow &= ~DIM_OP; ! 258: } else if((insnLow & INSN_MASK_DIM) == INSN_FP_DIM) ! 259: m_flow |= DIM_OP; ! 260: ! 261: decode_exec(insnLow); ! 262: ! 263: if (PENDING_TRAP()) { ! 264: handle_trap(savepc); ! 265: goto done; ! 266: } else if(GET_PC_UPDATED()) { ! 267: goto done; ! 268: } else { ! 269: // If the PC wasn't updated by a control flow instruction, just bump to next sequential instruction. ! 270: m_pc += 4; ! 271: CLEAR_FLOW(); ! 272: } ! 273: } ! 274: ! 275: if(m_pc & 4) { ! 276: UINT32 savepc = m_pc; ! 277: ! 278: #if ENABLE_DEBUGGER ! 279: if(m_single_stepping && !(m_dim)) debugger(0,0); ! 280: #endif ! 281: ! 282: UINT32 insnHigh= insn64 >> 32; ! 283: decode_exec(insnHigh); ! 284: ! 285: // only check for external interrupts ! 286: // - on high-word (speedup) ! 287: // - not DIM (safety :-) ! 288: // - when no other traps are pending ! 289: if(!(m_dim) && !(PENDING_TRAP())) { ! 290: if(m_flow & EXT_INTR) { ! 291: m_flow &= ~EXT_INTR; ! 292: gen_interrupt(); ! 293: } else ! 294: clr_interrupt(); ! 295: } ! 296: ! 297: if (PENDING_TRAP()) { ! 298: handle_trap(savepc); ! 299: } else if (GET_PC_UPDATED()) { ! 300: goto done; ! 301: } else { ! 302: // If the PC wasn't updated by a control flow instruction, just bump to next sequential instruction. ! 303: m_pc += 4; ! 304: } ! 305: } ! 306: done: ! 307: switch (m_dim) { ! 308: case DIM_NONE: ! 309: if(m_flow & DIM_OP) ! 310: m_dim = DIM_TEMP; ! 311: break; ! 312: case DIM_TEMP: ! 313: m_dim = m_flow & DIM_OP ? DIM_FULL : DIM_NONE; ! 314: break; ! 315: case DIM_FULL: ! 316: if(!(m_flow & DIM_OP)) ! 317: m_dim = DIM_TEMP; ! 318: break; ! 319: } ! 320: } ! 321: ! 322: int i860_cpu_device::memtest(bool be) { ! 323: const UINT32 P_TEST_ADDR = 0x28000000; // assume ND in slot 2 ! 324: ! 325: m_cregs[CR_DIRBASE] = 0; // turn VM off ! 326: ! 327: const UINT8 uint8 = 0x01; ! 328: const UINT16 uint16 = 0x0123; ! 329: const UINT32 uint32 = 0x01234567; ! 330: const UINT64 uint64 = 0x0123456789ABCDEFLL; ! 331: ! 332: UINT8 tmp8; ! 333: UINT16 tmp16; ! 334: UINT32 tmp32; ! 335: ! 336: int err = be ? 20000 : 30000; ! 337: ! 338: // intel manual example ! 339: SET_EPSR_BE(0); ! 340: set_mem_access(false); ! 341: ! 342: tmp8 = 'A'; wrmem[1](P_TEST_ADDR+0, (UINT32*)&tmp8); ! 343: tmp8 = 'B'; wrmem[1](P_TEST_ADDR+1, (UINT32*)&tmp8); ! 344: tmp8 = 'C'; wrmem[1](P_TEST_ADDR+2, (UINT32*)&tmp8); ! 345: tmp8 = 'D'; wrmem[1](P_TEST_ADDR+3, (UINT32*)&tmp8); ! 346: tmp8 = 'E'; wrmem[1](P_TEST_ADDR+4, (UINT32*)&tmp8); ! 347: tmp8 = 'F'; wrmem[1](P_TEST_ADDR+5, (UINT32*)&tmp8); ! 348: tmp8 = 'G'; wrmem[1](P_TEST_ADDR+6, (UINT32*)&tmp8); ! 349: tmp8 = 'H'; wrmem[1](P_TEST_ADDR+7, (UINT32*)&tmp8); ! 350: ! 351: rdmem[1](P_TEST_ADDR+0, (UINT32*)&tmp8); if(tmp8 != 'A') return err + 100; ! 352: rdmem[1](P_TEST_ADDR+1, (UINT32*)&tmp8); if(tmp8 != 'B') return err + 101; ! 353: rdmem[1](P_TEST_ADDR+2, (UINT32*)&tmp8); if(tmp8 != 'C') return err + 102; ! 354: rdmem[1](P_TEST_ADDR+3, (UINT32*)&tmp8); if(tmp8 != 'D') return err + 103; ! 355: rdmem[1](P_TEST_ADDR+4, (UINT32*)&tmp8); if(tmp8 != 'E') return err + 104; ! 356: rdmem[1](P_TEST_ADDR+5, (UINT32*)&tmp8); if(tmp8 != 'F') return err + 105; ! 357: rdmem[1](P_TEST_ADDR+6, (UINT32*)&tmp8); if(tmp8 != 'G') return err + 106; ! 358: rdmem[1](P_TEST_ADDR+7, (UINT32*)&tmp8); if(tmp8 != 'H') return err + 107; ! 359: ! 360: rdmem[2](P_TEST_ADDR+0, (UINT32*)&tmp16); if(tmp16 != (('B'<<8)|('A'))) return err + 110; ! 361: rdmem[2](P_TEST_ADDR+2, (UINT32*)&tmp16); if(tmp16 != (('D'<<8)|('C'))) return err + 111; ! 362: rdmem[2](P_TEST_ADDR+4, (UINT32*)&tmp16); if(tmp16 != (('F'<<8)|('E'))) return err + 112; ! 363: rdmem[2](P_TEST_ADDR+6, (UINT32*)&tmp16); if(tmp16 != (('H'<<8)|('G'))) return err + 113; ! 364: ! 365: rdmem[4](P_TEST_ADDR+0, &tmp32); if(tmp32 != (('D'<<24)|('C'<<16)|('B'<<8)|('A'))) return err + 120; ! 366: rdmem[4](P_TEST_ADDR+4, &tmp32); if(tmp32 != (('H'<<24)|('G'<<16)|('F'<<8)|('E'))) return err + 121; ! 367: ! 368: SET_EPSR_BE(1); ! 369: set_mem_access(true); ! 370: ! 371: rdmem[1](P_TEST_ADDR+0, (UINT32*)&tmp8); if(tmp8 != 'H') return err + 200; ! 372: rdmem[1](P_TEST_ADDR+1, (UINT32*)&tmp8); if(tmp8 != 'G') return err + 201; ! 373: rdmem[1](P_TEST_ADDR+2, (UINT32*)&tmp8); if(tmp8 != 'F') return err + 202; ! 374: rdmem[1](P_TEST_ADDR+3, (UINT32*)&tmp8); if(tmp8 != 'E') return err + 203; ! 375: rdmem[1](P_TEST_ADDR+4, (UINT32*)&tmp8); if(tmp8 != 'D') return err + 204; ! 376: rdmem[1](P_TEST_ADDR+5, (UINT32*)&tmp8); if(tmp8 != 'C') return err + 205; ! 377: rdmem[1](P_TEST_ADDR+6, (UINT32*)&tmp8); if(tmp8 != 'B') return err + 206; ! 378: rdmem[1](P_TEST_ADDR+7, (UINT32*)&tmp8); if(tmp8 != 'A') return err + 207; ! 379: ! 380: rdmem[2](P_TEST_ADDR+0, (UINT32*)&tmp16); if(tmp16 != (('H'<<8)|('G'))) return err + 210; ! 381: rdmem[2](P_TEST_ADDR+2, (UINT32*)&tmp16); if(tmp16 != (('F'<<8)|('E'))) return err + 211; ! 382: rdmem[2](P_TEST_ADDR+4, (UINT32*)&tmp16); if(tmp16 != (('D'<<8)|('C'))) return err + 212; ! 383: rdmem[2](P_TEST_ADDR+6, (UINT32*)&tmp16); if(tmp16 != (('B'<<8)|('A'))) return err + 213; ! 384: ! 385: rdmem[4](P_TEST_ADDR+0, &tmp32); if(tmp32 != (('H'<<24)|('G'<<16)|('F'<<8)|('E'))) return err + 220; ! 386: rdmem[4](P_TEST_ADDR+4, &tmp32); if(tmp32 != (('D'<<24)|('C'<<16)|('B'<<8)|('A'))) return err + 221; ! 387: ! 388: // some register and mem r/w tests ! 389: ! 390: SET_EPSR_BE(be); ! 391: set_mem_access(be); ! 392: ! 393: wrmem[1](P_TEST_ADDR, (UINT32*)&uint8); ! 394: rdmem[1](P_TEST_ADDR, (UINT32*)&tmp8); ! 395: if(tmp8 != 0x01) return err; ! 396: ! 397: wrmem[2](P_TEST_ADDR, (UINT32*)&uint16); ! 398: rdmem[2](P_TEST_ADDR, (UINT32*)&tmp16); ! 399: if(tmp16 != 0x0123) return err+1; ! 400: ! 401: wrmem[4](P_TEST_ADDR, &uint32); ! 402: rdmem[4](P_TEST_ADDR, &tmp32); if(tmp32 != 0x01234567) return err+2; ! 403: ! 404: readmem_emu(P_TEST_ADDR, 4, (UINT8*)&uint32); ! 405: if(uint32 != 0x01234567) return err+3; ! 406: ! 407: writemem_emu(P_TEST_ADDR, 4, (UINT8*)&uint32, 0xff); ! 408: rdmem[4](P_TEST_ADDR+0, &tmp32); if(tmp32 != 0x01234567) return err+4; ! 409: ! 410: UINT8* uint8p = (UINT8*)&uint64; ! 411: set_fregval_d(2, *((double*)uint8p)); ! 412: writemem_emu(P_TEST_ADDR, 8, &m_fregs[8], 0xff); ! 413: readmem_emu (P_TEST_ADDR, 8, &m_fregs[8]); ! 414: *((double*)&uint64) = get_fregval_d(2); ! 415: if(uint64 != 0x0123456789ABCDEFLL) return err+5; ! 416: ! 417: UINT32 lo; ! 418: UINT32 hi; ! 419: ! 420: rdmem[4](P_TEST_ADDR+0, &lo); ! 421: rdmem[4](P_TEST_ADDR+4, &hi); ! 422: ! 423: if(lo != 0x01234567) return err+6; ! 424: if(hi != 0x89ABCDEF) return err+7; ! 425: ! 426: return 0; ! 427: } ! 428: ! 429: void i860_cpu_device::init() { ! 430: /* Configurations - keep in sync with i860cfg.h */ ! 431: static const char* CFGS[8]; ! 432: for(int i = 0; i < 8; i++) CFGS[i] = "Unknown emulator configuration"; ! 433: CFGS[CONF_I860_SPEED] = CONF_STR(CONF_I860_SPEED); ! 434: CFGS[CONF_I860_DEV] = CONF_STR(CONF_I860_DEV); ! 435: CFGS[CONF_I860_NO_THREAD] = CONF_STR(CONF_I860_NO_THREAD); ! 436: Log_Printf(LOG_WARN, "[i860] Emulator configured for %s", CFGS[CONF_I860]); ! 437: ! 438: m_single_stepping = 0; ! 439: m_lastcmd = 0; ! 440: m_console_idx = 0; ! 441: m_break_on_next_msg = false; ! 442: m_dim = DIM_NONE; ! 443: m_traceback_idx = 0; ! 444: ! 445: set_mem_access(false); ! 446: ! 447: // some sanity checks for endianess ! 448: int err = 0; ! 449: { ! 450: UINT32 uint32 = 0x01234567; ! 451: UINT8* uint8p = (UINT8*)&uint32; ! 452: if(uint8p[3] != 0x01) {err = 1; goto error;} ! 453: if(uint8p[2] != 0x23) {err = 2; goto error;} ! 454: if(uint8p[1] != 0x45) {err = 3; goto error;} ! 455: if(uint8p[0] != 0x67) {err = 4; goto error;} ! 456: ! 457: for(int i = 0; i < 32; i++) { ! 458: uint8p[3] = i; ! 459: set_fregval_s(i, *((float*)uint8p)); ! 460: } ! 461: if(get_fregval_s(0) != 0) {err = 198; goto error;} ! 462: if(get_fregval_s(1) != 0) {err = 199; goto error;} ! 463: for(int i = 2; i < 32; i++) { ! 464: uint8p[3] = i; ! 465: if(get_fregval_s(i) != *((float*)uint8p)) ! 466: {err = 100+i; goto error;} ! 467: } ! 468: for(int i = 2; i < 32; i++) { ! 469: if(m_fregs[i*4+3] != i) {err = 200+i; goto error;} ! 470: if(m_fregs[i*4+2] != 0x23) {err = 200+i; goto error;} ! 471: if(m_fregs[i*4+1] != 0x45) {err = 200+i; goto error;} ! 472: if(m_fregs[i*4+0] != 0x67) {err = 200+i; goto error;} ! 473: } ! 474: } ! 475: ! 476: { ! 477: UINT64 uint64 = 0x0123456789ABCDEFLL; ! 478: UINT8* uint8p = (UINT8*)&uint64; ! 479: if(uint8p[7] != 0x01) {err = 10001; goto error;} ! 480: if(uint8p[6] != 0x23) {err = 10002; goto error;} ! 481: if(uint8p[5] != 0x45) {err = 10003; goto error;} ! 482: if(uint8p[4] != 0x67) {err = 10004; goto error;} ! 483: if(uint8p[3] != 0x89) {err = 10005; goto error;} ! 484: if(uint8p[2] != 0xAB) {err = 10006; goto error;} ! 485: if(uint8p[1] != 0xCD) {err = 10007; goto error;} ! 486: if(uint8p[0] != 0xEF) {err = 10008; goto error;} ! 487: ! 488: for(int i = 0; i < 16; i++) { ! 489: uint8p[7] = i; ! 490: set_fregval_d(i*2, *((double*)uint8p)); ! 491: } ! 492: if(get_fregval_d(0) != 0) ! 493: {err = 10199; goto error;} ! 494: for(int i = 1; i < 16; i++) { ! 495: uint8p[7] = i; ! 496: if(get_fregval_d(i*2) != *((double*)uint8p)) ! 497: {err = 10100+i; goto error;} ! 498: } ! 499: for(int i = 2; i < 32; i += 2) { ! 500: float hi = get_fregval_s(i+1); ! 501: float lo = get_fregval_s(i+0); ! 502: if((*(UINT32*)&hi) != (0x00234567 | (i<<23))) {err = 10100+i; goto error;} ! 503: if((*(UINT32*)&lo) != 0x89ABCDEF) {err = 10100+i; goto error;} ! 504: } ! 505: for(int i = 1; i < 16; i++) { ! 506: if(m_fregs[i*8+7] != i) {err = 10200+i; goto error;} ! 507: if(m_fregs[i*8+6] != 0x23) {err = 10200+i; goto error;} ! 508: if(m_fregs[i*8+5] != 0x45) {err = 10200+i; goto error;} ! 509: if(m_fregs[i*8+4] != 0x67) {err = 10200+i; goto error;} ! 510: if(m_fregs[i*8+3] != 0x89) {err = 10200+i; goto error;} ! 511: if(m_fregs[i*8+2] != 0xAB) {err = 10200+i; goto error;} ! 512: if(m_fregs[i*8+1] != 0xCD) {err = 10200+i; goto error;} ! 513: if(m_fregs[i*8+0] != 0xEF) {err = 10200+i; goto error;} ! 514: } ! 515: } ! 516: ! 517: err = memtest(true); if(err) goto error; ! 518: err = memtest(false); if(err) goto error; ! 519: ! 520: error: ! 521: if(err) { ! 522: fprintf(stderr, "NeXTdimension i860 emulator requires a little-endian host. This system seems to be big endian. Error %d. Exiting.\n", err); ! 523: fflush(stderr); ! 524: exit(err); ! 525: } ! 526: ! 527: send_msg(MSG_I860_RESET); ! 528: #if ENABLE_I860_THREAD ! 529: m_thread = thread_create(i860_thread, this); ! 530: #endif ! 531: } ! 532: ! 533: void i860_cpu_device::uninit() { ! 534: if(is_halted()) return; ! 535: ! 536: halt(true); ! 537: send_msg(MSG_I860_KILL); ! 538: #if ENABLE_I860_THREAD ! 539: if(m_thread) { ! 540: thread_wait(m_thread); ! 541: m_thread = NULL; ! 542: } ! 543: send_msg(MSG_NONE); ! 544: #endif ! 545: } ! 546: ! 547: /* Message disaptcher - executed on i860 thread, safe to call i860 methods */ ! 548: bool i860_cpu_device::handle_msgs() { ! 549: lock(&m_port_lock); ! 550: int msg = m_port; ! 551: m_port = 0; ! 552: unlock(&m_port_lock); ! 553: ! 554: if(msg & MSG_I860_KILL) ! 555: return false; ! 556: if(msg & MSG_I860_RESET) ! 557: reset(); ! 558: else if(msg & MSG_INTR) ! 559: intr(); ! 560: if(msg & MSG_DBG_BREAK) ! 561: debugger('d', "BREAK at pc=%08X", m_pc); ! 562: return true; ! 563: } ! 564: ! 565: void i860_cpu_device::run() { ! 566: while(handle_msgs()) { ! 567: ! 568: /* Sleep a bit if halted */ ! 569: if(is_halted()) { ! 570: sleep_ms(100); ! 571: continue; ! 572: } ! 573: ! 574: /* Run some i860 cycles before re-checking messages*/ ! 575: for(int i = 10; --i >= 0;) ! 576: run_cycle(); ! 577: } ! 578: } ! 579: ! 580: void i860_cpu_device::tick(bool intr) { ! 581: if(intr) send_msg(MSG_INTR); ! 582: #if ENABLE_PERF_COUNTERS ! 583: UINT32 now = time_ms(); ! 584: m_time_delta_ms += now - m_abs_time_ms; ! 585: m_abs_time_ms = now; ! 586: if(m_time_delta_ms > 5000) ! 587: dump_reset_perfc(); ! 588: #endif ! 589: } ! 590: ! 591: #if ENABLE_PERF_COUNTERS ! 592: void i860_cpu_device::dump_reset_perfc() { ! 593: static bool dump = false; ! 594: if(dump) { ! 595: UINT32 dt = m_time_delta_ms; ! 596: if(dt) { ! 597: if(trylock(&m_debugger_lock)) { ! 598: Log_Printf(LOG_WARN, "[i860] Stats: MIPS=%lld.%lld icache_hit=%lld%% tlb_hit=%lld%% icach_inval/s=%lld tlb_inval/s=%lld intr/s=%lld", ! 599: (m_insn_decoded / (dt * 100)) / 10, (m_insn_decoded / (dt * 100)) % 10, ! 600: m_icache_hit+m_icache_miss == 0 ? 0 : (100 * m_icache_hit) / (m_icache_hit+m_icache_miss) , ! 601: m_tlb_hit+m_tlb_miss == 0 ? 0 : (100 * m_tlb_hit) / (m_tlb_hit+m_tlb_miss), ! 602: (1000*m_icache_inval)/dt, ! 603: (1000*m_tlb_inval)/dt, ! 604: (1000*m_intrs)/dt ! 605: ); ! 606: Log_Printf(LOG_WARN, "[m68k] Stats: Mcycles/s=%lld.%lld", ! 607: (m_m68k_cylces / (dt * 100)) / 10, (m_insn_decoded / (dt * 100)) % 10); ! 608: ! 609: m_m68k_cylces = 0; ! 610: m_insn_decoded = 0; ! 611: m_icache_hit = 0; ! 612: m_icache_miss = 0; ! 613: m_icache_inval = 0; ! 614: m_tlb_hit = 0; ! 615: m_tlb_miss = 0; ! 616: m_tlb_inval = 0; ! 617: m_time_delta_ms = 0; ! 618: m_intrs = 0; ! 619: ! 620: unlock(&m_debugger_lock); ! 621: } ! 622: } ! 623: } ! 624: ! 625: dump = true; ! 626: } ! 627: #endif ! 628: ! 629: offs_t i860_cpu_device::disasm(char* buffer, offs_t pc) { ! 630: return pc + i860_disassembler(pc, ifetch_notrap(pc), buffer); ! 631: } ! 632: ! 633: /************************************************************************** ! 634: * The actual decode and execute code. ! 635: **************************************************************************/ ! 636: #include "i860dec.cpp" ! 637: ! 638: /************************************************************************** ! 639: * The debugger code. ! 640: **************************************************************************/ ! 641: #include "i860dbg.cpp"
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.