MIPS3: Add divide by zero floating point exception (nw)

This commit is contained in:
Ted Green 2019-04-06 13:10:14 -06:00
parent caa8d04ced
commit 43c7b9d8bb
4 changed files with 53 additions and 6 deletions

View File

@ -37,6 +37,7 @@
#define FTVALS_FR0 (((float *)&m_core->cpr[1][FTREG & 0x1E])[BYTE_XOR_LE(FTREG & 1)])
#define FSVALS_FR0 (((float *)&m_core->cpr[1][FSREG & 0x1E])[BYTE_XOR_LE(FSREG & 1)])
#define FDVALS_FR0 (((float *)&m_core->cpr[1][FDREG & 0x1E])[BYTE_XOR_LE(FDREG & 1)])
#define FTVALW_FR0 (((uint32_t *)&m_core->cpr[1][FTREG & 0x1E])[BYTE_XOR_LE(FTREG & 1)])
#define FSVALW_FR0 (((uint32_t *)&m_core->cpr[1][FSREG & 0x1E])[BYTE_XOR_LE(FSREG & 1)])
#define FDVALW_FR0 (((uint32_t *)&m_core->cpr[1][FDREG & 0x1E])[BYTE_XOR_LE(FDREG & 1)])
@ -44,6 +45,7 @@
#define FTVALD_FR0 (*(double *)&m_core->cpr[1][FTREG & 0x1E])
#define FSVALD_FR0 (*(double *)&m_core->cpr[1][FSREG & 0x1E])
#define FDVALD_FR0 (*(double *)&m_core->cpr[1][FDREG & 0x1E])
#define FTVALL_FR0 (*(uint64_t *)&m_core->cpr[1][FTREG & 0x1E])
#define FSVALL_FR0 (*(uint64_t *)&m_core->cpr[1][FSREG & 0x1E])
#define FDVALL_FR0 (*(uint64_t *)&m_core->cpr[1][FDREG & 0x1E])
@ -1977,10 +1979,28 @@ void mips3_device::handle_cop1_fr0(uint32_t op)
break;
case 0x03:
if (IS_SINGLE(op)) /* DIV.S */
FDVALS_FR0 = FSVALS_FR0 / FTVALS_FR0;
else /* DIV.D */
FDVALD_FR0 = FSVALD_FR0 / FTVALD_FR0;
if (IS_SINGLE(op)) { /* DIV.S */
if (FTVALW_FR0 == 0 && (COP1_FCR31 & (1 << (FCR31_ENABLE + FPE_DIV0)))) {
COP1_FCR31 |= (1 << (FCR31_FLAGS + FPE_DIV0)); // Set flag
COP1_FCR31 |= (1 << (FCR31_CAUSE + FPE_DIV0)); // Set cause
generate_exception(EXCEPTION_FPE, 1);
//machine().debug_break();
}
else {
FDVALS_FR0 = FSVALS_FR0 / FTVALS_FR0;
}
}
else { /* DIV.D */
if (FTVALL_FR0 == 0ull && (COP1_FCR31 & (1 << (FCR31_ENABLE + FPE_DIV0)))) {
COP1_FCR31 |= (1 << (FCR31_FLAGS + FPE_DIV0)); // Set flag
COP1_FCR31 |= (1 << (FCR31_CAUSE + FPE_DIV0)); // Set cause
generate_exception(EXCEPTION_FPE, 1);
//machine().debug_break();
}
else {
FDVALD_FR0 = FSVALD_FR0 / FTVALD_FR0;
}
}
break;
case 0x04:

View File

