syscall_emul: [patch 13/22] add system call retry capability
[gem5.git] / src / cpu / o3 / commit_impl.hh
index 104e7fb58db2aa6bd51876f074157044f35daa5c..ea77f18fb54613c916130c09c55284f70aec3aba 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2010 ARM Limited
+ * Copyright 2014 Google, Inc.
+ * Copyright (c) 2010-2014 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
  * Authors: Kevin Lim
  *          Korey Sewell
  */
+#ifndef __CPU_O3_COMMIT_IMPL_HH__
+#define __CPU_O3_COMMIT_IMPL_HH__
 
 #include <algorithm>
+#include <set>
 #include <string>
 
 #include "arch/utility.hh"
-#include "base/cp_annotate.hh"
 #include "base/loader/symtab.hh"
-#include "cpu/timebuf.hh"
-#include "config/full_system.hh"
+#include "base/cp_annotate.hh"
 #include "config/the_isa.hh"
-#include "config/use_checker.hh"
-#include "cpu/exetrace.hh"
+#include "cpu/checker/cpu.hh"
 #include "cpu/o3/commit.hh"
 #include "cpu/o3/thread_state.hh"
+#include "cpu/base.hh"
+#include "cpu/exetrace.hh"
+#include "cpu/timebuf.hh"
+#include "debug/Activity.hh"
+#include "debug/Commit.hh"
+#include "debug/CommitRate.hh"
+#include "debug/Drain.hh"
+#include "debug/ExecFaulting.hh"
+#include "debug/O3PipeView.hh"
 #include "params/DerivO3CPU.hh"
-
-#if USE_CHECKER
-#include "cpu/checker/cpu.hh"
-#endif
+#include "sim/faults.hh"
+#include "sim/full_system.hh"
 
 using namespace std;
 
 template <class Impl>
 DefaultCommit<Impl>::TrapEvent::TrapEvent(DefaultCommit<Impl> *_commit,
                                           ThreadID _tid)
-    : Event(CPU_Tick_Pri), commit(_commit), tid(_tid)
+    : Event(CPU_Tick_Pri, AutoDelete), commit(_commit), tid(_tid)
 {
-    this->setFlags(AutoDelete);
 }
 
 template <class Impl>
@@ -89,7 +96,6 @@ DefaultCommit<Impl>::TrapEvent::description() const
 template <class Impl>
 DefaultCommit<Impl>::DefaultCommit(O3CPU *_cpu, DerivO3CPUParams *params)
     : cpu(_cpu),
-      squashCounter(0),
       iewToCommitDelay(params->iewToCommitDelay),
       commitToIEWDelay(params->commitToIEWDelay),
       renameToROBDelay(params->renameToROBDelay),
@@ -98,9 +104,16 @@ DefaultCommit<Impl>::DefaultCommit(O3CPU *_cpu, DerivO3CPUParams *params)
       commitWidth(params->commitWidth),
       numThreads(params->numThreads),
       drainPending(false),
-      switchedOut(false),
-      trapLatency(params->trapLatency)
+      drainImminent(false),
+      trapLatency(params->trapLatency),
+      canHandleInterrupts(true),
+      avoidQuiesceLiveLock(false)
 {
+    if (commitWidth > Impl::MaxWidth)
+        fatal("commitWidth (%d) is larger than compiled limit (%d),\n"
+             "\tincrease MaxWidth in src/cpu/o3/impl.hh\n",
+             commitWidth, static_cast<int>(Impl::MaxWidth));
+
     _status = Active;
     _nextStatus = Inactive;
     std::string policy = params->smtCommitPolicy;
@@ -113,7 +126,7 @@ DefaultCommit<Impl>::DefaultCommit(O3CPU *_cpu, DerivO3CPUParams *params)
     if (policy == "aggressive"){
         commitPolicy = Aggressive;
 
-        DPRINTF(Commit,"Commit Policy set to Aggressive.");
+        DPRINTF(Commit,"Commit Policy set to Aggressive.\n");
     } else if (policy == "roundrobin"){
         commitPolicy = RoundRobin;
 
@@ -122,7 +135,7 @@ DefaultCommit<Impl>::DefaultCommit(O3CPU *_cpu, DerivO3CPUParams *params)
             priority_list.push_back(tid);
         }
 
-        DPRINTF(Commit,"Commit Policy set to Round Robin.");
+        DPRINTF(Commit,"Commit Policy set to Round Robin.\n");
     } else if (policy == "oldestready"){
         commitPolicy = OldestReady;
 
@@ -142,10 +155,9 @@ DefaultCommit<Impl>::DefaultCommit(O3CPU *_cpu, DerivO3CPUParams *params)
         tcSquash[tid] = false;
         pc[tid].set(0);
         lastCommitedSeqNum[tid] = 0;
+        squashAfterInst[tid] = NULL;
     }
-#if FULL_SYSTEM
     interrupt = NoFault;
-#endif
 }
 
 template <class Impl>
@@ -155,111 +167,123 @@ DefaultCommit<Impl>::name() const
     return cpu->name() + ".commit";
 }
 
