execute.cc (11419:9c7b55faea5d) | execute.cc (11567:560d7fbbddd1) |
---|---|
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 --- 72 unchanged lines hidden (view full) --- 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), | 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 --- 72 unchanged lines hidden (view full) --- 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) | 89 executeInfo(params.numThreads, ExecuteThreadInfo(params.executeCommitLimit)), 90 interruptPriority(0), 91 issuePriority(0), 92 commitPriority(0) |
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_, --- 59 unchanged lines hidden (view full) --- 165 } 166 167 if (!found_fu) { 168 warn("No functional unit for OpClass %s\n", 169 Enums::OpClassStrings[op_class]); 170 } 171 } 172 | 93{ 94 if (commitLimit < 1) { 95 fatal("%s: executeCommitLimit must be >= 1 (%d)\n", name_, 96 commitLimit); 97 } 98 99 if (issueLimit < 1) { 100 fatal("%s: executeCommitLimit must be >= 1 (%d)\n", name_, --- 59 unchanged lines hidden (view full) --- 160 } 161 162 if (!found_fu) { 163 warn("No functional unit for OpClass %s\n", 164 Enums::OpClassStrings[op_class]); 165 } 166 } 167 |
173 inFlightInsts = new Queue<QueuedInst, 174 ReportTraitsAdaptor<QueuedInst> >( 175 name_ + ".inFlightInsts", "insts", total_slots); | 168 /* Per-thread structures */ 169 for (ThreadID tid = 0; tid < params.numThreads; tid++) { 170 std::string tid_str = std::to_string(tid); |
176 | 171 |
177 inFUMemInsts = new Queue<QueuedInst, 178 ReportTraitsAdaptor<QueuedInst> >( 179 name_ + ".inFUMemInsts", "insts", total_slots); | 172 /* Input Buffers */ 173 inputBuffer.push_back( 174 InputBuffer<ForwardInstData>( 175 name_ + ".inputBuffer" + tid_str, "insts", 176 params.executeInputBufferSize)); 177 178 /* Scoreboards */ 179 scoreboard.push_back(Scoreboard(name_ + ".scoreboard" + tid_str)); 180 181 /* In-flight instruction records */ 182 executeInfo[tid].inFlightInsts = new Queue<QueuedInst, 183 ReportTraitsAdaptor<QueuedInst> >( 184 name_ + ".inFlightInsts" + tid_str, "insts", total_slots); 185 186 executeInfo[tid].inFUMemInsts = new Queue<QueuedInst, 187 ReportTraitsAdaptor<QueuedInst> >( 188 name_ + ".inFUMemInsts" + tid_str, "insts", total_slots); 189 } |
180} 181 182const ForwardInstData * | 190} 191 192const ForwardInstData * |
183Execute::getInput() | 193Execute::getInput(ThreadID tid) |
184{ 185 /* Get a line from the inputBuffer to work with */ | 194{ 195 /* Get a line from the inputBuffer to work with */ |
186 if (!inputBuffer.empty()) { 187 const ForwardInstData &head = inputBuffer.front(); | 196 if (!inputBuffer[tid].empty()) { 197 const ForwardInstData &head = inputBuffer[tid].front(); |
188 | 198 |
189 return (head.isBubble() ? NULL : &(inputBuffer.front())); | 199 return (head.isBubble() ? NULL : &(inputBuffer[tid].front())); |
190 } else { 191 return NULL; 192 } 193} 194 195void | 200 } else { 201 return NULL; 202 } 203} 204 205void |
196Execute::popInput() | 206Execute::popInput(ThreadID tid) |
197{ | 207{ |
198 if (!inputBuffer.empty()) 199 inputBuffer.pop(); | 208 if (!inputBuffer[tid].empty()) 209 inputBuffer[tid].pop(); |
200 | 210 |
201 inputIndex = 0; | 211 executeInfo[tid].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(); --- 61 unchanged lines hidden (view full) --- 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 | 212} 213 214void 215Execute::tryToBranch(MinorDynInstPtr inst, Fault fault, BranchData &branch) 216{ 217 ThreadContext *thread = cpu.getContext(inst->id.threadId); 218 const TheISA::PCState &pc_before = inst->pc; 219 TheISA::PCState target = thread->pcState(); --- 61 unchanged lines hidden (view full) --- 281 inst->pc.instAddr(), target.instAddr(), *inst); 282 283 reason = BranchData::UnpredictedBranch; 284 } else { 285 /* No branch at all */ 286 reason = BranchData::NoBranch; 287 } 288 |
279 updateBranchData(reason, inst, target, branch); | 289 updateBranchData(inst->id.threadId, reason, inst, target, branch); |
280} 281 282void 283Execute::updateBranchData( | 290} 291 292void 293Execute::updateBranchData( |
294 ThreadID tid, |
|
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)) | 295 BranchData::Reason reason, 296 MinorDynInstPtr inst, const TheISA::PCState &target, 297 BranchData &branch) 298{ 299 if (reason != BranchData::NoBranch) { 300 /* Bump up the stream sequence number on a real branch*/ 301 if (BranchData::isStreamChange(reason)) |
291 streamSeqNum++; | 302 executeInfo[tid].streamSeqNum++; |
292 293 /* Branches (even mis-predictions) don't change the predictionSeqNum, 294 * just the streamSeqNum */ | 303 304 /* Branches (even mis-predictions) don't change the predictionSeqNum, 305 * just the streamSeqNum */ |
295 branch = BranchData(reason, streamSeqNum, | 306 branch = BranchData(reason, tid, 307 executeInfo[tid].streamSeqNum, |
296 /* Maintaining predictionSeqNum if there's no inst is just a 297 * courtesy and looks better on minorview */ | 308 /* Maintaining predictionSeqNum if there's no inst is just a 309 * courtesy and looks better on minorview */ |
298 (inst->isBubble() ? lastPredictionSeqNum | 310 (inst->isBubble() ? executeInfo[tid].lastPredictionSeqNum |
299 : inst->id.predictionSeqNum), 300 target, inst); 301 302 DPRINTF(Branch, "Branch data signalled: %s\n", branch); 303 } 304} 305 306void --- 107 unchanged lines hidden (view full) --- 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 | 311 : inst->id.predictionSeqNum), 312 target, inst); 313 314 DPRINTF(Branch, "Branch data signalled: %s\n", branch); 315 } 316} 317 318void --- 107 unchanged lines hidden (view full) --- 426 427 assert(!lsq.accessesInFlight()); 428 429 DPRINTF(MinorInterrupt, "Invoking interrupt: %s to PC: %s\n", 430 interrupt->name(), cpu.getContext(thread_id)->pcState()); 431 432 /* Assume that an interrupt *must* cause a branch. Assert this? */ 433 |
422 updateBranchData(BranchData::Interrupt, MinorDynInst::bubble(), 423 cpu.getContext(thread_id)->pcState(), branch); | 434 updateBranchData(thread_id, BranchData::Interrupt, 435 MinorDynInst::bubble(), cpu.getContext(thread_id)->pcState(), 436 branch); |
424 } 425 426 return interrupt != NoFault; 427} 428 429bool 430Execute::executeMemRefInst(MinorDynInstPtr inst, BranchData &branch, 431 bool &passed_predicate, Fault &fault) --- 69 unchanged lines hidden (view full) --- 501 502 if (ret < 0) 503 ret = cycle_size - 1; 504 505 return ret; 506} 507 508unsigned int | 437 } 438 439 return interrupt != NoFault; 440} 441 442bool 443Execute::executeMemRefInst(MinorDynInstPtr inst, BranchData &branch, 444 bool &passed_predicate, Fault &fault) --- 69 unchanged lines hidden (view full) --- 514 515 if (ret < 0) 516 ret = cycle_size - 1; 517 518 return ret; 519} 520 521unsigned int |
509Execute::issue(bool only_issue_microops) | 522Execute::issue(ThreadID thread_id) |
510{ | 523{ |
511 const ForwardInstData *insts_in = getInput(); | 524 const ForwardInstData *insts_in = getInput(thread_id); 525 ExecuteThreadInfo &thread = executeInfo[thread_id]; |
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 --- 9 unchanged lines hidden (view full) --- 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 { | 526 527 /* Early termination if we have no instructions */ 528 if (!insts_in) 529 return 0; 530 531 /* Start from the first FU */ 532 unsigned int fu_index = 0; 533 --- 9 unchanged lines hidden (view full) --- 543 /* Number of memory ops issues this cycle to check for memoryIssueLimit */ 544 unsigned num_mem_insts_issued = 0; 545 546 /* Number of instructions discarded this cycle in order to enforce a 547 * discardLimit. @todo, add that parameter? */ 548 unsigned num_insts_discarded = 0; 549 550 do { |
537 MinorDynInstPtr inst = insts_in->insts[inputIndex]; 538 ThreadID thread_id = inst->id.threadId; | 551 MinorDynInstPtr inst = insts_in->insts[thread.inputIndex]; |
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; | 552 Fault fault = inst->fault; 553 bool discarded = false; 554 bool issued_mem_ref = false; 555 556 if (inst->isBubble()) { 557 /* Skip */ 558 issued = true; 559 } else if (cpu.getContext(thread_id)->status() == 560 ThreadContext::Suspended) 561 { 562 DPRINTF(MinorExecute, "Not issuing inst: %s from suspended" 563 " thread\n", *inst); 564 565 issued = false; |
553 } else if (inst->id.streamSeqNum != streamSeqNum) { | 566 } else if (inst->id.streamSeqNum != thread.streamSeqNum) { |
554 DPRINTF(MinorExecute, "Discarding inst: %s as its stream" 555 " state was unexpected, expected: %d\n", | 567 DPRINTF(MinorExecute, "Discarding inst: %s as its stream" 568 " state was unexpected, expected: %d\n", |
556 *inst, streamSeqNum); | 569 *inst, thread.streamSeqNum); |
557 issued = true; 558 discarded = true; | 570 issued = true; 571 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 --- 17 unchanged lines hidden (view full) --- 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 */ | 572 } else { 573 /* Try and issue an instruction into an FU, assume we didn't and 574 * fix that in the loop */ 575 issued = false; 576 577 /* Try FU from 0 each instruction */ 578 fu_index = 0; 579 --- 17 unchanged lines hidden (view full) --- 597 fu_index = noCostFUIndex; 598 599 /* And start the countdown on activity to allow 600 * this instruction to get to the end of its FU */ 601 cpu.activityRecorder->activity(); 602 603 /* Mark the destinations for this instruction as 604 * busy */ |
601 scoreboard.markupInstDests(inst, cpu.curCycle() + | 605 scoreboard[thread_id].markupInstDests(inst, cpu.curCycle() + |
602 Cycles(0), cpu.getContext(thread_id), false); 603 | 606 Cycles(0), cpu.getContext(thread_id), false); 607 |
608 DPRINTF(MinorExecute, "Issuing %s to %d\n", inst->id, noCostFUIndex); |
|
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); | 609 inst->fuIndex = noCostFUIndex; 610 inst->extraCommitDelay = Cycles(0); 611 inst->extraCommitDelayExpr = NULL; 612 613 /* Push the instruction onto the inFlight queue so 614 * it can be committed in order */ 615 QueuedInst fu_inst(inst); |
611 inFlightInsts->push(fu_inst); | 616 thread.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); --- 19 unchanged lines hidden (view full) --- 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); | 617 618 issued = true; 619 620 } else if (!fu_is_capable || fu->alreadyPushed()) { 621 /* Skip */ 622 if (!fu_is_capable) { 623 DPRINTF(MinorExecute, "Can't issue as FU: %d isn't" 624 " capable\n", fu_index); --- 19 unchanged lines hidden (view full) --- 644 645 const std::vector<bool> *cant_forward_from_fu_indices = 646 &(fu->cantForwardFromFUIndices); 647 648 if (timing && timing->suppress) { 649 DPRINTF(MinorExecute, "Can't issue inst: %s as extra" 650 " decoding is suppressing it\n", 651 *inst); |
647 } else if (!scoreboard.canInstIssue(inst, src_latencies, 648 cant_forward_from_fu_indices, | 652 } else if (!scoreboard[thread_id].canInstIssue(inst, 653 src_latencies, 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, --- 25 unchanged lines hidden (view full) --- 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 = | 654 cpu.curCycle(), cpu.getContext(thread_id))) 655 { 656 DPRINTF(MinorExecute, "Can't issue inst: %s yet\n", 657 *inst); 658 } else { 659 /* Can insert the instruction into this FU */ 660 DPRINTF(MinorExecute, "Issuing inst: %s" 661 " into FU %d\n", *inst, --- 25 unchanged lines hidden (view full) --- 687 extra_dest_retire_lat_expr; 688 689 if (issued_mem_ref) { 690 /* Remember which instruction this memory op 691 * depends on so that initiateAcc can be called 692 * early */ 693 if (allowEarlyMemIssue) { 694 inst->instToWaitFor = |
690 scoreboard.execSeqNumToWaitFor(inst, | 695 scoreboard[thread_id].execSeqNumToWaitFor(inst, |
691 cpu.getContext(thread_id)); 692 | 696 cpu.getContext(thread_id)); 697 |
693 if (lsq.getLastMemBarrier() > | 698 if (lsq.getLastMemBarrier(thread_id) > |
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, | 699 inst->instToWaitFor) 700 { 701 DPRINTF(MinorExecute, "A barrier will" 702 " cause a delay in mem ref issue of" 703 " inst: %s until after inst" 704 " %d(exec)\n", *inst, |
700 lsq.getLastMemBarrier()); | 705 lsq.getLastMemBarrier(thread_id)); |
701 702 inst->instToWaitFor = | 706 707 inst->instToWaitFor = |
703 lsq.getLastMemBarrier(); | 708 lsq.getLastMemBarrier(thread_id); |
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); | 709 } else { 710 DPRINTF(MinorExecute, "Memory ref inst:" 711 " %s must wait for inst %d(exec)" 712 " before issuing\n", 713 *inst, inst->instToWaitFor); 714 } 715 716 inst->canEarlyIssue = true; 717 } 718 /* Also queue this instruction in the memory ref 719 * queue to ensure in-order issue to the LSQ */ 720 DPRINTF(MinorExecute, "Pushing mem inst: %s\n", 721 *inst); |
717 inFUMemInsts->push(fu_inst); | 722 thread.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 */ | 723 } 724 725 /* Issue to FU */ 726 fu->push(fu_inst); 727 /* And start the countdown on activity to allow 728 * this instruction to get to the end of its FU */ 729 cpu.activityRecorder->activity(); 730 731 /* Mark the destinations for this instruction as 732 * busy */ |
728 scoreboard.markupInstDests(inst, cpu.curCycle() + | 733 scoreboard[thread_id].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 */ | 734 fu->description.opLat + 735 extra_dest_retire_lat + 736 extra_assumed_lat, 737 cpu.getContext(thread_id), 738 issued_mem_ref && extra_assumed_lat == Cycles(0)); 739 740 /* Push the instruction onto the inFlight queue so 741 * it can be committed in order */ |
737 inFlightInsts->push(fu_inst); | 742 thread.inFlightInsts->push(fu_inst); |
738 739 issued = true; 740 } 741 } 742 743 fu_index++; 744 } while (fu_index != numFuncUnits && !issued); 745 --- 26 unchanged lines hidden (view full) --- 772 num_insts_discarded++; 773 } else if (!inst->isBubble()) { 774 num_insts_issued++; 775 776 if (num_insts_issued == issueLimit) 777 DPRINTF(MinorExecute, "Reached inst issue limit\n"); 778 } 779 | 743 744 issued = true; 745 } 746 } 747 748 fu_index++; 749 } while (fu_index != numFuncUnits && !issued); 750 --- 26 unchanged lines hidden (view full) --- 777 num_insts_discarded++; 778 } else if (!inst->isBubble()) { 779 num_insts_issued++; 780 781 if (num_insts_issued == issueLimit) 782 DPRINTF(MinorExecute, "Reached inst issue limit\n"); 783 } 784 |
780 inputIndex++; | 785 thread.inputIndex++; |
781 DPRINTF(MinorExecute, "Stepping to next inst inputIndex: %d\n", | 786 DPRINTF(MinorExecute, "Stepping to next inst inputIndex: %d\n", |
782 inputIndex); | 787 thread.inputIndex); |
783 } 784 785 /* Got to the end of a line */ | 788 } 789 790 /* Got to the end of a line */ |
786 if (inputIndex == insts_in->width()) { 787 popInput(); | 791 if (thread.inputIndex == insts_in->width()) { 792 popInput(thread_id); |
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"); | 793 /* Set insts_in to null to force us to leave the surrounding 794 * loop */ 795 insts_in = NULL; 796 797 if (processMoreThanOneInput) { 798 DPRINTF(MinorExecute, "Wrapping\n"); |
794 insts_in = getInput(); | 799 insts_in = getInput(thread_id); |
795 } 796 } | 800 } 801 } |
797 } while (insts_in && inputIndex < insts_in->width() && | 802 } while (insts_in && thread.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 | 803 /* We still have instructions */ 804 fu_index != numFuncUnits && /* Not visited all FUs */ 805 issued && /* We've not yet failed to issue an instruction */ 806 num_insts_issued != issueLimit && /* Still allowed to issue */ 807 num_mem_insts_issued != memoryIssueLimit); 808 809 return num_insts_issued; 810} 811 812bool |
808Execute::tryPCEvents() | 813Execute::tryPCEvents(ThreadID thread_id) |
809{ | 814{ |
810 ThreadContext *thread = cpu.getContext(0); | 815 ThreadContext *thread = cpu.getContext(thread_id); |
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++; --- 110 unchanged lines hidden (view full) --- 929 completed_mem_issue = completed_inst; 930 } else if (inst->isInst() && inst->staticInst->isMemBarrier() && 931 !lsq.canPushIntoStoreBuffer()) 932 { 933 DPRINTF(MinorExecute, "Can't commit data barrier inst: %s yet as" 934 " there isn't space in the store buffer\n", *inst); 935 936 completed_inst = false; | 816 unsigned int num_pc_event_checks = 0; 817 818 /* Handle PC events on instructions */ 819 Addr oldPC; 820 do { 821 oldPC = thread->instAddr(); 822 cpu.system->pcEventQueue.service(thread); 823 num_pc_event_checks++; --- 110 unchanged lines hidden (view full) --- 934 completed_mem_issue = completed_inst; 935 } else if (inst->isInst() && inst->staticInst->isMemBarrier() && 936 !lsq.canPushIntoStoreBuffer()) 937 { 938 DPRINTF(MinorExecute, "Can't commit data barrier inst: %s yet as" 939 " there isn't space in the store buffer\n", *inst); 940 941 completed_inst = false; |
942 } else if (inst->isInst() && inst->staticInst->isQuiesce() 943 && !branch.isBubble()){ 944 /* This instruction can suspend, need to be able to communicate 945 * backwards, so no other branches may evaluate this cycle*/ 946 completed_inst = false; |
|
937 } else { 938 ExecContext context(cpu, *cpu.threads[thread_id], *this, inst); 939 940 DPRINTF(MinorExecute, "Committing inst: %s\n", *inst); 941 942 fault = inst->staticInst->execute(&context, 943 inst->traceData); 944 --- 12 unchanged lines hidden (view full) --- 957 doInstCommitAccounting(inst); 958 tryToBranch(inst, fault, branch); 959 } 960 961 if (completed_inst) { 962 /* Keep a copy of this instruction's predictionSeqNum just in case 963 * we need to issue a branch without an instruction (such as an 964 * interrupt) */ | 947 } else { 948 ExecContext context(cpu, *cpu.threads[thread_id], *this, inst); 949 950 DPRINTF(MinorExecute, "Committing inst: %s\n", *inst); 951 952 fault = inst->staticInst->execute(&context, 953 inst->traceData); 954 --- 12 unchanged lines hidden (view full) --- 967 doInstCommitAccounting(inst); 968 tryToBranch(inst, fault, branch); 969 } 970 971 if (completed_inst) { 972 /* Keep a copy of this instruction's predictionSeqNum just in case 973 * we need to issue a branch without an instruction (such as an 974 * interrupt) */ |
965 lastPredictionSeqNum = inst->id.predictionSeqNum; | 975 executeInfo[thread_id].lastPredictionSeqNum = inst->id.predictionSeqNum; |
966 967 /* Check to see if this instruction suspended the current thread. */ 968 if (!inst->isFault() && 969 thread->status() == ThreadContext::Suspended && 970 branch.isBubble() && /* It didn't branch too */ 971 !isInterrupted(thread_id)) /* Don't suspend if we have 972 interrupts */ 973 { | 976 977 /* Check to see if this instruction suspended the current thread. */ 978 if (!inst->isFault() && 979 thread->status() == ThreadContext::Suspended && 980 branch.isBubble() && /* It didn't branch too */ 981 !isInterrupted(thread_id)) /* Don't suspend if we have 982 interrupts */ 983 { |
974 TheISA::PCState resume_pc = cpu.getContext(0)->pcState(); | 984 TheISA::PCState resume_pc = cpu.getContext(thread_id)->pcState(); |
975 976 assert(resume_pc.microPC() == 0); 977 978 DPRINTF(MinorInterrupt, "Suspending thread: %d from Execute" | 985 986 assert(resume_pc.microPC() == 0); 987 988 DPRINTF(MinorInterrupt, "Suspending thread: %d from Execute" |
979 " inst: %s\n", inst->id.threadId, *inst); | 989 " inst: %s\n", thread_id, *inst); |
980 981 cpu.stats.numFetchSuspends++; 982 | 990 991 cpu.stats.numFetchSuspends++; 992 |
983 updateBranchData(BranchData::SuspendThread, inst, resume_pc, 984 branch); | 993 updateBranchData(thread_id, BranchData::SuspendThread, inst, 994 resume_pc, branch); |
985 } 986 } 987 988 return completed_inst; 989} 990 991void | 995 } 996 } 997 998 return completed_inst; 999} 1000 1001void |
992Execute::commit(bool only_commit_microops, bool discard, BranchData &branch) | 1002Execute::commit(ThreadID thread_id, bool only_commit_microops, bool discard, 1003 BranchData &branch) |
993{ 994 Fault fault = NoFault; 995 Cycles now = cpu.curCycle(); | 1004{ 1005 Fault fault = NoFault; 1006 Cycles now = cpu.curCycle(); |
1007 ExecuteThreadInfo &ex_info = executeInfo[thread_id]; |
|
996 997 /** 998 * Try and execute as many instructions from the end of FU pipelines as 999 * possible. This *doesn't* include actually advancing the pipelines. 1000 * 1001 * We do this by looping on the front of the inFlightInsts queue for as 1002 * long as we can find the desired instruction at the end of the 1003 * functional unit it was issued to without seeing a branch or a fault. --- 21 unchanged lines hidden (view full) --- 1025 1026 /* Number of insts committed this cycle to check against commitLimit */ 1027 unsigned int num_insts_committed = 0; 1028 1029 /* Number of memory access instructions committed to check against 1030 * memCommitLimit */ 1031 unsigned int num_mem_refs_committed = 0; 1032 | 1008 1009 /** 1010 * Try and execute as many instructions from the end of FU pipelines as 1011 * possible. This *doesn't* include actually advancing the pipelines. 1012 * 1013 * We do this by looping on the front of the inFlightInsts queue for as 1014 * long as we can find the desired instruction at the end of the 1015 * functional unit it was issued to without seeing a branch or a fault. --- 21 unchanged lines hidden (view full) --- 1037 1038 /* Number of insts committed this cycle to check against commitLimit */ 1039 unsigned int num_insts_committed = 0; 1040 1041 /* Number of memory access instructions committed to check against 1042 * memCommitLimit */ 1043 unsigned int num_mem_refs_committed = 0; 1044 |
1033 if (only_commit_microops && !inFlightInsts->empty()) { | 1045 if (only_commit_microops && !ex_info.inFlightInsts->empty()) { |
1034 DPRINTF(MinorInterrupt, "Only commit microops %s %d\n", | 1046 DPRINTF(MinorInterrupt, "Only commit microops %s %d\n", |
1035 *(inFlightInsts->front().inst), 1036 lastCommitWasEndOfMacroop); | 1047 *(ex_info.inFlightInsts->front().inst), 1048 ex_info.lastCommitWasEndOfMacroop); |
1037 } 1038 | 1049 } 1050 |
1039 while (!inFlightInsts->empty() && /* Some more instructions to process */ | 1051 while (!ex_info.inFlightInsts->empty() && /* Some more instructions to process */ |
1040 !branch.isStreamChange() && /* No real branch */ 1041 fault == NoFault && /* No faults */ 1042 completed_inst && /* Still finding instructions to execute */ 1043 num_insts_committed != commitLimit /* Not reached commit limit */ 1044 ) 1045 { 1046 if (only_commit_microops) { 1047 DPRINTF(MinorInterrupt, "Committing tail of insts before" 1048 " interrupt: %s\n", | 1052 !branch.isStreamChange() && /* No real branch */ 1053 fault == NoFault && /* No faults */ 1054 completed_inst && /* Still finding instructions to execute */ 1055 num_insts_committed != commitLimit /* Not reached commit limit */ 1056 ) 1057 { 1058 if (only_commit_microops) { 1059 DPRINTF(MinorInterrupt, "Committing tail of insts before" 1060 " interrupt: %s\n", |
1049 *(inFlightInsts->front().inst)); | 1061 *(ex_info.inFlightInsts->front().inst)); |
1050 } 1051 | 1062 } 1063 |
1052 QueuedInst *head_inflight_inst = &(inFlightInsts->front()); | 1064 QueuedInst *head_inflight_inst = &(ex_info.inFlightInsts->front()); |
1053 1054 InstSeqNum head_exec_seq_num = 1055 head_inflight_inst->inst->id.execSeqNum; 1056 1057 /* The instruction we actually process if completed_inst 1058 * remains true to the end of the loop body. 1059 * Start by considering the the head of the in flight insts queue */ 1060 MinorDynInstPtr inst = head_inflight_inst->inst; --- 5 unchanged lines hidden (view full) --- 1066 bool early_memory_issue = false; 1067 1068 /* Must set this again to go around the loop */ 1069 completed_inst = false; 1070 1071 /* If we're just completing a macroop before an interrupt or drain, 1072 * can we stil commit another microop (rather than a memory response) 1073 * without crosing into the next full instruction? */ | 1065 1066 InstSeqNum head_exec_seq_num = 1067 head_inflight_inst->inst->id.execSeqNum; 1068 1069 /* The instruction we actually process if completed_inst 1070 * remains true to the end of the loop body. 1071 * Start by considering the the head of the in flight insts queue */ 1072 MinorDynInstPtr inst = head_inflight_inst->inst; --- 5 unchanged lines hidden (view full) --- 1078 bool early_memory_issue = false; 1079 1080 /* Must set this again to go around the loop */ 1081 completed_inst = false; 1082 1083 /* If we're just completing a macroop before an interrupt or drain, 1084 * can we stil commit another microop (rather than a memory response) 1085 * without crosing into the next full instruction? */ |
1074 bool can_commit_insts = !inFlightInsts->empty() && 1075 !(only_commit_microops && lastCommitWasEndOfMacroop); | 1086 bool can_commit_insts = !ex_info.inFlightInsts->empty() && 1087 !(only_commit_microops && ex_info.lastCommitWasEndOfMacroop); |
1076 1077 /* Can we find a mem response for this inst */ 1078 LSQ::LSQRequestPtr mem_response = 1079 (inst->inLSQ ? lsq.findResponse(inst) : NULL); 1080 1081 DPRINTF(MinorExecute, "Trying to commit canCommitInsts: %d\n", 1082 can_commit_insts); 1083 1084 /* Test for PC events after every instruction */ | 1088 1089 /* Can we find a mem response for this inst */ 1090 LSQ::LSQRequestPtr mem_response = 1091 (inst->inLSQ ? lsq.findResponse(inst) : NULL); 1092 1093 DPRINTF(MinorExecute, "Trying to commit canCommitInsts: %d\n", 1094 can_commit_insts); 1095 1096 /* Test for PC events after every instruction */ |
1085 if (isInbetweenInsts() && tryPCEvents()) { 1086 ThreadContext *thread = cpu.getContext(0); | 1097 if (isInbetweenInsts(thread_id) && tryPCEvents(thread_id)) { 1098 ThreadContext *thread = cpu.getContext(thread_id); |
1087 1088 /* Branch as there was a change in PC */ | 1099 1100 /* Branch as there was a change in PC */ |
1089 updateBranchData(BranchData::UnpredictedBranch, | 1101 updateBranchData(thread_id, BranchData::UnpredictedBranch, |
1090 MinorDynInst::bubble(), thread->pcState(), branch); 1091 } else if (mem_response && 1092 num_mem_refs_committed < memoryCommitLimit) 1093 { 1094 /* Try to commit from the memory responses next */ | 1102 MinorDynInst::bubble(), thread->pcState(), branch); 1103 } else if (mem_response && 1104 num_mem_refs_committed < memoryCommitLimit) 1105 { 1106 /* Try to commit from the memory responses next */ |
1095 discard_inst = inst->id.streamSeqNum != streamSeqNum || 1096 discard; | 1107 discard_inst = inst->id.streamSeqNum != 1108 ex_info.streamSeqNum || discard; |
1097 1098 DPRINTF(MinorExecute, "Trying to commit mem response: %s\n", 1099 *inst); 1100 1101 /* Complete or discard the response */ 1102 if (discard_inst) { 1103 DPRINTF(MinorExecute, "Discarding mem inst: %s as its" 1104 " stream state was unexpected, expected: %d\n", | 1109 1110 DPRINTF(MinorExecute, "Trying to commit mem response: %s\n", 1111 *inst); 1112 1113 /* Complete or discard the response */ 1114 if (discard_inst) { 1115 DPRINTF(MinorExecute, "Discarding mem inst: %s as its" 1116 " stream state was unexpected, expected: %d\n", |
1105 *inst, streamSeqNum); | 1117 *inst, ex_info.streamSeqNum); |
1106 1107 lsq.popResponse(mem_response); 1108 } else { 1109 handleMemResponse(inst, mem_response, branch, fault); 1110 committed_inst = true; 1111 } 1112 1113 completed_mem_ref = true; --- 9 unchanged lines hidden (view full) --- 1123 * - Can push a request into the LSQ 1124 * - Have reached the end of their FUs 1125 * - Have had all their dependencies satisfied 1126 * - Are from the right stream 1127 * 1128 * For any other case, leave it to the normal instruction 1129 * issue below to handle them. 1130 */ | 1118 1119 lsq.popResponse(mem_response); 1120 } else { 1121 handleMemResponse(inst, mem_response, branch, fault); 1122 committed_inst = true; 1123 } 1124 1125 completed_mem_ref = true; --- 9 unchanged lines hidden (view full) --- 1135 * - Can push a request into the LSQ 1136 * - Have reached the end of their FUs 1137 * - Have had all their dependencies satisfied 1138 * - Are from the right stream 1139 * 1140 * For any other case, leave it to the normal instruction 1141 * issue below to handle them. 1142 */ |
1131 if (!inFUMemInsts->empty() && lsq.canRequest()) { | 1143 if (!ex_info.inFUMemInsts->empty() && lsq.canRequest()) { |
1132 DPRINTF(MinorExecute, "Trying to commit from mem FUs\n"); 1133 1134 const MinorDynInstPtr head_mem_ref_inst = | 1144 DPRINTF(MinorExecute, "Trying to commit from mem FUs\n"); 1145 1146 const MinorDynInstPtr head_mem_ref_inst = |
1135 inFUMemInsts->front().inst; | 1147 ex_info.inFUMemInsts->front().inst; |
1136 FUPipeline *fu = funcUnits[head_mem_ref_inst->fuIndex]; 1137 const MinorDynInstPtr &fu_inst = fu->front().inst; 1138 1139 /* Use this, possibly out of order, inst as the one 1140 * to 'commit'/send to the LSQ */ 1141 if (!fu_inst->isBubble() && 1142 !fu_inst->inLSQ && 1143 fu_inst->canEarlyIssue && | 1148 FUPipeline *fu = funcUnits[head_mem_ref_inst->fuIndex]; 1149 const MinorDynInstPtr &fu_inst = fu->front().inst; 1150 1151 /* Use this, possibly out of order, inst as the one 1152 * to 'commit'/send to the LSQ */ 1153 if (!fu_inst->isBubble() && 1154 !fu_inst->inLSQ && 1155 fu_inst->canEarlyIssue && |
1144 streamSeqNum == fu_inst->id.streamSeqNum && | 1156 ex_info.streamSeqNum == fu_inst->id.streamSeqNum && |
1145 head_exec_seq_num > fu_inst->instToWaitFor) 1146 { 1147 DPRINTF(MinorExecute, "Issuing mem ref early" 1148 " inst: %s instToWaitFor: %d\n", 1149 *(fu_inst), fu_inst->instToWaitFor); 1150 1151 inst = fu_inst; 1152 try_to_commit = true; --- 26 unchanged lines hidden (view full) --- 1179 /* No instruction ready */ 1180 completed_inst = false; 1181 } else if (fu_inst_seq_num != head_exec_seq_num) { 1182 /* Past instruction: we must have already executed it 1183 * in the same cycle and so the head inst isn't 1184 * actually at the end of its pipeline 1185 * Future instruction: handled above and only for 1186 * mem refs on their way to the LSQ */ | 1157 head_exec_seq_num > fu_inst->instToWaitFor) 1158 { 1159 DPRINTF(MinorExecute, "Issuing mem ref early" 1160 " inst: %s instToWaitFor: %d\n", 1161 *(fu_inst), fu_inst->instToWaitFor); 1162 1163 inst = fu_inst; 1164 try_to_commit = true; --- 26 unchanged lines hidden (view full) --- 1191 /* No instruction ready */ 1192 completed_inst = false; 1193 } else if (fu_inst_seq_num != head_exec_seq_num) { 1194 /* Past instruction: we must have already executed it 1195 * in the same cycle and so the head inst isn't 1196 * actually at the end of its pipeline 1197 * Future instruction: handled above and only for 1198 * mem refs on their way to the LSQ */ |
1187 } else /* if (fu_inst_seq_num == head_exec_seq_num) */ { | 1199 } else if (fu_inst.inst->id == inst->id) { |
1188 /* All instructions can be committed if they have the 1189 * right execSeqNum and there are no in-flight 1190 * mem insts before us */ 1191 try_to_commit = true; 1192 completed_inst = true; 1193 } 1194 } 1195 1196 if (try_to_commit) { | 1200 /* All instructions can be committed if they have the 1201 * right execSeqNum and there are no in-flight 1202 * mem insts before us */ 1203 try_to_commit = true; 1204 completed_inst = true; 1205 } 1206 } 1207 1208 if (try_to_commit) { |
1197 discard_inst = inst->id.streamSeqNum != streamSeqNum || 1198 discard; | 1209 discard_inst = inst->id.streamSeqNum != 1210 ex_info.streamSeqNum || discard; |
1199 1200 /* Is this instruction discardable as its streamSeqNum 1201 * doesn't match? */ 1202 if (!discard_inst) { 1203 /* Try to commit or discard a non-memory instruction. 1204 * Memory ops are actually 'committed' from this FUs 1205 * and 'issued' into the memory system so we need to 1206 * account for them later (commit_was_mem_issue gets 1207 * set) */ 1208 if (inst->extraCommitDelayExpr) { 1209 DPRINTF(MinorExecute, "Evaluating expression for" 1210 " extra commit delay inst: %s\n", *inst); 1211 | 1211 1212 /* Is this instruction discardable as its streamSeqNum 1213 * doesn't match? */ 1214 if (!discard_inst) { 1215 /* Try to commit or discard a non-memory instruction. 1216 * Memory ops are actually 'committed' from this FUs 1217 * and 'issued' into the memory system so we need to 1218 * account for them later (commit_was_mem_issue gets 1219 * set) */ 1220 if (inst->extraCommitDelayExpr) { 1221 DPRINTF(MinorExecute, "Evaluating expression for" 1222 " extra commit delay inst: %s\n", *inst); 1223 |
1212 ThreadContext *thread = 1213 cpu.getContext(inst->id.threadId); | 1224 ThreadContext *thread = cpu.getContext(thread_id); |
1214 1215 TimingExprEvalContext context(inst->staticInst, 1216 thread, NULL); 1217 1218 uint64_t extra_delay = inst->extraCommitDelayExpr-> 1219 eval(context); 1220 1221 DPRINTF(MinorExecute, "Extra commit delay expr" --- 14 unchanged lines hidden (view full) --- 1236 inst->minimumCommitCycle = cpu.curCycle() + 1237 inst->extraCommitDelay; 1238 inst->extraCommitDelay = Cycles(0); 1239 } 1240 1241 /* @todo Think about making lastMemBarrier be 1242 * MAX_UINT_64 to avoid using 0 as a marker value */ 1243 if (!inst->isFault() && inst->isMemRef() && | 1225 1226 TimingExprEvalContext context(inst->staticInst, 1227 thread, NULL); 1228 1229 uint64_t extra_delay = inst->extraCommitDelayExpr-> 1230 eval(context); 1231 1232 DPRINTF(MinorExecute, "Extra commit delay expr" --- 14 unchanged lines hidden (view full) --- 1247 inst->minimumCommitCycle = cpu.curCycle() + 1248 inst->extraCommitDelay; 1249 inst->extraCommitDelay = Cycles(0); 1250 } 1251 1252 /* @todo Think about making lastMemBarrier be 1253 * MAX_UINT_64 to avoid using 0 as a marker value */ 1254 if (!inst->isFault() && inst->isMemRef() && |
1244 lsq.getLastMemBarrier() < | 1255 lsq.getLastMemBarrier(thread_id) < |
1245 inst->id.execSeqNum && | 1256 inst->id.execSeqNum && |
1246 lsq.getLastMemBarrier() != 0) | 1257 lsq.getLastMemBarrier(thread_id) != 0) |
1247 { 1248 DPRINTF(MinorExecute, "Not committing inst: %s yet" 1249 " as there are incomplete barriers in flight\n", 1250 *inst); 1251 completed_inst = false; 1252 } else if (inst->minimumCommitCycle > now) { 1253 DPRINTF(MinorExecute, "Not committing inst: %s yet" 1254 " as it wants to be stalled for %d more cycles\n", --- 9 unchanged lines hidden (view full) --- 1264 completed_inst = true; 1265 } 1266 1267 if (completed_inst) { 1268 /* Allow the pipeline to advance. If the FU head 1269 * instruction wasn't the inFlightInsts head 1270 * but had already been committed, it would have 1271 * unstalled the pipeline before here */ | 1258 { 1259 DPRINTF(MinorExecute, "Not committing inst: %s yet" 1260 " as there are incomplete barriers in flight\n", 1261 *inst); 1262 completed_inst = false; 1263 } else if (inst->minimumCommitCycle > now) { 1264 DPRINTF(MinorExecute, "Not committing inst: %s yet" 1265 " as it wants to be stalled for %d more cycles\n", --- 9 unchanged lines hidden (view full) --- 1275 completed_inst = true; 1276 } 1277 1278 if (completed_inst) { 1279 /* Allow the pipeline to advance. If the FU head 1280 * instruction wasn't the inFlightInsts head 1281 * but had already been committed, it would have 1282 * unstalled the pipeline before here */ |
1272 if (inst->fuIndex != noCostFUIndex) | 1283 if (inst->fuIndex != noCostFUIndex) { 1284 DPRINTF(MinorExecute, "Unstalling %d for inst %s\n", inst->fuIndex, inst->id); |
1273 funcUnits[inst->fuIndex]->stalled = false; | 1285 funcUnits[inst->fuIndex]->stalled = false; |
1286 } |
|
1274 } 1275 } 1276 } else { 1277 DPRINTF(MinorExecute, "No instructions to commit\n"); 1278 completed_inst = false; 1279 } 1280 1281 /* All discardable instructions must also be 'completed' by now */ 1282 assert(!(discard_inst && !completed_inst)); 1283 1284 /* Instruction committed but was discarded due to streamSeqNum 1285 * mismatch */ 1286 if (discard_inst) { 1287 DPRINTF(MinorExecute, "Discarding inst: %s as its stream" 1288 " state was unexpected, expected: %d\n", | 1287 } 1288 } 1289 } else { 1290 DPRINTF(MinorExecute, "No instructions to commit\n"); 1291 completed_inst = false; 1292 } 1293 1294 /* All discardable instructions must also be 'completed' by now */ 1295 assert(!(discard_inst && !completed_inst)); 1296 1297 /* Instruction committed but was discarded due to streamSeqNum 1298 * mismatch */ 1299 if (discard_inst) { 1300 DPRINTF(MinorExecute, "Discarding inst: %s as its stream" 1301 " state was unexpected, expected: %d\n", |
1289 *inst, streamSeqNum); | 1302 *inst, ex_info.streamSeqNum); |
1290 1291 if (fault == NoFault) 1292 cpu.stats.numDiscardedOps++; 1293 } 1294 1295 /* Mark the mem inst as being in the LSQ */ 1296 if (issued_mem_ref) { 1297 inst->fuIndex = 0; 1298 inst->inLSQ = true; 1299 } 1300 1301 /* Pop issued (to LSQ) and discarded mem refs from the inFUMemInsts 1302 * as they've *definitely* exited the FUs */ 1303 if (completed_inst && inst->isMemRef()) { 1304 /* The MemRef could have been discarded from the FU or the memory 1305 * queue, so just check an FU instruction */ | 1303 1304 if (fault == NoFault) 1305 cpu.stats.numDiscardedOps++; 1306 } 1307 1308 /* Mark the mem inst as being in the LSQ */ 1309 if (issued_mem_ref) { 1310 inst->fuIndex = 0; 1311 inst->inLSQ = true; 1312 } 1313 1314 /* Pop issued (to LSQ) and discarded mem refs from the inFUMemInsts 1315 * as they've *definitely* exited the FUs */ 1316 if (completed_inst && inst->isMemRef()) { 1317 /* The MemRef could have been discarded from the FU or the memory 1318 * queue, so just check an FU instruction */ |
1306 if (!inFUMemInsts->empty() && 1307 inFUMemInsts->front().inst == inst) | 1319 if (!ex_info.inFUMemInsts->empty() && 1320 ex_info.inFUMemInsts->front().inst == inst) |
1308 { | 1321 { |
1309 inFUMemInsts->pop(); | 1322 ex_info.inFUMemInsts->pop(); |
1310 } 1311 } 1312 1313 if (completed_inst && !(issued_mem_ref && fault == NoFault)) { 1314 /* Note that this includes discarded insts */ 1315 DPRINTF(MinorExecute, "Completed inst: %s\n", *inst); 1316 1317 /* Got to the end of a full instruction? */ | 1323 } 1324 } 1325 1326 if (completed_inst && !(issued_mem_ref && fault == NoFault)) { 1327 /* Note that this includes discarded insts */ 1328 DPRINTF(MinorExecute, "Completed inst: %s\n", *inst); 1329 1330 /* Got to the end of a full instruction? */ |
1318 lastCommitWasEndOfMacroop = inst->isFault() || | 1331 ex_info.lastCommitWasEndOfMacroop = inst->isFault() || |
1319 inst->isLastOpInInst(); 1320 1321 /* lastPredictionSeqNum is kept as a convenience to prevent its 1322 * value from changing too much on the minorview display */ | 1332 inst->isLastOpInInst(); 1333 1334 /* lastPredictionSeqNum is kept as a convenience to prevent its 1335 * value from changing too much on the minorview display */ |
1323 lastPredictionSeqNum = inst->id.predictionSeqNum; | 1336 ex_info.lastPredictionSeqNum = inst->id.predictionSeqNum; |
1324 1325 /* Finished with the inst, remove it from the inst queue and 1326 * clear its dependencies */ | 1337 1338 /* Finished with the inst, remove it from the inst queue and 1339 * clear its dependencies */ |
1327 inFlightInsts->pop(); | 1340 ex_info.inFlightInsts->pop(); |
1328 1329 /* Complete barriers in the LSQ/move to store buffer */ 1330 if (inst->isInst() && inst->staticInst->isMemBarrier()) { 1331 DPRINTF(MinorMem, "Completing memory barrier" 1332 " inst: %s committed: %d\n", *inst, committed_inst); 1333 lsq.completeMemBarrierInst(inst, committed_inst); 1334 } 1335 | 1341 1342 /* Complete barriers in the LSQ/move to store buffer */ 1343 if (inst->isInst() && inst->staticInst->isMemBarrier()) { 1344 DPRINTF(MinorMem, "Completing memory barrier" 1345 " inst: %s committed: %d\n", *inst, committed_inst); 1346 lsq.completeMemBarrierInst(inst, committed_inst); 1347 } 1348 |
1336 scoreboard.clearInstDests(inst, inst->isMemRef()); | 1349 scoreboard[thread_id].clearInstDests(inst, inst->isMemRef()); |
1337 } 1338 1339 /* Handle per-cycle instruction counting */ 1340 if (committed_inst) { 1341 bool is_no_cost_inst = inst->isNoCostInst(); 1342 1343 /* Don't show no cost instructions as having taken a commit 1344 * slot */ 1345 if (DTRACE(MinorTrace) && !is_no_cost_inst) | 1350 } 1351 1352 /* Handle per-cycle instruction counting */ 1353 if (committed_inst) { 1354 bool is_no_cost_inst = inst->isNoCostInst(); 1355 1356 /* Don't show no cost instructions as having taken a commit 1357 * slot */ 1358 if (DTRACE(MinorTrace) && !is_no_cost_inst) |
1346 instsBeingCommitted.insts[num_insts_committed] = inst; | 1359 ex_info.instsBeingCommitted.insts[num_insts_committed] = inst; |
1347 1348 if (!is_no_cost_inst) 1349 num_insts_committed++; 1350 1351 if (num_insts_committed == commitLimit) 1352 DPRINTF(MinorExecute, "Reached inst commit limit\n"); 1353 1354 /* Re-set the time of the instruction if that's required for --- 9 unchanged lines hidden (view full) --- 1364 1365 if (num_mem_refs_committed == memoryCommitLimit) 1366 DPRINTF(MinorExecute, "Reached mem ref commit limit\n"); 1367 } 1368 } 1369} 1370 1371bool | 1360 1361 if (!is_no_cost_inst) 1362 num_insts_committed++; 1363 1364 if (num_insts_committed == commitLimit) 1365 DPRINTF(MinorExecute, "Reached inst commit limit\n"); 1366 1367 /* Re-set the time of the instruction if that's required for --- 9 unchanged lines hidden (view full) --- 1377 1378 if (num_mem_refs_committed == memoryCommitLimit) 1379 DPRINTF(MinorExecute, "Reached mem ref commit limit\n"); 1380 } 1381 } 1382} 1383 1384bool |
1372Execute::isInbetweenInsts() const | 1385Execute::isInbetweenInsts(ThreadID thread_id) const |
1373{ | 1386{ |
1374 return lastCommitWasEndOfMacroop && | 1387 return executeInfo[thread_id].lastCommitWasEndOfMacroop && |
1375 !lsq.accessesInFlight(); 1376} 1377 1378void 1379Execute::evaluate() 1380{ | 1388 !lsq.accessesInFlight(); 1389} 1390 1391void 1392Execute::evaluate() 1393{ |
1381 inputBuffer.setTail(*inp.outputWire); | 1394 if (!inp.outputWire->isBubble()) 1395 inputBuffer[inp.outputWire->threadId].setTail(*inp.outputWire); 1396 |
1382 BranchData &branch = *out.inputWire; 1383 | 1397 BranchData &branch = *out.inputWire; 1398 |
1384 const ForwardInstData *insts_in = getInput(); | 1399 unsigned int num_issued = 0; |
1385 1386 /* Do all the cycle-wise activities for dcachePort here to potentially 1387 * free up input spaces in the LSQ's requests queue */ 1388 lsq.step(); 1389 | 1400 1401 /* Do all the cycle-wise activities for dcachePort here to potentially 1402 * free up input spaces in the LSQ's requests queue */ 1403 lsq.step(); 1404 |
1390 /* Has an interrupt been signalled? This may not be acted on 1391 * straighaway so this is different from took_interrupt below */ | 1405 /* Check interrupts first. Will halt commit if interrupt found */ |
1392 bool interrupted = false; | 1406 bool interrupted = false; |
1393 /* If there was an interrupt signalled, was it acted on now? */ 1394 bool took_interrupt = false; | 1407 ThreadID interrupt_tid = checkInterrupts(branch, interrupted); |
1395 | 1408 |
1396 if (cpu.getInterruptController(0)) { 1397 /* This is here because it seems that after drainResume the 1398 * interrupt controller isn't always set */ 1399 interrupted = drainState == NotDraining && isInterrupted(0); 1400 } else { 1401 DPRINTF(MinorInterrupt, "No interrupt controller\n"); 1402 } 1403 1404 unsigned int num_issued = 0; 1405 1406 if (DTRACE(MinorTrace)) { 1407 /* Empty the instsBeingCommitted for MinorTrace */ 1408 instsBeingCommitted.bubbleFill(); 1409 } 1410 1411 /* THREAD threadId on isInterrupted */ 1412 /* Act on interrupts */ 1413 if (interrupted && isInbetweenInsts()) { 1414 took_interrupt = takeInterrupt(0, branch); 1415 /* Clear interrupted if no interrupt was actually waiting */ 1416 interrupted = took_interrupt; 1417 } 1418 1419 if (took_interrupt) { 1420 /* Do no commit/issue this cycle */ | 1409 if (interrupt_tid != InvalidThreadID) { 1410 /* Signalling an interrupt this cycle, not issuing/committing from 1411 * any other threads */ |
1421 } else if (!branch.isBubble()) { 1422 /* It's important that this is here to carry Fetch1 wakeups to Fetch1 1423 * without overwriting them */ 1424 DPRINTF(MinorInterrupt, "Execute skipping a cycle to allow old" 1425 " branch to complete\n"); 1426 } else { | 1412 } else if (!branch.isBubble()) { 1413 /* It's important that this is here to carry Fetch1 wakeups to Fetch1 1414 * without overwriting them */ 1415 DPRINTF(MinorInterrupt, "Execute skipping a cycle to allow old" 1416 " branch to complete\n"); 1417 } else { |
1427 if (interrupted) { 1428 if (inFlightInsts->empty()) { 1429 DPRINTF(MinorInterrupt, "Waiting but no insts\n"); | 1418 ThreadID commit_tid = getCommittingThread(); 1419 1420 if (commit_tid != InvalidThreadID) { 1421 ExecuteThreadInfo& commit_info = executeInfo[commit_tid]; 1422 1423 DPRINTF(MinorExecute, "Attempting to commit [tid:%d]\n", 1424 commit_tid); 1425 /* commit can set stalled flags observable to issue and so *must* be 1426 * called first */ 1427 if (commit_info.drainState != NotDraining) { 1428 if (commit_info.drainState == DrainCurrentInst) { 1429 /* Commit only micro-ops, don't kill anything else */ 1430 commit(commit_tid, true, false, branch); 1431 1432 if (isInbetweenInsts(commit_tid)) 1433 setDrainState(commit_tid, DrainHaltFetch); 1434 1435 /* Discard any generated branch */ 1436 branch = BranchData::bubble(); 1437 } else if (commit_info.drainState == DrainAllInsts) { 1438 /* Kill all instructions */ 1439 while (getInput(commit_tid)) 1440 popInput(commit_tid); 1441 commit(commit_tid, false, true, branch); 1442 } |
1430 } else { | 1443 } else { |
1431 DPRINTF(MinorInterrupt, "Waiting for end of inst before" 1432 " signalling interrupt\n"); | 1444 /* Commit micro-ops only if interrupted. Otherwise, commit 1445 * anything you like */ 1446 DPRINTF(MinorExecute, "Committing micro-ops for interrupt[tid:%d]\n", 1447 commit_tid); 1448 bool only_commit_microops = interrupted && 1449 hasInterrupt(commit_tid); 1450 commit(commit_tid, only_commit_microops, false, branch); |
1433 } | 1451 } |
1434 } | |
1435 | 1452 |
1436 /* commit can set stalled flags observable to issue and so *must* be 1437 * called first */ 1438 if (drainState != NotDraining) { 1439 if (drainState == DrainCurrentInst) { 1440 /* Commit only micro-ops, don't kill anything else */ 1441 commit(true, false, branch); | 1453 /* Halt fetch, but don't do it until we have the current instruction in 1454 * the bag */ 1455 if (commit_info.drainState == DrainHaltFetch) { 1456 updateBranchData(commit_tid, BranchData::HaltFetch, 1457 MinorDynInst::bubble(), TheISA::PCState(0), branch); |
1442 | 1458 |
1443 if (isInbetweenInsts()) 1444 setDrainState(DrainHaltFetch); 1445 1446 /* Discard any generated branch */ 1447 branch = BranchData::bubble(); 1448 } else if (drainState == DrainAllInsts) { 1449 /* Kill all instructions */ 1450 while (getInput()) 1451 popInput(); 1452 commit(false, true, branch); | 1459 cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 1460 setDrainState(commit_tid, DrainAllInsts); |
1453 } | 1461 } |
1454 } else { 1455 /* Commit micro-ops only if interrupted. Otherwise, commit 1456 * anything you like */ 1457 commit(interrupted, false, branch); | |
1458 } | 1462 } |
1459 | 1463 ThreadID issue_tid = getIssuingThread(); |
1460 /* This will issue merrily even when interrupted in the sure and 1461 * certain knowledge that the interrupt with change the stream */ | 1464 /* This will issue merrily even when interrupted in the sure and 1465 * certain knowledge that the interrupt with change the stream */ |
1462 if (insts_in) 1463 num_issued = issue(false); 1464 } | 1466 if (issue_tid != InvalidThreadID) { 1467 DPRINTF(MinorExecute, "Attempting to issue [tid:%d]\n", 1468 issue_tid); 1469 num_issued = issue(issue_tid); 1470 } |
1465 | 1471 |
1466 /* Halt fetch, but don't do it until we have the current instruction in 1467 * the bag */ 1468 if (drainState == DrainHaltFetch) { 1469 updateBranchData(BranchData::HaltFetch, MinorDynInst::bubble(), 1470 TheISA::PCState(0), branch); 1471 1472 cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 1473 setDrainState(DrainAllInsts); | |
1474 } 1475 | 1472 } 1473 |
1476 MinorDynInstPtr next_issuable_inst = NULL; | 1474 /* Run logic to step functional units + decide if we are active on the next 1475 * clock cycle */ 1476 std::vector<MinorDynInstPtr> next_issuable_insts; |
1477 bool can_issue_next = false; 1478 | 1477 bool can_issue_next = false; 1478 |
1479 /* Find the next issuable instruction and see if it can be issued */ 1480 if (getInput()) { 1481 MinorDynInstPtr inst = getInput()->insts[inputIndex]; 1482 1483 if (inst->isFault()) { 1484 can_issue_next = true; 1485 } else if (!inst->isBubble()) { 1486 if (cpu.getContext(inst->id.threadId)->status() != 1487 ThreadContext::Suspended) 1488 { 1489 next_issuable_inst = inst; | 1479 for (ThreadID tid = 0; tid < cpu.numThreads; tid++) { 1480 /* Find the next issuable instruction for each thread and see if it can 1481 be issued */ 1482 if (getInput(tid)) { 1483 unsigned int input_index = executeInfo[tid].inputIndex; 1484 MinorDynInstPtr inst = getInput(tid)->insts[input_index]; 1485 if (inst->isFault()) { 1486 can_issue_next = true; 1487 } else if (!inst->isBubble()) { 1488 if (cpu.getContext(tid)->status() != ThreadContext::Suspended) { 1489 next_issuable_insts.push_back(inst); 1490 } |
1490 } 1491 } 1492 } 1493 1494 bool becoming_stalled = true; 1495 1496 /* Advance the pipelines and note whether they still need to be | 1491 } 1492 } 1493 } 1494 1495 bool becoming_stalled = true; 1496 1497 /* Advance the pipelines and note whether they still need to be |
1497 * advanced */ | 1498 * advanced */ |
1498 for (unsigned int i = 0; i < numFuncUnits; i++) { 1499 FUPipeline *fu = funcUnits[i]; | 1499 for (unsigned int i = 0; i < numFuncUnits; i++) { 1500 FUPipeline *fu = funcUnits[i]; |
1500 | |
1501 fu->advance(); 1502 | 1501 fu->advance(); 1502 |
1503 /* If we need to go again, the pipeline will have been left or set 1504 * to be unstalled */ 1505 if (fu->occupancy != 0 && !fu->stalled) | 1503 /* If we need to tick again, the pipeline will have been left or set 1504 * to be unstalled */ 1505 if (fu->occupancy !=0 && !fu->stalled) |
1506 becoming_stalled = false; 1507 | 1506 becoming_stalled = false; 1507 |
1508 /* Could we possibly issue the next instruction? This is quite 1509 * an expensive test */ 1510 if (next_issuable_inst && !fu->stalled && 1511 scoreboard.canInstIssue(next_issuable_inst, 1512 NULL, NULL, cpu.curCycle() + Cycles(1), 1513 cpu.getContext(next_issuable_inst->id.threadId)) && 1514 fu->provides(next_issuable_inst->staticInst->opClass())) 1515 { 1516 can_issue_next = true; | 1508 /* Could we possibly issue the next instruction from any thread? 1509 * This is quite an expensive test and is only used to determine 1510 * if the CPU should remain active, only run it if we aren't sure 1511 * we are active next cycle yet */ 1512 for (auto inst : next_issuable_insts) { 1513 if (!fu->stalled && fu->provides(inst->staticInst->opClass()) && 1514 scoreboard[inst->id.threadId].canInstIssue(inst, 1515 NULL, NULL, cpu.curCycle() + Cycles(1), 1516 cpu.getContext(inst->id.threadId))) { 1517 can_issue_next = true; 1518 break; 1519 } |
1517 } 1518 } 1519 1520 bool head_inst_might_commit = false; 1521 1522 /* Could the head in flight insts be committed */ | 1520 } 1521 } 1522 1523 bool head_inst_might_commit = false; 1524 1525 /* Could the head in flight insts be committed */ |
1523 if (!inFlightInsts->empty()) { 1524 const QueuedInst &head_inst = inFlightInsts->front(); | 1526 for (auto const &info : executeInfo) { 1527 if (!info.inFlightInsts->empty()) { 1528 const QueuedInst &head_inst = info.inFlightInsts->front(); |
1525 | 1529 |
1526 if (head_inst.inst->isNoCostInst()) { 1527 head_inst_might_commit = true; 1528 } else { 1529 FUPipeline *fu = funcUnits[head_inst.inst->fuIndex]; 1530 1531 /* Head inst is commitable */ 1532 if ((fu->stalled && 1533 fu->front().inst->id == head_inst.inst->id) || 1534 lsq.findResponse(head_inst.inst)) 1535 { | 1530 if (head_inst.inst->isNoCostInst()) { |
1536 head_inst_might_commit = true; | 1531 head_inst_might_commit = true; |
1532 } else { 1533 FUPipeline *fu = funcUnits[head_inst.inst->fuIndex]; 1534 if ((fu->stalled && 1535 fu->front().inst->id == head_inst.inst->id) || 1536 lsq.findResponse(head_inst.inst)) 1537 { 1538 head_inst_might_commit = true; 1539 break; 1540 } |
|
1537 } 1538 } 1539 } 1540 1541 DPRINTF(Activity, "Need to tick num issued insts: %s%s%s%s%s%s\n", 1542 (num_issued != 0 ? " (issued some insts)" : ""), | 1541 } 1542 } 1543 } 1544 1545 DPRINTF(Activity, "Need to tick num issued insts: %s%s%s%s%s%s\n", 1546 (num_issued != 0 ? " (issued some insts)" : ""), |
1543 (becoming_stalled ? " (becoming stalled)" : "(not becoming stalled)"), | 1547 (becoming_stalled ? "(becoming stalled)" : "(not becoming stalled)"), |
1544 (can_issue_next ? " (can issued next inst)" : ""), 1545 (head_inst_might_commit ? "(head inst might commit)" : ""), 1546 (lsq.needsToTick() ? " (LSQ needs to tick)" : ""), 1547 (interrupted ? " (interrupted)" : "")); 1548 1549 bool need_to_tick = 1550 num_issued != 0 || /* Issued some insts this cycle */ 1551 !becoming_stalled || /* Some FU pipelines can still move */ --- 11 unchanged lines hidden (view full) --- 1563 if (need_to_tick) 1564 cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 1565 1566 /* Note activity of following buffer */ 1567 if (!branch.isBubble()) 1568 cpu.activityRecorder->activity(); 1569 1570 /* Make sure the input (if any left) is pushed */ | 1548 (can_issue_next ? " (can issued next inst)" : ""), 1549 (head_inst_might_commit ? "(head inst might commit)" : ""), 1550 (lsq.needsToTick() ? " (LSQ needs to tick)" : ""), 1551 (interrupted ? " (interrupted)" : "")); 1552 1553 bool need_to_tick = 1554 num_issued != 0 || /* Issued some insts this cycle */ 1555 !becoming_stalled || /* Some FU pipelines can still move */ --- 11 unchanged lines hidden (view full) --- 1567 if (need_to_tick) 1568 cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 1569 1570 /* Note activity of following buffer */ 1571 if (!branch.isBubble()) 1572 cpu.activityRecorder->activity(); 1573 1574 /* Make sure the input (if any left) is pushed */ |
1571 inputBuffer.pushTail(); | 1575 if (!inp.outputWire->isBubble()) 1576 inputBuffer[inp.outputWire->threadId].pushTail(); |
1572} 1573 | 1577} 1578 |
1574void 1575Execute::wakeupFetch(BranchData::Reason reason) | 1579ThreadID 1580Execute::checkInterrupts(BranchData& branch, bool& interrupted) |
1576{ | 1581{ |
1577 BranchData branch; 1578 assert(branch.isBubble()); | 1582 ThreadID tid = interruptPriority; 1583 /* Evaluate interrupts in round-robin based upon service */ 1584 do { 1585 /* Has an interrupt been signalled? This may not be acted on 1586 * straighaway so this is different from took_interrupt */ 1587 bool thread_interrupted = false; |
1579 | 1588 |
1580 /* THREAD thread id */ 1581 ThreadContext *thread = cpu.getContext(0); | 1589 if (FullSystem && cpu.getInterruptController(tid)) { 1590 /* This is here because it seems that after drainResume the 1591 * interrupt controller isn't always set */ 1592 thread_interrupted = executeInfo[tid].drainState == NotDraining && 1593 isInterrupted(tid); 1594 interrupted = interrupted || thread_interrupted; 1595 } else { 1596 DPRINTF(MinorInterrupt, "No interrupt controller\n"); 1597 } 1598 DPRINTF(MinorInterrupt, "[tid:%d] thread_interrupted?=%d isInbetweenInsts?=%d\n", 1599 tid, thread_interrupted, isInbetweenInsts(tid)); 1600 /* Act on interrupts */ 1601 if (thread_interrupted && isInbetweenInsts(tid)) { 1602 if (takeInterrupt(tid, branch)) { 1603 interruptPriority = tid; 1604 return tid; 1605 } 1606 } else { 1607 tid = (tid + 1) % cpu.numThreads; 1608 } 1609 } while (tid != interruptPriority); |
1582 | 1610 |
1583 /* Force a branch to the current PC (which should be the next inst.) to 1584 * wake up Fetch1 */ 1585 if (!branch.isStreamChange() /* No real branch already happened */) { 1586 DPRINTF(MinorInterrupt, "Waking up Fetch (via Execute) by issuing" 1587 " a branch: %s\n", thread->pcState()); | 1611 return InvalidThreadID; 1612} |
1588 | 1613 |
1589 assert(thread->pcState().microPC() == 0); 1590 1591 updateBranchData(reason, 1592 MinorDynInst::bubble(), thread->pcState(), branch); 1593 } else { 1594 DPRINTF(MinorInterrupt, "Already branching, no need for wakeup\n"); | 1614bool 1615Execute::hasInterrupt(ThreadID thread_id) 1616{ 1617 if (FullSystem && cpu.getInterruptController(thread_id)) { 1618 return executeInfo[thread_id].drainState == NotDraining && 1619 isInterrupted(thread_id); |
1595 } 1596 | 1620 } 1621 |
1597 *out.inputWire = branch; 1598 1599 /* Make sure we get ticked */ 1600 cpu.wakeupOnEvent(Pipeline::ExecuteStageId); | 1622 return false; |
1601} 1602 1603void 1604Execute::minorTrace() const 1605{ 1606 std::ostringstream insts; 1607 std::ostringstream stalled; 1608 | 1623} 1624 1625void 1626Execute::minorTrace() const 1627{ 1628 std::ostringstream insts; 1629 std::ostringstream stalled; 1630 |
1609 instsBeingCommitted.reportData(insts); | 1631 executeInfo[0].instsBeingCommitted.reportData(insts); |
1610 lsq.minorTrace(); | 1632 lsq.minorTrace(); |
1611 inputBuffer.minorTrace(); 1612 scoreboard.minorTrace(); | 1633 inputBuffer[0].minorTrace(); 1634 scoreboard[0].minorTrace(); |
1613 1614 /* Report functional unit stalling in one string */ 1615 unsigned int i = 0; 1616 while (i < numFuncUnits) 1617 { 1618 stalled << (funcUnits[i]->stalled ? '1' : 'E'); 1619 i++; 1620 if (i != numFuncUnits) 1621 stalled << ','; 1622 } 1623 1624 MINORTRACE("insts=%s inputIndex=%d streamSeqNum=%d" 1625 " stalled=%s drainState=%d isInbetweenInsts=%d\n", | 1635 1636 /* Report functional unit stalling in one string */ 1637 unsigned int i = 0; 1638 while (i < numFuncUnits) 1639 { 1640 stalled << (funcUnits[i]->stalled ? '1' : 'E'); 1641 i++; 1642 if (i != numFuncUnits) 1643 stalled << ','; 1644 } 1645 1646 MINORTRACE("insts=%s inputIndex=%d streamSeqNum=%d" 1647 " stalled=%s drainState=%d isInbetweenInsts=%d\n", |
1626 insts.str(), inputIndex, streamSeqNum, stalled.str(), drainState, 1627 isInbetweenInsts()); | 1648 insts.str(), executeInfo[0].inputIndex, executeInfo[0].streamSeqNum, 1649 stalled.str(), executeInfo[0].drainState, isInbetweenInsts(0)); |
1628 1629 std::for_each(funcUnits.begin(), funcUnits.end(), 1630 std::mem_fun(&FUPipeline::minorTrace)); 1631 | 1650 1651 std::for_each(funcUnits.begin(), funcUnits.end(), 1652 std::mem_fun(&FUPipeline::minorTrace)); 1653 |
1632 inFlightInsts->minorTrace(); 1633 inFUMemInsts->minorTrace(); | 1654 executeInfo[0].inFlightInsts->minorTrace(); 1655 executeInfo[0].inFUMemInsts->minorTrace(); |
1634} 1635 | 1656} 1657 |
1658inline ThreadID 1659Execute::getCommittingThread() 1660{ 1661 std::vector<ThreadID> priority_list; 1662 1663 switch (cpu.threadPolicy) { 1664 case Enums::SingleThreaded: 1665 return 0; 1666 case Enums::RoundRobin: 1667 priority_list = cpu.roundRobinPriority(commitPriority); 1668 break; 1669 case Enums::Random: 1670 priority_list = cpu.randomPriority(); 1671 break; 1672 default: 1673 panic("Invalid thread policy"); 1674 } 1675 1676 for (auto tid : priority_list) { 1677 ExecuteThreadInfo &ex_info = executeInfo[tid]; 1678 bool can_commit_insts = !ex_info.inFlightInsts->empty(); 1679 if (can_commit_insts) { 1680 QueuedInst *head_inflight_inst = &(ex_info.inFlightInsts->front()); 1681 MinorDynInstPtr inst = head_inflight_inst->inst; 1682 1683 can_commit_insts = can_commit_insts && 1684 (!inst->inLSQ || (lsq.findResponse(inst) != NULL)); 1685 1686 if (!inst->inLSQ) { 1687 bool can_transfer_mem_inst = false; 1688 if (!ex_info.inFUMemInsts->empty() && lsq.canRequest()) { 1689 const MinorDynInstPtr head_mem_ref_inst = 1690 ex_info.inFUMemInsts->front().inst; 1691 FUPipeline *fu = funcUnits[head_mem_ref_inst->fuIndex]; 1692 const MinorDynInstPtr &fu_inst = fu->front().inst; 1693 can_transfer_mem_inst = 1694 !fu_inst->isBubble() && 1695 fu_inst->id.threadId == tid && 1696 !fu_inst->inLSQ && 1697 fu_inst->canEarlyIssue && 1698 inst->id.execSeqNum > fu_inst->instToWaitFor; 1699 } 1700 1701 bool can_execute_fu_inst = inst->fuIndex == noCostFUIndex; 1702 if (can_commit_insts && !can_transfer_mem_inst && 1703 inst->fuIndex != noCostFUIndex) 1704 { 1705 QueuedInst& fu_inst = funcUnits[inst->fuIndex]->front(); 1706 can_execute_fu_inst = !fu_inst.inst->isBubble() && 1707 fu_inst.inst->id == inst->id; 1708 } 1709 1710 can_commit_insts = can_commit_insts && 1711 (can_transfer_mem_inst || can_execute_fu_inst); 1712 } 1713 } 1714 1715 1716 if (can_commit_insts) { 1717 commitPriority = tid; 1718 return tid; 1719 } 1720 } 1721 1722 return InvalidThreadID; 1723} 1724 1725inline ThreadID 1726Execute::getIssuingThread() 1727{ 1728 std::vector<ThreadID> priority_list; 1729 1730 switch (cpu.threadPolicy) { 1731 case Enums::SingleThreaded: 1732 return 0; 1733 case Enums::RoundRobin: 1734 priority_list = cpu.roundRobinPriority(issuePriority); 1735 break; 1736 case Enums::Random: 1737 priority_list = cpu.randomPriority(); 1738 break; 1739 default: 1740 panic("Invalid thread scheduling policy."); 1741 } 1742 1743 for (auto tid : priority_list) { 1744 if (cpu.getContext(tid)->status() == ThreadContext::Active && 1745 getInput(tid)) { 1746 issuePriority = tid; 1747 return tid; 1748 } 1749 } 1750 1751 return InvalidThreadID; 1752} 1753 |
|
1636void 1637Execute::drainResume() 1638{ 1639 DPRINTF(Drain, "MinorExecute drainResume\n"); 1640 | 1754void 1755Execute::drainResume() 1756{ 1757 DPRINTF(Drain, "MinorExecute drainResume\n"); 1758 |
1641 setDrainState(NotDraining); | 1759 for (ThreadID tid = 0; tid < cpu.numThreads; tid++) { 1760 setDrainState(tid, NotDraining); 1761 } |
1642 | 1762 |
1643 /* Wakeup fetch and keep the pipeline running until that branch takes 1644 * effect */ 1645 wakeupFetch(BranchData::WakeupFetch); | |
1646 cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 1647} 1648 1649std::ostream &operator <<(std::ostream &os, Execute::DrainState state) 1650{ 1651 switch (state) 1652 { 1653 case Execute::NotDraining: --- 12 unchanged lines hidden (view full) --- 1666 os << "Drain-" << static_cast<int>(state); 1667 break; 1668 } 1669 1670 return os; 1671} 1672 1673void | 1763 cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 1764} 1765 1766std::ostream &operator <<(std::ostream &os, Execute::DrainState state) 1767{ 1768 switch (state) 1769 { 1770 case Execute::NotDraining: --- 12 unchanged lines hidden (view full) --- 1783 os << "Drain-" << static_cast<int>(state); 1784 break; 1785 } 1786 1787 return os; 1788} 1789 1790void |
1674Execute::setDrainState(DrainState state) | 1791Execute::setDrainState(ThreadID thread_id, DrainState state) |
1675{ | 1792{ |
1676 DPRINTF(Drain, "setDrainState: %s\n", state); 1677 drainState = state; | 1793 DPRINTF(Drain, "setDrainState[%d]: %s\n", thread_id, state); 1794 executeInfo[thread_id].drainState = state; |
1678} 1679 1680unsigned int 1681Execute::drain() 1682{ 1683 DPRINTF(Drain, "MinorExecute drain\n"); 1684 | 1795} 1796 1797unsigned int 1798Execute::drain() 1799{ 1800 DPRINTF(Drain, "MinorExecute drain\n"); 1801 |
1685 if (drainState == NotDraining) { 1686 cpu.wakeupOnEvent(Pipeline::ExecuteStageId); | 1802 for (ThreadID tid = 0; tid < cpu.numThreads; tid++) { 1803 if (executeInfo[tid].drainState == NotDraining) { 1804 cpu.wakeupOnEvent(Pipeline::ExecuteStageId); |
1687 | 1805 |
1688 /* Go to DrainCurrentInst if we're between microops 1689 * or waiting on an unbufferable memory operation. 1690 * Otherwise we can go straight to DrainHaltFetch 1691 */ 1692 if (isInbetweenInsts()) 1693 setDrainState(DrainHaltFetch); 1694 else 1695 setDrainState(DrainCurrentInst); | 1806 /* Go to DrainCurrentInst if we're between microops 1807 * or waiting on an unbufferable memory operation. 1808 * Otherwise we can go straight to DrainHaltFetch 1809 */ 1810 if (isInbetweenInsts(tid)) 1811 setDrainState(tid, DrainHaltFetch); 1812 else 1813 setDrainState(tid, DrainCurrentInst); 1814 } |
1696 } | 1815 } |
1697 | |
1698 return (isDrained() ? 0 : 1); 1699} 1700 1701bool 1702Execute::isDrained() 1703{ | 1816 return (isDrained() ? 0 : 1); 1817} 1818 1819bool 1820Execute::isDrained() 1821{ |
1704 return drainState == DrainAllInsts && 1705 inputBuffer.empty() && 1706 inFlightInsts->empty() && 1707 lsq.isDrained(); | 1822 if (!lsq.isDrained()) 1823 return false; 1824 1825 for (ThreadID tid = 0; tid < cpu.numThreads; tid++) { 1826 if (executeInfo[tid].drainState != DrainAllInsts || 1827 !inputBuffer[tid].empty() || 1828 !executeInfo[tid].inFlightInsts->empty()) { 1829 1830 return false; 1831 } 1832 } 1833 1834 return true; |
1708} 1709 1710Execute::~Execute() 1711{ 1712 for (unsigned int i = 0; i < numFuncUnits; i++) 1713 delete funcUnits[i]; 1714 | 1835} 1836 1837Execute::~Execute() 1838{ 1839 for (unsigned int i = 0; i < numFuncUnits; i++) 1840 delete funcUnits[i]; 1841 |
1715 delete inFlightInsts; | 1842 for (ThreadID tid = 0; tid < cpu.numThreads; tid++) 1843 delete executeInfo[tid].inFlightInsts; |
1716} 1717 1718bool 1719Execute::instIsRightStream(MinorDynInstPtr inst) 1720{ | 1844} 1845 1846bool 1847Execute::instIsRightStream(MinorDynInstPtr inst) 1848{ |
1721 return inst->id.streamSeqNum == streamSeqNum; | 1849 return inst->id.streamSeqNum == executeInfo[inst->id.threadId].streamSeqNum; |
1722} 1723 1724bool 1725Execute::instIsHeadInst(MinorDynInstPtr inst) 1726{ 1727 bool ret = false; 1728 | 1850} 1851 1852bool 1853Execute::instIsHeadInst(MinorDynInstPtr inst) 1854{ 1855 bool ret = false; 1856 |
1729 if (!inFlightInsts->empty()) 1730 ret = inFlightInsts->front().inst->id == inst->id; | 1857 if (!executeInfo[inst->id.threadId].inFlightInsts->empty()) 1858 ret = executeInfo[inst->id.threadId].inFlightInsts->front().inst->id == inst->id; |
1731 1732 return ret; 1733} 1734 1735MinorCPU::MinorCPUPort & 1736Execute::getDcachePort() 1737{ 1738 return lsq.getDcachePort(); 1739} 1740 1741} | 1859 1860 return ret; 1861} 1862 1863MinorCPU::MinorCPUPort & 1864Execute::getDcachePort() 1865{ 1866 return lsq.getDcachePort(); 1867} 1868 1869} |