summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Ted Green <tedgreen99@users.noreply.github.com>2019-04-06 13:10:14 -0600
committer Ted Green <tedgreen99@users.noreply.github.com>2019-04-06 13:50:26 -0600
commit43c7b9d8bbf388217e658762c0a614607a31ee28 (patch)
tree346228f1caff9f0023f2995f6eec1b1fd5673923
parentcaa8d04cedddb816a2d0093ecfd544dc589640ed (diff)
MIPS3: Add divide by zero floating point exception (nw)
-rw-r--r--src/devices/cpu/mips/mips3.cpp28
-rw-r--r--src/devices/cpu/mips/mips3.h3
-rw-r--r--src/devices/cpu/mips/mips3com.h5
-rw-r--r--src/devices/cpu/mips/mips3drc.cpp23
4 files changed, 53 insertions, 6 deletions
diff --git a/src/devices/cpu/mips/mips3.cpp b/src/devices/cpu/mips/mips3.cpp
index 178d81fadbd..9b94601a70b 100644
--- a/src/devices/cpu/mips/mips3.cpp
+++ b/src/devices/cpu/mips/mips3.cpp
@@ -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:
diff --git a/src/devices/cpu/mips/mips3.h b/src/devices/cpu/mips/mips3.h
index 0afa4ef610b..64146e3451b 100644
--- a/src/devices/cpu/mips/mips3.h
+++ b/src/devices/cpu/mips/mips3.h
@@ -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
***************************************************************************/
diff --git a/src/devices/cpu/mips/mips3com.h b/src/devices/cpu/mips/mips3com.h
index 76b674a6a61..c9f1bdbf973 100644
--- a/src/devices/cpu/mips/mips3com.h
+++ b/src/devices/cpu/mips/mips3com.h
@@ -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
/***************************************************************************
diff --git a/src/devices/cpu/mips/mips3drc.cpp b/src/devices/cpu/mips/mips3drc.cpp
index 02439727608..fa5ba1839d4 100644
--- a/src/devices/cpu/mips/mips3drc.cpp
+++ b/src/devices/cpu/mips/mips3drc.cpp
@@ -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;