cpu: Enable fast-forwarding for MIPS InOrderCPU and O3CPU
authorChristopher Torng <clt67@cornell.edu>
Sun, 2 Mar 2014 05:35:23 +0000 (23:35 -0600)
committerChristopher Torng <clt67@cornell.edu>
Sun, 2 Mar 2014 05:35:23 +0000 (23:35 -0600)
A copyRegs() function is added to MIPS utilities
to copy architectural state from the old CPU to
the new CPU during fast-forwarding. This
addition alone enables fast-forwarding for the
o3 cpu model running MIPS.

The patch also adds takeOverFrom() and
drainResume() functions to the InOrderCPU to
enable it to take over from another CPU. This
change enables fast-forwarding for the inorder
cpu model running MIPS, but not for Alpha.

Committed by: Nilay Vaish <nilay@cs.wisc.edu>

src/arch/mips/utility.cc
src/cpu/inorder/InOrderCPU.py
src/cpu/inorder/cpu.cc
src/cpu/inorder/cpu.hh
src/cpu/inorder/first_stage.cc
src/cpu/inorder/first_stage.hh
src/cpu/inorder/pipeline_stage.hh

index f848197560c11015740e244887878b3dcc69ff65..ff410bad11a876191dba16ec99adc19405ff432a 100644 (file)
@@ -241,7 +241,23 @@ initCPU(ThreadContext *tc, int cpuId)
 void
 copyRegs(ThreadContext *src, ThreadContext *dest)
 {
-    panic("Copy Regs Not Implemented Yet\n");
+    // First loop through the integer registers.
+    for (int i = 0; i < NumIntRegs; i++)
+        dest->setIntRegFlat(i, src->readIntRegFlat(i));
+
+    // Then loop through the floating point registers.
+    for (int i = 0; i < NumFloatRegs; i++)
+        dest->setFloatRegFlat(i, src->readFloatRegFlat(i));
+
+    // Would need to add condition-code regs if implemented
+    assert(NumCCRegs == 0);
+
+    // Copy misc. registers
+    for (int i = 0; i < NumMiscRegs; i++)
+        dest->setMiscRegNoEffect(i, src->readMiscRegNoEffect(i));
+
+    // Copy over the PC State
+    dest->pcState(src->pcState());
 }
 
 void
index 4caf254c4ecb7939392947c844c240c5f4c12666..920b9cdc13bedca9714f9cff2520f40585f74c2c 100644 (file)
@@ -47,6 +47,10 @@ class InOrderCPU(BaseCPU):
     def require_caches(cls):
         return True
 
+    @classmethod
+    def support_take_over(cls):
+        return True
+
     threadModel = Param.ThreadModel('SMT', "Multithreading model (SE-MODE only)")
     
     cachePorts = Param.Unsigned(2, "Cache Ports")
index 5a02f94d9bcc969b8ca0fcf80ab666860596aea8..eecbd033ef0a5e12e678b2e79b9babb69034c21f 100644 (file)
@@ -64,6 +64,7 @@
 #include "cpu/simple_thread.hh"
 #include "cpu/thread_context.hh"
 #include "debug/Activity.hh"
+#include "debug/Drain.hh"
 #include "debug/InOrderCPU.hh"
 #include "debug/InOrderCachePort.hh"
 #include "debug/Interrupt.hh"
@@ -1490,6 +1491,67 @@ InOrderCPU::updateContextSwitchStats()
     instsPerSwitch = 0;
 }
 
+
+void
+InOrderCPU::drainResume()
+{
+    setDrainState(Drainable::Running);
+    if (switchedOut())
+        return;
+
+    DPRINTF(Drain, "Resuming...\n");
+    verifyMemoryMode();
+
+    assert(!tickEvent.scheduled());
+
+    // Activate threads and also signal the resource pool to activate
+    // the thread on all resources.
+    _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);
+            resPool->activateThread(i);
+            _status = Running;
+        }
+    }
+}
+
+void
+InOrderCPU::switchOut()
+{
+    DPRINTF(InOrderCPU, "Switching out\n");
+    BaseCPU::switchOut();
+
+    activityRec.reset();
+
+    _status = SwitchedOut;
+}
+
+void
+InOrderCPU::takeOverFrom(BaseCPU *oldCPU)
+{
+    BaseCPU::takeOverFrom(oldCPU);
+
+    // Call takeOverFrom() on each pipeline stage
+    for (int stNum=0; stNum < NumStages; stNum++) {
+        pipelineStage[stNum]->takeOverFrom();
+    }
+
+    assert(!tickEvent.scheduled());
+
+    // Copy over the current instruction sequence numbers if we are
+    // taking over from another InOrderCPU.
+    InOrderCPU *oldIOCPU = dynamic_cast<InOrderCPU*>(oldCPU);
+    if (oldIOCPU) {
+      for (ThreadID tid = 0; tid < numThreads; tid++)
+        globalSeqNum[tid] = oldIOCPU->globalSeqNum[tid];
+    }
+
+    lastRunningCycle = curCycle();
+    _status = Idle;
+}
+
     
 void
 InOrderCPU::instDone(DynInstPtr inst, ThreadID tid)
index 1183f6fc9ab29876b2b80fd653a132c6978d5504..0104cb95f0ef6839efaad4c0bc765b819e9a0209 100644 (file)
@@ -866,6 +866,15 @@ class InOrderCPU : public BaseCPU
     Stats::Average instsPerCtxtSwitch;    
     Stats::Scalar numCtxtSwitches;
     
+    /** Resumes execution after a drain. */
+    void drainResume();
+
+    /** Switches out this CPU. */
+    virtual void switchOut();
+
+    /** Takes over from another CPU. */
+    virtual void takeOverFrom(BaseCPU *oldCPU);
+
     /** Update Thread , used for statistic purposes*/
     inline void tickThreadStats();
 
index 20fd9169fe204571cf4292ed1a225190c85f685a..f59e894101cdb3610278d4635ed3ae8617b16193 100644 (file)
@@ -277,3 +277,13 @@ FirstStage::roundRobin()
 
     return InvalidThreadID;
 }
+
+void
+FirstStage::takeOverFrom()
+{
+    PipelineStage::takeOverFrom();
+
+    for(ThreadID tid = 0; tid < this->numThreads; tid++) {
+        stageStatus[tid] = Running;
+    }
+}
index 44ffb959954947da27de43fdaf89ad13dbd83fa8..ae8b12102fd3157f72fe1bb1690fbe0ac657a21c 100644 (file)
@@ -88,6 +88,9 @@ class FirstStage : public PipelineStage {
 
     /** Return next thread given Round Robin Policy for Thread Fetching */
     ThreadID roundRobin();
+
+    /** Takes over from another CPU's thread. */
+    void takeOverFrom();
 };
 
 #endif // __CPU_INORDER_FIRST_STAGE_HH__
index 963d96afb539b7f30bce6850a39c31b5914ac740..478561a8e1e1a5181ebd5b6b596f6c5fcc115f25 100644 (file)
@@ -135,7 +135,7 @@ class PipelineStage
     void switchOut();
 
     /** Takes over from another CPU's thread. */
-    void takeOverFrom();
+    virtual void takeOverFrom();
 
     /** Ticks stage, processing all input signals and executing as many
      *  instructions as possible.