changeset 0c6613ad8f18 in /z/repo/m5
details: http://repo.m5sim.org/m5?cmd=changeset;node=0c6613ad8f18
description:
        O3: Fixes fetch deadlock when the interrupt clears before CPU handles 
it.

        When this condition occurs the cpu should restart the fetch stage to 
fetch from
        the original execution path. Fault handling in the commit stage is 
cleaned up a
        little bit so the control flow is simplier. Finally, if an instruction 
is being
        used to carry a fault it isn't executed, so the fault propagates 
appropriately.

diffstat:

 src/arch/arm/interrupts.hh |    3 +-
 src/cpu/o3/commit.hh       |    3 +
 src/cpu/o3/commit_impl.hh  |  100 +++++++++++++++++++++++++-------------------
 src/cpu/o3/fetch.hh        |    9 ++++
 src/cpu/o3/fetch_impl.hh   |   18 ++++++-
 src/cpu/o3/iew_impl.hh     |    8 +++-
 6 files changed, 92 insertions(+), 49 deletions(-)

diffs (238 lines):

diff -r ff8e3075d762 -r 0c6613ad8f18 src/arch/arm/interrupts.hh
--- a/src/arch/arm/interrupts.hh        Tue Jan 18 16:30:01 2011 -0600
+++ b/src/arch/arm/interrupts.hh        Tue Jan 18 16:30:01 2011 -0600
@@ -102,7 +102,7 @@
     void
     clear(int int_num, int index)
     {
-        DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index);
+        DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index);
 
         if (int_num < 0 || int_num >= NumInterruptTypes)
             panic("int_num out of bounds\n");
@@ -112,7 +112,6 @@
 
         interrupts[int_num] = false;
         intStatus &= ~(ULL(1) << int_num);
-
     }
 
     void
diff -r ff8e3075d762 -r 0c6613ad8f18 src/cpu/o3/commit.hh
--- a/src/cpu/o3/commit.hh      Tue Jan 18 16:30:01 2011 -0600
+++ b/src/cpu/o3/commit.hh      Tue Jan 18 16:30:01 2011 -0600
@@ -255,6 +255,9 @@
 #if FULL_SYSTEM
     /** Handles processing an interrupt. */
     void handleInterrupt();
+
+    /** Get fetch redirecting so we can handle an interrupt */
+    void propagateInterrupt();
 #endif // FULL_SYSTEM
 
     /** Commits as many instructions as possible. */
