From 8205f140fe13928854ef3c3e7724af7e7123d4da Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Fri, 9 Aug 2019 17:58:13 +0700 Subject: mips1: rework interrupts (nw) This fixes a bug causing IRIX to crash on 4D/20. Specifically, IRIX doesn't handle the case where the pc is pointing to an unmapped address when an interrupt occurs; presumably on real hardware this doesn't happen because the instruction fetch happens before interrupts are tested (or the pc isn't updated until after), and the fetch exception is prioritised over the incoming interrupt. --- src/devices/cpu/mips/mips1.cpp | 93 +++++++++++++++++++----------------------- src/devices/cpu/mips/mips1.h | 1 - 2 files changed, 41 insertions(+), 53 deletions(-) diff --git a/src/devices/cpu/mips/mips1.cpp b/src/devices/cpu/mips/mips1.cpp index ec8aa88a59b..2288293c804 100644 --- a/src/devices/cpu/mips/mips1.cpp +++ b/src/devices/cpu/mips/mips1.cpp @@ -212,9 +212,6 @@ void mips1core_device_base::device_reset() void mips1core_device_base::execute_run() { - // check for interrupts - check_irqs(); - // core execution loop while (m_icount-- > 0) { @@ -239,10 +236,17 @@ void mips1core_device_base::execute_run() } } - // fetch and execute instruction + // fetch instruction fetch(m_pc, [this](u32 const op) { - // parse the instruction + // check for interrupts + if ((CAUSE & SR & SR_IM) && (SR & SR_IEc)) + { + generate_exception(EXCEPTION_INTERRUPT); + return; + } + + // decode and execute instruction switch (op >> 26) { case 0x00: // SPECIAL @@ -559,31 +563,31 @@ void mips1core_device_base::execute_run() break; } - // update pc and branch state - switch (m_branch_state) - { - case NONE: - m_pc += 4; - break; + // clear register 0 + m_r[0] = 0; + }); - case DELAY: - m_branch_state = NONE; - m_pc = m_branch_target; - break; + // update pc and branch state + switch (m_branch_state) + { + case NONE: + m_pc += 4; + break; - case BRANCH: - m_branch_state = DELAY; - m_pc += 4; - break; + case DELAY: + m_branch_state = NONE; + m_pc = m_branch_target; + break; - case EXCEPTION: - m_branch_state = NONE; - break; - } + case BRANCH: + m_branch_state = DELAY; + m_pc += 4; + break; - // clear register 0 - m_r[0] = 0; - }); + case EXCEPTION: + m_branch_state = NONE; + break; + } } } @@ -599,8 +603,6 @@ void mips1core_device_base::execute_set_input(int irqline, int state) } else CAUSE &= ~(CAUSE_IPEX0 << irqline); - - check_irqs(); } device_memory_interface::space_config_vector mips1core_device_base::memory_space_config() const @@ -846,12 +848,6 @@ void mips1core_device_base::generate_exception(u32 exception, bool refill) debugger_privilege_hook(); } -void mips1core_device_base::check_irqs() -{ - if ((CAUSE & SR & SR_IM) && (SR & SR_IEc)) - generate_exception(EXCEPTION_INTERRUPT); -} - void mips1core_device_base::handle_cop0(u32 const op) { switch (RSREG) @@ -888,7 +884,7 @@ void mips1core_device_base::handle_cop0(u32 const op) switch (op & 31) { case 0x10: // RFE - SR = (SR & ~SR_KUIEpc) | ((SR >> 2) & SR_KUIEpc); + SR = (SR & ~SR_KUIE) | ((SR >> 2) & SR_KUIEpc); if (bool(SR & SR_KUc) ^ bool(SR & SR_KUp)) debugger_privilege_hook(); break; @@ -921,10 +917,6 @@ void mips1core_device_base::set_cop0_reg(unsigned const reg, u32 const data) // handle cache isolation and swap m_data_spacenum = (data & SR_IsC) ? ((data & SR_SwC) ? 1 : 2) : 0; - // update interrupts - if (delta & (SR_IEc | SR_IM)) - check_irqs(); - if ((delta & SR_KUc) && (m_branch_state != EXCEPTION)) debugger_privilege_hook(); } @@ -932,9 +924,6 @@ void mips1core_device_base::set_cop0_reg(unsigned const reg, u32 const data) case COP0_Cause: CAUSE = (CAUSE & CAUSE_IPEX) | (data & ~CAUSE_IPEX); - - // update interrupts -- software ints can occur this way - check_irqs(); break; case COP0_PRId: @@ -1241,8 +1230,8 @@ void mips1_device_base::handle_cop0(u32 const op) m_tlb[index][0] = m_cop0[COP0_EntryHi]; m_tlb[index][1] = m_cop0[COP0_EntryLo]; - LOGMASKED(LOG_TLB, "tlb write index %d asid %d vpn 0x%08x pfn 0x%08x %c%c%c%c (%s)\n", - index, (m_cop0[COP0_EntryHi] & EH_ASID) >> 6, m_cop0[COP0_EntryHi] & EH_VPN, m_cop0[COP0_EntryLo] & EL_PFN, + LOGMASKED(LOG_TLB, "asid %2d tlb write index %2d vpn 0x%08x pfn 0x%08x %c%c%c%c (%s)\n", + (m_cop0[COP0_EntryHi] & EH_ASID) >> 6, index, m_cop0[COP0_EntryHi] & EH_VPN, m_cop0[COP0_EntryLo] & EL_PFN, m_cop0[COP0_EntryLo] & EL_N ? 'N' : '-', m_cop0[COP0_EntryLo] & EL_D ? 'D' : '-', m_cop0[COP0_EntryLo] & EL_V ? 'V' : '-', @@ -1258,8 +1247,8 @@ void mips1_device_base::handle_cop0(u32 const op) m_tlb[random][0] = m_cop0[COP0_EntryHi]; m_tlb[random][1] = m_cop0[COP0_EntryLo]; - LOGMASKED(LOG_TLB, "tlb write random %d asid %d vpn 0x%08x pfn 0x%08x %c%c%c%c (%s)\n", - random, (m_cop0[COP0_EntryHi] & EH_ASID) >> 6, m_cop0[COP0_EntryHi] & EH_VPN, m_cop0[COP0_EntryLo] & EL_PFN, + LOGMASKED(LOG_TLB, "asid %2d tlb write random %2d vpn 0x%08x pfn 0x%08x %c%c%c%c (%s)\n", + (m_cop0[COP0_EntryHi] & EH_ASID) >> 6, random, m_cop0[COP0_EntryHi] & EH_VPN, m_cop0[COP0_EntryLo] & EL_PFN, m_cop0[COP0_EntryLo] & EL_N ? 'N' : '-', m_cop0[COP0_EntryLo] & EL_D ? 'D' : '-', m_cop0[COP0_EntryLo] & EL_V ? 'V' : '-', @@ -1276,15 +1265,15 @@ void mips1_device_base::handle_cop0(u32 const op) u32 const mask = (m_tlb[index][1] & EL_G) ? EH_VPN : EH_VPN | EH_ASID; if ((m_tlb[index][0] & mask) == (m_cop0[COP0_EntryHi] & mask)) { - LOGMASKED(LOG_TLB, "tlb probe hit vpn 0x%08x index %d (%s)\n", - m_cop0[COP0_EntryHi] & mask, index, machine().describe_context()); + LOGMASKED(LOG_TLB, "asid %2d tlb probe index %2d vpn 0x%08x (%s)\n", + (m_cop0[COP0_EntryHi] & EH_ASID) >> 6, index, m_cop0[COP0_EntryHi] & mask, machine().describe_context()); m_cop0[COP0_Index] = index << 8; break; } } if ((VERBOSE & LOG_TLB) && BIT(m_cop0[COP0_Index], 31)) - LOGMASKED(LOG_TLB, "tlb probe miss asid %d vpn 0x%08x(%s)\n", + LOGMASKED(LOG_TLB, "asid %2d tlb probe miss vpn 0x%08x(%s)\n", (m_cop0[COP0_EntryHi] & EH_ASID) >> 6, m_cop0[COP0_EntryHi] & EH_VPN, machine().describe_context()); break; @@ -1971,11 +1960,11 @@ bool mips1_device_base::memory_translate(int spacenum, int intention, offs_t &ad if (VERBOSE & LOG_TLB) { if (modify) - LOGMASKED(LOG_TLB, "tlb modify asid %d address 0x%08x (%s)\n", + LOGMASKED(LOG_TLB, "asid %2d tlb modify address 0x%08x (%s)\n", (m_cop0[COP0_EntryHi] & EH_ASID) >> 6, address, machine().describe_context()); else - LOGMASKED(LOG_TLB, "tlb miss %c asid %d address 0x%08x (%s)\n", - (intention & TRANSLATE_WRITE) ? 'w' : 'r', (m_cop0[COP0_EntryHi] & EH_ASID) >> 6, address, machine().describe_context()); + LOGMASKED(LOG_TLB, "asid %2d tlb miss %c address 0x%08x (%s)\n", + (m_cop0[COP0_EntryHi] & EH_ASID) >> 6, (intention & TRANSLATE_WRITE) ? 'w' : 'r', address, machine().describe_context()); } // load tlb exception registers diff --git a/src/devices/cpu/mips/mips1.h b/src/devices/cpu/mips/mips1.h index a7cde9cdfd7..306944d358f 100644 --- a/src/devices/cpu/mips/mips1.h +++ b/src/devices/cpu/mips/mips1.h @@ -174,7 +174,6 @@ protected: // interrupts void generate_exception(u32 exception, bool refill = false); - void check_irqs(); // cop0 virtual void handle_cop0(u32 const op); -- cgit v1.2.3