+template <class Impl>
+void
+DefaultCommit<Impl>::regProbePoints()
+{
+    ppCommit = new ProbePointArg<DynInstPtr>(cpu->getProbeManager(), "Commit");
+    ppCommitStall = new ProbePointArg<DynInstPtr>(cpu->getProbeManager(), "CommitStall");
+    ppSquash = new ProbePointArg<DynInstPtr>(cpu->getProbeManager(), "Squash");
+}
+
 template <class Impl>
 void
 DefaultCommit<Impl>::regStats()
 {
     using namespace Stats;
-    commitCommittedInsts
-        .name(name() + ".commitCommittedInsts")
-        .desc("The number of committed instructions")
-        .prereq(commitCommittedInsts);
     commitSquashedInsts
         .name(name() + ".commitSquashedInsts")
         .desc("The number of squashed insts skipped by commit")
         .prereq(commitSquashedInsts);
-    commitSquashEvents
-        .name(name() + ".commitSquashEvents")
-        .desc("The number of times commit is told to squash")
-        .prereq(commitSquashEvents);
+
     commitNonSpecStalls
         .name(name() + ".commitNonSpecStalls")
         .desc("The number of times commit has been forced to stall to "
               "communicate backwards")
         .prereq(commitNonSpecStalls);
+
     branchMispredicts
         .name(name() + ".branchMispredicts")
         .desc("The number of times a branch was mispredicted")
         .prereq(branchMispredicts);
+
     numCommittedDist
         .init(0,commitWidth,1)
-        .name(name() + ".COM:committed_per_cycle")
+        .name(name() + ".committed_per_cycle")
         .desc("Number of insts commited each cycle")
         .flags(Stats::pdf)
         ;
 
-    statComInst
+    instsCommitted
         .init(cpu->numThreads)
-        .name(name() + ".COM:count")
+        .name(name() + ".committedInsts")
         .desc("Number of instructions committed")
         .flags(total)
         ;
 
+    opsCommitted
+        .init(cpu->numThreads)
+        .name(name() + ".committedOps")
+        .desc("Number of ops (including micro ops) committed")
+        .flags(total)
+        ;
+
     statComSwp
         .init(cpu->numThreads)
-        .name(name() + ".COM:swp_count")
+        .name(name() + ".swp_count")
         .desc("Number of s/w prefetches committed")
         .flags(total)
         ;
 
     statComRefs
         .init(cpu->numThreads)
-        .name(name() +  ".COM:refs")
+        .name(name() +  ".refs")
         .desc("Number of memory references committed")
         .flags(total)
         ;
 
     statComLoads
         .init(cpu->numThreads)
-        .name(name() +  ".COM:loads")
+        .name(name() +  ".loads")
         .desc("Number of loads committed")
         .flags(total)
         ;
 
     statComMembars
         .init(cpu->numThreads)
-        .name(name() +  ".COM:membars")
+        .name(name() +  ".membars")
         .desc("Number of memory barriers committed")
         .flags(total)
         ;
 
     statComBranches
         .init(cpu->numThreads)
-        .name(name() + ".COM:branches")
+        .name(name() + ".branches")
         .desc("Number of branches committed")
         .flags(total)
         ;
 
     statComFloating
         .init(cpu->numThreads)
-        .name(name() + ".COM:fp_insts")
+        .name(name() + ".fp_insts")
         .desc("Number of committed floating point instructions.")
         .flags(total)
         ;
 
     statComInteger
         .init(cpu->numThreads)
-        .name(name()+".COM:int_insts")
+        .name(name()+".int_insts")
         .desc("Number of committed integer instructions.")
         .flags(total)
         ;
 
     statComFunctionCalls
         .init(cpu->numThreads)
-        .name(name()+".COM:function_calls")
+        .name(name()+".function_calls")
         .desc("Number of function calls committed.")
         .flags(total)
         ;
 
-    commitEligible
-        .init(cpu->numThreads)
-        .name(name() + ".COM:bw_limited")
-        .desc("number of insts not committed due to BW limits")
-        .flags(total)
+    statCommittedInstType
+        .init(numThreads,Enums::Num_OpClass)
+        .name(name() + ".op_class")
+        .desc("Class of committed instruction")
+        .flags(total | pdf | dist)
         ;
+    statCommittedInstType.ysubnames(Enums::OpClassStrings);
 
     commitEligibleSamples
-        .name(name() + ".COM:bw_lim_events")
+        .name(name() + ".bw_lim_events")
         .desc("number cycles where commit BW limit reached")
         ;
 }
@@ -345,7 +369,7 @@ DefaultCommit<Impl>::setROB(ROB *rob_ptr)
 
 template <class Impl>
 void
-DefaultCommit<Impl>::initStage()
+DefaultCommit<Impl>::startupStage()
 {
     rob->setActiveThreads(activeThreads);
     rob->resetEntries();
@@ -362,39 +386,63 @@ DefaultCommit<Impl>::initStage()
     cpu->activateStage(O3CPU::CommitIdx);
 
     cpu->activityThisCycle();
-    trapLatency = cpu->ticks(trapLatency);
 }
 
 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();
+    drainImminent = false;
 }
 
 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++) {
@@ -402,11 +450,24 @@ DefaultCommit<Impl>::takeOverFrom()
         changedROBNumEntries[tid] = false;
         trapSquash[tid] = false;
         tcSquash[tid] = false;
+        squashAfterInst[tid] = NULL;
     }