diff -r ff8e3075d762 -r 0c6613ad8f18 src/cpu/o3/commit_impl.hh
--- a/src/cpu/o3/commit_impl.hh Tue Jan 18 16:30:01 2011 -0600
+++ b/src/cpu/o3/commit_impl.hh Tue Jan 18 16:30:01 2011 -0600
@@ -674,54 +674,67 @@
 void
 DefaultCommit<Impl>::handleInterrupt()
 {
-    if (interrupt != NoFault) {
-        // Wait until the ROB is empty and all stores have drained in
-        // order to enter the interrupt.
-        if (rob->isEmpty() && !iewStage->hasStoresToWB()) {
-            // Squash or record that I need to squash this cycle if
-            // an interrupt needed to be handled.
-            DPRINTF(Commit, "Interrupt detected.\n");
+    // Verify that we still have an interrupt to handle
+    if (!cpu->checkInterrupts(cpu->tcBase(0))) {
+        DPRINTF(Commit, "Pending interrupt is cleared by master before "
+                "it got handled. Restart fetching from the orig path.\n");
+        toIEW->commitInfo[0].clearInterrupt = true;
+        interrupt = NoFault;
+        return;
+    }
 
-            // Clear the interrupt now that it's going to be handled
-            toIEW->commitInfo[0].clearInterrupt = true;
+    // Wait until the ROB is empty and all stores have drained in
+    // order to enter the interrupt.
+    if (rob->isEmpty() && !iewStage->hasStoresToWB()) {
+        // Squash or record that I need to squash this cycle if
+        // an interrupt needed to be handled.
+        DPRINTF(Commit, "Interrupt detected.\n");
 
-            assert(!thread[0]->inSyscall);
-            thread[0]->inSyscall = true;
+        // Clear the interrupt now that it's going to be handled
+        toIEW->commitInfo[0].clearInterrupt = true;
 
-            // CPU will handle interrupt.
-            cpu->processInterrupts(interrupt);
+        assert(!thread[0]->inSyscall);
+        thread[0]->inSyscall = true;
 
-            thread[0]->inSyscall = false;
+        // CPU will handle interrupt.
+        cpu->processInterrupts(interrupt);
 
-            commitStatus[0] = TrapPending;
+        thread[0]->inSyscall = false;
 
-            // Generate trap squash event.
-            generateTrapEvent(0);
+        commitStatus[0] = TrapPending;
 
-            interrupt = NoFault;
-        } else {
-            DPRINTF(Commit, "Interrupt pending, waiting for ROB to empty.\n");
-        }
-    } else if (commitStatus[0] != TrapPending &&
-               cpu->checkInterrupts(cpu->tcBase(0)) &&
-               !trapSquash[0] &&
-               !tcSquash[0]) {
-        // Process interrupts if interrupts are enabled, not in PAL
-        // mode, and no other traps or external squashes are currently
-        // pending.
-        // @todo: Allow other threads to handle interrupts.
+        // Generate trap squash event.
+        generateTrapEvent(0);
 
-        // Get any interrupt that happened
-        interrupt = cpu->getInterrupts();
-
-        if (interrupt != NoFault) {
-            // Tell fetch that there is an interrupt pending.  This
-            // will make fetch wait until it sees a non PAL-mode PC,
-            // at which point it stops fetching instructions.
-            toIEW->commitInfo[0].interruptPending = true;
-        }
+        interrupt = NoFault;
+    } else {
+        DPRINTF(Commit, "Interrupt pending, waiting for ROB to empty.\n");
     }
 }
+
+template <class Impl>
+void
+DefaultCommit<Impl>::propagateInterrupt()
+{
+    if (commitStatus[0] == TrapPending || interrupt || trapSquash[0] ||
+            tcSquash[0])
+        return;
+
+    // Process interrupts if interrupts are enabled, not in PAL
+    // mode, and no other traps or external squashes are currently
+    // pending.
+    // @todo: Allow other threads to handle interrupts.
+
+    // Get any interrupt that happened
+    interrupt = cpu->getInterrupts();
+
+    // Tell fetch that there is an interrupt pending.  This
+    // will make fetch wait until it sees a non PAL-mode PC,
+    // at which point it stops fetching instructions.
+    if (interrupt != NoFault)
+        toIEW->commitInfo[0].interruptPending = true;
+}
+
 #endif // FULL_SYSTEM
 
 template <class Impl>
@@ -730,12 +743,13 @@
 {
 
 #if FULL_SYSTEM
-    // Check for any interrupt, and start processing it.  Or if we
-    // have an outstanding interrupt and are at a point when it is
-    // valid to take an interrupt, process it.
-    if (cpu->checkInterrupts(cpu->tcBase(0))) {
+    // Check for any interrupt that we've already squashed for and start 
processing it.
+    if (interrupt != NoFault)
         handleInterrupt();
-    }
+
+    // Check if we have a interrupt and get read to handle it
+    if (cpu->checkInterrupts(cpu->tcBase(0)))
+        propagateInterrupt();
 #endif // FULL_SYSTEM
 
     ////////////////////////////////////
diff -r ff8e3075d762 -r 0c6613ad8f18 src/cpu/o3/fetch.hh
--- a/src/cpu/o3/fetch.hh       Tue Jan 18 16:30:01 2011 -0600
+++ b/src/cpu/o3/fetch.hh       Tue Jan 18 16:30:01 2011 -0600
@@ -244,6 +244,15 @@
      */
     bool fetchCacheLine(Addr vaddr, Fault &ret_fault, ThreadID tid, Addr pc);
 
+
+    /** Check if an interrupt is pending and that we need to handle
+     */
+    bool
+    checkInterrupt(Addr pc)
+    {
+        return (interruptPending && (THE_ISA != ALPHA_ISA || !(pc & 0x3)));
+    }
+
     /** Squashes a specific thread and resets the PC. */
     inline void doSquash(const TheISA::PCState &newPC, ThreadID tid);
 
diff -r ff8e3075d762 -r 0c6613ad8f18 src/cpu/o3/fetch_impl.hh
--- a/src/cpu/o3/fetch_impl.hh  Tue Jan 18 16:30:01 2011 -0600
+++ b/src/cpu/o3/fetch_impl.hh  Tue Jan 18 16:30:01 2011 -0600
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2010 ARM Limited
+ * All rights reserved.
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 2004-2006 The Regents of The University of Michigan
  * All rights reserved.
  *
@@ -550,7 +562,7 @@
         DPRINTF(Fetch, "[tid:%i] Can't fetch cache line, switched out\n",
                 tid);
         return false;
-    } else if (interruptPending && !(pc & 0x3)) {
+    } else if (checkInterrupt(pc)) {
         // Hold off fetch from getting new instructions when:
         // Cache is blocked, or
         // while an interrupt is pending and we're not in PAL mode, or
@@ -1250,8 +1262,8 @@
         fetchStatus[tid] = TrapPending;
         status_change = true;
 
-        DPRINTF(Fetch, "[tid:%i]: fault (%s) detected @ PC %s",
-                tid, fault->name(), thisPC);
+        DPRINTF(Fetch, "[tid:%i]: fault (%s) detected @ PC %s, sending nop "
+                       "[sn:%lli]\n", tid, fault->name(), thisPC, inst_seq);
     }
 }
 
diff -r ff8e3075d762 -r 0c6613ad8f18 src/cpu/o3/iew_impl.hh
--- a/src/cpu/o3/iew_impl.hh    Tue Jan 18 16:30:01 2011 -0600
+++ b/src/cpu/o3/iew_impl.hh    Tue Jan 18 16:30:01 2011 -0600
@@ -1255,7 +1255,13 @@
             }
 
         } else {
-            inst->execute();
+            // If the instruction has already faulted, then skip executing it.
+            // Such case can happen when it faulted during ITLB translation.
+            // If we execute the instruction (even if it's a nop) the fault
+            // will be replaced and we will lose it.
+            if (inst->getFault() == NoFault) {
+                inst->execute();
+            }
 
             inst->setExecuted();
 
_______________________________________________
m5-dev mailing list
m5-dev@m5sim.org
http://m5sim.org/mailman/listinfo/m5-dev

Reply via email to