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