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