summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Patrick Mackinlay <pmackinlay@hotmail.com>2019-08-09 17:58:13 +0700
committer Patrick Mackinlay <pmackinlay@hotmail.com>2019-08-09 17:58:13 +0700
commit8205f140fe13928854ef3c3e7724af7e7123d4da (patch)
tree4dc651589b61bb592c22e7460b083aed65b3d72c
parente1b078da42f304ddf6ada0cc9134174c397874be (diff)
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.
-rw-r--r--src/devices/cpu/mips/mips1.cpp93
-rw-r--r--src/devices/cpu/mips/mips1.h1
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);