mips3: exception handling fixes (nw)

* nested exceptions shouldn't overwrite the EPC
* nested tlb exceptions go to the general exception vector
* remove breakpoint for tlb exceptions and branch to proper vector
This commit is contained in:
Patrick Mackinlay 2018-10-03 19:03:04 +07:00
parent 4148447f3a
commit f0f23e29a1

View File

@ -288,7 +288,9 @@ void mips3_device::generate_exception(int exception, int backup)
/* translate our fake fill exceptions into real exceptions */ /* translate our fake fill exceptions into real exceptions */
if (exception == EXCEPTION_TLBLOAD_FILL || exception == EXCEPTION_TLBSTORE_FILL) if (exception == EXCEPTION_TLBLOAD_FILL || exception == EXCEPTION_TLBSTORE_FILL)
{ {
offset = 0; /* don't use the tlb exception offset if within another exception */
if (!(SR & SR_EXL))
offset = 0;
exception = (exception - EXCEPTION_TLBLOAD_FILL) + EXCEPTION_TLBLOAD; exception = (exception - EXCEPTION_TLBLOAD_FILL) + EXCEPTION_TLBLOAD;
} }
else if (exception == EXCEPTION_INTERRUPT && m_flavor == MIPS3_TYPE_R5900) else if (exception == EXCEPTION_INTERRUPT && m_flavor == MIPS3_TYPE_R5900)
@ -296,9 +298,6 @@ void mips3_device::generate_exception(int exception, int backup)
offset = 0x200; offset = 0x200;
} }
/* set the exception PC */
m_core->cpr[0][COP0_EPC] = m_core->pc;
/* put the cause in the low 8 bits and clear the branch delay flag */ /* put the cause in the low 8 bits and clear the branch delay flag */
CAUSE = (CAUSE & ~0x800000ff) | (exception << 2); CAUSE = (CAUSE & ~0x800000ff) | (exception << 2);
@ -308,31 +307,26 @@ void mips3_device::generate_exception(int exception, int backup)
CAUSE |= m_badcop_value << 28; CAUSE |= m_badcop_value << 28;
} }
/* if we were in a branch delay slot, adjust */ /* check if exception within another exception */
if ((m_nextpc != ~0) || (m_delayslot)) if (!(SR & SR_EXL))
{ {
m_delayslot = false; /* if we were in a branch delay slot, adjust */
m_nextpc = ~0; if ((m_nextpc != ~0) || (m_delayslot))
m_core->cpr[0][COP0_EPC] -= 4; {
CAUSE |= 0x80000000; m_delayslot = false;
} m_nextpc = ~0;
m_core->cpr[0][COP0_EPC] = m_core->pc - 4;
CAUSE |= 0x80000000;
}
else
m_core->cpr[0][COP0_EPC] = m_core->pc;
/* set the exception level */ /* set the exception level */
SR |= SR_EXL; SR |= SR_EXL;
}
/* based on the BEV bit, we either go to ROM or RAM */ /* based on the BEV bit, we either go to ROM or RAM */
m_core->pc = (SR & SR_BEV) ? 0xbfc00200 : 0x80000000; m_core->pc = ((SR & SR_BEV) ? 0xbfc00200 : 0x80000000) + offset;
/* most exceptions go to offset 0x180, except for TLB stuff */
if (exception >= EXCEPTION_TLBMOD && exception <= EXCEPTION_TLBSTORE)
{
fprintf(stderr, "TLB miss @ %08X\n", (uint32_t)m_core->cpr[0][COP0_BadVAddr]);
machine().debug_break();
}
else
{
m_core->pc += offset;
}
/* /*
useful for tracking interrupts useful for tracking interrupts