-    squashCounter = 0;
     rob->takeOverFrom();
 }
 
+template <class Impl>
+void
+DefaultCommit<Impl>::deactivateThread(ThreadID tid)
+{
+    list<ThreadID>::iterator thread_it = std::find(priority_list.begin(),
+            priority_list.end(), tid);
+
+    if (thread_it != priority_list.end()) {
+        priority_list.erase(thread_it);
+    }
+}
+
+
 template <class Impl>
 void
 DefaultCommit<Impl>::updateStatus()
@@ -438,32 +499,6 @@ DefaultCommit<Impl>::updateStatus()
     _status = _nextStatus;
 }
 
-template <class Impl>
-void
-DefaultCommit<Impl>::setNextStatus()
-{
-    int squashes = 0;
-
-    list<ThreadID>::iterator threads = activeThreads->begin();
-    list<ThreadID>::iterator end = activeThreads->end();
-
-    while (threads != end) {
-        ThreadID tid = *threads++;
-
-        if (commitStatus[tid] == ROBSquashing) {
-            squashes++;
-        }
-    }
-
-    squashCounter = squashes;
-
-    // If commit is currently squashing, then it will have activity for the
-    // next cycle. Set its next status as active.
-    if (squashCounter) {
-        _nextStatus = Active;
-    }
-}
-
 template <class Impl>
 bool
 DefaultCommit<Impl>::changedROBEntries()
@@ -491,14 +526,18 @@ DefaultCommit<Impl>::numROBFreeEntries(ThreadID tid)
 
 template <class Impl>
 void
-DefaultCommit<Impl>::generateTrapEvent(ThreadID tid)
+DefaultCommit<Impl>::generateTrapEvent(ThreadID tid, Fault inst_fault)
 {
     DPRINTF(Commit, "Generating trap event for [tid:%i]\n", tid);
 
     TrapEvent *trap = new TrapEvent(this, tid);
 
-    cpu->schedule(trap, curTick() + trapLatency);
+    Cycles latency = dynamic_pointer_cast<SyscallRetryFault>(inst_fault) ?
+                     cpu->syscallRetryLatency : trapLatency;
+
+    cpu->schedule(trap, cpu->clockEdge(latency));
     trapInFlight[tid] = true;
+    thread[tid]->trapPending = true;
 }
 
 template <class Impl>
@@ -519,7 +558,7 @@ DefaultCommit<Impl>::squashAll(ThreadID tid)
     // then use one older sequence number.
     // Hopefully this doesn't mess things up.  Basically I want to squash
     // all instructions of this thread.
-    InstSeqNum squashed_inst = rob->isEmpty() ?
+    InstSeqNum squashed_inst = rob->isEmpty(tid) ?
         lastCommitedSeqNum[tid] : rob->readHeadInst(tid)->seqNum - 1;
 
     // All younger instructions will be squashed. Set the sequence
@@ -541,8 +580,8 @@ DefaultCommit<Impl>::squashAll(ThreadID tid)
     // the ROB is in the process of squashing.
     toIEW->commitInfo[tid].robSquashing = true;
 
-    toIEW->commitInfo[tid].branchMispredict = false;
     toIEW->commitInfo[tid].mispredictInst = NULL;
+    toIEW->commitInfo[tid].squashInst = NULL;
 
     toIEW->commitInfo[tid].pc = pc[tid];
 }
@@ -556,7 +595,7 @@ DefaultCommit<Impl>::squashFromTrap(ThreadID tid)
     DPRINTF(Commit, "Squashing from trap, restarting at PC %s\n", pc[tid]);
 
     thread[tid]->trapPending = false;
-    thread[tid]->inSyscall = false;
+    thread[tid]->noSquashFromTC = false;
     trapInFlight[tid] = false;
 
     trapSquash[tid] = false;
@@ -573,7 +612,7 @@ DefaultCommit<Impl>::squashFromTC(ThreadID tid)
 
     DPRINTF(Commit, "Squashing from TC, restarting at PC %s\n", pc[tid]);
 
-    thread[tid]->inSyscall = false;
+    thread[tid]->noSquashFromTC = false;
     assert(!thread[tid]->trapPending);
 
     commitStatus[tid] = ROBSquashing;
@@ -584,29 +623,32 @@ DefaultCommit<Impl>::squashFromTC(ThreadID tid)
 
 template <class Impl>
 void
-DefaultCommit<Impl>::squashAfter(ThreadID tid, uint64_t squash_after_seq_num)
+DefaultCommit<Impl>::squashFromSquashAfter(ThreadID tid)
 {
-    youngestSeqNum[tid] = squash_after_seq_num;
-
-    rob->squash(squash_after_seq_num, tid);
-    changedROBNumEntries[tid] = true;
+    DPRINTF(Commit, "Squashing after squash after request, "
+            "restarting at PC %s\n", pc[tid]);
 
-    // Send back the sequence number of the squashed instruction.
-    toIEW->commitInfo[tid].doneSeqNum = squash_after_seq_num;
-
-    // Send back the squash signal to tell stages that they should squash.
-    toIEW->commitInfo[tid].squash = true;
-
-    // Send back the rob squashing signal so other stages know that
-    // the ROB is in the process of squashing.
-    toIEW->commitInfo[tid].robSquashing = true;
+    squashAll(tid);
+    // Make sure to inform the fetch stage of which instruction caused
+    // the squash. It'll try to re-fetch an instruction executing in
+    // microcode unless this is set.
+    toIEW->commitInfo[tid].squashInst = squashAfterInst[tid];
+    squashAfterInst[tid] = NULL;
 
-    toIEW->commitInfo[tid].branchMispredict = false;
+    commitStatus[tid] = ROBSquashing;
+    cpu->activityThisCycle();
+}
 
