commit_impl.hh revision 4284:c8800319ed0c
1/*
2 * Copyright (c) 2004-2006 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Kevin Lim
29 *          Korey Sewell
30 */
31
32#include "config/full_system.hh"
33#include "config/use_checker.hh"
34
35#include <algorithm>
36#include <string>
37
38#include "arch/utility.hh"
39#include "base/loader/symtab.hh"
40#include "base/timebuf.hh"
41#include "cpu/exetrace.hh"
42#include "cpu/o3/commit.hh"
43#include "cpu/o3/thread_state.hh"
44
45#if USE_CHECKER
46#include "cpu/checker/cpu.hh"
47#endif
48
49template <class Impl>
50DefaultCommit<Impl>::TrapEvent::TrapEvent(DefaultCommit<Impl> *_commit,
51                                          unsigned _tid)
52    : Event(&mainEventQueue, CPU_Tick_Pri), commit(_commit), tid(_tid)
53{
54    this->setFlags(Event::AutoDelete);
55}
56
57template <class Impl>
58void
59DefaultCommit<Impl>::TrapEvent::process()
60{
61    // This will get reset by commit if it was switched out at the
62    // time of this event processing.
63    commit->trapSquash[tid] = true;
64}
65
66template <class Impl>
67const char *
68DefaultCommit<Impl>::TrapEvent::description()
69{
70    return "Trap event";
71}
72
73template <class Impl>
74DefaultCommit<Impl>::DefaultCommit(Params *params)
75    : squashCounter(0),
76      iewToCommitDelay(params->iewToCommitDelay),
77      commitToIEWDelay(params->commitToIEWDelay),
78      renameToROBDelay(params->renameToROBDelay),
79      fetchToCommitDelay(params->commitToFetchDelay),
80      renameWidth(params->renameWidth),
81      commitWidth(params->commitWidth),
82      numThreads(params->numberOfThreads),
83      drainPending(false),
84      switchedOut(false),
85      trapLatency(params->trapLatency)
86{
87    _status = Active;
88    _nextStatus = Inactive;
89    std::string policy = params->smtCommitPolicy;
90
91    //Convert string to lowercase
92    std::transform(policy.begin(), policy.end(), policy.begin(),
93                   (int(*)(int)) tolower);
94
95    //Assign commit policy
96    if (policy == "aggressive"){
97        commitPolicy = Aggressive;
98
99        DPRINTF(Commit,"Commit Policy set to Aggressive.");
100    } else if (policy == "roundrobin"){
101        commitPolicy = RoundRobin;
102
103        //Set-Up Priority List
104        for (int tid=0; tid < numThreads; tid++) {
105            priority_list.push_back(tid);
106        }
107
108        DPRINTF(Commit,"Commit Policy set to Round Robin.");
109    } else if (policy == "oldestready"){
110        commitPolicy = OldestReady;
111
112        DPRINTF(Commit,"Commit Policy set to Oldest Ready.");
113    } else {
114        assert(0 && "Invalid SMT Commit Policy. Options Are: {Aggressive,"
115               "RoundRobin,OldestReady}");
116    }
117
118    for (int i=0; i < numThreads; i++) {
119        commitStatus[i] = Idle;
120        changedROBNumEntries[i] = false;
121        checkEmptyROB[i] = false;
122        trapInFlight[i] = false;
123        committedStores[i] = false;
124        trapSquash[i] = false;
125        tcSquash[i] = false;
126        PC[i] = nextPC[i] = nextNPC[i] = 0;
127    }
128#if FULL_SYSTEM
129    interrupt = NoFault;
130#endif
131}
132
133template <class Impl>
134std::string
135DefaultCommit<Impl>::name() const
136{
137    return cpu->name() + ".commit";
138}
139
140template <class Impl>
141void
142DefaultCommit<Impl>::regStats()
143{
144    using namespace Stats;
145    commitCommittedInsts
146        .name(name() + ".commitCommittedInsts")
147        .desc("The number of committed instructions")
148        .prereq(commitCommittedInsts);
149    commitSquashedInsts
150        .name(name() + ".commitSquashedInsts")
151        .desc("The number of squashed insts skipped by commit")
152        .prereq(commitSquashedInsts);
153    commitSquashEvents
154        .name(name() + ".commitSquashEvents")
155        .desc("The number of times commit is told to squash")
156        .prereq(commitSquashEvents);
157    commitNonSpecStalls
158        .name(name() + ".commitNonSpecStalls")
159        .desc("The number of times commit has been forced to stall to "
160              "communicate backwards")
161        .prereq(commitNonSpecStalls);
162    branchMispredicts
163        .name(name() + ".branchMispredicts")
164        .desc("The number of times a branch was mispredicted")
165        .prereq(branchMispredicts);
166    numCommittedDist
167        .init(0,commitWidth,1)
168        .name(name() + ".COM:committed_per_cycle")
169        .desc("Number of insts commited each cycle")
170        .flags(Stats::pdf)
171        ;
172
173    statComInst
174        .init(cpu->number_of_threads)
175        .name(name() + ".COM:count")
176        .desc("Number of instructions committed")
177        .flags(total)
178        ;
179
180    statComSwp
181        .init(cpu->number_of_threads)
182        .name(name() + ".COM:swp_count")
183        .desc("Number of s/w prefetches committed")
184        .flags(total)
185        ;
186
187    statComRefs
188        .init(cpu->number_of_threads)
189        .name(name() +  ".COM:refs")
190        .desc("Number of memory references committed")
191        .flags(total)
192        ;
193
194    statComLoads
195        .init(cpu->number_of_threads)
196        .name(name() +  ".COM:loads")
197        .desc("Number of loads committed")
198        .flags(total)
199        ;
200
201    statComMembars
202        .init(cpu->number_of_threads)
203        .name(name() +  ".COM:membars")
204        .desc("Number of memory barriers committed")
205        .flags(total)
206        ;
207
208    statComBranches
209        .init(cpu->number_of_threads)
210        .name(name() + ".COM:branches")
211        .desc("Number of branches committed")
212        .flags(total)
213        ;
214
215    commitEligible
216        .init(cpu->number_of_threads)
217        .name(name() + ".COM:bw_limited")
218        .desc("number of insts not committed due to BW limits")
219        .flags(total)
220        ;
221
222    commitEligibleSamples
223        .name(name() + ".COM:bw_lim_events")
224        .desc("number cycles where commit BW limit reached")
225        ;
226}
227
228template <class Impl>
229void
230DefaultCommit<Impl>::setCPU(O3CPU *cpu_ptr)
231{
232    DPRINTF(Commit, "Commit: Setting CPU pointer.\n");
233    cpu = cpu_ptr;
234
235    // Commit must broadcast the number of free entries it has at the start of
236    // the simulation, so it starts as active.
237    cpu->activateStage(O3CPU::CommitIdx);
238
239    trapLatency = cpu->cycles(trapLatency);
240}
241
242template <class Impl>
243void
244DefaultCommit<Impl>::setThreads(std::vector<Thread *> &threads)
245{
246    thread = threads;
247}
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->dump();
1152        delete head_inst->traceData;
1153        head_inst->traceData = NULL;
1154    }
1155
1156    // Update the commit rename map
1157    for (int i = 0; i < head_inst->numDestRegs(); i++) {
1158        renameMap[tid]->setEntry(head_inst->flattenedDestRegIdx(i),
1159                                 head_inst->renamedDestRegIdx(i));
1160    }
1161
1162    if (head_inst->isCopy())
1163        panic("Should not commit any copy instructions!");
1164
1165    // Finally clear the head ROB entry.
1166    rob->retireHead(tid);
1167
1168    // If this was a store, record it for this cycle.
1169    if (head_inst->isStore())
1170        committedStores[tid] = true;
1171
1172    // Return true to indicate that we have committed an instruction.
1173    return true;
1174}
1175
1176template <class Impl>
1177void
1178DefaultCommit<Impl>::getInsts()
1179{
1180    DPRINTF(Commit, "Getting instructions from Rename stage.\n");
1181
1182#if ISA_HAS_DELAY_SLOT
1183    // Read any renamed instructions and place them into the ROB.
1184    int insts_to_process = std::min((int)renameWidth,
1185                               (int)(fromRename->size + skidBuffer.size()));
1186    int rename_idx = 0;
1187
1188    DPRINTF(Commit, "%i insts available to process. Rename Insts:%i "
1189            "SkidBuffer Insts:%i\n", insts_to_process, fromRename->size,
1190            skidBuffer.size());
1191#else
1192    // Read any renamed instructions and place them into the ROB.
1193    int insts_to_process = std::min((int)renameWidth, fromRename->size);
1194#endif
1195
1196
1197    for (int inst_num = 0; inst_num < insts_to_process; ++inst_num) {
1198        DynInstPtr inst;
1199
1200#if ISA_HAS_DELAY_SLOT
1201        // Get insts from skidBuffer or from Rename
1202        if (skidBuffer.size() > 0) {
1203            DPRINTF(Commit, "Grabbing skidbuffer inst.\n");
1204            inst = skidBuffer.front();
1205            skidBuffer.pop();
1206        } else {
1207            DPRINTF(Commit, "Grabbing rename inst.\n");
1208            inst = fromRename->insts[rename_idx++];
1209        }
1210#else
1211        inst = fromRename->insts[inst_num];
1212#endif
1213        int tid = inst->threadNumber;
1214
1215        if (!inst->isSquashed() &&
1216            commitStatus[tid] != ROBSquashing &&
1217            commitStatus[tid] != TrapPending) {
1218            changedROBNumEntries[tid] = true;
1219
1220            DPRINTF(Commit, "Inserting PC %#x [sn:%i] [tid:%i] into ROB.\n",
1221                    inst->readPC(), inst->seqNum, tid);
1222
1223            rob->insertInst(inst);
1224
1225            assert(rob->getThreadEntries(tid) <= rob->getMaxEntries(tid));
1226
1227            youngestSeqNum[tid] = inst->seqNum;
1228        } else {
1229            DPRINTF(Commit, "Instruction PC %#x [sn:%i] [tid:%i] was "
1230                    "squashed, skipping.\n",
1231                    inst->readPC(), inst->seqNum, tid);
1232        }
1233    }
1234
1235#if ISA_HAS_DELAY_SLOT
1236    if (rename_idx < fromRename->size) {
1237        DPRINTF(Commit,"Placing Rename Insts into skidBuffer.\n");
1238
1239        for (;
1240             rename_idx < fromRename->size;
1241             rename_idx++) {
1242            DynInstPtr inst = fromRename->insts[rename_idx];
1243
1244            if (!inst->isSquashed()) {
1245                DPRINTF(Commit, "Inserting PC %#x [sn:%i] [tid:%i] into ",
1246                        "skidBuffer.\n", inst->readPC(), inst->seqNum,
1247                        inst->threadNumber);
1248                skidBuffer.push(inst);
1249            } else {
1250                DPRINTF(Commit, "Instruction PC %#x [sn:%i] [tid:%i] was "
1251                        "squashed, skipping.\n",
1252                        inst->readPC(), inst->seqNum, inst->threadNumber);
1253            }
1254        }
1255    }
1256#endif
1257
1258}
1259
1260template <class Impl>
1261void
1262DefaultCommit<Impl>::skidInsert()
1263{
1264    DPRINTF(Commit, "Attempting to any instructions from rename into "
1265            "skidBuffer.\n");
1266
1267    for (int inst_num = 0; inst_num < fromRename->size; ++inst_num) {
1268        DynInstPtr inst = fromRename->insts[inst_num];
1269
1270        if (!inst->isSquashed()) {
1271            DPRINTF(Commit, "Inserting PC %#x [sn:%i] [tid:%i] into ",
1272                    "skidBuffer.\n", inst->readPC(), inst->seqNum,
1273                    inst->threadNumber);
1274            skidBuffer.push(inst);
1275        } else {
1276            DPRINTF(Commit, "Instruction PC %#x [sn:%i] [tid:%i] was "
1277                    "squashed, skipping.\n",
1278                    inst->readPC(), inst->seqNum, inst->threadNumber);
1279        }
1280    }
1281}
1282
1283template <class Impl>
1284void
1285DefaultCommit<Impl>::markCompletedInsts()
1286{
1287    // Grab completed insts out of the IEW instruction queue, and mark
1288    // instructions completed within the ROB.
1289    for (int inst_num = 0;
1290         inst_num < fromIEW->size && fromIEW->insts[inst_num];
1291         ++inst_num)
1292    {
1293        if (!fromIEW->insts[inst_num]->isSquashed()) {
1294            DPRINTF(Commit, "[tid:%i]: Marking PC %#x, [sn:%lli] ready "
1295                    "within ROB.\n",
1296                    fromIEW->insts[inst_num]->threadNumber,
1297                    fromIEW->insts[inst_num]->readPC(),
1298                    fromIEW->insts[inst_num]->seqNum);
1299
1300            // Mark the instruction as ready to commit.
1301            fromIEW->insts[inst_num]->setCanCommit();
1302        }
1303    }
1304}
1305
1306template <class Impl>
1307bool
1308DefaultCommit<Impl>::robDoneSquashing()
1309{
1310    std::list<unsigned>::iterator threads = activeThreads->begin();
1311    std::list<unsigned>::iterator end = activeThreads->end();
1312
1313    while (threads != end) {
1314        unsigned tid = *threads++;
1315
1316        if (!rob->isDoneSquashing(tid))
1317            return false;
1318    }
1319
1320    return true;
1321}
1322
1323template <class Impl>
1324void
1325DefaultCommit<Impl>::updateComInstStats(DynInstPtr &inst)
1326{
1327    unsigned thread = inst->threadNumber;
1328
1329    //
1330    //  Pick off the software prefetches
1331    //
1332#ifdef TARGET_ALPHA
1333    if (inst->isDataPrefetch()) {
1334        statComSwp[thread]++;
1335    } else {
1336        statComInst[thread]++;
1337    }
1338#else
1339    statComInst[thread]++;
1340#endif
1341
1342    //
1343    //  Control Instructions
1344    //
1345    if (inst->isControl())
1346        statComBranches[thread]++;
1347
1348    //
1349    //  Memory references
1350    //
1351    if (inst->isMemRef()) {
1352        statComRefs[thread]++;
1353
1354        if (inst->isLoad()) {
1355            statComLoads[thread]++;
1356        }
1357    }
1358
1359    if (inst->isMemBarrier()) {
1360        statComMembars[thread]++;
1361    }
1362}
1363
1364////////////////////////////////////////
1365//                                    //
1366//  SMT COMMIT POLICY MAINTAINED HERE //
1367//                                    //
1368////////////////////////////////////////
1369template <class Impl>
1370int
1371DefaultCommit<Impl>::getCommittingThread()
1372{
1373    if (numThreads > 1) {
1374        switch (commitPolicy) {
1375
1376          case Aggressive:
1377            //If Policy is Aggressive, commit will call
1378            //this function multiple times per
1379            //cycle
1380            return oldestReady();
1381
1382          case RoundRobin:
1383            return roundRobin();
1384
1385          case OldestReady:
1386            return oldestReady();
1387
1388          default:
1389            return -1;
1390        }
1391    } else {
1392        assert(!activeThreads->empty());
1393        int tid = activeThreads->front();
1394
1395        if (commitStatus[tid] == Running ||
1396            commitStatus[tid] == Idle ||
1397            commitStatus[tid] == FetchTrapPending) {
1398            return tid;
1399        } else {
1400            return -1;
1401        }
1402    }
1403}
1404
1405template<class Impl>
1406int
1407DefaultCommit<Impl>::roundRobin()
1408{
1409    std::list<unsigned>::iterator pri_iter = priority_list.begin();
1410    std::list<unsigned>::iterator end      = priority_list.end();
1411
1412    while (pri_iter != end) {
1413        unsigned tid = *pri_iter;
1414
1415        if (commitStatus[tid] == Running ||
1416            commitStatus[tid] == Idle ||
1417            commitStatus[tid] == FetchTrapPending) {
1418
1419            if (rob->isHeadReady(tid)) {
1420                priority_list.erase(pri_iter);
1421                priority_list.push_back(tid);
1422
1423                return tid;
1424            }
1425        }
1426
1427        pri_iter++;
1428    }
1429
1430    return -1;
1431}
1432
1433template<class Impl>
1434int
1435DefaultCommit<Impl>::oldestReady()
1436{
1437    unsigned oldest = 0;
1438    bool first = true;
1439
1440    std::list<unsigned>::iterator threads = activeThreads->begin();
1441    std::list<unsigned>::iterator end = activeThreads->end();
1442
1443    while (threads != end) {
1444        unsigned tid = *threads++;
1445
1446        if (!rob->isEmpty(tid) &&
1447            (commitStatus[tid] == Running ||
1448             commitStatus[tid] == Idle ||
1449             commitStatus[tid] == FetchTrapPending)) {
1450
1451            if (rob->isHeadReady(tid)) {
1452
1453                DynInstPtr head_inst = rob->readHeadInst(tid);
1454
1455                if (first) {
1456                    oldest = tid;
1457                    first = false;
1458                } else if (head_inst->seqNum < oldest) {
1459                    oldest = tid;
1460                }
1461            }
1462        }
1463    }
1464
1465    if (!first) {
1466        return oldest;
1467    } else {
1468        return -1;
1469    }
1470}
1471