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:
parent
d25b58036a
commit
8a476d387c
6 changed files with 130 additions and 45 deletions
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue