execute.cc revision 10366
1/* 2 * Copyright (c) 2013-2014 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions are 16 * met: redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer; 18 * redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution; 21 * neither the name of the copyright holders nor the names of its 22 * contributors may be used to endorse or promote products derived from 23 * this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * Authors: Andrew Bardsley 38 */ 39 40#include "arch/locked_mem.hh" 41#include "arch/registers.hh" 42#include "arch/utility.hh" 43#include "cpu/minor/cpu.hh" 44#include "cpu/minor/exec_context.hh" 45#include "cpu/minor/execute.hh" 46#include "cpu/minor/fetch1.hh" 47#include "cpu/minor/lsq.hh" 48#include "cpu/op_class.hh" 49#include "debug/Activity.hh" 50#include "debug/Branch.hh" 51#include "debug/Drain.hh" 52#include "debug/MinorExecute.hh" 53#include "debug/MinorInterrupt.hh" 54#include "debug/MinorMem.hh" 55#include "debug/MinorTrace.hh" 56#include "debug/PCEvent.hh" 57 58namespace Minor 59{ 60 61Execute::Execute(const std::string &name_, 62 MinorCPU &cpu_, 63 MinorCPUParams ¶ms, 64 Latch<ForwardInstData>::Output inp_, 65 Latch<BranchData>::Input out_) : 66 Named(name_), 67 inp(inp_), 68 out(out_), 69 cpu(cpu_), 70 issueLimit(params.executeIssueLimit), 71 memoryIssueLimit(params.executeMemoryIssueLimit), 72 commitLimit(params.executeCommitLimit), 73 memoryCommitLimit(params.executeMemoryCommitLimit), 74 processMoreThanOneInput(params.executeCycleInput), 75 fuDescriptions(*params.executeFuncUnits), 76 numFuncUnits(fuDescriptions.funcUnits.size()), 77 setTraceTimeOnCommit(params.executeSetTraceTimeOnCommit), 78 setTraceTimeOnIssue(params.executeSetTraceTimeOnIssue), 79 allowEarlyMemIssue(params.executeAllowEarlyMemoryIssue), 80 noCostFUIndex(fuDescriptions.funcUnits.size() + 1), 81 lsq(name_ + ".lsq", name_ + ".dcache_port", 82 cpu_, *this, 83 params.executeMaxAccessesInMemory, 84 params.executeMemoryWidth, 85 params.executeLSQRequestsQueueSize, 86 params.executeLSQTransfersQueueSize, 87 params.executeLSQStoreBufferSize, 88 params.executeLSQMaxStoreBufferStoresPerCycle), 89 scoreboard(name_ + ".scoreboard"), 90 inputBuffer(name_ + ".inputBuffer", "insts", 91 params.executeInputBufferSize), 92 inputIndex(0), 93 lastCommitWasEndOfMacroop(true), 94 instsBeingCommitted(params.executeCommitLimit), 95 streamSeqNum(InstId::firstStreamSeqNum), 96 lastPredictionSeqNum(InstId::firstPredictionSeqNum), 97 drainState(NotDraining) 98{ 99 if (commitLimit < 1) { 100 fatal("%s: executeCommitLimit must be >= 1 (%d)\n", name_, 101 commitLimit); 102 } 103 104 if (issueLimit < 1) { 105 fatal("%s: executeCommitLimit must be >= 1 (%d)\n", name_, 106 issueLimit); 107 } 108 109 if (memoryIssueLimit < 1) { 110 fatal("%s: executeMemoryIssueLimit must be >= 1 (%d)\n", name_, 111 memoryIssueLimit); 112 } 113 114 if (memoryCommitLimit > commitLimit) { 115 fatal("%s: executeMemoryCommitLimit (%d) must be <=" 116 " executeCommitLimit (%d)\n", 117 name_, memoryCommitLimit, commitLimit); 118 } 119 120 if (params.executeInputBufferSize < 1) { 121 fatal("%s: executeInputBufferSize must be >= 1 (%d)\n", name_, 122 params.executeInputBufferSize); 123 } 124 125 if (params.executeInputBufferSize < 1) { 126 fatal("%s: executeInputBufferSize must be >= 1 (%d)\n", name_, 127 params.executeInputBufferSize); 128 } 129 130 /* This should be large enough to count all the in-FU instructions 131 * which need to be accounted for in the inFlightInsts 132 * queue */ 133 unsigned int total_slots = 0; 134 135 /* Make FUPipelines for each MinorFU */ 136 for (unsigned int i = 0; i < numFuncUnits; i++) { 137 std::ostringstream fu_name; 138 MinorFU *fu_description = fuDescriptions.funcUnits[i]; 139 140 /* Note the total number of instruction slots (for sizing 141 * the inFlightInst queue) and the maximum latency of any FU 142 * (for sizing the activity recorder) */ 143 total_slots += fu_description->opLat; 144 145 fu_name << name_ << ".fu." << i; 146 147 FUPipeline *fu = new FUPipeline(fu_name.str(), *fu_description, cpu); 148 149 funcUnits.push_back(fu); 150 } 151 152 /** Check that there is a functional unit for all operation classes */ 153 for (int op_class = No_OpClass + 1; op_class < Num_OpClass; op_class++) { 154 bool found_fu = false; 155 unsigned int fu_index = 0; 156 157 while (fu_index < numFuncUnits && !found_fu) 158 { 159 if (funcUnits[fu_index]->provides( 160 static_cast<OpClass>(op_class))) 161 { 162 found_fu = true; 163 } 164 fu_index++; 165 } 166 167 if (!found_fu) { 168 warn("No functional unit for OpClass %s\n", 169 Enums::OpClassStrings[op_class]); 170 } 171 } 172 173 inFlightInsts = new Queue<QueuedInst, 174 ReportTraitsAdaptor<QueuedInst> >( 175 name_ + ".inFlightInsts", "insts", total_slots); 176 177 inFUMemInsts = new Queue<QueuedInst, 178 ReportTraitsAdaptor<QueuedInst> >( 179 name_ + ".inFUMemInsts", "insts", total_slots); 180} 181 182const ForwardInstData * 183Execute::getInput() 184{ 185 /* Get a line from the inputBuffer to work with */ 186 if (!inputBuffer.empty()) { 187 const ForwardInstData &head = inputBuffer.front(); 188 189 return (head.isBubble() ? NULL : &(inputBuffer.front())); 190 } else { 191 return NULL; 192 } 193} 194 195void 196Execute::popInput() 197{ 198 if (!inputBuffer.empty()) 199 inputBuffer.pop(); 200 201 inputIndex = 0; 202} 203 204void 205Execute::tryToBranch(MinorDynInstPtr inst, Fault fault, BranchData &branch) 206{ 207 ThreadContext *thread = cpu.getContext(inst->id.threadId); 208 const TheISA::PCState &pc_before = inst->pc; 209 TheISA::PCState target = thread->pcState(); 210 211 /* Force a branch for SerializeAfter instructions at the end of micro-op 212 * sequence when we're not suspended */ 213 bool force_branch = thread->status() != ThreadContext::Suspended && 214 !inst->isFault() && 215 inst->isLastOpInInst() && 216 (inst->staticInst->isSerializeAfter() || 217 inst->staticInst->isIprAccess()); 218 219 DPRINTF(Branch, "tryToBranch before: %s after: %s%s\n", 220 pc_before, target, (force_branch ? " (forcing)" : "")); 221 222 /* Will we change the PC to something other than the next instruction? */ 223 bool must_branch = pc_before != target || 224 fault != NoFault || 225 force_branch; 226 227 /* The reason for the branch data we're about to generate, set below */ 228 BranchData::Reason reason = BranchData::NoBranch; 229 230 if (fault == NoFault) 231 { 232 TheISA::advancePC(target, inst->staticInst); 233 thread->pcState(target); 234 235 DPRINTF(Branch, "Advancing current PC from: %s to: %s\n", 236 pc_before, target); 237 } 238 239 if (inst->predictedTaken && !force_branch) { 240 /* Predicted to branch */ 241 if (!must_branch) { 242 /* No branch was taken, change stream to get us back to the 243 * intended PC value */ 244 DPRINTF(Branch, "Predicted a branch from 0x%x to 0x%x but" 245 " none happened inst: %s\n", 246 inst->pc.instAddr(), inst->predictedTarget.instAddr(), *inst); 247 248 reason = BranchData::BadlyPredictedBranch; 249 } else if (inst->predictedTarget == target) { 250 /* Branch prediction got the right target, kill the branch and 251 * carry on. 252 * Note that this information to the branch predictor might get 253 * overwritten by a "real" branch during this cycle */ 254 DPRINTF(Branch, "Predicted a branch from 0x%x to 0x%x correctly" 255 " inst: %s\n", 256 inst->pc.instAddr(), inst->predictedTarget.instAddr(), *inst); 257 258 reason = BranchData::CorrectlyPredictedBranch; 259 } else { 260 /* Branch prediction got the wrong target */ 261 DPRINTF(Branch, "Predicted a branch from 0x%x to 0x%x" 262 " but got the wrong target (actual: 0x%x) inst: %s\n", 263 inst->pc.instAddr(), inst->predictedTarget.instAddr(), 264 target.instAddr(), *inst); 265 266 reason = BranchData::BadlyPredictedBranchTarget; 267 } 268 } else if (must_branch) { 269 /* Unpredicted branch */ 270 DPRINTF(Branch, "Unpredicted branch from 0x%x to 0x%x inst: %s\n", 271 inst->pc.instAddr(), target.instAddr(), *inst); 272 273 reason = BranchData::UnpredictedBranch; 274 } else { 275 /* No branch at all */ 276 reason = BranchData::NoBranch; 277 } 278 279 updateBranchData(reason, inst, target, branch); 280} 281 282void 283Execute::updateBranchData( 284 BranchData::Reason reason, 285 MinorDynInstPtr inst, const TheISA::PCState &target, 286 BranchData &branch) 287{ 288 if (reason != BranchData::NoBranch) { 289 /* Bump up the stream sequence number on a real branch*/ 290 if (BranchData::isStreamChange(reason)) 291 streamSeqNum++; 292 293 /* Branches (even mis-predictions) don't change the predictionSeqNum, 294 * just the streamSeqNum */ 295 branch = BranchData(reason, streamSeqNum, 296 /* Maintaining predictionSeqNum if there's no inst is just a 297 * courtesy and looks better on minorview */ 298 (inst->isBubble() ? lastPredictionSeqNum 299 : inst->id.predictionSeqNum), 300 target, inst); 301 302 DPRINTF(Branch, "Branch data signalled: %s\n", branch); 303 } 304} 305 306void 307Execute::handleMemResponse(MinorDynInstPtr inst, 308 LSQ::LSQRequestPtr response, BranchData &branch, Fault &fault) 309{ 310 ThreadID thread_id = inst->id.threadId; 311 ThreadContext *thread = cpu.getContext(thread_id); 312 313 ExecContext context(cpu, *cpu.threads[thread_id], *this, inst); 314 315 PacketPtr packet = response->packet; 316 317 bool is_load = inst->staticInst->isLoad(); 318 bool is_store = inst->staticInst->isStore(); 319 bool is_prefetch = inst->staticInst->isDataPrefetch(); 320 321 /* If true, the trace's predicate value will be taken from the exec 322 * context predicate, otherwise, it will be set to false */ 323 bool use_context_predicate = true; 324 325 if (response->fault != NoFault) { 326 /* Invoke memory faults. */ 327 DPRINTF(MinorMem, "Completing fault from DTLB access: %s\n", 328 response->fault->name()); 329 330 if (inst->staticInst->isPrefetch()) { 331 DPRINTF(MinorMem, "Not taking fault on prefetch: %s\n", 332 response->fault->name()); 333 334 /* Don't assign to fault */ 335 } else { 336 /* Take the fault raised during the TLB/memory access */ 337 fault = response->fault; 338 339 fault->invoke(thread, inst->staticInst); 340 } 341 } else if (!packet) { 342 DPRINTF(MinorMem, "Completing failed request inst: %s\n", 343 *inst); 344 use_context_predicate = false; 345 } else if (packet->isError()) { 346 DPRINTF(MinorMem, "Trying to commit error response: %s\n", 347 *inst); 348 349 fatal("Received error response packet for inst: %s\n", *inst); 350 } else if (is_store || is_load || is_prefetch) { 351 assert(packet); 352 353 DPRINTF(MinorMem, "Memory response inst: %s addr: 0x%x size: %d\n", 354 *inst, packet->getAddr(), packet->getSize()); 355 356 if (is_load && packet->getSize() > 0) { 357 DPRINTF(MinorMem, "Memory data[0]: 0x%x\n", 358 static_cast<unsigned int>(packet->getPtr<uint8_t>()[0])); 359 } 360 361 /* Complete the memory access instruction */ 362 fault = inst->staticInst->completeAcc(packet, &context, 363 inst->traceData); 364 365 if (fault != NoFault) { 366 /* Invoke fault created by instruction completion */ 367 DPRINTF(MinorMem, "Fault in memory completeAcc: %s\n", 368 fault->name()); 369 fault->invoke(thread, inst->staticInst); 370 } else { 371 /* Stores need to be pushed into the store buffer to finish 372 * them off */ 373 if (response->needsToBeSentToStoreBuffer()) 374 lsq.sendStoreToStoreBuffer(response); 375 } 376 } else { 377 fatal("There should only ever be reads, " 378 "writes or faults at this point\n"); 379 } 380 381 lsq.popResponse(response); 382 383 if (inst->traceData) { 384 inst->traceData->setPredicate((use_context_predicate ? 385 context.readPredicate() : false)); 386 } 387 388 doInstCommitAccounting(inst); 389 390 /* Generate output to account for branches */ 391 tryToBranch(inst, fault, branch); 392} 393 394bool 395Execute::isInterrupted(ThreadID thread_id) const 396{ 397 return cpu.checkInterrupts(cpu.getContext(thread_id)); 398} 399 400bool 401Execute::takeInterrupt(ThreadID thread_id, BranchData &branch) 402{ 403 DPRINTF(MinorInterrupt, "Considering interrupt status from PC: %s\n", 404 cpu.getContext(thread_id)->pcState()); 405 406 Fault interrupt = cpu.getInterruptController()->getInterrupt 407 (cpu.getContext(thread_id)); 408 409 if (interrupt != NoFault) { 410 /* The interrupt *must* set pcState */ 411 cpu.getInterruptController()->updateIntrInfo 412 (cpu.getContext(thread_id)); 413 interrupt->invoke(cpu.getContext(thread_id)); 414 415 assert(!lsq.accessesInFlight()); 416 417 DPRINTF(MinorInterrupt, "Invoking interrupt: %s to PC: %s\n", 418 interrupt->name(), cpu.getContext(thread_id)->pcState()); 419 420 /* Assume that an interrupt *must* cause a branch. Assert this? */ 421 422 updateBranchData(BranchData::Interrupt, MinorDynInst::bubble(), 423 cpu.getContext(thread_id)->pcState(), branch); 424 } 425 426 return interrupt != NoFault; 427} 428 429bool 430Execute::executeMemRefInst(MinorDynInstPtr inst, BranchData &branch, 431 bool &passed_predicate, Fault &fault) 432{ 433 bool issued = false; 434 435 /* Set to true if the mem op. is issued and sent to the mem system */ 436 passed_predicate = false; 437 438 if (!lsq.canRequest()) { 439 /* Not acting on instruction yet as the memory 440 * queues are full */ 441 issued = false; 442 } else { 443 ThreadContext *thread = cpu.getContext(inst->id.threadId); 444 TheISA::PCState old_pc = thread->pcState(); 445 446 ExecContext context(cpu, *cpu.threads[inst->id.threadId], 447 *this, inst); 448 449 DPRINTF(MinorExecute, "Initiating memRef inst: %s\n", *inst); 450 451 Fault init_fault = inst->staticInst->initiateAcc(&context, 452 inst->traceData); 453 454 if (init_fault != NoFault) { 455 DPRINTF(MinorExecute, "Fault on memory inst: %s" 456 " initiateAcc: %s\n", *inst, init_fault->name()); 457 fault = init_fault; 458 } else { 459 /* Only set this if the instruction passed its 460 * predicate */ 461 passed_predicate = context.readPredicate(); 462 463 /* Set predicate in tracing */ 464 if (inst->traceData) 465 inst->traceData->setPredicate(passed_predicate); 466 467 /* If the instruction didn't pass its predicate (and so will not 468 * progress from here) Try to branch to correct and branch 469 * mis-prediction. */ 470 if (!passed_predicate) { 471 /* Leave it up to commit to handle the fault */ 472 lsq.pushFailedRequest(inst); 473 } 474 } 475 476 /* Restore thread PC */ 477 thread->pcState(old_pc); 478 issued = true; 479 } 480 481 return issued; 482} 483 484/** Increment a cyclic buffer index for indices [0, cycle_size-1] */ 485inline unsigned int 486cyclicIndexInc(unsigned int index, unsigned int cycle_size) 487{ 488 unsigned int ret = index + 1; 489 490 if (ret == cycle_size) 491 ret = 0; 492 493 return ret; 494} 495 496/** Decrement a cyclic buffer index for indices [0, cycle_size-1] */ 497inline unsigned int 498cyclicIndexDec(unsigned int index, unsigned int cycle_size) 499{ 500 int ret = index - 1; 501 502 if (ret < 0) 503 ret = cycle_size - 1; 504 505 return ret; 506} 507 508unsigned int 509Execute::issue(bool only_issue_microops) 510{ 511 const ForwardInstData *insts_in = getInput(); 512 513 /* Early termination if we have no instructions */ 514 if (!insts_in) 515 return 0; 516 517 /* Start from the first FU */ 518 unsigned int fu_index = 0; 519 520 /* Remains true while instructions are still being issued. If any 521 * instruction fails to issue, this is set to false and we exit issue. 522 * This strictly enforces in-order issue. For other issue behaviours, 523 * a more complicated test in the outer while loop below is needed. */ 524 bool issued = true; 525 526 /* Number of insts issues this cycle to check for issueLimit */ 527 unsigned num_insts_issued = 0; 528 529 /* Number of memory ops issues this cycle to check for memoryIssueLimit */ 530 unsigned num_mem_insts_issued = 0; 531 532 /* Number of instructions discarded this cycle in order to enforce a 533 * discardLimit. @todo, add that parameter? */ 534 unsigned num_insts_discarded = 0; 535 536 do { 537 MinorDynInstPtr inst = insts_in->insts[inputIndex]; 538 ThreadID thread_id = inst->id.threadId; 539 Fault fault = inst->fault; 540 bool discarded = false; 541 bool issued_mem_ref = false; 542 543 if (inst->isBubble()) { 544 /* Skip */ 545 issued = true; 546 } else if (cpu.getContext(thread_id)->status() == 547 ThreadContext::Suspended) 548 { 549 DPRINTF(MinorExecute, "Not issuing inst: %s from suspended" 550 " thread\n", *inst); 551 552 issued = false; 553 } else if (inst->id.streamSeqNum != streamSeqNum) { 554 DPRINTF(MinorExecute, "Discarding inst: %s as its stream" 555 " state was unexpected, expected: %d\n", 556 *inst, streamSeqNum); 557 issued = true; 558 discarded = true; 559 } else if (fault == NoFault && only_issue_microops && 560 /* Is this anything other than a non-first microop */ 561 (!inst->staticInst->isMicroop() || 562 !inst->staticInst->isFirstMicroop())) 563 { 564 DPRINTF(MinorExecute, "Not issuing new non-microop inst: %s\n", 565 *inst); 566 567 issued = false; 568 } else { 569 /* Try and issue an instruction into an FU, assume we didn't and 570 * fix that in the loop */ 571 issued = false; 572 573 /* Try FU from 0 each instruction */ 574 fu_index = 0; 575 576 /* Try and issue a single instruction stepping through the 577 * available FUs */ 578 do { 579 FUPipeline *fu = funcUnits[fu_index]; 580 581 DPRINTF(MinorExecute, "Trying to issue inst: %s to FU: %d\n", 582 *inst, fu_index); 583 584 /* Does the examined fu have the OpClass-related capability 585 * needed to execute this instruction? Faults can always 586 * issue to any FU but probably should just 'live' in the 587 * inFlightInsts queue rather than having an FU. */ 588 bool fu_is_capable = (!inst->isFault() ? 589 fu->provides(inst->staticInst->opClass()) : true); 590 591 if (inst->isNoCostInst()) { 592 /* Issue free insts. to a fake numbered FU */ 593 fu_index = noCostFUIndex; 594 595 /* And start the countdown on activity to allow 596 * this instruction to get to the end of its FU */ 597 cpu.activityRecorder->activity(); 598 599 /* Mark the destinations for this instruction as 600 * busy */ 601 scoreboard.markupInstDests(inst, cpu.curCycle() + 602 Cycles(0), cpu.getContext(thread_id), false); 603 604 inst->fuIndex = noCostFUIndex; 605 inst->extraCommitDelay = Cycles(0); 606 inst->extraCommitDelayExpr = NULL; 607 608 /* Push the instruction onto the inFlight queue so 609 * it can be committed in order */ 610 QueuedInst fu_inst(inst); 611 inFlightInsts->push(fu_inst); 612 613 issued = true; 614 615 } else if (!fu_is_capable || fu->alreadyPushed()) { 616 /* Skip */ 617 if (!fu_is_capable) { 618 DPRINTF(MinorExecute, "Can't issue as FU: %d isn't" 619 " capable\n", fu_index); 620 } else { 621 DPRINTF(MinorExecute, "Can't issue as FU: %d is" 622 " already busy\n", fu_index); 623 } 624 } else if (fu->stalled) { 625 DPRINTF(MinorExecute, "Can't issue inst: %s into FU: %d," 626 " it's stalled\n", 627 *inst, fu_index); 628 } else if (!fu->canInsert()) { 629 DPRINTF(MinorExecute, "Can't issue inst: %s to busy FU" 630 " for another: %d cycles\n", 631 *inst, fu->cyclesBeforeInsert()); 632 } else { 633 MinorFUTiming *timing = (!inst->isFault() ? 634 fu->findTiming(inst->staticInst) : NULL); 635 636 const std::vector<Cycles> *src_latencies = 637 (timing ? &(timing->srcRegsRelativeLats) 638 : NULL); 639 640 const std::vector<bool> *cant_forward_from_fu_indices = 641 &(fu->cantForwardFromFUIndices); 642 643 if (timing && timing->suppress) { 644 DPRINTF(MinorExecute, "Can't issue inst: %s as extra" 645 " decoding is suppressing it\n", 646 *inst); 647 } else if (!scoreboard.canInstIssue(inst, src_latencies, 648 cant_forward_from_fu_indices, 649 cpu.curCycle(), cpu.getContext(thread_id))) 650 { 651 DPRINTF(MinorExecute, "Can't issue inst: %s yet\n", 652 *inst); 653 } else { 654 /* Can insert the instruction into this FU */ 655 DPRINTF(MinorExecute, "Issuing inst: %s" 656 " into FU %d\n", *inst, 657 fu_index); 658 659 Cycles extra_dest_retire_lat = Cycles(0); 660 TimingExpr *extra_dest_retire_lat_expr = NULL; 661 Cycles extra_assumed_lat = Cycles(0); 662 663 /* Add the extraCommitDelay and extraAssumeLat to 664 * the FU pipeline timings */ 665 if (timing) { 666 extra_dest_retire_lat = 667 timing->extraCommitLat; 668 extra_dest_retire_lat_expr = 669 timing->extraCommitLatExpr; 670 extra_assumed_lat = 671 timing->extraAssumedLat; 672 } 673 674 bool issued_mem_ref = inst->isMemRef(); 675 676 QueuedInst fu_inst(inst); 677 678 /* Decorate the inst with FU details */ 679 inst->fuIndex = fu_index; 680 inst->extraCommitDelay = extra_dest_retire_lat; 681 inst->extraCommitDelayExpr = 682 extra_dest_retire_lat_expr; 683 684 if (issued_mem_ref) { 685 /* Remember which instruction this memory op 686 * depends on so that initiateAcc can be called 687 * early */ 688 if (allowEarlyMemIssue) { 689 inst->instToWaitFor = 690 scoreboard.execSeqNumToWaitFor(inst, 691 cpu.getContext(thread_id)); 692 693 if (lsq.getLastMemBarrier() > 694 inst->instToWaitFor) 695 { 696 DPRINTF(MinorExecute, "A barrier will" 697 " cause a delay in mem ref issue of" 698 " inst: %s until after inst" 699 " %d(exec)\n", *inst, 700 lsq.getLastMemBarrier()); 701 702 inst->instToWaitFor = 703 lsq.getLastMemBarrier(); 704 } else { 705 DPRINTF(MinorExecute, "Memory ref inst:" 706 " %s must wait for inst %d(exec)" 707 " before issuing\n", 708 *inst, inst->instToWaitFor); 709 } 710 711 inst->canEarlyIssue = true; 712 } 713 /* Also queue this instruction in the memory ref 714 * queue to ensure in-order issue to the LSQ */ 715 DPRINTF(MinorExecute, "Pushing mem inst: %s\n", 716 *inst); 717 inFUMemInsts->push(fu_inst); 718 } 719 720 /* Issue to FU */ 721 fu->push(fu_inst); 722 /* And start the countdown on activity to allow 723 * this instruction to get to the end of its FU */ 724 cpu.activityRecorder->activity(); 725 726 /* Mark the destinations for this instruction as 727 * busy */ 728 scoreboard.markupInstDests(inst, cpu.curCycle() + 729 fu->description.opLat + 730 extra_dest_retire_lat + 731 extra_assumed_lat, 732 cpu.getContext(thread_id), 733 issued_mem_ref && extra_assumed_lat == Cycles(0)); 734 735 /* Push the instruction onto the inFlight queue so 736 * it can be committed in order */ 737 inFlightInsts->push(fu_inst); 738 739 issued = true; 740 } 741 } 742 743 fu_index++; 744 } while (fu_index != numFuncUnits && !issued); 745 746 if (!issued) 747 DPRINTF(MinorExecute, "Didn't issue inst: %s\n", *inst); 748 } 749 750 if (issued) { 751 /* Generate MinorTrace's MinorInst lines. Do this at commit 752 * to allow better instruction annotation? */ 753 if (DTRACE(MinorTrace) && !inst->isBubble()) 754 inst->minorTraceInst(*this); 755 756 /* Mark up barriers in the LSQ */ 757 if (!discarded && inst->isInst() && 758 inst->staticInst->isMemBarrier()) 759 { 760 DPRINTF(MinorMem, "Issuing memory barrier inst: %s\n", *inst); 761 lsq.issuedMemBarrierInst(inst); 762 } 763 764 if (inst->traceData && setTraceTimeOnIssue) { 765 inst->traceData->setWhen(curTick()); 766 } 767 768 if (issued_mem_ref) 769 num_mem_insts_issued++; 770 771 if (discarded) { 772 num_insts_discarded++; 773 } else { 774 num_insts_issued++; 775 776 if (num_insts_issued == issueLimit) 777 DPRINTF(MinorExecute, "Reached inst issue limit\n"); 778 } 779 780 inputIndex++; 781 DPRINTF(MinorExecute, "Stepping to next inst inputIndex: %d\n", 782 inputIndex); 783 } 784 785 /* Got to the end of a line */ 786 if (inputIndex == insts_in->width()) { 787 popInput(); 788 /* Set insts_in to null to force us to leave the surrounding 789 * loop */ 790 insts_in = NULL; 791 792 if (processMoreThanOneInput) { 793 DPRINTF(MinorExecute, "Wrapping\n"); 794 insts_in = getInput(); 795 } 796 } 797 } while (insts_in && inputIndex < insts_in->width() && 798 /* We still have instructions */ 799 fu_index != numFuncUnits && /* Not visited all FUs */ 800 issued && /* We've not yet failed to issue an instruction */ 801 num_insts_issued != issueLimit && /* Still allowed to issue */ 802 num_mem_insts_issued != memoryIssueLimit); 803 804 return num_insts_issued; 805} 806 807bool 808Execute::tryPCEvents() 809{ 810 ThreadContext *thread = cpu.getContext(0); 811 unsigned int num_pc_event_checks = 0; 812 813 /* Handle PC events on instructions */ 814 Addr oldPC; 815 do { 816 oldPC = thread->instAddr(); 817 cpu.system->pcEventQueue.service(thread); 818 num_pc_event_checks++; 819 } while (oldPC != thread->instAddr()); 820 821 if (num_pc_event_checks > 1) { 822 DPRINTF(PCEvent, "Acting on PC Event to PC: %s\n", 823 thread->pcState()); 824 } 825 826 return num_pc_event_checks > 1; 827} 828 829void 830Execute::doInstCommitAccounting(MinorDynInstPtr inst) 831{ 832 assert(!inst->isFault()); 833 834 MinorThread *thread = cpu.threads[inst->id.threadId]; 835 836 /* Increment the many and various inst and op counts in the 837 * thread and system */ 838 if (!inst->staticInst->isMicroop() || inst->staticInst->isLastMicroop()) 839 { 840 thread->numInst++; 841 thread->numInsts++; 842 cpu.stats.numInsts++; 843 } 844 thread->numOp++; 845 thread->numOps++; 846 cpu.stats.numOps++; 847 cpu.system->totalNumInsts++; 848 849 /* Act on events related to instruction counts */ 850 cpu.comInstEventQueue[inst->id.threadId]->serviceEvents(thread->numInst); 851 cpu.system->instEventQueue.serviceEvents(cpu.system->totalNumInsts); 852 853 /* Set the CP SeqNum to the numOps commit number */ 854 if (inst->traceData) 855 inst->traceData->setCPSeq(thread->numOp); 856} 857 858bool 859Execute::commitInst(MinorDynInstPtr inst, bool early_memory_issue, 860 BranchData &branch, Fault &fault, bool &committed, 861 bool &completed_mem_issue) 862{ 863 ThreadID thread_id = inst->id.threadId; 864 ThreadContext *thread = cpu.getContext(thread_id); 865 866 bool completed_inst = true; 867 fault = NoFault; 868 869 /* Is the thread for this instruction suspended? In that case, just 870 * stall as long as there are no pending interrupts */ 871 if (thread->status() == ThreadContext::Suspended && 872 !isInterrupted(thread_id)) 873 { 874 DPRINTF(MinorExecute, "Not committing inst from suspended thread" 875 " inst: %s\n", *inst); 876 completed_inst = false; 877 } else if (inst->isFault()) { 878 ExecContext context(cpu, *cpu.threads[thread_id], *this, inst); 879 880 DPRINTF(MinorExecute, "Fault inst reached Execute: %s\n", 881 inst->fault->name()); 882 883 fault = inst->fault; 884 inst->fault->invoke(thread, NULL); 885 886 tryToBranch(inst, fault, branch); 887 } else if (inst->staticInst->isMemRef()) { 888 /* Memory accesses are executed in two parts: 889 * executeMemRefInst -- calculates the EA and issues the access 890 * to memory. This is done here. 891 * handleMemResponse -- handles the response packet, done by 892 * Execute::commit 893 * 894 * While the memory access is in its FU, the EA is being 895 * calculated. At the end of the FU, when it is ready to 896 * 'commit' (in this function), the access is presented to the 897 * memory queues. When a response comes back from memory, 898 * Execute::commit will commit it. 899 */ 900 bool predicate_passed = false; 901 bool completed_mem_inst = executeMemRefInst(inst, branch, 902 predicate_passed, fault); 903 904 if (completed_mem_inst && fault != NoFault) { 905 if (early_memory_issue) { 906 DPRINTF(MinorExecute, "Fault in early executing inst: %s\n", 907 fault->name()); 908 /* Don't execute the fault, just stall the instruction 909 * until it gets to the head of inFlightInsts */ 910 inst->canEarlyIssue = false; 911 /* Not completed as we'll come here again to pick up 912 * the fault when we get to the end of the FU */ 913 completed_inst = false; 914 } else { 915 DPRINTF(MinorExecute, "Fault in execute: %s\n", 916 fault->name()); 917 fault->invoke(thread, NULL); 918 919 tryToBranch(inst, fault, branch); 920 completed_inst = true; 921 } 922 } else { 923 completed_inst = completed_mem_inst; 924 } 925 completed_mem_issue = completed_inst; 926 } else if (inst->isInst() && inst->staticInst->isMemBarrier() && 927 !lsq.canPushIntoStoreBuffer()) 928 { 929 DPRINTF(MinorExecute, "Can't commit data barrier inst: %s yet as" 930 " there isn't space in the store buffer\n", *inst); 931 932 completed_inst = false; 933 } else { 934 ExecContext context(cpu, *cpu.threads[thread_id], *this, inst); 935 936 DPRINTF(MinorExecute, "Committing inst: %s\n", *inst); 937 938 fault = inst->staticInst->execute(&context, 939 inst->traceData); 940 941 /* Set the predicate for tracing and dump */ 942 if (inst->traceData) 943 inst->traceData->setPredicate(context.readPredicate()); 944 945 committed = true; 946 947 if (fault != NoFault) { 948 DPRINTF(MinorExecute, "Fault in execute of inst: %s fault: %s\n", 949 *inst, fault->name()); 950 fault->invoke(thread, inst->staticInst); 951 } 952 953 doInstCommitAccounting(inst); 954 tryToBranch(inst, fault, branch); 955 } 956 957 if (completed_inst) { 958 /* Keep a copy of this instruction's predictionSeqNum just in case 959 * we need to issue a branch without an instruction (such as an 960 * interrupt) */ 961 lastPredictionSeqNum = inst->id.predictionSeqNum; 962 963 /* Check to see if this instruction suspended the current thread. */ 964 if (!inst->isFault() && 965 thread->status() == ThreadContext::Suspended && 966 branch.isBubble() && /* It didn't branch too */ 967 !isInterrupted(thread_id)) /* Don't suspend if we have 968 interrupts */ 969 { 970 TheISA::PCState resume_pc = cpu.getContext(0)->pcState(); 971 972 assert(resume_pc.microPC() == 0); 973 974 DPRINTF(MinorInterrupt, "Suspending thread: %d from Execute" 975 " inst: %s\n", inst->id.threadId, *inst); 976 977 cpu.stats.numFetchSuspends++; 978 979 updateBranchData(BranchData::SuspendThread, inst, resume_pc, 980 branch); 981 } 982 } 983 984 return completed_inst; 985} 986 987void 988Execute::commit(bool only_commit_microops, bool discard, BranchData &branch) 989{ 990 Fault fault = NoFault; 991 Cycles now = cpu.curCycle(); 992 993 /** 994 * Try and execute as many instructions from the end of FU pipelines as 995 * possible. This *doesn't* include actually advancing the pipelines. 996 * 997 * We do this by looping on the front of the inFlightInsts queue for as 998 * long as we can find the desired instruction at the end of the 999 * functional unit it was issued to without seeing a branch or a fault. 1000 * In this function, these terms are used: 1001 * complete -- The instruction has finished its passage through 1002 * its functional unit and its fate has been decided 1003 * (committed, discarded, issued to the memory system) 1004 * commit -- The instruction is complete(d), not discarded and has 1005 * its effects applied to the CPU state 1006 * discard(ed) -- The instruction is complete but not committed 1007 * as its streamSeqNum disagrees with the current 1008 * Execute::streamSeqNum 1009 * 1010 * Commits are also possible from two other places: 1011 * 1012 * 1) Responses returning from the LSQ 1013 * 2) Mem ops issued to the LSQ ('committed' from the FUs) earlier 1014 * than their position in the inFlightInsts queue, but after all 1015 * their dependencies are resolved. 1016 */ 1017 1018 /* Has an instruction been completed? Once this becomes false, we stop 1019 * trying to complete instructions. */ 1020 bool completed_inst = true; 1021 1022 /* Number of insts committed this cycle to check against commitLimit */ 1023 unsigned int num_insts_committed = 0; 1024 1025 /* Number of memory access instructions committed to check against 1026 * memCommitLimit */ 1027 unsigned int num_mem_refs_committed = 0; 1028 1029 if (only_commit_microops && !inFlightInsts->empty()) { 1030 DPRINTF(MinorInterrupt, "Only commit microops %s %d\n", 1031 *(inFlightInsts->front().inst), 1032 lastCommitWasEndOfMacroop); 1033 } 1034 1035 while (!inFlightInsts->empty() && /* Some more instructions to process */ 1036 !branch.isStreamChange() && /* No real branch */ 1037 fault == NoFault && /* No faults */ 1038 completed_inst && /* Still finding instructions to execute */ 1039 num_insts_committed != commitLimit /* Not reached commit limit */ 1040 ) 1041 { 1042 if (only_commit_microops) { 1043 DPRINTF(MinorInterrupt, "Committing tail of insts before" 1044 " interrupt: %s\n", 1045 *(inFlightInsts->front().inst)); 1046 } 1047 1048 QueuedInst *head_inflight_inst = &(inFlightInsts->front()); 1049 1050 InstSeqNum head_exec_seq_num = 1051 head_inflight_inst->inst->id.execSeqNum; 1052 1053 /* The instruction we actually process if completed_inst 1054 * remains true to the end of the loop body. 1055 * Start by considering the the head of the in flight insts queue */ 1056 MinorDynInstPtr inst = head_inflight_inst->inst; 1057 1058 bool committed_inst = false; 1059 bool discard_inst = false; 1060 bool completed_mem_ref = false; 1061 bool issued_mem_ref = false; 1062 bool early_memory_issue = false; 1063 1064 /* Must set this again to go around the loop */ 1065 completed_inst = false; 1066 1067 /* If we're just completing a macroop before an interrupt or drain, 1068 * can we stil commit another microop (rather than a memory response) 1069 * without crosing into the next full instruction? */ 1070 bool can_commit_insts = !inFlightInsts->empty() && 1071 !(only_commit_microops && lastCommitWasEndOfMacroop); 1072 1073 /* Can we find a mem response for this inst */ 1074 LSQ::LSQRequestPtr mem_response = 1075 (inst->inLSQ ? lsq.findResponse(inst) : NULL); 1076 1077 DPRINTF(MinorExecute, "Trying to commit canCommitInsts: %d\n", 1078 can_commit_insts); 1079 1080 /* Test for PC events after every instruction */ 1081 if (isInbetweenInsts() && tryPCEvents()) { 1082 ThreadContext *thread = cpu.getContext(0); 1083 1084 /* Branch as there was a change in PC */ 1085 updateBranchData(BranchData::UnpredictedBranch, 1086 MinorDynInst::bubble(), thread->pcState(), branch); 1087 } else if (mem_response && 1088 num_mem_refs_committed < memoryCommitLimit) 1089 { 1090 /* Try to commit from the memory responses next */ 1091 discard_inst = inst->id.streamSeqNum != streamSeqNum || 1092 discard; 1093 1094 DPRINTF(MinorExecute, "Trying to commit mem response: %s\n", 1095 *inst); 1096 1097 /* Complete or discard the response */ 1098 if (discard_inst) { 1099 DPRINTF(MinorExecute, "Discarding mem inst: %s as its" 1100 " stream state was unexpected, expected: %d\n", 1101 *inst, streamSeqNum); 1102 1103 lsq.popResponse(mem_response); 1104 } else { 1105 handleMemResponse(inst, mem_response, branch, fault); 1106 committed_inst = true; 1107 } 1108 1109 completed_mem_ref = true; 1110 completed_inst = true; 1111 } else if (can_commit_insts) { 1112 /* If true, this instruction will, subject to timing tweaks, 1113 * be considered for completion. try_to_commit flattens 1114 * the `if' tree a bit and allows other tests for inst 1115 * commit to be inserted here. */ 1116 bool try_to_commit = false; 1117 1118 /* Try and issue memory ops early if they: 1119 * - Can push a request into the LSQ 1120 * - Have reached the end of their FUs 1121 * - Have had all their dependencies satisfied 1122 * - Are from the right stream 1123 * 1124 * For any other case, leave it to the normal instruction 1125 * issue below to handle them. 1126 */ 1127 if (!inFUMemInsts->empty() && lsq.canRequest()) { 1128 DPRINTF(MinorExecute, "Trying to commit from mem FUs\n"); 1129 1130 const MinorDynInstPtr head_mem_ref_inst = 1131 inFUMemInsts->front().inst; 1132 FUPipeline *fu = funcUnits[head_mem_ref_inst->fuIndex]; 1133 const MinorDynInstPtr &fu_inst = fu->front().inst; 1134 1135 /* Use this, possibly out of order, inst as the one 1136 * to 'commit'/send to the LSQ */ 1137 if (!fu_inst->isBubble() && 1138 !fu_inst->inLSQ && 1139 fu_inst->canEarlyIssue && 1140 streamSeqNum == fu_inst->id.streamSeqNum && 1141 head_exec_seq_num > fu_inst->instToWaitFor) 1142 { 1143 DPRINTF(MinorExecute, "Issuing mem ref early" 1144 " inst: %s instToWaitFor: %d\n", 1145 *(fu_inst), fu_inst->instToWaitFor); 1146 1147 inst = fu_inst; 1148 try_to_commit = true; 1149 early_memory_issue = true; 1150 completed_inst = true; 1151 } 1152 } 1153 1154 /* Try and commit FU-less insts */ 1155 if (!completed_inst && inst->isNoCostInst()) { 1156 DPRINTF(MinorExecute, "Committing no cost inst: %s", *inst); 1157 1158 try_to_commit = true; 1159 completed_inst = true; 1160 } 1161 1162 /* Try to issue from the ends of FUs and the inFlightInsts 1163 * queue */ 1164 if (!completed_inst && !inst->inLSQ) { 1165 DPRINTF(MinorExecute, "Trying to commit from FUs\n"); 1166 1167 /* Try to commit from a functional unit */ 1168 /* Is the head inst of the expected inst's FU actually the 1169 * expected inst? */ 1170 QueuedInst &fu_inst = 1171 funcUnits[inst->fuIndex]->front(); 1172 InstSeqNum fu_inst_seq_num = fu_inst.inst->id.execSeqNum; 1173 1174 if (fu_inst.inst->isBubble()) { 1175 /* No instruction ready */ 1176 completed_inst = false; 1177 } else if (fu_inst_seq_num != head_exec_seq_num) { 1178 /* Past instruction: we must have already executed it 1179 * in the same cycle and so the head inst isn't 1180 * actually at the end of its pipeline 1181 * Future instruction: handled above and only for 1182 * mem refs on their way to the LSQ */ 1183 } else /* if (fu_inst_seq_num == head_exec_seq_num) */ { 1184 /* All instructions can be committed if they have the 1185 * right execSeqNum and there are no in-flight 1186 * mem insts before us */ 1187 try_to_commit = true; 1188 completed_inst = true; 1189 } 1190 } 1191 1192 if (try_to_commit) { 1193 discard_inst = inst->id.streamSeqNum != streamSeqNum || 1194 discard; 1195 1196 /* Is this instruction discardable as its streamSeqNum 1197 * doesn't match? */ 1198 if (!discard_inst) { 1199 /* Try to commit or discard a non-memory instruction. 1200 * Memory ops are actually 'committed' from this FUs 1201 * and 'issued' into the memory system so we need to 1202 * account for them later (commit_was_mem_issue gets 1203 * set) */ 1204 if (inst->extraCommitDelayExpr) { 1205 DPRINTF(MinorExecute, "Evaluating expression for" 1206 " extra commit delay inst: %s\n", *inst); 1207 1208 ThreadContext *thread = 1209 cpu.getContext(inst->id.threadId); 1210 1211 TimingExprEvalContext context(inst->staticInst, 1212 thread, NULL); 1213 1214 uint64_t extra_delay = inst->extraCommitDelayExpr-> 1215 eval(context); 1216 1217 DPRINTF(MinorExecute, "Extra commit delay expr" 1218 " result: %d\n", extra_delay); 1219 1220 if (extra_delay < 128) { 1221 inst->extraCommitDelay += Cycles(extra_delay); 1222 } else { 1223 DPRINTF(MinorExecute, "Extra commit delay was" 1224 " very long: %d\n", extra_delay); 1225 } 1226 inst->extraCommitDelayExpr = NULL; 1227 } 1228 1229 /* Move the extraCommitDelay from the instruction 1230 * into the minimumCommitCycle */ 1231 if (inst->extraCommitDelay != Cycles(0)) { 1232 inst->minimumCommitCycle = cpu.curCycle() + 1233 inst->extraCommitDelay; 1234 inst->extraCommitDelay = Cycles(0); 1235 } 1236 1237 /* @todo Think about making lastMemBarrier be 1238 * MAX_UINT_64 to avoid using 0 as a marker value */ 1239 if (!inst->isFault() && inst->isMemRef() && 1240 lsq.getLastMemBarrier() < 1241 inst->id.execSeqNum && 1242 lsq.getLastMemBarrier() != 0) 1243 { 1244 DPRINTF(MinorExecute, "Not committing inst: %s yet" 1245 " as there are incomplete barriers in flight\n", 1246 *inst); 1247 completed_inst = false; 1248 } else if (inst->minimumCommitCycle > now) { 1249 DPRINTF(MinorExecute, "Not committing inst: %s yet" 1250 " as it wants to be stalled for %d more cycles\n", 1251 *inst, inst->minimumCommitCycle - now); 1252 completed_inst = false; 1253 } else { 1254 completed_inst = commitInst(inst, 1255 early_memory_issue, branch, fault, 1256 committed_inst, issued_mem_ref); 1257 } 1258 } else { 1259 /* Discard instruction */ 1260 completed_inst = true; 1261 } 1262 1263 if (completed_inst) { 1264 /* Allow the pipeline to advance. If the FU head 1265 * instruction wasn't the inFlightInsts head 1266 * but had already been committed, it would have 1267 * unstalled the pipeline before here */ 1268 if (inst->fuIndex != noCostFUIndex) 1269 funcUnits[inst->fuIndex]->stalled = false; 1270 } 1271 } 1272 } else { 1273 DPRINTF(MinorExecute, "No instructions to commit\n"); 1274 completed_inst = false; 1275 } 1276 1277 /* All discardable instructions must also be 'completed' by now */ 1278 assert(!(discard_inst && !completed_inst)); 1279 1280 /* Instruction committed but was discarded due to streamSeqNum 1281 * mismatch */ 1282 if (discard_inst) { 1283 DPRINTF(MinorExecute, "Discarding inst: %s as its stream" 1284 " state was unexpected, expected: %d\n", 1285 *inst, streamSeqNum); 1286 1287 if (fault == NoFault) 1288 cpu.stats.numDiscardedOps++; 1289 } 1290 1291 /* Mark the mem inst as being in the LSQ */ 1292 if (issued_mem_ref) { 1293 inst->fuIndex = 0; 1294 inst->inLSQ = true; 1295 } 1296 1297 /* Pop issued (to LSQ) and discarded mem refs from the inFUMemInsts 1298 * as they've *definitely* exited the FUs */ 1299 if (completed_inst && inst->isMemRef()) { 1300 /* The MemRef could have been discarded from the FU or the memory 1301 * queue, so just check an FU instruction */ 1302 if (!inFUMemInsts->empty() && 1303 inFUMemInsts->front().inst == inst) 1304 { 1305 inFUMemInsts->pop(); 1306 } 1307 } 1308 1309 if (completed_inst && !(issued_mem_ref && fault == NoFault)) { 1310 /* Note that this includes discarded insts */ 1311 DPRINTF(MinorExecute, "Completed inst: %s\n", *inst); 1312 1313 /* Got to the end of a full instruction? */ 1314 lastCommitWasEndOfMacroop = inst->isFault() || 1315 inst->isLastOpInInst(); 1316 1317 /* lastPredictionSeqNum is kept as a convenience to prevent its 1318 * value from changing too much on the minorview display */ 1319 lastPredictionSeqNum = inst->id.predictionSeqNum; 1320 1321 /* Finished with the inst, remove it from the inst queue and 1322 * clear its dependencies */ 1323 inFlightInsts->pop(); 1324 1325 /* Complete barriers in the LSQ/move to store buffer */ 1326 if (inst->isInst() && inst->staticInst->isMemBarrier()) { 1327 DPRINTF(MinorMem, "Completing memory barrier" 1328 " inst: %s committed: %d\n", *inst, committed_inst); 1329 lsq.completeMemBarrierInst(inst, committed_inst); 1330 } 1331 1332 scoreboard.clearInstDests(inst, inst->isMemRef()); 1333 } 1334 1335 /* Handle per-cycle instruction counting */ 1336 if (committed_inst) { 1337 bool is_no_cost_inst = inst->isNoCostInst(); 1338 1339 /* Don't show no cost instructions as having taken a commit 1340 * slot */ 1341 if (DTRACE(MinorTrace) && !is_no_cost_inst) 1342 instsBeingCommitted.insts[num_insts_committed] = inst; 1343 1344 if (!is_no_cost_inst) 1345 num_insts_committed++; 1346 1347 if (num_insts_committed == commitLimit) 1348 DPRINTF(MinorExecute, "Reached inst commit limit\n"); 1349 1350 /* Re-set the time of the instruction if that's required for 1351 * tracing */ 1352 if (inst->traceData) { 1353 if (setTraceTimeOnCommit) 1354 inst->traceData->setWhen(curTick()); 1355 inst->traceData->dump(); 1356 } 1357 1358 if (completed_mem_ref) 1359 num_mem_refs_committed++; 1360 1361 if (num_mem_refs_committed == memoryCommitLimit) 1362 DPRINTF(MinorExecute, "Reached mem ref commit limit\n"); 1363 } 1364 } 1365} 1366 1367bool 1368Execute::isInbetweenInsts() const 1369{ 1370 return lastCommitWasEndOfMacroop && 1371 !lsq.accessesInFlight(); 1372} 1373 1374void 1375Execute::evaluate() 1376{ 1377 inputBuffer.setTail(*inp.outputWire); 1378 BranchData &branch = *out.inputWire; 1379 1380 const ForwardInstData *insts_in = getInput(); 1381 1382 /* Do all the cycle-wise activities for dcachePort here to potentially 1383 * free up input spaces in the LSQ's requests queue */ 1384 lsq.step(); 1385 1386 /* Has an interrupt been signalled? This may not be acted on 1387 * straighaway so this is different from took_interrupt below */ 1388 bool interrupted = false; 1389 /* If there was an interrupt signalled, was it acted on now? */ 1390 bool took_interrupt = false; 1391 1392 if (cpu.getInterruptController()) { 1393 /* This is here because it seems that after drainResume the 1394 * interrupt controller isn't always set */ 1395 interrupted = drainState == NotDraining && isInterrupted(0); 1396 } else { 1397 DPRINTF(MinorInterrupt, "No interrupt controller\n"); 1398 } 1399 1400 unsigned int num_issued = 0; 1401 1402 if (DTRACE(MinorTrace)) { 1403 /* Empty the instsBeingCommitted for MinorTrace */ 1404 instsBeingCommitted.bubbleFill(); 1405 } 1406 1407 /* THREAD threadId on isInterrupted */ 1408 /* Act on interrupts */ 1409 if (interrupted && isInbetweenInsts()) { 1410 took_interrupt = takeInterrupt(0, branch); 1411 /* Clear interrupted if no interrupt was actually waiting */ 1412 interrupted = took_interrupt; 1413 } 1414 1415 if (took_interrupt) { 1416 /* Do no commit/issue this cycle */ 1417 } else if (!branch.isBubble()) { 1418 /* It's important that this is here to carry Fetch1 wakeups to Fetch1 1419 * without overwriting them */ 1420 DPRINTF(MinorInterrupt, "Execute skipping a cycle to allow old" 1421 " branch to complete\n"); 1422 } else { 1423 if (interrupted) { 1424 if (inFlightInsts->empty()) { 1425 DPRINTF(MinorInterrupt, "Waiting but no insts\n"); 1426 } else { 1427 DPRINTF(MinorInterrupt, "Waiting for end of inst before" 1428 " signalling interrupt\n"); 1429 } 1430 } 1431 1432 /* commit can set stalled flags observable to issue and so *must* be 1433 * called first */ 1434 if (drainState != NotDraining) { 1435 if (drainState == DrainCurrentInst) { 1436 /* Commit only micro-ops, don't kill anything else */ 1437 commit(true, false, branch); 1438 1439 if (isInbetweenInsts()) 1440 setDrainState(DrainHaltFetch); 1441 1442 /* Discard any generated branch */ 1443 branch = BranchData::bubble(); 1444 } else if (drainState == DrainAllInsts) { 1445 /* Kill all instructions */ 1446 while (getInput()) 1447 popInput(); 1448 commit(false, true, branch); 1449 } 1450 } else { 1451 /* Commit micro-ops only if interrupted. Otherwise, commit 1452 * anything you like */ 1453 commit(interrupted, false, branch); 1454 } 1455 1456 /* This will issue merrily even when interrupted in the sure and 1457 * certain knowledge that the interrupt with change the stream */ 1458 if (insts_in) 1459 num_issued = issue(false); 1460 } 1461 1462 /* Halt fetch, but don't do it until we have the current instruction in 1463 * the bag */ 1464 if (drainState == DrainHaltFetch) { 1465 updateBranchData(BranchData::HaltFetch, MinorDynInst::bubble(), 1466 TheISA::PCState(0), branch); 1467 1468 cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 1469 setDrainState(DrainAllInsts); 1470 } 1471 1472 MinorDynInstPtr next_issuable_inst = NULL; 1473 bool can_issue_next = false; 1474 1475 /* Find the next issuable instruction and see if it can be issued */ 1476 if (getInput()) { 1477 MinorDynInstPtr inst = getInput()->insts[inputIndex]; 1478 1479 if (inst->isFault()) { 1480 can_issue_next = true; 1481 } else if (!inst->isBubble()) { 1482 if (cpu.getContext(inst->id.threadId)->status() != 1483 ThreadContext::Suspended) 1484 { 1485 next_issuable_inst = inst; 1486 } 1487 } 1488 } 1489 1490 bool becoming_stalled = true; 1491 1492 /* Advance the pipelines and note whether they still need to be 1493 * advanced */ 1494 for (unsigned int i = 0; i < numFuncUnits; i++) { 1495 FUPipeline *fu = funcUnits[i]; 1496 1497 fu->advance(); 1498 1499 /* If we need to go again, the pipeline will have been left or set 1500 * to be unstalled */ 1501 if (fu->occupancy != 0 && !fu->stalled) 1502 becoming_stalled = false; 1503 1504 /* Could we possibly issue the next instruction? This is quite 1505 * an expensive test */ 1506 if (next_issuable_inst && !fu->stalled && 1507 scoreboard.canInstIssue(next_issuable_inst, 1508 NULL, NULL, cpu.curCycle() + Cycles(1), 1509 cpu.getContext(next_issuable_inst->id.threadId)) && 1510 fu->provides(next_issuable_inst->staticInst->opClass())) 1511 { 1512 can_issue_next = true; 1513 } 1514 } 1515 1516 bool head_inst_might_commit = false; 1517 1518 /* Could the head in flight insts be committed */ 1519 if (!inFlightInsts->empty()) { 1520 const QueuedInst &head_inst = inFlightInsts->front(); 1521 1522 if (head_inst.inst->isNoCostInst()) { 1523 head_inst_might_commit = true; 1524 } else { 1525 FUPipeline *fu = funcUnits[head_inst.inst->fuIndex]; 1526 1527 /* Head inst is commitable */ 1528 if ((fu->stalled && 1529 fu->front().inst->id == head_inst.inst->id) || 1530 lsq.findResponse(head_inst.inst)) 1531 { 1532 head_inst_might_commit = true; 1533 } 1534 } 1535 } 1536 1537 DPRINTF(Activity, "Need to tick num issued insts: %s%s%s%s%s%s\n", 1538 (num_issued != 0 ? " (issued some insts)" : ""), 1539 (becoming_stalled ? " (becoming stalled)" : "(not becoming stalled)"), 1540 (can_issue_next ? " (can issued next inst)" : ""), 1541 (head_inst_might_commit ? "(head inst might commit)" : ""), 1542 (lsq.needsToTick() ? " (LSQ needs to tick)" : ""), 1543 (interrupted ? " (interrupted)" : "")); 1544 1545 bool need_to_tick = 1546 num_issued != 0 || /* Issued some insts this cycle */ 1547 !becoming_stalled || /* Some FU pipelines can still move */ 1548 can_issue_next || /* Can still issue a new inst */ 1549 head_inst_might_commit || /* Could possible commit the next inst */ 1550 lsq.needsToTick() || /* Must step the dcache port */ 1551 interrupted; /* There are pending interrupts */ 1552 1553 if (!need_to_tick) { 1554 DPRINTF(Activity, "The next cycle might be skippable as there are no" 1555 " advanceable FUs\n"); 1556 } 1557 1558 /* Wake up if we need to tick again */ 1559 if (need_to_tick) 1560 cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 1561 1562 /* Note activity of following buffer */ 1563 if (!branch.isBubble()) 1564 cpu.activityRecorder->activity(); 1565 1566 /* Make sure the input (if any left) is pushed */ 1567 inputBuffer.pushTail(); 1568} 1569 1570void 1571Execute::wakeupFetch(BranchData::Reason reason) 1572{ 1573 BranchData branch; 1574 assert(branch.isBubble()); 1575 1576 /* THREAD thread id */ 1577 ThreadContext *thread = cpu.getContext(0); 1578 1579 /* Force a branch to the current PC (which should be the next inst.) to 1580 * wake up Fetch1 */ 1581 if (!branch.isStreamChange() /* No real branch already happened */) { 1582 DPRINTF(MinorInterrupt, "Waking up Fetch (via Execute) by issuing" 1583 " a branch: %s\n", thread->pcState()); 1584 1585 assert(thread->pcState().microPC() == 0); 1586 1587 updateBranchData(reason, 1588 MinorDynInst::bubble(), thread->pcState(), branch); 1589 } else { 1590 DPRINTF(MinorInterrupt, "Already branching, no need for wakeup\n"); 1591 } 1592 1593 *out.inputWire = branch; 1594 1595 /* Make sure we get ticked */ 1596 cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 1597} 1598 1599void 1600Execute::minorTrace() const 1601{ 1602 std::ostringstream insts; 1603 std::ostringstream stalled; 1604 1605 instsBeingCommitted.reportData(insts); 1606 lsq.minorTrace(); 1607 inputBuffer.minorTrace(); 1608 scoreboard.minorTrace(); 1609 1610 /* Report functional unit stalling in one string */ 1611 unsigned int i = 0; 1612 while (i < numFuncUnits) 1613 { 1614 stalled << (funcUnits[i]->stalled ? '1' : 'E'); 1615 i++; 1616 if (i != numFuncUnits) 1617 stalled << ','; 1618 } 1619 1620 MINORTRACE("insts=%s inputIndex=%d streamSeqNum=%d" 1621 " stalled=%s drainState=%d isInbetweenInsts=%d\n", 1622 insts.str(), inputIndex, streamSeqNum, stalled.str(), drainState, 1623 isInbetweenInsts()); 1624 1625 std::for_each(funcUnits.begin(), funcUnits.end(), 1626 std::mem_fun(&FUPipeline::minorTrace)); 1627 1628 inFlightInsts->minorTrace(); 1629 inFUMemInsts->minorTrace(); 1630} 1631 1632void 1633Execute::drainResume() 1634{ 1635 DPRINTF(Drain, "MinorExecute drainResume\n"); 1636 1637 setDrainState(NotDraining); 1638 1639 /* Wakeup fetch and keep the pipeline running until that branch takes 1640 * effect */ 1641 wakeupFetch(BranchData::WakeupFetch); 1642 cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 1643} 1644 1645std::ostream &operator <<(std::ostream &os, Execute::DrainState state) 1646{ 1647 switch (state) 1648 { 1649 case Execute::NotDraining: 1650 os << "NotDraining"; 1651 break; 1652 case Execute::DrainCurrentInst: 1653 os << "DrainCurrentInst"; 1654 break; 1655 case Execute::DrainHaltFetch: 1656 os << "DrainHaltFetch"; 1657 break; 1658 case Execute::DrainAllInsts: 1659 os << "DrainAllInsts"; 1660 break; 1661 default: 1662 os << "Drain-" << static_cast<int>(state); 1663 break; 1664 } 1665 1666 return os; 1667} 1668 1669void 1670Execute::setDrainState(DrainState state) 1671{ 1672 DPRINTF(Drain, "setDrainState: %s\n", state); 1673 drainState = state; 1674} 1675 1676unsigned int 1677Execute::drain() 1678{ 1679 DPRINTF(Drain, "MinorExecute drain\n"); 1680 1681 if (drainState == NotDraining) { 1682 cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 1683 1684 /* Go to DrainCurrentInst if we're not between operations 1685 * this should probably test the LSQ as well. Or maybe 1686 * just always go to DrainCurrentInst anyway */ 1687 if (lastCommitWasEndOfMacroop) 1688 setDrainState(DrainHaltFetch); 1689 else 1690 setDrainState(DrainCurrentInst); 1691 } 1692 1693 return (isDrained() ? 0 : 1); 1694} 1695 1696bool 1697Execute::isDrained() 1698{ 1699 return drainState == DrainAllInsts && 1700 inputBuffer.empty() && 1701 inFlightInsts->empty() && 1702 lsq.isDrained(); 1703} 1704 1705Execute::~Execute() 1706{ 1707 for (unsigned int i = 0; i < numFuncUnits; i++) 1708 delete funcUnits[i]; 1709 1710 delete inFlightInsts; 1711} 1712 1713bool 1714Execute::instIsRightStream(MinorDynInstPtr inst) 1715{ 1716 return inst->id.streamSeqNum == streamSeqNum; 1717} 1718 1719bool 1720Execute::instIsHeadInst(MinorDynInstPtr inst) 1721{ 1722 bool ret = false; 1723 1724 if (!inFlightInsts->empty()) 1725 ret = inFlightInsts->front().inst->id == inst->id; 1726 1727 return ret; 1728} 1729 1730MinorCPU::MinorCPUPort & 1731Execute::getDcachePort() 1732{ 1733 return lsq.getDcachePort(); 1734} 1735 1736} 1737