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