isa: Modify get/check interrupt routines
authorMitch Hayenga <mitch.hayenga@arm.com>
Thu, 21 Jul 2016 16:19:15 +0000 (17:19 +0100)
committerMitch Hayenga <mitch.hayenga@arm.com>
Thu, 21 Jul 2016 16:19:15 +0000 (17:19 +0100)
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
src/arch/arm/interrupts.hh
src/arch/mips/interrupts.cc
src/arch/mips/interrupts.hh
src/arch/power/interrupts.hh
src/arch/sparc/interrupts.hh

index 1e67f54b5567c6f774e25b678a6d1c92f3821d24..61ac6c9687c481c3efa557985fe83bdc971741df 100644 (file)
@@ -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<InterruptFault>();
-        } 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<InterruptFault>();
     }
 
     void
index d5d2dac348c275904fa6493d4cf674fdc8d5790a..d09176ca9cef44929213cc8bed3c0bb575417e4a 100644 (file)
@@ -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<Interrupt>();
         if ((interrupts[INT_VIRT_IRQ] || hcr.vi) && allowVIrq)
index a0d9de03b10697e790e11b78e3dbde3fb2eaf882..98c1b8e23e80525c848ce18148b9aa3f4326652b 100755 (executable)
@@ -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<InterruptFault>();
-        }
+        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<InterruptFault>();
 }
 
 bool
index b5323e4e1dbc8c001a98017921039b756b1253d3..2205510d23e5a70400080e7859ba5dcb04a77b18 100755 (executable)
@@ -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
index 9c11c8e8a909e213068844387acacc4aa2771807..be5c72151070f6bb905f75d01121bc7545e3e406 100644 (file)
@@ -89,6 +89,7 @@ class Interrupts : public SimObject
     Fault
     getInterrupt(ThreadContext *tc)
     {
+        assert(checkInterrupts(tc));
         panic("Interrupts::getInterrupt not implemented.\n");
     }
 
index 8929759f323488ea43e70decf8cba060e2a52a6b..e6c92667603244f966ed20312b8596d56dfa2fe6 100644 (file)
@@ -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);