commit_impl.hh revision 2670:9107b8bd08cd
12315SN/A/* 28733Sgeoffrey.blake@arm.com * Copyright (c) 2004-2006 The Regents of The University of Michigan 39913Ssteve.reinhardt@amd.com * All rights reserved. 48733Sgeoffrey.blake@arm.com * 58733Sgeoffrey.blake@arm.com * Redistribution and use in source and binary forms, with or without 68733Sgeoffrey.blake@arm.com * modification, are permitted provided that the following conditions are 78733Sgeoffrey.blake@arm.com * met: redistributions of source code must retain the above copyright 88733Sgeoffrey.blake@arm.com * notice, this list of conditions and the following disclaimer; 98733Sgeoffrey.blake@arm.com * redistributions in binary form must reproduce the above copyright 108733Sgeoffrey.blake@arm.com * notice, this list of conditions and the following disclaimer in the 118733Sgeoffrey.blake@arm.com * documentation and/or other materials provided with the distribution; 128733Sgeoffrey.blake@arm.com * neither the name of the copyright holders nor the names of its 138733Sgeoffrey.blake@arm.com * contributors may be used to endorse or promote products derived from 148733Sgeoffrey.blake@arm.com * this software without specific prior written permission. 152332SN/A * 162315SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172315SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182315SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192315SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202315SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212315SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222315SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232315SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242315SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252315SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262315SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272315SN/A * 282315SN/A * Authors: Kevin Lim 292315SN/A */ 302315SN/A 312315SN/A#include <algorithm> 322315SN/A#include <string> 332315SN/A 342315SN/A#include "base/loader/symtab.hh" 352315SN/A#include "base/timebuf.hh" 362315SN/A#include "cpu/checker/cpu.hh" 372315SN/A#include "cpu/exetrace.hh" 382315SN/A#include "cpu/o3/commit.hh" 392315SN/A#include "cpu/o3/thread_state.hh" 402689SN/A 412689SN/Ausing namespace std; 428733Sgeoffrey.blake@arm.com 432315SN/Atemplate <class Impl> 442315SN/ADefaultCommit<Impl>::TrapEvent::TrapEvent(DefaultCommit<Impl> *_commit, 452315SN/A unsigned _tid) 462315SN/A : Event(&mainEventQueue, CPU_Tick_Pri), commit(_commit), tid(_tid) 472315SN/A{ 488888Sgeoffrey.blake@arm.com this->setFlags(Event::AutoDelete); 498793Sgblack@eecs.umich.edu} 502315SN/A 516658Snate@binkert.orgtemplate <class Impl> 522315SN/Avoid 538733Sgeoffrey.blake@arm.comDefaultCommit<Impl>::TrapEvent::process() 549913Ssteve.reinhardt@amd.com{ 552683SN/A // This will get reset by commit if it was switched out at the 568229Snate@binkert.org // time of this event processing. 572680SN/A commit->trapSquash[tid] = true; 588733Sgeoffrey.blake@arm.com} 598733Sgeoffrey.blake@arm.com 608793Sgblack@eecs.umich.edutemplate <class Impl> 612315SN/Aconst char * 622315SN/ADefaultCommit<Impl>::TrapEvent::description() 632315SN/A{ 642315SN/A return "Trap event"; 658733Sgeoffrey.blake@arm.com} 662315SN/A 678733Sgeoffrey.blake@arm.comtemplate <class Impl> 682315SN/ADefaultCommit<Impl>::DefaultCommit(Params *params) 698733Sgeoffrey.blake@arm.com : squashCounter(0), 708733Sgeoffrey.blake@arm.com iewToCommitDelay(params->iewToCommitDelay), 718733Sgeoffrey.blake@arm.com commitToIEWDelay(params->commitToIEWDelay), 728733Sgeoffrey.blake@arm.com renameToROBDelay(params->renameToROBDelay), 738733Sgeoffrey.blake@arm.com fetchToCommitDelay(params->commitToFetchDelay), 749023Sgblack@eecs.umich.edu renameWidth(params->renameWidth), 758733Sgeoffrey.blake@arm.com iewWidth(params->executeWidth), 768733Sgeoffrey.blake@arm.com commitWidth(params->commitWidth), 778733Sgeoffrey.blake@arm.com numThreads(params->numberOfThreads), 788733Sgeoffrey.blake@arm.com switchedOut(false), 798733Sgeoffrey.blake@arm.com trapLatency(params->trapLatency), 808733Sgeoffrey.blake@arm.com fetchTrapLatency(params->fetchTrapLatency) 818733Sgeoffrey.blake@arm.com{ 828733Sgeoffrey.blake@arm.com _status = Active; 838733Sgeoffrey.blake@arm.com _nextStatus = Inactive; 848733Sgeoffrey.blake@arm.com string policy = params->smtCommitPolicy; 858733Sgeoffrey.blake@arm.com 868733Sgeoffrey.blake@arm.com //Convert string to lowercase 878733Sgeoffrey.blake@arm.com std::transform(policy.begin(), policy.end(), policy.begin(), 888733Sgeoffrey.blake@arm.com (int(*)(int)) tolower); 898733Sgeoffrey.blake@arm.com 908733Sgeoffrey.blake@arm.com //Assign commit policy 918733Sgeoffrey.blake@arm.com if (policy == "aggressive"){ 928733Sgeoffrey.blake@arm.com commitPolicy = Aggressive; 938733Sgeoffrey.blake@arm.com 948733Sgeoffrey.blake@arm.com DPRINTF(Commit,"Commit Policy set to Aggressive."); 958733Sgeoffrey.blake@arm.com } else if (policy == "roundrobin"){ 968733Sgeoffrey.blake@arm.com commitPolicy = RoundRobin; 978733Sgeoffrey.blake@arm.com 988733Sgeoffrey.blake@arm.com //Set-Up Priority List 998733Sgeoffrey.blake@arm.com for (int tid=0; tid < numThreads; tid++) { 1008733Sgeoffrey.blake@arm.com priority_list.push_back(tid); 1018733Sgeoffrey.blake@arm.com } 1028733Sgeoffrey.blake@arm.com 1038733Sgeoffrey.blake@arm.com DPRINTF(Commit,"Commit Policy set to Round Robin."); 1048733Sgeoffrey.blake@arm.com } else if (policy == "oldestready"){ 1058733Sgeoffrey.blake@arm.com commitPolicy = OldestReady; 1068733Sgeoffrey.blake@arm.com 1078733Sgeoffrey.blake@arm.com DPRINTF(Commit,"Commit Policy set to Oldest Ready."); 1088733Sgeoffrey.blake@arm.com } else { 1098733Sgeoffrey.blake@arm.com assert(0 && "Invalid SMT Commit Policy. Options Are: {Aggressive," 1108733Sgeoffrey.blake@arm.com "RoundRobin,OldestReady}"); 1118733Sgeoffrey.blake@arm.com } 1128733Sgeoffrey.blake@arm.com 1138733Sgeoffrey.blake@arm.com for (int i=0; i < numThreads; i++) { 1148733Sgeoffrey.blake@arm.com commitStatus[i] = Idle; 1158733Sgeoffrey.blake@arm.com changedROBNumEntries[i] = false; 1168733Sgeoffrey.blake@arm.com trapSquash[i] = false; 1178733Sgeoffrey.blake@arm.com xcSquash[i] = false; 1189023Sgblack@eecs.umich.edu } 1198733Sgeoffrey.blake@arm.com 1208733Sgeoffrey.blake@arm.com fetchFaultTick = 0; 1218733Sgeoffrey.blake@arm.com fetchTrapWait = 0; 1228733Sgeoffrey.blake@arm.com} 1238733Sgeoffrey.blake@arm.com 1248733Sgeoffrey.blake@arm.comtemplate <class Impl> 1252315SN/Astd::string 1262315SN/ADefaultCommit<Impl>::name() const 1272315SN/A{ 1288733Sgeoffrey.blake@arm.com return cpu->name() + ".commit"; 1298733Sgeoffrey.blake@arm.com} 1308733Sgeoffrey.blake@arm.com 1318733Sgeoffrey.blake@arm.comtemplate <class Impl> 1328733Sgeoffrey.blake@arm.comvoid 1338733Sgeoffrey.blake@arm.comDefaultCommit<Impl>::regStats() 1348733Sgeoffrey.blake@arm.com{ 1358733Sgeoffrey.blake@arm.com using namespace Stats; 1368733Sgeoffrey.blake@arm.com commitCommittedInsts 1378733Sgeoffrey.blake@arm.com .name(name() + ".commitCommittedInsts") 1388733Sgeoffrey.blake@arm.com .desc("The number of committed instructions") 1398733Sgeoffrey.blake@arm.com .prereq(commitCommittedInsts); 1402332SN/A commitSquashedInsts 1412332SN/A .name(name() + ".commitSquashedInsts") 1422332SN/A .desc("The number of squashed insts skipped by commit") 1432332SN/A .prereq(commitSquashedInsts); 1442332SN/A commitSquashEvents 1452315SN/A .name(name() + ".commitSquashEvents") 1462315SN/A .desc("The number of times commit is told to squash") 1478733Sgeoffrey.blake@arm.com .prereq(commitSquashEvents); 1488733Sgeoffrey.blake@arm.com commitNonSpecStalls 1492315SN/A .name(name() + ".commitNonSpecStalls") 1502315SN/A .desc("The number of times commit has been forced to stall to " 1512315SN/A "communicate backwards") 1522315SN/A .prereq(commitNonSpecStalls); 1532315SN/A branchMispredicts 1542315SN/A .name(name() + ".branchMispredicts") 1552315SN/A .desc("The number of times a branch was mispredicted") 1562315SN/A .prereq(branchMispredicts); 1572315SN/A numCommittedDist 1582315SN/A .init(0,commitWidth,1) 1592315SN/A .name(name() + ".COM:committed_per_cycle") 1602315SN/A .desc("Number of insts commited each cycle") 1612315SN/A .flags(Stats::pdf) 1628733Sgeoffrey.blake@arm.com ; 1638733Sgeoffrey.blake@arm.com 1642315SN/A statComInst 1652315SN/A .init(cpu->number_of_threads) 1662315SN/A .name(name() + ".COM:count") 1672315SN/A .desc("Number of instructions committed") 1682315SN/A .flags(total) 1692315SN/A ; 1702315SN/A 1712315SN/A statComSwp 1722315SN/A .init(cpu->number_of_threads) 1732315SN/A .name(name() + ".COM:swp_count") 1742315SN/A .desc("Number of s/w prefetches committed") 1752315SN/A .flags(total) 1762315SN/A ; 1772315SN/A 1788733Sgeoffrey.blake@arm.com statComRefs 1798733Sgeoffrey.blake@arm.com .init(cpu->number_of_threads) 1808733Sgeoffrey.blake@arm.com .name(name() + ".COM:refs") 1818733Sgeoffrey.blake@arm.com .desc("Number of memory references committed") 1828733Sgeoffrey.blake@arm.com .flags(total) 1838733Sgeoffrey.blake@arm.com ; 1848733Sgeoffrey.blake@arm.com 1852354SN/A statComLoads 1868733Sgeoffrey.blake@arm.com .init(cpu->number_of_threads) 1872354SN/A .name(name() + ".COM:loads") 1882332SN/A .desc("Number of loads committed") 1892332SN/A .flags(total) 1902332SN/A ; 1912315SN/A 1928733Sgeoffrey.blake@arm.com statComMembars 1938733Sgeoffrey.blake@arm.com .init(cpu->number_of_threads) 1948733Sgeoffrey.blake@arm.com .name(name() + ".COM:membars") 1958733Sgeoffrey.blake@arm.com .desc("Number of memory barriers committed") 1968733Sgeoffrey.blake@arm.com .flags(total) 1978733Sgeoffrey.blake@arm.com ; 1988733Sgeoffrey.blake@arm.com 1998733Sgeoffrey.blake@arm.com statComBranches 2008733Sgeoffrey.blake@arm.com .init(cpu->number_of_threads) 2012315SN/A .name(name() + ".COM:branches") 2022315SN/A .desc("Number of branches committed") 2032315SN/A .flags(total) 2042315SN/A ; 2052315SN/A 2062683SN/A // 2078888Sgeoffrey.blake@arm.com // Commit-Eligible instructions... 2088888Sgeoffrey.blake@arm.com // 2098888Sgeoffrey.blake@arm.com // -> The number of instructions eligible to commit in those 2102315SN/A // cycles where we reached our commit BW limit (less the number 2112332SN/A // actually committed) 2122332SN/A // 2132332SN/A // -> The average value is computed over ALL CYCLES... not just 2142315SN/A // the BW limited cycles 2158733Sgeoffrey.blake@arm.com // 2168733Sgeoffrey.blake@arm.com // -> The standard deviation is computed only over cycles where 2172315SN/A // we reached the BW limit 2188733Sgeoffrey.blake@arm.com // 2192315SN/A commitEligible 2202315SN/A .init(cpu->number_of_threads) 2212332SN/A .name(name() + ".COM:bw_limited") 2228733Sgeoffrey.blake@arm.com .desc("number of insts not committed due to BW limits") 2238733Sgeoffrey.blake@arm.com .flags(total) 2242732SN/A ; 2252315SN/A 2262315SN/A commitEligibleSamples 2272315SN/A .name(name() + ".COM:bw_lim_events") 2282315SN/A .desc("number cycles where commit BW limit reached") 2292315SN/A ; 2302315SN/A} 2312315SN/A 2328733Sgeoffrey.blake@arm.comtemplate <class Impl> 2332315SN/Avoid 2342315SN/ADefaultCommit<Impl>::setCPU(FullCPU *cpu_ptr) 2352315SN/A{ 2362332SN/A DPRINTF(Commit, "Commit: Setting CPU pointer.\n"); 2378733Sgeoffrey.blake@arm.com cpu = cpu_ptr; 2388733Sgeoffrey.blake@arm.com 2392332SN/A // Commit must broadcast the number of free entries it has at the start of 2408733Sgeoffrey.blake@arm.com // the simulation, so it starts as active. 2418733Sgeoffrey.blake@arm.com cpu->activateStage(FullCPU::CommitIdx); 2428733Sgeoffrey.blake@arm.com 2432332SN/A trapLatency = cpu->cycles(trapLatency); 2449023Sgblack@eecs.umich.edu fetchTrapLatency = cpu->cycles(fetchTrapLatency); 2459023Sgblack@eecs.umich.edu} 2468733Sgeoffrey.blake@arm.com 2478733Sgeoffrey.blake@arm.comtemplate <class Impl> 2488733Sgeoffrey.blake@arm.comvoid 2498733Sgeoffrey.blake@arm.comDefaultCommit<Impl>::setThreads(vector<Thread *> &threads) 2508733Sgeoffrey.blake@arm.com{ 2518733Sgeoffrey.blake@arm.com thread = threads; 2528887Sgeoffrey.blake@arm.com} 2538733Sgeoffrey.blake@arm.com 2548733Sgeoffrey.blake@arm.comtemplate <class Impl> 2558733Sgeoffrey.blake@arm.comvoid 2568832SAli.Saidi@ARM.comDefaultCommit<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) 2572679SN/A{ 2582315SN/A DPRINTF(Commit, "Commit: Setting time buffer pointer.\n"); 2598733Sgeoffrey.blake@arm.com timeBuffer = tb_ptr; 2602315SN/A 2618733Sgeoffrey.blake@arm.com // Setup wire to send information back to IEW. 2628733Sgeoffrey.blake@arm.com toIEW = timeBuffer->getWire(0); 2638733Sgeoffrey.blake@arm.com 2648733Sgeoffrey.blake@arm.com // Setup wire to read data from IEW (for the ROB). 2658733Sgeoffrey.blake@arm.com robInfoFromIEW = timeBuffer->getWire(-iewToCommitDelay); 2668733Sgeoffrey.blake@arm.com} 2678733Sgeoffrey.blake@arm.com 2688733Sgeoffrey.blake@arm.comtemplate <class Impl> 2698733Sgeoffrey.blake@arm.comvoid 2708733Sgeoffrey.blake@arm.comDefaultCommit<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr) 2712315SN/A{ 2728733Sgeoffrey.blake@arm.com DPRINTF(Commit, "Commit: Setting fetch queue pointer.\n"); 2738733Sgeoffrey.blake@arm.com fetchQueue = fq_ptr; 2742315SN/A 2758733Sgeoffrey.blake@arm.com // Setup wire to get instructions from rename (for the ROB). 2768733Sgeoffrey.blake@arm.com fromFetch = fetchQueue->getWire(-fetchToCommitDelay); 2778733Sgeoffrey.blake@arm.com} 2788733Sgeoffrey.blake@arm.com 2798733Sgeoffrey.blake@arm.comtemplate <class Impl> 2808733Sgeoffrey.blake@arm.comvoid 2818733Sgeoffrey.blake@arm.comDefaultCommit<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr) 2828733Sgeoffrey.blake@arm.com{ 2838733Sgeoffrey.blake@arm.com DPRINTF(Commit, "Commit: Setting rename queue pointer.\n"); 2848733Sgeoffrey.blake@arm.com renameQueue = rq_ptr; 2858733Sgeoffrey.blake@arm.com 2868733Sgeoffrey.blake@arm.com // Setup wire to get instructions from rename (for the ROB). 2878733Sgeoffrey.blake@arm.com fromRename = renameQueue->getWire(-renameToROBDelay); 2888949Sandreas.hansson@arm.com} 2898733Sgeoffrey.blake@arm.com 2908733Sgeoffrey.blake@arm.comtemplate <class Impl> 2918733Sgeoffrey.blake@arm.comvoid 2928733Sgeoffrey.blake@arm.comDefaultCommit<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr) 2938733Sgeoffrey.blake@arm.com{ 2948733Sgeoffrey.blake@arm.com DPRINTF(Commit, "Commit: Setting IEW queue pointer.\n"); 2958733Sgeoffrey.blake@arm.com iewQueue = iq_ptr; 2968733Sgeoffrey.blake@arm.com 2978733Sgeoffrey.blake@arm.com // Setup wire to get instructions from IEW. 2988733Sgeoffrey.blake@arm.com fromIEW = iewQueue->getWire(-iewToCommitDelay); 2998733Sgeoffrey.blake@arm.com} 3008733Sgeoffrey.blake@arm.com 3018733Sgeoffrey.blake@arm.comtemplate <class Impl> 3028733Sgeoffrey.blake@arm.comvoid 3038733Sgeoffrey.blake@arm.comDefaultCommit<Impl>::setFetchStage(Fetch *fetch_stage) 3048733Sgeoffrey.blake@arm.com{ 3058733Sgeoffrey.blake@arm.com fetchStage = fetch_stage; 3068733Sgeoffrey.blake@arm.com} 3078733Sgeoffrey.blake@arm.com 3088733Sgeoffrey.blake@arm.comtemplate <class Impl> 3098733Sgeoffrey.blake@arm.comvoid 3108733Sgeoffrey.blake@arm.comDefaultCommit<Impl>::setIEWStage(IEW *iew_stage) 3118733Sgeoffrey.blake@arm.com{ 3128733Sgeoffrey.blake@arm.com iewStage = iew_stage; 3139023Sgblack@eecs.umich.edu} 3148733Sgeoffrey.blake@arm.com 3158733Sgeoffrey.blake@arm.comtemplate<class Impl> 3168733Sgeoffrey.blake@arm.comvoid 3178733Sgeoffrey.blake@arm.comDefaultCommit<Impl>::setActiveThreads(list<unsigned> *at_ptr) 3189023Sgblack@eecs.umich.edu{ 3198733Sgeoffrey.blake@arm.com DPRINTF(Commit, "Commit: Setting active threads list pointer.\n"); 3209023Sgblack@eecs.umich.edu activeThreads = at_ptr; 3218733Sgeoffrey.blake@arm.com} 3228733Sgeoffrey.blake@arm.com 3238733Sgeoffrey.blake@arm.comtemplate <class Impl> 3248733Sgeoffrey.blake@arm.comvoid 3258733Sgeoffrey.blake@arm.comDefaultCommit<Impl>::setRenameMap(RenameMap rm_ptr[]) 3268733Sgeoffrey.blake@arm.com{ 3278733Sgeoffrey.blake@arm.com DPRINTF(Commit, "Setting rename map pointers.\n"); 3288733Sgeoffrey.blake@arm.com 3298733Sgeoffrey.blake@arm.com for (int i=0; i < numThreads; i++) { 3308733Sgeoffrey.blake@arm.com renameMap[i] = &rm_ptr[i]; 3318733Sgeoffrey.blake@arm.com } 3328733Sgeoffrey.blake@arm.com} 3338733Sgeoffrey.blake@arm.com 3348733Sgeoffrey.blake@arm.comtemplate <class Impl> 3358733Sgeoffrey.blake@arm.comvoid 3368733Sgeoffrey.blake@arm.comDefaultCommit<Impl>::setROB(ROB *rob_ptr) 3378733Sgeoffrey.blake@arm.com{ 3388733Sgeoffrey.blake@arm.com DPRINTF(Commit, "Commit: Setting ROB pointer.\n"); 3398733Sgeoffrey.blake@arm.com rob = rob_ptr; 3408733Sgeoffrey.blake@arm.com} 3418733Sgeoffrey.blake@arm.com 3422323SN/Atemplate <class Impl> 3432315SN/Avoid 3449023Sgblack@eecs.umich.eduDefaultCommit<Impl>::initStage() 3459023Sgblack@eecs.umich.edu{ 3462315SN/A rob->setActiveThreads(activeThreads); 3478733Sgeoffrey.blake@arm.com rob->resetEntries(); 3488733Sgeoffrey.blake@arm.com 3498733Sgeoffrey.blake@arm.com // Broadcast the number of free entries. 3502323SN/A for (int i=0; i < numThreads; i++) { 3518733Sgeoffrey.blake@arm.com toIEW->commitInfo[i].usedROB = true; 3522679SN/A toIEW->commitInfo[i].freeROBEntries = rob->numFreeEntries(i); 3532323SN/A } 3542323SN/A 3558733Sgeoffrey.blake@arm.com cpu->activityThisCycle(); 3562323SN/A} 3572315SN/A 3588733Sgeoffrey.blake@arm.comtemplate <class Impl> 3598733Sgeoffrey.blake@arm.comvoid 3608733Sgeoffrey.blake@arm.comDefaultCommit<Impl>::switchOut() 3612679SN/A{ 3622315SN/A switchPending = true; 3632315SN/A} 3642315SN/A 3652315SN/Atemplate <class Impl> 3668733Sgeoffrey.blake@arm.comvoid 3678733Sgeoffrey.blake@arm.comDefaultCommit<Impl>::doSwitchOut() 3688733Sgeoffrey.blake@arm.com{ 3698733Sgeoffrey.blake@arm.com switchedOut = true; 3708733Sgeoffrey.blake@arm.com switchPending = false; 3718733Sgeoffrey.blake@arm.com rob->switchOut(); 3728733Sgeoffrey.blake@arm.com} 3738733Sgeoffrey.blake@arm.com 3748733Sgeoffrey.blake@arm.comtemplate <class Impl> 3758733Sgeoffrey.blake@arm.comvoid 3768733Sgeoffrey.blake@arm.comDefaultCommit<Impl>::takeOverFrom() 3778733Sgeoffrey.blake@arm.com{ 3788733Sgeoffrey.blake@arm.com switchedOut = false; 3792315SN/A _status = Active; 3808733Sgeoffrey.blake@arm.com _nextStatus = Inactive; 3818733Sgeoffrey.blake@arm.com for (int i=0; i < numThreads; i++) { 3828733Sgeoffrey.blake@arm.com commitStatus[i] = Idle; 3838733Sgeoffrey.blake@arm.com changedROBNumEntries[i] = false; 3842315SN/A trapSquash[i] = false; 3858733Sgeoffrey.blake@arm.com xcSquash[i] = false; 3868733Sgeoffrey.blake@arm.com } 3878733Sgeoffrey.blake@arm.com squashCounter = 0; 3888733Sgeoffrey.blake@arm.com rob->takeOverFrom(); 3898733Sgeoffrey.blake@arm.com} 3908733Sgeoffrey.blake@arm.com 3918733Sgeoffrey.blake@arm.comtemplate <class Impl> 3928733Sgeoffrey.blake@arm.comvoid 3938733Sgeoffrey.blake@arm.comDefaultCommit<Impl>::updateStatus() 3948733Sgeoffrey.blake@arm.com{ 3958733Sgeoffrey.blake@arm.com // reset ROB changed variable 3962315SN/A list<unsigned>::iterator threads = (*activeThreads).begin(); 3972315SN/A while (threads != (*activeThreads).end()) { 3982315SN/A unsigned tid = *threads++; 3998733Sgeoffrey.blake@arm.com changedROBNumEntries[tid] = false; 4002315SN/A 4018887Sgeoffrey.blake@arm.com // Also check if any of the threads has a trap pending 4028887Sgeoffrey.blake@arm.com if (commitStatus[tid] == TrapPending || 4038887Sgeoffrey.blake@arm.com commitStatus[tid] == FetchTrapPending) { 4048887Sgeoffrey.blake@arm.com _nextStatus = Active; 4058887Sgeoffrey.blake@arm.com } 4068887Sgeoffrey.blake@arm.com } 4078887Sgeoffrey.blake@arm.com 4082315SN/A if (_nextStatus == Inactive && _status == Active) { 4098733Sgeoffrey.blake@arm.com DPRINTF(Activity, "Deactivating stage.\n"); 4102315SN/A cpu->deactivateStage(FullCPU::CommitIdx); 4112315SN/A } else if (_nextStatus == Active && _status == Inactive) { 4128793Sgblack@eecs.umich.edu DPRINTF(Activity, "Activating stage.\n"); 4138793Sgblack@eecs.umich.edu cpu->activateStage(FullCPU::CommitIdx); 4148793Sgblack@eecs.umich.edu } 4158793Sgblack@eecs.umich.edu 4168793Sgblack@eecs.umich.edu _status = _nextStatus; 4178793Sgblack@eecs.umich.edu} 4188793Sgblack@eecs.umich.edu 4198809Sgblack@eecs.umich.edutemplate <class Impl> 4208793Sgblack@eecs.umich.eduvoid 4218793Sgblack@eecs.umich.eduDefaultCommit<Impl>::setNextStatus() 4228809Sgblack@eecs.umich.edu{ 4238793Sgblack@eecs.umich.edu int squashes = 0; 4248793Sgblack@eecs.umich.edu 4258809Sgblack@eecs.umich.edu list<unsigned>::iterator threads = (*activeThreads).begin(); 4268809Sgblack@eecs.umich.edu 4278793Sgblack@eecs.umich.edu while (threads != (*activeThreads).end()) { 4282315SN/A unsigned tid = *threads++; 4292315SN/A 4302332SN/A if (commitStatus[tid] == ROBSquashing) { 4312315SN/A squashes++; 4322315SN/A } 4332315SN/A } 4342332SN/A 4352332SN/A assert(squashes == squashCounter); 4362315SN/A 4372315SN/A // If commit is currently squashing, then it will have activity for the 4382315SN/A // next cycle. Set its next status as active. 4398733Sgeoffrey.blake@arm.com if (squashCounter) { 4408733Sgeoffrey.blake@arm.com _nextStatus = Active; 4412315SN/A } 4422315SN/A} 4432315SN/A 4442315SN/Atemplate <class Impl> 4452315SN/Abool 4462354SN/ADefaultCommit<Impl>::changedROBEntries() 4472315SN/A{ 4482315SN/A list<unsigned>::iterator threads = (*activeThreads).begin(); 4498733Sgeoffrey.blake@arm.com 4502315SN/A while (threads != (*activeThreads).end()) { 4518733Sgeoffrey.blake@arm.com unsigned tid = *threads++; 4522315SN/A 4532315SN/A if (changedROBNumEntries[tid]) { 4542315SN/A return true; 4552315SN/A } 4568733Sgeoffrey.blake@arm.com } 4572315SN/A 4588733Sgeoffrey.blake@arm.com return false; 4592315SN/A} 4602315SN/A 4612315SN/Atemplate <class Impl> 4628733Sgeoffrey.blake@arm.comunsigned 4632315SN/ADefaultCommit<Impl>::numROBFreeEntries(unsigned tid) 4648733Sgeoffrey.blake@arm.com{ 4652315SN/A return rob->numFreeEntries(tid); 4668733Sgeoffrey.blake@arm.com} 4678733Sgeoffrey.blake@arm.com 4688733Sgeoffrey.blake@arm.comtemplate <class Impl> 4692315SN/Avoid 4702332SN/ADefaultCommit<Impl>::generateTrapEvent(unsigned tid) 4717823Ssteve.reinhardt@amd.com{ 4722315SN/A DPRINTF(Commit, "Generating trap event for [tid:%i]\n", tid); 4732732SN/A 4742315SN/A TrapEvent *trap = new TrapEvent(this, tid); 4752315SN/A 4762315SN/A trap->schedule(curTick + trapLatency); 4779023Sgblack@eecs.umich.edu 4789023Sgblack@eecs.umich.edu thread[tid]->trapPending = true; 4799023Sgblack@eecs.umich.edu} 4802315SN/A 4812315SN/Atemplate <class Impl> 4822315SN/Avoid 4838733Sgeoffrey.blake@arm.comDefaultCommit<Impl>::generateXCEvent(unsigned tid) 4842315SN/A{ 4858733Sgeoffrey.blake@arm.com DPRINTF(Commit, "Generating XC squash event for [tid:%i]\n", tid); 4862315SN/A 4878733Sgeoffrey.blake@arm.com xcSquash[tid] = true; 4888733Sgeoffrey.blake@arm.com} 4898733Sgeoffrey.blake@arm.com 4902732SN/Atemplate <class Impl> 4918733Sgeoffrey.blake@arm.comvoid 4928733Sgeoffrey.blake@arm.comDefaultCommit<Impl>::squashAll(unsigned tid) 4938733Sgeoffrey.blake@arm.com{ 4948733Sgeoffrey.blake@arm.com // If we want to include the squashing instruction in the squash, 4958733Sgeoffrey.blake@arm.com // then use one older sequence number. 4968733Sgeoffrey.blake@arm.com // Hopefully this doesn't mess things up. Basically I want to squash 4978733Sgeoffrey.blake@arm.com // all instructions of this thread. 4988733Sgeoffrey.blake@arm.com InstSeqNum squashed_inst = rob->isEmpty() ? 4998733Sgeoffrey.blake@arm.com 0 : rob->readHeadInst(tid)->seqNum - 1;; 5008733Sgeoffrey.blake@arm.com 5018733Sgeoffrey.blake@arm.com // All younger instructions will be squashed. Set the sequence 5028733Sgeoffrey.blake@arm.com // number as the youngest instruction in the ROB (0 in this case. 5038733Sgeoffrey.blake@arm.com // Hopefully nothing breaks.) 5048733Sgeoffrey.blake@arm.com youngestSeqNum[tid] = 0; 5058733Sgeoffrey.blake@arm.com 5068733Sgeoffrey.blake@arm.com rob->squash(squashed_inst, tid); 5078733Sgeoffrey.blake@arm.com changedROBNumEntries[tid] = true; 5088733Sgeoffrey.blake@arm.com 5098733Sgeoffrey.blake@arm.com // Send back the sequence number of the squashed instruction. 5102732SN/A toIEW->commitInfo[tid].doneSeqNum = squashed_inst; 5118733Sgeoffrey.blake@arm.com 5128733Sgeoffrey.blake@arm.com // Send back the squash signal to tell stages that they should 5138733Sgeoffrey.blake@arm.com // squash. 5148733Sgeoffrey.blake@arm.com toIEW->commitInfo[tid].squash = true; 5158733Sgeoffrey.blake@arm.com 5162732SN/A // Send back the rob squashing signal so other stages know that 5172732SN/A // the ROB is in the process of squashing. 5182732SN/A toIEW->commitInfo[tid].robSquashing = true; 5192732SN/A 5208733Sgeoffrey.blake@arm.com toIEW->commitInfo[tid].branchMispredict = false; 5212732SN/A 5222732SN/A toIEW->commitInfo[tid].nextPC = PC[tid]; 5232732SN/A} 5242732SN/A 5252732SN/Atemplate <class Impl> 5262732SN/Avoid 5278733Sgeoffrey.blake@arm.comDefaultCommit<Impl>::squashFromTrap(unsigned tid) 5288733Sgeoffrey.blake@arm.com{ 5292732SN/A squashAll(tid); 5308733Sgeoffrey.blake@arm.com 5312732SN/A DPRINTF(Commit, "Squashing from trap, restarting at PC %#x\n", PC[tid]); 5322732SN/A 5332315SN/A thread[tid]->trapPending = false; 5342315SN/A thread[tid]->inSyscall = false; 5352315SN/A 5368733Sgeoffrey.blake@arm.com trapSquash[tid] = false; 5372332SN/A 5382332SN/A commitStatus[tid] = ROBSquashing; 5398733Sgeoffrey.blake@arm.com cpu->activityThisCycle(); 5402732SN/A 5412315SN/A ++squashCounter; 5422315SN/A} 5432315SN/A 5442315SN/Atemplate <class Impl> 5452315SN/Avoid 5462315SN/ADefaultCommit<Impl>::squashFromXC(unsigned tid) 5472315SN/A{ 5482315SN/A squashAll(tid); 5492315SN/A 5502315SN/A DPRINTF(Commit, "Squashing from XC, restarting at PC %#x\n", PC[tid]); 5512315SN/A 5524172Ssaidi@eecs.umich.edu thread[tid]->inSyscall = false; 5534172Ssaidi@eecs.umich.edu assert(!thread[tid]->trapPending); 5542332SN/A 5552332SN/A commitStatus[tid] = ROBSquashing; 5567823Ssteve.reinhardt@amd.com cpu->activityThisCycle(); 5574172Ssaidi@eecs.umich.edu 5584172Ssaidi@eecs.umich.edu xcSquash[tid] = false; 5592732SN/A 5602315SN/A ++squashCounter; 5612315SN/A} 5622315SN/A 5632315SN/Atemplate <class Impl> 5648733Sgeoffrey.blake@arm.comvoid 5658733Sgeoffrey.blake@arm.comDefaultCommit<Impl>::tick() 5668733Sgeoffrey.blake@arm.com{ 5678733Sgeoffrey.blake@arm.com wroteToTimeBuffer = false; 5688733Sgeoffrey.blake@arm.com _nextStatus = Inactive; 5692315SN/A 5708733Sgeoffrey.blake@arm.com if (switchPending && rob->isEmpty() && !iewStage->hasStoresToWB()) { 5712315SN/A cpu->signalSwitched(); 5722354SN/A return; 5738733Sgeoffrey.blake@arm.com } 5748733Sgeoffrey.blake@arm.com 5758733Sgeoffrey.blake@arm.com list<unsigned>::iterator threads = (*activeThreads).begin(); 5768733Sgeoffrey.blake@arm.com 5778733Sgeoffrey.blake@arm.com // Check if any of the threads are done squashing. Change the 5789382SAli.Saidi@ARM.com // status if they are done. 5799382SAli.Saidi@ARM.com while (threads != (*activeThreads).end()) { 5808733Sgeoffrey.blake@arm.com unsigned tid = *threads++; 5812354SN/A 5823126Sktlim@umich.edu if (commitStatus[tid] == ROBSquashing) { 5839382SAli.Saidi@ARM.com 5848733Sgeoffrey.blake@arm.com if (rob->isDoneSquashing(tid)) { 5858733Sgeoffrey.blake@arm.com commitStatus[tid] = Running; 5868733Sgeoffrey.blake@arm.com --squashCounter; 5872356SN/A } else { 5888733Sgeoffrey.blake@arm.com DPRINTF(Commit,"[tid:%u]: Still Squashing, cannot commit any" 5892354SN/A "insts this cycle.\n", tid); 5903126Sktlim@umich.edu } 5912315SN/A } 5922315SN/A } 5938733Sgeoffrey.blake@arm.com 5942315SN/A commit(); 5958733Sgeoffrey.blake@arm.com 5968733Sgeoffrey.blake@arm.com markCompletedInsts(); 5972732SN/A 5988733Sgeoffrey.blake@arm.com threads = (*activeThreads).begin(); 5998733Sgeoffrey.blake@arm.com 6008733Sgeoffrey.blake@arm.com while (threads != (*activeThreads).end()) { 6018733Sgeoffrey.blake@arm.com unsigned tid = *threads++; 6029913Ssteve.reinhardt@amd.com 6039913Ssteve.reinhardt@amd.com if (!rob->isEmpty(tid) && rob->readHeadInst(tid)->readyToCommit()) { 6048733Sgeoffrey.blake@arm.com // The ROB has more instructions it can commit. Its next status 6059913Ssteve.reinhardt@amd.com // will be active. 6069913Ssteve.reinhardt@amd.com _nextStatus = Active; 6078733Sgeoffrey.blake@arm.com 6089913Ssteve.reinhardt@amd.com DynInstPtr inst = rob->readHeadInst(tid); 6099920Syasuko.eckert@amd.com 6109920Syasuko.eckert@amd.com DPRINTF(Commit,"[tid:%i]: Instruction [sn:%lli] PC %#x is head of" 6119920Syasuko.eckert@amd.com " ROB and ready to commit\n", 6129913Ssteve.reinhardt@amd.com tid, inst->seqNum, inst->readPC()); 6139918Ssteve.reinhardt@amd.com 6148733Sgeoffrey.blake@arm.com } else if (!rob->isEmpty(tid)) { 6159913Ssteve.reinhardt@amd.com DynInstPtr inst = rob->readHeadInst(tid); 6168733Sgeoffrey.blake@arm.com 6178733Sgeoffrey.blake@arm.com DPRINTF(Commit,"[tid:%i]: Can't commit, Instruction [sn:%lli] PC " 6188733Sgeoffrey.blake@arm.com "%#x is head of ROB and not ready\n", 6198733Sgeoffrey.blake@arm.com tid, inst->seqNum, inst->readPC()); 6208733Sgeoffrey.blake@arm.com } 6218733Sgeoffrey.blake@arm.com 6228733Sgeoffrey.blake@arm.com DPRINTF(Commit, "[tid:%i]: ROB has %d insts & %d free entries.\n", 6239913Ssteve.reinhardt@amd.com tid, rob->countInsts(tid), rob->numFreeEntries(tid)); 6249913Ssteve.reinhardt@amd.com } 6258733Sgeoffrey.blake@arm.com 6269913Ssteve.reinhardt@amd.com 6279913Ssteve.reinhardt@amd.com if (wroteToTimeBuffer) { 6288733Sgeoffrey.blake@arm.com DPRINTF(Activity, "Activity This Cycle.\n"); 6299913Ssteve.reinhardt@amd.com cpu->activityThisCycle(); 6309920Syasuko.eckert@amd.com } 6319920Syasuko.eckert@amd.com 6329920Syasuko.eckert@amd.com updateStatus(); 6339913Ssteve.reinhardt@amd.com} 6348733Sgeoffrey.blake@arm.com 6359918Ssteve.reinhardt@amd.comtemplate <class Impl> 6369913Ssteve.reinhardt@amd.comvoid 6379913Ssteve.reinhardt@amd.comDefaultCommit<Impl>::commit() 6389913Ssteve.reinhardt@amd.com{ 6392732SN/A 6402732SN/A ////////////////////////////////////// 6412732SN/A // Check for interrupts 6428733Sgeoffrey.blake@arm.com ////////////////////////////////////// 6432732SN/A 6448733Sgeoffrey.blake@arm.com#if FULL_SYSTEM 6452732SN/A // Process interrupts if interrupts are enabled, not in PAL mode, 6462732SN/A // and no other traps or external squashes are currently pending. 6478733Sgeoffrey.blake@arm.com // @todo: Allow other threads to handle interrupts. 6482732SN/A if (cpu->checkInterrupts && 6498733Sgeoffrey.blake@arm.com cpu->check_interrupts() && 6508733Sgeoffrey.blake@arm.com !cpu->inPalMode(readPC()) && 6512732SN/A !trapSquash[0] && 6522732SN/A !xcSquash[0]) { 6532732SN/A // Tell fetch that there is an interrupt pending. This will 6542732SN/A // make fetch wait until it sees a non PAL-mode PC, at which 6552732SN/A // point it stops fetching instructions. 6562732SN/A toIEW->commitInfo[0].interruptPending = true; 6572732SN/A 6588733Sgeoffrey.blake@arm.com // Wait until the ROB is empty and all stores have drained in 6592732SN/A // order to enter the interrupt. 6608733Sgeoffrey.blake@arm.com if (rob->isEmpty() && !iewStage->hasStoresToWB()) { 6612315SN/A // Not sure which thread should be the one to interrupt. For now 6622315SN/A // always do thread 0. 6632315SN/A assert(!thread[0]->inSyscall); 6642315SN/A thread[0]->inSyscall = true; 6652315SN/A 6662315SN/A // CPU will handle implementation of the interrupt. 6672315SN/A cpu->processInterrupts(); 6682315SN/A 6692315SN/A // Now squash or record that I need to squash this cycle. 6702315SN/A commitStatus[0] = TrapPending; 6712315SN/A 6722315SN/A // Exit state update mode to avoid accidental updating. 6738733Sgeoffrey.blake@arm.com thread[0]->inSyscall = false; 6742315SN/A 6758733Sgeoffrey.blake@arm.com // Generate trap squash event. 6762315SN/A generateTrapEvent(0); 6772315SN/A 6782315SN/A toIEW->commitInfo[0].clearInterrupt = true; 6792315SN/A 6802315SN/A DPRINTF(Commit, "Interrupt detected.\n"); 6812315SN/A } else { 6822315SN/A DPRINTF(Commit, "Interrupt pending, waiting for ROB to empty.\n"); 6832315SN/A } 6842315SN/A } 6852315SN/A#endif // FULL_SYSTEM 6862315SN/A 687 //////////////////////////////////// 688 // Check for any possible squashes, handle them first 689 //////////////////////////////////// 690 691 list<unsigned>::iterator threads = (*activeThreads).begin(); 692 693 while (threads != (*activeThreads).end()) { 694 unsigned tid = *threads++; 695 696 if (fromFetch->fetchFault && commitStatus[0] != TrapPending) { 697 // Record the fault. Wait until it's empty in the ROB. 698 // Then handle the trap. Ignore it if there's already a 699 // trap pending as fetch will be redirected. 700 fetchFault = fromFetch->fetchFault; 701 fetchFaultTick = curTick + fetchTrapLatency; 702 commitStatus[0] = FetchTrapPending; 703 DPRINTF(Commit, "Fault from fetch recorded. Will trap if the " 704 "ROB empties without squashing the fault.\n"); 705 fetchTrapWait = 0; 706 } 707 708 // Fetch may tell commit to clear the trap if it's been squashed. 709 if (fromFetch->clearFetchFault) { 710 DPRINTF(Commit, "Received clear fetch fault signal\n"); 711 fetchTrapWait = 0; 712 if (commitStatus[0] == FetchTrapPending) { 713 DPRINTF(Commit, "Clearing fault from fetch\n"); 714 commitStatus[0] = Running; 715 } 716 } 717 718 // Not sure which one takes priority. I think if we have 719 // both, that's a bad sign. 720 if (trapSquash[tid] == true) { 721 assert(!xcSquash[tid]); 722 squashFromTrap(tid); 723 } else if (xcSquash[tid] == true) { 724 squashFromXC(tid); 725 } 726 727 // Squashed sequence number must be older than youngest valid 728 // instruction in the ROB. This prevents squashes from younger 729 // instructions overriding squashes from older instructions. 730 if (fromIEW->squash[tid] && 731 commitStatus[tid] != TrapPending && 732 fromIEW->squashedSeqNum[tid] <= youngestSeqNum[tid]) { 733 734 DPRINTF(Commit, "[tid:%i]: Squashing due to PC %#x [sn:%i]\n", 735 tid, 736 fromIEW->mispredPC[tid], 737 fromIEW->squashedSeqNum[tid]); 738 739 DPRINTF(Commit, "[tid:%i]: Redirecting to PC %#x\n", 740 tid, 741 fromIEW->nextPC[tid]); 742 743 commitStatus[tid] = ROBSquashing; 744 745 ++squashCounter; 746 747 // If we want to include the squashing instruction in the squash, 748 // then use one older sequence number. 749 InstSeqNum squashed_inst = fromIEW->squashedSeqNum[tid]; 750 751 if (fromIEW->includeSquashInst[tid] == true) 752 squashed_inst--; 753 754 // All younger instructions will be squashed. Set the sequence 755 // number as the youngest instruction in the ROB. 756 youngestSeqNum[tid] = squashed_inst; 757 758 rob->squash(squashed_inst, tid); 759 changedROBNumEntries[tid] = true; 760 761 toIEW->commitInfo[tid].doneSeqNum = squashed_inst; 762 763 toIEW->commitInfo[tid].squash = true; 764 765 // Send back the rob squashing signal so other stages know that 766 // the ROB is in the process of squashing. 767 toIEW->commitInfo[tid].robSquashing = true; 768 769 toIEW->commitInfo[tid].branchMispredict = 770 fromIEW->branchMispredict[tid]; 771 772 toIEW->commitInfo[tid].branchTaken = 773 fromIEW->branchTaken[tid]; 774 775 toIEW->commitInfo[tid].nextPC = fromIEW->nextPC[tid]; 776 777 toIEW->commitInfo[tid].mispredPC = fromIEW->mispredPC[tid]; 778 779 if (toIEW->commitInfo[tid].branchMispredict) { 780 ++branchMispredicts; 781 } 782 } 783 784 } 785 786 setNextStatus(); 787 788 if (squashCounter != numThreads) { 789 // If we're not currently squashing, then get instructions. 790 getInsts(); 791 792 // Try to commit any instructions. 793 commitInsts(); 794 } 795 796 //Check for any activity 797 threads = (*activeThreads).begin(); 798 799 while (threads != (*activeThreads).end()) { 800 unsigned tid = *threads++; 801 802 if (changedROBNumEntries[tid]) { 803 toIEW->commitInfo[tid].usedROB = true; 804 toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid); 805 806 if (rob->isEmpty(tid)) { 807 toIEW->commitInfo[tid].emptyROB = true; 808 } 809 810 wroteToTimeBuffer = true; 811 changedROBNumEntries[tid] = false; 812 } 813 } 814} 815 816template <class Impl> 817void 818DefaultCommit<Impl>::commitInsts() 819{ 820 //////////////////////////////////// 821 // Handle commit 822 // Note that commit will be handled prior to putting new 823 // instructions in the ROB so that the ROB only tries to commit 824 // instructions it has in this current cycle, and not instructions 825 // it is writing in during this cycle. Can't commit and squash 826 // things at the same time... 827 //////////////////////////////////// 828 829 DPRINTF(Commit, "Trying to commit instructions in the ROB.\n"); 830 831 unsigned num_committed = 0; 832 833 DynInstPtr head_inst; 834 835 // Commit as many instructions as possible until the commit bandwidth 836 // limit is reached, or it becomes impossible to commit any more. 837 while (num_committed < commitWidth) { 838 int commit_thread = getCommittingThread(); 839 840 if (commit_thread == -1 || !rob->isHeadReady(commit_thread)) 841 break; 842 843 head_inst = rob->readHeadInst(commit_thread); 844 845 int tid = head_inst->threadNumber; 846 847 assert(tid == commit_thread); 848 849 DPRINTF(Commit, "Trying to commit head instruction, [sn:%i] [tid:%i]\n", 850 head_inst->seqNum, tid); 851 852 // If the head instruction is squashed, it is ready to retire 853 // (be removed from the ROB) at any time. 854 if (head_inst->isSquashed()) { 855 856 DPRINTF(Commit, "Retiring squashed instruction from " 857 "ROB.\n"); 858 859 rob->retireHead(commit_thread); 860 861 ++commitSquashedInsts; 862 863 // Record that the number of ROB entries has changed. 864 changedROBNumEntries[tid] = true; 865 } else { 866 PC[tid] = head_inst->readPC(); 867 nextPC[tid] = head_inst->readNextPC(); 868 869 // Increment the total number of non-speculative instructions 870 // executed. 871 // Hack for now: it really shouldn't happen until after the 872 // commit is deemed to be successful, but this count is needed 873 // for syscalls. 874 thread[tid]->funcExeInst++; 875 876 // Try to commit the head instruction. 877 bool commit_success = commitHead(head_inst, num_committed); 878 879 if (commit_success) { 880 ++num_committed; 881 882 changedROBNumEntries[tid] = true; 883 884 // Set the doneSeqNum to the youngest committed instruction. 885 toIEW->commitInfo[tid].doneSeqNum = head_inst->seqNum; 886 887 ++commitCommittedInsts; 888 889 // To match the old model, don't count nops and instruction 890 // prefetches towards the total commit count. 891 if (!head_inst->isNop() && !head_inst->isInstPrefetch()) { 892 cpu->instDone(tid); 893 } 894 895 PC[tid] = nextPC[tid]; 896 nextPC[tid] = nextPC[tid] + sizeof(TheISA::MachInst); 897#if FULL_SYSTEM 898 int count = 0; 899 Addr oldpc; 900 do { 901 // Debug statement. Checks to make sure we're not 902 // currently updating state while handling PC events. 903 if (count == 0) 904 assert(!thread[tid]->inSyscall && 905 !thread[tid]->trapPending); 906 oldpc = PC[tid]; 907 cpu->system->pcEventQueue.service( 908 thread[tid]->getXCProxy()); 909 count++; 910 } while (oldpc != PC[tid]); 911 if (count > 1) { 912 DPRINTF(Commit, "PC skip function event, stopping commit\n"); 913 break; 914 } 915#endif 916 } else { 917 DPRINTF(Commit, "Unable to commit head instruction PC:%#x " 918 "[tid:%i] [sn:%i].\n", 919 head_inst->readPC(), tid ,head_inst->seqNum); 920 break; 921 } 922 } 923 } 924 925 DPRINTF(CommitRate, "%i\n", num_committed); 926 numCommittedDist.sample(num_committed); 927 928 if (num_committed == commitWidth) { 929 commitEligible[0]++; 930 } 931} 932 933template <class Impl> 934bool 935DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num) 936{ 937 assert(head_inst); 938 939 int tid = head_inst->threadNumber; 940 941 // If the instruction is not executed yet, then it will need extra 942 // handling. Signal backwards that it should be executed. 943 if (!head_inst->isExecuted()) { 944 // Keep this number correct. We have not yet actually executed 945 // and committed this instruction. 946 thread[tid]->funcExeInst--; 947 948 head_inst->reachedCommit = true; 949 950 if (head_inst->isNonSpeculative() || 951 head_inst->isMemBarrier() || 952 head_inst->isWriteBarrier()) { 953 954 DPRINTF(Commit, "Encountered a barrier or non-speculative " 955 "instruction [sn:%lli] at the head of the ROB, PC %#x.\n", 956 head_inst->seqNum, head_inst->readPC()); 957 958#if !FULL_SYSTEM 959 // Hack to make sure syscalls/memory barriers/quiesces 960 // aren't executed until all stores write back their data. 961 // This direct communication shouldn't be used for 962 // anything other than this. 963 if (inst_num > 0 || iewStage->hasStoresToWB()) 964#else 965 if ((head_inst->isMemBarrier() || head_inst->isWriteBarrier() || 966 head_inst->isQuiesce()) && 967 iewStage->hasStoresToWB()) 968#endif 969 { 970 DPRINTF(Commit, "Waiting for all stores to writeback.\n"); 971 return false; 972 } 973 974 toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum; 975 976 // Change the instruction so it won't try to commit again until 977 // it is executed. 978 head_inst->clearCanCommit(); 979 980 ++commitNonSpecStalls; 981 982 return false; 983 } else if (head_inst->isLoad()) { 984 DPRINTF(Commit, "[sn:%lli]: Uncached load, PC %#x.\n", 985 head_inst->seqNum, head_inst->readPC()); 986 987 // Send back the non-speculative instruction's sequence 988 // number. Tell the lsq to re-execute the load. 989 toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum; 990 toIEW->commitInfo[tid].uncached = true; 991 toIEW->commitInfo[tid].uncachedLoad = head_inst; 992 993 head_inst->clearCanCommit(); 994 995 return false; 996 } else { 997 panic("Trying to commit un-executed instruction " 998 "of unknown type!\n"); 999 } 1000 } 1001 1002 if (head_inst->isThreadSync()) { 1003 // Not handled for now. 1004 panic("Thread sync instructions are not handled yet.\n"); 1005 } 1006 1007 // Stores mark themselves as completed. 1008 if (!head_inst->isStore()) { 1009 head_inst->setCompleted(); 1010 } 1011 1012 // Use checker prior to updating anything due to traps or PC 1013 // based events. 1014 if (cpu->checker) { 1015 cpu->checker->tick(head_inst); 1016 } 1017 1018 // Check if the instruction caused a fault. If so, trap. 1019 Fault inst_fault = head_inst->getFault(); 1020 1021 if (inst_fault != NoFault) { 1022 head_inst->setCompleted(); 1023#if FULL_SYSTEM 1024 DPRINTF(Commit, "Inst [sn:%lli] PC %#x has a fault\n", 1025 head_inst->seqNum, head_inst->readPC()); 1026 1027 if (iewStage->hasStoresToWB() || inst_num > 0) { 1028 DPRINTF(Commit, "Stores outstanding, fault must wait.\n"); 1029 return false; 1030 } 1031 1032 if (cpu->checker && head_inst->isStore()) { 1033 cpu->checker->tick(head_inst); 1034 } 1035 1036 assert(!thread[tid]->inSyscall); 1037 1038 // Mark that we're in state update mode so that the trap's 1039 // execution doesn't generate extra squashes. 1040 thread[tid]->inSyscall = true; 1041 1042 // DTB will sometimes need the machine instruction for when 1043 // faults happen. So we will set it here, prior to the DTB 1044 // possibly needing it for its fault. 1045 thread[tid]->setInst( 1046 static_cast<TheISA::MachInst>(head_inst->staticInst->machInst)); 1047 1048 // Execute the trap. Although it's slightly unrealistic in 1049 // terms of timing (as it doesn't wait for the full timing of 1050 // the trap event to complete before updating state), it's 1051 // needed to update the state as soon as possible. This 1052 // prevents external agents from changing any specific state 1053 // that the trap need. 1054 cpu->trap(inst_fault, tid); 1055 1056 // Exit state update mode to avoid accidental updating. 1057 thread[tid]->inSyscall = false; 1058 1059 commitStatus[tid] = TrapPending; 1060 1061 // Generate trap squash event. 1062 generateTrapEvent(tid); 1063 1064 return false; 1065#else // !FULL_SYSTEM 1066 panic("fault (%d) detected @ PC %08p", inst_fault, 1067 head_inst->PC); 1068#endif // FULL_SYSTEM 1069 } 1070 1071 updateComInstStats(head_inst); 1072 1073 if (head_inst->traceData) { 1074 head_inst->traceData->setFetchSeq(head_inst->seqNum); 1075 head_inst->traceData->setCPSeq(thread[tid]->numInst); 1076 head_inst->traceData->finalize(); 1077 head_inst->traceData = NULL; 1078 } 1079 1080 // Update the commit rename map 1081 for (int i = 0; i < head_inst->numDestRegs(); i++) { 1082 renameMap[tid]->setEntry(head_inst->destRegIdx(i), 1083 head_inst->renamedDestRegIdx(i)); 1084 } 1085 1086 // Finally clear the head ROB entry. 1087 rob->retireHead(tid); 1088 1089 // Return true to indicate that we have committed an instruction. 1090 return true; 1091} 1092 1093template <class Impl> 1094void 1095DefaultCommit<Impl>::getInsts() 1096{ 1097 // Read any renamed instructions and place them into the ROB. 1098 int insts_to_process = min((int)renameWidth, fromRename->size); 1099 1100 for (int inst_num = 0; inst_num < insts_to_process; ++inst_num) 1101 { 1102 DynInstPtr inst = fromRename->insts[inst_num]; 1103 int tid = inst->threadNumber; 1104 1105 if (!inst->isSquashed() && 1106 commitStatus[tid] != ROBSquashing) { 1107 changedROBNumEntries[tid] = true; 1108 1109 DPRINTF(Commit, "Inserting PC %#x [sn:%i] [tid:%i] into ROB.\n", 1110 inst->readPC(), inst->seqNum, tid); 1111 1112 rob->insertInst(inst); 1113 1114 assert(rob->getThreadEntries(tid) <= rob->getMaxEntries(tid)); 1115 1116 youngestSeqNum[tid] = inst->seqNum; 1117 } else { 1118 DPRINTF(Commit, "Instruction PC %#x [sn:%i] [tid:%i] was " 1119 "squashed, skipping.\n", 1120 inst->readPC(), inst->seqNum, tid); 1121 } 1122 } 1123} 1124 1125template <class Impl> 1126void 1127DefaultCommit<Impl>::markCompletedInsts() 1128{ 1129 // Grab completed insts out of the IEW instruction queue, and mark 1130 // instructions completed within the ROB. 1131 for (int inst_num = 0; 1132 inst_num < fromIEW->size && fromIEW->insts[inst_num]; 1133 ++inst_num) 1134 { 1135 if (!fromIEW->insts[inst_num]->isSquashed()) { 1136 DPRINTF(Commit, "[tid:%i]: Marking PC %#x, [sn:%lli] ready " 1137 "within ROB.\n", 1138 fromIEW->insts[inst_num]->threadNumber, 1139 fromIEW->insts[inst_num]->readPC(), 1140 fromIEW->insts[inst_num]->seqNum); 1141 1142 // Mark the instruction as ready to commit. 1143 fromIEW->insts[inst_num]->setCanCommit(); 1144 } 1145 } 1146} 1147 1148template <class Impl> 1149bool 1150DefaultCommit<Impl>::robDoneSquashing() 1151{ 1152 list<unsigned>::iterator threads = (*activeThreads).begin(); 1153 1154 while (threads != (*activeThreads).end()) { 1155 unsigned tid = *threads++; 1156 1157 if (!rob->isDoneSquashing(tid)) 1158 return false; 1159 } 1160 1161 return true; 1162} 1163 1164template <class Impl> 1165void 1166DefaultCommit<Impl>::updateComInstStats(DynInstPtr &inst) 1167{ 1168 unsigned thread = inst->threadNumber; 1169 1170 // 1171 // Pick off the software prefetches 1172 // 1173#ifdef TARGET_ALPHA 1174 if (inst->isDataPrefetch()) { 1175 statComSwp[thread]++; 1176 } else { 1177 statComInst[thread]++; 1178 } 1179#else 1180 statComInst[thread]++; 1181#endif 1182 1183 // 1184 // Control Instructions 1185 // 1186 if (inst->isControl()) 1187 statComBranches[thread]++; 1188 1189 // 1190 // Memory references 1191 // 1192 if (inst->isMemRef()) { 1193 statComRefs[thread]++; 1194 1195 if (inst->isLoad()) { 1196 statComLoads[thread]++; 1197 } 1198 } 1199 1200 if (inst->isMemBarrier()) { 1201 statComMembars[thread]++; 1202 } 1203} 1204 1205//////////////////////////////////////// 1206// // 1207// SMT COMMIT POLICY MAINTAINED HERE // 1208// // 1209//////////////////////////////////////// 1210template <class Impl> 1211int 1212DefaultCommit<Impl>::getCommittingThread() 1213{ 1214 if (numThreads > 1) { 1215 switch (commitPolicy) { 1216 1217 case Aggressive: 1218 //If Policy is Aggressive, commit will call 1219 //this function multiple times per 1220 //cycle 1221 return oldestReady(); 1222 1223 case RoundRobin: 1224 return roundRobin(); 1225 1226 case OldestReady: 1227 return oldestReady(); 1228 1229 default: 1230 return -1; 1231 } 1232 } else { 1233 int tid = (*activeThreads).front(); 1234 1235 if (commitStatus[tid] == Running || 1236 commitStatus[tid] == Idle || 1237 commitStatus[tid] == FetchTrapPending) { 1238 return tid; 1239 } else { 1240 return -1; 1241 } 1242 } 1243} 1244 1245template<class Impl> 1246int 1247DefaultCommit<Impl>::roundRobin() 1248{ 1249 list<unsigned>::iterator pri_iter = priority_list.begin(); 1250 list<unsigned>::iterator end = priority_list.end(); 1251 1252 while (pri_iter != end) { 1253 unsigned tid = *pri_iter; 1254 1255 if (commitStatus[tid] == Running || 1256 commitStatus[tid] == Idle) { 1257 1258 if (rob->isHeadReady(tid)) { 1259 priority_list.erase(pri_iter); 1260 priority_list.push_back(tid); 1261 1262 return tid; 1263 } 1264 } 1265 1266 pri_iter++; 1267 } 1268 1269 return -1; 1270} 1271 1272template<class Impl> 1273int 1274DefaultCommit<Impl>::oldestReady() 1275{ 1276 unsigned oldest = 0; 1277 bool first = true; 1278 1279 list<unsigned>::iterator threads = (*activeThreads).begin(); 1280 1281 while (threads != (*activeThreads).end()) { 1282 unsigned tid = *threads++; 1283 1284 if (!rob->isEmpty(tid) && 1285 (commitStatus[tid] == Running || 1286 commitStatus[tid] == Idle || 1287 commitStatus[tid] == FetchTrapPending)) { 1288 1289 if (rob->isHeadReady(tid)) { 1290 1291 DynInstPtr head_inst = rob->readHeadInst(tid); 1292 1293 if (first) { 1294 oldest = tid; 1295 first = false; 1296 } else if (head_inst->seqNum < oldest) { 1297 oldest = tid; 1298 } 1299 } 1300 } 1301 } 1302 1303 if (!first) { 1304 return oldest; 1305 } else { 1306 return -1; 1307 } 1308} 1309