diff --git a/src/emu/cpu/mips/mips3.c b/src/emu/cpu/mips/mips3.c index 2234a4f86a6..c3c97c4713d 100644 --- a/src/emu/cpu/mips/mips3.c +++ b/src/emu/cpu/mips/mips3.c @@ -2447,6 +2447,31 @@ inline void mips3_device::set_cop2_creg(int idx, UINT64 val) m_core->ccr[2][idx] = val; } +inline void mips3_device::handle_integer_divide_by_zero(UINT32 op) +{ + HIVAL64 = (INT32)RSVAL32; + if (m_flavor == MIPS3_TYPE_VR4300) + { + if (RSVAL32 >= 0) + { + LOVAL64 = -1; + } + else + { + LOVAL64 = 1; + } + } + else + { + if (RSVAL32 >= 0) + { + } + else + { + } + } +} + inline void mips3_device::handle_cop2(UINT32 op) { if (!(SR & SR_COP2)) @@ -2616,6 +2641,10 @@ void mips3_device::execute_run() LOVAL64 = (INT32)((INT32)RSVAL32 / (INT32)RTVAL32); HIVAL64 = (INT32)((INT32)RSVAL32 % (INT32)RTVAL32); } + else + { + handle_integer_divide_by_zero(op); + } m_core->icount -= 35; break; case 0x1b: /* DIVU */ @@ -2624,6 +2653,10 @@ void mips3_device::execute_run() LOVAL64 = (INT32)(RSVAL32 / RTVAL32); HIVAL64 = (INT32)(RSVAL32 % RTVAL32); } + else + { + handle_integer_divide_by_zero(op); + } m_core->icount -= 35; break; case 0x1c: /* DMULT */ diff --git a/src/emu/cpu/mips/mips3.h b/src/emu/cpu/mips/mips3.h index 5910669e6bc..5a95b87823e 100644 --- a/src/emu/cpu/mips/mips3.h +++ b/src/emu/cpu/mips/mips3.h @@ -511,6 +511,7 @@ private: UINT64 get_cop2_creg(int idx); void set_cop2_creg(int idx, UINT64 val); void handle_cop2(UINT32 op); + void handle_integer_divide_by_zero(UINT32 op); void lwl_be(UINT32 op); void lwr_be(UINT32 op); void ldl_be(UINT32 op); @@ -756,6 +757,7 @@ private: #define MIPS3DRC_STRICT_COP2 0x0008 /* validate all COP2 instructions */ #define MIPS3DRC_FLUSH_PC 0x0010 /* flush the PC value before each memory access */ #define MIPS3DRC_CHECK_OVERFLOWS 0x0020 /* actually check overflows on add/sub instructions */ +#define MIPS3DRC_ACCURATE_DIVZERO 0x0040 /* load correct values into HI/LO on integer divide-by-zero */ #define MIPS3DRC_COMPATIBLE_OPTIONS (MIPS3DRC_STRICT_VERIFY | MIPS3DRC_STRICT_COP1 | MIPS3DRC_STRICT_COP0 | MIPS3DRC_STRICT_COP2 | MIPS3DRC_FLUSH_PC) #define MIPS3DRC_FASTEST_OPTIONS (0) diff --git a/src/emu/cpu/mips/mips3drc.c b/src/emu/cpu/mips/mips3drc.c index effe2154468..1800913fed6 100644 --- a/src/emu/cpu/mips/mips3drc.c +++ b/src/emu/cpu/mips/mips3drc.c @@ -2054,15 +2054,79 @@ int mips3_device::generate_special(drcuml_block *block, compiler_state *compiler return TRUE; case 0x1a: /* DIV - MIPS I */ - UML_DIVS(block, I0, I1, R32(RSREG), R32(RTREG)); // divs i0,i1,, - UML_DSEXT(block, LO64, I0, SIZE_DWORD); // dsext lo,i0,dword - UML_DSEXT(block, HI64, I1, SIZE_DWORD); // dsext hi,i1,dword + { + if (m_drcoptions & MIPS3DRC_ACCURATE_DIVZERO) + { + code_label divzero, done; + + UML_CMP(block, R32(RTREG), 0); // cmp , 0 + UML_JMPc(block, COND_E, divzero = compiler->labelnum++); // jmp divzero,E + + UML_DIVS(block, I0, I1, R32(RSREG), R32(RTREG)); // divs i0,i1,, + UML_DSEXT(block, LO64, I0, SIZE_DWORD); // dsext lo,i0,dword + UML_DSEXT(block, HI64, I1, SIZE_DWORD); // dsext hi,i1,dword + UML_JMP(block, done = compiler->labelnum++); // jmp done + + UML_LABEL(block, divzero); // divzero: + if (m_flavor != MIPS3_TYPE_VR4300) + { + UML_MOVc(block, COND_L, I0, 0x00000001); // mov i0,0x00000001,L + UML_MOVc(block, COND_GE, I0, 0xffffffff); // mov i0,0xffffffff,GE + } + else + { + UML_MOVc(block, COND_L, I0, 0x80000001); // mov i0,0x80000001,L + UML_MOVc(block, COND_GE, I0, 0x7fffffff); // mov i0,0x7fffffff,GE + } + UML_DSEXT(block, HI64, R32(RSREG), SIZE_DWORD); // dsext hi,,dword + UML_DSEXT(block, LO64, I0, SIZE_DWORD); // dsext lo,i0,dword + + UML_LABEL(block, done); // done: + } + else + { + UML_DIVS(block, I0, I1, R32(RSREG), R32(RTREG)); // divs i0,i1,, + UML_DSEXT(block, LO64, I0, SIZE_DWORD); // dsext lo,i0,dword + UML_DSEXT(block, HI64, I1, SIZE_DWORD); // dsext hi,i1,dword + } return TRUE; + } case 0x1b: /* DIVU - MIPS I */ - UML_DIVU(block, I0, I1, R32(RSREG), R32(RTREG)); // divu i0,i1,, - UML_DSEXT(block, LO64, I0, SIZE_DWORD); // dsext lo,i0,dword - UML_DSEXT(block, HI64, I1, SIZE_DWORD); // dsext hi,i1,dword + if (m_drcoptions & MIPS3DRC_ACCURATE_DIVZERO) + { + code_label divzero, done; + + UML_CMP(block, R32(RTREG), 0); // cmp , 0 + UML_JMPc(block, COND_E, divzero = compiler->labelnum++); // jmp divzero,E + + UML_DIVU(block, I0, I1, R32(RSREG), R32(RTREG)); // divu i0,i1,, + UML_DSEXT(block, LO64, I0, SIZE_DWORD); // dsext lo,i0,dword + UML_DSEXT(block, HI64, I1, SIZE_DWORD); // dsext hi,i1,dword + UML_JMP(block, done = compiler->labelnum++); // jmp done + + UML_LABEL(block, divzero); // divzero: + if (m_flavor != MIPS3_TYPE_VR4300) + { + UML_MOVc(block, COND_L, I0, 0x00000001); // mov i0,0x00000001,L + UML_MOVc(block, COND_GE, I0, 0xffffffff); // mov i0,0xffffffff,GE + } + else + { + UML_MOVc(block, COND_L, I0, 0x80000001); // mov i0,0x80000001,L + UML_MOVc(block, COND_GE, I0, 0x7fffffff); // mov i0,0x7fffffff,GE + } + UML_DSEXT(block, HI64, R32(RSREG), SIZE_DWORD); // dsext hi,,dword + UML_DSEXT(block, LO64, I0, SIZE_DWORD); // dsext lo,i0,dword + + UML_LABEL(block, done); // done: + } + else + { + UML_DIVU(block, I0, I1, R32(RSREG), R32(RTREG)); // divu i0,i1,, + UML_DSEXT(block, LO64, I0, SIZE_DWORD); // dsext lo,i0,dword + UML_DSEXT(block, HI64, I1, SIZE_DWORD); // dsext hi,i1,dword + } return TRUE; case 0x1e: /* DDIV - MIPS III */