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