inst_queue_impl.hh revision 4762:c94e103c83ad
111988Sandreas.sandberg@arm.com/* 28839Sandreas.hansson@arm.com * Copyright (c) 2004-2006 The Regents of The University of Michigan 38839Sandreas.hansson@arm.com * All rights reserved. 48839Sandreas.hansson@arm.com * 58839Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without 68839Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions are 78839Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright 88839Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer; 98839Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright 108839Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the 118839Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution; 128839Sandreas.hansson@arm.com * neither the name of the copyright holders nor the names of its 133101Sstever@eecs.umich.edu * contributors may be used to endorse or promote products derived from 148579Ssteve.reinhardt@amd.com * this software without specific prior written permission. 153101Sstever@eecs.umich.edu * 163101Sstever@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 173101Sstever@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 183101Sstever@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 193101Sstever@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 203101Sstever@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 213101Sstever@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 223101Sstever@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 233101Sstever@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 243101Sstever@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 253101Sstever@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 263101Sstever@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 273101Sstever@eecs.umich.edu * 283101Sstever@eecs.umich.edu * Authors: Kevin Lim 293101Sstever@eecs.umich.edu * Korey Sewell 303101Sstever@eecs.umich.edu */ 313101Sstever@eecs.umich.edu 323101Sstever@eecs.umich.edu#include <limits> 333101Sstever@eecs.umich.edu#include <vector> 343101Sstever@eecs.umich.edu 353101Sstever@eecs.umich.edu#include "cpu/o3/fu_pool.hh" 363101Sstever@eecs.umich.edu#include "cpu/o3/inst_queue.hh" 373101Sstever@eecs.umich.edu#include "enums/OpClass.hh" 383101Sstever@eecs.umich.edu#include "sim/core.hh" 393101Sstever@eecs.umich.edu 403101Sstever@eecs.umich.edutemplate <class Impl> 413101Sstever@eecs.umich.eduInstructionQueue<Impl>::FUCompletion::FUCompletion(DynInstPtr &_inst, 427778Sgblack@eecs.umich.edu int fu_idx, 438839Sandreas.hansson@arm.com InstructionQueue<Impl> *iq_ptr) 443101Sstever@eecs.umich.edu : Event(&mainEventQueue, Stat_Event_Pri), 453101Sstever@eecs.umich.edu inst(_inst), fuIdx(fu_idx), iqPtr(iq_ptr), freeFU(false) 463101Sstever@eecs.umich.edu{ 473101Sstever@eecs.umich.edu this->setFlags(Event::AutoDelete); 483101Sstever@eecs.umich.edu} 493101Sstever@eecs.umich.edu 503101Sstever@eecs.umich.edutemplate <class Impl> 513101Sstever@eecs.umich.eduvoid 523101Sstever@eecs.umich.eduInstructionQueue<Impl>::FUCompletion::process() 533101Sstever@eecs.umich.edu{ 543101Sstever@eecs.umich.edu iqPtr->processFUCompletion(inst, freeFU ? fuIdx : -1); 553101Sstever@eecs.umich.edu inst = NULL; 563101Sstever@eecs.umich.edu} 573101Sstever@eecs.umich.edu 583101Sstever@eecs.umich.edu 593101Sstever@eecs.umich.edutemplate <class Impl> 603101Sstever@eecs.umich.educonst char * 613101Sstever@eecs.umich.eduInstructionQueue<Impl>::FUCompletion::description() 623885Sbinkertn@umich.edu{ 633885Sbinkertn@umich.edu return "Functional unit completion event"; 644762Snate@binkert.org} 653885Sbinkertn@umich.edu 663885Sbinkertn@umich.edutemplate <class Impl> 677528Ssteve.reinhardt@amd.comInstructionQueue<Impl>::InstructionQueue(O3CPU *cpu_ptr, IEW *iew_ptr, 683885Sbinkertn@umich.edu Params *params) 694380Sbinkertn@umich.edu : cpu(cpu_ptr), 704167Sbinkertn@umich.edu iewStage(iew_ptr), 713102Sstever@eecs.umich.edu fuPool(params->fuPool), 723101Sstever@eecs.umich.edu numEntries(params->numIQEntries), 734762Snate@binkert.org totalWidth(params->issueWidth), 744762Snate@binkert.org numPhysIntRegs(params->numPhysIntRegs), 754762Snate@binkert.org numPhysFloatRegs(params->numPhysFloatRegs), 764762Snate@binkert.org commitToIEWDelay(params->commitToIEWDelay) 774762Snate@binkert.org{ 784762Snate@binkert.org assert(fuPool); 794762Snate@binkert.org 804762Snate@binkert.org switchedOut = false; 814762Snate@binkert.org 825033Smilesck@eecs.umich.edu numThreads = params->numberOfThreads; 835033Smilesck@eecs.umich.edu 845033Smilesck@eecs.umich.edu // Set the number of physical registers as the number of int + float 855033Smilesck@eecs.umich.edu numPhysRegs = numPhysIntRegs + numPhysFloatRegs; 865033Smilesck@eecs.umich.edu 875033Smilesck@eecs.umich.edu //Create an entry for each physical register within the 885033Smilesck@eecs.umich.edu //dependency graph. 895033Smilesck@eecs.umich.edu dependGraph.resize(numPhysRegs); 905033Smilesck@eecs.umich.edu 915033Smilesck@eecs.umich.edu // Resize the register scoreboard. 923101Sstever@eecs.umich.edu regScoreboard.resize(numPhysRegs); 933101Sstever@eecs.umich.edu 943101Sstever@eecs.umich.edu //Initialize Mem Dependence Units 955033Smilesck@eecs.umich.edu for (int i = 0; i < numThreads; i++) { 9610267SGeoffrey.Blake@arm.com memDepUnit[i].init(params,i); 978596Ssteve.reinhardt@amd.com memDepUnit[i].setIQ(this); 988596Ssteve.reinhardt@amd.com } 998596Ssteve.reinhardt@amd.com 1008596Ssteve.reinhardt@amd.com resetState(); 1017673Snate@binkert.org 1027673Snate@binkert.org std::string policy = params->smtIQPolicy; 1037673Snate@binkert.org 1047673Snate@binkert.org //Convert string to lowercase 10511988Sandreas.sandberg@arm.com std::transform(policy.begin(), policy.end(), policy.begin(), 10611988Sandreas.sandberg@arm.com (int(*)(int)) tolower); 10711988Sandreas.sandberg@arm.com 10811988Sandreas.sandberg@arm.com //Figure out resource sharing policy 1093101Sstever@eecs.umich.edu if (policy == "dynamic") { 1103101Sstever@eecs.umich.edu iqPolicy = Dynamic; 1113101Sstever@eecs.umich.edu 1123101Sstever@eecs.umich.edu //Set Max Entries to Total ROB Capacity 1133101Sstever@eecs.umich.edu for (int i = 0; i < numThreads; i++) { 11410380SAndrew.Bardsley@arm.com maxEntries[i] = numEntries; 11510380SAndrew.Bardsley@arm.com } 11610380SAndrew.Bardsley@arm.com 11710380SAndrew.Bardsley@arm.com } else if (policy == "partitioned") { 11810380SAndrew.Bardsley@arm.com iqPolicy = Partitioned; 11910380SAndrew.Bardsley@arm.com 12010458Sandreas.hansson@arm.com //@todo:make work if part_amt doesnt divide evenly. 12110458Sandreas.hansson@arm.com int part_amt = numEntries / numThreads; 12210458Sandreas.hansson@arm.com 12310458Sandreas.hansson@arm.com //Divide ROB up evenly 12410458Sandreas.hansson@arm.com for (int i = 0; i < numThreads; i++) { 12510458Sandreas.hansson@arm.com maxEntries[i] = part_amt; 12610458Sandreas.hansson@arm.com } 12710458Sandreas.hansson@arm.com 12810458Sandreas.hansson@arm.com DPRINTF(IQ, "IQ sharing policy set to Partitioned:" 12910458Sandreas.hansson@arm.com "%i entries per thread.\n",part_amt); 13010458Sandreas.hansson@arm.com } else if (policy == "threshold") { 13110458Sandreas.hansson@arm.com iqPolicy = Threshold; 1323101Sstever@eecs.umich.edu 1333101Sstever@eecs.umich.edu double threshold = (double)params->smtIQThreshold / 100; 1343101Sstever@eecs.umich.edu 1353101Sstever@eecs.umich.edu int thresholdIQ = (int)((double)threshold * numEntries); 1363101Sstever@eecs.umich.edu 13710267SGeoffrey.Blake@arm.com //Divide up by threshold amount 13810267SGeoffrey.Blake@arm.com for (int i = 0; i < numThreads; i++) { 13910267SGeoffrey.Blake@arm.com maxEntries[i] = thresholdIQ; 14010267SGeoffrey.Blake@arm.com } 1413101Sstever@eecs.umich.edu 1423101Sstever@eecs.umich.edu DPRINTF(IQ, "IQ sharing policy set to Threshold:" 1433101Sstever@eecs.umich.edu "%i entries per thread.\n",thresholdIQ); 1443101Sstever@eecs.umich.edu } else { 1453101Sstever@eecs.umich.edu assert(0 && "Invalid IQ Sharing Policy.Options Are:{Dynamic," 1463101Sstever@eecs.umich.edu "Partitioned, Threshold}"); 1473101Sstever@eecs.umich.edu } 1483101Sstever@eecs.umich.edu} 1493101Sstever@eecs.umich.edu 1503101Sstever@eecs.umich.edutemplate <class Impl> 1513101Sstever@eecs.umich.eduInstructionQueue<Impl>::~InstructionQueue() 1523101Sstever@eecs.umich.edu{ 1533101Sstever@eecs.umich.edu dependGraph.reset(); 1543101Sstever@eecs.umich.edu#ifdef DEBUG 1553101Sstever@eecs.umich.edu cprintf("Nodes traversed: %i, removed: %i\n", 1563101Sstever@eecs.umich.edu dependGraph.nodesTraversed, dependGraph.nodesRemoved); 1573101Sstever@eecs.umich.edu#endif 1583101Sstever@eecs.umich.edu} 1593101Sstever@eecs.umich.edu 1603101Sstever@eecs.umich.edutemplate <class Impl> 1613101Sstever@eecs.umich.edustd::string 1623101Sstever@eecs.umich.eduInstructionQueue<Impl>::name() const 1633101Sstever@eecs.umich.edu{ 1643101Sstever@eecs.umich.edu return cpu->name() + ".iq"; 1653101Sstever@eecs.umich.edu} 1663101Sstever@eecs.umich.edu 1673101Sstever@eecs.umich.edutemplate <class Impl> 1683101Sstever@eecs.umich.eduvoid 1693101Sstever@eecs.umich.eduInstructionQueue<Impl>::regStats() 1703101Sstever@eecs.umich.edu{ 1713101Sstever@eecs.umich.edu using namespace Stats; 1723101Sstever@eecs.umich.edu iqInstsAdded 1733101Sstever@eecs.umich.edu .name(name() + ".iqInstsAdded") 1743101Sstever@eecs.umich.edu .desc("Number of instructions added to the IQ (excludes non-spec)") 1753101Sstever@eecs.umich.edu .prereq(iqInstsAdded); 1765033Smilesck@eecs.umich.edu 1776656Snate@binkert.org iqNonSpecInstsAdded 1785033Smilesck@eecs.umich.edu .name(name() + ".iqNonSpecInstsAdded") 1795033Smilesck@eecs.umich.edu .desc("Number of non-speculative instructions added to the IQ") 1805033Smilesck@eecs.umich.edu .prereq(iqNonSpecInstsAdded); 1813101Sstever@eecs.umich.edu 1823101Sstever@eecs.umich.edu iqInstsIssued 1833101Sstever@eecs.umich.edu .name(name() + ".iqInstsIssued") 18410267SGeoffrey.Blake@arm.com .desc("Number of instructions issued") 18510267SGeoffrey.Blake@arm.com .prereq(iqInstsIssued); 18610267SGeoffrey.Blake@arm.com 18710267SGeoffrey.Blake@arm.com iqIntInstsIssued 18810267SGeoffrey.Blake@arm.com .name(name() + ".iqIntInstsIssued") 18910267SGeoffrey.Blake@arm.com .desc("Number of integer instructions issued") 19010267SGeoffrey.Blake@arm.com .prereq(iqIntInstsIssued); 19110267SGeoffrey.Blake@arm.com 19210267SGeoffrey.Blake@arm.com iqFloatInstsIssued 19310267SGeoffrey.Blake@arm.com .name(name() + ".iqFloatInstsIssued") 19410267SGeoffrey.Blake@arm.com .desc("Number of float instructions issued") 19510267SGeoffrey.Blake@arm.com .prereq(iqFloatInstsIssued); 19610267SGeoffrey.Blake@arm.com 1973101Sstever@eecs.umich.edu iqBranchInstsIssued 1983101Sstever@eecs.umich.edu .name(name() + ".iqBranchInstsIssued") 1993101Sstever@eecs.umich.edu .desc("Number of branch instructions issued") 2003101Sstever@eecs.umich.edu .prereq(iqBranchInstsIssued); 2013101Sstever@eecs.umich.edu 2023101Sstever@eecs.umich.edu iqMemInstsIssued 2033101Sstever@eecs.umich.edu .name(name() + ".iqMemInstsIssued") 2043101Sstever@eecs.umich.edu .desc("Number of memory instructions issued") 2053101Sstever@eecs.umich.edu .prereq(iqMemInstsIssued); 2063101Sstever@eecs.umich.edu 2073102Sstever@eecs.umich.edu iqMiscInstsIssued 2083101Sstever@eecs.umich.edu .name(name() + ".iqMiscInstsIssued") 2093101Sstever@eecs.umich.edu .desc("Number of miscellaneous instructions issued") 2103101Sstever@eecs.umich.edu .prereq(iqMiscInstsIssued); 21110267SGeoffrey.Blake@arm.com 21210267SGeoffrey.Blake@arm.com iqSquashedInstsIssued 21310267SGeoffrey.Blake@arm.com .name(name() + ".iqSquashedInstsIssued") 21410267SGeoffrey.Blake@arm.com .desc("Number of squashed instructions issued") 21510267SGeoffrey.Blake@arm.com .prereq(iqSquashedInstsIssued); 21610267SGeoffrey.Blake@arm.com 21710267SGeoffrey.Blake@arm.com iqSquashedInstsExamined 2187673Snate@binkert.org .name(name() + ".iqSquashedInstsExamined") 2198607Sgblack@eecs.umich.edu .desc("Number of squashed instructions iterated over during squash;" 2207673Snate@binkert.org " mainly for profiling") 2213101Sstever@eecs.umich.edu .prereq(iqSquashedInstsExamined); 22211988Sandreas.sandberg@arm.com 22311988Sandreas.sandberg@arm.com iqSquashedOperandsExamined 22411988Sandreas.sandberg@arm.com .name(name() + ".iqSquashedOperandsExamined") 2257673Snate@binkert.org .desc("Number of squashed operands that are examined and possibly " 2267673Snate@binkert.org "removed from graph") 2273101Sstever@eecs.umich.edu .prereq(iqSquashedOperandsExamined); 2283101Sstever@eecs.umich.edu 2293101Sstever@eecs.umich.edu iqSquashedNonSpecRemoved 2303101Sstever@eecs.umich.edu .name(name() + ".iqSquashedNonSpecRemoved") 2313101Sstever@eecs.umich.edu .desc("Number of squashed non-spec instructions that were removed") 2323101Sstever@eecs.umich.edu .prereq(iqSquashedNonSpecRemoved); 2335033Smilesck@eecs.umich.edu/* 2345475Snate@binkert.org queueResDist 2355475Snate@binkert.org .init(Num_OpClasses, 0, 99, 2) 2365475Snate@binkert.org .name(name() + ".IQ:residence:") 2375475Snate@binkert.org .desc("cycles from dispatch to issue") 23810380SAndrew.Bardsley@arm.com .flags(total | pdf | cdf ) 23910380SAndrew.Bardsley@arm.com ; 24010380SAndrew.Bardsley@arm.com for (int i = 0; i < Num_OpClasses; ++i) { 2413101Sstever@eecs.umich.edu queueResDist.subname(i, opClassStrings[i]); 2423101Sstever@eecs.umich.edu } 2433101Sstever@eecs.umich.edu*/ 2444762Snate@binkert.org numIssuedDist 2454762Snate@binkert.org .init(0,totalWidth,1) 2464762Snate@binkert.org .name(name() + ".ISSUE:issued_per_cycle") 2473101Sstever@eecs.umich.edu .desc("Number of insts issued each cycle") 24812050Snikos.nikoleris@arm.com .flags(pdf) 24912050Snikos.nikoleris@arm.com ; 25012050Snikos.nikoleris@arm.com/* 2518459SAli.Saidi@ARM.com dist_unissued 2528459SAli.Saidi@ARM.com .init(Num_OpClasses+2) 25312050Snikos.nikoleris@arm.com .name(name() + ".ISSUE:unissued_cause") 2543101Sstever@eecs.umich.edu .desc("Reason ready instruction not issued") 2557528Ssteve.reinhardt@amd.com .flags(pdf | dist) 2567528Ssteve.reinhardt@amd.com ; 2577528Ssteve.reinhardt@amd.com for (int i=0; i < (Num_OpClasses + 2); ++i) { 2587528Ssteve.reinhardt@amd.com dist_unissued.subname(i, unissued_names[i]); 2597528Ssteve.reinhardt@amd.com } 2607528Ssteve.reinhardt@amd.com*/ 2613101Sstever@eecs.umich.edu statIssuedInstType 2627528Ssteve.reinhardt@amd.com .init(numThreads,Enums::Num_OpClass) 2637528Ssteve.reinhardt@amd.com .name(name() + ".ISSUE:FU_type") 2647528Ssteve.reinhardt@amd.com .desc("Type of FU issued") 2657528Ssteve.reinhardt@amd.com .flags(total | pdf | dist) 2667528Ssteve.reinhardt@amd.com ; 2677528Ssteve.reinhardt@amd.com statIssuedInstType.ysubnames(Enums::OpClassStrings); 2687528Ssteve.reinhardt@amd.com 2697528Ssteve.reinhardt@amd.com // 2707528Ssteve.reinhardt@amd.com // How long did instructions for a particular FU type wait prior to issue 2717528Ssteve.reinhardt@amd.com // 2728321Ssteve.reinhardt@amd.com/* 2738321Ssteve.reinhardt@amd.com issueDelayDist 2747528Ssteve.reinhardt@amd.com .init(Num_OpClasses,0,99,2) 2757528Ssteve.reinhardt@amd.com .name(name() + ".ISSUE:") 2767528Ssteve.reinhardt@amd.com .desc("cycles from operands ready to issue") 2777528Ssteve.reinhardt@amd.com .flags(pdf | cdf) 2787528Ssteve.reinhardt@amd.com ; 2797528Ssteve.reinhardt@amd.com 2807528Ssteve.reinhardt@amd.com for (int i=0; i<Num_OpClasses; ++i) { 2817528Ssteve.reinhardt@amd.com std::stringstream subname; 2827528Ssteve.reinhardt@amd.com subname << opClassStrings[i] << "_delay"; 2837528Ssteve.reinhardt@amd.com issueDelayDist.subname(i, subname.str()); 2847528Ssteve.reinhardt@amd.com } 2857528Ssteve.reinhardt@amd.com*/ 2867528Ssteve.reinhardt@amd.com issueRate 2873101Sstever@eecs.umich.edu .name(name() + ".ISSUE:rate") 2888664SAli.Saidi@ARM.com .desc("Inst issue rate") 2898664SAli.Saidi@ARM.com .flags(total) 2908664SAli.Saidi@ARM.com ; 2918664SAli.Saidi@ARM.com issueRate = iqInstsIssued / cpu->numCycles; 2928664SAli.Saidi@ARM.com 2938664SAli.Saidi@ARM.com statFuBusy 2949953Sgeoffrey.blake@arm.com .init(Num_OpClasses) 2959953Sgeoffrey.blake@arm.com .name(name() + ".ISSUE:fu_full") 2969953Sgeoffrey.blake@arm.com .desc("attempts to use FU when none available") 2979953Sgeoffrey.blake@arm.com .flags(pdf | dist) 2989953Sgeoffrey.blake@arm.com ; 2999953Sgeoffrey.blake@arm.com for (int i=0; i < Num_OpClasses; ++i) { 3009953Sgeoffrey.blake@arm.com statFuBusy.subname(i, Enums::OpClassStrings[i]); 3019953Sgeoffrey.blake@arm.com } 3029953Sgeoffrey.blake@arm.com 3039953Sgeoffrey.blake@arm.com fuBusy 3049953Sgeoffrey.blake@arm.com .init(numThreads) 3059953Sgeoffrey.blake@arm.com .name(name() + ".ISSUE:fu_busy_cnt") 3069953Sgeoffrey.blake@arm.com .desc("FU busy when requested") 30710267SGeoffrey.Blake@arm.com .flags(total) 30810267SGeoffrey.Blake@arm.com ; 30910267SGeoffrey.Blake@arm.com 31010267SGeoffrey.Blake@arm.com fuBusyRate 31110267SGeoffrey.Blake@arm.com .name(name() + ".ISSUE:fu_busy_rate") 31210267SGeoffrey.Blake@arm.com .desc("FU busy rate (busy events/executed inst)") 31310267SGeoffrey.Blake@arm.com .flags(total) 31410267SGeoffrey.Blake@arm.com ; 31510267SGeoffrey.Blake@arm.com fuBusyRate = fuBusy / iqInstsIssued; 31610267SGeoffrey.Blake@arm.com 31710267SGeoffrey.Blake@arm.com for ( int i=0; i < numThreads; i++) { 31810267SGeoffrey.Blake@arm.com // Tell mem dependence unit to reg stats as well. 31910267SGeoffrey.Blake@arm.com memDepUnit[i].regStats(); 32010267SGeoffrey.Blake@arm.com } 32110267SGeoffrey.Blake@arm.com} 32210267SGeoffrey.Blake@arm.com 32310267SGeoffrey.Blake@arm.comtemplate <class Impl> 32410267SGeoffrey.Blake@arm.comvoid 32510267SGeoffrey.Blake@arm.comInstructionQueue<Impl>::resetState() 32610267SGeoffrey.Blake@arm.com{ 3273101Sstever@eecs.umich.edu //Initialize thread IQ counts 3283101Sstever@eecs.umich.edu for (int i = 0; i <numThreads; i++) { 3293101Sstever@eecs.umich.edu count[i] = 0; 3303101Sstever@eecs.umich.edu instList[i].clear(); 3313101Sstever@eecs.umich.edu } 3323101Sstever@eecs.umich.edu 3333101Sstever@eecs.umich.edu // Initialize the number of free IQ entries. 33410364SGeoffrey.Blake@arm.com freeEntries = numEntries; 33510364SGeoffrey.Blake@arm.com 33610364SGeoffrey.Blake@arm.com // Note that in actuality, the registers corresponding to the logical 33710364SGeoffrey.Blake@arm.com // registers start off as ready. However this doesn't matter for the 3383101Sstever@eecs.umich.edu // IQ as the instruction should have been correctly told if those 3394762Snate@binkert.org // registers are ready in rename. Thus it can all be initialized as 3404762Snate@binkert.org // unready. 3414762Snate@binkert.org for (int i = 0; i < numPhysRegs; ++i) { 3424762Snate@binkert.org regScoreboard[i] = false; 3437528Ssteve.reinhardt@amd.com } 3444762Snate@binkert.org 3454762Snate@binkert.org for (int i = 0; i < numThreads; ++i) { 3464762Snate@binkert.org squashedSeqNum[i] = 0; 34710267SGeoffrey.Blake@arm.com } 34810267SGeoffrey.Blake@arm.com 34910267SGeoffrey.Blake@arm.com for (int i = 0; i < Num_OpClasses; ++i) { 35010267SGeoffrey.Blake@arm.com while (!readyInsts[i].empty()) 35110267SGeoffrey.Blake@arm.com readyInsts[i].pop(); 35210267SGeoffrey.Blake@arm.com queueOnList[i] = false; 35310267SGeoffrey.Blake@arm.com readyIt[i] = listOrder.end(); 35410267SGeoffrey.Blake@arm.com } 35510267SGeoffrey.Blake@arm.com nonSpecInsts.clear(); 35610267SGeoffrey.Blake@arm.com listOrder.clear(); 35710267SGeoffrey.Blake@arm.com} 35810267SGeoffrey.Blake@arm.com 35910267SGeoffrey.Blake@arm.comtemplate <class Impl> 36010267SGeoffrey.Blake@arm.comvoid 36110267SGeoffrey.Blake@arm.comInstructionQueue<Impl>::setActiveThreads(std::list<unsigned> *at_ptr) 36210267SGeoffrey.Blake@arm.com{ 36310267SGeoffrey.Blake@arm.com activeThreads = at_ptr; 36410267SGeoffrey.Blake@arm.com} 36510267SGeoffrey.Blake@arm.com 36610267SGeoffrey.Blake@arm.comtemplate <class Impl> 36710267SGeoffrey.Blake@arm.comvoid 36810267SGeoffrey.Blake@arm.comInstructionQueue<Impl>::setIssueToExecuteQueue(TimeBuffer<IssueStruct> *i2e_ptr) 36910267SGeoffrey.Blake@arm.com{ 37010267SGeoffrey.Blake@arm.com issueToExecuteQueue = i2e_ptr; 37110267SGeoffrey.Blake@arm.com} 37210267SGeoffrey.Blake@arm.com 37310364SGeoffrey.Blake@arm.comtemplate <class Impl> 37410364SGeoffrey.Blake@arm.comvoid 37510267SGeoffrey.Blake@arm.comInstructionQueue<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) 37610267SGeoffrey.Blake@arm.com{ 37710267SGeoffrey.Blake@arm.com timeBuffer = tb_ptr; 37810267SGeoffrey.Blake@arm.com 37910267SGeoffrey.Blake@arm.com fromCommit = timeBuffer->getWire(-commitToIEWDelay); 38010267SGeoffrey.Blake@arm.com} 3817673Snate@binkert.org 3827673Snate@binkert.orgtemplate <class Impl> 3837673Snate@binkert.orgvoid 3843101Sstever@eecs.umich.eduInstructionQueue<Impl>::switchOut() 38511988Sandreas.sandberg@arm.com{ 38611988Sandreas.sandberg@arm.com/* 38711988Sandreas.sandberg@arm.com if (!instList[0].empty() || (numEntries != freeEntries) || 38811988Sandreas.sandberg@arm.com !readyInsts[0].empty() || !nonSpecInsts.empty() || !listOrder.empty()) { 3897673Snate@binkert.org dumpInsts(); 3907673Snate@binkert.org// assert(0); 3913101Sstever@eecs.umich.edu } 3923101Sstever@eecs.umich.edu*/ 3933101Sstever@eecs.umich.edu resetState(); 3943101Sstever@eecs.umich.edu dependGraph.reset(); 3953101Sstever@eecs.umich.edu instsToExecute.clear(); 3963101Sstever@eecs.umich.edu switchedOut = true; 3973101Sstever@eecs.umich.edu for (int i = 0; i < numThreads; ++i) { 3983101Sstever@eecs.umich.edu memDepUnit[i].switchOut(); 3993101Sstever@eecs.umich.edu } 4003101Sstever@eecs.umich.edu} 4013101Sstever@eecs.umich.edu 4023101Sstever@eecs.umich.edutemplate <class Impl> 4033101Sstever@eecs.umich.eduvoid 4043101Sstever@eecs.umich.eduInstructionQueue<Impl>::takeOverFrom() 4053101Sstever@eecs.umich.edu{ 4065033Smilesck@eecs.umich.edu switchedOut = false; 4075033Smilesck@eecs.umich.edu} 4083101Sstever@eecs.umich.edu 4093101Sstever@eecs.umich.edutemplate <class Impl> 4103101Sstever@eecs.umich.eduint 4113101Sstever@eecs.umich.eduInstructionQueue<Impl>::entryAmount(int num_threads) 4123101Sstever@eecs.umich.edu{ 4133101Sstever@eecs.umich.edu if (iqPolicy == Partitioned) { 4143101Sstever@eecs.umich.edu return numEntries / num_threads; 4153101Sstever@eecs.umich.edu } else { 4163101Sstever@eecs.umich.edu return 0; 4173101Sstever@eecs.umich.edu } 4183101Sstever@eecs.umich.edu} 4193101Sstever@eecs.umich.edu 4203101Sstever@eecs.umich.edu 4213101Sstever@eecs.umich.edutemplate <class Impl> 4223101Sstever@eecs.umich.eduvoid 4233101Sstever@eecs.umich.eduInstructionQueue<Impl>::resetEntries() 4243101Sstever@eecs.umich.edu{ 4253101Sstever@eecs.umich.edu if (iqPolicy != Dynamic || numThreads > 1) { 4263101Sstever@eecs.umich.edu int active_threads = activeThreads->size(); 4273101Sstever@eecs.umich.edu 4283101Sstever@eecs.umich.edu std::list<unsigned>::iterator threads = activeThreads->begin(); 4293101Sstever@eecs.umich.edu std::list<unsigned>::iterator end = activeThreads->end(); 4303101Sstever@eecs.umich.edu 4313101Sstever@eecs.umich.edu while (threads != end) { 4323101Sstever@eecs.umich.edu unsigned tid = *threads++; 43310267SGeoffrey.Blake@arm.com 4347673Snate@binkert.org if (iqPolicy == Partitioned) { 4357673Snate@binkert.org maxEntries[tid] = numEntries / active_threads; 4367673Snate@binkert.org } else if(iqPolicy == Threshold && active_threads == 1) { 4377673Snate@binkert.org maxEntries[tid] = numEntries; 4387673Snate@binkert.org } 43910267SGeoffrey.Blake@arm.com } 44010267SGeoffrey.Blake@arm.com } 44110267SGeoffrey.Blake@arm.com} 44210267SGeoffrey.Blake@arm.com 44310458Sandreas.hansson@arm.comtemplate <class Impl> 44410458Sandreas.hansson@arm.comunsigned 44510458Sandreas.hansson@arm.comInstructionQueue<Impl>::numFreeEntries() 44610458Sandreas.hansson@arm.com{ 44710458Sandreas.hansson@arm.com return freeEntries; 4484762Snate@binkert.org} 4494762Snate@binkert.org 4503101Sstever@eecs.umich.edutemplate <class Impl> 4513101Sstever@eecs.umich.eduunsigned 4523101Sstever@eecs.umich.eduInstructionQueue<Impl>::numFreeEntries(unsigned tid) 4533101Sstever@eecs.umich.edu{ 4543101Sstever@eecs.umich.edu return maxEntries[tid] - count[tid]; 4553101Sstever@eecs.umich.edu} 4563101Sstever@eecs.umich.edu 4573101Sstever@eecs.umich.edu// Might want to do something more complex if it knows how many instructions 4583101Sstever@eecs.umich.edu// will be issued this cycle. 4593101Sstever@eecs.umich.edutemplate <class Impl> 4603101Sstever@eecs.umich.edubool 4613714Sstever@eecs.umich.eduInstructionQueue<Impl>::isFull() 4623714Sstever@eecs.umich.edu{ 4633714Sstever@eecs.umich.edu if (freeEntries == 0) { 4643714Sstever@eecs.umich.edu return(true); 4653714Sstever@eecs.umich.edu } else { 4663714Sstever@eecs.umich.edu return(false); 4673101Sstever@eecs.umich.edu } 4683101Sstever@eecs.umich.edu} 4693101Sstever@eecs.umich.edu 4703101Sstever@eecs.umich.edutemplate <class Impl> 4713101Sstever@eecs.umich.edubool 4723101Sstever@eecs.umich.eduInstructionQueue<Impl>::isFull(unsigned tid) 4733101Sstever@eecs.umich.edu{ 4743101Sstever@eecs.umich.edu if (numFreeEntries(tid) == 0) { 4753101Sstever@eecs.umich.edu return(true); 4763101Sstever@eecs.umich.edu } else { 4773101Sstever@eecs.umich.edu return(false); 4783101Sstever@eecs.umich.edu } 4793101Sstever@eecs.umich.edu} 4803101Sstever@eecs.umich.edu 4813101Sstever@eecs.umich.edutemplate <class Impl> 4823101Sstever@eecs.umich.edubool 4833101Sstever@eecs.umich.eduInstructionQueue<Impl>::hasReadyInsts() 4843101Sstever@eecs.umich.edu{ 4853101Sstever@eecs.umich.edu if (!listOrder.empty()) { 4863101Sstever@eecs.umich.edu return true; 4873101Sstever@eecs.umich.edu } 4883101Sstever@eecs.umich.edu 4893101Sstever@eecs.umich.edu for (int i = 0; i < Num_OpClasses; ++i) { 4903101Sstever@eecs.umich.edu if (!readyInsts[i].empty()) { 49110380SAndrew.Bardsley@arm.com return true; 49210380SAndrew.Bardsley@arm.com } 49310380SAndrew.Bardsley@arm.com } 49410458Sandreas.hansson@arm.com 49510458Sandreas.hansson@arm.com return false; 49610458Sandreas.hansson@arm.com} 49710458Sandreas.hansson@arm.com 49810458Sandreas.hansson@arm.comtemplate <class Impl> 49910458Sandreas.hansson@arm.comvoid 50010458Sandreas.hansson@arm.comInstructionQueue<Impl>::insert(DynInstPtr &new_inst) 50110458Sandreas.hansson@arm.com{ 50210458Sandreas.hansson@arm.com // Make sure the instruction is valid 50310458Sandreas.hansson@arm.com assert(new_inst); 50410458Sandreas.hansson@arm.com 50510458Sandreas.hansson@arm.com DPRINTF(IQ, "Adding instruction [sn:%lli] PC %#x to the IQ.\n", 50610458Sandreas.hansson@arm.com new_inst->seqNum, new_inst->readPC()); 5073101Sstever@eecs.umich.edu 5085033Smilesck@eecs.umich.edu assert(freeEntries != 0); 5093101Sstever@eecs.umich.edu 5103101Sstever@eecs.umich.edu instList[new_inst->threadNumber].push_back(new_inst); 5113101Sstever@eecs.umich.edu 5123101Sstever@eecs.umich.edu --freeEntries; 5133101Sstever@eecs.umich.edu 5143101Sstever@eecs.umich.edu new_inst->setInIQ(); 5153101Sstever@eecs.umich.edu 5163101Sstever@eecs.umich.edu // Look through its source registers (physical regs), and mark any 5173101Sstever@eecs.umich.edu // dependencies. 5183101Sstever@eecs.umich.edu addToDependents(new_inst); 5193101Sstever@eecs.umich.edu 5203101Sstever@eecs.umich.edu // Have this instruction set itself as the producer of its destination 5215822Ssaidi@eecs.umich.edu // register(s). 5225822Ssaidi@eecs.umich.edu addToProducers(new_inst); 5233101Sstever@eecs.umich.edu 5243101Sstever@eecs.umich.edu if (new_inst->isMemRef()) { 5253101Sstever@eecs.umich.edu memDepUnit[new_inst->threadNumber].insert(new_inst); 5263101Sstever@eecs.umich.edu } else { 5273101Sstever@eecs.umich.edu addIfReady(new_inst); 5283101Sstever@eecs.umich.edu } 5293101Sstever@eecs.umich.edu 5303101Sstever@eecs.umich.edu ++iqInstsAdded; 5313101Sstever@eecs.umich.edu 5323101Sstever@eecs.umich.edu count[new_inst->threadNumber]++; 5333101Sstever@eecs.umich.edu 5343101Sstever@eecs.umich.edu assert(freeEntries == (numEntries - countInsts())); 5353101Sstever@eecs.umich.edu} 53610267SGeoffrey.Blake@arm.com 5373101Sstever@eecs.umich.edutemplate <class Impl> 5383101Sstever@eecs.umich.eduvoid 5393101Sstever@eecs.umich.eduInstructionQueue<Impl>::insertNonSpec(DynInstPtr &new_inst) 5403101Sstever@eecs.umich.edu{ 5413101Sstever@eecs.umich.edu // @todo: Clean up this code; can do it by setting inst as unable 5423101Sstever@eecs.umich.edu // to issue, then calling normal insert on the inst. 5433101Sstever@eecs.umich.edu 5443101Sstever@eecs.umich.edu assert(new_inst); 5453102Sstever@eecs.umich.edu 5463714Sstever@eecs.umich.edu nonSpecInsts[new_inst->seqNum] = new_inst; 5473101Sstever@eecs.umich.edu 5483714Sstever@eecs.umich.edu DPRINTF(IQ, "Adding non-speculative instruction [sn:%lli] PC %#x " 5493714Sstever@eecs.umich.edu "to the IQ.\n", 5503714Sstever@eecs.umich.edu new_inst->seqNum, new_inst->readPC()); 5513101Sstever@eecs.umich.edu 5523101Sstever@eecs.umich.edu assert(freeEntries != 0); 55310267SGeoffrey.Blake@arm.com 55410267SGeoffrey.Blake@arm.com instList[new_inst->threadNumber].push_back(new_inst); 55510267SGeoffrey.Blake@arm.com 55610267SGeoffrey.Blake@arm.com --freeEntries; 5577673Snate@binkert.org 5587673Snate@binkert.org new_inst->setInIQ(); 5597673Snate@binkert.org 5607673Snate@binkert.org // Have this instruction set itself as the producer of its destination 5617673Snate@binkert.org // register(s). 5624762Snate@binkert.org addToProducers(new_inst); 5634762Snate@binkert.org 5644762Snate@binkert.org // If it's a memory instruction, add it to the memory dependency 5653101Sstever@eecs.umich.edu // unit. 5663101Sstever@eecs.umich.edu if (new_inst->isMemRef()) { 5673101Sstever@eecs.umich.edu memDepUnit[new_inst->threadNumber].insertNonSpec(new_inst); 5683101Sstever@eecs.umich.edu } 5693101Sstever@eecs.umich.edu 5703101Sstever@eecs.umich.edu ++iqNonSpecInstsAdded; 5713101Sstever@eecs.umich.edu 5723101Sstever@eecs.umich.edu count[new_inst->threadNumber]++; 5733101Sstever@eecs.umich.edu 5743101Sstever@eecs.umich.edu assert(freeEntries == (numEntries - countInsts())); 5753101Sstever@eecs.umich.edu} 5763101Sstever@eecs.umich.edu 5773101Sstever@eecs.umich.edutemplate <class Impl> 5783101Sstever@eecs.umich.eduvoid 5793101Sstever@eecs.umich.eduInstructionQueue<Impl>::insertBarrier(DynInstPtr &barr_inst) 5803101Sstever@eecs.umich.edu{ 5813101Sstever@eecs.umich.edu memDepUnit[barr_inst->threadNumber].insertBarrier(barr_inst); 5823101Sstever@eecs.umich.edu 5833101Sstever@eecs.umich.edu insertNonSpec(barr_inst); 5849184Sandreas.hansson@arm.com} 5859184Sandreas.hansson@arm.com 5869184Sandreas.hansson@arm.comtemplate <class Impl> 5879184Sandreas.hansson@arm.comtypename Impl::DynInstPtr 5889184Sandreas.hansson@arm.comInstructionQueue<Impl>::getInstToExecute() 5899184Sandreas.hansson@arm.com{ 59011802Sandreas.sandberg@arm.com assert(!instsToExecute.empty()); 5919184Sandreas.hansson@arm.com DynInstPtr inst = instsToExecute.front(); 5929184Sandreas.hansson@arm.com instsToExecute.pop_front(); 59310458Sandreas.hansson@arm.com return inst; 59410458Sandreas.hansson@arm.com} 59510458Sandreas.hansson@arm.com 59610458Sandreas.hansson@arm.comtemplate <class Impl> 59710458Sandreas.hansson@arm.comvoid 59810458Sandreas.hansson@arm.comInstructionQueue<Impl>::addToOrderList(OpClass op_class) 59910458Sandreas.hansson@arm.com{ 60010458Sandreas.hansson@arm.com assert(!readyInsts[op_class].empty()); 60110458Sandreas.hansson@arm.com 60210458Sandreas.hansson@arm.com ListOrderEntry queue_entry; 60310458Sandreas.hansson@arm.com 60410458Sandreas.hansson@arm.com queue_entry.queueType = op_class; 60510458Sandreas.hansson@arm.com 60610458Sandreas.hansson@arm.com queue_entry.oldestInst = readyInsts[op_class].top()->seqNum; 6073101Sstever@eecs.umich.edu 6084446Sbinkertn@umich.edu ListOrderIt list_it = listOrder.begin(); 60910668SGeoffrey.Blake@arm.com ListOrderIt list_end_it = listOrder.end(); 6103101Sstever@eecs.umich.edu 6115468Snate@binkert.org while (list_it != list_end_it) { 61210267SGeoffrey.Blake@arm.com if ((*list_it).oldestInst > queue_entry.oldestInst) { 6135468Snate@binkert.org break; 6145468Snate@binkert.org } 6155468Snate@binkert.org 6165468Snate@binkert.org list_it++; 6175468Snate@binkert.org } 61810267SGeoffrey.Blake@arm.com 61910267SGeoffrey.Blake@arm.com readyIt[op_class] = listOrder.insert(list_it, queue_entry); 62010267SGeoffrey.Blake@arm.com queueOnList[op_class] = true; 62110267SGeoffrey.Blake@arm.com} 6224762Snate@binkert.org 6234762Snate@binkert.orgtemplate <class Impl> 6244762Snate@binkert.orgvoid 62510380SAndrew.Bardsley@arm.comInstructionQueue<Impl>::moveToYoungerInst(ListOrderIt list_order_it) 62610380SAndrew.Bardsley@arm.com{ 62710380SAndrew.Bardsley@arm.com // Get iterator of next item on the list 62810458Sandreas.hansson@arm.com // Delete the original iterator 62910458Sandreas.hansson@arm.com // Determine if the next item is either the end of the list or younger 63010458Sandreas.hansson@arm.com // than the new instruction. If so, then add in a new iterator right here. 63110458Sandreas.hansson@arm.com // If not, then move along. 63210458Sandreas.hansson@arm.com ListOrderEntry queue_entry; 63310458Sandreas.hansson@arm.com OpClass op_class = (*list_order_it).queueType; 63410458Sandreas.hansson@arm.com ListOrderIt next_it = list_order_it; 63510458Sandreas.hansson@arm.com 6363101Sstever@eecs.umich.edu ++next_it; 6373101Sstever@eecs.umich.edu 63810267SGeoffrey.Blake@arm.com queue_entry.queueType = op_class; 6393101Sstever@eecs.umich.edu queue_entry.oldestInst = readyInsts[op_class].top()->seqNum; 6403101Sstever@eecs.umich.edu 6413101Sstever@eecs.umich.edu while (next_it != listOrder.end() && 6423101Sstever@eecs.umich.edu (*next_it).oldestInst < queue_entry.oldestInst) { 6433101Sstever@eecs.umich.edu ++next_it; 6443101Sstever@eecs.umich.edu } 6453102Sstever@eecs.umich.edu 6463101Sstever@eecs.umich.edu readyIt[op_class] = listOrder.insert(next_it, queue_entry); 6473101Sstever@eecs.umich.edu} 6483101Sstever@eecs.umich.edu 6494168Sbinkertn@umich.edutemplate <class Impl> 65010267SGeoffrey.Blake@arm.comvoid 6513101Sstever@eecs.umich.eduInstructionQueue<Impl>::processFUCompletion(DynInstPtr &inst, int fu_idx) 6523101Sstever@eecs.umich.edu{ 6533101Sstever@eecs.umich.edu DPRINTF(IQ, "Processing FU completion [sn:%lli]\n", inst->seqNum); 6543101Sstever@eecs.umich.edu // The CPU could have been sleeping until this op completed (*extremely* 6553101Sstever@eecs.umich.edu // long latency op). Wake it if it was. This may be overkill. 6563101Sstever@eecs.umich.edu if (isSwitchedOut()) { 6573102Sstever@eecs.umich.edu DPRINTF(IQ, "FU completion not processed, IQ is switched out [sn:%lli]\n", 6583101Sstever@eecs.umich.edu inst->seqNum); 6593101Sstever@eecs.umich.edu return; 6603101Sstever@eecs.umich.edu } 6613101Sstever@eecs.umich.edu 6623101Sstever@eecs.umich.edu iewStage->wakeCPU(); 6633101Sstever@eecs.umich.edu 6643101Sstever@eecs.umich.edu if (fu_idx > -1) 6653101Sstever@eecs.umich.edu fuPool->freeUnitNextCycle(fu_idx); 6663101Sstever@eecs.umich.edu 6673101Sstever@eecs.umich.edu // @todo: Ensure that these FU Completions happen at the beginning 6683101Sstever@eecs.umich.edu // of a cycle, otherwise they could add too many instructions to 66910317Smitch.hayenga@arm.com // the queue. 67010317Smitch.hayenga@arm.com issueToExecuteQueue->access(0)->size++; 67110317Smitch.hayenga@arm.com instsToExecute.push_back(inst); 67210317Smitch.hayenga@arm.com} 67310317Smitch.hayenga@arm.com 6743102Sstever@eecs.umich.edu// @todo: Figure out a better way to remove the squashed items from the 67510317Smitch.hayenga@arm.com// lists. Checking the top item of each list to see if it's squashed 67610317Smitch.hayenga@arm.com// wastes time and forces jumps. 67710317Smitch.hayenga@arm.comtemplate <class Impl> 67810317Smitch.hayenga@arm.comvoid 67910317Smitch.hayenga@arm.comInstructionQueue<Impl>::scheduleReadyInsts() 6803101Sstever@eecs.umich.edu{ 6813584Ssaidi@eecs.umich.edu DPRINTF(IQ, "Attempting to schedule ready instructions from " 6823584Ssaidi@eecs.umich.edu "the IQ.\n"); 6833584Ssaidi@eecs.umich.edu 6843584Ssaidi@eecs.umich.edu IssueStruct *i2e_info = issueToExecuteQueue->access(0); 6853584Ssaidi@eecs.umich.edu 68610267SGeoffrey.Blake@arm.com // Have iterator to head of the list 68710267SGeoffrey.Blake@arm.com // While I haven't exceeded bandwidth or reached the end of the list, 68810267SGeoffrey.Blake@arm.com // Try to get a FU that can do what this op needs. 68910267SGeoffrey.Blake@arm.com // If successful, change the oldestInst to the new top of the list, put 69010267SGeoffrey.Blake@arm.com // the queue in the proper place in the list. 69110267SGeoffrey.Blake@arm.com // Increment the iterator. 6923101Sstever@eecs.umich.edu // This will avoid trying to schedule a certain op class if there are no 6939232Sandreas.hansson@arm.com // FUs that handle it. 6949235Sandreas.hansson@arm.com ListOrderIt order_it = listOrder.begin(); 6953101Sstever@eecs.umich.edu ListOrderIt order_end_it = listOrder.end(); 6963101Sstever@eecs.umich.edu int total_issued = 0; 69710676Sandreas.hansson@arm.com 6989411Sandreas.hansson@arm.com while (total_issued < totalWidth && 69910676Sandreas.hansson@arm.com iewStage->canIssue() && 7009411Sandreas.hansson@arm.com order_it != order_end_it) { 7019411Sandreas.hansson@arm.com OpClass op_class = (*order_it).queueType; 7029411Sandreas.hansson@arm.com 7033101Sstever@eecs.umich.edu assert(!readyInsts[op_class].empty()); 7049411Sandreas.hansson@arm.com 7059411Sandreas.hansson@arm.com DynInstPtr issuing_inst = readyInsts[op_class].top(); 7069411Sandreas.hansson@arm.com 7073101Sstever@eecs.umich.edu assert(issuing_inst->seqNum == (*order_it).oldestInst); 7089232Sandreas.hansson@arm.com 7093101Sstever@eecs.umich.edu if (issuing_inst->isSquashed()) { 7109232Sandreas.hansson@arm.com readyInsts[op_class].pop(); 7113101Sstever@eecs.umich.edu 7123101Sstever@eecs.umich.edu if (!readyInsts[op_class].empty()) { 7133101Sstever@eecs.umich.edu moveToYoungerInst(order_it); 7149411Sandreas.hansson@arm.com } else { 7159411Sandreas.hansson@arm.com readyIt[op_class] = listOrder.end(); 7169411Sandreas.hansson@arm.com queueOnList[op_class] = false; 71710676Sandreas.hansson@arm.com } 71810676Sandreas.hansson@arm.com 7199411Sandreas.hansson@arm.com listOrder.erase(order_it++); 7209411Sandreas.hansson@arm.com 7219411Sandreas.hansson@arm.com ++iqSquashedInstsIssued; 7229411Sandreas.hansson@arm.com 7239411Sandreas.hansson@arm.com continue; 7243101Sstever@eecs.umich.edu } 7259232Sandreas.hansson@arm.com 7263101Sstever@eecs.umich.edu int idx = -2; 7273101Sstever@eecs.umich.edu int op_latency = 1; 7283101Sstever@eecs.umich.edu int tid = issuing_inst->threadNumber; 7293101Sstever@eecs.umich.edu 7309232Sandreas.hansson@arm.com if (op_class != No_OpClass) { 7313101Sstever@eecs.umich.edu idx = fuPool->getUnit(op_class); 7325219Ssaidi@eecs.umich.edu 7339232Sandreas.hansson@arm.com if (idx > -1) { 7349232Sandreas.hansson@arm.com op_latency = fuPool->getOpLatency(op_class); 7353101Sstever@eecs.umich.edu } 7369232Sandreas.hansson@arm.com } 7379232Sandreas.hansson@arm.com 7383101Sstever@eecs.umich.edu // If we have an instruction that doesn't require a FU, or a 7393101Sstever@eecs.umich.edu // valid FU, then schedule for execution. 7409232Sandreas.hansson@arm.com if (idx == -2 || idx != -1) { 7419232Sandreas.hansson@arm.com if (op_latency == 1) { 7423101Sstever@eecs.umich.edu i2e_info->size++; 7433101Sstever@eecs.umich.edu instsToExecute.push_back(issuing_inst); 7443101Sstever@eecs.umich.edu 7453101Sstever@eecs.umich.edu // Add the FU onto the list of FU's to be freed next 7469232Sandreas.hansson@arm.com // cycle if we used one. 7473101Sstever@eecs.umich.edu if (idx >= 0) 7483101Sstever@eecs.umich.edu fuPool->freeUnitNextCycle(idx); 74911620SMatthew.Poremba@amd.com } else { 75011620SMatthew.Poremba@amd.com int issue_latency = fuPool->getIssueLatency(op_class); 75111620SMatthew.Poremba@amd.com // Generate completion event for the FU 7529232Sandreas.hansson@arm.com FUCompletion *execution = new FUCompletion(issuing_inst, 7539232Sandreas.hansson@arm.com idx, this); 7549411Sandreas.hansson@arm.com 7559411Sandreas.hansson@arm.com execution->schedule(curTick + cpu->cycles(issue_latency - 1)); 7563101Sstever@eecs.umich.edu 7577673Snate@binkert.org // @todo: Enforce that issue_latency == 1 or op_latency 7587673Snate@binkert.org if (issue_latency > 1) { 7599232Sandreas.hansson@arm.com // If FU isn't pipelined, then it must be freed 7609235Sandreas.hansson@arm.com // upon the execution completing. 7617675Snate@binkert.org execution->setFreeFU(); 7627675Snate@binkert.org } else { 76311988Sandreas.sandberg@arm.com // Add the FU onto the list of FU's to be freed next cycle. 76411988Sandreas.sandberg@arm.com fuPool->freeUnitNextCycle(idx); 76511988Sandreas.sandberg@arm.com } 76611988Sandreas.sandberg@arm.com } 76711988Sandreas.sandberg@arm.com 76810458Sandreas.hansson@arm.com DPRINTF(IQ, "Thread %i: Issuing instruction PC %#x " 76910458Sandreas.hansson@arm.com "[sn:%lli]\n", 77010458Sandreas.hansson@arm.com tid, issuing_inst->readPC(), 77110458Sandreas.hansson@arm.com issuing_inst->seqNum); 77210458Sandreas.hansson@arm.com 77311620SMatthew.Poremba@amd.com readyInsts[op_class].pop(); 77411620SMatthew.Poremba@amd.com 77510458Sandreas.hansson@arm.com if (!readyInsts[op_class].empty()) { 77610458Sandreas.hansson@arm.com moveToYoungerInst(order_it); 77710458Sandreas.hansson@arm.com } else { 77810458Sandreas.hansson@arm.com readyIt[op_class] = listOrder.end(); 77910458Sandreas.hansson@arm.com queueOnList[op_class] = false; 78011620SMatthew.Poremba@amd.com } 78111620SMatthew.Poremba@amd.com 78211620SMatthew.Poremba@amd.com issuing_inst->setIssued(); 78311620SMatthew.Poremba@amd.com ++total_issued; 78411620SMatthew.Poremba@amd.com 78511620SMatthew.Poremba@amd.com if (!issuing_inst->isMemRef()) { 78611620SMatthew.Poremba@amd.com // Memory instructions can not be freed from the IQ until they 78711620SMatthew.Poremba@amd.com // complete. 78811620SMatthew.Poremba@amd.com ++freeEntries; 78911620SMatthew.Poremba@amd.com count[tid]--; 79010458Sandreas.hansson@arm.com issuing_inst->clearInIQ(); 79110458Sandreas.hansson@arm.com } else { 79210458Sandreas.hansson@arm.com memDepUnit[tid].issue(issuing_inst); 79311620SMatthew.Poremba@amd.com } 79411620SMatthew.Poremba@amd.com 79510458Sandreas.hansson@arm.com listOrder.erase(order_it++); 79610458Sandreas.hansson@arm.com statIssuedInstType[tid][op_class]++; 7974762Snate@binkert.org iewStage->incrWb(issuing_inst->seqNum); 79811991Sandreas.sandberg@arm.com } else { 79911802Sandreas.sandberg@arm.com statFuBusy[op_class]++; 8004762Snate@binkert.org fuBusy[tid]++; 8019411Sandreas.hansson@arm.com ++order_it; 80210676Sandreas.hansson@arm.com } 80310676Sandreas.hansson@arm.com } 8043101Sstever@eecs.umich.edu 8053101Sstever@eecs.umich.edu numIssuedDist.sample(total_issued); 8063101Sstever@eecs.umich.edu iqInstsIssued+= total_issued; 8073101Sstever@eecs.umich.edu 8083101Sstever@eecs.umich.edu // If we issued any instructions, tell the CPU we had activity. 8093101Sstever@eecs.umich.edu if (total_issued) { 81010267SGeoffrey.Blake@arm.com cpu->activityThisCycle(); 81110267SGeoffrey.Blake@arm.com } else { 8123101Sstever@eecs.umich.edu DPRINTF(IQ, "Not able to schedule any instructions.\n"); 8133101Sstever@eecs.umich.edu } 8143102Sstever@eecs.umich.edu} 8153101Sstever@eecs.umich.edu 8163101Sstever@eecs.umich.edutemplate <class Impl> 8173101Sstever@eecs.umich.eduvoid 81810267SGeoffrey.Blake@arm.comInstructionQueue<Impl>::scheduleNonSpec(const InstSeqNum &inst) 81910267SGeoffrey.Blake@arm.com{ 82010267SGeoffrey.Blake@arm.com DPRINTF(IQ, "Marking nonspeculative instruction [sn:%lli] as ready " 82110267SGeoffrey.Blake@arm.com "to execute.\n", inst); 8224762Snate@binkert.org 8234762Snate@binkert.org NonSpecMapIt inst_it = nonSpecInsts.find(inst); 8244762Snate@binkert.org 8253101Sstever@eecs.umich.edu assert(inst_it != nonSpecInsts.end()); 8263101Sstever@eecs.umich.edu 8273101Sstever@eecs.umich.edu unsigned tid = (*inst_it).second->threadNumber; 8288934SBrad.Beckmann@amd.com 8298934SBrad.Beckmann@amd.com (*inst_it).second->setAtCommit(); 8308934SBrad.Beckmann@amd.com 8318934SBrad.Beckmann@amd.com (*inst_it).second->setCanIssue(); 8328934SBrad.Beckmann@amd.com 8333101Sstever@eecs.umich.edu if (!(*inst_it).second->isMemRef()) { 8343101Sstever@eecs.umich.edu addIfReady((*inst_it).second); 8353101Sstever@eecs.umich.edu } else { 8363101Sstever@eecs.umich.edu memDepUnit[tid].nonSpecInstReady((*inst_it).second); 8373101Sstever@eecs.umich.edu } 83810380SAndrew.Bardsley@arm.com 83910380SAndrew.Bardsley@arm.com (*inst_it).second = NULL; 84010380SAndrew.Bardsley@arm.com 84110458Sandreas.hansson@arm.com nonSpecInsts.erase(inst_it); 84210458Sandreas.hansson@arm.com} 84310458Sandreas.hansson@arm.com 84410458Sandreas.hansson@arm.comtemplate <class Impl> 84510458Sandreas.hansson@arm.comvoid 84610458Sandreas.hansson@arm.comInstructionQueue<Impl>::commit(const InstSeqNum &inst, unsigned tid) 84710458Sandreas.hansson@arm.com{ 84810458Sandreas.hansson@arm.com DPRINTF(IQ, "[tid:%i]: Committing instructions older than [sn:%i]\n", 84910458Sandreas.hansson@arm.com tid,inst); 85010458Sandreas.hansson@arm.com 8513101Sstever@eecs.umich.edu ListIt iq_it = instList[tid].begin(); 8523101Sstever@eecs.umich.edu 8533101Sstever@eecs.umich.edu while (iq_it != instList[tid].end() && 8543101Sstever@eecs.umich.edu (*iq_it)->seqNum <= inst) { 8553101Sstever@eecs.umich.edu ++iq_it; 8563101Sstever@eecs.umich.edu instList[tid].pop_front(); 8573101Sstever@eecs.umich.edu } 8583101Sstever@eecs.umich.edu 8593101Sstever@eecs.umich.edu assert(freeEntries == (numEntries - countInsts())); 8603101Sstever@eecs.umich.edu} 8613101Sstever@eecs.umich.edu 8623101Sstever@eecs.umich.edutemplate <class Impl> 8634380Sbinkertn@umich.eduint 8644380Sbinkertn@umich.eduInstructionQueue<Impl>::wakeDependents(DynInstPtr &completed_inst) 8654380Sbinkertn@umich.edu{ 8663101Sstever@eecs.umich.edu int dependents = 0; 8674380Sbinkertn@umich.edu 8684380Sbinkertn@umich.edu DPRINTF(IQ, "Waking dependents of completed instruction.\n"); 8694380Sbinkertn@umich.edu 8703101Sstever@eecs.umich.edu assert(!completed_inst->isSquashed()); 8713101Sstever@eecs.umich.edu 8723101Sstever@eecs.umich.edu // Tell the memory dependence unit to wake any dependents on this 87310267SGeoffrey.Blake@arm.com // instruction if it is a memory instruction. Also complete the memory 87410267SGeoffrey.Blake@arm.com // instruction at this point since we know it executed without issues. 8757673Snate@binkert.org // @todo: Might want to rename "completeMemInst" to something that 8767673Snate@binkert.org // indicates that it won't need to be replayed, and call this 8777673Snate@binkert.org // earlier. Might not be a big deal. 8787673Snate@binkert.org if (completed_inst->isMemRef()) { 8797673Snate@binkert.org memDepUnit[completed_inst->threadNumber].wakeDependents(completed_inst); 8803101Sstever@eecs.umich.edu completeMemInst(completed_inst); 8813101Sstever@eecs.umich.edu } else if (completed_inst->isMemBarrier() || 8823101Sstever@eecs.umich.edu completed_inst->isWriteBarrier()) { 8833101Sstever@eecs.umich.edu memDepUnit[completed_inst->threadNumber].completeBarrier(completed_inst); 8843101Sstever@eecs.umich.edu } 8853101Sstever@eecs.umich.edu 8863101Sstever@eecs.umich.edu for (int dest_reg_idx = 0; 8873101Sstever@eecs.umich.edu dest_reg_idx < completed_inst->numDestRegs(); 8883101Sstever@eecs.umich.edu dest_reg_idx++) 8893101Sstever@eecs.umich.edu { 8903101Sstever@eecs.umich.edu PhysRegIndex dest_reg = 8913101Sstever@eecs.umich.edu completed_inst->renamedDestRegIdx(dest_reg_idx); 8923101Sstever@eecs.umich.edu 8939941SGeoffrey.Blake@arm.com // Special case of uniq or control registers. They are not 8943101Sstever@eecs.umich.edu // handled by the IQ and thus have no dependency graph entry. 8953101Sstever@eecs.umich.edu // @todo Figure out a cleaner way to handle this. 8963101Sstever@eecs.umich.edu if (dest_reg >= numPhysRegs) { 8973101Sstever@eecs.umich.edu continue; 89810267SGeoffrey.Blake@arm.com } 89910267SGeoffrey.Blake@arm.com 90010267SGeoffrey.Blake@arm.com DPRINTF(IQ, "Waking any dependents on register %i.\n", 90110267SGeoffrey.Blake@arm.com (int) dest_reg); 9023101Sstever@eecs.umich.edu 9033101Sstever@eecs.umich.edu //Go through the dependency chain, marking the registers as 9044380Sbinkertn@umich.edu //ready within the waiting instructions. 9053101Sstever@eecs.umich.edu DynInstPtr dep_inst = dependGraph.pop(dest_reg); 9063101Sstever@eecs.umich.edu 9074762Snate@binkert.org while (dep_inst) { 90811988Sandreas.sandberg@arm.com DPRINTF(IQ, "Waking up a dependent instruction, PC%#x.\n", 9094762Snate@binkert.org dep_inst->readPC()); 9104762Snate@binkert.org 91111228SAndrew.Bardsley@arm.com // Might want to give more information to the instruction 91211228SAndrew.Bardsley@arm.com // so that it knows which of its source registers is 91311228SAndrew.Bardsley@arm.com // ready. However that would mean that the dependency 9144380Sbinkertn@umich.edu // graph entries would need to hold the src_reg_idx. 9154380Sbinkertn@umich.edu dep_inst->markSrcRegReady(); 9163101Sstever@eecs.umich.edu 91710458Sandreas.hansson@arm.com addIfReady(dep_inst); 91810458Sandreas.hansson@arm.com 91910458Sandreas.hansson@arm.com dep_inst = dependGraph.pop(dest_reg); 92010458Sandreas.hansson@arm.com 92110458Sandreas.hansson@arm.com ++dependents; 9227777Sgblack@eecs.umich.edu } 9237777Sgblack@eecs.umich.edu 9247777Sgblack@eecs.umich.edu // Reset the head node now that all of its dependents have 9257777Sgblack@eecs.umich.edu // been woken up. 92610267SGeoffrey.Blake@arm.com assert(dependGraph.empty(dest_reg)); 92710267SGeoffrey.Blake@arm.com dependGraph.clearInst(dest_reg); 9287777Sgblack@eecs.umich.edu 9297777Sgblack@eecs.umich.edu // Mark the scoreboard as having that register ready. 9307777Sgblack@eecs.umich.edu regScoreboard[dest_reg] = true; 9317777Sgblack@eecs.umich.edu } 9327777Sgblack@eecs.umich.edu return dependents; 9337777Sgblack@eecs.umich.edu} 9347777Sgblack@eecs.umich.edu 9357777Sgblack@eecs.umich.edutemplate <class Impl> 9367777Sgblack@eecs.umich.eduvoid 9377777Sgblack@eecs.umich.eduInstructionQueue<Impl>::addReadyMemInst(DynInstPtr &ready_inst) 9387777Sgblack@eecs.umich.edu{ 9397777Sgblack@eecs.umich.edu OpClass op_class = ready_inst->opClass(); 9407777Sgblack@eecs.umich.edu 9417777Sgblack@eecs.umich.edu readyInsts[op_class].push(ready_inst); 9427777Sgblack@eecs.umich.edu 94310267SGeoffrey.Blake@arm.com // Will need to reorder the list if either a queue is not on the list, 94410267SGeoffrey.Blake@arm.com // or it has an older instruction than last time. 94510267SGeoffrey.Blake@arm.com if (!queueOnList[op_class]) { 94610267SGeoffrey.Blake@arm.com addToOrderList(op_class); 9478579Ssteve.reinhardt@amd.com } else if (readyInsts[op_class].top()->seqNum < 9488579Ssteve.reinhardt@amd.com (*readyIt[op_class]).oldestInst) { 9498579Ssteve.reinhardt@amd.com listOrder.erase(readyIt[op_class]); 9508579Ssteve.reinhardt@amd.com addToOrderList(op_class); 9518579Ssteve.reinhardt@amd.com } 9528579Ssteve.reinhardt@amd.com 9538579Ssteve.reinhardt@amd.com DPRINTF(IQ, "Instruction is ready to issue, putting it onto " 9548579Ssteve.reinhardt@amd.com "the ready list, PC %#x opclass:%i [sn:%lli].\n", 9558579Ssteve.reinhardt@amd.com ready_inst->readPC(), op_class, ready_inst->seqNum); 9568579Ssteve.reinhardt@amd.com} 9578579Ssteve.reinhardt@amd.com 9588579Ssteve.reinhardt@amd.comtemplate <class Impl> 9598579Ssteve.reinhardt@amd.comvoid 9608579Ssteve.reinhardt@amd.comInstructionQueue<Impl>::rescheduleMemInst(DynInstPtr &resched_inst) 9618579Ssteve.reinhardt@amd.com{ 9628579Ssteve.reinhardt@amd.com DPRINTF(IQ, "Rescheduling mem inst [sn:%lli]\n", resched_inst->seqNum); 9638579Ssteve.reinhardt@amd.com resched_inst->clearCanIssue(); 9648579Ssteve.reinhardt@amd.com memDepUnit[resched_inst->threadNumber].reschedule(resched_inst); 9657777Sgblack@eecs.umich.edu} 9667777Sgblack@eecs.umich.edu 9677798Sgblack@eecs.umich.edutemplate <class Impl> 9687777Sgblack@eecs.umich.eduvoid 9697777Sgblack@eecs.umich.eduInstructionQueue<Impl>::replayMemInst(DynInstPtr &replay_inst) 97011988Sandreas.sandberg@arm.com{ 9717777Sgblack@eecs.umich.edu memDepUnit[replay_inst->threadNumber].replay(replay_inst); 9727777Sgblack@eecs.umich.edu} 9737777Sgblack@eecs.umich.edu 9747777Sgblack@eecs.umich.edutemplate <class Impl> 9757777Sgblack@eecs.umich.eduvoid 9767777Sgblack@eecs.umich.eduInstructionQueue<Impl>::completeMemInst(DynInstPtr &completed_inst) 9777777Sgblack@eecs.umich.edu{ 97810267SGeoffrey.Blake@arm.com int tid = completed_inst->threadNumber; 97910267SGeoffrey.Blake@arm.com 9807777Sgblack@eecs.umich.edu DPRINTF(IQ, "Completing mem instruction PC:%#x [sn:%lli]\n", 9817777Sgblack@eecs.umich.edu completed_inst->readPC(), completed_inst->seqNum); 9827777Sgblack@eecs.umich.edu 9837777Sgblack@eecs.umich.edu ++freeEntries; 9847777Sgblack@eecs.umich.edu 9857777Sgblack@eecs.umich.edu completed_inst->memOpDone = true; 9867777Sgblack@eecs.umich.edu 9877777Sgblack@eecs.umich.edu memDepUnit[tid].completed(completed_inst); 9887777Sgblack@eecs.umich.edu count[tid]--; 9897777Sgblack@eecs.umich.edu} 9907777Sgblack@eecs.umich.edu 9917777Sgblack@eecs.umich.edutemplate <class Impl> 9927777Sgblack@eecs.umich.eduvoid 9937777Sgblack@eecs.umich.eduInstructionQueue<Impl>::violation(DynInstPtr &store, 9947777Sgblack@eecs.umich.edu DynInstPtr &faulting_load) 9957777Sgblack@eecs.umich.edu{ 9967777Sgblack@eecs.umich.edu memDepUnit[store->threadNumber].violation(store, faulting_load); 9977777Sgblack@eecs.umich.edu} 9987777Sgblack@eecs.umich.edu 9997777Sgblack@eecs.umich.edutemplate <class Impl> 10007777Sgblack@eecs.umich.eduvoid 10017777Sgblack@eecs.umich.eduInstructionQueue<Impl>::squash(unsigned tid) 10027777Sgblack@eecs.umich.edu{ 10037777Sgblack@eecs.umich.edu DPRINTF(IQ, "[tid:%i]: Starting to squash instructions in " 10047777Sgblack@eecs.umich.edu "the IQ.\n", tid); 10057777Sgblack@eecs.umich.edu 10067777Sgblack@eecs.umich.edu // Read instruction sequence number of last instruction out of the 10077777Sgblack@eecs.umich.edu // time buffer. 10087777Sgblack@eecs.umich.edu squashedSeqNum[tid] = fromCommit->commitInfo[tid].doneSeqNum; 10097777Sgblack@eecs.umich.edu 10107777Sgblack@eecs.umich.edu // Call doSquash if there are insts in the IQ 10117777Sgblack@eecs.umich.edu if (count[tid] > 0) { 10127777Sgblack@eecs.umich.edu doSquash(tid); 10137777Sgblack@eecs.umich.edu } 10147777Sgblack@eecs.umich.edu 10157777Sgblack@eecs.umich.edu // Also tell the memory dependence unit to squash. 10167777Sgblack@eecs.umich.edu memDepUnit[tid].squash(squashedSeqNum[tid], tid); 10177777Sgblack@eecs.umich.edu} 10187777Sgblack@eecs.umich.edu 10197777Sgblack@eecs.umich.edutemplate <class Impl> 10207777Sgblack@eecs.umich.eduvoid 102110267SGeoffrey.Blake@arm.comInstructionQueue<Impl>::doSquash(unsigned tid) 102210267SGeoffrey.Blake@arm.com{ 102310267SGeoffrey.Blake@arm.com // Start at the tail. 102410267SGeoffrey.Blake@arm.com ListIt squash_it = instList[tid].end(); 10258579Ssteve.reinhardt@amd.com --squash_it; 10268579Ssteve.reinhardt@amd.com 10278579Ssteve.reinhardt@amd.com DPRINTF(IQ, "[tid:%i]: Squashing until sequence number %i!\n", 10288579Ssteve.reinhardt@amd.com tid, squashedSeqNum[tid]); 10298579Ssteve.reinhardt@amd.com 10308579Ssteve.reinhardt@amd.com // Squash any instructions younger than the squashed sequence number 10318579Ssteve.reinhardt@amd.com // given. 10328579Ssteve.reinhardt@amd.com while (squash_it != instList[tid].end() && 10338579Ssteve.reinhardt@amd.com (*squash_it)->seqNum > squashedSeqNum[tid]) { 10348579Ssteve.reinhardt@amd.com 10358579Ssteve.reinhardt@amd.com DynInstPtr squashed_inst = (*squash_it); 10368579Ssteve.reinhardt@amd.com 10378579Ssteve.reinhardt@amd.com // Only handle the instruction if it actually is in the IQ and 10388579Ssteve.reinhardt@amd.com // hasn't already been squashed in the IQ. 10397777Sgblack@eecs.umich.edu if (squashed_inst->threadNumber != tid || 10407777Sgblack@eecs.umich.edu squashed_inst->isSquashedInIQ()) { 10417777Sgblack@eecs.umich.edu --squash_it; 10427777Sgblack@eecs.umich.edu continue; 10437777Sgblack@eecs.umich.edu } 10447777Sgblack@eecs.umich.edu 104511988Sandreas.sandberg@arm.com if (!squashed_inst->isIssued() || 10467777Sgblack@eecs.umich.edu (squashed_inst->isMemRef() && 10477777Sgblack@eecs.umich.edu !squashed_inst->memOpDone)) { 10487777Sgblack@eecs.umich.edu 10497777Sgblack@eecs.umich.edu DPRINTF(IQ, "[tid:%i]: Instruction [sn:%lli] PC %#x " 10507777Sgblack@eecs.umich.edu "squashed.\n", 10517777Sgblack@eecs.umich.edu tid, squashed_inst->seqNum, squashed_inst->readPC()); 105210267SGeoffrey.Blake@arm.com 105310267SGeoffrey.Blake@arm.com // Remove the instruction from the dependency list. 10547777Sgblack@eecs.umich.edu if (!squashed_inst->isNonSpeculative() && 10557777Sgblack@eecs.umich.edu !squashed_inst->isStoreConditional() && 10567777Sgblack@eecs.umich.edu !squashed_inst->isMemBarrier() && 10577777Sgblack@eecs.umich.edu !squashed_inst->isWriteBarrier()) { 10587777Sgblack@eecs.umich.edu 10597777Sgblack@eecs.umich.edu for (int src_reg_idx = 0; 10607777Sgblack@eecs.umich.edu src_reg_idx < squashed_inst->numSrcRegs(); 10617777Sgblack@eecs.umich.edu src_reg_idx++) 10627777Sgblack@eecs.umich.edu { 10637777Sgblack@eecs.umich.edu PhysRegIndex src_reg = 10647777Sgblack@eecs.umich.edu squashed_inst->renamedSrcRegIdx(src_reg_idx); 10657777Sgblack@eecs.umich.edu 10667777Sgblack@eecs.umich.edu // Only remove it from the dependency graph if it 10677777Sgblack@eecs.umich.edu // was placed there in the first place. 10687777Sgblack@eecs.umich.edu 10697777Sgblack@eecs.umich.edu // Instead of doing a linked list traversal, we 10707777Sgblack@eecs.umich.edu // can just remove these squashed instructions 10717777Sgblack@eecs.umich.edu // either at issue time, or when the register is 10727777Sgblack@eecs.umich.edu // overwritten. The only downside to this is it 10737777Sgblack@eecs.umich.edu // leaves more room for error. 10747777Sgblack@eecs.umich.edu 10757777Sgblack@eecs.umich.edu if (!squashed_inst->isReadySrcRegIdx(src_reg_idx) && 10767777Sgblack@eecs.umich.edu src_reg < numPhysRegs) { 10777777Sgblack@eecs.umich.edu dependGraph.remove(src_reg, squashed_inst); 10787777Sgblack@eecs.umich.edu } 10797777Sgblack@eecs.umich.edu 10807777Sgblack@eecs.umich.edu 10817777Sgblack@eecs.umich.edu ++iqSquashedOperandsExamined; 10827777Sgblack@eecs.umich.edu } 10837777Sgblack@eecs.umich.edu } else if (!squashed_inst->isStoreConditional() || 10847777Sgblack@eecs.umich.edu !squashed_inst->isCompleted()) { 10857777Sgblack@eecs.umich.edu NonSpecMapIt ns_inst_it = 10867777Sgblack@eecs.umich.edu nonSpecInsts.find(squashed_inst->seqNum); 10877777Sgblack@eecs.umich.edu assert(ns_inst_it != nonSpecInsts.end()); 10887777Sgblack@eecs.umich.edu if (ns_inst_it == nonSpecInsts.end()) { 10897777Sgblack@eecs.umich.edu assert(squashed_inst->getFault() != NoFault); 10907777Sgblack@eecs.umich.edu } else { 10917777Sgblack@eecs.umich.edu 10927777Sgblack@eecs.umich.edu (*ns_inst_it).second = NULL; 10937777Sgblack@eecs.umich.edu 10947777Sgblack@eecs.umich.edu nonSpecInsts.erase(ns_inst_it); 109510267SGeoffrey.Blake@arm.com 109610267SGeoffrey.Blake@arm.com ++iqSquashedNonSpecRemoved; 109710267SGeoffrey.Blake@arm.com } 109810267SGeoffrey.Blake@arm.com } 10998579Ssteve.reinhardt@amd.com 11008579Ssteve.reinhardt@amd.com // Might want to also clear out the head of the dependency graph. 11018579Ssteve.reinhardt@amd.com 11028579Ssteve.reinhardt@amd.com // Mark it as squashed within the IQ. 11038579Ssteve.reinhardt@amd.com squashed_inst->setSquashedInIQ(); 11048579Ssteve.reinhardt@amd.com 11058579Ssteve.reinhardt@amd.com // @todo: Remove this hack where several statuses are set so the 11068579Ssteve.reinhardt@amd.com // inst will flow through the rest of the pipeline. 11078579Ssteve.reinhardt@amd.com squashed_inst->setIssued(); 11088579Ssteve.reinhardt@amd.com squashed_inst->setCanCommit(); 11098579Ssteve.reinhardt@amd.com squashed_inst->clearInIQ(); 11108579Ssteve.reinhardt@amd.com 11118579Ssteve.reinhardt@amd.com //Update Thread IQ Count 11128579Ssteve.reinhardt@amd.com count[squashed_inst->threadNumber]--; 11137777Sgblack@eecs.umich.edu 11147777Sgblack@eecs.umich.edu ++freeEntries; 11157777Sgblack@eecs.umich.edu } 11167777Sgblack@eecs.umich.edu 11177777Sgblack@eecs.umich.edu instList[tid].erase(squash_it--); 11187777Sgblack@eecs.umich.edu ++iqSquashedInstsExamined; 111911988Sandreas.sandberg@arm.com } 11207777Sgblack@eecs.umich.edu} 11217777Sgblack@eecs.umich.edu 11223932Sbinkertn@umich.edutemplate <class Impl> 112310380SAndrew.Bardsley@arm.combool 11243932Sbinkertn@umich.eduInstructionQueue<Impl>::addToDependents(DynInstPtr &new_inst) 11253932Sbinkertn@umich.edu{ 11263932Sbinkertn@umich.edu // Loop through the instruction's source registers, adding 11273932Sbinkertn@umich.edu // them to the dependency list if they are not ready. 11283932Sbinkertn@umich.edu int8_t total_src_regs = new_inst->numSrcRegs(); 11293932Sbinkertn@umich.edu bool return_val = false; 11303932Sbinkertn@umich.edu 11313932Sbinkertn@umich.edu for (int src_reg_idx = 0; 11323932Sbinkertn@umich.edu src_reg_idx < total_src_regs; 11333932Sbinkertn@umich.edu src_reg_idx++) 11343932Sbinkertn@umich.edu { 11353885Sbinkertn@umich.edu // Only add it to the dependency graph if it's not ready. 11363932Sbinkertn@umich.edu if (!new_inst->isReadySrcRegIdx(src_reg_idx)) { 11373932Sbinkertn@umich.edu PhysRegIndex src_reg = new_inst->renamedSrcRegIdx(src_reg_idx); 11383885Sbinkertn@umich.edu 11393932Sbinkertn@umich.edu // Check the IQ's scoreboard to make sure the register 11403932Sbinkertn@umich.edu // hasn't become ready while the instruction was in flight 11413932Sbinkertn@umich.edu // between stages. Only if it really isn't ready should 11423932Sbinkertn@umich.edu // it be added to the dependency graph. 11433932Sbinkertn@umich.edu if (src_reg >= numPhysRegs) { 11443932Sbinkertn@umich.edu continue; 11453932Sbinkertn@umich.edu } else if (regScoreboard[src_reg] == false) { 11463932Sbinkertn@umich.edu DPRINTF(IQ, "Instruction PC %#x has src reg %i that " 11473932Sbinkertn@umich.edu "is being added to the dependency chain.\n", 11483932Sbinkertn@umich.edu new_inst->readPC(), src_reg); 11493932Sbinkertn@umich.edu 11503932Sbinkertn@umich.edu dependGraph.insert(src_reg, new_inst); 11513932Sbinkertn@umich.edu 11523932Sbinkertn@umich.edu // Change the return value to indicate that something 11533932Sbinkertn@umich.edu // was added to the dependency graph. 11543932Sbinkertn@umich.edu return_val = true; 11553932Sbinkertn@umich.edu } else { 11563932Sbinkertn@umich.edu DPRINTF(IQ, "Instruction PC %#x has src reg %i that " 11573885Sbinkertn@umich.edu "became ready before it reached the IQ.\n", 11583885Sbinkertn@umich.edu new_inst->readPC(), src_reg); 11593885Sbinkertn@umich.edu // Mark a register ready within the instruction. 11603885Sbinkertn@umich.edu new_inst->markSrcRegReady(src_reg_idx); 11614762Snate@binkert.org } 11627673Snate@binkert.org } 11637673Snate@binkert.org } 11647673Snate@binkert.org 11657673Snate@binkert.org return return_val; 11667673Snate@binkert.org} 11673885Sbinkertn@umich.edu 11683932Sbinkertn@umich.edutemplate <class Impl> 11693885Sbinkertn@umich.eduvoid 117010267SGeoffrey.Blake@arm.comInstructionQueue<Impl>::addToProducers(DynInstPtr &new_inst) 117110267SGeoffrey.Blake@arm.com{ 117210267SGeoffrey.Blake@arm.com // Nothing really needs to be marked when an instruction becomes 117310267SGeoffrey.Blake@arm.com // the producer of a register's value, but for convenience a ptr 11744762Snate@binkert.org // to the producing instruction will be placed in the head node of 117511988Sandreas.sandberg@arm.com // the dependency links. 117611988Sandreas.sandberg@arm.com int8_t total_dest_regs = new_inst->numDestRegs(); 11774762Snate@binkert.org 117811988Sandreas.sandberg@arm.com for (int dest_reg_idx = 0; 11794762Snate@binkert.org dest_reg_idx < total_dest_regs; 11803885Sbinkertn@umich.edu dest_reg_idx++) 11814762Snate@binkert.org { 11823885Sbinkertn@umich.edu PhysRegIndex dest_reg = new_inst->renamedDestRegIdx(dest_reg_idx); 11833885Sbinkertn@umich.edu 11843932Sbinkertn@umich.edu // Instructions that use the misc regs will have a reg number 11853885Sbinkertn@umich.edu // higher than the normal physical registers. In this case these 11868664SAli.Saidi@ARM.com // registers are not renamed, and there is no need to track 118710380SAndrew.Bardsley@arm.com // dependencies as these instructions must be executed at commit. 11888664SAli.Saidi@ARM.com if (dest_reg >= numPhysRegs) { 11898664SAli.Saidi@ARM.com continue; 119010458Sandreas.hansson@arm.com } 119110458Sandreas.hansson@arm.com 119210458Sandreas.hansson@arm.com if (!dependGraph.empty(dest_reg)) { 119310458Sandreas.hansson@arm.com dependGraph.dump(); 119410458Sandreas.hansson@arm.com panic("Dependency graph %i not empty!", dest_reg); 119510458Sandreas.hansson@arm.com } 119610458Sandreas.hansson@arm.com 119710458Sandreas.hansson@arm.com dependGraph.setInst(dest_reg, new_inst); 119810458Sandreas.hansson@arm.com 119910458Sandreas.hansson@arm.com // Mark the scoreboard to say it's not yet ready. 12003101Sstever@eecs.umich.edu regScoreboard[dest_reg] = false; 12013101Sstever@eecs.umich.edu } 12023101Sstever@eecs.umich.edu} 12033101Sstever@eecs.umich.edu 12043101Sstever@eecs.umich.edutemplate <class Impl> 12053101Sstever@eecs.umich.eduvoid 12063101Sstever@eecs.umich.eduInstructionQueue<Impl>::addIfReady(DynInstPtr &inst) 12073101Sstever@eecs.umich.edu{ 12083101Sstever@eecs.umich.edu // If the instruction now has all of its source registers 12093101Sstever@eecs.umich.edu // available, then add it to the list of ready instructions. 12103101Sstever@eecs.umich.edu if (inst->readyToIssue()) { 12113101Sstever@eecs.umich.edu 12123101Sstever@eecs.umich.edu //Add the instruction to the proper ready list. 12133101Sstever@eecs.umich.edu if (inst->isMemRef()) { 12144762Snate@binkert.org 12153101Sstever@eecs.umich.edu DPRINTF(IQ, "Checking if memory instruction can issue.\n"); 12165033Smilesck@eecs.umich.edu 12174762Snate@binkert.org // Message to the mem dependence unit that this instruction has 12184762Snate@binkert.org // its registers ready. 12194762Snate@binkert.org memDepUnit[inst->threadNumber].regsReady(inst); 12204762Snate@binkert.org 12214762Snate@binkert.org return; 12224762Snate@binkert.org } 12234762Snate@binkert.org 12243101Sstever@eecs.umich.edu OpClass op_class = inst->opClass(); 12253101Sstever@eecs.umich.edu 12263101Sstever@eecs.umich.edu DPRINTF(IQ, "Instruction is ready to issue, putting it onto " 12273101Sstever@eecs.umich.edu "the ready list, PC %#x opclass:%i [sn:%lli].\n", 12283101Sstever@eecs.umich.edu inst->readPC(), op_class, inst->seqNum); 12293101Sstever@eecs.umich.edu 12303101Sstever@eecs.umich.edu readyInsts[op_class].push(inst); 12313101Sstever@eecs.umich.edu 12323101Sstever@eecs.umich.edu // Will need to reorder the list if either a queue is not on the list, 12333101Sstever@eecs.umich.edu // or it has an older instruction than last time. 12343101Sstever@eecs.umich.edu if (!queueOnList[op_class]) { 12353101Sstever@eecs.umich.edu addToOrderList(op_class); 12363101Sstever@eecs.umich.edu } else if (readyInsts[op_class].top()->seqNum < 12373101Sstever@eecs.umich.edu (*readyIt[op_class]).oldestInst) { 12383101Sstever@eecs.umich.edu listOrder.erase(readyIt[op_class]); 12393101Sstever@eecs.umich.edu addToOrderList(op_class); 12403101Sstever@eecs.umich.edu } 12413101Sstever@eecs.umich.edu } 12423101Sstever@eecs.umich.edu} 12433101Sstever@eecs.umich.edu 12444762Snate@binkert.orgtemplate <class Impl> 12453101Sstever@eecs.umich.eduint 12463101Sstever@eecs.umich.eduInstructionQueue<Impl>::countInsts() 12473101Sstever@eecs.umich.edu{ 12483101Sstever@eecs.umich.edu#if 0 12493101Sstever@eecs.umich.edu //ksewell:This works but definitely could use a cleaner write 12503101Sstever@eecs.umich.edu //with a more intuitive way of counting. Right now it's 12517673Snate@binkert.org //just brute force .... 125210201SAndrew.Bardsley@arm.com // Change the #if if you want to use this method. 125310201SAndrew.Bardsley@arm.com int total_insts = 0; 125410201SAndrew.Bardsley@arm.com 125510201SAndrew.Bardsley@arm.com for (int i = 0; i < numThreads; ++i) { 125610201SAndrew.Bardsley@arm.com ListIt count_it = instList[i].begin(); 12577673Snate@binkert.org 125810201SAndrew.Bardsley@arm.com while (count_it != instList[i].end()) { 125910201SAndrew.Bardsley@arm.com if (!(*count_it)->isSquashed() && !(*count_it)->isSquashedInIQ()) { 12607673Snate@binkert.org if (!(*count_it)->isIssued()) { 126110201SAndrew.Bardsley@arm.com ++total_insts; 12627673Snate@binkert.org } else if ((*count_it)->isMemRef() && 12637673Snate@binkert.org !(*count_it)->memOpDone) { 12647673Snate@binkert.org // Loads that have not been marked as executed still count 12654762Snate@binkert.org // towards the total instructions. 12667673Snate@binkert.org ++total_insts; 12678902Sandreas.hansson@arm.com } 12687673Snate@binkert.org } 126910201SAndrew.Bardsley@arm.com 12704762Snate@binkert.org ++count_it; 127110201SAndrew.Bardsley@arm.com } 127210201SAndrew.Bardsley@arm.com } 127310201SAndrew.Bardsley@arm.com 127410201SAndrew.Bardsley@arm.com return total_insts; 127510201SAndrew.Bardsley@arm.com#else 127610201SAndrew.Bardsley@arm.com return numEntries - freeEntries; 127710201SAndrew.Bardsley@arm.com#endif 127810201SAndrew.Bardsley@arm.com} 127910201SAndrew.Bardsley@arm.com 12807673Snate@binkert.orgtemplate <class Impl> 12817673Snate@binkert.orgvoid 128210201SAndrew.Bardsley@arm.comInstructionQueue<Impl>::dumpLists() 128310201SAndrew.Bardsley@arm.com{ 128410201SAndrew.Bardsley@arm.com for (int i = 0; i < Num_OpClasses; ++i) { 128510201SAndrew.Bardsley@arm.com cprintf("Ready list %i size: %i\n", i, readyInsts[i].size()); 128610201SAndrew.Bardsley@arm.com 128710201SAndrew.Bardsley@arm.com cprintf("\n"); 128810201SAndrew.Bardsley@arm.com } 128910201SAndrew.Bardsley@arm.com 129010201SAndrew.Bardsley@arm.com cprintf("Non speculative list size: %i\n", nonSpecInsts.size()); 129110201SAndrew.Bardsley@arm.com 129210201SAndrew.Bardsley@arm.com NonSpecMapIt non_spec_it = nonSpecInsts.begin(); 129310201SAndrew.Bardsley@arm.com NonSpecMapIt non_spec_end_it = nonSpecInsts.end(); 129410201SAndrew.Bardsley@arm.com 129510201SAndrew.Bardsley@arm.com cprintf("Non speculative list: "); 129610201SAndrew.Bardsley@arm.com 12974762Snate@binkert.org while (non_spec_it != non_spec_end_it) { 12987673Snate@binkert.org cprintf("%#x [sn:%lli]", (*non_spec_it).second->readPC(), 129910201SAndrew.Bardsley@arm.com (*non_spec_it).second->seqNum); 130010201SAndrew.Bardsley@arm.com ++non_spec_it; 130110201SAndrew.Bardsley@arm.com } 130210201SAndrew.Bardsley@arm.com 130310201SAndrew.Bardsley@arm.com cprintf("\n"); 130410201SAndrew.Bardsley@arm.com 13053101Sstever@eecs.umich.edu ListOrderIt list_order_it = listOrder.begin(); 130611988Sandreas.sandberg@arm.com ListOrderIt list_order_end_it = listOrder.end(); 130711988Sandreas.sandberg@arm.com int i = 1; 130811988Sandreas.sandberg@arm.com 130911988Sandreas.sandberg@arm.com cprintf("List order: "); 131011988Sandreas.sandberg@arm.com 131111988Sandreas.sandberg@arm.com while (list_order_it != list_order_end_it) { 131211988Sandreas.sandberg@arm.com cprintf("%i OpClass:%i [sn:%lli] ", i, (*list_order_it).queueType, 131311988Sandreas.sandberg@arm.com (*list_order_it).oldestInst); 131411988Sandreas.sandberg@arm.com 131511988Sandreas.sandberg@arm.com ++list_order_it; 131611988Sandreas.sandberg@arm.com ++i; 131711988Sandreas.sandberg@arm.com } 131811988Sandreas.sandberg@arm.com 131911988Sandreas.sandberg@arm.com cprintf("\n"); 132011988Sandreas.sandberg@arm.com} 132111988Sandreas.sandberg@arm.com 132211988Sandreas.sandberg@arm.com 132311988Sandreas.sandberg@arm.comtemplate <class Impl> 132411988Sandreas.sandberg@arm.comvoid 132511988Sandreas.sandberg@arm.comInstructionQueue<Impl>::dumpInsts() 132611988Sandreas.sandberg@arm.com{ 132711988Sandreas.sandberg@arm.com for (int i = 0; i < numThreads; ++i) { 132811988Sandreas.sandberg@arm.com int num = 0; 132911988Sandreas.sandberg@arm.com int valid_num = 0; 133011988Sandreas.sandberg@arm.com ListIt inst_list_it = instList[i].begin(); 133111988Sandreas.sandberg@arm.com 133211988Sandreas.sandberg@arm.com while (inst_list_it != instList[i].end()) 133311988Sandreas.sandberg@arm.com { 133411988Sandreas.sandberg@arm.com cprintf("Instruction:%i\n", 133511988Sandreas.sandberg@arm.com num); 133611988Sandreas.sandberg@arm.com if (!(*inst_list_it)->isSquashed()) { 133711988Sandreas.sandberg@arm.com if (!(*inst_list_it)->isIssued()) { 133811988Sandreas.sandberg@arm.com ++valid_num; 133911988Sandreas.sandberg@arm.com cprintf("Count:%i\n", valid_num); 13408596Ssteve.reinhardt@amd.com } else if ((*inst_list_it)->isMemRef() && 13413101Sstever@eecs.umich.edu !(*inst_list_it)->memOpDone) { 13423101Sstever@eecs.umich.edu // Loads that have not been marked as executed 13433101Sstever@eecs.umich.edu // still count towards the total instructions. 13443101Sstever@eecs.umich.edu ++valid_num; 134510267SGeoffrey.Blake@arm.com cprintf("Count:%i\n", valid_num); 13463101Sstever@eecs.umich.edu } 134710201SAndrew.Bardsley@arm.com } 134810201SAndrew.Bardsley@arm.com 134910201SAndrew.Bardsley@arm.com cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" 135010201SAndrew.Bardsley@arm.com "Issued:%i\nSquashed:%i\n", 135110201SAndrew.Bardsley@arm.com (*inst_list_it)->readPC(), 135210201SAndrew.Bardsley@arm.com (*inst_list_it)->seqNum, 135310201SAndrew.Bardsley@arm.com (*inst_list_it)->threadNumber, 135410201SAndrew.Bardsley@arm.com (*inst_list_it)->isIssued(), 135510201SAndrew.Bardsley@arm.com (*inst_list_it)->isSquashed()); 13563101Sstever@eecs.umich.edu 13573101Sstever@eecs.umich.edu if ((*inst_list_it)->isMemRef()) { 13583101Sstever@eecs.umich.edu cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); 13593101Sstever@eecs.umich.edu } 13603101Sstever@eecs.umich.edu 13613101Sstever@eecs.umich.edu cprintf("\n"); 136210267SGeoffrey.Blake@arm.com 136310267SGeoffrey.Blake@arm.com inst_list_it++; 136410267SGeoffrey.Blake@arm.com ++num; 136510267SGeoffrey.Blake@arm.com } 13667675Snate@binkert.org } 13677675Snate@binkert.org 13687675Snate@binkert.org cprintf("Insts to Execute list:\n"); 13697675Snate@binkert.org 13707675Snate@binkert.org int num = 0; 137110458Sandreas.hansson@arm.com int valid_num = 0; 137210458Sandreas.hansson@arm.com ListIt inst_list_it = instsToExecute.begin(); 137310458Sandreas.hansson@arm.com 137410458Sandreas.hansson@arm.com while (inst_list_it != instsToExecute.end()) 137510458Sandreas.hansson@arm.com { 137610458Sandreas.hansson@arm.com cprintf("Instruction:%i\n", 137710458Sandreas.hansson@arm.com num); 137810458Sandreas.hansson@arm.com if (!(*inst_list_it)->isSquashed()) { 137910458Sandreas.hansson@arm.com if (!(*inst_list_it)->isIssued()) { 138010458Sandreas.hansson@arm.com ++valid_num; 138110458Sandreas.hansson@arm.com cprintf("Count:%i\n", valid_num); 138210458Sandreas.hansson@arm.com } else if ((*inst_list_it)->isMemRef() && 13834762Snate@binkert.org !(*inst_list_it)->memOpDone) { 138411988Sandreas.sandberg@arm.com // Loads that have not been marked as executed 138511988Sandreas.sandberg@arm.com // still count towards the total instructions. 138611988Sandreas.sandberg@arm.com ++valid_num; 13874762Snate@binkert.org cprintf("Count:%i\n", valid_num); 13883101Sstever@eecs.umich.edu } 13893101Sstever@eecs.umich.edu } 13903101Sstever@eecs.umich.edu 13913101Sstever@eecs.umich.edu cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" 13923101Sstever@eecs.umich.edu "Issued:%i\nSquashed:%i\n", 13933101Sstever@eecs.umich.edu (*inst_list_it)->readPC(), 13944167Sbinkertn@umich.edu (*inst_list_it)->seqNum, 13953101Sstever@eecs.umich.edu (*inst_list_it)->threadNumber, 139610267SGeoffrey.Blake@arm.com (*inst_list_it)->isIssued(), 139710267SGeoffrey.Blake@arm.com (*inst_list_it)->isSquashed()); 13987673Snate@binkert.org 13997673Snate@binkert.org if ((*inst_list_it)->isMemRef()) { 14007673Snate@binkert.org cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); 14017673Snate@binkert.org } 14027673Snate@binkert.org 140310267SGeoffrey.Blake@arm.com cprintf("\n"); 140410267SGeoffrey.Blake@arm.com 140510267SGeoffrey.Blake@arm.com inst_list_it++; 140610267SGeoffrey.Blake@arm.com ++num; 14074762Snate@binkert.org } 14084762Snate@binkert.org} 14094762Snate@binkert.org