summaryrefslogtreecommitdiff
path: root/src/cpu
diff options
context:
space:
mode:
authorMitch Hayenga <mitch.hayenga@arm.com>2014-09-03 07:42:45 -0400
committerMitch Hayenga <mitch.hayenga@arm.com>2014-09-03 07:42:45 -0400
commit659bdc1a6b50ace4803d754ad982cd6a79b5695f (patch)
treec9107ba714b79605e0ea90a003757cdf4b152a23 /src/cpu
parentbb1e6cf7c4d64a56b80d3d69ba25e8ff7d455bbd (diff)
downloadgem5-659bdc1a6b50ace4803d754ad982cd6a79b5695f.tar.xz
cpu: Fix o3 drain bug
For X86, the o3 CPU would get stuck with the commit stage not being drained if an interrupt arrived while drain was pending. isDrained() makes sure that pcState.microPC() == 0, thus ensuring that we are at an instruction boundary. However, when we take an interrupt we execute: pcState.upc(romMicroPC(entry)); pcState.nupc(romMicroPC(entry) + 1); tc->pcState(pcState); As a result, the MicroPC is no longer zero. This patch ensures the drain is delayed until no interrupts are present. Once draining, non-synchronous interrupts are deffered until after the switch.
Diffstat (limited to 'src/cpu')
-rw-r--r--src/cpu/o3/commit.hh11
-rw-r--r--src/cpu/o3/commit_impl.hh15
2 files changed, 22 insertions, 4 deletions
diff --git a/src/cpu/o3/commit.hh b/src/cpu/o3/commit.hh
index 4c9ccf1eb..93c145d5b 100644
--- a/src/cpu/o3/commit.hh
+++ b/src/cpu/o3/commit.hh
@@ -438,9 +438,18 @@ class DefaultCommit
/** Number of Active Threads */
ThreadID numThreads;
- /** Is a drain pending. */
+ /** Is a drain pending? Commit is looking for an instruction boundary while
+ * there are no pending interrupts
+ */
bool drainPending;
+ /** Is a drain imminent? Commit has found an instruction boundary while no
+ * interrupts were present or in flight. This was the last architecturally
+ * committed instruction. Interrupts disabled and pipeline flushed.
+ * Waiting for structures to finish draining.
+ */
+ bool drainImminent;
+
/** The latency to handle a trap. Used when scheduling trap
* squash event.
*/
diff --git a/src/cpu/o3/commit_impl.hh b/src/cpu/o3/commit_impl.hh
index 347b23359..f0566233c 100644
--- a/src/cpu/o3/commit_impl.hh
+++ b/src/cpu/o3/commit_impl.hh
@@ -104,6 +104,7 @@ DefaultCommit<Impl>::DefaultCommit(O3CPU *_cpu, DerivO3CPUParams *params)
commitWidth(params->commitWidth),
numThreads(params->numThreads),
drainPending(false),
+ drainImminent(false),
trapLatency(params->trapLatency),
canHandleInterrupts(true),
avoidQuiesceLiveLock(false)
@@ -406,6 +407,7 @@ void
DefaultCommit<Impl>::drainResume()
{
drainPending = false;
+ drainImminent = false;
}
template <class Impl>
@@ -816,8 +818,10 @@ template <class Impl>
void
DefaultCommit<Impl>::propagateInterrupt()
{
+ // Don't propagate intterupts if we are currently handling a trap or
+ // in draining and the last observable instruction has been committed.
if (commitStatus[0] == TrapPending || interrupt || trapSquash[0] ||
- tcSquash[0])
+ tcSquash[0] || drainImminent)
return;
// Process interrupts if interrupts are enabled, not in PAL
@@ -1089,10 +1093,15 @@ DefaultCommit<Impl>::commitInsts()
squashAfter(tid, head_inst);
if (drainPending) {
- DPRINTF(Drain, "Draining: %i:%s\n", tid, pc[tid]);
- if (pc[tid].microPC() == 0 && interrupt == NoFault) {
+ if (pc[tid].microPC() == 0 && interrupt == NoFault &&
+ !thread[tid]->trapPending) {
+ // Last architectually committed instruction.
+ // Squash the pipeline, stall fetch, and use
+ // drainImminent to disable interrupts
+ DPRINTF(Drain, "Draining: %i:%s\n", tid, pc[tid]);
squashAfter(tid, head_inst);
cpu->commitDrained(tid);
+ drainImminent = true;
}
}