execute.cc revision 13954
110259SAndrew.Bardsley@arm.com/* 213954Sgiacomo.gabrielli@arm.com * Copyright (c) 2013-2014,2018 ARM Limited 310259SAndrew.Bardsley@arm.com * All rights reserved 410259SAndrew.Bardsley@arm.com * 510259SAndrew.Bardsley@arm.com * The license below extends only to copyright in the software and shall 610259SAndrew.Bardsley@arm.com * not be construed as granting a license to any other intellectual 710259SAndrew.Bardsley@arm.com * property including but not limited to intellectual property relating 810259SAndrew.Bardsley@arm.com * to a hardware implementation of the functionality of the software 910259SAndrew.Bardsley@arm.com * licensed hereunder. You may use the software subject to the license 1010259SAndrew.Bardsley@arm.com * terms below provided that you ensure that this notice is replicated 1110259SAndrew.Bardsley@arm.com * unmodified and in its entirety in all distributions of the software, 1210259SAndrew.Bardsley@arm.com * modified or unmodified, in source code or in binary form. 1310259SAndrew.Bardsley@arm.com * 1410259SAndrew.Bardsley@arm.com * Redistribution and use in source and binary forms, with or without 1510259SAndrew.Bardsley@arm.com * modification, are permitted provided that the following conditions are 1610259SAndrew.Bardsley@arm.com * met: redistributions of source code must retain the above copyright 1710259SAndrew.Bardsley@arm.com * notice, this list of conditions and the following disclaimer; 1810259SAndrew.Bardsley@arm.com * redistributions in binary form must reproduce the above copyright 1910259SAndrew.Bardsley@arm.com * notice, this list of conditions and the following disclaimer in the 2010259SAndrew.Bardsley@arm.com * documentation and/or other materials provided with the distribution; 2110259SAndrew.Bardsley@arm.com * neither the name of the copyright holders nor the names of its 2210259SAndrew.Bardsley@arm.com * contributors may be used to endorse or promote products derived from 2310259SAndrew.Bardsley@arm.com * this software without specific prior written permission. 2410259SAndrew.Bardsley@arm.com * 2510259SAndrew.Bardsley@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2610259SAndrew.Bardsley@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2710259SAndrew.Bardsley@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2810259SAndrew.Bardsley@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2910259SAndrew.Bardsley@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3010259SAndrew.Bardsley@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3110259SAndrew.Bardsley@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3210259SAndrew.Bardsley@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3310259SAndrew.Bardsley@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3410259SAndrew.Bardsley@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3510259SAndrew.Bardsley@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3610259SAndrew.Bardsley@arm.com * 3710259SAndrew.Bardsley@arm.com * Authors: Andrew Bardsley 3810259SAndrew.Bardsley@arm.com */ 3910259SAndrew.Bardsley@arm.com 4011793Sbrandon.potter@amd.com#include "cpu/minor/execute.hh" 4111793Sbrandon.potter@amd.com 4210259SAndrew.Bardsley@arm.com#include "arch/locked_mem.hh" 4310259SAndrew.Bardsley@arm.com#include "arch/registers.hh" 4410259SAndrew.Bardsley@arm.com#include "arch/utility.hh" 4510259SAndrew.Bardsley@arm.com#include "cpu/minor/cpu.hh" 4610259SAndrew.Bardsley@arm.com#include "cpu/minor/exec_context.hh" 4710259SAndrew.Bardsley@arm.com#include "cpu/minor/fetch1.hh" 4810259SAndrew.Bardsley@arm.com#include "cpu/minor/lsq.hh" 4910259SAndrew.Bardsley@arm.com#include "cpu/op_class.hh" 5010259SAndrew.Bardsley@arm.com#include "debug/Activity.hh" 5110259SAndrew.Bardsley@arm.com#include "debug/Branch.hh" 5210259SAndrew.Bardsley@arm.com#include "debug/Drain.hh" 5310259SAndrew.Bardsley@arm.com#include "debug/MinorExecute.hh" 5410259SAndrew.Bardsley@arm.com#include "debug/MinorInterrupt.hh" 5510259SAndrew.Bardsley@arm.com#include "debug/MinorMem.hh" 5610259SAndrew.Bardsley@arm.com#include "debug/MinorTrace.hh" 5710259SAndrew.Bardsley@arm.com#include "debug/PCEvent.hh" 5810259SAndrew.Bardsley@arm.com 5910259SAndrew.Bardsley@arm.comnamespace Minor 6010259SAndrew.Bardsley@arm.com{ 6110259SAndrew.Bardsley@arm.com 6210259SAndrew.Bardsley@arm.comExecute::Execute(const std::string &name_, 6310259SAndrew.Bardsley@arm.com MinorCPU &cpu_, 6410259SAndrew.Bardsley@arm.com MinorCPUParams ¶ms, 6510259SAndrew.Bardsley@arm.com Latch<ForwardInstData>::Output inp_, 6610259SAndrew.Bardsley@arm.com Latch<BranchData>::Input out_) : 6710259SAndrew.Bardsley@arm.com Named(name_), 6810259SAndrew.Bardsley@arm.com inp(inp_), 6910259SAndrew.Bardsley@arm.com out(out_), 7010259SAndrew.Bardsley@arm.com cpu(cpu_), 7110259SAndrew.Bardsley@arm.com issueLimit(params.executeIssueLimit), 7210259SAndrew.Bardsley@arm.com memoryIssueLimit(params.executeMemoryIssueLimit), 7310259SAndrew.Bardsley@arm.com commitLimit(params.executeCommitLimit), 7410259SAndrew.Bardsley@arm.com memoryCommitLimit(params.executeMemoryCommitLimit), 7510259SAndrew.Bardsley@arm.com processMoreThanOneInput(params.executeCycleInput), 7610259SAndrew.Bardsley@arm.com fuDescriptions(*params.executeFuncUnits), 7710259SAndrew.Bardsley@arm.com numFuncUnits(fuDescriptions.funcUnits.size()), 7810259SAndrew.Bardsley@arm.com setTraceTimeOnCommit(params.executeSetTraceTimeOnCommit), 7910259SAndrew.Bardsley@arm.com setTraceTimeOnIssue(params.executeSetTraceTimeOnIssue), 8010259SAndrew.Bardsley@arm.com allowEarlyMemIssue(params.executeAllowEarlyMemoryIssue), 8110259SAndrew.Bardsley@arm.com noCostFUIndex(fuDescriptions.funcUnits.size() + 1), 8210259SAndrew.Bardsley@arm.com lsq(name_ + ".lsq", name_ + ".dcache_port", 8310259SAndrew.Bardsley@arm.com cpu_, *this, 8410259SAndrew.Bardsley@arm.com params.executeMaxAccessesInMemory, 8510259SAndrew.Bardsley@arm.com params.executeMemoryWidth, 8610259SAndrew.Bardsley@arm.com params.executeLSQRequestsQueueSize, 8710259SAndrew.Bardsley@arm.com params.executeLSQTransfersQueueSize, 8810259SAndrew.Bardsley@arm.com params.executeLSQStoreBufferSize, 8910259SAndrew.Bardsley@arm.com params.executeLSQMaxStoreBufferStoresPerCycle), 9011567Smitch.hayenga@arm.com executeInfo(params.numThreads, ExecuteThreadInfo(params.executeCommitLimit)), 9111567Smitch.hayenga@arm.com interruptPriority(0), 9211567Smitch.hayenga@arm.com issuePriority(0), 9311567Smitch.hayenga@arm.com commitPriority(0) 9410259SAndrew.Bardsley@arm.com{ 9510259SAndrew.Bardsley@arm.com if (commitLimit < 1) { 9610259SAndrew.Bardsley@arm.com fatal("%s: executeCommitLimit must be >= 1 (%d)\n", name_, 9710259SAndrew.Bardsley@arm.com commitLimit); 9810259SAndrew.Bardsley@arm.com } 9910259SAndrew.Bardsley@arm.com 10010259SAndrew.Bardsley@arm.com if (issueLimit < 1) { 10110259SAndrew.Bardsley@arm.com fatal("%s: executeCommitLimit must be >= 1 (%d)\n", name_, 10210259SAndrew.Bardsley@arm.com issueLimit); 10310259SAndrew.Bardsley@arm.com } 10410259SAndrew.Bardsley@arm.com 10510259SAndrew.Bardsley@arm.com if (memoryIssueLimit < 1) { 10610259SAndrew.Bardsley@arm.com fatal("%s: executeMemoryIssueLimit must be >= 1 (%d)\n", name_, 10710259SAndrew.Bardsley@arm.com memoryIssueLimit); 10810259SAndrew.Bardsley@arm.com } 10910259SAndrew.Bardsley@arm.com 11010259SAndrew.Bardsley@arm.com if (memoryCommitLimit > commitLimit) { 11110259SAndrew.Bardsley@arm.com fatal("%s: executeMemoryCommitLimit (%d) must be <=" 11210259SAndrew.Bardsley@arm.com " executeCommitLimit (%d)\n", 11310259SAndrew.Bardsley@arm.com name_, memoryCommitLimit, commitLimit); 11410259SAndrew.Bardsley@arm.com } 11510259SAndrew.Bardsley@arm.com 11610259SAndrew.Bardsley@arm.com if (params.executeInputBufferSize < 1) { 11710259SAndrew.Bardsley@arm.com fatal("%s: executeInputBufferSize must be >= 1 (%d)\n", name_, 11810259SAndrew.Bardsley@arm.com params.executeInputBufferSize); 11910259SAndrew.Bardsley@arm.com } 12010259SAndrew.Bardsley@arm.com 12110259SAndrew.Bardsley@arm.com if (params.executeInputBufferSize < 1) { 12210259SAndrew.Bardsley@arm.com fatal("%s: executeInputBufferSize must be >= 1 (%d)\n", name_, 12310259SAndrew.Bardsley@arm.com params.executeInputBufferSize); 12410259SAndrew.Bardsley@arm.com } 12510259SAndrew.Bardsley@arm.com 12610259SAndrew.Bardsley@arm.com /* This should be large enough to count all the in-FU instructions 12710259SAndrew.Bardsley@arm.com * which need to be accounted for in the inFlightInsts 12810259SAndrew.Bardsley@arm.com * queue */ 12910259SAndrew.Bardsley@arm.com unsigned int total_slots = 0; 13010259SAndrew.Bardsley@arm.com 13110259SAndrew.Bardsley@arm.com /* Make FUPipelines for each MinorFU */ 13210259SAndrew.Bardsley@arm.com for (unsigned int i = 0; i < numFuncUnits; i++) { 13310259SAndrew.Bardsley@arm.com std::ostringstream fu_name; 13410259SAndrew.Bardsley@arm.com MinorFU *fu_description = fuDescriptions.funcUnits[i]; 13510259SAndrew.Bardsley@arm.com 13610259SAndrew.Bardsley@arm.com /* Note the total number of instruction slots (for sizing 13710259SAndrew.Bardsley@arm.com * the inFlightInst queue) and the maximum latency of any FU 13810259SAndrew.Bardsley@arm.com * (for sizing the activity recorder) */ 13910259SAndrew.Bardsley@arm.com total_slots += fu_description->opLat; 14010259SAndrew.Bardsley@arm.com 14110259SAndrew.Bardsley@arm.com fu_name << name_ << ".fu." << i; 14210259SAndrew.Bardsley@arm.com 14310259SAndrew.Bardsley@arm.com FUPipeline *fu = new FUPipeline(fu_name.str(), *fu_description, cpu); 14410259SAndrew.Bardsley@arm.com 14510259SAndrew.Bardsley@arm.com funcUnits.push_back(fu); 14610259SAndrew.Bardsley@arm.com } 14710259SAndrew.Bardsley@arm.com 14810259SAndrew.Bardsley@arm.com /** Check that there is a functional unit for all operation classes */ 14910814Sandreas.hansson@arm.com for (int op_class = No_OpClass + 1; op_class < Num_OpClasses; op_class++) { 15010259SAndrew.Bardsley@arm.com bool found_fu = false; 15110259SAndrew.Bardsley@arm.com unsigned int fu_index = 0; 15210259SAndrew.Bardsley@arm.com 15310259SAndrew.Bardsley@arm.com while (fu_index < numFuncUnits && !found_fu) 15410259SAndrew.Bardsley@arm.com { 15510259SAndrew.Bardsley@arm.com if (funcUnits[fu_index]->provides( 15610259SAndrew.Bardsley@arm.com static_cast<OpClass>(op_class))) 15710259SAndrew.Bardsley@arm.com { 15810259SAndrew.Bardsley@arm.com found_fu = true; 15910259SAndrew.Bardsley@arm.com } 16010259SAndrew.Bardsley@arm.com fu_index++; 16110259SAndrew.Bardsley@arm.com } 16210259SAndrew.Bardsley@arm.com 16310259SAndrew.Bardsley@arm.com if (!found_fu) { 16410259SAndrew.Bardsley@arm.com warn("No functional unit for OpClass %s\n", 16510259SAndrew.Bardsley@arm.com Enums::OpClassStrings[op_class]); 16610259SAndrew.Bardsley@arm.com } 16710259SAndrew.Bardsley@arm.com } 16810259SAndrew.Bardsley@arm.com 16911567Smitch.hayenga@arm.com /* Per-thread structures */ 17011567Smitch.hayenga@arm.com for (ThreadID tid = 0; tid < params.numThreads; tid++) { 17111567Smitch.hayenga@arm.com std::string tid_str = std::to_string(tid); 17210259SAndrew.Bardsley@arm.com 17311567Smitch.hayenga@arm.com /* Input Buffers */ 17411567Smitch.hayenga@arm.com inputBuffer.push_back( 17511567Smitch.hayenga@arm.com InputBuffer<ForwardInstData>( 17611567Smitch.hayenga@arm.com name_ + ".inputBuffer" + tid_str, "insts", 17711567Smitch.hayenga@arm.com params.executeInputBufferSize)); 17811567Smitch.hayenga@arm.com 17911567Smitch.hayenga@arm.com /* Scoreboards */ 18011567Smitch.hayenga@arm.com scoreboard.push_back(Scoreboard(name_ + ".scoreboard" + tid_str)); 18111567Smitch.hayenga@arm.com 18211567Smitch.hayenga@arm.com /* In-flight instruction records */ 18311567Smitch.hayenga@arm.com executeInfo[tid].inFlightInsts = new Queue<QueuedInst, 18411567Smitch.hayenga@arm.com ReportTraitsAdaptor<QueuedInst> >( 18511567Smitch.hayenga@arm.com name_ + ".inFlightInsts" + tid_str, "insts", total_slots); 18611567Smitch.hayenga@arm.com 18711567Smitch.hayenga@arm.com executeInfo[tid].inFUMemInsts = new Queue<QueuedInst, 18811567Smitch.hayenga@arm.com ReportTraitsAdaptor<QueuedInst> >( 18911567Smitch.hayenga@arm.com name_ + ".inFUMemInsts" + tid_str, "insts", total_slots); 19011567Smitch.hayenga@arm.com } 19110259SAndrew.Bardsley@arm.com} 19210259SAndrew.Bardsley@arm.com 19310259SAndrew.Bardsley@arm.comconst ForwardInstData * 19411567Smitch.hayenga@arm.comExecute::getInput(ThreadID tid) 19510259SAndrew.Bardsley@arm.com{ 19610259SAndrew.Bardsley@arm.com /* Get a line from the inputBuffer to work with */ 19711567Smitch.hayenga@arm.com if (!inputBuffer[tid].empty()) { 19811567Smitch.hayenga@arm.com const ForwardInstData &head = inputBuffer[tid].front(); 19910259SAndrew.Bardsley@arm.com 20011567Smitch.hayenga@arm.com return (head.isBubble() ? NULL : &(inputBuffer[tid].front())); 20110259SAndrew.Bardsley@arm.com } else { 20210259SAndrew.Bardsley@arm.com return NULL; 20310259SAndrew.Bardsley@arm.com } 20410259SAndrew.Bardsley@arm.com} 20510259SAndrew.Bardsley@arm.com 20610259SAndrew.Bardsley@arm.comvoid 20711567Smitch.hayenga@arm.comExecute::popInput(ThreadID tid) 20810259SAndrew.Bardsley@arm.com{ 20911567Smitch.hayenga@arm.com if (!inputBuffer[tid].empty()) 21011567Smitch.hayenga@arm.com inputBuffer[tid].pop(); 21110259SAndrew.Bardsley@arm.com 21211567Smitch.hayenga@arm.com executeInfo[tid].inputIndex = 0; 21310259SAndrew.Bardsley@arm.com} 21410259SAndrew.Bardsley@arm.com 21510259SAndrew.Bardsley@arm.comvoid 21610259SAndrew.Bardsley@arm.comExecute::tryToBranch(MinorDynInstPtr inst, Fault fault, BranchData &branch) 21710259SAndrew.Bardsley@arm.com{ 21810259SAndrew.Bardsley@arm.com ThreadContext *thread = cpu.getContext(inst->id.threadId); 21910259SAndrew.Bardsley@arm.com const TheISA::PCState &pc_before = inst->pc; 22010259SAndrew.Bardsley@arm.com TheISA::PCState target = thread->pcState(); 22110259SAndrew.Bardsley@arm.com 22212489Sgiacomo.travaglini@arm.com /* Force a branch for SerializeAfter/SquashAfter instructions 22312489Sgiacomo.travaglini@arm.com * at the end of micro-op sequence when we're not suspended */ 22410259SAndrew.Bardsley@arm.com bool force_branch = thread->status() != ThreadContext::Suspended && 22510259SAndrew.Bardsley@arm.com !inst->isFault() && 22610259SAndrew.Bardsley@arm.com inst->isLastOpInInst() && 22710259SAndrew.Bardsley@arm.com (inst->staticInst->isSerializeAfter() || 22812489Sgiacomo.travaglini@arm.com inst->staticInst->isSquashAfter() || 22912489Sgiacomo.travaglini@arm.com inst->staticInst->isIprAccess()); 23010259SAndrew.Bardsley@arm.com 23110259SAndrew.Bardsley@arm.com DPRINTF(Branch, "tryToBranch before: %s after: %s%s\n", 23210259SAndrew.Bardsley@arm.com pc_before, target, (force_branch ? " (forcing)" : "")); 23310259SAndrew.Bardsley@arm.com 23410259SAndrew.Bardsley@arm.com /* Will we change the PC to something other than the next instruction? */ 23510259SAndrew.Bardsley@arm.com bool must_branch = pc_before != target || 23610259SAndrew.Bardsley@arm.com fault != NoFault || 23710259SAndrew.Bardsley@arm.com force_branch; 23810259SAndrew.Bardsley@arm.com 23910259SAndrew.Bardsley@arm.com /* The reason for the branch data we're about to generate, set below */ 24010259SAndrew.Bardsley@arm.com BranchData::Reason reason = BranchData::NoBranch; 24110259SAndrew.Bardsley@arm.com 24210259SAndrew.Bardsley@arm.com if (fault == NoFault) 24310259SAndrew.Bardsley@arm.com { 24410259SAndrew.Bardsley@arm.com TheISA::advancePC(target, inst->staticInst); 24510259SAndrew.Bardsley@arm.com thread->pcState(target); 24610259SAndrew.Bardsley@arm.com 24710259SAndrew.Bardsley@arm.com DPRINTF(Branch, "Advancing current PC from: %s to: %s\n", 24810259SAndrew.Bardsley@arm.com pc_before, target); 24910259SAndrew.Bardsley@arm.com } 25010259SAndrew.Bardsley@arm.com 25113647Sqtt2@cornell.edu if (thread->status() == ThreadContext::Suspended) { 25213647Sqtt2@cornell.edu /* Thread got suspended */ 25313647Sqtt2@cornell.edu DPRINTF(Branch, "Thread got suspended: branch from 0x%x to 0x%x " 25413647Sqtt2@cornell.edu "inst: %s\n", 25513647Sqtt2@cornell.edu inst->pc.instAddr(), target.instAddr(), *inst); 25613647Sqtt2@cornell.edu 25713647Sqtt2@cornell.edu reason = BranchData::SuspendThread; 25813647Sqtt2@cornell.edu } else if (inst->predictedTaken && !force_branch) { 25910259SAndrew.Bardsley@arm.com /* Predicted to branch */ 26010259SAndrew.Bardsley@arm.com if (!must_branch) { 26110259SAndrew.Bardsley@arm.com /* No branch was taken, change stream to get us back to the 26210259SAndrew.Bardsley@arm.com * intended PC value */ 26310259SAndrew.Bardsley@arm.com DPRINTF(Branch, "Predicted a branch from 0x%x to 0x%x but" 26410259SAndrew.Bardsley@arm.com " none happened inst: %s\n", 26510259SAndrew.Bardsley@arm.com inst->pc.instAddr(), inst->predictedTarget.instAddr(), *inst); 26610259SAndrew.Bardsley@arm.com 26710259SAndrew.Bardsley@arm.com reason = BranchData::BadlyPredictedBranch; 26810259SAndrew.Bardsley@arm.com } else if (inst->predictedTarget == target) { 26910259SAndrew.Bardsley@arm.com /* Branch prediction got the right target, kill the branch and 27010259SAndrew.Bardsley@arm.com * carry on. 27110259SAndrew.Bardsley@arm.com * Note that this information to the branch predictor might get 27210259SAndrew.Bardsley@arm.com * overwritten by a "real" branch during this cycle */ 27310259SAndrew.Bardsley@arm.com DPRINTF(Branch, "Predicted a branch from 0x%x to 0x%x correctly" 27410259SAndrew.Bardsley@arm.com " inst: %s\n", 27510259SAndrew.Bardsley@arm.com inst->pc.instAddr(), inst->predictedTarget.instAddr(), *inst); 27610259SAndrew.Bardsley@arm.com 27710259SAndrew.Bardsley@arm.com reason = BranchData::CorrectlyPredictedBranch; 27810259SAndrew.Bardsley@arm.com } else { 27910259SAndrew.Bardsley@arm.com /* Branch prediction got the wrong target */ 28010259SAndrew.Bardsley@arm.com DPRINTF(Branch, "Predicted a branch from 0x%x to 0x%x" 28110366Sandreas.hansson@arm.com " but got the wrong target (actual: 0x%x) inst: %s\n", 28210366Sandreas.hansson@arm.com inst->pc.instAddr(), inst->predictedTarget.instAddr(), 28310366Sandreas.hansson@arm.com target.instAddr(), *inst); 28410259SAndrew.Bardsley@arm.com 28510259SAndrew.Bardsley@arm.com reason = BranchData::BadlyPredictedBranchTarget; 28610259SAndrew.Bardsley@arm.com } 28710259SAndrew.Bardsley@arm.com } else if (must_branch) { 28810259SAndrew.Bardsley@arm.com /* Unpredicted branch */ 28910259SAndrew.Bardsley@arm.com DPRINTF(Branch, "Unpredicted branch from 0x%x to 0x%x inst: %s\n", 29010259SAndrew.Bardsley@arm.com inst->pc.instAddr(), target.instAddr(), *inst); 29110259SAndrew.Bardsley@arm.com 29210259SAndrew.Bardsley@arm.com reason = BranchData::UnpredictedBranch; 29310259SAndrew.Bardsley@arm.com } else { 29410259SAndrew.Bardsley@arm.com /* No branch at all */ 29510259SAndrew.Bardsley@arm.com reason = BranchData::NoBranch; 29610259SAndrew.Bardsley@arm.com } 29710259SAndrew.Bardsley@arm.com 29811567Smitch.hayenga@arm.com updateBranchData(inst->id.threadId, reason, inst, target, branch); 29910259SAndrew.Bardsley@arm.com} 30010259SAndrew.Bardsley@arm.com 30110259SAndrew.Bardsley@arm.comvoid 30210259SAndrew.Bardsley@arm.comExecute::updateBranchData( 30311567Smitch.hayenga@arm.com ThreadID tid, 30410259SAndrew.Bardsley@arm.com BranchData::Reason reason, 30510259SAndrew.Bardsley@arm.com MinorDynInstPtr inst, const TheISA::PCState &target, 30610259SAndrew.Bardsley@arm.com BranchData &branch) 30710259SAndrew.Bardsley@arm.com{ 30810259SAndrew.Bardsley@arm.com if (reason != BranchData::NoBranch) { 30910259SAndrew.Bardsley@arm.com /* Bump up the stream sequence number on a real branch*/ 31010259SAndrew.Bardsley@arm.com if (BranchData::isStreamChange(reason)) 31111567Smitch.hayenga@arm.com executeInfo[tid].streamSeqNum++; 31210259SAndrew.Bardsley@arm.com 31310259SAndrew.Bardsley@arm.com /* Branches (even mis-predictions) don't change the predictionSeqNum, 31410259SAndrew.Bardsley@arm.com * just the streamSeqNum */ 31511567Smitch.hayenga@arm.com branch = BranchData(reason, tid, 31611567Smitch.hayenga@arm.com executeInfo[tid].streamSeqNum, 31710259SAndrew.Bardsley@arm.com /* Maintaining predictionSeqNum if there's no inst is just a 31810259SAndrew.Bardsley@arm.com * courtesy and looks better on minorview */ 31911567Smitch.hayenga@arm.com (inst->isBubble() ? executeInfo[tid].lastPredictionSeqNum 32010259SAndrew.Bardsley@arm.com : inst->id.predictionSeqNum), 32110259SAndrew.Bardsley@arm.com target, inst); 32210259SAndrew.Bardsley@arm.com 32310259SAndrew.Bardsley@arm.com DPRINTF(Branch, "Branch data signalled: %s\n", branch); 32410259SAndrew.Bardsley@arm.com } 32510259SAndrew.Bardsley@arm.com} 32610259SAndrew.Bardsley@arm.com 32710259SAndrew.Bardsley@arm.comvoid 32810259SAndrew.Bardsley@arm.comExecute::handleMemResponse(MinorDynInstPtr inst, 32910259SAndrew.Bardsley@arm.com LSQ::LSQRequestPtr response, BranchData &branch, Fault &fault) 33010259SAndrew.Bardsley@arm.com{ 33110259SAndrew.Bardsley@arm.com ThreadID thread_id = inst->id.threadId; 33210259SAndrew.Bardsley@arm.com ThreadContext *thread = cpu.getContext(thread_id); 33310259SAndrew.Bardsley@arm.com 33410259SAndrew.Bardsley@arm.com ExecContext context(cpu, *cpu.threads[thread_id], *this, inst); 33510259SAndrew.Bardsley@arm.com 33610259SAndrew.Bardsley@arm.com PacketPtr packet = response->packet; 33710259SAndrew.Bardsley@arm.com 33810259SAndrew.Bardsley@arm.com bool is_load = inst->staticInst->isLoad(); 33910259SAndrew.Bardsley@arm.com bool is_store = inst->staticInst->isStore(); 34013652Sqtt2@cornell.edu bool is_atomic = inst->staticInst->isAtomic(); 34110259SAndrew.Bardsley@arm.com bool is_prefetch = inst->staticInst->isDataPrefetch(); 34210259SAndrew.Bardsley@arm.com 34310259SAndrew.Bardsley@arm.com /* If true, the trace's predicate value will be taken from the exec 34410259SAndrew.Bardsley@arm.com * context predicate, otherwise, it will be set to false */ 34510259SAndrew.Bardsley@arm.com bool use_context_predicate = true; 34610259SAndrew.Bardsley@arm.com 34710259SAndrew.Bardsley@arm.com if (response->fault != NoFault) { 34810259SAndrew.Bardsley@arm.com /* Invoke memory faults. */ 34910259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Completing fault from DTLB access: %s\n", 35010259SAndrew.Bardsley@arm.com response->fault->name()); 35110259SAndrew.Bardsley@arm.com 35210259SAndrew.Bardsley@arm.com if (inst->staticInst->isPrefetch()) { 35310259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Not taking fault on prefetch: %s\n", 35410259SAndrew.Bardsley@arm.com response->fault->name()); 35510259SAndrew.Bardsley@arm.com 35610259SAndrew.Bardsley@arm.com /* Don't assign to fault */ 35710259SAndrew.Bardsley@arm.com } else { 35810259SAndrew.Bardsley@arm.com /* Take the fault raised during the TLB/memory access */ 35910259SAndrew.Bardsley@arm.com fault = response->fault; 36010259SAndrew.Bardsley@arm.com 36110259SAndrew.Bardsley@arm.com fault->invoke(thread, inst->staticInst); 36210259SAndrew.Bardsley@arm.com } 36310259SAndrew.Bardsley@arm.com } else if (!packet) { 36410259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Completing failed request inst: %s\n", 36510259SAndrew.Bardsley@arm.com *inst); 36610259SAndrew.Bardsley@arm.com use_context_predicate = false; 36713954Sgiacomo.gabrielli@arm.com if (!context.readMemAccPredicate()) 36813954Sgiacomo.gabrielli@arm.com inst->staticInst->completeAcc(nullptr, &context, inst->traceData); 36910259SAndrew.Bardsley@arm.com } else if (packet->isError()) { 37010259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Trying to commit error response: %s\n", 37110259SAndrew.Bardsley@arm.com *inst); 37210259SAndrew.Bardsley@arm.com 37310259SAndrew.Bardsley@arm.com fatal("Received error response packet for inst: %s\n", *inst); 37413652Sqtt2@cornell.edu } else if (is_store || is_load || is_prefetch || is_atomic) { 37510259SAndrew.Bardsley@arm.com assert(packet); 37610259SAndrew.Bardsley@arm.com 37710259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Memory response inst: %s addr: 0x%x size: %d\n", 37810259SAndrew.Bardsley@arm.com *inst, packet->getAddr(), packet->getSize()); 37910259SAndrew.Bardsley@arm.com 38010259SAndrew.Bardsley@arm.com if (is_load && packet->getSize() > 0) { 38110259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Memory data[0]: 0x%x\n", 38210563Sandreas.hansson@arm.com static_cast<unsigned int>(packet->getConstPtr<uint8_t>()[0])); 38310259SAndrew.Bardsley@arm.com } 38410259SAndrew.Bardsley@arm.com 38510259SAndrew.Bardsley@arm.com /* Complete the memory access instruction */ 38610259SAndrew.Bardsley@arm.com fault = inst->staticInst->completeAcc(packet, &context, 38710259SAndrew.Bardsley@arm.com inst->traceData); 38810259SAndrew.Bardsley@arm.com 38910259SAndrew.Bardsley@arm.com if (fault != NoFault) { 39010259SAndrew.Bardsley@arm.com /* Invoke fault created by instruction completion */ 39110259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Fault in memory completeAcc: %s\n", 39210259SAndrew.Bardsley@arm.com fault->name()); 39310259SAndrew.Bardsley@arm.com fault->invoke(thread, inst->staticInst); 39410259SAndrew.Bardsley@arm.com } else { 39510259SAndrew.Bardsley@arm.com /* Stores need to be pushed into the store buffer to finish 39610259SAndrew.Bardsley@arm.com * them off */ 39710259SAndrew.Bardsley@arm.com if (response->needsToBeSentToStoreBuffer()) 39810259SAndrew.Bardsley@arm.com lsq.sendStoreToStoreBuffer(response); 39910259SAndrew.Bardsley@arm.com } 40010259SAndrew.Bardsley@arm.com } else { 40110259SAndrew.Bardsley@arm.com fatal("There should only ever be reads, " 40210259SAndrew.Bardsley@arm.com "writes or faults at this point\n"); 40310259SAndrew.Bardsley@arm.com } 40410259SAndrew.Bardsley@arm.com 40510259SAndrew.Bardsley@arm.com lsq.popResponse(response); 40610259SAndrew.Bardsley@arm.com 40710259SAndrew.Bardsley@arm.com if (inst->traceData) { 40810259SAndrew.Bardsley@arm.com inst->traceData->setPredicate((use_context_predicate ? 40910259SAndrew.Bardsley@arm.com context.readPredicate() : false)); 41010259SAndrew.Bardsley@arm.com } 41110259SAndrew.Bardsley@arm.com 41210259SAndrew.Bardsley@arm.com doInstCommitAccounting(inst); 41310259SAndrew.Bardsley@arm.com 41410259SAndrew.Bardsley@arm.com /* Generate output to account for branches */ 41510259SAndrew.Bardsley@arm.com tryToBranch(inst, fault, branch); 41610259SAndrew.Bardsley@arm.com} 41710259SAndrew.Bardsley@arm.com 41810259SAndrew.Bardsley@arm.combool 41910259SAndrew.Bardsley@arm.comExecute::isInterrupted(ThreadID thread_id) const 42010259SAndrew.Bardsley@arm.com{ 42110259SAndrew.Bardsley@arm.com return cpu.checkInterrupts(cpu.getContext(thread_id)); 42210259SAndrew.Bardsley@arm.com} 42310259SAndrew.Bardsley@arm.com 42410259SAndrew.Bardsley@arm.combool 42510259SAndrew.Bardsley@arm.comExecute::takeInterrupt(ThreadID thread_id, BranchData &branch) 42610259SAndrew.Bardsley@arm.com{ 42710259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Considering interrupt status from PC: %s\n", 42810259SAndrew.Bardsley@arm.com cpu.getContext(thread_id)->pcState()); 42910259SAndrew.Bardsley@arm.com 43011150Smitch.hayenga@arm.com Fault interrupt = cpu.getInterruptController(thread_id)->getInterrupt 43110259SAndrew.Bardsley@arm.com (cpu.getContext(thread_id)); 43210259SAndrew.Bardsley@arm.com 43310259SAndrew.Bardsley@arm.com if (interrupt != NoFault) { 43410259SAndrew.Bardsley@arm.com /* The interrupt *must* set pcState */ 43511150Smitch.hayenga@arm.com cpu.getInterruptController(thread_id)->updateIntrInfo 43610259SAndrew.Bardsley@arm.com (cpu.getContext(thread_id)); 43710259SAndrew.Bardsley@arm.com interrupt->invoke(cpu.getContext(thread_id)); 43810259SAndrew.Bardsley@arm.com 43910259SAndrew.Bardsley@arm.com assert(!lsq.accessesInFlight()); 44010259SAndrew.Bardsley@arm.com 44110259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Invoking interrupt: %s to PC: %s\n", 44210259SAndrew.Bardsley@arm.com interrupt->name(), cpu.getContext(thread_id)->pcState()); 44310259SAndrew.Bardsley@arm.com 44410259SAndrew.Bardsley@arm.com /* Assume that an interrupt *must* cause a branch. Assert this? */ 44510259SAndrew.Bardsley@arm.com 44611567Smitch.hayenga@arm.com updateBranchData(thread_id, BranchData::Interrupt, 44711567Smitch.hayenga@arm.com MinorDynInst::bubble(), cpu.getContext(thread_id)->pcState(), 44811567Smitch.hayenga@arm.com branch); 44910259SAndrew.Bardsley@arm.com } 45010259SAndrew.Bardsley@arm.com 45110259SAndrew.Bardsley@arm.com return interrupt != NoFault; 45210259SAndrew.Bardsley@arm.com} 45310259SAndrew.Bardsley@arm.com 45410259SAndrew.Bardsley@arm.combool 45510259SAndrew.Bardsley@arm.comExecute::executeMemRefInst(MinorDynInstPtr inst, BranchData &branch, 45610259SAndrew.Bardsley@arm.com bool &passed_predicate, Fault &fault) 45710259SAndrew.Bardsley@arm.com{ 45810259SAndrew.Bardsley@arm.com bool issued = false; 45910259SAndrew.Bardsley@arm.com 46010259SAndrew.Bardsley@arm.com /* Set to true if the mem op. is issued and sent to the mem system */ 46110259SAndrew.Bardsley@arm.com passed_predicate = false; 46210259SAndrew.Bardsley@arm.com 46310259SAndrew.Bardsley@arm.com if (!lsq.canRequest()) { 46410259SAndrew.Bardsley@arm.com /* Not acting on instruction yet as the memory 46510259SAndrew.Bardsley@arm.com * queues are full */ 46610259SAndrew.Bardsley@arm.com issued = false; 46710259SAndrew.Bardsley@arm.com } else { 46810259SAndrew.Bardsley@arm.com ThreadContext *thread = cpu.getContext(inst->id.threadId); 46910259SAndrew.Bardsley@arm.com TheISA::PCState old_pc = thread->pcState(); 47010259SAndrew.Bardsley@arm.com 47110259SAndrew.Bardsley@arm.com ExecContext context(cpu, *cpu.threads[inst->id.threadId], 47210259SAndrew.Bardsley@arm.com *this, inst); 47310259SAndrew.Bardsley@arm.com 47410259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Initiating memRef inst: %s\n", *inst); 47510259SAndrew.Bardsley@arm.com 47610259SAndrew.Bardsley@arm.com Fault init_fault = inst->staticInst->initiateAcc(&context, 47710259SAndrew.Bardsley@arm.com inst->traceData); 47810259SAndrew.Bardsley@arm.com 47910259SAndrew.Bardsley@arm.com if (init_fault != NoFault) { 48010259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Fault on memory inst: %s" 48110259SAndrew.Bardsley@arm.com " initiateAcc: %s\n", *inst, init_fault->name()); 48210259SAndrew.Bardsley@arm.com fault = init_fault; 48310259SAndrew.Bardsley@arm.com } else { 48410259SAndrew.Bardsley@arm.com /* Only set this if the instruction passed its 48510259SAndrew.Bardsley@arm.com * predicate */ 48613954Sgiacomo.gabrielli@arm.com if (!context.readMemAccPredicate()) { 48713954Sgiacomo.gabrielli@arm.com DPRINTF(MinorMem, "No memory access for inst: %s\n", *inst); 48813954Sgiacomo.gabrielli@arm.com assert(context.readPredicate()); 48913954Sgiacomo.gabrielli@arm.com } 49010259SAndrew.Bardsley@arm.com passed_predicate = context.readPredicate(); 49110259SAndrew.Bardsley@arm.com 49210259SAndrew.Bardsley@arm.com /* Set predicate in tracing */ 49310259SAndrew.Bardsley@arm.com if (inst->traceData) 49410259SAndrew.Bardsley@arm.com inst->traceData->setPredicate(passed_predicate); 49510259SAndrew.Bardsley@arm.com 49610259SAndrew.Bardsley@arm.com /* If the instruction didn't pass its predicate (and so will not 49710259SAndrew.Bardsley@arm.com * progress from here) Try to branch to correct and branch 49810259SAndrew.Bardsley@arm.com * mis-prediction. */ 49910259SAndrew.Bardsley@arm.com if (!passed_predicate) { 50010259SAndrew.Bardsley@arm.com /* Leave it up to commit to handle the fault */ 50110259SAndrew.Bardsley@arm.com lsq.pushFailedRequest(inst); 50210259SAndrew.Bardsley@arm.com } 50310259SAndrew.Bardsley@arm.com } 50410259SAndrew.Bardsley@arm.com 50510259SAndrew.Bardsley@arm.com /* Restore thread PC */ 50610259SAndrew.Bardsley@arm.com thread->pcState(old_pc); 50710259SAndrew.Bardsley@arm.com issued = true; 50810259SAndrew.Bardsley@arm.com } 50910259SAndrew.Bardsley@arm.com 51010259SAndrew.Bardsley@arm.com return issued; 51110259SAndrew.Bardsley@arm.com} 51210259SAndrew.Bardsley@arm.com 51310259SAndrew.Bardsley@arm.com/** Increment a cyclic buffer index for indices [0, cycle_size-1] */ 51410259SAndrew.Bardsley@arm.cominline unsigned int 51510259SAndrew.Bardsley@arm.comcyclicIndexInc(unsigned int index, unsigned int cycle_size) 51610259SAndrew.Bardsley@arm.com{ 51710259SAndrew.Bardsley@arm.com unsigned int ret = index + 1; 51810259SAndrew.Bardsley@arm.com 51910259SAndrew.Bardsley@arm.com if (ret == cycle_size) 52010259SAndrew.Bardsley@arm.com ret = 0; 52110259SAndrew.Bardsley@arm.com 52210259SAndrew.Bardsley@arm.com return ret; 52310259SAndrew.Bardsley@arm.com} 52410259SAndrew.Bardsley@arm.com 52510259SAndrew.Bardsley@arm.com/** Decrement a cyclic buffer index for indices [0, cycle_size-1] */ 52610259SAndrew.Bardsley@arm.cominline unsigned int 52710259SAndrew.Bardsley@arm.comcyclicIndexDec(unsigned int index, unsigned int cycle_size) 52810259SAndrew.Bardsley@arm.com{ 52910259SAndrew.Bardsley@arm.com int ret = index - 1; 53010259SAndrew.Bardsley@arm.com 53110259SAndrew.Bardsley@arm.com if (ret < 0) 53210259SAndrew.Bardsley@arm.com ret = cycle_size - 1; 53310259SAndrew.Bardsley@arm.com 53410259SAndrew.Bardsley@arm.com return ret; 53510259SAndrew.Bardsley@arm.com} 53610259SAndrew.Bardsley@arm.com 53710259SAndrew.Bardsley@arm.comunsigned int 53811567Smitch.hayenga@arm.comExecute::issue(ThreadID thread_id) 53910259SAndrew.Bardsley@arm.com{ 54011567Smitch.hayenga@arm.com const ForwardInstData *insts_in = getInput(thread_id); 54111567Smitch.hayenga@arm.com ExecuteThreadInfo &thread = executeInfo[thread_id]; 54210259SAndrew.Bardsley@arm.com 54310259SAndrew.Bardsley@arm.com /* Early termination if we have no instructions */ 54410259SAndrew.Bardsley@arm.com if (!insts_in) 54510259SAndrew.Bardsley@arm.com return 0; 54610259SAndrew.Bardsley@arm.com 54710259SAndrew.Bardsley@arm.com /* Start from the first FU */ 54810259SAndrew.Bardsley@arm.com unsigned int fu_index = 0; 54910259SAndrew.Bardsley@arm.com 55010259SAndrew.Bardsley@arm.com /* Remains true while instructions are still being issued. If any 55110259SAndrew.Bardsley@arm.com * instruction fails to issue, this is set to false and we exit issue. 55210259SAndrew.Bardsley@arm.com * This strictly enforces in-order issue. For other issue behaviours, 55310259SAndrew.Bardsley@arm.com * a more complicated test in the outer while loop below is needed. */ 55410259SAndrew.Bardsley@arm.com bool issued = true; 55510259SAndrew.Bardsley@arm.com 55610259SAndrew.Bardsley@arm.com /* Number of insts issues this cycle to check for issueLimit */ 55710259SAndrew.Bardsley@arm.com unsigned num_insts_issued = 0; 55810259SAndrew.Bardsley@arm.com 55910259SAndrew.Bardsley@arm.com /* Number of memory ops issues this cycle to check for memoryIssueLimit */ 56010259SAndrew.Bardsley@arm.com unsigned num_mem_insts_issued = 0; 56110259SAndrew.Bardsley@arm.com 56210259SAndrew.Bardsley@arm.com /* Number of instructions discarded this cycle in order to enforce a 56310259SAndrew.Bardsley@arm.com * discardLimit. @todo, add that parameter? */ 56410259SAndrew.Bardsley@arm.com unsigned num_insts_discarded = 0; 56510259SAndrew.Bardsley@arm.com 56610259SAndrew.Bardsley@arm.com do { 56711567Smitch.hayenga@arm.com MinorDynInstPtr inst = insts_in->insts[thread.inputIndex]; 56810259SAndrew.Bardsley@arm.com Fault fault = inst->fault; 56910259SAndrew.Bardsley@arm.com bool discarded = false; 57010259SAndrew.Bardsley@arm.com bool issued_mem_ref = false; 57110259SAndrew.Bardsley@arm.com 57210259SAndrew.Bardsley@arm.com if (inst->isBubble()) { 57310259SAndrew.Bardsley@arm.com /* Skip */ 57410259SAndrew.Bardsley@arm.com issued = true; 57510259SAndrew.Bardsley@arm.com } else if (cpu.getContext(thread_id)->status() == 57610259SAndrew.Bardsley@arm.com ThreadContext::Suspended) 57710259SAndrew.Bardsley@arm.com { 57811568Smitch.hayenga@arm.com DPRINTF(MinorExecute, "Discarding inst: %s from suspended" 57910259SAndrew.Bardsley@arm.com " thread\n", *inst); 58010259SAndrew.Bardsley@arm.com 58111568Smitch.hayenga@arm.com issued = true; 58211568Smitch.hayenga@arm.com discarded = true; 58311567Smitch.hayenga@arm.com } else if (inst->id.streamSeqNum != thread.streamSeqNum) { 58410259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Discarding inst: %s as its stream" 58510259SAndrew.Bardsley@arm.com " state was unexpected, expected: %d\n", 58611567Smitch.hayenga@arm.com *inst, thread.streamSeqNum); 58710259SAndrew.Bardsley@arm.com issued = true; 58810259SAndrew.Bardsley@arm.com discarded = true; 58910259SAndrew.Bardsley@arm.com } else { 59010259SAndrew.Bardsley@arm.com /* Try and issue an instruction into an FU, assume we didn't and 59110259SAndrew.Bardsley@arm.com * fix that in the loop */ 59210259SAndrew.Bardsley@arm.com issued = false; 59310259SAndrew.Bardsley@arm.com 59410259SAndrew.Bardsley@arm.com /* Try FU from 0 each instruction */ 59510259SAndrew.Bardsley@arm.com fu_index = 0; 59610259SAndrew.Bardsley@arm.com 59710259SAndrew.Bardsley@arm.com /* Try and issue a single instruction stepping through the 59810259SAndrew.Bardsley@arm.com * available FUs */ 59910259SAndrew.Bardsley@arm.com do { 60010259SAndrew.Bardsley@arm.com FUPipeline *fu = funcUnits[fu_index]; 60110259SAndrew.Bardsley@arm.com 60210259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Trying to issue inst: %s to FU: %d\n", 60310259SAndrew.Bardsley@arm.com *inst, fu_index); 60410259SAndrew.Bardsley@arm.com 60510259SAndrew.Bardsley@arm.com /* Does the examined fu have the OpClass-related capability 60610259SAndrew.Bardsley@arm.com * needed to execute this instruction? Faults can always 60710259SAndrew.Bardsley@arm.com * issue to any FU but probably should just 'live' in the 60810259SAndrew.Bardsley@arm.com * inFlightInsts queue rather than having an FU. */ 60910259SAndrew.Bardsley@arm.com bool fu_is_capable = (!inst->isFault() ? 61010259SAndrew.Bardsley@arm.com fu->provides(inst->staticInst->opClass()) : true); 61110259SAndrew.Bardsley@arm.com 61210259SAndrew.Bardsley@arm.com if (inst->isNoCostInst()) { 61310259SAndrew.Bardsley@arm.com /* Issue free insts. to a fake numbered FU */ 61410259SAndrew.Bardsley@arm.com fu_index = noCostFUIndex; 61510259SAndrew.Bardsley@arm.com 61610259SAndrew.Bardsley@arm.com /* And start the countdown on activity to allow 61710259SAndrew.Bardsley@arm.com * this instruction to get to the end of its FU */ 61810259SAndrew.Bardsley@arm.com cpu.activityRecorder->activity(); 61910259SAndrew.Bardsley@arm.com 62010259SAndrew.Bardsley@arm.com /* Mark the destinations for this instruction as 62110259SAndrew.Bardsley@arm.com * busy */ 62211567Smitch.hayenga@arm.com scoreboard[thread_id].markupInstDests(inst, cpu.curCycle() + 62310259SAndrew.Bardsley@arm.com Cycles(0), cpu.getContext(thread_id), false); 62410259SAndrew.Bardsley@arm.com 62511567Smitch.hayenga@arm.com DPRINTF(MinorExecute, "Issuing %s to %d\n", inst->id, noCostFUIndex); 62610259SAndrew.Bardsley@arm.com inst->fuIndex = noCostFUIndex; 62710259SAndrew.Bardsley@arm.com inst->extraCommitDelay = Cycles(0); 62810259SAndrew.Bardsley@arm.com inst->extraCommitDelayExpr = NULL; 62910259SAndrew.Bardsley@arm.com 63010259SAndrew.Bardsley@arm.com /* Push the instruction onto the inFlight queue so 63110259SAndrew.Bardsley@arm.com * it can be committed in order */ 63210259SAndrew.Bardsley@arm.com QueuedInst fu_inst(inst); 63311567Smitch.hayenga@arm.com thread.inFlightInsts->push(fu_inst); 63410259SAndrew.Bardsley@arm.com 63510259SAndrew.Bardsley@arm.com issued = true; 63610259SAndrew.Bardsley@arm.com 63710259SAndrew.Bardsley@arm.com } else if (!fu_is_capable || fu->alreadyPushed()) { 63810259SAndrew.Bardsley@arm.com /* Skip */ 63910259SAndrew.Bardsley@arm.com if (!fu_is_capable) { 64010259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue as FU: %d isn't" 64110259SAndrew.Bardsley@arm.com " capable\n", fu_index); 64210259SAndrew.Bardsley@arm.com } else { 64310259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue as FU: %d is" 64410259SAndrew.Bardsley@arm.com " already busy\n", fu_index); 64510259SAndrew.Bardsley@arm.com } 64610259SAndrew.Bardsley@arm.com } else if (fu->stalled) { 64710259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue inst: %s into FU: %d," 64810259SAndrew.Bardsley@arm.com " it's stalled\n", 64910259SAndrew.Bardsley@arm.com *inst, fu_index); 65010259SAndrew.Bardsley@arm.com } else if (!fu->canInsert()) { 65110259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue inst: %s to busy FU" 65210259SAndrew.Bardsley@arm.com " for another: %d cycles\n", 65310259SAndrew.Bardsley@arm.com *inst, fu->cyclesBeforeInsert()); 65410259SAndrew.Bardsley@arm.com } else { 65510259SAndrew.Bardsley@arm.com MinorFUTiming *timing = (!inst->isFault() ? 65610259SAndrew.Bardsley@arm.com fu->findTiming(inst->staticInst) : NULL); 65710259SAndrew.Bardsley@arm.com 65810259SAndrew.Bardsley@arm.com const std::vector<Cycles> *src_latencies = 65910259SAndrew.Bardsley@arm.com (timing ? &(timing->srcRegsRelativeLats) 66010259SAndrew.Bardsley@arm.com : NULL); 66110259SAndrew.Bardsley@arm.com 66210259SAndrew.Bardsley@arm.com const std::vector<bool> *cant_forward_from_fu_indices = 66310259SAndrew.Bardsley@arm.com &(fu->cantForwardFromFUIndices); 66410259SAndrew.Bardsley@arm.com 66510259SAndrew.Bardsley@arm.com if (timing && timing->suppress) { 66610259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue inst: %s as extra" 66710259SAndrew.Bardsley@arm.com " decoding is suppressing it\n", 66810259SAndrew.Bardsley@arm.com *inst); 66911567Smitch.hayenga@arm.com } else if (!scoreboard[thread_id].canInstIssue(inst, 67011567Smitch.hayenga@arm.com src_latencies, cant_forward_from_fu_indices, 67110259SAndrew.Bardsley@arm.com cpu.curCycle(), cpu.getContext(thread_id))) 67210259SAndrew.Bardsley@arm.com { 67310259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue inst: %s yet\n", 67410259SAndrew.Bardsley@arm.com *inst); 67510259SAndrew.Bardsley@arm.com } else { 67610259SAndrew.Bardsley@arm.com /* Can insert the instruction into this FU */ 67710259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Issuing inst: %s" 67810259SAndrew.Bardsley@arm.com " into FU %d\n", *inst, 67910259SAndrew.Bardsley@arm.com fu_index); 68010259SAndrew.Bardsley@arm.com 68110259SAndrew.Bardsley@arm.com Cycles extra_dest_retire_lat = Cycles(0); 68210259SAndrew.Bardsley@arm.com TimingExpr *extra_dest_retire_lat_expr = NULL; 68310259SAndrew.Bardsley@arm.com Cycles extra_assumed_lat = Cycles(0); 68410259SAndrew.Bardsley@arm.com 68510259SAndrew.Bardsley@arm.com /* Add the extraCommitDelay and extraAssumeLat to 68610259SAndrew.Bardsley@arm.com * the FU pipeline timings */ 68710259SAndrew.Bardsley@arm.com if (timing) { 68810259SAndrew.Bardsley@arm.com extra_dest_retire_lat = 68910259SAndrew.Bardsley@arm.com timing->extraCommitLat; 69010259SAndrew.Bardsley@arm.com extra_dest_retire_lat_expr = 69110259SAndrew.Bardsley@arm.com timing->extraCommitLatExpr; 69210259SAndrew.Bardsley@arm.com extra_assumed_lat = 69310259SAndrew.Bardsley@arm.com timing->extraAssumedLat; 69410259SAndrew.Bardsley@arm.com } 69510259SAndrew.Bardsley@arm.com 69610580SAndrew.Bardsley@arm.com issued_mem_ref = inst->isMemRef(); 69710259SAndrew.Bardsley@arm.com 69810259SAndrew.Bardsley@arm.com QueuedInst fu_inst(inst); 69910259SAndrew.Bardsley@arm.com 70010259SAndrew.Bardsley@arm.com /* Decorate the inst with FU details */ 70110259SAndrew.Bardsley@arm.com inst->fuIndex = fu_index; 70210259SAndrew.Bardsley@arm.com inst->extraCommitDelay = extra_dest_retire_lat; 70310259SAndrew.Bardsley@arm.com inst->extraCommitDelayExpr = 70410259SAndrew.Bardsley@arm.com extra_dest_retire_lat_expr; 70510259SAndrew.Bardsley@arm.com 70610259SAndrew.Bardsley@arm.com if (issued_mem_ref) { 70710259SAndrew.Bardsley@arm.com /* Remember which instruction this memory op 70810259SAndrew.Bardsley@arm.com * depends on so that initiateAcc can be called 70910259SAndrew.Bardsley@arm.com * early */ 71010259SAndrew.Bardsley@arm.com if (allowEarlyMemIssue) { 71110259SAndrew.Bardsley@arm.com inst->instToWaitFor = 71211567Smitch.hayenga@arm.com scoreboard[thread_id].execSeqNumToWaitFor(inst, 71310259SAndrew.Bardsley@arm.com cpu.getContext(thread_id)); 71410259SAndrew.Bardsley@arm.com 71511567Smitch.hayenga@arm.com if (lsq.getLastMemBarrier(thread_id) > 71610259SAndrew.Bardsley@arm.com inst->instToWaitFor) 71710259SAndrew.Bardsley@arm.com { 71810259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "A barrier will" 71910259SAndrew.Bardsley@arm.com " cause a delay in mem ref issue of" 72010259SAndrew.Bardsley@arm.com " inst: %s until after inst" 72110259SAndrew.Bardsley@arm.com " %d(exec)\n", *inst, 72211567Smitch.hayenga@arm.com lsq.getLastMemBarrier(thread_id)); 72310259SAndrew.Bardsley@arm.com 72410259SAndrew.Bardsley@arm.com inst->instToWaitFor = 72511567Smitch.hayenga@arm.com lsq.getLastMemBarrier(thread_id); 72610259SAndrew.Bardsley@arm.com } else { 72710259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Memory ref inst:" 72810259SAndrew.Bardsley@arm.com " %s must wait for inst %d(exec)" 72910259SAndrew.Bardsley@arm.com " before issuing\n", 73010259SAndrew.Bardsley@arm.com *inst, inst->instToWaitFor); 73110259SAndrew.Bardsley@arm.com } 73210259SAndrew.Bardsley@arm.com 73310259SAndrew.Bardsley@arm.com inst->canEarlyIssue = true; 73410259SAndrew.Bardsley@arm.com } 73510259SAndrew.Bardsley@arm.com /* Also queue this instruction in the memory ref 73610259SAndrew.Bardsley@arm.com * queue to ensure in-order issue to the LSQ */ 73710259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Pushing mem inst: %s\n", 73810259SAndrew.Bardsley@arm.com *inst); 73911567Smitch.hayenga@arm.com thread.inFUMemInsts->push(fu_inst); 74010259SAndrew.Bardsley@arm.com } 74110259SAndrew.Bardsley@arm.com 74210259SAndrew.Bardsley@arm.com /* Issue to FU */ 74310259SAndrew.Bardsley@arm.com fu->push(fu_inst); 74410259SAndrew.Bardsley@arm.com /* And start the countdown on activity to allow 74510259SAndrew.Bardsley@arm.com * this instruction to get to the end of its FU */ 74610259SAndrew.Bardsley@arm.com cpu.activityRecorder->activity(); 74710259SAndrew.Bardsley@arm.com 74810259SAndrew.Bardsley@arm.com /* Mark the destinations for this instruction as 74910259SAndrew.Bardsley@arm.com * busy */ 75011567Smitch.hayenga@arm.com scoreboard[thread_id].markupInstDests(inst, cpu.curCycle() + 75110259SAndrew.Bardsley@arm.com fu->description.opLat + 75210259SAndrew.Bardsley@arm.com extra_dest_retire_lat + 75310259SAndrew.Bardsley@arm.com extra_assumed_lat, 75410259SAndrew.Bardsley@arm.com cpu.getContext(thread_id), 75510259SAndrew.Bardsley@arm.com issued_mem_ref && extra_assumed_lat == Cycles(0)); 75610259SAndrew.Bardsley@arm.com 75710259SAndrew.Bardsley@arm.com /* Push the instruction onto the inFlight queue so 75810259SAndrew.Bardsley@arm.com * it can be committed in order */ 75911567Smitch.hayenga@arm.com thread.inFlightInsts->push(fu_inst); 76010259SAndrew.Bardsley@arm.com 76110259SAndrew.Bardsley@arm.com issued = true; 76210259SAndrew.Bardsley@arm.com } 76310259SAndrew.Bardsley@arm.com } 76410259SAndrew.Bardsley@arm.com 76510259SAndrew.Bardsley@arm.com fu_index++; 76610259SAndrew.Bardsley@arm.com } while (fu_index != numFuncUnits && !issued); 76710259SAndrew.Bardsley@arm.com 76810259SAndrew.Bardsley@arm.com if (!issued) 76910259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Didn't issue inst: %s\n", *inst); 77010259SAndrew.Bardsley@arm.com } 77110259SAndrew.Bardsley@arm.com 77210259SAndrew.Bardsley@arm.com if (issued) { 77310259SAndrew.Bardsley@arm.com /* Generate MinorTrace's MinorInst lines. Do this at commit 77410259SAndrew.Bardsley@arm.com * to allow better instruction annotation? */ 77510259SAndrew.Bardsley@arm.com if (DTRACE(MinorTrace) && !inst->isBubble()) 77610259SAndrew.Bardsley@arm.com inst->minorTraceInst(*this); 77710259SAndrew.Bardsley@arm.com 77810259SAndrew.Bardsley@arm.com /* Mark up barriers in the LSQ */ 77910259SAndrew.Bardsley@arm.com if (!discarded && inst->isInst() && 78010259SAndrew.Bardsley@arm.com inst->staticInst->isMemBarrier()) 78110259SAndrew.Bardsley@arm.com { 78210259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Issuing memory barrier inst: %s\n", *inst); 78310259SAndrew.Bardsley@arm.com lsq.issuedMemBarrierInst(inst); 78410259SAndrew.Bardsley@arm.com } 78510259SAndrew.Bardsley@arm.com 78610259SAndrew.Bardsley@arm.com if (inst->traceData && setTraceTimeOnIssue) { 78710259SAndrew.Bardsley@arm.com inst->traceData->setWhen(curTick()); 78810259SAndrew.Bardsley@arm.com } 78910259SAndrew.Bardsley@arm.com 79010259SAndrew.Bardsley@arm.com if (issued_mem_ref) 79110259SAndrew.Bardsley@arm.com num_mem_insts_issued++; 79210259SAndrew.Bardsley@arm.com 79310259SAndrew.Bardsley@arm.com if (discarded) { 79410259SAndrew.Bardsley@arm.com num_insts_discarded++; 79510851SAndrew.Bardsley@arm.com } else if (!inst->isBubble()) { 79610259SAndrew.Bardsley@arm.com num_insts_issued++; 79710259SAndrew.Bardsley@arm.com 79810259SAndrew.Bardsley@arm.com if (num_insts_issued == issueLimit) 79910259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Reached inst issue limit\n"); 80010259SAndrew.Bardsley@arm.com } 80110259SAndrew.Bardsley@arm.com 80211567Smitch.hayenga@arm.com thread.inputIndex++; 80310259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Stepping to next inst inputIndex: %d\n", 80411567Smitch.hayenga@arm.com thread.inputIndex); 80510259SAndrew.Bardsley@arm.com } 80610259SAndrew.Bardsley@arm.com 80710259SAndrew.Bardsley@arm.com /* Got to the end of a line */ 80811567Smitch.hayenga@arm.com if (thread.inputIndex == insts_in->width()) { 80911567Smitch.hayenga@arm.com popInput(thread_id); 81010259SAndrew.Bardsley@arm.com /* Set insts_in to null to force us to leave the surrounding 81110259SAndrew.Bardsley@arm.com * loop */ 81210259SAndrew.Bardsley@arm.com insts_in = NULL; 81310259SAndrew.Bardsley@arm.com 81410259SAndrew.Bardsley@arm.com if (processMoreThanOneInput) { 81510259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Wrapping\n"); 81611567Smitch.hayenga@arm.com insts_in = getInput(thread_id); 81710259SAndrew.Bardsley@arm.com } 81810259SAndrew.Bardsley@arm.com } 81911567Smitch.hayenga@arm.com } while (insts_in && thread.inputIndex < insts_in->width() && 82010259SAndrew.Bardsley@arm.com /* We still have instructions */ 82110259SAndrew.Bardsley@arm.com fu_index != numFuncUnits && /* Not visited all FUs */ 82210259SAndrew.Bardsley@arm.com issued && /* We've not yet failed to issue an instruction */ 82310259SAndrew.Bardsley@arm.com num_insts_issued != issueLimit && /* Still allowed to issue */ 82410259SAndrew.Bardsley@arm.com num_mem_insts_issued != memoryIssueLimit); 82510259SAndrew.Bardsley@arm.com 82610259SAndrew.Bardsley@arm.com return num_insts_issued; 82710259SAndrew.Bardsley@arm.com} 82810259SAndrew.Bardsley@arm.com 82910259SAndrew.Bardsley@arm.combool 83011567Smitch.hayenga@arm.comExecute::tryPCEvents(ThreadID thread_id) 83110259SAndrew.Bardsley@arm.com{ 83211567Smitch.hayenga@arm.com ThreadContext *thread = cpu.getContext(thread_id); 83310259SAndrew.Bardsley@arm.com unsigned int num_pc_event_checks = 0; 83410259SAndrew.Bardsley@arm.com 83510259SAndrew.Bardsley@arm.com /* Handle PC events on instructions */ 83610259SAndrew.Bardsley@arm.com Addr oldPC; 83710259SAndrew.Bardsley@arm.com do { 83810259SAndrew.Bardsley@arm.com oldPC = thread->instAddr(); 83910259SAndrew.Bardsley@arm.com cpu.system->pcEventQueue.service(thread); 84010259SAndrew.Bardsley@arm.com num_pc_event_checks++; 84110259SAndrew.Bardsley@arm.com } while (oldPC != thread->instAddr()); 84210259SAndrew.Bardsley@arm.com 84310259SAndrew.Bardsley@arm.com if (num_pc_event_checks > 1) { 84410259SAndrew.Bardsley@arm.com DPRINTF(PCEvent, "Acting on PC Event to PC: %s\n", 84510259SAndrew.Bardsley@arm.com thread->pcState()); 84610259SAndrew.Bardsley@arm.com } 84710259SAndrew.Bardsley@arm.com 84810259SAndrew.Bardsley@arm.com return num_pc_event_checks > 1; 84910259SAndrew.Bardsley@arm.com} 85010259SAndrew.Bardsley@arm.com 85110259SAndrew.Bardsley@arm.comvoid 85210259SAndrew.Bardsley@arm.comExecute::doInstCommitAccounting(MinorDynInstPtr inst) 85310259SAndrew.Bardsley@arm.com{ 85410259SAndrew.Bardsley@arm.com assert(!inst->isFault()); 85510259SAndrew.Bardsley@arm.com 85610259SAndrew.Bardsley@arm.com MinorThread *thread = cpu.threads[inst->id.threadId]; 85710259SAndrew.Bardsley@arm.com 85810259SAndrew.Bardsley@arm.com /* Increment the many and various inst and op counts in the 85910259SAndrew.Bardsley@arm.com * thread and system */ 86010259SAndrew.Bardsley@arm.com if (!inst->staticInst->isMicroop() || inst->staticInst->isLastMicroop()) 86110259SAndrew.Bardsley@arm.com { 86210259SAndrew.Bardsley@arm.com thread->numInst++; 86310259SAndrew.Bardsley@arm.com thread->numInsts++; 86410259SAndrew.Bardsley@arm.com cpu.stats.numInsts++; 86510774Snikos.nikoleris@gmail.com cpu.system->totalNumInsts++; 86610774Snikos.nikoleris@gmail.com 86710774Snikos.nikoleris@gmail.com /* Act on events related to instruction counts */ 86810774Snikos.nikoleris@gmail.com cpu.comInstEventQueue[inst->id.threadId]->serviceEvents(thread->numInst); 86910774Snikos.nikoleris@gmail.com cpu.system->instEventQueue.serviceEvents(cpu.system->totalNumInsts); 87010259SAndrew.Bardsley@arm.com } 87110259SAndrew.Bardsley@arm.com thread->numOp++; 87210259SAndrew.Bardsley@arm.com thread->numOps++; 87310259SAndrew.Bardsley@arm.com cpu.stats.numOps++; 87411419Smitch.hayenga@arm.com cpu.stats.committedInstType[inst->id.threadId] 87511419Smitch.hayenga@arm.com [inst->staticInst->opClass()]++; 87610259SAndrew.Bardsley@arm.com 87710259SAndrew.Bardsley@arm.com /* Set the CP SeqNum to the numOps commit number */ 87810259SAndrew.Bardsley@arm.com if (inst->traceData) 87910259SAndrew.Bardsley@arm.com inst->traceData->setCPSeq(thread->numOp); 88010464SAndreas.Sandberg@ARM.com 88113818Sjavier.bueno@metempsy.com cpu.probeInstCommit(inst->staticInst, inst->pc.instAddr()); 88210259SAndrew.Bardsley@arm.com} 88310259SAndrew.Bardsley@arm.com 88410259SAndrew.Bardsley@arm.combool 88510259SAndrew.Bardsley@arm.comExecute::commitInst(MinorDynInstPtr inst, bool early_memory_issue, 88610259SAndrew.Bardsley@arm.com BranchData &branch, Fault &fault, bool &committed, 88710259SAndrew.Bardsley@arm.com bool &completed_mem_issue) 88810259SAndrew.Bardsley@arm.com{ 88910259SAndrew.Bardsley@arm.com ThreadID thread_id = inst->id.threadId; 89010259SAndrew.Bardsley@arm.com ThreadContext *thread = cpu.getContext(thread_id); 89110259SAndrew.Bardsley@arm.com 89210259SAndrew.Bardsley@arm.com bool completed_inst = true; 89310259SAndrew.Bardsley@arm.com fault = NoFault; 89410259SAndrew.Bardsley@arm.com 89510259SAndrew.Bardsley@arm.com /* Is the thread for this instruction suspended? In that case, just 89610259SAndrew.Bardsley@arm.com * stall as long as there are no pending interrupts */ 89710259SAndrew.Bardsley@arm.com if (thread->status() == ThreadContext::Suspended && 89810259SAndrew.Bardsley@arm.com !isInterrupted(thread_id)) 89910259SAndrew.Bardsley@arm.com { 90011568Smitch.hayenga@arm.com panic("We should never hit the case where we try to commit from a " 90111568Smitch.hayenga@arm.com "suspended thread as the streamSeqNum should not match"); 90210259SAndrew.Bardsley@arm.com } else if (inst->isFault()) { 90310259SAndrew.Bardsley@arm.com ExecContext context(cpu, *cpu.threads[thread_id], *this, inst); 90410259SAndrew.Bardsley@arm.com 90510259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Fault inst reached Execute: %s\n", 90610259SAndrew.Bardsley@arm.com inst->fault->name()); 90710259SAndrew.Bardsley@arm.com 90810259SAndrew.Bardsley@arm.com fault = inst->fault; 90910259SAndrew.Bardsley@arm.com inst->fault->invoke(thread, NULL); 91010259SAndrew.Bardsley@arm.com 91110259SAndrew.Bardsley@arm.com tryToBranch(inst, fault, branch); 91210259SAndrew.Bardsley@arm.com } else if (inst->staticInst->isMemRef()) { 91310259SAndrew.Bardsley@arm.com /* Memory accesses are executed in two parts: 91410259SAndrew.Bardsley@arm.com * executeMemRefInst -- calculates the EA and issues the access 91510259SAndrew.Bardsley@arm.com * to memory. This is done here. 91610259SAndrew.Bardsley@arm.com * handleMemResponse -- handles the response packet, done by 91710259SAndrew.Bardsley@arm.com * Execute::commit 91810259SAndrew.Bardsley@arm.com * 91910259SAndrew.Bardsley@arm.com * While the memory access is in its FU, the EA is being 92010259SAndrew.Bardsley@arm.com * calculated. At the end of the FU, when it is ready to 92110259SAndrew.Bardsley@arm.com * 'commit' (in this function), the access is presented to the 92210259SAndrew.Bardsley@arm.com * memory queues. When a response comes back from memory, 92310259SAndrew.Bardsley@arm.com * Execute::commit will commit it. 92410259SAndrew.Bardsley@arm.com */ 92510259SAndrew.Bardsley@arm.com bool predicate_passed = false; 92610259SAndrew.Bardsley@arm.com bool completed_mem_inst = executeMemRefInst(inst, branch, 92710259SAndrew.Bardsley@arm.com predicate_passed, fault); 92810259SAndrew.Bardsley@arm.com 92910259SAndrew.Bardsley@arm.com if (completed_mem_inst && fault != NoFault) { 93010259SAndrew.Bardsley@arm.com if (early_memory_issue) { 93110259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Fault in early executing inst: %s\n", 93210259SAndrew.Bardsley@arm.com fault->name()); 93310259SAndrew.Bardsley@arm.com /* Don't execute the fault, just stall the instruction 93410259SAndrew.Bardsley@arm.com * until it gets to the head of inFlightInsts */ 93510259SAndrew.Bardsley@arm.com inst->canEarlyIssue = false; 93610259SAndrew.Bardsley@arm.com /* Not completed as we'll come here again to pick up 93713954Sgiacomo.gabrielli@arm.com * the fault when we get to the end of the FU */ 93810259SAndrew.Bardsley@arm.com completed_inst = false; 93910259SAndrew.Bardsley@arm.com } else { 94010259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Fault in execute: %s\n", 94110259SAndrew.Bardsley@arm.com fault->name()); 94210259SAndrew.Bardsley@arm.com fault->invoke(thread, NULL); 94310259SAndrew.Bardsley@arm.com 94410259SAndrew.Bardsley@arm.com tryToBranch(inst, fault, branch); 94510259SAndrew.Bardsley@arm.com completed_inst = true; 94610259SAndrew.Bardsley@arm.com } 94710259SAndrew.Bardsley@arm.com } else { 94810259SAndrew.Bardsley@arm.com completed_inst = completed_mem_inst; 94910259SAndrew.Bardsley@arm.com } 95010259SAndrew.Bardsley@arm.com completed_mem_issue = completed_inst; 95110259SAndrew.Bardsley@arm.com } else if (inst->isInst() && inst->staticInst->isMemBarrier() && 95210259SAndrew.Bardsley@arm.com !lsq.canPushIntoStoreBuffer()) 95310259SAndrew.Bardsley@arm.com { 95410259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't commit data barrier inst: %s yet as" 95510259SAndrew.Bardsley@arm.com " there isn't space in the store buffer\n", *inst); 95610259SAndrew.Bardsley@arm.com 95710259SAndrew.Bardsley@arm.com completed_inst = false; 95811567Smitch.hayenga@arm.com } else if (inst->isInst() && inst->staticInst->isQuiesce() 95911567Smitch.hayenga@arm.com && !branch.isBubble()){ 96011567Smitch.hayenga@arm.com /* This instruction can suspend, need to be able to communicate 96111567Smitch.hayenga@arm.com * backwards, so no other branches may evaluate this cycle*/ 96211567Smitch.hayenga@arm.com completed_inst = false; 96310259SAndrew.Bardsley@arm.com } else { 96410259SAndrew.Bardsley@arm.com ExecContext context(cpu, *cpu.threads[thread_id], *this, inst); 96510259SAndrew.Bardsley@arm.com 96610259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Committing inst: %s\n", *inst); 96710259SAndrew.Bardsley@arm.com 96810259SAndrew.Bardsley@arm.com fault = inst->staticInst->execute(&context, 96910259SAndrew.Bardsley@arm.com inst->traceData); 97010259SAndrew.Bardsley@arm.com 97110259SAndrew.Bardsley@arm.com /* Set the predicate for tracing and dump */ 97210259SAndrew.Bardsley@arm.com if (inst->traceData) 97310259SAndrew.Bardsley@arm.com inst->traceData->setPredicate(context.readPredicate()); 97410259SAndrew.Bardsley@arm.com 97510259SAndrew.Bardsley@arm.com committed = true; 97610259SAndrew.Bardsley@arm.com 97710259SAndrew.Bardsley@arm.com if (fault != NoFault) { 97810259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Fault in execute of inst: %s fault: %s\n", 97910259SAndrew.Bardsley@arm.com *inst, fault->name()); 98010259SAndrew.Bardsley@arm.com fault->invoke(thread, inst->staticInst); 98110259SAndrew.Bardsley@arm.com } 98210259SAndrew.Bardsley@arm.com 98310259SAndrew.Bardsley@arm.com doInstCommitAccounting(inst); 98410259SAndrew.Bardsley@arm.com tryToBranch(inst, fault, branch); 98510259SAndrew.Bardsley@arm.com } 98610259SAndrew.Bardsley@arm.com 98710259SAndrew.Bardsley@arm.com if (completed_inst) { 98810259SAndrew.Bardsley@arm.com /* Keep a copy of this instruction's predictionSeqNum just in case 98910259SAndrew.Bardsley@arm.com * we need to issue a branch without an instruction (such as an 99010259SAndrew.Bardsley@arm.com * interrupt) */ 99111567Smitch.hayenga@arm.com executeInfo[thread_id].lastPredictionSeqNum = inst->id.predictionSeqNum; 99210259SAndrew.Bardsley@arm.com 99310259SAndrew.Bardsley@arm.com /* Check to see if this instruction suspended the current thread. */ 99410259SAndrew.Bardsley@arm.com if (!inst->isFault() && 99510259SAndrew.Bardsley@arm.com thread->status() == ThreadContext::Suspended && 99610259SAndrew.Bardsley@arm.com branch.isBubble() && /* It didn't branch too */ 99710259SAndrew.Bardsley@arm.com !isInterrupted(thread_id)) /* Don't suspend if we have 99810259SAndrew.Bardsley@arm.com interrupts */ 99910259SAndrew.Bardsley@arm.com { 100011567Smitch.hayenga@arm.com TheISA::PCState resume_pc = cpu.getContext(thread_id)->pcState(); 100110259SAndrew.Bardsley@arm.com 100210259SAndrew.Bardsley@arm.com assert(resume_pc.microPC() == 0); 100310259SAndrew.Bardsley@arm.com 100410259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Suspending thread: %d from Execute" 100511567Smitch.hayenga@arm.com " inst: %s\n", thread_id, *inst); 100610259SAndrew.Bardsley@arm.com 100710259SAndrew.Bardsley@arm.com cpu.stats.numFetchSuspends++; 100810259SAndrew.Bardsley@arm.com 100911567Smitch.hayenga@arm.com updateBranchData(thread_id, BranchData::SuspendThread, inst, 101011567Smitch.hayenga@arm.com resume_pc, branch); 101110259SAndrew.Bardsley@arm.com } 101210259SAndrew.Bardsley@arm.com } 101310259SAndrew.Bardsley@arm.com 101410259SAndrew.Bardsley@arm.com return completed_inst; 101510259SAndrew.Bardsley@arm.com} 101610259SAndrew.Bardsley@arm.com 101710259SAndrew.Bardsley@arm.comvoid 101811567Smitch.hayenga@arm.comExecute::commit(ThreadID thread_id, bool only_commit_microops, bool discard, 101911567Smitch.hayenga@arm.com BranchData &branch) 102010259SAndrew.Bardsley@arm.com{ 102110259SAndrew.Bardsley@arm.com Fault fault = NoFault; 102210259SAndrew.Bardsley@arm.com Cycles now = cpu.curCycle(); 102311567Smitch.hayenga@arm.com ExecuteThreadInfo &ex_info = executeInfo[thread_id]; 102410259SAndrew.Bardsley@arm.com 102510259SAndrew.Bardsley@arm.com /** 102610259SAndrew.Bardsley@arm.com * Try and execute as many instructions from the end of FU pipelines as 102710259SAndrew.Bardsley@arm.com * possible. This *doesn't* include actually advancing the pipelines. 102810259SAndrew.Bardsley@arm.com * 102910259SAndrew.Bardsley@arm.com * We do this by looping on the front of the inFlightInsts queue for as 103010259SAndrew.Bardsley@arm.com * long as we can find the desired instruction at the end of the 103110259SAndrew.Bardsley@arm.com * functional unit it was issued to without seeing a branch or a fault. 103210259SAndrew.Bardsley@arm.com * In this function, these terms are used: 103310259SAndrew.Bardsley@arm.com * complete -- The instruction has finished its passage through 103410259SAndrew.Bardsley@arm.com * its functional unit and its fate has been decided 103510259SAndrew.Bardsley@arm.com * (committed, discarded, issued to the memory system) 103610259SAndrew.Bardsley@arm.com * commit -- The instruction is complete(d), not discarded and has 103710259SAndrew.Bardsley@arm.com * its effects applied to the CPU state 103810259SAndrew.Bardsley@arm.com * discard(ed) -- The instruction is complete but not committed 103910259SAndrew.Bardsley@arm.com * as its streamSeqNum disagrees with the current 104010259SAndrew.Bardsley@arm.com * Execute::streamSeqNum 104110259SAndrew.Bardsley@arm.com * 104210259SAndrew.Bardsley@arm.com * Commits are also possible from two other places: 104310259SAndrew.Bardsley@arm.com * 104410259SAndrew.Bardsley@arm.com * 1) Responses returning from the LSQ 104510259SAndrew.Bardsley@arm.com * 2) Mem ops issued to the LSQ ('committed' from the FUs) earlier 104610259SAndrew.Bardsley@arm.com * than their position in the inFlightInsts queue, but after all 104710259SAndrew.Bardsley@arm.com * their dependencies are resolved. 104810259SAndrew.Bardsley@arm.com */ 104910259SAndrew.Bardsley@arm.com 105010259SAndrew.Bardsley@arm.com /* Has an instruction been completed? Once this becomes false, we stop 105110259SAndrew.Bardsley@arm.com * trying to complete instructions. */ 105210259SAndrew.Bardsley@arm.com bool completed_inst = true; 105310259SAndrew.Bardsley@arm.com 105410259SAndrew.Bardsley@arm.com /* Number of insts committed this cycle to check against commitLimit */ 105510259SAndrew.Bardsley@arm.com unsigned int num_insts_committed = 0; 105610259SAndrew.Bardsley@arm.com 105710259SAndrew.Bardsley@arm.com /* Number of memory access instructions committed to check against 105810259SAndrew.Bardsley@arm.com * memCommitLimit */ 105910259SAndrew.Bardsley@arm.com unsigned int num_mem_refs_committed = 0; 106010259SAndrew.Bardsley@arm.com 106111567Smitch.hayenga@arm.com if (only_commit_microops && !ex_info.inFlightInsts->empty()) { 106210259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Only commit microops %s %d\n", 106311567Smitch.hayenga@arm.com *(ex_info.inFlightInsts->front().inst), 106411567Smitch.hayenga@arm.com ex_info.lastCommitWasEndOfMacroop); 106510259SAndrew.Bardsley@arm.com } 106610259SAndrew.Bardsley@arm.com 106711567Smitch.hayenga@arm.com while (!ex_info.inFlightInsts->empty() && /* Some more instructions to process */ 106810259SAndrew.Bardsley@arm.com !branch.isStreamChange() && /* No real branch */ 106910259SAndrew.Bardsley@arm.com fault == NoFault && /* No faults */ 107010259SAndrew.Bardsley@arm.com completed_inst && /* Still finding instructions to execute */ 107113647Sqtt2@cornell.edu num_insts_committed != commitLimit /* Not reached commit limit */ 107210259SAndrew.Bardsley@arm.com ) 107310259SAndrew.Bardsley@arm.com { 107410259SAndrew.Bardsley@arm.com if (only_commit_microops) { 107510259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Committing tail of insts before" 107610259SAndrew.Bardsley@arm.com " interrupt: %s\n", 107711567Smitch.hayenga@arm.com *(ex_info.inFlightInsts->front().inst)); 107810259SAndrew.Bardsley@arm.com } 107910259SAndrew.Bardsley@arm.com 108011567Smitch.hayenga@arm.com QueuedInst *head_inflight_inst = &(ex_info.inFlightInsts->front()); 108110259SAndrew.Bardsley@arm.com 108210259SAndrew.Bardsley@arm.com InstSeqNum head_exec_seq_num = 108310259SAndrew.Bardsley@arm.com head_inflight_inst->inst->id.execSeqNum; 108410259SAndrew.Bardsley@arm.com 108510259SAndrew.Bardsley@arm.com /* The instruction we actually process if completed_inst 108610259SAndrew.Bardsley@arm.com * remains true to the end of the loop body. 108710259SAndrew.Bardsley@arm.com * Start by considering the the head of the in flight insts queue */ 108810259SAndrew.Bardsley@arm.com MinorDynInstPtr inst = head_inflight_inst->inst; 108910259SAndrew.Bardsley@arm.com 109010259SAndrew.Bardsley@arm.com bool committed_inst = false; 109110259SAndrew.Bardsley@arm.com bool discard_inst = false; 109210259SAndrew.Bardsley@arm.com bool completed_mem_ref = false; 109310259SAndrew.Bardsley@arm.com bool issued_mem_ref = false; 109410259SAndrew.Bardsley@arm.com bool early_memory_issue = false; 109510259SAndrew.Bardsley@arm.com 109610259SAndrew.Bardsley@arm.com /* Must set this again to go around the loop */ 109710259SAndrew.Bardsley@arm.com completed_inst = false; 109810259SAndrew.Bardsley@arm.com 109910259SAndrew.Bardsley@arm.com /* If we're just completing a macroop before an interrupt or drain, 110010259SAndrew.Bardsley@arm.com * can we stil commit another microop (rather than a memory response) 110110259SAndrew.Bardsley@arm.com * without crosing into the next full instruction? */ 110211567Smitch.hayenga@arm.com bool can_commit_insts = !ex_info.inFlightInsts->empty() && 110311567Smitch.hayenga@arm.com !(only_commit_microops && ex_info.lastCommitWasEndOfMacroop); 110410259SAndrew.Bardsley@arm.com 110510259SAndrew.Bardsley@arm.com /* Can we find a mem response for this inst */ 110610259SAndrew.Bardsley@arm.com LSQ::LSQRequestPtr mem_response = 110710259SAndrew.Bardsley@arm.com (inst->inLSQ ? lsq.findResponse(inst) : NULL); 110810259SAndrew.Bardsley@arm.com 110910259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Trying to commit canCommitInsts: %d\n", 111010259SAndrew.Bardsley@arm.com can_commit_insts); 111110259SAndrew.Bardsley@arm.com 111210259SAndrew.Bardsley@arm.com /* Test for PC events after every instruction */ 111311567Smitch.hayenga@arm.com if (isInbetweenInsts(thread_id) && tryPCEvents(thread_id)) { 111411567Smitch.hayenga@arm.com ThreadContext *thread = cpu.getContext(thread_id); 111510259SAndrew.Bardsley@arm.com 111610259SAndrew.Bardsley@arm.com /* Branch as there was a change in PC */ 111711567Smitch.hayenga@arm.com updateBranchData(thread_id, BranchData::UnpredictedBranch, 111810259SAndrew.Bardsley@arm.com MinorDynInst::bubble(), thread->pcState(), branch); 111910259SAndrew.Bardsley@arm.com } else if (mem_response && 112010259SAndrew.Bardsley@arm.com num_mem_refs_committed < memoryCommitLimit) 112110259SAndrew.Bardsley@arm.com { 112210259SAndrew.Bardsley@arm.com /* Try to commit from the memory responses next */ 112311567Smitch.hayenga@arm.com discard_inst = inst->id.streamSeqNum != 112411567Smitch.hayenga@arm.com ex_info.streamSeqNum || discard; 112510259SAndrew.Bardsley@arm.com 112610259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Trying to commit mem response: %s\n", 112710259SAndrew.Bardsley@arm.com *inst); 112810259SAndrew.Bardsley@arm.com 112910259SAndrew.Bardsley@arm.com /* Complete or discard the response */ 113010259SAndrew.Bardsley@arm.com if (discard_inst) { 113110259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Discarding mem inst: %s as its" 113210259SAndrew.Bardsley@arm.com " stream state was unexpected, expected: %d\n", 113311567Smitch.hayenga@arm.com *inst, ex_info.streamSeqNum); 113410259SAndrew.Bardsley@arm.com 113510259SAndrew.Bardsley@arm.com lsq.popResponse(mem_response); 113610259SAndrew.Bardsley@arm.com } else { 113710259SAndrew.Bardsley@arm.com handleMemResponse(inst, mem_response, branch, fault); 113810259SAndrew.Bardsley@arm.com committed_inst = true; 113910259SAndrew.Bardsley@arm.com } 114010259SAndrew.Bardsley@arm.com 114110259SAndrew.Bardsley@arm.com completed_mem_ref = true; 114210259SAndrew.Bardsley@arm.com completed_inst = true; 114310259SAndrew.Bardsley@arm.com } else if (can_commit_insts) { 114410259SAndrew.Bardsley@arm.com /* If true, this instruction will, subject to timing tweaks, 114510259SAndrew.Bardsley@arm.com * be considered for completion. try_to_commit flattens 114610259SAndrew.Bardsley@arm.com * the `if' tree a bit and allows other tests for inst 114710259SAndrew.Bardsley@arm.com * commit to be inserted here. */ 114810259SAndrew.Bardsley@arm.com bool try_to_commit = false; 114910259SAndrew.Bardsley@arm.com 115010259SAndrew.Bardsley@arm.com /* Try and issue memory ops early if they: 115110259SAndrew.Bardsley@arm.com * - Can push a request into the LSQ 115210259SAndrew.Bardsley@arm.com * - Have reached the end of their FUs 115310259SAndrew.Bardsley@arm.com * - Have had all their dependencies satisfied 115410259SAndrew.Bardsley@arm.com * - Are from the right stream 115510259SAndrew.Bardsley@arm.com * 115610259SAndrew.Bardsley@arm.com * For any other case, leave it to the normal instruction 115710259SAndrew.Bardsley@arm.com * issue below to handle them. 115810259SAndrew.Bardsley@arm.com */ 115911567Smitch.hayenga@arm.com if (!ex_info.inFUMemInsts->empty() && lsq.canRequest()) { 116010259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Trying to commit from mem FUs\n"); 116110259SAndrew.Bardsley@arm.com 116210259SAndrew.Bardsley@arm.com const MinorDynInstPtr head_mem_ref_inst = 116311567Smitch.hayenga@arm.com ex_info.inFUMemInsts->front().inst; 116410259SAndrew.Bardsley@arm.com FUPipeline *fu = funcUnits[head_mem_ref_inst->fuIndex]; 116510259SAndrew.Bardsley@arm.com const MinorDynInstPtr &fu_inst = fu->front().inst; 116610259SAndrew.Bardsley@arm.com 116710259SAndrew.Bardsley@arm.com /* Use this, possibly out of order, inst as the one 116810259SAndrew.Bardsley@arm.com * to 'commit'/send to the LSQ */ 116910259SAndrew.Bardsley@arm.com if (!fu_inst->isBubble() && 117010259SAndrew.Bardsley@arm.com !fu_inst->inLSQ && 117110259SAndrew.Bardsley@arm.com fu_inst->canEarlyIssue && 117211567Smitch.hayenga@arm.com ex_info.streamSeqNum == fu_inst->id.streamSeqNum && 117310259SAndrew.Bardsley@arm.com head_exec_seq_num > fu_inst->instToWaitFor) 117410259SAndrew.Bardsley@arm.com { 117510259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Issuing mem ref early" 117610259SAndrew.Bardsley@arm.com " inst: %s instToWaitFor: %d\n", 117710259SAndrew.Bardsley@arm.com *(fu_inst), fu_inst->instToWaitFor); 117810259SAndrew.Bardsley@arm.com 117910259SAndrew.Bardsley@arm.com inst = fu_inst; 118010259SAndrew.Bardsley@arm.com try_to_commit = true; 118110259SAndrew.Bardsley@arm.com early_memory_issue = true; 118210259SAndrew.Bardsley@arm.com completed_inst = true; 118310259SAndrew.Bardsley@arm.com } 118410259SAndrew.Bardsley@arm.com } 118510259SAndrew.Bardsley@arm.com 118610259SAndrew.Bardsley@arm.com /* Try and commit FU-less insts */ 118710259SAndrew.Bardsley@arm.com if (!completed_inst && inst->isNoCostInst()) { 118810259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Committing no cost inst: %s", *inst); 118910259SAndrew.Bardsley@arm.com 119010259SAndrew.Bardsley@arm.com try_to_commit = true; 119110259SAndrew.Bardsley@arm.com completed_inst = true; 119210259SAndrew.Bardsley@arm.com } 119310259SAndrew.Bardsley@arm.com 119410259SAndrew.Bardsley@arm.com /* Try to issue from the ends of FUs and the inFlightInsts 119510259SAndrew.Bardsley@arm.com * queue */ 119610259SAndrew.Bardsley@arm.com if (!completed_inst && !inst->inLSQ) { 119710259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Trying to commit from FUs\n"); 119810259SAndrew.Bardsley@arm.com 119910259SAndrew.Bardsley@arm.com /* Try to commit from a functional unit */ 120010259SAndrew.Bardsley@arm.com /* Is the head inst of the expected inst's FU actually the 120110259SAndrew.Bardsley@arm.com * expected inst? */ 120210259SAndrew.Bardsley@arm.com QueuedInst &fu_inst = 120310259SAndrew.Bardsley@arm.com funcUnits[inst->fuIndex]->front(); 120410259SAndrew.Bardsley@arm.com InstSeqNum fu_inst_seq_num = fu_inst.inst->id.execSeqNum; 120510259SAndrew.Bardsley@arm.com 120610259SAndrew.Bardsley@arm.com if (fu_inst.inst->isBubble()) { 120710259SAndrew.Bardsley@arm.com /* No instruction ready */ 120810259SAndrew.Bardsley@arm.com completed_inst = false; 120910259SAndrew.Bardsley@arm.com } else if (fu_inst_seq_num != head_exec_seq_num) { 121010259SAndrew.Bardsley@arm.com /* Past instruction: we must have already executed it 121110259SAndrew.Bardsley@arm.com * in the same cycle and so the head inst isn't 121210259SAndrew.Bardsley@arm.com * actually at the end of its pipeline 121310259SAndrew.Bardsley@arm.com * Future instruction: handled above and only for 121410259SAndrew.Bardsley@arm.com * mem refs on their way to the LSQ */ 121511567Smitch.hayenga@arm.com } else if (fu_inst.inst->id == inst->id) { 121610259SAndrew.Bardsley@arm.com /* All instructions can be committed if they have the 121710259SAndrew.Bardsley@arm.com * right execSeqNum and there are no in-flight 121810259SAndrew.Bardsley@arm.com * mem insts before us */ 121910259SAndrew.Bardsley@arm.com try_to_commit = true; 122010259SAndrew.Bardsley@arm.com completed_inst = true; 122110259SAndrew.Bardsley@arm.com } 122210259SAndrew.Bardsley@arm.com } 122310259SAndrew.Bardsley@arm.com 122410259SAndrew.Bardsley@arm.com if (try_to_commit) { 122511567Smitch.hayenga@arm.com discard_inst = inst->id.streamSeqNum != 122611567Smitch.hayenga@arm.com ex_info.streamSeqNum || discard; 122710259SAndrew.Bardsley@arm.com 122810259SAndrew.Bardsley@arm.com /* Is this instruction discardable as its streamSeqNum 122910259SAndrew.Bardsley@arm.com * doesn't match? */ 123010259SAndrew.Bardsley@arm.com if (!discard_inst) { 123110259SAndrew.Bardsley@arm.com /* Try to commit or discard a non-memory instruction. 123210259SAndrew.Bardsley@arm.com * Memory ops are actually 'committed' from this FUs 123310259SAndrew.Bardsley@arm.com * and 'issued' into the memory system so we need to 123410259SAndrew.Bardsley@arm.com * account for them later (commit_was_mem_issue gets 123510259SAndrew.Bardsley@arm.com * set) */ 123610259SAndrew.Bardsley@arm.com if (inst->extraCommitDelayExpr) { 123710259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Evaluating expression for" 123810259SAndrew.Bardsley@arm.com " extra commit delay inst: %s\n", *inst); 123910259SAndrew.Bardsley@arm.com 124011567Smitch.hayenga@arm.com ThreadContext *thread = cpu.getContext(thread_id); 124110259SAndrew.Bardsley@arm.com 124210259SAndrew.Bardsley@arm.com TimingExprEvalContext context(inst->staticInst, 124310259SAndrew.Bardsley@arm.com thread, NULL); 124410259SAndrew.Bardsley@arm.com 124510259SAndrew.Bardsley@arm.com uint64_t extra_delay = inst->extraCommitDelayExpr-> 124610259SAndrew.Bardsley@arm.com eval(context); 124710259SAndrew.Bardsley@arm.com 124810259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Extra commit delay expr" 124910259SAndrew.Bardsley@arm.com " result: %d\n", extra_delay); 125010259SAndrew.Bardsley@arm.com 125110259SAndrew.Bardsley@arm.com if (extra_delay < 128) { 125210259SAndrew.Bardsley@arm.com inst->extraCommitDelay += Cycles(extra_delay); 125310259SAndrew.Bardsley@arm.com } else { 125410259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Extra commit delay was" 125510259SAndrew.Bardsley@arm.com " very long: %d\n", extra_delay); 125610259SAndrew.Bardsley@arm.com } 125710259SAndrew.Bardsley@arm.com inst->extraCommitDelayExpr = NULL; 125810259SAndrew.Bardsley@arm.com } 125910259SAndrew.Bardsley@arm.com 126010259SAndrew.Bardsley@arm.com /* Move the extraCommitDelay from the instruction 126110259SAndrew.Bardsley@arm.com * into the minimumCommitCycle */ 126210259SAndrew.Bardsley@arm.com if (inst->extraCommitDelay != Cycles(0)) { 126310259SAndrew.Bardsley@arm.com inst->minimumCommitCycle = cpu.curCycle() + 126410259SAndrew.Bardsley@arm.com inst->extraCommitDelay; 126510259SAndrew.Bardsley@arm.com inst->extraCommitDelay = Cycles(0); 126610259SAndrew.Bardsley@arm.com } 126710259SAndrew.Bardsley@arm.com 126810259SAndrew.Bardsley@arm.com /* @todo Think about making lastMemBarrier be 126910259SAndrew.Bardsley@arm.com * MAX_UINT_64 to avoid using 0 as a marker value */ 127010259SAndrew.Bardsley@arm.com if (!inst->isFault() && inst->isMemRef() && 127111567Smitch.hayenga@arm.com lsq.getLastMemBarrier(thread_id) < 127210259SAndrew.Bardsley@arm.com inst->id.execSeqNum && 127311567Smitch.hayenga@arm.com lsq.getLastMemBarrier(thread_id) != 0) 127410259SAndrew.Bardsley@arm.com { 127510259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Not committing inst: %s yet" 127610259SAndrew.Bardsley@arm.com " as there are incomplete barriers in flight\n", 127710259SAndrew.Bardsley@arm.com *inst); 127810259SAndrew.Bardsley@arm.com completed_inst = false; 127910259SAndrew.Bardsley@arm.com } else if (inst->minimumCommitCycle > now) { 128010259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Not committing inst: %s yet" 128110259SAndrew.Bardsley@arm.com " as it wants to be stalled for %d more cycles\n", 128210259SAndrew.Bardsley@arm.com *inst, inst->minimumCommitCycle - now); 128310259SAndrew.Bardsley@arm.com completed_inst = false; 128410259SAndrew.Bardsley@arm.com } else { 128510259SAndrew.Bardsley@arm.com completed_inst = commitInst(inst, 128610259SAndrew.Bardsley@arm.com early_memory_issue, branch, fault, 128710259SAndrew.Bardsley@arm.com committed_inst, issued_mem_ref); 128810259SAndrew.Bardsley@arm.com } 128910259SAndrew.Bardsley@arm.com } else { 129010259SAndrew.Bardsley@arm.com /* Discard instruction */ 129110259SAndrew.Bardsley@arm.com completed_inst = true; 129210259SAndrew.Bardsley@arm.com } 129310259SAndrew.Bardsley@arm.com 129410259SAndrew.Bardsley@arm.com if (completed_inst) { 129510259SAndrew.Bardsley@arm.com /* Allow the pipeline to advance. If the FU head 129610259SAndrew.Bardsley@arm.com * instruction wasn't the inFlightInsts head 129710259SAndrew.Bardsley@arm.com * but had already been committed, it would have 129810259SAndrew.Bardsley@arm.com * unstalled the pipeline before here */ 129911567Smitch.hayenga@arm.com if (inst->fuIndex != noCostFUIndex) { 130011567Smitch.hayenga@arm.com DPRINTF(MinorExecute, "Unstalling %d for inst %s\n", inst->fuIndex, inst->id); 130110259SAndrew.Bardsley@arm.com funcUnits[inst->fuIndex]->stalled = false; 130211567Smitch.hayenga@arm.com } 130310259SAndrew.Bardsley@arm.com } 130410259SAndrew.Bardsley@arm.com } 130510259SAndrew.Bardsley@arm.com } else { 130610259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "No instructions to commit\n"); 130710259SAndrew.Bardsley@arm.com completed_inst = false; 130810259SAndrew.Bardsley@arm.com } 130910259SAndrew.Bardsley@arm.com 131010259SAndrew.Bardsley@arm.com /* All discardable instructions must also be 'completed' by now */ 131110259SAndrew.Bardsley@arm.com assert(!(discard_inst && !completed_inst)); 131210259SAndrew.Bardsley@arm.com 131310259SAndrew.Bardsley@arm.com /* Instruction committed but was discarded due to streamSeqNum 131410259SAndrew.Bardsley@arm.com * mismatch */ 131510259SAndrew.Bardsley@arm.com if (discard_inst) { 131610259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Discarding inst: %s as its stream" 131710259SAndrew.Bardsley@arm.com " state was unexpected, expected: %d\n", 131811567Smitch.hayenga@arm.com *inst, ex_info.streamSeqNum); 131910259SAndrew.Bardsley@arm.com 132010259SAndrew.Bardsley@arm.com if (fault == NoFault) 132110259SAndrew.Bardsley@arm.com cpu.stats.numDiscardedOps++; 132210259SAndrew.Bardsley@arm.com } 132310259SAndrew.Bardsley@arm.com 132410259SAndrew.Bardsley@arm.com /* Mark the mem inst as being in the LSQ */ 132510259SAndrew.Bardsley@arm.com if (issued_mem_ref) { 132610259SAndrew.Bardsley@arm.com inst->fuIndex = 0; 132710259SAndrew.Bardsley@arm.com inst->inLSQ = true; 132810259SAndrew.Bardsley@arm.com } 132910259SAndrew.Bardsley@arm.com 133010259SAndrew.Bardsley@arm.com /* Pop issued (to LSQ) and discarded mem refs from the inFUMemInsts 133110259SAndrew.Bardsley@arm.com * as they've *definitely* exited the FUs */ 133210259SAndrew.Bardsley@arm.com if (completed_inst && inst->isMemRef()) { 133310259SAndrew.Bardsley@arm.com /* The MemRef could have been discarded from the FU or the memory 133410259SAndrew.Bardsley@arm.com * queue, so just check an FU instruction */ 133511567Smitch.hayenga@arm.com if (!ex_info.inFUMemInsts->empty() && 133611567Smitch.hayenga@arm.com ex_info.inFUMemInsts->front().inst == inst) 133710259SAndrew.Bardsley@arm.com { 133811567Smitch.hayenga@arm.com ex_info.inFUMemInsts->pop(); 133910259SAndrew.Bardsley@arm.com } 134010259SAndrew.Bardsley@arm.com } 134110259SAndrew.Bardsley@arm.com 134210259SAndrew.Bardsley@arm.com if (completed_inst && !(issued_mem_ref && fault == NoFault)) { 134310259SAndrew.Bardsley@arm.com /* Note that this includes discarded insts */ 134410259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Completed inst: %s\n", *inst); 134510259SAndrew.Bardsley@arm.com 134610259SAndrew.Bardsley@arm.com /* Got to the end of a full instruction? */ 134711567Smitch.hayenga@arm.com ex_info.lastCommitWasEndOfMacroop = inst->isFault() || 134810259SAndrew.Bardsley@arm.com inst->isLastOpInInst(); 134910259SAndrew.Bardsley@arm.com 135010259SAndrew.Bardsley@arm.com /* lastPredictionSeqNum is kept as a convenience to prevent its 135110259SAndrew.Bardsley@arm.com * value from changing too much on the minorview display */ 135211567Smitch.hayenga@arm.com ex_info.lastPredictionSeqNum = inst->id.predictionSeqNum; 135310259SAndrew.Bardsley@arm.com 135410259SAndrew.Bardsley@arm.com /* Finished with the inst, remove it from the inst queue and 135510259SAndrew.Bardsley@arm.com * clear its dependencies */ 135611567Smitch.hayenga@arm.com ex_info.inFlightInsts->pop(); 135710259SAndrew.Bardsley@arm.com 135810259SAndrew.Bardsley@arm.com /* Complete barriers in the LSQ/move to store buffer */ 135910259SAndrew.Bardsley@arm.com if (inst->isInst() && inst->staticInst->isMemBarrier()) { 136010259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Completing memory barrier" 136110259SAndrew.Bardsley@arm.com " inst: %s committed: %d\n", *inst, committed_inst); 136210259SAndrew.Bardsley@arm.com lsq.completeMemBarrierInst(inst, committed_inst); 136310259SAndrew.Bardsley@arm.com } 136410259SAndrew.Bardsley@arm.com 136511567Smitch.hayenga@arm.com scoreboard[thread_id].clearInstDests(inst, inst->isMemRef()); 136610259SAndrew.Bardsley@arm.com } 136710259SAndrew.Bardsley@arm.com 136810259SAndrew.Bardsley@arm.com /* Handle per-cycle instruction counting */ 136910259SAndrew.Bardsley@arm.com if (committed_inst) { 137010259SAndrew.Bardsley@arm.com bool is_no_cost_inst = inst->isNoCostInst(); 137110259SAndrew.Bardsley@arm.com 137210259SAndrew.Bardsley@arm.com /* Don't show no cost instructions as having taken a commit 137310259SAndrew.Bardsley@arm.com * slot */ 137410259SAndrew.Bardsley@arm.com if (DTRACE(MinorTrace) && !is_no_cost_inst) 137511567Smitch.hayenga@arm.com ex_info.instsBeingCommitted.insts[num_insts_committed] = inst; 137610259SAndrew.Bardsley@arm.com 137710259SAndrew.Bardsley@arm.com if (!is_no_cost_inst) 137810259SAndrew.Bardsley@arm.com num_insts_committed++; 137910259SAndrew.Bardsley@arm.com 138010259SAndrew.Bardsley@arm.com if (num_insts_committed == commitLimit) 138110259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Reached inst commit limit\n"); 138210259SAndrew.Bardsley@arm.com 138310259SAndrew.Bardsley@arm.com /* Re-set the time of the instruction if that's required for 138410259SAndrew.Bardsley@arm.com * tracing */ 138510259SAndrew.Bardsley@arm.com if (inst->traceData) { 138610259SAndrew.Bardsley@arm.com if (setTraceTimeOnCommit) 138710259SAndrew.Bardsley@arm.com inst->traceData->setWhen(curTick()); 138810259SAndrew.Bardsley@arm.com inst->traceData->dump(); 138910259SAndrew.Bardsley@arm.com } 139010259SAndrew.Bardsley@arm.com 139110259SAndrew.Bardsley@arm.com if (completed_mem_ref) 139210259SAndrew.Bardsley@arm.com num_mem_refs_committed++; 139310259SAndrew.Bardsley@arm.com 139410259SAndrew.Bardsley@arm.com if (num_mem_refs_committed == memoryCommitLimit) 139510259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Reached mem ref commit limit\n"); 139610259SAndrew.Bardsley@arm.com } 139710259SAndrew.Bardsley@arm.com } 139810259SAndrew.Bardsley@arm.com} 139910259SAndrew.Bardsley@arm.com 140010259SAndrew.Bardsley@arm.combool 140111567Smitch.hayenga@arm.comExecute::isInbetweenInsts(ThreadID thread_id) const 140210259SAndrew.Bardsley@arm.com{ 140311567Smitch.hayenga@arm.com return executeInfo[thread_id].lastCommitWasEndOfMacroop && 140410259SAndrew.Bardsley@arm.com !lsq.accessesInFlight(); 140510259SAndrew.Bardsley@arm.com} 140610259SAndrew.Bardsley@arm.com 140710259SAndrew.Bardsley@arm.comvoid 140810259SAndrew.Bardsley@arm.comExecute::evaluate() 140910259SAndrew.Bardsley@arm.com{ 141011567Smitch.hayenga@arm.com if (!inp.outputWire->isBubble()) 141111567Smitch.hayenga@arm.com inputBuffer[inp.outputWire->threadId].setTail(*inp.outputWire); 141211567Smitch.hayenga@arm.com 141310259SAndrew.Bardsley@arm.com BranchData &branch = *out.inputWire; 141410259SAndrew.Bardsley@arm.com 141511567Smitch.hayenga@arm.com unsigned int num_issued = 0; 141610259SAndrew.Bardsley@arm.com 141710259SAndrew.Bardsley@arm.com /* Do all the cycle-wise activities for dcachePort here to potentially 141810259SAndrew.Bardsley@arm.com * free up input spaces in the LSQ's requests queue */ 141910259SAndrew.Bardsley@arm.com lsq.step(); 142010259SAndrew.Bardsley@arm.com 142111567Smitch.hayenga@arm.com /* Check interrupts first. Will halt commit if interrupt found */ 142210259SAndrew.Bardsley@arm.com bool interrupted = false; 142311567Smitch.hayenga@arm.com ThreadID interrupt_tid = checkInterrupts(branch, interrupted); 142410259SAndrew.Bardsley@arm.com 142511567Smitch.hayenga@arm.com if (interrupt_tid != InvalidThreadID) { 142611567Smitch.hayenga@arm.com /* Signalling an interrupt this cycle, not issuing/committing from 142711567Smitch.hayenga@arm.com * any other threads */ 142810259SAndrew.Bardsley@arm.com } else if (!branch.isBubble()) { 142910259SAndrew.Bardsley@arm.com /* It's important that this is here to carry Fetch1 wakeups to Fetch1 143010259SAndrew.Bardsley@arm.com * without overwriting them */ 143110259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Execute skipping a cycle to allow old" 143210259SAndrew.Bardsley@arm.com " branch to complete\n"); 143310259SAndrew.Bardsley@arm.com } else { 143411567Smitch.hayenga@arm.com ThreadID commit_tid = getCommittingThread(); 143511567Smitch.hayenga@arm.com 143611567Smitch.hayenga@arm.com if (commit_tid != InvalidThreadID) { 143711567Smitch.hayenga@arm.com ExecuteThreadInfo& commit_info = executeInfo[commit_tid]; 143811567Smitch.hayenga@arm.com 143911567Smitch.hayenga@arm.com DPRINTF(MinorExecute, "Attempting to commit [tid:%d]\n", 144011567Smitch.hayenga@arm.com commit_tid); 144111567Smitch.hayenga@arm.com /* commit can set stalled flags observable to issue and so *must* be 144211567Smitch.hayenga@arm.com * called first */ 144311567Smitch.hayenga@arm.com if (commit_info.drainState != NotDraining) { 144411567Smitch.hayenga@arm.com if (commit_info.drainState == DrainCurrentInst) { 144511567Smitch.hayenga@arm.com /* Commit only micro-ops, don't kill anything else */ 144611567Smitch.hayenga@arm.com commit(commit_tid, true, false, branch); 144711567Smitch.hayenga@arm.com 144811567Smitch.hayenga@arm.com if (isInbetweenInsts(commit_tid)) 144911567Smitch.hayenga@arm.com setDrainState(commit_tid, DrainHaltFetch); 145011567Smitch.hayenga@arm.com 145111567Smitch.hayenga@arm.com /* Discard any generated branch */ 145211567Smitch.hayenga@arm.com branch = BranchData::bubble(); 145311567Smitch.hayenga@arm.com } else if (commit_info.drainState == DrainAllInsts) { 145411567Smitch.hayenga@arm.com /* Kill all instructions */ 145511567Smitch.hayenga@arm.com while (getInput(commit_tid)) 145611567Smitch.hayenga@arm.com popInput(commit_tid); 145711567Smitch.hayenga@arm.com commit(commit_tid, false, true, branch); 145811567Smitch.hayenga@arm.com } 145910259SAndrew.Bardsley@arm.com } else { 146011567Smitch.hayenga@arm.com /* Commit micro-ops only if interrupted. Otherwise, commit 146111567Smitch.hayenga@arm.com * anything you like */ 146211567Smitch.hayenga@arm.com DPRINTF(MinorExecute, "Committing micro-ops for interrupt[tid:%d]\n", 146311567Smitch.hayenga@arm.com commit_tid); 146411567Smitch.hayenga@arm.com bool only_commit_microops = interrupted && 146511567Smitch.hayenga@arm.com hasInterrupt(commit_tid); 146611567Smitch.hayenga@arm.com commit(commit_tid, only_commit_microops, false, branch); 146711567Smitch.hayenga@arm.com } 146811567Smitch.hayenga@arm.com 146911567Smitch.hayenga@arm.com /* Halt fetch, but don't do it until we have the current instruction in 147011567Smitch.hayenga@arm.com * the bag */ 147111567Smitch.hayenga@arm.com if (commit_info.drainState == DrainHaltFetch) { 147211567Smitch.hayenga@arm.com updateBranchData(commit_tid, BranchData::HaltFetch, 147311567Smitch.hayenga@arm.com MinorDynInst::bubble(), TheISA::PCState(0), branch); 147411567Smitch.hayenga@arm.com 147511567Smitch.hayenga@arm.com cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 147611567Smitch.hayenga@arm.com setDrainState(commit_tid, DrainAllInsts); 147710259SAndrew.Bardsley@arm.com } 147810259SAndrew.Bardsley@arm.com } 147911567Smitch.hayenga@arm.com ThreadID issue_tid = getIssuingThread(); 148011567Smitch.hayenga@arm.com /* This will issue merrily even when interrupted in the sure and 148111567Smitch.hayenga@arm.com * certain knowledge that the interrupt with change the stream */ 148211567Smitch.hayenga@arm.com if (issue_tid != InvalidThreadID) { 148311567Smitch.hayenga@arm.com DPRINTF(MinorExecute, "Attempting to issue [tid:%d]\n", 148411567Smitch.hayenga@arm.com issue_tid); 148511567Smitch.hayenga@arm.com num_issued = issue(issue_tid); 148610259SAndrew.Bardsley@arm.com } 148710259SAndrew.Bardsley@arm.com 148810259SAndrew.Bardsley@arm.com } 148910259SAndrew.Bardsley@arm.com 149011567Smitch.hayenga@arm.com /* Run logic to step functional units + decide if we are active on the next 149111567Smitch.hayenga@arm.com * clock cycle */ 149211567Smitch.hayenga@arm.com std::vector<MinorDynInstPtr> next_issuable_insts; 149310259SAndrew.Bardsley@arm.com bool can_issue_next = false; 149410259SAndrew.Bardsley@arm.com 149511567Smitch.hayenga@arm.com for (ThreadID tid = 0; tid < cpu.numThreads; tid++) { 149611567Smitch.hayenga@arm.com /* Find the next issuable instruction for each thread and see if it can 149711567Smitch.hayenga@arm.com be issued */ 149811567Smitch.hayenga@arm.com if (getInput(tid)) { 149911567Smitch.hayenga@arm.com unsigned int input_index = executeInfo[tid].inputIndex; 150011567Smitch.hayenga@arm.com MinorDynInstPtr inst = getInput(tid)->insts[input_index]; 150111567Smitch.hayenga@arm.com if (inst->isFault()) { 150211567Smitch.hayenga@arm.com can_issue_next = true; 150311567Smitch.hayenga@arm.com } else if (!inst->isBubble()) { 150411568Smitch.hayenga@arm.com next_issuable_insts.push_back(inst); 150510259SAndrew.Bardsley@arm.com } 150610259SAndrew.Bardsley@arm.com } 150710259SAndrew.Bardsley@arm.com } 150810259SAndrew.Bardsley@arm.com 150910259SAndrew.Bardsley@arm.com bool becoming_stalled = true; 151010259SAndrew.Bardsley@arm.com 151110259SAndrew.Bardsley@arm.com /* Advance the pipelines and note whether they still need to be 151211567Smitch.hayenga@arm.com * advanced */ 151310259SAndrew.Bardsley@arm.com for (unsigned int i = 0; i < numFuncUnits; i++) { 151410259SAndrew.Bardsley@arm.com FUPipeline *fu = funcUnits[i]; 151510259SAndrew.Bardsley@arm.com fu->advance(); 151610259SAndrew.Bardsley@arm.com 151711567Smitch.hayenga@arm.com /* If we need to tick again, the pipeline will have been left or set 151811567Smitch.hayenga@arm.com * to be unstalled */ 151911567Smitch.hayenga@arm.com if (fu->occupancy !=0 && !fu->stalled) 152010259SAndrew.Bardsley@arm.com becoming_stalled = false; 152110259SAndrew.Bardsley@arm.com 152211567Smitch.hayenga@arm.com /* Could we possibly issue the next instruction from any thread? 152311567Smitch.hayenga@arm.com * This is quite an expensive test and is only used to determine 152411567Smitch.hayenga@arm.com * if the CPU should remain active, only run it if we aren't sure 152511567Smitch.hayenga@arm.com * we are active next cycle yet */ 152611567Smitch.hayenga@arm.com for (auto inst : next_issuable_insts) { 152711567Smitch.hayenga@arm.com if (!fu->stalled && fu->provides(inst->staticInst->opClass()) && 152811567Smitch.hayenga@arm.com scoreboard[inst->id.threadId].canInstIssue(inst, 152911567Smitch.hayenga@arm.com NULL, NULL, cpu.curCycle() + Cycles(1), 153011567Smitch.hayenga@arm.com cpu.getContext(inst->id.threadId))) { 153111567Smitch.hayenga@arm.com can_issue_next = true; 153211567Smitch.hayenga@arm.com break; 153311567Smitch.hayenga@arm.com } 153410259SAndrew.Bardsley@arm.com } 153510259SAndrew.Bardsley@arm.com } 153610259SAndrew.Bardsley@arm.com 153710259SAndrew.Bardsley@arm.com bool head_inst_might_commit = false; 153810259SAndrew.Bardsley@arm.com 153910259SAndrew.Bardsley@arm.com /* Could the head in flight insts be committed */ 154011567Smitch.hayenga@arm.com for (auto const &info : executeInfo) { 154111567Smitch.hayenga@arm.com if (!info.inFlightInsts->empty()) { 154211567Smitch.hayenga@arm.com const QueuedInst &head_inst = info.inFlightInsts->front(); 154310259SAndrew.Bardsley@arm.com 154411567Smitch.hayenga@arm.com if (head_inst.inst->isNoCostInst()) { 154510259SAndrew.Bardsley@arm.com head_inst_might_commit = true; 154611567Smitch.hayenga@arm.com } else { 154711567Smitch.hayenga@arm.com FUPipeline *fu = funcUnits[head_inst.inst->fuIndex]; 154811567Smitch.hayenga@arm.com if ((fu->stalled && 154911567Smitch.hayenga@arm.com fu->front().inst->id == head_inst.inst->id) || 155011567Smitch.hayenga@arm.com lsq.findResponse(head_inst.inst)) 155111567Smitch.hayenga@arm.com { 155211567Smitch.hayenga@arm.com head_inst_might_commit = true; 155311567Smitch.hayenga@arm.com break; 155411567Smitch.hayenga@arm.com } 155510259SAndrew.Bardsley@arm.com } 155610259SAndrew.Bardsley@arm.com } 155710259SAndrew.Bardsley@arm.com } 155810259SAndrew.Bardsley@arm.com 155910259SAndrew.Bardsley@arm.com DPRINTF(Activity, "Need to tick num issued insts: %s%s%s%s%s%s\n", 156010259SAndrew.Bardsley@arm.com (num_issued != 0 ? " (issued some insts)" : ""), 156111567Smitch.hayenga@arm.com (becoming_stalled ? "(becoming stalled)" : "(not becoming stalled)"), 156210259SAndrew.Bardsley@arm.com (can_issue_next ? " (can issued next inst)" : ""), 156310259SAndrew.Bardsley@arm.com (head_inst_might_commit ? "(head inst might commit)" : ""), 156410259SAndrew.Bardsley@arm.com (lsq.needsToTick() ? " (LSQ needs to tick)" : ""), 156510259SAndrew.Bardsley@arm.com (interrupted ? " (interrupted)" : "")); 156610259SAndrew.Bardsley@arm.com 156710259SAndrew.Bardsley@arm.com bool need_to_tick = 156810259SAndrew.Bardsley@arm.com num_issued != 0 || /* Issued some insts this cycle */ 156910259SAndrew.Bardsley@arm.com !becoming_stalled || /* Some FU pipelines can still move */ 157010259SAndrew.Bardsley@arm.com can_issue_next || /* Can still issue a new inst */ 157110259SAndrew.Bardsley@arm.com head_inst_might_commit || /* Could possible commit the next inst */ 157210259SAndrew.Bardsley@arm.com lsq.needsToTick() || /* Must step the dcache port */ 157310259SAndrew.Bardsley@arm.com interrupted; /* There are pending interrupts */ 157410259SAndrew.Bardsley@arm.com 157510259SAndrew.Bardsley@arm.com if (!need_to_tick) { 157610259SAndrew.Bardsley@arm.com DPRINTF(Activity, "The next cycle might be skippable as there are no" 157710259SAndrew.Bardsley@arm.com " advanceable FUs\n"); 157810259SAndrew.Bardsley@arm.com } 157910259SAndrew.Bardsley@arm.com 158010259SAndrew.Bardsley@arm.com /* Wake up if we need to tick again */ 158110259SAndrew.Bardsley@arm.com if (need_to_tick) 158210259SAndrew.Bardsley@arm.com cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 158310259SAndrew.Bardsley@arm.com 158410259SAndrew.Bardsley@arm.com /* Note activity of following buffer */ 158510259SAndrew.Bardsley@arm.com if (!branch.isBubble()) 158610259SAndrew.Bardsley@arm.com cpu.activityRecorder->activity(); 158710259SAndrew.Bardsley@arm.com 158810259SAndrew.Bardsley@arm.com /* Make sure the input (if any left) is pushed */ 158911567Smitch.hayenga@arm.com if (!inp.outputWire->isBubble()) 159011567Smitch.hayenga@arm.com inputBuffer[inp.outputWire->threadId].pushTail(); 159110259SAndrew.Bardsley@arm.com} 159210259SAndrew.Bardsley@arm.com 159311567Smitch.hayenga@arm.comThreadID 159411567Smitch.hayenga@arm.comExecute::checkInterrupts(BranchData& branch, bool& interrupted) 159510259SAndrew.Bardsley@arm.com{ 159611567Smitch.hayenga@arm.com ThreadID tid = interruptPriority; 159711567Smitch.hayenga@arm.com /* Evaluate interrupts in round-robin based upon service */ 159811567Smitch.hayenga@arm.com do { 159911567Smitch.hayenga@arm.com /* Has an interrupt been signalled? This may not be acted on 160011567Smitch.hayenga@arm.com * straighaway so this is different from took_interrupt */ 160111567Smitch.hayenga@arm.com bool thread_interrupted = false; 160210259SAndrew.Bardsley@arm.com 160311567Smitch.hayenga@arm.com if (FullSystem && cpu.getInterruptController(tid)) { 160411567Smitch.hayenga@arm.com /* This is here because it seems that after drainResume the 160511567Smitch.hayenga@arm.com * interrupt controller isn't always set */ 160611567Smitch.hayenga@arm.com thread_interrupted = executeInfo[tid].drainState == NotDraining && 160711567Smitch.hayenga@arm.com isInterrupted(tid); 160811567Smitch.hayenga@arm.com interrupted = interrupted || thread_interrupted; 160911567Smitch.hayenga@arm.com } else { 161011567Smitch.hayenga@arm.com DPRINTF(MinorInterrupt, "No interrupt controller\n"); 161111567Smitch.hayenga@arm.com } 161211567Smitch.hayenga@arm.com DPRINTF(MinorInterrupt, "[tid:%d] thread_interrupted?=%d isInbetweenInsts?=%d\n", 161311567Smitch.hayenga@arm.com tid, thread_interrupted, isInbetweenInsts(tid)); 161411567Smitch.hayenga@arm.com /* Act on interrupts */ 161511567Smitch.hayenga@arm.com if (thread_interrupted && isInbetweenInsts(tid)) { 161611567Smitch.hayenga@arm.com if (takeInterrupt(tid, branch)) { 161711567Smitch.hayenga@arm.com interruptPriority = tid; 161811567Smitch.hayenga@arm.com return tid; 161911567Smitch.hayenga@arm.com } 162011567Smitch.hayenga@arm.com } else { 162111567Smitch.hayenga@arm.com tid = (tid + 1) % cpu.numThreads; 162211567Smitch.hayenga@arm.com } 162311567Smitch.hayenga@arm.com } while (tid != interruptPriority); 162410259SAndrew.Bardsley@arm.com 162511567Smitch.hayenga@arm.com return InvalidThreadID; 162611567Smitch.hayenga@arm.com} 162710259SAndrew.Bardsley@arm.com 162811567Smitch.hayenga@arm.combool 162911567Smitch.hayenga@arm.comExecute::hasInterrupt(ThreadID thread_id) 163011567Smitch.hayenga@arm.com{ 163111567Smitch.hayenga@arm.com if (FullSystem && cpu.getInterruptController(thread_id)) { 163211567Smitch.hayenga@arm.com return executeInfo[thread_id].drainState == NotDraining && 163311567Smitch.hayenga@arm.com isInterrupted(thread_id); 163410259SAndrew.Bardsley@arm.com } 163510259SAndrew.Bardsley@arm.com 163611567Smitch.hayenga@arm.com return false; 163710259SAndrew.Bardsley@arm.com} 163810259SAndrew.Bardsley@arm.com 163910259SAndrew.Bardsley@arm.comvoid 164010259SAndrew.Bardsley@arm.comExecute::minorTrace() const 164110259SAndrew.Bardsley@arm.com{ 164210259SAndrew.Bardsley@arm.com std::ostringstream insts; 164310259SAndrew.Bardsley@arm.com std::ostringstream stalled; 164410259SAndrew.Bardsley@arm.com 164511567Smitch.hayenga@arm.com executeInfo[0].instsBeingCommitted.reportData(insts); 164610259SAndrew.Bardsley@arm.com lsq.minorTrace(); 164711567Smitch.hayenga@arm.com inputBuffer[0].minorTrace(); 164811567Smitch.hayenga@arm.com scoreboard[0].minorTrace(); 164910259SAndrew.Bardsley@arm.com 165010259SAndrew.Bardsley@arm.com /* Report functional unit stalling in one string */ 165110259SAndrew.Bardsley@arm.com unsigned int i = 0; 165210259SAndrew.Bardsley@arm.com while (i < numFuncUnits) 165310259SAndrew.Bardsley@arm.com { 165410259SAndrew.Bardsley@arm.com stalled << (funcUnits[i]->stalled ? '1' : 'E'); 165510259SAndrew.Bardsley@arm.com i++; 165610259SAndrew.Bardsley@arm.com if (i != numFuncUnits) 165710259SAndrew.Bardsley@arm.com stalled << ','; 165810259SAndrew.Bardsley@arm.com } 165910259SAndrew.Bardsley@arm.com 166010259SAndrew.Bardsley@arm.com MINORTRACE("insts=%s inputIndex=%d streamSeqNum=%d" 166110259SAndrew.Bardsley@arm.com " stalled=%s drainState=%d isInbetweenInsts=%d\n", 166211567Smitch.hayenga@arm.com insts.str(), executeInfo[0].inputIndex, executeInfo[0].streamSeqNum, 166311567Smitch.hayenga@arm.com stalled.str(), executeInfo[0].drainState, isInbetweenInsts(0)); 166410259SAndrew.Bardsley@arm.com 166510259SAndrew.Bardsley@arm.com std::for_each(funcUnits.begin(), funcUnits.end(), 166610259SAndrew.Bardsley@arm.com std::mem_fun(&FUPipeline::minorTrace)); 166710259SAndrew.Bardsley@arm.com 166811567Smitch.hayenga@arm.com executeInfo[0].inFlightInsts->minorTrace(); 166911567Smitch.hayenga@arm.com executeInfo[0].inFUMemInsts->minorTrace(); 167011567Smitch.hayenga@arm.com} 167111567Smitch.hayenga@arm.com 167211567Smitch.hayenga@arm.cominline ThreadID 167311567Smitch.hayenga@arm.comExecute::getCommittingThread() 167411567Smitch.hayenga@arm.com{ 167511567Smitch.hayenga@arm.com std::vector<ThreadID> priority_list; 167611567Smitch.hayenga@arm.com 167711567Smitch.hayenga@arm.com switch (cpu.threadPolicy) { 167811567Smitch.hayenga@arm.com case Enums::SingleThreaded: 167911567Smitch.hayenga@arm.com return 0; 168011567Smitch.hayenga@arm.com case Enums::RoundRobin: 168111567Smitch.hayenga@arm.com priority_list = cpu.roundRobinPriority(commitPriority); 168211567Smitch.hayenga@arm.com break; 168311567Smitch.hayenga@arm.com case Enums::Random: 168411567Smitch.hayenga@arm.com priority_list = cpu.randomPriority(); 168511567Smitch.hayenga@arm.com break; 168611567Smitch.hayenga@arm.com default: 168711567Smitch.hayenga@arm.com panic("Invalid thread policy"); 168811567Smitch.hayenga@arm.com } 168911567Smitch.hayenga@arm.com 169011567Smitch.hayenga@arm.com for (auto tid : priority_list) { 169111567Smitch.hayenga@arm.com ExecuteThreadInfo &ex_info = executeInfo[tid]; 169213646Sqtt2@cornell.edu 169313646Sqtt2@cornell.edu bool is_thread_active = 169413646Sqtt2@cornell.edu cpu.getContext(tid)->status() == ThreadContext::Active; 169513646Sqtt2@cornell.edu bool can_commit_insts = !ex_info.inFlightInsts->empty() && 169613646Sqtt2@cornell.edu is_thread_active; 169713646Sqtt2@cornell.edu 169811567Smitch.hayenga@arm.com if (can_commit_insts) { 169911567Smitch.hayenga@arm.com QueuedInst *head_inflight_inst = &(ex_info.inFlightInsts->front()); 170011567Smitch.hayenga@arm.com MinorDynInstPtr inst = head_inflight_inst->inst; 170111567Smitch.hayenga@arm.com 170211567Smitch.hayenga@arm.com can_commit_insts = can_commit_insts && 170311567Smitch.hayenga@arm.com (!inst->inLSQ || (lsq.findResponse(inst) != NULL)); 170411567Smitch.hayenga@arm.com 170511567Smitch.hayenga@arm.com if (!inst->inLSQ) { 170611567Smitch.hayenga@arm.com bool can_transfer_mem_inst = false; 170711567Smitch.hayenga@arm.com if (!ex_info.inFUMemInsts->empty() && lsq.canRequest()) { 170811567Smitch.hayenga@arm.com const MinorDynInstPtr head_mem_ref_inst = 170911567Smitch.hayenga@arm.com ex_info.inFUMemInsts->front().inst; 171011567Smitch.hayenga@arm.com FUPipeline *fu = funcUnits[head_mem_ref_inst->fuIndex]; 171111567Smitch.hayenga@arm.com const MinorDynInstPtr &fu_inst = fu->front().inst; 171211567Smitch.hayenga@arm.com can_transfer_mem_inst = 171311567Smitch.hayenga@arm.com !fu_inst->isBubble() && 171411567Smitch.hayenga@arm.com fu_inst->id.threadId == tid && 171511567Smitch.hayenga@arm.com !fu_inst->inLSQ && 171611567Smitch.hayenga@arm.com fu_inst->canEarlyIssue && 171711567Smitch.hayenga@arm.com inst->id.execSeqNum > fu_inst->instToWaitFor; 171811567Smitch.hayenga@arm.com } 171911567Smitch.hayenga@arm.com 172011567Smitch.hayenga@arm.com bool can_execute_fu_inst = inst->fuIndex == noCostFUIndex; 172111567Smitch.hayenga@arm.com if (can_commit_insts && !can_transfer_mem_inst && 172211567Smitch.hayenga@arm.com inst->fuIndex != noCostFUIndex) 172311567Smitch.hayenga@arm.com { 172411567Smitch.hayenga@arm.com QueuedInst& fu_inst = funcUnits[inst->fuIndex]->front(); 172511567Smitch.hayenga@arm.com can_execute_fu_inst = !fu_inst.inst->isBubble() && 172611567Smitch.hayenga@arm.com fu_inst.inst->id == inst->id; 172711567Smitch.hayenga@arm.com } 172811567Smitch.hayenga@arm.com 172911567Smitch.hayenga@arm.com can_commit_insts = can_commit_insts && 173011567Smitch.hayenga@arm.com (can_transfer_mem_inst || can_execute_fu_inst); 173111567Smitch.hayenga@arm.com } 173211567Smitch.hayenga@arm.com } 173311567Smitch.hayenga@arm.com 173411567Smitch.hayenga@arm.com 173511567Smitch.hayenga@arm.com if (can_commit_insts) { 173611567Smitch.hayenga@arm.com commitPriority = tid; 173711567Smitch.hayenga@arm.com return tid; 173811567Smitch.hayenga@arm.com } 173911567Smitch.hayenga@arm.com } 174011567Smitch.hayenga@arm.com 174111567Smitch.hayenga@arm.com return InvalidThreadID; 174211567Smitch.hayenga@arm.com} 174311567Smitch.hayenga@arm.com 174411567Smitch.hayenga@arm.cominline ThreadID 174511567Smitch.hayenga@arm.comExecute::getIssuingThread() 174611567Smitch.hayenga@arm.com{ 174711567Smitch.hayenga@arm.com std::vector<ThreadID> priority_list; 174811567Smitch.hayenga@arm.com 174911567Smitch.hayenga@arm.com switch (cpu.threadPolicy) { 175011567Smitch.hayenga@arm.com case Enums::SingleThreaded: 175111567Smitch.hayenga@arm.com return 0; 175211567Smitch.hayenga@arm.com case Enums::RoundRobin: 175311567Smitch.hayenga@arm.com priority_list = cpu.roundRobinPriority(issuePriority); 175411567Smitch.hayenga@arm.com break; 175511567Smitch.hayenga@arm.com case Enums::Random: 175611567Smitch.hayenga@arm.com priority_list = cpu.randomPriority(); 175711567Smitch.hayenga@arm.com break; 175811567Smitch.hayenga@arm.com default: 175911567Smitch.hayenga@arm.com panic("Invalid thread scheduling policy."); 176011567Smitch.hayenga@arm.com } 176111567Smitch.hayenga@arm.com 176211567Smitch.hayenga@arm.com for (auto tid : priority_list) { 176313646Sqtt2@cornell.edu if (cpu.getContext(tid)->status() == ThreadContext::Active && 176413646Sqtt2@cornell.edu getInput(tid)) { 176511567Smitch.hayenga@arm.com issuePriority = tid; 176611567Smitch.hayenga@arm.com return tid; 176711567Smitch.hayenga@arm.com } 176811567Smitch.hayenga@arm.com } 176911567Smitch.hayenga@arm.com 177011567Smitch.hayenga@arm.com return InvalidThreadID; 177110259SAndrew.Bardsley@arm.com} 177210259SAndrew.Bardsley@arm.com 177310259SAndrew.Bardsley@arm.comvoid 177410259SAndrew.Bardsley@arm.comExecute::drainResume() 177510259SAndrew.Bardsley@arm.com{ 177610259SAndrew.Bardsley@arm.com DPRINTF(Drain, "MinorExecute drainResume\n"); 177710259SAndrew.Bardsley@arm.com 177811567Smitch.hayenga@arm.com for (ThreadID tid = 0; tid < cpu.numThreads; tid++) { 177911567Smitch.hayenga@arm.com setDrainState(tid, NotDraining); 178011567Smitch.hayenga@arm.com } 178110259SAndrew.Bardsley@arm.com 178210259SAndrew.Bardsley@arm.com cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 178310259SAndrew.Bardsley@arm.com} 178410259SAndrew.Bardsley@arm.com 178510259SAndrew.Bardsley@arm.comstd::ostream &operator <<(std::ostream &os, Execute::DrainState state) 178610259SAndrew.Bardsley@arm.com{ 178710259SAndrew.Bardsley@arm.com switch (state) 178810259SAndrew.Bardsley@arm.com { 178910259SAndrew.Bardsley@arm.com case Execute::NotDraining: 179010259SAndrew.Bardsley@arm.com os << "NotDraining"; 179110259SAndrew.Bardsley@arm.com break; 179210259SAndrew.Bardsley@arm.com case Execute::DrainCurrentInst: 179310259SAndrew.Bardsley@arm.com os << "DrainCurrentInst"; 179410259SAndrew.Bardsley@arm.com break; 179510259SAndrew.Bardsley@arm.com case Execute::DrainHaltFetch: 179610259SAndrew.Bardsley@arm.com os << "DrainHaltFetch"; 179710259SAndrew.Bardsley@arm.com break; 179810259SAndrew.Bardsley@arm.com case Execute::DrainAllInsts: 179910259SAndrew.Bardsley@arm.com os << "DrainAllInsts"; 180010259SAndrew.Bardsley@arm.com break; 180110259SAndrew.Bardsley@arm.com default: 180210259SAndrew.Bardsley@arm.com os << "Drain-" << static_cast<int>(state); 180310259SAndrew.Bardsley@arm.com break; 180410259SAndrew.Bardsley@arm.com } 180510259SAndrew.Bardsley@arm.com 180610259SAndrew.Bardsley@arm.com return os; 180710259SAndrew.Bardsley@arm.com} 180810259SAndrew.Bardsley@arm.com 180910259SAndrew.Bardsley@arm.comvoid 181011567Smitch.hayenga@arm.comExecute::setDrainState(ThreadID thread_id, DrainState state) 181110259SAndrew.Bardsley@arm.com{ 181211567Smitch.hayenga@arm.com DPRINTF(Drain, "setDrainState[%d]: %s\n", thread_id, state); 181311567Smitch.hayenga@arm.com executeInfo[thread_id].drainState = state; 181410259SAndrew.Bardsley@arm.com} 181510259SAndrew.Bardsley@arm.com 181610259SAndrew.Bardsley@arm.comunsigned int 181710259SAndrew.Bardsley@arm.comExecute::drain() 181810259SAndrew.Bardsley@arm.com{ 181910259SAndrew.Bardsley@arm.com DPRINTF(Drain, "MinorExecute drain\n"); 182010259SAndrew.Bardsley@arm.com 182111567Smitch.hayenga@arm.com for (ThreadID tid = 0; tid < cpu.numThreads; tid++) { 182211567Smitch.hayenga@arm.com if (executeInfo[tid].drainState == NotDraining) { 182311567Smitch.hayenga@arm.com cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 182410259SAndrew.Bardsley@arm.com 182511567Smitch.hayenga@arm.com /* Go to DrainCurrentInst if we're between microops 182611567Smitch.hayenga@arm.com * or waiting on an unbufferable memory operation. 182711567Smitch.hayenga@arm.com * Otherwise we can go straight to DrainHaltFetch 182811567Smitch.hayenga@arm.com */ 182911567Smitch.hayenga@arm.com if (isInbetweenInsts(tid)) 183011567Smitch.hayenga@arm.com setDrainState(tid, DrainHaltFetch); 183111567Smitch.hayenga@arm.com else 183211567Smitch.hayenga@arm.com setDrainState(tid, DrainCurrentInst); 183311567Smitch.hayenga@arm.com } 183410259SAndrew.Bardsley@arm.com } 183510259SAndrew.Bardsley@arm.com return (isDrained() ? 0 : 1); 183610259SAndrew.Bardsley@arm.com} 183710259SAndrew.Bardsley@arm.com 183810259SAndrew.Bardsley@arm.combool 183910259SAndrew.Bardsley@arm.comExecute::isDrained() 184010259SAndrew.Bardsley@arm.com{ 184111567Smitch.hayenga@arm.com if (!lsq.isDrained()) 184211567Smitch.hayenga@arm.com return false; 184311567Smitch.hayenga@arm.com 184411567Smitch.hayenga@arm.com for (ThreadID tid = 0; tid < cpu.numThreads; tid++) { 184511568Smitch.hayenga@arm.com if (!inputBuffer[tid].empty() || 184611567Smitch.hayenga@arm.com !executeInfo[tid].inFlightInsts->empty()) { 184711567Smitch.hayenga@arm.com 184811567Smitch.hayenga@arm.com return false; 184911567Smitch.hayenga@arm.com } 185011567Smitch.hayenga@arm.com } 185111567Smitch.hayenga@arm.com 185211567Smitch.hayenga@arm.com return true; 185310259SAndrew.Bardsley@arm.com} 185410259SAndrew.Bardsley@arm.com 185510259SAndrew.Bardsley@arm.comExecute::~Execute() 185610259SAndrew.Bardsley@arm.com{ 185710259SAndrew.Bardsley@arm.com for (unsigned int i = 0; i < numFuncUnits; i++) 185810259SAndrew.Bardsley@arm.com delete funcUnits[i]; 185910259SAndrew.Bardsley@arm.com 186011567Smitch.hayenga@arm.com for (ThreadID tid = 0; tid < cpu.numThreads; tid++) 186111567Smitch.hayenga@arm.com delete executeInfo[tid].inFlightInsts; 186210259SAndrew.Bardsley@arm.com} 186310259SAndrew.Bardsley@arm.com 186410259SAndrew.Bardsley@arm.combool 186510259SAndrew.Bardsley@arm.comExecute::instIsRightStream(MinorDynInstPtr inst) 186610259SAndrew.Bardsley@arm.com{ 186711567Smitch.hayenga@arm.com return inst->id.streamSeqNum == executeInfo[inst->id.threadId].streamSeqNum; 186810259SAndrew.Bardsley@arm.com} 186910259SAndrew.Bardsley@arm.com 187010259SAndrew.Bardsley@arm.combool 187110259SAndrew.Bardsley@arm.comExecute::instIsHeadInst(MinorDynInstPtr inst) 187210259SAndrew.Bardsley@arm.com{ 187310259SAndrew.Bardsley@arm.com bool ret = false; 187410259SAndrew.Bardsley@arm.com 187511567Smitch.hayenga@arm.com if (!executeInfo[inst->id.threadId].inFlightInsts->empty()) 187611567Smitch.hayenga@arm.com ret = executeInfo[inst->id.threadId].inFlightInsts->front().inst->id == inst->id; 187710259SAndrew.Bardsley@arm.com 187810259SAndrew.Bardsley@arm.com return ret; 187910259SAndrew.Bardsley@arm.com} 188010259SAndrew.Bardsley@arm.com 188110259SAndrew.Bardsley@arm.comMinorCPU::MinorCPUPort & 188210259SAndrew.Bardsley@arm.comExecute::getDcachePort() 188310259SAndrew.Bardsley@arm.com{ 188410259SAndrew.Bardsley@arm.com return lsq.getDcachePort(); 188510259SAndrew.Bardsley@arm.com} 188610259SAndrew.Bardsley@arm.com 188710259SAndrew.Bardsley@arm.com} 1888