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