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