summaryrefslogtreecommitdiff
path: root/src/cpu/o3/commit_impl.hh
diff options
context:
space:
mode:
Diffstat (limited to 'src/cpu/o3/commit_impl.hh')
-rw-r--r--src/cpu/o3/commit_impl.hh59
1 files changed, 42 insertions, 17 deletions
diff --git a/src/cpu/o3/commit_impl.hh b/src/cpu/o3/commit_impl.hh
index 333ccc89f..ea709e92c 100644
--- a/src/cpu/o3/commit_impl.hh
+++ b/src/cpu/o3/commit_impl.hh
@@ -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