commit_impl.hh revision 4035:f80ad98b2304
15081Sgblack@eecs.umich.edu/*
25081Sgblack@eecs.umich.edu * Copyright (c) 2004-2006 The Regents of The University of Michigan
35081Sgblack@eecs.umich.edu * All rights reserved.
45081Sgblack@eecs.umich.edu *
55081Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
65081Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
75081Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
85081Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
95081Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
105081Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
115081Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
125081Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
135081Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
145081Sgblack@eecs.umich.edu * this software without specific prior written permission.
155081Sgblack@eecs.umich.edu *
165081Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
175081Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
185081Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
195081Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
205081Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
215081Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
225081Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
235081Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
245081Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255081Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
265081Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275081Sgblack@eecs.umich.edu *
285081Sgblack@eecs.umich.edu * Authors: Kevin Lim
295081Sgblack@eecs.umich.edu *          Korey Sewell
305081Sgblack@eecs.umich.edu */
315081Sgblack@eecs.umich.edu
325081Sgblack@eecs.umich.edu#include "config/full_system.hh"
335081Sgblack@eecs.umich.edu#include "config/use_checker.hh"
345081Sgblack@eecs.umich.edu
355081Sgblack@eecs.umich.edu#include <algorithm>
365081Sgblack@eecs.umich.edu#include <string>
375081Sgblack@eecs.umich.edu
385081Sgblack@eecs.umich.edu#include "arch/utility.hh"
395081Sgblack@eecs.umich.edu#include "base/loader/symtab.hh"
405081Sgblack@eecs.umich.edu#include "base/timebuf.hh"
415081Sgblack@eecs.umich.edu#include "cpu/exetrace.hh"
425081Sgblack@eecs.umich.edu#include "cpu/o3/commit.hh"
435081Sgblack@eecs.umich.edu#include "cpu/o3/thread_state.hh"
445081Sgblack@eecs.umich.edu
455081Sgblack@eecs.umich.edu#if USE_CHECKER
465081Sgblack@eecs.umich.edu#include "cpu/checker/cpu.hh"
475081Sgblack@eecs.umich.edu#endif
485081Sgblack@eecs.umich.edu
495081Sgblack@eecs.umich.edutemplate <class Impl>
505081Sgblack@eecs.umich.eduDefaultCommit<Impl>::TrapEvent::TrapEvent(DefaultCommit<Impl> *_commit,
515081Sgblack@eecs.umich.edu                                          unsigned _tid)
525081Sgblack@eecs.umich.edu    : Event(&mainEventQueue, CPU_Tick_Pri), commit(_commit), tid(_tid)
535081Sgblack@eecs.umich.edu{
545081Sgblack@eecs.umich.edu    this->setFlags(Event::AutoDelete);
555081Sgblack@eecs.umich.edu}
565907Sgblack@eecs.umich.edu
575907Sgblack@eecs.umich.edutemplate <class Impl>
585907Sgblack@eecs.umich.eduvoid
595907Sgblack@eecs.umich.eduDefaultCommit<Impl>::TrapEvent::process()
606062Sgblack@eecs.umich.edu{
615907Sgblack@eecs.umich.edu    // This will get reset by commit if it was switched out at the
625907Sgblack@eecs.umich.edu    // time of this event processing.
635907Sgblack@eecs.umich.edu    commit->trapSquash[tid] = true;
645907Sgblack@eecs.umich.edu}
655907Sgblack@eecs.umich.edu
665907Sgblack@eecs.umich.edutemplate <class Impl>
676062Sgblack@eecs.umich.educonst char *
686344Sgblack@eecs.umich.eduDefaultCommit<Impl>::TrapEvent::description()
695907Sgblack@eecs.umich.edu{
705907Sgblack@eecs.umich.edu    return "Trap event";
715907Sgblack@eecs.umich.edu}
725907Sgblack@eecs.umich.edu
735907Sgblack@eecs.umich.edutemplate <class Impl>
745907Sgblack@eecs.umich.eduDefaultCommit<Impl>::DefaultCommit(Params *params)
755907Sgblack@eecs.umich.edu    : squashCounter(0),
765907Sgblack@eecs.umich.edu      iewToCommitDelay(params->iewToCommitDelay),
775907Sgblack@eecs.umich.edu      commitToIEWDelay(params->commitToIEWDelay),
785907Sgblack@eecs.umich.edu      renameToROBDelay(params->renameToROBDelay),
795907Sgblack@eecs.umich.edu      fetchToCommitDelay(params->commitToFetchDelay),
806222Sgblack@eecs.umich.edu      renameWidth(params->renameWidth),
816222Sgblack@eecs.umich.edu      commitWidth(params->commitWidth),
826222Sgblack@eecs.umich.edu      numThreads(params->numberOfThreads),
836222Sgblack@eecs.umich.edu      drainPending(false),
845907Sgblack@eecs.umich.edu      switchedOut(false),
855907Sgblack@eecs.umich.edu      trapLatency(params->trapLatency)
865907Sgblack@eecs.umich.edu{
875907Sgblack@eecs.umich.edu    _status = Active;
885907Sgblack@eecs.umich.edu    _nextStatus = Inactive;
895907Sgblack@eecs.umich.edu    std::string policy = params->smtCommitPolicy;
905907Sgblack@eecs.umich.edu
915907Sgblack@eecs.umich.edu    //Convert string to lowercase
925907Sgblack@eecs.umich.edu    std::transform(policy.begin(), policy.end(), policy.begin(),
936222Sgblack@eecs.umich.edu                   (int(*)(int)) tolower);
946222Sgblack@eecs.umich.edu
956222Sgblack@eecs.umich.edu    //Assign commit policy
966222Sgblack@eecs.umich.edu    if (policy == "aggressive"){
975907Sgblack@eecs.umich.edu        commitPolicy = Aggressive;
985907Sgblack@eecs.umich.edu
995907Sgblack@eecs.umich.edu        DPRINTF(Commit,"Commit Policy set to Aggressive.");
1005907Sgblack@eecs.umich.edu    } else if (policy == "roundrobin"){
1015907Sgblack@eecs.umich.edu        commitPolicy = RoundRobin;
1025907Sgblack@eecs.umich.edu
1035907Sgblack@eecs.umich.edu        //Set-Up Priority List
1045907Sgblack@eecs.umich.edu        for (int tid=0; tid < numThreads; tid++) {
1055907Sgblack@eecs.umich.edu            priority_list.push_back(tid);
1065907Sgblack@eecs.umich.edu        }
1075907Sgblack@eecs.umich.edu
1085907Sgblack@eecs.umich.edu        DPRINTF(Commit,"Commit Policy set to Round Robin.");
1095907Sgblack@eecs.umich.edu    } else if (policy == "oldestready"){
1105907Sgblack@eecs.umich.edu        commitPolicy = OldestReady;
1115907Sgblack@eecs.umich.edu
1125907Sgblack@eecs.umich.edu        DPRINTF(Commit,"Commit Policy set to Oldest Ready.");
1136062Sgblack@eecs.umich.edu    } else {
1145907Sgblack@eecs.umich.edu        assert(0 && "Invalid SMT Commit Policy. Options Are: {Aggressive,"
1155907Sgblack@eecs.umich.edu               "RoundRobin,OldestReady}");
1165907Sgblack@eecs.umich.edu    }
1175907Sgblack@eecs.umich.edu
1185907Sgblack@eecs.umich.edu    for (int i=0; i < numThreads; i++) {
1195907Sgblack@eecs.umich.edu        commitStatus[i] = Idle;
1206062Sgblack@eecs.umich.edu        changedROBNumEntries[i] = false;
1216344Sgblack@eecs.umich.edu        checkEmptyROB[i] = false;
1225907Sgblack@eecs.umich.edu        trapInFlight[i] = false;
1235907Sgblack@eecs.umich.edu        committedStores[i] = false;
1245907Sgblack@eecs.umich.edu        trapSquash[i] = false;
1255907Sgblack@eecs.umich.edu        tcSquash[i] = false;
1265907Sgblack@eecs.umich.edu        PC[i] = nextPC[i] = nextNPC[i] = 0;
1275907Sgblack@eecs.umich.edu    }
1285907Sgblack@eecs.umich.edu#if FULL_SYSTEM
1295907Sgblack@eecs.umich.edu    interrupt = NoFault;
1305907Sgblack@eecs.umich.edu#endif
1315907Sgblack@eecs.umich.edu}
1325907Sgblack@eecs.umich.edu
1336222Sgblack@eecs.umich.edutemplate <class Impl>
1346222Sgblack@eecs.umich.edustd::string
1356222Sgblack@eecs.umich.eduDefaultCommit<Impl>::name() const
1366222Sgblack@eecs.umich.edu{
1375907Sgblack@eecs.umich.edu    return cpu->name() + ".commit";
1385907Sgblack@eecs.umich.edu}
1395907Sgblack@eecs.umich.edu
1405907Sgblack@eecs.umich.edutemplate <class Impl>
1415907Sgblack@eecs.umich.eduvoid
1425907Sgblack@eecs.umich.eduDefaultCommit<Impl>::regStats()
1435907Sgblack@eecs.umich.edu{
1445907Sgblack@eecs.umich.edu    using namespace Stats;
1455907Sgblack@eecs.umich.edu    commitCommittedInsts
1466222Sgblack@eecs.umich.edu        .name(name() + ".commitCommittedInsts")
1476222Sgblack@eecs.umich.edu        .desc("The number of committed instructions")
1486222Sgblack@eecs.umich.edu        .prereq(commitCommittedInsts);
1496222Sgblack@eecs.umich.edu    commitSquashedInsts
1505907Sgblack@eecs.umich.edu        .name(name() + ".commitSquashedInsts")
1515907Sgblack@eecs.umich.edu        .desc("The number of squashed insts skipped by commit")
1525907Sgblack@eecs.umich.edu        .prereq(commitSquashedInsts);
1535907Sgblack@eecs.umich.edu    commitSquashEvents
1545907Sgblack@eecs.umich.edu        .name(name() + ".commitSquashEvents")
1555907Sgblack@eecs.umich.edu        .desc("The number of times commit is told to squash")
1565907Sgblack@eecs.umich.edu        .prereq(commitSquashEvents);
1575907Sgblack@eecs.umich.edu    commitNonSpecStalls
1585907Sgblack@eecs.umich.edu        .name(name() + ".commitNonSpecStalls")
1595907Sgblack@eecs.umich.edu        .desc("The number of times commit has been forced to stall to "
1605907Sgblack@eecs.umich.edu              "communicate backwards")
1615907Sgblack@eecs.umich.edu        .prereq(commitNonSpecStalls);
1625907Sgblack@eecs.umich.edu    branchMispredicts
1635907Sgblack@eecs.umich.edu        .name(name() + ".branchMispredicts")
1645907Sgblack@eecs.umich.edu        .desc("The number of times a branch was mispredicted")
1655907Sgblack@eecs.umich.edu        .prereq(branchMispredicts);
1665907Sgblack@eecs.umich.edu    numCommittedDist
1675908Sgblack@eecs.umich.edu        .init(0,commitWidth,1)
1685908Sgblack@eecs.umich.edu        .name(name() + ".COM:committed_per_cycle")
1695908Sgblack@eecs.umich.edu        .desc("Number of insts commited each cycle")
1705908Sgblack@eecs.umich.edu        .flags(Stats::pdf)
1716062Sgblack@eecs.umich.edu        ;
1725908Sgblack@eecs.umich.edu
1735908Sgblack@eecs.umich.edu    statComInst
1745908Sgblack@eecs.umich.edu        .init(cpu->number_of_threads)
1755908Sgblack@eecs.umich.edu        .name(name() + ".COM:count")
1765908Sgblack@eecs.umich.edu        .desc("Number of instructions committed")
1775908Sgblack@eecs.umich.edu        .flags(total)
1786062Sgblack@eecs.umich.edu        ;
1795908Sgblack@eecs.umich.edu
1805908Sgblack@eecs.umich.edu    statComSwp
1815908Sgblack@eecs.umich.edu        .init(cpu->number_of_threads)
1825908Sgblack@eecs.umich.edu        .name(name() + ".COM:swp_count")
1835908Sgblack@eecs.umich.edu        .desc("Number of s/w prefetches committed")
1845908Sgblack@eecs.umich.edu        .flags(total)
1855908Sgblack@eecs.umich.edu        ;
1865908Sgblack@eecs.umich.edu
1875908Sgblack@eecs.umich.edu    statComRefs
1885908Sgblack@eecs.umich.edu        .init(cpu->number_of_threads)
1896222Sgblack@eecs.umich.edu        .name(name() +  ".COM:refs")
1906222Sgblack@eecs.umich.edu        .desc("Number of memory references committed")
1916222Sgblack@eecs.umich.edu        .flags(total)
1926222Sgblack@eecs.umich.edu        ;
1935908Sgblack@eecs.umich.edu
1945908Sgblack@eecs.umich.edu    statComLoads
1955908Sgblack@eecs.umich.edu        .init(cpu->number_of_threads)
1965908Sgblack@eecs.umich.edu        .name(name() +  ".COM:loads")
1975908Sgblack@eecs.umich.edu        .desc("Number of loads committed")
1985908Sgblack@eecs.umich.edu        .flags(total)
1995908Sgblack@eecs.umich.edu        ;
2005908Sgblack@eecs.umich.edu
2015908Sgblack@eecs.umich.edu    statComMembars
2025908Sgblack@eecs.umich.edu        .init(cpu->number_of_threads)
2035908Sgblack@eecs.umich.edu        .name(name() +  ".COM:membars")
2045908Sgblack@eecs.umich.edu        .desc("Number of memory barriers committed")
2055908Sgblack@eecs.umich.edu        .flags(total)
2066062Sgblack@eecs.umich.edu        ;
2075908Sgblack@eecs.umich.edu
2085908Sgblack@eecs.umich.edu    statComBranches
2095908Sgblack@eecs.umich.edu        .init(cpu->number_of_threads)
2105908Sgblack@eecs.umich.edu        .name(name() + ".COM:branches")
2115908Sgblack@eecs.umich.edu        .desc("Number of branches committed")
2125908Sgblack@eecs.umich.edu        .flags(total)
2136062Sgblack@eecs.umich.edu        ;
2145908Sgblack@eecs.umich.edu
2155908Sgblack@eecs.umich.edu    commitEligible
2165908Sgblack@eecs.umich.edu        .init(cpu->number_of_threads)
2175908Sgblack@eecs.umich.edu        .name(name() + ".COM:bw_limited")
2185908Sgblack@eecs.umich.edu        .desc("number of insts not committed due to BW limits")
2195908Sgblack@eecs.umich.edu        .flags(total)
2205908Sgblack@eecs.umich.edu        ;
2215908Sgblack@eecs.umich.edu
2225908Sgblack@eecs.umich.edu    commitEligibleSamples
2236222Sgblack@eecs.umich.edu        .name(name() + ".COM:bw_lim_events")
2246222Sgblack@eecs.umich.edu        .desc("number cycles where commit BW limit reached")
2256222Sgblack@eecs.umich.edu        ;
2266222Sgblack@eecs.umich.edu}
2275908Sgblack@eecs.umich.edu
2285908Sgblack@eecs.umich.edutemplate <class Impl>
2295908Sgblack@eecs.umich.eduvoid
2305908Sgblack@eecs.umich.eduDefaultCommit<Impl>::setCPU(O3CPU *cpu_ptr)
2315908Sgblack@eecs.umich.edu{
2325908Sgblack@eecs.umich.edu    DPRINTF(Commit, "Commit: Setting CPU pointer.\n");
2335908Sgblack@eecs.umich.edu    cpu = cpu_ptr;
2345908Sgblack@eecs.umich.edu
2355908Sgblack@eecs.umich.edu    // Commit must broadcast the number of free entries it has at the start of
2365908Sgblack@eecs.umich.edu    // the simulation, so it starts as active.
2375908Sgblack@eecs.umich.edu    cpu->activateStage(O3CPU::CommitIdx);
2385908Sgblack@eecs.umich.edu
2395908Sgblack@eecs.umich.edu    trapLatency = cpu->cycles(trapLatency);
2405908Sgblack@eecs.umich.edu}
2415907Sgblack@eecs.umich.edu
2425081Sgblack@eecs.umich.edutemplate <class Impl>
2435081Sgblack@eecs.umich.eduvoid
2445543Ssaidi@eecs.umich.eduDefaultCommit<Impl>::setThreads(std::vector<Thread *> &threads)
2455081Sgblack@eecs.umich.edu{
2465543Ssaidi@eecs.umich.edu    thread = threads;
2475081Sgblack@eecs.umich.edu}
248
249template <class Impl>
250void
251DefaultCommit<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
252{
253    DPRINTF(Commit, "Commit: Setting time buffer pointer.\n");
254    timeBuffer = tb_ptr;
255
256    // Setup wire to send information back to IEW.
257    toIEW = timeBuffer->getWire(0);
258
259    // Setup wire to read data from IEW (for the ROB).
260    robInfoFromIEW = timeBuffer->getWire(-iewToCommitDelay);
261}
262
263template <class Impl>
264void
265DefaultCommit<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr)
266{
267    DPRINTF(Commit, "Commit: Setting fetch queue pointer.\n");
268    fetchQueue = fq_ptr;
269
270    // Setup wire to get instructions from rename (for the ROB).
271    fromFetch = fetchQueue->getWire(-fetchToCommitDelay);
272}
273
274template <class Impl>
275void
276DefaultCommit<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr)
277{
278    DPRINTF(Commit, "Commit: Setting rename queue pointer.\n");
279    renameQueue = rq_ptr;
280
281    // Setup wire to get instructions from rename (for the ROB).
282    fromRename = renameQueue->getWire(-renameToROBDelay);
283}
284
285template <class Impl>
286void
287DefaultCommit<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr)
288{
289    DPRINTF(Commit, "Commit: Setting IEW queue pointer.\n");
290    iewQueue = iq_ptr;
291
292    // Setup wire to get instructions from IEW.
293    fromIEW = iewQueue->getWire(-iewToCommitDelay);
294}
295
296template <class Impl>
297void
298DefaultCommit<Impl>::setIEWStage(IEW *iew_stage)
299{
300    iewStage = iew_stage;
301}
302
303template<class Impl>
304void
305DefaultCommit<Impl>::setActiveThreads(std::list<unsigned> *at_ptr)
306{
307    DPRINTF(Commit, "Commit: Setting active threads list pointer.\n");
308    activeThreads = at_ptr;
309}
310
311template <class Impl>
312void
313DefaultCommit<Impl>::setRenameMap(RenameMap rm_ptr[])
314{
315    DPRINTF(Commit, "Setting rename map pointers.\n");
316
317    for (int i=0; i < numThreads; i++) {
318        renameMap[i] = &rm_ptr[i];
319    }
320}
321
322template <class Impl>
323void
324DefaultCommit<Impl>::setROB(ROB *rob_ptr)
325{
326    DPRINTF(Commit, "Commit: Setting ROB pointer.\n");
327    rob = rob_ptr;
328}
329
330template <class Impl>
331void
332DefaultCommit<Impl>::initStage()
333{
334    rob->setActiveThreads(activeThreads);
335    rob->resetEntries();
336
337    // Broadcast the number of free entries.
338    for (int i=0; i < numThreads; i++) {
339        toIEW->commitInfo[i].usedROB = true;
340        toIEW->commitInfo[i].freeROBEntries = rob->numFreeEntries(i);
341        toIEW->commitInfo[i].emptyROB = true;
342    }
343
344    cpu->activityThisCycle();
345}
346
347template <class Impl>
348bool
349DefaultCommit<Impl>::drain()
350{
351    drainPending = true;
352
353    return false;
354}
355
356template <class Impl>
357void
358DefaultCommit<Impl>::switchOut()
359{
360    switchedOut = true;
361    drainPending = false;
362    rob->switchOut();
363}
364
365template <class Impl>
366void
367DefaultCommit<Impl>::resume()
368{
369    drainPending = false;
370}
371
372template <class Impl>
373void
374DefaultCommit<Impl>::takeOverFrom()
375{
376    switchedOut = false;
377    _status = Active;
378    _nextStatus = Inactive;
379    for (int i=0; i < numThreads; i++) {
380        commitStatus[i] = Idle;
381        changedROBNumEntries[i] = false;
382        trapSquash[i] = false;
383        tcSquash[i] = false;
384    }
385    squashCounter = 0;
386    rob->takeOverFrom();
387}
388
389template <class Impl>
390void
391DefaultCommit<Impl>::updateStatus()
392{
393    // reset ROB changed variable
394    std::list<unsigned>::iterator threads = activeThreads->begin();
395    std::list<unsigned>::iterator end = activeThreads->end();
396
397    while (threads != end) {
398        unsigned tid = *threads++;
399
400        changedROBNumEntries[tid] = false;
401
402        // Also check if any of the threads has a trap pending
403        if (commitStatus[tid] == TrapPending ||
404            commitStatus[tid] == FetchTrapPending) {
405            _nextStatus = Active;
406        }
407    }
408
409    if (_nextStatus == Inactive && _status == Active) {
410        DPRINTF(Activity, "Deactivating stage.\n");
411        cpu->deactivateStage(O3CPU::CommitIdx);
412    } else if (_nextStatus == Active && _status == Inactive) {
413        DPRINTF(Activity, "Activating stage.\n");
414        cpu->activateStage(O3CPU::CommitIdx);
415    }
416
417    _status = _nextStatus;
418}
419
420template <class Impl>
421void
422DefaultCommit<Impl>::setNextStatus()
423{
424    int squashes = 0;
425
426    std::list<unsigned>::iterator threads = activeThreads->begin();
427    std::list<unsigned>::iterator end = activeThreads->end();
428
429    while (threads != end) {
430        unsigned tid = *threads++;
431
432        if (commitStatus[tid] == ROBSquashing) {
433            squashes++;
434        }
435    }
436
437    squashCounter = squashes;
438
439    // If commit is currently squashing, then it will have activity for the
440    // next cycle. Set its next status as active.
441    if (squashCounter) {
442        _nextStatus = Active;
443    }
444}
445
446template <class Impl>
447bool
448DefaultCommit<Impl>::changedROBEntries()
449{
450    std::list<unsigned>::iterator threads = activeThreads->begin();
451    std::list<unsigned>::iterator end = activeThreads->end();
452
453    while (threads != end) {
454        unsigned tid = *threads++;
455
456        if (changedROBNumEntries[tid]) {
457            return true;
458        }
459    }
460
461    return false;
462}
463
464template <class Impl>
465unsigned
466DefaultCommit<Impl>::numROBFreeEntries(unsigned tid)
467{
468    return rob->numFreeEntries(tid);
469}
470
471template <class Impl>
472void
473DefaultCommit<Impl>::generateTrapEvent(unsigned tid)
474{
475    DPRINTF(Commit, "Generating trap event for [tid:%i]\n", tid);
476
477    TrapEvent *trap = new TrapEvent(this, tid);
478
479    trap->schedule(curTick + trapLatency);
480    trapInFlight[tid] = true;
481}
482
483template <class Impl>
484void
485DefaultCommit<Impl>::generateTCEvent(unsigned tid)
486{
487    assert(!trapInFlight[tid]);
488    DPRINTF(Commit, "Generating TC squash event for [tid:%i]\n", tid);
489
490    tcSquash[tid] = true;
491}
492
493template <class Impl>
494void
495DefaultCommit<Impl>::squashAll(unsigned tid)
496{
497    // If we want to include the squashing instruction in the squash,
498    // then use one older sequence number.
499    // Hopefully this doesn't mess things up.  Basically I want to squash
500    // all instructions of this thread.
501    InstSeqNum squashed_inst = rob->isEmpty() ?
502        0 : rob->readHeadInst(tid)->seqNum - 1;
503
504    // All younger instructions will be squashed. Set the sequence
505    // number as the youngest instruction in the ROB (0 in this case.
506    // Hopefully nothing breaks.)
507    youngestSeqNum[tid] = 0;
508
509    rob->squash(squashed_inst, tid);
510    changedROBNumEntries[tid] = true;
511
512    // Send back the sequence number of the squashed instruction.
513    toIEW->commitInfo[tid].doneSeqNum = squashed_inst;
514
515    // Send back the squash signal to tell stages that they should
516    // squash.
517    toIEW->commitInfo[tid].squash = true;
518
519    // Send back the rob squashing signal so other stages know that
520    // the ROB is in the process of squashing.
521    toIEW->commitInfo[tid].robSquashing = true;
522
523    toIEW->commitInfo[tid].branchMispredict = false;
524
525    toIEW->commitInfo[tid].nextPC = PC[tid];
526    toIEW->commitInfo[tid].nextNPC = nextPC[tid];
527}
528
529template <class Impl>
530void
531DefaultCommit<Impl>::squashFromTrap(unsigned tid)
532{
533    squashAll(tid);
534
535    DPRINTF(Commit, "Squashing from trap, restarting at PC %#x\n", PC[tid]);
536
537    thread[tid]->trapPending = false;
538    thread[tid]->inSyscall = false;
539    trapInFlight[tid] = false;
540
541    trapSquash[tid] = false;
542
543    commitStatus[tid] = ROBSquashing;
544    cpu->activityThisCycle();
545}
546
547template <class Impl>
548void
549DefaultCommit<Impl>::squashFromTC(unsigned tid)
550{
551    squashAll(tid);
552
553    DPRINTF(Commit, "Squashing from TC, restarting at PC %#x\n", PC[tid]);
554
555    thread[tid]->inSyscall = false;
556    assert(!thread[tid]->trapPending);
557
558    commitStatus[tid] = ROBSquashing;
559    cpu->activityThisCycle();
560
561    tcSquash[tid] = false;
562}
563
564template <class Impl>
565void
566DefaultCommit<Impl>::tick()
567{
568    wroteToTimeBuffer = false;
569    _nextStatus = Inactive;
570
571    if (drainPending && rob->isEmpty() && !iewStage->hasStoresToWB()) {
572        cpu->signalDrained();
573        drainPending = false;
574        return;
575    }
576
577    if (activeThreads->empty())
578        return;
579
580    std::list<unsigned>::iterator threads = activeThreads->begin();
581    std::list<unsigned>::iterator end = activeThreads->end();
582
583    // Check if any of the threads are done squashing.  Change the
584    // status if they are done.
585    while (threads != end) {
586        unsigned tid = *threads++;
587
588        // Clear the bit saying if the thread has committed stores
589        // this cycle.
590        committedStores[tid] = false;
591
592        if (commitStatus[tid] == ROBSquashing) {
593
594            if (rob->isDoneSquashing(tid)) {
595                commitStatus[tid] = Running;
596            } else {
597                DPRINTF(Commit,"[tid:%u]: Still Squashing, cannot commit any"
598                        " insts this cycle.\n", tid);
599                rob->doSquash(tid);
600                toIEW->commitInfo[tid].robSquashing = true;
601                wroteToTimeBuffer = true;
602            }
603        }
604    }
605
606    commit();
607
608    markCompletedInsts();
609
610    threads = activeThreads->begin();
611
612    while (threads != end) {
613        unsigned tid = *threads++;
614
615        if (!rob->isEmpty(tid) && rob->readHeadInst(tid)->readyToCommit()) {
616            // The ROB has more instructions it can commit. Its next status
617            // will be active.
618            _nextStatus = Active;
619
620            DynInstPtr inst = rob->readHeadInst(tid);
621
622            DPRINTF(Commit,"[tid:%i]: Instruction [sn:%lli] PC %#x is head of"
623                    " ROB and ready to commit\n",
624                    tid, inst->seqNum, inst->readPC());
625
626        } else if (!rob->isEmpty(tid)) {
627            DynInstPtr inst = rob->readHeadInst(tid);
628
629            DPRINTF(Commit,"[tid:%i]: Can't commit, Instruction [sn:%lli] PC "
630                    "%#x is head of ROB and not ready\n",
631                    tid, inst->seqNum, inst->readPC());
632        }
633
634        DPRINTF(Commit, "[tid:%i]: ROB has %d insts & %d free entries.\n",
635                tid, rob->countInsts(tid), rob->numFreeEntries(tid));
636    }
637
638
639    if (wroteToTimeBuffer) {
640        DPRINTF(Activity, "Activity This Cycle.\n");
641        cpu->activityThisCycle();
642    }
643
644    updateStatus();
645}
646
647#if FULL_SYSTEM
648template <class Impl>
649void
650DefaultCommit<Impl>::handleInterrupt()
651{
652    if (interrupt != NoFault) {
653        // Wait until the ROB is empty and all stores have drained in
654        // order to enter the interrupt.
655        if (rob->isEmpty() && !iewStage->hasStoresToWB()) {
656            // Squash or record that I need to squash this cycle if
657            // an interrupt needed to be handled.
658            DPRINTF(Commit, "Interrupt detected.\n");
659
660            Fault new_interrupt = cpu->getInterrupts();
661            assert(new_interrupt == interrupt);
662
663            // Clear the interrupt now that it's going to be handled
664            toIEW->commitInfo[0].clearInterrupt = true;
665
666            assert(!thread[0]->inSyscall);
667            thread[0]->inSyscall = true;
668
669            // CPU will handle interrupt.
670            cpu->processInterrupts(interrupt);
671
672            thread[0]->inSyscall = false;
673
674            commitStatus[0] = TrapPending;
675
676            // Generate trap squash event.
677            generateTrapEvent(0);
678
679            interrupt = NoFault;
680        } else {
681            DPRINTF(Commit, "Interrupt pending, waiting for ROB to empty.\n");
682        }
683    } else if (commitStatus[0] != TrapPending &&
684               cpu->check_interrupts(cpu->tcBase(0)) &&
685               !trapSquash[0] &&
686               !tcSquash[0]) {
687        // Process interrupts if interrupts are enabled, not in PAL
688        // mode, and no other traps or external squashes are currently
689        // pending.
690        // @todo: Allow other threads to handle interrupts.
691
692        // Get any interrupt that happened
693        interrupt = cpu->getInterrupts();
694
695        if (interrupt != NoFault) {
696            // Tell fetch that there is an interrupt pending.  This
697            // will make fetch wait until it sees a non PAL-mode PC,
698            // at which point it stops fetching instructions.
699            toIEW->commitInfo[0].interruptPending = true;
700        }
701    }
702}
703#endif // FULL_SYSTEM
704
705template <class Impl>
706void
707DefaultCommit<Impl>::commit()
708{
709
710#if FULL_SYSTEM
711    // Check for any interrupt, and start processing it.  Or if we
712    // have an outstanding interrupt and are at a point when it is
713    // valid to take an interrupt, process it.
714    if (cpu->check_interrupts(cpu->tcBase(0))) {
715        handleInterrupt();
716    }
717#endif // FULL_SYSTEM
718
719    ////////////////////////////////////
720    // Check for any possible squashes, handle them first
721    ////////////////////////////////////
722    std::list<unsigned>::iterator threads = activeThreads->begin();
723    std::list<unsigned>::iterator end = activeThreads->end();
724
725    while (threads != end) {
726        unsigned tid = *threads++;
727
728        // Not sure which one takes priority.  I think if we have
729        // both, that's a bad sign.
730        if (trapSquash[tid] == true) {
731            assert(!tcSquash[tid]);
732            squashFromTrap(tid);
733        } else if (tcSquash[tid] == true) {
734            assert(commitStatus[tid] != TrapPending);
735            squashFromTC(tid);
736        }
737
738        // Squashed sequence number must be older than youngest valid
739        // instruction in the ROB. This prevents squashes from younger
740        // instructions overriding squashes from older instructions.
741        if (fromIEW->squash[tid] &&
742            commitStatus[tid] != TrapPending &&
743            fromIEW->squashedSeqNum[tid] <= youngestSeqNum[tid]) {
744
745            DPRINTF(Commit, "[tid:%i]: Squashing due to PC %#x [sn:%i]\n",
746                    tid,
747                    fromIEW->mispredPC[tid],
748                    fromIEW->squashedSeqNum[tid]);
749
750            DPRINTF(Commit, "[tid:%i]: Redirecting to PC %#x\n",
751                    tid,
752                    fromIEW->nextPC[tid]);
753
754            commitStatus[tid] = ROBSquashing;
755
756            // If we want to include the squashing instruction in the squash,
757            // then use one older sequence number.
758            InstSeqNum squashed_inst = fromIEW->squashedSeqNum[tid];
759
760#if ISA_HAS_DELAY_SLOT
761            InstSeqNum bdelay_done_seq_num = squashed_inst;
762            bool squash_bdelay_slot = fromIEW->squashDelaySlot[tid];
763            bool branchMispredict = fromIEW->branchMispredict[tid];
764
765            // Squashing/not squashing the branch delay slot only makes
766            // sense when you're squashing from a branch, ie from a branch
767            // mispredict.
768            if (branchMispredict && !squash_bdelay_slot) {
769                bdelay_done_seq_num++;
770            }
771#endif
772
773            if (fromIEW->includeSquashInst[tid] == true) {
774                squashed_inst--;
775#if ISA_HAS_DELAY_SLOT
776                bdelay_done_seq_num--;
777#endif
778            }
779
780            // All younger instructions will be squashed. Set the sequence
781            // number as the youngest instruction in the ROB.
782            youngestSeqNum[tid] = squashed_inst;
783
784#if ISA_HAS_DELAY_SLOT
785            rob->squash(bdelay_done_seq_num, tid);
786            toIEW->commitInfo[tid].squashDelaySlot = squash_bdelay_slot;
787            toIEW->commitInfo[tid].bdelayDoneSeqNum = bdelay_done_seq_num;
788#else
789            rob->squash(squashed_inst, tid);
790            toIEW->commitInfo[tid].squashDelaySlot = true;
791#endif
792            changedROBNumEntries[tid] = true;
793
794            toIEW->commitInfo[tid].doneSeqNum = squashed_inst;
795
796            toIEW->commitInfo[tid].squash = true;
797
798            // Send back the rob squashing signal so other stages know that
799            // the ROB is in the process of squashing.
800            toIEW->commitInfo[tid].robSquashing = true;
801
802            toIEW->commitInfo[tid].branchMispredict =
803                fromIEW->branchMispredict[tid];
804
805            toIEW->commitInfo[tid].branchTaken =
806                fromIEW->branchTaken[tid];
807
808            toIEW->commitInfo[tid].nextPC = fromIEW->nextPC[tid];
809            toIEW->commitInfo[tid].nextNPC = fromIEW->nextNPC[tid];
810
811            toIEW->commitInfo[tid].mispredPC = fromIEW->mispredPC[tid];
812
813            if (toIEW->commitInfo[tid].branchMispredict) {
814                ++branchMispredicts;
815            }
816        }
817
818    }
819
820    setNextStatus();
821
822    if (squashCounter != numThreads) {
823        // If we're not currently squashing, then get instructions.
824        getInsts();
825
826        // Try to commit any instructions.
827        commitInsts();
828    } else {
829#if ISA_HAS_DELAY_SLOT
830        skidInsert();
831#endif
832    }
833
834    //Check for any activity
835    threads = activeThreads->begin();
836
837    while (threads != end) {
838        unsigned tid = *threads++;
839
840        if (changedROBNumEntries[tid]) {
841            toIEW->commitInfo[tid].usedROB = true;
842            toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid);
843
844            wroteToTimeBuffer = true;
845            changedROBNumEntries[tid] = false;
846            if (rob->isEmpty(tid))
847                checkEmptyROB[tid] = true;
848        }
849
850        // ROB is only considered "empty" for previous stages if: a)
851        // ROB is empty, b) there are no outstanding stores, c) IEW
852        // stage has received any information regarding stores that
853        // committed.
854        // c) is checked by making sure to not consider the ROB empty
855        // on the same cycle as when stores have been committed.
856        // @todo: Make this handle multi-cycle communication between
857        // commit and IEW.
858        if (checkEmptyROB[tid] && rob->isEmpty(tid) &&
859            !iewStage->hasStoresToWB() && !committedStores[tid]) {
860            checkEmptyROB[tid] = false;
861            toIEW->commitInfo[tid].usedROB = true;
862            toIEW->commitInfo[tid].emptyROB = true;
863            toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid);
864            wroteToTimeBuffer = true;
865        }
866
867    }
868}
869
870template <class Impl>
871void
872DefaultCommit<Impl>::commitInsts()
873{
874    ////////////////////////////////////
875    // Handle commit
876    // Note that commit will be handled prior to putting new
877    // instructions in the ROB so that the ROB only tries to commit
878    // instructions it has in this current cycle, and not instructions
879    // it is writing in during this cycle.  Can't commit and squash
880    // things at the same time...
881    ////////////////////////////////////
882
883    DPRINTF(Commit, "Trying to commit instructions in the ROB.\n");
884
885    unsigned num_committed = 0;
886
887    DynInstPtr head_inst;
888
889    // Commit as many instructions as possible until the commit bandwidth
890    // limit is reached, or it becomes impossible to commit any more.
891    while (num_committed < commitWidth) {
892        int commit_thread = getCommittingThread();
893
894        if (commit_thread == -1 || !rob->isHeadReady(commit_thread))
895            break;
896
897        head_inst = rob->readHeadInst(commit_thread);
898
899        int tid = head_inst->threadNumber;
900
901        assert(tid == commit_thread);
902
903        DPRINTF(Commit, "Trying to commit head instruction, [sn:%i] [tid:%i]\n",
904                head_inst->seqNum, tid);
905
906        // If the head instruction is squashed, it is ready to retire
907        // (be removed from the ROB) at any time.
908        if (head_inst->isSquashed()) {
909
910            DPRINTF(Commit, "Retiring squashed instruction from "
911                    "ROB.\n");
912
913            rob->retireHead(commit_thread);
914
915            ++commitSquashedInsts;
916
917            // Record that the number of ROB entries has changed.
918            changedROBNumEntries[tid] = true;
919        } else {
920            PC[tid] = head_inst->readPC();
921            nextPC[tid] = head_inst->readNextPC();
922            nextNPC[tid] = head_inst->readNextNPC();
923
924            // Increment the total number of non-speculative instructions
925            // executed.
926            // Hack for now: it really shouldn't happen until after the
927            // commit is deemed to be successful, but this count is needed
928            // for syscalls.
929            thread[tid]->funcExeInst++;
930
931            // Try to commit the head instruction.
932            bool commit_success = commitHead(head_inst, num_committed);
933
934            if (commit_success) {
935                ++num_committed;
936
937                changedROBNumEntries[tid] = true;
938
939                // Set the doneSeqNum to the youngest committed instruction.
940                toIEW->commitInfo[tid].doneSeqNum = head_inst->seqNum;
941
942                ++commitCommittedInsts;
943
944                // To match the old model, don't count nops and instruction
945                // prefetches towards the total commit count.
946                if (!head_inst->isNop() && !head_inst->isInstPrefetch()) {
947                    cpu->instDone(tid);
948                }
949
950                PC[tid] = nextPC[tid];
951#if ISA_HAS_DELAY_SLOT
952                nextPC[tid] = nextNPC[tid];
953                nextNPC[tid] = nextNPC[tid] + sizeof(TheISA::MachInst);
954#else
955                nextPC[tid] = nextPC[tid] + sizeof(TheISA::MachInst);
956#endif
957
958#if FULL_SYSTEM
959                int count = 0;
960                Addr oldpc;
961                do {
962                    // Debug statement.  Checks to make sure we're not
963                    // currently updating state while handling PC events.
964                    if (count == 0)
965                        assert(!thread[tid]->inSyscall &&
966                               !thread[tid]->trapPending);
967                    oldpc = PC[tid];
968                    cpu->system->pcEventQueue.service(
969                        thread[tid]->getTC());
970                    count++;
971                } while (oldpc != PC[tid]);
972                if (count > 1) {
973                    DPRINTF(Commit, "PC skip function event, stopping commit\n");
974                    break;
975                }
976#endif
977            } else {
978                DPRINTF(Commit, "Unable to commit head instruction PC:%#x "
979                        "[tid:%i] [sn:%i].\n",
980                        head_inst->readPC(), tid ,head_inst->seqNum);
981                break;
982            }
983        }
984    }
985
986    DPRINTF(CommitRate, "%i\n", num_committed);
987    numCommittedDist.sample(num_committed);
988
989    if (num_committed == commitWidth) {
990        commitEligibleSamples++;
991    }
992}
993
994template <class Impl>
995bool
996DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
997{
998    assert(head_inst);
999
1000    int tid = head_inst->threadNumber;
1001
1002    // If the instruction is not executed yet, then it will need extra
1003    // handling.  Signal backwards that it should be executed.
1004    if (!head_inst->isExecuted()) {
1005        // Keep this number correct.  We have not yet actually executed
1006        // and committed this instruction.
1007        thread[tid]->funcExeInst--;
1008
1009        if (head_inst->isNonSpeculative() ||
1010            head_inst->isStoreConditional() ||
1011            head_inst->isMemBarrier() ||
1012            head_inst->isWriteBarrier()) {
1013
1014            DPRINTF(Commit, "Encountered a barrier or non-speculative "
1015                    "instruction [sn:%lli] at the head of the ROB, PC %#x.\n",
1016                    head_inst->seqNum, head_inst->readPC());
1017
1018            if (inst_num > 0 || iewStage->hasStoresToWB()) {
1019                DPRINTF(Commit, "Waiting for all stores to writeback.\n");
1020                return false;
1021            }
1022
1023            toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum;
1024
1025            // Change the instruction so it won't try to commit again until
1026            // it is executed.
1027            head_inst->clearCanCommit();
1028
1029            ++commitNonSpecStalls;
1030
1031            return false;
1032        } else if (head_inst->isLoad()) {
1033            if (inst_num > 0 || iewStage->hasStoresToWB()) {
1034                DPRINTF(Commit, "Waiting for all stores to writeback.\n");
1035                return false;
1036            }
1037
1038            assert(head_inst->uncacheable());
1039            DPRINTF(Commit, "[sn:%lli]: Uncached load, PC %#x.\n",
1040                    head_inst->seqNum, head_inst->readPC());
1041
1042            // Send back the non-speculative instruction's sequence
1043            // number.  Tell the lsq to re-execute the load.
1044            toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum;
1045            toIEW->commitInfo[tid].uncached = true;
1046            toIEW->commitInfo[tid].uncachedLoad = head_inst;
1047
1048            head_inst->clearCanCommit();
1049
1050            return false;
1051        } else {
1052            panic("Trying to commit un-executed instruction "
1053                  "of unknown type!\n");
1054        }
1055    }
1056
1057    if (head_inst->isThreadSync()) {
1058        // Not handled for now.
1059        panic("Thread sync instructions are not handled yet.\n");
1060    }
1061
1062    // Check if the instruction caused a fault.  If so, trap.
1063    Fault inst_fault = head_inst->getFault();
1064
1065    // Stores mark themselves as completed.
1066    if (!head_inst->isStore() && inst_fault == NoFault) {
1067        head_inst->setCompleted();
1068    }
1069
1070#if USE_CHECKER
1071    // Use checker prior to updating anything due to traps or PC
1072    // based events.
1073    if (cpu->checker) {
1074        cpu->checker->verify(head_inst);
1075    }
1076#endif
1077
1078    // DTB will sometimes need the machine instruction for when
1079    // faults happen.  So we will set it here, prior to the DTB
1080    // possibly needing it for its fault.
1081    thread[tid]->setInst(
1082        static_cast<TheISA::MachInst>(head_inst->staticInst->machInst));
1083
1084    if (inst_fault != NoFault) {
1085        DPRINTF(Commit, "Inst [sn:%lli] PC %#x has a fault\n",
1086                head_inst->seqNum, head_inst->readPC());
1087
1088        if (iewStage->hasStoresToWB() || inst_num > 0) {
1089            DPRINTF(Commit, "Stores outstanding, fault must wait.\n");
1090            return false;
1091        }
1092
1093        head_inst->setCompleted();
1094
1095#if USE_CHECKER
1096        if (cpu->checker && head_inst->isStore()) {
1097            cpu->checker->verify(head_inst);
1098        }
1099#endif
1100
1101        assert(!thread[tid]->inSyscall);
1102
1103        // Mark that we're in state update mode so that the trap's
1104        // execution doesn't generate extra squashes.
1105        thread[tid]->inSyscall = true;
1106
1107        // Execute the trap.  Although it's slightly unrealistic in
1108        // terms of timing (as it doesn't wait for the full timing of
1109        // the trap event to complete before updating state), it's
1110        // needed to update the state as soon as possible.  This
1111        // prevents external agents from changing any specific state
1112        // that the trap need.
1113        cpu->trap(inst_fault, tid);
1114
1115        // Exit state update mode to avoid accidental updating.
1116        thread[tid]->inSyscall = false;
1117
1118        commitStatus[tid] = TrapPending;
1119
1120        if (head_inst->traceData) {
1121            head_inst->traceData->setFetchSeq(head_inst->seqNum);
1122            head_inst->traceData->setCPSeq(thread[tid]->numInst);
1123            head_inst->traceData->finalize();
1124            head_inst->traceData = NULL;
1125        }
1126
1127        // Generate trap squash event.
1128        generateTrapEvent(tid);
1129//        warn("%lli fault (%d) handled @ PC %08p", curTick, inst_fault->name(), head_inst->readPC());
1130        return false;
1131    }
1132
1133    updateComInstStats(head_inst);
1134
1135#if FULL_SYSTEM
1136    if (thread[tid]->profile) {
1137//        bool usermode = TheISA::inUserMode(thread[tid]->getTC());
1138//        thread[tid]->profilePC = usermode ? 1 : head_inst->readPC();
1139        thread[tid]->profilePC = head_inst->readPC();
1140        ProfileNode *node = thread[tid]->profile->consume(thread[tid]->getTC(),
1141                                                          head_inst->staticInst);
1142
1143        if (node)
1144            thread[tid]->profileNode = node;
1145    }
1146#endif
1147
1148    if (head_inst->traceData) {
1149        head_inst->traceData->setFetchSeq(head_inst->seqNum);
1150        head_inst->traceData->setCPSeq(thread[tid]->numInst);
1151        head_inst->traceData->finalize();
1152        head_inst->traceData = NULL;
1153    }
1154
1155    // Update the commit rename map
1156    for (int i = 0; i < head_inst->numDestRegs(); i++) {
1157        renameMap[tid]->setEntry(head_inst->flattenedDestRegIdx(i),
1158                                 head_inst->renamedDestRegIdx(i));
1159    }
1160
1161    if (head_inst->isCopy())
1162        panic("Should not commit any copy instructions!");
1163
1164    // Finally clear the head ROB entry.
1165    rob->retireHead(tid);
1166
1167    // If this was a store, record it for this cycle.
1168    if (head_inst->isStore())
1169        committedStores[tid] = true;
1170
1171    // Return true to indicate that we have committed an instruction.
1172    return true;
1173}
1174
1175template <class Impl>
1176void
1177DefaultCommit<Impl>::getInsts()
1178{
1179    DPRINTF(Commit, "Getting instructions from Rename stage.\n");
1180
1181#if ISA_HAS_DELAY_SLOT
1182    // Read any renamed instructions and place them into the ROB.
1183    int insts_to_process = std::min((int)renameWidth,
1184                               (int)(fromRename->size + skidBuffer.size()));
1185    int rename_idx = 0;
1186
1187    DPRINTF(Commit, "%i insts available to process. Rename Insts:%i "
1188            "SkidBuffer Insts:%i\n", insts_to_process, fromRename->size,
1189            skidBuffer.size());
1190#else
1191    // Read any renamed instructions and place them into the ROB.
1192    int insts_to_process = std::min((int)renameWidth, fromRename->size);
1193#endif
1194
1195
1196    for (int inst_num = 0; inst_num < insts_to_process; ++inst_num) {
1197        DynInstPtr inst;
1198
1199#if ISA_HAS_DELAY_SLOT
1200        // Get insts from skidBuffer or from Rename
1201        if (skidBuffer.size() > 0) {
1202            DPRINTF(Commit, "Grabbing skidbuffer inst.\n");
1203            inst = skidBuffer.front();
1204            skidBuffer.pop();
1205        } else {
1206            DPRINTF(Commit, "Grabbing rename inst.\n");
1207            inst = fromRename->insts[rename_idx++];
1208        }
1209#else
1210        inst = fromRename->insts[inst_num];
1211#endif
1212        int tid = inst->threadNumber;
1213
1214        if (!inst->isSquashed() &&
1215            commitStatus[tid] != ROBSquashing &&
1216            commitStatus[tid] != TrapPending) {
1217            changedROBNumEntries[tid] = true;
1218
1219            DPRINTF(Commit, "Inserting PC %#x [sn:%i] [tid:%i] into ROB.\n",
1220                    inst->readPC(), inst->seqNum, tid);
1221
1222            rob->insertInst(inst);
1223
1224            assert(rob->getThreadEntries(tid) <= rob->getMaxEntries(tid));
1225
1226            youngestSeqNum[tid] = inst->seqNum;
1227        } else {
1228            DPRINTF(Commit, "Instruction PC %#x [sn:%i] [tid:%i] was "
1229                    "squashed, skipping.\n",
1230                    inst->readPC(), inst->seqNum, tid);
1231        }
1232    }
1233
1234#if ISA_HAS_DELAY_SLOT
1235    if (rename_idx < fromRename->size) {
1236        DPRINTF(Commit,"Placing Rename Insts into skidBuffer.\n");
1237
1238        for (;
1239             rename_idx < fromRename->size;
1240             rename_idx++) {
1241            DynInstPtr inst = fromRename->insts[rename_idx];
1242
1243            if (!inst->isSquashed()) {
1244                DPRINTF(Commit, "Inserting PC %#x [sn:%i] [tid:%i] into ",
1245                        "skidBuffer.\n", inst->readPC(), inst->seqNum,
1246                        inst->threadNumber);
1247                skidBuffer.push(inst);
1248            } else {
1249                DPRINTF(Commit, "Instruction PC %#x [sn:%i] [tid:%i] was "
1250                        "squashed, skipping.\n",
1251                        inst->readPC(), inst->seqNum, inst->threadNumber);
1252            }
1253        }
1254    }
1255#endif
1256
1257}
1258
1259template <class Impl>
1260void
1261DefaultCommit<Impl>::skidInsert()
1262{
1263    DPRINTF(Commit, "Attempting to any instructions from rename into "
1264            "skidBuffer.\n");
1265
1266    for (int inst_num = 0; inst_num < fromRename->size; ++inst_num) {
1267        DynInstPtr inst = fromRename->insts[inst_num];
1268
1269        if (!inst->isSquashed()) {
1270            DPRINTF(Commit, "Inserting PC %#x [sn:%i] [tid:%i] into ",
1271                    "skidBuffer.\n", inst->readPC(), inst->seqNum,
1272                    inst->threadNumber);
1273            skidBuffer.push(inst);
1274        } else {
1275            DPRINTF(Commit, "Instruction PC %#x [sn:%i] [tid:%i] was "
1276                    "squashed, skipping.\n",
1277                    inst->readPC(), inst->seqNum, inst->threadNumber);
1278        }
1279    }
1280}
1281
1282template <class Impl>
1283void
1284DefaultCommit<Impl>::markCompletedInsts()
1285{
1286    // Grab completed insts out of the IEW instruction queue, and mark
1287    // instructions completed within the ROB.
1288    for (int inst_num = 0;
1289         inst_num < fromIEW->size && fromIEW->insts[inst_num];
1290         ++inst_num)
1291    {
1292        if (!fromIEW->insts[inst_num]->isSquashed()) {
1293            DPRINTF(Commit, "[tid:%i]: Marking PC %#x, [sn:%lli] ready "
1294                    "within ROB.\n",
1295                    fromIEW->insts[inst_num]->threadNumber,
1296                    fromIEW->insts[inst_num]->readPC(),
1297                    fromIEW->insts[inst_num]->seqNum);
1298
1299            // Mark the instruction as ready to commit.
1300            fromIEW->insts[inst_num]->setCanCommit();
1301        }
1302    }
1303}
1304
1305template <class Impl>
1306bool
1307DefaultCommit<Impl>::robDoneSquashing()
1308{
1309    std::list<unsigned>::iterator threads = activeThreads->begin();
1310    std::list<unsigned>::iterator end = activeThreads->end();
1311
1312    while (threads != end) {
1313        unsigned tid = *threads++;
1314
1315        if (!rob->isDoneSquashing(tid))
1316            return false;
1317    }
1318
1319    return true;
1320}
1321
1322template <class Impl>
1323void
1324DefaultCommit<Impl>::updateComInstStats(DynInstPtr &inst)
1325{
1326    unsigned thread = inst->threadNumber;
1327
1328    //
1329    //  Pick off the software prefetches
1330    //
1331#ifdef TARGET_ALPHA
1332    if (inst->isDataPrefetch()) {
1333        statComSwp[thread]++;
1334    } else {
1335        statComInst[thread]++;
1336    }
1337#else
1338    statComInst[thread]++;
1339#endif
1340
1341    //
1342    //  Control Instructions
1343    //
1344    if (inst->isControl())
1345        statComBranches[thread]++;
1346
1347    //
1348    //  Memory references
1349    //
1350    if (inst->isMemRef()) {
1351        statComRefs[thread]++;
1352
1353        if (inst->isLoad()) {
1354            statComLoads[thread]++;
1355        }
1356    }
1357
1358    if (inst->isMemBarrier()) {
1359        statComMembars[thread]++;
1360    }
1361}
1362
1363////////////////////////////////////////
1364//                                    //
1365//  SMT COMMIT POLICY MAINTAINED HERE //
1366//                                    //
1367////////////////////////////////////////
1368template <class Impl>
1369int
1370DefaultCommit<Impl>::getCommittingThread()
1371{
1372    if (numThreads > 1) {
1373        switch (commitPolicy) {
1374
1375          case Aggressive:
1376            //If Policy is Aggressive, commit will call
1377            //this function multiple times per
1378            //cycle
1379            return oldestReady();
1380
1381          case RoundRobin:
1382            return roundRobin();
1383
1384          case OldestReady:
1385            return oldestReady();
1386
1387          default:
1388            return -1;
1389        }
1390    } else {
1391        assert(!activeThreads->empty());
1392        int tid = activeThreads->front();
1393
1394        if (commitStatus[tid] == Running ||
1395            commitStatus[tid] == Idle ||
1396            commitStatus[tid] == FetchTrapPending) {
1397            return tid;
1398        } else {
1399            return -1;
1400        }
1401    }
1402}
1403
1404template<class Impl>
1405int
1406DefaultCommit<Impl>::roundRobin()
1407{
1408    std::list<unsigned>::iterator pri_iter = priority_list.begin();
1409    std::list<unsigned>::iterator end      = priority_list.end();
1410
1411    while (pri_iter != end) {
1412        unsigned tid = *pri_iter;
1413
1414        if (commitStatus[tid] == Running ||
1415            commitStatus[tid] == Idle ||
1416            commitStatus[tid] == FetchTrapPending) {
1417
1418            if (rob->isHeadReady(tid)) {
1419                priority_list.erase(pri_iter);
1420                priority_list.push_back(tid);
1421
1422                return tid;
1423            }
1424        }
1425
1426        pri_iter++;
1427    }
1428
1429    return -1;
1430}
1431
1432template<class Impl>
1433int
1434DefaultCommit<Impl>::oldestReady()
1435{
1436    unsigned oldest = 0;
1437    bool first = true;
1438
1439    std::list<unsigned>::iterator threads = activeThreads->begin();
1440    std::list<unsigned>::iterator end = activeThreads->end();
1441
1442    while (threads != end) {
1443        unsigned tid = *threads++;
1444
1445        if (!rob->isEmpty(tid) &&
1446            (commitStatus[tid] == Running ||
1447             commitStatus[tid] == Idle ||
1448             commitStatus[tid] == FetchTrapPending)) {
1449
1450            if (rob->isHeadReady(tid)) {
1451
1452                DynInstPtr head_inst = rob->readHeadInst(tid);
1453
1454                if (first) {
1455                    oldest = tid;
1456                    first = false;
1457                } else if (head_inst->seqNum < oldest) {
1458                    oldest = tid;
1459                }
1460            }
1461        }
1462    }
1463
1464    if (!first) {
1465        return oldest;
1466    } else {
1467        return -1;
1468    }
1469}
1470