-    toIEW->commitInfo[tid].pc = pc[tid];
+template <class Impl>
+void
+DefaultCommit<Impl>::squashAfter(ThreadID tid, DynInstPtr &head_inst)
+{
     DPRINTF(Commit, "Executing squash after for [tid:%i] inst [sn:%lli]\n",
-            tid, squash_after_seq_num);
-    commitStatus[tid] = ROBSquashing;
+            tid, head_inst->seqNum);
+
+    assert(!squashAfterInst[tid] || squashAfterInst[tid] == head_inst);
+    commitStatus[tid] = SquashAfterPending;
+    squashAfterInst[tid] = head_inst;
 }
 
 template <class Impl>
@@ -616,12 +658,6 @@ DefaultCommit<Impl>::tick()
     wroteToTimeBuffer = false;
     _nextStatus = Inactive;
 
-    if (drainPending && rob->isEmpty() && !iewStage->hasStoresToWB()) {
-        cpu->signalDrained();
-        drainPending = false;
-        return;
-    }
-
     if (activeThreads->empty())
         return;
 
@@ -674,6 +710,8 @@ DefaultCommit<Impl>::tick()
         } else if (!rob->isEmpty(tid)) {
             DynInstPtr inst = rob->readHeadInst(tid);
 
+            ppCommitStall->notify(inst);
+
             DPRINTF(Commit,"[tid:%i]: Can't commit, Instruction [sn:%lli] PC "
                     "%s is head of ROB and not ready\n",
                     tid, inst->seqNum, inst->pcState());
@@ -692,7 +730,6 @@ DefaultCommit<Impl>::tick()
     updateStatus();
 }
 
-#if FULL_SYSTEM
 template <class Impl>
 void
 DefaultCommit<Impl>::handleInterrupt()
@@ -703,12 +740,13 @@ DefaultCommit<Impl>::handleInterrupt()
                 "it got handled. Restart fetching from the orig path.\n");
         toIEW->commitInfo[0].clearInterrupt = true;
         interrupt = NoFault;
+        avoidQuiesceLiveLock = true;
         return;
     }
 
-    // Wait until the ROB is empty and all stores have drained in
-    // order to enter the interrupt.
-    if (rob->isEmpty() && !iewStage->hasStoresToWB()) {
+    // Wait until all in flight instructions are finished before enterring
+    // the interrupt.
+    if (canHandleInterrupts && cpu->instList.empty()) {
         // Squash or record that I need to squash this cycle if
         // an interrupt needed to be handled.
         DPRINTF(Commit, "Interrupt detected.\n");
@@ -716,22 +754,33 @@ DefaultCommit<Impl>::handleInterrupt()
         // Clear the interrupt now that it's going to be handled
         toIEW->commitInfo[0].clearInterrupt = true;
 
-        assert(!thread[0]->inSyscall);
-        thread[0]->inSyscall = true;
+        assert(!thread[0]->noSquashFromTC);
+        thread[0]->noSquashFromTC = true;
 
-        // CPU will handle interrupt.
-        cpu->processInterrupts(interrupt);
+        if (cpu->checker) {
+            cpu->checker->handlePendingInt();
+        }
+
+        // CPU will handle interrupt. Note that we ignore the local copy of
+        // interrupt. This is because the local copy may no longer be the
+        // interrupt that the interrupt controller thinks is being handled.
+        cpu->processInterrupts(cpu->getInterrupts());
 
-        thread[0]->inSyscall = false;
+        thread[0]->noSquashFromTC = false;
 
         commitStatus[0] = TrapPending;
 
+        interrupt = NoFault;
+
         // Generate trap squash event.
-        generateTrapEvent(0);
+        generateTrapEvent(0, interrupt);
 
-        interrupt = NoFault;
+        avoidQuiesceLiveLock = false;
     } else {
-        DPRINTF(Commit, "Interrupt pending, waiting for ROB to empty.\n");
+        DPRINTF(Commit, "Interrupt pending: instruction is %sin "
+                "flight, ROB is %sempty\n",
+                canHandleInterrupts ? "not " : "",
+                cpu->instList.empty() ? "" : "not " );
     }
 }
 
@@ -739,8 +788,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
@@ -758,22 +809,15 @@ DefaultCommit<Impl>::propagateInterrupt()
         toIEW->commitInfo[0].interruptPending = true;
 }
 
