isa: Modify get/check interrupt routines

Make it so that getInterrupt *always* returns an interrupt if
checkInterrupts() returns true.  This fixes/simplifies handling
of interrupts on the SMT FS CPUs (currently minor).
This commit is contained in:
Mitch Hayenga 2016-07-21 17:19:15 +01:00
parent d25b58036a
commit 8a476d387c
6 changed files with 130 additions and 45 deletions

View file

@ -137,18 +137,18 @@ class Interrupts : public SimObject
bool bool
checkInterrupts(ThreadContext *tc) const checkInterrupts(ThreadContext *tc) const
{ {
return (intstatus != 0) && !(tc->pcState().pc() & 0x3); if (intstatus == 0)
} return false;
Fault if (tc->pcState().pc() & 0x3)
getInterrupt(ThreadContext *tc) return false;
{
uint64_t ipl = 0;
uint64_t summary = 0;
if (tc->readMiscRegNoEffect(IPR_ASTRR)) if (tc->readMiscRegNoEffect(IPR_ASTRR))
panic("asynchronous traps not implemented\n"); panic("asynchronous traps not implemented\n");
uint64_t ipl = 0;
uint64_t summary = 0;
if (tc->readMiscRegNoEffect(IPR_SIRR)) { if (tc->readMiscRegNoEffect(IPR_SIRR)) {
for (uint64_t i = INTLEVEL_SOFTWARE_MIN; for (uint64_t i = INTLEVEL_SOFTWARE_MIN;
i < INTLEVEL_SOFTWARE_MAX; i++) { i < INTLEVEL_SOFTWARE_MAX; i++) {
@ -160,18 +160,45 @@ class Interrupts : public SimObject
} }
} }
if (intstatus) { for (uint64_t i = INTLEVEL_EXTERNAL_MIN; i < INTLEVEL_EXTERNAL_MAX;
for (uint64_t i = INTLEVEL_EXTERNAL_MIN; i++) {
i < INTLEVEL_EXTERNAL_MAX; i++) {
if (intstatus & (ULL(1) << i)) { if (intstatus & (ULL(1) << i)) {
// See table 4-19 of 21164 hardware reference // See table 4-19 of 21164 hardware reference
ipl = i; ipl = i;
summary |= (ULL(1) << i); summary |= (ULL(1) << i);
} }
} }
return ipl && ipl > tc->readMiscRegNoEffect(IPR_IPLR);
}
Fault
getInterrupt(ThreadContext *tc)
{
assert(checkInterrupts(tc));
uint64_t ipl = 0;
uint64_t summary = 0;
if (tc->readMiscRegNoEffect(IPR_SIRR)) {
for (uint64_t i = INTLEVEL_SOFTWARE_MIN;
i < INTLEVEL_SOFTWARE_MAX; i++) {
if (tc->readMiscRegNoEffect(IPR_SIRR) & (ULL(1) << i)) {
// See table 4-19 of 21164 hardware reference
ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1;
summary |= (ULL(1) << i);
}
}
}
for (uint64_t i = INTLEVEL_EXTERNAL_MIN; i < INTLEVEL_EXTERNAL_MAX;
i++) {
if (intstatus & (ULL(1) << i)) {
// See table 4-19 of 21164 hardware reference
ipl = i;
summary |= (ULL(1) << i);
}
} }
if (ipl && ipl > tc->readMiscRegNoEffect(IPR_IPLR)) {
newIpl = ipl; newIpl = ipl;
newSummary = summary; newSummary = summary;
newInfoSet = true; newInfoSet = true;
@ -179,9 +206,6 @@ class Interrupts : public SimObject
tc->readMiscRegNoEffect(IPR_IPLR), ipl, summary); tc->readMiscRegNoEffect(IPR_IPLR), ipl, summary);
return std::make_shared<InterruptFault>(); return std::make_shared<InterruptFault>();
} else {
return NoFault;
}
} }
void void

View file

