From 8a476d387c84f037d0ccf3cc20dc88870ab45fec Mon Sep 17 00:00:00 2001 From: Mitch Hayenga Date: Thu, 21 Jul 2016 17:19:15 +0100 Subject: [PATCH] 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). --- src/arch/alpha/interrupts.hh | 68 ++++++++++++++++++++++++------------ src/arch/arm/interrupts.hh | 11 +++--- src/arch/mips/interrupts.cc | 31 ++++++++++------ src/arch/mips/interrupts.hh | 8 +---- src/arch/power/interrupts.hh | 1 + src/arch/sparc/interrupts.hh | 56 ++++++++++++++++++++++++++++- 6 files changed, 130 insertions(+), 45 deletions(-) diff --git a/src/arch/alpha/interrupts.hh b/src/arch/alpha/interrupts.hh index 1e67f54b5..61ac6c968 100644 --- a/src/arch/alpha/interrupts.hh +++ b/src/arch/alpha/interrupts.hh @@ -137,18 +137,18 @@ class Interrupts : public SimObject bool checkInterrupts(ThreadContext *tc) const { - return (intstatus != 0) && !(tc->pcState().pc() & 0x3); - } + if (intstatus == 0) + return false; - Fault - getInterrupt(ThreadContext *tc) - { - uint64_t ipl = 0; - uint64_t summary = 0; + if (tc->pcState().pc() & 0x3) + return false; if (tc->readMiscRegNoEffect(IPR_ASTRR)) panic("asynchronous traps not implemented\n"); + 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++) { @@ -160,28 +160,52 @@ class Interrupts : public SimObject } } - if (intstatus) { - for (uint64_t i = INTLEVEL_EXTERNAL_MIN; - i < INTLEVEL_EXTERNAL_MAX; i++) { - if (intstatus & (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); + } + } + + 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; + ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1; summary |= (ULL(1) << i); } } } - if (ipl && ipl > tc->readMiscRegNoEffect(IPR_IPLR)) { - newIpl = ipl; - newSummary = summary; - newInfoSet = true; - DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", - tc->readMiscRegNoEffect(IPR_IPLR), ipl, summary); - - return std::make_shared(); - } else { - return NoFault; + 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); + } } + + newIpl = ipl; + newSummary = summary; + newInfoSet = true; + DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", + tc->readMiscRegNoEffect(IPR_IPLR), ipl, summary); + + return std::make_shared(); } void diff --git a/src/arch/arm/interrupts.hh b/src/arch/arm/interrupts.hh index d5d2dac34..d09176ca9 100644 --- a/src/arch/arm/interrupts.hh +++ b/src/arch/arm/interrupts.hh @@ -149,6 +149,10 @@ class Interrupts : public SimObject bool allowVFiq = !cpsr.f && hcr.fmo && !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_fiq = takeInt(tc, INT_FIQ); bool take_ea = takeInt(tc, INT_ABT); @@ -221,6 +225,8 @@ class Interrupts : public SimObject Fault getInterrupt(ThreadContext *tc) { + assert(checkInterrupts(tc)); + HCR hcr = tc->readMiscReg(MISCREG_HCR); CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); SCR scr = tc->readMiscReg(MISCREG_SCR); @@ -234,15 +240,10 @@ class Interrupts : public SimObject bool allowVFiq = !cpsr.f && hcr.fmo && !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_fiq = takeInt(tc, INT_FIQ); bool take_ea = takeInt(tc, INT_ABT); - if (interrupts[INT_IRQ] && take_irq) return std::make_shared(); if ((interrupts[INT_VIRT_IRQ] || hcr.vi) && allowVIrq) diff --git a/src/arch/mips/interrupts.cc b/src/arch/mips/interrupts.cc index a0d9de03b..98c1b8e23 100755 --- a/src/arch/mips/interrupts.cc +++ b/src/arch/mips/interrupts.cc @@ -105,11 +105,11 @@ Interrupts::clearAll() } - -Fault -Interrupts::getInterrupt(ThreadContext * tc) +bool +Interrupts::checkInterrupts(ThreadContext *tc) const { - DPRINTF(Interrupt, "Interrupts getInterrupt\n"); + if (!interruptsPending(tc)) + return false; //Check if there are any outstanding interrupts 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 // handler CauseReg cause = tc->readMiscRegNoEffect(MISCREG_CAUSE); - if (status.im && cause.ip) { - DPRINTF(Interrupt, "Interrupt! IM[7:0]=%d IP[7:0]=%d \n", - (unsigned)status.im, (unsigned)cause.ip); - return std::make_shared(); - } + if (status.im && cause.ip) + return true; + } - 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(); } bool diff --git a/src/arch/mips/interrupts.hh b/src/arch/mips/interrupts.hh index b5323e4e1..2205510d2 100755 --- a/src/arch/mips/interrupts.hh +++ b/src/arch/mips/interrupts.hh @@ -107,13 +107,7 @@ class Interrupts : public SimObject void updateIntrInfo(ThreadContext *tc) const; bool interruptsPending(ThreadContext *tc) const; bool onCpuTimerInterrupt(ThreadContext *tc) const; - - bool - checkInterrupts(ThreadContext *tc) const - { - return interruptsPending(tc); - } - + bool checkInterrupts(ThreadContext *tc) const; void serialize(CheckpointOut &cp) const override diff --git a/src/arch/power/interrupts.hh b/src/arch/power/interrupts.hh index 9c11c8e8a..be5c72151 100644 --- a/src/arch/power/interrupts.hh +++ b/src/arch/power/interrupts.hh @@ -89,6 +89,7 @@ class Interrupts : public SimObject Fault getInterrupt(ThreadContext *tc) { + assert(checkInterrupts(tc)); panic("Interrupts::getInterrupt not implemented.\n"); } diff --git a/src/arch/sparc/interrupts.hh b/src/arch/sparc/interrupts.hh index 8929759f3..e6c926676 100644 --- a/src/arch/sparc/interrupts.hh +++ b/src/arch/sparc/interrupts.hh @@ -121,12 +121,66 @@ class Interrupts : public SimObject bool 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 getInterrupt(ThreadContext *tc) { + assert(checkInterrupts(tc)); + HPSTATE hpstate = tc->readMiscRegNoEffect(MISCREG_HPSTATE); PSTATE pstate = tc->readMiscRegNoEffect(MISCREG_PSTATE);