- mips3: Add integer divide-by-zero handling to MIPS III cores. [MooglyGuy]

This commit is contained in:
mooglyguy 2015-03-25 14:28:02 +01:00
parent 4fc1911e96
commit 3cf16b2eb1
3 changed files with 105 additions and 6 deletions

View File

@ -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 */

View File

@ -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)

View File

@ -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,<rsreg>,<rtreg>
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 <rtreg>, 0
UML_JMPc(block, COND_E, divzero = compiler->labelnum++); // jmp divzero,E
UML_DIVS(block, I0, I1, R32(RSREG), R32(RTREG)); // divs i0,i1,<rsreg>,<rtreg>
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,<rsreg>,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,<rsreg>,<rtreg>
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,<rsreg>,<rtreg>
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 <rtreg>, 0
UML_JMPc(block, COND_E, divzero = compiler->labelnum++); // jmp divzero,E
UML_DIVU(block, I0, I1, R32(RSREG), R32(RTREG)); // divu i0,i1,<rsreg>,<rtreg>
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,<rsreg>,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,<rsreg>,<rtreg>
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 */