commit_impl.hh revision 2292
1/* 2 * Copyright (c) 2004-2005 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 29#include <algorithm> 30#include <cstdio> 31#include <cstdlib> 32#include <cstring> 33#include <iomanip> 34#include <stdio.h> 35#include <string.h> 36 37#include "base/loader/symtab.hh" 38#include "base/timebuf.hh" 39#include "cpu/exetrace.hh" 40#include "cpu/o3/commit.hh" 41#include "cpu/o3/thread_state.hh" 42 43using namespace std; 44 45template <class Impl> 46DefaultCommit<Impl>::TrapEvent::TrapEvent(DefaultCommit<Impl> *_commit, 47 unsigned _tid) 48 : Event(&mainEventQueue, CPU_Tick_Pri), commit(_commit), tid(_tid) 49{ 50 this->setFlags(Event::AutoDelete); 51} 52 53template <class Impl> 54void 55DefaultCommit<Impl>::TrapEvent::process() 56{ 57 commit->trapSquash[tid] = true; 58} 59 60template <class Impl> 61const char * 62DefaultCommit<Impl>::TrapEvent::description() 63{ 64 return "Trap event"; 65} 66 67template <class Impl> 68DefaultCommit<Impl>::DefaultCommit(Params *params) 69 : dcacheInterface(params->dcacheInterface), 70 squashCounter(0), 71 iewToCommitDelay(params->iewToCommitDelay), 72 commitToIEWDelay(params->commitToIEWDelay), 73 renameToROBDelay(params->renameToROBDelay), 74 fetchToCommitDelay(params->commitToFetchDelay), 75 renameWidth(params->renameWidth), 76 iewWidth(params->executeWidth), 77 commitWidth(params->commitWidth), 78 numThreads(params->numberOfThreads) 79{ 80 _status = Active; 81 _nextStatus = Inactive; 82 string policy = params->smtCommitPolicy; 83 84 //Convert string to lowercase 85 std::transform(policy.begin(), policy.end(), policy.begin(), 86 (int(*)(int)) tolower); 87 88 //Assign commit policy 89 if (policy == "aggressive"){ 90 commitPolicy = Aggressive; 91 92 DPRINTF(Commit,"Commit Policy set to Aggressive."); 93 } else if (policy == "roundrobin"){ 94 commitPolicy = RoundRobin; 95 96 //Set-Up Priority List 97 for (int tid=0; tid < numThreads; tid++) { 98 priority_list.push_back(tid); 99 } 100 101 DPRINTF(Commit,"Commit Policy set to Round Robin."); 102 } else if (policy == "oldestready"){ 103 commitPolicy = OldestReady; 104 105 DPRINTF(Commit,"Commit Policy set to Oldest Ready."); 106 } else { 107 assert(0 && "Invalid SMT Commit Policy. Options Are: {Aggressive," 108 "RoundRobin,OldestReady}"); 109 } 110 111 for (int i=0; i < numThreads; i++) { 112 commitStatus[i] = Idle; 113 changedROBNumEntries[i] = false; 114 trapSquash[i] = false; 115 xcSquash[i] = false; 116 } 117 118 // Hardcoded trap latency. 119 trapLatency = 6; 120 fetchTrapLatency = 12; 121 fetchFaultTick = 0; 122 fetchTrapWait = 0; 123} 124 125template <class Impl> 126std::string 127DefaultCommit<Impl>::name() const 128{ 129 return cpu->name() + ".commit"; 130} 131 132template <class Impl> 133void 134DefaultCommit<Impl>::regStats() 135{ 136 commitCommittedInsts 137 .name(name() + ".commitCommittedInsts") 138 .desc("The number of committed instructions") 139 .prereq(commitCommittedInsts); 140 commitSquashedInsts 141 .name(name() + ".commitSquashedInsts") 142 .desc("The number of squashed insts skipped by commit") 143 .prereq(commitSquashedInsts); 144 commitSquashEvents 145 .name(name() + ".commitSquashEvents") 146 .desc("The number of times commit is told to squash") 147 .prereq(commitSquashEvents); 148 commitNonSpecStalls 149 .name(name() + ".commitNonSpecStalls") 150 .desc("The number of times commit has been forced to stall to " 151 "communicate backwards") 152 .prereq(commitNonSpecStalls); 153 commitCommittedBranches 154 .name(name() + ".commitCommittedBranches") 155 .desc("The number of committed branches") 156 .prereq(commitCommittedBranches); 157 commitCommittedLoads 158 .name(name() + ".commitCommittedLoads") 159 .desc("The number of committed loads") 160 .prereq(commitCommittedLoads); 161 commitCommittedMemRefs 162 .name(name() + ".commitCommittedMemRefs") 163 .desc("The number of committed memory references") 164 .prereq(commitCommittedMemRefs); 165 branchMispredicts 166 .name(name() + ".branchMispredicts") 167 .desc("The number of times a branch was mispredicted") 168 .prereq(branchMispredicts); 169 numCommittedDist 170 .init(0,commitWidth,1) 171 .name(name() + ".COM:committed_per_cycle") 172 .desc("Number of insts commited each cycle") 173 .flags(Stats::pdf) 174 ; 175} 176 177template <class Impl> 178void 179DefaultCommit<Impl>::setCPU(FullCPU *cpu_ptr) 180{ 181 DPRINTF(Commit, "Commit: Setting CPU pointer.\n"); 182 cpu = cpu_ptr; 183 184 // Commit must broadcast the number of free entries it has at the start of 185 // the simulation, so it starts as active. 186 cpu->activateStage(FullCPU::CommitIdx); 187} 188 189template <class Impl> 190void 191DefaultCommit<Impl>::setThreads(vector<Thread *> &threads) 192{ 193 thread = threads; 194} 195 196template <class Impl> 197void 198DefaultCommit<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) 199{ 200 DPRINTF(Commit, "Commit: Setting time buffer pointer.\n"); 201 timeBuffer = tb_ptr; 202 203 // Setup wire to send information back to IEW. 204 toIEW = timeBuffer->getWire(0); 205 206 // Setup wire to read data from IEW (for the ROB). 207 robInfoFromIEW = timeBuffer->getWire(-iewToCommitDelay); 208} 209 210template <class Impl> 211void 212DefaultCommit<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr) 213{ 214 DPRINTF(Commit, "Commit: Setting fetch queue pointer.\n"); 215 fetchQueue = fq_ptr; 216 217 // Setup wire to get instructions from rename (for the ROB). 218 fromFetch = fetchQueue->getWire(-fetchToCommitDelay); 219} 220 221template <class Impl> 222void 223DefaultCommit<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr) 224{ 225 DPRINTF(Commit, "Commit: Setting rename queue pointer.\n"); 226 renameQueue = rq_ptr; 227 228 // Setup wire to get instructions from rename (for the ROB). 229 fromRename = renameQueue->getWire(-renameToROBDelay); 230} 231 232template <class Impl> 233void 234DefaultCommit<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr) 235{ 236 DPRINTF(Commit, "Commit: Setting IEW queue pointer.\n"); 237 iewQueue = iq_ptr; 238 239 // Setup wire to get instructions from IEW. 240 fromIEW = iewQueue->getWire(-iewToCommitDelay); 241} 242 243template <class Impl> 244void 245DefaultCommit<Impl>::setIEWStage(IEW *iew_stage) 246{ 247 iewStage = iew_stage; 248} 249 250template<class Impl> 251void 252DefaultCommit<Impl>::setActiveThreads(list<unsigned> *at_ptr) 253{ 254 DPRINTF(Commit, "Commit: Setting active threads list pointer.\n"); 255 activeThreads = at_ptr; 256} 257 258template <class Impl> 259void 260DefaultCommit<Impl>::setRenameMap(RenameMap rm_ptr[]) 261{ 262 DPRINTF(Commit, "Setting rename map pointers.\n"); 263 264 for (int i=0; i < numThreads; i++) { 265 renameMap[i] = &rm_ptr[i]; 266 } 267} 268 269template <class Impl> 270void 271DefaultCommit<Impl>::setROB(ROB *rob_ptr) 272{ 273 DPRINTF(Commit, "Commit: Setting ROB pointer.\n"); 274 rob = rob_ptr; 275} 276 277template <class Impl> 278void 279DefaultCommit<Impl>::initStage() 280{ 281 rob->setActiveThreads(activeThreads); 282 rob->resetEntries(); 283 284 // Broadcast the number of free entries. 285 for (int i=0; i < numThreads; i++) { 286 toIEW->commitInfo[i].usedROB = true; 287 toIEW->commitInfo[i].freeROBEntries = rob->numFreeEntries(i); 288 } 289 290 cpu->activityThisCycle(); 291} 292 293template <class Impl> 294void 295DefaultCommit<Impl>::updateStatus() 296{ 297 if (commitStatus[0] == TrapPending || 298 commitStatus[0] == FetchTrapPending) { 299 _nextStatus = Active; 300 } 301 302 if (_nextStatus == Inactive && _status == Active) { 303 DPRINTF(Activity, "Deactivating stage.\n"); 304 cpu->deactivateStage(FullCPU::CommitIdx); 305 } else if (_nextStatus == Active && _status == Inactive) { 306 DPRINTF(Activity, "Activating stage.\n"); 307 cpu->activateStage(FullCPU::CommitIdx); 308 } 309 310 _status = _nextStatus; 311 312 // reset ROB changed variable 313 list<unsigned>::iterator threads = (*activeThreads).begin(); 314 while (threads != (*activeThreads).end()) { 315 unsigned tid = *threads++; 316 changedROBNumEntries[tid] = false; 317 } 318} 319 320template <class Impl> 321void 322DefaultCommit<Impl>::setNextStatus() 323{ 324 int squashes = 0; 325 326 list<unsigned>::iterator threads = (*activeThreads).begin(); 327 328 while (threads != (*activeThreads).end()) { 329 unsigned tid = *threads++; 330 331 if (commitStatus[tid] == ROBSquashing) { 332 squashes++; 333 } 334 } 335 336 assert(squashes == squashCounter); 337 338 // If commit is currently squashing, then it will have activity for the 339 // next cycle. Set its next status as active. 340 if (squashCounter) { 341 _nextStatus = Active; 342 } 343} 344 345template <class Impl> 346bool 347DefaultCommit<Impl>::changedROBEntries() 348{ 349 list<unsigned>::iterator threads = (*activeThreads).begin(); 350 351 while (threads != (*activeThreads).end()) { 352 unsigned tid = *threads++; 353 354 if (changedROBNumEntries[tid]) { 355 return true; 356 } 357 } 358 359 return false; 360} 361 362template <class Impl> 363unsigned 364DefaultCommit<Impl>::numROBFreeEntries(unsigned tid) 365{ 366 return rob->numFreeEntries(tid); 367} 368 369template <class Impl> 370void 371DefaultCommit<Impl>::generateTrapEvent(unsigned tid) 372{ 373 DPRINTF(Commit, "Generating trap event for [tid:%i]\n", tid); 374 375 TrapEvent *trap = new TrapEvent(this, tid); 376 377 trap->schedule(curTick + trapLatency); 378 379 thread[tid]->trapPending = true; 380} 381 382template <class Impl> 383void 384DefaultCommit<Impl>::generateXCEvent(unsigned tid) 385{ 386 DPRINTF(Commit, "Generating XC squash event for [tid:%i]\n", tid); 387 388 xcSquash[tid] = true; 389} 390 391template <class Impl> 392void 393DefaultCommit<Impl>::squashFromTrap(unsigned tid) 394{ 395 // If we want to include the squashing instruction in the squash, 396 // then use one older sequence number. 397 // Hopefully this doesn't mess things up. Basically I want to squash 398 // all instructions of this thread. 399 InstSeqNum squashed_inst = rob->isEmpty() ? 400 0 : rob->readHeadInst(tid)->seqNum - 1; 401 402 // All younger instructions will be squashed. Set the sequence 403 // number as the youngest instruction in the ROB (0 in this case. 404 // Hopefully nothing breaks.) 405 youngestSeqNum[tid] = 0; 406 407 rob->squash(squashed_inst, tid); 408 changedROBNumEntries[tid] = true; 409 410 // Send back the sequence number of the squashed instruction. 411 toIEW->commitInfo[tid].doneSeqNum = squashed_inst; 412 413 // Send back the squash signal to tell stages that they should 414 // squash. 415 toIEW->commitInfo[tid].squash = true; 416 417 // Send back the rob squashing signal so other stages know that 418 // the ROB is in the process of squashing. 419 toIEW->commitInfo[tid].robSquashing = true; 420 421 toIEW->commitInfo[tid].branchMispredict = false; 422 423// toIEW->commitInfo[tid].branchTaken = fromIEW->branchTaken[tid]; 424 425 toIEW->commitInfo[tid].nextPC = PC[tid]; 426 427 DPRINTF(Commit, "Squashing from trap, restarting at PC %#x\n", PC[tid]); 428 // Hopefully nobody tries to use the mispredPC becuase I said there 429 // wasn't a branch mispredict. 430// toIEW->commitInfo[tid].mispredPC = fromIEW->mispredPC[tid]; 431 432 thread[tid]->trapPending = false; 433 thread[tid]->inSyscall = false; 434 435 trapSquash[tid] = false; 436 437 // Not sure what to set this to... 438 commitStatus[tid] = ROBSquashing; 439 cpu->activityThisCycle(); 440 441 ++squashCounter; 442} 443 444template <class Impl> 445void 446DefaultCommit<Impl>::squashFromXC(unsigned tid) 447{ 448 // For now these are identical. In the future, the squash from trap 449 // might execute the trap prior to the squash. 450 451 // If we want to include the squashing instruction in the squash, 452 // then use one older sequence number. 453 // Hopefully this doesn't mess things up. Basically I want to squash 454 // all instructions of this thread. 455 InstSeqNum squashed_inst = rob->isEmpty() ? 456 0 : rob->readHeadInst(tid)->seqNum - 1;; 457 458 // All younger instructions will be squashed. Set the sequence 459 // number as the youngest instruction in the ROB (0 in this case. 460 // Hopefully nothing breaks.) 461 youngestSeqNum[tid] = 0; 462 463 rob->squash(squashed_inst, tid); 464 changedROBNumEntries[tid] = true; 465 466 // Send back the sequence number of the squashed instruction. 467 toIEW->commitInfo[tid].doneSeqNum = squashed_inst; 468 469 // Send back the squash signal to tell stages that they should 470 // squash. 471 toIEW->commitInfo[tid].squash = true; 472 473 // Send back the rob squashing signal so other stages know that 474 // the ROB is in the process of squashing. 475 toIEW->commitInfo[tid].robSquashing = true; 476 477 toIEW->commitInfo[tid].branchMispredict = false; 478 479// toIEW->commitInfo[tid].branchTaken = fromIEW->branchTaken[tid]; 480 481 toIEW->commitInfo[tid].nextPC = PC[tid]; 482 483 DPRINTF(Commit, "Squashing from XC, restarting at PC %#x\n", PC[tid]); 484 // Hopefully nobody tries to use the mispredPC becuase I said there 485 // wasn't a branch mispredict. 486// toIEW->commitInfo[tid].mispredPC = fromIEW->mispredPC[tid]; 487 488 thread[tid]->inSyscall = false; 489 assert(!thread[tid]->trapPending); 490 // Not sure what to set this to... 491 commitStatus[tid] = ROBSquashing; 492 cpu->activityThisCycle(); 493 494 xcSquash[tid] = false; 495 496 ++squashCounter; 497} 498 499template <class Impl> 500void 501DefaultCommit<Impl>::squashInFlightInsts(unsigned tid) 502{ 503 // @todo: Fix this hardcoded number. 504 for (int i = 0; i < -5; ++i) { 505 for (int j = 0; j < (*iewQueue)[i].size; ++j) { 506 DynInstPtr inst = (*iewQueue)[i].insts[j]; 507 if (inst->threadNumber == tid && 508 !inst->isSquashed()) { 509 inst->setSquashed(); 510 } 511 } 512 } 513} 514 515template <class Impl> 516void 517DefaultCommit<Impl>::tick() 518{ 519 wroteToTimeBuffer = false; 520 _nextStatus = Inactive; 521 522 // If the ROB is currently in its squash sequence, then continue 523 // to squash. In this case, commit does not do anything. Otherwise 524 // run commit. 525 list<unsigned>::iterator threads = (*activeThreads).begin(); 526 527 // Maybe this should be dependent upon any of the commits actually 528 // squashing. 529 while (threads != (*activeThreads).end()) { 530 unsigned tid = *threads++; 531 532 if (commitStatus[tid] == ROBSquashing) { 533 534 if (rob->isDoneSquashing(tid)) { 535 commitStatus[tid] = Running; 536 --squashCounter; 537 } else { 538 DPRINTF(Commit,"[tid:%u]: Still Squashing, cannot commit any" 539 "insts this cycle.\n", tid); 540 } 541 } 542 } 543 544 commit(); 545 546 markCompletedInsts(); 547 548 threads = (*activeThreads).begin(); 549 550 while (threads != (*activeThreads).end()) { 551 unsigned tid = *threads++; 552 553 if (!rob->isEmpty(tid) && rob->readHeadInst(tid)->readyToCommit()) { 554 // The ROB has more instructions it can commit. Its next status 555 // will be active. 556 _nextStatus = Active; 557 558 DynInstPtr inst = rob->readHeadInst(tid); 559 560 DPRINTF(Commit,"[tid:%i]: Instruction [sn:%lli] PC %#x is head of" 561 " ROB and ready to commit\n", 562 tid, inst->seqNum, inst->readPC()); 563 564 } else if (!rob->isEmpty(tid)) { 565 DynInstPtr inst = rob->readHeadInst(tid); 566 567 DPRINTF(Commit,"[tid:%i]: Can't commit, Instruction [sn:%lli] PC " 568 "%#x is head of ROB and not ready\n", 569 tid, inst->seqNum, inst->readPC()); 570 } 571 572 DPRINTF(Commit, "[tid:%i]: ROB has %d insts & %d free entries.\n", 573 tid, rob->countInsts(tid), rob->numFreeEntries(tid)); 574 } 575 576 577 if (wroteToTimeBuffer) { 578 DPRINTF(Activity,"Activity This Cycle.\n"); 579 cpu->activityThisCycle(); 580 } 581 582 updateStatus(); 583} 584 585template <class Impl> 586void 587DefaultCommit<Impl>::commit() 588{ 589 590 ////////////////////////////////////// 591 // Check for interrupts 592 ////////////////////////////////////// 593 594 // Process interrupts if interrupts are enabled and not in PAL mode. 595 // Take the PC from commit and write it to the IPR, then squash. The 596 // interrupt completing will take care of restoring the PC from that value 597 // in the IPR. Look at IPR[EXC_ADDR]; 598 // hwrei() is what resets the PC to the place where instruction execution 599 // beings again. 600#if FULL_SYSTEM 601//#if 0 602 if (cpu->checkInterrupts && 603 cpu->check_interrupts() && 604 !cpu->inPalMode(readPC()) && 605 !trapSquash[0] && 606 !xcSquash[0]) { 607// commitStatus[0] = TrapPending; 608 toIEW->commitInfo[0].interruptPending = true; 609 if (rob->isEmpty() && !iewStage->hasStoresToWB()) { 610 // Will need to squash all instructions currently in flight and have 611 // the interrupt handler restart at the last non-committed inst. 612 // Most of that can be handled through the trap() function. The 613 // processInterrupts() function really just checks for interrupts 614 // and then calls trap() if there is an interrupt present. 615 616 // Not sure which thread should be the one to interrupt. For now 617 // always do thread 0. 618 assert(!thread[0]->inSyscall); 619 thread[0]->inSyscall = true; 620 621 // CPU will handle implementation of the interrupt. 622 cpu->processInterrupts(); 623 624 // Now squash or record that I need to squash this cycle. 625 commitStatus[0] = TrapPending; 626 627 // Exit state update mode to avoid accidental updating. 628 thread[0]->inSyscall = false; 629 630 // Generate trap squash event. 631 generateTrapEvent(0); 632 633 toIEW->commitInfo[0].clearInterrupt = true; 634 635 DPRINTF(Commit, "Interrupt detected.\n"); 636 } else { 637 DPRINTF(Commit, "Interrupt pending, waiting for ROB to empty.\n"); 638 } 639 } 640#endif // FULL_SYSTEM 641 642 //////////////////////////////////// 643 // Check for squash signal, handle that first 644 //////////////////////////////////// 645 646 // Check if the IEW stage is telling the ROB to squash. 647 list<unsigned>::iterator threads = (*activeThreads).begin(); 648 649 while (threads != (*activeThreads).end()) { 650 unsigned tid = *threads++; 651 652 if (fromFetch->fetchFault) { 653 // Record the fault. Wait until it's empty in the ROB. Then handle the trap. 654 fetchFault = fromFetch->fetchFault; 655 fetchFaultSN = fromFetch->fetchFaultSN; 656 fetchFaultTick = curTick + fetchTrapLatency; 657 commitStatus[0] = FetchTrapPending; 658 DPRINTF(Commit, "Fault from fetch recorded. Will trap if the " 659 "ROB empties without squashing the fault.\n"); 660 fetchTrapWait = 0; 661 } 662 if (fromFetch->clearFetchFault) { 663 DPRINTF(Commit, "Received clear fetch fault signal\n"); 664 fetchTrapWait = 0; 665 if (commitStatus[0] == FetchTrapPending) { 666 DPRINTF(Commit, "Clearing fault from fetch\n"); 667 commitStatus[0] = Running; 668 } 669 } 670 671 // Not sure which one takes priority. I think if we have 672 // both, that's a bad sign. 673 if (trapSquash[tid] == true) { 674 assert(!xcSquash[tid]); 675 squashFromTrap(tid); 676 } else if (xcSquash[tid] == true) { 677 squashFromXC(tid); 678 } 679 680 // Squashed sequence number must be older than youngest valid 681 // instruction in the ROB. This prevents squashes from younger 682 // instructions overriding squashes from older instructions. 683 if (fromIEW->squash[tid] && 684 commitStatus[tid] != TrapPending && 685 fromIEW->squashedSeqNum[tid] <= youngestSeqNum[tid]) { 686 687 DPRINTF(Commit, "[tid:%u]: Squashing instructions in the " 688 "ROB.\n", 689 tid); 690 691 DPRINTF(Commit, "[tid:%i]: Squashing due to PC %#x [sn:%i]\n", 692 tid, 693 fromIEW->mispredPC[tid], 694 fromIEW->squashedSeqNum[tid]); 695 696 DPRINTF(Commit, "[tid:%i]: Redirecting to PC %#x\n", 697 tid, 698 fromIEW->nextPC[tid]); 699 700 commitStatus[tid] = ROBSquashing; 701 702 ++squashCounter; 703 704 // If we want to include the squashing instruction in the squash, 705 // then use one older sequence number. 706 InstSeqNum squashed_inst = fromIEW->squashedSeqNum[tid]; 707 708 if (fromIEW->includeSquashInst[tid] == true) 709 squashed_inst--; 710 711 // All younger instructions will be squashed. Set the sequence 712 // number as the youngest instruction in the ROB. 713 youngestSeqNum[tid] = squashed_inst; 714 715 rob->squash(squashed_inst, tid); 716 changedROBNumEntries[tid] = true; 717 718 // Send back the sequence number of the squashed instruction. 719 toIEW->commitInfo[tid].doneSeqNum = squashed_inst; 720 721 // Send back the squash signal to tell stages that they should 722 // squash. 723 toIEW->commitInfo[tid].squash = true; 724 725 // Send back the rob squashing signal so other stages know that 726 // the ROB is in the process of squashing. 727 toIEW->commitInfo[tid].robSquashing = true; 728 729 toIEW->commitInfo[tid].branchMispredict = 730 fromIEW->branchMispredict[tid]; 731 732 toIEW->commitInfo[tid].branchTaken = 733 fromIEW->branchTaken[tid]; 734 735 toIEW->commitInfo[tid].nextPC = fromIEW->nextPC[tid]; 736 737 DPRINTF(Commit, "Squashing from IEW, restarting at PC %#x\n", 738 fromIEW->nextPC[tid]); 739 740 toIEW->commitInfo[tid].mispredPC = 741 fromIEW->mispredPC[tid]; 742 743 if (toIEW->commitInfo[tid].branchMispredict) { 744 ++branchMispredicts; 745 } 746 } 747 748 } 749 750 setNextStatus(); 751 752 if (squashCounter != numThreads) { 753 // If we're not currently squashing, then get instructions. 754 getInsts(); 755 756 // Try to commit any instructions. 757 commitInsts(); 758 } 759 760 //Check for any activity 761 threads = (*activeThreads).begin(); 762 763 while (threads != (*activeThreads).end()) { 764 unsigned tid = *threads++; 765 766 if (changedROBNumEntries[tid]) { 767 toIEW->commitInfo[tid].usedROB = true; 768 toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid); 769 770 if (rob->isEmpty(tid)) { 771 toIEW->commitInfo[tid].emptyROB = true; 772 } 773 774 wroteToTimeBuffer = true; 775 changedROBNumEntries[tid] = false; 776 } 777 } 778} 779 780template <class Impl> 781void 782DefaultCommit<Impl>::commitInsts() 783{ 784 //////////////////////////////////// 785 // Handle commit 786 // Note that commit will be handled prior to the ROB so that the ROB 787 // only tries to commit instructions it has in this current cycle, and 788 // not instructions it is writing in during this cycle. 789 // Can't commit and squash things at the same time... 790 //////////////////////////////////// 791 792 DPRINTF(Commit, "Trying to commit instructions in the ROB.\n"); 793 794 unsigned num_committed = 0; 795 796 DynInstPtr head_inst; 797#if FULL_SYSTEM 798 if (commitStatus[0] == FetchTrapPending) { 799 DPRINTF(Commit, "Fault from fetch is pending.\n"); 800 if (rob->isEmpty()) { 801 fetchTrapWait++; 802 if (fetchTrapWait > 10000000) { 803 panic("Fetch trap has been pending for a long time!"); 804 } 805 if (fetchFaultTick > curTick) { 806 DPRINTF(Commit, "Not enough cycles since fault, fault will " 807 "happen on %lli\n", 808 fetchFaultTick); 809 cpu->activityThisCycle(); 810 return; 811 } else if (iewStage->hasStoresToWB()) { 812 DPRINTF(Commit, "IEW still has stores to WB. Waiting until " 813 "they are completed. fetchTrapWait:%i\n", 814 fetchTrapWait); 815 cpu->activityThisCycle(); 816 return; 817 } else if (cpu->inPalMode(readPC())) { 818 DPRINTF(Commit, "In pal mode right now. fetchTrapWait:%i\n", 819 fetchTrapWait); 820 return; 821 } 822 fetchTrapWait = 0; 823 DPRINTF(Commit, "ROB is empty, handling fetch trap.\n"); 824 825 assert(!thread[0]->inSyscall); 826 827 thread[0]->inSyscall = true; 828 829 // Consider holding onto the trap and waiting until the trap event 830 // happens for this to be executed. 831 cpu->trap(fetchFault, 0); 832 833 // Exit state update mode to avoid accidental updating. 834 thread[0]->inSyscall = false; 835 836 commitStatus[0] = TrapPending; 837 // Set it up so that we squash next cycle 838 trapSquash[0] = true; 839 return; 840 } 841 } 842#endif 843 // Commit as many instructions as possible until the commit bandwidth 844 // limit is reached, or it becomes impossible to commit any more. 845 while (num_committed < commitWidth) { 846 int commit_thread = getCommittingThread(); 847 848 if (commit_thread == -1 || !rob->isHeadReady(commit_thread)) 849 break; 850 851 head_inst = rob->readHeadInst(commit_thread); 852 853 int tid = head_inst->threadNumber; 854 855 assert(tid == commit_thread); 856 857 DPRINTF(Commit, "Trying to commit head instruction, [sn:%i] [tid:%i]\n", 858 head_inst->seqNum, tid); 859 860 // If the head instruction is squashed, it is ready to retire at any 861 // time. However, we need to avoid updating any other state 862 // incorrectly if it's already been squashed. 863 if (head_inst->isSquashed()) { 864 865 DPRINTF(Commit, "Retiring squashed instruction from " 866 "ROB.\n"); 867 868 // Tell ROB to retire head instruction. This retires the head 869 // inst in the ROB without affecting any other stages. 870 rob->retireHead(commit_thread); 871 872 ++commitSquashedInsts; 873 874 // Record that the number of ROB entries has changed. 875 changedROBNumEntries[tid] = true; 876 } else { 877 PC[tid] = head_inst->readPC(); 878 nextPC[tid] = head_inst->readNextPC(); 879 880 // Increment the total number of non-speculative instructions 881 // executed. 882 // Hack for now: it really shouldn't happen until after the 883 // commit is deemed to be successful, but this count is needed 884 // for syscalls. 885 thread[tid]->funcExeInst++; 886 887 // Try to commit the head instruction. 888 bool commit_success = commitHead(head_inst, num_committed); 889 890 if (commit_success) { 891 ++num_committed; 892 893 // Record that the number of ROB entries has changed. 894 changedROBNumEntries[tid] = true; 895 896 // Set the doneSeqNum to the youngest committed instruction. 897 toIEW->commitInfo[tid].doneSeqNum = head_inst->seqNum; 898 899 ++commitCommittedInsts; 900 901 // To match the old model, don't count nops and instruction 902 // prefetches towards the total commit count. 903 if (!head_inst->isNop() && !head_inst->isInstPrefetch()) { 904 cpu->instDone(tid); 905 } 906 907 PC[tid] = nextPC[tid]; 908#if FULL_SYSTEM 909 int count = 0; 910 Addr oldpc; 911 do { 912 if (count == 0) 913 assert(!thread[tid]->inSyscall && !thread[tid]->trapPending); 914 oldpc = PC[tid]; 915 cpu->system->pcEventQueue.service( 916 thread[tid]->getXCProxy()); 917 count++; 918 } while (oldpc != PC[tid]); 919 if (count > 1) { 920 DPRINTF(Commit, "PC skip function event, stopping commit\n"); 921 break; 922 } 923#endif 924 } else { 925 DPRINTF(Commit, "Unable to commit head instruction PC:%#x " 926 "[tid:%i] [sn:%i].\n", 927 head_inst->readPC(), tid ,head_inst->seqNum); 928 break; 929 } 930 } 931 } 932 933 DPRINTF(CommitRate, "%i\n", num_committed); 934 numCommittedDist.sample(num_committed); 935} 936 937template <class Impl> 938bool 939DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num) 940{ 941 // Make sure instruction is valid 942 assert(head_inst); 943 944 int tid = head_inst->threadNumber; 945 946 // If the instruction is not executed yet, then it is a non-speculative 947 // or store inst. Signal backwards that it should be executed. 948 if (!head_inst->isExecuted()) { 949 // Keep this number correct. We have not yet actually executed 950 // and committed this instruction. 951 thread[tid]->funcExeInst--; 952 953 head_inst->reachedCommit = true; 954 955 if (head_inst->isNonSpeculative() || 956 head_inst->isMemBarrier() || 957 head_inst->isWriteBarrier()) { 958#if !FULL_SYSTEM 959 // Hack to make sure syscalls aren't executed until all stores 960 // write back their data. This direct communication shouldn't 961 // be used for anything other than this. 962 if (inst_num > 0 || iewStage->hasStoresToWB()) 963#else 964 if ((head_inst->isMemBarrier() || head_inst->isWriteBarrier() || 965 head_inst->isQuiesce()) && 966 iewStage->hasStoresToWB()) 967#endif 968 { 969 DPRINTF(Commit, "Waiting for all stores to writeback.\n"); 970 return false; 971 } 972 973 DPRINTF(Commit, "Encountered a barrier or non-speculative " 974 "instruction [sn:%lli] at the head of the ROB, PC %#x.\n", 975 head_inst->seqNum, head_inst->readPC()); 976 977 // Send back the non-speculative instruction's sequence number. 978 toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum; 979 980 // Change the instruction so it won't try to commit again until 981 // it is executed. 982 head_inst->clearCanCommit(); 983 984 ++commitNonSpecStalls; 985 986 return false; 987 } else if (head_inst->isLoad()) { 988 DPRINTF(Commit, "[sn:%lli]: Uncached load, PC %#x.\n", 989 head_inst->seqNum, head_inst->readPC()); 990 991 // Send back the non-speculative instruction's sequence 992 // number. Maybe just tell the lsq to re-execute the load. 993 toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum; 994 toIEW->commitInfo[tid].uncached = true; 995 toIEW->commitInfo[tid].uncachedLoad = head_inst; 996 997 head_inst->clearCanCommit(); 998 999 return false; 1000 } else { 1001 panic("Trying to commit un-executed instruction " 1002 "of unknown type!\n"); 1003 } 1004 } 1005 1006 // Now check if it's one of the special trap or barrier or 1007 // serializing instructions. 1008 if (head_inst->isThreadSync())/* || 1009// head_inst->isMemBarrier() || 1010head_inst->isWriteBarrier())*/ 1011 { 1012 // Not handled for now. 1013 panic("Barrier instructions are not handled yet.\n"); 1014 } 1015 1016 // Check if the instruction caused a fault. If so, trap. 1017 Fault inst_fault = head_inst->getFault(); 1018 1019 if (inst_fault != NoFault) { 1020 if (!head_inst->isNop()) { 1021#if FULL_SYSTEM 1022 DPRINTF(Commit, "Inst [sn:%lli] PC %#x has a fault\n", 1023 head_inst->seqNum, head_inst->readPC()); 1024 1025 assert(!thread[tid]->inSyscall); 1026 1027 thread[tid]->inSyscall = true; 1028 1029 // Hack for now; DTB will sometimes need the machine instruction 1030 // for when faults happen. So we will set it here, prior to the 1031 // DTB possibly needing it for this translation. 1032 thread[tid]->setInst( 1033 static_cast<TheISA::MachInst>(head_inst->staticInst->machInst)); 1034 1035 // Consider holding onto the trap and waiting until the trap event 1036 // happens for this to be executed. 1037 cpu->trap(inst_fault, tid); 1038 1039 // Exit state update mode to avoid accidental updating. 1040 thread[tid]->inSyscall = false; 1041 1042 commitStatus[tid] = TrapPending; 1043 1044 // Generate trap squash event. 1045 generateTrapEvent(tid); 1046 1047 return false; 1048#else // !FULL_SYSTEM 1049 panic("fault (%d) detected @ PC %08p", inst_fault, 1050 head_inst->PC); 1051#endif // FULL_SYSTEM 1052 } 1053 } 1054 1055 // Check if we're really ready to commit. If not then return false. 1056 // I'm pretty sure all instructions should be able to commit if they've 1057 // reached this far. For now leave this in as a check. 1058 if (!rob->isHeadReady(tid)) { 1059 panic("Unable to commit head instruction!\n"); 1060 return false; 1061 } 1062 1063 if (head_inst->isControl()) { 1064 ++commitCommittedBranches; 1065 } 1066 1067 // Now that the instruction is going to be committed, finalize its 1068 // trace data. 1069 if (head_inst->traceData) { 1070 head_inst->traceData->setFetchSeq(head_inst->seqNum); 1071 head_inst->traceData->setCPSeq(thread[tid]->numInst); 1072 head_inst->traceData->finalize(); 1073 head_inst->traceData = NULL; 1074 } 1075 1076 // Update the commit rename map 1077 for (int i = 0; i < head_inst->numDestRegs(); i++) { 1078 renameMap[tid]->setEntry(head_inst->destRegIdx(i), 1079 head_inst->renamedDestRegIdx(i)); 1080 } 1081 1082 // Finally clear the head ROB entry. 1083 rob->retireHead(tid); 1084 1085 // Return true to indicate that we have committed an instruction. 1086 return true; 1087} 1088 1089template <class Impl> 1090void 1091DefaultCommit<Impl>::getInsts() 1092{ 1093 ////////////////////////////////////// 1094 // Handle ROB functions 1095 ////////////////////////////////////// 1096 1097 // Read any renamed instructions and place them into the ROB. Do this 1098 // prior to squashing to avoid having instructions in the ROB that 1099 // don't get squashed properly. 1100 int insts_to_process = min((int)renameWidth, fromRename->size); 1101 1102 for (int inst_num = 0; inst_num < insts_to_process; ++inst_num) 1103 { 1104 DynInstPtr inst = fromRename->insts[inst_num]; 1105 int tid = inst->threadNumber; 1106 1107 if (!inst->isSquashed() && 1108 commitStatus[tid] != ROBSquashing) { 1109 changedROBNumEntries[tid] = true; 1110 1111 DPRINTF(Commit, "Inserting PC %#x [sn:%i] [tid:%i] into ROB.\n", 1112 inst->readPC(), inst->seqNum, tid); 1113 1114 rob->insertInst(inst); 1115 1116 assert(rob->getThreadEntries(tid) <= rob->getMaxEntries(tid)); 1117 1118 youngestSeqNum[tid] = inst->seqNum; 1119 } else { 1120 DPRINTF(Commit, "Instruction PC %#x [sn:%i] [tid:%i] was " 1121 "squashed, skipping.\n", 1122 inst->readPC(), inst->seqNum, tid); 1123 } 1124 } 1125} 1126 1127template <class Impl> 1128void 1129DefaultCommit<Impl>::markCompletedInsts() 1130{ 1131 // Grab completed insts out of the IEW instruction queue, and mark 1132 // instructions completed within the ROB. 1133 for (int inst_num = 0; 1134 inst_num < fromIEW->size && fromIEW->insts[inst_num]; 1135 ++inst_num) 1136 { 1137 if (!fromIEW->insts[inst_num]->isSquashed()) { 1138 DPRINTF(Commit, "[tid:%i]: Marking PC %#x, SN %i ready within ROB.\n", 1139 fromIEW->insts[inst_num]->threadNumber, 1140 fromIEW->insts[inst_num]->readPC(), 1141 fromIEW->insts[inst_num]->seqNum); 1142 1143 // Mark the instruction as ready to commit. 1144 fromIEW->insts[inst_num]->setCanCommit(); 1145 } 1146 } 1147} 1148 1149template <class Impl> 1150uint64_t 1151DefaultCommit<Impl>::readPC() 1152{ 1153 // @todo: Fix this single thread hack. 1154 return PC[0]; 1155} 1156 1157template <class Impl> 1158void 1159DefaultCommit<Impl>::setSquashing(unsigned tid) 1160{ 1161 if (_status == Inactive) { 1162 DPRINTF(Activity, "Activating stage.\n"); 1163 _status = Active; 1164 cpu->activateStage(FullCPU::CommitIdx); 1165 } 1166 1167 if (commitStatus[tid] != ROBSquashing) { 1168 commitStatus[tid] = ROBSquashing; 1169 ++squashCounter; 1170 } 1171} 1172 1173template <class Impl> 1174bool 1175DefaultCommit<Impl>::robDoneSquashing() 1176{ 1177 list<unsigned>::iterator threads = (*activeThreads).begin(); 1178 1179 while (threads != (*activeThreads).end()) { 1180 unsigned tid = *threads++; 1181 1182 if (!rob->isDoneSquashing(tid)) 1183 return false; 1184 } 1185 1186 return true; 1187} 1188 1189//////////////////////////////////////// 1190// // 1191// SMT COMMIT POLICY MAITAINED HERE // 1192// // 1193//////////////////////////////////////// 1194template <class Impl> 1195int 1196DefaultCommit<Impl>::getCommittingThread() 1197{ 1198 if (numThreads > 1) { 1199 switch (commitPolicy) { 1200 1201 case Aggressive: 1202 //If Policy is Aggressive, commit will call 1203 //this function multiple times per 1204 //cycle 1205 return oldestReady(); 1206 1207 case RoundRobin: 1208 return roundRobin(); 1209 1210 case OldestReady: 1211 return oldestReady(); 1212 1213 default: 1214 return -1; 1215 } 1216 } else { 1217 int tid = (*activeThreads).front(); 1218 1219 if (commitStatus[tid] == Running || 1220 commitStatus[tid] == Idle || 1221 commitStatus[tid] == FetchTrapPending) { 1222 return tid; 1223 } else { 1224 return -1; 1225 } 1226 } 1227} 1228 1229template<class Impl> 1230int 1231DefaultCommit<Impl>::roundRobin() 1232{ 1233 list<unsigned>::iterator pri_iter = priority_list.begin(); 1234 list<unsigned>::iterator end = priority_list.end(); 1235 1236 while (pri_iter != end) { 1237 unsigned tid = *pri_iter; 1238 1239 if (commitStatus[tid] == Running || 1240 commitStatus[tid] == Idle) { 1241 1242 if (rob->isHeadReady(tid)) { 1243 priority_list.erase(pri_iter); 1244 priority_list.push_back(tid); 1245 1246 return tid; 1247 } 1248 } 1249 1250 pri_iter++; 1251 } 1252 1253 return -1; 1254} 1255 1256template<class Impl> 1257int 1258DefaultCommit<Impl>::oldestReady() 1259{ 1260 unsigned oldest = 0; 1261 bool first = true; 1262 1263 list<unsigned>::iterator threads = (*activeThreads).begin(); 1264 1265 while (threads != (*activeThreads).end()) { 1266 unsigned tid = *threads++; 1267 1268 if (!rob->isEmpty(tid) && 1269 (commitStatus[tid] == Running || 1270 commitStatus[tid] == Idle || 1271 commitStatus[tid] == FetchTrapPending)) { 1272 1273 if (rob->isHeadReady(tid)) { 1274 1275 DynInstPtr head_inst = rob->readHeadInst(tid); 1276 1277 if (first) { 1278 oldest = tid; 1279 first = false; 1280 } else if (head_inst->seqNum < oldest) { 1281 oldest = tid; 1282 } 1283 } 1284 } 1285 } 1286 1287 if (!first) { 1288 return oldest; 1289 } else { 1290 return -1; 1291 } 1292} 1293