@ -238,6 +238,9 @@ enum {
#define MIPS3_MAX_FASTRAM 3
#define MIPS3_MAX_HOTSPOTS 16
/* COP1 CCR register */
#define COP1_FCR31 (m_core->ccr[1][31])
/***************************************************************************
INTERRUPT CONSTANTS
***************************************************************************/

View File

@ -155,10 +155,15 @@
#define EXCEPTION_BADCOP 11
#define EXCEPTION_OVERFLOW 12
#define EXCEPTION_TRAP 13
#define EXCEPTION_FPE 15
#define EXCEPTION_TLBLOAD_FILL 16
#define EXCEPTION_TLBSTORE_FILL 17
#define EXCEPTION_COUNT 18
#define FCR31_FLAGS 2 // FLAGS start bit
#define FCR31_ENABLE 7 // Enable start bit
#define FCR31_CAUSE 12 // Cause start bit
#define FPE_DIV0 3 // Divide by zero bit index
/***************************************************************************

View File

@ -247,6 +247,7 @@ void mips3_device::code_flush_cache()
static_generate_exception(EXCEPTION_BADCOP, true, "exception_badcop");
static_generate_exception(EXCEPTION_OVERFLOW, true, "exception_overflow");
static_generate_exception(EXCEPTION_TRAP, true, "exception_trap");
static_generate_exception(EXCEPTION_FPE, true, "exception_fpe");
/* add subroutines for memory accesses */
for (mode = 0; mode < 3; mode++)
@ -728,6 +729,14 @@ void mips3_device::static_generate_exception(uint8_t exception, int recover, con
UML_ROLINS(block, CPR032(COP0_Context), I0, 32-9, 0x7ffff0); // rolins [Context],i0,32-9,0x7ffff0
}
if (exception == EXCEPTION_FPE)
{
/* set the flag and cause */
UML_GETEXP(block, I0); // getexp i0
UML_ROLINS(block, CCR132(31), I0, FCR31_FLAGS, 0x0000007c); // rolins [CCR31],i0,FCR31_FLAGS,0x0000007c
UML_ROLINS(block, CCR132(31), I0, FCR31_CAUSE, 0x0003f000); // rolins [CCR31],i0,FCR31_CAUSE,0x0003f000
}
/* set the EPC and Cause registers */
if (recover)
{
@ -2778,11 +2787,21 @@ bool mips3_device::generate_cop1(drcuml_block &block, compiler_state &compiler,
case 0x03:
if (IS_SINGLE(op)) /* DIV.S - MIPS I */
{
UML_FSDIV(block, FPR32(FDREG), FPR32(FSREG), FPR32(FTREG)); // fsdiv <fdreg>,<fsreg>,<ftreg>
UML_TEST(block, FPR32(FTREG), 0xffffffff); // test <ftreg>,-1
UML_JMPc(block, COND_NZ, skip = compiler.labelnum++); // jmp skip,NZ
UML_TEST(block, CCR132(31), 1 << (FCR31_ENABLE + FPE_DIV0)); // test [FCR31], 1 << DIV0_EN
UML_EXHc(block, COND_NZ, *m_exception[EXCEPTION_FPE], 1 << FPE_DIV0); // exh FPE,cop,FPE_DIV0
UML_LABEL(block, skip); // skip:
UML_FSDIV(block, FPR32(FDREG), FPR32(FSREG), FPR32(FTREG)); // fsdiv <fdreg>,<fsreg>,<ftreg>
}
else /* DIV.D - MIPS I */
{
UML_FDDIV(block, FPR64(FDREG), FPR64(FSREG), FPR64(FTREG)); // fddiv <fdreg>,<fsreg>,<ftreg>
UML_DTEST(block, FPR64(FTREG), 0xffffffff'ffffffffull); // dtest <ftreg>,-1
UML_JMPc(block, COND_NZ, skip = compiler.labelnum++); // jmp skip,NZ
UML_TEST(block, CCR132(31), 1 << (FCR31_ENABLE + FPE_DIV0)); // test [FCR31], 1 << DIV0_EN
UML_EXHc(block, COND_NZ, *m_exception[EXCEPTION_FPE], 1 << FPE_DIV0); // exh FPE,cop,FPE_DIV0
UML_LABEL(block, skip); // skip:
UML_FDDIV(block, FPR64(FDREG), FPR64(FSREG), FPR64(FTREG)); // fddiv <fdreg>,<fsreg>,<ftreg>
}
return true;