@ -149,6 +149,10 @@ class Interrupts : public SimObject
bool allowVFiq = !cpsr.f && hcr.fmo && !isSecure && !isHypMode; bool allowVFiq = !cpsr.f && hcr.fmo && !isSecure && !isHypMode;
bool allowVAbort = !cpsr.a && hcr.amo && !isSecure && !isHypMode; bool allowVAbort = !cpsr.a && hcr.amo && !isSecure && !isHypMode;
if ( !(intStatus || (hcr.vi && allowVIrq) || (hcr.vf && allowVFiq) ||
(hcr.va && allowVAbort)) )
return false;
bool take_irq = takeInt(tc, INT_IRQ); bool take_irq = takeInt(tc, INT_IRQ);
bool take_fiq = takeInt(tc, INT_FIQ); bool take_fiq = takeInt(tc, INT_FIQ);
bool take_ea = takeInt(tc, INT_ABT); bool take_ea = takeInt(tc, INT_ABT);
@ -221,6 +225,8 @@ class Interrupts : public SimObject
Fault Fault
getInterrupt(ThreadContext *tc) getInterrupt(ThreadContext *tc)
{ {
assert(checkInterrupts(tc));
HCR hcr = tc->readMiscReg(MISCREG_HCR); HCR hcr = tc->readMiscReg(MISCREG_HCR);
CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
SCR scr = tc->readMiscReg(MISCREG_SCR); SCR scr = tc->readMiscReg(MISCREG_SCR);
@ -234,15 +240,10 @@ class Interrupts : public SimObject
bool allowVFiq = !cpsr.f && hcr.fmo && !isSecure && !isHypMode; bool allowVFiq = !cpsr.f && hcr.fmo && !isSecure && !isHypMode;
bool allowVAbort = !cpsr.a && hcr.amo && !isSecure && !isHypMode; bool allowVAbort = !cpsr.a && hcr.amo && !isSecure && !isHypMode;
if ( !(intStatus || (hcr.vi && allowVIrq) || (hcr.vf && allowVFiq) ||
(hcr.va && allowVAbort)) )
return NoFault;
bool take_irq = takeInt(tc, INT_IRQ); bool take_irq = takeInt(tc, INT_IRQ);
bool take_fiq = takeInt(tc, INT_FIQ); bool take_fiq = takeInt(tc, INT_FIQ);
bool take_ea = takeInt(tc, INT_ABT); bool take_ea = takeInt(tc, INT_ABT);
if (interrupts[INT_IRQ] && take_irq) if (interrupts[INT_IRQ] && take_irq)
return std::make_shared<Interrupt>(); return std::make_shared<Interrupt>();
if ((interrupts[INT_VIRT_IRQ] || hcr.vi) && allowVIrq) if ((interrupts[INT_VIRT_IRQ] || hcr.vi) && allowVIrq)

View file

@ -105,11 +105,11 @@ Interrupts::clearAll()
} }
bool
Fault Interrupts::checkInterrupts(ThreadContext *tc) const
Interrupts::getInterrupt(ThreadContext * tc)
{ {
DPRINTF(Interrupt, "Interrupts getInterrupt\n"); if (!interruptsPending(tc))
return false;
//Check if there are any outstanding interrupts //Check if there are any outstanding interrupts
StatusReg status = tc->readMiscRegNoEffect(MISCREG_STATUS); StatusReg status = tc->readMiscRegNoEffect(MISCREG_STATUS);
@ -120,14 +120,25 @@ Interrupts::getInterrupt(ThreadContext * tc)
// So if any interrupt that isn't masked is detected, jump to interrupt // So if any interrupt that isn't masked is detected, jump to interrupt
// handler // handler
CauseReg cause = tc->readMiscRegNoEffect(MISCREG_CAUSE); CauseReg cause = tc->readMiscRegNoEffect(MISCREG_CAUSE);
if (status.im && cause.ip) { if (status.im && cause.ip)
DPRINTF(Interrupt, "Interrupt! IM[7:0]=%d IP[7:0]=%d \n", return true;
(unsigned)status.im, (unsigned)cause.ip);
return std::make_shared<InterruptFault>();
}
} }
return NoFault; return false;
}
Fault
Interrupts::getInterrupt(ThreadContext * tc)
{
assert(checkInterrupts(tc));
StatusReg M5_VAR_USED status = tc->readMiscRegNoEffect(MISCREG_STATUS);
CauseReg M5_VAR_USED cause = tc->readMiscRegNoEffect(MISCREG_CAUSE);
DPRINTF(Interrupt, "Interrupt! IM[7:0]=%d IP[7:0]=%d \n",
(unsigned)status.im, (unsigned)cause.ip);
return std::make_shared<InterruptFault>();
} }
bool bool

