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