From: Christopher Torng Date: Sun, 2 Mar 2014 05:35:23 +0000 (-0600) Subject: cpu: Enable fast-forwarding for MIPS InOrderCPU and O3CPU X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=919baa603d0b835c3202f9968a617a31f9116549;p=gem5.git cpu: Enable fast-forwarding for MIPS InOrderCPU and O3CPU 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 --- diff --git a/src/arch/mips/utility.cc b/src/arch/mips/utility.cc index f84819756..ff410bad1 100644 --- a/src/arch/mips/utility.cc +++ b/src/arch/mips/utility.cc @@ -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 diff --git a/src/cpu/inorder/InOrderCPU.py b/src/cpu/inorder/InOrderCPU.py index 4caf254c4..920b9cdc1 100644 --- a/src/cpu/inorder/InOrderCPU.py +++ b/src/cpu/inorder/InOrderCPU.py @@ -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") diff --git a/src/cpu/inorder/cpu.cc b/src/cpu/inorder/cpu.cc index 5a02f94d9..eecbd033e 100644 --- a/src/cpu/inorder/cpu.cc +++ b/src/cpu/inorder/cpu.cc @@ -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(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) diff --git a/src/cpu/inorder/cpu.hh b/src/cpu/inorder/cpu.hh index 1183f6fc9..0104cb95f 100644 --- a/src/cpu/inorder/cpu.hh +++ b/src/cpu/inorder/cpu.hh @@ -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(); diff --git a/src/cpu/inorder/first_stage.cc b/src/cpu/inorder/first_stage.cc index 20fd9169f..f59e89410 100644 --- a/src/cpu/inorder/first_stage.cc +++ b/src/cpu/inorder/first_stage.cc @@ -277,3 +277,13 @@ FirstStage::roundRobin() return InvalidThreadID; } + +void +FirstStage::takeOverFrom() +{ + PipelineStage::takeOverFrom(); + + for(ThreadID tid = 0; tid < this->numThreads; tid++) { + stageStatus[tid] = Running; + } +} diff --git a/src/cpu/inorder/first_stage.hh b/src/cpu/inorder/first_stage.hh index 44ffb9599..ae8b12102 100644 --- a/src/cpu/inorder/first_stage.hh +++ b/src/cpu/inorder/first_stage.hh @@ -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__ diff --git a/src/cpu/inorder/pipeline_stage.hh b/src/cpu/inorder/pipeline_stage.hh index 963d96afb..478561a8e 100644 --- a/src/cpu/inorder/pipeline_stage.hh +++ b/src/cpu/inorder/pipeline_stage.hh @@ -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.