commit_impl.hh revision 2316
12SN/A/*
21762SN/A * Copyright (c) 2004-2006 The Regents of The University of Michigan
32SN/A * All rights reserved.
42SN/A *
52SN/A * Redistribution and use in source and binary forms, with or without
62SN/A * modification, are permitted provided that the following conditions are
72SN/A * met: redistributions of source code must retain the above copyright
82SN/A * notice, this list of conditions and the following disclaimer;
92SN/A * redistributions in binary form must reproduce the above copyright
102SN/A * notice, this list of conditions and the following disclaimer in the
112SN/A * documentation and/or other materials provided with the distribution;
122SN/A * neither the name of the copyright holders nor the names of its
132SN/A * contributors may be used to endorse or promote products derived from
142SN/A * this software without specific prior written permission.
152SN/A *
162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu */
282665Ssaidi@eecs.umich.edu
292665Ssaidi@eecs.umich.edu#include <algorithm>
302665Ssaidi@eecs.umich.edu#include <cstdio>
312665Ssaidi@eecs.umich.edu#include <cstdlib>
322SN/A#include <cstring>
332SN/A#include <iomanip>
342SN/A#include <stdio.h>
352SN/A#include <string.h>
363506Ssaidi@eecs.umich.edu
373506Ssaidi@eecs.umich.edu#include "base/loader/symtab.hh"
382SN/A#include "base/timebuf.hh"
392973Sgblack@eecs.umich.edu#include "cpu/checker/cpu.hh"
403584Ssaidi@eecs.umich.edu#include "cpu/exetrace.hh"
4156SN/A#include "cpu/o3/commit.hh"
423614Sgblack@eecs.umich.edu#include "cpu/o3/thread_state.hh"
431717SN/A
442518SN/Ausing namespace std;
4556SN/A
462518SN/Atemplate <class Impl>
472518SN/ADefaultCommit<Impl>::TrapEvent::TrapEvent(DefaultCommit<Impl> *_commit,
482SN/A                                          unsigned _tid)
493614Sgblack@eecs.umich.edu    : Event(&mainEventQueue, CPU_Tick_Pri), commit(_commit), tid(_tid)
503614Sgblack@eecs.umich.edu{
513614Sgblack@eecs.umich.edu    this->setFlags(Event::AutoDelete);
523614Sgblack@eecs.umich.edu}
533065Sgblack@eecs.umich.edu
543065Sgblack@eecs.umich.edutemplate <class Impl>
553506Ssaidi@eecs.umich.eduvoid
563065Sgblack@eecs.umich.eduDefaultCommit<Impl>::TrapEvent::process()
572SN/A{
582973Sgblack@eecs.umich.edu    // This will get reset by commit if it was switched out at the
592SN/A    // time of this event processing.
603506Ssaidi@eecs.umich.edu    commit->trapSquash[tid] = true;
613506Ssaidi@eecs.umich.edu}
623506Ssaidi@eecs.umich.edu
633506Ssaidi@eecs.umich.edutemplate <class Impl>
642SN/Aconst char *
652SN/ADefaultCommit<Impl>::TrapEvent::description()
662SN/A{
672SN/A    return "Trap event";
682SN/A}
693748Sgblack@eecs.umich.edu
703748Sgblack@eecs.umich.edutemplate <class Impl>
713748Sgblack@eecs.umich.eduDefaultCommit<Impl>::DefaultCommit(Params *params)
723748Sgblack@eecs.umich.edu    : dcacheInterface(params->dcacheInterface),
733748Sgblack@eecs.umich.edu      squashCounter(0),
743748Sgblack@eecs.umich.edu      iewToCommitDelay(params->iewToCommitDelay),
753748Sgblack@eecs.umich.edu      commitToIEWDelay(params->commitToIEWDelay),
763748Sgblack@eecs.umich.edu      renameToROBDelay(params->renameToROBDelay),
773748Sgblack@eecs.umich.edu      fetchToCommitDelay(params->commitToFetchDelay),
783748Sgblack@eecs.umich.edu      renameWidth(params->renameWidth),
793748Sgblack@eecs.umich.edu      iewWidth(params->executeWidth),
803748Sgblack@eecs.umich.edu      commitWidth(params->commitWidth),
813748Sgblack@eecs.umich.edu      numThreads(params->numberOfThreads),
823748Sgblack@eecs.umich.edu      switchedOut(false),
833748Sgblack@eecs.umich.edu      trapLatency(params->trapLatency),
843748Sgblack@eecs.umich.edu      fetchTrapLatency(params->fetchTrapLatency)
853748Sgblack@eecs.umich.edu{
863748Sgblack@eecs.umich.edu    _status = Active;
873748Sgblack@eecs.umich.edu    _nextStatus = Inactive;
883748Sgblack@eecs.umich.edu    string policy = params->smtCommitPolicy;
893748Sgblack@eecs.umich.edu
903748Sgblack@eecs.umich.edu    //Convert string to lowercase
913748Sgblack@eecs.umich.edu    std::transform(policy.begin(), policy.end(), policy.begin(),
923748Sgblack@eecs.umich.edu                   (int(*)(int)) tolower);
933748Sgblack@eecs.umich.edu
943748Sgblack@eecs.umich.edu    //Assign commit policy
953748Sgblack@eecs.umich.edu    if (policy == "aggressive"){
963748Sgblack@eecs.umich.edu        commitPolicy = Aggressive;
973748Sgblack@eecs.umich.edu
983748Sgblack@eecs.umich.edu        DPRINTF(Commit,"Commit Policy set to Aggressive.");
993748Sgblack@eecs.umich.edu    } else if (policy == "roundrobin"){
1003748Sgblack@eecs.umich.edu        commitPolicy = RoundRobin;
1013748Sgblack@eecs.umich.edu
1023748Sgblack@eecs.umich.edu        //Set-Up Priority List
1033748Sgblack@eecs.umich.edu        for (int tid=0; tid < numThreads; tid++) {
1043748Sgblack@eecs.umich.edu            priority_list.push_back(tid);
1053748Sgblack@eecs.umich.edu        }
1063748Sgblack@eecs.umich.edu
1073748Sgblack@eecs.umich.edu        DPRINTF(Commit,"Commit Policy set to Round Robin.");
1083748Sgblack@eecs.umich.edu    } else if (policy == "oldestready"){
1093748Sgblack@eecs.umich.edu        commitPolicy = OldestReady;
1103748Sgblack@eecs.umich.edu
1113748Sgblack@eecs.umich.edu        DPRINTF(Commit,"Commit Policy set to Oldest Ready.");
1123748Sgblack@eecs.umich.edu    } else {
1133748Sgblack@eecs.umich.edu        assert(0 && "Invalid SMT Commit Policy. Options Are: {Aggressive,"
1143748Sgblack@eecs.umich.edu               "RoundRobin,OldestReady}");
1153748Sgblack@eecs.umich.edu    }
1163748Sgblack@eecs.umich.edu
1173748Sgblack@eecs.umich.edu    for (int i=0; i < numThreads; i++) {
1183748Sgblack@eecs.umich.edu        commitStatus[i] = Idle;
1192SN/A        changedROBNumEntries[i] = false;
1202SN/A        trapSquash[i] = false;
1212SN/A        xcSquash[i] = false;
1222SN/A    }
1232973Sgblack@eecs.umich.edu
1242973Sgblack@eecs.umich.edu    fetchFaultTick = 0;
1253065Sgblack@eecs.umich.edu    fetchTrapWait = 0;
1263380Sgblack@eecs.umich.edu}
1273380Sgblack@eecs.umich.edu
1283380Sgblack@eecs.umich.edutemplate <class Impl>
1293380Sgblack@eecs.umich.edustd::string
1303380Sgblack@eecs.umich.eduDefaultCommit<Impl>::name() const
1313380Sgblack@eecs.umich.edu{
1323380Sgblack@eecs.umich.edu    return cpu->name() + ".commit";
1333380Sgblack@eecs.umich.edu}
1343380Sgblack@eecs.umich.edu
1353380Sgblack@eecs.umich.edutemplate <class Impl>
1363380Sgblack@eecs.umich.eduvoid
1373380Sgblack@eecs.umich.eduDefaultCommit<Impl>::regStats()
1383380Sgblack@eecs.umich.edu{
1393380Sgblack@eecs.umich.edu    using namespace Stats;
1403065Sgblack@eecs.umich.edu    commitCommittedInsts
1413588Sgblack@eecs.umich.edu        .name(name() + ".commitCommittedInsts")
1423588Sgblack@eecs.umich.edu        .desc("The number of committed instructions")
1433588Sgblack@eecs.umich.edu        .prereq(commitCommittedInsts);
1443380Sgblack@eecs.umich.edu    commitSquashedInsts
1453380Sgblack@eecs.umich.edu        .name(name() + ".commitSquashedInsts")
1463059Sgblack@eecs.umich.edu        .desc("The number of squashed insts skipped by commit")
1473588Sgblack@eecs.umich.edu        .prereq(commitSquashedInsts);
1483380Sgblack@eecs.umich.edu    commitSquashEvents
1493380Sgblack@eecs.umich.edu        .name(name() + ".commitSquashEvents")
1503380Sgblack@eecs.umich.edu        .desc("The number of times commit is told to squash")
1513380Sgblack@eecs.umich.edu        .prereq(commitSquashEvents);
1523380Sgblack@eecs.umich.edu    commitNonSpecStalls
1533588Sgblack@eecs.umich.edu        .name(name() + ".commitNonSpecStalls")
1543380Sgblack@eecs.umich.edu        .desc("The number of times commit has been forced to stall to "
1553380Sgblack@eecs.umich.edu              "communicate backwards")
1563380Sgblack@eecs.umich.edu        .prereq(commitNonSpecStalls);
1573380Sgblack@eecs.umich.edu    branchMispredicts
1583380Sgblack@eecs.umich.edu        .name(name() + ".branchMispredicts")
1593059Sgblack@eecs.umich.edu        .desc("The number of times a branch was mispredicted")
1603380Sgblack@eecs.umich.edu        .prereq(branchMispredicts);
1613380Sgblack@eecs.umich.edu    numCommittedDist
1623380Sgblack@eecs.umich.edu        .init(0,commitWidth,1)
1633380Sgblack@eecs.umich.edu        .name(name() + ".COM:committed_per_cycle")
1643588Sgblack@eecs.umich.edu        .desc("Number of insts commited each cycle")
1653380Sgblack@eecs.umich.edu        .flags(Stats::pdf)
1663380Sgblack@eecs.umich.edu        ;
1673059Sgblack@eecs.umich.edu
1683059Sgblack@eecs.umich.edu    statComInst
1693380Sgblack@eecs.umich.edu        .init(cpu->number_of_threads)
1703380Sgblack@eecs.umich.edu        .name(name() + ".COM:count")
1713380Sgblack@eecs.umich.edu        .desc("Number of instructions committed")
1723380Sgblack@eecs.umich.edu        .flags(total)
1733380Sgblack@eecs.umich.edu        ;
1743588Sgblack@eecs.umich.edu
1753380Sgblack@eecs.umich.edu    statComSwp
1763380Sgblack@eecs.umich.edu        .init(cpu->number_of_threads)
1773380Sgblack@eecs.umich.edu        .name(name() + ".COM:swp_count")
1783588Sgblack@eecs.umich.edu        .desc("Number of s/w prefetches committed")
1793059Sgblack@eecs.umich.edu        .flags(total)
1803065Sgblack@eecs.umich.edu        ;
1812973Sgblack@eecs.umich.edu
1822973Sgblack@eecs.umich.edu    statComRefs
1831968SN/A        .init(cpu->number_of_threads)
1843064Sgblack@eecs.umich.edu        .name(name() +  ".COM:refs")
1851968SN/A        .desc("Number of memory references committed")
1861968SN/A        .flags(total)
1871968SN/A        ;
1881968SN/A
1891967SN/A    statComLoads
1901967SN/A        .init(cpu->number_of_threads)
1911967SN/A        .name(name() +  ".COM:loads")
1921967SN/A        .desc("Number of loads committed")
1931967SN/A        .flags(total)
1941967SN/A        ;
1951967SN/A
1961967SN/A    statComMembars
1971967SN/A        .init(cpu->number_of_threads)
1981967SN/A        .name(name() +  ".COM:membars")
1991904SN/A        .desc("Number of memory barriers committed")
2001904SN/A        .flags(total)
2011904SN/A        ;
2021904SN/A
203452SN/A    statComBranches
2043064Sgblack@eecs.umich.edu        .init(cpu->number_of_threads)
2052SN/A        .name(name() + ".COM:branches")
2061904SN/A        .desc("Number of branches committed")
2071904SN/A        .flags(total)
2082SN/A        ;
2091904SN/A
2103064Sgblack@eecs.umich.edu    //
2112SN/A    //  Commit-Eligible instructions...
2122SN/A    //
2131904SN/A    //  -> The number of instructions eligible to commit in those
2141904SN/A    //  cycles where we reached our commit BW limit (less the number
2151904SN/A    //  actually committed)
2162299SN/A    //
2172299SN/A    //  -> The average value is computed over ALL CYCLES... not just
2181904SN/A    //  the BW limited cycles
2191904SN/A    //
2201904SN/A    //  -> The standard deviation is computed only over cycles where
2211904SN/A    //  we reached the BW limit
2221904SN/A    //
2231904SN/A    commitEligible
2241904SN/A        .init(cpu->number_of_threads)
225452SN/A        .name(name() + ".COM:bw_limited")
2261904SN/A        .desc("number of insts not committed due to BW limits")
2271904SN/A        .flags(total)
2281904SN/A        ;
2292SN/A
2302SN/A    commitEligibleSamples
2311904SN/A        .name(name() + ".COM:bw_lim_events")
2321904SN/A        .desc("number cycles where commit BW limit reached")
2331904SN/A        ;
2341904SN/A}
2351904SN/A
2361904SN/Atemplate <class Impl>
2372SN/Avoid
2381904SN/ADefaultCommit<Impl>::setCPU(FullCPU *cpu_ptr)
2392SN/A{
2402SN/A    DPRINTF(Commit, "Commit: Setting CPU pointer.\n");
2411904SN/A    cpu = cpu_ptr;
2422SN/A
2431904SN/A    // Commit must broadcast the number of free entries it has at the start of
2441904SN/A    // the simulation, so it starts as active.
2451904SN/A    cpu->activateStage(FullCPU::CommitIdx);
2461904SN/A
2471904SN/A    trapLatency = cpu->cycles(trapLatency);
2481904SN/A    fetchTrapLatency = cpu->cycles(fetchTrapLatency);
2491904SN/A}
2501904SN/A
2511904SN/Atemplate <class Impl>
2521904SN/Avoid
2531904SN/ADefaultCommit<Impl>::setThreads(vector<Thread *> &threads)
2541904SN/A{
2551904SN/A    thread = threads;
2561904SN/A}
2571904SN/A
2581904SN/Atemplate <class Impl>
2591904SN/Avoid
2601904SN/ADefaultCommit<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
2611904SN/A{
2621904SN/A    DPRINTF(Commit, "Commit: Setting time buffer pointer.\n");
2632525SN/A    timeBuffer = tb_ptr;
2641904SN/A
2652525SN/A    // Setup wire to send information back to IEW.
2662525SN/A    toIEW = timeBuffer->getWire(0);
2672525SN/A
2681904SN/A    // Setup wire to read data from IEW (for the ROB).
2691904SN/A    robInfoFromIEW = timeBuffer->getWire(-iewToCommitDelay);
2701904SN/A}
2711904SN/A
2721904SN/Atemplate <class Impl>
2731904SN/Avoid
2741904SN/ADefaultCommit<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr)
2751904SN/A{
2761967SN/A    DPRINTF(Commit, "Commit: Setting fetch queue pointer.\n");
2771967SN/A    fetchQueue = fq_ptr;
2781967SN/A
2791967SN/A    // Setup wire to get instructions from rename (for the ROB).
2801967SN/A    fromFetch = fetchQueue->getWire(-fetchToCommitDelay);
2812SN/A}
2823584Ssaidi@eecs.umich.edu
2833506Ssaidi@eecs.umich.edutemplate <class Impl>
2843506Ssaidi@eecs.umich.eduvoid
2853506Ssaidi@eecs.umich.eduDefaultCommit<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr)
2863506Ssaidi@eecs.umich.edu{
2873506Ssaidi@eecs.umich.edu    DPRINTF(Commit, "Commit: Setting rename queue pointer.\n");
2883814Ssaidi@eecs.umich.edu    renameQueue = rq_ptr;
2893506Ssaidi@eecs.umich.edu
2903506Ssaidi@eecs.umich.edu    // Setup wire to get instructions from rename (for the ROB).
2913748Sgblack@eecs.umich.edu    fromRename = renameQueue->getWire(-renameToROBDelay);
2923748Sgblack@eecs.umich.edu}
2933748Sgblack@eecs.umich.edu
2943748Sgblack@eecs.umich.edutemplate <class Impl>
2953748Sgblack@eecs.umich.eduvoid
2963748Sgblack@eecs.umich.eduDefaultCommit<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr)
2973748Sgblack@eecs.umich.edu{
2983748Sgblack@eecs.umich.edu    DPRINTF(Commit, "Commit: Setting IEW queue pointer.\n");
2993748Sgblack@eecs.umich.edu    iewQueue = iq_ptr;
3003748Sgblack@eecs.umich.edu
3013748Sgblack@eecs.umich.edu    // Setup wire to get instructions from IEW.
3023748Sgblack@eecs.umich.edu    fromIEW = iewQueue->getWire(-iewToCommitDelay);
3033748Sgblack@eecs.umich.edu}
3043748Sgblack@eecs.umich.edu
3053748Sgblack@eecs.umich.edutemplate <class Impl>
3063748Sgblack@eecs.umich.eduvoid
3073748Sgblack@eecs.umich.eduDefaultCommit<Impl>::setFetchStage(Fetch *fetch_stage)
3083748Sgblack@eecs.umich.edu{
3093748Sgblack@eecs.umich.edu    fetchStage = fetch_stage;
3103748Sgblack@eecs.umich.edu}
3113603Ssaidi@eecs.umich.edu
3123603Ssaidi@eecs.umich.edutemplate <class Impl>
3133506Ssaidi@eecs.umich.eduvoid
3143584Ssaidi@eecs.umich.eduDefaultCommit<Impl>::setIEWStage(IEW *iew_stage)
3153584Ssaidi@eecs.umich.edu{
3163584Ssaidi@eecs.umich.edu    iewStage = iew_stage;
3173748Sgblack@eecs.umich.edu}
3183748Sgblack@eecs.umich.edu
3193603Ssaidi@eecs.umich.edutemplate<class Impl>
3203584Ssaidi@eecs.umich.eduvoid
3213814Ssaidi@eecs.umich.eduDefaultCommit<Impl>::setActiveThreads(list<unsigned> *at_ptr)
3223814Ssaidi@eecs.umich.edu{
3233814Ssaidi@eecs.umich.edu    DPRINTF(Commit, "Commit: Setting active threads list pointer.\n");
3243814Ssaidi@eecs.umich.edu    activeThreads = at_ptr;
3253814Ssaidi@eecs.umich.edu}
3263743Sgblack@eecs.umich.edu
3273743Sgblack@eecs.umich.edutemplate <class Impl>
3283584Ssaidi@eecs.umich.eduvoid
3293743Sgblack@eecs.umich.eduDefaultCommit<Impl>::setRenameMap(RenameMap rm_ptr[])
3303754Sgblack@eecs.umich.edu{
3313603Ssaidi@eecs.umich.edu    DPRINTF(Commit, "Setting rename map pointers.\n");
3323584Ssaidi@eecs.umich.edu
3333603Ssaidi@eecs.umich.edu    for (int i=0; i < numThreads; i++) {
3343584Ssaidi@eecs.umich.edu        renameMap[i] = &rm_ptr[i];
3353748Sgblack@eecs.umich.edu    }
3363748Sgblack@eecs.umich.edu}
3373748Sgblack@eecs.umich.edu
3383748Sgblack@eecs.umich.edutemplate <class Impl>
3393748Sgblack@eecs.umich.eduvoid
3403748Sgblack@eecs.umich.eduDefaultCommit<Impl>::setROB(ROB *rob_ptr)
3413748Sgblack@eecs.umich.edu{
3423748Sgblack@eecs.umich.edu    DPRINTF(Commit, "Commit: Setting ROB pointer.\n");
3433748Sgblack@eecs.umich.edu    rob = rob_ptr;
3443748Sgblack@eecs.umich.edu}
3453748Sgblack@eecs.umich.edu
3463748Sgblack@eecs.umich.edutemplate <class Impl>
3473748Sgblack@eecs.umich.eduvoid
3483748Sgblack@eecs.umich.eduDefaultCommit<Impl>::initStage()
3493748Sgblack@eecs.umich.edu{
3503748Sgblack@eecs.umich.edu    rob->setActiveThreads(activeThreads);
3513748Sgblack@eecs.umich.edu    rob->resetEntries();
3523748Sgblack@eecs.umich.edu
3533748Sgblack@eecs.umich.edu    // Broadcast the number of free entries.
3543748Sgblack@eecs.umich.edu    for (int i=0; i < numThreads; i++) {
3553748Sgblack@eecs.umich.edu        toIEW->commitInfo[i].usedROB = true;
3563748Sgblack@eecs.umich.edu        toIEW->commitInfo[i].freeROBEntries = rob->numFreeEntries(i);
3573584Ssaidi@eecs.umich.edu    }
3583748Sgblack@eecs.umich.edu
3593748Sgblack@eecs.umich.edu    cpu->activityThisCycle();
3603748Sgblack@eecs.umich.edu}
3613748Sgblack@eecs.umich.edu
3623748Sgblack@eecs.umich.edutemplate <class Impl>
3633748Sgblack@eecs.umich.eduvoid
3643748Sgblack@eecs.umich.eduDefaultCommit<Impl>::switchOut()
3653748Sgblack@eecs.umich.edu{
3663748Sgblack@eecs.umich.edu    switchPending = true;
3673748Sgblack@eecs.umich.edu}
3683748Sgblack@eecs.umich.edu
3693748Sgblack@eecs.umich.edutemplate <class Impl>
3703748Sgblack@eecs.umich.eduvoid
3713748Sgblack@eecs.umich.eduDefaultCommit<Impl>::doSwitchOut()
3723748Sgblack@eecs.umich.edu{
3733748Sgblack@eecs.umich.edu    switchedOut = true;
3743748Sgblack@eecs.umich.edu    switchPending = false;
3753748Sgblack@eecs.umich.edu    rob->switchOut();
3763748Sgblack@eecs.umich.edu}
3773748Sgblack@eecs.umich.edu
3783748Sgblack@eecs.umich.edutemplate <class Impl>
3793748Sgblack@eecs.umich.eduvoid
3803748Sgblack@eecs.umich.eduDefaultCommit<Impl>::takeOverFrom()
3813748Sgblack@eecs.umich.edu{
3823748Sgblack@eecs.umich.edu    switchedOut = false;
3833748Sgblack@eecs.umich.edu    _status = Active;
3843748Sgblack@eecs.umich.edu    _nextStatus = Inactive;
3853748Sgblack@eecs.umich.edu    for (int i=0; i < numThreads; i++) {
3863748Sgblack@eecs.umich.edu        commitStatus[i] = Idle;
3873748Sgblack@eecs.umich.edu        changedROBNumEntries[i] = false;
3883748Sgblack@eecs.umich.edu        trapSquash[i] = false;
3893748Sgblack@eecs.umich.edu        xcSquash[i] = false;
3903748Sgblack@eecs.umich.edu    }
3913748Sgblack@eecs.umich.edu    squashCounter = 0;
3923748Sgblack@eecs.umich.edu    rob->takeOverFrom();
3933748Sgblack@eecs.umich.edu}
3943814Ssaidi@eecs.umich.edu
3953814Ssaidi@eecs.umich.edutemplate <class Impl>
3963748Sgblack@eecs.umich.eduvoid
3973748Sgblack@eecs.umich.eduDefaultCommit<Impl>::updateStatus()
3983748Sgblack@eecs.umich.edu{
3993748Sgblack@eecs.umich.edu    // reset ROB changed variable
4003584Ssaidi@eecs.umich.edu    list<unsigned>::iterator threads = (*activeThreads).begin();
4013584Ssaidi@eecs.umich.edu    while (threads != (*activeThreads).end()) {
4023584Ssaidi@eecs.umich.edu        unsigned tid = *threads++;
4033814Ssaidi@eecs.umich.edu        changedROBNumEntries[tid] = false;
4043814Ssaidi@eecs.umich.edu
4053584Ssaidi@eecs.umich.edu        // Also check if any of the threads has a trap pending
4063584Ssaidi@eecs.umich.edu        if (commitStatus[tid] == TrapPending ||
4073584Ssaidi@eecs.umich.edu            commitStatus[tid] == FetchTrapPending) {
4083584Ssaidi@eecs.umich.edu            _nextStatus = Active;
4093748Sgblack@eecs.umich.edu        }
4103748Sgblack@eecs.umich.edu    }
4113748Sgblack@eecs.umich.edu
4123748Sgblack@eecs.umich.edu    if (_nextStatus == Inactive && _status == Active) {
4133748Sgblack@eecs.umich.edu        DPRINTF(Activity, "Deactivating stage.\n");
4143748Sgblack@eecs.umich.edu        cpu->deactivateStage(FullCPU::CommitIdx);
4153748Sgblack@eecs.umich.edu    } else if (_nextStatus == Active && _status == Inactive) {
4163748Sgblack@eecs.umich.edu        DPRINTF(Activity, "Activating stage.\n");
4173748Sgblack@eecs.umich.edu        cpu->activateStage(FullCPU::CommitIdx);
4183748Sgblack@eecs.umich.edu    }
4193748Sgblack@eecs.umich.edu
4203748Sgblack@eecs.umich.edu    _status = _nextStatus;
4213748Sgblack@eecs.umich.edu}
4223748Sgblack@eecs.umich.edu
4233748Sgblack@eecs.umich.edutemplate <class Impl>
4243748Sgblack@eecs.umich.eduvoid
4253748Sgblack@eecs.umich.eduDefaultCommit<Impl>::setNextStatus()
4263748Sgblack@eecs.umich.edu{
4273748Sgblack@eecs.umich.edu    int squashes = 0;
4283748Sgblack@eecs.umich.edu
4293748Sgblack@eecs.umich.edu    list<unsigned>::iterator threads = (*activeThreads).begin();
4303748Sgblack@eecs.umich.edu
4313748Sgblack@eecs.umich.edu    while (threads != (*activeThreads).end()) {
4323748Sgblack@eecs.umich.edu        unsigned tid = *threads++;
4333748Sgblack@eecs.umich.edu
4343748Sgblack@eecs.umich.edu        if (commitStatus[tid] == ROBSquashing) {
4353748Sgblack@eecs.umich.edu            squashes++;
4363748Sgblack@eecs.umich.edu        }
4373748Sgblack@eecs.umich.edu    }
4383748Sgblack@eecs.umich.edu
4393748Sgblack@eecs.umich.edu    assert(squashes == squashCounter);
4403748Sgblack@eecs.umich.edu
4413748Sgblack@eecs.umich.edu    // If commit is currently squashing, then it will have activity for the
4423748Sgblack@eecs.umich.edu    // next cycle. Set its next status as active.
4433748Sgblack@eecs.umich.edu    if (squashCounter) {
4443748Sgblack@eecs.umich.edu        _nextStatus = Active;
4453748Sgblack@eecs.umich.edu    }
4463748Sgblack@eecs.umich.edu}
4473603Ssaidi@eecs.umich.edu
4483584Ssaidi@eecs.umich.edutemplate <class Impl>
4493603Ssaidi@eecs.umich.edubool
4503584Ssaidi@eecs.umich.eduDefaultCommit<Impl>::changedROBEntries()
4513603Ssaidi@eecs.umich.edu{
4523584Ssaidi@eecs.umich.edu    list<unsigned>::iterator threads = (*activeThreads).begin();
4533584Ssaidi@eecs.umich.edu
4543603Ssaidi@eecs.umich.edu    while (threads != (*activeThreads).end()) {
4553584Ssaidi@eecs.umich.edu        unsigned tid = *threads++;
4563814Ssaidi@eecs.umich.edu
4573814Ssaidi@eecs.umich.edu        if (changedROBNumEntries[tid]) {
4583814Ssaidi@eecs.umich.edu            return true;
4593814Ssaidi@eecs.umich.edu        }
4603814Ssaidi@eecs.umich.edu    }
4613814Ssaidi@eecs.umich.edu
4623814Ssaidi@eecs.umich.edu    return false;
4633584Ssaidi@eecs.umich.edu}
4643584Ssaidi@eecs.umich.edu
4653584Ssaidi@eecs.umich.edutemplate <class Impl>
4663603Ssaidi@eecs.umich.eduunsigned
4673584Ssaidi@eecs.umich.eduDefaultCommit<Impl>::numROBFreeEntries(unsigned tid)
4683584Ssaidi@eecs.umich.edu{
4693748Sgblack@eecs.umich.edu    return rob->numFreeEntries(tid);
4703748Sgblack@eecs.umich.edu}
4713748Sgblack@eecs.umich.edu
4723584Ssaidi@eecs.umich.edutemplate <class Impl>
4733584Ssaidi@eecs.umich.eduvoid
4743584Ssaidi@eecs.umich.eduDefaultCommit<Impl>::generateTrapEvent(unsigned tid)
4753584Ssaidi@eecs.umich.edu{
4763603Ssaidi@eecs.umich.edu    DPRINTF(Commit, "Generating trap event for [tid:%i]\n", tid);
4773748Sgblack@eecs.umich.edu
4783584Ssaidi@eecs.umich.edu    TrapEvent *trap = new TrapEvent(this, tid);
4793748Sgblack@eecs.umich.edu
4803748Sgblack@eecs.umich.edu    trap->schedule(curTick + trapLatency);
4813748Sgblack@eecs.umich.edu
4823748Sgblack@eecs.umich.edu    thread[tid]->trapPending = true;
4833748Sgblack@eecs.umich.edu}
4843748Sgblack@eecs.umich.edu
4853748Sgblack@eecs.umich.edutemplate <class Impl>
4863748Sgblack@eecs.umich.eduvoid
4873748Sgblack@eecs.umich.eduDefaultCommit<Impl>::generateXCEvent(unsigned tid)
4883748Sgblack@eecs.umich.edu{
4893748Sgblack@eecs.umich.edu    DPRINTF(Commit, "Generating XC squash event for [tid:%i]\n", tid);
4903748Sgblack@eecs.umich.edu
4913748Sgblack@eecs.umich.edu    xcSquash[tid] = true;
4923748Sgblack@eecs.umich.edu}
4933748Sgblack@eecs.umich.edu
4943748Sgblack@eecs.umich.edutemplate <class Impl>
4953748Sgblack@eecs.umich.eduvoid
4963748Sgblack@eecs.umich.eduDefaultCommit<Impl>::squashAll(unsigned tid)
4973748Sgblack@eecs.umich.edu{
4983748Sgblack@eecs.umich.edu    // If we want to include the squashing instruction in the squash,
4993748Sgblack@eecs.umich.edu    // then use one older sequence number.
5003748Sgblack@eecs.umich.edu    // Hopefully this doesn't mess things up.  Basically I want to squash
5013748Sgblack@eecs.umich.edu    // all instructions of this thread.
5023748Sgblack@eecs.umich.edu    InstSeqNum squashed_inst = rob->isEmpty() ?
5033748Sgblack@eecs.umich.edu        0 : rob->readHeadInst(tid)->seqNum - 1;;
5043748Sgblack@eecs.umich.edu
5053748Sgblack@eecs.umich.edu    // All younger instructions will be squashed. Set the sequence
5063748Sgblack@eecs.umich.edu    // number as the youngest instruction in the ROB (0 in this case.
5073748Sgblack@eecs.umich.edu    // Hopefully nothing breaks.)
5083748Sgblack@eecs.umich.edu    youngestSeqNum[tid] = 0;
5093748Sgblack@eecs.umich.edu
5103748Sgblack@eecs.umich.edu    rob->squash(squashed_inst, tid);
5113748Sgblack@eecs.umich.edu    changedROBNumEntries[tid] = true;
5123748Sgblack@eecs.umich.edu
5133748Sgblack@eecs.umich.edu    // Send back the sequence number of the squashed instruction.
5143748Sgblack@eecs.umich.edu    toIEW->commitInfo[tid].doneSeqNum = squashed_inst;
5153748Sgblack@eecs.umich.edu
5163748Sgblack@eecs.umich.edu    // Send back the squash signal to tell stages that they should
5173748Sgblack@eecs.umich.edu    // squash.
5183748Sgblack@eecs.umich.edu    toIEW->commitInfo[tid].squash = true;
5193748Sgblack@eecs.umich.edu
5203748Sgblack@eecs.umich.edu    // Send back the rob squashing signal so other stages know that
5213748Sgblack@eecs.umich.edu    // the ROB is in the process of squashing.
5223748Sgblack@eecs.umich.edu    toIEW->commitInfo[tid].robSquashing = true;
5233748Sgblack@eecs.umich.edu
5243748Sgblack@eecs.umich.edu    toIEW->commitInfo[tid].branchMispredict = false;
5253748Sgblack@eecs.umich.edu
5263748Sgblack@eecs.umich.edu    toIEW->commitInfo[tid].nextPC = PC[tid];
5273748Sgblack@eecs.umich.edu}
5283748Sgblack@eecs.umich.edu
5293748Sgblack@eecs.umich.edutemplate <class Impl>
5303748Sgblack@eecs.umich.eduvoid
5313748Sgblack@eecs.umich.eduDefaultCommit<Impl>::squashFromTrap(unsigned tid)
5323748Sgblack@eecs.umich.edu{
5333748Sgblack@eecs.umich.edu    squashAll(tid);
5343748Sgblack@eecs.umich.edu
5353748Sgblack@eecs.umich.edu    DPRINTF(Commit, "Squashing from trap, restarting at PC %#x\n", PC[tid]);
5363748Sgblack@eecs.umich.edu
5373748Sgblack@eecs.umich.edu    thread[tid]->trapPending = false;
5383748Sgblack@eecs.umich.edu    thread[tid]->inSyscall = false;
5393748Sgblack@eecs.umich.edu
5403748Sgblack@eecs.umich.edu    trapSquash[tid] = false;
5413748Sgblack@eecs.umich.edu
5423748Sgblack@eecs.umich.edu    commitStatus[tid] = ROBSquashing;
5433748Sgblack@eecs.umich.edu    cpu->activityThisCycle();
5443748Sgblack@eecs.umich.edu
5453584Ssaidi@eecs.umich.edu    ++squashCounter;
5463584Ssaidi@eecs.umich.edu}
5473748Sgblack@eecs.umich.edu
5483584Ssaidi@eecs.umich.edutemplate <class Impl>
5493584Ssaidi@eecs.umich.eduvoid
5503584Ssaidi@eecs.umich.eduDefaultCommit<Impl>::squashFromXC(unsigned tid)
5513584Ssaidi@eecs.umich.edu{
5523584Ssaidi@eecs.umich.edu    squashAll(tid);
5533748Sgblack@eecs.umich.edu
5543748Sgblack@eecs.umich.edu    DPRINTF(Commit, "Squashing from XC, restarting at PC %#x\n", PC[tid]);
5553748Sgblack@eecs.umich.edu
5563748Sgblack@eecs.umich.edu    thread[tid]->inSyscall = false;
5573748Sgblack@eecs.umich.edu    assert(!thread[tid]->trapPending);
5583748Sgblack@eecs.umich.edu
5593748Sgblack@eecs.umich.edu    commitStatus[tid] = ROBSquashing;
5603748Sgblack@eecs.umich.edu    cpu->activityThisCycle();
5613748Sgblack@eecs.umich.edu
5623748Sgblack@eecs.umich.edu    xcSquash[tid] = false;
5633584Ssaidi@eecs.umich.edu
5643584Ssaidi@eecs.umich.edu    ++squashCounter;
5653584Ssaidi@eecs.umich.edu}
5663748Sgblack@eecs.umich.edu
5673748Sgblack@eecs.umich.edutemplate <class Impl>
5683748Sgblack@eecs.umich.eduvoid
5693584Ssaidi@eecs.umich.eduDefaultCommit<Impl>::tick()
5703584Ssaidi@eecs.umich.edu{
5713584Ssaidi@eecs.umich.edu    wroteToTimeBuffer = false;
5723584Ssaidi@eecs.umich.edu    _nextStatus = Inactive;
5733584Ssaidi@eecs.umich.edu
5743584Ssaidi@eecs.umich.edu    if (switchPending && rob->isEmpty() && !iewStage->hasStoresToWB()) {
5753584Ssaidi@eecs.umich.edu        cpu->signalSwitched();
5763506Ssaidi@eecs.umich.edu        return;
5773584Ssaidi@eecs.umich.edu    }
5783584Ssaidi@eecs.umich.edu
5793506Ssaidi@eecs.umich.edu    list<unsigned>::iterator threads = (*activeThreads).begin();
5803584Ssaidi@eecs.umich.edu
5812SN/A    // Check if any of the threads are done squashing.  Change the
5822SN/A    // status if they are done.
5832SN/A    while (threads != (*activeThreads).end()) {
5842SN/A        unsigned tid = *threads++;
5851967SN/A
5862SN/A        if (commitStatus[tid] == ROBSquashing) {
5872SN/A
5882SN/A            if (rob->isDoneSquashing(tid)) {
5892SN/A                commitStatus[tid] = Running;
5902SN/A                --squashCounter;
5912SN/A            } else {
5922SN/A                DPRINTF(Commit,"[tid:%u]: Still Squashing, cannot commit any"
5932SN/A                        "insts this cycle.\n", tid);
5942SN/A            }
5952SN/A        }
5962SN/A    }
5972SN/A
5982SN/A    commit();
5992SN/A
6002SN/A    markCompletedInsts();
6012SN/A
6022SN/A    threads = (*activeThreads).begin();
6032SN/A
6042SN/A    while (threads != (*activeThreads).end()) {
6052SN/A        unsigned tid = *threads++;
6061413SN/A
6072SN/A        if (!rob->isEmpty(tid) && rob->readHeadInst(tid)->readyToCommit()) {
6082SN/A            // The ROB has more instructions it can commit. Its next status
6092SN/A            // will be active.
6102SN/A            _nextStatus = Active;
6112SN/A
6122SN/A            DynInstPtr inst = rob->readHeadInst(tid);
6132SN/A
6142SN/A            DPRINTF(Commit,"[tid:%i]: Instruction [sn:%lli] PC %#x is head of"
6152SN/A                    " ROB and ready to commit\n",
6162SN/A                    tid, inst->seqNum, inst->readPC());
6172SN/A
6182SN/A        } else if (!rob->isEmpty(tid)) {
6192SN/A            DynInstPtr inst = rob->readHeadInst(tid);
6202SN/A
6212SN/A            DPRINTF(Commit,"[tid:%i]: Can't commit, Instruction [sn:%lli] PC "
6222SN/A                    "%#x is head of ROB and not ready\n",
6232SN/A                    tid, inst->seqNum, inst->readPC());
6242973Sgblack@eecs.umich.edu        }
6252973Sgblack@eecs.umich.edu
6262299SN/A        DPRINTF(Commit, "[tid:%i]: ROB has %d insts & %d free entries.\n",
6272299SN/A                tid, rob->countInsts(tid), rob->numFreeEntries(tid));
6281904SN/A    }
6291904SN/A
6303506Ssaidi@eecs.umich.edu
6313506Ssaidi@eecs.umich.edu    if (wroteToTimeBuffer) {
6323506Ssaidi@eecs.umich.edu        DPRINTF(Activity, "Activity This Cycle.\n");
6331967SN/A        cpu->activityThisCycle();
6341967SN/A    }
6351967SN/A
6361904SN/A    updateStatus();
6372SN/A}
6382SN/A
6392SN/Atemplate <class Impl>
6402SN/Avoid
6412SN/ADefaultCommit<Impl>::commit()
6422SN/A{
6432SN/A
6442SN/A    //////////////////////////////////////
6452SN/A    // Check for interrupts
6462SN/A    //////////////////////////////////////
6472SN/A
6482SN/A#if FULL_SYSTEM
6492SN/A    // Process interrupts if interrupts are enabled, not in PAL mode,
6502SN/A    // and no other traps or external squashes are currently pending.
6512SN/A    // @todo: Allow other threads to handle interrupts.
6522SN/A    if (cpu->checkInterrupts &&
6532SN/A        cpu->check_interrupts() &&
6542SN/A        !cpu->inPalMode(readPC()) &&
6552973Sgblack@eecs.umich.edu        !trapSquash[0] &&
6562299SN/A        !xcSquash[0]) {
6571904SN/A        // Tell fetch that there is an interrupt pending.  This will
6583506Ssaidi@eecs.umich.edu        // make fetch wait until it sees a non PAL-mode PC, at which
6591967SN/A        // point it stops fetching instructions.
6603506Ssaidi@eecs.umich.edu        toIEW->commitInfo[0].interruptPending = true;
6613506Ssaidi@eecs.umich.edu
6623506Ssaidi@eecs.umich.edu        // Wait until the ROB is empty and all stores have drained in
6633506Ssaidi@eecs.umich.edu        // order to enter the interrupt.
6643603Ssaidi@eecs.umich.edu        if (rob->isEmpty() && !iewStage->hasStoresToWB()) {
6653506Ssaidi@eecs.umich.edu            // Not sure which thread should be the one to interrupt.  For now
6663506Ssaidi@eecs.umich.edu            // always do thread 0.
6673506Ssaidi@eecs.umich.edu            assert(!thread[0]->inSyscall);
6683506Ssaidi@eecs.umich.edu            thread[0]->inSyscall = true;
6693506Ssaidi@eecs.umich.edu
6703506Ssaidi@eecs.umich.edu            // CPU will handle implementation of the interrupt.
6713506Ssaidi@eecs.umich.edu            cpu->processInterrupts();
6723506Ssaidi@eecs.umich.edu
6733506Ssaidi@eecs.umich.edu            // Now squash or record that I need to squash this cycle.
6743506Ssaidi@eecs.umich.edu            commitStatus[0] = TrapPending;
6753506Ssaidi@eecs.umich.edu
6763506Ssaidi@eecs.umich.edu            // Exit state update mode to avoid accidental updating.
6773506Ssaidi@eecs.umich.edu            thread[0]->inSyscall = false;
6783506Ssaidi@eecs.umich.edu
6793603Ssaidi@eecs.umich.edu            // Generate trap squash event.
6803603Ssaidi@eecs.umich.edu            generateTrapEvent(0);
6813506Ssaidi@eecs.umich.edu
6822SN/A            toIEW->commitInfo[0].clearInterrupt = true;
6832SN/A
6842SN/A            DPRINTF(Commit, "Interrupt detected.\n");
6852SN/A        } else {
6862SN/A            DPRINTF(Commit, "Interrupt pending, waiting for ROB to empty.\n");
6872SN/A        }
6882SN/A    }
6892SN/A#endif // FULL_SYSTEM
690
691    ////////////////////////////////////
692    // Check for any possible squashes, handle them first
693    ////////////////////////////////////
694
695    list<unsigned>::iterator threads = (*activeThreads).begin();
696
697    while (threads != (*activeThreads).end()) {
698        unsigned tid = *threads++;
699
700        if (fromFetch->fetchFault && commitStatus[0] != TrapPending) {
701            // Record the fault.  Wait until it's empty in the ROB.
702            // Then handle the trap.  Ignore it if there's already a
703            // trap pending as fetch will be redirected.
704            fetchFault = fromFetch->fetchFault;
705            fetchFaultTick = curTick + fetchTrapLatency;
706            commitStatus[0] = FetchTrapPending;
707            DPRINTF(Commit, "Fault from fetch recorded.  Will trap if the "
708                    "ROB empties without squashing the fault.\n");
709            fetchTrapWait = 0;
710        }
711
712        // Fetch may tell commit to clear the trap if it's been squashed.
713        if (fromFetch->clearFetchFault) {
714            DPRINTF(Commit, "Received clear fetch fault signal\n");
715            fetchTrapWait = 0;
716            if (commitStatus[0] == FetchTrapPending) {
717                DPRINTF(Commit, "Clearing fault from fetch\n");
718                commitStatus[0] = Running;
719            }
720        }
721
722        // Not sure which one takes priority.  I think if we have
723        // both, that's a bad sign.
724        if (trapSquash[tid] == true) {
725            assert(!xcSquash[tid]);
726            squashFromTrap(tid);
727        } else if (xcSquash[tid] == true) {
728            squashFromXC(tid);
729        }
730
731        // Squashed sequence number must be older than youngest valid
732        // instruction in the ROB. This prevents squashes from younger
733        // instructions overriding squashes from older instructions.
734        if (fromIEW->squash[tid] &&
735            commitStatus[tid] != TrapPending &&
736            fromIEW->squashedSeqNum[tid] <= youngestSeqNum[tid]) {
737
738            DPRINTF(Commit, "[tid:%i]: Squashing due to PC %#x [sn:%i]\n",
739                    tid,
740                    fromIEW->mispredPC[tid],
741                    fromIEW->squashedSeqNum[tid]);
742
743            DPRINTF(Commit, "[tid:%i]: Redirecting to PC %#x\n",
744                    tid,
745                    fromIEW->nextPC[tid]);
746
747            commitStatus[tid] = ROBSquashing;
748
749            ++squashCounter;
750
751            // If we want to include the squashing instruction in the squash,
752            // then use one older sequence number.
753            InstSeqNum squashed_inst = fromIEW->squashedSeqNum[tid];
754
755            if (fromIEW->includeSquashInst[tid] == true)
756                squashed_inst--;
757
758            // All younger instructions will be squashed. Set the sequence
759            // number as the youngest instruction in the ROB.
760            youngestSeqNum[tid] = squashed_inst;
761
762            rob->squash(squashed_inst, tid);
763            changedROBNumEntries[tid] = true;
764
765            toIEW->commitInfo[tid].doneSeqNum = squashed_inst;
766
767            toIEW->commitInfo[tid].squash = true;
768
769            // Send back the rob squashing signal so other stages know that
770            // the ROB is in the process of squashing.
771            toIEW->commitInfo[tid].robSquashing = true;
772
773            toIEW->commitInfo[tid].branchMispredict =
774                fromIEW->branchMispredict[tid];
775
776            toIEW->commitInfo[tid].branchTaken =
777                fromIEW->branchTaken[tid];
778
779            toIEW->commitInfo[tid].nextPC = fromIEW->nextPC[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    }
799
800    //Check for any activity
801    threads = (*activeThreads).begin();
802
803    while (threads != (*activeThreads).end()) {
804        unsigned tid = *threads++;
805
806        if (changedROBNumEntries[tid]) {
807            toIEW->commitInfo[tid].usedROB = true;
808            toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid);
809
810            if (rob->isEmpty(tid)) {
811                toIEW->commitInfo[tid].emptyROB = true;
812            }
813
814            wroteToTimeBuffer = true;
815            changedROBNumEntries[tid] = false;
816        }
817    }
818}
819
820template <class Impl>
821void
822DefaultCommit<Impl>::commitInsts()
823{
824    ////////////////////////////////////
825    // Handle commit
826    // Note that commit will be handled prior to putting new
827    // instructions in the ROB so that the ROB only tries to commit
828    // instructions it has in this current cycle, and not instructions
829    // it is writing in during this cycle.  Can't commit and squash
830    // things at the same time...
831    ////////////////////////////////////
832
833    DPRINTF(Commit, "Trying to commit instructions in the ROB.\n");
834
835    unsigned num_committed = 0;
836
837    DynInstPtr head_inst;
838#if FULL_SYSTEM
839    // Not the best way to check if the front end is empty, but it should
840    // work.
841    // @todo: Try to avoid directly accessing fetch.
842    if (commitStatus[0] == FetchTrapPending && rob->isEmpty()) {
843        DPRINTF(Commit, "Fault from fetch is pending.\n");
844
845        fetchTrapWait++;
846        if (fetchTrapWait > 10000000) {
847            panic("Fetch trap has been pending for a long time!");
848        }
849        if (fetchFaultTick > curTick) {
850            DPRINTF(Commit, "Not enough cycles since fault, fault will "
851                    "happen on %lli\n",
852                    fetchFaultTick);
853            cpu->activityThisCycle();
854            return;
855        } else if (iewStage->hasStoresToWB()) {
856            DPRINTF(Commit, "IEW still has stores to WB.  Waiting until "
857                    "they are completed. fetchTrapWait:%i\n",
858                    fetchTrapWait);
859            cpu->activityThisCycle();
860            return;
861        } else if (cpu->inPalMode(readPC())) {
862            DPRINTF(Commit, "In pal mode right now. fetchTrapWait:%i\n",
863                    fetchTrapWait);
864            return;
865        } else if (fetchStage->getYoungestSN() > youngestSeqNum[0]) {
866            DPRINTF(Commit, "Waiting for front end to drain. fetchTrapWait:%i\n",
867                    fetchTrapWait);
868            return;
869        }
870        fetchTrapWait = 0;
871        DPRINTF(Commit, "ROB is empty, handling fetch trap.\n");
872
873        assert(!thread[0]->inSyscall);
874
875        thread[0]->inSyscall = true;
876
877        // Consider holding onto the trap and waiting until the trap event
878        // happens for this to be executed.
879        cpu->trap(fetchFault, 0);
880
881        // Exit state update mode to avoid accidental updating.
882        thread[0]->inSyscall = false;
883
884        commitStatus[0] = TrapPending;
885        // Set it up so that we squash next cycle
886        trapSquash[0] = true;
887        return;
888    }
889#endif
890
891    // Commit as many instructions as possible until the commit bandwidth
892    // limit is reached, or it becomes impossible to commit any more.
893    while (num_committed < commitWidth) {
894        int commit_thread = getCommittingThread();
895
896        if (commit_thread == -1 || !rob->isHeadReady(commit_thread))
897            break;
898
899        head_inst = rob->readHeadInst(commit_thread);
900
901        int tid = head_inst->threadNumber;
902
903        assert(tid == commit_thread);
904
905        DPRINTF(Commit, "Trying to commit head instruction, [sn:%i] [tid:%i]\n",
906                head_inst->seqNum, tid);
907
908        // If the head instruction is squashed, it is ready to retire
909        // (be removed from the ROB) at any time.
910        if (head_inst->isSquashed()) {
911
912            DPRINTF(Commit, "Retiring squashed instruction from "
913                    "ROB.\n");
914
915            rob->retireHead(commit_thread);
916
917            ++commitSquashedInsts;
918
919            // Record that the number of ROB entries has changed.
920            changedROBNumEntries[tid] = true;
921        } else {
922            PC[tid] = head_inst->readPC();
923            nextPC[tid] = head_inst->readNextPC();
924
925            // Increment the total number of non-speculative instructions
926            // executed.
927            // Hack for now: it really shouldn't happen until after the
928            // commit is deemed to be successful, but this count is needed
929            // for syscalls.
930            thread[tid]->funcExeInst++;
931
932            // Try to commit the head instruction.
933            bool commit_success = commitHead(head_inst, num_committed);
934
935            if (commit_success) {
936                ++num_committed;
937
938                changedROBNumEntries[tid] = true;
939
940                // Set the doneSeqNum to the youngest committed instruction.
941                toIEW->commitInfo[tid].doneSeqNum = head_inst->seqNum;
942
943                ++commitCommittedInsts;
944
945                // To match the old model, don't count nops and instruction
946                // prefetches towards the total commit count.
947                if (!head_inst->isNop() && !head_inst->isInstPrefetch()) {
948                    cpu->instDone(tid);
949                }
950
951                PC[tid] = nextPC[tid];
952                nextPC[tid] = nextPC[tid] + sizeof(TheISA::MachInst);
953#if FULL_SYSTEM
954                int count = 0;
955                Addr oldpc;
956                do {
957                    // Debug statement.  Checks to make sure we're not
958                    // currently updating state while handling PC events.
959                    if (count == 0)
960                        assert(!thread[tid]->inSyscall &&
961                               !thread[tid]->trapPending);
962                    oldpc = PC[tid];
963                    cpu->system->pcEventQueue.service(
964                        thread[tid]->getXCProxy());
965                    count++;
966                } while (oldpc != PC[tid]);
967                if (count > 1) {
968                    DPRINTF(Commit, "PC skip function event, stopping commit\n");
969                    break;
970                }
971#endif
972            } else {
973                DPRINTF(Commit, "Unable to commit head instruction PC:%#x "
974                        "[tid:%i] [sn:%i].\n",
975                        head_inst->readPC(), tid ,head_inst->seqNum);
976                break;
977            }
978        }
979    }
980
981    DPRINTF(CommitRate, "%i\n", num_committed);
982    numCommittedDist.sample(num_committed);
983
984    if (num_committed == commitWidth) {
985        commitEligible[0]++;
986    }
987}
988
989template <class Impl>
990bool
991DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
992{
993    assert(head_inst);
994
995    int tid = head_inst->threadNumber;
996
997    // If the instruction is not executed yet, then it will need extra
998    // handling.  Signal backwards that it should be executed.
999    if (!head_inst->isExecuted()) {
1000        // Keep this number correct.  We have not yet actually executed
1001        // and committed this instruction.
1002        thread[tid]->funcExeInst--;
1003
1004        head_inst->reachedCommit = true;
1005
1006        if (head_inst->isNonSpeculative() ||
1007            head_inst->isMemBarrier() ||
1008            head_inst->isWriteBarrier()) {
1009
1010            DPRINTF(Commit, "Encountered a barrier or non-speculative "
1011                    "instruction [sn:%lli] at the head of the ROB, PC %#x.\n",
1012                    head_inst->seqNum, head_inst->readPC());
1013
1014#if !FULL_SYSTEM
1015            // Hack to make sure syscalls/memory barriers/quiesces
1016            // aren't executed until all stores write back their data.
1017            // This direct communication shouldn't be used for
1018            // anything other than this.
1019            if (inst_num > 0 || iewStage->hasStoresToWB())
1020#else
1021            if ((head_inst->isMemBarrier() || head_inst->isWriteBarrier() ||
1022                    head_inst->isQuiesce()) &&
1023                iewStage->hasStoresToWB())
1024#endif
1025            {
1026                DPRINTF(Commit, "Waiting for all stores to writeback.\n");
1027                return false;
1028            }
1029
1030            toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum;
1031
1032            // Change the instruction so it won't try to commit again until
1033            // it is executed.
1034            head_inst->clearCanCommit();
1035
1036            ++commitNonSpecStalls;
1037
1038            return false;
1039        } else if (head_inst->isLoad()) {
1040            DPRINTF(Commit, "[sn:%lli]: Uncached load, PC %#x.\n",
1041                    head_inst->seqNum, head_inst->readPC());
1042
1043            // Send back the non-speculative instruction's sequence
1044            // number.  Tell the lsq to re-execute the load.
1045            toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum;
1046            toIEW->commitInfo[tid].uncached = true;
1047            toIEW->commitInfo[tid].uncachedLoad = head_inst;
1048
1049            head_inst->clearCanCommit();
1050
1051            return false;
1052        } else {
1053            panic("Trying to commit un-executed instruction "
1054                  "of unknown type!\n");
1055        }
1056    }
1057
1058    if (head_inst->isThreadSync()) {
1059        // Not handled for now.
1060        panic("Thread sync instructions are not handled yet.\n");
1061    }
1062
1063    // Stores mark themselves as completed.
1064    if (!head_inst->isStore()) {
1065        head_inst->setCompleted();
1066    }
1067
1068    // Use checker prior to updating anything due to traps or PC
1069    // based events.
1070    if (cpu->checker) {
1071        cpu->checker->tick(head_inst);
1072    }
1073
1074    // Check if the instruction caused a fault.  If so, trap.
1075    Fault inst_fault = head_inst->getFault();
1076
1077    if (inst_fault != NoFault) {
1078        head_inst->setCompleted();
1079#if FULL_SYSTEM
1080        DPRINTF(Commit, "Inst [sn:%lli] PC %#x has a fault\n",
1081                head_inst->seqNum, head_inst->readPC());
1082
1083        if (iewStage->hasStoresToWB() || inst_num > 0) {
1084            DPRINTF(Commit, "Stores outstanding, fault must wait.\n");
1085            return false;
1086        }
1087
1088        if (cpu->checker && head_inst->isStore()) {
1089            cpu->checker->tick(head_inst);
1090        }
1091
1092        assert(!thread[tid]->inSyscall);
1093
1094        // Mark that we're in state update mode so that the trap's
1095        // execution doesn't generate extra squashes.
1096        thread[tid]->inSyscall = true;
1097
1098        // DTB will sometimes need the machine instruction for when
1099        // faults happen.  So we will set it here, prior to the DTB
1100        // possibly needing it for its fault.
1101        thread[tid]->setInst(
1102            static_cast<TheISA::MachInst>(head_inst->staticInst->machInst));
1103
1104        // Execute the trap.  Although it's slightly unrealistic in
1105        // terms of timing (as it doesn't wait for the full timing of
1106        // the trap event to complete before updating state), it's
1107        // needed to update the state as soon as possible.  This
1108        // prevents external agents from changing any specific state
1109        // that the trap need.
1110        cpu->trap(inst_fault, tid);
1111
1112        // Exit state update mode to avoid accidental updating.
1113        thread[tid]->inSyscall = false;
1114
1115        commitStatus[tid] = TrapPending;
1116
1117        // Generate trap squash event.
1118        generateTrapEvent(tid);
1119
1120        return false;
1121#else // !FULL_SYSTEM
1122        panic("fault (%d) detected @ PC %08p", inst_fault,
1123              head_inst->PC);
1124#endif // FULL_SYSTEM
1125    }
1126
1127    updateComInstStats(head_inst);
1128
1129    if (head_inst->traceData) {
1130        head_inst->traceData->setFetchSeq(head_inst->seqNum);
1131        head_inst->traceData->setCPSeq(thread[tid]->numInst);
1132        head_inst->traceData->finalize();
1133        head_inst->traceData = NULL;
1134    }
1135
1136    // Update the commit rename map
1137    for (int i = 0; i < head_inst->numDestRegs(); i++) {
1138        renameMap[tid]->setEntry(head_inst->destRegIdx(i),
1139                                 head_inst->renamedDestRegIdx(i));
1140    }
1141
1142    // Finally clear the head ROB entry.
1143    rob->retireHead(tid);
1144
1145    // Return true to indicate that we have committed an instruction.
1146    return true;
1147}
1148
1149template <class Impl>
1150void
1151DefaultCommit<Impl>::getInsts()
1152{
1153    // Read any renamed instructions and place them into the ROB.
1154    int insts_to_process = min((int)renameWidth, fromRename->size);
1155
1156    for (int inst_num = 0; inst_num < insts_to_process; ++inst_num)
1157    {
1158        DynInstPtr inst = fromRename->insts[inst_num];
1159        int tid = inst->threadNumber;
1160
1161        if (!inst->isSquashed() &&
1162            commitStatus[tid] != ROBSquashing) {
1163            changedROBNumEntries[tid] = true;
1164
1165            DPRINTF(Commit, "Inserting PC %#x [sn:%i] [tid:%i] into ROB.\n",
1166                    inst->readPC(), inst->seqNum, tid);
1167
1168            rob->insertInst(inst);
1169
1170            assert(rob->getThreadEntries(tid) <= rob->getMaxEntries(tid));
1171
1172            youngestSeqNum[tid] = inst->seqNum;
1173        } else {
1174            DPRINTF(Commit, "Instruction PC %#x [sn:%i] [tid:%i] was "
1175                    "squashed, skipping.\n",
1176                    inst->readPC(), inst->seqNum, tid);
1177        }
1178    }
1179}
1180
1181template <class Impl>
1182void
1183DefaultCommit<Impl>::markCompletedInsts()
1184{
1185    // Grab completed insts out of the IEW instruction queue, and mark
1186    // instructions completed within the ROB.
1187    for (int inst_num = 0;
1188         inst_num < fromIEW->size && fromIEW->insts[inst_num];
1189         ++inst_num)
1190    {
1191        if (!fromIEW->insts[inst_num]->isSquashed()) {
1192            DPRINTF(Commit, "[tid:%i]: Marking PC %#x, [sn:%lli] ready "
1193                    "within ROB.\n",
1194                    fromIEW->insts[inst_num]->threadNumber,
1195                    fromIEW->insts[inst_num]->readPC(),
1196                    fromIEW->insts[inst_num]->seqNum);
1197
1198            // Mark the instruction as ready to commit.
1199            fromIEW->insts[inst_num]->setCanCommit();
1200        }
1201    }
1202}
1203
1204template <class Impl>
1205bool
1206DefaultCommit<Impl>::robDoneSquashing()
1207{
1208    list<unsigned>::iterator threads = (*activeThreads).begin();
1209
1210    while (threads != (*activeThreads).end()) {
1211        unsigned tid = *threads++;
1212
1213        if (!rob->isDoneSquashing(tid))
1214            return false;
1215    }
1216
1217    return true;
1218}
1219
1220template <class Impl>
1221void
1222DefaultCommit<Impl>::updateComInstStats(DynInstPtr &inst)
1223{
1224    unsigned thread = inst->threadNumber;
1225
1226    //
1227    //  Pick off the software prefetches
1228    //
1229#ifdef TARGET_ALPHA
1230    if (inst->isDataPrefetch()) {
1231        statComSwp[thread]++;
1232    } else {
1233        statComInst[thread]++;
1234    }
1235#else
1236    statComInst[thread]++;
1237#endif
1238
1239    //
1240    //  Control Instructions
1241    //
1242    if (inst->isControl())
1243        statComBranches[thread]++;
1244
1245    //
1246    //  Memory references
1247    //
1248    if (inst->isMemRef()) {
1249        statComRefs[thread]++;
1250
1251        if (inst->isLoad()) {
1252            statComLoads[thread]++;
1253        }
1254    }
1255
1256    if (inst->isMemBarrier()) {
1257        statComMembars[thread]++;
1258    }
1259}
1260
1261////////////////////////////////////////
1262//                                    //
1263//  SMT COMMIT POLICY MAINTAINED HERE //
1264//                                    //
1265////////////////////////////////////////
1266template <class Impl>
1267int
1268DefaultCommit<Impl>::getCommittingThread()
1269{
1270    if (numThreads > 1) {
1271        switch (commitPolicy) {
1272
1273          case Aggressive:
1274            //If Policy is Aggressive, commit will call
1275            //this function multiple times per
1276            //cycle
1277            return oldestReady();
1278
1279          case RoundRobin:
1280            return roundRobin();
1281
1282          case OldestReady:
1283            return oldestReady();
1284
1285          default:
1286            return -1;
1287        }
1288    } else {
1289        int tid = (*activeThreads).front();
1290
1291        if (commitStatus[tid] == Running ||
1292            commitStatus[tid] == Idle ||
1293            commitStatus[tid] == FetchTrapPending) {
1294            return tid;
1295        } else {
1296            return -1;
1297        }
1298    }
1299}
1300
1301template<class Impl>
1302int
1303DefaultCommit<Impl>::roundRobin()
1304{
1305    list<unsigned>::iterator pri_iter = priority_list.begin();
1306    list<unsigned>::iterator end      = priority_list.end();
1307
1308    while (pri_iter != end) {
1309        unsigned tid = *pri_iter;
1310
1311        if (commitStatus[tid] == Running ||
1312            commitStatus[tid] == Idle) {
1313
1314            if (rob->isHeadReady(tid)) {
1315                priority_list.erase(pri_iter);
1316                priority_list.push_back(tid);
1317
1318                return tid;
1319            }
1320        }
1321
1322        pri_iter++;
1323    }
1324
1325    return -1;
1326}
1327
1328template<class Impl>
1329int
1330DefaultCommit<Impl>::oldestReady()
1331{
1332    unsigned oldest = 0;
1333    bool first = true;
1334
1335    list<unsigned>::iterator threads = (*activeThreads).begin();
1336
1337    while (threads != (*activeThreads).end()) {
1338        unsigned tid = *threads++;
1339
1340        if (!rob->isEmpty(tid) &&
1341            (commitStatus[tid] == Running ||
1342             commitStatus[tid] == Idle ||
1343             commitStatus[tid] == FetchTrapPending)) {
1344
1345            if (rob->isHeadReady(tid)) {
1346
1347                DynInstPtr head_inst = rob->readHeadInst(tid);
1348
1349                if (first) {
1350                    oldest = tid;
1351                    first = false;
1352                } else if (head_inst->seqNum < oldest) {
1353                    oldest = tid;
1354                }
1355            }
1356        }
1357    }
1358
1359    if (!first) {
1360        return oldest;
1361    } else {
1362        return -1;
1363    }
1364}
1365