-#endif // FULL_SYSTEM
-
 template <class Impl>
 void
 DefaultCommit<Impl>::commit()
 {
-
-#if FULL_SYSTEM
-    // Check for any interrupt that we've already squashed for and start processing it.
-    if (interrupt != NoFault)
-        handleInterrupt();
-
-    // Check if we have a interrupt and get read to handle it
-    if (cpu->checkInterrupts(cpu->tcBase(0)))
-        propagateInterrupt();
-#endif // FULL_SYSTEM
+    if (FullSystem) {
+        // Check if we have a interrupt and get read to handle it
+        if (cpu->checkInterrupts(cpu->tcBase(0)))
+            propagateInterrupt();
+    }
 
     ////////////////////////////////////
     // Check for any possible squashes, handle them first
@@ -781,17 +825,24 @@ DefaultCommit<Impl>::commit()
     list<ThreadID>::iterator threads = activeThreads->begin();
     list<ThreadID>::iterator end = activeThreads->end();
 
+    int num_squashing_threads = 0;
+
     while (threads != end) {
         ThreadID tid = *threads++;
 
         // Not sure which one takes priority.  I think if we have
         // both, that's a bad sign.
-        if (trapSquash[tid] == true) {
+        if (trapSquash[tid]) {
             assert(!tcSquash[tid]);
             squashFromTrap(tid);
-        } else if (tcSquash[tid] == true) {
+        } else if (tcSquash[tid]) {
             assert(commitStatus[tid] != TrapPending);
             squashFromTC(tid);
+        } else if (commitStatus[tid] == SquashAfterPending) {
+            // A squash from the previous cycle of the commit stage (i.e.,
+            // commitInsts() called squashAfter) is pending. Squash the
+            // thread now.
+            squashFromSquashAfter(tid);
         }
 
         // Squashed sequence number must be older than youngest valid
@@ -801,10 +852,17 @@ DefaultCommit<Impl>::commit()
             commitStatus[tid] != TrapPending &&
             fromIEW->squashedSeqNum[tid] <= youngestSeqNum[tid]) {
 
-            DPRINTF(Commit, "[tid:%i]: Squashing due to PC %#x [sn:%i]\n",
+            if (fromIEW->mispredictInst[tid]) {
+                DPRINTF(Commit,
+                    "[tid:%i]: Squashing due to branch mispred PC:%#x [sn:%i]\n",
                     tid,
-                    fromIEW->mispredPC[tid],
+                    fromIEW->mispredictInst[tid]->instAddr(),
                     fromIEW->squashedSeqNum[tid]);
+            } else {
+                DPRINTF(Commit,
+                    "[tid:%i]: Squashing due to order violation [sn:%i]\n",
+                    tid, fromIEW->squashedSeqNum[tid]);
+            }
 
             DPRINTF(Commit, "[tid:%i]: Redirecting to PC %#x\n",
                     tid,
@@ -816,7 +874,7 @@ DefaultCommit<Impl>::commit()
             // then use one older sequence number.
             InstSeqNum squashed_inst = fromIEW->squashedSeqNum[tid];
 
-            if (fromIEW->includeSquashInst[tid] == true) {
+            if (fromIEW->includeSquashInst[tid]) {
                 squashed_inst--;
             }
 
@@ -835,27 +893,34 @@ DefaultCommit<Impl>::commit()
             // the ROB is in the process of squashing.
             toIEW->commitInfo[tid].robSquashing = true;
 
-            toIEW->commitInfo[tid].branchMispredict =
-                fromIEW->branchMispredict[tid];
             toIEW->commitInfo[tid].mispredictInst =
                 fromIEW->mispredictInst[tid];
             toIEW->commitInfo[tid].branchTaken =
                 fromIEW->branchTaken[tid];
-
-            toIEW->commitInfo[tid].pc = fromIEW->pc[tid];
-
-            toIEW->commitInfo[tid].mispredPC = fromIEW->mispredPC[tid];
-
-            if (toIEW->commitInfo[tid].branchMispredict) {
+            toIEW->commitInfo[tid].squashInst =
+                                    rob->findInst(tid, squashed_inst);
+            if (toIEW->commitInfo[tid].mispredictInst) {
+                if (toIEW->commitInfo[tid].mispredictInst->isUncondCtrl()) {
+                     toIEW->commitInfo[tid].branchTaken = true;
+                }
                 ++branchMispredicts;
             }
+
+            toIEW->commitInfo[tid].pc = fromIEW->pc[tid];
         }
 
+        if (commitStatus[tid] == ROBSquashing) {
+            num_squashing_threads++;
+        }
     }
 
-    setNextStatus();
+    // If commit is currently squashing, then it will have activity for the
+    // next cycle. Set its next status as active.
+    if (num_squashing_threads) {
+        _nextStatus = Active;
+    }
 
-    if (squashCounter != numThreads) {
+    if (num_squashing_threads != numThreads) {
         // If we're not currently squashing, then get instructions.
         getInsts();
 
@@ -921,7 +986,12 @@ DefaultCommit<Impl>::commitInsts()
     // Commit as many instructions as possible until the commit bandwidth
     // limit is reached, or it becomes impossible to commit any more.
     while (num_committed < commitWidth) {
-        int commit_thread = getCommittingThread();
+        // Check for any interrupt that we've already squashed for
+        // and start processing it.
+        if (interrupt != NoFault)
+            handleInterrupt();
+
+        ThreadID commit_thread = getCommittingThread();
 
         if (commit_thread == -1 || !rob->isHeadReady(commit_thread))
             break;
@@ -945,6 +1015,8 @@ DefaultCommit<Impl>::commitInsts()
             rob->retireHead(commit_thread);
 
             ++commitSquashedInsts;
+            // Notify potential listeners that this instruction is squashed
+            ppSquash->notify(head_inst);
 
             // Record that the number of ROB entries has changed.
             changedROBNumEntries[tid] = true;
@@ -963,23 +1035,31 @@ DefaultCommit<Impl>::commitInsts()
 
             if (commit_success) {
                 ++num_committed;
+                statCommittedInstType[tid][head_inst->opClass()]++;
+                ppCommit->notify(head_inst);
 
                 changedROBNumEntries[tid] = true;
 
                 // Set the doneSeqNum to the youngest committed instruction.
                 toIEW->commitInfo[tid].doneSeqNum = head_inst->seqNum;
 
-                ++commitCommittedInsts;
-
-                // To match the old model, don't count nops and instruction
-                // prefetches towards the total commit count.
-                if (!head_inst->isNop() && !head_inst->isInstPrefetch()) {
-                    cpu->instDone(tid);
+                if (tid == 0) {
+                    canHandleInterrupts =  (!head_inst->isDelayedCommit()) &&
+                                           ((THE_ISA != ALPHA_ISA) ||
+                                             (!(pc[0].instAddr() & 0x3)));
                 }
 
                 // Updates misc. registers.
                 head_inst->updateMiscRegs();
 
+                // Check instruction execution if it successfully commits and
+                // is not carrying a fault.
+                if (cpu->checker) {
+                    cpu->checker->verify(head_inst);
+                }
+
+                cpu->traceFunctions(pc[tid].instAddr());
+
                 TheISA::advancePC(pc[tid], head_inst->staticInst);
 
                 // Keep track of the last sequence number commited
@@ -988,23 +1068,54 @@ DefaultCommit<Impl>::commitInsts()
                 // If this is an instruction that doesn't play nicely with
                 // others squash everything and restart fetch
                 if (head_inst->isSquashAfter())
-                    squashAfter(tid, head_inst->seqNum);
-
-                int count = 0;
-                Addr oldpc;
-                // Debug statement.  Checks to make sure we're not
-                // currently updating state while handling PC events.
-                assert(!thread[tid]->inSyscall && !thread[tid]->trapPending);
-                do {
-                    oldpc = pc[tid].instAddr();
-                    cpu->system->pcEventQueue.service(thread[tid]->getTC());
-                    count++;
-                } while (oldpc != pc[tid].instAddr());
-                if (count > 1) {
-                    DPRINTF(Commit,
-                            "PC skip function event, stopping commit\n");
-                    break;
+                    squashAfter(tid, head_inst);
+
+                if (drainPending) {
+                    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;
+                    }
+                }
+
+                bool onInstBoundary = !head_inst->isMicroop() ||
+                                      head_inst->isLastMicroop() ||
+                                      !head_inst->isDelayedCommit();
+
+                if (onInstBoundary) {
+                    int count = 0;
+                    Addr oldpc;
+                    // Make sure we're not currently updating state while
+                    // handling PC events.
+                    assert(!thread[tid]->noSquashFromTC &&
+                           !thread[tid]->trapPending);
+                    do {
+                        oldpc = pc[tid].instAddr();
+                        cpu->system->pcEventQueue.service(thread[tid]->getTC());
+                        count++;
+                    } while (oldpc != pc[tid].instAddr());
+                    if (count > 1) {
+                        DPRINTF(Commit,
+                                "PC skip function event, stopping commit\n");
+                        break;
+                    }
                 }
+
+                // Check if an instruction just enabled interrupts and we've
+                // previously had an interrupt pending that was not handled
+                // because interrupts were subsequently disabled before the
+                // pipeline reached a place to handle the interrupt. In that
+                // case squash now to make sure the interrupt is handled.
+                //
+                // If we don't do this, we might end up in a live lock situation
+                if (!interrupt && avoidQuiesceLiveLock &&
+                    onInstBoundary && cpu->checkInterrupts(cpu->tcBase(0)))
+                    squashAfter(tid, head_inst);
             } else {
                 DPRINTF(Commit, "Unable to commit head instruction PC:%s "
                         "[tid:%i] [sn:%i].\n",
@@ -1037,52 +1148,37 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
         // and committed this instruction.
         thread[tid]->funcExeInst--;
 
-        if (head_inst->isNonSpeculative() ||
-            head_inst->isStoreConditional() ||
-            head_inst->isMemBarrier() ||
-            head_inst->isWriteBarrier()) {
-
-            DPRINTF(Commit, "Encountered a barrier or non-speculative "
-                    "instruction [sn:%lli] at the head of the ROB, PC %s.\n",
-                    head_inst->seqNum, head_inst->pcState());
-
-            if (inst_num > 0 || iewStage->hasStoresToWB(tid)) {
-                DPRINTF(Commit, "Waiting for all stores to writeback.\n");
-                return false;
-            }
-
-            toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum;
+        // Make sure we are only trying to commit un-executed instructions we
+        // think are possible.
+        assert(head_inst->isNonSpeculative() || head_inst->isStoreConditional()
+               || head_inst->isMemBarrier() || head_inst->isWriteBarrier() ||
+               (head_inst->isLoad() && head_inst->strictlyOrdered()));
 
-            // Change the instruction so it won't try to commit again until
-            // it is executed.
-            head_inst->clearCanCommit();
-
-            ++commitNonSpecStalls;
+        DPRINTF(Commit, "Encountered a barrier or non-speculative "
+                "instruction [sn:%lli] at the head of the ROB, PC %s.\n",
+                head_inst->seqNum, head_inst->pcState());
 
+        if (inst_num > 0 || iewStage->hasStoresToWB(tid)) {
+            DPRINTF(Commit, "Waiting for all stores to writeback.\n");
             return false;
-        } else if (head_inst->isLoad()) {
-            if (inst_num > 0 || iewStage->hasStoresToWB(tid)) {
-                DPRINTF(Commit, "Waiting for all stores to writeback.\n");
-                return false;
-            }
-
-            assert(head_inst->uncacheable());
-            DPRINTF(Commit, "[sn:%lli]: Uncached load, PC %s.\n",
-                    head_inst->seqNum, head_inst->pcState());
+        }
 
-            // Send back the non-speculative instruction's sequence
-            // number.  Tell the lsq to re-execute the load.
-            toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum;
-            toIEW->commitInfo[tid].uncached = true;
-            toIEW->commitInfo[tid].uncachedLoad = head_inst;
+        toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum;
 
-            head_inst->clearCanCommit();
+        // Change the instruction so it won't try to commit again until
+        // it is executed.
+        head_inst->clearCanCommit();
 
-            return false;
+        if (head_inst->isLoad() && head_inst->strictlyOrdered()) {
+            DPRINTF(Commit, "[sn:%lli]: Strictly ordered load, PC %s.\n",
+                    head_inst->seqNum, head_inst->pcState());
+            toIEW->commitInfo[tid].strictlyOrdered = true;
+            toIEW->commitInfo[tid].strictlyOrderedLoad = head_inst;
         } else {
-            panic("Trying to commit un-executed instruction "
-                  "of unknown type!\n");
+            ++commitNonSpecStalls;
         }
+
+        return false;
     }
 
     if (head_inst->isThreadSync()) {
@@ -1098,14 +1194,6 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
         head_inst->setCompleted();
     }
 
-#if USE_CHECKER
-    // Use checker prior to updating anything due to traps or PC
-    // based events.
-    if (cpu->checker) {
-        cpu->checker->verify(head_inst);
-    }
-#endif
-
     if (inst_fault != NoFault) {
         DPRINTF(Commit, "Inst [sn:%lli] PC %s has a fault\n",
                 head_inst->seqNum, head_inst->pcState());
@@ -1117,17 +1205,18 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
 
         head_inst->setCompleted();
 
-#if USE_CHECKER
-        if (cpu->checker && head_inst->isStore()) {
+        // If instruction has faulted, let the checker execute it and
+        // check if it sees the same fault and control flow.
+        if (cpu->checker) {
+            // Need to check the instruction before its fault is processed
             cpu->checker->verify(head_inst);
         }
-#endif
 
-        assert(!thread[tid]->inSyscall);
+        assert(!thread[tid]->noSquashFromTC);
 
         // Mark that we're in state update mode so that the trap's
         // execution doesn't generate extra squashes.
-        thread[tid]->inSyscall = true;
+        thread[tid]->noSquashFromTC = true;
 
         // Execute the trap.  Although it's slightly unrealistic in
         // terms of timing (as it doesn't wait for the full timing of
@@ -1138,7 +1227,7 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
         cpu->trap(inst_fault, tid, head_inst->staticInst);
 
         // Exit state update mode to avoid accidental updating.
-        thread[tid]->inSyscall = false;
+        thread[tid]->noSquashFromTC = false;
 
         commitStatus[tid] = TrapPending;
 
@@ -1147,7 +1236,7 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
         if (head_inst->traceData) {
             if (DTRACE(ExecFaulting)) {
                 head_inst->traceData->setFetchSeq(head_inst->seqNum);
-                head_inst->traceData->setCPSeq(thread[tid]->numInst);
+                head_inst->traceData->setCPSeq(thread[tid]->numOp);
                 head_inst->traceData->dump();
             }
             delete head_inst->traceData;
@@ -1155,37 +1244,41 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
         }
 
         // Generate trap squash event.
-        generateTrapEvent(tid);
+        generateTrapEvent(tid, inst_fault);
         return false;
     }
 
     updateComInstStats(head_inst);
 
-#if FULL_SYSTEM
-    if (thread[tid]->profile) {
-        thread[tid]->profilePC = head_inst->instAddr();
-        ProfileNode *node = thread[tid]->profile->consume(thread[tid]->getTC(),
-                                                          head_inst->staticInst);
+    if (FullSystem) {
+        if (thread[tid]->profile) {
+            thread[tid]->profilePC = head_inst->instAddr();
+            ProfileNode *node = thread[tid]->profile->consume(
+                    thread[tid]->getTC(), head_inst->staticInst);
 
-        if (node)
-            thread[tid]->profileNode = node;
-    }
-    if (CPA::available()) {
-        if (head_inst->isControl()) {
-            ThreadContext *tc = thread[tid]->getTC();
-            CPA::cpa()->swAutoBegin(tc, head_inst->nextInstAddr());
+            if (node)
+                thread[tid]->profileNode = node;
+        }
+        if (CPA::available()) {
+            if (head_inst->isControl()) {
+                ThreadContext *tc = thread[tid]->getTC();
+                CPA::cpa()->swAutoBegin(tc, head_inst->nextInstAddr());
+            }
         }
     }
-#endif
-    DPRINTF(Commit, "Committing instruction with [sn:%lli]\n",
-            head_inst->seqNum);
+    DPRINTF(Commit, "Committing instruction with [sn:%lli] PC %s\n",
+            head_inst->seqNum, head_inst->pcState());
     if (head_inst->traceData) {
         head_inst->traceData->setFetchSeq(head_inst->seqNum);
-        head_inst->traceData->setCPSeq(thread[tid]->numInst);
+        head_inst->traceData->setCPSeq(thread[tid]->numOp);
         head_inst->traceData->dump();
         delete head_inst->traceData;
         head_inst->traceData = NULL;
     }
+    if (head_inst->isReturn()) {
+        DPRINTF(Commit,"Return Instruction Committed [sn:%lli] PC %s \n",
+                        head_inst->seqNum, head_inst->pcState());
+    }
 
     // Update the commit rename map
     for (int i = 0; i < head_inst->numDestRegs(); i++) {
@@ -1193,12 +1286,15 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
                                  head_inst->renamedDestRegIdx(i));
     }
 
-    if (head_inst->isCopy())
-        panic("Should not commit any copy instructions!");
-
     // Finally clear the head ROB entry.
     rob->retireHead(tid);
 
+#if TRACING_ON
+    if (DTRACE(O3PipeView)) {
+        head_inst->commitTick = curTick() - head_inst->fetchTick;
+    }
+#endif
+
     // If this was a store, record it for this cycle.
     if (head_inst->isStore())
         committedStores[tid] = true;
@@ -1243,39 +1339,14 @@ DefaultCommit<Impl>::getInsts()
     }
 }
 
-template <class Impl>
-void
-DefaultCommit<Impl>::skidInsert()
-{
-    DPRINTF(Commit, "Attempting to any instructions from rename into "
-            "skidBuffer.\n");
-
-    for (int inst_num = 0; inst_num < fromRename->size; ++inst_num) {
-        DynInstPtr inst = fromRename->insts[inst_num];
-
-        if (!inst->isSquashed()) {
-            DPRINTF(Commit, "Inserting PC %s [sn:%i] [tid:%i] into ",
-                    "skidBuffer.\n", inst->pcState(), inst->seqNum,
-                    inst->threadNumber);
-            skidBuffer.push(inst);
-        } else {
-            DPRINTF(Commit, "Instruction PC %s [sn:%i] [tid:%i] was "
-                    "squashed, skipping.\n",
-                    inst->pcState(), inst->seqNum, inst->threadNumber);
-        }
-    }
-}
-
 template <class Impl>
 void
 DefaultCommit<Impl>::markCompletedInsts()
 {
     // Grab completed insts out of the IEW instruction queue, and mark
     // instructions completed within the ROB.
-    for (int inst_num = 0;
-         inst_num < fromIEW->size && fromIEW->insts[inst_num];
-         ++inst_num)
-    {
+    for (int inst_num = 0; inst_num < fromIEW->size; ++inst_num) {
+        assert(fromIEW->insts[inst_num]);
         if (!fromIEW->insts[inst_num]->isSquashed()) {
             DPRINTF(Commit, "[tid:%i]: Marking PC %s, [sn:%lli] ready "
                     "within ROB.\n",
@@ -1289,41 +1360,21 @@ DefaultCommit<Impl>::markCompletedInsts()
     }
 }
 
-template <class Impl>
-bool
-DefaultCommit<Impl>::robDoneSquashing()
-{
-    list<ThreadID>::iterator threads = activeThreads->begin();
-    list<ThreadID>::iterator end = activeThreads->end();
-
-    while (threads != end) {
-        ThreadID tid = *threads++;
-
-        if (!rob->isDoneSquashing(tid))
-            return false;
-    }
-
-    return true;
-}
-
 template <class Impl>
 void
 DefaultCommit<Impl>::updateComInstStats(DynInstPtr &inst)
 {
     ThreadID tid = inst->threadNumber;
 
-    //
-    //  Pick off the software prefetches
-    //
-#ifdef TARGET_ALPHA
-    if (inst->isDataPrefetch()) {
-        statComSwp[tid]++;
-    } else {
-        statComInst[tid]++;
+    if (!inst->isMicroop() || inst->isLastMicroop())
+        instsCommitted[tid]++;
+    opsCommitted[tid]++;
+
+    // To match the old model, don't count nops and instruction
+    // prefetches towards the total commit count.
+    if (!inst->isNop() && !inst->isInstPrefetch()) {
+        cpu->instDone(tid, inst);
     }
-#else
-    statComInst[tid]++;
-#endif
 
     //
     //  Control Instructions
@@ -1467,3 +1518,5 @@ DefaultCommit<Impl>::oldestReady()
         return InvalidThreadID;
     }
 }
+
+#endif//__CPU_O3_COMMIT_IMPL_HH__