diff options
Diffstat (limited to 'trunk/src/emu/cpu/sharc/sharcops.c')
-rw-r--r-- | trunk/src/emu/cpu/sharc/sharcops.c | 2754 |
1 files changed, 2754 insertions, 0 deletions
diff --git a/trunk/src/emu/cpu/sharc/sharcops.c b/trunk/src/emu/cpu/sharc/sharcops.c new file mode 100644 index 00000000000..bbe2bc2414a --- /dev/null +++ b/trunk/src/emu/cpu/sharc/sharcops.c @@ -0,0 +1,2754 @@ +#define SIGN_EXTEND6(x) (((x) & 0x20) ? (0xffffffc0 | (x)) : (x)) +#define SIGN_EXTEND24(x) (((x) & 0x800000) ? (0xff000000 | (x)) : (x)) + +#define PM_REG_I(x) (cpustate->dag2.i[x]) +#define PM_REG_M(x) (cpustate->dag2.m[x]) +#define PM_REG_B(x) (cpustate->dag2.b[x]) +#define PM_REG_L(x) (cpustate->dag2.l[x]) +#define DM_REG_I(x) (cpustate->dag1.i[x]) +#define DM_REG_M(x) (cpustate->dag1.m[x]) +#define DM_REG_B(x) (cpustate->dag1.b[x]) +#define DM_REG_L(x) (cpustate->dag1.l[x]) + +// ASTAT flags +#define AZ 0x1 /* ALU result zero */ +#define AV 0x2 /* ALU overflow */ +#define AN 0x4 /* ALU result negative */ +#define AC 0x8 /* ALU fixed-point carry */ +#define AS 0x10 /* ALU X input sign */ +#define AI 0x20 /* ALU floating-point invalid operation */ +#define MN 0x40 /* Multiplier result negative */ +#define MV 0x80 /* Multiplier overflow */ +#define MU 0x100 /* Multiplier underflow */ +#define MI 0x200 /* Multiplier floating-point invalid operation */ +#define AF 0x400 +#define SV 0x800 /* Shifter overflow */ +#define SZ 0x1000 /* Shifter result zero */ +#define SS 0x2000 /* Shifter input sign */ +#define BTF 0x40000 /* Bit Test Flag */ +#define FLG0 0x80000 /* FLAG0 */ +#define FLG1 0x100000 /* FLAG1 */ +#define FLG2 0x200000 /* FLAG2 */ +#define FLG3 0x400000 /* FLAG3 */ + +// STKY flags +#define AUS 0x1 /* ALU floating-point underflow */ +#define AVS 0x2 /* ALU floating-point overflow */ +#define AOS 0x4 /* ALU fixed-point overflow */ +#define AIS 0x20 /* ALU floating-point invalid operation */ + +// MODE1 flags +#define MODE1_BR8 0x1 /* Bit-reverse for I8 */ +#define MODE1_BR0 0x2 /* Bit-reverse for I0 */ +#define MODE1_SRCU 0x4 /* Alternate register select for computational units */ +#define MODE1_SRD1H 0x8 /* DAG alternate register select (7-4) */ +#define MODE1_SRD1L 0x10 /* DAG alternate register select (3-0) */ +#define MODE1_SRD2H 0x20 /* DAG alternate register select (15-12) */ +#define MODE1_SRD2L 0x40 /* DAG alternate register select (11-8) */ +#define MODE1_SRRFH 0x80 /* Register file alternate select for R(15-8) */ +#define MODE1_SRRFL 0x400 /* Register file alternate select for R(7-0) */ +#define MODE1_NESTM 0x800 /* Interrupt nesting enable */ +#define MODE1_IRPTEN 0x1000 /* Global interrupt enable */ +#define MODE1_ALUSAT 0x2000 /* Enable ALU fixed-point saturation */ +#define MODE1_SSE 0x4000 /* Enable short word sign extension */ +#define MODE1_TRUNCATE 0x8000 /* (1) Floating-point truncation / (0) round to nearest */ +#define MODE1_RND32 0x10000 /* (1) 32-bit floating-point rounding / (0) 40-bit rounding */ +#define MODE1_CSEL 0x60000 /* CSelect */ + +// MODE2 flags +#define MODE2_IRQ0E 0x1 /* IRQ0 (1) Edge sens. / (0) Level sens. */ +#define MODE2_IRQ1E 0x2 /* IRQ1 (1) Edge sens. / (0) Level sens. */ +#define MODE2_IRQ2E 0x4 /* IRQ2 (1) Edge sens. / (0) Level sens. */ +#define MODE2_CADIS 0x10 /* Cache disable */ +#define MODE2_TIMEN 0x20 /* Timer enable */ +#define MODE2_BUSLK 0x40 /* External bus lock */ +#define MODE2_FLG0O 0x8000 /* FLAG0 (1) Output / (0) Input */ +#define MODE2_FLG1O 0x10000 /* FLAG1 (1) Output / (0) Input */ +#define MODE2_FLG2O 0x20000 /* FLAG2 (1) Output / (0) Input */ +#define MODE2_FLG3O 0x40000 /* FLAG3 (1) Output / (0) Input */ +#define MODE2_CAFRZ 0x80000 /* Cache freeze */ + + +#define REG_PC 0x63 +#define REG_PCSTK 0x64 +#define REG_PCSTKP 0x65 +#define REG_LADDR 0x66 +#define REG_CURLCNTR 0x67 +#define REG_LCNTR 0x68 +#define REG_USTAT1 0x70 +#define REG_USTAT2 0x71 +#define REG_IRPTL 0x79 +#define REG_MODE2 0x7a +#define REG_MODE1 0x7b +#define REG_ASTAT 0x7c +#define REG_IMASK 0x7d +#define REG_STKY 0x7e +#define REG_IMASKP 0x7f + + + +#define REG(x) (cpustate->r[x].r) +#define FREG(x) (cpustate->r[x].f) + +#define UPDATE_CIRCULAR_BUFFER_PM(x) \ + { \ + if (PM_REG_L(x) != 0) \ + { \ + if (PM_REG_I(x) > PM_REG_B(x)+PM_REG_L(x)) \ + { \ + PM_REG_I(x) -= PM_REG_L(x); \ + } \ + else if (PM_REG_I(x) < PM_REG_B(x)) \ + { \ + PM_REG_I(x) += PM_REG_L(x); \ + } \ + } \ + } + +#define UPDATE_CIRCULAR_BUFFER_DM(x) \ + { \ + if (DM_REG_L(x) != 0) \ + { \ + if (DM_REG_I(x) > DM_REG_B(x)+DM_REG_L(x)) \ + { \ + DM_REG_I(x) -= DM_REG_L(x); \ + } \ + else if (DM_REG_I(x) < DM_REG_B(x)) \ + { \ + DM_REG_I(x) += DM_REG_L(x); \ + } \ + } \ + } + + +/*****************************************************************************/ + +static void systemreg_write_latency_effect(SHARC_REGS *cpustate); + +static void add_systemreg_write_latency_effect(SHARC_REGS *cpustate, int sysreg, UINT32 data, UINT32 prev_data) +{ + if (cpustate->systemreg_latency_cycles > 0) + { + //fatalerror("SHARC: add_systemreg_write_latency_effect: already scheduled! (reg: %02X, data: %08X, PC: %08X)\n", systemreg_latency_reg, systemreg_latency_data, cpustate->pc); + systemreg_write_latency_effect(cpustate); + } + + cpustate->systemreg_latency_cycles = 2; + cpustate->systemreg_latency_reg = sysreg; + cpustate->systemreg_latency_data = data; + cpustate->systemreg_previous_data = prev_data; +} + +INLINE void swap_register(UINT32 *a, UINT32 *b) +{ + UINT32 temp = *a; + *a = *b; + *b = temp; +} + +static void systemreg_write_latency_effect(SHARC_REGS *cpustate) +{ + int i; + UINT32 data = cpustate->systemreg_latency_data; + UINT32 old_data = cpustate->systemreg_previous_data; + + switch(cpustate->systemreg_latency_reg) + { + case 0xb: /* MODE1 */ + { + UINT32 oldreg = old_data; + cpustate->mode1 = data; + + if ((data & 0x1) != (oldreg & 0x1)) + { + fatalerror("SHARC: systemreg_latency_op: enable I8 bit-reversing"); + } + if ((data & 0x2) != (oldreg & 0x2)) + { + fatalerror("SHARC: systemreg_latency_op: enable I0 bit-reversing"); + } + if ((data & 0x4) != (oldreg & 0x4)) + { + fatalerror("SHARC: systemreg_latency_op: enable MR alternate"); + } + + if ((data & 0x8) != (oldreg & 0x8)) /* Switch DAG1 7-4 */ + { + swap_register(&cpustate->dag1.i[4], &cpustate->dag1_alt.i[4]); + swap_register(&cpustate->dag1.i[5], &cpustate->dag1_alt.i[5]); + swap_register(&cpustate->dag1.i[6], &cpustate->dag1_alt.i[6]); + swap_register(&cpustate->dag1.i[7], &cpustate->dag1_alt.i[7]); + swap_register(&cpustate->dag1.m[4], &cpustate->dag1_alt.m[4]); + swap_register(&cpustate->dag1.m[5], &cpustate->dag1_alt.m[5]); + swap_register(&cpustate->dag1.m[6], &cpustate->dag1_alt.m[6]); + swap_register(&cpustate->dag1.m[7], &cpustate->dag1_alt.m[7]); + swap_register(&cpustate->dag1.l[4], &cpustate->dag1_alt.l[4]); + swap_register(&cpustate->dag1.l[5], &cpustate->dag1_alt.l[5]); + swap_register(&cpustate->dag1.l[6], &cpustate->dag1_alt.l[6]); + swap_register(&cpustate->dag1.l[7], &cpustate->dag1_alt.l[7]); + swap_register(&cpustate->dag1.b[4], &cpustate->dag1_alt.b[4]); + swap_register(&cpustate->dag1.b[5], &cpustate->dag1_alt.b[5]); + swap_register(&cpustate->dag1.b[6], &cpustate->dag1_alt.b[6]); + swap_register(&cpustate->dag1.b[7], &cpustate->dag1_alt.b[7]); + } + if ((data & 0x10) != (oldreg & 0x10)) /* Switch DAG1 3-0 */ + { + swap_register(&cpustate->dag1.i[0], &cpustate->dag1_alt.i[0]); + swap_register(&cpustate->dag1.i[1], &cpustate->dag1_alt.i[1]); + swap_register(&cpustate->dag1.i[2], &cpustate->dag1_alt.i[2]); + swap_register(&cpustate->dag1.i[3], &cpustate->dag1_alt.i[3]); + swap_register(&cpustate->dag1.m[0], &cpustate->dag1_alt.m[0]); + swap_register(&cpustate->dag1.m[1], &cpustate->dag1_alt.m[1]); + swap_register(&cpustate->dag1.m[2], &cpustate->dag1_alt.m[2]); + swap_register(&cpustate->dag1.m[3], &cpustate->dag1_alt.m[3]); + swap_register(&cpustate->dag1.l[0], &cpustate->dag1_alt.l[0]); + swap_register(&cpustate->dag1.l[1], &cpustate->dag1_alt.l[1]); + swap_register(&cpustate->dag1.l[2], &cpustate->dag1_alt.l[2]); + swap_register(&cpustate->dag1.l[3], &cpustate->dag1_alt.l[3]); + swap_register(&cpustate->dag1.b[0], &cpustate->dag1_alt.b[0]); + swap_register(&cpustate->dag1.b[1], &cpustate->dag1_alt.b[1]); + swap_register(&cpustate->dag1.b[2], &cpustate->dag1_alt.b[2]); + swap_register(&cpustate->dag1.b[3], &cpustate->dag1_alt.b[3]); + } + if ((data & 0x20) != (oldreg & 0x20)) /* Switch DAG2 15-12 */ + { + swap_register(&cpustate->dag2.i[4], &cpustate->dag2_alt.i[4]); + swap_register(&cpustate->dag2.i[5], &cpustate->dag2_alt.i[5]); + swap_register(&cpustate->dag2.i[6], &cpustate->dag2_alt.i[6]); + swap_register(&cpustate->dag2.i[7], &cpustate->dag2_alt.i[7]); + swap_register(&cpustate->dag2.m[4], &cpustate->dag2_alt.m[4]); + swap_register(&cpustate->dag2.m[5], &cpustate->dag2_alt.m[5]); + swap_register(&cpustate->dag2.m[6], &cpustate->dag2_alt.m[6]); + swap_register(&cpustate->dag2.m[7], &cpustate->dag2_alt.m[7]); + swap_register(&cpustate->dag2.l[4], &cpustate->dag2_alt.l[4]); + swap_register(&cpustate->dag2.l[5], &cpustate->dag2_alt.l[5]); + swap_register(&cpustate->dag2.l[6], &cpustate->dag2_alt.l[6]); + swap_register(&cpustate->dag2.l[7], &cpustate->dag2_alt.l[7]); + swap_register(&cpustate->dag2.b[4], &cpustate->dag2_alt.b[4]); + swap_register(&cpustate->dag2.b[5], &cpustate->dag2_alt.b[5]); + swap_register(&cpustate->dag2.b[6], &cpustate->dag2_alt.b[6]); + swap_register(&cpustate->dag2.b[7], &cpustate->dag2_alt.b[7]); + } + if ((data & 0x40) != (oldreg & 0x40)) /* Switch DAG2 11-8 */ + { + swap_register(&cpustate->dag2.i[0], &cpustate->dag2_alt.i[0]); + swap_register(&cpustate->dag2.i[1], &cpustate->dag2_alt.i[1]); + swap_register(&cpustate->dag2.i[2], &cpustate->dag2_alt.i[2]); + swap_register(&cpustate->dag2.i[3], &cpustate->dag2_alt.i[3]); + swap_register(&cpustate->dag2.m[0], &cpustate->dag2_alt.m[0]); + swap_register(&cpustate->dag2.m[1], &cpustate->dag2_alt.m[1]); + swap_register(&cpustate->dag2.m[2], &cpustate->dag2_alt.m[2]); + swap_register(&cpustate->dag2.m[3], &cpustate->dag2_alt.m[3]); + swap_register(&cpustate->dag2.l[0], &cpustate->dag2_alt.l[0]); + swap_register(&cpustate->dag2.l[1], &cpustate->dag2_alt.l[1]); + swap_register(&cpustate->dag2.l[2], &cpustate->dag2_alt.l[2]); + swap_register(&cpustate->dag2.l[3], &cpustate->dag2_alt.l[3]); + swap_register(&cpustate->dag2.b[0], &cpustate->dag2_alt.b[0]); + swap_register(&cpustate->dag2.b[1], &cpustate->dag2_alt.b[1]); + swap_register(&cpustate->dag2.b[2], &cpustate->dag2_alt.b[2]); + swap_register(&cpustate->dag2.b[3], &cpustate->dag2_alt.b[3]); + } + if ((data & 0x80) != (oldreg & 0x80)) + { + for (i=8; i<16; i++) + swap_register((UINT32*)&cpustate->r[i].r, (UINT32*)&cpustate->reg_alt[i].r); + } + if ((data & 0x400) != (oldreg & 0x400)) + { + for (i=0; i<8; i++) + swap_register((UINT32*)&cpustate->r[i].r, (UINT32*)&cpustate->reg_alt[i].r); + } + break; + } + default: fatalerror("SHARC: systemreg_latency_op: unknown register %02X at %08X", cpustate->systemreg_latency_reg, cpustate->pc); + } + + cpustate->systemreg_latency_reg = -1; +} + +static UINT32 GET_UREG(SHARC_REGS *cpustate, int ureg) +{ + int reg = ureg & 0xf; + switch((ureg >> 4) & 0xf) + { + case 0x0: /* R0 - R15 */ + { + return cpustate->r[reg].r; + } + + case 0x1: + { + if (reg & 0x8) /* I8 - I15 */ + { + return cpustate->dag2.i[reg & 0x7]; + } + else /* I0 - I7 */ + { + return cpustate->dag1.i[reg & 0x7]; + } + } + + case 0x2: + { + if (reg & 0x8) /* M8 - M15 */ + { + INT32 r = cpustate->dag2.m[reg & 0x7]; + if (r & 0x800000) r |= 0xff000000; + + return r; + } + else /* M0 - M7 */ + { + return cpustate->dag1.m[reg & 0x7]; + } + } + + case 0x3: + { + if (reg & 0x8) /* L8 - L15 */ + { + return cpustate->dag2.l[reg & 0x7]; + } + else /* L0 - L7 */ + { + return cpustate->dag1.l[reg & 0x7]; + } + } + + case 0x4: + { + if (reg & 0x8) /* B8 - B15 */ + { + return cpustate->dag2.b[reg & 0x7]; + } + else /* B0 - B7 */ + { + return cpustate->dag1.b[reg & 0x7]; + } + } + + case 0x6: + { + switch(reg) + { + case 0x4: return cpustate->pcstack[cpustate->pcstkp]; /* PCSTK */ + default: fatalerror("SHARC: GET_UREG: unknown register %08X at %08X", ureg, cpustate->pc); + } + break; + } + + case 0x7: + { + switch(reg) + { + case 0x0: return cpustate->ustat1; /* USTAT1 */ + case 0x1: return cpustate->ustat2; /* USTAT2 */ + case 0x9: return cpustate->irptl; /* IRPTL */ + case 0xa: return cpustate->mode2; /* MODE2 */ + case 0xb: return cpustate->mode1; /* MODE1 */ + case 0xc: /* ASTAT */ + { + UINT32 r = cpustate->astat; + r &= ~0x00780000; + r |= (cpustate->flag[0] << 19); + r |= (cpustate->flag[1] << 20); + r |= (cpustate->flag[2] << 21); + r |= (cpustate->flag[3] << 22); + return r; + } + case 0xd: return cpustate->imask; /* IMASK */ + case 0xe: return cpustate->stky; /* STKY */ + default: fatalerror("SHARC: GET_UREG: unknown register %08X at %08X", ureg, cpustate->pc); + } + break; + } + + case 0xd: + { + switch(reg) + { + /* PX needs to be handled separately if the whole 48 bits are needed */ + case 0xb: return (UINT32)(cpustate->px); /* PX */ + case 0xc: return (UINT16)(cpustate->px); /* PX1 */ + case 0xd: return (UINT32)(cpustate->px >> 16); /* PX2 */ + default: fatalerror("SHARC: GET_UREG: unknown register %08X at %08X", ureg, cpustate->pc); + } + break; + } + + default: fatalerror("SHARC: GET_UREG: unknown register %08X at %08X", ureg, cpustate->pc); + } +} + +static void SET_UREG(SHARC_REGS *cpustate, int ureg, UINT32 data) +{ + int reg = ureg & 0xf; + switch((ureg >> 4) & 0xf) + { + case 0x0: /* R0 - R15 */ + cpustate->r[reg].r = data; + break; + + case 0x1: + if (reg & 0x8) /* I8 - I15 */ + { + cpustate->dag2.i[reg & 0x7] = data; + } + else /* I0 - I7 */ + { + cpustate->dag1.i[reg & 0x7] = data; + } + break; + + case 0x2: + if (reg & 0x8) /* M8 - M15 */ + { + cpustate->dag2.m[reg & 0x7] = data; + } + else /* M0 - M7 */ + { + cpustate->dag1.m[reg & 0x7] = data; + } + break; + + case 0x3: + if (reg & 0x8) /* L8 - L15 */ + { + cpustate->dag2.l[reg & 0x7] = data; + } + else /* L0 - L7 */ + { + cpustate->dag1.l[reg & 0x7] = data; + } + break; + + case 0x4: + // Note: loading B also loads the same value in I + if (reg & 0x8) /* B8 - B15 */ + { + cpustate->dag2.b[reg & 0x7] = data; + cpustate->dag2.i[reg & 0x7] = data; + } + else /* B0 - B7 */ + { + cpustate->dag1.b[reg & 0x7] = data; + cpustate->dag1.i[reg & 0x7] = data; + } + break; + + case 0x6: + switch (reg) + { + case 0x5: cpustate->pcstkp = data; break; /* PCSTKP */ + case 0x8: cpustate->lcntr = data; break; /* LCNTR */ + default: fatalerror("SHARC: SET_UREG: unknown register %08X at %08X", ureg, cpustate->pc); + } + break; + + case 0x7: /* system regs */ + switch(reg) + { + case 0x0: cpustate->ustat1 = data; break; /* USTAT1 */ + case 0x1: cpustate->ustat2 = data; break; /* USTAT2 */ + + case 0x9: cpustate->irptl = data; break; /* IRPTL */ + case 0xa: cpustate->mode2 = data; break; /* MODE2 */ + + case 0xb: /* MODE1 */ + { + add_systemreg_write_latency_effect(cpustate, reg, data, cpustate->mode1); + cpustate->mode1 = data; + break; + } + + case 0xc: cpustate->astat = data; break; /* ASTAT */ + + case 0xd: /* IMASK */ + { + check_interrupts(cpustate); + cpustate->imask = data; + break; + } + + case 0xe: cpustate->stky = data; break; /* STKY */ + default: fatalerror("SHARC: SET_UREG: unknown register %08X at %08X", ureg, cpustate->pc); + } + break; + + case 0xd: + switch(reg) + { + case 0xc: cpustate->px &= U64(0xffffffffffff0000); cpustate->px |= (data & 0xffff); break; /* PX1 */ + case 0xd: cpustate->px &= U64(0x000000000000ffff); cpustate->px |= (UINT64)data << 16; break; /* PX2 */ + default: fatalerror("SHARC: SET_UREG: unknown register %08X at %08X", ureg, cpustate->pc); + } + break; + + default: fatalerror("SHARC: SET_UREG: unknown register %08X at %08X", ureg, cpustate->pc); + } +} + +/*****************************************************************************/ +#define SET_FLAG_SV_LSHIFT(x, shift) if((x) & ((UINT32)0xffffffff << shift)) cpustate->astat |= SV +#define SET_FLAG_SV_RSHIFT(x, shift) if((x) & ((UINT32)0xffffffff >> shift)) cpustate->astat |= SV + +#define SET_FLAG_SZ(x) if((x) == 0) cpustate->astat |= SZ + +#define MAKE_EXTRACT_MASK(start_bit, length) ((0xffffffff << start_bit) & (((UINT32)0xffffffff) >> (32 - (start_bit + length)))) + +static void SHIFT_OPERATION_IMM(SHARC_REGS *cpustate, int shiftop, int data, int rn, int rx) +{ + INT8 shift = data & 0xff; + int bit = data & 0x3f; + int len = (data >> 6) & 0x3f; + + cpustate->astat &= ~(SZ|SV|SS); + + switch(shiftop) + { + case 0x00: /* LSHIFT Rx BY <data8>*/ + { + if(shift < 0) { + REG(rn) = (shift > -32 ) ? (REG(rx) >> -shift) : 0; + } else { + REG(rn) = (shift < 32) ? (REG(rx) << shift) : 0; + if (shift > 0) + { + cpustate->astat |= SV; + } + } + SET_FLAG_SZ(REG(rn)); + break; + } + + case 0x01: /* ASHIFT Rx BY <data8> */ + { + if (shift < 0) + { + REG(rn) = (shift > -32) ? ((INT32)REG(rx) >> -shift) : ((REG(rx) & 0x80000000) ? 0xffffffff : 0); + } + else + { + REG(rn) = (shift < 32) ? ((INT32)REG(rx) << shift) : 0; + if (shift > 0) + { + cpustate->astat |= SV; + } + } + SET_FLAG_SZ(REG(rn)); + break; + } + + case 0x02: /* ROT Rx BY <data8> */ + { + if (shift < 0) + { + int s = (-shift) & 0x1f; + REG(rn) = (((UINT32)REG(rx) >> s) & ((UINT32)(0xffffffff) >> s)) | + (((UINT32)REG(rx) << (32-s)) & ((UINT32)(0xffffffff) << (32-s))); + } + else + { + int s = shift & 0x1f; + REG(rn) = (((UINT32)REG(rx) << s) & ((UINT32)(0xffffffff) << s)) | + (((UINT32)REG(rx) >> (32-s)) & ((UINT32)(0xffffffff) >> (32-s))); + } + SET_FLAG_SZ(REG(rn)); + break; + } + + case 0x08: /* Rn = Rn OR LSHIFT Rx BY <data8> */ + { + UINT32 r = 0; + if(shift < 0) { + r = (shift > -32 ) ? (REG(rx) >> -shift) : 0; + } else { + r = (shift < 32) ? (REG(rx) << shift) : 0; + if (shift > 0) + { + cpustate->astat |= SV; + } + } + SET_FLAG_SZ(r); + + REG(rn) = REG(rn) | r; + break; + } + + case 0x10: /* FEXT Rx BY <bit6>:<len6> */ + { + UINT32 ext = REG(rx) & MAKE_EXTRACT_MASK(bit, len); + REG(rn) = ext >> bit; + + SET_FLAG_SZ(REG(rn)); + if (bit+len > 32) + { + cpustate->astat |= SV; + } + break; + } + + case 0x12: /* FEXT Rx BY <bit6>:<len6> (Sign Extended) */ + { + UINT32 ext = (REG(rx) & MAKE_EXTRACT_MASK(bit, len)) >> bit; + if (ext & (1 << (len-1))) { + ext |= (UINT32)0xffffffff << (len-1); + } + REG(rn) = ext; + + SET_FLAG_SZ(REG(rn)); + if (bit+len > 32) + { + cpustate->astat |= SV; + } + break; + } + + case 0x13: /* FDEP Rx BY Ry <bit6>:<len6> (Sign Extended) */ + { + UINT32 ext = REG(rx) & MAKE_EXTRACT_MASK(0, len); + if (ext & (1 << (len-1))) { + ext |= (UINT32)0xffffffff << (len-1); + } + REG(rn) = ext << bit; + + SET_FLAG_SZ(REG(rn)); + if (bit+len > 32) + { + cpustate->astat |= SV; + } + break; + } + + case 0x19: /* Rn = Rn OR FDEP Rx BY <bit6>:<len6> */ + { + UINT32 ext = REG(rx) & MAKE_EXTRACT_MASK(0, len); + + REG(rn) |= ext << bit; + + SET_FLAG_SZ(REG(rn)); + if (bit+len > 32) + { + cpustate->astat |= SV; + } + break; + } + + case 0x30: /* BSET Rx BY <data8> */ + { + REG(rn) = REG(rx); + if (data >= 0 && data < 32) + { + REG(rn) |= (1 << data); + } + else + { + cpustate->astat |= SV; + } + SET_FLAG_SZ(REG(rn)); + break; + } + + case 0x31: /* BCLR Rx BY <data8> */ + { + REG(rn) = REG(rx); + if (data >= 0 && data < 32) + { + REG(rn) &= ~(1 << data); + } + else + { + cpustate->astat |= SV; + } + SET_FLAG_SZ(REG(rn)); + break; + } + + case 0x32: /* BTGL Rx BY <data8> */ + { + REG(rn) = REG(rx); + if (data >= 0 && data < 32) + { + REG(rn) ^= (1 << data); + } + else + { + cpustate->astat |= SV; + } + SET_FLAG_SZ(REG(rn)); + break; + } + + case 0x33: /* BTST Rx BY <data8> */ + { + if (data < 32) + { + UINT32 r = REG(rx) & (1 << data); + + SET_FLAG_SZ(r); + } + else + { + cpustate->astat |= SZ | SV; + } + break; + } + + default: fatalerror("SHARC: unimplemented shift operation %02X at %08X", shiftop, cpustate->pc); + } +} + +#include "compute.c" + +static void COMPUTE(SHARC_REGS *cpustate, UINT32 opcode) +{ + int multiop; + int op = (opcode >> 12) & 0xff; + int cu = (opcode >> 20) & 0x3; + int rn = (opcode >> 8) & 0xf; + int rx = (opcode >> 4) & 0xf; + int ry = (opcode >> 0) & 0xf; + //int rs = (opcode >> 12) & 0xf; + //int ra = rn; + //int rm = rs; + + if(opcode & 0x400000) /* Multi-function opcode */ + { + int fm = (opcode >> 12) & 0xf; + int fa = (opcode >> 8) & 0xf; + int fxm = (opcode >> 6) & 0x3; // registers 0 - 3 + int fym = ((opcode >> 4) & 0x3) + 4; // registers 4 - 7 + int fxa = ((opcode >> 2) & 0x3) + 8; // registers 8 - 11 + int fya = (opcode & 0x3) + 12; // registers 12 - 15 + + multiop = (opcode >> 16) & 0x3f; + switch(multiop) + { + case 0x00: compute_multi_mr_to_reg(cpustate, op & 0xf, rn); break; + case 0x01: compute_multi_reg_to_mr(cpustate, op & 0xf, rn); break; + + case 0x04: /* Rm = Rxm * Rym (SSFR), Ra = Rxa + Rya */ + { + compute_mul_ssfr_add(cpustate, fm, fxm, fym, fa, fxa, fya); + break; + } + + case 0x05: /* Rm = Rxm * Rym (SSFR), Ra = Rxa - Rya */ + { + compute_mul_ssfr_sub(cpustate, fm, fxm, fym, fa, fxa, fya); + break; + } + + case 0x18: /* Fm = Fxm * Fym, Fa = Fxa + Fya */ + { + compute_fmul_fadd(cpustate, fm, fxm, fym, fa, fxa, fya); + break; + } + + case 0x19: /* Fm = Fxm * Fym, Fa = Fxa - Fya */ + { + compute_fmul_fsub(cpustate, fm, fxm, fym, fa, fxa, fya); + break; + } + + case 0x1a: /* Fm = Fxm * Fym, Fa = FLOAT Fxa BY Fya */ + { + compute_fmul_float_scaled(cpustate, fm, fxm, fym, fa, fxa, fya); + break; + } + + case 0x1b: /* Fm = Fxm * Fym, Fa = FIX Fxa BY Fya */ + { + compute_fmul_fix_scaled(cpustate, fm, fxm, fym, fa, fxa, fya); + break; + } + + case 0x1e: /* Fm = Fxm * Fym, Fa = MAX(Fxa, Fya) */ + { + compute_fmul_fmax(cpustate, fm, fxm, fym, fa, fxa, fya); + break; + } + + case 0x1f: /* Fm = Fxm * Fym, Fa = MIN(Fxa, Fya) */ + { + compute_fmul_fmin(cpustate, fm, fxm, fym, fa, fxa, fya); + break; + } + + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: + case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: + { + /* Parallel Multiplier & Dual Add/Subtract */ + /* Floating-point */ + int fs = (opcode >> 16) & 0xf; + compute_fmul_dual_fadd_fsub(cpustate, fm, fxm, fym, fa, fs, fxa, fya); + break; + } + + default: + fatalerror("SHARC: compute: multi-function opcode %02X not implemented ! (%08X, %08X)", multiop, cpustate->pc, opcode); + break; + } + } + else /* Single-function opcode */ + { + switch(cu) + { + /* ALU operations */ + case 0: + { + switch(op) + { + case 0x01: compute_add(cpustate, rn, rx, ry); break; + case 0x02: compute_sub(cpustate, rn, rx, ry); break; + case 0x05: compute_add_ci(cpustate, rn, rx, ry); break; + case 0x06: compute_sub_ci(cpustate, rn, rx, ry); break; + case 0x0a: compute_comp(cpustate, rx, ry); break; + case 0x21: compute_pass(cpustate, rn, rx); break; + case 0x22: compute_neg(cpustate, rn, rx); break; + case 0x29: compute_inc(cpustate, rn, rx); break; + case 0x2a: compute_dec(cpustate, rn, rx); break; + case 0x40: compute_and(cpustate, rn, rx, ry); break; + case 0x41: compute_or(cpustate, rn, rx, ry); break; + case 0x42: compute_xor(cpustate, rn, rx, ry); break; + case 0x43: compute_not(cpustate, rn, rx); break; + case 0x61: compute_min(cpustate, rn, rx, ry); break; + case 0x62: compute_max(cpustate, rn, rx, ry); break; + case 0x81: compute_fadd(cpustate, rn, rx, ry); break; + case 0x82: compute_fsub(cpustate, rn, rx, ry); break; + case 0x8a: compute_fcomp(cpustate, rx, ry); break; + case 0x91: compute_fabs_plus(cpustate, rn, rx, ry); break; + case 0xa1: compute_fpass(cpustate, rn, rx); break; + case 0xa2: compute_fneg(cpustate, rn, rx); break; + case 0xb0: compute_fabs(cpustate, rn, rx); break; + case 0xbd: compute_scalb(cpustate, rn, rx, ry); break; + case 0xc1: compute_logb(cpustate, rn, rx); break; + case 0xc4: compute_recips(cpustate, rn, rx); break; + case 0xc5: compute_rsqrts(cpustate, rn, rx); break; + case 0xc9: compute_fix(cpustate, rn, rx); break; + case 0xca: compute_float(cpustate, rn, rx); break; + case 0xd9: compute_fix_scaled(cpustate, rn, rx, ry); break; + case 0xda: compute_float_scaled(cpustate, rn, rx, ry); break; + case 0xe1: compute_fmin(cpustate, rn, rx, ry); break; + case 0xe2: compute_fmax(cpustate, rn, rx, ry); break; + case 0xe3: compute_fclip(cpustate, rn, rx, ry); break; + + case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: + { + /* Fixed-point Dual Add/Subtract */ + int rs = (opcode >> 12) & 0xf; + int ra = (opcode >> 8) & 0xf; + compute_dual_add_sub(cpustate, ra, rs, rx, ry); + break; + } + + case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: + { + /* Floating-point Dual Add/Subtract */ + int rs = (opcode >> 12) & 0xf; + int ra = (opcode >> 8) & 0xf; + compute_dual_fadd_fsub(cpustate, ra, rs, rx, ry); + break; + } + + default: fatalerror("SHARC: compute: unimplemented ALU operation %02X (%08X, %08X)", op, cpustate->pc, opcode); + } + break; + } + + + /* Multiplier operations */ + case 1: + { + switch(op) + { + case 0x14: cpustate->mrf = 0; break; + case 0x16: cpustate->mrb = 0; break; + + case 0x30: compute_fmul(cpustate, rn, rx, ry); break; + case 0x40: compute_mul_uuin(cpustate, rn, rx, ry); break; + case 0x70: compute_mul_ssin(cpustate, rn, rx, ry); break; + + case 0xb0: REG(rn) = compute_mrf_plus_mul_ssin(cpustate, rx, ry); break; + case 0xb2: REG(rn) = compute_mrb_plus_mul_ssin(cpustate, rx, ry); break; + + default: + fatalerror("SHARC: compute: multiplier operation %02X not implemented ! (%08X, %08X)", op, cpustate->pc, opcode); + break; + } + break; + } + + + /* Shifter operations */ + case 2: + { + cpustate->astat &= ~(SZ|SV|SS); + + op >>= 2; + switch(op) + { + case 0x00: /* LSHIFT Rx BY Ry*/ + { + int shift = REG(ry); + if(shift < 0) + { + REG(rn) = (shift > -32 ) ? (REG(rx) >> -shift) : 0; + } + else + { + REG(rn) = (shift < 32) ? (REG(rx) << shift) : 0; + if (shift > 0) + { + cpustate->astat |= SV; + } + } + SET_FLAG_SZ(REG(rn)); + break; + } + + case 0x02: /* ROT Rx BY Ry */ + { + int shift = REG(ry); + if (shift < 0) + { + int s = (-shift) & 0x1f; + REG(rn) = (((UINT32)REG(rx) >> s) & ((UINT32)(0xffffffff) >> s)) | + (((UINT32)REG(rx) << (32-s)) & ((UINT32)(0xffffffff) << (32-s))); + } + else + { + int s = shift & 0x1f; + REG(rn) = (((UINT32)REG(rx) << s) & ((UINT32)(0xffffffff) << s)) | + (((UINT32)REG(rx) >> (32-s)) & ((UINT32)(0xffffffff) >> (32-s))); + if (shift > 0) + { + cpustate->astat |= SV; + } + } + SET_FLAG_SZ(REG(rn)); + break; + } + + case 0x08: /* Rn = Rn OR LSHIFT Rx BY Ry*/ + { + INT8 shift = REG(ry); + if(shift < 0) { + REG(rn) = REG(rn) | ((shift > -32 ) ? (REG(rx) >> -shift) : 0); + } else { + REG(rn) = REG(rn) | ((shift < 32) ? (REG(rx) << shift) : 0); + if (shift > 0) + { + cpustate->astat |= SV; + } + } + SET_FLAG_SZ(REG(rn)); + break; + } + + case 0x10: /* FEXT Rx BY Ry */ + { + int bit = REG(ry) & 0x3f; + int len = (REG(ry) >> 6) & 0x3f; + UINT32 ext = REG(rx) & MAKE_EXTRACT_MASK(bit, len); + REG(rn) = ext >> bit; + + SET_FLAG_SZ(REG(rn)); + if (bit+len > 32) + { + cpustate->astat |= SV; + } + break; + } + + case 0x12: /* FEXT Rx BY Ry (Sign Extended) */ + { + int bit = REG(ry) & 0x3f; + int len = (REG(ry) >> 6) & 0x3f; + UINT32 ext = (REG(rx) & MAKE_EXTRACT_MASK(bit, len)) >> bit; + if (ext & (1 << (len-1))) { + ext |= (UINT32)0xffffffff << (len-1); + } + REG(rn) = ext; + + SET_FLAG_SZ(REG(rn)); + if (bit+len > 32) + { + cpustate->astat |= SV; + } + break; + } + + case 0x19: /* Rn = Rn OR FDEP Rx BY Ry */ + { + int bit = REG(ry) & 0x3f; + int len = (REG(ry) >> 6) & 0x3f; + UINT32 ext = REG(rx) & MAKE_EXTRACT_MASK(0, len); + + REG(rn) |= ext << bit; + + SET_FLAG_SZ(REG(rn)); + if (bit+len > 32) + { + cpustate->astat |= SV; + } + break; + } + + case 0x30: /* BSET Rx BY Ry */ + { + UINT32 shift = REG(ry); + REG(rn) = REG(rx); + if (shift < 32) + { + REG(rn) |= (1 << shift); + } + else + { + cpustate->astat |= SV; + } + SET_FLAG_SZ(REG(rn)); + break; + } + + case 0x31: /* BCLR Rx BY Ry */ + { + UINT32 shift = REG(ry); + REG(rn) = REG(rx); + if (shift < 32) + { + REG(rn) &= ~(1 << shift); + } + else + { + cpustate->astat |= SV; + } + SET_FLAG_SZ(REG(rn)); + break; + } + + case 0x33: /* BTST Rx BY Ry */ + { + UINT32 shift = REG(ry); + if (shift < 32) + { + UINT32 r = REG(rx) & (1 << shift); + + SET_FLAG_SZ(r); + } + else + { + cpustate->astat |= SZ | SV; + } + break; + } + + default: + fatalerror("SHARC: compute: shift operation %02X not implemented ! (%08X, %08X)", op, cpustate->pc, opcode); + } + break; + } + + default: + fatalerror("SHARC: compute: invalid single-function operation %02X", cu); + } + } +} + +INLINE void PUSH_PC(SHARC_REGS *cpustate, UINT32 pc) +{ + cpustate->pcstkp++; + if(cpustate->pcstkp >= 32) + { + fatalerror("SHARC: PC Stack overflow !"); + } + + if (cpustate->pcstkp == 0) + { + cpustate->stky |= 0x400000; + } + else + { + cpustate->stky &= ~0x400000; + } + + cpustate->pcstk = pc; + cpustate->pcstack[cpustate->pcstkp] = pc; +} + +INLINE UINT32 POP_PC(SHARC_REGS *cpustate) +{ + cpustate->pcstk = cpustate->pcstack[cpustate->pcstkp]; + + if(cpustate->pcstkp == 0) + { + fatalerror("SHARC: PC Stack underflow !"); + } + + cpustate->pcstkp--; + + if (cpustate->pcstkp == 0) + { + cpustate->stky |= 0x400000; + } + else + { + cpustate->stky &= ~0x400000; + } + + return cpustate->pcstk; +} + +INLINE UINT32 TOP_PC(SHARC_REGS *cpustate) +{ + return cpustate->pcstack[cpustate->pcstkp]; +} + +INLINE void PUSH_LOOP(SHARC_REGS *cpustate, UINT32 pc, UINT32 count) +{ + cpustate->lstkp++; + if(cpustate->lstkp >= 6) + { + fatalerror("SHARC: Loop Stack overflow !"); + } + + if (cpustate->lstkp == 0) + { + cpustate->stky |= 0x4000000; + } + else + { + cpustate->stky &= ~0x4000000; + } + + cpustate->lcstack[cpustate->lstkp] = count; + cpustate->lastack[cpustate->lstkp] = pc; + cpustate->curlcntr = count; + cpustate->laddr = pc; +} + +INLINE void POP_LOOP(SHARC_REGS *cpustate) +{ + if(cpustate->lstkp == 0) + { + fatalerror("SHARC: Loop Stack underflow !"); + } + + cpustate->lstkp--; + + if (cpustate->lstkp == 0) + { + cpustate->stky |= 0x4000000; + } + else + { + cpustate->stky &= ~0x4000000; + } + + cpustate->curlcntr = cpustate->lcstack[cpustate->lstkp]; + cpustate->laddr = cpustate->lastack[cpustate->lstkp]; +} + +INLINE void PUSH_STATUS_STACK(SHARC_REGS *cpustate) +{ + cpustate->status_stkp++; + if (cpustate->status_stkp >= 5) + { + fatalerror("SHARC: Status stack overflow !"); + } + + if (cpustate->status_stkp == 0) + { + cpustate->stky |= 0x1000000; + } + else + { + cpustate->stky &= ~0x1000000; + } + + cpustate->status_stack[cpustate->status_stkp].mode1 = GET_UREG(cpustate, REG_MODE1); + cpustate->status_stack[cpustate->status_stkp].astat = GET_UREG(cpustate, REG_ASTAT); +} + +INLINE void POP_STATUS_STACK(SHARC_REGS *cpustate) +{ + SET_UREG(cpustate, REG_MODE1, cpustate->status_stack[cpustate->status_stkp].mode1); + SET_UREG(cpustate, REG_ASTAT, cpustate->status_stack[cpustate->status_stkp].astat); + + cpustate->status_stkp--; + if (cpustate->status_stkp < 0) + { + fatalerror("SHARC: Status stack underflow !"); + } + + if (cpustate->status_stkp == 0) + { + cpustate->stky |= 0x1000000; + } + else + { + cpustate->stky &= ~0x1000000; + } +} + +INLINE int IF_CONDITION_CODE(SHARC_REGS *cpustate, int cond) +{ + switch(cond) + { + case 0x00: return cpustate->astat & AZ; /* EQ */ + case 0x01: return !(cpustate->astat & AZ) && (cpustate->astat & AN); /* LT */ + case 0x02: return (cpustate->astat & AZ) || (cpustate->astat & AN); /* LE */ + case 0x03: return (cpustate->astat & AC); /* AC */ + case 0x04: return (cpustate->astat & AV); /* AV */ + case 0x05: return (cpustate->astat & MV); /* MV */ + case 0x06: return (cpustate->astat & MN); /* MS */ + case 0x07: return (cpustate->astat & SV); /* SV */ + case 0x08: return (cpustate->astat & SZ); /* SZ */ + case 0x09: return (cpustate->flag[0] != 0); /* FLAG0 */ + case 0x0a: return (cpustate->flag[1] != 0); /* FLAG1 */ + case 0x0b: return (cpustate->flag[2] != 0); /* FLAG2 */ + case 0x0c: return (cpustate->flag[3] != 0); /* FLAG3 */ + case 0x0d: return (cpustate->astat & BTF); /* TF */ + case 0x0e: return 0; /* BM */ + case 0x0f: return (cpustate->curlcntr!=1); /* NOT LCE */ + case 0x10: return !(cpustate->astat & AZ); /* NOT EQUAL */ + case 0x11: return (cpustate->astat & AZ) || !(cpustate->astat & AN); /* GE */ + case 0x12: return !(cpustate->astat & AZ) && !(cpustate->astat & AN); /* GT */ + case 0x13: return !(cpustate->astat & AC); /* NOT AC */ + case 0x14: return !(cpustate->astat & AV); /* NOT AV */ + case 0x15: return !(cpustate->astat & MV); /* NOT MV */ + case 0x16: return !(cpustate->astat & MN); /* NOT MS */ + case 0x17: return !(cpustate->astat & SV); /* NOT SV */ + case 0x18: return !(cpustate->astat & SZ); /* NOT SZ */ + case 0x19: return (cpustate->flag[0] == 0); /* NOT FLAG0 */ + case 0x1a: return (cpustate->flag[1] == 0); /* NOT FLAG1 */ + case 0x1b: return (cpustate->flag[2] == 0); /* NOT FLAG2 */ + case 0x1c: return (cpustate->flag[3] == 0); /* NOT FLAG3 */ + case 0x1d: return !(cpustate->astat & BTF); /* NOT TF */ + case 0x1e: return 1; /* NOT BM */ + case 0x1f: return 1; /* TRUE */ + } + return 1; +} + +INLINE int DO_CONDITION_CODE(SHARC_REGS *cpustate, int cond) +{ + switch(cond) + { + case 0x00: return cpustate->astat & AZ; /* EQ */ + case 0x01: return !(cpustate->astat & AZ) && (cpustate->astat & AN); /* LT */ + case 0x02: return (cpustate->astat & AZ) || (cpustate->astat & AN); /* LE */ + case 0x03: return (cpustate->astat & AC); /* AC */ + case 0x04: return (cpustate->astat & AV); /* AV */ + case 0x05: return (cpustate->astat & MV); /* MV */ + case 0x06: return (cpustate->astat & MN); /* MS */ + case 0x07: return (cpustate->astat & SV); /* SV */ + case 0x08: return (cpustate->astat & SZ); /* SZ */ + case 0x09: return (cpustate->flag[0] != 0); /* FLAG0 */ + case 0x0a: return (cpustate->flag[1] != 0); /* FLAG1 */ + case 0x0b: return (cpustate->flag[2] != 0); /* FLAG2 */ + case 0x0c: return (cpustate->flag[3] != 0); /* FLAG3 */ + case 0x0d: return (cpustate->astat & BTF); /* TF */ + case 0x0e: return 0; /* BM */ + case 0x0f: return (cpustate->curlcntr==1); /* LCE */ + case 0x10: return !(cpustate->astat & AZ); /* NOT EQUAL */ + case 0x11: return (cpustate->astat & AZ) || !(cpustate->astat & AN); /* GE */ + case 0x12: return !(cpustate->astat & AZ) && !(cpustate->astat & AN); /* GT */ + case 0x13: return !(cpustate->astat & AC); /* NOT AC */ + case 0x14: return !(cpustate->astat & AV); /* NOT AV */ + case 0x15: return !(cpustate->astat & MV); /* NOT MV */ + case 0x16: return !(cpustate->astat & MN); /* NOT MS */ + case 0x17: return !(cpustate->astat & SV); /* NOT SV */ + case 0x18: return !(cpustate->astat & SZ); /* NOT SZ */ + case 0x19: return (cpustate->flag[0] == 0); /* NOT FLAG0 */ + case 0x1a: return (cpustate->flag[1] == 0); /* NOT FLAG1 */ + case 0x1b: return (cpustate->flag[2] == 0); /* NOT FLAG2 */ + case 0x1c: return (cpustate->flag[3] == 0); /* NOT FLAG3 */ + case 0x1d: return !(cpustate->astat & BTF); /* NOT TF */ + case 0x1e: return 1; /* NOT BM */ + case 0x1f: return 0; /* FALSE (FOREVER) */ + } + return 1; +} + +/*****************************************************************************/ +/* | 001xxxxxx | */ + +/* compute / dreg <-> DM / dreg <-> PM */ +static void sharcop_compute_dreg_dm_dreg_pm(SHARC_REGS *cpustate) +{ + int pm_dreg = (cpustate->opcode >> 23) & 0xf; + int pmm = (cpustate->opcode >> 27) & 0x7; + int pmi = (cpustate->opcode >> 30) & 0x7; + int dm_dreg = (cpustate->opcode >> 33) & 0xf; + int dmm = (cpustate->opcode >> 38) & 0x7; + int dmi = (cpustate->opcode >> 41) & 0x7; + int pmd = (cpustate->opcode >> 37) & 0x1; + int dmd = (cpustate->opcode >> 44) & 0x1; + int compute = cpustate->opcode & 0x7fffff; + + /* due to parallelity issues, source DREGs must be saved */ + /* because the compute operation may change them */ + UINT32 parallel_pm_dreg = REG(pm_dreg); + UINT32 parallel_dm_dreg = REG(dm_dreg); + + if (compute) + { + COMPUTE(cpustate, compute); + } + + if (pmd) // dreg -> PM + { + pm_write32(cpustate, PM_REG_I(pmi), parallel_pm_dreg); + PM_REG_I(pmi) += PM_REG_M(pmm); + UPDATE_CIRCULAR_BUFFER_PM(pmi); + } + else // PM -> dreg + { + REG(pm_dreg) = pm_read32(cpustate, PM_REG_I(pmi)); + PM_REG_I(pmi) += PM_REG_M(pmm); + UPDATE_CIRCULAR_BUFFER_PM(pmi); + } + + if (dmd) // dreg -> DM + { + dm_write32(cpustate, DM_REG_I(dmi), parallel_dm_dreg); + DM_REG_I(dmi) += DM_REG_M(dmm); + UPDATE_CIRCULAR_BUFFER_DM(dmi); + } + else // DM -> dreg + { + REG(dm_dreg) = dm_read32(cpustate, DM_REG_I(dmi)); + DM_REG_I(dmi) += DM_REG_M(dmm); + UPDATE_CIRCULAR_BUFFER_DM(dmi); + } +} + +/*****************************************************************************/ +/* | 00000001x | */ + +/* compute */ +static void sharcop_compute(SHARC_REGS *cpustate) +{ + int cond = (cpustate->opcode >> 33) & 0x1f; + int compute = cpustate->opcode & 0x7fffff; + + if (IF_CONDITION_CODE(cpustate, cond) && compute != 0) + { + COMPUTE(cpustate, compute); + } +} + +/*****************************************************************************/ +/* | 010xxxxxx | */ + +/* compute / ureg <-> DM|PM, pre-modify */ +static void sharcop_compute_ureg_dmpm_premod(SHARC_REGS *cpustate) +{ + int i = (cpustate->opcode >> 41) & 0x7; + int m = (cpustate->opcode >> 38) & 0x7; + int cond = (cpustate->opcode >> 33) & 0x1f; + int g = (cpustate->opcode >> 32) & 0x1; + int d = (cpustate->opcode >> 31) & 0x1; + int ureg = (cpustate->opcode >> 23) & 0xff; + int compute = cpustate->opcode & 0x7fffff; + + if (IF_CONDITION_CODE(cpustate, cond)) + { + /* due to parallelity issues, source UREG must be saved */ + /* because the compute operation may change it */ + UINT32 parallel_ureg = GET_UREG(cpustate, ureg); + + if (compute) + { + COMPUTE(cpustate, compute); + } + + if (g) /* PM */ + { + if (d) /* ureg -> PM */ + { + if (ureg == 0xdb) /* PX register access is always 48-bit */ + { + pm_write48(cpustate, PM_REG_I(i)+PM_REG_M(m), cpustate->px); + } + else + { + pm_write32(cpustate, PM_REG_I(i)+PM_REG_M(m), parallel_ureg); + } + } + else /* PM <- ureg */ + { + if (ureg == 0xdb) /* PX register access is always 48-bit */ + { + cpustate->px = pm_read48(cpustate, PM_REG_I(i)+PM_REG_M(m)); + } + else + { + SET_UREG(cpustate, ureg, pm_read32(cpustate, PM_REG_I(i)+PM_REG_M(m))); + } + } + } + else /* DM */ + { + if (d) /* ureg -> DM */ + { + dm_write32(cpustate, DM_REG_I(i)+DM_REG_M(m), parallel_ureg); + } + else /* DM <- ureg */ + { + SET_UREG(cpustate, ureg, dm_read32(cpustate, DM_REG_I(i)+DM_REG_M(m))); + } + } + } +} + +/* compute / ureg <-> DM|PM, post-modify */ +static void sharcop_compute_ureg_dmpm_postmod(SHARC_REGS *cpustate) +{ + int i = (cpustate->opcode >> 41) & 0x7; + int m = (cpustate->opcode >> 38) & 0x7; + int cond = (cpustate->opcode >> 33) & 0x1f; + int g = (cpustate->opcode >> 32) & 0x1; + int d = (cpustate->opcode >> 31) & 0x1; + int ureg = (cpustate->opcode >> 23) & 0xff; + int compute = cpustate->opcode & 0x7fffff; + + if(IF_CONDITION_CODE(cpustate, cond)) + { + /* due to parallelity issues, source UREG must be saved */ + /* because the compute operation may change it */ + UINT32 parallel_ureg = GET_UREG(cpustate, ureg); + + if (compute) + { + COMPUTE(cpustate, compute); + } + + if (g) /* PM */ + { + if (d) /* ureg -> PM */ + { + if (ureg == 0xdb) /* PX register access is always 48-bit */ + { + pm_write48(cpustate, PM_REG_I(i), cpustate->px); + } + else + { + pm_write32(cpustate, PM_REG_I(i), parallel_ureg); + } + PM_REG_I(i) += PM_REG_M(m); + UPDATE_CIRCULAR_BUFFER_PM(i); + } + else /* PM <- ureg */ + { + if (ureg == 0xdb) /* PX register access is always 48-bit */ + { + cpustate->px = pm_read48(cpustate, PM_REG_I(i)); + } + else + { + SET_UREG(cpustate, ureg, pm_read32(cpustate, PM_REG_I(i))); + } + PM_REG_I(i) += PM_REG_M(m); + UPDATE_CIRCULAR_BUFFER_PM(i); + } + } + else /* DM */ + { + if (d) /* ureg -> DM */ + { + dm_write32(cpustate, DM_REG_I(i), parallel_ureg); + DM_REG_I(i) += DM_REG_M(m); + UPDATE_CIRCULAR_BUFFER_DM(i); + } + else /* DM <- ureg */ + { + SET_UREG(cpustate, ureg, dm_read32(cpustate, DM_REG_I(i))); + DM_REG_I(i) += DM_REG_M(m); + UPDATE_CIRCULAR_BUFFER_DM(i); + } + } + } +} + +/*****************************************************************************/ +/* | 0110xxxxx | */ + +/* compute / dreg <- DM, immediate modify */ +static void sharcop_compute_dm_to_dreg_immmod(SHARC_REGS *cpustate) +{ + int cond = (cpustate->opcode >> 33) & 0x1f; + int u = (cpustate->opcode >> 38) & 0x1; + int dreg = (cpustate->opcode >> 23) & 0xf; + int i = (cpustate->opcode >> 41) & 0x7; + int mod = SIGN_EXTEND6((cpustate->opcode >> 27) & 0x3f); + int compute = cpustate->opcode & 0x7fffff; + + if (IF_CONDITION_CODE(cpustate, cond)) + { + if (compute != 0) + { + COMPUTE(cpustate, compute); + } + + if (u) /* post-modify with update */ + { + REG(dreg) = dm_read32(cpustate, DM_REG_I(i)); + DM_REG_I(i) += mod; + UPDATE_CIRCULAR_BUFFER_DM(i); + } + else /* pre-modify, no update */ + { + REG(dreg) = dm_read32(cpustate, DM_REG_I(i) + mod); + } + } +} + +/* compute / dreg -> DM, immediate modify */ +static void sharcop_compute_dreg_to_dm_immmod(SHARC_REGS *cpustate) +{ + int cond = (cpustate->opcode >> 33) & 0x1f; + int u = (cpustate->opcode >> 38) & 0x1; + int dreg = (cpustate->opcode >> 23) & 0xf; + int i = (cpustate->opcode >> 41) & 0x7; + int mod = SIGN_EXTEND6((cpustate->opcode >> 27) & 0x3f); + int compute = cpustate->opcode & 0x7fffff; + + /* due to parallelity issues, source REG must be saved */ + /* because the shift operation may change it */ + UINT32 parallel_dreg = REG(dreg); + + if (IF_CONDITION_CODE(cpustate, cond)) + { + if (compute != 0) + { + COMPUTE(cpustate, compute); + } + + if (u) /* post-modify with update */ + { + dm_write32(cpustate, DM_REG_I(i), parallel_dreg); + DM_REG_I(i) += mod; + UPDATE_CIRCULAR_BUFFER_DM(i); + } + else /* pre-modify, no update */ + { + dm_write32(cpustate, DM_REG_I(i) + mod, parallel_dreg); + } + } +} + +/* compute / dreg <- PM, immediate modify */ +static void sharcop_compute_pm_to_dreg_immmod(SHARC_REGS *cpustate) +{ + int cond = (cpustate->opcode >> 33) & 0x1f; + int u = (cpustate->opcode >> 38) & 0x1; + int dreg = (cpustate->opcode >> 23) & 0xf; + int i = (cpustate->opcode >> 41) & 0x7; + int mod = SIGN_EXTEND6((cpustate->opcode >> 27) & 0x3f); + int compute = cpustate->opcode & 0x7fffff; + + if (IF_CONDITION_CODE(cpustate, cond)) + { + if (compute != 0) + { + COMPUTE(cpustate, compute); + } + + if (u) /* post-modify with update */ + { + REG(dreg) = pm_read32(cpustate, PM_REG_I(i)); + PM_REG_I(i) += mod; + UPDATE_CIRCULAR_BUFFER_PM(i); + } + else /* pre-modify, no update */ + { + REG(dreg) = pm_read32(cpustate, PM_REG_I(i) + mod); + } + } +} + +/* compute / dreg -> PM, immediate modify */ +static void sharcop_compute_dreg_to_pm_immmod(SHARC_REGS *cpustate) +{ + int cond = (cpustate->opcode >> 33) & 0x1f; + int u = (cpustate->opcode >> 38) & 0x1; + int dreg = (cpustate->opcode >> 23) & 0xf; + int i = (cpustate->opcode >> 41) & 0x7; + int mod = SIGN_EXTEND6((cpustate->opcode >> 27) & 0x3f); + int compute = cpustate->opcode & 0x7fffff; + + /* due to parallelity issues, source REG must be saved */ + /* because the compute operation may change it */ + UINT32 parallel_dreg = REG(dreg); + + if (IF_CONDITION_CODE(cpustate, cond)) + { + if (compute != 0) + { + COMPUTE(cpustate, compute); + } + + if (u) /* post-modify with update */ + { + pm_write32(cpustate, PM_REG_I(i), parallel_dreg); + PM_REG_I(i) += mod; + UPDATE_CIRCULAR_BUFFER_PM(i); + } + else /* pre-modify, no update */ + { + pm_write32(cpustate, PM_REG_I(i) + mod, parallel_dreg); + } + } +} + +/*****************************************************************************/ +/* | 0111xxxxx | */ + +/* compute / ureg <-> ureg */ +static void sharcop_compute_ureg_to_ureg(SHARC_REGS *cpustate) +{ + int src_ureg = (cpustate->opcode >> 36) & 0xff; + int dst_ureg = (cpustate->opcode >> 23) & 0xff; + int cond = (cpustate->opcode >> 31) & 0x1f; + int compute = cpustate->opcode & 0x7fffff; + + if (IF_CONDITION_CODE(cpustate, cond)) + { + /* due to parallelity issues, source UREG must be saved */ + /* because the compute operation may change it */ + UINT32 parallel_ureg = GET_UREG(cpustate, src_ureg); + + if (compute != 0) + { + COMPUTE(cpustate, compute); + } + + SET_UREG(cpustate, dst_ureg, parallel_ureg); + } +} + +/*****************************************************************************/ +/* | 1000xxxxx | */ + +/* immediate shift / dreg <-> DM|PM */ +static void sharcop_imm_shift_dreg_dmpm(SHARC_REGS *cpustate) +{ + int i = (cpustate->opcode >> 41) & 0x7; + int m = (cpustate->opcode >> 38) & 0x7; + int g = (cpustate->opcode >> 32) & 0x1; + int d = (cpustate->opcode >> 31) & 0x1; + int dreg = (cpustate->opcode >> 23) & 0xf; + int cond = (cpustate->opcode >> 33) & 0x1f; + int data = ((cpustate->opcode >> 8) & 0xff) | ((cpustate->opcode >> 19) & 0xf00); + int shiftop = (cpustate->opcode >> 16) & 0x3f; + int rn = (cpustate->opcode >> 4) & 0xf; + int rx = (cpustate->opcode & 0xf); + + if (IF_CONDITION_CODE(cpustate, cond)) + { + /* due to parallelity issues, source REG must be saved */ + /* because the shift operation may change it */ + UINT32 parallel_dreg = REG(dreg); + + SHIFT_OPERATION_IMM(cpustate, shiftop, data, rn, rx); + + if (g) /* PM */ + { + if (d) /* dreg -> PM */ + { + pm_write32(cpustate, PM_REG_I(i), parallel_dreg); + PM_REG_I(i) += PM_REG_M(m); + UPDATE_CIRCULAR_BUFFER_PM(i); + } + else /* PM <- dreg */ + { + REG(dreg) = pm_read32(cpustate, PM_REG_I(i)); + PM_REG_I(i) += PM_REG_M(m); + UPDATE_CIRCULAR_BUFFER_PM(i); + } + } + else /* DM */ + { + if (d) /* dreg -> DM */ + { + dm_write32(cpustate, DM_REG_I(i), parallel_dreg); + DM_REG_I(i) += DM_REG_M(m); + UPDATE_CIRCULAR_BUFFER_DM(i); + } + else /* DM <- dreg */ + { + REG(dreg) = dm_read32(cpustate, DM_REG_I(i)); + DM_REG_I(i) += DM_REG_M(m); + UPDATE_CIRCULAR_BUFFER_DM(i); + } + } + } +} + +/*****************************************************************************/ +/* | 00000010x | */ + +/* immediate shift */ +static void sharcop_imm_shift(SHARC_REGS *cpustate) +{ + int cond = (cpustate->opcode >> 33) & 0x1f; + int data = ((cpustate->opcode >> 8) & 0xff) | ((cpustate->opcode >> 19) & 0xf00); + int shiftop = (cpustate->opcode >> 16) & 0x3f; + int rn = (cpustate->opcode >> 4) & 0xf; + int rx = (cpustate->opcode & 0xf); + + if (IF_CONDITION_CODE(cpustate, cond)) + { + SHIFT_OPERATION_IMM(cpustate, shiftop, data, rn, rx); + } +} + +/*****************************************************************************/ +/* | 00000100x | */ + +/* compute / modify */ +static void sharcop_compute_modify(SHARC_REGS *cpustate) +{ + int cond = (cpustate->opcode >> 33) & 0x1f; + int compute = cpustate->opcode & 0x7fffff; + int g = (cpustate->opcode >> 38) & 0x1; + int m = (cpustate->opcode >> 27) & 0x7; + int i = (cpustate->opcode >> 30) & 0x7; + + if (IF_CONDITION_CODE(cpustate, cond)) + { + if (compute != 0) + { + COMPUTE(cpustate, compute); + } + + if (g) /* Modify PM */ + { + PM_REG_I(i) += PM_REG_M(m); + UPDATE_CIRCULAR_BUFFER_PM(i); + } + else /* Modify DM */ + { + DM_REG_I(i) += DM_REG_M(m); + UPDATE_CIRCULAR_BUFFER_DM(i); + } + } +} + +/*****************************************************************************/ +/* | 00000110x | */ + +/* direct call to absolute address */ +static void sharcop_direct_call(SHARC_REGS *cpustate) +{ + int j = (cpustate->opcode >> 26) & 0x1; + int cond = (cpustate->opcode >> 33) & 0x1f; + UINT32 address = cpustate->opcode & 0xffffff; + + if (IF_CONDITION_CODE(cpustate, cond)) + { + if (j) + { + //PUSH_PC(cpustate, cpustate->pc+3); /* 1 instruction + 2 delayed instructions */ + PUSH_PC(cpustate, cpustate->nfaddr); /* 1 instruction + 2 delayed instructions */ + CHANGE_PC_DELAYED(cpustate, address); + } + else + { + //PUSH_PC(cpustate, cpustate->pc+1); + PUSH_PC(cpustate, cpustate->daddr); + CHANGE_PC(cpustate, address); + } + } +} + +/* direct jump to absolute address */ +static void sharcop_direct_jump(SHARC_REGS *cpustate) +{ + int la = (cpustate->opcode >> 38) & 0x1; + int ci = (cpustate->opcode >> 24) & 0x1; + int j = (cpustate->opcode >> 26) & 0x1; + int cond = (cpustate->opcode >> 33) & 0x1f; + UINT32 address = cpustate->opcode & 0xffffff; + + if(IF_CONDITION_CODE(cpustate, cond)) + { + // Clear Interrupt + if (ci) + { + // TODO: anything else? + if (cpustate->status_stkp > 0) + { + POP_STATUS_STACK(cpustate); + } + + cpustate->interrupt_active = 0; + cpustate->irptl &= ~(1 << cpustate->active_irq_num); + } + + if (la) + { + POP_PC(cpustate); + POP_LOOP(cpustate); + } + + if (j) + { + CHANGE_PC_DELAYED(cpustate, address); + } + else + { + CHANGE_PC(cpustate, address); + } + } +} + +/*****************************************************************************/ +/* | 00000111x | */ + +/* direct call to relative address */ +static void sharcop_relative_call(SHARC_REGS *cpustate) +{ + int j = (cpustate->opcode >> 26) & 0x1; + int cond = (cpustate->opcode >> 33) & 0x1f; + UINT32 address = cpustate->opcode & 0xffffff; + + if (IF_CONDITION_CODE(cpustate, cond)) + { + if (j) + { + PUSH_PC(cpustate, cpustate->pc+3); /* 1 instruction + 2 delayed instructions */ + CHANGE_PC_DELAYED(cpustate, cpustate->pc + SIGN_EXTEND24(address)); + } + else + { + PUSH_PC(cpustate, cpustate->pc+1); + CHANGE_PC(cpustate, cpustate->pc + SIGN_EXTEND24(address)); + } + } +} + +/* direct jump to relative address */ +static void sharcop_relative_jump(SHARC_REGS *cpustate) +{ + int la = (cpustate->opcode >> 38) & 0x1; + int ci = (cpustate->opcode >> 24) & 0x1; + int j = (cpustate->opcode >> 26) & 0x1; + int cond = (cpustate->opcode >> 33) & 0x1f; + UINT32 address = cpustate->opcode & 0xffffff; + + if (IF_CONDITION_CODE(cpustate, cond)) + { + // Clear Interrupt + if (ci) + { + // TODO: anything else? + if (cpustate->status_stkp > 0) + { + POP_STATUS_STACK(cpustate); + } + + cpustate->interrupt_active = 0; + cpustate->irptl &= ~(1 << cpustate->active_irq_num); + } + + if (la) + { + POP_PC(cpustate); + POP_LOOP(cpustate); + } + + if (j) + { + CHANGE_PC_DELAYED(cpustate, cpustate->pc + SIGN_EXTEND24(address)); + } + else + { + CHANGE_PC(cpustate, cpustate->pc + SIGN_EXTEND24(address)); + } + } +} + +/*****************************************************************************/ +/* | 00001000x | */ + +/* indirect jump */ +static void sharcop_indirect_jump(SHARC_REGS *cpustate) +{ + int la = (cpustate->opcode >> 38) & 0x1; + int ci = (cpustate->opcode >> 24) & 0x1; + int j = (cpustate->opcode >> 26) & 0x1; + int e = (cpustate->opcode >> 25) & 0x1; + int pmi = (cpustate->opcode >> 30) & 0x7; + int pmm = (cpustate->opcode >> 27) & 0x7; + int cond = (cpustate->opcode >> 33) & 0x1f; + int compute = cpustate->opcode & 0x7fffff; + + // Clear Interrupt + if (ci) + { + // TODO: anything else? + if (cpustate->status_stkp > 0) + { + POP_STATUS_STACK(cpustate); + } + + cpustate->interrupt_active = 0; + cpustate->irptl &= ~(1 << cpustate->active_irq_num); + } + + if (e) /* IF...ELSE */ + { + if (IF_CONDITION_CODE(cpustate, cond)) + { + if (la) + { + POP_PC(cpustate); + POP_LOOP(cpustate); + } + + if(j) + { + CHANGE_PC_DELAYED(cpustate, PM_REG_I(pmi) + PM_REG_M(pmm)); + } + else + { + CHANGE_PC(cpustate, PM_REG_I(pmi) + PM_REG_M(pmm)); + } + } + else + { + if (compute) + { + COMPUTE(cpustate, compute); + } + } + } + else /* IF */ + { + if (IF_CONDITION_CODE(cpustate, cond)) + { + if (compute) + { + COMPUTE(cpustate, compute); + } + + if (la) + { + POP_PC(cpustate); + POP_LOOP(cpustate); + } + + if(j) + { + CHANGE_PC_DELAYED(cpustate, PM_REG_I(pmi) + PM_REG_M(pmm)); + } + else + { + CHANGE_PC(cpustate, PM_REG_I(pmi) + PM_REG_M(pmm)); + } + } + } +} + +/* indirect call */ +static void sharcop_indirect_call(SHARC_REGS *cpustate) +{ + int j = (cpustate->opcode >> 26) & 0x1; + int e = (cpustate->opcode >> 25) & 0x1; + int pmi = (cpustate->opcode >> 30) & 0x7; + int pmm = (cpustate->opcode >> 27) & 0x7; + int cond = (cpustate->opcode >> 33) & 0x1f; + int compute = cpustate->opcode & 0x7fffff; + + if (e) /* IF...ELSE */ + { + if (IF_CONDITION_CODE(cpustate, cond)) + { + if (j) + { + //PUSH_PC(cpustate, cpustate->pc+3); /* 1 instruction + 2 delayed instructions */ + PUSH_PC(cpustate, cpustate->nfaddr); /* 1 instruction + 2 delayed instructions */ + CHANGE_PC_DELAYED(cpustate, PM_REG_I(pmi) + PM_REG_M(pmm)); + } + else + { + //PUSH_PC(cpustate, cpustate->pc+1); + PUSH_PC(cpustate, cpustate->daddr); + CHANGE_PC(cpustate, PM_REG_I(pmi) + PM_REG_M(pmm)); + } + } + else + { + if (compute) + { + COMPUTE(cpustate, compute); + } + } + } + else /* IF */ + { + if (IF_CONDITION_CODE(cpustate, cond)) + { + if (compute) + { + COMPUTE(cpustate, compute); + } + + if (j) + { + //PUSH_PC(cpustate, cpustate->pc+3); /* 1 instruction + 2 delayed instructions */ + PUSH_PC(cpustate, cpustate->nfaddr); /* 1 instruction + 2 delayed instructions */ + CHANGE_PC_DELAYED(cpustate, PM_REG_I(pmi) + PM_REG_M(pmm)); + } + else + { + //PUSH_PC(cpustate, cpustate->pc+1); + PUSH_PC(cpustate, cpustate->daddr); + CHANGE_PC(cpustate, PM_REG_I(pmi) + PM_REG_M(pmm)); + } + } + } +} + +/*****************************************************************************/ +/* | 00001001x | */ + +/* indirect jump to relative address */ +static void sharcop_relative_jump_compute(SHARC_REGS *cpustate) +{ + int la = (cpustate->opcode >> 38) & 0x1; + int ci = (cpustate->opcode >> 24) & 0x1; + int j = (cpustate->opcode >> 26) & 0x1; + int e = (cpustate->opcode >> 25) & 0x1; + int cond = (cpustate->opcode >> 33) & 0x1f; + int compute = cpustate->opcode & 0x7fffff; + + // Clear Interrupt + if (ci) + { + // TODO: anything else? + if (cpustate->status_stkp > 0) + { + POP_STATUS_STACK(cpustate); + } + + cpustate->interrupt_active = 0; + cpustate->irptl &= ~(1 << cpustate->active_irq_num); + } + + if (e) /* IF...ELSE */ + { + if (IF_CONDITION_CODE(cpustate, cond)) + { + if (la) + { + POP_PC(cpustate); + POP_LOOP(cpustate); + } + + if (j) + { + CHANGE_PC_DELAYED(cpustate, cpustate->pc + SIGN_EXTEND6((cpustate->opcode >> 27) & 0x3f)); + } + else + { + CHANGE_PC(cpustate, cpustate->pc + SIGN_EXTEND6((cpustate->opcode >> 27) & 0x3f)); + } + } + else + { + if (compute) + { + COMPUTE(cpustate, compute); + } + } + } + else /* IF */ + { + if (IF_CONDITION_CODE(cpustate, cond)) + { + if (compute) + { + COMPUTE(cpustate, compute); + } + + if (la) + { + POP_PC(cpustate); + POP_LOOP(cpustate); + } + + if (j) + { + CHANGE_PC_DELAYED(cpustate, cpustate->pc + SIGN_EXTEND6((cpustate->opcode >> 27) & 0x3f)); + } + else + { + CHANGE_PC(cpustate, cpustate->pc + SIGN_EXTEND6((cpustate->opcode >> 27) & 0x3f)); + } + } + } +} + +/* indirect call to relative address */ +static void sharcop_relative_call_compute(SHARC_REGS *cpustate) +{ + int j = (cpustate->opcode >> 26) & 0x1; + int e = (cpustate->opcode >> 25) & 0x1; + int cond = (cpustate->opcode >> 33) & 0x1f; + int compute = cpustate->opcode & 0x7fffff; + + if (e) /* IF...ELSE */ + { + if (IF_CONDITION_CODE(cpustate, cond)) + { + if (j) + { + //PUSH_PC(cpustate, cpustate->pc+3); /* 1 instruction + 2 delayed instructions */ + PUSH_PC(cpustate, cpustate->nfaddr); /* 1 instruction + 2 delayed instructions */ + CHANGE_PC_DELAYED(cpustate, cpustate->pc + SIGN_EXTEND6((cpustate->opcode >> 27) & 0x3f)); + } + else + { + //PUSH_PC(cpustate, cpustate->pc+1); + PUSH_PC(cpustate, cpustate->daddr); + CHANGE_PC(cpustate, cpustate->pc + SIGN_EXTEND6((cpustate->opcode >> 27) & 0x3f)); + } + } + else + { + if (compute) + { + COMPUTE(cpustate, compute); + } + } + } + else /* IF */ + { + if (IF_CONDITION_CODE(cpustate, cond)) + { + if (compute) + { + COMPUTE(cpustate, compute); + } + + if (j) + { + //PUSH_PC(cpustate, cpustate->pc+3); /* 1 instruction + 2 delayed instructions */ + PUSH_PC(cpustate, cpustate->nfaddr); /* 1 instruction + 2 delayed instructions */ + CHANGE_PC_DELAYED(cpustate, cpustate->pc + SIGN_EXTEND6((cpustate->opcode >> 27) & 0x3f)); + } + else + { + //PUSH_PC(cpustate, cpustate->pc+1); + PUSH_PC(cpustate, cpustate->daddr); + CHANGE_PC(cpustate, cpustate->pc + SIGN_EXTEND6((cpustate->opcode >> 27) & 0x3f)); + } + } + } +} + +/*****************************************************************************/ +/* | 110xxxxxx | */ + +/* indirect jump / compute / dreg <-> DM */ +static void sharcop_indirect_jump_compute_dreg_dm(SHARC_REGS *cpustate) +{ + int d = (cpustate->opcode >> 44) & 0x1; + int dmi = (cpustate->opcode >> 41) & 0x7; + int dmm = (cpustate->opcode >> 38) & 0x7; + int pmi = (cpustate->opcode >> 30) & 0x7; + int pmm = (cpustate->opcode >> 27) & 0x7; + int cond = (cpustate->opcode >> 33) & 0x1f; + int dreg = (cpustate->opcode >> 23) & 0xf; + + if (IF_CONDITION_CODE(cpustate, cond)) + { + CHANGE_PC(cpustate, PM_REG_I(pmi) + PM_REG_M(pmm)); + } + else + { + UINT32 compute = cpustate->opcode & 0x7fffff; + /* due to parallelity issues, source REG must be saved */ + /* because the compute operation may change it */ + UINT32 parallel_dreg = REG(dreg); + + if (compute) + { + COMPUTE(cpustate, compute); + } + + if (d) /* dreg -> DM */ + { + dm_write32(cpustate, DM_REG_I(dmi), parallel_dreg); + DM_REG_I(dmi) += DM_REG_M(dmm); + UPDATE_CIRCULAR_BUFFER_DM(dmi); + } + else /* DM <- dreg */ + { + REG(dreg) = dm_read32(cpustate, DM_REG_I(dmi)); + DM_REG_I(dmi) += DM_REG_M(dmm); + UPDATE_CIRCULAR_BUFFER_DM(dmi); + } + } +} + +/*****************************************************************************/ +/* | 111xxxxxx | */ + +/* relative jump / compute / dreg <-> DM */ +static void sharcop_relative_jump_compute_dreg_dm(SHARC_REGS *cpustate) +{ + int d = (cpustate->opcode >> 44) & 0x1; + int dmi = (cpustate->opcode >> 41) & 0x7; + int dmm = (cpustate->opcode >> 38) & 0x7; + int cond = (cpustate->opcode >> 33) & 0x1f; + int dreg = (cpustate->opcode >> 23) & 0xf; + + if (IF_CONDITION_CODE(cpustate, cond)) + { + CHANGE_PC(cpustate, cpustate->pc + SIGN_EXTEND6((cpustate->opcode >> 27) & 0x3f)); + } + else + { + UINT32 compute = cpustate->opcode & 0x7fffff; + /* due to parallelity issues, source REG must be saved */ + /* because the compute operation may change it */ + UINT32 parallel_dreg = REG(dreg); + + if (compute) + { + COMPUTE(cpustate, compute); + } + + if (d) /* dreg -> DM */ + { + dm_write32(cpustate, DM_REG_I(dmi), parallel_dreg); + DM_REG_I(dmi) += DM_REG_M(dmm); + UPDATE_CIRCULAR_BUFFER_DM(dmi); + } + else /* DM <- dreg */ + { + REG(dreg) = dm_read32(cpustate, DM_REG_I(dmi)); + DM_REG_I(dmi) += DM_REG_M(dmm); + UPDATE_CIRCULAR_BUFFER_DM(dmi); + } + } +} + +/*****************************************************************************/ +/* | 00001010x | */ + +/* return from subroutine / compute */ +static void sharcop_rts(SHARC_REGS *cpustate) +{ + int cond = (cpustate->opcode >> 33) & 0x1f; + int j = (cpustate->opcode >> 26) & 0x1; + int e = (cpustate->opcode >> 25) & 0x1; + //int lr = (cpustate->opcode >> 24) & 0x1; + int compute = cpustate->opcode & 0x7fffff; + + //if(lr) + // fatalerror("SHARC: rts: loop reentry not implemented !"); + + if (e) /* IF...ELSE */ + { + if(IF_CONDITION_CODE(cpustate, cond)) + { + if (j) + { + CHANGE_PC_DELAYED(cpustate, POP_PC(cpustate)); + } + else + { + CHANGE_PC(cpustate, POP_PC(cpustate)); + } + } + else + { + if (compute) + { + COMPUTE(cpustate, compute); + } + } + } + else /* IF */ + { + if (IF_CONDITION_CODE(cpustate, cond)) + { + if (compute) + { + COMPUTE(cpustate, compute); + } + + if (j) + { + CHANGE_PC_DELAYED(cpustate, POP_PC(cpustate)); + } + else + { + CHANGE_PC(cpustate, POP_PC(cpustate)); + } + } + } +} + +/*****************************************************************************/ +/* | 00001011x | */ + +/* return from interrupt / compute */ +static void sharcop_rti(SHARC_REGS *cpustate) +{ + int cond = (cpustate->opcode >> 33) & 0x1f; + int j = (cpustate->opcode >> 26) & 0x1; + int e = (cpustate->opcode >> 25) & 0x1; + int compute = cpustate->opcode & 0x7fffff; + + cpustate->irptl &= ~(1 << cpustate->active_irq_num); + + if(e) /* IF...ELSE */ + { + if (IF_CONDITION_CODE(cpustate, cond)) + { + if (j) + { + CHANGE_PC_DELAYED(cpustate, POP_PC(cpustate)); + } + else + { + CHANGE_PC(cpustate, POP_PC(cpustate)); + } + } + else + { + if (compute) + { + COMPUTE(cpustate, compute); + } + } + } + else /* IF */ + { + if (IF_CONDITION_CODE(cpustate, cond)) + { + if (compute) + { + COMPUTE(cpustate, compute); + } + + if (j) + { + CHANGE_PC_DELAYED(cpustate, POP_PC(cpustate)); + } + else + { + CHANGE_PC(cpustate, POP_PC(cpustate)); + } + } + } + + if (cpustate->status_stkp > 0) + { + POP_STATUS_STACK(cpustate); + } + + cpustate->interrupt_active = 0; + check_interrupts(cpustate); +} + +/*****************************************************************************/ +/* | 00001100x | */ + +/* do until counter expired, LCNTR immediate */ +static void sharcop_do_until_counter_imm(SHARC_REGS *cpustate) +{ + UINT16 data = (UINT16)(cpustate->opcode >> 24); + int offset = SIGN_EXTEND24(cpustate->opcode & 0xffffff); + UINT32 address = cpustate->pc + offset; + int type; + int cond = 0xf; /* until LCE (loop counter expired */ + int distance = abs(offset); + + if (distance == 1) + { + type = 1; + } + else if (distance == 2) + { + type = 2; + } + else + { + type = 3; + } + + cpustate->lcntr = data; + if (cpustate->lcntr > 0) + { + PUSH_PC(cpustate, cpustate->pc+1); + PUSH_LOOP(cpustate, address | (type << 30) | (cond << 24), cpustate->lcntr); + } +} + +/*****************************************************************************/ +/* | 00001101x | */ + +/* do until counter expired, LCNTR from UREG */ +static void sharcop_do_until_counter_ureg(SHARC_REGS *cpustate) +{ + int ureg = (cpustate->opcode >> 32) & 0xff; + int offset = SIGN_EXTEND24(cpustate->opcode & 0xffffff); + UINT32 address = cpustate->pc + offset; + int type; + int cond = 0xf; /* until LCE (loop counter expired */ + int distance = abs(offset); + + if (distance == 1) + { + type = 1; + } + else if (distance == 2) + { + type = 2; + } + else + { + type = 3; + } + + cpustate->lcntr = GET_UREG(cpustate, ureg); + if (cpustate->lcntr > 0) + { + PUSH_PC(cpustate, cpustate->pc+1); + PUSH_LOOP(cpustate, address | (type << 30) | (cond << 24), cpustate->lcntr); + } +} + +/*****************************************************************************/ +/* | 00001110x | */ + +/* do until */ +static void sharcop_do_until(SHARC_REGS *cpustate) +{ + int cond = (cpustate->opcode >> 33) & 0x1f; + int offset = SIGN_EXTEND24(cpustate->opcode & 0xffffff); + UINT32 address = (cpustate->pc + offset); + + PUSH_PC(cpustate, cpustate->pc+1); + PUSH_LOOP(cpustate, address | (cond << 24), 0); +} + +/*****************************************************************************/ +/* | 000100 | G | D | */ + +/* ureg <- DM (direct addressing) */ +static void sharcop_dm_to_ureg_direct(SHARC_REGS *cpustate) +{ + int ureg = (cpustate->opcode >> 32) & 0xff; + UINT32 address = (UINT32)(cpustate->opcode); + + SET_UREG(cpustate, ureg, dm_read32(cpustate, address)); +} + +/* ureg -> DM (direct addressing) */ +static void sharcop_ureg_to_dm_direct(SHARC_REGS *cpustate) +{ + int ureg = (cpustate->opcode >> 32) & 0xff; + UINT32 address = (UINT32)(cpustate->opcode); + + dm_write32(cpustate, address, GET_UREG(cpustate, ureg)); +} + +/* ureg <- PM (direct addressing) */ +static void sharcop_pm_to_ureg_direct(SHARC_REGS *cpustate) +{ + int ureg = (cpustate->opcode >> 32) & 0xff; + UINT32 address = (UINT32)(cpustate->opcode); + + if (ureg == 0xdb) // PX is 48-bit + { + cpustate->px = pm_read48(cpustate, address); + } + else + { + SET_UREG(cpustate, ureg, pm_read32(cpustate, address)); + } +} + +/* ureg -> PM (direct addressing) */ +static void sharcop_ureg_to_pm_direct(SHARC_REGS *cpustate) +{ + int ureg = (cpustate->opcode >> 32) & 0xff; + UINT32 address = (UINT32)(cpustate->opcode); + + if (ureg == 0xdb) // PX is 48-bit + { + pm_write48(cpustate, address, cpustate->px); + } + else + { + pm_write32(cpustate, address, GET_UREG(cpustate, ureg)); + } +} + +/*****************************************************************************/ +/* | 101 | G | III | D | */ + +/* ureg <- DM (indirect addressing) */ +static void sharcop_dm_to_ureg_indirect(SHARC_REGS *cpustate) +{ + int ureg = (cpustate->opcode >> 32) & 0xff; + UINT32 offset = (UINT32)cpustate->opcode; + int i = (cpustate->opcode >> 41) & 0x7; + + SET_UREG(cpustate, ureg, dm_read32(cpustate, DM_REG_I(i) + offset)); +} + +/* ureg -> DM (indirect addressing) */ +static void sharcop_ureg_to_dm_indirect(SHARC_REGS *cpustate) +{ + int ureg = (cpustate->opcode >> 32) & 0xff; + UINT32 offset = (UINT32)cpustate->opcode; + int i = (cpustate->opcode >> 41) & 0x7; + + dm_write32(cpustate, DM_REG_I(i) + offset, GET_UREG(cpustate, ureg)); +} + +/* ureg <- PM (indirect addressing) */ +static void sharcop_pm_to_ureg_indirect(SHARC_REGS *cpustate) +{ + int ureg = (cpustate->opcode >> 32) & 0xff; + UINT32 offset = cpustate->opcode & 0xffffff; + int i = (cpustate->opcode >> 41) & 0x7; + + if (ureg == 0xdb) /* PX is 48-bit */ + { + cpustate->px = pm_read48(cpustate, PM_REG_I(i) + offset); + } + else + { + SET_UREG(cpustate, ureg, pm_read32(cpustate, PM_REG_I(i) + offset)); + } +} + +/* ureg -> PM (indirect addressing) */ +static void sharcop_ureg_to_pm_indirect(SHARC_REGS *cpustate) +{ + int ureg = (cpustate->opcode >> 32) & 0xff; + UINT32 offset = (UINT32)cpustate->opcode; + int i = (cpustate->opcode >> 41) & 0x7; + + if (ureg == 0xdb) /* PX is 48-bit */ + { + pm_write48(cpustate, PM_REG_I(i) + offset, cpustate->px); + } + else + { + pm_write32(cpustate, PM_REG_I(i) + offset, GET_UREG(cpustate, ureg)); + } +} + +/*****************************************************************************/ +/* | 1001xxxxx | */ + +/* immediate data -> DM|PM */ +static void sharcop_imm_to_dmpm(SHARC_REGS *cpustate) +{ + int i = (cpustate->opcode >> 41) & 0x7; + int m = (cpustate->opcode >> 38) & 0x7; + int g = (cpustate->opcode >> 37) & 0x1; + UINT32 data = (UINT32)cpustate->opcode; + + if (g) + { + /* program memory (PM) */ + pm_write32(cpustate, PM_REG_I(i), data); + PM_REG_I(i) += PM_REG_M(m); + UPDATE_CIRCULAR_BUFFER_PM(i); + } + else + { + /* data memory (DM) */ + dm_write32(cpustate, DM_REG_I(i), data); + DM_REG_I(i) += DM_REG_M(m); + UPDATE_CIRCULAR_BUFFER_DM(i); + } +} + +/*****************************************************************************/ +/* | 00001111x | */ + +/* immediate data -> ureg */ +static void sharcop_imm_to_ureg(SHARC_REGS *cpustate) +{ + int ureg = (cpustate->opcode >> 32) & 0xff; + UINT32 data = (UINT32)cpustate->opcode; + + SET_UREG(cpustate, ureg, data); +} + +/*****************************************************************************/ +/* | 00010100x | */ + +/* system register bit manipulation */ +static void sharcop_sysreg_bitop(SHARC_REGS *cpustate) +{ + int bop = (cpustate->opcode >> 37) & 0x7; + int sreg = (cpustate->opcode >> 32) & 0xf; + UINT32 data = (UINT32)cpustate->opcode; + + UINT32 src = GET_UREG(cpustate, 0x70 | sreg); + + switch(bop) + { + case 0: /* SET */ + { + src |= data; + break; + } + case 1: /* CLEAR */ + { + src &= ~data; + break; + } + case 2: /* TOGGLE */ + { + src ^= data; + break; + } + case 4: /* TEST */ + { + if ((src & data) == data) + { + cpustate->astat |= BTF; + } + else + { + cpustate->astat &= ~BTF; + } + break; + } + case 5: /* XOR */ + { + if (src == data) + { + cpustate->astat |= BTF; + } + else + { + cpustate->astat &= ~BTF; + } + break; + } + default: + fatalerror("SHARC: sysreg_bitop: invalid bitop %d", bop); + break; + } + + SET_UREG(cpustate, 0x70 | sreg, src); +} + +/*****************************************************************************/ +/* | 000101100 | */ + +/* I register modify */ +static void sharcop_modify(SHARC_REGS *cpustate) +{ + int g = (cpustate->opcode >> 38) & 0x1; + int i = (cpustate->opcode >> 32) & 0x7; + INT32 data = (cpustate->opcode); + + if (g) // PM + { + PM_REG_I(i) += data; + UPDATE_CIRCULAR_BUFFER_PM(i); + } + else // DM + { + DM_REG_I(i) += data; + UPDATE_CIRCULAR_BUFFER_DM(i); + } +} + +/*****************************************************************************/ +/* | 000101101 | */ + +/* I register bit-reverse */ +static void sharcop_bit_reverse(SHARC_REGS *cpustate) +{ + fatalerror("SHARC: sharcop_bit_reverse unimplemented"); +} + +/*****************************************************************************/ +/* | 00010111x | */ + +/* push/pop stacks / flush cache */ +static void sharcop_push_pop_stacks(SHARC_REGS *cpustate) +{ + if (cpustate->opcode & U64(0x008000000000)) + { + fatalerror("sharcop_push_pop_stacks: push loop not implemented"); + } + if (cpustate->opcode & U64(0x004000000000)) + { + fatalerror("sharcop_push_pop_stacks: pop loop not implemented"); + } + if (cpustate->opcode & U64(0x002000000000)) + { + //fatalerror("sharcop_push_pop_stacks: push sts not implemented"); + PUSH_STATUS_STACK(cpustate); + } + if (cpustate->opcode & U64(0x001000000000)) + { + //fatalerror("sharcop_push_pop_stacks: pop sts not implemented"); + POP_STATUS_STACK(cpustate); + } + if (cpustate->opcode & U64(0x000800000000)) + { + PUSH_PC(cpustate, cpustate->pcstk); + } + if (cpustate->opcode & U64(0x000400000000)) + { + POP_PC(cpustate); + } +} + +/*****************************************************************************/ +/* | 000000000 | */ + +static void sharcop_nop(SHARC_REGS *cpustate) +{ + +} + +/*****************************************************************************/ +/* | 000000001 | */ + +static void sharcop_idle(SHARC_REGS *cpustate) +{ + //CHANGE_PC(cpustate, cpustate->pc); + + cpustate->daddr = cpustate->pc; + cpustate->faddr = cpustate->pc+1; + cpustate->nfaddr = cpustate->pc+2; + + cpustate->decode_opcode = ROPCODE(cpustate->daddr); + cpustate->fetch_opcode = ROPCODE(cpustate->faddr); + + cpustate->idle = 1; +} + +/*****************************************************************************/ + +static void sharcop_unimplemented(SHARC_REGS *cpustate) +{ + char dasm[1000]; + CPU_DISASSEMBLE_NAME(sharc)(NULL, dasm, cpustate->pc, NULL, NULL, 0); + mame_printf_debug("SHARC: %08X: %s\n", cpustate->pc, dasm); + fatalerror("SHARC: Unimplemented opcode %04X%08X at %08X", (UINT16)(cpustate->opcode >> 32), (UINT32)(cpustate->opcode), cpustate->pc); +} |