commit_impl.hh revision 7720:65d338a8dba4
114039Sstacze01@arm.com/* 214039Sstacze01@arm.com * Copyright (c) 2004-2006 The Regents of The University of Michigan 314039Sstacze01@arm.com * All rights reserved. 414039Sstacze01@arm.com * 514039Sstacze01@arm.com * Redistribution and use in source and binary forms, with or without 614039Sstacze01@arm.com * modification, are permitted provided that the following conditions are 714039Sstacze01@arm.com * met: redistributions of source code must retain the above copyright 814039Sstacze01@arm.com * notice, this list of conditions and the following disclaimer; 914039Sstacze01@arm.com * redistributions in binary form must reproduce the above copyright 1014039Sstacze01@arm.com * notice, this list of conditions and the following disclaimer in the 1114039Sstacze01@arm.com * documentation and/or other materials provided with the distribution; 1214039Sstacze01@arm.com * neither the name of the copyright holders nor the names of its 1314039Sstacze01@arm.com * contributors may be used to endorse or promote products derived from 1414039Sstacze01@arm.com * this software without specific prior written permission. 1514039Sstacze01@arm.com * 1614039Sstacze01@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1714039Sstacze01@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1814039Sstacze01@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1914039Sstacze01@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2014039Sstacze01@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2114039Sstacze01@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2214039Sstacze01@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2314039Sstacze01@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2414039Sstacze01@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2514039Sstacze01@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2614039Sstacze01@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2714039Sstacze01@arm.com * 2814039Sstacze01@arm.com * Authors: Kevin Lim 2914039Sstacze01@arm.com * Korey Sewell 3014039Sstacze01@arm.com */ 3114039Sstacze01@arm.com 3214039Sstacze01@arm.com#include <algorithm> 3314039Sstacze01@arm.com#include <string> 3414039Sstacze01@arm.com 3514039Sstacze01@arm.com#include "arch/utility.hh" 3614039Sstacze01@arm.com#include "base/cp_annotate.hh" 3714039Sstacze01@arm.com#include "base/loader/symtab.hh" 3814039Sstacze01@arm.com#include "base/timebuf.hh" 3914039Sstacze01@arm.com#include "config/full_system.hh" 4014039Sstacze01@arm.com#include "config/the_isa.hh" 4114039Sstacze01@arm.com#include "config/use_checker.hh" 4214039Sstacze01@arm.com#include "cpu/exetrace.hh" 4314039Sstacze01@arm.com#include "cpu/o3/commit.hh" 4414039Sstacze01@arm.com#include "cpu/o3/thread_state.hh" 4514039Sstacze01@arm.com#include "params/DerivO3CPU.hh" 4614039Sstacze01@arm.com 4714039Sstacze01@arm.com#if USE_CHECKER 4814039Sstacze01@arm.com#include "cpu/checker/cpu.hh" 4914039Sstacze01@arm.com#endif 5014039Sstacze01@arm.com 5114039Sstacze01@arm.comusing namespace std; 5214039Sstacze01@arm.com 5314039Sstacze01@arm.comtemplate <class Impl> 5414039Sstacze01@arm.comDefaultCommit<Impl>::TrapEvent::TrapEvent(DefaultCommit<Impl> *_commit, 5514039Sstacze01@arm.com ThreadID _tid) 5614039Sstacze01@arm.com : Event(CPU_Tick_Pri), commit(_commit), tid(_tid) 5714039Sstacze01@arm.com{ 5814039Sstacze01@arm.com this->setFlags(AutoDelete); 5914039Sstacze01@arm.com} 6014039Sstacze01@arm.com 6114039Sstacze01@arm.comtemplate <class Impl> 6214039Sstacze01@arm.comvoid 6314039Sstacze01@arm.comDefaultCommit<Impl>::TrapEvent::process() 6414039Sstacze01@arm.com{ 6514039Sstacze01@arm.com // This will get reset by commit if it was switched out at the 6614039Sstacze01@arm.com // time of this event processing. 6714039Sstacze01@arm.com commit->trapSquash[tid] = true; 6814039Sstacze01@arm.com} 6914039Sstacze01@arm.com 7014039Sstacze01@arm.comtemplate <class Impl> 7114039Sstacze01@arm.comconst char * 7214039Sstacze01@arm.comDefaultCommit<Impl>::TrapEvent::description() const 7314039Sstacze01@arm.com{ 7414039Sstacze01@arm.com return "Trap"; 7514039Sstacze01@arm.com} 7614039Sstacze01@arm.com 7714039Sstacze01@arm.comtemplate <class Impl> 7814039Sstacze01@arm.comDefaultCommit<Impl>::DefaultCommit(O3CPU *_cpu, DerivO3CPUParams *params) 7914039Sstacze01@arm.com : cpu(_cpu), 8014039Sstacze01@arm.com squashCounter(0), 8114063Sadrian.herrera@arm.com iewToCommitDelay(params->iewToCommitDelay), 8214063Sadrian.herrera@arm.com commitToIEWDelay(params->commitToIEWDelay), 8314063Sadrian.herrera@arm.com renameToROBDelay(params->renameToROBDelay), 8414063Sadrian.herrera@arm.com fetchToCommitDelay(params->commitToFetchDelay), 8514063Sadrian.herrera@arm.com renameWidth(params->renameWidth), 8614063Sadrian.herrera@arm.com commitWidth(params->commitWidth), 8714063Sadrian.herrera@arm.com numThreads(params->numThreads), 8814063Sadrian.herrera@arm.com drainPending(false), 8914063Sadrian.herrera@arm.com switchedOut(false), 9014063Sadrian.herrera@arm.com trapLatency(params->trapLatency) 9114063Sadrian.herrera@arm.com{ 9214063Sadrian.herrera@arm.com _status = Active; 9314063Sadrian.herrera@arm.com _nextStatus = Inactive; 9414063Sadrian.herrera@arm.com std::string policy = params->smtCommitPolicy; 9514063Sadrian.herrera@arm.com 9614063Sadrian.herrera@arm.com //Convert string to lowercase 9714063Sadrian.herrera@arm.com std::transform(policy.begin(), policy.end(), policy.begin(), 9814063Sadrian.herrera@arm.com (int(*)(int)) tolower); 9914039Sstacze01@arm.com 10014039Sstacze01@arm.com //Assign commit policy 10114039Sstacze01@arm.com if (policy == "aggressive"){ 10214039Sstacze01@arm.com commitPolicy = Aggressive; 10314039Sstacze01@arm.com 10414039Sstacze01@arm.com DPRINTF(Commit,"Commit Policy set to Aggressive."); 10514039Sstacze01@arm.com } else if (policy == "roundrobin"){ 10614039Sstacze01@arm.com commitPolicy = RoundRobin; 10714039Sstacze01@arm.com 10814039Sstacze01@arm.com //Set-Up Priority List 10914039Sstacze01@arm.com for (ThreadID tid = 0; tid < numThreads; tid++) { 11014039Sstacze01@arm.com priority_list.push_back(tid); 11114039Sstacze01@arm.com } 11214039Sstacze01@arm.com 11314039Sstacze01@arm.com DPRINTF(Commit,"Commit Policy set to Round Robin."); 11414039Sstacze01@arm.com } else if (policy == "oldestready"){ 11514039Sstacze01@arm.com commitPolicy = OldestReady; 11614039Sstacze01@arm.com 11714039Sstacze01@arm.com DPRINTF(Commit,"Commit Policy set to Oldest Ready."); 11814039Sstacze01@arm.com } else { 11914039Sstacze01@arm.com assert(0 && "Invalid SMT Commit Policy. Options Are: {Aggressive," 12014039Sstacze01@arm.com "RoundRobin,OldestReady}"); 12114039Sstacze01@arm.com } 12214039Sstacze01@arm.com 12314039Sstacze01@arm.com for (ThreadID tid = 0; tid < numThreads; tid++) { 12414039Sstacze01@arm.com commitStatus[tid] = Idle; 12514039Sstacze01@arm.com changedROBNumEntries[tid] = false; 12614039Sstacze01@arm.com checkEmptyROB[tid] = false; 12714039Sstacze01@arm.com trapInFlight[tid] = false; 12814039Sstacze01@arm.com committedStores[tid] = false; 12914039Sstacze01@arm.com trapSquash[tid] = false; 13014039Sstacze01@arm.com tcSquash[tid] = false; 13114039Sstacze01@arm.com pc[tid].set(0); 13214039Sstacze01@arm.com } 13314039Sstacze01@arm.com#if FULL_SYSTEM 13414039Sstacze01@arm.com interrupt = NoFault; 13514039Sstacze01@arm.com#endif 13614039Sstacze01@arm.com} 13714039Sstacze01@arm.com 13814039Sstacze01@arm.comtemplate <class Impl> 13914039Sstacze01@arm.comstd::string 14014039Sstacze01@arm.comDefaultCommit<Impl>::name() const 14114039Sstacze01@arm.com{ 14214039Sstacze01@arm.com return cpu->name() + ".commit"; 14314039Sstacze01@arm.com} 14414039Sstacze01@arm.com 14514039Sstacze01@arm.comtemplate <class Impl> 14614039Sstacze01@arm.comvoid 14714039Sstacze01@arm.comDefaultCommit<Impl>::regStats() 14814039Sstacze01@arm.com{ 14914039Sstacze01@arm.com using namespace Stats; 15014039Sstacze01@arm.com commitCommittedInsts 15114039Sstacze01@arm.com .name(name() + ".commitCommittedInsts") 15214039Sstacze01@arm.com .desc("The number of committed instructions") 15314039Sstacze01@arm.com .prereq(commitCommittedInsts); 15414039Sstacze01@arm.com commitSquashedInsts 15514039Sstacze01@arm.com .name(name() + ".commitSquashedInsts") 15614039Sstacze01@arm.com .desc("The number of squashed insts skipped by commit") 15714039Sstacze01@arm.com .prereq(commitSquashedInsts); 15814039Sstacze01@arm.com commitSquashEvents 15914039Sstacze01@arm.com .name(name() + ".commitSquashEvents") 16014039Sstacze01@arm.com .desc("The number of times commit is told to squash") 16114039Sstacze01@arm.com .prereq(commitSquashEvents); 16214039Sstacze01@arm.com commitNonSpecStalls 16314039Sstacze01@arm.com .name(name() + ".commitNonSpecStalls") 16414039Sstacze01@arm.com .desc("The number of times commit has been forced to stall to " 16514039Sstacze01@arm.com "communicate backwards") 16614039Sstacze01@arm.com .prereq(commitNonSpecStalls); 16714039Sstacze01@arm.com branchMispredicts 16814039Sstacze01@arm.com .name(name() + ".branchMispredicts") 16914039Sstacze01@arm.com .desc("The number of times a branch was mispredicted") 17014039Sstacze01@arm.com .prereq(branchMispredicts); 17114039Sstacze01@arm.com numCommittedDist 17214039Sstacze01@arm.com .init(0,commitWidth,1) 17314039Sstacze01@arm.com .name(name() + ".COM:committed_per_cycle") 17414039Sstacze01@arm.com .desc("Number of insts commited each cycle") 17514039Sstacze01@arm.com .flags(Stats::pdf) 17614039Sstacze01@arm.com ; 17714039Sstacze01@arm.com 17814039Sstacze01@arm.com statComInst 17914039Sstacze01@arm.com .init(cpu->numThreads) 18014039Sstacze01@arm.com .name(name() + ".COM:count") 18114039Sstacze01@arm.com .desc("Number of instructions committed") 18214039Sstacze01@arm.com .flags(total) 18314039Sstacze01@arm.com ; 18414039Sstacze01@arm.com 18514039Sstacze01@arm.com statComSwp 18614039Sstacze01@arm.com .init(cpu->numThreads) 18714039Sstacze01@arm.com .name(name() + ".COM:swp_count") 18814039Sstacze01@arm.com .desc("Number of s/w prefetches committed") 18914039Sstacze01@arm.com .flags(total) 19014039Sstacze01@arm.com ; 19114039Sstacze01@arm.com 19214039Sstacze01@arm.com statComRefs 19314039Sstacze01@arm.com .init(cpu->numThreads) 19414039Sstacze01@arm.com .name(name() + ".COM:refs") 19514039Sstacze01@arm.com .desc("Number of memory references committed") 19614039Sstacze01@arm.com .flags(total) 19714039Sstacze01@arm.com ; 19814039Sstacze01@arm.com 19914039Sstacze01@arm.com statComLoads 20014039Sstacze01@arm.com .init(cpu->numThreads) 20114039Sstacze01@arm.com .name(name() + ".COM:loads") 20214039Sstacze01@arm.com .desc("Number of loads committed") 20314039Sstacze01@arm.com .flags(total) 20414039Sstacze01@arm.com ; 20514039Sstacze01@arm.com 20614039Sstacze01@arm.com statComMembars 20714039Sstacze01@arm.com .init(cpu->numThreads) 20814039Sstacze01@arm.com .name(name() + ".COM:membars") 20914039Sstacze01@arm.com .desc("Number of memory barriers committed") 21014039Sstacze01@arm.com .flags(total) 21114039Sstacze01@arm.com ; 21214039Sstacze01@arm.com 21314039Sstacze01@arm.com statComBranches 21414039Sstacze01@arm.com .init(cpu->numThreads) 21514039Sstacze01@arm.com .name(name() + ".COM:branches") 21614039Sstacze01@arm.com .desc("Number of branches committed") 21714039Sstacze01@arm.com .flags(total) 21814039Sstacze01@arm.com ; 21914039Sstacze01@arm.com 22014039Sstacze01@arm.com commitEligible 22114039Sstacze01@arm.com .init(cpu->numThreads) 22214039Sstacze01@arm.com .name(name() + ".COM:bw_limited") 22314039Sstacze01@arm.com .desc("number of insts not committed due to BW limits") 22414039Sstacze01@arm.com .flags(total) 22514039Sstacze01@arm.com ; 22614039Sstacze01@arm.com 22714039Sstacze01@arm.com commitEligibleSamples 22814039Sstacze01@arm.com .name(name() + ".COM:bw_lim_events") 22914039Sstacze01@arm.com .desc("number cycles where commit BW limit reached") 23014039Sstacze01@arm.com ; 23114039Sstacze01@arm.com} 23214039Sstacze01@arm.com 23314039Sstacze01@arm.comtemplate <class Impl> 23414039Sstacze01@arm.comvoid 23514039Sstacze01@arm.comDefaultCommit<Impl>::setThreads(std::vector<Thread *> &threads) 23614039Sstacze01@arm.com{ 23714039Sstacze01@arm.com thread = threads; 23814039Sstacze01@arm.com} 23914039Sstacze01@arm.com 24014039Sstacze01@arm.comtemplate <class Impl> 24114039Sstacze01@arm.comvoid 24214039Sstacze01@arm.comDefaultCommit<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) 24314039Sstacze01@arm.com{ 24414039Sstacze01@arm.com timeBuffer = tb_ptr; 24514039Sstacze01@arm.com 24614039Sstacze01@arm.com // Setup wire to send information back to IEW. 24714039Sstacze01@arm.com toIEW = timeBuffer->getWire(0); 24814039Sstacze01@arm.com 24914039Sstacze01@arm.com // Setup wire to read data from IEW (for the ROB). 25014039Sstacze01@arm.com robInfoFromIEW = timeBuffer->getWire(-iewToCommitDelay); 25114039Sstacze01@arm.com} 25214039Sstacze01@arm.com 25314039Sstacze01@arm.comtemplate <class Impl> 25414039Sstacze01@arm.comvoid 25514039Sstacze01@arm.comDefaultCommit<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr) 25614039Sstacze01@arm.com{ 25714039Sstacze01@arm.com fetchQueue = fq_ptr; 25814039Sstacze01@arm.com 25914039Sstacze01@arm.com // Setup wire to get instructions from rename (for the ROB). 26014039Sstacze01@arm.com fromFetch = fetchQueue->getWire(-fetchToCommitDelay); 26114039Sstacze01@arm.com} 26214039Sstacze01@arm.com 26314039Sstacze01@arm.comtemplate <class Impl> 26414039Sstacze01@arm.comvoid 26514039Sstacze01@arm.comDefaultCommit<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr) 26614039Sstacze01@arm.com{ 26714039Sstacze01@arm.com renameQueue = rq_ptr; 26814039Sstacze01@arm.com 26914039Sstacze01@arm.com // Setup wire to get instructions from rename (for the ROB). 27014039Sstacze01@arm.com fromRename = renameQueue->getWire(-renameToROBDelay); 27114039Sstacze01@arm.com} 27214039Sstacze01@arm.com 27314039Sstacze01@arm.comtemplate <class Impl> 27414039Sstacze01@arm.comvoid 27514039Sstacze01@arm.comDefaultCommit<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr) 27614039Sstacze01@arm.com{ 27714039Sstacze01@arm.com iewQueue = iq_ptr; 27814039Sstacze01@arm.com 27914039Sstacze01@arm.com // Setup wire to get instructions from IEW. 28014039Sstacze01@arm.com fromIEW = iewQueue->getWire(-iewToCommitDelay); 28114039Sstacze01@arm.com} 28214039Sstacze01@arm.com 28314039Sstacze01@arm.comtemplate <class Impl> 28414039Sstacze01@arm.comvoid 28514039Sstacze01@arm.comDefaultCommit<Impl>::setIEWStage(IEW *iew_stage) 28614039Sstacze01@arm.com{ 28714039Sstacze01@arm.com iewStage = iew_stage; 28814039Sstacze01@arm.com} 28914039Sstacze01@arm.com 29014039Sstacze01@arm.comtemplate<class Impl> 29114039Sstacze01@arm.comvoid 29214039Sstacze01@arm.comDefaultCommit<Impl>::setActiveThreads(list<ThreadID> *at_ptr) 29314039Sstacze01@arm.com{ 29414039Sstacze01@arm.com activeThreads = at_ptr; 29514039Sstacze01@arm.com} 29614039Sstacze01@arm.com 29714039Sstacze01@arm.comtemplate <class Impl> 29814039Sstacze01@arm.comvoid 29914039Sstacze01@arm.comDefaultCommit<Impl>::setRenameMap(RenameMap rm_ptr[]) 30014039Sstacze01@arm.com{ 30114039Sstacze01@arm.com for (ThreadID tid = 0; tid < numThreads; tid++) 30214039Sstacze01@arm.com renameMap[tid] = &rm_ptr[tid]; 30314039Sstacze01@arm.com} 30414039Sstacze01@arm.com 30514039Sstacze01@arm.comtemplate <class Impl> 30614039Sstacze01@arm.comvoid 30714039Sstacze01@arm.comDefaultCommit<Impl>::setROB(ROB *rob_ptr) 30814039Sstacze01@arm.com{ 30914039Sstacze01@arm.com rob = rob_ptr; 31014039Sstacze01@arm.com} 31114039Sstacze01@arm.com 31214039Sstacze01@arm.comtemplate <class Impl> 31314039Sstacze01@arm.comvoid 31414039Sstacze01@arm.comDefaultCommit<Impl>::initStage() 31514039Sstacze01@arm.com{ 31614039Sstacze01@arm.com rob->setActiveThreads(activeThreads); 31714039Sstacze01@arm.com rob->resetEntries(); 31814039Sstacze01@arm.com 31914039Sstacze01@arm.com // Broadcast the number of free entries. 32014039Sstacze01@arm.com for (ThreadID tid = 0; tid < numThreads; tid++) { 32114039Sstacze01@arm.com toIEW->commitInfo[tid].usedROB = true; 32214039Sstacze01@arm.com toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid); 32314039Sstacze01@arm.com toIEW->commitInfo[tid].emptyROB = true; 32414039Sstacze01@arm.com } 32514039Sstacze01@arm.com 32614039Sstacze01@arm.com // Commit must broadcast the number of free entries it has at the 32714039Sstacze01@arm.com // start of the simulation, so it starts as active. 32814039Sstacze01@arm.com cpu->activateStage(O3CPU::CommitIdx); 32914039Sstacze01@arm.com 33014039Sstacze01@arm.com cpu->activityThisCycle(); 33114039Sstacze01@arm.com trapLatency = cpu->ticks(trapLatency); 33214039Sstacze01@arm.com} 33314039Sstacze01@arm.com 33414039Sstacze01@arm.comtemplate <class Impl> 33514039Sstacze01@arm.combool 33614039Sstacze01@arm.comDefaultCommit<Impl>::drain() 33714039Sstacze01@arm.com{ 33814039Sstacze01@arm.com drainPending = true; 33914039Sstacze01@arm.com 34014039Sstacze01@arm.com return false; 34114039Sstacze01@arm.com} 34214039Sstacze01@arm.com 34314039Sstacze01@arm.comtemplate <class Impl> 34414039Sstacze01@arm.comvoid 34514039Sstacze01@arm.comDefaultCommit<Impl>::switchOut() 34614039Sstacze01@arm.com{ 34714039Sstacze01@arm.com switchedOut = true; 34814039Sstacze01@arm.com drainPending = false; 34914039Sstacze01@arm.com rob->switchOut(); 35014039Sstacze01@arm.com} 35114039Sstacze01@arm.com 35214039Sstacze01@arm.comtemplate <class Impl> 35314039Sstacze01@arm.comvoid 35414039Sstacze01@arm.comDefaultCommit<Impl>::resume() 35514039Sstacze01@arm.com{ 35614039Sstacze01@arm.com drainPending = false; 35714039Sstacze01@arm.com} 35814039Sstacze01@arm.com 35914039Sstacze01@arm.comtemplate <class Impl> 36014039Sstacze01@arm.comvoid 36114039Sstacze01@arm.comDefaultCommit<Impl>::takeOverFrom() 36214039Sstacze01@arm.com{ 36314039Sstacze01@arm.com switchedOut = false; 36414039Sstacze01@arm.com _status = Active; 36514039Sstacze01@arm.com _nextStatus = Inactive; 36614039Sstacze01@arm.com for (ThreadID tid = 0; tid < numThreads; tid++) { 36714039Sstacze01@arm.com commitStatus[tid] = Idle; 36814039Sstacze01@arm.com changedROBNumEntries[tid] = false; 36914039Sstacze01@arm.com trapSquash[tid] = false; 37014039Sstacze01@arm.com tcSquash[tid] = false; 37114039Sstacze01@arm.com } 37214039Sstacze01@arm.com squashCounter = 0; 37314039Sstacze01@arm.com rob->takeOverFrom(); 37414039Sstacze01@arm.com} 37514039Sstacze01@arm.com 37614039Sstacze01@arm.comtemplate <class Impl> 37714039Sstacze01@arm.comvoid 37814039Sstacze01@arm.comDefaultCommit<Impl>::updateStatus() 37914039Sstacze01@arm.com{ 38014039Sstacze01@arm.com // reset ROB changed variable 38114039Sstacze01@arm.com list<ThreadID>::iterator threads = activeThreads->begin(); 38214039Sstacze01@arm.com list<ThreadID>::iterator end = activeThreads->end(); 38314039Sstacze01@arm.com 38414039Sstacze01@arm.com while (threads != end) { 38514039Sstacze01@arm.com ThreadID tid = *threads++; 38614039Sstacze01@arm.com 38714039Sstacze01@arm.com changedROBNumEntries[tid] = false; 38814039Sstacze01@arm.com 38914039Sstacze01@arm.com // Also check if any of the threads has a trap pending 39014039Sstacze01@arm.com if (commitStatus[tid] == TrapPending || 39114039Sstacze01@arm.com commitStatus[tid] == FetchTrapPending) { 39214039Sstacze01@arm.com _nextStatus = Active; 39314039Sstacze01@arm.com } 39414039Sstacze01@arm.com } 39514039Sstacze01@arm.com 39614039Sstacze01@arm.com if (_nextStatus == Inactive && _status == Active) { 39714039Sstacze01@arm.com DPRINTF(Activity, "Deactivating stage.\n"); 39814039Sstacze01@arm.com cpu->deactivateStage(O3CPU::CommitIdx); 39914039Sstacze01@arm.com } else if (_nextStatus == Active && _status == Inactive) { 40014039Sstacze01@arm.com DPRINTF(Activity, "Activating stage.\n"); 40114039Sstacze01@arm.com cpu->activateStage(O3CPU::CommitIdx); 40214039Sstacze01@arm.com } 40314039Sstacze01@arm.com 40414039Sstacze01@arm.com _status = _nextStatus; 40514039Sstacze01@arm.com} 40614039Sstacze01@arm.com 40714039Sstacze01@arm.comtemplate <class Impl> 40814039Sstacze01@arm.comvoid 40914039Sstacze01@arm.comDefaultCommit<Impl>::setNextStatus() 41014039Sstacze01@arm.com{ 41114039Sstacze01@arm.com int squashes = 0; 41214039Sstacze01@arm.com 41314039Sstacze01@arm.com list<ThreadID>::iterator threads = activeThreads->begin(); 41414039Sstacze01@arm.com list<ThreadID>::iterator end = activeThreads->end(); 41514039Sstacze01@arm.com 41614039Sstacze01@arm.com while (threads != end) { 41714039Sstacze01@arm.com ThreadID tid = *threads++; 41814039Sstacze01@arm.com 41914039Sstacze01@arm.com if (commitStatus[tid] == ROBSquashing) { 42014039Sstacze01@arm.com squashes++; 42114039Sstacze01@arm.com } 42214039Sstacze01@arm.com } 42314039Sstacze01@arm.com 42414039Sstacze01@arm.com squashCounter = squashes; 42514039Sstacze01@arm.com 42614039Sstacze01@arm.com // If commit is currently squashing, then it will have activity for the 42714039Sstacze01@arm.com // next cycle. Set its next status as active. 42814039Sstacze01@arm.com if (squashCounter) { 42914039Sstacze01@arm.com _nextStatus = Active; 43014039Sstacze01@arm.com } 43114039Sstacze01@arm.com} 43214039Sstacze01@arm.com 43314039Sstacze01@arm.comtemplate <class Impl> 43414039Sstacze01@arm.combool 43514039Sstacze01@arm.comDefaultCommit<Impl>::changedROBEntries() 43614039Sstacze01@arm.com{ 43714039Sstacze01@arm.com list<ThreadID>::iterator threads = activeThreads->begin(); 43814039Sstacze01@arm.com list<ThreadID>::iterator end = activeThreads->end(); 43914039Sstacze01@arm.com 44014039Sstacze01@arm.com while (threads != end) { 44114039Sstacze01@arm.com ThreadID tid = *threads++; 44214039Sstacze01@arm.com 44314039Sstacze01@arm.com if (changedROBNumEntries[tid]) { 44414039Sstacze01@arm.com return true; 44514039Sstacze01@arm.com } 44614039Sstacze01@arm.com } 44714039Sstacze01@arm.com 44814039Sstacze01@arm.com return false; 44914039Sstacze01@arm.com} 45014039Sstacze01@arm.com 45114039Sstacze01@arm.comtemplate <class Impl> 45214039Sstacze01@arm.comsize_t 45314039Sstacze01@arm.comDefaultCommit<Impl>::numROBFreeEntries(ThreadID tid) 45414039Sstacze01@arm.com{ 45514039Sstacze01@arm.com return rob->numFreeEntries(tid); 45614039Sstacze01@arm.com} 45714039Sstacze01@arm.com 45814039Sstacze01@arm.comtemplate <class Impl> 45914039Sstacze01@arm.comvoid 46014039Sstacze01@arm.comDefaultCommit<Impl>::generateTrapEvent(ThreadID tid) 46114039Sstacze01@arm.com{ 46214039Sstacze01@arm.com DPRINTF(Commit, "Generating trap event for [tid:%i]\n", tid); 46314039Sstacze01@arm.com 46414039Sstacze01@arm.com TrapEvent *trap = new TrapEvent(this, tid); 46514039Sstacze01@arm.com 46614039Sstacze01@arm.com cpu->schedule(trap, curTick + trapLatency); 46714039Sstacze01@arm.com trapInFlight[tid] = true; 46814039Sstacze01@arm.com} 46914039Sstacze01@arm.com 47014039Sstacze01@arm.comtemplate <class Impl> 47114039Sstacze01@arm.comvoid 47214039Sstacze01@arm.comDefaultCommit<Impl>::generateTCEvent(ThreadID tid) 47314039Sstacze01@arm.com{ 47414039Sstacze01@arm.com assert(!trapInFlight[tid]); 47514039Sstacze01@arm.com DPRINTF(Commit, "Generating TC squash event for [tid:%i]\n", tid); 47614039Sstacze01@arm.com 47714039Sstacze01@arm.com tcSquash[tid] = true; 47814039Sstacze01@arm.com} 47914039Sstacze01@arm.com 48014039Sstacze01@arm.comtemplate <class Impl> 48114039Sstacze01@arm.comvoid 48214039Sstacze01@arm.comDefaultCommit<Impl>::squashAll(ThreadID tid) 48314039Sstacze01@arm.com{ 48414039Sstacze01@arm.com // If we want to include the squashing instruction in the squash, 48514039Sstacze01@arm.com // then use one older sequence number. 48614039Sstacze01@arm.com // Hopefully this doesn't mess things up. Basically I want to squash 48714039Sstacze01@arm.com // all instructions of this thread. 48814039Sstacze01@arm.com InstSeqNum squashed_inst = rob->isEmpty() ? 48914039Sstacze01@arm.com 0 : rob->readHeadInst(tid)->seqNum - 1; 49014039Sstacze01@arm.com 49114039Sstacze01@arm.com // All younger instructions will be squashed. Set the sequence 49214039Sstacze01@arm.com // number as the youngest instruction in the ROB (0 in this case. 49314039Sstacze01@arm.com // Hopefully nothing breaks.) 49414039Sstacze01@arm.com youngestSeqNum[tid] = 0; 49514039Sstacze01@arm.com 49614039Sstacze01@arm.com rob->squash(squashed_inst, tid); 49714039Sstacze01@arm.com changedROBNumEntries[tid] = true; 49814039Sstacze01@arm.com 49914039Sstacze01@arm.com // Send back the sequence number of the squashed instruction. 50014039Sstacze01@arm.com toIEW->commitInfo[tid].doneSeqNum = squashed_inst; 50114039Sstacze01@arm.com 50214039Sstacze01@arm.com // Send back the squash signal to tell stages that they should 50314039Sstacze01@arm.com // squash. 50414039Sstacze01@arm.com toIEW->commitInfo[tid].squash = true; 50514039Sstacze01@arm.com 50614039Sstacze01@arm.com // Send back the rob squashing signal so other stages know that 50714039Sstacze01@arm.com // the ROB is in the process of squashing. 50814039Sstacze01@arm.com toIEW->commitInfo[tid].robSquashing = true; 50914039Sstacze01@arm.com 51014039Sstacze01@arm.com toIEW->commitInfo[tid].branchMispredict = false; 51114039Sstacze01@arm.com 51214039Sstacze01@arm.com toIEW->commitInfo[tid].pc = pc[tid]; 51314039Sstacze01@arm.com} 51414039Sstacze01@arm.com 51514039Sstacze01@arm.comtemplate <class Impl> 51614039Sstacze01@arm.comvoid 51714039Sstacze01@arm.comDefaultCommit<Impl>::squashFromTrap(ThreadID tid) 51814039Sstacze01@arm.com{ 51914039Sstacze01@arm.com squashAll(tid); 52014039Sstacze01@arm.com 52114039Sstacze01@arm.com DPRINTF(Commit, "Squashing from trap, restarting at PC %s\n", pc[tid]); 52214039Sstacze01@arm.com 52314039Sstacze01@arm.com thread[tid]->trapPending = false; 52414039Sstacze01@arm.com thread[tid]->inSyscall = false; 52514039Sstacze01@arm.com trapInFlight[tid] = false; 52614039Sstacze01@arm.com 52714039Sstacze01@arm.com trapSquash[tid] = false; 52814039Sstacze01@arm.com 52914039Sstacze01@arm.com commitStatus[tid] = ROBSquashing; 53014039Sstacze01@arm.com cpu->activityThisCycle(); 53114039Sstacze01@arm.com} 53214039Sstacze01@arm.com 53314039Sstacze01@arm.comtemplate <class Impl> 53414039Sstacze01@arm.comvoid 53514039Sstacze01@arm.comDefaultCommit<Impl>::squashFromTC(ThreadID tid) 53614039Sstacze01@arm.com{ 53714039Sstacze01@arm.com squashAll(tid); 53814039Sstacze01@arm.com 53914039Sstacze01@arm.com DPRINTF(Commit, "Squashing from TC, restarting at PC %s\n", pc[tid]); 54014039Sstacze01@arm.com 54114039Sstacze01@arm.com thread[tid]->inSyscall = false; 54214039Sstacze01@arm.com assert(!thread[tid]->trapPending); 54314039Sstacze01@arm.com 54414039Sstacze01@arm.com commitStatus[tid] = ROBSquashing; 54514039Sstacze01@arm.com cpu->activityThisCycle(); 54614039Sstacze01@arm.com 54714039Sstacze01@arm.com tcSquash[tid] = false; 54814039Sstacze01@arm.com} 54914039Sstacze01@arm.com 55014039Sstacze01@arm.comtemplate <class Impl> 55114039Sstacze01@arm.comvoid 55214039Sstacze01@arm.comDefaultCommit<Impl>::tick() 55314039Sstacze01@arm.com{ 55414039Sstacze01@arm.com wroteToTimeBuffer = false; 55514039Sstacze01@arm.com _nextStatus = Inactive; 55614039Sstacze01@arm.com 55714039Sstacze01@arm.com if (drainPending && rob->isEmpty() && !iewStage->hasStoresToWB()) { 55814039Sstacze01@arm.com cpu->signalDrained(); 55914039Sstacze01@arm.com drainPending = false; 56014039Sstacze01@arm.com return; 56114039Sstacze01@arm.com } 56214039Sstacze01@arm.com 56314039Sstacze01@arm.com if (activeThreads->empty()) 56414039Sstacze01@arm.com return; 56514039Sstacze01@arm.com 56614039Sstacze01@arm.com list<ThreadID>::iterator threads = activeThreads->begin(); 56714039Sstacze01@arm.com list<ThreadID>::iterator end = activeThreads->end(); 56814039Sstacze01@arm.com 56914039Sstacze01@arm.com // Check if any of the threads are done squashing. Change the 57014039Sstacze01@arm.com // status if they are done. 57114039Sstacze01@arm.com while (threads != end) { 57214039Sstacze01@arm.com ThreadID tid = *threads++; 57314039Sstacze01@arm.com 57414039Sstacze01@arm.com // Clear the bit saying if the thread has committed stores 57514039Sstacze01@arm.com // this cycle. 57614039Sstacze01@arm.com committedStores[tid] = false; 57714039Sstacze01@arm.com 57814039Sstacze01@arm.com if (commitStatus[tid] == ROBSquashing) { 57914039Sstacze01@arm.com 58014039Sstacze01@arm.com if (rob->isDoneSquashing(tid)) { 58114039Sstacze01@arm.com commitStatus[tid] = Running; 58214039Sstacze01@arm.com } else { 58314039Sstacze01@arm.com DPRINTF(Commit,"[tid:%u]: Still Squashing, cannot commit any" 58414039Sstacze01@arm.com " insts this cycle.\n", tid); 58514039Sstacze01@arm.com rob->doSquash(tid); 58614039Sstacze01@arm.com toIEW->commitInfo[tid].robSquashing = true; 58714039Sstacze01@arm.com wroteToTimeBuffer = true; 58814039Sstacze01@arm.com } 58914039Sstacze01@arm.com } 59014039Sstacze01@arm.com } 59114039Sstacze01@arm.com 59214039Sstacze01@arm.com commit(); 59314039Sstacze01@arm.com 59414039Sstacze01@arm.com markCompletedInsts(); 59514039Sstacze01@arm.com 59614039Sstacze01@arm.com threads = activeThreads->begin(); 59714039Sstacze01@arm.com 59814039Sstacze01@arm.com while (threads != end) { 59914039Sstacze01@arm.com ThreadID tid = *threads++; 60014039Sstacze01@arm.com 60114039Sstacze01@arm.com if (!rob->isEmpty(tid) && rob->readHeadInst(tid)->readyToCommit()) { 60214039Sstacze01@arm.com // The ROB has more instructions it can commit. Its next status 60314039Sstacze01@arm.com // will be active. 60414039Sstacze01@arm.com _nextStatus = Active; 60514039Sstacze01@arm.com 60614039Sstacze01@arm.com DynInstPtr inst = rob->readHeadInst(tid); 60714039Sstacze01@arm.com 60814039Sstacze01@arm.com DPRINTF(Commit,"[tid:%i]: Instruction [sn:%lli] PC %s is head of" 60914039Sstacze01@arm.com " ROB and ready to commit\n", 61014039Sstacze01@arm.com tid, inst->seqNum, inst->pcState()); 61114039Sstacze01@arm.com 61214039Sstacze01@arm.com } else if (!rob->isEmpty(tid)) { 61314039Sstacze01@arm.com DynInstPtr inst = rob->readHeadInst(tid); 61414039Sstacze01@arm.com 61514039Sstacze01@arm.com DPRINTF(Commit,"[tid:%i]: Can't commit, Instruction [sn:%lli] PC " 61614039Sstacze01@arm.com "%s is head of ROB and not ready\n", 61714039Sstacze01@arm.com tid, inst->seqNum, inst->pcState()); 61814039Sstacze01@arm.com } 61914039Sstacze01@arm.com 62014039Sstacze01@arm.com DPRINTF(Commit, "[tid:%i]: ROB has %d insts & %d free entries.\n", 62114039Sstacze01@arm.com tid, rob->countInsts(tid), rob->numFreeEntries(tid)); 62214039Sstacze01@arm.com } 62314039Sstacze01@arm.com 62414039Sstacze01@arm.com 62514039Sstacze01@arm.com if (wroteToTimeBuffer) { 62614039Sstacze01@arm.com DPRINTF(Activity, "Activity This Cycle.\n"); 62714039Sstacze01@arm.com cpu->activityThisCycle(); 62814039Sstacze01@arm.com } 62914039Sstacze01@arm.com 63014039Sstacze01@arm.com updateStatus(); 63114039Sstacze01@arm.com} 63214039Sstacze01@arm.com 63314039Sstacze01@arm.com#if FULL_SYSTEM 63414039Sstacze01@arm.comtemplate <class Impl> 63514039Sstacze01@arm.comvoid 63614039Sstacze01@arm.comDefaultCommit<Impl>::handleInterrupt() 63714039Sstacze01@arm.com{ 63814039Sstacze01@arm.com if (interrupt != NoFault) { 63914039Sstacze01@arm.com // Wait until the ROB is empty and all stores have drained in 64014039Sstacze01@arm.com // order to enter the interrupt. 64114039Sstacze01@arm.com if (rob->isEmpty() && !iewStage->hasStoresToWB()) { 64214039Sstacze01@arm.com // Squash or record that I need to squash this cycle if 64314039Sstacze01@arm.com // an interrupt needed to be handled. 64414039Sstacze01@arm.com DPRINTF(Commit, "Interrupt detected.\n"); 64514039Sstacze01@arm.com 64614039Sstacze01@arm.com // Clear the interrupt now that it's going to be handled 64714039Sstacze01@arm.com toIEW->commitInfo[0].clearInterrupt = true; 64814039Sstacze01@arm.com 64914039Sstacze01@arm.com assert(!thread[0]->inSyscall); 65014039Sstacze01@arm.com thread[0]->inSyscall = true; 65114039Sstacze01@arm.com 65214039Sstacze01@arm.com // CPU will handle interrupt. 65314039Sstacze01@arm.com cpu->processInterrupts(interrupt); 65414039Sstacze01@arm.com 65514039Sstacze01@arm.com thread[0]->inSyscall = false; 65614039Sstacze01@arm.com 65714039Sstacze01@arm.com commitStatus[0] = TrapPending; 65814039Sstacze01@arm.com 65914039Sstacze01@arm.com // Generate trap squash event. 66014039Sstacze01@arm.com generateTrapEvent(0); 66114039Sstacze01@arm.com 66214039Sstacze01@arm.com interrupt = NoFault; 66314039Sstacze01@arm.com } else { 66414039Sstacze01@arm.com DPRINTF(Commit, "Interrupt pending, waiting for ROB to empty.\n"); 66514039Sstacze01@arm.com } 66614039Sstacze01@arm.com } else if (commitStatus[0] != TrapPending && 66714039Sstacze01@arm.com cpu->checkInterrupts(cpu->tcBase(0)) && 66814039Sstacze01@arm.com !trapSquash[0] && 66914039Sstacze01@arm.com !tcSquash[0]) { 67014039Sstacze01@arm.com // Process interrupts if interrupts are enabled, not in PAL 67114039Sstacze01@arm.com // mode, and no other traps or external squashes are currently 67214039Sstacze01@arm.com // pending. 67314039Sstacze01@arm.com // @todo: Allow other threads to handle interrupts. 67414039Sstacze01@arm.com 67514039Sstacze01@arm.com // Get any interrupt that happened 67614039Sstacze01@arm.com interrupt = cpu->getInterrupts(); 67714039Sstacze01@arm.com 67814039Sstacze01@arm.com if (interrupt != NoFault) { 67914039Sstacze01@arm.com // Tell fetch that there is an interrupt pending. This 68014039Sstacze01@arm.com // will make fetch wait until it sees a non PAL-mode PC, 68114039Sstacze01@arm.com // at which point it stops fetching instructions. 68214039Sstacze01@arm.com toIEW->commitInfo[0].interruptPending = true; 68314039Sstacze01@arm.com } 68414039Sstacze01@arm.com } 68514039Sstacze01@arm.com} 68614039Sstacze01@arm.com#endif // FULL_SYSTEM 68714039Sstacze01@arm.com 68814039Sstacze01@arm.comtemplate <class Impl> 68914039Sstacze01@arm.comvoid 69014039Sstacze01@arm.comDefaultCommit<Impl>::commit() 69114039Sstacze01@arm.com{ 69214039Sstacze01@arm.com 69314039Sstacze01@arm.com#if FULL_SYSTEM 69414039Sstacze01@arm.com // Check for any interrupt, and start processing it. Or if we 69514039Sstacze01@arm.com // have an outstanding interrupt and are at a point when it is 69614039Sstacze01@arm.com // valid to take an interrupt, process it. 69714039Sstacze01@arm.com if (cpu->checkInterrupts(cpu->tcBase(0))) { 69814039Sstacze01@arm.com handleInterrupt(); 69914039Sstacze01@arm.com } 70014039Sstacze01@arm.com#endif // FULL_SYSTEM 70114039Sstacze01@arm.com 70214039Sstacze01@arm.com //////////////////////////////////// 70314039Sstacze01@arm.com // Check for any possible squashes, handle them first 70414039Sstacze01@arm.com //////////////////////////////////// 70514039Sstacze01@arm.com list<ThreadID>::iterator threads = activeThreads->begin(); 70614039Sstacze01@arm.com list<ThreadID>::iterator end = activeThreads->end(); 70714039Sstacze01@arm.com 70814039Sstacze01@arm.com while (threads != end) { 70914039Sstacze01@arm.com ThreadID tid = *threads++; 71014039Sstacze01@arm.com 71114039Sstacze01@arm.com // Not sure which one takes priority. I think if we have 71214039Sstacze01@arm.com // both, that's a bad sign. 71314039Sstacze01@arm.com if (trapSquash[tid] == true) { 71414039Sstacze01@arm.com assert(!tcSquash[tid]); 71514039Sstacze01@arm.com squashFromTrap(tid); 71614039Sstacze01@arm.com } else if (tcSquash[tid] == true) { 71714039Sstacze01@arm.com assert(commitStatus[tid] != TrapPending); 71814039Sstacze01@arm.com squashFromTC(tid); 71914039Sstacze01@arm.com } 72014039Sstacze01@arm.com 72114039Sstacze01@arm.com // Squashed sequence number must be older than youngest valid 72214039Sstacze01@arm.com // instruction in the ROB. This prevents squashes from younger 72314039Sstacze01@arm.com // instructions overriding squashes from older instructions. 72414039Sstacze01@arm.com if (fromIEW->squash[tid] && 72514039Sstacze01@arm.com commitStatus[tid] != TrapPending && 72614039Sstacze01@arm.com fromIEW->squashedSeqNum[tid] <= youngestSeqNum[tid]) { 72714039Sstacze01@arm.com 72814039Sstacze01@arm.com DPRINTF(Commit, "[tid:%i]: Squashing due to PC %#x [sn:%i]\n", 72914039Sstacze01@arm.com tid, 73014039Sstacze01@arm.com fromIEW->mispredPC[tid], 73114039Sstacze01@arm.com fromIEW->squashedSeqNum[tid]); 73214039Sstacze01@arm.com 73314039Sstacze01@arm.com DPRINTF(Commit, "[tid:%i]: Redirecting to PC %#x\n", 73414039Sstacze01@arm.com tid, 73514039Sstacze01@arm.com fromIEW->pc[tid].nextInstAddr()); 73614039Sstacze01@arm.com 73714039Sstacze01@arm.com commitStatus[tid] = ROBSquashing; 73814039Sstacze01@arm.com 73914039Sstacze01@arm.com // If we want to include the squashing instruction in the squash, 74014039Sstacze01@arm.com // then use one older sequence number. 74114039Sstacze01@arm.com InstSeqNum squashed_inst = fromIEW->squashedSeqNum[tid]; 74214039Sstacze01@arm.com 74314039Sstacze01@arm.com if (fromIEW->includeSquashInst[tid] == true) { 74414039Sstacze01@arm.com squashed_inst--; 74514039Sstacze01@arm.com } 74614039Sstacze01@arm.com 74714039Sstacze01@arm.com // All younger instructions will be squashed. Set the sequence 74814039Sstacze01@arm.com // number as the youngest instruction in the ROB. 74914039Sstacze01@arm.com youngestSeqNum[tid] = squashed_inst; 75014039Sstacze01@arm.com 75114039Sstacze01@arm.com rob->squash(squashed_inst, tid); 75214039Sstacze01@arm.com changedROBNumEntries[tid] = true; 75314039Sstacze01@arm.com 75414039Sstacze01@arm.com toIEW->commitInfo[tid].doneSeqNum = squashed_inst; 75514039Sstacze01@arm.com 75614039Sstacze01@arm.com toIEW->commitInfo[tid].squash = true; 75714039Sstacze01@arm.com 75814039Sstacze01@arm.com // Send back the rob squashing signal so other stages know that 75914039Sstacze01@arm.com // the ROB is in the process of squashing. 76014039Sstacze01@arm.com toIEW->commitInfo[tid].robSquashing = true; 76114039Sstacze01@arm.com 76214039Sstacze01@arm.com toIEW->commitInfo[tid].branchMispredict = 76314039Sstacze01@arm.com fromIEW->branchMispredict[tid]; 76414039Sstacze01@arm.com 76514039Sstacze01@arm.com toIEW->commitInfo[tid].branchTaken = 76614039Sstacze01@arm.com fromIEW->branchTaken[tid]; 76714039Sstacze01@arm.com 76814039Sstacze01@arm.com toIEW->commitInfo[tid].pc = fromIEW->pc[tid]; 76914039Sstacze01@arm.com 77014039Sstacze01@arm.com toIEW->commitInfo[tid].mispredPC = fromIEW->mispredPC[tid]; 77114039Sstacze01@arm.com 77214039Sstacze01@arm.com if (toIEW->commitInfo[tid].branchMispredict) { 77314039Sstacze01@arm.com ++branchMispredicts; 77414039Sstacze01@arm.com } 77514039Sstacze01@arm.com } 77614039Sstacze01@arm.com 77714039Sstacze01@arm.com } 77814039Sstacze01@arm.com 77914039Sstacze01@arm.com setNextStatus(); 78014039Sstacze01@arm.com 78114039Sstacze01@arm.com if (squashCounter != numThreads) { 78214039Sstacze01@arm.com // If we're not currently squashing, then get instructions. 78314039Sstacze01@arm.com getInsts(); 78414039Sstacze01@arm.com 78514039Sstacze01@arm.com // Try to commit any instructions. 78614039Sstacze01@arm.com commitInsts(); 78714039Sstacze01@arm.com } 78814039Sstacze01@arm.com 78914039Sstacze01@arm.com //Check for any activity 79014039Sstacze01@arm.com threads = activeThreads->begin(); 79114039Sstacze01@arm.com 79214039Sstacze01@arm.com while (threads != end) { 79314039Sstacze01@arm.com ThreadID tid = *threads++; 79414039Sstacze01@arm.com 79514039Sstacze01@arm.com if (changedROBNumEntries[tid]) { 79614039Sstacze01@arm.com toIEW->commitInfo[tid].usedROB = true; 79714039Sstacze01@arm.com toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid); 79814039Sstacze01@arm.com 79914039Sstacze01@arm.com wroteToTimeBuffer = true; 80014039Sstacze01@arm.com changedROBNumEntries[tid] = false; 80114039Sstacze01@arm.com if (rob->isEmpty(tid)) 80214039Sstacze01@arm.com checkEmptyROB[tid] = true; 80314039Sstacze01@arm.com } 80414039Sstacze01@arm.com 80514039Sstacze01@arm.com // ROB is only considered "empty" for previous stages if: a) 80614039Sstacze01@arm.com // ROB is empty, b) there are no outstanding stores, c) IEW 80714039Sstacze01@arm.com // stage has received any information regarding stores that 80814039Sstacze01@arm.com // committed. 80914039Sstacze01@arm.com // c) is checked by making sure to not consider the ROB empty 81014039Sstacze01@arm.com // on the same cycle as when stores have been committed. 81114039Sstacze01@arm.com // @todo: Make this handle multi-cycle communication between 81214039Sstacze01@arm.com // commit and IEW. 81314039Sstacze01@arm.com if (checkEmptyROB[tid] && rob->isEmpty(tid) && 81414039Sstacze01@arm.com !iewStage->hasStoresToWB(tid) && !committedStores[tid]) { 81514039Sstacze01@arm.com checkEmptyROB[tid] = false; 81614039Sstacze01@arm.com toIEW->commitInfo[tid].usedROB = true; 81714039Sstacze01@arm.com toIEW->commitInfo[tid].emptyROB = true; 81814039Sstacze01@arm.com toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid); 81914039Sstacze01@arm.com wroteToTimeBuffer = true; 82014039Sstacze01@arm.com } 82114039Sstacze01@arm.com 82214039Sstacze01@arm.com } 82314039Sstacze01@arm.com} 82414039Sstacze01@arm.com 82514039Sstacze01@arm.comtemplate <class Impl> 82614039Sstacze01@arm.comvoid 82714039Sstacze01@arm.comDefaultCommit<Impl>::commitInsts() 82814039Sstacze01@arm.com{ 82914039Sstacze01@arm.com //////////////////////////////////// 83014039Sstacze01@arm.com // Handle commit 83114039Sstacze01@arm.com // Note that commit will be handled prior to putting new 83214039Sstacze01@arm.com // instructions in the ROB so that the ROB only tries to commit 83314039Sstacze01@arm.com // instructions it has in this current cycle, and not instructions 83414039Sstacze01@arm.com // it is writing in during this cycle. Can't commit and squash 83514039Sstacze01@arm.com // things at the same time... 83614039Sstacze01@arm.com //////////////////////////////////// 83714039Sstacze01@arm.com 83814039Sstacze01@arm.com DPRINTF(Commit, "Trying to commit instructions in the ROB.\n"); 83914039Sstacze01@arm.com 84014039Sstacze01@arm.com unsigned num_committed = 0; 84114039Sstacze01@arm.com 84214039Sstacze01@arm.com DynInstPtr head_inst; 84314039Sstacze01@arm.com 84414039Sstacze01@arm.com // Commit as many instructions as possible until the commit bandwidth 84514039Sstacze01@arm.com // limit is reached, or it becomes impossible to commit any more. 84614039Sstacze01@arm.com while (num_committed < commitWidth) { 84714039Sstacze01@arm.com int commit_thread = getCommittingThread(); 84814039Sstacze01@arm.com 84914039Sstacze01@arm.com if (commit_thread == -1 || !rob->isHeadReady(commit_thread)) 85014039Sstacze01@arm.com break; 85114039Sstacze01@arm.com 85214039Sstacze01@arm.com head_inst = rob->readHeadInst(commit_thread); 85314039Sstacze01@arm.com 85414039Sstacze01@arm.com ThreadID tid = head_inst->threadNumber; 85514039Sstacze01@arm.com 85614039Sstacze01@arm.com assert(tid == commit_thread); 85714039Sstacze01@arm.com 85814039Sstacze01@arm.com DPRINTF(Commit, "Trying to commit head instruction, [sn:%i] [tid:%i]\n", 85914039Sstacze01@arm.com head_inst->seqNum, tid); 86014039Sstacze01@arm.com 86114039Sstacze01@arm.com // If the head instruction is squashed, it is ready to retire 86214039Sstacze01@arm.com // (be removed from the ROB) at any time. 86314039Sstacze01@arm.com if (head_inst->isSquashed()) { 86414039Sstacze01@arm.com 86514039Sstacze01@arm.com DPRINTF(Commit, "Retiring squashed instruction from " 86614039Sstacze01@arm.com "ROB.\n"); 86714039Sstacze01@arm.com 86814039Sstacze01@arm.com rob->retireHead(commit_thread); 86914039Sstacze01@arm.com 87014039Sstacze01@arm.com ++commitSquashedInsts; 87114039Sstacze01@arm.com 87214039Sstacze01@arm.com // Record that the number of ROB entries has changed. 87314039Sstacze01@arm.com changedROBNumEntries[tid] = true; 87414039Sstacze01@arm.com } else { 87514039Sstacze01@arm.com pc[tid] = head_inst->pcState(); 87614039Sstacze01@arm.com 87714039Sstacze01@arm.com // Increment the total number of non-speculative instructions 87814039Sstacze01@arm.com // executed. 87914039Sstacze01@arm.com // Hack for now: it really shouldn't happen until after the 88014039Sstacze01@arm.com // commit is deemed to be successful, but this count is needed 88114039Sstacze01@arm.com // for syscalls. 88214039Sstacze01@arm.com thread[tid]->funcExeInst++; 88314039Sstacze01@arm.com 88414039Sstacze01@arm.com // Try to commit the head instruction. 88514039Sstacze01@arm.com bool commit_success = commitHead(head_inst, num_committed); 88614039Sstacze01@arm.com 88714039Sstacze01@arm.com if (commit_success) { 88814039Sstacze01@arm.com ++num_committed; 88914039Sstacze01@arm.com 89014039Sstacze01@arm.com changedROBNumEntries[tid] = true; 89114039Sstacze01@arm.com 89214039Sstacze01@arm.com // Set the doneSeqNum to the youngest committed instruction. 89314039Sstacze01@arm.com toIEW->commitInfo[tid].doneSeqNum = head_inst->seqNum; 89414039Sstacze01@arm.com 89514039Sstacze01@arm.com ++commitCommittedInsts; 89614039Sstacze01@arm.com 89714039Sstacze01@arm.com // To match the old model, don't count nops and instruction 89814039Sstacze01@arm.com // prefetches towards the total commit count. 89914039Sstacze01@arm.com if (!head_inst->isNop() && !head_inst->isInstPrefetch()) { 90014039Sstacze01@arm.com cpu->instDone(tid); 90114039Sstacze01@arm.com } 90214039Sstacze01@arm.com 90314039Sstacze01@arm.com TheISA::advancePC(pc[tid], head_inst->staticInst); 90414039Sstacze01@arm.com 90514039Sstacze01@arm.com int count = 0; 90614039Sstacze01@arm.com Addr oldpc; 90714039Sstacze01@arm.com // Debug statement. Checks to make sure we're not 90814039Sstacze01@arm.com // currently updating state while handling PC events. 90914039Sstacze01@arm.com assert(!thread[tid]->inSyscall && !thread[tid]->trapPending); 91014039Sstacze01@arm.com do { 91114039Sstacze01@arm.com oldpc = pc[tid].instAddr(); 91214039Sstacze01@arm.com cpu->system->pcEventQueue.service(thread[tid]->getTC()); 91314039Sstacze01@arm.com count++; 91414039Sstacze01@arm.com } while (oldpc != pc[tid].instAddr()); 91514039Sstacze01@arm.com if (count > 1) { 91614039Sstacze01@arm.com DPRINTF(Commit, 91714039Sstacze01@arm.com "PC skip function event, stopping commit\n"); 91814039Sstacze01@arm.com break; 91914039Sstacze01@arm.com } 92014039Sstacze01@arm.com } else { 92114039Sstacze01@arm.com DPRINTF(Commit, "Unable to commit head instruction PC:%s " 92214039Sstacze01@arm.com "[tid:%i] [sn:%i].\n", 92314039Sstacze01@arm.com head_inst->pcState(), tid ,head_inst->seqNum); 92414039Sstacze01@arm.com break; 92514039Sstacze01@arm.com } 92614039Sstacze01@arm.com } 92714039Sstacze01@arm.com } 92814039Sstacze01@arm.com 92914039Sstacze01@arm.com DPRINTF(CommitRate, "%i\n", num_committed); 93014039Sstacze01@arm.com numCommittedDist.sample(num_committed); 93114039Sstacze01@arm.com 93214039Sstacze01@arm.com if (num_committed == commitWidth) { 93314039Sstacze01@arm.com commitEligibleSamples++; 93414039Sstacze01@arm.com } 93514039Sstacze01@arm.com} 93614039Sstacze01@arm.com 93714039Sstacze01@arm.comtemplate <class Impl> 93814039Sstacze01@arm.combool 93914039Sstacze01@arm.comDefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num) 94014039Sstacze01@arm.com{ 94114039Sstacze01@arm.com assert(head_inst); 94214039Sstacze01@arm.com 94314039Sstacze01@arm.com ThreadID tid = head_inst->threadNumber; 94414039Sstacze01@arm.com 94514039Sstacze01@arm.com // If the instruction is not executed yet, then it will need extra 94614039Sstacze01@arm.com // handling. Signal backwards that it should be executed. 94714039Sstacze01@arm.com if (!head_inst->isExecuted()) { 94814039Sstacze01@arm.com // Keep this number correct. We have not yet actually executed 94914039Sstacze01@arm.com // and committed this instruction. 95014039Sstacze01@arm.com thread[tid]->funcExeInst--; 95114039Sstacze01@arm.com 95214039Sstacze01@arm.com if (head_inst->isNonSpeculative() || 95314039Sstacze01@arm.com head_inst->isStoreConditional() || 95414039Sstacze01@arm.com head_inst->isMemBarrier() || 95514039Sstacze01@arm.com head_inst->isWriteBarrier()) { 95614039Sstacze01@arm.com 95714039Sstacze01@arm.com DPRINTF(Commit, "Encountered a barrier or non-speculative " 95814039Sstacze01@arm.com "instruction [sn:%lli] at the head of the ROB, PC %s.\n", 95914039Sstacze01@arm.com head_inst->seqNum, head_inst->pcState()); 96014039Sstacze01@arm.com 96114039Sstacze01@arm.com if (inst_num > 0 || iewStage->hasStoresToWB(tid)) { 96214039Sstacze01@arm.com DPRINTF(Commit, "Waiting for all stores to writeback.\n"); 96314039Sstacze01@arm.com return false; 96414039Sstacze01@arm.com } 96514039Sstacze01@arm.com 96614039Sstacze01@arm.com toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum; 96714039Sstacze01@arm.com 96814039Sstacze01@arm.com // Change the instruction so it won't try to commit again until 96914039Sstacze01@arm.com // it is executed. 97014039Sstacze01@arm.com head_inst->clearCanCommit(); 97114039Sstacze01@arm.com 97214039Sstacze01@arm.com ++commitNonSpecStalls; 97314039Sstacze01@arm.com 97414039Sstacze01@arm.com return false; 97514039Sstacze01@arm.com } else if (head_inst->isLoad()) { 97614039Sstacze01@arm.com if (inst_num > 0 || iewStage->hasStoresToWB(tid)) { 97714039Sstacze01@arm.com DPRINTF(Commit, "Waiting for all stores to writeback.\n"); 97814039Sstacze01@arm.com return false; 97914039Sstacze01@arm.com } 98014039Sstacze01@arm.com 98114039Sstacze01@arm.com assert(head_inst->uncacheable()); 98214039Sstacze01@arm.com DPRINTF(Commit, "[sn:%lli]: Uncached load, PC %s.\n", 98314039Sstacze01@arm.com head_inst->seqNum, head_inst->pcState()); 98414039Sstacze01@arm.com 98514039Sstacze01@arm.com // Send back the non-speculative instruction's sequence 98614039Sstacze01@arm.com // number. Tell the lsq to re-execute the load. 98714039Sstacze01@arm.com toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum; 98814039Sstacze01@arm.com toIEW->commitInfo[tid].uncached = true; 98914039Sstacze01@arm.com toIEW->commitInfo[tid].uncachedLoad = head_inst; 99014039Sstacze01@arm.com 99114039Sstacze01@arm.com head_inst->clearCanCommit(); 99214039Sstacze01@arm.com 99314039Sstacze01@arm.com return false; 99414039Sstacze01@arm.com } else { 99514039Sstacze01@arm.com panic("Trying to commit un-executed instruction " 99614039Sstacze01@arm.com "of unknown type!\n"); 99714039Sstacze01@arm.com } 99814039Sstacze01@arm.com } 99914039Sstacze01@arm.com 100014039Sstacze01@arm.com if (head_inst->isThreadSync()) { 100114039Sstacze01@arm.com // Not handled for now. 100214039Sstacze01@arm.com panic("Thread sync instructions are not handled yet.\n"); 100314039Sstacze01@arm.com } 100414039Sstacze01@arm.com 100514039Sstacze01@arm.com // Check if the instruction caused a fault. If so, trap. 100614039Sstacze01@arm.com Fault inst_fault = head_inst->getFault(); 100714039Sstacze01@arm.com 100814039Sstacze01@arm.com // Stores mark themselves as completed. 100914039Sstacze01@arm.com if (!head_inst->isStore() && inst_fault == NoFault) { 101014039Sstacze01@arm.com head_inst->setCompleted(); 101114039Sstacze01@arm.com } 101214039Sstacze01@arm.com 101314039Sstacze01@arm.com#if USE_CHECKER 101414039Sstacze01@arm.com // Use checker prior to updating anything due to traps or PC 101514039Sstacze01@arm.com // based events. 101614039Sstacze01@arm.com if (cpu->checker) { 101714039Sstacze01@arm.com cpu->checker->verify(head_inst); 101814039Sstacze01@arm.com } 101914039Sstacze01@arm.com#endif 102014039Sstacze01@arm.com 102114039Sstacze01@arm.com if (inst_fault != NoFault) { 102214039Sstacze01@arm.com DPRINTF(Commit, "Inst [sn:%lli] PC %s has a fault\n", 102314039Sstacze01@arm.com head_inst->seqNum, head_inst->pcState()); 102414039Sstacze01@arm.com 102514039Sstacze01@arm.com if (iewStage->hasStoresToWB(tid) || inst_num > 0) { 102614039Sstacze01@arm.com DPRINTF(Commit, "Stores outstanding, fault must wait.\n"); 102714039Sstacze01@arm.com return false; 102814039Sstacze01@arm.com } 102914039Sstacze01@arm.com 103014039Sstacze01@arm.com head_inst->setCompleted(); 103114039Sstacze01@arm.com 103214039Sstacze01@arm.com#if USE_CHECKER 103314039Sstacze01@arm.com if (cpu->checker && head_inst->isStore()) { 103414039Sstacze01@arm.com cpu->checker->verify(head_inst); 103514039Sstacze01@arm.com } 103614039Sstacze01@arm.com#endif 103714039Sstacze01@arm.com 103814039Sstacze01@arm.com assert(!thread[tid]->inSyscall); 103914039Sstacze01@arm.com 104014039Sstacze01@arm.com // Mark that we're in state update mode so that the trap's 104114039Sstacze01@arm.com // execution doesn't generate extra squashes. 104214039Sstacze01@arm.com thread[tid]->inSyscall = true; 104314039Sstacze01@arm.com 104414039Sstacze01@arm.com // Execute the trap. Although it's slightly unrealistic in 104514039Sstacze01@arm.com // terms of timing (as it doesn't wait for the full timing of 104614039Sstacze01@arm.com // the trap event to complete before updating state), it's 104714039Sstacze01@arm.com // needed to update the state as soon as possible. This 104814039Sstacze01@arm.com // prevents external agents from changing any specific state 104914039Sstacze01@arm.com // that the trap need. 105014039Sstacze01@arm.com cpu->trap(inst_fault, tid, head_inst->staticInst); 105114039Sstacze01@arm.com 105214039Sstacze01@arm.com // Exit state update mode to avoid accidental updating. 105314039Sstacze01@arm.com thread[tid]->inSyscall = false; 105414039Sstacze01@arm.com 105514039Sstacze01@arm.com commitStatus[tid] = TrapPending; 105614039Sstacze01@arm.com 105714039Sstacze01@arm.com if (head_inst->traceData) { 105814039Sstacze01@arm.com if (DTRACE(ExecFaulting)) { 105914039Sstacze01@arm.com head_inst->traceData->setFetchSeq(head_inst->seqNum); 106014039Sstacze01@arm.com head_inst->traceData->setCPSeq(thread[tid]->numInst); 106114039Sstacze01@arm.com head_inst->traceData->dump(); 106214039Sstacze01@arm.com } 106314039Sstacze01@arm.com delete head_inst->traceData; 106414039Sstacze01@arm.com head_inst->traceData = NULL; 106514039Sstacze01@arm.com } 106614039Sstacze01@arm.com 106714039Sstacze01@arm.com // Generate trap squash event. 106814039Sstacze01@arm.com generateTrapEvent(tid); 106914039Sstacze01@arm.com return false; 107014039Sstacze01@arm.com } 107114039Sstacze01@arm.com 107214039Sstacze01@arm.com updateComInstStats(head_inst); 107314039Sstacze01@arm.com 107414039Sstacze01@arm.com#if FULL_SYSTEM 107514039Sstacze01@arm.com if (thread[tid]->profile) { 107614039Sstacze01@arm.com thread[tid]->profilePC = head_inst->instAddr(); 107714039Sstacze01@arm.com ProfileNode *node = thread[tid]->profile->consume(thread[tid]->getTC(), 107814039Sstacze01@arm.com head_inst->staticInst); 107914039Sstacze01@arm.com 108014039Sstacze01@arm.com if (node) 108114039Sstacze01@arm.com thread[tid]->profileNode = node; 108214039Sstacze01@arm.com } 108314039Sstacze01@arm.com if (CPA::available()) { 108414039Sstacze01@arm.com if (head_inst->isControl()) { 108514039Sstacze01@arm.com ThreadContext *tc = thread[tid]->getTC(); 108614039Sstacze01@arm.com CPA::cpa()->swAutoBegin(tc, head_inst->nextInstAddr()); 108714039Sstacze01@arm.com } 108814039Sstacze01@arm.com } 108914039Sstacze01@arm.com#endif 109014039Sstacze01@arm.com 109114039Sstacze01@arm.com if (head_inst->traceData) { 109214039Sstacze01@arm.com head_inst->traceData->setFetchSeq(head_inst->seqNum); 109314039Sstacze01@arm.com head_inst->traceData->setCPSeq(thread[tid]->numInst); 109414039Sstacze01@arm.com head_inst->traceData->dump(); 109514039Sstacze01@arm.com delete head_inst->traceData; 109614039Sstacze01@arm.com head_inst->traceData = NULL; 109714039Sstacze01@arm.com } 109814039Sstacze01@arm.com 109914039Sstacze01@arm.com // Update the commit rename map 110014039Sstacze01@arm.com for (int i = 0; i < head_inst->numDestRegs(); i++) { 110114039Sstacze01@arm.com renameMap[tid]->setEntry(head_inst->flattenedDestRegIdx(i), 110214039Sstacze01@arm.com head_inst->renamedDestRegIdx(i)); 110314039Sstacze01@arm.com } 110414039Sstacze01@arm.com 110514039Sstacze01@arm.com if (head_inst->isCopy()) 110614039Sstacze01@arm.com panic("Should not commit any copy instructions!"); 110714039Sstacze01@arm.com 110814039Sstacze01@arm.com // Finally clear the head ROB entry. 110914039Sstacze01@arm.com rob->retireHead(tid); 111014039Sstacze01@arm.com 111114039Sstacze01@arm.com // If this was a store, record it for this cycle. 111214039Sstacze01@arm.com if (head_inst->isStore()) 111314039Sstacze01@arm.com committedStores[tid] = true; 111414039Sstacze01@arm.com 111514039Sstacze01@arm.com // Return true to indicate that we have committed an instruction. 111614039Sstacze01@arm.com return true; 111714039Sstacze01@arm.com} 111814039Sstacze01@arm.com 111914039Sstacze01@arm.comtemplate <class Impl> 112014039Sstacze01@arm.comvoid 112114039Sstacze01@arm.comDefaultCommit<Impl>::getInsts() 112214039Sstacze01@arm.com{ 112314039Sstacze01@arm.com DPRINTF(Commit, "Getting instructions from Rename stage.\n"); 112414039Sstacze01@arm.com 112514039Sstacze01@arm.com // Read any renamed instructions and place them into the ROB. 112614039Sstacze01@arm.com int insts_to_process = std::min((int)renameWidth, fromRename->size); 112714039Sstacze01@arm.com 112814039Sstacze01@arm.com for (int inst_num = 0; inst_num < insts_to_process; ++inst_num) { 112914039Sstacze01@arm.com DynInstPtr inst; 113014039Sstacze01@arm.com 113114039Sstacze01@arm.com inst = fromRename->insts[inst_num]; 113214039Sstacze01@arm.com ThreadID tid = inst->threadNumber; 113314039Sstacze01@arm.com 113414039Sstacze01@arm.com if (!inst->isSquashed() && 113514039Sstacze01@arm.com commitStatus[tid] != ROBSquashing && 113614039Sstacze01@arm.com commitStatus[tid] != TrapPending) { 113714039Sstacze01@arm.com changedROBNumEntries[tid] = true; 113814039Sstacze01@arm.com 113914039Sstacze01@arm.com DPRINTF(Commit, "Inserting PC %s [sn:%i] [tid:%i] into ROB.\n", 114014039Sstacze01@arm.com inst->pcState(), inst->seqNum, tid); 114114039Sstacze01@arm.com 114214039Sstacze01@arm.com rob->insertInst(inst); 114314039Sstacze01@arm.com 114414039Sstacze01@arm.com assert(rob->getThreadEntries(tid) <= rob->getMaxEntries(tid)); 114514039Sstacze01@arm.com 114614039Sstacze01@arm.com youngestSeqNum[tid] = inst->seqNum; 114714039Sstacze01@arm.com } else { 114814039Sstacze01@arm.com DPRINTF(Commit, "Instruction PC %s [sn:%i] [tid:%i] was " 114914039Sstacze01@arm.com "squashed, skipping.\n", 115014039Sstacze01@arm.com inst->pcState(), inst->seqNum, tid); 115114039Sstacze01@arm.com } 115214039Sstacze01@arm.com } 115314039Sstacze01@arm.com} 115414039Sstacze01@arm.com 115514039Sstacze01@arm.comtemplate <class Impl> 115614039Sstacze01@arm.comvoid 115714039Sstacze01@arm.comDefaultCommit<Impl>::skidInsert() 115814039Sstacze01@arm.com{ 115914039Sstacze01@arm.com DPRINTF(Commit, "Attempting to any instructions from rename into " 116014039Sstacze01@arm.com "skidBuffer.\n"); 116114039Sstacze01@arm.com 116214039Sstacze01@arm.com for (int inst_num = 0; inst_num < fromRename->size; ++inst_num) { 116314039Sstacze01@arm.com DynInstPtr inst = fromRename->insts[inst_num]; 116414039Sstacze01@arm.com 116514039Sstacze01@arm.com if (!inst->isSquashed()) { 116614039Sstacze01@arm.com DPRINTF(Commit, "Inserting PC %s [sn:%i] [tid:%i] into ", 116714039Sstacze01@arm.com "skidBuffer.\n", inst->pcState(), inst->seqNum, 116814039Sstacze01@arm.com inst->threadNumber); 116914039Sstacze01@arm.com skidBuffer.push(inst); 117014039Sstacze01@arm.com } else { 117114039Sstacze01@arm.com DPRINTF(Commit, "Instruction PC %s [sn:%i] [tid:%i] was " 117214039Sstacze01@arm.com "squashed, skipping.\n", 117314039Sstacze01@arm.com inst->pcState(), inst->seqNum, inst->threadNumber); 117414039Sstacze01@arm.com } 117514039Sstacze01@arm.com } 117614039Sstacze01@arm.com} 117714039Sstacze01@arm.com 117814039Sstacze01@arm.comtemplate <class Impl> 117914039Sstacze01@arm.comvoid 118014039Sstacze01@arm.comDefaultCommit<Impl>::markCompletedInsts() 118114039Sstacze01@arm.com{ 118214039Sstacze01@arm.com // Grab completed insts out of the IEW instruction queue, and mark 118314039Sstacze01@arm.com // instructions completed within the ROB. 118414039Sstacze01@arm.com for (int inst_num = 0; 118514039Sstacze01@arm.com inst_num < fromIEW->size && fromIEW->insts[inst_num]; 118614039Sstacze01@arm.com ++inst_num) 118714039Sstacze01@arm.com { 118814039Sstacze01@arm.com if (!fromIEW->insts[inst_num]->isSquashed()) { 118914039Sstacze01@arm.com DPRINTF(Commit, "[tid:%i]: Marking PC %s, [sn:%lli] ready " 119014039Sstacze01@arm.com "within ROB.\n", 119114039Sstacze01@arm.com fromIEW->insts[inst_num]->threadNumber, 119214039Sstacze01@arm.com fromIEW->insts[inst_num]->pcState(), 119314039Sstacze01@arm.com fromIEW->insts[inst_num]->seqNum); 119414039Sstacze01@arm.com 119514039Sstacze01@arm.com // Mark the instruction as ready to commit. 119614039Sstacze01@arm.com fromIEW->insts[inst_num]->setCanCommit(); 119714039Sstacze01@arm.com } 119814039Sstacze01@arm.com } 119914039Sstacze01@arm.com} 120014039Sstacze01@arm.com 120114039Sstacze01@arm.comtemplate <class Impl> 120214039Sstacze01@arm.combool 120314039Sstacze01@arm.comDefaultCommit<Impl>::robDoneSquashing() 120414039Sstacze01@arm.com{ 120514039Sstacze01@arm.com list<ThreadID>::iterator threads = activeThreads->begin(); 120614039Sstacze01@arm.com list<ThreadID>::iterator end = activeThreads->end(); 120714039Sstacze01@arm.com 120814039Sstacze01@arm.com while (threads != end) { 120914039Sstacze01@arm.com ThreadID tid = *threads++; 121014039Sstacze01@arm.com 121114039Sstacze01@arm.com if (!rob->isDoneSquashing(tid)) 121214039Sstacze01@arm.com return false; 121314039Sstacze01@arm.com } 121414039Sstacze01@arm.com 121514039Sstacze01@arm.com return true; 121614039Sstacze01@arm.com} 121714039Sstacze01@arm.com 121814039Sstacze01@arm.comtemplate <class Impl> 121914039Sstacze01@arm.comvoid 122014039Sstacze01@arm.comDefaultCommit<Impl>::updateComInstStats(DynInstPtr &inst) 122114039Sstacze01@arm.com{ 122214039Sstacze01@arm.com ThreadID tid = inst->threadNumber; 122314039Sstacze01@arm.com 122414039Sstacze01@arm.com // 122514039Sstacze01@arm.com // Pick off the software prefetches 122614039Sstacze01@arm.com // 122714039Sstacze01@arm.com#ifdef TARGET_ALPHA 122814039Sstacze01@arm.com if (inst->isDataPrefetch()) { 122914039Sstacze01@arm.com statComSwp[tid]++; 123014039Sstacze01@arm.com } else { 123114039Sstacze01@arm.com statComInst[tid]++; 123214039Sstacze01@arm.com } 123314039Sstacze01@arm.com#else 123414039Sstacze01@arm.com statComInst[tid]++; 123514039Sstacze01@arm.com#endif 123614039Sstacze01@arm.com 123714039Sstacze01@arm.com // 123814039Sstacze01@arm.com // Control Instructions 123914039Sstacze01@arm.com // 124014039Sstacze01@arm.com if (inst->isControl()) 124114039Sstacze01@arm.com statComBranches[tid]++; 124214039Sstacze01@arm.com 124314039Sstacze01@arm.com // 124414039Sstacze01@arm.com // Memory references 124514039Sstacze01@arm.com // 124614039Sstacze01@arm.com if (inst->isMemRef()) { 124714039Sstacze01@arm.com statComRefs[tid]++; 124814039Sstacze01@arm.com 124914039Sstacze01@arm.com if (inst->isLoad()) { 125014039Sstacze01@arm.com statComLoads[tid]++; 125114039Sstacze01@arm.com } 125214039Sstacze01@arm.com } 125314039Sstacze01@arm.com 125414039Sstacze01@arm.com if (inst->isMemBarrier()) { 125514039Sstacze01@arm.com statComMembars[tid]++; 125614039Sstacze01@arm.com } 125714039Sstacze01@arm.com} 125814039Sstacze01@arm.com 125914039Sstacze01@arm.com//////////////////////////////////////// 126014039Sstacze01@arm.com// // 126114039Sstacze01@arm.com// SMT COMMIT POLICY MAINTAINED HERE // 126214039Sstacze01@arm.com// // 126314039Sstacze01@arm.com//////////////////////////////////////// 126414039Sstacze01@arm.comtemplate <class Impl> 126514039Sstacze01@arm.comThreadID 126614039Sstacze01@arm.comDefaultCommit<Impl>::getCommittingThread() 126714039Sstacze01@arm.com{ 126814039Sstacze01@arm.com if (numThreads > 1) { 126914039Sstacze01@arm.com switch (commitPolicy) { 127014039Sstacze01@arm.com 127114039Sstacze01@arm.com case Aggressive: 127214039Sstacze01@arm.com //If Policy is Aggressive, commit will call 127314039Sstacze01@arm.com //this function multiple times per 127414039Sstacze01@arm.com //cycle 127514039Sstacze01@arm.com return oldestReady(); 127614039Sstacze01@arm.com 127714039Sstacze01@arm.com case RoundRobin: 127814039Sstacze01@arm.com return roundRobin(); 127914039Sstacze01@arm.com 128014039Sstacze01@arm.com case OldestReady: 128114039Sstacze01@arm.com return oldestReady(); 128214039Sstacze01@arm.com 128314039Sstacze01@arm.com default: 128414039Sstacze01@arm.com return InvalidThreadID; 128514039Sstacze01@arm.com } 128614039Sstacze01@arm.com } else { 128714039Sstacze01@arm.com assert(!activeThreads->empty()); 128814039Sstacze01@arm.com ThreadID tid = activeThreads->front(); 128914039Sstacze01@arm.com 129014039Sstacze01@arm.com if (commitStatus[tid] == Running || 129114039Sstacze01@arm.com commitStatus[tid] == Idle || 129214039Sstacze01@arm.com commitStatus[tid] == FetchTrapPending) { 129314039Sstacze01@arm.com return tid; 129414039Sstacze01@arm.com } else { 129514039Sstacze01@arm.com return InvalidThreadID; 129614039Sstacze01@arm.com } 129714039Sstacze01@arm.com } 129814039Sstacze01@arm.com} 129914039Sstacze01@arm.com 130014039Sstacze01@arm.comtemplate<class Impl> 130114039Sstacze01@arm.comThreadID 130214039Sstacze01@arm.comDefaultCommit<Impl>::roundRobin() 130314039Sstacze01@arm.com{ 130414039Sstacze01@arm.com list<ThreadID>::iterator pri_iter = priority_list.begin(); 130514039Sstacze01@arm.com list<ThreadID>::iterator end = priority_list.end(); 130614039Sstacze01@arm.com 130714039Sstacze01@arm.com while (pri_iter != end) { 130814039Sstacze01@arm.com ThreadID tid = *pri_iter; 130914039Sstacze01@arm.com 131014039Sstacze01@arm.com if (commitStatus[tid] == Running || 131114039Sstacze01@arm.com commitStatus[tid] == Idle || 131214039Sstacze01@arm.com commitStatus[tid] == FetchTrapPending) { 131314039Sstacze01@arm.com 131414039Sstacze01@arm.com if (rob->isHeadReady(tid)) { 131514039Sstacze01@arm.com priority_list.erase(pri_iter); 131614039Sstacze01@arm.com priority_list.push_back(tid); 131714039Sstacze01@arm.com 131814039Sstacze01@arm.com return tid; 131914039Sstacze01@arm.com } 132014039Sstacze01@arm.com } 132114039Sstacze01@arm.com 132214039Sstacze01@arm.com pri_iter++; 132314039Sstacze01@arm.com } 132414039Sstacze01@arm.com 132514039Sstacze01@arm.com return InvalidThreadID; 132614039Sstacze01@arm.com} 132714039Sstacze01@arm.com 132814039Sstacze01@arm.comtemplate<class Impl> 132914039Sstacze01@arm.comThreadID 133014039Sstacze01@arm.comDefaultCommit<Impl>::oldestReady() 133114039Sstacze01@arm.com{ 133214039Sstacze01@arm.com unsigned oldest = 0; 133314039Sstacze01@arm.com bool first = true; 133414039Sstacze01@arm.com 133514039Sstacze01@arm.com list<ThreadID>::iterator threads = activeThreads->begin(); 133614039Sstacze01@arm.com list<ThreadID>::iterator end = activeThreads->end(); 133714039Sstacze01@arm.com 133814039Sstacze01@arm.com while (threads != end) { 133914039Sstacze01@arm.com ThreadID tid = *threads++; 134014039Sstacze01@arm.com 134114039Sstacze01@arm.com if (!rob->isEmpty(tid) && 134214039Sstacze01@arm.com (commitStatus[tid] == Running || 134314039Sstacze01@arm.com commitStatus[tid] == Idle || 134414039Sstacze01@arm.com commitStatus[tid] == FetchTrapPending)) { 134514039Sstacze01@arm.com 134614039Sstacze01@arm.com if (rob->isHeadReady(tid)) { 134714039Sstacze01@arm.com 134814039Sstacze01@arm.com DynInstPtr head_inst = rob->readHeadInst(tid); 134914039Sstacze01@arm.com 135014039Sstacze01@arm.com if (first) { 135114039Sstacze01@arm.com oldest = tid; 135214039Sstacze01@arm.com first = false; 135314039Sstacze01@arm.com } else if (head_inst->seqNum < oldest) { 135414039Sstacze01@arm.com oldest = tid; 135514039Sstacze01@arm.com } 135614039Sstacze01@arm.com } 135714039Sstacze01@arm.com } 135814039Sstacze01@arm.com } 135914039Sstacze01@arm.com 136014039Sstacze01@arm.com if (!first) { 136114039Sstacze01@arm.com return oldest; 136214039Sstacze01@arm.com } else { 136314039Sstacze01@arm.com return InvalidThreadID; 136414039Sstacze01@arm.com } 136514039Sstacze01@arm.com} 136614039Sstacze01@arm.com