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