commit_impl.hh revision 3957:37329de528a9
16313Sgblack@eecs.umich.edu/*
26313Sgblack@eecs.umich.edu * Copyright (c) 2004-2006 The Regents of The University of Michigan
36313Sgblack@eecs.umich.edu * All rights reserved.
46313Sgblack@eecs.umich.edu *
56313Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
66313Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
76313Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
86313Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
96313Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
106313Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
116313Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
126313Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
136313Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
146313Sgblack@eecs.umich.edu * this software without specific prior written permission.
156313Sgblack@eecs.umich.edu *
166313Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
176313Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
186313Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
196313Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
206313Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
216313Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
226313Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
236313Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
246313Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
256313Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
266313Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
276313Sgblack@eecs.umich.edu *
286313Sgblack@eecs.umich.edu * Authors: Kevin Lim
296313Sgblack@eecs.umich.edu *          Korey Sewell
306313Sgblack@eecs.umich.edu */
319376Sgblack@eecs.umich.edu
326313Sgblack@eecs.umich.edu#include "config/full_system.hh"
336336Sgblack@eecs.umich.edu#include "config/use_checker.hh"
346336Sgblack@eecs.umich.edu
356313Sgblack@eecs.umich.edu#include <algorithm>
366336Sgblack@eecs.umich.edu#include <string>
376313Sgblack@eecs.umich.edu
386313Sgblack@eecs.umich.edu#include "arch/utility.hh"
396313Sgblack@eecs.umich.edu#include "base/loader/symtab.hh"
406313Sgblack@eecs.umich.edu#include "base/timebuf.hh"
416313Sgblack@eecs.umich.edu#include "cpu/exetrace.hh"
426336Sgblack@eecs.umich.edu#include "cpu/o3/commit.hh"
439376Sgblack@eecs.umich.edu#include "cpu/o3/thread_state.hh"
449376Sgblack@eecs.umich.edu
456336Sgblack@eecs.umich.edu#if USE_CHECKER
466712Snate@binkert.org#include "cpu/checker/cpu.hh"
476336Sgblack@eecs.umich.edu#endif
486336Sgblack@eecs.umich.edu
496336Sgblack@eecs.umich.edutemplate <class Impl>
506336Sgblack@eecs.umich.eduDefaultCommit<Impl>::TrapEvent::TrapEvent(DefaultCommit<Impl> *_commit,
516336Sgblack@eecs.umich.edu                                          unsigned _tid)
526336Sgblack@eecs.umich.edu    : Event(&mainEventQueue, CPU_Tick_Pri), commit(_commit), tid(_tid)
536336Sgblack@eecs.umich.edu{
546336Sgblack@eecs.umich.edu    this->setFlags(Event::AutoDelete);
556336Sgblack@eecs.umich.edu}
566336Sgblack@eecs.umich.edu
576336Sgblack@eecs.umich.edutemplate <class Impl>
586336Sgblack@eecs.umich.eduvoid
596336Sgblack@eecs.umich.eduDefaultCommit<Impl>::TrapEvent::process()
606336Sgblack@eecs.umich.edu{
616336Sgblack@eecs.umich.edu    // This will get reset by commit if it was switched out at the
626336Sgblack@eecs.umich.edu    // time of this event processing.
636336Sgblack@eecs.umich.edu    commit->trapSquash[tid] = true;
646336Sgblack@eecs.umich.edu}
656336Sgblack@eecs.umich.edu
666336Sgblack@eecs.umich.edutemplate <class Impl>
676336Sgblack@eecs.umich.educonst char *
686336Sgblack@eecs.umich.eduDefaultCommit<Impl>::TrapEvent::description()
696336Sgblack@eecs.umich.edu{
706336Sgblack@eecs.umich.edu    return "Trap event";
716336Sgblack@eecs.umich.edu}
726336Sgblack@eecs.umich.edu
736336Sgblack@eecs.umich.edutemplate <class Impl>
746336Sgblack@eecs.umich.eduDefaultCommit<Impl>::DefaultCommit(Params *params)
756336Sgblack@eecs.umich.edu    : squashCounter(0),
766336Sgblack@eecs.umich.edu      iewToCommitDelay(params->iewToCommitDelay),
776336Sgblack@eecs.umich.edu      commitToIEWDelay(params->commitToIEWDelay),
786336Sgblack@eecs.umich.edu      renameToROBDelay(params->renameToROBDelay),
796336Sgblack@eecs.umich.edu      fetchToCommitDelay(params->commitToFetchDelay),
806336Sgblack@eecs.umich.edu      renameWidth(params->renameWidth),
816336Sgblack@eecs.umich.edu      commitWidth(params->commitWidth),
826336Sgblack@eecs.umich.edu      numThreads(params->numberOfThreads),
836336Sgblack@eecs.umich.edu      drainPending(false),
846336Sgblack@eecs.umich.edu      switchedOut(false),
856336Sgblack@eecs.umich.edu      trapLatency(params->trapLatency)
866336Sgblack@eecs.umich.edu{
876336Sgblack@eecs.umich.edu    _status = Active;
886336Sgblack@eecs.umich.edu    _nextStatus = Inactive;
896336Sgblack@eecs.umich.edu    std::string policy = params->smtCommitPolicy;
906336Sgblack@eecs.umich.edu
916336Sgblack@eecs.umich.edu    //Convert string to lowercase
926336Sgblack@eecs.umich.edu    std::transform(policy.begin(), policy.end(), policy.begin(),
936336Sgblack@eecs.umich.edu                   (int(*)(int)) tolower);
946336Sgblack@eecs.umich.edu
956336Sgblack@eecs.umich.edu    //Assign commit policy
966336Sgblack@eecs.umich.edu    if (policy == "aggressive"){
976336Sgblack@eecs.umich.edu        commitPolicy = Aggressive;
986336Sgblack@eecs.umich.edu
999376Sgblack@eecs.umich.edu        DPRINTF(Commit,"Commit Policy set to Aggressive.");
1009376Sgblack@eecs.umich.edu    } else if (policy == "roundrobin"){
1016336Sgblack@eecs.umich.edu        commitPolicy = RoundRobin;
1026336Sgblack@eecs.umich.edu
1036336Sgblack@eecs.umich.edu        //Set-Up Priority List
1046313Sgblack@eecs.umich.edu        for (int tid=0; tid < numThreads; tid++) {
1056313Sgblack@eecs.umich.edu            priority_list.push_back(tid);
1066336Sgblack@eecs.umich.edu        }
1076336Sgblack@eecs.umich.edu
1086336Sgblack@eecs.umich.edu        DPRINTF(Commit,"Commit Policy set to Round Robin.");
1096336Sgblack@eecs.umich.edu    } else if (policy == "oldestready"){
1106336Sgblack@eecs.umich.edu        commitPolicy = OldestReady;
1116313Sgblack@eecs.umich.edu
1126313Sgblack@eecs.umich.edu        DPRINTF(Commit,"Commit Policy set to Oldest Ready.");
1136313Sgblack@eecs.umich.edu    } else {
1146313Sgblack@eecs.umich.edu        assert(0 && "Invalid SMT Commit Policy. Options Are: {Aggressive,"
1156313Sgblack@eecs.umich.edu               "RoundRobin,OldestReady}");
1166336Sgblack@eecs.umich.edu    }
1176336Sgblack@eecs.umich.edu
1186336Sgblack@eecs.umich.edu    for (int i=0; i < numThreads; i++) {
1196336Sgblack@eecs.umich.edu        commitStatus[i] = Idle;
1206336Sgblack@eecs.umich.edu        changedROBNumEntries[i] = false;
1216336Sgblack@eecs.umich.edu        trapSquash[i] = false;
1226336Sgblack@eecs.umich.edu        tcSquash[i] = false;
1236336Sgblack@eecs.umich.edu        PC[i] = nextPC[i] = nextNPC[i] = 0;
1246336Sgblack@eecs.umich.edu    }
1256336Sgblack@eecs.umich.edu#if FULL_SYSTEM
1266313Sgblack@eecs.umich.edu    interrupt = NoFault;
1276313Sgblack@eecs.umich.edu#endif
1286313Sgblack@eecs.umich.edu}
1296336Sgblack@eecs.umich.edu
1306313Sgblack@eecs.umich.edutemplate <class Impl>
1316336Sgblack@eecs.umich.edustd::string
1326336Sgblack@eecs.umich.eduDefaultCommit<Impl>::name() const
1336336Sgblack@eecs.umich.edu{
1349372Snilay@cs.wisc.edu    return cpu->name() + ".commit";
1359372Snilay@cs.wisc.edu}
1369372Snilay@cs.wisc.edu
1379372Snilay@cs.wisc.edutemplate <class Impl>
1389372Snilay@cs.wisc.eduvoid
1399372Snilay@cs.wisc.eduDefaultCommit<Impl>::regStats()
1409372Snilay@cs.wisc.edu{
1416336Sgblack@eecs.umich.edu    using namespace Stats;
1426313Sgblack@eecs.umich.edu    commitCommittedInsts
1436313Sgblack@eecs.umich.edu        .name(name() + ".commitCommittedInsts")
1446313Sgblack@eecs.umich.edu        .desc("The number of committed instructions")
1456336Sgblack@eecs.umich.edu        .prereq(commitCommittedInsts);
1466313Sgblack@eecs.umich.edu    commitSquashedInsts
1476336Sgblack@eecs.umich.edu        .name(name() + ".commitSquashedInsts")
1486336Sgblack@eecs.umich.edu        .desc("The number of squashed insts skipped by commit")
1496336Sgblack@eecs.umich.edu        .prereq(commitSquashedInsts);
1506336Sgblack@eecs.umich.edu    commitSquashEvents
1516336Sgblack@eecs.umich.edu        .name(name() + ".commitSquashEvents")
1526336Sgblack@eecs.umich.edu        .desc("The number of times commit is told to squash")
1536336Sgblack@eecs.umich.edu        .prereq(commitSquashEvents);
1546336Sgblack@eecs.umich.edu    commitNonSpecStalls
1556336Sgblack@eecs.umich.edu        .name(name() + ".commitNonSpecStalls")
1566313Sgblack@eecs.umich.edu        .desc("The number of times commit has been forced to stall to "
1576313Sgblack@eecs.umich.edu              "communicate backwards")
1586313Sgblack@eecs.umich.edu        .prereq(commitNonSpecStalls);
1596336Sgblack@eecs.umich.edu    branchMispredicts
1606313Sgblack@eecs.umich.edu        .name(name() + ".branchMispredicts")
1616336Sgblack@eecs.umich.edu        .desc("The number of times a branch was mispredicted")
1626336Sgblack@eecs.umich.edu        .prereq(branchMispredicts);
1636336Sgblack@eecs.umich.edu    numCommittedDist
1646336Sgblack@eecs.umich.edu        .init(0,commitWidth,1)
1656336Sgblack@eecs.umich.edu        .name(name() + ".COM:committed_per_cycle")
1666336Sgblack@eecs.umich.edu        .desc("Number of insts commited each cycle")
1676336Sgblack@eecs.umich.edu        .flags(Stats::pdf)
1686336Sgblack@eecs.umich.edu        ;
1696336Sgblack@eecs.umich.edu
1706336Sgblack@eecs.umich.edu    statComInst
1716336Sgblack@eecs.umich.edu        .init(cpu->number_of_threads)
1726336Sgblack@eecs.umich.edu        .name(name() + ".COM:count")
1736336Sgblack@eecs.umich.edu        .desc("Number of instructions committed")
1746336Sgblack@eecs.umich.edu        .flags(total)
1756336Sgblack@eecs.umich.edu        ;
1766336Sgblack@eecs.umich.edu
1776336Sgblack@eecs.umich.edu    statComSwp
1786336Sgblack@eecs.umich.edu        .init(cpu->number_of_threads)
1796336Sgblack@eecs.umich.edu        .name(name() + ".COM:swp_count")
1806336Sgblack@eecs.umich.edu        .desc("Number of s/w prefetches committed")
1816336Sgblack@eecs.umich.edu        .flags(total)
1826336Sgblack@eecs.umich.edu        ;
1836336Sgblack@eecs.umich.edu
1846336Sgblack@eecs.umich.edu    statComRefs
1856336Sgblack@eecs.umich.edu        .init(cpu->number_of_threads)
1866336Sgblack@eecs.umich.edu        .name(name() +  ".COM:refs")
1876336Sgblack@eecs.umich.edu        .desc("Number of memory references committed")
1886336Sgblack@eecs.umich.edu        .flags(total)
1896336Sgblack@eecs.umich.edu        ;
1906336Sgblack@eecs.umich.edu
1919376Sgblack@eecs.umich.edu    statComLoads
1929376Sgblack@eecs.umich.edu        .init(cpu->number_of_threads)
1936336Sgblack@eecs.umich.edu        .name(name() +  ".COM:loads")
1946336Sgblack@eecs.umich.edu        .desc("Number of loads committed")
1956336Sgblack@eecs.umich.edu        .flags(total)
1966336Sgblack@eecs.umich.edu        ;
1976336Sgblack@eecs.umich.edu
1986336Sgblack@eecs.umich.edu    statComMembars
1996336Sgblack@eecs.umich.edu        .init(cpu->number_of_threads)
2006336Sgblack@eecs.umich.edu        .name(name() +  ".COM:membars")
2016336Sgblack@eecs.umich.edu        .desc("Number of memory barriers committed")
2026336Sgblack@eecs.umich.edu        .flags(total)
2036336Sgblack@eecs.umich.edu        ;
2046336Sgblack@eecs.umich.edu
2056336Sgblack@eecs.umich.edu    statComBranches
2066336Sgblack@eecs.umich.edu        .init(cpu->number_of_threads)
2076336Sgblack@eecs.umich.edu        .name(name() + ".COM:branches")
2086336Sgblack@eecs.umich.edu        .desc("Number of branches committed")
2096336Sgblack@eecs.umich.edu        .flags(total)
2106336Sgblack@eecs.umich.edu        ;
2116336Sgblack@eecs.umich.edu
2126336Sgblack@eecs.umich.edu    commitEligible
2136336Sgblack@eecs.umich.edu        .init(cpu->number_of_threads)
2146336Sgblack@eecs.umich.edu        .name(name() + ".COM:bw_limited")
2156336Sgblack@eecs.umich.edu        .desc("number of insts not committed due to BW limits")
2166336Sgblack@eecs.umich.edu        .flags(total)
2176336Sgblack@eecs.umich.edu        ;
2186336Sgblack@eecs.umich.edu
2196336Sgblack@eecs.umich.edu    commitEligibleSamples
2206336Sgblack@eecs.umich.edu        .name(name() + ".COM:bw_lim_events")
2216336Sgblack@eecs.umich.edu        .desc("number cycles where commit BW limit reached")
2226336Sgblack@eecs.umich.edu        ;
2236336Sgblack@eecs.umich.edu}
2246336Sgblack@eecs.umich.edu
2256336Sgblack@eecs.umich.edutemplate <class Impl>
2266336Sgblack@eecs.umich.eduvoid
2276336Sgblack@eecs.umich.eduDefaultCommit<Impl>::setCPU(O3CPU *cpu_ptr)
2286336Sgblack@eecs.umich.edu{
2296336Sgblack@eecs.umich.edu    DPRINTF(Commit, "Commit: Setting CPU pointer.\n");
2306336Sgblack@eecs.umich.edu    cpu = cpu_ptr;
2316336Sgblack@eecs.umich.edu
2326336Sgblack@eecs.umich.edu    // Commit must broadcast the number of free entries it has at the start of
2339376Sgblack@eecs.umich.edu    // the simulation, so it starts as active.
2349376Sgblack@eecs.umich.edu    cpu->activateStage(O3CPU::CommitIdx);
2356336Sgblack@eecs.umich.edu
2366336Sgblack@eecs.umich.edu    trapLatency = cpu->cycles(trapLatency);
2376336Sgblack@eecs.umich.edu}
2386336Sgblack@eecs.umich.edu
2396336Sgblack@eecs.umich.edutemplate <class Impl>
2406336Sgblack@eecs.umich.eduvoid
2416336Sgblack@eecs.umich.eduDefaultCommit<Impl>::setThreads(std::vector<Thread *> &threads)
2429376Sgblack@eecs.umich.edu{
2439376Sgblack@eecs.umich.edu    thread = threads;
2446336Sgblack@eecs.umich.edu}
2456336Sgblack@eecs.umich.edu
2466336Sgblack@eecs.umich.edutemplate <class Impl>
2476336Sgblack@eecs.umich.eduvoid
2486336Sgblack@eecs.umich.eduDefaultCommit<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
2496336Sgblack@eecs.umich.edu{
2506336Sgblack@eecs.umich.edu    DPRINTF(Commit, "Commit: Setting time buffer pointer.\n");
2516336Sgblack@eecs.umich.edu    timeBuffer = tb_ptr;
2526336Sgblack@eecs.umich.edu
2536336Sgblack@eecs.umich.edu    // Setup wire to send information back to IEW.
2546336Sgblack@eecs.umich.edu    toIEW = timeBuffer->getWire(0);
2556336Sgblack@eecs.umich.edu
2566336Sgblack@eecs.umich.edu    // Setup wire to read data from IEW (for the ROB).
2576336Sgblack@eecs.umich.edu    robInfoFromIEW = timeBuffer->getWire(-iewToCommitDelay);
2586336Sgblack@eecs.umich.edu}
2596336Sgblack@eecs.umich.edu
2606336Sgblack@eecs.umich.edutemplate <class Impl>
2616336Sgblack@eecs.umich.eduvoid
2626336Sgblack@eecs.umich.eduDefaultCommit<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr)
2636336Sgblack@eecs.umich.edu{
2646336Sgblack@eecs.umich.edu    DPRINTF(Commit, "Commit: Setting fetch queue pointer.\n");
2656336Sgblack@eecs.umich.edu    fetchQueue = fq_ptr;
2666336Sgblack@eecs.umich.edu
2676336Sgblack@eecs.umich.edu    // Setup wire to get instructions from rename (for the ROB).
2686336Sgblack@eecs.umich.edu    fromFetch = fetchQueue->getWire(-fetchToCommitDelay);
2696336Sgblack@eecs.umich.edu}
2706336Sgblack@eecs.umich.edu
2716336Sgblack@eecs.umich.edutemplate <class Impl>
2726336Sgblack@eecs.umich.eduvoid
2736336Sgblack@eecs.umich.eduDefaultCommit<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr)
2746336Sgblack@eecs.umich.edu{
2756336Sgblack@eecs.umich.edu    DPRINTF(Commit, "Commit: Setting rename queue pointer.\n");
2766336Sgblack@eecs.umich.edu    renameQueue = rq_ptr;
2776336Sgblack@eecs.umich.edu
2786336Sgblack@eecs.umich.edu    // Setup wire to get instructions from rename (for the ROB).
2796336Sgblack@eecs.umich.edu    fromRename = renameQueue->getWire(-renameToROBDelay);
2806336Sgblack@eecs.umich.edu}
2816336Sgblack@eecs.umich.edu
2826336Sgblack@eecs.umich.edutemplate <class Impl>
2836336Sgblack@eecs.umich.eduvoid
2846336Sgblack@eecs.umich.eduDefaultCommit<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr)
2856336Sgblack@eecs.umich.edu{
2866336Sgblack@eecs.umich.edu    DPRINTF(Commit, "Commit: Setting IEW queue pointer.\n");
2876336Sgblack@eecs.umich.edu    iewQueue = iq_ptr;
2886336Sgblack@eecs.umich.edu
2896336Sgblack@eecs.umich.edu    // Setup wire to get instructions from IEW.
2906336Sgblack@eecs.umich.edu    fromIEW = iewQueue->getWire(-iewToCommitDelay);
2916336Sgblack@eecs.umich.edu}
2926336Sgblack@eecs.umich.edu
2936336Sgblack@eecs.umich.edutemplate <class Impl>
2946336Sgblack@eecs.umich.eduvoid
2956336Sgblack@eecs.umich.eduDefaultCommit<Impl>::setIEWStage(IEW *iew_stage)
2966336Sgblack@eecs.umich.edu{
2976336Sgblack@eecs.umich.edu    iewStage = iew_stage;
2986336Sgblack@eecs.umich.edu}
2996336Sgblack@eecs.umich.edu
3006336Sgblack@eecs.umich.edutemplate<class Impl>
3016336Sgblack@eecs.umich.eduvoid
3026336Sgblack@eecs.umich.eduDefaultCommit<Impl>::setActiveThreads(std::list<unsigned> *at_ptr)
3036336Sgblack@eecs.umich.edu{
3046336Sgblack@eecs.umich.edu    DPRINTF(Commit, "Commit: Setting active threads list pointer.\n");
3056336Sgblack@eecs.umich.edu    activeThreads = at_ptr;
3066336Sgblack@eecs.umich.edu}
3076336Sgblack@eecs.umich.edu
3086336Sgblack@eecs.umich.edutemplate <class Impl>
3096336Sgblack@eecs.umich.eduvoid
3106336Sgblack@eecs.umich.eduDefaultCommit<Impl>::setRenameMap(RenameMap rm_ptr[])
3116336Sgblack@eecs.umich.edu{
3126336Sgblack@eecs.umich.edu    DPRINTF(Commit, "Setting rename map pointers.\n");
3136336Sgblack@eecs.umich.edu
3146336Sgblack@eecs.umich.edu    for (int i=0; i < numThreads; i++) {
3156336Sgblack@eecs.umich.edu        renameMap[i] = &rm_ptr[i];
3166336Sgblack@eecs.umich.edu    }
3176336Sgblack@eecs.umich.edu}
3186336Sgblack@eecs.umich.edu
3196336Sgblack@eecs.umich.edutemplate <class Impl>
3206336Sgblack@eecs.umich.eduvoid
3216336Sgblack@eecs.umich.eduDefaultCommit<Impl>::setROB(ROB *rob_ptr)
3226336Sgblack@eecs.umich.edu{
3236336Sgblack@eecs.umich.edu    DPRINTF(Commit, "Commit: Setting ROB pointer.\n");
3246336Sgblack@eecs.umich.edu    rob = rob_ptr;
3256336Sgblack@eecs.umich.edu}
3266336Sgblack@eecs.umich.edu
3276336Sgblack@eecs.umich.edutemplate <class Impl>
3286336Sgblack@eecs.umich.eduvoid
3296336Sgblack@eecs.umich.eduDefaultCommit<Impl>::initStage()
3306336Sgblack@eecs.umich.edu{
3316336Sgblack@eecs.umich.edu    rob->setActiveThreads(activeThreads);
3326336Sgblack@eecs.umich.edu    rob->resetEntries();
3336336Sgblack@eecs.umich.edu
3346336Sgblack@eecs.umich.edu    // Broadcast the number of free entries.
3356336Sgblack@eecs.umich.edu    for (int i=0; i < numThreads; i++) {
3366336Sgblack@eecs.umich.edu        toIEW->commitInfo[i].usedROB = true;
3376336Sgblack@eecs.umich.edu        toIEW->commitInfo[i].freeROBEntries = rob->numFreeEntries(i);
3386336Sgblack@eecs.umich.edu    }
3396336Sgblack@eecs.umich.edu
3406336Sgblack@eecs.umich.edu    cpu->activityThisCycle();
3416336Sgblack@eecs.umich.edu}
3426336Sgblack@eecs.umich.edu
3436336Sgblack@eecs.umich.edutemplate <class Impl>
3446336Sgblack@eecs.umich.edubool
3456336Sgblack@eecs.umich.eduDefaultCommit<Impl>::drain()
3466336Sgblack@eecs.umich.edu{
3476336Sgblack@eecs.umich.edu    drainPending = true;
3486336Sgblack@eecs.umich.edu
3496336Sgblack@eecs.umich.edu    return false;
3509376Sgblack@eecs.umich.edu}
3519376Sgblack@eecs.umich.edu
3526336Sgblack@eecs.umich.edutemplate <class Impl>
3536336Sgblack@eecs.umich.eduvoid
3546336Sgblack@eecs.umich.eduDefaultCommit<Impl>::switchOut()
3556336Sgblack@eecs.umich.edu{
3566336Sgblack@eecs.umich.edu    switchedOut = true;
3576336Sgblack@eecs.umich.edu    drainPending = false;
3586336Sgblack@eecs.umich.edu    rob->switchOut();
3596336Sgblack@eecs.umich.edu}
3606336Sgblack@eecs.umich.edu
3616336Sgblack@eecs.umich.edutemplate <class Impl>
3626336Sgblack@eecs.umich.eduvoid
3636336Sgblack@eecs.umich.eduDefaultCommit<Impl>::resume()
3646336Sgblack@eecs.umich.edu{
3656336Sgblack@eecs.umich.edu    drainPending = false;
3666336Sgblack@eecs.umich.edu}
3676336Sgblack@eecs.umich.edu
3686336Sgblack@eecs.umich.edutemplate <class Impl>
3696336Sgblack@eecs.umich.eduvoid
3707533Ssteve.reinhardt@amd.comDefaultCommit<Impl>::takeOverFrom()
3717533Ssteve.reinhardt@amd.com{
3727533Ssteve.reinhardt@amd.com    switchedOut = false;
3737533Ssteve.reinhardt@amd.com    _status = Active;
3749376Sgblack@eecs.umich.edu    _nextStatus = Inactive;
3759376Sgblack@eecs.umich.edu    for (int i=0; i < numThreads; i++) {
3766313Sgblack@eecs.umich.edu        commitStatus[i] = Idle;
3776313Sgblack@eecs.umich.edu        changedROBNumEntries[i] = false;
3786313Sgblack@eecs.umich.edu        trapSquash[i] = false;
379        tcSquash[i] = false;
380    }
381    squashCounter = 0;
382    rob->takeOverFrom();
383}
384
385template <class Impl>
386void
387DefaultCommit<Impl>::updateStatus()
388{
389    // reset ROB changed variable
390    std::list<unsigned>::iterator threads = (*activeThreads).begin();
391    while (threads != (*activeThreads).end()) {
392        unsigned tid = *threads++;
393        changedROBNumEntries[tid] = false;
394
395        // Also check if any of the threads has a trap pending
396        if (commitStatus[tid] == TrapPending ||
397            commitStatus[tid] == FetchTrapPending) {
398            _nextStatus = Active;
399        }
400    }
401
402    if (_nextStatus == Inactive && _status == Active) {
403        DPRINTF(Activity, "Deactivating stage.\n");
404        cpu->deactivateStage(O3CPU::CommitIdx);
405    } else if (_nextStatus == Active && _status == Inactive) {
406        DPRINTF(Activity, "Activating stage.\n");
407        cpu->activateStage(O3CPU::CommitIdx);
408    }
409
410    _status = _nextStatus;
411}
412
413template <class Impl>
414void
415DefaultCommit<Impl>::setNextStatus()
416{
417    int squashes = 0;
418
419    std::list<unsigned>::iterator threads = (*activeThreads).begin();
420
421    while (threads != (*activeThreads).end()) {
422        unsigned tid = *threads++;
423
424        if (commitStatus[tid] == ROBSquashing) {
425            squashes++;
426        }
427    }
428
429    squashCounter = squashes;
430
431    // If commit is currently squashing, then it will have activity for the
432    // next cycle. Set its next status as active.
433    if (squashCounter) {
434        _nextStatus = Active;
435    }
436}
437
438template <class Impl>
439bool
440DefaultCommit<Impl>::changedROBEntries()
441{
442    std::list<unsigned>::iterator threads = (*activeThreads).begin();
443
444    while (threads != (*activeThreads).end()) {
445        unsigned tid = *threads++;
446
447        if (changedROBNumEntries[tid]) {
448            return true;
449        }
450    }
451
452    return false;
453}
454
455template <class Impl>
456unsigned
457DefaultCommit<Impl>::numROBFreeEntries(unsigned tid)
458{
459    return rob->numFreeEntries(tid);
460}
461
462template <class Impl>
463void
464DefaultCommit<Impl>::generateTrapEvent(unsigned tid)
465{
466    DPRINTF(Commit, "Generating trap event for [tid:%i]\n", tid);
467
468    TrapEvent *trap = new TrapEvent(this, tid);
469
470    trap->schedule(curTick + trapLatency);
471
472    thread[tid]->trapPending = true;
473}
474
475template <class Impl>
476void
477DefaultCommit<Impl>::generateTCEvent(unsigned tid)
478{
479    DPRINTF(Commit, "Generating TC squash event for [tid:%i]\n", tid);
480
481    tcSquash[tid] = true;
482}
483
484template <class Impl>
485void
486DefaultCommit<Impl>::squashAll(unsigned tid)
487{
488    // If we want to include the squashing instruction in the squash,
489    // then use one older sequence number.
490    // Hopefully this doesn't mess things up.  Basically I want to squash
491    // all instructions of this thread.
492    InstSeqNum squashed_inst = rob->isEmpty() ?
493        0 : rob->readHeadInst(tid)->seqNum - 1;;
494
495    // All younger instructions will be squashed. Set the sequence
496    // number as the youngest instruction in the ROB (0 in this case.
497    // Hopefully nothing breaks.)
498    youngestSeqNum[tid] = 0;
499
500    rob->squash(squashed_inst, tid);
501    changedROBNumEntries[tid] = true;
502
503    // Send back the sequence number of the squashed instruction.
504    toIEW->commitInfo[tid].doneSeqNum = squashed_inst;
505
506    // Send back the squash signal to tell stages that they should
507    // squash.
508    toIEW->commitInfo[tid].squash = true;
509
510    // Send back the rob squashing signal so other stages know that
511    // the ROB is in the process of squashing.
512    toIEW->commitInfo[tid].robSquashing = true;
513
514    toIEW->commitInfo[tid].branchMispredict = false;
515
516    toIEW->commitInfo[tid].nextPC = PC[tid];
517    toIEW->commitInfo[tid].nextNPC = nextPC[tid];
518}
519
520template <class Impl>
521void
522DefaultCommit<Impl>::squashFromTrap(unsigned tid)
523{
524    squashAll(tid);
525
526    DPRINTF(Commit, "Squashing from trap, restarting at PC %#x\n", PC[tid]);
527
528    thread[tid]->trapPending = false;
529    thread[tid]->inSyscall = false;
530
531    trapSquash[tid] = false;
532
533    commitStatus[tid] = ROBSquashing;
534    cpu->activityThisCycle();
535}
536
537template <class Impl>
538void
539DefaultCommit<Impl>::squashFromTC(unsigned tid)
540{
541    squashAll(tid);
542
543    DPRINTF(Commit, "Squashing from TC, restarting at PC %#x\n", PC[tid]);
544
545    thread[tid]->inSyscall = false;
546    assert(!thread[tid]->trapPending);
547
548    commitStatus[tid] = ROBSquashing;
549    cpu->activityThisCycle();
550
551    tcSquash[tid] = false;
552}
553
554template <class Impl>
555void
556DefaultCommit<Impl>::tick()
557{
558    wroteToTimeBuffer = false;
559    _nextStatus = Inactive;
560
561    if (drainPending && rob->isEmpty() && !iewStage->hasStoresToWB()) {
562        cpu->signalDrained();
563        drainPending = false;
564        return;
565    }
566
567    if ((*activeThreads).size() <= 0)
568        return;
569
570    std::list<unsigned>::iterator threads = (*activeThreads).begin();
571
572    // Check if any of the threads are done squashing.  Change the
573    // status if they are done.
574    while (threads != (*activeThreads).end()) {
575        unsigned tid = *threads++;
576
577        if (commitStatus[tid] == ROBSquashing) {
578
579            if (rob->isDoneSquashing(tid)) {
580                commitStatus[tid] = Running;
581            } else {
582                DPRINTF(Commit,"[tid:%u]: Still Squashing, cannot commit any"
583                        " insts this cycle.\n", tid);
584                rob->doSquash(tid);
585                toIEW->commitInfo[tid].robSquashing = true;
586                wroteToTimeBuffer = true;
587            }
588        }
589    }
590
591    commit();
592
593    markCompletedInsts();
594
595    threads = (*activeThreads).begin();
596
597    while (threads != (*activeThreads).end()) {
598        unsigned tid = *threads++;
599
600        if (!rob->isEmpty(tid) && rob->readHeadInst(tid)->readyToCommit()) {
601            // The ROB has more instructions it can commit. Its next status
602            // will be active.
603            _nextStatus = Active;
604
605            DynInstPtr inst = rob->readHeadInst(tid);
606
607            DPRINTF(Commit,"[tid:%i]: Instruction [sn:%lli] PC %#x is head of"
608                    " ROB and ready to commit\n",
609                    tid, inst->seqNum, inst->readPC());
610
611        } else if (!rob->isEmpty(tid)) {
612            DynInstPtr inst = rob->readHeadInst(tid);
613
614            DPRINTF(Commit,"[tid:%i]: Can't commit, Instruction [sn:%lli] PC "
615                    "%#x is head of ROB and not ready\n",
616                    tid, inst->seqNum, inst->readPC());
617        }
618
619        DPRINTF(Commit, "[tid:%i]: ROB has %d insts & %d free entries.\n",
620                tid, rob->countInsts(tid), rob->numFreeEntries(tid));
621    }
622
623
624    if (wroteToTimeBuffer) {
625        DPRINTF(Activity, "Activity This Cycle.\n");
626        cpu->activityThisCycle();
627    }
628
629    updateStatus();
630}
631
632template <class Impl>
633void
634DefaultCommit<Impl>::commit()
635{
636
637    //////////////////////////////////////
638    // Check for interrupts
639    //////////////////////////////////////
640
641#if FULL_SYSTEM
642    if (interrupt != NoFault) {
643        // Wait until the ROB is empty and all stores have drained in
644        // order to enter the interrupt.
645        if (rob->isEmpty() && !iewStage->hasStoresToWB()) {
646            // Squash or record that I need to squash this cycle if
647            // an interrupt needed to be handled.
648            DPRINTF(Commit, "Interrupt detected.\n");
649
650            assert(!thread[0]->inSyscall);
651            thread[0]->inSyscall = true;
652
653            // CPU will handle interrupt.
654            cpu->processInterrupts(interrupt);
655
656            thread[0]->inSyscall = false;
657
658            commitStatus[0] = TrapPending;
659
660            // Generate trap squash event.
661            generateTrapEvent(0);
662
663            // Clear the interrupt now that it's been handled
664            toIEW->commitInfo[0].clearInterrupt = true;
665            interrupt = NoFault;
666        } else {
667            DPRINTF(Commit, "Interrupt pending, waiting for ROB to empty.\n");
668        }
669    } else if (cpu->checkInterrupts &&
670        cpu->check_interrupts(cpu->tcBase(0)) &&
671        commitStatus[0] != TrapPending &&
672        !trapSquash[0] &&
673        !tcSquash[0]) {
674        // Process interrupts if interrupts are enabled, not in PAL
675        // mode, and no other traps or external squashes are currently
676        // pending.
677        // @todo: Allow other threads to handle interrupts.
678
679        // Get any interrupt that happened
680        interrupt = cpu->getInterrupts();
681
682        if (interrupt != NoFault) {
683            // Tell fetch that there is an interrupt pending.  This
684            // will make fetch wait until it sees a non PAL-mode PC,
685            // at which point it stops fetching instructions.
686            toIEW->commitInfo[0].interruptPending = true;
687        }
688    }
689
690#endif // FULL_SYSTEM
691
692    ////////////////////////////////////
693    // Check for any possible squashes, handle them first
694    ////////////////////////////////////
695    std::list<unsigned>::iterator threads = (*activeThreads).begin();
696
697    while (threads != (*activeThreads).end()) {
698        unsigned tid = *threads++;
699
700        // Not sure which one takes priority.  I think if we have
701        // both, that's a bad sign.
702        if (trapSquash[tid] == true) {
703            assert(!tcSquash[tid]);
704            squashFromTrap(tid);
705        } else if (tcSquash[tid] == true) {
706            squashFromTC(tid);
707        }
708
709        // Squashed sequence number must be older than youngest valid
710        // instruction in the ROB. This prevents squashes from younger
711        // instructions overriding squashes from older instructions.
712        if (fromIEW->squash[tid] &&
713            commitStatus[tid] != TrapPending &&
714            fromIEW->squashedSeqNum[tid] <= youngestSeqNum[tid]) {
715
716            DPRINTF(Commit, "[tid:%i]: Squashing due to PC %#x [sn:%i]\n",
717                    tid,
718                    fromIEW->mispredPC[tid],
719                    fromIEW->squashedSeqNum[tid]);
720
721            DPRINTF(Commit, "[tid:%i]: Redirecting to PC %#x\n",
722                    tid,
723                    fromIEW->nextPC[tid]);
724
725            commitStatus[tid] = ROBSquashing;
726
727            // If we want to include the squashing instruction in the squash,
728            // then use one older sequence number.
729            InstSeqNum squashed_inst = fromIEW->squashedSeqNum[tid];
730
731#if ISA_HAS_DELAY_SLOT
732            InstSeqNum bdelay_done_seq_num = squashed_inst;
733            bool squash_bdelay_slot = fromIEW->squashDelaySlot[tid];
734            bool branchMispredict = fromIEW->branchMispredict[tid];
735
736            // Squashing/not squashing the branch delay slot only makes
737            // sense when you're squashing from a branch, ie from a branch
738            // mispredict.
739            if (branchMispredict && !squash_bdelay_slot) {
740                bdelay_done_seq_num++;
741            }
742#endif
743
744            if (fromIEW->includeSquashInst[tid] == true) {
745                squashed_inst--;
746#if ISA_HAS_DELAY_SLOT
747                bdelay_done_seq_num--;
748#endif
749            }
750            // All younger instructions will be squashed. Set the sequence
751            // number as the youngest instruction in the ROB.
752            youngestSeqNum[tid] = squashed_inst;
753
754#if ISA_HAS_DELAY_SLOT
755            rob->squash(bdelay_done_seq_num, tid);
756            toIEW->commitInfo[tid].squashDelaySlot = squash_bdelay_slot;
757            toIEW->commitInfo[tid].bdelayDoneSeqNum = bdelay_done_seq_num;
758#else
759            rob->squash(squashed_inst, tid);
760            toIEW->commitInfo[tid].squashDelaySlot = true;
761#endif
762            changedROBNumEntries[tid] = true;
763
764            toIEW->commitInfo[tid].doneSeqNum = squashed_inst;
765
766            toIEW->commitInfo[tid].squash = true;
767
768            // Send back the rob squashing signal so other stages know that
769            // the ROB is in the process of squashing.
770            toIEW->commitInfo[tid].robSquashing = true;
771
772            toIEW->commitInfo[tid].branchMispredict =
773                fromIEW->branchMispredict[tid];
774
775            toIEW->commitInfo[tid].branchTaken =
776                fromIEW->branchTaken[tid];
777
778            toIEW->commitInfo[tid].nextPC = fromIEW->nextPC[tid];
779            toIEW->commitInfo[tid].nextNPC = fromIEW->nextNPC[tid];
780
781            toIEW->commitInfo[tid].mispredPC = fromIEW->mispredPC[tid];
782
783            if (toIEW->commitInfo[tid].branchMispredict) {
784                ++branchMispredicts;
785            }
786        }
787
788    }
789
790    setNextStatus();
791
792    if (squashCounter != numThreads) {
793        // If we're not currently squashing, then get instructions.
794        getInsts();
795
796        // Try to commit any instructions.
797        commitInsts();
798    } else {
799#if ISA_HAS_DELAY_SLOT
800        skidInsert();
801#endif
802    }
803
804    //Check for any activity
805    threads = (*activeThreads).begin();
806
807    while (threads != (*activeThreads).end()) {
808        unsigned tid = *threads++;
809
810        if (changedROBNumEntries[tid]) {
811            toIEW->commitInfo[tid].usedROB = true;
812            toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid);
813
814            if (rob->isEmpty(tid)) {
815                toIEW->commitInfo[tid].emptyROB = true;
816            }
817
818            wroteToTimeBuffer = true;
819            changedROBNumEntries[tid] = false;
820        }
821    }
822}
823
824template <class Impl>
825void
826DefaultCommit<Impl>::commitInsts()
827{
828    ////////////////////////////////////
829    // Handle commit
830    // Note that commit will be handled prior to putting new
831    // instructions in the ROB so that the ROB only tries to commit
832    // instructions it has in this current cycle, and not instructions
833    // it is writing in during this cycle.  Can't commit and squash
834    // things at the same time...
835    ////////////////////////////////////
836
837    DPRINTF(Commit, "Trying to commit instructions in the ROB.\n");
838
839    unsigned num_committed = 0;
840
841    DynInstPtr head_inst;
842
843    // Commit as many instructions as possible until the commit bandwidth
844    // limit is reached, or it becomes impossible to commit any more.
845    while (num_committed < commitWidth) {
846        int commit_thread = getCommittingThread();
847
848        if (commit_thread == -1 || !rob->isHeadReady(commit_thread))
849            break;
850
851        head_inst = rob->readHeadInst(commit_thread);
852
853        int tid = head_inst->threadNumber;
854
855        assert(tid == commit_thread);
856
857        DPRINTF(Commit, "Trying to commit head instruction, [sn:%i] [tid:%i]\n",
858                head_inst->seqNum, tid);
859
860        // If the head instruction is squashed, it is ready to retire
861        // (be removed from the ROB) at any time.
862        if (head_inst->isSquashed()) {
863
864            DPRINTF(Commit, "Retiring squashed instruction from "
865                    "ROB.\n");
866
867            rob->retireHead(commit_thread);
868
869            ++commitSquashedInsts;
870
871            // Record that the number of ROB entries has changed.
872            changedROBNumEntries[tid] = true;
873        } else {
874            PC[tid] = head_inst->readPC();
875            nextPC[tid] = head_inst->readNextPC();
876            nextNPC[tid] = head_inst->readNextNPC();
877
878            // Increment the total number of non-speculative instructions
879            // executed.
880            // Hack for now: it really shouldn't happen until after the
881            // commit is deemed to be successful, but this count is needed
882            // for syscalls.
883            thread[tid]->funcExeInst++;
884
885            // Try to commit the head instruction.
886            bool commit_success = commitHead(head_inst, num_committed);
887
888            if (commit_success) {
889                ++num_committed;
890
891                changedROBNumEntries[tid] = true;
892
893                // Set the doneSeqNum to the youngest committed instruction.
894                toIEW->commitInfo[tid].doneSeqNum = head_inst->seqNum;
895
896                ++commitCommittedInsts;
897
898                // To match the old model, don't count nops and instruction
899                // prefetches towards the total commit count.
900                if (!head_inst->isNop() && !head_inst->isInstPrefetch()) {
901                    cpu->instDone(tid);
902                }
903
904                PC[tid] = nextPC[tid];
905#if ISA_HAS_DELAY_SLOT
906                nextPC[tid] = nextNPC[tid];
907                nextNPC[tid] = nextNPC[tid] + sizeof(TheISA::MachInst);
908#else
909                nextPC[tid] = nextPC[tid] + sizeof(TheISA::MachInst);
910#endif
911
912#if FULL_SYSTEM
913                int count = 0;
914                Addr oldpc;
915                do {
916                    // Debug statement.  Checks to make sure we're not
917                    // currently updating state while handling PC events.
918                    if (count == 0)
919                        assert(!thread[tid]->inSyscall &&
920                               !thread[tid]->trapPending);
921                    oldpc = PC[tid];
922                    cpu->system->pcEventQueue.service(
923                        thread[tid]->getTC());
924                    count++;
925                } while (oldpc != PC[tid]);
926                if (count > 1) {
927                    DPRINTF(Commit, "PC skip function event, stopping commit\n");
928                    break;
929                }
930#endif
931            } else {
932                DPRINTF(Commit, "Unable to commit head instruction PC:%#x "
933                        "[tid:%i] [sn:%i].\n",
934                        head_inst->readPC(), tid ,head_inst->seqNum);
935                break;
936            }
937        }
938    }
939
940    DPRINTF(CommitRate, "%i\n", num_committed);
941    numCommittedDist.sample(num_committed);
942
943    if (num_committed == commitWidth) {
944        commitEligibleSamples++;
945    }
946}
947
948template <class Impl>
949bool
950DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
951{
952    assert(head_inst);
953
954    int tid = head_inst->threadNumber;
955
956    // If the instruction is not executed yet, then it will need extra
957    // handling.  Signal backwards that it should be executed.
958    if (!head_inst->isExecuted()) {
959        // Keep this number correct.  We have not yet actually executed
960        // and committed this instruction.
961        thread[tid]->funcExeInst--;
962
963        head_inst->setAtCommit();
964
965        if (head_inst->isNonSpeculative() ||
966            head_inst->isStoreConditional() ||
967            head_inst->isMemBarrier() ||
968            head_inst->isWriteBarrier()) {
969
970            DPRINTF(Commit, "Encountered a barrier or non-speculative "
971                    "instruction [sn:%lli] at the head of the ROB, PC %#x.\n",
972                    head_inst->seqNum, head_inst->readPC());
973
974#if !FULL_SYSTEM
975            // Hack to make sure syscalls/memory barriers/quiesces
976            // aren't executed until all stores write back their data.
977            // This direct communication shouldn't be used for
978            // anything other than this.
979            if (inst_num > 0 || iewStage->hasStoresToWB())
980#else
981            if ((head_inst->isMemBarrier() || head_inst->isWriteBarrier() ||
982                    head_inst->isQuiesce()) &&
983                iewStage->hasStoresToWB())
984#endif
985            {
986                DPRINTF(Commit, "Waiting for all stores to writeback.\n");
987                return false;
988            }
989
990            toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum;
991
992            // Change the instruction so it won't try to commit again until
993            // it is executed.
994            head_inst->clearCanCommit();
995
996            ++commitNonSpecStalls;
997
998            return false;
999        } else if (head_inst->isLoad()) {
1000            DPRINTF(Commit, "[sn:%lli]: Uncached load, PC %#x.\n",
1001                    head_inst->seqNum, head_inst->readPC());
1002
1003            // Send back the non-speculative instruction's sequence
1004            // number.  Tell the lsq to re-execute the load.
1005            toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum;
1006            toIEW->commitInfo[tid].uncached = true;
1007            toIEW->commitInfo[tid].uncachedLoad = head_inst;
1008
1009            head_inst->clearCanCommit();
1010
1011            return false;
1012        } else {
1013            panic("Trying to commit un-executed instruction "
1014                  "of unknown type!\n");
1015        }
1016    }
1017
1018    if (head_inst->isThreadSync()) {
1019        // Not handled for now.
1020        panic("Thread sync instructions are not handled yet.\n");
1021    }
1022
1023    // Stores mark themselves as completed.
1024    if (!head_inst->isStore()) {
1025        head_inst->setCompleted();
1026    }
1027
1028#if USE_CHECKER
1029    // Use checker prior to updating anything due to traps or PC
1030    // based events.
1031    if (cpu->checker) {
1032        cpu->checker->verify(head_inst);
1033    }
1034#endif
1035
1036    // Check if the instruction caused a fault.  If so, trap.
1037    Fault inst_fault = head_inst->getFault();
1038
1039    // DTB will sometimes need the machine instruction for when
1040    // faults happen.  So we will set it here, prior to the DTB
1041    // possibly needing it for its fault.
1042    thread[tid]->setInst(
1043        static_cast<TheISA::MachInst>(head_inst->staticInst->machInst));
1044
1045    if (inst_fault != NoFault) {
1046        head_inst->setCompleted();
1047        DPRINTF(Commit, "Inst [sn:%lli] PC %#x has a fault\n",
1048                head_inst->seqNum, head_inst->readPC());
1049
1050        if (iewStage->hasStoresToWB() || inst_num > 0) {
1051            DPRINTF(Commit, "Stores outstanding, fault must wait.\n");
1052            return false;
1053        }
1054
1055#if USE_CHECKER
1056        if (cpu->checker && head_inst->isStore()) {
1057            cpu->checker->verify(head_inst);
1058        }
1059#endif
1060
1061        assert(!thread[tid]->inSyscall);
1062
1063        // Mark that we're in state update mode so that the trap's
1064        // execution doesn't generate extra squashes.
1065        thread[tid]->inSyscall = true;
1066
1067        // Execute the trap.  Although it's slightly unrealistic in
1068        // terms of timing (as it doesn't wait for the full timing of
1069        // the trap event to complete before updating state), it's
1070        // needed to update the state as soon as possible.  This
1071        // prevents external agents from changing any specific state
1072        // that the trap need.
1073        cpu->trap(inst_fault, tid);
1074
1075        // Exit state update mode to avoid accidental updating.
1076        thread[tid]->inSyscall = false;
1077
1078        commitStatus[tid] = TrapPending;
1079
1080        // Generate trap squash event.
1081        generateTrapEvent(tid);
1082//        warn("%lli fault (%d) handled @ PC %08p", curTick, inst_fault->name(), head_inst->readPC());
1083        return false;
1084    }
1085
1086    updateComInstStats(head_inst);
1087
1088#if FULL_SYSTEM
1089    if (thread[tid]->profile) {
1090//        bool usermode = TheISA::inUserMode(thread[tid]->getTC());
1091//        thread[tid]->profilePC = usermode ? 1 : head_inst->readPC();
1092        thread[tid]->profilePC = head_inst->readPC();
1093        ProfileNode *node = thread[tid]->profile->consume(thread[tid]->getTC(),
1094                                                          head_inst->staticInst);
1095
1096        if (node)
1097            thread[tid]->profileNode = node;
1098    }
1099#endif
1100
1101    if (head_inst->traceData) {
1102        head_inst->traceData->setFetchSeq(head_inst->seqNum);
1103        head_inst->traceData->setCPSeq(thread[tid]->numInst);
1104        head_inst->traceData->finalize();
1105        head_inst->traceData = NULL;
1106    }
1107
1108    // Update the commit rename map
1109    for (int i = 0; i < head_inst->numDestRegs(); i++) {
1110        renameMap[tid]->setEntry(head_inst->flattenedDestRegIdx(i),
1111                                 head_inst->renamedDestRegIdx(i));
1112    }
1113
1114    if (head_inst->isCopy())
1115        panic("Should not commit any copy instructions!");
1116
1117    // Finally clear the head ROB entry.
1118    rob->retireHead(tid);
1119
1120    // Return true to indicate that we have committed an instruction.
1121    return true;
1122}
1123
1124template <class Impl>
1125void
1126DefaultCommit<Impl>::getInsts()
1127{
1128    DPRINTF(Commit, "Getting instructions from Rename stage.\n");
1129
1130#if ISA_HAS_DELAY_SLOT
1131    // Read any renamed instructions and place them into the ROB.
1132    int insts_to_process = std::min((int)renameWidth,
1133                               (int)(fromRename->size + skidBuffer.size()));
1134    int rename_idx = 0;
1135
1136    DPRINTF(Commit, "%i insts available to process. Rename Insts:%i "
1137            "SkidBuffer Insts:%i\n", insts_to_process, fromRename->size,
1138            skidBuffer.size());
1139#else
1140    // Read any renamed instructions and place them into the ROB.
1141    int insts_to_process = std::min((int)renameWidth, fromRename->size);
1142#endif
1143
1144
1145    for (int inst_num = 0; inst_num < insts_to_process; ++inst_num) {
1146        DynInstPtr inst;
1147
1148#if ISA_HAS_DELAY_SLOT
1149        // Get insts from skidBuffer or from Rename
1150        if (skidBuffer.size() > 0) {
1151            DPRINTF(Commit, "Grabbing skidbuffer inst.\n");
1152            inst = skidBuffer.front();
1153            skidBuffer.pop();
1154        } else {
1155            DPRINTF(Commit, "Grabbing rename inst.\n");
1156            inst = fromRename->insts[rename_idx++];
1157        }
1158#else
1159        inst = fromRename->insts[inst_num];
1160#endif
1161        int tid = inst->threadNumber;
1162
1163        if (!inst->isSquashed() &&
1164            commitStatus[tid] != ROBSquashing) {
1165            changedROBNumEntries[tid] = true;
1166
1167            DPRINTF(Commit, "Inserting PC %#x [sn:%i] [tid:%i] into ROB.\n",
1168                    inst->readPC(), inst->seqNum, tid);
1169
1170            rob->insertInst(inst);
1171
1172            assert(rob->getThreadEntries(tid) <= rob->getMaxEntries(tid));
1173
1174            youngestSeqNum[tid] = inst->seqNum;
1175        } else {
1176            DPRINTF(Commit, "Instruction PC %#x [sn:%i] [tid:%i] was "
1177                    "squashed, skipping.\n",
1178                    inst->readPC(), inst->seqNum, tid);
1179        }
1180    }
1181
1182#if ISA_HAS_DELAY_SLOT
1183    if (rename_idx < fromRename->size) {
1184        DPRINTF(Commit,"Placing Rename Insts into skidBuffer.\n");
1185
1186        for (;
1187             rename_idx < fromRename->size;
1188             rename_idx++) {
1189            DynInstPtr inst = fromRename->insts[rename_idx];
1190
1191            if (!inst->isSquashed()) {
1192                DPRINTF(Commit, "Inserting PC %#x [sn:%i] [tid:%i] into ",
1193                        "skidBuffer.\n", inst->readPC(), inst->seqNum,
1194                        inst->threadNumber);
1195                skidBuffer.push(inst);
1196            } else {
1197                DPRINTF(Commit, "Instruction PC %#x [sn:%i] [tid:%i] was "
1198                        "squashed, skipping.\n",
1199                        inst->readPC(), inst->seqNum, inst->threadNumber);
1200            }
1201        }
1202    }
1203#endif
1204
1205}
1206
1207template <class Impl>
1208void
1209DefaultCommit<Impl>::skidInsert()
1210{
1211    DPRINTF(Commit, "Attempting to any instructions from rename into "
1212            "skidBuffer.\n");
1213
1214    for (int inst_num = 0; inst_num < fromRename->size; ++inst_num) {
1215        DynInstPtr inst = fromRename->insts[inst_num];
1216
1217        if (!inst->isSquashed()) {
1218            DPRINTF(Commit, "Inserting PC %#x [sn:%i] [tid:%i] into ",
1219                    "skidBuffer.\n", inst->readPC(), inst->seqNum,
1220                    inst->threadNumber);
1221            skidBuffer.push(inst);
1222        } else {
1223            DPRINTF(Commit, "Instruction PC %#x [sn:%i] [tid:%i] was "
1224                    "squashed, skipping.\n",
1225                    inst->readPC(), inst->seqNum, inst->threadNumber);
1226        }
1227    }
1228}
1229
1230template <class Impl>
1231void
1232DefaultCommit<Impl>::markCompletedInsts()
1233{
1234    // Grab completed insts out of the IEW instruction queue, and mark
1235    // instructions completed within the ROB.
1236    for (int inst_num = 0;
1237         inst_num < fromIEW->size && fromIEW->insts[inst_num];
1238         ++inst_num)
1239    {
1240        if (!fromIEW->insts[inst_num]->isSquashed()) {
1241            DPRINTF(Commit, "[tid:%i]: Marking PC %#x, [sn:%lli] ready "
1242                    "within ROB.\n",
1243                    fromIEW->insts[inst_num]->threadNumber,
1244                    fromIEW->insts[inst_num]->readPC(),
1245                    fromIEW->insts[inst_num]->seqNum);
1246
1247            // Mark the instruction as ready to commit.
1248            fromIEW->insts[inst_num]->setCanCommit();
1249        }
1250    }
1251}
1252
1253template <class Impl>
1254bool
1255DefaultCommit<Impl>::robDoneSquashing()
1256{
1257    std::list<unsigned>::iterator threads = (*activeThreads).begin();
1258
1259    while (threads != (*activeThreads).end()) {
1260        unsigned tid = *threads++;
1261
1262        if (!rob->isDoneSquashing(tid))
1263            return false;
1264    }
1265
1266    return true;
1267}
1268
1269template <class Impl>
1270void
1271DefaultCommit<Impl>::updateComInstStats(DynInstPtr &inst)
1272{
1273    unsigned thread = inst->threadNumber;
1274
1275    //
1276    //  Pick off the software prefetches
1277    //
1278#ifdef TARGET_ALPHA
1279    if (inst->isDataPrefetch()) {
1280        statComSwp[thread]++;
1281    } else {
1282        statComInst[thread]++;
1283    }
1284#else
1285    statComInst[thread]++;
1286#endif
1287
1288    //
1289    //  Control Instructions
1290    //
1291    if (inst->isControl())
1292        statComBranches[thread]++;
1293
1294    //
1295    //  Memory references
1296    //
1297    if (inst->isMemRef()) {
1298        statComRefs[thread]++;
1299
1300        if (inst->isLoad()) {
1301            statComLoads[thread]++;
1302        }
1303    }
1304
1305    if (inst->isMemBarrier()) {
1306        statComMembars[thread]++;
1307    }
1308}
1309
1310////////////////////////////////////////
1311//                                    //
1312//  SMT COMMIT POLICY MAINTAINED HERE //
1313//                                    //
1314////////////////////////////////////////
1315template <class Impl>
1316int
1317DefaultCommit<Impl>::getCommittingThread()
1318{
1319    if (numThreads > 1) {
1320        switch (commitPolicy) {
1321
1322          case Aggressive:
1323            //If Policy is Aggressive, commit will call
1324            //this function multiple times per
1325            //cycle
1326            return oldestReady();
1327
1328          case RoundRobin:
1329            return roundRobin();
1330
1331          case OldestReady:
1332            return oldestReady();
1333
1334          default:
1335            return -1;
1336        }
1337    } else {
1338        int tid = (*activeThreads).front();
1339
1340        if (commitStatus[tid] == Running ||
1341            commitStatus[tid] == Idle ||
1342            commitStatus[tid] == FetchTrapPending) {
1343            return tid;
1344        } else {
1345            return -1;
1346        }
1347    }
1348}
1349
1350template<class Impl>
1351int
1352DefaultCommit<Impl>::roundRobin()
1353{
1354    std::list<unsigned>::iterator pri_iter = priority_list.begin();
1355    std::list<unsigned>::iterator end      = priority_list.end();
1356
1357    while (pri_iter != end) {
1358        unsigned tid = *pri_iter;
1359
1360        if (commitStatus[tid] == Running ||
1361            commitStatus[tid] == Idle ||
1362            commitStatus[tid] == FetchTrapPending) {
1363
1364            if (rob->isHeadReady(tid)) {
1365                priority_list.erase(pri_iter);
1366                priority_list.push_back(tid);
1367
1368                return tid;
1369            }
1370        }
1371
1372        pri_iter++;
1373    }
1374
1375    return -1;
1376}
1377
1378template<class Impl>
1379int
1380DefaultCommit<Impl>::oldestReady()
1381{
1382    unsigned oldest = 0;
1383    bool first = true;
1384
1385    std::list<unsigned>::iterator threads = (*activeThreads).begin();
1386
1387    while (threads != (*activeThreads).end()) {
1388        unsigned tid = *threads++;
1389
1390        if (!rob->isEmpty(tid) &&
1391            (commitStatus[tid] == Running ||
1392             commitStatus[tid] == Idle ||
1393             commitStatus[tid] == FetchTrapPending)) {
1394
1395            if (rob->isHeadReady(tid)) {
1396
1397                DynInstPtr head_inst = rob->readHeadInst(tid);
1398
1399                if (first) {
1400                    oldest = tid;
1401                    first = false;
1402                } else if (head_inst->seqNum < oldest) {
1403                    oldest = tid;
1404                }
1405            }
1406        }
1407    }
1408
1409    if (!first) {
1410        return oldest;
1411    } else {
1412        return -1;
1413    }
1414}
1415