From 43c7b9d8bbf388217e658762c0a614607a31ee28 Mon Sep 17 00:00:00 2001 From: Ted Green Date: Sat, 6 Apr 2019 13:10:14 -0600 Subject: MIPS3: Add divide by zero floating point exception (nw) --- src/devices/cpu/mips/mips3.cpp | 28 ++++++++++++++++++++++++---- src/devices/cpu/mips/mips3.h | 3 +++ src/devices/cpu/mips/mips3com.h | 5 +++++ src/devices/cpu/mips/mips3drc.cpp | 23 +++++++++++++++++++++-- 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 ,, + UML_TEST(block, FPR32(FTREG), 0xffffffff); // test ,-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 ,, } else /* DIV.D - MIPS I */ { - UML_FDDIV(block, FPR64(FDREG), FPR64(FSREG), FPR64(FTREG)); // fddiv ,, + UML_DTEST(block, FPR64(FTREG), 0xffffffff'ffffffffull); // dtest ,-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 ,, } return true; -- cgit v1.2.3