260c260
< drainCount(0),
---
> drainManager(NULL),
586a587,588
> assert(!switchedOut());
> assert(getDrainState() != Drainable::Drained);
621,622c623
< if (_status == SwitchedOut ||
< getDrainState() == Drainable::Drained) {
---
> if (_status == SwitchedOut) {
637a639,640
>
> tryDrain();
660,666d662
< // 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();
<
685a682
> decode.startupStage();
698a696
> assert(!switchedOut());
716a715
> assert(!switchedOut());
754a754,755
> assert(!switchedOut());
>
763a765,770
> // 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;
>
809a817
> assert(!switchedOut());
826a835
> assert(!switchedOut());
1123,1124d1131
< DPRINTF(O3CPU, "Switching out\n");
<
1126c1133,1134
< if (_status == SwitchedOut)
---
> if (switchedOut()) {
> setDrainState(Drainable::Drained);
1127a1136
> }
1129,1133c1138,1146
< drainCount = 0;
< fetch.drain();
< decode.drain();
< rename.drain();
< iew.drain();
---
> DPRINTF(Drain, "Draining...\n");
> setDrainState(Drainable::Draining);
>
> // 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.
1138,1142c1151
< 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()) {
1151a1161,1178
> 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();
1156a1184,1200
> 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>
1158c1202
< FullO3CPU<Impl>::drainResume()
---
> FullO3CPU<Impl>::drainSanityCheck() const
1160,1164c1204,1210
< fetch.resume();
< decode.resume();
< rename.resume();
< iew.resume();
< commit.resume();
---
> assert(isDrained());
> fetch.drainSanityCheck();
> decode.drainSanityCheck();
> rename.drainSanityCheck();
> iew.drainSanityCheck();
> commit.drainSanityCheck();
> }
1166c1212,1216
< setDrainState(Drainable::Running);
---
> template <class Impl>
> bool
> FullO3CPU<Impl>::isDrained() const
> {
> bool drained(true);
1168,1169c1218,1229
< 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;
> }
> }
1171,1173c1231,1233
< 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;
1176,1178c1236,1261
< 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;
1183c1266
< FullO3CPU<Impl>::signalDrained()
---
> FullO3CPU<Impl>::commitDrained(ThreadID tid)
1185,1187c1268,1269
< if (++drainCount == NumStages) {
< if (tickEvent.scheduled())
< tickEvent.squash();
---
> fetch.drainStall(tid);
> }
1189c1271,1277
< setDrainState(Drainable::Drained);
---
> template <class Impl>
> void
> FullO3CPU<Impl>::drainResume()
> {
> setDrainState(Drainable::Running);
> if (switchedOut())
> return;
1191,1194c1279,1294
< if (drainManager) {
< DPRINTF(Drain, "CPU done draining, processing drain event\n");
< drainManager->signalDrainDone();
< drainManager = NULL;
---
> DPRINTF(Drain, "Resuming...\n");
>
> 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;
1197c1297,1300
< assert(drainCount <= 5);
---
>
> assert(!tickEvent.scheduled());
> if (_status == Running)
> schedule(tickEvent, nextCycle());
1203a1307
> DPRINTF(O3CPU, "Switching out\n");
1206,1213c1310
< fetch.switchOut();
< rename.switchOut();
< iew.switchOut();
< commit.switchOut();
< instList.clear();
< while (!removeList.empty()) {
< removeList.pop();
< }
---
> activityRec.reset();
1219,1221d1315
<
< if (tickEvent.scheduled())
< tickEvent.squash();
1228,1238d1321
< // 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();
<
1247c1330
< assert(!tickEvent.scheduled() || tickEvent.squashed());
---
> assert(!tickEvent.scheduled());
1253,1281d1335
< // @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());
<
1282a1337
> _status = Idle;