From 659bdc1a6b50ace4803d754ad982cd6a79b5695f Mon Sep 17 00:00:00 2001 From: Mitch Hayenga Date: Wed, 3 Sep 2014 07:42:45 -0400 Subject: 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. --- src/cpu/o3/commit_impl.hh | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'src/cpu/o3/commit_impl.hh') 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::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::drainResume() { drainPending = false; + drainImminent = false; } template @@ -816,8 +818,10 @@ template void DefaultCommit::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::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; } } -- cgit v1.2.3