diff options
Diffstat (limited to 'trunk/src/emu/cpu/i960/i960.c')
-rw-r--r-- | trunk/src/emu/cpu/i960/i960.c | 2232 |
1 files changed, 2232 insertions, 0 deletions
diff --git a/trunk/src/emu/cpu/i960/i960.c b/trunk/src/emu/cpu/i960/i960.c new file mode 100644 index 00000000000..632c9f5c8e9 --- /dev/null +++ b/trunk/src/emu/cpu/i960/i960.c @@ -0,0 +1,2232 @@ +#include "emu.h" +#include "debugger.h" +#include "i960.h" + +CPU_DISASSEMBLE( i960 ); + +#ifdef _MSC_VER +/* logb prototype is different for MS Visual C */ +#include <float.h> +#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; + + device_irq_callback irq_cb; + legacy_cpu_device *device; + address_space *program; + direct_read_data *direct; + + int icount; +}; + +INLINE i960_state_t *get_safe_token(device_t *device) +{ + assert(device != NULL); + assert(device->type() == I960); + return (i960_state_t *)downcast<legacy_cpu_device *>(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 i960->program->read_byte(address) | i960->program->read_byte(address+1)<<8 | i960->program->read_byte(address+2)<<16 | i960->program->read_byte(address+3)<<24; + else + return i960->program->read_dword(address); +} + +INLINE UINT16 i960_read_word_unaligned(i960_state_t *i960, UINT32 address) +{ + if (address & 1) + return i960->program->read_byte(address) | i960->program->read_byte(address+1)<<8; + else + return i960->program->read_word(address); +} + +INLINE void i960_write_dword_unaligned(i960_state_t *i960, UINT32 address, UINT32 data) +{ + if (address & 3) + { + i960->program->write_byte(address, data & 0xff); + i960->program->write_byte(address+1, (data>>8)&0xff); + i960->program->write_byte(address+2, (data>>16)&0xff); + i960->program->write_byte(address+3, (data>>24)&0xff); + } + else + { + i960->program->write_dword(address, data); + } +} + +INLINE void i960_write_word_unaligned(i960_state_t *i960, UINT32 address, UINT16 data) +{ + if (address & 1) + { + i960->program->write_byte(address, data & 0xff); + i960->program->write_byte(address+1, (data>>8)&0xff); + } + else + { + i960->program->write_word(address, data); + } +} + +INLINE void send_iac(i960_state_t *i960, UINT32 adr) +{ + UINT32 iac[4]; + iac[0] = i960->program->read_dword(adr); + iac[1] = i960->program->read_dword(adr+4); + iac[2] = i960->program->read_dword(adr+8); + iac[3] = i960->program->read_dword(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 = i960->direct->read_decrypted_dword(i960->IP); + i960->IP += 4; + return ret; + + case 0xd: + ret = i960->direct->read_decrypted_dword(i960->IP) + i960->r[abase]; + i960->IP += 4; + return ret; + + case 0xe: + ret = i960->direct->read_decrypted_dword(i960->IP) + (i960->r[index] << scale); + i960->IP += 4; + return ret; + + case 0xf: + ret = i960->direct->read_decrypted_dword(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(v1<v2) + i960->AC |= 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(v1<v2) + i960->AC |= 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(v1<v2) + i960->AC |= 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 = i960->program->read_dword(i960->PRCB+20); // interrupt table + int int_SP = i960->program->read_dword(i960->PRCB+24); // interrupt stack + int SP; + UINT32 IRQV; + + IRQV = i960->program->read_dword(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 + i960->program->write_dword(i960->r[I960_FP]-16, i960->PC); + i960->program->write_dword(i960->r[I960_FP]-12, i960->AC); + // store the vector + i960->program->write_dword(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 = i960->program->read_dword(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 = i960->program->read_dword(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 = i960->program->read_dword(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); + i960->program->write_dword(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); + i960->program->write_dword(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); + i960->program->write_dword(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++) { + i960->program->write_dword(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] = i960->program->read_dword(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 = i960->program->read_dword(i960->r[I960_FP]-16); + y = i960->program->read_dword(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<<t1))) { + i960->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<<t1)) { + i960->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)) + set_ri(i960, opcode, (((INT32)t2)>>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<<t1); + break; + + case 0xd: // rotate + i960->icount--; + t1 = get_1_ri(i960, opcode) & 0x1f; + t2 = get_2_ri(i960, opcode); + set_ri(i960, opcode, (t2<<t1)|(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<<t1); + break; + + default: + fatalerror("I960: %x: Unhandled 59.%x", i960->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<<t1)) + i960->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 = i960->program->read_dword(t2); + else + i960->program->write_dword(t1, i960->program->read_dword(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 { + i960->program->write_dword(t1, i960->program->read_dword(t2)); + i960->program->write_dword(t1+4, i960->program->read_dword(t2+4)); + i960->program->write_dword(t1+8, i960->program->read_dword(t2+8)); + i960->program->write_dword(t1+12, i960->program->read_dword(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<<i))) + { + i960->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<<i)) + { + i960->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++) + { + i960->program->write_dword(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] = i960->program->read_byte(get_ea(i960, opcode)); + break; + + case 0x82: // stob + i960->icount -= 2; + i960->program->write_byte(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)i960->program->read_byte(get_ea(i960, opcode)); + break; + + case 0xc2: // stib + i960->icount -= 2; + i960->program->write_byte(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; + + check_irqs(i960); + while(i960->icount > 0) { + i960->PIP = i960->IP; + debugger_instruction_hook(device, i960->IP); + + i960->bursting = 0; + + opcode = i960->direct->read_decrypted_dword(i960->IP); + i960->IP += 4; + + execute_op(i960, opcode); + } +} + +static void set_irq_line(i960_state_t *i960, int irqline, int state) +{ + int int_tab = i960->program->read_dword(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 = i960->program->read_dword(int_tab); + pend |= (1 << priority); + i960->program->write_dword(int_tab, pend); + + // now bitfield-ize the vector + word = ((vector / 32) * 4) + 4; + wordofs = vector % 32; + pend = i960->program->read_dword(int_tab + word); + pend |= (1 << wordofs); + i960->program->write_dword(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 = device->space(AS_PROGRAM); + i960->direct = &i960->program->direct(); + + device->save_item(NAME(i960->PIP)); + device->save_item(NAME(i960->SAT)); + device->save_item(NAME(i960->PRCB)); + device->save_item(NAME(i960->PC)); + device->save_item(NAME(i960->AC)); + device->save_item(NAME(i960->ICR)); + device->save_item(NAME(i960->r)); + device->save_item(NAME(i960->fp)); + device->save_item(NAME(i960->rcache)); + device->save_item(NAME(i960->rcache_frame_addr)); +} + +static CPU_RESET( i960 ) +{ + i960_state_t *i960 = get_safe_token(device); + + i960->SAT = i960->program->read_dword(0); + i960->PRCB = i960->program->read_dword(4); + i960->IP = i960->program->read_dword(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] = i960->program->read_dword(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 DEVINFO_INT_DATABUS_WIDTH + AS_PROGRAM: info->i = 32; break; + case DEVINFO_INT_ADDRBUS_WIDTH + AS_PROGRAM: info->i = 32; break; + case DEVINFO_INT_ADDRBUS_SHIFT + AS_PROGRAM: info->i = 0; break; + case CPUINFO_INT_LOGADDR_WIDTH_PROGRAM: info->i = 0; break; + case DEVINFO_INT_DATABUS_WIDTH + AS_DATA: info->i = 0; break; + case DEVINFO_INT_ADDRBUS_WIDTH + AS_DATA: info->i = 0; break; + case DEVINFO_INT_ADDRBUS_SHIFT + AS_DATA: info->i = 0; break; + case CPUINFO_INT_LOGADDR_WIDTH_DATA: info->i = 0; break; + case DEVINFO_INT_DATABUS_WIDTH + AS_IO: info->i = 0; break; + case DEVINFO_INT_ADDRBUS_WIDTH + AS_IO: info->i = 0; break; + case DEVINFO_INT_ADDRBUS_SHIFT + AS_IO: info->i = 0; break; + case CPUINFO_INT_LOGADDR_WIDTH_IO: info->i = 0; break; + + // Internal maps + case DEVINFO_PTR_INTERNAL_MEMORY_MAP + AS_PROGRAM: info->internal_map32 = NULL;break; + case DEVINFO_PTR_INTERNAL_MEMORY_MAP + AS_DATA: info->internal_map32 = NULL;break; + case DEVINFO_PTR_INTERNAL_MEMORY_MAP + AS_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(device_t *device) +{ + i960_state_t *i960 = get_safe_token(device); + i960->bursting = 0; +} + +void i960_stall(device_t *device) +{ + i960_state_t *i960 = get_safe_token(device); + i960->IP = i960->PIP; +} + +DEFINE_LEGACY_CPU_DEVICE(I960, i960); |