commit_impl.hh revision 6667:8b5bc1a777bc
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 <algorithm>
33#include <string>
34
35#include "arch/utility.hh"
36#include "base/cp_annotate.hh"
37#include "base/loader/symtab.hh"
38#include "base/timebuf.hh"
39#include "config/full_system.hh"
40#include "config/the_isa.hh"
41#include "config/use_checker.hh"
42#include "cpu/exetrace.hh"
43#include "cpu/o3/commit.hh"
44#include "cpu/o3/thread_state.hh"
45#include "params/DerivO3CPU.hh"
46
47#if USE_CHECKER
48#include "cpu/checker/cpu.hh"
49#endif
50
51using namespace std;
52
53template <class Impl>
54DefaultCommit<Impl>::TrapEvent::TrapEvent(DefaultCommit<Impl> *_commit,
55                                          ThreadID _tid)
56    : Event(CPU_Tick_Pri), commit(_commit), tid(_tid)
57{
58    this->setFlags(AutoDelete);
59}
60
61template <class Impl>
62void
63DefaultCommit<Impl>::TrapEvent::process()
64{
65    // This will get reset by commit if it was switched out at the
66    // time of this event processing.
67    commit->trapSquash[tid] = true;
68}
69
70template <class Impl>
71const char *
72DefaultCommit<Impl>::TrapEvent::description() const
73{
74    return "Trap";
75}
76
77template <class Impl>
78DefaultCommit<Impl>::DefaultCommit(O3CPU *_cpu, DerivO3CPUParams *params)
79    : cpu(_cpu),
80      squashCounter(0),
81      iewToCommitDelay(params->iewToCommitDelay),
82      commitToIEWDelay(params->commitToIEWDelay),
83      renameToROBDelay(params->renameToROBDelay),
84      fetchToCommitDelay(params->commitToFetchDelay),
85      renameWidth(params->renameWidth),
86      commitWidth(params->commitWidth),
87      numThreads(params->numThreads),
88      drainPending(false),
89      switchedOut(false),
90      trapLatency(params->trapLatency)
91{
92    _status = Active;
93    _nextStatus = Inactive;
94    std::string policy = params->smtCommitPolicy;
95
96    //Convert string to lowercase
97    std::transform(policy.begin(), policy.end(), policy.begin(),
98                   (int(*)(int)) tolower);
99
100    //Assign commit policy
101    if (policy == "aggressive"){
102        commitPolicy = Aggressive;
103
104        DPRINTF(Commit,"Commit Policy set to Aggressive.");
105    } else if (policy == "roundrobin"){
106        commitPolicy = RoundRobin;
107
108        //Set-Up Priority List
109        for (ThreadID tid = 0; tid < numThreads; tid++) {
110            priority_list.push_back(tid);
111        }
112
113        DPRINTF(Commit,"Commit Policy set to Round Robin.");
114    } else if (policy == "oldestready"){
115        commitPolicy = OldestReady;
116
117        DPRINTF(Commit,"Commit Policy set to Oldest Ready.");
118    } else {
119        assert(0 && "Invalid SMT Commit Policy. Options Are: {Aggressive,"
120               "RoundRobin,OldestReady}");
121    }
122
123    for (ThreadID tid = 0; tid < numThreads; tid++) {
124        commitStatus[tid] = Idle;
125        changedROBNumEntries[tid] = false;
126        checkEmptyROB[tid] = false;
127        trapInFlight[tid] = false;
128        committedStores[tid] = false;
129        trapSquash[tid] = false;
130        tcSquash[tid] = false;
131        microPC[tid] = 0;
132        nextMicroPC[tid] = 0;
133        PC[tid] = 0;
134        nextPC[tid] = 0;
135        nextNPC[tid] = 0;
136    }
137#if FULL_SYSTEM
138    interrupt = NoFault;
139#endif
140}
141
142template <class Impl>
143std::string
144DefaultCommit<Impl>::name() const
145{
146    return cpu->name() + ".commit";
147}
148
149template <class Impl>
150void
151DefaultCommit<Impl>::regStats()
152{
153    using namespace Stats;
154    commitCommittedInsts
155        .name(name() + ".commitCommittedInsts")
156        .desc("The number of committed instructions")
157        .prereq(commitCommittedInsts);
158    commitSquashedInsts
159        .name(name() + ".commitSquashedInsts")
160        .desc("The number of squashed insts skipped by commit")
161        .prereq(commitSquashedInsts);
162    commitSquashEvents
163        .name(name() + ".commitSquashEvents")
164        .desc("The number of times commit is told to squash")
165        .prereq(commitSquashEvents);
166    commitNonSpecStalls
167        .name(name() + ".commitNonSpecStalls")
168        .desc("The number of times commit has been forced to stall to "
169              "communicate backwards")
170        .prereq(commitNonSpecStalls);
171    branchMispredicts
172        .name(name() + ".branchMispredicts")
173        .desc("The number of times a branch was mispredicted")
174        .prereq(branchMispredicts);
175    numCommittedDist
176        .init(0,commitWidth,1)
177        .name(name() + ".COM:committed_per_cycle")
178        .desc("Number of insts commited each cycle")
179        .flags(Stats::pdf)
180        ;
181
182    statComInst
183        .init(cpu->numThreads)
184        .name(name() + ".COM:count")
185        .desc("Number of instructions committed")
186        .flags(total)
187        ;
188
189    statComSwp
190        .init(cpu->numThreads)
191        .name(name() + ".COM:swp_count")
192        .desc("Number of s/w prefetches committed")
193        .flags(total)
194        ;
195
196    statComRefs
197        .init(cpu->numThreads)
198        .name(name() +  ".COM:refs")
199        .desc("Number of memory references committed")
200        .flags(total)
201        ;
202
203    statComLoads
204        .init(cpu->numThreads)
205        .name(name() +  ".COM:loads")
206        .desc("Number of loads committed")
207        .flags(total)
208        ;
209
210    statComMembars
211        .init(cpu->numThreads)
212        .name(name() +  ".COM:membars")
213        .desc("Number of memory barriers committed")
214        .flags(total)
215        ;
216
217    statComBranches
218        .init(cpu->numThreads)
219        .name(name() + ".COM:branches")
220        .desc("Number of branches committed")
221        .flags(total)
222        ;
223
224    commitEligible
225        .init(cpu->numThreads)
226        .name(name() + ".COM:bw_limited")
227        .desc("number of insts not committed due to BW limits")
228        .flags(total)
229        ;
230
231    commitEligibleSamples
232        .name(name() + ".COM:bw_lim_events")
233        .desc("number cycles where commit BW limit reached")
234        ;
235}
236
237template <class Impl>
238void
239DefaultCommit<Impl>::setThreads(std::vector<Thread *> &threads)
240{
241    thread = threads;
242}
243
244template <class Impl>
245void
246DefaultCommit<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
247{
248    timeBuffer = tb_ptr;
249
250    // Setup wire to send information back to IEW.
251    toIEW = timeBuffer->getWire(0);
252
253    // Setup wire to read data from IEW (for the ROB).
254    robInfoFromIEW = timeBuffer->getWire(-iewToCommitDelay);
255}
256
257template <class Impl>
258void
259DefaultCommit<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr)
260{
261    fetchQueue = fq_ptr;
262
263    // Setup wire to get instructions from rename (for the ROB).
264    fromFetch = fetchQueue->getWire(-fetchToCommitDelay);
265}
266
267template <class Impl>
268void
269DefaultCommit<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr)
270{
271    renameQueue = rq_ptr;
272
273    // Setup wire to get instructions from rename (for the ROB).
274    fromRename = renameQueue->getWire(-renameToROBDelay);
275}
276
277template <class Impl>
278void
279DefaultCommit<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr)
280{
281    iewQueue = iq_ptr;
282
283    // Setup wire to get instructions from IEW.
284    fromIEW = iewQueue->getWire(-iewToCommitDelay);
285}
286
287template <class Impl>
288void
289DefaultCommit<Impl>::setIEWStage(IEW *iew_stage)
290{
291    iewStage = iew_stage;
292}
293
294template<class Impl>
295void
296DefaultCommit<Impl>::setActiveThreads(list<ThreadID> *at_ptr)
297{
298    activeThreads = at_ptr;
299}
300
301template <class Impl>
302void
303DefaultCommit<Impl>::setRenameMap(RenameMap rm_ptr[])
304{
305    for (ThreadID tid = 0; tid < numThreads; tid++)
306        renameMap[tid] = &rm_ptr[tid];
307}
308
309template <class Impl>
310void
311DefaultCommit<Impl>::setROB(ROB *rob_ptr)
312{
313    rob = rob_ptr;
314}
315
316template <class Impl>
317void
318DefaultCommit<Impl>::initStage()
319{
320    rob->setActiveThreads(activeThreads);
321    rob->resetEntries();
322
323    // Broadcast the number of free entries.
324    for (ThreadID tid = 0; tid < numThreads; tid++) {
325        toIEW->commitInfo[tid].usedROB = true;
326        toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid);
327        toIEW->commitInfo[tid].emptyROB = true;
328    }
329
330    // Commit must broadcast the number of free entries it has at the
331    // start of the simulation, so it starts as active.
332    cpu->activateStage(O3CPU::CommitIdx);
333
334    cpu->activityThisCycle();
335    trapLatency = cpu->ticks(trapLatency);
336}
337
338template <class Impl>
339bool
340DefaultCommit<Impl>::drain()
341{
342    drainPending = true;
343
344    return false;
345}
346
347template <class Impl>
348void
349DefaultCommit<Impl>::switchOut()
350{
351    switchedOut = true;
352    drainPending = false;
353    rob->switchOut();
354}
355
356template <class Impl>
357void
358DefaultCommit<Impl>::resume()
359{
360    drainPending = false;
361}
362
363template <class Impl>
364void
365DefaultCommit<Impl>::takeOverFrom()
366{
367    switchedOut = false;
368    _status = Active;
369    _nextStatus = Inactive;
370    for (ThreadID tid = 0; tid < numThreads; tid++) {
371        commitStatus[tid] = Idle;
372        changedROBNumEntries[tid] = false;
373        trapSquash[tid] = false;
374        tcSquash[tid] = false;
375    }
376    squashCounter = 0;
377    rob->takeOverFrom();
378}
379
380template <class Impl>
381void
382DefaultCommit<Impl>::updateStatus()
383{
384    // reset ROB changed variable
385    list<ThreadID>::iterator threads = activeThreads->begin();
386    list<ThreadID>::iterator end = activeThreads->end();
387
388    while (threads != end) {
389        ThreadID tid = *threads++;
390
391        changedROBNumEntries[tid] = false;
392
393        // Also check if any of the threads has a trap pending
394        if (commitStatus[tid] == TrapPending ||
395            commitStatus[tid] == FetchTrapPending) {
396            _nextStatus = Active;
397        }
398    }
399
400    if (_nextStatus == Inactive && _status == Active) {
401        DPRINTF(Activity, "Deactivating stage.\n");
402        cpu->deactivateStage(O3CPU::CommitIdx);
403    } else if (_nextStatus == Active && _status == Inactive) {
404        DPRINTF(Activity, "Activating stage.\n");
405        cpu->activateStage(O3CPU::CommitIdx);
406    }
407
408    _status = _nextStatus;
409}
410
411template <class Impl>
412void
413DefaultCommit<Impl>::setNextStatus()
414{
415    int squashes = 0;
416
417    list<ThreadID>::iterator threads = activeThreads->begin();
418    list<ThreadID>::iterator end = activeThreads->end();
419
420    while (threads != end) {
421        ThreadID tid = *threads++;
422
423        if (commitStatus[tid] == ROBSquashing) {
424            squashes++;
425        }
426    }
427
428    squashCounter = squashes;
429
430    // If commit is currently squashing, then it will have activity for the
431    // next cycle. Set its next status as active.
432    if (squashCounter) {
433        _nextStatus = Active;
434    }
435}
436
437template <class Impl>
438bool
439DefaultCommit<Impl>::changedROBEntries()
440{
441    list<ThreadID>::iterator threads = activeThreads->begin();
442    list<ThreadID>::iterator end = activeThreads->end();
443
444    while (threads != end) {
445        ThreadID tid = *threads++;
446
447        if (changedROBNumEntries[tid]) {
448            return true;
449        }
450    }
451
452    return false;
453}
454
455template <class Impl>
456size_t
457DefaultCommit<Impl>::numROBFreeEntries(ThreadID tid)
458{
459    return rob->numFreeEntries(tid);
460}
461
462template <class Impl>
463void
464DefaultCommit<Impl>::generateTrapEvent(ThreadID tid)
465{
466    DPRINTF(Commit, "Generating trap event for [tid:%i]\n", tid);
467
468    TrapEvent *trap = new TrapEvent(this, tid);
469
470    cpu->schedule(trap, curTick + trapLatency);
471    trapInFlight[tid] = true;
472}
473
474template <class Impl>
475void
476DefaultCommit<Impl>::generateTCEvent(ThreadID tid)
477{
478    assert(!trapInFlight[tid]);
479    DPRINTF(Commit, "Generating TC squash event for [tid:%i]\n", tid);
480
481    tcSquash[tid] = true;
482}
483
484template <class Impl>
485void
486DefaultCommit<Impl>::squashAll(ThreadID tid)
487{
488    // If we want to include the squashing instruction in the squash,
489    // then use one older sequence number.
490    // Hopefully this doesn't mess things up.  Basically I want to squash
491    // all instructions of this thread.
492    InstSeqNum squashed_inst = rob->isEmpty() ?
493        0 : rob->readHeadInst(tid)->seqNum - 1;
494
495    // All younger instructions will be squashed. Set the sequence
496    // number as the youngest instruction in the ROB (0 in this case.
497    // Hopefully nothing breaks.)
498    youngestSeqNum[tid] = 0;
499
500    rob->squash(squashed_inst, tid);
501    changedROBNumEntries[tid] = true;
502
503    // Send back the sequence number of the squashed instruction.
504    toIEW->commitInfo[tid].doneSeqNum = squashed_inst;
505
506    // Send back the squash signal to tell stages that they should
507    // squash.
508    toIEW->commitInfo[tid].squash = true;
509
510    // Send back the rob squashing signal so other stages know that
511    // the ROB is in the process of squashing.
512    toIEW->commitInfo[tid].robSquashing = true;
513
514    toIEW->commitInfo[tid].branchMispredict = false;
515
516    toIEW->commitInfo[tid].nextPC = PC[tid];
517    toIEW->commitInfo[tid].nextNPC = nextPC[tid];
518    toIEW->commitInfo[tid].nextMicroPC = nextMicroPC[tid];
519}
520
521template <class Impl>
522void
523DefaultCommit<Impl>::squashFromTrap(ThreadID tid)
524{
525    squashAll(tid);
526
527    DPRINTF(Commit, "Squashing from trap, restarting at PC %#x\n", PC[tid]);
528
529    thread[tid]->trapPending = false;
530    thread[tid]->inSyscall = false;
531    trapInFlight[tid] = false;
532
533    trapSquash[tid] = false;
534
535    commitStatus[tid] = ROBSquashing;
536    cpu->activityThisCycle();
537}
538
539template <class Impl>
540void
541DefaultCommit<Impl>::squashFromTC(ThreadID tid)
542{
543    squashAll(tid);
544
545    DPRINTF(Commit, "Squashing from TC, restarting at PC %#x\n", PC[tid]);
546
547    thread[tid]->inSyscall = false;
548    assert(!thread[tid]->trapPending);
549
550    commitStatus[tid] = ROBSquashing;
551    cpu->activityThisCycle();
552
553    tcSquash[tid] = false;
554}
555
556template <class Impl>
557void
558DefaultCommit<Impl>::tick()
559{
560    wroteToTimeBuffer = false;
561    _nextStatus = Inactive;
562
563    if (drainPending && rob->isEmpty() && !iewStage->hasStoresToWB()) {
564        cpu->signalDrained();
565        drainPending = false;
566        return;
567    }
568
569    if (activeThreads->empty())
570        return;
571
572    list<ThreadID>::iterator threads = activeThreads->begin();
573    list<ThreadID>::iterator end = activeThreads->end();
574
575    // Check if any of the threads are done squashing.  Change the
576    // status if they are done.
577    while (threads != end) {
578        ThreadID tid = *threads++;
579
580        // Clear the bit saying if the thread has committed stores
581        // this cycle.
582        committedStores[tid] = false;
583
584        if (commitStatus[tid] == ROBSquashing) {
585
586            if (rob->isDoneSquashing(tid)) {
587                commitStatus[tid] = Running;
588            } else {
589                DPRINTF(Commit,"[tid:%u]: Still Squashing, cannot commit any"
590                        " insts this cycle.\n", tid);
591                rob->doSquash(tid);
592                toIEW->commitInfo[tid].robSquashing = true;
593                wroteToTimeBuffer = true;
594            }
595        }
596    }
597
598    commit();
599
600    markCompletedInsts();
601
602    threads = activeThreads->begin();
603
604    while (threads != end) {
605        ThreadID tid = *threads++;
606
607        if (!rob->isEmpty(tid) && rob->readHeadInst(tid)->readyToCommit()) {
608            // The ROB has more instructions it can commit. Its next status
609            // will be active.
610            _nextStatus = Active;
611
612            DynInstPtr inst = rob->readHeadInst(tid);
613
614            DPRINTF(Commit,"[tid:%i]: Instruction [sn:%lli] PC %#x is head of"
615                    " ROB and ready to commit\n",
616                    tid, inst->seqNum, inst->readPC());
617
618        } else if (!rob->isEmpty(tid)) {
619            DynInstPtr inst = rob->readHeadInst(tid);
620
621            DPRINTF(Commit,"[tid:%i]: Can't commit, Instruction [sn:%lli] PC "
622                    "%#x is head of ROB and not ready\n",
623                    tid, inst->seqNum, inst->readPC());
624        }
625
626        DPRINTF(Commit, "[tid:%i]: ROB has %d insts & %d free entries.\n",
627                tid, rob->countInsts(tid), rob->numFreeEntries(tid));
628    }
629
630
631    if (wroteToTimeBuffer) {
632        DPRINTF(Activity, "Activity This Cycle.\n");
633        cpu->activityThisCycle();
634    }
635
636    updateStatus();
637}
638
639#if FULL_SYSTEM
640template <class Impl>
641void
642DefaultCommit<Impl>::handleInterrupt()
643{
644    if (interrupt != NoFault) {
645        // Wait until the ROB is empty and all stores have drained in
646        // order to enter the interrupt.
647        if (rob->isEmpty() && !iewStage->hasStoresToWB()) {
648            // Squash or record that I need to squash this cycle if
649            // an interrupt needed to be handled.
650            DPRINTF(Commit, "Interrupt detected.\n");
651
652            // Clear the interrupt now that it's going to be handled
653            toIEW->commitInfo[0].clearInterrupt = true;
654
655            assert(!thread[0]->inSyscall);
656            thread[0]->inSyscall = true;
657
658            // CPU will handle interrupt.
659            cpu->processInterrupts(interrupt);
660
661            thread[0]->inSyscall = false;
662
663            commitStatus[0] = TrapPending;
664
665            // Generate trap squash event.
666            generateTrapEvent(0);
667
668            interrupt = NoFault;
669        } else {
670            DPRINTF(Commit, "Interrupt pending, waiting for ROB to empty.\n");
671        }
672    } else if (commitStatus[0] != TrapPending &&
673               cpu->checkInterrupts(cpu->tcBase(0)) &&
674               !trapSquash[0] &&
675               !tcSquash[0]) {
676        // Process interrupts if interrupts are enabled, not in PAL
677        // mode, and no other traps or external squashes are currently
678        // pending.
679        // @todo: Allow other threads to handle interrupts.
680
681        // Get any interrupt that happened
682        interrupt = cpu->getInterrupts();
683
684        if (interrupt != NoFault) {
685            // Tell fetch that there is an interrupt pending.  This
686            // will make fetch wait until it sees a non PAL-mode PC,
687            // at which point it stops fetching instructions.
688            toIEW->commitInfo[0].interruptPending = true;
689        }
690    }
691}
692#endif // FULL_SYSTEM
693
694template <class Impl>
695void
696DefaultCommit<Impl>::commit()
697{
698
699#if FULL_SYSTEM
700    // Check for any interrupt, and start processing it.  Or if we
701    // have an outstanding interrupt and are at a point when it is
702    // valid to take an interrupt, process it.
703    if (cpu->checkInterrupts(cpu->tcBase(0))) {
704        handleInterrupt();
705    }
706#endif // FULL_SYSTEM
707
708    ////////////////////////////////////
709    // Check for any possible squashes, handle them first
710    ////////////////////////////////////
711    list<ThreadID>::iterator threads = activeThreads->begin();
712    list<ThreadID>::iterator end = activeThreads->end();
713
714    while (threads != end) {
715        ThreadID tid = *threads++;
716
717        // Not sure which one takes priority.  I think if we have
718        // both, that's a bad sign.
719        if (trapSquash[tid] == true) {
720            assert(!tcSquash[tid]);
721            squashFromTrap(tid);
722        } else if (tcSquash[tid] == true) {
723            assert(commitStatus[tid] != TrapPending);
724            squashFromTC(tid);
725        }
726
727        // Squashed sequence number must be older than youngest valid
728        // instruction in the ROB. This prevents squashes from younger
729        // instructions overriding squashes from older instructions.
730        if (fromIEW->squash[tid] &&
731            commitStatus[tid] != TrapPending &&
732            fromIEW->squashedSeqNum[tid] <= youngestSeqNum[tid]) {
733
734            DPRINTF(Commit, "[tid:%i]: Squashing due to PC %#x [sn:%i]\n",
735                    tid,
736                    fromIEW->mispredPC[tid],
737                    fromIEW->squashedSeqNum[tid]);
738
739            DPRINTF(Commit, "[tid:%i]: Redirecting to PC %#x\n",
740                    tid,
741                    fromIEW->nextPC[tid]);
742
743            commitStatus[tid] = ROBSquashing;
744
745            // If we want to include the squashing instruction in the squash,
746            // then use one older sequence number.
747            InstSeqNum squashed_inst = fromIEW->squashedSeqNum[tid];
748
749            if (fromIEW->includeSquashInst[tid] == true) {
750                squashed_inst--;
751            }
752
753            // All younger instructions will be squashed. Set the sequence
754            // number as the youngest instruction in the ROB.
755            youngestSeqNum[tid] = squashed_inst;
756
757            rob->squash(squashed_inst, tid);
758            changedROBNumEntries[tid] = true;
759
760            toIEW->commitInfo[tid].doneSeqNum = squashed_inst;
761
762            toIEW->commitInfo[tid].squash = true;
763
764            // Send back the rob squashing signal so other stages know that
765            // the ROB is in the process of squashing.
766            toIEW->commitInfo[tid].robSquashing = true;
767
768            toIEW->commitInfo[tid].branchMispredict =
769                fromIEW->branchMispredict[tid];
770
771            toIEW->commitInfo[tid].branchTaken =
772                fromIEW->branchTaken[tid];
773
774            toIEW->commitInfo[tid].nextPC = fromIEW->nextPC[tid];
775            toIEW->commitInfo[tid].nextNPC = fromIEW->nextNPC[tid];
776            toIEW->commitInfo[tid].nextMicroPC = fromIEW->nextMicroPC[tid];
777
778            toIEW->commitInfo[tid].mispredPC = fromIEW->mispredPC[tid];
779
780            if (toIEW->commitInfo[tid].branchMispredict) {
781                ++branchMispredicts;
782            }
783        }
784
785    }
786
787    setNextStatus();
788
789    if (squashCounter != numThreads) {
790        // If we're not currently squashing, then get instructions.
791        getInsts();
792
793        // Try to commit any instructions.
794        commitInsts();
795    }
796
797    //Check for any activity
798    threads = activeThreads->begin();
799
800    while (threads != end) {
801        ThreadID tid = *threads++;
802
803        if (changedROBNumEntries[tid]) {
804            toIEW->commitInfo[tid].usedROB = true;
805            toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid);
806
807            wroteToTimeBuffer = true;
808            changedROBNumEntries[tid] = false;
809            if (rob->isEmpty(tid))
810                checkEmptyROB[tid] = true;
811        }
812
813        // ROB is only considered "empty" for previous stages if: a)
814        // ROB is empty, b) there are no outstanding stores, c) IEW
815        // stage has received any information regarding stores that
816        // committed.
817        // c) is checked by making sure to not consider the ROB empty
818        // on the same cycle as when stores have been committed.
819        // @todo: Make this handle multi-cycle communication between
820        // commit and IEW.
821        if (checkEmptyROB[tid] && rob->isEmpty(tid) &&
822            !iewStage->hasStoresToWB(tid) && !committedStores[tid]) {
823            checkEmptyROB[tid] = false;
824            toIEW->commitInfo[tid].usedROB = true;
825            toIEW->commitInfo[tid].emptyROB = true;
826            toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid);
827            wroteToTimeBuffer = true;
828        }
829
830    }
831}
832
833template <class Impl>
834void
835DefaultCommit<Impl>::commitInsts()
836{
837    ////////////////////////////////////
838    // Handle commit
839    // Note that commit will be handled prior to putting new
840    // instructions in the ROB so that the ROB only tries to commit
841    // instructions it has in this current cycle, and not instructions
842    // it is writing in during this cycle.  Can't commit and squash
843    // things at the same time...
844    ////////////////////////////////////
845
846    DPRINTF(Commit, "Trying to commit instructions in the ROB.\n");
847
848    unsigned num_committed = 0;
849
850    DynInstPtr head_inst;
851
852    // Commit as many instructions as possible until the commit bandwidth
853    // limit is reached, or it becomes impossible to commit any more.
854    while (num_committed < commitWidth) {
855        int commit_thread = getCommittingThread();
856
857        if (commit_thread == -1 || !rob->isHeadReady(commit_thread))
858            break;
859
860        head_inst = rob->readHeadInst(commit_thread);
861
862        ThreadID tid = head_inst->threadNumber;
863
864        assert(tid == commit_thread);
865
866        DPRINTF(Commit, "Trying to commit head instruction, [sn:%i] [tid:%i]\n",
867                head_inst->seqNum, tid);
868
869        // If the head instruction is squashed, it is ready to retire
870        // (be removed from the ROB) at any time.
871        if (head_inst->isSquashed()) {
872
873            DPRINTF(Commit, "Retiring squashed instruction from "
874                    "ROB.\n");
875
876            rob->retireHead(commit_thread);
877
878            ++commitSquashedInsts;
879
880            // Record that the number of ROB entries has changed.
881            changedROBNumEntries[tid] = true;
882        } else {
883            PC[tid] = head_inst->readPC();
884            nextPC[tid] = head_inst->readNextPC();
885            nextNPC[tid] = head_inst->readNextNPC();
886            nextMicroPC[tid] = head_inst->readNextMicroPC();
887
888            // Increment the total number of non-speculative instructions
889            // executed.
890            // Hack for now: it really shouldn't happen until after the
891            // commit is deemed to be successful, but this count is needed
892            // for syscalls.
893            thread[tid]->funcExeInst++;
894
895            // Try to commit the head instruction.
896            bool commit_success = commitHead(head_inst, num_committed);
897
898            if (commit_success) {
899                ++num_committed;
900
901                changedROBNumEntries[tid] = true;
902
903                // Set the doneSeqNum to the youngest committed instruction.
904                toIEW->commitInfo[tid].doneSeqNum = head_inst->seqNum;
905
906                ++commitCommittedInsts;
907
908                // To match the old model, don't count nops and instruction
909                // prefetches towards the total commit count.
910                if (!head_inst->isNop() && !head_inst->isInstPrefetch()) {
911                    cpu->instDone(tid);
912                }
913
914                PC[tid] = nextPC[tid];
915                nextPC[tid] = nextNPC[tid];
916                nextNPC[tid] = nextNPC[tid] + sizeof(TheISA::MachInst);
917                microPC[tid] = nextMicroPC[tid];
918                nextMicroPC[tid] = microPC[tid] + 1;
919
920                int count = 0;
921                Addr oldpc;
922                // Debug statement.  Checks to make sure we're not
923                // currently updating state while handling PC events.
924                assert(!thread[tid]->inSyscall && !thread[tid]->trapPending);
925                do {
926                    oldpc = PC[tid];
927                    cpu->system->pcEventQueue.service(thread[tid]->getTC());
928                    count++;
929                } while (oldpc != PC[tid]);
930                if (count > 1) {
931                    DPRINTF(Commit,
932                            "PC skip function event, stopping commit\n");
933                    break;
934                }
935            } else {
936                DPRINTF(Commit, "Unable to commit head instruction PC:%#x "
937                        "[tid:%i] [sn:%i].\n",
938                        head_inst->readPC(), tid ,head_inst->seqNum);
939                break;
940            }
941        }
942    }
943
944    DPRINTF(CommitRate, "%i\n", num_committed);
945    numCommittedDist.sample(num_committed);
946
947    if (num_committed == commitWidth) {
948        commitEligibleSamples++;
949    }
950}
951
952template <class Impl>
953bool
954DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
955{
956    assert(head_inst);
957
958    ThreadID tid = head_inst->threadNumber;
959
960    // If the instruction is not executed yet, then it will need extra
961    // handling.  Signal backwards that it should be executed.
962    if (!head_inst->isExecuted()) {
963        // Keep this number correct.  We have not yet actually executed
964        // and committed this instruction.
965        thread[tid]->funcExeInst--;
966
967        if (head_inst->isNonSpeculative() ||
968            head_inst->isStoreConditional() ||
969            head_inst->isMemBarrier() ||
970            head_inst->isWriteBarrier()) {
971
972            DPRINTF(Commit, "Encountered a barrier or non-speculative "
973                    "instruction [sn:%lli] at the head of the ROB, PC %#x.\n",
974                    head_inst->seqNum, head_inst->readPC());
975
976            if (inst_num > 0 || iewStage->hasStoresToWB(tid)) {
977                DPRINTF(Commit, "Waiting for all stores to writeback.\n");
978                return false;
979            }
980
981            toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum;
982
983            // Change the instruction so it won't try to commit again until
984            // it is executed.
985            head_inst->clearCanCommit();
986
987            ++commitNonSpecStalls;
988
989            return false;
990        } else if (head_inst->isLoad()) {
991            if (inst_num > 0 || iewStage->hasStoresToWB(tid)) {
992                DPRINTF(Commit, "Waiting for all stores to writeback.\n");
993                return false;
994            }
995
996            assert(head_inst->uncacheable());
997            DPRINTF(Commit, "[sn:%lli]: Uncached load, PC %#x.\n",
998                    head_inst->seqNum, head_inst->readPC());
999
1000            // Send back the non-speculative instruction's sequence
1001            // number.  Tell the lsq to re-execute the load.
1002            toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum;
1003            toIEW->commitInfo[tid].uncached = true;
1004            toIEW->commitInfo[tid].uncachedLoad = head_inst;
1005
1006            head_inst->clearCanCommit();
1007
1008            return false;
1009        } else {
1010            panic("Trying to commit un-executed instruction "
1011                  "of unknown type!\n");
1012        }
1013    }
1014
1015    if (head_inst->isThreadSync()) {
1016        // Not handled for now.
1017        panic("Thread sync instructions are not handled yet.\n");
1018    }
1019
1020    // Check if the instruction caused a fault.  If so, trap.
1021    Fault inst_fault = head_inst->getFault();
1022
1023    // Stores mark themselves as completed.
1024    if (!head_inst->isStore() && inst_fault == NoFault) {
1025        head_inst->setCompleted();
1026    }
1027
1028#if USE_CHECKER
1029    // Use checker prior to updating anything due to traps or PC
1030    // based events.
1031    if (cpu->checker) {
1032        cpu->checker->verify(head_inst);
1033    }
1034#endif
1035
1036    // DTB will sometimes need the machine instruction for when
1037    // faults happen.  So we will set it here, prior to the DTB
1038    // possibly needing it for its fault.
1039    thread[tid]->setInst(
1040        static_cast<TheISA::MachInst>(head_inst->staticInst->machInst));
1041
1042    if (inst_fault != NoFault) {
1043        DPRINTF(Commit, "Inst [sn:%lli] PC %#x has a fault\n",
1044                head_inst->seqNum, head_inst->readPC());
1045
1046        if (iewStage->hasStoresToWB(tid) || inst_num > 0) {
1047            DPRINTF(Commit, "Stores outstanding, fault must wait.\n");
1048            return false;
1049        }
1050
1051        head_inst->setCompleted();
1052
1053#if USE_CHECKER
1054        if (cpu->checker && head_inst->isStore()) {
1055            cpu->checker->verify(head_inst);
1056        }
1057#endif
1058
1059        assert(!thread[tid]->inSyscall);
1060
1061        // Mark that we're in state update mode so that the trap's
1062        // execution doesn't generate extra squashes.
1063        thread[tid]->inSyscall = true;
1064
1065        // Execute the trap.  Although it's slightly unrealistic in
1066        // terms of timing (as it doesn't wait for the full timing of
1067        // the trap event to complete before updating state), it's
1068        // needed to update the state as soon as possible.  This
1069        // prevents external agents from changing any specific state
1070        // that the trap need.
1071        cpu->trap(inst_fault, tid);
1072
1073        // Exit state update mode to avoid accidental updating.
1074        thread[tid]->inSyscall = false;
1075
1076        commitStatus[tid] = TrapPending;
1077
1078        if (head_inst->traceData) {
1079            if (DTRACE(ExecFaulting)) {
1080                head_inst->traceData->setFetchSeq(head_inst->seqNum);
1081                head_inst->traceData->setCPSeq(thread[tid]->numInst);
1082                head_inst->traceData->dump();
1083            }
1084            delete head_inst->traceData;
1085            head_inst->traceData = NULL;
1086        }
1087
1088        // Generate trap squash event.
1089        generateTrapEvent(tid);
1090//        warn("%lli fault (%d) handled @ PC %08p", curTick, inst_fault->name(), head_inst->readPC());
1091        return false;
1092    }
1093
1094    updateComInstStats(head_inst);
1095
1096#if FULL_SYSTEM
1097    if (thread[tid]->profile) {
1098//        bool usermode = TheISA::inUserMode(thread[tid]->getTC());
1099//        thread[tid]->profilePC = usermode ? 1 : head_inst->readPC();
1100        thread[tid]->profilePC = head_inst->readPC();
1101        ProfileNode *node = thread[tid]->profile->consume(thread[tid]->getTC(),
1102                                                          head_inst->staticInst);
1103
1104        if (node)
1105            thread[tid]->profileNode = node;
1106    }
1107    if (CPA::available()) {
1108        if (head_inst->isControl()) {
1109            ThreadContext *tc = thread[tid]->getTC();
1110            CPA::cpa()->swAutoBegin(tc, head_inst->readNextPC());
1111        }
1112    }
1113#endif
1114
1115    if (head_inst->traceData) {
1116        head_inst->traceData->setFetchSeq(head_inst->seqNum);
1117        head_inst->traceData->setCPSeq(thread[tid]->numInst);
1118        head_inst->traceData->dump();
1119        delete head_inst->traceData;
1120        head_inst->traceData = NULL;
1121    }
1122
1123    // Update the commit rename map
1124    for (int i = 0; i < head_inst->numDestRegs(); i++) {
1125        renameMap[tid]->setEntry(head_inst->flattenedDestRegIdx(i),
1126                                 head_inst->renamedDestRegIdx(i));
1127    }
1128
1129    if (head_inst->isCopy())
1130        panic("Should not commit any copy instructions!");
1131
1132    // Finally clear the head ROB entry.
1133    rob->retireHead(tid);
1134
1135    // If this was a store, record it for this cycle.
1136    if (head_inst->isStore())
1137        committedStores[tid] = true;
1138
1139    // Return true to indicate that we have committed an instruction.
1140    return true;
1141}
1142
1143template <class Impl>
1144void
1145DefaultCommit<Impl>::getInsts()
1146{
1147    DPRINTF(Commit, "Getting instructions from Rename stage.\n");
1148
1149    // Read any renamed instructions and place them into the ROB.
1150    int insts_to_process = std::min((int)renameWidth, fromRename->size);
1151
1152    for (int inst_num = 0; inst_num < insts_to_process; ++inst_num) {
1153        DynInstPtr inst;
1154
1155        inst = fromRename->insts[inst_num];
1156        ThreadID tid = inst->threadNumber;
1157
1158        if (!inst->isSquashed() &&
1159            commitStatus[tid] != ROBSquashing &&
1160            commitStatus[tid] != TrapPending) {
1161            changedROBNumEntries[tid] = true;
1162
1163            DPRINTF(Commit, "Inserting PC %#x [sn:%i] [tid:%i] into ROB.\n",
1164                    inst->readPC(), inst->seqNum, tid);
1165
1166            rob->insertInst(inst);
1167
1168            assert(rob->getThreadEntries(tid) <= rob->getMaxEntries(tid));
1169
1170            youngestSeqNum[tid] = inst->seqNum;
1171        } else {
1172            DPRINTF(Commit, "Instruction PC %#x [sn:%i] [tid:%i] was "
1173                    "squashed, skipping.\n",
1174                    inst->readPC(), inst->seqNum, tid);
1175        }
1176    }
1177}
1178
1179template <class Impl>
1180void
1181DefaultCommit<Impl>::skidInsert()
1182{
1183    DPRINTF(Commit, "Attempting to any instructions from rename into "
1184            "skidBuffer.\n");
1185
1186    for (int inst_num = 0; inst_num < fromRename->size; ++inst_num) {
1187        DynInstPtr inst = fromRename->insts[inst_num];
1188
1189        if (!inst->isSquashed()) {
1190            DPRINTF(Commit, "Inserting PC %#x [sn:%i] [tid:%i] into ",
1191                    "skidBuffer.\n", inst->readPC(), inst->seqNum,
1192                    inst->threadNumber);
1193            skidBuffer.push(inst);
1194        } else {
1195            DPRINTF(Commit, "Instruction PC %#x [sn:%i] [tid:%i] was "
1196                    "squashed, skipping.\n",
1197                    inst->readPC(), inst->seqNum, inst->threadNumber);
1198        }
1199    }
1200}
1201
1202template <class Impl>
1203void
1204DefaultCommit<Impl>::markCompletedInsts()
1205{
1206    // Grab completed insts out of the IEW instruction queue, and mark
1207    // instructions completed within the ROB.
1208    for (int inst_num = 0;
1209         inst_num < fromIEW->size && fromIEW->insts[inst_num];
1210         ++inst_num)
1211    {
1212        if (!fromIEW->insts[inst_num]->isSquashed()) {
1213            DPRINTF(Commit, "[tid:%i]: Marking PC %#x, [sn:%lli] ready "
1214                    "within ROB.\n",
1215                    fromIEW->insts[inst_num]->threadNumber,
1216                    fromIEW->insts[inst_num]->readPC(),
1217                    fromIEW->insts[inst_num]->seqNum);
1218
1219            // Mark the instruction as ready to commit.
1220            fromIEW->insts[inst_num]->setCanCommit();
1221        }
1222    }
1223}
1224
1225template <class Impl>
1226bool
1227DefaultCommit<Impl>::robDoneSquashing()
1228{
1229    list<ThreadID>::iterator threads = activeThreads->begin();
1230    list<ThreadID>::iterator end = activeThreads->end();
1231
1232    while (threads != end) {
1233        ThreadID tid = *threads++;
1234
1235        if (!rob->isDoneSquashing(tid))
1236            return false;
1237    }
1238
1239    return true;
1240}
1241
1242template <class Impl>
1243void
1244DefaultCommit<Impl>::updateComInstStats(DynInstPtr &inst)
1245{
1246    ThreadID tid = inst->threadNumber;
1247
1248    //
1249    //  Pick off the software prefetches
1250    //
1251#ifdef TARGET_ALPHA
1252    if (inst->isDataPrefetch()) {
1253        statComSwp[tid]++;
1254    } else {
1255        statComInst[tid]++;
1256    }
1257#else
1258    statComInst[tid]++;
1259#endif
1260
1261    //
1262    //  Control Instructions
1263    //
1264    if (inst->isControl())
1265        statComBranches[tid]++;
1266
1267    //
1268    //  Memory references
1269    //
1270    if (inst->isMemRef()) {
1271        statComRefs[tid]++;
1272
1273        if (inst->isLoad()) {
1274            statComLoads[tid]++;
1275        }
1276    }
1277
1278    if (inst->isMemBarrier()) {
1279        statComMembars[tid]++;
1280    }
1281}
1282
1283////////////////////////////////////////
1284//                                    //
1285//  SMT COMMIT POLICY MAINTAINED HERE //
1286//                                    //
1287////////////////////////////////////////
1288template <class Impl>
1289ThreadID
1290DefaultCommit<Impl>::getCommittingThread()
1291{
1292    if (numThreads > 1) {
1293        switch (commitPolicy) {
1294
1295          case Aggressive:
1296            //If Policy is Aggressive, commit will call
1297            //this function multiple times per
1298            //cycle
1299            return oldestReady();
1300
1301          case RoundRobin:
1302            return roundRobin();
1303
1304          case OldestReady:
1305            return oldestReady();
1306
1307          default:
1308            return InvalidThreadID;
1309        }
1310    } else {
1311        assert(!activeThreads->empty());
1312        ThreadID tid = activeThreads->front();
1313
1314        if (commitStatus[tid] == Running ||
1315            commitStatus[tid] == Idle ||
1316            commitStatus[tid] == FetchTrapPending) {
1317            return tid;
1318        } else {
1319            return InvalidThreadID;
1320        }
1321    }
1322}
1323
1324template<class Impl>
1325ThreadID
1326DefaultCommit<Impl>::roundRobin()
1327{
1328    list<ThreadID>::iterator pri_iter = priority_list.begin();
1329    list<ThreadID>::iterator end      = priority_list.end();
1330
1331    while (pri_iter != end) {
1332        ThreadID tid = *pri_iter;
1333
1334        if (commitStatus[tid] == Running ||
1335            commitStatus[tid] == Idle ||
1336            commitStatus[tid] == FetchTrapPending) {
1337
1338            if (rob->isHeadReady(tid)) {
1339                priority_list.erase(pri_iter);
1340                priority_list.push_back(tid);
1341
1342                return tid;
1343            }
1344        }
1345
1346        pri_iter++;
1347    }
1348
1349    return InvalidThreadID;
1350}
1351
1352template<class Impl>
1353ThreadID
1354DefaultCommit<Impl>::oldestReady()
1355{
1356    unsigned oldest = 0;
1357    bool first = true;
1358
1359    list<ThreadID>::iterator threads = activeThreads->begin();
1360    list<ThreadID>::iterator end = activeThreads->end();
1361
1362    while (threads != end) {
1363        ThreadID tid = *threads++;
1364
1365        if (!rob->isEmpty(tid) &&
1366            (commitStatus[tid] == Running ||
1367             commitStatus[tid] == Idle ||
1368             commitStatus[tid] == FetchTrapPending)) {
1369
1370            if (rob->isHeadReady(tid)) {
1371
1372                DynInstPtr head_inst = rob->readHeadInst(tid);
1373
1374                if (first) {
1375                    oldest = tid;
1376                    first = false;
1377                } else if (head_inst->seqNum < oldest) {
1378                    oldest = tid;
1379                }
1380            }
1381        }
1382    }
1383
1384    if (!first) {
1385        return oldest;
1386    } else {
1387        return InvalidThreadID;
1388    }
1389}
1390