commit_impl.hh revision 2690
1955SN/A/*
2955SN/A * Copyright (c) 2004-2006 The Regents of The University of Michigan
31762SN/A * All rights reserved.
4955SN/A *
5955SN/A * Redistribution and use in source and binary forms, with or without
6955SN/A * modification, are permitted provided that the following conditions are
7955SN/A * met: redistributions of source code must retain the above copyright
8955SN/A * notice, this list of conditions and the following disclaimer;
9955SN/A * redistributions in binary form must reproduce the above copyright
10955SN/A * notice, this list of conditions and the following disclaimer in the
11955SN/A * documentation and/or other materials provided with the distribution;
12955SN/A * neither the name of the copyright holders nor the names of its
13955SN/A * contributors may be used to endorse or promote products derived from
14955SN/A * this software without specific prior written permission.
15955SN/A *
16955SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17955SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18955SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19955SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20955SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21955SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22955SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23955SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24955SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25955SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26955SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27955SN/A *
282665Ssaidi@eecs.umich.edu * Authors: Kevin Lim
294762Snate@binkert.org */
30955SN/A
315522Snate@binkert.org#include <algorithm>
326143Snate@binkert.org#include <string>
334762Snate@binkert.org
345522Snate@binkert.org#include "base/loader/symtab.hh"
35955SN/A#include "base/timebuf.hh"
365522Snate@binkert.org#include "cpu/checker/cpu.hh"
37955SN/A#include "cpu/exetrace.hh"
385522Snate@binkert.org#include "cpu/o3/commit.hh"
394202Sbinkertn@umich.edu#include "cpu/o3/thread_state.hh"
405742Snate@binkert.org
41955SN/Ausing namespace std;
424381Sbinkertn@umich.edu
434381Sbinkertn@umich.edutemplate <class Impl>
448334Snate@binkert.orgDefaultCommit<Impl>::TrapEvent::TrapEvent(DefaultCommit<Impl> *_commit,
45955SN/A                                          unsigned _tid)
46955SN/A    : Event(&mainEventQueue, CPU_Tick_Pri), commit(_commit), tid(_tid)
474202Sbinkertn@umich.edu{
48955SN/A    this->setFlags(Event::AutoDelete);
494382Sbinkertn@umich.edu}
504382Sbinkertn@umich.edu
514382Sbinkertn@umich.edutemplate <class Impl>
526654Snate@binkert.orgvoid
535517Snate@binkert.orgDefaultCommit<Impl>::TrapEvent::process()
548614Sgblack@eecs.umich.edu{
557674Snate@binkert.org    // This will get reset by commit if it was switched out at the
566143Snate@binkert.org    // time of this event processing.
576143Snate@binkert.org    commit->trapSquash[tid] = true;
586143Snate@binkert.org}
598233Snate@binkert.org
608233Snate@binkert.orgtemplate <class Impl>
618233Snate@binkert.orgconst char *
628233Snate@binkert.orgDefaultCommit<Impl>::TrapEvent::description()
638233Snate@binkert.org{
648334Snate@binkert.org    return "Trap event";
658334Snate@binkert.org}
668233Snate@binkert.org
678233Snate@binkert.orgtemplate <class Impl>
688233Snate@binkert.orgDefaultCommit<Impl>::DefaultCommit(Params *params)
698233Snate@binkert.org    : squashCounter(0),
708233Snate@binkert.org      iewToCommitDelay(params->iewToCommitDelay),
718233Snate@binkert.org      commitToIEWDelay(params->commitToIEWDelay),
726143Snate@binkert.org      renameToROBDelay(params->renameToROBDelay),
738233Snate@binkert.org      fetchToCommitDelay(params->commitToFetchDelay),
748233Snate@binkert.org      renameWidth(params->renameWidth),
758233Snate@binkert.org      iewWidth(params->executeWidth),
766143Snate@binkert.org      commitWidth(params->commitWidth),
776143Snate@binkert.org      numThreads(params->numberOfThreads),
786143Snate@binkert.org      switchPending(false),
796143Snate@binkert.org      switchedOut(false),
808233Snate@binkert.org      trapLatency(params->trapLatency),
818233Snate@binkert.org      fetchTrapLatency(params->fetchTrapLatency)
828233Snate@binkert.org{
836143Snate@binkert.org    _status = Active;
848233Snate@binkert.org    _nextStatus = Inactive;
858233Snate@binkert.org    string policy = params->smtCommitPolicy;
868233Snate@binkert.org
878233Snate@binkert.org    //Convert string to lowercase
886143Snate@binkert.org    std::transform(policy.begin(), policy.end(), policy.begin(),
896143Snate@binkert.org                   (int(*)(int)) tolower);
906143Snate@binkert.org
914762Snate@binkert.org    //Assign commit policy
926143Snate@binkert.org    if (policy == "aggressive"){
938233Snate@binkert.org        commitPolicy = Aggressive;
948233Snate@binkert.org
958233Snate@binkert.org        DPRINTF(Commit,"Commit Policy set to Aggressive.");
968233Snate@binkert.org    } else if (policy == "roundrobin"){
978233Snate@binkert.org        commitPolicy = RoundRobin;
986143Snate@binkert.org
998233Snate@binkert.org        //Set-Up Priority List
1008233Snate@binkert.org        for (int tid=0; tid < numThreads; tid++) {
1018233Snate@binkert.org            priority_list.push_back(tid);
1028233Snate@binkert.org        }
1036143Snate@binkert.org
1046143Snate@binkert.org        DPRINTF(Commit,"Commit Policy set to Round Robin.");
1056143Snate@binkert.org    } else if (policy == "oldestready"){
1066143Snate@binkert.org        commitPolicy = OldestReady;
1076143Snate@binkert.org
1086143Snate@binkert.org        DPRINTF(Commit,"Commit Policy set to Oldest Ready.");
1096143Snate@binkert.org    } else {
1106143Snate@binkert.org        assert(0 && "Invalid SMT Commit Policy. Options Are: {Aggressive,"
1116143Snate@binkert.org               "RoundRobin,OldestReady}");
1127065Snate@binkert.org    }
1136143Snate@binkert.org
1148233Snate@binkert.org    for (int i=0; i < numThreads; i++) {
1158233Snate@binkert.org        commitStatus[i] = Idle;
1168233Snate@binkert.org        changedROBNumEntries[i] = false;
1178233Snate@binkert.org        trapSquash[i] = false;
1188233Snate@binkert.org        tcSquash[i] = false;
1198233Snate@binkert.org        PC[i] = nextPC[i] = 0;
1208233Snate@binkert.org    }
1218233Snate@binkert.org
1228233Snate@binkert.org    fetchFaultTick = 0;
1238233Snate@binkert.org    fetchTrapWait = 0;
1248233Snate@binkert.org}
1258233Snate@binkert.org
1268233Snate@binkert.orgtemplate <class Impl>
1278233Snate@binkert.orgstd::string
1288233Snate@binkert.orgDefaultCommit<Impl>::name() const
1298233Snate@binkert.org{
1308233Snate@binkert.org    return cpu->name() + ".commit";
1318233Snate@binkert.org}
1328233Snate@binkert.org
1338233Snate@binkert.orgtemplate <class Impl>
1348233Snate@binkert.orgvoid
1358233Snate@binkert.orgDefaultCommit<Impl>::regStats()
1368233Snate@binkert.org{
1378233Snate@binkert.org    using namespace Stats;
1388233Snate@binkert.org    commitCommittedInsts
1398233Snate@binkert.org        .name(name() + ".commitCommittedInsts")
1408233Snate@binkert.org        .desc("The number of committed instructions")
1418233Snate@binkert.org        .prereq(commitCommittedInsts);
1428233Snate@binkert.org    commitSquashedInsts
1438233Snate@binkert.org        .name(name() + ".commitSquashedInsts")
1448233Snate@binkert.org        .desc("The number of squashed insts skipped by commit")
1456143Snate@binkert.org        .prereq(commitSquashedInsts);
1466143Snate@binkert.org    commitSquashEvents
1476143Snate@binkert.org        .name(name() + ".commitSquashEvents")
1486143Snate@binkert.org        .desc("The number of times commit is told to squash")
1496143Snate@binkert.org        .prereq(commitSquashEvents);
1506143Snate@binkert.org    commitNonSpecStalls
1516143Snate@binkert.org        .name(name() + ".commitNonSpecStalls")
1526143Snate@binkert.org        .desc("The number of times commit has been forced to stall to "
1536143Snate@binkert.org              "communicate backwards")
1548233Snate@binkert.org        .prereq(commitNonSpecStalls);
1558233Snate@binkert.org    branchMispredicts
1568233Snate@binkert.org        .name(name() + ".branchMispredicts")
1576143Snate@binkert.org        .desc("The number of times a branch was mispredicted")
1586143Snate@binkert.org        .prereq(branchMispredicts);
1596143Snate@binkert.org    numCommittedDist
1606143Snate@binkert.org        .init(0,commitWidth,1)
1616143Snate@binkert.org        .name(name() + ".COM:committed_per_cycle")
1626143Snate@binkert.org        .desc("Number of insts commited each cycle")
1635522Snate@binkert.org        .flags(Stats::pdf)
1646143Snate@binkert.org        ;
1656143Snate@binkert.org
1666143Snate@binkert.org    statComInst
1676143Snate@binkert.org        .init(cpu->number_of_threads)
1688233Snate@binkert.org        .name(name() + ".COM:count")
1698233Snate@binkert.org        .desc("Number of instructions committed")
1708233Snate@binkert.org        .flags(total)
1716143Snate@binkert.org        ;
1726143Snate@binkert.org
1736143Snate@binkert.org    statComSwp
1746143Snate@binkert.org        .init(cpu->number_of_threads)
1755522Snate@binkert.org        .name(name() + ".COM:swp_count")
1765522Snate@binkert.org        .desc("Number of s/w prefetches committed")
1775522Snate@binkert.org        .flags(total)
1785522Snate@binkert.org        ;
1795604Snate@binkert.org
1805604Snate@binkert.org    statComRefs
1816143Snate@binkert.org        .init(cpu->number_of_threads)
1826143Snate@binkert.org        .name(name() +  ".COM:refs")
1834762Snate@binkert.org        .desc("Number of memory references committed")
1844762Snate@binkert.org        .flags(total)
1856143Snate@binkert.org        ;
1866727Ssteve.reinhardt@amd.com
1876727Ssteve.reinhardt@amd.com    statComLoads
1886727Ssteve.reinhardt@amd.com        .init(cpu->number_of_threads)
1894762Snate@binkert.org        .name(name() +  ".COM:loads")
1906143Snate@binkert.org        .desc("Number of loads committed")
1916143Snate@binkert.org        .flags(total)
1926143Snate@binkert.org        ;
1936143Snate@binkert.org
1946727Ssteve.reinhardt@amd.com    statComMembars
1956143Snate@binkert.org        .init(cpu->number_of_threads)
1967674Snate@binkert.org        .name(name() +  ".COM:membars")
1977674Snate@binkert.org        .desc("Number of memory barriers committed")
1985604Snate@binkert.org        .flags(total)
1996143Snate@binkert.org        ;
2006143Snate@binkert.org
2016143Snate@binkert.org    statComBranches
2024762Snate@binkert.org        .init(cpu->number_of_threads)
2036143Snate@binkert.org        .name(name() + ".COM:branches")
2044762Snate@binkert.org        .desc("Number of branches committed")
2054762Snate@binkert.org        .flags(total)
2064762Snate@binkert.org        ;
2076143Snate@binkert.org
2086143Snate@binkert.org    //
2094762Snate@binkert.org    //  Commit-Eligible instructions...
2108233Snate@binkert.org    //
2118233Snate@binkert.org    //  -> The number of instructions eligible to commit in those
2128233Snate@binkert.org    //  cycles where we reached our commit BW limit (less the number
2138233Snate@binkert.org    //  actually committed)
2146143Snate@binkert.org    //
2156143Snate@binkert.org    //  -> The average value is computed over ALL CYCLES... not just
2164762Snate@binkert.org    //  the BW limited cycles
2176143Snate@binkert.org    //
2184762Snate@binkert.org    //  -> The standard deviation is computed only over cycles where
2196143Snate@binkert.org    //  we reached the BW limit
2204762Snate@binkert.org    //
2216143Snate@binkert.org    commitEligible
2228233Snate@binkert.org        .init(cpu->number_of_threads)
2238233Snate@binkert.org        .name(name() + ".COM:bw_limited")
2248233Snate@binkert.org        .desc("number of insts not committed due to BW limits")
2256143Snate@binkert.org        .flags(total)
2266143Snate@binkert.org        ;
2276143Snate@binkert.org
2286143Snate@binkert.org    commitEligibleSamples
2296143Snate@binkert.org        .name(name() + ".COM:bw_lim_events")
2306143Snate@binkert.org        .desc("number cycles where commit BW limit reached")
2316143Snate@binkert.org        ;
2326143Snate@binkert.org}
2338233Snate@binkert.org
2348233Snate@binkert.orgtemplate <class Impl>
235955SN/Avoid
2368235Snate@binkert.orgDefaultCommit<Impl>::setCPU(FullCPU *cpu_ptr)
2378235Snate@binkert.org{
2386143Snate@binkert.org    DPRINTF(Commit, "Commit: Setting CPU pointer.\n");
2398235Snate@binkert.org    cpu = cpu_ptr;
2408235Snate@binkert.org
2418235Snate@binkert.org    // Commit must broadcast the number of free entries it has at the start of
2428235Snate@binkert.org    // the simulation, so it starts as active.
2438235Snate@binkert.org    cpu->activateStage(FullCPU::CommitIdx);
2448235Snate@binkert.org
2458235Snate@binkert.org    trapLatency = cpu->cycles(trapLatency);
2468235Snate@binkert.org    fetchTrapLatency = cpu->cycles(fetchTrapLatency);
2478235Snate@binkert.org}
2488235Snate@binkert.org
2498235Snate@binkert.orgtemplate <class Impl>
2508235Snate@binkert.orgvoid
2518235Snate@binkert.orgDefaultCommit<Impl>::setThreads(vector<Thread *> &threads)
2528235Snate@binkert.org{
2538235Snate@binkert.org    thread = threads;
2548235Snate@binkert.org}
2558235Snate@binkert.org
2565584Snate@binkert.orgtemplate <class Impl>
2574382Sbinkertn@umich.eduvoid
2584202Sbinkertn@umich.eduDefaultCommit<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
2594382Sbinkertn@umich.edu{
2604382Sbinkertn@umich.edu    DPRINTF(Commit, "Commit: Setting time buffer pointer.\n");
2614382Sbinkertn@umich.edu    timeBuffer = tb_ptr;
2625584Snate@binkert.org
2634382Sbinkertn@umich.edu    // Setup wire to send information back to IEW.
2644382Sbinkertn@umich.edu    toIEW = timeBuffer->getWire(0);
2654382Sbinkertn@umich.edu
2668232Snate@binkert.org    // Setup wire to read data from IEW (for the ROB).
2675192Ssaidi@eecs.umich.edu    robInfoFromIEW = timeBuffer->getWire(-iewToCommitDelay);
2688232Snate@binkert.org}
2698232Snate@binkert.org
2708232Snate@binkert.orgtemplate <class Impl>
2715192Ssaidi@eecs.umich.eduvoid
2728232Snate@binkert.orgDefaultCommit<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr)
2735192Ssaidi@eecs.umich.edu{
2745799Snate@binkert.org    DPRINTF(Commit, "Commit: Setting fetch queue pointer.\n");
2758232Snate@binkert.org    fetchQueue = fq_ptr;
2765192Ssaidi@eecs.umich.edu
2775192Ssaidi@eecs.umich.edu    // Setup wire to get instructions from rename (for the ROB).
2785192Ssaidi@eecs.umich.edu    fromFetch = fetchQueue->getWire(-fetchToCommitDelay);
2798232Snate@binkert.org}
2805192Ssaidi@eecs.umich.edu
2818232Snate@binkert.orgtemplate <class Impl>
2825192Ssaidi@eecs.umich.eduvoid
2835192Ssaidi@eecs.umich.eduDefaultCommit<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr)
2845192Ssaidi@eecs.umich.edu{
2855192Ssaidi@eecs.umich.edu    DPRINTF(Commit, "Commit: Setting rename queue pointer.\n");
2864382Sbinkertn@umich.edu    renameQueue = rq_ptr;
2874382Sbinkertn@umich.edu
2884382Sbinkertn@umich.edu    // Setup wire to get instructions from rename (for the ROB).
2892667Sstever@eecs.umich.edu    fromRename = renameQueue->getWire(-renameToROBDelay);
2902667Sstever@eecs.umich.edu}
2912667Sstever@eecs.umich.edu
2922667Sstever@eecs.umich.edutemplate <class Impl>
2932667Sstever@eecs.umich.eduvoid
2942667Sstever@eecs.umich.eduDefaultCommit<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr)
2955742Snate@binkert.org{
2965742Snate@binkert.org    DPRINTF(Commit, "Commit: Setting IEW queue pointer.\n");
2975742Snate@binkert.org    iewQueue = iq_ptr;
2985793Snate@binkert.org
2998334Snate@binkert.org    // Setup wire to get instructions from IEW.
3005793Snate@binkert.org    fromIEW = iewQueue->getWire(-iewToCommitDelay);
3015793Snate@binkert.org}
3025793Snate@binkert.org
3034382Sbinkertn@umich.edutemplate <class Impl>
3044762Snate@binkert.orgvoid
3055344Sstever@gmail.comDefaultCommit<Impl>::setFetchStage(Fetch *fetch_stage)
3064382Sbinkertn@umich.edu{
3075341Sstever@gmail.com    fetchStage = fetch_stage;
3085742Snate@binkert.org}
3095742Snate@binkert.org
3105742Snate@binkert.orgtemplate <class Impl>
3115742Snate@binkert.orgvoid
3125742Snate@binkert.orgDefaultCommit<Impl>::setIEWStage(IEW *iew_stage)
3134762Snate@binkert.org{
3145742Snate@binkert.org    iewStage = iew_stage;
3155742Snate@binkert.org}
3167722Sgblack@eecs.umich.edu
3175742Snate@binkert.orgtemplate<class Impl>
3185742Snate@binkert.orgvoid
3195742Snate@binkert.orgDefaultCommit<Impl>::setActiveThreads(list<unsigned> *at_ptr)
3205742Snate@binkert.org{
3218242Sbradley.danofsky@amd.com    DPRINTF(Commit, "Commit: Setting active threads list pointer.\n");
3228242Sbradley.danofsky@amd.com    activeThreads = at_ptr;
3238242Sbradley.danofsky@amd.com}
3248242Sbradley.danofsky@amd.com
3255341Sstever@gmail.comtemplate <class Impl>
3265742Snate@binkert.orgvoid
3277722Sgblack@eecs.umich.eduDefaultCommit<Impl>::setRenameMap(RenameMap rm_ptr[])
3284773Snate@binkert.org{
3296108Snate@binkert.org    DPRINTF(Commit, "Setting rename map pointers.\n");
3301858SN/A
3311085SN/A    for (int i=0; i < numThreads; i++) {
3326658Snate@binkert.org        renameMap[i] = &rm_ptr[i];
3336658Snate@binkert.org    }
3347673Snate@binkert.org}
3356658Snate@binkert.org
3366658Snate@binkert.orgtemplate <class Impl>
3376658Snate@binkert.orgvoid
3386658Snate@binkert.orgDefaultCommit<Impl>::setROB(ROB *rob_ptr)
3396658Snate@binkert.org{
3406658Snate@binkert.org    DPRINTF(Commit, "Commit: Setting ROB pointer.\n");
3416658Snate@binkert.org    rob = rob_ptr;
3427673Snate@binkert.org}
3437673Snate@binkert.org
3447673Snate@binkert.orgtemplate <class Impl>
3457673Snate@binkert.orgvoid
3467673Snate@binkert.orgDefaultCommit<Impl>::initStage()
3477673Snate@binkert.org{
3487673Snate@binkert.org    rob->setActiveThreads(activeThreads);
3496658Snate@binkert.org    rob->resetEntries();
3507673Snate@binkert.org
3517673Snate@binkert.org    // Broadcast the number of free entries.
3527673Snate@binkert.org    for (int i=0; i < numThreads; i++) {
3537673Snate@binkert.org        toIEW->commitInfo[i].usedROB = true;
3547673Snate@binkert.org        toIEW->commitInfo[i].freeROBEntries = rob->numFreeEntries(i);
3557673Snate@binkert.org    }
3567673Snate@binkert.org
3577673Snate@binkert.org    cpu->activityThisCycle();
3587673Snate@binkert.org}
3597673Snate@binkert.org
3606658Snate@binkert.orgtemplate <class Impl>
3617756SAli.Saidi@ARM.comvoid
3627816Ssteve.reinhardt@amd.comDefaultCommit<Impl>::switchOut()
3636658Snate@binkert.org{
3644382Sbinkertn@umich.edu    switchPending = true;
3654382Sbinkertn@umich.edu}
3664762Snate@binkert.org
3674762Snate@binkert.orgtemplate <class Impl>
3684762Snate@binkert.orgvoid
3696654Snate@binkert.orgDefaultCommit<Impl>::doSwitchOut()
3706654Snate@binkert.org{
3715517Snate@binkert.org    switchedOut = true;
3725517Snate@binkert.org    switchPending = false;
3735517Snate@binkert.org    rob->switchOut();
3745517Snate@binkert.org}
3755517Snate@binkert.org
3765517Snate@binkert.orgtemplate <class Impl>
3775517Snate@binkert.orgvoid
3785517Snate@binkert.orgDefaultCommit<Impl>::takeOverFrom()
3795517Snate@binkert.org{
3805517Snate@binkert.org    switchedOut = false;
3815517Snate@binkert.org    _status = Active;
3825517Snate@binkert.org    _nextStatus = Inactive;
3835517Snate@binkert.org    for (int i=0; i < numThreads; i++) {
3845517Snate@binkert.org        commitStatus[i] = Idle;
3855517Snate@binkert.org        changedROBNumEntries[i] = false;
3865517Snate@binkert.org        trapSquash[i] = false;
3875517Snate@binkert.org        tcSquash[i] = false;
3886654Snate@binkert.org    }
3895517Snate@binkert.org    squashCounter = 0;
3905517Snate@binkert.org    rob->takeOverFrom();
3915517Snate@binkert.org}
3925517Snate@binkert.org
3935517Snate@binkert.orgtemplate <class Impl>
3945517Snate@binkert.orgvoid
3955517Snate@binkert.orgDefaultCommit<Impl>::updateStatus()
3965517Snate@binkert.org{
3976143Snate@binkert.org    // reset ROB changed variable
3986654Snate@binkert.org    list<unsigned>::iterator threads = (*activeThreads).begin();
3995517Snate@binkert.org    while (threads != (*activeThreads).end()) {
4005517Snate@binkert.org        unsigned tid = *threads++;
4015517Snate@binkert.org        changedROBNumEntries[tid] = false;
4025517Snate@binkert.org
4035517Snate@binkert.org        // Also check if any of the threads has a trap pending
4045517Snate@binkert.org        if (commitStatus[tid] == TrapPending ||
4055517Snate@binkert.org            commitStatus[tid] == FetchTrapPending) {
4065517Snate@binkert.org            _nextStatus = Active;
4075517Snate@binkert.org        }
4085517Snate@binkert.org    }
4095517Snate@binkert.org
4105517Snate@binkert.org    if (_nextStatus == Inactive && _status == Active) {
4115517Snate@binkert.org        DPRINTF(Activity, "Deactivating stage.\n");
4125517Snate@binkert.org        cpu->deactivateStage(FullCPU::CommitIdx);
4136654Snate@binkert.org    } else if (_nextStatus == Active && _status == Inactive) {
4146654Snate@binkert.org        DPRINTF(Activity, "Activating stage.\n");
4155517Snate@binkert.org        cpu->activateStage(FullCPU::CommitIdx);
4165517Snate@binkert.org    }
4176143Snate@binkert.org
4186143Snate@binkert.org    _status = _nextStatus;
4196143Snate@binkert.org}
4206727Ssteve.reinhardt@amd.com
4215517Snate@binkert.orgtemplate <class Impl>
4226727Ssteve.reinhardt@amd.comvoid
4235517Snate@binkert.orgDefaultCommit<Impl>::setNextStatus()
4245517Snate@binkert.org{
4255517Snate@binkert.org    int squashes = 0;
4266654Snate@binkert.org
4276654Snate@binkert.org    list<unsigned>::iterator threads = (*activeThreads).begin();
4287673Snate@binkert.org
4296654Snate@binkert.org    while (threads != (*activeThreads).end()) {
4306654Snate@binkert.org        unsigned tid = *threads++;
4316654Snate@binkert.org
4326654Snate@binkert.org        if (commitStatus[tid] == ROBSquashing) {
4335517Snate@binkert.org            squashes++;
4345517Snate@binkert.org        }
4355517Snate@binkert.org    }
4366143Snate@binkert.org
4375517Snate@binkert.org    assert(squashes == squashCounter);
4384762Snate@binkert.org
4395517Snate@binkert.org    // If commit is currently squashing, then it will have activity for the
4405517Snate@binkert.org    // next cycle. Set its next status as active.
4416143Snate@binkert.org    if (squashCounter) {
4426143Snate@binkert.org        _nextStatus = Active;
4435517Snate@binkert.org    }
4445517Snate@binkert.org}
4455517Snate@binkert.org
4465517Snate@binkert.orgtemplate <class Impl>
4475517Snate@binkert.orgbool
4485517Snate@binkert.orgDefaultCommit<Impl>::changedROBEntries()
4495517Snate@binkert.org{
4505517Snate@binkert.org    list<unsigned>::iterator threads = (*activeThreads).begin();
4515517Snate@binkert.org
4528596Ssteve.reinhardt@amd.com    while (threads != (*activeThreads).end()) {
4538596Ssteve.reinhardt@amd.com        unsigned tid = *threads++;
4548596Ssteve.reinhardt@amd.com
4558596Ssteve.reinhardt@amd.com        if (changedROBNumEntries[tid]) {
4568596Ssteve.reinhardt@amd.com            return true;
4578596Ssteve.reinhardt@amd.com        }
4588596Ssteve.reinhardt@amd.com    }
4596143Snate@binkert.org
4605517Snate@binkert.org    return false;
4616654Snate@binkert.org}
4626654Snate@binkert.org
4636654Snate@binkert.orgtemplate <class Impl>
4646654Snate@binkert.orgunsigned
4656654Snate@binkert.orgDefaultCommit<Impl>::numROBFreeEntries(unsigned tid)
4666654Snate@binkert.org{
4675517Snate@binkert.org    return rob->numFreeEntries(tid);
4685517Snate@binkert.org}
4695517Snate@binkert.org
4708596Ssteve.reinhardt@amd.comtemplate <class Impl>
4718596Ssteve.reinhardt@amd.comvoid
4724762Snate@binkert.orgDefaultCommit<Impl>::generateTrapEvent(unsigned tid)
4734762Snate@binkert.org{
4744762Snate@binkert.org    DPRINTF(Commit, "Generating trap event for [tid:%i]\n", tid);
4754762Snate@binkert.org
4764762Snate@binkert.org    TrapEvent *trap = new TrapEvent(this, tid);
4774762Snate@binkert.org
4787675Snate@binkert.org    trap->schedule(curTick + trapLatency);
4794762Snate@binkert.org
4804762Snate@binkert.org    thread[tid]->trapPending = true;
4814762Snate@binkert.org}
4824762Snate@binkert.org
4834382Sbinkertn@umich.edutemplate <class Impl>
4844382Sbinkertn@umich.eduvoid
4855517Snate@binkert.orgDefaultCommit<Impl>::generateTCEvent(unsigned tid)
4866654Snate@binkert.org{
4875517Snate@binkert.org    DPRINTF(Commit, "Generating TC squash event for [tid:%i]\n", tid);
4888126Sgblack@eecs.umich.edu
4896654Snate@binkert.org    tcSquash[tid] = true;
4907673Snate@binkert.org}
4916654Snate@binkert.org
4926654Snate@binkert.orgtemplate <class Impl>
4936654Snate@binkert.orgvoid
4946654Snate@binkert.orgDefaultCommit<Impl>::squashAll(unsigned tid)
4956654Snate@binkert.org{
4966654Snate@binkert.org    // If we want to include the squashing instruction in the squash,
4976654Snate@binkert.org    // then use one older sequence number.
4986669Snate@binkert.org    // Hopefully this doesn't mess things up.  Basically I want to squash
4996669Snate@binkert.org    // all instructions of this thread.
5006669Snate@binkert.org    InstSeqNum squashed_inst = rob->isEmpty() ?
5016669Snate@binkert.org        0 : rob->readHeadInst(tid)->seqNum - 1;;
5026669Snate@binkert.org
5036669Snate@binkert.org    // All younger instructions will be squashed. Set the sequence
5046654Snate@binkert.org    // number as the youngest instruction in the ROB (0 in this case.
5057673Snate@binkert.org    // Hopefully nothing breaks.)
5065517Snate@binkert.org    youngestSeqNum[tid] = 0;
5078126Sgblack@eecs.umich.edu
5085798Snate@binkert.org    rob->squash(squashed_inst, tid);
5097756SAli.Saidi@ARM.com    changedROBNumEntries[tid] = true;
5107816Ssteve.reinhardt@amd.com
5115798Snate@binkert.org    // Send back the sequence number of the squashed instruction.
5125798Snate@binkert.org    toIEW->commitInfo[tid].doneSeqNum = squashed_inst;
5135517Snate@binkert.org
5145517Snate@binkert.org    // Send back the squash signal to tell stages that they should
5157673Snate@binkert.org    // squash.
5165517Snate@binkert.org    toIEW->commitInfo[tid].squash = true;
5175517Snate@binkert.org
5187673Snate@binkert.org    // Send back the rob squashing signal so other stages know that
5197673Snate@binkert.org    // the ROB is in the process of squashing.
5205517Snate@binkert.org    toIEW->commitInfo[tid].robSquashing = true;
5215798Snate@binkert.org
5225798Snate@binkert.org    toIEW->commitInfo[tid].branchMispredict = false;
5238333Snate@binkert.org
5247816Ssteve.reinhardt@amd.com    toIEW->commitInfo[tid].nextPC = PC[tid];
5255798Snate@binkert.org}
5265798Snate@binkert.org
5274762Snate@binkert.orgtemplate <class Impl>
5284762Snate@binkert.orgvoid
5294762Snate@binkert.orgDefaultCommit<Impl>::squashFromTrap(unsigned tid)
5304762Snate@binkert.org{
5314762Snate@binkert.org    squashAll(tid);
5328596Ssteve.reinhardt@amd.com
5335517Snate@binkert.org    DPRINTF(Commit, "Squashing from trap, restarting at PC %#x\n", PC[tid]);
5345517Snate@binkert.org
5355517Snate@binkert.org    thread[tid]->trapPending = false;
5365517Snate@binkert.org    thread[tid]->inSyscall = false;
5375517Snate@binkert.org
5387673Snate@binkert.org    trapSquash[tid] = false;
5398596Ssteve.reinhardt@amd.com
5407673Snate@binkert.org    commitStatus[tid] = ROBSquashing;
5415517Snate@binkert.org    cpu->activityThisCycle();
5428596Ssteve.reinhardt@amd.com
5435517Snate@binkert.org    ++squashCounter;
5445517Snate@binkert.org}
5455517Snate@binkert.org
5468596Ssteve.reinhardt@amd.comtemplate <class Impl>
5475517Snate@binkert.orgvoid
5487673Snate@binkert.orgDefaultCommit<Impl>::squashFromTC(unsigned tid)
5497673Snate@binkert.org{
5507673Snate@binkert.org    squashAll(tid);
5515517Snate@binkert.org
5525517Snate@binkert.org    DPRINTF(Commit, "Squashing from TC, restarting at PC %#x\n", PC[tid]);
5535517Snate@binkert.org
5545517Snate@binkert.org    thread[tid]->inSyscall = false;
5555517Snate@binkert.org    assert(!thread[tid]->trapPending);
5565517Snate@binkert.org
5575517Snate@binkert.org    commitStatus[tid] = ROBSquashing;
5587673Snate@binkert.org    cpu->activityThisCycle();
5597673Snate@binkert.org
5607673Snate@binkert.org    tcSquash[tid] = false;
5615517Snate@binkert.org
5628596Ssteve.reinhardt@amd.com    ++squashCounter;
5635517Snate@binkert.org}
5645517Snate@binkert.org
5655517Snate@binkert.orgtemplate <class Impl>
5665517Snate@binkert.orgvoid
5675517Snate@binkert.orgDefaultCommit<Impl>::tick()
5687673Snate@binkert.org{
5697673Snate@binkert.org    wroteToTimeBuffer = false;
5707673Snate@binkert.org    _nextStatus = Inactive;
5715517Snate@binkert.org
5728596Ssteve.reinhardt@amd.com    if (switchPending && rob->isEmpty() && !iewStage->hasStoresToWB()) {
5737675Snate@binkert.org        cpu->signalSwitched();
5747675Snate@binkert.org        return;
5757675Snate@binkert.org    }
5767675Snate@binkert.org
5777675Snate@binkert.org    list<unsigned>::iterator threads = (*activeThreads).begin();
5787675Snate@binkert.org
5798596Ssteve.reinhardt@amd.com    // Check if any of the threads are done squashing.  Change the
5807675Snate@binkert.org    // status if they are done.
5817675Snate@binkert.org    while (threads != (*activeThreads).end()) {
5828596Ssteve.reinhardt@amd.com        unsigned tid = *threads++;
5838596Ssteve.reinhardt@amd.com
5848596Ssteve.reinhardt@amd.com        if (commitStatus[tid] == ROBSquashing) {
5858596Ssteve.reinhardt@amd.com
5868596Ssteve.reinhardt@amd.com            if (rob->isDoneSquashing(tid)) {
5878596Ssteve.reinhardt@amd.com                commitStatus[tid] = Running;
5888596Ssteve.reinhardt@amd.com                --squashCounter;
5898596Ssteve.reinhardt@amd.com            } else {
5908596Ssteve.reinhardt@amd.com                DPRINTF(Commit,"[tid:%u]: Still Squashing, cannot commit any"
5914762Snate@binkert.org                        "insts this cycle.\n", tid);
5926143Snate@binkert.org            }
5936143Snate@binkert.org        }
5946143Snate@binkert.org    }
5954762Snate@binkert.org
5964762Snate@binkert.org    commit();
5974762Snate@binkert.org
5987756SAli.Saidi@ARM.com    markCompletedInsts();
5998596Ssteve.reinhardt@amd.com
6004762Snate@binkert.org    threads = (*activeThreads).begin();
6014762Snate@binkert.org
6028596Ssteve.reinhardt@amd.com    while (threads != (*activeThreads).end()) {
6035463Snate@binkert.org        unsigned tid = *threads++;
6048596Ssteve.reinhardt@amd.com
6058596Ssteve.reinhardt@amd.com        if (!rob->isEmpty(tid) && rob->readHeadInst(tid)->readyToCommit()) {
6065463Snate@binkert.org            // The ROB has more instructions it can commit. Its next status
6077756SAli.Saidi@ARM.com            // will be active.
6088596Ssteve.reinhardt@amd.com            _nextStatus = Active;
6094762Snate@binkert.org
6107677Snate@binkert.org            DynInstPtr inst = rob->readHeadInst(tid);
6114762Snate@binkert.org
6124762Snate@binkert.org            DPRINTF(Commit,"[tid:%i]: Instruction [sn:%lli] PC %#x is head of"
6136143Snate@binkert.org                    " ROB and ready to commit\n",
6146143Snate@binkert.org                    tid, inst->seqNum, inst->readPC());
6156143Snate@binkert.org
6164762Snate@binkert.org        } else if (!rob->isEmpty(tid)) {
6174762Snate@binkert.org            DynInstPtr inst = rob->readHeadInst(tid);
6187756SAli.Saidi@ARM.com
6197816Ssteve.reinhardt@amd.com            DPRINTF(Commit,"[tid:%i]: Can't commit, Instruction [sn:%lli] PC "
6204762Snate@binkert.org                    "%#x is head of ROB and not ready\n",
6214762Snate@binkert.org                    tid, inst->seqNum, inst->readPC());
6224762Snate@binkert.org        }
6234762Snate@binkert.org
6247756SAli.Saidi@ARM.com        DPRINTF(Commit, "[tid:%i]: ROB has %d insts & %d free entries.\n",
6258596Ssteve.reinhardt@amd.com                tid, rob->countInsts(tid), rob->numFreeEntries(tid));
6264762Snate@binkert.org    }
6274762Snate@binkert.org
6287677Snate@binkert.org
6297756SAli.Saidi@ARM.com    if (wroteToTimeBuffer) {
6308596Ssteve.reinhardt@amd.com        DPRINTF(Activity, "Activity This Cycle.\n");
6317675Snate@binkert.org        cpu->activityThisCycle();
6327677Snate@binkert.org    }
6335517Snate@binkert.org
6348596Ssteve.reinhardt@amd.com    updateStatus();
6357675Snate@binkert.org}
6368596Ssteve.reinhardt@amd.com
6378596Ssteve.reinhardt@amd.comtemplate <class Impl>
6388596Ssteve.reinhardt@amd.comvoid
6398596Ssteve.reinhardt@amd.comDefaultCommit<Impl>::commit()
6408596Ssteve.reinhardt@amd.com{
6414762Snate@binkert.org
6427674Snate@binkert.org    //////////////////////////////////////
6437674Snate@binkert.org    // Check for interrupts
6447674Snate@binkert.org    //////////////////////////////////////
6457674Snate@binkert.org
6467674Snate@binkert.org#if FULL_SYSTEM
6477674Snate@binkert.org    // Process interrupts if interrupts are enabled, not in PAL mode,
6487674Snate@binkert.org    // and no other traps or external squashes are currently pending.
6497674Snate@binkert.org    // @todo: Allow other threads to handle interrupts.
6507674Snate@binkert.org    if (cpu->checkInterrupts &&
6517674Snate@binkert.org        cpu->check_interrupts() &&
6527674Snate@binkert.org        !cpu->inPalMode(readPC()) &&
6537674Snate@binkert.org        !trapSquash[0] &&
6547674Snate@binkert.org        !tcSquash[0]) {
6557674Snate@binkert.org        // Tell fetch that there is an interrupt pending.  This will
6567674Snate@binkert.org        // make fetch wait until it sees a non PAL-mode PC, at which
6574762Snate@binkert.org        // point it stops fetching instructions.
6586143Snate@binkert.org        toIEW->commitInfo[0].interruptPending = true;
6596143Snate@binkert.org
6607756SAli.Saidi@ARM.com        // Wait until the ROB is empty and all stores have drained in
6617816Ssteve.reinhardt@amd.com        // order to enter the interrupt.
6628235Snate@binkert.org        if (rob->isEmpty() && !iewStage->hasStoresToWB()) {
6638596Ssteve.reinhardt@amd.com            // Not sure which thread should be the one to interrupt.  For now
6647756SAli.Saidi@ARM.com            // always do thread 0.
6657816Ssteve.reinhardt@amd.com            assert(!thread[0]->inSyscall);
6668235Snate@binkert.org            thread[0]->inSyscall = true;
6674382Sbinkertn@umich.edu
6688232Snate@binkert.org            // CPU will handle implementation of the interrupt.
6698232Snate@binkert.org            cpu->processInterrupts();
6708232Snate@binkert.org
6718232Snate@binkert.org            // Now squash or record that I need to squash this cycle.
6728232Snate@binkert.org            commitStatus[0] = TrapPending;
6736229Snate@binkert.org
6748232Snate@binkert.org            // Exit state update mode to avoid accidental updating.
6758232Snate@binkert.org            thread[0]->inSyscall = false;
6768232Snate@binkert.org
6776229Snate@binkert.org            // Generate trap squash event.
6787673Snate@binkert.org            generateTrapEvent(0);
6795517Snate@binkert.org
6805517Snate@binkert.org            toIEW->commitInfo[0].clearInterrupt = true;
6817673Snate@binkert.org
6825517Snate@binkert.org            DPRINTF(Commit, "Interrupt detected.\n");
6835517Snate@binkert.org        } else {
6845517Snate@binkert.org            DPRINTF(Commit, "Interrupt pending, waiting for ROB to empty.\n");
6855517Snate@binkert.org        }
6868232Snate@binkert.org    }
6877673Snate@binkert.org#endif // FULL_SYSTEM
6887673Snate@binkert.org
6898232Snate@binkert.org    ////////////////////////////////////
6908232Snate@binkert.org    // Check for any possible squashes, handle them first
6918232Snate@binkert.org    ////////////////////////////////////
6928232Snate@binkert.org
6937673Snate@binkert.org    list<unsigned>::iterator threads = (*activeThreads).begin();
6945517Snate@binkert.org
6958232Snate@binkert.org    while (threads != (*activeThreads).end()) {
6968232Snate@binkert.org        unsigned tid = *threads++;
6978232Snate@binkert.org/*
6988232Snate@binkert.org        if (fromFetch->fetchFault && commitStatus[0] != TrapPending) {
6997673Snate@binkert.org            // Record the fault.  Wait until it's empty in the ROB.
7008232Snate@binkert.org            // Then handle the trap.  Ignore it if there's already a
7018232Snate@binkert.org            // trap pending as fetch will be redirected.
7028232Snate@binkert.org            fetchFault = fromFetch->fetchFault;
7038232Snate@binkert.org            fetchFaultTick = curTick + fetchTrapLatency;
7048232Snate@binkert.org            commitStatus[0] = FetchTrapPending;
7058232Snate@binkert.org            DPRINTF(Commit, "Fault from fetch recorded.  Will trap if the "
7067673Snate@binkert.org                    "ROB empties without squashing the fault.\n");
7075517Snate@binkert.org            fetchTrapWait = 0;
7088232Snate@binkert.org        }
7098232Snate@binkert.org
7105517Snate@binkert.org        // Fetch may tell commit to clear the trap if it's been squashed.
7117673Snate@binkert.org        if (fromFetch->clearFetchFault) {
7125517Snate@binkert.org            DPRINTF(Commit, "Received clear fetch fault signal\n");
7138232Snate@binkert.org            fetchTrapWait = 0;
7148232Snate@binkert.org            if (commitStatus[0] == FetchTrapPending) {
7155517Snate@binkert.org                DPRINTF(Commit, "Clearing fault from fetch\n");
7168232Snate@binkert.org                commitStatus[0] = Running;
7178232Snate@binkert.org            }
7188232Snate@binkert.org        }
7197673Snate@binkert.org*/
7205517Snate@binkert.org        // Not sure which one takes priority.  I think if we have
7215517Snate@binkert.org        // both, that's a bad sign.
7227673Snate@binkert.org        if (trapSquash[tid] == true) {
7235517Snate@binkert.org            assert(!tcSquash[tid]);
7245517Snate@binkert.org            squashFromTrap(tid);
7255517Snate@binkert.org        } else if (tcSquash[tid] == true) {
7268232Snate@binkert.org            squashFromTC(tid);
7275517Snate@binkert.org        }
7285517Snate@binkert.org
7298232Snate@binkert.org        // Squashed sequence number must be older than youngest valid
7308232Snate@binkert.org        // instruction in the ROB. This prevents squashes from younger
7315517Snate@binkert.org        // instructions overriding squashes from older instructions.
7328232Snate@binkert.org        if (fromIEW->squash[tid] &&
7338232Snate@binkert.org            commitStatus[tid] != TrapPending &&
7345517Snate@binkert.org            fromIEW->squashedSeqNum[tid] <= youngestSeqNum[tid]) {
7358232Snate@binkert.org
7368232Snate@binkert.org            DPRINTF(Commit, "[tid:%i]: Squashing due to PC %#x [sn:%i]\n",
7378232Snate@binkert.org                    tid,
7385517Snate@binkert.org                    fromIEW->mispredPC[tid],
7398232Snate@binkert.org                    fromIEW->squashedSeqNum[tid]);
7408232Snate@binkert.org
7418232Snate@binkert.org            DPRINTF(Commit, "[tid:%i]: Redirecting to PC %#x\n",
7428232Snate@binkert.org                    tid,
7438232Snate@binkert.org                    fromIEW->nextPC[tid]);
7448232Snate@binkert.org
7455517Snate@binkert.org            commitStatus[tid] = ROBSquashing;
7468232Snate@binkert.org
7478232Snate@binkert.org            ++squashCounter;
7485517Snate@binkert.org
7498232Snate@binkert.org            // If we want to include the squashing instruction in the squash,
7507673Snate@binkert.org            // then use one older sequence number.
7515517Snate@binkert.org            InstSeqNum squashed_inst = fromIEW->squashedSeqNum[tid];
7527673Snate@binkert.org
7535517Snate@binkert.org            if (fromIEW->includeSquashInst[tid] == true)
7548232Snate@binkert.org                squashed_inst--;
7558232Snate@binkert.org
7568232Snate@binkert.org            // All younger instructions will be squashed. Set the sequence
7575192Ssaidi@eecs.umich.edu            // number as the youngest instruction in the ROB.
7588232Snate@binkert.org            youngestSeqNum[tid] = squashed_inst;
7598232Snate@binkert.org
7608232Snate@binkert.org            rob->squash(squashed_inst, tid);
7618232Snate@binkert.org            changedROBNumEntries[tid] = true;
7628232Snate@binkert.org
7635192Ssaidi@eecs.umich.edu            toIEW->commitInfo[tid].doneSeqNum = squashed_inst;
7647674Snate@binkert.org
7655522Snate@binkert.org            toIEW->commitInfo[tid].squash = true;
7665522Snate@binkert.org
7677674Snate@binkert.org            // Send back the rob squashing signal so other stages know that
7687674Snate@binkert.org            // the ROB is in the process of squashing.
7697674Snate@binkert.org            toIEW->commitInfo[tid].robSquashing = true;
7707674Snate@binkert.org
7717674Snate@binkert.org            toIEW->commitInfo[tid].branchMispredict =
7727674Snate@binkert.org                fromIEW->branchMispredict[tid];
7737674Snate@binkert.org
7747674Snate@binkert.org            toIEW->commitInfo[tid].branchTaken =
7755522Snate@binkert.org                fromIEW->branchTaken[tid];
7765522Snate@binkert.org
7775522Snate@binkert.org            toIEW->commitInfo[tid].nextPC = fromIEW->nextPC[tid];
7785517Snate@binkert.org
7795522Snate@binkert.org            toIEW->commitInfo[tid].mispredPC = fromIEW->mispredPC[tid];
7805517Snate@binkert.org
7816143Snate@binkert.org            if (toIEW->commitInfo[tid].branchMispredict) {
7826727Ssteve.reinhardt@amd.com                ++branchMispredicts;
7835522Snate@binkert.org            }
7845522Snate@binkert.org        }
7855522Snate@binkert.org
7867674Snate@binkert.org    }
7875517Snate@binkert.org
7887673Snate@binkert.org    setNextStatus();
7897673Snate@binkert.org
7907674Snate@binkert.org    if (squashCounter != numThreads) {
7917673Snate@binkert.org        // If we're not currently squashing, then get instructions.
7927674Snate@binkert.org        getInsts();
7937674Snate@binkert.org
7947674Snate@binkert.org        // Try to commit any instructions.
7957674Snate@binkert.org        commitInsts();
7967674Snate@binkert.org    }
7977674Snate@binkert.org
7985522Snate@binkert.org    //Check for any activity
7995522Snate@binkert.org    threads = (*activeThreads).begin();
8007674Snate@binkert.org
8017674Snate@binkert.org    while (threads != (*activeThreads).end()) {
8027674Snate@binkert.org        unsigned tid = *threads++;
8037674Snate@binkert.org
8047673Snate@binkert.org        if (changedROBNumEntries[tid]) {
8057674Snate@binkert.org            toIEW->commitInfo[tid].usedROB = true;
8067674Snate@binkert.org            toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid);
8077674Snate@binkert.org
8087674Snate@binkert.org            if (rob->isEmpty(tid)) {
8097674Snate@binkert.org                toIEW->commitInfo[tid].emptyROB = true;
8107674Snate@binkert.org            }
8117674Snate@binkert.org
8127674Snate@binkert.org            wroteToTimeBuffer = true;
8137811Ssteve.reinhardt@amd.com            changedROBNumEntries[tid] = false;
8147674Snate@binkert.org        }
8157673Snate@binkert.org    }
8165522Snate@binkert.org}
8176143Snate@binkert.org
8187756SAli.Saidi@ARM.comtemplate <class Impl>
8197816Ssteve.reinhardt@amd.comvoid
8207674Snate@binkert.orgDefaultCommit<Impl>::commitInsts()
8214382Sbinkertn@umich.edu{
8224382Sbinkertn@umich.edu    ////////////////////////////////////
8234382Sbinkertn@umich.edu    // Handle commit
8244382Sbinkertn@umich.edu    // Note that commit will be handled prior to putting new
8254382Sbinkertn@umich.edu    // instructions in the ROB so that the ROB only tries to commit
8264382Sbinkertn@umich.edu    // instructions it has in this current cycle, and not instructions
8274382Sbinkertn@umich.edu    // it is writing in during this cycle.  Can't commit and squash
8284382Sbinkertn@umich.edu    // things at the same time...
8294382Sbinkertn@umich.edu    ////////////////////////////////////
8304382Sbinkertn@umich.edu
8316143Snate@binkert.org    DPRINTF(Commit, "Trying to commit instructions in the ROB.\n");
832955SN/A
8332655Sstever@eecs.umich.edu    unsigned num_committed = 0;
8342655Sstever@eecs.umich.edu
8352655Sstever@eecs.umich.edu    DynInstPtr head_inst;
8362655Sstever@eecs.umich.edu
8372655Sstever@eecs.umich.edu    // Commit as many instructions as possible until the commit bandwidth
8385601Snate@binkert.org    // limit is reached, or it becomes impossible to commit any more.
8395601Snate@binkert.org    while (num_committed < commitWidth) {
8408334Snate@binkert.org        int commit_thread = getCommittingThread();
8418334Snate@binkert.org
8428334Snate@binkert.org        if (commit_thread == -1 || !rob->isHeadReady(commit_thread))
8435522Snate@binkert.org            break;
8445863Snate@binkert.org
8455601Snate@binkert.org        head_inst = rob->readHeadInst(commit_thread);
8465601Snate@binkert.org
8475601Snate@binkert.org        int tid = head_inst->threadNumber;
8485863Snate@binkert.org
8496143Snate@binkert.org        assert(tid == commit_thread);
8505559Snate@binkert.org
8515559Snate@binkert.org        DPRINTF(Commit, "Trying to commit head instruction, [sn:%i] [tid:%i]\n",
8525559Snate@binkert.org                head_inst->seqNum, tid);
8535559Snate@binkert.org
8548656Sandreas.hansson@arm.com        // If the head instruction is squashed, it is ready to retire
8558614Sgblack@eecs.umich.edu        // (be removed from the ROB) at any time.
8568614Sgblack@eecs.umich.edu        if (head_inst->isSquashed()) {
8578737Skoansin.tan@gmail.com
8588737Skoansin.tan@gmail.com            DPRINTF(Commit, "Retiring squashed instruction from "
8598737Skoansin.tan@gmail.com                    "ROB.\n");
8605601Snate@binkert.org
8616143Snate@binkert.org            rob->retireHead(commit_thread);
8626143Snate@binkert.org
8636143Snate@binkert.org            ++commitSquashedInsts;
8646143Snate@binkert.org
8656143Snate@binkert.org            // Record that the number of ROB entries has changed.
8666143Snate@binkert.org            changedROBNumEntries[tid] = true;
8676143Snate@binkert.org        } else {
8686143Snate@binkert.org            PC[tid] = head_inst->readPC();
8696143Snate@binkert.org            nextPC[tid] = head_inst->readNextPC();
8706143Snate@binkert.org
8716143Snate@binkert.org            // Increment the total number of non-speculative instructions
8726143Snate@binkert.org            // executed.
8736143Snate@binkert.org            // Hack for now: it really shouldn't happen until after the
8746143Snate@binkert.org            // commit is deemed to be successful, but this count is needed
8756143Snate@binkert.org            // for syscalls.
8766143Snate@binkert.org            thread[tid]->funcExeInst++;
8776143Snate@binkert.org
8786143Snate@binkert.org            // Try to commit the head instruction.
8796143Snate@binkert.org            bool commit_success = commitHead(head_inst, num_committed);
8806143Snate@binkert.org
8816143Snate@binkert.org            if (commit_success) {
8826143Snate@binkert.org                ++num_committed;
8836143Snate@binkert.org
8846143Snate@binkert.org                changedROBNumEntries[tid] = true;
8856143Snate@binkert.org
8868594Snate@binkert.org                // Set the doneSeqNum to the youngest committed instruction.
8878594Snate@binkert.org                toIEW->commitInfo[tid].doneSeqNum = head_inst->seqNum;
8888594Snate@binkert.org
8898594Snate@binkert.org                ++commitCommittedInsts;
8906143Snate@binkert.org
8916143Snate@binkert.org                // To match the old model, don't count nops and instruction
8926143Snate@binkert.org                // prefetches towards the total commit count.
8936143Snate@binkert.org                if (!head_inst->isNop() && !head_inst->isInstPrefetch()) {
8946143Snate@binkert.org                    cpu->instDone(tid);
8956240Snate@binkert.org                }
8965554Snate@binkert.org
8975522Snate@binkert.org                PC[tid] = nextPC[tid];
8985522Snate@binkert.org                nextPC[tid] = nextPC[tid] + sizeof(TheISA::MachInst);
8995797Snate@binkert.org#if FULL_SYSTEM
9005797Snate@binkert.org                int count = 0;
9015522Snate@binkert.org                Addr oldpc;
9025601Snate@binkert.org                do {
9038233Snate@binkert.org                    // Debug statement.  Checks to make sure we're not
9048233Snate@binkert.org                    // currently updating state while handling PC events.
9058235Snate@binkert.org                    if (count == 0)
9068235Snate@binkert.org                        assert(!thread[tid]->inSyscall &&
9078235Snate@binkert.org                               !thread[tid]->trapPending);
9088235Snate@binkert.org                    oldpc = PC[tid];
9098235Snate@binkert.org                    cpu->system->pcEventQueue.service(
9108235Snate@binkert.org                        thread[tid]->getTC());
9118235Snate@binkert.org                    count++;
9126143Snate@binkert.org                } while (oldpc != PC[tid]);
9132655Sstever@eecs.umich.edu                if (count > 1) {
9146143Snate@binkert.org                    DPRINTF(Commit, "PC skip function event, stopping commit\n");
9156143Snate@binkert.org                    break;
9168233Snate@binkert.org                }
9176143Snate@binkert.org#endif
9186143Snate@binkert.org            } else {
9194007Ssaidi@eecs.umich.edu                DPRINTF(Commit, "Unable to commit head instruction PC:%#x "
9204596Sbinkertn@umich.edu                        "[tid:%i] [sn:%i].\n",
9214007Ssaidi@eecs.umich.edu                        head_inst->readPC(), tid ,head_inst->seqNum);
9224596Sbinkertn@umich.edu                break;
9237756SAli.Saidi@ARM.com            }
9247816Ssteve.reinhardt@amd.com        }
9258334Snate@binkert.org    }
9268334Snate@binkert.org
9278334Snate@binkert.org    DPRINTF(CommitRate, "%i\n", num_committed);
9288334Snate@binkert.org    numCommittedDist.sample(num_committed);
9295601Snate@binkert.org
9305601Snate@binkert.org    if (num_committed == commitWidth) {
9312655Sstever@eecs.umich.edu        commitEligibleSamples++;
932955SN/A    }
9333918Ssaidi@eecs.umich.edu}
9348737Skoansin.tan@gmail.com
9353918Ssaidi@eecs.umich.edutemplate <class Impl>
9363918Ssaidi@eecs.umich.edubool
9373918Ssaidi@eecs.umich.eduDefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
9383918Ssaidi@eecs.umich.edu{
9393918Ssaidi@eecs.umich.edu    assert(head_inst);
9403918Ssaidi@eecs.umich.edu
9413918Ssaidi@eecs.umich.edu    int tid = head_inst->threadNumber;
9423918Ssaidi@eecs.umich.edu
9433918Ssaidi@eecs.umich.edu    // If the instruction is not executed yet, then it will need extra
9443918Ssaidi@eecs.umich.edu    // handling.  Signal backwards that it should be executed.
9453918Ssaidi@eecs.umich.edu    if (!head_inst->isExecuted()) {
9463918Ssaidi@eecs.umich.edu        // Keep this number correct.  We have not yet actually executed
9473940Ssaidi@eecs.umich.edu        // and committed this instruction.
9483940Ssaidi@eecs.umich.edu        thread[tid]->funcExeInst--;
9493940Ssaidi@eecs.umich.edu
9503942Ssaidi@eecs.umich.edu        head_inst->reachedCommit = true;
9513940Ssaidi@eecs.umich.edu
9523515Ssaidi@eecs.umich.edu        if (head_inst->isNonSpeculative() ||
9533918Ssaidi@eecs.umich.edu            head_inst->isStoreConditional() ||
9544762Snate@binkert.org            head_inst->isMemBarrier() ||
9553515Ssaidi@eecs.umich.edu            head_inst->isWriteBarrier()) {
9568881Smarc.orr@gmail.com
9578881Smarc.orr@gmail.com            DPRINTF(Commit, "Encountered a barrier or non-speculative "
9588881Smarc.orr@gmail.com                    "instruction [sn:%lli] at the head of the ROB, PC %#x.\n",
9598881Smarc.orr@gmail.com                    head_inst->seqNum, head_inst->readPC());
9608881Smarc.orr@gmail.com
9618881Smarc.orr@gmail.com#if !FULL_SYSTEM
9628881Smarc.orr@gmail.com            // Hack to make sure syscalls/memory barriers/quiesces
9638881Smarc.orr@gmail.com            // aren't executed until all stores write back their data.
9648881Smarc.orr@gmail.com            // This direct communication shouldn't be used for
9658881Smarc.orr@gmail.com            // anything other than this.
9668881Smarc.orr@gmail.com            if (inst_num > 0 || iewStage->hasStoresToWB())
9678881Smarc.orr@gmail.com#else
9688881Smarc.orr@gmail.com            if ((head_inst->isMemBarrier() || head_inst->isWriteBarrier() ||
9698881Smarc.orr@gmail.com                    head_inst->isQuiesce()) &&
9708881Smarc.orr@gmail.com                iewStage->hasStoresToWB())
9718881Smarc.orr@gmail.com#endif
9728881Smarc.orr@gmail.com            {
9738881Smarc.orr@gmail.com                DPRINTF(Commit, "Waiting for all stores to writeback.\n");
9748881Smarc.orr@gmail.com                return false;
9758881Smarc.orr@gmail.com            }
9768881Smarc.orr@gmail.com
9778881Smarc.orr@gmail.com            toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum;
9788881Smarc.orr@gmail.com
9798881Smarc.orr@gmail.com            // Change the instruction so it won't try to commit again until
9808881Smarc.orr@gmail.com            // it is executed.
9818881Smarc.orr@gmail.com            head_inst->clearCanCommit();
9828881Smarc.orr@gmail.com
9838881Smarc.orr@gmail.com            ++commitNonSpecStalls;
984955SN/A
985955SN/A            return false;
9868881Smarc.orr@gmail.com        } else if (head_inst->isLoad()) {
9878881Smarc.orr@gmail.com            DPRINTF(Commit, "[sn:%lli]: Uncached load, PC %#x.\n",
9888881Smarc.orr@gmail.com                    head_inst->seqNum, head_inst->readPC());
9898881Smarc.orr@gmail.com
990955SN/A            // Send back the non-speculative instruction's sequence
991955SN/A            // number.  Tell the lsq to re-execute the load.
9928881Smarc.orr@gmail.com            toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum;
9938881Smarc.orr@gmail.com            toIEW->commitInfo[tid].uncached = true;
9948881Smarc.orr@gmail.com            toIEW->commitInfo[tid].uncachedLoad = head_inst;
9958881Smarc.orr@gmail.com
996955SN/A            head_inst->clearCanCommit();
997955SN/A
9988881Smarc.orr@gmail.com            return false;
9998881Smarc.orr@gmail.com        } else {
10008881Smarc.orr@gmail.com            panic("Trying to commit un-executed instruction "
10018881Smarc.orr@gmail.com                  "of unknown type!\n");
10028881Smarc.orr@gmail.com        }
10031869SN/A    }
10041869SN/A
1005    if (head_inst->isThreadSync()) {
1006        // Not handled for now.
1007        panic("Thread sync instructions are not handled yet.\n");
1008    }
1009
1010    // Stores mark themselves as completed.
1011    if (!head_inst->isStore()) {
1012        head_inst->setCompleted();
1013    }
1014
1015    // Use checker prior to updating anything due to traps or PC
1016    // based events.
1017    if (cpu->checker) {
1018        cpu->checker->tick(head_inst);
1019    }
1020
1021    // Check if the instruction caused a fault.  If so, trap.
1022    Fault inst_fault = head_inst->getFault();
1023
1024    if (inst_fault != NoFault) {
1025        head_inst->setCompleted();
1026#if FULL_SYSTEM
1027        DPRINTF(Commit, "Inst [sn:%lli] PC %#x has a fault\n",
1028                head_inst->seqNum, head_inst->readPC());
1029
1030        if (iewStage->hasStoresToWB() || inst_num > 0) {
1031            DPRINTF(Commit, "Stores outstanding, fault must wait.\n");
1032            return false;
1033        }
1034
1035        if (cpu->checker && head_inst->isStore()) {
1036            cpu->checker->tick(head_inst);
1037        }
1038
1039        assert(!thread[tid]->inSyscall);
1040
1041        // Mark that we're in state update mode so that the trap's
1042        // execution doesn't generate extra squashes.
1043        thread[tid]->inSyscall = true;
1044
1045        // DTB will sometimes need the machine instruction for when
1046        // faults happen.  So we will set it here, prior to the DTB
1047        // possibly needing it for its fault.
1048        thread[tid]->setInst(
1049            static_cast<TheISA::MachInst>(head_inst->staticInst->machInst));
1050
1051        // Execute the trap.  Although it's slightly unrealistic in
1052        // terms of timing (as it doesn't wait for the full timing of
1053        // the trap event to complete before updating state), it's
1054        // needed to update the state as soon as possible.  This
1055        // prevents external agents from changing any specific state
1056        // that the trap need.
1057        cpu->trap(inst_fault, tid);
1058
1059        // Exit state update mode to avoid accidental updating.
1060        thread[tid]->inSyscall = false;
1061
1062        commitStatus[tid] = TrapPending;
1063
1064        // Generate trap squash event.
1065        generateTrapEvent(tid);
1066
1067        return false;
1068#else // !FULL_SYSTEM
1069        panic("fault (%d) detected @ PC %08p", inst_fault,
1070              head_inst->PC);
1071#endif // FULL_SYSTEM
1072    }
1073
1074    updateComInstStats(head_inst);
1075
1076    if (head_inst->traceData) {
1077        head_inst->traceData->setFetchSeq(head_inst->seqNum);
1078        head_inst->traceData->setCPSeq(thread[tid]->numInst);
1079        head_inst->traceData->finalize();
1080        head_inst->traceData = NULL;
1081    }
1082
1083    // Update the commit rename map
1084    for (int i = 0; i < head_inst->numDestRegs(); i++) {
1085        renameMap[tid]->setEntry(head_inst->destRegIdx(i),
1086                                 head_inst->renamedDestRegIdx(i));
1087    }
1088
1089    // Finally clear the head ROB entry.
1090    rob->retireHead(tid);
1091
1092    // Return true to indicate that we have committed an instruction.
1093    return true;
1094}
1095
1096template <class Impl>
1097void
1098DefaultCommit<Impl>::getInsts()
1099{
1100    // Read any renamed instructions and place them into the ROB.
1101    int insts_to_process = min((int)renameWidth, fromRename->size);
1102
1103    for (int inst_num = 0; inst_num < insts_to_process; ++inst_num)
1104    {
1105        DynInstPtr inst = fromRename->insts[inst_num];
1106        int tid = inst->threadNumber;
1107
1108        if (!inst->isSquashed() &&
1109            commitStatus[tid] != ROBSquashing) {
1110            changedROBNumEntries[tid] = true;
1111
1112            DPRINTF(Commit, "Inserting PC %#x [sn:%i] [tid:%i] into ROB.\n",
1113                    inst->readPC(), inst->seqNum, tid);
1114
1115            rob->insertInst(inst);
1116
1117            assert(rob->getThreadEntries(tid) <= rob->getMaxEntries(tid));
1118
1119            youngestSeqNum[tid] = inst->seqNum;
1120        } else {
1121            DPRINTF(Commit, "Instruction PC %#x [sn:%i] [tid:%i] was "
1122                    "squashed, skipping.\n",
1123                    inst->readPC(), inst->seqNum, tid);
1124        }
1125    }
1126}
1127
1128template <class Impl>
1129void
1130DefaultCommit<Impl>::markCompletedInsts()
1131{
1132    // Grab completed insts out of the IEW instruction queue, and mark
1133    // instructions completed within the ROB.
1134    for (int inst_num = 0;
1135         inst_num < fromIEW->size && fromIEW->insts[inst_num];
1136         ++inst_num)
1137    {
1138        if (!fromIEW->insts[inst_num]->isSquashed()) {
1139            DPRINTF(Commit, "[tid:%i]: Marking PC %#x, [sn:%lli] ready "
1140                    "within ROB.\n",
1141                    fromIEW->insts[inst_num]->threadNumber,
1142                    fromIEW->insts[inst_num]->readPC(),
1143                    fromIEW->insts[inst_num]->seqNum);
1144
1145            // Mark the instruction as ready to commit.
1146            fromIEW->insts[inst_num]->setCanCommit();
1147        }
1148    }
1149}
1150
1151template <class Impl>
1152bool
1153DefaultCommit<Impl>::robDoneSquashing()
1154{
1155    list<unsigned>::iterator threads = (*activeThreads).begin();
1156
1157    while (threads != (*activeThreads).end()) {
1158        unsigned tid = *threads++;
1159
1160        if (!rob->isDoneSquashing(tid))
1161            return false;
1162    }
1163
1164    return true;
1165}
1166
1167template <class Impl>
1168void
1169DefaultCommit<Impl>::updateComInstStats(DynInstPtr &inst)
1170{
1171    unsigned thread = inst->threadNumber;
1172
1173    //
1174    //  Pick off the software prefetches
1175    //
1176#ifdef TARGET_ALPHA
1177    if (inst->isDataPrefetch()) {
1178        statComSwp[thread]++;
1179    } else {
1180        statComInst[thread]++;
1181    }
1182#else
1183    statComInst[thread]++;
1184#endif
1185
1186    //
1187    //  Control Instructions
1188    //
1189    if (inst->isControl())
1190        statComBranches[thread]++;
1191
1192    //
1193    //  Memory references
1194    //
1195    if (inst->isMemRef()) {
1196        statComRefs[thread]++;
1197
1198        if (inst->isLoad()) {
1199            statComLoads[thread]++;
1200        }
1201    }
1202
1203    if (inst->isMemBarrier()) {
1204        statComMembars[thread]++;
1205    }
1206}
1207
1208////////////////////////////////////////
1209//                                    //
1210//  SMT COMMIT POLICY MAINTAINED HERE //
1211//                                    //
1212////////////////////////////////////////
1213template <class Impl>
1214int
1215DefaultCommit<Impl>::getCommittingThread()
1216{
1217    if (numThreads > 1) {
1218        switch (commitPolicy) {
1219
1220          case Aggressive:
1221            //If Policy is Aggressive, commit will call
1222            //this function multiple times per
1223            //cycle
1224            return oldestReady();
1225
1226          case RoundRobin:
1227            return roundRobin();
1228
1229          case OldestReady:
1230            return oldestReady();
1231
1232          default:
1233            return -1;
1234        }
1235    } else {
1236        int tid = (*activeThreads).front();
1237
1238        if (commitStatus[tid] == Running ||
1239            commitStatus[tid] == Idle ||
1240            commitStatus[tid] == FetchTrapPending) {
1241            return tid;
1242        } else {
1243            return -1;
1244        }
1245    }
1246}
1247
1248template<class Impl>
1249int
1250DefaultCommit<Impl>::roundRobin()
1251{
1252    list<unsigned>::iterator pri_iter = priority_list.begin();
1253    list<unsigned>::iterator end      = priority_list.end();
1254
1255    while (pri_iter != end) {
1256        unsigned tid = *pri_iter;
1257
1258        if (commitStatus[tid] == Running ||
1259            commitStatus[tid] == Idle) {
1260
1261            if (rob->isHeadReady(tid)) {
1262                priority_list.erase(pri_iter);
1263                priority_list.push_back(tid);
1264
1265                return tid;
1266            }
1267        }
1268
1269        pri_iter++;
1270    }
1271
1272    return -1;
1273}
1274
1275template<class Impl>
1276int
1277DefaultCommit<Impl>::oldestReady()
1278{
1279    unsigned oldest = 0;
1280    bool first = true;
1281
1282    list<unsigned>::iterator threads = (*activeThreads).begin();
1283
1284    while (threads != (*activeThreads).end()) {
1285        unsigned tid = *threads++;
1286
1287        if (!rob->isEmpty(tid) &&
1288            (commitStatus[tid] == Running ||
1289             commitStatus[tid] == Idle ||
1290             commitStatus[tid] == FetchTrapPending)) {
1291
1292            if (rob->isHeadReady(tid)) {
1293
1294                DynInstPtr head_inst = rob->readHeadInst(tid);
1295
1296                if (first) {
1297                    oldest = tid;
1298                    first = false;
1299                } else if (head_inst->seqNum < oldest) {
1300                    oldest = tid;
1301                }
1302            }
1303        }
1304    }
1305
1306    if (!first) {
1307        return oldest;
1308    } else {
1309        return -1;
1310    }
1311}
1312