commit_impl.hh revision 9527:68154bc0e0ea
1/*
2 * Copyright (c) 2010-2012 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2004-2006 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Kevin Lim
41 *          Korey Sewell
42 */
43
44#include <algorithm>
45#include <set>
46#include <string>
47
48#include "arch/utility.hh"
49#include "base/loader/symtab.hh"
50#include "base/cp_annotate.hh"
51#include "config/the_isa.hh"
52#include "cpu/checker/cpu.hh"
53#include "cpu/o3/commit.hh"
54#include "cpu/o3/thread_state.hh"
55#include "cpu/base.hh"
56#include "cpu/exetrace.hh"
57#include "cpu/timebuf.hh"
58#include "debug/Activity.hh"
59#include "debug/Commit.hh"
60#include "debug/CommitRate.hh"
61#include "debug/Drain.hh"
62#include "debug/ExecFaulting.hh"
63#include "debug/O3PipeView.hh"
64#include "params/DerivO3CPU.hh"
65#include "sim/faults.hh"
66#include "sim/full_system.hh"
67
68using namespace std;
69
70template <class Impl>
71DefaultCommit<Impl>::TrapEvent::TrapEvent(DefaultCommit<Impl> *_commit,
72                                          ThreadID _tid)
73    : Event(CPU_Tick_Pri, AutoDelete), commit(_commit), tid(_tid)
74{
75}
76
77template <class Impl>
78void
79DefaultCommit<Impl>::TrapEvent::process()
80{
81    // This will get reset by commit if it was switched out at the
82    // time of this event processing.
83    commit->trapSquash[tid] = true;
84}
85
86template <class Impl>
87const char *
88DefaultCommit<Impl>::TrapEvent::description() const
89{
90    return "Trap";
91}
92
93template <class Impl>
94DefaultCommit<Impl>::DefaultCommit(O3CPU *_cpu, DerivO3CPUParams *params)
95    : cpu(_cpu),
96      squashCounter(0),
97      iewToCommitDelay(params->iewToCommitDelay),
98      commitToIEWDelay(params->commitToIEWDelay),
99      renameToROBDelay(params->renameToROBDelay),
100      fetchToCommitDelay(params->commitToFetchDelay),
101      renameWidth(params->renameWidth),
102      commitWidth(params->commitWidth),
103      numThreads(params->numThreads),
104      drainPending(false),
105      trapLatency(params->trapLatency),
106      canHandleInterrupts(true),
107      avoidQuiesceLiveLock(false)
108{
109    _status = Active;
110    _nextStatus = Inactive;
111    std::string policy = params->smtCommitPolicy;
112
113    //Convert string to lowercase
114    std::transform(policy.begin(), policy.end(), policy.begin(),
115                   (int(*)(int)) tolower);
116
117    //Assign commit policy
118    if (policy == "aggressive"){
119        commitPolicy = Aggressive;
120
121        DPRINTF(Commit,"Commit Policy set to Aggressive.\n");
122    } else if (policy == "roundrobin"){
123        commitPolicy = RoundRobin;
124
125        //Set-Up Priority List
126        for (ThreadID tid = 0; tid < numThreads; tid++) {
127            priority_list.push_back(tid);
128        }
129
130        DPRINTF(Commit,"Commit Policy set to Round Robin.\n");
131    } else if (policy == "oldestready"){
132        commitPolicy = OldestReady;
133
134        DPRINTF(Commit,"Commit Policy set to Oldest Ready.");
135    } else {
136        assert(0 && "Invalid SMT Commit Policy. Options Are: {Aggressive,"
137               "RoundRobin,OldestReady}");
138    }
139
140    for (ThreadID tid = 0; tid < numThreads; tid++) {
141        commitStatus[tid] = Idle;
142        changedROBNumEntries[tid] = false;
143        checkEmptyROB[tid] = false;
144        trapInFlight[tid] = false;
145        committedStores[tid] = false;
146        trapSquash[tid] = false;
147        tcSquash[tid] = false;
148        pc[tid].set(0);
149        lastCommitedSeqNum[tid] = 0;
150        squashAfterInst[tid] = NULL;
151    }
152    interrupt = NoFault;
153}
154
155template <class Impl>
156std::string
157DefaultCommit<Impl>::name() const
158{
159    return cpu->name() + ".commit";
160}
161
162template <class Impl>
163void
164DefaultCommit<Impl>::regStats()
165{
166    using namespace Stats;
167    commitSquashedInsts
168        .name(name() + ".commitSquashedInsts")
169        .desc("The number of squashed insts skipped by commit")
170        .prereq(commitSquashedInsts);
171    commitSquashEvents
172        .name(name() + ".commitSquashEvents")
173        .desc("The number of times commit is told to squash")
174        .prereq(commitSquashEvents);
175    commitNonSpecStalls
176        .name(name() + ".commitNonSpecStalls")
177        .desc("The number of times commit has been forced to stall to "
178              "communicate backwards")
179        .prereq(commitNonSpecStalls);
180    branchMispredicts
181        .name(name() + ".branchMispredicts")
182        .desc("The number of times a branch was mispredicted")
183        .prereq(branchMispredicts);
184    numCommittedDist
185        .init(0,commitWidth,1)
186        .name(name() + ".committed_per_cycle")
187        .desc("Number of insts commited each cycle")
188        .flags(Stats::pdf)
189        ;
190
191    instsCommitted
192        .init(cpu->numThreads)
193        .name(name() + ".committedInsts")
194        .desc("Number of instructions committed")
195        .flags(total)
196        ;
197
198    opsCommitted
199        .init(cpu->numThreads)
200        .name(name() + ".committedOps")
201        .desc("Number of ops (including micro ops) committed")
202        .flags(total)
203        ;
204
205    statComSwp
206        .init(cpu->numThreads)
207        .name(name() + ".swp_count")
208        .desc("Number of s/w prefetches committed")
209        .flags(total)
210        ;
211
212    statComRefs
213        .init(cpu->numThreads)
214        .name(name() +  ".refs")
215        .desc("Number of memory references committed")
216        .flags(total)
217        ;
218
219    statComLoads
220        .init(cpu->numThreads)
221        .name(name() +  ".loads")
222        .desc("Number of loads committed")
223        .flags(total)
224        ;
225
226    statComMembars
227        .init(cpu->numThreads)
228        .name(name() +  ".membars")
229        .desc("Number of memory barriers committed")
230        .flags(total)
231        ;
232
233    statComBranches
234        .init(cpu->numThreads)
235        .name(name() + ".branches")
236        .desc("Number of branches committed")
237        .flags(total)
238        ;
239
240    statComFloating
241        .init(cpu->numThreads)
242        .name(name() + ".fp_insts")
243        .desc("Number of committed floating point instructions.")
244        .flags(total)
245        ;
246
247    statComInteger
248        .init(cpu->numThreads)
249        .name(name()+".int_insts")
250        .desc("Number of committed integer instructions.")
251        .flags(total)
252        ;
253
254    statComFunctionCalls
255        .init(cpu->numThreads)
256        .name(name()+".function_calls")
257        .desc("Number of function calls committed.")
258        .flags(total)
259        ;
260
261    commitEligible
262        .init(cpu->numThreads)
263        .name(name() + ".bw_limited")
264        .desc("number of insts not committed due to BW limits")
265        .flags(total)
266        ;
267
268    commitEligibleSamples
269        .name(name() + ".bw_lim_events")
270        .desc("number cycles where commit BW limit reached")
271        ;
272}
273
274template <class Impl>
275void
276DefaultCommit<Impl>::setThreads(std::vector<Thread *> &threads)
277{
278    thread = threads;
279}
280
281template <class Impl>
282void
283DefaultCommit<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
284{
285    timeBuffer = tb_ptr;
286
287    // Setup wire to send information back to IEW.
288    toIEW = timeBuffer->getWire(0);
289
290    // Setup wire to read data from IEW (for the ROB).
291    robInfoFromIEW = timeBuffer->getWire(-iewToCommitDelay);
292}
293
294template <class Impl>
295void
296DefaultCommit<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr)
297{
298    fetchQueue = fq_ptr;
299
300    // Setup wire to get instructions from rename (for the ROB).
301    fromFetch = fetchQueue->getWire(-fetchToCommitDelay);
302}
303
304template <class Impl>
305void
306DefaultCommit<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr)
307{
308    renameQueue = rq_ptr;
309
310    // Setup wire to get instructions from rename (for the ROB).
311    fromRename = renameQueue->getWire(-renameToROBDelay);
312}
313
314template <class Impl>
315void
316DefaultCommit<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr)
317{
318    iewQueue = iq_ptr;
319
320    // Setup wire to get instructions from IEW.
321    fromIEW = iewQueue->getWire(-iewToCommitDelay);
322}
323
324template <class Impl>
325void
326DefaultCommit<Impl>::setIEWStage(IEW *iew_stage)
327{
328    iewStage = iew_stage;
329}
330
331template<class Impl>
332void
333DefaultCommit<Impl>::setActiveThreads(list<ThreadID> *at_ptr)
334{
335    activeThreads = at_ptr;
336}
337
338template <class Impl>
339void
340DefaultCommit<Impl>::setRenameMap(RenameMap rm_ptr[])
341{
342    for (ThreadID tid = 0; tid < numThreads; tid++)
343        renameMap[tid] = &rm_ptr[tid];
344}
345
346template <class Impl>
347void
348DefaultCommit<Impl>::setROB(ROB *rob_ptr)
349{
350    rob = rob_ptr;
351}
352
353template <class Impl>
354void
355DefaultCommit<Impl>::startupStage()
356{
357    rob->setActiveThreads(activeThreads);
358    rob->resetEntries();
359
360    // Broadcast the number of free entries.
361    for (ThreadID tid = 0; tid < numThreads; tid++) {
362        toIEW->commitInfo[tid].usedROB = true;
363        toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid);
364        toIEW->commitInfo[tid].emptyROB = true;
365    }
366
367    // Commit must broadcast the number of free entries it has at the
368    // start of the simulation, so it starts as active.
369    cpu->activateStage(O3CPU::CommitIdx);
370
371    cpu->activityThisCycle();
372}
373
374template <class Impl>
375void
376DefaultCommit<Impl>::drain()
377{
378    drainPending = true;
379}
380
381template <class Impl>
382void
383DefaultCommit<Impl>::drainResume()
384{
385    drainPending = false;
386}
387
388template <class Impl>
389void
390DefaultCommit<Impl>::drainSanityCheck() const
391{
392    assert(isDrained());
393    rob->drainSanityCheck();
394}
395
396template <class Impl>
397bool
398DefaultCommit<Impl>::isDrained() const
399{
400    /* Make sure no one is executing microcode. There are two reasons
401     * for this:
402     * - Hardware virtualized CPUs can't switch into the middle of a
403     *   microcode sequence.
404     * - The current fetch implementation will most likely get very
405     *   confused if it tries to start fetching an instruction that
406     *   is executing in the middle of a ucode sequence that changes
407     *   address mappings. This can happen on for example x86.
408     */
409    for (ThreadID tid = 0; tid < numThreads; tid++) {
410        if (pc[tid].microPC() != 0)
411            return false;
412    }
413
414    /* Make sure that all instructions have finished committing before
415     * declaring the system as drained. We want the pipeline to be
416     * completely empty when we declare the CPU to be drained. This
417     * makes debugging easier since CPU handover and restoring from a
418     * checkpoint with a different CPU should have the same timing.
419     */
420    return rob->isEmpty() &&
421        interrupt == NoFault;
422}
423
424template <class Impl>
425void
426DefaultCommit<Impl>::takeOverFrom()
427{
428    _status = Active;
429    _nextStatus = Inactive;
430    for (ThreadID tid = 0; tid < numThreads; tid++) {
431        commitStatus[tid] = Idle;
432        changedROBNumEntries[tid] = false;
433        trapSquash[tid] = false;
434        tcSquash[tid] = false;
435        squashAfterInst[tid] = NULL;
436    }
437    squashCounter = 0;
438    rob->takeOverFrom();
439}
440
441template <class Impl>
442void
443DefaultCommit<Impl>::updateStatus()
444{
445    // reset ROB changed variable
446    list<ThreadID>::iterator threads = activeThreads->begin();
447    list<ThreadID>::iterator end = activeThreads->end();
448
449    while (threads != end) {
450        ThreadID tid = *threads++;
451
452        changedROBNumEntries[tid] = false;
453
454        // Also check if any of the threads has a trap pending
455        if (commitStatus[tid] == TrapPending ||
456            commitStatus[tid] == FetchTrapPending) {
457            _nextStatus = Active;
458        }
459    }
460
461    if (_nextStatus == Inactive && _status == Active) {
462        DPRINTF(Activity, "Deactivating stage.\n");
463        cpu->deactivateStage(O3CPU::CommitIdx);
464    } else if (_nextStatus == Active && _status == Inactive) {
465        DPRINTF(Activity, "Activating stage.\n");
466        cpu->activateStage(O3CPU::CommitIdx);
467    }
468
469    _status = _nextStatus;
470}
471
472template <class Impl>
473void
474DefaultCommit<Impl>::setNextStatus()
475{
476    int squashes = 0;
477
478    list<ThreadID>::iterator threads = activeThreads->begin();
479    list<ThreadID>::iterator end = activeThreads->end();
480
481    while (threads != end) {
482        ThreadID tid = *threads++;
483
484        if (commitStatus[tid] == ROBSquashing) {
485            squashes++;
486        }
487    }
488
489    squashCounter = squashes;
490
491    // If commit is currently squashing, then it will have activity for the
492    // next cycle. Set its next status as active.
493    if (squashCounter) {
494        _nextStatus = Active;
495    }
496}
497
498template <class Impl>
499bool
500DefaultCommit<Impl>::changedROBEntries()
501{
502    list<ThreadID>::iterator threads = activeThreads->begin();
503    list<ThreadID>::iterator end = activeThreads->end();
504
505    while (threads != end) {
506        ThreadID tid = *threads++;
507
508        if (changedROBNumEntries[tid]) {
509            return true;
510        }
511    }
512
513    return false;
514}
515
516template <class Impl>
517size_t
518DefaultCommit<Impl>::numROBFreeEntries(ThreadID tid)
519{
520    return rob->numFreeEntries(tid);
521}
522
523template <class Impl>
524void
525DefaultCommit<Impl>::generateTrapEvent(ThreadID tid)
526{
527    DPRINTF(Commit, "Generating trap event for [tid:%i]\n", tid);
528
529    TrapEvent *trap = new TrapEvent(this, tid);
530
531    cpu->schedule(trap, cpu->clockEdge(trapLatency));
532    trapInFlight[tid] = true;
533    thread[tid]->trapPending = true;
534}
535
536template <class Impl>
537void
538DefaultCommit<Impl>::generateTCEvent(ThreadID tid)
539{
540    assert(!trapInFlight[tid]);
541    DPRINTF(Commit, "Generating TC squash event for [tid:%i]\n", tid);
542
543    tcSquash[tid] = true;
544}
545
546template <class Impl>
547void
548DefaultCommit<Impl>::squashAll(ThreadID tid)
549{
550    // If we want to include the squashing instruction in the squash,
551    // then use one older sequence number.
552    // Hopefully this doesn't mess things up.  Basically I want to squash
553    // all instructions of this thread.
554    InstSeqNum squashed_inst = rob->isEmpty() ?
555        lastCommitedSeqNum[tid] : rob->readHeadInst(tid)->seqNum - 1;
556
557    // All younger instructions will be squashed. Set the sequence
558    // number as the youngest instruction in the ROB (0 in this case.
559    // Hopefully nothing breaks.)
560    youngestSeqNum[tid] = lastCommitedSeqNum[tid];
561
562    rob->squash(squashed_inst, tid);
563    changedROBNumEntries[tid] = true;
564
565    // Send back the sequence number of the squashed instruction.
566    toIEW->commitInfo[tid].doneSeqNum = squashed_inst;
567
568    // Send back the squash signal to tell stages that they should
569    // squash.
570    toIEW->commitInfo[tid].squash = true;
571
572    // Send back the rob squashing signal so other stages know that
573    // the ROB is in the process of squashing.
574    toIEW->commitInfo[tid].robSquashing = true;
575
576    toIEW->commitInfo[tid].mispredictInst = NULL;
577    toIEW->commitInfo[tid].squashInst = NULL;
578
579    toIEW->commitInfo[tid].pc = pc[tid];
580}
581
582template <class Impl>
583void
584DefaultCommit<Impl>::squashFromTrap(ThreadID tid)
585{
586    squashAll(tid);
587
588    DPRINTF(Commit, "Squashing from trap, restarting at PC %s\n", pc[tid]);
589
590    thread[tid]->trapPending = false;
591    thread[tid]->noSquashFromTC = false;
592    trapInFlight[tid] = false;
593
594    trapSquash[tid] = false;
595
596    commitStatus[tid] = ROBSquashing;
597    cpu->activityThisCycle();
598}
599
600template <class Impl>
601void
602DefaultCommit<Impl>::squashFromTC(ThreadID tid)
603{
604    squashAll(tid);
605
606    DPRINTF(Commit, "Squashing from TC, restarting at PC %s\n", pc[tid]);
607
608    thread[tid]->noSquashFromTC = false;
609    assert(!thread[tid]->trapPending);
610
611    commitStatus[tid] = ROBSquashing;
612    cpu->activityThisCycle();
613
614    tcSquash[tid] = false;
615}
616
617template <class Impl>
618void
619DefaultCommit<Impl>::squashFromSquashAfter(ThreadID tid)
620{
621    DPRINTF(Commit, "Squashing after squash after request, "
622            "restarting at PC %s\n", pc[tid]);
623
624    squashAll(tid);
625    // Make sure to inform the fetch stage of which instruction caused
626    // the squash. It'll try to re-fetch an instruction executing in
627    // microcode unless this is set.
628    toIEW->commitInfo[tid].squashInst = squashAfterInst[tid];
629    squashAfterInst[tid] = NULL;
630
631    commitStatus[tid] = ROBSquashing;
632    cpu->activityThisCycle();
633}
634
635template <class Impl>
636void
637DefaultCommit<Impl>::squashAfter(ThreadID tid, DynInstPtr &head_inst)
638{
639    DPRINTF(Commit, "Executing squash after for [tid:%i] inst [sn:%lli]\n",
640            tid, head_inst->seqNum);
641
642    assert(!squashAfterInst[tid] || squashAfterInst[tid] == head_inst);
643    commitStatus[tid] = SquashAfterPending;
644    squashAfterInst[tid] = head_inst;
645}
646
647template <class Impl>
648void
649DefaultCommit<Impl>::tick()
650{
651    wroteToTimeBuffer = false;
652    _nextStatus = Inactive;
653
654    if (activeThreads->empty())
655        return;
656
657    list<ThreadID>::iterator threads = activeThreads->begin();
658    list<ThreadID>::iterator end = activeThreads->end();
659
660    // Check if any of the threads are done squashing.  Change the
661    // status if they are done.
662    while (threads != end) {
663        ThreadID tid = *threads++;
664
665        // Clear the bit saying if the thread has committed stores
666        // this cycle.
667        committedStores[tid] = false;
668
669        if (commitStatus[tid] == ROBSquashing) {
670
671            if (rob->isDoneSquashing(tid)) {
672                commitStatus[tid] = Running;
673            } else {
674                DPRINTF(Commit,"[tid:%u]: Still Squashing, cannot commit any"
675                        " insts this cycle.\n", tid);
676                rob->doSquash(tid);
677                toIEW->commitInfo[tid].robSquashing = true;
678                wroteToTimeBuffer = true;
679            }
680        }
681    }
682
683    commit();
684
685    markCompletedInsts();
686
687    threads = activeThreads->begin();
688
689    while (threads != end) {
690        ThreadID tid = *threads++;
691
692        if (!rob->isEmpty(tid) && rob->readHeadInst(tid)->readyToCommit()) {
693            // The ROB has more instructions it can commit. Its next status
694            // will be active.
695            _nextStatus = Active;
696
697            DynInstPtr inst = rob->readHeadInst(tid);
698
699            DPRINTF(Commit,"[tid:%i]: Instruction [sn:%lli] PC %s is head of"
700                    " ROB and ready to commit\n",
701                    tid, inst->seqNum, inst->pcState());
702
703        } else if (!rob->isEmpty(tid)) {
704            DynInstPtr inst = rob->readHeadInst(tid);
705
706            DPRINTF(Commit,"[tid:%i]: Can't commit, Instruction [sn:%lli] PC "
707                    "%s is head of ROB and not ready\n",
708                    tid, inst->seqNum, inst->pcState());
709        }
710
711        DPRINTF(Commit, "[tid:%i]: ROB has %d insts & %d free entries.\n",
712                tid, rob->countInsts(tid), rob->numFreeEntries(tid));
713    }
714
715
716    if (wroteToTimeBuffer) {
717        DPRINTF(Activity, "Activity This Cycle.\n");
718        cpu->activityThisCycle();
719    }
720
721    updateStatus();
722}
723
724template <class Impl>
725void
726DefaultCommit<Impl>::handleInterrupt()
727{
728    // Verify that we still have an interrupt to handle
729    if (!cpu->checkInterrupts(cpu->tcBase(0))) {
730        DPRINTF(Commit, "Pending interrupt is cleared by master before "
731                "it got handled. Restart fetching from the orig path.\n");
732        toIEW->commitInfo[0].clearInterrupt = true;
733        interrupt = NoFault;
734        avoidQuiesceLiveLock = true;
735        return;
736    }
737
738    // Wait until all in flight instructions are finished before enterring
739    // the interrupt.
740    if (canHandleInterrupts && cpu->instList.empty()) {
741        // Squash or record that I need to squash this cycle if
742        // an interrupt needed to be handled.
743        DPRINTF(Commit, "Interrupt detected.\n");
744
745        // Clear the interrupt now that it's going to be handled
746        toIEW->commitInfo[0].clearInterrupt = true;
747
748        assert(!thread[0]->noSquashFromTC);
749        thread[0]->noSquashFromTC = true;
750
751        if (cpu->checker) {
752            cpu->checker->handlePendingInt();
753        }
754
755        // CPU will handle interrupt.
756        cpu->processInterrupts(interrupt);
757
758        thread[0]->noSquashFromTC = false;
759
760        commitStatus[0] = TrapPending;
761
762        // Generate trap squash event.
763        generateTrapEvent(0);
764
765        interrupt = NoFault;
766        avoidQuiesceLiveLock = false;
767    } else {
768        DPRINTF(Commit, "Interrupt pending: instruction is %sin "
769                "flight, ROB is %sempty\n",
770                canHandleInterrupts ? "not " : "",
771                cpu->instList.empty() ? "" : "not " );
772    }
773}
774
775template <class Impl>
776void
777DefaultCommit<Impl>::propagateInterrupt()
778{
779    if (commitStatus[0] == TrapPending || interrupt || trapSquash[0] ||
780            tcSquash[0])
781        return;
782
783    // Process interrupts if interrupts are enabled, not in PAL
784    // mode, and no other traps or external squashes are currently
785    // pending.
786    // @todo: Allow other threads to handle interrupts.
787
788    // Get any interrupt that happened
789    interrupt = cpu->getInterrupts();
790
791    // Tell fetch that there is an interrupt pending.  This
792    // will make fetch wait until it sees a non PAL-mode PC,
793    // at which point it stops fetching instructions.
794    if (interrupt != NoFault)
795        toIEW->commitInfo[0].interruptPending = true;
796}
797
798template <class Impl>
799void
800DefaultCommit<Impl>::commit()
801{
802    if (FullSystem) {
803        // Check if we have a interrupt and get read to handle it
804        if (cpu->checkInterrupts(cpu->tcBase(0)))
805            propagateInterrupt();
806    }
807
808    ////////////////////////////////////
809    // Check for any possible squashes, handle them first
810    ////////////////////////////////////
811    list<ThreadID>::iterator threads = activeThreads->begin();
812    list<ThreadID>::iterator end = activeThreads->end();
813
814    while (threads != end) {
815        ThreadID tid = *threads++;
816
817        // Not sure which one takes priority.  I think if we have
818        // both, that's a bad sign.
819        if (trapSquash[tid] == true) {
820            assert(!tcSquash[tid]);
821            squashFromTrap(tid);
822        } else if (tcSquash[tid] == true) {
823            assert(commitStatus[tid] != TrapPending);
824            squashFromTC(tid);
825        } else if (commitStatus[tid] == SquashAfterPending) {
826            // A squash from the previous cycle of the commit stage (i.e.,
827            // commitInsts() called squashAfter) is pending. Squash the
828            // thread now.
829            squashFromSquashAfter(tid);
830        }
831
832        // Squashed sequence number must be older than youngest valid
833        // instruction in the ROB. This prevents squashes from younger
834        // instructions overriding squashes from older instructions.
835        if (fromIEW->squash[tid] &&
836            commitStatus[tid] != TrapPending &&
837            fromIEW->squashedSeqNum[tid] <= youngestSeqNum[tid]) {
838
839            if (fromIEW->mispredictInst[tid]) {
840                DPRINTF(Commit,
841                    "[tid:%i]: Squashing due to branch mispred PC:%#x [sn:%i]\n",
842                    tid,
843                    fromIEW->mispredictInst[tid]->instAddr(),
844                    fromIEW->squashedSeqNum[tid]);
845            } else {
846                DPRINTF(Commit,
847                    "[tid:%i]: Squashing due to order violation [sn:%i]\n",
848                    tid, fromIEW->squashedSeqNum[tid]);
849            }
850
851            DPRINTF(Commit, "[tid:%i]: Redirecting to PC %#x\n",
852                    tid,
853                    fromIEW->pc[tid].nextInstAddr());
854
855            commitStatus[tid] = ROBSquashing;
856
857            // If we want to include the squashing instruction in the squash,
858            // then use one older sequence number.
859            InstSeqNum squashed_inst = fromIEW->squashedSeqNum[tid];
860
861            if (fromIEW->includeSquashInst[tid] == true) {
862                squashed_inst--;
863            }
864
865            // All younger instructions will be squashed. Set the sequence
866            // number as the youngest instruction in the ROB.
867            youngestSeqNum[tid] = squashed_inst;
868
869            rob->squash(squashed_inst, tid);
870            changedROBNumEntries[tid] = true;
871
872            toIEW->commitInfo[tid].doneSeqNum = squashed_inst;
873
874            toIEW->commitInfo[tid].squash = true;
875
876            // Send back the rob squashing signal so other stages know that
877            // the ROB is in the process of squashing.
878            toIEW->commitInfo[tid].robSquashing = true;
879
880            toIEW->commitInfo[tid].mispredictInst =
881                fromIEW->mispredictInst[tid];
882            toIEW->commitInfo[tid].branchTaken =
883                fromIEW->branchTaken[tid];
884            toIEW->commitInfo[tid].squashInst =
885                                    rob->findInst(tid, squashed_inst);
886            if (toIEW->commitInfo[tid].mispredictInst) {
887                if (toIEW->commitInfo[tid].mispredictInst->isUncondCtrl()) {
888                     toIEW->commitInfo[tid].branchTaken = true;
889                }
890            }
891
892            toIEW->commitInfo[tid].pc = fromIEW->pc[tid];
893
894            if (toIEW->commitInfo[tid].mispredictInst) {
895                ++branchMispredicts;
896            }
897        }
898
899    }
900
901    setNextStatus();
902
903    if (squashCounter != numThreads) {
904        // If we're not currently squashing, then get instructions.
905        getInsts();
906
907        // Try to commit any instructions.
908        commitInsts();
909    }
910
911    //Check for any activity
912    threads = activeThreads->begin();
913
914    while (threads != end) {
915        ThreadID tid = *threads++;
916
917        if (changedROBNumEntries[tid]) {
918            toIEW->commitInfo[tid].usedROB = true;
919            toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid);
920
921            wroteToTimeBuffer = true;
922            changedROBNumEntries[tid] = false;
923            if (rob->isEmpty(tid))
924                checkEmptyROB[tid] = true;
925        }
926
927        // ROB is only considered "empty" for previous stages if: a)
928        // ROB is empty, b) there are no outstanding stores, c) IEW
929        // stage has received any information regarding stores that
930        // committed.
931        // c) is checked by making sure to not consider the ROB empty
932        // on the same cycle as when stores have been committed.
933        // @todo: Make this handle multi-cycle communication between
934        // commit and IEW.
935        if (checkEmptyROB[tid] && rob->isEmpty(tid) &&
936            !iewStage->hasStoresToWB(tid) && !committedStores[tid]) {
937            checkEmptyROB[tid] = false;
938            toIEW->commitInfo[tid].usedROB = true;
939            toIEW->commitInfo[tid].emptyROB = true;
940            toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid);
941            wroteToTimeBuffer = true;
942        }
943
944    }
945}
946
947template <class Impl>
948void
949DefaultCommit<Impl>::commitInsts()
950{
951    ////////////////////////////////////
952    // Handle commit
953    // Note that commit will be handled prior to putting new
954    // instructions in the ROB so that the ROB only tries to commit
955    // instructions it has in this current cycle, and not instructions
956    // it is writing in during this cycle.  Can't commit and squash
957    // things at the same time...
958    ////////////////////////////////////
959
960    DPRINTF(Commit, "Trying to commit instructions in the ROB.\n");
961
962    unsigned num_committed = 0;
963
964    DynInstPtr head_inst;
965
966    // Commit as many instructions as possible until the commit bandwidth
967    // limit is reached, or it becomes impossible to commit any more.
968    while (num_committed < commitWidth) {
969        // Check for any interrupt that we've already squashed for
970        // and start processing it.
971        if (interrupt != NoFault)
972            handleInterrupt();
973
974        int commit_thread = getCommittingThread();
975
976        if (commit_thread == -1 || !rob->isHeadReady(commit_thread))
977            break;
978
979        head_inst = rob->readHeadInst(commit_thread);
980
981        ThreadID tid = head_inst->threadNumber;
982
983        assert(tid == commit_thread);
984
985        DPRINTF(Commit, "Trying to commit head instruction, [sn:%i] [tid:%i]\n",
986                head_inst->seqNum, tid);
987
988        // If the head instruction is squashed, it is ready to retire
989        // (be removed from the ROB) at any time.
990        if (head_inst->isSquashed()) {
991
992            DPRINTF(Commit, "Retiring squashed instruction from "
993                    "ROB.\n");
994
995            rob->retireHead(commit_thread);
996
997            ++commitSquashedInsts;
998
999            // Record that the number of ROB entries has changed.
1000            changedROBNumEntries[tid] = true;
1001        } else {
1002            pc[tid] = head_inst->pcState();
1003
1004            // Increment the total number of non-speculative instructions
1005            // executed.
1006            // Hack for now: it really shouldn't happen until after the
1007            // commit is deemed to be successful, but this count is needed
1008            // for syscalls.
1009            thread[tid]->funcExeInst++;
1010
1011            // Try to commit the head instruction.
1012            bool commit_success = commitHead(head_inst, num_committed);
1013
1014            if (commit_success) {
1015                ++num_committed;
1016
1017                changedROBNumEntries[tid] = true;
1018
1019                // Set the doneSeqNum to the youngest committed instruction.
1020                toIEW->commitInfo[tid].doneSeqNum = head_inst->seqNum;
1021
1022                if (tid == 0) {
1023                    canHandleInterrupts =  (!head_inst->isDelayedCommit()) &&
1024                                           ((THE_ISA != ALPHA_ISA) ||
1025                                             (!(pc[0].instAddr() & 0x3)));
1026                }
1027
1028                // Updates misc. registers.
1029                head_inst->updateMiscRegs();
1030
1031                cpu->traceFunctions(pc[tid].instAddr());
1032
1033                TheISA::advancePC(pc[tid], head_inst->staticInst);
1034
1035                // Keep track of the last sequence number commited
1036                lastCommitedSeqNum[tid] = head_inst->seqNum;
1037
1038                // If this is an instruction that doesn't play nicely with
1039                // others squash everything and restart fetch
1040                if (head_inst->isSquashAfter())
1041                    squashAfter(tid, head_inst);
1042
1043                if (drainPending) {
1044                    DPRINTF(Drain, "Draining: %i:%s\n", tid, pc[tid]);
1045                    if (pc[tid].microPC() == 0 && interrupt == NoFault) {
1046                        squashAfter(tid, head_inst);
1047                        cpu->commitDrained(tid);
1048                    }
1049                }
1050
1051                int count = 0;
1052                Addr oldpc;
1053                // Debug statement.  Checks to make sure we're not
1054                // currently updating state while handling PC events.
1055                assert(!thread[tid]->noSquashFromTC && !thread[tid]->trapPending);
1056                do {
1057                    oldpc = pc[tid].instAddr();
1058                    cpu->system->pcEventQueue.service(thread[tid]->getTC());
1059                    count++;
1060                } while (oldpc != pc[tid].instAddr());
1061                if (count > 1) {
1062                    DPRINTF(Commit,
1063                            "PC skip function event, stopping commit\n");
1064                    break;
1065                }
1066
1067                // Check if an instruction just enabled interrupts and we've
1068                // previously had an interrupt pending that was not handled
1069                // because interrupts were subsequently disabled before the
1070                // pipeline reached a place to handle the interrupt. In that
1071                // case squash now to make sure the interrupt is handled.
1072                //
1073                // If we don't do this, we might end up in a live lock situation
1074                if (!interrupt  && avoidQuiesceLiveLock &&
1075                   (!head_inst->isMicroop() || head_inst->isLastMicroop()) &&
1076                   cpu->checkInterrupts(cpu->tcBase(0)))
1077                    squashAfter(tid, head_inst);
1078            } else {
1079                DPRINTF(Commit, "Unable to commit head instruction PC:%s "
1080                        "[tid:%i] [sn:%i].\n",
1081                        head_inst->pcState(), tid ,head_inst->seqNum);
1082                break;
1083            }
1084        }
1085    }
1086
1087    DPRINTF(CommitRate, "%i\n", num_committed);
1088    numCommittedDist.sample(num_committed);
1089
1090    if (num_committed == commitWidth) {
1091        commitEligibleSamples++;
1092    }
1093}
1094
1095template <class Impl>
1096bool
1097DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
1098{
1099    assert(head_inst);
1100
1101    ThreadID tid = head_inst->threadNumber;
1102
1103    // If the instruction is not executed yet, then it will need extra
1104    // handling.  Signal backwards that it should be executed.
1105    if (!head_inst->isExecuted()) {
1106        // Keep this number correct.  We have not yet actually executed
1107        // and committed this instruction.
1108        thread[tid]->funcExeInst--;
1109
1110        if (head_inst->isNonSpeculative() ||
1111            head_inst->isStoreConditional() ||
1112            head_inst->isMemBarrier() ||
1113            head_inst->isWriteBarrier()) {
1114
1115            DPRINTF(Commit, "Encountered a barrier or non-speculative "
1116                    "instruction [sn:%lli] at the head of the ROB, PC %s.\n",
1117                    head_inst->seqNum, head_inst->pcState());
1118
1119            if (inst_num > 0 || iewStage->hasStoresToWB(tid)) {
1120                DPRINTF(Commit, "Waiting for all stores to writeback.\n");
1121                return false;
1122            }
1123
1124            toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum;
1125
1126            // Change the instruction so it won't try to commit again until
1127            // it is executed.
1128            head_inst->clearCanCommit();
1129
1130            ++commitNonSpecStalls;
1131
1132            return false;
1133        } else if (head_inst->isLoad()) {
1134            if (inst_num > 0 || iewStage->hasStoresToWB(tid)) {
1135                DPRINTF(Commit, "Waiting for all stores to writeback.\n");
1136                return false;
1137            }
1138
1139            assert(head_inst->uncacheable());
1140            DPRINTF(Commit, "[sn:%lli]: Uncached load, PC %s.\n",
1141                    head_inst->seqNum, head_inst->pcState());
1142
1143            // Send back the non-speculative instruction's sequence
1144            // number.  Tell the lsq to re-execute the load.
1145            toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum;
1146            toIEW->commitInfo[tid].uncached = true;
1147            toIEW->commitInfo[tid].uncachedLoad = head_inst;
1148
1149            head_inst->clearCanCommit();
1150
1151            return false;
1152        } else {
1153            panic("Trying to commit un-executed instruction "
1154                  "of unknown type!\n");
1155        }
1156    }
1157
1158    if (head_inst->isThreadSync()) {
1159        // Not handled for now.
1160        panic("Thread sync instructions are not handled yet.\n");
1161    }
1162
1163    // Check if the instruction caused a fault.  If so, trap.
1164    Fault inst_fault = head_inst->getFault();
1165
1166    // Stores mark themselves as completed.
1167    if (!head_inst->isStore() && inst_fault == NoFault) {
1168        head_inst->setCompleted();
1169    }
1170
1171    // Use checker prior to updating anything due to traps or PC
1172    // based events.
1173    if (cpu->checker) {
1174        cpu->checker->verify(head_inst);
1175    }
1176
1177    if (inst_fault != NoFault) {
1178        DPRINTF(Commit, "Inst [sn:%lli] PC %s has a fault\n",
1179                head_inst->seqNum, head_inst->pcState());
1180
1181        if (iewStage->hasStoresToWB(tid) || inst_num > 0) {
1182            DPRINTF(Commit, "Stores outstanding, fault must wait.\n");
1183            return false;
1184        }
1185
1186        head_inst->setCompleted();
1187
1188        if (cpu->checker) {
1189            // Need to check the instruction before its fault is processed
1190            cpu->checker->verify(head_inst);
1191        }
1192
1193        assert(!thread[tid]->noSquashFromTC);
1194
1195        // Mark that we're in state update mode so that the trap's
1196        // execution doesn't generate extra squashes.
1197        thread[tid]->noSquashFromTC = true;
1198
1199        // Execute the trap.  Although it's slightly unrealistic in
1200        // terms of timing (as it doesn't wait for the full timing of
1201        // the trap event to complete before updating state), it's
1202        // needed to update the state as soon as possible.  This
1203        // prevents external agents from changing any specific state
1204        // that the trap need.
1205        cpu->trap(inst_fault, tid, head_inst->staticInst);
1206
1207        // Exit state update mode to avoid accidental updating.
1208        thread[tid]->noSquashFromTC = false;
1209
1210        commitStatus[tid] = TrapPending;
1211
1212        DPRINTF(Commit, "Committing instruction with fault [sn:%lli]\n",
1213            head_inst->seqNum);
1214        if (head_inst->traceData) {
1215            if (DTRACE(ExecFaulting)) {
1216                head_inst->traceData->setFetchSeq(head_inst->seqNum);
1217                head_inst->traceData->setCPSeq(thread[tid]->numOp);
1218                head_inst->traceData->dump();
1219            }
1220            delete head_inst->traceData;
1221            head_inst->traceData = NULL;
1222        }
1223
1224        // Generate trap squash event.
1225        generateTrapEvent(tid);
1226        return false;
1227    }
1228
1229    updateComInstStats(head_inst);
1230
1231    if (FullSystem) {
1232        if (thread[tid]->profile) {
1233            thread[tid]->profilePC = head_inst->instAddr();
1234            ProfileNode *node = thread[tid]->profile->consume(
1235                    thread[tid]->getTC(), head_inst->staticInst);
1236
1237            if (node)
1238                thread[tid]->profileNode = node;
1239        }
1240        if (CPA::available()) {
1241            if (head_inst->isControl()) {
1242                ThreadContext *tc = thread[tid]->getTC();
1243                CPA::cpa()->swAutoBegin(tc, head_inst->nextInstAddr());
1244            }
1245        }
1246    }
1247    DPRINTF(Commit, "Committing instruction with [sn:%lli] PC %s\n",
1248            head_inst->seqNum, head_inst->pcState());
1249    if (head_inst->traceData) {
1250        head_inst->traceData->setFetchSeq(head_inst->seqNum);
1251        head_inst->traceData->setCPSeq(thread[tid]->numOp);
1252        head_inst->traceData->dump();
1253        delete head_inst->traceData;
1254        head_inst->traceData = NULL;
1255    }
1256    if (head_inst->isReturn()) {
1257        DPRINTF(Commit,"Return Instruction Committed [sn:%lli] PC %s \n",
1258                        head_inst->seqNum, head_inst->pcState());
1259    }
1260
1261    // Update the commit rename map
1262    for (int i = 0; i < head_inst->numDestRegs(); i++) {
1263        renameMap[tid]->setEntry(head_inst->flattenedDestRegIdx(i),
1264                                 head_inst->renamedDestRegIdx(i));
1265    }
1266
1267    // Finally clear the head ROB entry.
1268    rob->retireHead(tid);
1269
1270#if TRACING_ON
1271    if (DTRACE(O3PipeView)) {
1272        head_inst->commitTick = curTick() - head_inst->fetchTick;
1273    }
1274#endif
1275
1276    // If this was a store, record it for this cycle.
1277    if (head_inst->isStore())
1278        committedStores[tid] = true;
1279
1280    // Return true to indicate that we have committed an instruction.
1281    return true;
1282}
1283
1284template <class Impl>
1285void
1286DefaultCommit<Impl>::getInsts()
1287{
1288    DPRINTF(Commit, "Getting instructions from Rename stage.\n");
1289
1290    // Read any renamed instructions and place them into the ROB.
1291    int insts_to_process = std::min((int)renameWidth, fromRename->size);
1292
1293    for (int inst_num = 0; inst_num < insts_to_process; ++inst_num) {
1294        DynInstPtr inst;
1295
1296        inst = fromRename->insts[inst_num];
1297        ThreadID tid = inst->threadNumber;
1298
1299        if (!inst->isSquashed() &&
1300            commitStatus[tid] != ROBSquashing &&
1301            commitStatus[tid] != TrapPending) {
1302            changedROBNumEntries[tid] = true;
1303
1304            DPRINTF(Commit, "Inserting PC %s [sn:%i] [tid:%i] into ROB.\n",
1305                    inst->pcState(), inst->seqNum, tid);
1306
1307            rob->insertInst(inst);
1308
1309            assert(rob->getThreadEntries(tid) <= rob->getMaxEntries(tid));
1310
1311            youngestSeqNum[tid] = inst->seqNum;
1312        } else {
1313            DPRINTF(Commit, "Instruction PC %s [sn:%i] [tid:%i] was "
1314                    "squashed, skipping.\n",
1315                    inst->pcState(), inst->seqNum, tid);
1316        }
1317    }
1318}
1319
1320template <class Impl>
1321void
1322DefaultCommit<Impl>::skidInsert()
1323{
1324    DPRINTF(Commit, "Attempting to any instructions from rename into "
1325            "skidBuffer.\n");
1326
1327    for (int inst_num = 0; inst_num < fromRename->size; ++inst_num) {
1328        DynInstPtr inst = fromRename->insts[inst_num];
1329
1330        if (!inst->isSquashed()) {
1331            DPRINTF(Commit, "Inserting PC %s [sn:%i] [tid:%i] into ",
1332                    "skidBuffer.\n", inst->pcState(), inst->seqNum,
1333                    inst->threadNumber);
1334            skidBuffer.push(inst);
1335        } else {
1336            DPRINTF(Commit, "Instruction PC %s [sn:%i] [tid:%i] was "
1337                    "squashed, skipping.\n",
1338                    inst->pcState(), inst->seqNum, inst->threadNumber);
1339        }
1340    }
1341}
1342
1343template <class Impl>
1344void
1345DefaultCommit<Impl>::markCompletedInsts()
1346{
1347    // Grab completed insts out of the IEW instruction queue, and mark
1348    // instructions completed within the ROB.
1349    for (int inst_num = 0;
1350         inst_num < fromIEW->size && fromIEW->insts[inst_num];
1351         ++inst_num)
1352    {
1353        if (!fromIEW->insts[inst_num]->isSquashed()) {
1354            DPRINTF(Commit, "[tid:%i]: Marking PC %s, [sn:%lli] ready "
1355                    "within ROB.\n",
1356                    fromIEW->insts[inst_num]->threadNumber,
1357                    fromIEW->insts[inst_num]->pcState(),
1358                    fromIEW->insts[inst_num]->seqNum);
1359
1360            // Mark the instruction as ready to commit.
1361            fromIEW->insts[inst_num]->setCanCommit();
1362        }
1363    }
1364}
1365
1366template <class Impl>
1367bool
1368DefaultCommit<Impl>::robDoneSquashing()
1369{
1370    list<ThreadID>::iterator threads = activeThreads->begin();
1371    list<ThreadID>::iterator end = activeThreads->end();
1372
1373    while (threads != end) {
1374        ThreadID tid = *threads++;
1375
1376        if (!rob->isDoneSquashing(tid))
1377            return false;
1378    }
1379
1380    return true;
1381}
1382
1383template <class Impl>
1384void
1385DefaultCommit<Impl>::updateComInstStats(DynInstPtr &inst)
1386{
1387    ThreadID tid = inst->threadNumber;
1388
1389    if (!inst->isMicroop() || inst->isLastMicroop())
1390        instsCommitted[tid]++;
1391    opsCommitted[tid]++;
1392
1393    // To match the old model, don't count nops and instruction
1394    // prefetches towards the total commit count.
1395    if (!inst->isNop() && !inst->isInstPrefetch()) {
1396        cpu->instDone(tid, inst);
1397    }
1398
1399    //
1400    //  Control Instructions
1401    //
1402    if (inst->isControl())
1403        statComBranches[tid]++;
1404
1405    //
1406    //  Memory references
1407    //
1408    if (inst->isMemRef()) {
1409        statComRefs[tid]++;
1410
1411        if (inst->isLoad()) {
1412            statComLoads[tid]++;
1413        }
1414    }
1415
1416    if (inst->isMemBarrier()) {
1417        statComMembars[tid]++;
1418    }
1419
1420    // Integer Instruction
1421    if (inst->isInteger())
1422        statComInteger[tid]++;
1423
1424    // Floating Point Instruction
1425    if (inst->isFloating())
1426        statComFloating[tid]++;
1427
1428    // Function Calls
1429    if (inst->isCall())
1430        statComFunctionCalls[tid]++;
1431
1432}
1433
1434////////////////////////////////////////
1435//                                    //
1436//  SMT COMMIT POLICY MAINTAINED HERE //
1437//                                    //
1438////////////////////////////////////////
1439template <class Impl>
1440ThreadID
1441DefaultCommit<Impl>::getCommittingThread()
1442{
1443    if (numThreads > 1) {
1444        switch (commitPolicy) {
1445
1446          case Aggressive:
1447            //If Policy is Aggressive, commit will call
1448            //this function multiple times per
1449            //cycle
1450            return oldestReady();
1451
1452          case RoundRobin:
1453            return roundRobin();
1454
1455          case OldestReady:
1456            return oldestReady();
1457
1458          default:
1459            return InvalidThreadID;
1460        }
1461    } else {
1462        assert(!activeThreads->empty());
1463        ThreadID tid = activeThreads->front();
1464
1465        if (commitStatus[tid] == Running ||
1466            commitStatus[tid] == Idle ||
1467            commitStatus[tid] == FetchTrapPending) {
1468            return tid;
1469        } else {
1470            return InvalidThreadID;
1471        }
1472    }
1473}
1474
1475template<class Impl>
1476ThreadID
1477DefaultCommit<Impl>::roundRobin()
1478{
1479    list<ThreadID>::iterator pri_iter = priority_list.begin();
1480    list<ThreadID>::iterator end      = priority_list.end();
1481
1482    while (pri_iter != end) {
1483        ThreadID tid = *pri_iter;
1484
1485        if (commitStatus[tid] == Running ||
1486            commitStatus[tid] == Idle ||
1487            commitStatus[tid] == FetchTrapPending) {
1488
1489            if (rob->isHeadReady(tid)) {
1490                priority_list.erase(pri_iter);
1491                priority_list.push_back(tid);
1492
1493                return tid;
1494            }
1495        }
1496
1497        pri_iter++;
1498    }
1499
1500    return InvalidThreadID;
1501}
1502
1503template<class Impl>
1504ThreadID
1505DefaultCommit<Impl>::oldestReady()
1506{
1507    unsigned oldest = 0;
1508    bool first = true;
1509
1510    list<ThreadID>::iterator threads = activeThreads->begin();
1511    list<ThreadID>::iterator end = activeThreads->end();
1512
1513    while (threads != end) {
1514        ThreadID tid = *threads++;
1515
1516        if (!rob->isEmpty(tid) &&
1517            (commitStatus[tid] == Running ||
1518             commitStatus[tid] == Idle ||
1519             commitStatus[tid] == FetchTrapPending)) {
1520
1521            if (rob->isHeadReady(tid)) {
1522
1523                DynInstPtr head_inst = rob->readHeadInst(tid);
1524
1525                if (first) {
1526                    oldest = tid;
1527                    first = false;
1528                } else if (head_inst->seqNum < oldest) {
1529                    oldest = tid;
1530                }
1531            }
1532        }
1533    }
1534
1535    if (!first) {
1536        return oldest;
1537    } else {
1538        return InvalidThreadID;
1539    }
1540}
1541