/** 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.
*/
commitWidth(params->commitWidth),
numThreads(params->numThreads),
drainPending(false),
+ drainImminent(false),
trapLatency(params->trapLatency),
canHandleInterrupts(true),
avoidQuiesceLiveLock(false)
DefaultCommit<Impl>::drainResume()
{
drainPending = false;
+ drainImminent = false;
}
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
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;
}
}