View file

@ -107,13 +107,7 @@ class Interrupts : public SimObject
void updateIntrInfo(ThreadContext *tc) const; void updateIntrInfo(ThreadContext *tc) const;
bool interruptsPending(ThreadContext *tc) const; bool interruptsPending(ThreadContext *tc) const;
bool onCpuTimerInterrupt(ThreadContext *tc) const; bool onCpuTimerInterrupt(ThreadContext *tc) const;
bool checkInterrupts(ThreadContext *tc) const;
bool
checkInterrupts(ThreadContext *tc) const
{
return interruptsPending(tc);
}
void void
serialize(CheckpointOut &cp) const override serialize(CheckpointOut &cp) const override

View file

@ -89,6 +89,7 @@ class Interrupts : public SimObject
Fault Fault
getInterrupt(ThreadContext *tc) getInterrupt(ThreadContext *tc)
{ {
assert(checkInterrupts(tc));
panic("Interrupts::getInterrupt not implemented.\n"); panic("Interrupts::getInterrupt not implemented.\n");
} }

View file

@ -121,12 +121,66 @@ class Interrupts : public SimObject
bool bool
checkInterrupts(ThreadContext *tc) const checkInterrupts(ThreadContext *tc) const
{ {
return intStatus; if (!intStatus)
return false;
HPSTATE hpstate = tc->readMiscRegNoEffect(MISCREG_HPSTATE);
PSTATE pstate = tc->readMiscRegNoEffect(MISCREG_PSTATE);
// THESE ARE IN ORDER OF PRIORITY
// since there are early returns, and the highest
// priority interrupts should get serviced,
// it is v. important that new interrupts are inserted
// in the right order of processing
if (hpstate.hpriv) {
if (pstate.ie) {
if (interrupts[IT_HINTP]) {
// This will be cleaned by a HINTP write
return true;
}
if (interrupts[IT_INT_VEC]) {
// this will be cleared by an ASI read (or write)
return true;
}
}
} else {
if (interrupts[IT_TRAP_LEVEL_ZERO]) {
// this is cleared by deasserting HPSTATE::tlz
return true;
}
// HStick matches always happen in priv mode (ie doesn't matter)
if (interrupts[IT_HINTP]) {
return true;
}
if (interrupts[IT_INT_VEC]) {
// this will be cleared by an ASI read (or write)
return true;
}
if (pstate.ie) {
if (interrupts[IT_CPU_MONDO]) {
return true;
}
if (interrupts[IT_DEV_MONDO]) {
return true;
}
if (interrupts[IT_SOFT_INT]) {
return true;
}
if (interrupts[IT_RES_ERROR]) {
return true;
}
} // !hpriv && pstate.ie
} // !hpriv
return false;
} }
Fault Fault
getInterrupt(ThreadContext *tc) getInterrupt(ThreadContext *tc)
{ {
assert(checkInterrupts(tc));
HPSTATE hpstate = tc->readMiscRegNoEffect(MISCREG_HPSTATE); HPSTATE hpstate = tc->readMiscRegNoEffect(MISCREG_HPSTATE);
PSTATE pstate = tc->readMiscRegNoEffect(MISCREG_PSTATE); PSTATE pstate = tc->readMiscRegNoEffect(MISCREG_PSTATE);