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