cpu: Rewrite O3 draining to avoid stopping in microcode
authorAndreas Sandberg <Andreas.Sandberg@ARM.com>
Mon, 7 Jan 2013 18:05:46 +0000 (13:05 -0500)
committerAndreas Sandberg <Andreas.Sandberg@ARM.com>
Mon, 7 Jan 2013 18:05:46 +0000 (13:05 -0500)
Previously, the O3 CPU could stop in the middle of a microcode
sequence. This patch makes sure that the pipeline stops when it has
committed a normal instruction or exited from a microcode
sequence. Additionally, it makes sure that the pipeline has no
instructions in flight when it is drained, which should make draining
more robust.

Draining is controlled in the commit stage, which checks if the next
PC after a committed instruction is in microcode. If this isn't the
case, it requests a squash of all instructions after that the
instruction that just committed and immediately signals a drain stall
to the fetch stage. The CPU then continues to execute until the
pipeline and all associated buffers are empty.

27 files changed:
src/cpu/o3/bpred_unit.hh
src/cpu/o3/bpred_unit_impl.hh
src/cpu/o3/commit.hh
src/cpu/o3/commit_impl.hh
src/cpu/o3/cpu.cc
src/cpu/o3/cpu.hh
src/cpu/o3/decode.hh
src/cpu/o3/decode_impl.hh
src/cpu/o3/dep_graph.hh
src/cpu/o3/fetch.hh
src/cpu/o3/fetch_impl.hh
src/cpu/o3/fu_pool.cc
src/cpu/o3/fu_pool.hh
src/cpu/o3/iew.hh
src/cpu/o3/iew_impl.hh
src/cpu/o3/inst_queue.hh
src/cpu/o3/inst_queue_impl.hh
src/cpu/o3/lsq.hh
src/cpu/o3/lsq_impl.hh
src/cpu/o3/lsq_unit.hh
src/cpu/o3/lsq_unit_impl.hh
src/cpu/o3/mem_dep_unit.hh
src/cpu/o3/mem_dep_unit_impl.hh
src/cpu/o3/rename.hh
src/cpu/o3/rename_impl.hh
src/cpu/o3/rob.hh
src/cpu/o3/rob_impl.hh

index c1afb4720c9a3aeb51acaab756fc7e46bd85420a..3f83f9bef63a0ea628d6fe84528a33dd73a4acae 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 ARM Limited
+ * Copyright (c) 2011-2012 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -88,8 +88,10 @@ class BPredUnit
      */
     void regStats();
 
-    void switchOut();
+    /** Perform sanity checks after a drain. */
+    void drainSanityCheck() const;
 
+    /** Take over execution from another CPU's thread. */
     void takeOverFrom();
 
     /**
index 74fe27a6a5c480b427f765f383bffa240065fe1c..43e80171037b42c34082b9da29250da339f47bc7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 ARM Limited
+ * Copyright (c) 2011-2012 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -131,12 +131,12 @@ BPredUnit<Impl>::regStats()
 
 template <class Impl>
 void
-BPredUnit<Impl>::switchOut()
+BPredUnit<Impl>::drainSanityCheck() const
 {
-    // Clear any state upon switch out.
-    for (int i = 0; i < Impl::MaxThreads; ++i) {
-        squash(0, i);
-    }
+    // We shouldn't have any outstanding requests when we resume from
+    // a drained system.
+    for (int i = 0; i < Impl::MaxThreads; ++i)
+        assert(predHist[i].empty());
 }
 
 template <class Impl>
index 2d8d88b2185a9604bc1396b6a1c0efe569f8b43f..c76d6c1d0394adb5be327a1fc990ff0e0e038339 100644 (file)
@@ -199,13 +199,16 @@ class DefaultCommit
     void startupStage();
 
     /** Initializes the draining of commit. */
-    bool drain();
+    void drain();
 
     /** Resumes execution after draining. */
-    void resume();
+    void drainResume();
 
-    /** Completes the switch out of commit. */
-    void switchOut();
+    /** Perform sanity checks after a drain. */
+    void drainSanityCheck() const;
+
+    /** Has the stage drained? */
+    bool isDrained() const;
 
     /** Takes over from another CPU's thread. */
     void takeOverFrom();
@@ -438,9 +441,6 @@ class DefaultCommit
     /** Is a drain pending. */
     bool drainPending;
 
-    /** Is commit switched out. */
-    bool switchedOut;
-
     /** The latency to handle a trap.  Used when scheduling trap
      * squash event.
      */
index 333ccc89f4b1097a3586571754d53360ff26af37..ea709e92c1ab8ddd6bafe5bee22d67b872499f4b 100644 (file)
@@ -57,6 +57,7 @@
 #include "debug/Activity.hh"
 #include "debug/Commit.hh"
 #include "debug/CommitRate.hh"
+#include "debug/Drain.hh"
 #include "debug/ExecFaulting.hh"
 #include "params/DerivO3CPU.hh"
 #include "sim/faults.hh"
@@ -99,7 +100,6 @@ DefaultCommit<Impl>::DefaultCommit(O3CPU *_cpu, DerivO3CPUParams *params)
       commitWidth(params->commitWidth),
       numThreads(params->numThreads),
       drainPending(false),
-      switchedOut(false),
       trapLatency(params->trapLatency),
       canHandleInterrupts(true)
 {
@@ -369,35 +369,59 @@ DefaultCommit<Impl>::startupStage()
 }
 
 template <class Impl>
-bool
+void
 DefaultCommit<Impl>::drain()
 {
     drainPending = true;
-
-    return false;
 }
 
 template <class Impl>
 void
-DefaultCommit<Impl>::switchOut()
+DefaultCommit<Impl>::drainResume()
 {
-    switchedOut = true;
     drainPending = false;
-    rob->switchOut();
 }
 
 template <class Impl>
 void
