#include "debugger.h" #include "i960.h" #include "i960dis.h" #include #ifdef _MSC_VER /* logb prototype is different for MS Visual C */ #include #define logb _logb #endif // Warning, IP = Instruction Pointer, called PC outside of Intel // PC = Process Control enum { RCACHE_SIZE = 4 }; typedef struct _i960_state_t i960_state_t; struct _i960_state_t { UINT32 r[0x20]; UINT32 rcache[RCACHE_SIZE][0x10]; UINT32 rcache_frame_addr[RCACHE_SIZE]; // rcache_pos = how deep in the stack we are. 0-(RCACHE_SIZE-1) means in-cache. // RCACHE_SIZE or greater means out of cache, must save to memory. INT32 rcache_pos; double fp[4]; UINT32 SAT, PRCB, PC, AC; UINT32 IP, PIP, ICR; int bursting; int immediate_irq, immediate_vector, immediate_pri; cpu_irq_callback irq_cb; const device_config *device; const address_space *program; int icount; }; INLINE i960_state_t *get_safe_token(const device_config *device) { assert(device != NULL); assert(device->token != NULL); assert(device->type == CPU); assert(cpu_get_type(device) == CPU_I960); return (i960_state_t *)device->token; } static void do_call(i960_state_t *i960, UINT32 adr, int type, UINT32 stack); INLINE UINT32 i960_read_dword_unaligned(i960_state_t *i960, UINT32 address) { if (address & 3) return memory_read_byte_32le(i960->program, address) | memory_read_byte_32le(i960->program, address+1)<<8 | memory_read_byte_32le(i960->program, address+2)<<16 | memory_read_byte_32le(i960->program, address+3)<<24; else return memory_read_dword_32le(i960->program, address); } INLINE UINT16 i960_read_word_unaligned(i960_state_t *i960, UINT32 address) { if (address & 1) return memory_read_byte_32le(i960->program, address) | memory_read_byte_32le(i960->program, address+1)<<8; else return memory_read_word_32le(i960->program, address); } INLINE void i960_write_dword_unaligned(i960_state_t *i960, UINT32 address, UINT32 data) { if (address & 3) { memory_write_byte_32le(i960->program, address, data & 0xff); memory_write_byte_32le(i960->program, address+1, (data>>8)&0xff); memory_write_byte_32le(i960->program, address+2, (data>>16)&0xff); memory_write_byte_32le(i960->program, address+3, (data>>24)&0xff); } else { memory_write_dword_32le(i960->program, address, data); } } INLINE void i960_write_word_unaligned(i960_state_t *i960, UINT32 address, UINT16 data) { if (address & 1) { memory_write_byte_32le(i960->program, address, data & 0xff); memory_write_byte_32le(i960->program, address+1, (data>>8)&0xff); } else { memory_write_word_32le(i960->program, address, data); } } INLINE void send_iac(i960_state_t *i960, UINT32 adr) { UINT32 iac[4]; iac[0] = memory_read_dword_32le(i960->program, adr); iac[1] = memory_read_dword_32le(i960->program, adr+4); iac[2] = memory_read_dword_32le(i960->program, adr+8); iac[3] = memory_read_dword_32le(i960->program, adr+12); switch(iac[0]>>24) { case 0x93: // reinit i960->SAT = iac[1]; i960->PRCB = iac[2]; i960->IP = iac[3]; break; default: fatalerror("I960: %x: IAC %08x %08x %08x %08x", i960->PIP, iac[0], iac[1], iac[2], iac[3]); break; } } INLINE UINT32 get_ea(i960_state_t *i960, UINT32 opcode) { int abase = (opcode >> 14) & 0x1f; if(!(opcode & 0x00001000)) { // MEMA UINT32 offset = opcode & 0x1fff; if(!(opcode & 0x2000)) return offset; else return i960->r[abase]+offset; } else { // MEMB int index = opcode & 0x1f; int scale = (opcode >> 7) & 0x7; int mode = (opcode >> 10) & 0xf; UINT32 ret; switch(mode) { case 0x4: return i960->r[abase]; case 0x7: return i960->r[abase] + (i960->r[index] << scale); case 0xc: ret = memory_decrypted_read_dword(i960->program, i960->IP); i960->IP += 4; return ret; case 0xd: ret = memory_decrypted_read_dword(i960->program, i960->IP) + i960->r[abase]; i960->IP += 4; return ret; case 0xe: ret = memory_decrypted_read_dword(i960->program, i960->IP) + (i960->r[index] << scale); i960->IP += 4; return ret; case 0xf: ret = memory_decrypted_read_dword(i960->program, i960->IP) + i960->r[abase] + (i960->r[index] << scale); i960->IP += 4; return ret; default: fatalerror("I960: %x: unhandled MEMB mode %x", i960->PIP, mode); return 0; } } } INLINE UINT32 get_1_ri(i960_state_t *i960, UINT32 opcode) { if(!(opcode & 0x00000800)) return i960->r[opcode & 0x1f]; else return opcode & 0x1f; } INLINE UINT32 get_2_ri(i960_state_t *i960, UINT32 opcode) { if(!(opcode & 0x00001000)) return i960->r[(opcode>>14) & 0x1f]; else return (opcode>>14) & 0x1f; } INLINE UINT64 get_2_ri64(i960_state_t *i960, UINT32 opcode) { if(!(opcode & 0x00001000)) return i960->r[(opcode>>14) & 0x1f] | ((UINT64)i960->r[((opcode>>14) & 0x1f)+1]<<32); else return (opcode>>14) & 0x1f; } INLINE void set_ri(i960_state_t *i960, UINT32 opcode, UINT32 val) { if(!(opcode & 0x00002000)) i960->r[(opcode>>19) & 0x1f] = val; else { fatalerror("I960: %x: set_ri on literal?", i960->PIP); } } INLINE void set_ri2(i960_state_t *i960, UINT32 opcode, UINT32 val, UINT32 val2) { if(!(opcode & 0x00002000)) { i960->r[(opcode>>19) & 0x1f] = val; i960->r[((opcode>>19) & 0x1f)+1] = val2; } else { fatalerror("I960: %x: set_ri2 on literal?", i960->PIP); } } INLINE void set_ri64(i960_state_t *i960, UINT32 opcode, UINT64 val) { if(!(opcode & 0x00002000)) { i960->r[(opcode>>19) & 0x1f] = val; i960->r[((opcode>>19) & 0x1f)+1] = val >> 32; } else fatalerror("I960: %x: set_ri64 on literal?", i960->PIP); } INLINE double get_1_rif(i960_state_t *i960, UINT32 opcode) { if(!(opcode & 0x00000800)) return u2f(i960->r[opcode & 0x1f]); else { int idx = opcode & 0x1f; if(idx < 4) return i960->fp[idx]; if(idx == 0x16) return 1.0; return 0.0; } } INLINE double get_2_rif(i960_state_t *i960, UINT32 opcode) { if(!(opcode & 0x00001000)) return u2f(i960->r[(opcode>>14) & 0x1f]); else { int idx = (opcode>>14) & 0x1f; if(idx < 4) return i960->fp[idx]; if(idx == 0x16) return 1.0; return 0.0; } } INLINE void set_rif(i960_state_t *i960, UINT32 opcode, double val) { if(!(opcode & 0x00002000)) i960->r[(opcode>>19) & 0x1f] = f2u(val); else if(!(opcode & 0x00e00000)) i960->fp[(opcode>>19) & 3] = val; else fatalerror("I960: %x: set_rif on literal?", i960->PIP); } INLINE double get_1_rifl(i960_state_t *i960, UINT32 opcode) { if(!(opcode & 0x00000800)) { UINT64 v = i960->r[opcode & 0x1e]; v |= ((UINT64)(i960->r[(opcode & 0x1e)+1]))<<32; return u2d(v); } else { int idx = opcode & 0x1f; if(idx < 4) return i960->fp[idx]; if(idx == 0x16) return 1.0; return 0.0; } } INLINE double get_2_rifl(i960_state_t *i960, UINT32 opcode) { if(!(opcode & 0x00001000)) { UINT64 v = i960->r[(opcode >> 14) & 0x1e]; v |= ((UINT64)(i960->r[((opcode>>14) & 0x1e)+1]))<<32; return u2d(v); } else { int idx = (opcode>>14) & 0x1f; if(idx < 4) return i960->fp[idx]; if(idx == 0x16) return 1.0; return 0.0; } } INLINE void set_rifl(i960_state_t *i960, UINT32 opcode, double val) { if(!(opcode & 0x00002000)) { UINT64 v = d2u(val); i960->r[(opcode>>19) & 0x1e] = v; i960->r[((opcode>>19) & 0x1e)+1] = v>>32; } else if(!(opcode & 0x00e00000)) i960->fp[(opcode>>19) & 3] = val; else fatalerror("I960: %x: set_rifl on literal?", i960->PIP); } INLINE UINT32 get_1_ci(i960_state_t *i960, UINT32 opcode) { if(!(opcode & 0x00002000)) return i960->r[(opcode >> 19) & 0x1f]; else return (opcode >> 19) & 0x1f; } INLINE UINT32 get_2_ci(i960_state_t *i960, UINT32 opcode) { return i960->r[(opcode >> 14) & 0x1f]; } INLINE UINT32 get_disp(i960_state_t *i960, UINT32 opcode) { UINT32 disp; disp = opcode & 0xffffff; if(disp & 0x00800000) disp |= 0xff000000; return disp-4; } INLINE UINT32 get_disp_s(i960_state_t *i960, UINT32 opcode) { UINT32 disp; disp = opcode & 0x1fff; if(disp & 0x00001000) disp |= 0xffffe000; return disp-4; } INLINE void cmp_s(i960_state_t *i960, INT32 v1, INT32 v2) { i960->AC &= ~7; if(v1AC |= 4; else if(v1 == v2) i960->AC |= 2; else i960->AC |= 1; } INLINE void cmp_u(i960_state_t *i960, UINT32 v1, UINT32 v2) { i960->AC &= ~7; if(v1AC |= 4; else if(v1 == v2) i960->AC |= 2; else i960->AC |= 1; } INLINE void concmp_s(i960_state_t *i960, INT32 v1, INT32 v2) { i960->AC &= ~7; if(v1 <= v2) i960->AC |= 2; else i960->AC |= 1; } INLINE void concmp_u(i960_state_t *i960, UINT32 v1, UINT32 v2) { i960->AC &= ~7; if(v1 <= v2) i960->AC |= 2; else i960->AC |= 1; } INLINE void cmp_d(i960_state_t *i960, double v1, double v2) { i960->AC &= ~7; if(v1AC |= 4; else if(v1 == v2) i960->AC |= 2; else if(v1 > v2) i960->AC |= 1; } INLINE void bxx(i960_state_t *i960, UINT32 opcode, int mask) { if(i960->AC & mask) { i960->IP += get_disp(i960, opcode); } } INLINE void bxx_s(i960_state_t *i960, UINT32 opcode, int mask) { if(i960->AC & mask) { i960->IP += get_disp_s(i960, opcode); } } INLINE void test(i960_state_t *i960, UINT32 opcode, int mask) { if(i960->AC & mask) i960->r[(opcode>>19) & 0x1f] = 1; else i960->r[(opcode>>19) & 0x1f] = 0; } INLINE const char *i960_get_strflags(i960_state_t *i960) { static const char *const conditions[8] = { "no", "g", "e", "ge", "l", "ne", "le", "o" }; return (conditions[i960->AC & 7]); } // interrupt dispatch static void take_interrupt(i960_state_t *i960, int vector, int lvl) { int int_tab = memory_read_dword_32le(i960->program, i960->PRCB+20); // interrupt table int int_SP = memory_read_dword_32le(i960->program, i960->PRCB+24); // interrupt stack int SP; UINT32 IRQV; IRQV = memory_read_dword_32le(i960->program, int_tab + 36 + (vector-8)*4); // start the process if(!(i960->PC & 0x2000)) // if this is a nested interrupt, don't re-get int_SP { SP = int_SP; } else { SP = i960->r[I960_SP]; } SP = (SP + 63) & ~63; SP += 128; // emulate ElSemi's core, this fixes the crash in sonic the fighters do_call(i960, IRQV, 7, SP); // save the processor state memory_write_dword_32le(i960->program, i960->r[I960_FP]-16, i960->PC); memory_write_dword_32le(i960->program, i960->r[I960_FP]-12, i960->AC); // store the vector memory_write_dword_32le(i960->program, i960->r[I960_FP]-8, vector-8); i960->PC &= ~0x1f00; // clear priority, state, trace-fault pending, and trace enable i960->PC |= (lvl<<16); // set CPU level to current IRQ level i960->PC |= 0x2002; // set supervisor mode & interrupt flag } static void check_irqs(i960_state_t *i960) { int int_tab = memory_read_dword_32le(i960->program, i960->PRCB+20); // interrupt table int cpu_pri = (i960->PC>>16)&0x1f; int pending_pri; int lvl, irq, take = -1; int vword; static const UINT32 lvlmask[4] = { 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 }; pending_pri = memory_read_dword_32le(i960->program, int_tab); // read pending priorities if ((i960->immediate_irq) && ((cpu_pri < i960->immediate_pri) || (i960->immediate_pri == 31))) { take_interrupt(i960, i960->immediate_vector, i960->immediate_pri); i960->immediate_irq = 0; } else { for(lvl = 31; lvl >= 0; lvl--) { if((pending_pri & (1 << lvl)) && ((cpu_pri < lvl) || (lvl == 31))) { int word, wordl, wordh; // figure out which word contains this level's priorities word = ((lvl / 4) * 4) + 4; // (lvl/4) = word address, *4 for byte address, +4 to skip pending priorities wordl = (lvl % 4) * 8; wordh = (wordl + 8) - 1; vword = memory_read_dword_32le(i960->program, int_tab + word); // take the first vector we find for this level for (irq = wordh; irq >= wordl; irq--) { if(vword & (1 << irq)) { // clear pending bit vword &= ~(1 << irq); memory_write_dword_32le(i960->program, int_tab + word, vword); take = irq; break; } } // if no vectors were found at our level, it's an error if(take == -1) { logerror("i960: ERROR! no vector found for pending level %d\n", lvl); // try to recover... pending_pri &= ~(1 << lvl); memory_write_dword_32le(i960->program, int_tab, pending_pri); return; } // if no vectors are waiting for this level, clear the level bit if(!(vword & lvlmask[lvl % 4])) { pending_pri &= ~(1 << lvl); memory_write_dword_32le(i960->program, int_tab, pending_pri); } take += ((lvl/4) * 32); take_interrupt(i960, take, lvl); return; } } } } static void do_call(i960_state_t *i960, UINT32 adr, int type, UINT32 stack) { int i; UINT32 FP; // call and callx take 9 cycles base i960->icount -= 9; // set the new RIP i960->r[I960_RIP] = i960->IP; // mame_printf_debug("CALL (type %d): FP %x, %x => %x, stack %x, rcache_pos %d\n", type, i960->r[I960_FP], i960->r[I960_RIP], adr, stack, i960->rcache_pos); // are we out of cache entries? if (i960->rcache_pos >= RCACHE_SIZE) { // flush the current register set to the current frame FP = i960->r[I960_FP] & ~0x3f; for (i = 0; i < 16; i++) { memory_write_dword_32le(i960->program, FP + (i*4), i960->r[i]); } } else // a cache entry is available, use it { memcpy(&i960->rcache[i960->rcache_pos][0], i960->r, 0x10 * sizeof(UINT32)); i960->rcache_frame_addr[i960->rcache_pos] = i960->r[I960_FP] & ~0x3f; } i960->rcache_pos++; i960->IP = adr; i960->r[I960_PFP] = i960->r[I960_FP] & ~7; i960->r[I960_PFP] |= type; if(type == 7) { // interrupts need special handling // set the stack to the passed-in value to properly handle nested interrupts // (can't set it externally or the original program's SP will be lost) i960->r[I960_SP] = stack; } i960->r[I960_FP] = (i960->r[I960_SP] + 63) & ~63; i960->r[I960_SP] = i960->r[I960_FP] + 64; } static void do_ret_0(i960_state_t *i960) { // int type = i960->r[I960_PFP] & 7; i960->r[I960_FP] = i960->r[I960_PFP] & ~0x3f; i960->rcache_pos--; // normal situation: if we're still above rcache size, we're not in cache. // abnormal situation (after the app does a FLUSHREG): rcache_pos will be 0 // coming in, but we must still treat it as a not-in-cache situation. if ((i960->rcache_pos >= RCACHE_SIZE) || (i960->rcache_pos < 0)) { int i; for(i=0; i<0x10; i++) i960->r[i] = memory_read_dword_32le(i960->program, i960->r[I960_FP]+4*i); if (i960->rcache_pos < 0) { i960->rcache_pos = 0; } } else { memcpy(i960->r, i960->rcache[i960->rcache_pos], 0x10*sizeof(UINT32)); } // mame_printf_debug("RET (type %d): FP %x, %x => %x, rcache_pos %d\n", type, i960->r[I960_FP], i960->IP, i960->r[I960_RIP], i960->rcache_pos); i960->IP = i960->r[I960_RIP]; } static void do_ret(i960_state_t *i960) { UINT32 x, y; i960->icount -= 7; switch(i960->r[I960_PFP] & 7) { case 0: do_ret_0(i960); break; case 7: x = memory_read_dword(i960->program, i960->r[I960_FP]-16); y = memory_read_dword(i960->program, i960->r[I960_FP]-12); do_ret_0(i960); i960->AC = y; // #### test supervisor i960->PC = x; // check for another IRQ now that we're back check_irqs(i960); break; default: fatalerror("I960: %x: Unsupported return mode %d", i960->PIP, i960->r[I960_PFP] & 7); } } INLINE void execute_op(i960_state_t *i960, UINT32 opcode) { UINT32 t1, t2; double t1f, t2f; switch(opcode >> 24) { case 0x08: // b i960->icount--; i960->IP += get_disp(i960, opcode); break; case 0x09: // call do_call(i960, i960->IP+get_disp(i960, opcode), 0, i960->r[I960_SP]); break; case 0x0a: // ret do_ret(i960); break; case 0x0b: // bal i960->icount -= 5; i960->r[0x1e] = i960->IP; i960->IP += get_disp(i960, opcode); break; case 0x10: // bno i960->icount--; if(!(i960->AC & 7)) { i960->IP += get_disp(i960, opcode); } break; case 0x11: // bg i960->icount--; bxx(i960, opcode, 1); break; case 0x12: // be i960->icount--; bxx(i960, opcode, 2); break; case 0x13: // bge i960->icount--; bxx(i960, opcode, 3); break; case 0x14: // bl i960->icount--; bxx(i960, opcode, 4); break; case 0x15: // bne i960->icount--; bxx(i960, opcode, 5); break; case 0x16: // ble i960->icount--; bxx(i960, opcode, 6); break; case 0x17: // bo i960->icount--; bxx(i960, opcode, 7); break; case 0x20: // testno i960->icount--; if(!(i960->AC & 7)) i960->r[(opcode>>19) & 0x1f] = 1; else i960->r[(opcode>>19) & 0x1f] = 0; break; case 0x21: // testg i960->icount--; test(i960, opcode, 1); break; case 0x22: // teste i960->icount--; test(i960, opcode, 2); break; case 0x23: // testge i960->icount--; test(i960, opcode, 3); break; case 0x24: // testl i960->icount--; test(i960, opcode, 4); break; case 0x25: // testne i960->icount--; test(i960, opcode, 5); break; case 0x26: // testle i960->icount--; test(i960, opcode, 6); break; case 0x27: // testo i960->icount--; test(i960, opcode, 7); break; case 0x30: // bbc i960->icount -= 4; t1 = get_1_ci(i960, opcode) & 0x1f; t2 = get_2_ci(i960, opcode); if(!(t2 & (1<AC = (i960->AC & ~7) | 2; i960->IP += get_disp_s(i960, opcode); } else i960->AC &= ~7; break; case 0x31: // cmp0bg i960->icount -= 4; t1 = get_1_ci(i960, opcode); t2 = get_2_ci(i960, opcode); cmp_u(i960, t1, t2); bxx_s(i960, opcode, 1); break; case 0x32: // cmpobe i960->icount -= 4; t1 = get_1_ci(i960, opcode); t2 = get_2_ci(i960, opcode); cmp_u(i960, t1, t2); bxx_s(i960, opcode, 2); break; case 0x33: // cmpobge i960->icount -= 4; t1 = get_1_ci(i960, opcode); t2 = get_2_ci(i960, opcode); cmp_u(i960, t1, t2); bxx_s(i960, opcode, 3); break; case 0x34: // cmpobl i960->icount -= 4; t1 = get_1_ci(i960, opcode); t2 = get_2_ci(i960, opcode); cmp_u(i960, t1, t2); bxx_s(i960, opcode, 4); break; case 0x35: // cmpobne i960->icount -= 4; t1 = get_1_ci(i960, opcode); t2 = get_2_ci(i960, opcode); cmp_u(i960, t1, t2); bxx_s(i960, opcode, 5); break; case 0x36: // cmpoble i960->icount -= 4; t1 = get_1_ci(i960, opcode); t2 = get_2_ci(i960, opcode); cmp_u(i960, t1, t2); bxx_s(i960, opcode, 6); break; case 0x37: // bbs i960->icount -= 4; t1 = get_1_ci(i960, opcode) & 0x1f; t2 = get_2_ci(i960, opcode); if(t2 & (1<AC = (i960->AC & ~7) | 2; i960->IP += get_disp_s(i960, opcode); } else i960->AC &= ~7; break; case 0x39: // cmpibg i960->icount -= 4; t1 = get_1_ci(i960, opcode); t2 = get_2_ci(i960, opcode); cmp_s(i960, t1, t2); bxx_s(i960, opcode, 1); break; case 0x3a: // cmpibe i960->icount -= 4; t1 = get_1_ci(i960, opcode); t2 = get_2_ci(i960, opcode); cmp_s(i960, t1, t2); bxx_s(i960, opcode, 2); break; case 0x3b: // cmpibge i960->icount -= 4; t1 = get_1_ci(i960, opcode); t2 = get_2_ci(i960, opcode); cmp_s(i960, t1, t2); bxx_s(i960, opcode, 3); break; case 0x3c: // cmpibl i960->icount -= 4; t1 = get_1_ci(i960, opcode); t2 = get_2_ci(i960, opcode); cmp_s(i960, t1, t2); bxx_s(i960, opcode, 4); break; case 0x3d: // cmpibne i960->icount -= 4; t1 = get_1_ci(i960, opcode); t2 = get_2_ci(i960, opcode); cmp_s(i960, t1, t2); bxx_s(i960, opcode, 5); break; case 0x3e: // cmpible i960->icount -= 4; t1 = get_1_ci(i960, opcode); t2 = get_2_ci(i960, opcode); cmp_s(i960, t1, t2); bxx_s(i960, opcode, 6); break; case 0x58: switch((opcode >> 7) & 0xf) { case 0x0: // notbit i960->icount -= 2; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); set_ri(i960, opcode, t2 ^ (1<<(t1 & 31))); break; case 0x1: // and i960->icount--; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); set_ri(i960, opcode, t2 & t1); break; case 0x2: // andnot i960->icount--; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); set_ri(i960, opcode, t2 & ~t1); break; case 0x3: // setbit i960->icount -= 2; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); set_ri(i960, opcode, t2 | (1<<(t1 & 31))); break; case 0x4: // notand i960->icount--; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); set_ri(i960, opcode, (~t2) & t1); break; case 0x6: // xor i960->icount--; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); set_ri(i960, opcode, t2 ^ t1); break; case 0x7: // or i960->icount--; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); set_ri(i960, opcode, t2 | t1); break; case 0x8: // nor i960->icount--; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); set_ri(i960, opcode, ((~t2) & (~t1))); break; case 0x9: // xnor i960->icount--; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); set_ri(i960, opcode, ~(t2 ^ t1)); break; case 0xa: // not i960->icount--; t1 = get_1_ri(i960, opcode); set_ri(i960, opcode, ~t1); break; case 0xb: // ornot i960->icount--; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); set_ri(i960, opcode, t2 | ~t1); break; case 0xc: // clrbit i960->icount -= 2; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); set_ri(i960, opcode, t2 & ~(1<<(t1 & 31))); break; case 0xd: // notor i960->icount--; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); set_ri(i960, opcode, (~t2) | t1); break; case 0xe: // nand i960->icount -= 2; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); set_ri(i960, opcode, ~t2 | ~t1); break; case 0xf: // alterbit i960->icount -= 2; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); if(i960->AC & 2) set_ri(i960, opcode, t2 | (1<<(t1 & 31))); else set_ri(i960, opcode, t2 & ~(1<<(t1 & 31))); break; default: fatalerror("I960: %x: Unhandled 58.%x", i960->PIP, (opcode >> 7) & 0xf); } break; case 0x59: switch((opcode >> 7) & 0xf) { case 0x0: // addo i960->icount--; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); set_ri(i960, opcode, t2+t1); break; case 0x1: // addi // #### overflow i960->icount--; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); set_ri(i960, opcode, t2+t1); break; case 0x2: // subo i960->icount--; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); set_ri(i960, opcode, t2-t1); break; case 0x3: // subi // #### overflow i960->icount--; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); set_ri(i960, opcode, t2-t1); break; case 0x8: // shro i960->icount--; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); set_ri(i960, opcode, t2>>t1); break; case 0xa: // shrdi i960->icount--; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); if(((INT32)t2) < 0) { if(t2 & ((1<>t1)+1); else set_ri(i960, opcode, ((INT32)t2)>>t1); } else set_ri(i960, opcode, t2>>t1); break; case 0xb: // shri i960->icount--; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); set_ri(i960, opcode, ((INT32)t2)>>t1); break; case 0xc: // shlo i960->icount--; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); set_ri(i960, opcode, t2<icount--; t1 = get_1_ri(i960, opcode) & 0x1f; t2 = get_2_ri(i960, opcode); set_ri(i960, opcode, (t2<>(32-t1))); break; case 0xe: // shli // missing overflow i960->icount--; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); set_ri(i960, opcode, t2<PIP, (opcode >> 7) & 0xf); } break; case 0x5a: switch((opcode >> 7) & 0xf) { case 0x0: // cmpo i960->icount--; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); cmp_u(i960, t1, t2); break; case 0x1: // cmpi i960->icount--; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); cmp_s(i960, t1, t2); break; case 0x2: // concmpo i960->icount--; if(!(i960->AC & 0x4)) { t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); concmp_u(i960, t1, t2); } break; case 0x3: // concmpi i960->icount--; if(!(i960->AC & 0x4)) { t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); concmp_s(i960, t1, t2); } break; case 0x4: // cmpinco i960->icount -= 2; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); cmp_u(i960, t1, t2); set_ri(i960, opcode, t2+1); break; case 0x5: // cmpinci i960->icount -= 2; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); cmp_s(i960, t1, t2); set_ri(i960, opcode, t2+1); break; case 0x6: // cmpdeco i960->icount -= 2; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); cmp_u(i960, t1, t2); set_ri(i960, opcode, t2-1); break; case 0x7: // cmpdeci i960->icount -= 2; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); cmp_s(i960, t1, t2); set_ri(i960, opcode, t2-1); break; case 0xe: // chkbit i960->icount -= 2; t1 = get_1_ri(i960, opcode) & 0x1f; t2 = get_2_ri(i960, opcode); if(t2 & (1<AC = (i960->AC & ~7) | 2; else i960->AC &= ~7; break; default: fatalerror("I960: %x: Unhandled 5a.%x", i960->PIP, (opcode >> 7) & 0xf); } break; case 0x5b: switch((opcode >> 7) & 0xf) { case 0x0: // addc { UINT64 res; i960->icount -= 2; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); res = t2+(t1+((i960->AC>>1)&1)); set_ri(i960, opcode, res&0xffffffff); i960->AC &= ~0x3; // clear C and V // set carry i960->AC |= ((res) & (((UINT64)1) << 32)) ? 0x2 : 0; // set overflow i960->AC |= (((res) ^ (t1)) & ((res) ^ (t2)) & 0x80000000) ? 1: 0; } break; case 0x2: // subc { UINT64 res; i960->icount -= 2; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); res = t2-(t1+((i960->AC>>1)&1)); set_ri(i960, opcode, res&0xffffffff); i960->AC &= ~0x3; // clear C and V // set carry i960->AC |= ((res) & (((UINT64)1) << 32)) ? 0x2 : 0; // set overflow i960->AC |= (((t2) ^ (t1)) & ((t2) ^ (res)) & 0x80000000) ? 1 : 0; } break; default: fatalerror("I960: %x: Unhandled 5b.%x", i960->PIP, (opcode >> 7) & 0xf); } break; case 0x5c: switch((opcode >> 7) & 0xf) { case 0xc: // mov i960->icount -= 2; t1 = get_1_ri(i960, opcode); set_ri(i960, opcode, t1); break; default: fatalerror("I960: %x: Unhandled 5c.%x", i960->PIP, (opcode >> 7) & 0xf); } break; case 0x5d: switch((opcode >> 7) & 0xf) { case 0xc: // movl i960->icount -= 2; t2 = (opcode>>19) & 0x1e; if(opcode & 0x00000800) { // litteral t1 = opcode & 0x1f; i960->r[t2] = i960->r[t2+1] = t1; } else memcpy(i960->r+t2, i960->r+(opcode & 0x1f), 2*sizeof(UINT32)); break; default: fatalerror("I960: %x: Unhandled 5d.%x", i960->PIP, (opcode >> 7) & 0xf); } break; case 0x5e: switch((opcode >> 7) & 0xf) { case 0xc: // movt i960->icount -= 3; t2 = (opcode>>19) & 0x1c; if(opcode & 0x00000800) { // litteral t1 = opcode & 0x1f; i960->r[t2] = i960->r[t2+1] = i960->r[t2+2]= t1; } else memcpy(i960->r+t2, i960->r+(opcode & 0x1f), 3*sizeof(UINT32)); break; default: fatalerror("I960: %x: Unhandled 5e.%x", i960->PIP, (opcode >> 7) & 0xf); } break; case 0x5f: switch((opcode >> 7) & 0xf) { case 0xc: // movq i960->icount -= 4; t2 = (opcode>>19) & 0x1c; if(opcode & 0x00000800) { // litteral t1 = opcode & 0x1f; i960->r[t2] = i960->r[t2+1] = i960->r[t2+2] = i960->r[t2+3] = t1; } else memcpy(i960->r+t2, i960->r+(opcode & 0x1f), 4*sizeof(UINT32)); break; default: fatalerror("I960: %x: Unhandled 5f.%x", i960->PIP, (opcode >> 7) & 0xf); } break; case 0x60: switch((opcode >> 7) & 0xf) { case 0x0: // synmov i960->icount -= 6; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); // interrupt control register if(t1 == 0xff000004) i960->ICR = memory_read_dword_32le(i960->program, t2); else memory_write_dword_32le(i960->program, t1, memory_read_dword_32le(i960->program, t2)); i960->AC = (i960->AC & ~7) | 2; break; case 0x2: // synmovq i960->icount -= 12; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); if(t1 == 0xff000010) send_iac(i960, t2); else { memory_write_dword_32le(i960->program, t1, memory_read_dword_32le(i960->program, t2)); memory_write_dword_32le(i960->program, t1+4, memory_read_dword_32le(i960->program, t2+4)); memory_write_dword_32le(i960->program, t1+8, memory_read_dword_32le(i960->program, t2+8)); memory_write_dword_32le(i960->program, t1+12, memory_read_dword_32le(i960->program, t2+12)); } i960->AC = (i960->AC & ~7) | 2; break; default: fatalerror("I960: %x: Unhandled 60.%x", i960->PIP, (opcode >> 7) & 0xf); } break; case 0x64: switch((opcode >> 7) & 0xf) { case 0x0: // spanbit { UINT32 res = 0xffffffff; int i; i960->icount -= 10; t1 = get_1_ri(i960, opcode); i960->AC &= ~7; for (i = 31; i >= 0; i--) { if (!(t1 & (1<AC |= 2; res = i; break; } } set_ri(i960, opcode, res); } break; case 0x1: // scanbit { UINT32 res = 0xffffffff; int i; i960->icount -= 10; t1 = get_1_ri(i960, opcode); i960->AC &= ~7; for (i = 31; i >= 0; i--) { if (t1 & (1<AC |= 2; res = i; break; } } set_ri(i960, opcode, res); } break; case 0x5: // modac i960->icount -= 10; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); set_ri(i960, opcode, i960->AC); i960->AC = (i960->AC & ~t1) | (t2 & t1); break; default: fatalerror("I960: %x: Unhandled 64.%x", i960->PIP, (opcode >> 7) & 0xf); } break; case 0x65: switch((opcode >> 7) & 0xf) { case 0x5: // modpc i960->icount -= 10; t1 = i960->PC; t2 = get_2_ri(i960, opcode); i960->PC = (i960->PC & ~t2) | (i960->r[(opcode>>19) & 0x1f] & t2); set_ri(i960, opcode, t1); break; default: fatalerror("I960: %x: Unhandled 65.%x", i960->PIP, (opcode >> 7) & 0xf); } break; case 0x66: switch((opcode >> 7) & 0xf) { case 0xd: // flushreg if (i960->rcache_pos > 4) { i960->rcache_pos = 4; } for(t1=0; t1 < i960->rcache_pos; t1++) { int i; for (i = 0; i < 0x10; i++) { memory_write_dword_32le(i960->program, i960->rcache_frame_addr[t1] + (i * sizeof(UINT32)), i960->rcache[t1][i]); } } i960->rcache_pos = 0; break; default: fatalerror("I960: %x: Unhandled 66.%x", i960->PIP, (opcode >> 7) & 0xf); } break; case 0x67: switch((opcode >> 7) & 0xf) { case 0x0: // emul i960->icount -= 37; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); set_ri64(i960, opcode, (INT64)t1 * (INT64)t2); break; case 0x1: // ediv i960->icount -= 37; { UINT64 src1, src2; src1 = get_1_ri(i960, opcode); src2 = get_2_ri64(i960, opcode); set_ri2(i960, opcode, src2 % src1, src2 / src1); } break; case 0x4: // cvtir i960->icount -= 30; t1 = get_1_ri(i960, opcode); set_rif(i960, opcode, (double)(INT32)t1); break; case 0x6: // scalerl i960->icount -= 30; t1 = get_1_ri(i960, opcode); t2f = get_2_rifl(i960, opcode); set_rifl(i960, opcode, t2f * pow(2.0, (double)(INT32)t1)); break; case 0x7: // scaler i960->icount -= 30; t1 = get_1_ri(i960, opcode); t2f = get_2_rif(i960, opcode); set_rif(i960, opcode, t2f * pow(2.0, (double)(INT32)t1)); break; default: fatalerror("I960: %x: Unhandled 67.%x", i960->PIP, (opcode >> 7) & 0xf); } break; case 0x68: switch((opcode >> 7) & 0xf) { case 0x0: // atanr i960->icount -= 267; t1f = get_1_rif(i960, opcode); t2f = get_2_rif(i960, opcode); set_rif(i960, opcode, atan2(t2f, t1f)); break; case 0x1: // logepr i960->icount -= 400; t1f = get_1_rif(i960, opcode); t2f = get_2_rif(i960, opcode); set_rif(i960, opcode, t2f*log(t1f+1.0)/log(2.0)); break; case 0x3: // remr i960->icount -= 67; // (67 to 75878 depending on opcodes!!!) t1f = get_1_rif(i960, opcode); t2f = get_2_rif(i960, opcode); set_rif(i960, opcode, fmod(t2f, t1f)); break; case 0x5: // cmpr i960->icount -= 10; t1f = get_1_rif(i960, opcode); t2f = get_2_rif(i960, opcode); cmp_d(i960, t1f, t2f); break; case 0x8: // sqrtr i960->icount -= 104; t1f = get_1_rif(i960, opcode); set_rif(i960, opcode, sqrt(t1f)); break; case 0xa: // logbnr i960->icount -= 37; t1f = get_1_rif(i960, opcode); set_rif(i960, opcode, logb(t1f)); break; case 0xb: // roundr { INT32 st1 = get_1_rif(i960, opcode); i960->icount -= 69; set_rif(i960, opcode, (double)st1); } break; case 0xc: // sinr i960->icount -= 406; t1f = get_1_rif(i960, opcode); set_rif(i960, opcode, sin(t1f)); break; case 0xd: // cosr i960->icount -= 406; t1f = get_1_rif(i960, opcode); set_rif(i960, opcode, sin(t1f)); break; case 0xe: // tanr i960->icount -= 293; t1f = get_1_rif(i960, opcode); set_rif(i960, opcode, tan(t1f)); break; default: fatalerror("I960: %x: Unhandled 68.%x", i960->PIP, (opcode >> 7) & 0xf); } break; case 0x69: switch((opcode >> 7) & 0xf) { case 0x0: // atanrl i960->icount -= 350; t1f = get_1_rifl(i960, opcode); t2f = get_2_rifl(i960, opcode); set_rifl(i960, opcode, atan2(t2f, t1f)); break; case 0x2: // logrl i960->icount -= 438; t1f = get_1_rifl(i960, opcode); set_rifl(i960, opcode, log(t1f)); break; case 0x5: // cmprl i960->icount -= 12; t1f = get_1_rifl(i960, opcode); t2f = get_2_rifl(i960, opcode); cmp_d(i960, t1f, t2f); break; case 0x8: // sqrtrl i960->icount -= 104; t1f = get_1_rifl(i960, opcode); set_rifl(i960, opcode, sqrt(t1f)); break; case 0x9: // exprl i960->icount -= 334; t1f = get_1_rifl(i960, opcode); set_rifl(i960, opcode, pow(2.0, t1f)-1.0); break; case 0xa: // logbnrl i960->icount -= 37; t1f = get_1_rifl(i960, opcode); set_rifl(i960, opcode, logb(t1f)); break; case 0xb: // roundrl { INT32 st1 = get_1_rifl(i960, opcode); i960->icount -= 70; set_rifl(i960, opcode, (double)st1); } break; case 0xc: // sinrl i960->icount -= 441; t1f = get_1_rifl(i960, opcode); set_rifl(i960, opcode, sin(t1f)); break; case 0xd: // cosrl i960->icount -= 441; t1f = get_1_rifl(i960, opcode); set_rifl(i960, opcode, cos(t1f)); break; case 0xe: // tanrl i960->icount -= 323; t1f = get_1_rifl(i960, opcode); set_rifl(i960, opcode, tan(t1f)); break; default: fatalerror("I960: %x: Unhandled 69.%x", i960->PIP, (opcode >> 7) & 0xf); } break; case 0x6c: switch((opcode >> 7) & 0xf) { case 0x0: // cvtri i960->icount -= 33; t1f = get_1_rif(i960, opcode); // apply rounding mode // we do this a little indirectly to avoid some odd GCC warnings t2f = 0.0; switch((i960->AC>>30)&3) { case 0: t2f = floor(t1f+0.5); break; case 1: t2f = floor(t1f); break; case 2: t2f = ceil(t1f); break; case 3: t2f = t1f; break; } set_ri(i960, opcode, (INT32)t2f); break; case 0x2: // cvtzri i960->icount -= 43; t1f = get_1_rif(i960, opcode); set_ri(i960, opcode, (INT32)t1f); break; case 0x3: // cvtzril i960->icount -= 44; t1f = get_1_rif(i960, opcode); set_ri64(i960, opcode, (INT64)t1f); break; case 0x9: // movr i960->icount -= 5; t1f = get_1_rif(i960, opcode); set_rif(i960, opcode, t1f); break; default: fatalerror("I960: %x: Unhandled 6c.%x", i960->PIP, (opcode >> 7) & 0xf); } break; case 0x6d: switch((opcode >> 7) & 0xf) { case 0x9: // movrl i960->icount -= 6; t1f = get_1_rifl(i960, opcode); set_rifl(i960, opcode, t1f); break; default: fatalerror("I960: %x: Unhandled 6d.%x", i960->PIP, (opcode >> 7) & 0xf); } break; case 0x6e: switch((opcode >> 7) & 0xf) { case 0x1: // movre { UINT32 *src=0, *dst=0; i960->icount -= 8; if(!(opcode & 0x00000800)) { src = (UINT32 *)&i960->r[opcode & 0x1e]; } else { int idx = opcode & 0x1f; if(idx < 4) src = (UINT32 *)&i960->fp[idx]; } if(!(opcode & 0x00002000)) { dst = (UINT32 *)&i960->r[(opcode>>19) & 0x1e]; } else if(!(opcode & 0x00e00000)) dst = (UINT32 *)&i960->fp[(opcode>>19) & 3]; dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]&0xffff; } break; case 0x2: // cpysre i960->icount -= 8; t1f = get_1_rifl(i960, opcode); t2f = get_2_rifl(i960, opcode); if (t2f >= 0.0) set_rifl(i960, opcode, fabs(t1f)); else set_rifl(i960, opcode, -fabs(t1f)); break; default: fatalerror("I960: %x: Unhandled 6e.%x", i960->PIP, (opcode >> 7) & 0xf); } break; case 0x70: switch((opcode >> 7) & 0xf) { case 0x1: // mulo i960->icount -= 18; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); set_ri(i960, opcode, t2*t1); break; case 0x8: // remo i960->icount -= 37; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); set_ri(i960, opcode, t2%t1); break; case 0xb: // divo i960->icount -= 37; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); if (t1 == 0) // HACK! set_ri(i960, opcode, 0); else set_ri(i960, opcode, t2/t1); break; default: fatalerror("I960: %x: Unhandled 70.%x", i960->PIP, (opcode >> 7) & 0xf); } break; case 0x74: switch((opcode >> 7) & 0xf) { case 0x1: // muli i960->icount -= 18; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); set_ri(i960, opcode, ((INT32)t2)*((INT32)t1)); break; case 0x8: // remi i960->icount -= 37; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); set_ri(i960, opcode, ((INT32)t2)%((INT32)t1)); break; case 0x9:{// modi INT32 src1, src2, dst; i960->icount -= 37; src1 = (INT32)get_1_ri(i960, opcode); src2 = (INT32)get_2_ri(i960, opcode); dst = src2 - ((src2/src1)*src1); if(((src2*src1) < 0) && (dst != 0)) dst += src1; set_ri(i960, opcode, dst); break; } case 0xb: // divi i960->icount -= 37; t1 = get_1_ri(i960, opcode); t2 = get_2_ri(i960, opcode); set_ri(i960, opcode, ((INT32)t2)/((INT32)t1)); break; default: fatalerror("I960: %x: Unhandled 74.%x", i960->PIP, (opcode >> 7) & 0xf); } break; case 0x78: switch((opcode >> 7) & 0xf) { case 0xb: // divr i960->icount -= 35; t1f = get_1_rif(i960, opcode); t2f = get_2_rif(i960, opcode); set_rif(i960, opcode, t2f/t1f); break; case 0xc: // mulr i960->icount -= 18; t1f = get_1_rif(i960, opcode); t2f = get_2_rif(i960, opcode); set_rif(i960, opcode, t2f*t1f); break; case 0xd: // subr i960->icount -= 10; t1f = get_1_rif(i960, opcode); t2f = get_2_rif(i960, opcode); set_rif(i960, opcode, t2f-t1f); break; case 0xf: // addr i960->icount -= 10; t1f = get_1_rif(i960, opcode); t2f = get_2_rif(i960, opcode); set_rif(i960, opcode, t2f+t1f); break; default: fatalerror("I960: %x: Unhandled 78.%x", i960->PIP, (opcode >> 7) & 0xf); } break; case 0x79: switch((opcode >> 7) & 0xf) { case 0xb: // divrl i960->icount -= 77; t1f = get_1_rifl(i960, opcode); t2f = get_2_rifl(i960, opcode); set_rifl(i960, opcode, t2f/t1f); break; case 0xc: // mulrl i960->icount -= 36; t1f = get_1_rifl(i960, opcode); t2f = get_2_rifl(i960, opcode); set_rifl(i960, opcode, t2f*t1f); break; case 0xd: // subrl i960->icount -= 13; t1f = get_1_rifl(i960, opcode); t2f = get_2_rifl(i960, opcode); set_rifl(i960, opcode, t2f-t1f); break; case 0xf: // addrl i960->icount -= 13; t1f = get_1_rifl(i960, opcode); t2f = get_2_rifl(i960, opcode); set_rifl(i960, opcode, t2f+t1f); break; default: fatalerror("I960: %x: Unhandled 79.%x", i960->PIP, (opcode >> 7) & 0xf); } break; case 0x80: // ldob i960->icount -= 4; i960->r[(opcode>>19)&0x1f] = memory_read_byte_32le(i960->program, get_ea(i960, opcode)); break; case 0x82: // stob i960->icount -= 2; memory_write_byte_32le(i960->program, get_ea(i960, opcode), i960->r[(opcode>>19)&0x1f]); break; case 0x84: // bx i960->icount -= 3; i960->IP = get_ea(i960, opcode); break; case 0x85: // balx i960->icount -= 5; t1 = get_ea(i960, opcode); i960->r[(opcode>>19)&0x1f] = i960->IP; i960->IP = t1; break; case 0x86: // callx t1 = get_ea(i960, opcode); do_call(i960, t1, 0, i960->r[I960_SP]); break; case 0x88: // ldos i960->icount -= 4; i960->r[(opcode>>19)&0x1f] = i960_read_word_unaligned(i960, get_ea(i960, opcode)); break; case 0x8a: // stos i960->icount -= 2; i960_write_word_unaligned(i960, get_ea(i960, opcode), i960->r[(opcode>>19)&0x1f]); break; case 0x8c: // lda i960->icount--; i960->r[(opcode>>19)&0x1f] = get_ea(i960, opcode); break; case 0x90: // ld i960->icount -= 4; i960->r[(opcode>>19)&0x1f] = i960_read_dword_unaligned(i960, get_ea(i960, opcode)); break; case 0x92: // st i960->icount -= 2; i960_write_dword_unaligned(i960, get_ea(i960, opcode), i960->r[(opcode>>19)&0x1f]); break; case 0x98:{// ldl int i; i960->icount -= 5; t1 = get_ea(i960, opcode); t2 = (opcode>>19)&0x1e; i960->bursting = 1; for(i=0; i<2; i++) { i960->r[t2+i] = i960_read_dword_unaligned(i960, t1); if(i960->bursting) t1 += 4; } break; } case 0x9a:{// stl int i; i960->icount -= 3; t1 = get_ea(i960, opcode); t2 = (opcode>>19)&0x1e; i960->bursting = 1; for(i=0; i<2; i++) { i960_write_dword_unaligned(i960, t1, i960->r[t2+i]); if(i960->bursting) t1 += 4; } break; } case 0xa0:{// ldt int i; i960->icount -= 6; t1 = get_ea(i960, opcode); t2 = (opcode>>19)&0x1c; i960->bursting = 1; for(i=0; i<3; i++) { i960->r[t2+i] = i960_read_dword_unaligned(i960, t1); if(i960->bursting) t1 += 4; } break; } case 0xa2:{// stt int i; i960->icount -= 4; t1 = get_ea(i960, opcode); t2 = (opcode>>19)&0x1c; i960->bursting = 1; for(i=0; i<3; i++) { i960_write_dword_unaligned(i960, t1, i960->r[t2+i]); if(i960->bursting) t1 += 4; } break; } case 0xb0:{// ldq int i; i960->icount -= 7; t1 = get_ea(i960, opcode); t2 = (opcode>>19)&0x1c; i960->bursting = 1; for(i=0; i<4; i++) { i960->r[t2+i] = i960_read_dword_unaligned(i960, t1); if(i960->bursting) t1 += 4; } break; } case 0xb2:{// stq int i; i960->icount -= 5; t1 = get_ea(i960, opcode); t2 = (opcode>>19)&0x1c; i960->bursting = 1; for(i=0; i<4; i++) { i960_write_dword_unaligned(i960, t1, i960->r[t2+i]); if(i960->bursting) t1 += 4; } break; } case 0xc0: // ldib i960->icount -= 4; i960->r[(opcode>>19)&0x1f] = (INT8)memory_read_byte_32le(i960->program, get_ea(i960, opcode)); break; case 0xc2: // stib i960->icount -= 2; memory_write_byte_32le(i960->program, get_ea(i960, opcode), i960->r[(opcode>>19)&0x1f]); break; case 0xc8: // ldis i960->icount -= 4; i960->r[(opcode>>19)&0x1f] = (INT16)i960_read_word_unaligned(i960, get_ea(i960, opcode)); break; case 0xca: // stis i960->icount -= 2; i960_write_word_unaligned(i960, get_ea(i960, opcode), i960->r[(opcode>>19)&0x1f]); break; default: fatalerror("I960: %x: Unhandled %02x", i960->PIP, opcode >> 24); } } static CPU_EXECUTE( i960 ) { i960_state_t *i960 = get_safe_token(device); UINT32 opcode; i960->icount = cycles; check_irqs(i960); while(i960->icount > 0) { i960->PIP = i960->IP; debugger_instruction_hook(device, i960->IP); i960->bursting = 0; opcode = memory_decrypted_read_dword(i960->program, i960->IP); i960->IP += 4; execute_op(i960, opcode); } return cycles - i960->icount; } static void set_irq_line(i960_state_t *i960, int irqline, int state) { int int_tab = memory_read_dword_32le(i960->program, i960->PRCB+20); // interrupt table int cpu_pri = (i960->PC>>16)&0x1f; int vector =0; int priority; UINT32 pend, word, wordofs; // We support the 4 external IRQ lines in "normal" mode only. // The i960's interrupt support is a bit more complete than that, // but Namco and Sega both went for the cheapest solution. switch (irqline) { case I960_IRQ0: vector = i960->ICR & 0xff; break; case I960_IRQ1: vector = (i960->ICR>>8)&0xff; break; case I960_IRQ2: vector = (i960->ICR>>16)&0xff; break; case I960_IRQ3: vector = (i960->ICR>>24)&0xff; break; } if(!vector) { logerror("i960: interrupt line %d in IAC mode, unsupported!\n", irqline); return; } priority = vector / 8; if(state) { // check if we can take this "right now" if (((cpu_pri < priority) || (priority == 31)) && (i960->immediate_irq == 0)) { i960->immediate_irq = 1; i960->immediate_vector = vector; i960->immediate_pri = priority; } else { // store the interrupt in the "pending" table pend = memory_read_dword_32le(i960->program, int_tab); pend |= (1 << priority); memory_write_dword_32le(i960->program, int_tab, pend); // now bitfield-ize the vector word = ((vector / 32) * 4) + 4; wordofs = vector % 32; pend = memory_read_dword_32le(i960->program, int_tab + word); pend |= (1 << wordofs); memory_write_dword_32le(i960->program, int_tab + word, pend); } // and ack it to the core now that it's queued (*i960->irq_cb)(i960->device, irqline); } } static CPU_SET_INFO( i960 ) { i960_state_t *i960 = get_safe_token(device); if(state >= CPUINFO_INT_REGISTER+I960_R0 && state <= CPUINFO_INT_REGISTER + I960_G15) { i960->r[state - (CPUINFO_INT_REGISTER + I960_R0)] = info->i; return; } switch(state) { // Interfacing case CPUINFO_INT_REGISTER + I960_IP: i960->IP = info->i; break; case CPUINFO_INT_INPUT_STATE + I960_IRQ0: set_irq_line(i960, I960_IRQ0, info->i); break; case CPUINFO_INT_INPUT_STATE + I960_IRQ1: set_irq_line(i960, I960_IRQ1, info->i); break; case CPUINFO_INT_INPUT_STATE + I960_IRQ2: set_irq_line(i960, I960_IRQ2, info->i); break; case CPUINFO_INT_INPUT_STATE + I960_IRQ3: set_irq_line(i960, I960_IRQ3, info->i); break; default: fatalerror("i960_set_info %x", state); } } static CPU_INIT( i960 ) { i960_state_t *i960 = get_safe_token(device); i960->irq_cb = irqcallback; i960->device = device; i960->program = memory_find_address_space(device, ADDRESS_SPACE_PROGRAM); state_save_register_device_item(device, 0, i960->PIP); state_save_register_device_item(device, 0, i960->SAT); state_save_register_device_item(device, 0, i960->PRCB); state_save_register_device_item(device, 0, i960->PC); state_save_register_device_item(device, 0, i960->AC); state_save_register_device_item(device, 0, i960->ICR); state_save_register_device_item_array(device, 0, i960->r); state_save_register_device_item_array(device, 0, i960->fp); state_save_register_device_item_2d_array(device, 0, i960->rcache); state_save_register_device_item_array(device, 0, i960->rcache_frame_addr); } static CPU_DISASSEMBLE( i960 ) { disassemble_t dis; dis.IP = pc; dis.buffer = buffer; dis.oprom = oprom; i960_disassemble(&dis); return dis.IPinc | dis.disflags | DASMFLAG_SUPPORTED; } static CPU_RESET( i960 ) { i960_state_t *i960 = get_safe_token(device); i960->SAT = memory_read_dword_32le(i960->program, 0); i960->PRCB = memory_read_dword_32le(i960->program, 4); i960->IP = memory_read_dword_32le(i960->program, 12); i960->PC = 0x001f2002; i960->AC = 0; i960->ICR = 0xff000000; i960->bursting = 0; i960->immediate_irq = 0; memset(i960->r, 0, sizeof(i960->r)); memset(i960->rcache, 0, sizeof(i960->rcache)); i960->r[I960_FP] = memory_read_dword_32le(i960->program, i960->PRCB+24); i960->r[I960_SP] = i960->r[I960_FP] + 64; i960->rcache_pos = 0; } CPU_GET_INFO( i960 ) { i960_state_t *i960 = (device != NULL && device->token != NULL) ? get_safe_token(device) : NULL; if(state >= CPUINFO_INT_REGISTER+I960_R0 && state <= CPUINFO_INT_REGISTER + I960_G15) { info->i = i960->r[state - (CPUINFO_INT_REGISTER + I960_R0)]; return; } switch(state) { // Interface functions and variables case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(i960); break; case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(i960); break; case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(i960); break; case CPUINFO_FCT_EXIT: info->exit = 0; break; case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(i960); break; case CPUINFO_FCT_BURN: info->burn = 0; break; case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(i960); break; case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &i960->icount; break; case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(i960_state_t); break; case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break; case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 8; break; // Bus sizes case CPUINFO_INT_DATABUS_WIDTH_PROGRAM: info->i = 32; break; case CPUINFO_INT_ADDRBUS_WIDTH_PROGRAM: info->i = 32; break; case CPUINFO_INT_ADDRBUS_SHIFT_PROGRAM: info->i = 0; break; case CPUINFO_INT_LOGADDR_WIDTH_PROGRAM: info->i = 0; break; case CPUINFO_INT_DATABUS_WIDTH_DATA: info->i = 0; break; case CPUINFO_INT_ADDRBUS_WIDTH_DATA: info->i = 0; break; case CPUINFO_INT_ADDRBUS_SHIFT_DATA: info->i = 0; break; case CPUINFO_INT_LOGADDR_WIDTH_DATA: info->i = 0; break; case CPUINFO_INT_DATABUS_WIDTH_IO: info->i = 0; break; case CPUINFO_INT_ADDRBUS_WIDTH_IO: info->i = 0; break; case CPUINFO_INT_ADDRBUS_SHIFT_IO: info->i = 0; break; case CPUINFO_INT_LOGADDR_WIDTH_IO: info->i = 0; break; // Internal maps case CPUINFO_PTR_INTERNAL_MEMORY_MAP_PROGRAM: info->internal_map32 = NULL;break; case CPUINFO_PTR_INTERNAL_MEMORY_MAP_DATA: info->internal_map32 = NULL;break; case CPUINFO_PTR_INTERNAL_MEMORY_MAP_IO: info->internal_map32 = NULL;break; // CPU misc parameters case DEVINFO_STR_NAME: strcpy(info->s, "i960KB"); break; case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; case CPUINFO_STR_FLAGS: strcpy(info->s, i960_get_strflags(i960)); break; case DEVINFO_INT_ENDIANNESS: info->i = ENDIANNESS_LITTLE; break; case CPUINFO_INT_INPUT_LINES: info->i = 4; break; case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = -1; break; case CPUINFO_INT_CLOCK_MULTIPLIER: info->i = 1; break; case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break; // CPU main state case CPUINFO_INT_PC: info->i = i960->IP; break; case CPUINFO_INT_SP: info->i = i960->r[I960_SP]; break; case CPUINFO_INT_PREVIOUSPC: info->i = i960->PIP; break; case CPUINFO_INT_REGISTER + I960_SAT: info->i = i960->SAT; break; case CPUINFO_INT_REGISTER + I960_PRCB: info->i = i960->PRCB; break; case CPUINFO_INT_REGISTER + I960_PC: info->i = i960->PC; break; case CPUINFO_INT_REGISTER + I960_AC: info->i = i960->AC; break; case CPUINFO_INT_REGISTER + I960_IP: info->i = i960->IP; break; case CPUINFO_INT_REGISTER + I960_PIP: info->i = i960->PIP; break; // CPU debug stuff case CPUINFO_STR_REGISTER + I960_SAT: sprintf(info->s, "sat :%08x", i960->SAT); break; case CPUINFO_STR_REGISTER + I960_PRCB: sprintf(info->s, "prcb :%08x", i960->PRCB); break; case CPUINFO_STR_REGISTER + I960_PC: sprintf(info->s, "pc :%08x", i960->PC); break; case CPUINFO_STR_REGISTER + I960_AC: sprintf(info->s, "ac :%08x", i960->AC); break; case CPUINFO_STR_REGISTER + I960_IP: sprintf(info->s, "ip :%08x", i960->IP); break; case CPUINFO_STR_REGISTER + I960_PIP: sprintf(info->s, "pip :%08x", i960->PIP); break; case CPUINFO_STR_REGISTER + I960_R0: sprintf(info->s, "pfp :%08x", i960->r[ 0]); break; case CPUINFO_STR_REGISTER + I960_R1: sprintf(info->s, "sp :%08x", i960->r[ 1]); break; case CPUINFO_STR_REGISTER + I960_R2: sprintf(info->s, "rip :%08x", i960->r[ 2]); break; case CPUINFO_STR_REGISTER + I960_R3: sprintf(info->s, "r3 :%08x", i960->r[ 3]); break; case CPUINFO_STR_REGISTER + I960_R4: sprintf(info->s, "r4 :%08x", i960->r[ 4]); break; case CPUINFO_STR_REGISTER + I960_R5: sprintf(info->s, "r5 :%08x", i960->r[ 5]); break; case CPUINFO_STR_REGISTER + I960_R6: sprintf(info->s, "r6 :%08x", i960->r[ 6]); break; case CPUINFO_STR_REGISTER + I960_R7: sprintf(info->s, "r7 :%08x", i960->r[ 7]); break; case CPUINFO_STR_REGISTER + I960_R8: sprintf(info->s, "r8 :%08x", i960->r[ 8]); break; case CPUINFO_STR_REGISTER + I960_R9: sprintf(info->s, "r9 :%08x", i960->r[ 9]); break; case CPUINFO_STR_REGISTER + I960_R10: sprintf(info->s, "r10 :%08x", i960->r[10]); break; case CPUINFO_STR_REGISTER + I960_R11: sprintf(info->s, "r11 :%08x", i960->r[11]); break; case CPUINFO_STR_REGISTER + I960_R12: sprintf(info->s, "r12 :%08x", i960->r[12]); break; case CPUINFO_STR_REGISTER + I960_R13: sprintf(info->s, "r13 :%08x", i960->r[13]); break; case CPUINFO_STR_REGISTER + I960_R14: sprintf(info->s, "r14 :%08x", i960->r[14]); break; case CPUINFO_STR_REGISTER + I960_R15: sprintf(info->s, "r15 :%08x", i960->r[15]); break; case CPUINFO_STR_REGISTER + I960_G0: sprintf(info->s, "g0 :%08x", i960->r[16]); break; case CPUINFO_STR_REGISTER + I960_G1: sprintf(info->s, "g1 :%08x", i960->r[17]); break; case CPUINFO_STR_REGISTER + I960_G2: sprintf(info->s, "g2 :%08x", i960->r[18]); break; case CPUINFO_STR_REGISTER + I960_G3: sprintf(info->s, "g3 :%08x", i960->r[19]); break; case CPUINFO_STR_REGISTER + I960_G4: sprintf(info->s, "g4 :%08x", i960->r[20]); break; case CPUINFO_STR_REGISTER + I960_G5: sprintf(info->s, "g5 :%08x", i960->r[21]); break; case CPUINFO_STR_REGISTER + I960_G6: sprintf(info->s, "g6 :%08x", i960->r[22]); break; case CPUINFO_STR_REGISTER + I960_G7: sprintf(info->s, "g7 :%08x", i960->r[23]); break; case CPUINFO_STR_REGISTER + I960_G8: sprintf(info->s, "g8 :%08x", i960->r[24]); break; case CPUINFO_STR_REGISTER + I960_G9: sprintf(info->s, "g9 :%08x", i960->r[25]); break; case CPUINFO_STR_REGISTER + I960_G10: sprintf(info->s, "g10 :%08x", i960->r[26]); break; case CPUINFO_STR_REGISTER + I960_G11: sprintf(info->s, "g11 :%08x", i960->r[27]); break; case CPUINFO_STR_REGISTER + I960_G12: sprintf(info->s, "g12 :%08x", i960->r[28]); break; case CPUINFO_STR_REGISTER + I960_G13: sprintf(info->s, "g13 :%08x", i960->r[29]); break; case CPUINFO_STR_REGISTER + I960_G14: sprintf(info->s, "g14 :%08x", i960->r[30]); break; case CPUINFO_STR_REGISTER + I960_G15: sprintf(info->s, "fp :%08x", i960->r[31]); break; // default: // fatalerror("i960_get_info %x ", state); } } // call from any read/write handler for a memory area that can't be bursted // on the real hardware (e.g. Model 2's interrupt control registers) void i960_noburst(const device_config *device) { i960_state_t *i960 = get_safe_token(device); i960->bursting = 0; } void i960_stall(const device_config *device) { i960_state_t *i960 = get_safe_token(device); i960->IP = i960->PIP; }