summaryrefslogtreecommitdiff
path: root/src/cpu/o3/cpu.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/cpu/o3/cpu.cc')
-rw-r--r--src/cpu/o3/cpu.cc255
1 files changed, 155 insertions, 100 deletions
diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc
index 724d88405..cb17581e5 100644
--- a/src/cpu/o3/cpu.cc
+++ b/src/cpu/o3/cpu.cc
@@ -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>