-DefaultCommit<Impl>::resume()
+DefaultCommit<Impl>::drainSanityCheck() const
 {
-    drainPending = false;
+    assert(isDrained());
+    rob->drainSanityCheck();
+}
+
+template <class Impl>
+bool
+DefaultCommit<Impl>::isDrained() const
+{
+    /* Make sure no one is executing microcode. There are two reasons
+     * for this:
+     * - Hardware virtualized CPUs can't switch into the middle of a
+     *   microcode sequence.
+     * - The current fetch implementation will most likely get very
+     *   confused if it tries to start fetching an instruction that
+     *   is executing in the middle of a ucode sequence that changes
+     *   address mappings. This can happen on for example x86.
+     */
+    for (ThreadID tid = 0; tid < numThreads; tid++) {
+        if (pc[tid].microPC() != 0)
+            return false;
+    }
+
+    /* Make sure that all instructions have finished committing before
+     * declaring the system as drained. We want the pipeline to be
+     * completely empty when we declare the CPU to be drained. This
+     * makes debugging easier since CPU handover and restoring from a
+     * checkpoint with a different CPU should have the same timing.
+     */
+    return rob->isEmpty() &&
+        interrupt == NoFault;
 }
 
 template <class Impl>
 void
 DefaultCommit<Impl>::takeOverFrom()
 {
-    switchedOut = false;
     _status = Active;
     _nextStatus = Inactive;
     for (ThreadID tid = 0; tid < numThreads; tid++) {
@@ -624,13 +648,6 @@ DefaultCommit<Impl>::tick()
     wroteToTimeBuffer = false;
     _nextStatus = Inactive;
 
-    if (drainPending && cpu->instList.empty() && !iewStage->hasStoresToWB() &&
-        interrupt == NoFault) {
-        cpu->signalDrained();
-        drainPending = false;
-        return;
-    }
-
     if (activeThreads->empty())
         return;
 
@@ -1018,6 +1035,14 @@ DefaultCommit<Impl>::commitInsts()
                 if (head_inst->isSquashAfter())
                     squashAfter(tid, head_inst);
 
+                if (drainPending) {
+                    DPRINTF(Drain, "Draining: %i:%s\n", tid, pc[tid]);
+                    if (pc[tid].microPC() == 0 && interrupt == NoFault) {
+                        squashAfter(tid, head_inst);
+                        cpu->commitDrained(tid);
+                    }
+                }
+
                 int count = 0;
                 Addr oldpc;
                 // Debug statement.  Checks to make sure we're not
index 724d88405c9a4633816b8e2eb09a765a8e2cd662..cb17581e593c8052a55284005b615a69f52cc23f 100644 (file)
@@ -257,7 +257,7 @@ FullO3CPU<Impl>::FullO3CPU(DerivO3CPUParams *params)
 
       globalSeqNum(1),
       system(params->system),
-      drainCount(0),
+      drainManager(NULL),
       lastRunningCycle(curCycle())
 {
     if (!params->switched_out) {
@@ -584,6 +584,8 @@ void
 FullO3CPU<Impl>::tick()
 {
     DPRINTF(O3CPU, "\n\nFullO3CPU: Ticking main, FullO3CPU.\n");
+    assert(!switchedOut());
+    assert(getDrainState() != Drainable::Drained);
 
     ++numCycles;
 
@@ -618,8 +620,7 @@ FullO3CPU<Impl>::tick()
     }
 
     if (!tickEvent.scheduled()) {
-        if (_status == SwitchedOut ||
-            getDrainState() == Drainable::Drained) {
+        if (_status == SwitchedOut) {
             DPRINTF(O3CPU, "Switched out!\n");
             // increment stat
             lastRunningCycle = curCycle();
@@ -635,6 +636,8 @@ FullO3CPU<Impl>::tick()
 
     if (!FullSystem)
         updateThreadPriority();
+
+    tryDrain();
 }
 
 template <class Impl>
@@ -657,13 +660,6 @@ FullO3CPU<Impl>::init()
         thread[tid]->initMemProxies(thread[tid]->getTC());
     }
 
-    // this CPU could still be unconnected if we are restoring from a
-    // checkpoint and this CPU is to be switched in, thus we can only
-    // do this here if the instruction port is actually connected, if
-    // not we have to do it as part of takeOverFrom
-    if (icachePort.isConnected())
-        fetch.setIcache();
-
     if (FullSystem && !params()->switched_out) {
         for (ThreadID tid = 0; tid < numThreads; tid++) {
             ThreadContext *src_tc = threadContexts[tid];
@@ -683,6 +679,7 @@ void
 FullO3CPU<Impl>::startup()
 {
     fetch.startupStage();
+    decode.startupStage();
     iew.startupStage();
     rename.startupStage();
     commit.startupStage();
@@ -696,6 +693,7 @@ FullO3CPU<Impl>::activateThread(ThreadID tid)
         std::find(activeThreads.begin(), activeThreads.end(), tid);
 
     DPRINTF(O3CPU, "[tid:%i]: Calling activate thread.\n", tid);
+    assert(!switchedOut());
 
     if (isActive == activeThreads.end()) {
         DPRINTF(O3CPU, "[tid:%i]: Adding to active threads list\n",
@@ -714,6 +712,7 @@ FullO3CPU<Impl>::deactivateThread(ThreadID tid)
         std::find(activeThreads.begin(), activeThreads.end(), tid);
 
     DPRINTF(O3CPU, "[tid:%i]: Calling deactivate thread.\n", tid);
+    assert(!switchedOut());
 
     if (thread_it != activeThreads.end()) {
         DPRINTF(O3CPU,"[tid:%i]: Removing from active threads list\n",
@@ -752,6 +751,8 @@ template <class Impl>
 void
 FullO3CPU<Impl>::activateContext(ThreadID tid, Cycles delay)
 {
+    assert(!switchedOut());
+
     // Needs to set each stage to running as well.
     if (delay){
         DPRINTF(O3CPU, "[tid:%i]: Scheduling thread context to activate "
@@ -761,6 +762,12 @@ FullO3CPU<Impl>::activateContext(ThreadID tid, Cycles delay)
         activateThread(tid);
     }
 
+    // We don't want to wake the CPU if it is drained. In that case,
+    // we just want to flag the thread as active and schedule the tick
+    // event from drainResume() instead.
+    if (getDrainState() == Drainable::Drained)
+        return;
+
     // If we are time 0 or if the last activation time is in the past,
     // schedule the next tick and wake up the fetch unit
     if (lastActivatedCycle == 0 || lastActivatedCycle < curTick()) {
@@ -807,6 +814,7 @@ void
 FullO3CPU<Impl>::suspendContext(ThreadID tid)
 {
     DPRINTF(O3CPU,"[tid: %i]: Suspending Thread Context.\n", tid);
+    assert(!switchedOut());
     bool deallocated = scheduleDeallocateContext(tid, false, Cycles(1));
     // If this was the last thread then unschedule the tick event.
     if ((activeThreads.size() == 1 && !deallocated) ||
@@ -824,6 +832,7 @@ FullO3CPU<Impl>::haltContext(ThreadID tid)
 {
     //For now, this is the same as deallocate
     DPRINTF(O3CPU,"[tid:%i]: Halt Context called. Deallocating", tid);
+    assert(!switchedOut());
     scheduleDeallocateContext(tid, true, Cycles(1));
 }
 
@@ -1120,26 +1129,26 @@ template <class Impl>
 unsigned int
 FullO3CPU<Impl>::drain(DrainManager *drain_manager)
 {
-    DPRINTF(O3CPU, "Switching out\n");
-
     // If the CPU isn't doing anything, then return immediately.
-    if (_status == SwitchedOut)
+    if (switchedOut()) {
+        setDrainState(Drainable::Drained);
         return 0;
+    }
+
+    DPRINTF(Drain, "Draining...\n");
+    setDrainState(Drainable::Draining);
 
-    drainCount = 0;
-    fetch.drain();
-    decode.drain();
-    rename.drain();
-    iew.drain();
+    // We only need to signal a drain to the commit stage as this
+    // initiates squashing controls the draining. Once the commit
+    // stage commits an instruction where it is safe to stop, it'll
+    // squash the rest of the instructions in the pipeline and force
+    // the fetch stage to stall. The pipeline will be drained once all
+    // in-flight instructions have retired.
     commit.drain();
 
     // Wake the CPU and record activity so everything can drain out if
     // the CPU was not able to immediately drain.
-    if (getDrainState() != Drainable::Drained) {
-        // A bit of a hack...set the drainManager after all the drain()
-        // calls have been made, that way if all of the stages drain
-        // immediately, the signalDrained() function knows not to call
-        // process on the drain event.
+    if (!isDrained())  {
         drainManager = drain_manager;
 
         wakeCPU();
@@ -1149,93 +1158,167 @@ FullO3CPU<Impl>::drain(DrainManager *drain_manager)
 
         return 1;
     } else {
+        setDrainState(Drainable::Drained);
+        DPRINTF(Drain, "CPU is already drained\n");
+        if (tickEvent.scheduled())
+            deschedule(tickEvent);
+
+        // Flush out any old data from the time buffers.  In
+        // particular, there might be some data in flight from the
+        // fetch stage that isn't visible in any of the CPU buffers we
+        // test in isDrained().
+        for (int i = 0; i < timeBuffer.getSize(); ++i) {
+            timeBuffer.advance();
+            fetchQueue.advance();
+            decodeQueue.advance();
+            renameQueue.advance();
+            iewQueue.advance();
+        }
+
+        drainSanityCheck();
         return 0;
     }
 }
 
+template <class Impl>
+bool
+FullO3CPU<Impl>::tryDrain()
+{
+    if (!drainManager || !isDrained())
+        return false;
+
+    if (tickEvent.scheduled())
+        deschedule(tickEvent);
+
+    DPRINTF(Drain, "CPU done draining, processing drain event\n");
+    drainManager->signalDrainDone();
+    drainManager = NULL;
+
+    return true;
+}
+
 template <class Impl>
 void
-FullO3CPU<Impl>::drainResume()
+FullO3CPU<Impl>::drainSanityCheck() const
 {
-    fetch.resume();
-    decode.resume();
-    rename.resume();
-    iew.resume();
-    commit.resume();
+    assert(isDrained());
+    fetch.drainSanityCheck();
+    decode.drainSanityCheck();
+    rename.drainSanityCheck();
+    iew.drainSanityCheck();
+    commit.drainSanityCheck();
+}
 
-    setDrainState(Drainable::Running);
+template <class Impl>
+bool
+FullO3CPU<Impl>::isDrained() const
+{
+    bool drained(true);
 
-    if (_status == SwitchedOut)
-        return;
+    for (ThreadID i = 0; i < thread.size(); ++i) {
+        if (activateThreadEvent[i].scheduled()) {
+            DPRINTF(Drain, "CPU not drained, tread %i has a "
+                    "pending activate event\n", i);
+            drained = false;
+        }
+        if (deallocateContextEvent[i].scheduled()) {
+            DPRINTF(Drain, "CPU not drained, tread %i has a "
+                    "pending deallocate context event\n", i);
+            drained = false;
+        }
+    }
 
-    if (system->getMemoryMode() != Enums::timing) {
-        fatal("The O3 CPU requires the memory system to be in "
-              "'timing' mode.\n");
+    if (!instList.empty() || !removeList.empty()) {
+        DPRINTF(Drain, "Main CPU structures not drained.\n");
+        drained = false;
     }
 
-    if (!tickEvent.scheduled())
-        schedule(tickEvent, nextCycle());
-    _status = Running;
+    if (!fetch.isDrained()) {
+        DPRINTF(Drain, "Fetch not drained.\n");
+        drained = false;
+    }
+
+    if (!decode.isDrained()) {
+        DPRINTF(Drain, "Decode not drained.\n");
+        drained = false;
+    }
+
+    if (!rename.isDrained()) {
+        DPRINTF(Drain, "Rename not drained.\n");
+        drained = false;
+    }
+
+    if (!iew.isDrained()) {
+        DPRINTF(Drain, "IEW not drained.\n");
+        drained = false;
+    }
+
+    if (!commit.isDrained()) {
+        DPRINTF(Drain, "Commit not drained.\n");
+        drained = false;
+    }
+
+    return drained;
 }
 
 template <class Impl>
 void
-FullO3CPU<Impl>::signalDrained()
+FullO3CPU<Impl>::commitDrained(ThreadID tid)
 {
-    if (++drainCount == NumStages) {
-        if (tickEvent.scheduled())
-            tickEvent.squash();
+    fetch.drainStall(tid);
+}
 
-        setDrainState(Drainable::Drained);
+template <class Impl>
+void
+FullO3CPU<Impl>::drainResume()
+{
+    setDrainState(Drainable::Running);
+    if (switchedOut())
+        return;
+
+    DPRINTF(Drain, "Resuming...\n");
 
-        if (drainManager) {
-            DPRINTF(Drain, "CPU done draining, processing drain event\n");
-            drainManager->signalDrainDone();
-            drainManager = NULL;
+    if (system->getMemoryMode() != Enums::timing) {
+        fatal("The O3 CPU requires the memory system to be in "
+              "'timing' mode.\n");
+    }
+
+    fetch.drainResume();
+    commit.drainResume();
+
+    _status = Idle;
+    for (ThreadID i = 0; i < thread.size(); i++) {
+        if (thread[i]->status() == ThreadContext::Active) {
+            DPRINTF(Drain, "Activating thread: %i\n", i);
+            activateThread(i);
+            _status = Running;
         }
     }
-    assert(drainCount <= 5);
+
+    assert(!tickEvent.scheduled());
+    if (_status == Running)
+        schedule(tickEvent, nextCycle());
 }
 
 template <class Impl>
 void
 FullO3CPU<Impl>::switchOut()
 {
+    DPRINTF(O3CPU, "Switching out\n");
     BaseCPU::switchOut();
 
-    fetch.switchOut();
-    rename.switchOut();
-    iew.switchOut();
-    commit.switchOut();
-    instList.clear();
-    while (!removeList.empty()) {
-        removeList.pop();
-    }
+    activityRec.reset();
 
     _status = SwitchedOut;
 
     if (checker)
         checker->switchOut();
-
-    if (tickEvent.scheduled())
-        tickEvent.squash();
 }
 
 template <class Impl>
 void
 FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
 {
-    // Flush out any old data from the time buffers.
-    for (int i = 0; i < timeBuffer.getSize(); ++i) {
-        timeBuffer.advance();
-        fetchQueue.advance();
-        decodeQueue.advance();
-        renameQueue.advance();
-        iewQueue.advance();
-    }
-
-    activityRec.reset();
-
     BaseCPU::takeOverFrom(oldCPU);
 
     fetch.takeOverFrom();
@@ -1244,42 +1327,14 @@ FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
     iew.takeOverFrom();
     commit.takeOverFrom();
 
-    assert(!tickEvent.scheduled() || tickEvent.squashed());
+    assert(!tickEvent.scheduled());
 
     FullO3CPU<Impl> *oldO3CPU = dynamic_cast<FullO3CPU<Impl>*>(oldCPU);
     if (oldO3CPU)
         globalSeqNum = oldO3CPU->globalSeqNum;
 
-    // @todo: Figure out how to properly select the tid to put onto
-    // the active threads list.
-    ThreadID tid = 0;
-
-    list<ThreadID>::iterator isActive =
-        std::find(activeThreads.begin(), activeThreads.end(), tid);
-
-    if (isActive == activeThreads.end()) {
-        //May Need to Re-code this if the delay variable is the delay
-        //needed for thread to activate
-        DPRINTF(O3CPU, "Adding Thread %i to active threads list\n",
-                tid);
-
-        activeThreads.push_back(tid);
-    }
-
-    // Set all statuses to active, schedule the CPU's tick event.
-    // @todo: Fix up statuses so this is handled properly
-    ThreadID size = threadContexts.size();
-    for (ThreadID i = 0; i < size; ++i) {
-        ThreadContext *tc = threadContexts[i];
-        if (tc->status() == ThreadContext::Active && _status != Running) {
-            _status = Running;
-            reschedule(tickEvent, nextCycle(), true);
-        }
-    }
-    if (!tickEvent.scheduled())
-        schedule(tickEvent, nextCycle());
-
     lastRunningCycle = curCycle();
+    _status = Idle;
 }
 
 template <class Impl>
index 890598b0fff939057bf638f257cd291926961e5d..24c4b46a8f9893cd65c16b3b089ccedabe9f3a08 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 ARM Limited
+ * Copyright (c) 2011-2012 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -333,6 +333,33 @@ class FullO3CPU : public BaseO3CPU
     /** The tick event used for scheduling CPU ticks. */
     DeallocateContextEvent deallocateContextEvent[Impl::MaxThreads];
 
+    /**
+     * Check if the pipeline has drained and signal the DrainManager.
+     *
+     * This method checks if a drain has been requested and if the CPU
+     * has drained successfully (i.e., there are no instructions in
+     * the pipeline). If the CPU has drained, it deschedules the tick
+     * event and signals the drain manager.
+     *
+     * @return False if a drain hasn't been requested or the CPU
+     * hasn't drained, true otherwise.
+     */
+    bool tryDrain();
+
+    /**
+     * Perform sanity checks after a drain.
+     *
+     * This method is called from drain() when it has determined that
+     * the CPU is fully drained when gem5 is compiled with the NDEBUG
+     * macro undefined. The intention of this method is to do more
+     * extensive tests than the isDrained() method to weed out any
+     * draining bugs.
+     */
+    void drainSanityCheck() const;
+
+    /** Check if a system is in a drained state. */
+    bool isDrained() const;
+
   public:
     /** Constructs a CPU with the given parameters. */
     FullO3CPU(DerivO3CPUParams *params);
@@ -416,6 +443,9 @@ class FullO3CPU : public BaseO3CPU
     /** Update The Order In Which We Process Threads. */
     void updateThreadPriority();
 
+    /** Is the CPU draining? */
+    bool isDraining() const { return getDrainState() == Drainable::Draining; }
+
     /** Serialize state. */
     virtual void serialize(std::ostream &os);
 
@@ -435,8 +465,14 @@ class FullO3CPU : public BaseO3CPU
     /** Resumes execution after a drain. */
     void drainResume();
 
-    /** Signals to this CPU that a stage has completed switching out. */
-    void signalDrained();
+    /**
+     * Commit has reached a safe point to drain a thread.
+     *
+     * Commit calls this method to inform the pipeline that it has
+     * reached a point where it is not executed microcode and is about
+     * to squash uncommitted instructions to fully drain the pipeline.
+     */
+    void commitDrained(ThreadID tid);
 
     /** Switches out this CPU. */
     virtual void switchOut();
@@ -732,9 +768,6 @@ class FullO3CPU : public BaseO3CPU
     /** DrainManager to notify when draining has completed. */
     DrainManager *drainManager;
 
-    /** Counter of how many stages have completed draining. */
-    int drainCount;
-
     /** Pointers to all of the threads in the CPU. */
     std::vector<Thread *> thread;
 
index 817c5263f4faf210a02375f279d116b13273d36a..3424b1d074e47618bf4c30dfee344076b2497bd9 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2012 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.
  *
@@ -89,6 +101,9 @@ class DefaultDecode
     /** DefaultDecode constructor. */
     DefaultDecode(O3CPU *_cpu, DerivO3CPUParams *params);
 
+    void startupStage();
+    void resetStage();
+
     /** Returns the name of decode. */
     std::string name() const;
 
@@ -107,17 +122,14 @@ class DefaultDecode
     /** Sets pointer to list of active threads. */
     void setActiveThreads(std::list<ThreadID> *at_ptr);
 
-    /** Drains the decode stage. */
-    bool drain();
+    /** Perform sanity checks after a drain. */
+    void drainSanityCheck() const;
 
-    /** Resumes execution after a drain. */
-    void resume() { }
-
-    /** Switches out the decode stage. */
-    void switchOut() { }
+    /** Has the stage drained? */
+    bool isDrained() const { return true; }
 
     /** Takes over from another CPU's thread. */
-    void takeOverFrom();
+    void takeOverFrom() { resetStage(); }
 
     /** Ticks decode, processing all input signals and decoding as many
      * instructions as possible.
@@ -268,9 +280,6 @@ class DefaultDecode
     /** List of active thread ids */
     std::list<ThreadID> *activeThreads;
 
-    /** Number of branches in flight. */
-    unsigned branchCount[Impl::MaxThreads];
-
     /** Maximum size of the skid buffer. */
     unsigned skidBufferMax;
 
index 315d53155323568cec5bb87ece999f5387ee3028..cd226017f79c8f20ef6454ede1e7dc8a25cbd303 100644 (file)
@@ -1,4 +1,16 @@
-/*
+/* 
+ * Copyright (c) 2012 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.
  *
@@ -51,6 +63,21 @@ DefaultDecode<Impl>::DefaultDecode(O3CPU *_cpu, DerivO3CPUParams *params)
       fetchToDecodeDelay(params->fetchToDecodeDelay),
       decodeWidth(params->decodeWidth),
       numThreads(params->numThreads)
+{
+    // @todo: Make into a parameter
+    skidBufferMax = (fetchToDecodeDelay + 1) *  params->fetchWidth;
+}
+
+template<class Impl>
+void
+DefaultDecode<Impl>::startupStage()
+{
+    resetStage();
+}
+
+template<class Impl>
+void
+DefaultDecode<Impl>::resetStage()
 {
     _status = Inactive;
 
@@ -62,9 +89,6 @@ DefaultDecode<Impl>::DefaultDecode(O3CPU *_cpu, DerivO3CPUParams *params)
         stalls[tid].iew = false;
         stalls[tid].commit = false;
     }
-
-    // @todo: Make into a parameter
-    skidBufferMax = (fetchToDecodeDelay + 1) *  params->fetchWidth;
 }
 
 template <class Impl>
@@ -163,35 +187,14 @@ DefaultDecode<Impl>::setActiveThreads(std::list<ThreadID> *at_ptr)
     activeThreads = at_ptr;
 }
 
-template <class Impl>
-bool
-DefaultDecode<Impl>::drain()
-{
-    // Decode is done draining at any time.
-    cpu->signalDrained();
-    return true;
-}
-
 template <class Impl>
 void
-DefaultDecode<Impl>::takeOverFrom()
+DefaultDecode<Impl>::drainSanityCheck() const
 {
-    _status = Inactive;
-
-    // Be sure to reset state and clear out any old instructions.
     for (ThreadID tid = 0; tid < numThreads; ++tid) {
-        decodeStatus[tid] = Idle;
-
-        stalls[tid].rename = false;
-        stalls[tid].iew = false;
-        stalls[tid].commit = false;
-        while (!insts[tid].empty())
-            insts[tid].pop();
-        while (!skidBuffer[tid].empty())
-            skidBuffer[tid].pop();
-        branchCount[tid] = 0;
+        assert(insts[tid].empty());
+        assert(skidBuffer[tid].empty());
     }
-    wroteToTimeBuffer = false;
 }
 
 template<class Impl>
index 804b3f9cd4f5be1787a2c85f346211490fc33f3b..41ab6e94fd7020512698677ec7161fe5dd25b1e9 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2012 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) 2006 The Regents of The University of Michigan
  * All rights reserved.
  *
@@ -93,8 +105,11 @@ class DependencyGraph
     /** Removes and returns the newest dependent of a specific register. */
     DynInstPtr pop(PhysRegIndex idx);
 
+    /** Checks if the entire dependency graph is empty. */
+    bool empty() const;
+
     /** Checks if there are any dependents on a specific register. */
-    bool empty(PhysRegIndex idx) { return !dependGraph[idx].next; }
+    bool empty(PhysRegIndex idx) const { return !dependGraph[idx].next; }
 
     /** Debugging function to dump out the dependency graph.
      */
@@ -240,6 +255,17 @@ DependencyGraph<DynInstPtr>::pop(PhysRegIndex idx)
     return inst;
 }
 
+template <class DynInstPtr>
+bool
+DependencyGraph<DynInstPtr>::empty() const
+{
+    for (int i = 0; i < numEntries; ++i) {
+        if (!empty(i))
+            return false;
+    }
+    return true;
+}
+
 template <class DynInstPtr>
 void
 DependencyGraph<DynInstPtr>::dump()
index 702a45e15554b944a550d929b487f48e045e657e..fb17a924774ed3836d93dc347f34016f7efa8599 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2011 ARM Limited
+ * Copyright (c) 2010-2012 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -165,7 +165,6 @@ class DefaultFetch
         Fetching,
         TrapPending,
         QuiescePending,
-        SwitchOut,
         ItlbWait,
         IcacheWaitResponse,
         IcacheWaitRetry,
@@ -226,25 +225,36 @@ class DefaultFetch
     /** Processes cache completion event. */
     void processCacheCompletion(PacketPtr pkt);
 
-    /** Begins the drain of the fetch stage. */
-    bool drain();
+    /** Resume after a drain. */
+    void drainResume();
 
-    /** Resumes execution after a drain. */
-    void resume();
+    /** Perform sanity checks after a drain. */
+    void drainSanityCheck() const;
 
-    /** Tells fetch stage to prepare to be switched out. */
-    void switchOut();
+    /** Has the stage drained? */
+    bool isDrained() const;
 
     /** Takes over from another CPU's thread. */
     void takeOverFrom();
 
-    /** Checks if the fetch stage is switched out. */
-    bool isSwitchedOut() { return switchedOut; }
+    /**
+     * Stall the fetch stage after reaching a safe drain point.
+     *
+     * The CPU uses this method to stop fetching instructions from a
+     * thread that has been drained. The drain stall is different from
+     * all other stalls in that it is signaled instantly from the
+     * commit stage (without the normal communication delay) when it
+     * has reached a safe point to drain from.
+     */
+    void drainStall(ThreadID tid);
 
     /** Tells fetch to wake up from a quiesce instruction. */
     void wakeFromQuiesce();
 
   private:
+    /** Reset this pipeline stage */
+    void resetStage();
+
     /** Changes the status of this stage to active, and indicates this
      * to the CPU.
      */
@@ -423,6 +433,7 @@ class DefaultFetch
         bool rename;
         bool iew;
         bool commit;
+        bool drain;
     };
 
     /** Tracks which stages are telling fetch to stall. */
@@ -490,12 +501,6 @@ class DefaultFetch
      */
     bool interruptPending;
 
-    /** Is there a drain pending. */
-    bool drainPending;
-
-    /** Records if fetch is switched out. */
-    bool switchedOut;
-
     /** Set to true if a pipelined I-cache request should be issued. */
     bool issuePipelinedIfetch[Impl::MaxThreads];
 
index 87d2bc593cfcbada84e3ec3a958b41e239123df8..f531203d95a4c4e41fef1f20004eb6c97c90daef 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2011 ARM Limited
+ * Copyright (c) 2010-2012 ARM Limited
  * All rights reserved.
  *
  * The license below extends only to copyright in the software and shall
@@ -58,6 +58,7 @@
 #include "cpu/o3/fetch.hh"
 #include "cpu/exetrace.hh"
 #include "debug/Activity.hh"
+#include "debug/Drain.hh"
 #include "debug/Fetch.hh"
 #include "mem/packet.hh"
 #include "params/DerivO3CPU.hh"
@@ -73,20 +74,15 @@ template<class Impl>
 DefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, DerivO3CPUParams *params)
     : cpu(_cpu),
       branchPred(params),
-      numInst(0),
       decodeToFetchDelay(params->decodeToFetchDelay),
       renameToFetchDelay(params->renameToFetchDelay),
       iewToFetchDelay(params->iewToFetchDelay),
       commitToFetchDelay(params->commitToFetchDelay),
       fetchWidth(params->fetchWidth),
-      cacheBlocked(false),
       retryPkt(NULL),
       retryTid(InvalidThreadID),
       numThreads(params->numThreads),
       numFetchingThreads(params->smtNumFetchingThreads),
-      interruptPending(false),
-      drainPending(false),
-      switchedOut(false),
       finishTranslationEvent(this)
 {
     if (numThreads > Impl::MaxThreads)
@@ -98,9 +94,6 @@ DefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, DerivO3CPUParams *params)
              "\tincrease MaxWidth in src/cpu/o3/impl.hh\n",
              fetchWidth, static_cast<int>(Impl::MaxWidth));
 
-    // Set fetch stage's status to inactive.
-    _status = Inactive;
-
     std::string policy = params->smtFetchPolicy;
 
     // Convert string to lowercase
@@ -304,34 +297,52 @@ template<class Impl>
 void
 DefaultFetch<Impl>::startupStage()
 {
+    assert(priorityList.empty());
+    resetStage();
+
+    // Fetch needs to start fetching instructions at the very beginning,
+    // so it must start up in active state.
+    switchToActive();
+}
+
+template<class Impl>
+void
+DefaultFetch<Impl>::resetStage()
+{
+    numInst = 0;
+    interruptPending = false;
+    cacheBlocked = false;
+
+    priorityList.clear();
+
     // Setup PC and nextPC with initial state.
     for (ThreadID tid = 0; tid < numThreads; tid++) {
+        fetchStatus[tid] = Running;
         pc[tid] = cpu->pcState(tid);
         fetchOffset[tid] = 0;
         macroop[tid] = NULL;
-        delayedCommit[tid] = false;
-    }
-
-    for (ThreadID tid = 0; tid < numThreads; tid++) {
-
-        fetchStatus[tid] = Running;
-
-        priorityList.push_back(tid);
 
+        delayedCommit[tid] = false;
         memReq[tid] = NULL;
 
         stalls[tid].decode = false;
         stalls[tid].rename = false;
         stalls[tid].iew = false;
         stalls[tid].commit = false;
+        stalls[tid].drain = false;
+
+        priorityList.push_back(tid);
     }
 
-    // Schedule fetch to get the correct PC from the CPU
-    // scheduleFetchStartupEvent(1);
+    wroteToTimeBuffer = false;
+    _status = Inactive;
 
-    // Fetch needs to start fetching instructions at the very beginning,
-    // so it must start up in active state.
-    switchToActive();
+    // this CPU could still be unconnected if we are restoring from a
+    // checkpoint and this CPU is to be switched in, thus we can only
+    // do this here if the instruction port is actually connected, if
+    // not we have to do it as part of takeOverFrom.
+    if (cpu->getInstPort().isConnected())
+        setIcache();
 }
 
 template<class Impl>
@@ -362,12 +373,12 @@ DefaultFetch<Impl>::processCacheCompletion(PacketPtr pkt)
     ThreadID tid = pkt->req->threadId();
 
     DPRINTF(Fetch, "[tid:%u] Waking up from cache miss.\n", tid);
+    assert(!cpu->switchedOut());
 
     // Only change the status if it's still waiting on the icache access
     // to return.
     if (fetchStatus[tid] != IcacheWaitResponse ||
-        pkt->req != memReq[tid] ||
-        isSwitchedOut()) {
+        pkt->req != memReq[tid]) {
         ++fetchIcacheSquashes;
         delete pkt->req;
         delete pkt;
@@ -377,16 +388,14 @@ DefaultFetch<Impl>::processCacheCompletion(PacketPtr pkt)
     memcpy(cacheData[tid], pkt->getPtr<uint8_t>(), cacheBlkSize);
     cacheDataValid[tid] = true;
 
-    if (!drainPending) {
-        // Wake up the CPU (if it went to sleep and was waiting on
-        // this completion event).
-        cpu->wakeCPU();
+    // Wake up the CPU (if it went to sleep and was waiting on
+    // this completion event).
+    cpu->wakeCPU();
 
-        DPRINTF(Activity, "[tid:%u] Activating fetch due to cache completion\n",
-                tid);
+    DPRINTF(Activity, "[tid:%u] Activating fetch due to cache completion\n",
+            tid);
 
-        switchToActive();
-    }
+    switchToActive();
 
     // Only switch to IcacheAccessComplete if we're not stalled as well.
     if (checkStall(tid)) {
@@ -402,56 +411,78 @@ DefaultFetch<Impl>::processCacheCompletion(PacketPtr pkt)
 }
 
 template <class Impl>
-bool
-DefaultFetch<Impl>::drain()
+void
+DefaultFetch<Impl>::drainResume()
 {
-    // Fetch is ready to drain at any time.
-    cpu->signalDrained();
-    drainPending = true;
-    return true;
+    for (ThreadID i = 0; i < Impl::MaxThreads; ++i)
+        stalls[i].drain = false;
 }
 
 template <class Impl>
 void
-DefaultFetch<Impl>::resume()
+DefaultFetch<Impl>::drainSanityCheck() const
 {
-    drainPending = false;
+    assert(isDrained());
+    assert(retryPkt == NULL);
+    assert(retryTid == InvalidThreadID);
+    assert(cacheBlocked == false);
+    assert(interruptPending == false);
+
+    for (ThreadID i = 0; i < numThreads; ++i) {
+        assert(!memReq[i]);
+        assert(!stalls[i].decode);
+        assert(!stalls[i].rename);
+        assert(!stalls[i].iew);
+        assert(!stalls[i].commit);
+        assert(fetchStatus[i] == Idle || stalls[i].drain);
+    }
+
+    branchPred.drainSanityCheck();
 }
 
 template <class Impl>
-void
-DefaultFetch<Impl>::switchOut()
+bool
+DefaultFetch<Impl>::isDrained() const
 {
-    switchedOut = true;
-    // Branch predictor needs to have its state cleared.
-    branchPred.switchOut();
+    /* Make sure that threads are either idle of that the commit stage
+     * has signaled that draining has completed by setting the drain
+     * stall flag. This effectively forces the pipeline to be disabled
+     * until the whole system is drained (simulation may continue to
+     * drain other components).
+     */
+    for (ThreadID i = 0; i < numThreads; ++i) {
+        if (!(fetchStatus[i] == Idle ||
+              (fetchStatus[i] == Blocked && stalls[i].drain)))
+            return false;
+    }
+
+    /* The pipeline might start up again in the middle of the drain
+     * cycle if the finish translation event is scheduled, so make
+     * sure that's not the case.
+     */
+    return !finishTranslationEvent.scheduled();
 }
 
 template <class Impl>
 void
 DefaultFetch<Impl>::takeOverFrom()
 {
-    // the instruction port is now connected so we can get the block
-    // size
-    setIcache();
+    assert(cpu->getInstPort().isConnected());
+    resetStage();
 
-    // Reset all state
-    for (ThreadID i = 0; i < Impl::MaxThreads; ++i) {
-        stalls[i].decode = 0;
-        stalls[i].rename = 0;
-        stalls[i].iew = 0;
-        stalls[i].commit = 0;
-        pc[i] = cpu->pcState(i);
-        fetchStatus[i] = Running;
-    }
-    numInst = 0;
-    wroteToTimeBuffer = false;
-    _status = Inactive;
-    switchedOut = false;
-    interruptPending = false;
     branchPred.takeOverFrom();
 }
 
+template <class Impl>
+void
+DefaultFetch<Impl>::drainStall(ThreadID tid)
+{
+    assert(cpu->isDraining());
+    assert(!stalls[tid].drain);
+    DPRINTF(Drain, "%i: Thread drained.\n", tid);
+    stalls[tid].drain = true;
+}
+
 template <class Impl>
 void
 DefaultFetch<Impl>::wakeFromQuiesce()
@@ -536,16 +567,14 @@ DefaultFetch<Impl>::fetchCacheLine(Addr vaddr, ThreadID tid, Addr pc)
 {
     Fault fault = NoFault;
 
+    assert(!cpu->switchedOut());
+
     // @todo: not sure if these should block translation.
     //AlphaDep
     if (cacheBlocked) {
         DPRINTF(Fetch, "[tid:%i] Can't fetch cache line, cache blocked\n",
                 tid);
         return false;
-    } else if (isSwitchedOut()) {
-        DPRINTF(Fetch, "[tid:%i] Can't fetch cache line, switched out\n",
-                tid);
-        return false;
     } else if (checkInterrupt(pc) && !delayedCommit[tid]) {
         // Hold off fetch from getting new instructions when:
         // Cache is blocked, or
@@ -586,11 +615,13 @@ DefaultFetch<Impl>::finishTranslation(Fault fault, RequestPtr mem_req)
     ThreadID tid = mem_req->threadId();
     Addr block_PC = mem_req->getVaddr();
 
+    assert(!cpu->switchedOut());
+
     // Wake up CPU if it was idle
     cpu->wakeCPU();
 
     if (fetchStatus[tid] != ItlbWait || mem_req != memReq[tid] ||
-        mem_req->getVaddr() != memReq[tid]->getVaddr() || isSwitchedOut()) {
+        mem_req->getVaddr() != memReq[tid]->getVaddr()) {
         DPRINTF(Fetch, "[tid:%i] Ignoring itlb completed after squash\n",
                 tid);
         ++fetchTlbSquashes;
@@ -757,6 +788,10 @@ DefaultFetch<Impl>::checkStall(ThreadID tid) const
     if (cpu->contextSwitch) {
         DPRINTF(Fetch,"[tid:%i]: Stalling for a context switch.\n",tid);
         ret_val = true;
+    } else if (stalls[tid].drain) {
+        assert(cpu->isDraining());
+        DPRINTF(Fetch,"[tid:%i]: Drain stall detected.\n",tid);
+        ret_val = true;
     } else if (stalls[tid].decode) {
         DPRINTF(Fetch,"[tid:%i]: Stall from Decode stage detected.\n",tid);
         ret_val = true;
@@ -1097,7 +1132,9 @@ DefaultFetch<Impl>::fetch(bool &status_change)
     //////////////////////////////////////////
     ThreadID tid = getFetchingThread(fetchPolicy);
 
-    if (tid == InvalidThreadID || drainPending) {
+    assert(!cpu->switchedOut());
+
+    if (tid == InvalidThreadID) {
         // Breaks looping condition in tick()
         threadFetched = numFetchingThreads;
 
@@ -1147,8 +1184,7 @@ DefaultFetch<Impl>::fetch(bool &status_change)
             else
                 ++fetchMiscStallCycles;
             return;
-        } else if ((checkInterrupt(thisPC.instAddr()) && !delayedCommit[tid])
-                   || isSwitchedOut()) {
+        } else if ((checkInterrupt(thisPC.instAddr()) && !delayedCommit[tid])) {
             // Stall CPU if an interrupt is posted and we're not issuing
             // an delayed commit micro-op currently (delayed commit instructions
             // are not interruptable by interrupts, only faults)
@@ -1566,7 +1602,7 @@ DefaultFetch<Impl>::profileStall(ThreadID tid) {
 
     // @todo Per-thread stats
 
-    if (drainPending) {
+    if (stalls[tid].drain) {
         ++fetchPendingDrainCycles;
         DPRINTF(Fetch, "Fetch is waiting for a drain!\n");
     } else if (activeThreads->empty()) {
index ecbd79ee7025e0d4e3af3e58314c3468d031e222..c0db5cbfc3fac1514b0645dd82fc3870aac739fc 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2012 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) 2006 The Regents of The University of Michigan
  * All rights reserved.
  *
@@ -247,17 +259,11 @@ FUPool::dump()
 }
 
 void
-FUPool::switchOut()
+FUPool::drainSanityCheck() const
 {
-}
-
-void
-FUPool::takeOver()
-{
-    for (int i = 0; i < numFU; i++) {
-        unitBusy[i] = false;
-    }
-    unitsToBeFreed.clear();
+    assert(unitsToBeFreed.empty());
+    for (int i = 0; i < numFU; i++)
+        assert(!unitBusy[i]);
 }
 
 //
index fbdc1d89a392b283cde1cbaf9423cf995d3721ad..85912af3a08a806f33875601c54a1dd37ec307f6 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2012 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) 2006 The Regents of The University of Michigan
  * All rights reserved.
  *
@@ -157,11 +169,11 @@ class FUPool : public SimObject
         return maxIssueLatencies[capability];
     }
 
-    /** Switches out functional unit pool. */
-    void switchOut();
+    /** Perform sanity checks after a drain. */
+    void drainSanityCheck() const;
 
     /** Takes over from another CPU's thread. */
-    void takeOver();
+    void takeOverFrom() {};
 };
 
 #endif // __CPU_O3_FU_POOL_HH__
index dcc8ecf82d6d673a48a84c828d4e618fb0c8601c..5adf32752c3febf249e08fb5f26aad69ff7148bd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 ARM Limited
+ * Copyright (c) 2010-2012 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -150,21 +150,15 @@ class DefaultIEW
     /** Sets pointer to the scoreboard. */
     void setScoreboard(Scoreboard *sb_ptr);
 
-    /** Drains IEW stage. */
-    bool drain();
+    /** Perform sanity checks after a drain. */
+    void drainSanityCheck() const;
 
-    /** Resumes execution after a drain. */
-    void resume();
-
-    /** Completes switch out of IEW stage. */
-    void switchOut();
+    /** Has the stage drained? */
+    bool isDrained() const;
 
     /** Takes over from another CPU's thread. */
     void takeOverFrom();
 
-    /** Returns if IEW is switched out. */
-    bool isSwitchedOut() { return switchedOut; }
-
     /** Squashes instructions in IEW for a specific thread. */
     void squash(ThreadID tid);
 
@@ -470,9 +464,6 @@ class DefaultIEW
     /** Maximum size of the skid buffer. */
     unsigned skidBufferMax;
 
-    /** Is this stage switched out. */
-    bool switchedOut;
-
     /** Stat for total number of idle cycles. */
     Stats::Scalar iewIdleCycles;
     /** Stat for total number of squashing cycles. */
index e25c8829bbcf67704ec951f1c478090b829a7f57..4b4f66a1fd8fc284e57221228354c2a8fac7447a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2011 ARM Limited
+ * Copyright (c) 2010-2012 ARM Limited
  * All rights reserved.
  *
  * The license below extends only to copyright in the software and shall
@@ -54,6 +54,7 @@
 #include "cpu/timebuf.hh"
 #include "debug/Activity.hh"
 #include "debug/Decode.hh"
+#include "debug/Drain.hh"
 #include "debug/IEW.hh"
 #include "params/DerivO3CPU.hh"
 
@@ -73,8 +74,7 @@ DefaultIEW<Impl>::DefaultIEW(O3CPU *_cpu, DerivO3CPUParams *params)
       issueWidth(params->issueWidth),
       wbOutstanding(0),
       wbWidth(params->wbWidth),
-      numThreads(params->numThreads),
-      switchedOut(false)
+      numThreads(params->numThreads)
 {
     _status = Active;
     exeStatus = Running;
@@ -360,38 +360,33 @@ DefaultIEW<Impl>::setScoreboard(Scoreboard *sb_ptr)
 
 template <class Impl>
 bool
-DefaultIEW<Impl>::drain()
+DefaultIEW<Impl>::isDrained() const
 {
-    // IEW is ready to drain at any time.
-    cpu->signalDrained();
-    return true;
-}
+    bool drained(ldstQueue.isDrained());
 
-template <class Impl>
-void
-DefaultIEW<Impl>::resume()
-{
+    for (ThreadID tid = 0; tid < numThreads; tid++) {
+        if (!insts[tid].empty()) {
+            DPRINTF(Drain, "%i: Insts not empty.\n", tid);
+            drained = false;
+        }
+        if (!skidBuffer[tid].empty()) {
+            DPRINTF(Drain, "%i: Skid buffer not empty.\n", tid);
+            drained = false;
+        }
+    }
+
+    return drained;
 }
 
 template <class Impl>
 void
-DefaultIEW<Impl>::switchOut()
+DefaultIEW<Impl>::drainSanityCheck() const
 {
-    // Clear any state.
-    switchedOut = true;
-    assert(insts[0].empty());
-    assert(skidBuffer[0].empty());
+    assert(isDrained());
 
-    instQueue.switchOut();
-    ldstQueue.switchOut();
-    fuPool->switchOut();
-
-    for (ThreadID tid = 0; tid < numThreads; tid++) {
-        while (!insts[tid].empty())
-            insts[tid].pop();
-        while (!skidBuffer[tid].empty())
-            skidBuffer[tid].pop();
-    }
+    instQueue.drainSanityCheck();
+    ldstQueue.drainSanityCheck();
+    fuPool->drainSanityCheck();
 }
 
 template <class Impl>
@@ -402,11 +397,10 @@ DefaultIEW<Impl>::takeOverFrom()
     _status = Active;
     exeStatus = Running;
     wbStatus = Idle;
-    switchedOut = false;
 
     instQueue.takeOverFrom();
     ldstQueue.takeOverFrom();
-    fuPool->takeOver();
+    fuPool->takeOverFrom();
 
     startupStage();
     cpu->activityThisCycle();
index 42a244c0afbe0baf7a9308325d46b37b60033904..15190970dad214500969bf76ea6985e14a47433e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 ARM Limited
+ * Copyright (c) 2011-2012 ARM Limited
  * All rights reserved.
  *
  * The license below extends only to copyright in the software and shall
@@ -144,15 +144,12 @@ class InstructionQueue
     /** Sets the global time buffer. */
     void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr);
 
-    /** Switches out the instruction queue. */
-    void switchOut();
+    /** Perform sanity checks after a drain. */
+    void drainSanityCheck() const;
 
     /** Takes over execution from another CPU's thread. */
     void takeOverFrom();
 
-    /** Returns if the IQ is switched out. */
-    bool isSwitchedOut() { return switchedOut; }
-
     /** Number of entries needed for given amount of threads. */
     int entryAmount(ThreadID num_threads);
 
@@ -428,9 +425,6 @@ class InstructionQueue
      */
     Cycles commitToIEWDelay;
 
-    /** Is the IQ switched out. */
-    bool switchedOut;
-
     /** The sequence number of the squashed instruction. */
     InstSeqNum squashedSeqNum[Impl::MaxThreads];
 
index 785f86676ae6f41bfdbc7768d322ca6508fceca5..3e3325beb529aa4ed154c35ab684efe6ab3ec1b6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 ARM Limited
+ * Copyright (c) 2011-2012 ARM Limited
  * All rights reserved.
  *
  * The license below extends only to copyright in the software and shall
@@ -93,8 +93,6 @@ InstructionQueue<Impl>::InstructionQueue(O3CPU *cpu_ptr, IEW *iew_ptr,
 {
     assert(fuPool);
 
-    switchedOut = false;
-
     numThreads = params->numThreads;
 
     // Set the number of physical registers as the number of int + float
@@ -439,29 +437,19 @@ InstructionQueue<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
 
 template <class Impl>
 void
-InstructionQueue<Impl>::switchOut()
+InstructionQueue<Impl>::drainSanityCheck() const
 {
-/*
-    if (!instList[0].empty() || (numEntries != freeEntries) ||
-        !readyInsts[0].empty() || !nonSpecInsts.empty() || !listOrder.empty()) {
-        dumpInsts();
-//        assert(0);
-    }
-*/
-    resetState();
-    dependGraph.reset();
-    instsToExecute.clear();
-    switchedOut = true;
-    for (ThreadID tid = 0; tid < numThreads; ++tid) {
-        memDepUnit[tid].switchOut();
-    }
+    assert(dependGraph.empty());
+    assert(instsToExecute.empty());
+    for (ThreadID tid = 0; tid < numThreads; ++tid)
+        memDepUnit[tid].drainSanityCheck();
 }
 
 template <class Impl>
 void
 InstructionQueue<Impl>::takeOverFrom()
 {
-    switchedOut = false;
+    resetState();
 }
 
 template <class Impl>
@@ -716,14 +704,9 @@ void
 InstructionQueue<Impl>::processFUCompletion(DynInstPtr &inst, int fu_idx)
 {
     DPRINTF(IQ, "Processing FU completion [sn:%lli]\n", inst->seqNum);
+    assert(!cpu->switchedOut());
     // The CPU could have been sleeping until this op completed (*extremely*
     // long latency op).  Wake it if it was.  This may be overkill.
-    if (isSwitchedOut()) {
-        DPRINTF(IQ, "FU completion not processed, IQ is switched out [sn:%lli]\n",
-                inst->seqNum);
-        return;
-    }
-
     iewStage->wakeCPU();
 
     if (fu_idx > -1)
index 7caee86f6ffe8168e84ce2fb4d39dfe1eb5decd5..6857a6aca5bf39a2c7af3b4e960b2c571c34d005 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 ARM Limited
+ * Copyright (c) 2011-2012 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -79,8 +79,11 @@ class LSQ {
 
     /** Sets the pointer to the list of active threads. */
     void setActiveThreads(std::list<ThreadID> *at_ptr);
-    /** Switches out the LSQ. */
-    void switchOut();
+
+    /** Perform sanity checks after a drain. */
+    void drainSanityCheck() const;
+    /** Has the LSQ drained? */
+    bool isDrained() const;
     /** Takes over execution from another CPU's thread. */
     void takeOverFrom();
 
@@ -211,6 +214,13 @@ class LSQ {
      */
     bool isFull(ThreadID tid);
 
+    /** Returns if the LSQ is empty (both LQ and SQ are empty). */
+    bool isEmpty() const;
+    /** Returns if all of the LQs are empty. */
+    bool lqEmpty() const;
+    /** Returns if all of the SQs are empty. */
+    bool sqEmpty() const;
+
     /** Returns if any of the LQs are full. */
     bool lqFull();
     /** Returns if the LQ of a given thread is full. */
@@ -254,7 +264,7 @@ class LSQ {
     { return thread[tid].willWB(); }
 
     /** Returns if the cache is currently blocked. */
-    bool cacheBlocked()
+    bool cacheBlocked() const
     { return retryTid != InvalidThreadID; }
 
     /** Sets the retry thread id, indicating that one of the LSQUnits
index 7051c9f7c089c993827552e50015a6506a957644..c796d7078fbc83a8f3aa75e13a6d0230f0ed47c7 100644 (file)
@@ -45,6 +45,7 @@
 #include <string>
 
 #include "cpu/o3/lsq.hh"
+#include "debug/Drain.hh"
 #include "debug/Fetch.hh"
 #include "debug/LSQ.hh"
 #include "debug/Writeback.hh"
@@ -143,11 +144,36 @@ LSQ<Impl>::setActiveThreads(list<ThreadID> *at_ptr)
 
 template <class Impl>
 void
-LSQ<Impl>::switchOut()
+LSQ<Impl>::drainSanityCheck() const
 {
-    for (ThreadID tid = 0; tid < numThreads; tid++) {
-        thread[tid].switchOut();
+    assert(isDrained());
+
+    for (ThreadID tid = 0; tid < numThreads; tid++)
+        thread[tid].drainSanityCheck();
+}
+
+template <class Impl>
+bool
+LSQ<Impl>::isDrained() const
+{
+    bool drained(true);
+
+    if (!lqEmpty()) {
+        DPRINTF(Drain, "Not drained, LQ not empty.\n");
+        drained = false;
+    }
+
+    if (!sqEmpty()) {
+        DPRINTF(Drain, "Not drained, SQ not empty.\n");
+        drained = false;
+    }
+
+    if (retryTid != InvalidThreadID) {
+        DPRINTF(Drain, "Not drained, the LSQ has blocked the caches.\n");
+        drained = false;
     }
+
+    return drained;
 }
 
 template <class Impl>
@@ -456,6 +482,47 @@ LSQ<Impl>::isFull(ThreadID tid)
         return thread[tid].lqFull() || thread[tid].sqFull();
 }
 
+template<class Impl>
+bool
+LSQ<Impl>::isEmpty() const
+{
+    return lqEmpty() && sqEmpty();
+}
+
+template<class Impl>
+bool
+LSQ<Impl>::lqEmpty() const
+{
+    list<ThreadID>::const_iterator threads = activeThreads->begin();
+    list<ThreadID>::const_iterator end = activeThreads->end();
+
+    while (threads != end) {
+        ThreadID tid = *threads++;
+
+        if (!thread[tid].lqEmpty())
+            return false;
+    }
+
+    return true;
+}
+
+template<class Impl>
+bool
+LSQ<Impl>::sqEmpty() const
+{
+    list<ThreadID>::const_iterator threads = activeThreads->begin();
+    list<ThreadID>::const_iterator end = activeThreads->end();
+
+    while (threads != end) {
+        ThreadID tid = *threads++;
+
+        if (!thread[tid].sqEmpty())
+            return false;
+    }
+
+    return true;
+}
+
 template<class Impl>
 bool
 LSQ<Impl>::lqFull()
index 2c79931e29335b74f0707ddd9d0ec1ac490ca612..5b8e02fc6776a84ddea07c7c47174f38a20d2062 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2012 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.
  *
@@ -91,15 +103,12 @@ class LSQUnit {
     /** Sets the pointer to the dcache port. */
     void setDcachePort(MasterPort *dcache_port);
 
-    /** Switches out LSQ unit. */
-    void switchOut();
+    /** Perform sanity checks after a drain. */
+    void drainSanityCheck() const;
 
     /** Takes over from another CPU's thread. */
     void takeOverFrom();
 
-    /** Returns if the LSQ is switched out. */
-    bool isSwitchedOut() { return switchedOut; }
-
     /** Ticks the LSQ unit, which in this case only resets the number of
      * used cache ports.
      * @todo: Move the number of used ports up to the LSQ level so it can
@@ -201,12 +210,21 @@ class LSQUnit {
     /** Returns if either the LQ or SQ is full. */
     bool isFull() { return lqFull() || sqFull(); }
 
+    /** Returns if both the LQ and SQ are empty. */
+    bool isEmpty() const { return lqEmpty() && sqEmpty(); }
+
     /** Returns if the LQ is full. */
     bool lqFull() { return loads >= (LQEntries - 1); }
 
     /** Returns if the SQ is full. */
     bool sqFull() { return stores >= (SQEntries - 1); }
 
+    /** Returns if the LQ is empty. */
+    bool lqEmpty() const { return loads == 0; }
+
+    /** Returns if the SQ is empty. */
+    bool sqEmpty() const { return stores == 0; }
+
     /** Returns the number of instructions in the LSQ. */
     unsigned getCount() { return loads + stores; }
 
@@ -225,6 +243,9 @@ class LSQUnit {
     void recvRetry();
 
   private:
+    /** Reset the LSQ state */
+    void resetState();
+
     /** Writes back the instruction, sending it to IEW. */
     void writeback(DynInstPtr &inst, PacketPtr pkt);
 
@@ -420,9 +441,6 @@ class LSQUnit {
     /** The number of used cache ports in this cycle. */
     int usedPorts;
 
-    /** Is the LSQ switched out. */
-    bool switchedOut;
-
     //list<InstSeqNum> mshrSeqNums;
 
     /** Address Mask for a cache block (e.g. ~(cache_block_size-1)) */
index d640f94a369993f6748444f422323e4ec12020f3..a4cb567673adacd7d320d68e72b89408b0a15fce 100644 (file)
@@ -66,9 +66,9 @@ template<class Impl>
 void
 LSQUnit<Impl>::WritebackEvent::process()
 {
-    if (!lsqPtr->isSwitchedOut()) {
-        lsqPtr->writeback(inst, pkt);
-    }
+    assert(!lsqPtr->cpu->switchedOut());
+
+    lsqPtr->writeback(inst, pkt);
 
     if (pkt->senderState)
         delete pkt->senderState;
@@ -102,7 +102,8 @@ LSQUnit<Impl>::completeDataAccess(PacketPtr pkt)
         return;
     }
 
-    if (isSwitchedOut() || inst->isSquashed()) {
+    assert(!cpu->switchedOut());
+    if (inst->isSquashed()) {
         iewStage->decrWb(inst->seqNum);
     } else {
         if (!state->noWB) {
@@ -147,10 +148,6 @@ LSQUnit<Impl>::init(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params,
 
     DPRINTF(LSQUnit, "Creating LSQUnit%i object.\n",id);
 
-    switchedOut = false;
-
-    cacheBlockMask = 0;
-
     lsq = lsq_ptr;
 
     lsqID = id;
@@ -164,19 +161,35 @@ LSQUnit<Impl>::init(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params,
 
     depCheckShift = params->LSQDepCheckShift;
     checkLoads = params->LSQCheckLoads;
+    cachePorts = params->cachePorts;
+    needsTSO = params->needsTSO;
+
+    resetState();
+}
+
+
+template<class Impl>
+void
+LSQUnit<Impl>::resetState()
+{
+    loads = stores = storesToWB = 0;
 
     loadHead = loadTail = 0;
 
     storeHead = storeWBIdx = storeTail = 0;
 
     usedPorts = 0;
-    cachePorts = params->cachePorts;
 
     retryPkt = NULL;
     memDepViolator = NULL;
 
     blockedLoadSeqNum = 0;
-    needsTSO = params->needsTSO;
+
+    stalled = false;
+    isLoadBlocked = false;
+    loadBlockedHandled = false;
+
+    cacheBlockMask = 0;
 }
 
 template<class Impl>
@@ -258,40 +271,20 @@ LSQUnit<Impl>::clearSQ()
 
 template<class Impl>
 void
-LSQUnit<Impl>::switchOut()
+LSQUnit<Impl>::drainSanityCheck() const
 {
-    switchedOut = true;
-    for (int i = 0; i < loadQueue.size(); ++i) {
+    for (int i = 0; i < loadQueue.size(); ++i)
         assert(!loadQueue[i]);
-        loadQueue[i] = NULL;
-    }
 
     assert(storesToWB == 0);
+    assert(!retryPkt);
 }
 
 template<class Impl>
 void
 LSQUnit<Impl>::takeOverFrom()
 {
-    switchedOut = false;
-    loads = stores = storesToWB = 0;
-
-    loadHead = loadTail = 0;
-
-    storeHead = storeWBIdx = storeTail = 0;
-
-    usedPorts = 0;
-
-    memDepViolator = NULL;
-
-    blockedLoadSeqNum = 0;
-
-    stalled = false;
-    isLoadBlocked = false;
-    loadBlockedHandled = false;
-
-    // Just incase the memory system changed out from under us
-    cacheBlockMask = 0;
+    resetState();
 }
 
 template<class Impl>
index ce5a62ef8b4a4627e87a1265314cf374788c2c10..989d36ea1ae4493a5ece74c63bdfa9579296cd1c 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2012 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.
  *
@@ -92,8 +104,8 @@ class MemDepUnit
     /** Registers statistics. */
     void regStats();
 
-    /** Switches out the memory dependence predictor. */
-    void switchOut();
+    /** Perform sanity checks after a drain. */
+    void drainSanityCheck() const;
 
     /** Takes over from another CPU's thread. */
     void takeOverFrom();
index d30dcbd3d4f17e974cd4def6d1786fabea12a24a..7fbea0216b9ffc79d4c1dfd08752f74469423d0b 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2012 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.
  *
@@ -114,17 +126,14 @@ MemDepUnit<MemDepPred, Impl>::regStats()
 
 template <class MemDepPred, class Impl>
 void
-MemDepUnit<MemDepPred, Impl>::switchOut()
+MemDepUnit<MemDepPred, Impl>::drainSanityCheck() const
 {
-    assert(instList[0].empty());
     assert(instsToReplay.empty());
     assert(memDepHash.empty());
-    // Clear any state.
-    for (int i = 0; i < Impl::MaxThreads; ++i) {
-        instList[i].clear();
-    }
-    instsToReplay.clear();
-    memDepHash.clear();
+    for (int i = 0; i < Impl::MaxThreads; ++i)
+        assert(instList[i].empty());
+    assert(instsToReplay.empty());
+    assert(memDepHash.empty());
 }
 
 template <class MemDepPred, class Impl>
index 0aa238c068c5a2f82048c040f0dcb00b3e192c8a..606c3365e321a35243b1cfd4373763e8df0aaa08 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2012 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.
  *
@@ -157,14 +169,11 @@ class DefaultRename
     /** Sets pointer to the scoreboard. */
     void setScoreboard(Scoreboard *_scoreboard);
 
-    /** Drains the rename stage. */
-    bool drain();
+    /** Perform sanity checks after a drain. */
+    void drainSanityCheck() const;
 
-    /** Resumes execution after a drain. */
-    void resume() { }
-
-    /** Switches out the rename stage. */
-    void switchOut();
+    /** Has the stage drained? */
+    bool isDrained() const;
 
     /** Takes over from another CPU's thread. */
     void takeOverFrom();
@@ -181,6 +190,9 @@ class DefaultRename
     void dumpHistory();
 
   private:
+    /** Reset this pipeline stage */
+    void resetStage();
+
     /** Determines what to do based on rename's current status.
      * @param status_change rename() sets this variable if there was a status
      * change (ie switching from blocking to unblocking).
index 4996cfcad951bf18fc02be84edab75219a9bb070..15a4ebc1345ee2714ee790a9361fb775e13d1f61 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 ARM Limited
+ * Copyright (c) 2010-2012 ARM Limited
  * All rights reserved.
  *
  * The license below extends only to copyright in the software and shall
@@ -61,31 +61,9 @@ DefaultRename<Impl>::DefaultRename(O3CPU *_cpu, DerivO3CPUParams *params)
       commitToRenameDelay(params->commitToRenameDelay),
       renameWidth(params->renameWidth),
       commitWidth(params->commitWidth),
-      resumeSerialize(false),
-      resumeUnblocking(false),
       numThreads(params->numThreads),
       maxPhysicalRegs(params->numPhysIntRegs + params->numPhysFloatRegs)
 {
-    _status = Inactive;
-
-    for (ThreadID tid = 0; tid < numThreads; tid++) {
-        renameStatus[tid] = Idle;
-
-        freeEntries[tid].iqEntries = 0;
-        freeEntries[tid].lsqEntries = 0;
-        freeEntries[tid].robEntries = 0;
-
-        stalls[tid].iew = false;
-        stalls[tid].commit = false;
-        serializeInst[tid] = NULL;
-
-        instsInProgress[tid] = 0;
-
-        emptyROB[tid] = true;
-
-        serializeOnNextInst[tid] = false;
-    }
-
     // @todo: Make into a parameter.
     skidBufferMax = (2 * (decodeToRenameDelay * params->decodeWidth)) + renameWidth;
 }
@@ -230,12 +208,34 @@ template <class Impl>
 void
 DefaultRename<Impl>::startupStage()
 {
+    resetStage();
+}
+
+template <class Impl>
+void
+DefaultRename<Impl>::resetStage()
+{
+    _status = Inactive;
+
+    resumeSerialize = false;
+    resumeUnblocking = false;
+
     // Grab the number of free entries directly from the stages.
     for (ThreadID tid = 0; tid < numThreads; tid++) {
+        renameStatus[tid] = Idle;
+
         freeEntries[tid].iqEntries = iew_ptr->instQueue.numFreeEntries(tid);
         freeEntries[tid].lsqEntries = iew_ptr->ldstQueue.numFreeEntries(tid);
         freeEntries[tid].robEntries = commit_ptr->numROBFreeEntries(tid);
         emptyROB[tid] = true;
+
+        stalls[tid].iew = false;
+        stalls[tid].commit = false;
+        serializeInst[tid] = NULL;
+
+        instsInProgress[tid] = 0;
+
+        serializeOnNextInst[tid] = false;
     }
 }
 
@@ -271,67 +271,34 @@ DefaultRename<Impl>::setScoreboard(Scoreboard *_scoreboard)
 
 template <class Impl>
 bool
-DefaultRename<Impl>::drain()
+DefaultRename<Impl>::isDrained() const
 {
-    // Rename is ready to switch out at any time.
-    cpu->signalDrained();
+    for (ThreadID tid = 0; tid < numThreads; tid++) {
+        if (instsInProgress[tid] != 0 ||
+            !historyBuffer[tid].empty() ||
+            !skidBuffer[tid].empty() ||
+            !insts[tid].empty())
+            return false;
+    }
     return true;
 }
 
 template <class Impl>
 void
-DefaultRename<Impl>::switchOut()
+DefaultRename<Impl>::takeOverFrom()
 {
-    // Clear any state, fix up the rename map.
-    for (ThreadID tid = 0; tid < numThreads; tid++) {
-        typename std::list<RenameHistory>::iterator hb_it =
-            historyBuffer[tid].begin();
-
-        while (!historyBuffer[tid].empty()) {
-            assert(hb_it != historyBuffer[tid].end());
-
-            DPRINTF(Rename, "[tid:%u]: Removing history entry with sequence "
-                    "number %i.\n", tid, (*hb_it).instSeqNum);
-
-            // Tell the rename map to set the architected register to the
-            // previous physical register that it was renamed to.
-            renameMap[tid]->setEntry(hb_it->archReg, hb_it->prevPhysReg);
-
-            // Put the renamed physical register back on the free list.
-            freeList->addReg(hb_it->newPhysReg);
-
-            // Be sure to mark its register as ready if it's a misc register.
-            if (hb_it->newPhysReg >= maxPhysicalRegs) {
-                scoreboard->setReg(hb_it->newPhysReg);
-            }
-
-            historyBuffer[tid].erase(hb_it++);
-        }
-        insts[tid].clear();
-        skidBuffer[tid].clear();
-    }
+    resetStage();
 }
 
 template <class Impl>
 void
-DefaultRename<Impl>::takeOverFrom()
+DefaultRename<Impl>::drainSanityCheck() const
 {
-    _status = Inactive;
-    startupStage();
-
-    // Reset all state prior to taking over from the other CPU.
     for (ThreadID tid = 0; tid < numThreads; tid++) {
-        renameStatus[tid] = Idle;
-
-        stalls[tid].iew = false;
-        stalls[tid].commit = false;
-        serializeInst[tid] = NULL;
-
-        instsInProgress[tid] = 0;
-
-        emptyROB[tid] = true;
-
-        serializeOnNextInst[tid] = false;
+        assert(historyBuffer[tid].empty());
+        assert(insts[tid].empty());
+        assert(skidBuffer[tid].empty());
+        assert(instsInProgress[tid] == 0);
     }
 }
 
index d0b15695416a869428e67e751b7ebc7adfe2fc77..171781ce250d0e0835cbba0083801f18408e3781 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2012 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.
  *
@@ -97,8 +109,8 @@ class ROB
      */
     void setActiveThreads(std::list<ThreadID> *at_ptr);
 
-    /** Switches out the ROB. */
-    void switchOut();
+    /** Perform sanity checks after a drain. */
+    void drainSanityCheck() const;
 
     /** Takes over another CPU's thread. */
     void takeOverFrom();
@@ -185,11 +197,11 @@ class ROB
     { return threadEntries[tid] == numEntries; }
 
     /** Returns if the ROB is empty. */
-    bool isEmpty()
+    bool isEmpty() const
     { return numInstsInROB == 0; }
 
     /** Returns if a specific thread's partition is empty. */
-    bool isEmpty(ThreadID tid)
+    bool isEmpty(ThreadID tid) const
     { return threadEntries[tid] == 0; }
 
     /** Executes the squash, marking squashed instructions. */
@@ -264,6 +276,9 @@ class ROB
     void regStats();
 
   private:
+    /** Reset the ROB state */
+    void resetState();
+
     /** Pointer to the CPU. */
     O3CPU *cpu;
 
index ee4a9e5763eb85e21b9fd4eb7528df2a686c7d4c..5f62ce539003c2bc7a41b8a77963b2e0a14b2b11 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2012 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.
  *
@@ -47,12 +59,6 @@ ROB<Impl>::ROB(O3CPU *_cpu, unsigned _numEntries, unsigned _squashWidth,
       numInstsInROB(0),
       numThreads(_numThreads)
 {
-    for (ThreadID tid = 0; tid  < numThreads; tid++) {
-        squashedSeqNum[tid] = 0;
-        doneSquashing[tid] = true;
-        threadEntries[tid] = 0;
-    }
-
     std::string policy = _smtROBPolicy;
 
     //Convert string to lowercase
@@ -95,10 +101,20 @@ ROB<Impl>::ROB(O3CPU *_cpu, unsigned _numEntries, unsigned _squashWidth,
                     "Partitioned, Threshold}");
     }
 
-    // Set the per-thread iterators to the end of the instruction list.
-    for (ThreadID tid = 0; tid < numThreads; tid++) {
+    resetState();
+}
+
+template <class Impl>
+void
+ROB<Impl>::resetState()
+{
+    for (ThreadID tid = 0; tid  < numThreads; tid++) {
+        doneSquashing[tid] = true;
+        threadEntries[tid] = 0;
         squashIt[tid] = instList[tid].end();
+        squashedSeqNum[tid] = 0;
     }
+    numInstsInROB = 0;
 
     // Initialize the "universal" ROB head & tail point to invalid
     // pointers
@@ -123,28 +139,18 @@ ROB<Impl>::setActiveThreads(list<ThreadID> *at_ptr)
 
 template <class Impl>
 void
-ROB<Impl>::switchOut()
+ROB<Impl>::drainSanityCheck() const
 {
-    for (ThreadID tid = 0; tid < numThreads; tid++) {
-        instList[tid].clear();
-    }
+    for (ThreadID tid = 0; tid  < numThreads; tid++)
+        assert(instList[tid].empty());
+    assert(isEmpty());
 }
 
 template <class Impl>
 void
 ROB<Impl>::takeOverFrom()
 {
-    for (ThreadID tid = 0; tid  < numThreads; tid++) {
-        doneSquashing[tid] = true;
-        threadEntries[tid] = 0;
-        squashIt[tid] = instList[tid].end();
-    }
-    numInstsInROB = 0;
-
-    // Initialize the "universal" ROB head & tail point to invalid
-    // pointers
-    head = instList[0].end();
-    tail = instList[0].end();
+    resetState();
 }
 
 template <class Impl>