execute.cc revision 13652
110259SAndrew.Bardsley@arm.com/* 210259SAndrew.Bardsley@arm.com * Copyright (c) 2013-2014 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; 36710259SAndrew.Bardsley@arm.com } else if (packet->isError()) { 36810259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Trying to commit error response: %s\n", 36910259SAndrew.Bardsley@arm.com *inst); 37010259SAndrew.Bardsley@arm.com 37110259SAndrew.Bardsley@arm.com fatal("Received error response packet for inst: %s\n", *inst); 37213652Sqtt2@cornell.edu } else if (is_store || is_load || is_prefetch || is_atomic) { 37310259SAndrew.Bardsley@arm.com assert(packet); 37410259SAndrew.Bardsley@arm.com 37510259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Memory response inst: %s addr: 0x%x size: %d\n", 37610259SAndrew.Bardsley@arm.com *inst, packet->getAddr(), packet->getSize()); 37710259SAndrew.Bardsley@arm.com 37810259SAndrew.Bardsley@arm.com if (is_load && packet->getSize() > 0) { 37910259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Memory data[0]: 0x%x\n", 38010563Sandreas.hansson@arm.com static_cast<unsigned int>(packet->getConstPtr<uint8_t>()[0])); 38110259SAndrew.Bardsley@arm.com } 38210259SAndrew.Bardsley@arm.com 38310259SAndrew.Bardsley@arm.com /* Complete the memory access instruction */ 38410259SAndrew.Bardsley@arm.com fault = inst->staticInst->completeAcc(packet, &context, 38510259SAndrew.Bardsley@arm.com inst->traceData); 38610259SAndrew.Bardsley@arm.com 38710259SAndrew.Bardsley@arm.com if (fault != NoFault) { 38810259SAndrew.Bardsley@arm.com /* Invoke fault created by instruction completion */ 38910259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Fault in memory completeAcc: %s\n", 39010259SAndrew.Bardsley@arm.com fault->name()); 39110259SAndrew.Bardsley@arm.com fault->invoke(thread, inst->staticInst); 39210259SAndrew.Bardsley@arm.com } else { 39310259SAndrew.Bardsley@arm.com /* Stores need to be pushed into the store buffer to finish 39410259SAndrew.Bardsley@arm.com * them off */ 39510259SAndrew.Bardsley@arm.com if (response->needsToBeSentToStoreBuffer()) 39610259SAndrew.Bardsley@arm.com lsq.sendStoreToStoreBuffer(response); 39710259SAndrew.Bardsley@arm.com } 39810259SAndrew.Bardsley@arm.com } else { 39910259SAndrew.Bardsley@arm.com fatal("There should only ever be reads, " 40010259SAndrew.Bardsley@arm.com "writes or faults at this point\n"); 40110259SAndrew.Bardsley@arm.com } 40210259SAndrew.Bardsley@arm.com 40310259SAndrew.Bardsley@arm.com lsq.popResponse(response); 40410259SAndrew.Bardsley@arm.com 40510259SAndrew.Bardsley@arm.com if (inst->traceData) { 40610259SAndrew.Bardsley@arm.com inst->traceData->setPredicate((use_context_predicate ? 40710259SAndrew.Bardsley@arm.com context.readPredicate() : false)); 40810259SAndrew.Bardsley@arm.com } 40910259SAndrew.Bardsley@arm.com 41010259SAndrew.Bardsley@arm.com doInstCommitAccounting(inst); 41110259SAndrew.Bardsley@arm.com 41210259SAndrew.Bardsley@arm.com /* Generate output to account for branches */ 41310259SAndrew.Bardsley@arm.com tryToBranch(inst, fault, branch); 41410259SAndrew.Bardsley@arm.com} 41510259SAndrew.Bardsley@arm.com 41610259SAndrew.Bardsley@arm.combool 41710259SAndrew.Bardsley@arm.comExecute::isInterrupted(ThreadID thread_id) const 41810259SAndrew.Bardsley@arm.com{ 41910259SAndrew.Bardsley@arm.com return cpu.checkInterrupts(cpu.getContext(thread_id)); 42010259SAndrew.Bardsley@arm.com} 42110259SAndrew.Bardsley@arm.com 42210259SAndrew.Bardsley@arm.combool 42310259SAndrew.Bardsley@arm.comExecute::takeInterrupt(ThreadID thread_id, BranchData &branch) 42410259SAndrew.Bardsley@arm.com{ 42510259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Considering interrupt status from PC: %s\n", 42610259SAndrew.Bardsley@arm.com cpu.getContext(thread_id)->pcState()); 42710259SAndrew.Bardsley@arm.com 42811150Smitch.hayenga@arm.com Fault interrupt = cpu.getInterruptController(thread_id)->getInterrupt 42910259SAndrew.Bardsley@arm.com (cpu.getContext(thread_id)); 43010259SAndrew.Bardsley@arm.com 43110259SAndrew.Bardsley@arm.com if (interrupt != NoFault) { 43210259SAndrew.Bardsley@arm.com /* The interrupt *must* set pcState */ 43311150Smitch.hayenga@arm.com cpu.getInterruptController(thread_id)->updateIntrInfo 43410259SAndrew.Bardsley@arm.com (cpu.getContext(thread_id)); 43510259SAndrew.Bardsley@arm.com interrupt->invoke(cpu.getContext(thread_id)); 43610259SAndrew.Bardsley@arm.com 43710259SAndrew.Bardsley@arm.com assert(!lsq.accessesInFlight()); 43810259SAndrew.Bardsley@arm.com 43910259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Invoking interrupt: %s to PC: %s\n", 44010259SAndrew.Bardsley@arm.com interrupt->name(), cpu.getContext(thread_id)->pcState()); 44110259SAndrew.Bardsley@arm.com 44210259SAndrew.Bardsley@arm.com /* Assume that an interrupt *must* cause a branch. Assert this? */ 44310259SAndrew.Bardsley@arm.com 44411567Smitch.hayenga@arm.com updateBranchData(thread_id, BranchData::Interrupt, 44511567Smitch.hayenga@arm.com MinorDynInst::bubble(), cpu.getContext(thread_id)->pcState(), 44611567Smitch.hayenga@arm.com branch); 44710259SAndrew.Bardsley@arm.com } 44810259SAndrew.Bardsley@arm.com 44910259SAndrew.Bardsley@arm.com return interrupt != NoFault; 45010259SAndrew.Bardsley@arm.com} 45110259SAndrew.Bardsley@arm.com 45210259SAndrew.Bardsley@arm.combool 45310259SAndrew.Bardsley@arm.comExecute::executeMemRefInst(MinorDynInstPtr inst, BranchData &branch, 45410259SAndrew.Bardsley@arm.com bool &passed_predicate, Fault &fault) 45510259SAndrew.Bardsley@arm.com{ 45610259SAndrew.Bardsley@arm.com bool issued = false; 45710259SAndrew.Bardsley@arm.com 45810259SAndrew.Bardsley@arm.com /* Set to true if the mem op. is issued and sent to the mem system */ 45910259SAndrew.Bardsley@arm.com passed_predicate = false; 46010259SAndrew.Bardsley@arm.com 46110259SAndrew.Bardsley@arm.com if (!lsq.canRequest()) { 46210259SAndrew.Bardsley@arm.com /* Not acting on instruction yet as the memory 46310259SAndrew.Bardsley@arm.com * queues are full */ 46410259SAndrew.Bardsley@arm.com issued = false; 46510259SAndrew.Bardsley@arm.com } else { 46610259SAndrew.Bardsley@arm.com ThreadContext *thread = cpu.getContext(inst->id.threadId); 46710259SAndrew.Bardsley@arm.com TheISA::PCState old_pc = thread->pcState(); 46810259SAndrew.Bardsley@arm.com 46910259SAndrew.Bardsley@arm.com ExecContext context(cpu, *cpu.threads[inst->id.threadId], 47010259SAndrew.Bardsley@arm.com *this, inst); 47110259SAndrew.Bardsley@arm.com 47210259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Initiating memRef inst: %s\n", *inst); 47310259SAndrew.Bardsley@arm.com 47410259SAndrew.Bardsley@arm.com Fault init_fault = inst->staticInst->initiateAcc(&context, 47510259SAndrew.Bardsley@arm.com inst->traceData); 47610259SAndrew.Bardsley@arm.com 47710259SAndrew.Bardsley@arm.com if (init_fault != NoFault) { 47810259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Fault on memory inst: %s" 47910259SAndrew.Bardsley@arm.com " initiateAcc: %s\n", *inst, init_fault->name()); 48010259SAndrew.Bardsley@arm.com fault = init_fault; 48110259SAndrew.Bardsley@arm.com } else { 48210259SAndrew.Bardsley@arm.com /* Only set this if the instruction passed its 48310259SAndrew.Bardsley@arm.com * predicate */ 48410259SAndrew.Bardsley@arm.com passed_predicate = context.readPredicate(); 48510259SAndrew.Bardsley@arm.com 48610259SAndrew.Bardsley@arm.com /* Set predicate in tracing */ 48710259SAndrew.Bardsley@arm.com if (inst->traceData) 48810259SAndrew.Bardsley@arm.com inst->traceData->setPredicate(passed_predicate); 48910259SAndrew.Bardsley@arm.com 49010259SAndrew.Bardsley@arm.com /* If the instruction didn't pass its predicate (and so will not 49110259SAndrew.Bardsley@arm.com * progress from here) Try to branch to correct and branch 49210259SAndrew.Bardsley@arm.com * mis-prediction. */ 49310259SAndrew.Bardsley@arm.com if (!passed_predicate) { 49410259SAndrew.Bardsley@arm.com /* Leave it up to commit to handle the fault */ 49510259SAndrew.Bardsley@arm.com lsq.pushFailedRequest(inst); 49610259SAndrew.Bardsley@arm.com } 49710259SAndrew.Bardsley@arm.com } 49810259SAndrew.Bardsley@arm.com 49910259SAndrew.Bardsley@arm.com /* Restore thread PC */ 50010259SAndrew.Bardsley@arm.com thread->pcState(old_pc); 50110259SAndrew.Bardsley@arm.com issued = true; 50210259SAndrew.Bardsley@arm.com } 50310259SAndrew.Bardsley@arm.com 50410259SAndrew.Bardsley@arm.com return issued; 50510259SAndrew.Bardsley@arm.com} 50610259SAndrew.Bardsley@arm.com 50710259SAndrew.Bardsley@arm.com/** Increment a cyclic buffer index for indices [0, cycle_size-1] */ 50810259SAndrew.Bardsley@arm.cominline unsigned int 50910259SAndrew.Bardsley@arm.comcyclicIndexInc(unsigned int index, unsigned int cycle_size) 51010259SAndrew.Bardsley@arm.com{ 51110259SAndrew.Bardsley@arm.com unsigned int ret = index + 1; 51210259SAndrew.Bardsley@arm.com 51310259SAndrew.Bardsley@arm.com if (ret == cycle_size) 51410259SAndrew.Bardsley@arm.com ret = 0; 51510259SAndrew.Bardsley@arm.com 51610259SAndrew.Bardsley@arm.com return ret; 51710259SAndrew.Bardsley@arm.com} 51810259SAndrew.Bardsley@arm.com 51910259SAndrew.Bardsley@arm.com/** Decrement a cyclic buffer index for indices [0, cycle_size-1] */ 52010259SAndrew.Bardsley@arm.cominline unsigned int 52110259SAndrew.Bardsley@arm.comcyclicIndexDec(unsigned int index, unsigned int cycle_size) 52210259SAndrew.Bardsley@arm.com{ 52310259SAndrew.Bardsley@arm.com int ret = index - 1; 52410259SAndrew.Bardsley@arm.com 52510259SAndrew.Bardsley@arm.com if (ret < 0) 52610259SAndrew.Bardsley@arm.com ret = cycle_size - 1; 52710259SAndrew.Bardsley@arm.com 52810259SAndrew.Bardsley@arm.com return ret; 52910259SAndrew.Bardsley@arm.com} 53010259SAndrew.Bardsley@arm.com 53110259SAndrew.Bardsley@arm.comunsigned int 53211567Smitch.hayenga@arm.comExecute::issue(ThreadID thread_id) 53310259SAndrew.Bardsley@arm.com{ 53411567Smitch.hayenga@arm.com const ForwardInstData *insts_in = getInput(thread_id); 53511567Smitch.hayenga@arm.com ExecuteThreadInfo &thread = executeInfo[thread_id]; 53610259SAndrew.Bardsley@arm.com 53710259SAndrew.Bardsley@arm.com /* Early termination if we have no instructions */ 53810259SAndrew.Bardsley@arm.com if (!insts_in) 53910259SAndrew.Bardsley@arm.com return 0; 54010259SAndrew.Bardsley@arm.com 54110259SAndrew.Bardsley@arm.com /* Start from the first FU */ 54210259SAndrew.Bardsley@arm.com unsigned int fu_index = 0; 54310259SAndrew.Bardsley@arm.com 54410259SAndrew.Bardsley@arm.com /* Remains true while instructions are still being issued. If any 54510259SAndrew.Bardsley@arm.com * instruction fails to issue, this is set to false and we exit issue. 54610259SAndrew.Bardsley@arm.com * This strictly enforces in-order issue. For other issue behaviours, 54710259SAndrew.Bardsley@arm.com * a more complicated test in the outer while loop below is needed. */ 54810259SAndrew.Bardsley@arm.com bool issued = true; 54910259SAndrew.Bardsley@arm.com 55010259SAndrew.Bardsley@arm.com /* Number of insts issues this cycle to check for issueLimit */ 55110259SAndrew.Bardsley@arm.com unsigned num_insts_issued = 0; 55210259SAndrew.Bardsley@arm.com 55310259SAndrew.Bardsley@arm.com /* Number of memory ops issues this cycle to check for memoryIssueLimit */ 55410259SAndrew.Bardsley@arm.com unsigned num_mem_insts_issued = 0; 55510259SAndrew.Bardsley@arm.com 55610259SAndrew.Bardsley@arm.com /* Number of instructions discarded this cycle in order to enforce a 55710259SAndrew.Bardsley@arm.com * discardLimit. @todo, add that parameter? */ 55810259SAndrew.Bardsley@arm.com unsigned num_insts_discarded = 0; 55910259SAndrew.Bardsley@arm.com 56010259SAndrew.Bardsley@arm.com do { 56111567Smitch.hayenga@arm.com MinorDynInstPtr inst = insts_in->insts[thread.inputIndex]; 56210259SAndrew.Bardsley@arm.com Fault fault = inst->fault; 56310259SAndrew.Bardsley@arm.com bool discarded = false; 56410259SAndrew.Bardsley@arm.com bool issued_mem_ref = false; 56510259SAndrew.Bardsley@arm.com 56610259SAndrew.Bardsley@arm.com if (inst->isBubble()) { 56710259SAndrew.Bardsley@arm.com /* Skip */ 56810259SAndrew.Bardsley@arm.com issued = true; 56910259SAndrew.Bardsley@arm.com } else if (cpu.getContext(thread_id)->status() == 57010259SAndrew.Bardsley@arm.com ThreadContext::Suspended) 57110259SAndrew.Bardsley@arm.com { 57211568Smitch.hayenga@arm.com DPRINTF(MinorExecute, "Discarding inst: %s from suspended" 57310259SAndrew.Bardsley@arm.com " thread\n", *inst); 57410259SAndrew.Bardsley@arm.com 57511568Smitch.hayenga@arm.com issued = true; 57611568Smitch.hayenga@arm.com discarded = true; 57711567Smitch.hayenga@arm.com } else if (inst->id.streamSeqNum != thread.streamSeqNum) { 57810259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Discarding inst: %s as its stream" 57910259SAndrew.Bardsley@arm.com " state was unexpected, expected: %d\n", 58011567Smitch.hayenga@arm.com *inst, thread.streamSeqNum); 58110259SAndrew.Bardsley@arm.com issued = true; 58210259SAndrew.Bardsley@arm.com discarded = true; 58310259SAndrew.Bardsley@arm.com } else { 58410259SAndrew.Bardsley@arm.com /* Try and issue an instruction into an FU, assume we didn't and 58510259SAndrew.Bardsley@arm.com * fix that in the loop */ 58610259SAndrew.Bardsley@arm.com issued = false; 58710259SAndrew.Bardsley@arm.com 58810259SAndrew.Bardsley@arm.com /* Try FU from 0 each instruction */ 58910259SAndrew.Bardsley@arm.com fu_index = 0; 59010259SAndrew.Bardsley@arm.com 59110259SAndrew.Bardsley@arm.com /* Try and issue a single instruction stepping through the 59210259SAndrew.Bardsley@arm.com * available FUs */ 59310259SAndrew.Bardsley@arm.com do { 59410259SAndrew.Bardsley@arm.com FUPipeline *fu = funcUnits[fu_index]; 59510259SAndrew.Bardsley@arm.com 59610259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Trying to issue inst: %s to FU: %d\n", 59710259SAndrew.Bardsley@arm.com *inst, fu_index); 59810259SAndrew.Bardsley@arm.com 59910259SAndrew.Bardsley@arm.com /* Does the examined fu have the OpClass-related capability 60010259SAndrew.Bardsley@arm.com * needed to execute this instruction? Faults can always 60110259SAndrew.Bardsley@arm.com * issue to any FU but probably should just 'live' in the 60210259SAndrew.Bardsley@arm.com * inFlightInsts queue rather than having an FU. */ 60310259SAndrew.Bardsley@arm.com bool fu_is_capable = (!inst->isFault() ? 60410259SAndrew.Bardsley@arm.com fu->provides(inst->staticInst->opClass()) : true); 60510259SAndrew.Bardsley@arm.com 60610259SAndrew.Bardsley@arm.com if (inst->isNoCostInst()) { 60710259SAndrew.Bardsley@arm.com /* Issue free insts. to a fake numbered FU */ 60810259SAndrew.Bardsley@arm.com fu_index = noCostFUIndex; 60910259SAndrew.Bardsley@arm.com 61010259SAndrew.Bardsley@arm.com /* And start the countdown on activity to allow 61110259SAndrew.Bardsley@arm.com * this instruction to get to the end of its FU */ 61210259SAndrew.Bardsley@arm.com cpu.activityRecorder->activity(); 61310259SAndrew.Bardsley@arm.com 61410259SAndrew.Bardsley@arm.com /* Mark the destinations for this instruction as 61510259SAndrew.Bardsley@arm.com * busy */ 61611567Smitch.hayenga@arm.com scoreboard[thread_id].markupInstDests(inst, cpu.curCycle() + 61710259SAndrew.Bardsley@arm.com Cycles(0), cpu.getContext(thread_id), false); 61810259SAndrew.Bardsley@arm.com 61911567Smitch.hayenga@arm.com DPRINTF(MinorExecute, "Issuing %s to %d\n", inst->id, noCostFUIndex); 62010259SAndrew.Bardsley@arm.com inst->fuIndex = noCostFUIndex; 62110259SAndrew.Bardsley@arm.com inst->extraCommitDelay = Cycles(0); 62210259SAndrew.Bardsley@arm.com inst->extraCommitDelayExpr = NULL; 62310259SAndrew.Bardsley@arm.com 62410259SAndrew.Bardsley@arm.com /* Push the instruction onto the inFlight queue so 62510259SAndrew.Bardsley@arm.com * it can be committed in order */ 62610259SAndrew.Bardsley@arm.com QueuedInst fu_inst(inst); 62711567Smitch.hayenga@arm.com thread.inFlightInsts->push(fu_inst); 62810259SAndrew.Bardsley@arm.com 62910259SAndrew.Bardsley@arm.com issued = true; 63010259SAndrew.Bardsley@arm.com 63110259SAndrew.Bardsley@arm.com } else if (!fu_is_capable || fu->alreadyPushed()) { 63210259SAndrew.Bardsley@arm.com /* Skip */ 63310259SAndrew.Bardsley@arm.com if (!fu_is_capable) { 63410259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue as FU: %d isn't" 63510259SAndrew.Bardsley@arm.com " capable\n", fu_index); 63610259SAndrew.Bardsley@arm.com } else { 63710259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue as FU: %d is" 63810259SAndrew.Bardsley@arm.com " already busy\n", fu_index); 63910259SAndrew.Bardsley@arm.com } 64010259SAndrew.Bardsley@arm.com } else if (fu->stalled) { 64110259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue inst: %s into FU: %d," 64210259SAndrew.Bardsley@arm.com " it's stalled\n", 64310259SAndrew.Bardsley@arm.com *inst, fu_index); 64410259SAndrew.Bardsley@arm.com } else if (!fu->canInsert()) { 64510259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue inst: %s to busy FU" 64610259SAndrew.Bardsley@arm.com " for another: %d cycles\n", 64710259SAndrew.Bardsley@arm.com *inst, fu->cyclesBeforeInsert()); 64810259SAndrew.Bardsley@arm.com } else { 64910259SAndrew.Bardsley@arm.com MinorFUTiming *timing = (!inst->isFault() ? 65010259SAndrew.Bardsley@arm.com fu->findTiming(inst->staticInst) : NULL); 65110259SAndrew.Bardsley@arm.com 65210259SAndrew.Bardsley@arm.com const std::vector<Cycles> *src_latencies = 65310259SAndrew.Bardsley@arm.com (timing ? &(timing->srcRegsRelativeLats) 65410259SAndrew.Bardsley@arm.com : NULL); 65510259SAndrew.Bardsley@arm.com 65610259SAndrew.Bardsley@arm.com const std::vector<bool> *cant_forward_from_fu_indices = 65710259SAndrew.Bardsley@arm.com &(fu->cantForwardFromFUIndices); 65810259SAndrew.Bardsley@arm.com 65910259SAndrew.Bardsley@arm.com if (timing && timing->suppress) { 66010259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue inst: %s as extra" 66110259SAndrew.Bardsley@arm.com " decoding is suppressing it\n", 66210259SAndrew.Bardsley@arm.com *inst); 66311567Smitch.hayenga@arm.com } else if (!scoreboard[thread_id].canInstIssue(inst, 66411567Smitch.hayenga@arm.com src_latencies, cant_forward_from_fu_indices, 66510259SAndrew.Bardsley@arm.com cpu.curCycle(), cpu.getContext(thread_id))) 66610259SAndrew.Bardsley@arm.com { 66710259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue inst: %s yet\n", 66810259SAndrew.Bardsley@arm.com *inst); 66910259SAndrew.Bardsley@arm.com } else { 67010259SAndrew.Bardsley@arm.com /* Can insert the instruction into this FU */ 67110259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Issuing inst: %s" 67210259SAndrew.Bardsley@arm.com " into FU %d\n", *inst, 67310259SAndrew.Bardsley@arm.com fu_index); 67410259SAndrew.Bardsley@arm.com 67510259SAndrew.Bardsley@arm.com Cycles extra_dest_retire_lat = Cycles(0); 67610259SAndrew.Bardsley@arm.com TimingExpr *extra_dest_retire_lat_expr = NULL; 67710259SAndrew.Bardsley@arm.com Cycles extra_assumed_lat = Cycles(0); 67810259SAndrew.Bardsley@arm.com 67910259SAndrew.Bardsley@arm.com /* Add the extraCommitDelay and extraAssumeLat to 68010259SAndrew.Bardsley@arm.com * the FU pipeline timings */ 68110259SAndrew.Bardsley@arm.com if (timing) { 68210259SAndrew.Bardsley@arm.com extra_dest_retire_lat = 68310259SAndrew.Bardsley@arm.com timing->extraCommitLat; 68410259SAndrew.Bardsley@arm.com extra_dest_retire_lat_expr = 68510259SAndrew.Bardsley@arm.com timing->extraCommitLatExpr; 68610259SAndrew.Bardsley@arm.com extra_assumed_lat = 68710259SAndrew.Bardsley@arm.com timing->extraAssumedLat; 68810259SAndrew.Bardsley@arm.com } 68910259SAndrew.Bardsley@arm.com 69010580SAndrew.Bardsley@arm.com issued_mem_ref = inst->isMemRef(); 69110259SAndrew.Bardsley@arm.com 69210259SAndrew.Bardsley@arm.com QueuedInst fu_inst(inst); 69310259SAndrew.Bardsley@arm.com 69410259SAndrew.Bardsley@arm.com /* Decorate the inst with FU details */ 69510259SAndrew.Bardsley@arm.com inst->fuIndex = fu_index; 69610259SAndrew.Bardsley@arm.com inst->extraCommitDelay = extra_dest_retire_lat; 69710259SAndrew.Bardsley@arm.com inst->extraCommitDelayExpr = 69810259SAndrew.Bardsley@arm.com extra_dest_retire_lat_expr; 69910259SAndrew.Bardsley@arm.com 70010259SAndrew.Bardsley@arm.com if (issued_mem_ref) { 70110259SAndrew.Bardsley@arm.com /* Remember which instruction this memory op 70210259SAndrew.Bardsley@arm.com * depends on so that initiateAcc can be called 70310259SAndrew.Bardsley@arm.com * early */ 70410259SAndrew.Bardsley@arm.com if (allowEarlyMemIssue) { 70510259SAndrew.Bardsley@arm.com inst->instToWaitFor = 70611567Smitch.hayenga@arm.com scoreboard[thread_id].execSeqNumToWaitFor(inst, 70710259SAndrew.Bardsley@arm.com cpu.getContext(thread_id)); 70810259SAndrew.Bardsley@arm.com 70911567Smitch.hayenga@arm.com if (lsq.getLastMemBarrier(thread_id) > 71010259SAndrew.Bardsley@arm.com inst->instToWaitFor) 71110259SAndrew.Bardsley@arm.com { 71210259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "A barrier will" 71310259SAndrew.Bardsley@arm.com " cause a delay in mem ref issue of" 71410259SAndrew.Bardsley@arm.com " inst: %s until after inst" 71510259SAndrew.Bardsley@arm.com " %d(exec)\n", *inst, 71611567Smitch.hayenga@arm.com lsq.getLastMemBarrier(thread_id)); 71710259SAndrew.Bardsley@arm.com 71810259SAndrew.Bardsley@arm.com inst->instToWaitFor = 71911567Smitch.hayenga@arm.com lsq.getLastMemBarrier(thread_id); 72010259SAndrew.Bardsley@arm.com } else { 72110259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Memory ref inst:" 72210259SAndrew.Bardsley@arm.com " %s must wait for inst %d(exec)" 72310259SAndrew.Bardsley@arm.com " before issuing\n", 72410259SAndrew.Bardsley@arm.com *inst, inst->instToWaitFor); 72510259SAndrew.Bardsley@arm.com } 72610259SAndrew.Bardsley@arm.com 72710259SAndrew.Bardsley@arm.com inst->canEarlyIssue = true; 72810259SAndrew.Bardsley@arm.com } 72910259SAndrew.Bardsley@arm.com /* Also queue this instruction in the memory ref 73010259SAndrew.Bardsley@arm.com * queue to ensure in-order issue to the LSQ */ 73110259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Pushing mem inst: %s\n", 73210259SAndrew.Bardsley@arm.com *inst); 73311567Smitch.hayenga@arm.com thread.inFUMemInsts->push(fu_inst); 73410259SAndrew.Bardsley@arm.com } 73510259SAndrew.Bardsley@arm.com 73610259SAndrew.Bardsley@arm.com /* Issue to FU */ 73710259SAndrew.Bardsley@arm.com fu->push(fu_inst); 73810259SAndrew.Bardsley@arm.com /* And start the countdown on activity to allow 73910259SAndrew.Bardsley@arm.com * this instruction to get to the end of its FU */ 74010259SAndrew.Bardsley@arm.com cpu.activityRecorder->activity(); 74110259SAndrew.Bardsley@arm.com 74210259SAndrew.Bardsley@arm.com /* Mark the destinations for this instruction as 74310259SAndrew.Bardsley@arm.com * busy */ 74411567Smitch.hayenga@arm.com scoreboard[thread_id].markupInstDests(inst, cpu.curCycle() + 74510259SAndrew.Bardsley@arm.com fu->description.opLat + 74610259SAndrew.Bardsley@arm.com extra_dest_retire_lat + 74710259SAndrew.Bardsley@arm.com extra_assumed_lat, 74810259SAndrew.Bardsley@arm.com cpu.getContext(thread_id), 74910259SAndrew.Bardsley@arm.com issued_mem_ref && extra_assumed_lat == Cycles(0)); 75010259SAndrew.Bardsley@arm.com 75110259SAndrew.Bardsley@arm.com /* Push the instruction onto the inFlight queue so 75210259SAndrew.Bardsley@arm.com * it can be committed in order */ 75311567Smitch.hayenga@arm.com thread.inFlightInsts->push(fu_inst); 75410259SAndrew.Bardsley@arm.com 75510259SAndrew.Bardsley@arm.com issued = true; 75610259SAndrew.Bardsley@arm.com } 75710259SAndrew.Bardsley@arm.com } 75810259SAndrew.Bardsley@arm.com 75910259SAndrew.Bardsley@arm.com fu_index++; 76010259SAndrew.Bardsley@arm.com } while (fu_index != numFuncUnits && !issued); 76110259SAndrew.Bardsley@arm.com 76210259SAndrew.Bardsley@arm.com if (!issued) 76310259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Didn't issue inst: %s\n", *inst); 76410259SAndrew.Bardsley@arm.com } 76510259SAndrew.Bardsley@arm.com 76610259SAndrew.Bardsley@arm.com if (issued) { 76710259SAndrew.Bardsley@arm.com /* Generate MinorTrace's MinorInst lines. Do this at commit 76810259SAndrew.Bardsley@arm.com * to allow better instruction annotation? */ 76910259SAndrew.Bardsley@arm.com if (DTRACE(MinorTrace) && !inst->isBubble()) 77010259SAndrew.Bardsley@arm.com inst->minorTraceInst(*this); 77110259SAndrew.Bardsley@arm.com 77210259SAndrew.Bardsley@arm.com /* Mark up barriers in the LSQ */ 77310259SAndrew.Bardsley@arm.com if (!discarded && inst->isInst() && 77410259SAndrew.Bardsley@arm.com inst->staticInst->isMemBarrier()) 77510259SAndrew.Bardsley@arm.com { 77610259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Issuing memory barrier inst: %s\n", *inst); 77710259SAndrew.Bardsley@arm.com lsq.issuedMemBarrierInst(inst); 77810259SAndrew.Bardsley@arm.com } 77910259SAndrew.Bardsley@arm.com 78010259SAndrew.Bardsley@arm.com if (inst->traceData && setTraceTimeOnIssue) { 78110259SAndrew.Bardsley@arm.com inst->traceData->setWhen(curTick()); 78210259SAndrew.Bardsley@arm.com } 78310259SAndrew.Bardsley@arm.com 78410259SAndrew.Bardsley@arm.com if (issued_mem_ref) 78510259SAndrew.Bardsley@arm.com num_mem_insts_issued++; 78610259SAndrew.Bardsley@arm.com 78710259SAndrew.Bardsley@arm.com if (discarded) { 78810259SAndrew.Bardsley@arm.com num_insts_discarded++; 78910851SAndrew.Bardsley@arm.com } else if (!inst->isBubble()) { 79010259SAndrew.Bardsley@arm.com num_insts_issued++; 79110259SAndrew.Bardsley@arm.com 79210259SAndrew.Bardsley@arm.com if (num_insts_issued == issueLimit) 79310259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Reached inst issue limit\n"); 79410259SAndrew.Bardsley@arm.com } 79510259SAndrew.Bardsley@arm.com 79611567Smitch.hayenga@arm.com thread.inputIndex++; 79710259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Stepping to next inst inputIndex: %d\n", 79811567Smitch.hayenga@arm.com thread.inputIndex); 79910259SAndrew.Bardsley@arm.com } 80010259SAndrew.Bardsley@arm.com 80110259SAndrew.Bardsley@arm.com /* Got to the end of a line */ 80211567Smitch.hayenga@arm.com if (thread.inputIndex == insts_in->width()) { 80311567Smitch.hayenga@arm.com popInput(thread_id); 80410259SAndrew.Bardsley@arm.com /* Set insts_in to null to force us to leave the surrounding 80510259SAndrew.Bardsley@arm.com * loop */ 80610259SAndrew.Bardsley@arm.com insts_in = NULL; 80710259SAndrew.Bardsley@arm.com 80810259SAndrew.Bardsley@arm.com if (processMoreThanOneInput) { 80910259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Wrapping\n"); 81011567Smitch.hayenga@arm.com insts_in = getInput(thread_id); 81110259SAndrew.Bardsley@arm.com } 81210259SAndrew.Bardsley@arm.com } 81311567Smitch.hayenga@arm.com } while (insts_in && thread.inputIndex < insts_in->width() && 81410259SAndrew.Bardsley@arm.com /* We still have instructions */ 81510259SAndrew.Bardsley@arm.com fu_index != numFuncUnits && /* Not visited all FUs */ 81610259SAndrew.Bardsley@arm.com issued && /* We've not yet failed to issue an instruction */ 81710259SAndrew.Bardsley@arm.com num_insts_issued != issueLimit && /* Still allowed to issue */ 81810259SAndrew.Bardsley@arm.com num_mem_insts_issued != memoryIssueLimit); 81910259SAndrew.Bardsley@arm.com 82010259SAndrew.Bardsley@arm.com return num_insts_issued; 82110259SAndrew.Bardsley@arm.com} 82210259SAndrew.Bardsley@arm.com 82310259SAndrew.Bardsley@arm.combool 82411567Smitch.hayenga@arm.comExecute::tryPCEvents(ThreadID thread_id) 82510259SAndrew.Bardsley@arm.com{ 82611567Smitch.hayenga@arm.com ThreadContext *thread = cpu.getContext(thread_id); 82710259SAndrew.Bardsley@arm.com unsigned int num_pc_event_checks = 0; 82810259SAndrew.Bardsley@arm.com 82910259SAndrew.Bardsley@arm.com /* Handle PC events on instructions */ 83010259SAndrew.Bardsley@arm.com Addr oldPC; 83110259SAndrew.Bardsley@arm.com do { 83210259SAndrew.Bardsley@arm.com oldPC = thread->instAddr(); 83310259SAndrew.Bardsley@arm.com cpu.system->pcEventQueue.service(thread); 83410259SAndrew.Bardsley@arm.com num_pc_event_checks++; 83510259SAndrew.Bardsley@arm.com } while (oldPC != thread->instAddr()); 83610259SAndrew.Bardsley@arm.com 83710259SAndrew.Bardsley@arm.com if (num_pc_event_checks > 1) { 83810259SAndrew.Bardsley@arm.com DPRINTF(PCEvent, "Acting on PC Event to PC: %s\n", 83910259SAndrew.Bardsley@arm.com thread->pcState()); 84010259SAndrew.Bardsley@arm.com } 84110259SAndrew.Bardsley@arm.com 84210259SAndrew.Bardsley@arm.com return num_pc_event_checks > 1; 84310259SAndrew.Bardsley@arm.com} 84410259SAndrew.Bardsley@arm.com 84510259SAndrew.Bardsley@arm.comvoid 84610259SAndrew.Bardsley@arm.comExecute::doInstCommitAccounting(MinorDynInstPtr inst) 84710259SAndrew.Bardsley@arm.com{ 84810259SAndrew.Bardsley@arm.com assert(!inst->isFault()); 84910259SAndrew.Bardsley@arm.com 85010259SAndrew.Bardsley@arm.com MinorThread *thread = cpu.threads[inst->id.threadId]; 85110259SAndrew.Bardsley@arm.com 85210259SAndrew.Bardsley@arm.com /* Increment the many and various inst and op counts in the 85310259SAndrew.Bardsley@arm.com * thread and system */ 85410259SAndrew.Bardsley@arm.com if (!inst->staticInst->isMicroop() || inst->staticInst->isLastMicroop()) 85510259SAndrew.Bardsley@arm.com { 85610259SAndrew.Bardsley@arm.com thread->numInst++; 85710259SAndrew.Bardsley@arm.com thread->numInsts++; 85810259SAndrew.Bardsley@arm.com cpu.stats.numInsts++; 85910774Snikos.nikoleris@gmail.com cpu.system->totalNumInsts++; 86010774Snikos.nikoleris@gmail.com 86110774Snikos.nikoleris@gmail.com /* Act on events related to instruction counts */ 86210774Snikos.nikoleris@gmail.com cpu.comInstEventQueue[inst->id.threadId]->serviceEvents(thread->numInst); 86310774Snikos.nikoleris@gmail.com cpu.system->instEventQueue.serviceEvents(cpu.system->totalNumInsts); 86410259SAndrew.Bardsley@arm.com } 86510259SAndrew.Bardsley@arm.com thread->numOp++; 86610259SAndrew.Bardsley@arm.com thread->numOps++; 86710259SAndrew.Bardsley@arm.com cpu.stats.numOps++; 86811419Smitch.hayenga@arm.com cpu.stats.committedInstType[inst->id.threadId] 86911419Smitch.hayenga@arm.com [inst->staticInst->opClass()]++; 87010259SAndrew.Bardsley@arm.com 87110259SAndrew.Bardsley@arm.com /* Set the CP SeqNum to the numOps commit number */ 87210259SAndrew.Bardsley@arm.com if (inst->traceData) 87310259SAndrew.Bardsley@arm.com inst->traceData->setCPSeq(thread->numOp); 87410464SAndreas.Sandberg@ARM.com 87510464SAndreas.Sandberg@ARM.com cpu.probeInstCommit(inst->staticInst); 87610259SAndrew.Bardsley@arm.com} 87710259SAndrew.Bardsley@arm.com 87810259SAndrew.Bardsley@arm.combool 87910259SAndrew.Bardsley@arm.comExecute::commitInst(MinorDynInstPtr inst, bool early_memory_issue, 88010259SAndrew.Bardsley@arm.com BranchData &branch, Fault &fault, bool &committed, 88110259SAndrew.Bardsley@arm.com bool &completed_mem_issue) 88210259SAndrew.Bardsley@arm.com{ 88310259SAndrew.Bardsley@arm.com ThreadID thread_id = inst->id.threadId; 88410259SAndrew.Bardsley@arm.com ThreadContext *thread = cpu.getContext(thread_id); 88510259SAndrew.Bardsley@arm.com 88610259SAndrew.Bardsley@arm.com bool completed_inst = true; 88710259SAndrew.Bardsley@arm.com fault = NoFault; 88810259SAndrew.Bardsley@arm.com 88910259SAndrew.Bardsley@arm.com /* Is the thread for this instruction suspended? In that case, just 89010259SAndrew.Bardsley@arm.com * stall as long as there are no pending interrupts */ 89110259SAndrew.Bardsley@arm.com if (thread->status() == ThreadContext::Suspended && 89210259SAndrew.Bardsley@arm.com !isInterrupted(thread_id)) 89310259SAndrew.Bardsley@arm.com { 89411568Smitch.hayenga@arm.com panic("We should never hit the case where we try to commit from a " 89511568Smitch.hayenga@arm.com "suspended thread as the streamSeqNum should not match"); 89610259SAndrew.Bardsley@arm.com } else if (inst->isFault()) { 89710259SAndrew.Bardsley@arm.com ExecContext context(cpu, *cpu.threads[thread_id], *this, inst); 89810259SAndrew.Bardsley@arm.com 89910259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Fault inst reached Execute: %s\n", 90010259SAndrew.Bardsley@arm.com inst->fault->name()); 90110259SAndrew.Bardsley@arm.com 90210259SAndrew.Bardsley@arm.com fault = inst->fault; 90310259SAndrew.Bardsley@arm.com inst->fault->invoke(thread, NULL); 90410259SAndrew.Bardsley@arm.com 90510259SAndrew.Bardsley@arm.com tryToBranch(inst, fault, branch); 90610259SAndrew.Bardsley@arm.com } else if (inst->staticInst->isMemRef()) { 90710259SAndrew.Bardsley@arm.com /* Memory accesses are executed in two parts: 90810259SAndrew.Bardsley@arm.com * executeMemRefInst -- calculates the EA and issues the access 90910259SAndrew.Bardsley@arm.com * to memory. This is done here. 91010259SAndrew.Bardsley@arm.com * handleMemResponse -- handles the response packet, done by 91110259SAndrew.Bardsley@arm.com * Execute::commit 91210259SAndrew.Bardsley@arm.com * 91310259SAndrew.Bardsley@arm.com * While the memory access is in its FU, the EA is being 91410259SAndrew.Bardsley@arm.com * calculated. At the end of the FU, when it is ready to 91510259SAndrew.Bardsley@arm.com * 'commit' (in this function), the access is presented to the 91610259SAndrew.Bardsley@arm.com * memory queues. When a response comes back from memory, 91710259SAndrew.Bardsley@arm.com * Execute::commit will commit it. 91810259SAndrew.Bardsley@arm.com */ 91910259SAndrew.Bardsley@arm.com bool predicate_passed = false; 92010259SAndrew.Bardsley@arm.com bool completed_mem_inst = executeMemRefInst(inst, branch, 92110259SAndrew.Bardsley@arm.com predicate_passed, fault); 92210259SAndrew.Bardsley@arm.com 92310259SAndrew.Bardsley@arm.com if (completed_mem_inst && fault != NoFault) { 92410259SAndrew.Bardsley@arm.com if (early_memory_issue) { 92510259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Fault in early executing inst: %s\n", 92610259SAndrew.Bardsley@arm.com fault->name()); 92710259SAndrew.Bardsley@arm.com /* Don't execute the fault, just stall the instruction 92810259SAndrew.Bardsley@arm.com * until it gets to the head of inFlightInsts */ 92910259SAndrew.Bardsley@arm.com inst->canEarlyIssue = false; 93010259SAndrew.Bardsley@arm.com /* Not completed as we'll come here again to pick up 93110259SAndrew.Bardsley@arm.com * the fault when we get to the end of the FU */ 93210259SAndrew.Bardsley@arm.com completed_inst = false; 93310259SAndrew.Bardsley@arm.com } else { 93410259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Fault in execute: %s\n", 93510259SAndrew.Bardsley@arm.com fault->name()); 93610259SAndrew.Bardsley@arm.com fault->invoke(thread, NULL); 93710259SAndrew.Bardsley@arm.com 93810259SAndrew.Bardsley@arm.com tryToBranch(inst, fault, branch); 93910259SAndrew.Bardsley@arm.com completed_inst = true; 94010259SAndrew.Bardsley@arm.com } 94110259SAndrew.Bardsley@arm.com } else { 94210259SAndrew.Bardsley@arm.com completed_inst = completed_mem_inst; 94310259SAndrew.Bardsley@arm.com } 94410259SAndrew.Bardsley@arm.com completed_mem_issue = completed_inst; 94510259SAndrew.Bardsley@arm.com } else if (inst->isInst() && inst->staticInst->isMemBarrier() && 94610259SAndrew.Bardsley@arm.com !lsq.canPushIntoStoreBuffer()) 94710259SAndrew.Bardsley@arm.com { 94810259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't commit data barrier inst: %s yet as" 94910259SAndrew.Bardsley@arm.com " there isn't space in the store buffer\n", *inst); 95010259SAndrew.Bardsley@arm.com 95110259SAndrew.Bardsley@arm.com completed_inst = false; 95211567Smitch.hayenga@arm.com } else if (inst->isInst() && inst->staticInst->isQuiesce() 95311567Smitch.hayenga@arm.com && !branch.isBubble()){ 95411567Smitch.hayenga@arm.com /* This instruction can suspend, need to be able to communicate 95511567Smitch.hayenga@arm.com * backwards, so no other branches may evaluate this cycle*/ 95611567Smitch.hayenga@arm.com completed_inst = false; 95710259SAndrew.Bardsley@arm.com } else { 95810259SAndrew.Bardsley@arm.com ExecContext context(cpu, *cpu.threads[thread_id], *this, inst); 95910259SAndrew.Bardsley@arm.com 96010259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Committing inst: %s\n", *inst); 96110259SAndrew.Bardsley@arm.com 96210259SAndrew.Bardsley@arm.com fault = inst->staticInst->execute(&context, 96310259SAndrew.Bardsley@arm.com inst->traceData); 96410259SAndrew.Bardsley@arm.com 96510259SAndrew.Bardsley@arm.com /* Set the predicate for tracing and dump */ 96610259SAndrew.Bardsley@arm.com if (inst->traceData) 96710259SAndrew.Bardsley@arm.com inst->traceData->setPredicate(context.readPredicate()); 96810259SAndrew.Bardsley@arm.com 96910259SAndrew.Bardsley@arm.com committed = true; 97010259SAndrew.Bardsley@arm.com 97110259SAndrew.Bardsley@arm.com if (fault != NoFault) { 97210259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Fault in execute of inst: %s fault: %s\n", 97310259SAndrew.Bardsley@arm.com *inst, fault->name()); 97410259SAndrew.Bardsley@arm.com fault->invoke(thread, inst->staticInst); 97510259SAndrew.Bardsley@arm.com } 97610259SAndrew.Bardsley@arm.com 97710259SAndrew.Bardsley@arm.com doInstCommitAccounting(inst); 97810259SAndrew.Bardsley@arm.com tryToBranch(inst, fault, branch); 97910259SAndrew.Bardsley@arm.com } 98010259SAndrew.Bardsley@arm.com 98110259SAndrew.Bardsley@arm.com if (completed_inst) { 98210259SAndrew.Bardsley@arm.com /* Keep a copy of this instruction's predictionSeqNum just in case 98310259SAndrew.Bardsley@arm.com * we need to issue a branch without an instruction (such as an 98410259SAndrew.Bardsley@arm.com * interrupt) */ 98511567Smitch.hayenga@arm.com executeInfo[thread_id].lastPredictionSeqNum = inst->id.predictionSeqNum; 98610259SAndrew.Bardsley@arm.com 98710259SAndrew.Bardsley@arm.com /* Check to see if this instruction suspended the current thread. */ 98810259SAndrew.Bardsley@arm.com if (!inst->isFault() && 98910259SAndrew.Bardsley@arm.com thread->status() == ThreadContext::Suspended && 99010259SAndrew.Bardsley@arm.com branch.isBubble() && /* It didn't branch too */ 99110259SAndrew.Bardsley@arm.com !isInterrupted(thread_id)) /* Don't suspend if we have 99210259SAndrew.Bardsley@arm.com interrupts */ 99310259SAndrew.Bardsley@arm.com { 99411567Smitch.hayenga@arm.com TheISA::PCState resume_pc = cpu.getContext(thread_id)->pcState(); 99510259SAndrew.Bardsley@arm.com 99610259SAndrew.Bardsley@arm.com assert(resume_pc.microPC() == 0); 99710259SAndrew.Bardsley@arm.com 99810259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Suspending thread: %d from Execute" 99911567Smitch.hayenga@arm.com " inst: %s\n", thread_id, *inst); 100010259SAndrew.Bardsley@arm.com 100110259SAndrew.Bardsley@arm.com cpu.stats.numFetchSuspends++; 100210259SAndrew.Bardsley@arm.com 100311567Smitch.hayenga@arm.com updateBranchData(thread_id, BranchData::SuspendThread, inst, 100411567Smitch.hayenga@arm.com resume_pc, branch); 100510259SAndrew.Bardsley@arm.com } 100610259SAndrew.Bardsley@arm.com } 100710259SAndrew.Bardsley@arm.com 100810259SAndrew.Bardsley@arm.com return completed_inst; 100910259SAndrew.Bardsley@arm.com} 101010259SAndrew.Bardsley@arm.com 101110259SAndrew.Bardsley@arm.comvoid 101211567Smitch.hayenga@arm.comExecute::commit(ThreadID thread_id, bool only_commit_microops, bool discard, 101311567Smitch.hayenga@arm.com BranchData &branch) 101410259SAndrew.Bardsley@arm.com{ 101510259SAndrew.Bardsley@arm.com Fault fault = NoFault; 101610259SAndrew.Bardsley@arm.com Cycles now = cpu.curCycle(); 101711567Smitch.hayenga@arm.com ExecuteThreadInfo &ex_info = executeInfo[thread_id]; 101810259SAndrew.Bardsley@arm.com 101910259SAndrew.Bardsley@arm.com /** 102010259SAndrew.Bardsley@arm.com * Try and execute as many instructions from the end of FU pipelines as 102110259SAndrew.Bardsley@arm.com * possible. This *doesn't* include actually advancing the pipelines. 102210259SAndrew.Bardsley@arm.com * 102310259SAndrew.Bardsley@arm.com * We do this by looping on the front of the inFlightInsts queue for as 102410259SAndrew.Bardsley@arm.com * long as we can find the desired instruction at the end of the 102510259SAndrew.Bardsley@arm.com * functional unit it was issued to without seeing a branch or a fault. 102610259SAndrew.Bardsley@arm.com * In this function, these terms are used: 102710259SAndrew.Bardsley@arm.com * complete -- The instruction has finished its passage through 102810259SAndrew.Bardsley@arm.com * its functional unit and its fate has been decided 102910259SAndrew.Bardsley@arm.com * (committed, discarded, issued to the memory system) 103010259SAndrew.Bardsley@arm.com * commit -- The instruction is complete(d), not discarded and has 103110259SAndrew.Bardsley@arm.com * its effects applied to the CPU state 103210259SAndrew.Bardsley@arm.com * discard(ed) -- The instruction is complete but not committed 103310259SAndrew.Bardsley@arm.com * as its streamSeqNum disagrees with the current 103410259SAndrew.Bardsley@arm.com * Execute::streamSeqNum 103510259SAndrew.Bardsley@arm.com * 103610259SAndrew.Bardsley@arm.com * Commits are also possible from two other places: 103710259SAndrew.Bardsley@arm.com * 103810259SAndrew.Bardsley@arm.com * 1) Responses returning from the LSQ 103910259SAndrew.Bardsley@arm.com * 2) Mem ops issued to the LSQ ('committed' from the FUs) earlier 104010259SAndrew.Bardsley@arm.com * than their position in the inFlightInsts queue, but after all 104110259SAndrew.Bardsley@arm.com * their dependencies are resolved. 104210259SAndrew.Bardsley@arm.com */ 104310259SAndrew.Bardsley@arm.com 104410259SAndrew.Bardsley@arm.com /* Has an instruction been completed? Once this becomes false, we stop 104510259SAndrew.Bardsley@arm.com * trying to complete instructions. */ 104610259SAndrew.Bardsley@arm.com bool completed_inst = true; 104710259SAndrew.Bardsley@arm.com 104810259SAndrew.Bardsley@arm.com /* Number of insts committed this cycle to check against commitLimit */ 104910259SAndrew.Bardsley@arm.com unsigned int num_insts_committed = 0; 105010259SAndrew.Bardsley@arm.com 105110259SAndrew.Bardsley@arm.com /* Number of memory access instructions committed to check against 105210259SAndrew.Bardsley@arm.com * memCommitLimit */ 105310259SAndrew.Bardsley@arm.com unsigned int num_mem_refs_committed = 0; 105410259SAndrew.Bardsley@arm.com 105511567Smitch.hayenga@arm.com if (only_commit_microops && !ex_info.inFlightInsts->empty()) { 105610259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Only commit microops %s %d\n", 105711567Smitch.hayenga@arm.com *(ex_info.inFlightInsts->front().inst), 105811567Smitch.hayenga@arm.com ex_info.lastCommitWasEndOfMacroop); 105910259SAndrew.Bardsley@arm.com } 106010259SAndrew.Bardsley@arm.com 106111567Smitch.hayenga@arm.com while (!ex_info.inFlightInsts->empty() && /* Some more instructions to process */ 106210259SAndrew.Bardsley@arm.com !branch.isStreamChange() && /* No real branch */ 106310259SAndrew.Bardsley@arm.com fault == NoFault && /* No faults */ 106410259SAndrew.Bardsley@arm.com completed_inst && /* Still finding instructions to execute */ 106513647Sqtt2@cornell.edu num_insts_committed != commitLimit /* Not reached commit limit */ 106610259SAndrew.Bardsley@arm.com ) 106710259SAndrew.Bardsley@arm.com { 106810259SAndrew.Bardsley@arm.com if (only_commit_microops) { 106910259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Committing tail of insts before" 107010259SAndrew.Bardsley@arm.com " interrupt: %s\n", 107111567Smitch.hayenga@arm.com *(ex_info.inFlightInsts->front().inst)); 107210259SAndrew.Bardsley@arm.com } 107310259SAndrew.Bardsley@arm.com 107411567Smitch.hayenga@arm.com QueuedInst *head_inflight_inst = &(ex_info.inFlightInsts->front()); 107510259SAndrew.Bardsley@arm.com 107610259SAndrew.Bardsley@arm.com InstSeqNum head_exec_seq_num = 107710259SAndrew.Bardsley@arm.com head_inflight_inst->inst->id.execSeqNum; 107810259SAndrew.Bardsley@arm.com 107910259SAndrew.Bardsley@arm.com /* The instruction we actually process if completed_inst 108010259SAndrew.Bardsley@arm.com * remains true to the end of the loop body. 108110259SAndrew.Bardsley@arm.com * Start by considering the the head of the in flight insts queue */ 108210259SAndrew.Bardsley@arm.com MinorDynInstPtr inst = head_inflight_inst->inst; 108310259SAndrew.Bardsley@arm.com 108410259SAndrew.Bardsley@arm.com bool committed_inst = false; 108510259SAndrew.Bardsley@arm.com bool discard_inst = false; 108610259SAndrew.Bardsley@arm.com bool completed_mem_ref = false; 108710259SAndrew.Bardsley@arm.com bool issued_mem_ref = false; 108810259SAndrew.Bardsley@arm.com bool early_memory_issue = false; 108910259SAndrew.Bardsley@arm.com 109010259SAndrew.Bardsley@arm.com /* Must set this again to go around the loop */ 109110259SAndrew.Bardsley@arm.com completed_inst = false; 109210259SAndrew.Bardsley@arm.com 109310259SAndrew.Bardsley@arm.com /* If we're just completing a macroop before an interrupt or drain, 109410259SAndrew.Bardsley@arm.com * can we stil commit another microop (rather than a memory response) 109510259SAndrew.Bardsley@arm.com * without crosing into the next full instruction? */ 109611567Smitch.hayenga@arm.com bool can_commit_insts = !ex_info.inFlightInsts->empty() && 109711567Smitch.hayenga@arm.com !(only_commit_microops && ex_info.lastCommitWasEndOfMacroop); 109810259SAndrew.Bardsley@arm.com 109910259SAndrew.Bardsley@arm.com /* Can we find a mem response for this inst */ 110010259SAndrew.Bardsley@arm.com LSQ::LSQRequestPtr mem_response = 110110259SAndrew.Bardsley@arm.com (inst->inLSQ ? lsq.findResponse(inst) : NULL); 110210259SAndrew.Bardsley@arm.com 110310259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Trying to commit canCommitInsts: %d\n", 110410259SAndrew.Bardsley@arm.com can_commit_insts); 110510259SAndrew.Bardsley@arm.com 110610259SAndrew.Bardsley@arm.com /* Test for PC events after every instruction */ 110711567Smitch.hayenga@arm.com if (isInbetweenInsts(thread_id) && tryPCEvents(thread_id)) { 110811567Smitch.hayenga@arm.com ThreadContext *thread = cpu.getContext(thread_id); 110910259SAndrew.Bardsley@arm.com 111010259SAndrew.Bardsley@arm.com /* Branch as there was a change in PC */ 111111567Smitch.hayenga@arm.com updateBranchData(thread_id, BranchData::UnpredictedBranch, 111210259SAndrew.Bardsley@arm.com MinorDynInst::bubble(), thread->pcState(), branch); 111310259SAndrew.Bardsley@arm.com } else if (mem_response && 111410259SAndrew.Bardsley@arm.com num_mem_refs_committed < memoryCommitLimit) 111510259SAndrew.Bardsley@arm.com { 111610259SAndrew.Bardsley@arm.com /* Try to commit from the memory responses next */ 111711567Smitch.hayenga@arm.com discard_inst = inst->id.streamSeqNum != 111811567Smitch.hayenga@arm.com ex_info.streamSeqNum || discard; 111910259SAndrew.Bardsley@arm.com 112010259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Trying to commit mem response: %s\n", 112110259SAndrew.Bardsley@arm.com *inst); 112210259SAndrew.Bardsley@arm.com 112310259SAndrew.Bardsley@arm.com /* Complete or discard the response */ 112410259SAndrew.Bardsley@arm.com if (discard_inst) { 112510259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Discarding mem inst: %s as its" 112610259SAndrew.Bardsley@arm.com " stream state was unexpected, expected: %d\n", 112711567Smitch.hayenga@arm.com *inst, ex_info.streamSeqNum); 112810259SAndrew.Bardsley@arm.com 112910259SAndrew.Bardsley@arm.com lsq.popResponse(mem_response); 113010259SAndrew.Bardsley@arm.com } else { 113110259SAndrew.Bardsley@arm.com handleMemResponse(inst, mem_response, branch, fault); 113210259SAndrew.Bardsley@arm.com committed_inst = true; 113310259SAndrew.Bardsley@arm.com } 113410259SAndrew.Bardsley@arm.com 113510259SAndrew.Bardsley@arm.com completed_mem_ref = true; 113610259SAndrew.Bardsley@arm.com completed_inst = true; 113710259SAndrew.Bardsley@arm.com } else if (can_commit_insts) { 113810259SAndrew.Bardsley@arm.com /* If true, this instruction will, subject to timing tweaks, 113910259SAndrew.Bardsley@arm.com * be considered for completion. try_to_commit flattens 114010259SAndrew.Bardsley@arm.com * the `if' tree a bit and allows other tests for inst 114110259SAndrew.Bardsley@arm.com * commit to be inserted here. */ 114210259SAndrew.Bardsley@arm.com bool try_to_commit = false; 114310259SAndrew.Bardsley@arm.com 114410259SAndrew.Bardsley@arm.com /* Try and issue memory ops early if they: 114510259SAndrew.Bardsley@arm.com * - Can push a request into the LSQ 114610259SAndrew.Bardsley@arm.com * - Have reached the end of their FUs 114710259SAndrew.Bardsley@arm.com * - Have had all their dependencies satisfied 114810259SAndrew.Bardsley@arm.com * - Are from the right stream 114910259SAndrew.Bardsley@arm.com * 115010259SAndrew.Bardsley@arm.com * For any other case, leave it to the normal instruction 115110259SAndrew.Bardsley@arm.com * issue below to handle them. 115210259SAndrew.Bardsley@arm.com */ 115311567Smitch.hayenga@arm.com if (!ex_info.inFUMemInsts->empty() && lsq.canRequest()) { 115410259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Trying to commit from mem FUs\n"); 115510259SAndrew.Bardsley@arm.com 115610259SAndrew.Bardsley@arm.com const MinorDynInstPtr head_mem_ref_inst = 115711567Smitch.hayenga@arm.com ex_info.inFUMemInsts->front().inst; 115810259SAndrew.Bardsley@arm.com FUPipeline *fu = funcUnits[head_mem_ref_inst->fuIndex]; 115910259SAndrew.Bardsley@arm.com const MinorDynInstPtr &fu_inst = fu->front().inst; 116010259SAndrew.Bardsley@arm.com 116110259SAndrew.Bardsley@arm.com /* Use this, possibly out of order, inst as the one 116210259SAndrew.Bardsley@arm.com * to 'commit'/send to the LSQ */ 116310259SAndrew.Bardsley@arm.com if (!fu_inst->isBubble() && 116410259SAndrew.Bardsley@arm.com !fu_inst->inLSQ && 116510259SAndrew.Bardsley@arm.com fu_inst->canEarlyIssue && 116611567Smitch.hayenga@arm.com ex_info.streamSeqNum == fu_inst->id.streamSeqNum && 116710259SAndrew.Bardsley@arm.com head_exec_seq_num > fu_inst->instToWaitFor) 116810259SAndrew.Bardsley@arm.com { 116910259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Issuing mem ref early" 117010259SAndrew.Bardsley@arm.com " inst: %s instToWaitFor: %d\n", 117110259SAndrew.Bardsley@arm.com *(fu_inst), fu_inst->instToWaitFor); 117210259SAndrew.Bardsley@arm.com 117310259SAndrew.Bardsley@arm.com inst = fu_inst; 117410259SAndrew.Bardsley@arm.com try_to_commit = true; 117510259SAndrew.Bardsley@arm.com early_memory_issue = true; 117610259SAndrew.Bardsley@arm.com completed_inst = true; 117710259SAndrew.Bardsley@arm.com } 117810259SAndrew.Bardsley@arm.com } 117910259SAndrew.Bardsley@arm.com 118010259SAndrew.Bardsley@arm.com /* Try and commit FU-less insts */ 118110259SAndrew.Bardsley@arm.com if (!completed_inst && inst->isNoCostInst()) { 118210259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Committing no cost inst: %s", *inst); 118310259SAndrew.Bardsley@arm.com 118410259SAndrew.Bardsley@arm.com try_to_commit = true; 118510259SAndrew.Bardsley@arm.com completed_inst = true; 118610259SAndrew.Bardsley@arm.com } 118710259SAndrew.Bardsley@arm.com 118810259SAndrew.Bardsley@arm.com /* Try to issue from the ends of FUs and the inFlightInsts 118910259SAndrew.Bardsley@arm.com * queue */ 119010259SAndrew.Bardsley@arm.com if (!completed_inst && !inst->inLSQ) { 119110259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Trying to commit from FUs\n"); 119210259SAndrew.Bardsley@arm.com 119310259SAndrew.Bardsley@arm.com /* Try to commit from a functional unit */ 119410259SAndrew.Bardsley@arm.com /* Is the head inst of the expected inst's FU actually the 119510259SAndrew.Bardsley@arm.com * expected inst? */ 119610259SAndrew.Bardsley@arm.com QueuedInst &fu_inst = 119710259SAndrew.Bardsley@arm.com funcUnits[inst->fuIndex]->front(); 119810259SAndrew.Bardsley@arm.com InstSeqNum fu_inst_seq_num = fu_inst.inst->id.execSeqNum; 119910259SAndrew.Bardsley@arm.com 120010259SAndrew.Bardsley@arm.com if (fu_inst.inst->isBubble()) { 120110259SAndrew.Bardsley@arm.com /* No instruction ready */ 120210259SAndrew.Bardsley@arm.com completed_inst = false; 120310259SAndrew.Bardsley@arm.com } else if (fu_inst_seq_num != head_exec_seq_num) { 120410259SAndrew.Bardsley@arm.com /* Past instruction: we must have already executed it 120510259SAndrew.Bardsley@arm.com * in the same cycle and so the head inst isn't 120610259SAndrew.Bardsley@arm.com * actually at the end of its pipeline 120710259SAndrew.Bardsley@arm.com * Future instruction: handled above and only for 120810259SAndrew.Bardsley@arm.com * mem refs on their way to the LSQ */ 120911567Smitch.hayenga@arm.com } else if (fu_inst.inst->id == inst->id) { 121010259SAndrew.Bardsley@arm.com /* All instructions can be committed if they have the 121110259SAndrew.Bardsley@arm.com * right execSeqNum and there are no in-flight 121210259SAndrew.Bardsley@arm.com * mem insts before us */ 121310259SAndrew.Bardsley@arm.com try_to_commit = true; 121410259SAndrew.Bardsley@arm.com completed_inst = true; 121510259SAndrew.Bardsley@arm.com } 121610259SAndrew.Bardsley@arm.com } 121710259SAndrew.Bardsley@arm.com 121810259SAndrew.Bardsley@arm.com if (try_to_commit) { 121911567Smitch.hayenga@arm.com discard_inst = inst->id.streamSeqNum != 122011567Smitch.hayenga@arm.com ex_info.streamSeqNum || discard; 122110259SAndrew.Bardsley@arm.com 122210259SAndrew.Bardsley@arm.com /* Is this instruction discardable as its streamSeqNum 122310259SAndrew.Bardsley@arm.com * doesn't match? */ 122410259SAndrew.Bardsley@arm.com if (!discard_inst) { 122510259SAndrew.Bardsley@arm.com /* Try to commit or discard a non-memory instruction. 122610259SAndrew.Bardsley@arm.com * Memory ops are actually 'committed' from this FUs 122710259SAndrew.Bardsley@arm.com * and 'issued' into the memory system so we need to 122810259SAndrew.Bardsley@arm.com * account for them later (commit_was_mem_issue gets 122910259SAndrew.Bardsley@arm.com * set) */ 123010259SAndrew.Bardsley@arm.com if (inst->extraCommitDelayExpr) { 123110259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Evaluating expression for" 123210259SAndrew.Bardsley@arm.com " extra commit delay inst: %s\n", *inst); 123310259SAndrew.Bardsley@arm.com 123411567Smitch.hayenga@arm.com ThreadContext *thread = cpu.getContext(thread_id); 123510259SAndrew.Bardsley@arm.com 123610259SAndrew.Bardsley@arm.com TimingExprEvalContext context(inst->staticInst, 123710259SAndrew.Bardsley@arm.com thread, NULL); 123810259SAndrew.Bardsley@arm.com 123910259SAndrew.Bardsley@arm.com uint64_t extra_delay = inst->extraCommitDelayExpr-> 124010259SAndrew.Bardsley@arm.com eval(context); 124110259SAndrew.Bardsley@arm.com 124210259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Extra commit delay expr" 124310259SAndrew.Bardsley@arm.com " result: %d\n", extra_delay); 124410259SAndrew.Bardsley@arm.com 124510259SAndrew.Bardsley@arm.com if (extra_delay < 128) { 124610259SAndrew.Bardsley@arm.com inst->extraCommitDelay += Cycles(extra_delay); 124710259SAndrew.Bardsley@arm.com } else { 124810259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Extra commit delay was" 124910259SAndrew.Bardsley@arm.com " very long: %d\n", extra_delay); 125010259SAndrew.Bardsley@arm.com } 125110259SAndrew.Bardsley@arm.com inst->extraCommitDelayExpr = NULL; 125210259SAndrew.Bardsley@arm.com } 125310259SAndrew.Bardsley@arm.com 125410259SAndrew.Bardsley@arm.com /* Move the extraCommitDelay from the instruction 125510259SAndrew.Bardsley@arm.com * into the minimumCommitCycle */ 125610259SAndrew.Bardsley@arm.com if (inst->extraCommitDelay != Cycles(0)) { 125710259SAndrew.Bardsley@arm.com inst->minimumCommitCycle = cpu.curCycle() + 125810259SAndrew.Bardsley@arm.com inst->extraCommitDelay; 125910259SAndrew.Bardsley@arm.com inst->extraCommitDelay = Cycles(0); 126010259SAndrew.Bardsley@arm.com } 126110259SAndrew.Bardsley@arm.com 126210259SAndrew.Bardsley@arm.com /* @todo Think about making lastMemBarrier be 126310259SAndrew.Bardsley@arm.com * MAX_UINT_64 to avoid using 0 as a marker value */ 126410259SAndrew.Bardsley@arm.com if (!inst->isFault() && inst->isMemRef() && 126511567Smitch.hayenga@arm.com lsq.getLastMemBarrier(thread_id) < 126610259SAndrew.Bardsley@arm.com inst->id.execSeqNum && 126711567Smitch.hayenga@arm.com lsq.getLastMemBarrier(thread_id) != 0) 126810259SAndrew.Bardsley@arm.com { 126910259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Not committing inst: %s yet" 127010259SAndrew.Bardsley@arm.com " as there are incomplete barriers in flight\n", 127110259SAndrew.Bardsley@arm.com *inst); 127210259SAndrew.Bardsley@arm.com completed_inst = false; 127310259SAndrew.Bardsley@arm.com } else if (inst->minimumCommitCycle > now) { 127410259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Not committing inst: %s yet" 127510259SAndrew.Bardsley@arm.com " as it wants to be stalled for %d more cycles\n", 127610259SAndrew.Bardsley@arm.com *inst, inst->minimumCommitCycle - now); 127710259SAndrew.Bardsley@arm.com completed_inst = false; 127810259SAndrew.Bardsley@arm.com } else { 127910259SAndrew.Bardsley@arm.com completed_inst = commitInst(inst, 128010259SAndrew.Bardsley@arm.com early_memory_issue, branch, fault, 128110259SAndrew.Bardsley@arm.com committed_inst, issued_mem_ref); 128210259SAndrew.Bardsley@arm.com } 128310259SAndrew.Bardsley@arm.com } else { 128410259SAndrew.Bardsley@arm.com /* Discard instruction */ 128510259SAndrew.Bardsley@arm.com completed_inst = true; 128610259SAndrew.Bardsley@arm.com } 128710259SAndrew.Bardsley@arm.com 128810259SAndrew.Bardsley@arm.com if (completed_inst) { 128910259SAndrew.Bardsley@arm.com /* Allow the pipeline to advance. If the FU head 129010259SAndrew.Bardsley@arm.com * instruction wasn't the inFlightInsts head 129110259SAndrew.Bardsley@arm.com * but had already been committed, it would have 129210259SAndrew.Bardsley@arm.com * unstalled the pipeline before here */ 129311567Smitch.hayenga@arm.com if (inst->fuIndex != noCostFUIndex) { 129411567Smitch.hayenga@arm.com DPRINTF(MinorExecute, "Unstalling %d for inst %s\n", inst->fuIndex, inst->id); 129510259SAndrew.Bardsley@arm.com funcUnits[inst->fuIndex]->stalled = false; 129611567Smitch.hayenga@arm.com } 129710259SAndrew.Bardsley@arm.com } 129810259SAndrew.Bardsley@arm.com } 129910259SAndrew.Bardsley@arm.com } else { 130010259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "No instructions to commit\n"); 130110259SAndrew.Bardsley@arm.com completed_inst = false; 130210259SAndrew.Bardsley@arm.com } 130310259SAndrew.Bardsley@arm.com 130410259SAndrew.Bardsley@arm.com /* All discardable instructions must also be 'completed' by now */ 130510259SAndrew.Bardsley@arm.com assert(!(discard_inst && !completed_inst)); 130610259SAndrew.Bardsley@arm.com 130710259SAndrew.Bardsley@arm.com /* Instruction committed but was discarded due to streamSeqNum 130810259SAndrew.Bardsley@arm.com * mismatch */ 130910259SAndrew.Bardsley@arm.com if (discard_inst) { 131010259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Discarding inst: %s as its stream" 131110259SAndrew.Bardsley@arm.com " state was unexpected, expected: %d\n", 131211567Smitch.hayenga@arm.com *inst, ex_info.streamSeqNum); 131310259SAndrew.Bardsley@arm.com 131410259SAndrew.Bardsley@arm.com if (fault == NoFault) 131510259SAndrew.Bardsley@arm.com cpu.stats.numDiscardedOps++; 131610259SAndrew.Bardsley@arm.com } 131710259SAndrew.Bardsley@arm.com 131810259SAndrew.Bardsley@arm.com /* Mark the mem inst as being in the LSQ */ 131910259SAndrew.Bardsley@arm.com if (issued_mem_ref) { 132010259SAndrew.Bardsley@arm.com inst->fuIndex = 0; 132110259SAndrew.Bardsley@arm.com inst->inLSQ = true; 132210259SAndrew.Bardsley@arm.com } 132310259SAndrew.Bardsley@arm.com 132410259SAndrew.Bardsley@arm.com /* Pop issued (to LSQ) and discarded mem refs from the inFUMemInsts 132510259SAndrew.Bardsley@arm.com * as they've *definitely* exited the FUs */ 132610259SAndrew.Bardsley@arm.com if (completed_inst && inst->isMemRef()) { 132710259SAndrew.Bardsley@arm.com /* The MemRef could have been discarded from the FU or the memory 132810259SAndrew.Bardsley@arm.com * queue, so just check an FU instruction */ 132911567Smitch.hayenga@arm.com if (!ex_info.inFUMemInsts->empty() && 133011567Smitch.hayenga@arm.com ex_info.inFUMemInsts->front().inst == inst) 133110259SAndrew.Bardsley@arm.com { 133211567Smitch.hayenga@arm.com ex_info.inFUMemInsts->pop(); 133310259SAndrew.Bardsley@arm.com } 133410259SAndrew.Bardsley@arm.com } 133510259SAndrew.Bardsley@arm.com 133610259SAndrew.Bardsley@arm.com if (completed_inst && !(issued_mem_ref && fault == NoFault)) { 133710259SAndrew.Bardsley@arm.com /* Note that this includes discarded insts */ 133810259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Completed inst: %s\n", *inst); 133910259SAndrew.Bardsley@arm.com 134010259SAndrew.Bardsley@arm.com /* Got to the end of a full instruction? */ 134111567Smitch.hayenga@arm.com ex_info.lastCommitWasEndOfMacroop = inst->isFault() || 134210259SAndrew.Bardsley@arm.com inst->isLastOpInInst(); 134310259SAndrew.Bardsley@arm.com 134410259SAndrew.Bardsley@arm.com /* lastPredictionSeqNum is kept as a convenience to prevent its 134510259SAndrew.Bardsley@arm.com * value from changing too much on the minorview display */ 134611567Smitch.hayenga@arm.com ex_info.lastPredictionSeqNum = inst->id.predictionSeqNum; 134710259SAndrew.Bardsley@arm.com 134810259SAndrew.Bardsley@arm.com /* Finished with the inst, remove it from the inst queue and 134910259SAndrew.Bardsley@arm.com * clear its dependencies */ 135011567Smitch.hayenga@arm.com ex_info.inFlightInsts->pop(); 135110259SAndrew.Bardsley@arm.com 135210259SAndrew.Bardsley@arm.com /* Complete barriers in the LSQ/move to store buffer */ 135310259SAndrew.Bardsley@arm.com if (inst->isInst() && inst->staticInst->isMemBarrier()) { 135410259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Completing memory barrier" 135510259SAndrew.Bardsley@arm.com " inst: %s committed: %d\n", *inst, committed_inst); 135610259SAndrew.Bardsley@arm.com lsq.completeMemBarrierInst(inst, committed_inst); 135710259SAndrew.Bardsley@arm.com } 135810259SAndrew.Bardsley@arm.com 135911567Smitch.hayenga@arm.com scoreboard[thread_id].clearInstDests(inst, inst->isMemRef()); 136010259SAndrew.Bardsley@arm.com } 136110259SAndrew.Bardsley@arm.com 136210259SAndrew.Bardsley@arm.com /* Handle per-cycle instruction counting */ 136310259SAndrew.Bardsley@arm.com if (committed_inst) { 136410259SAndrew.Bardsley@arm.com bool is_no_cost_inst = inst->isNoCostInst(); 136510259SAndrew.Bardsley@arm.com 136610259SAndrew.Bardsley@arm.com /* Don't show no cost instructions as having taken a commit 136710259SAndrew.Bardsley@arm.com * slot */ 136810259SAndrew.Bardsley@arm.com if (DTRACE(MinorTrace) && !is_no_cost_inst) 136911567Smitch.hayenga@arm.com ex_info.instsBeingCommitted.insts[num_insts_committed] = inst; 137010259SAndrew.Bardsley@arm.com 137110259SAndrew.Bardsley@arm.com if (!is_no_cost_inst) 137210259SAndrew.Bardsley@arm.com num_insts_committed++; 137310259SAndrew.Bardsley@arm.com 137410259SAndrew.Bardsley@arm.com if (num_insts_committed == commitLimit) 137510259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Reached inst commit limit\n"); 137610259SAndrew.Bardsley@arm.com 137710259SAndrew.Bardsley@arm.com /* Re-set the time of the instruction if that's required for 137810259SAndrew.Bardsley@arm.com * tracing */ 137910259SAndrew.Bardsley@arm.com if (inst->traceData) { 138010259SAndrew.Bardsley@arm.com if (setTraceTimeOnCommit) 138110259SAndrew.Bardsley@arm.com inst->traceData->setWhen(curTick()); 138210259SAndrew.Bardsley@arm.com inst->traceData->dump(); 138310259SAndrew.Bardsley@arm.com } 138410259SAndrew.Bardsley@arm.com 138510259SAndrew.Bardsley@arm.com if (completed_mem_ref) 138610259SAndrew.Bardsley@arm.com num_mem_refs_committed++; 138710259SAndrew.Bardsley@arm.com 138810259SAndrew.Bardsley@arm.com if (num_mem_refs_committed == memoryCommitLimit) 138910259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Reached mem ref commit limit\n"); 139010259SAndrew.Bardsley@arm.com } 139110259SAndrew.Bardsley@arm.com } 139210259SAndrew.Bardsley@arm.com} 139310259SAndrew.Bardsley@arm.com 139410259SAndrew.Bardsley@arm.combool 139511567Smitch.hayenga@arm.comExecute::isInbetweenInsts(ThreadID thread_id) const 139610259SAndrew.Bardsley@arm.com{ 139711567Smitch.hayenga@arm.com return executeInfo[thread_id].lastCommitWasEndOfMacroop && 139810259SAndrew.Bardsley@arm.com !lsq.accessesInFlight(); 139910259SAndrew.Bardsley@arm.com} 140010259SAndrew.Bardsley@arm.com 140110259SAndrew.Bardsley@arm.comvoid 140210259SAndrew.Bardsley@arm.comExecute::evaluate() 140310259SAndrew.Bardsley@arm.com{ 140411567Smitch.hayenga@arm.com if (!inp.outputWire->isBubble()) 140511567Smitch.hayenga@arm.com inputBuffer[inp.outputWire->threadId].setTail(*inp.outputWire); 140611567Smitch.hayenga@arm.com 140710259SAndrew.Bardsley@arm.com BranchData &branch = *out.inputWire; 140810259SAndrew.Bardsley@arm.com 140911567Smitch.hayenga@arm.com unsigned int num_issued = 0; 141010259SAndrew.Bardsley@arm.com 141110259SAndrew.Bardsley@arm.com /* Do all the cycle-wise activities for dcachePort here to potentially 141210259SAndrew.Bardsley@arm.com * free up input spaces in the LSQ's requests queue */ 141310259SAndrew.Bardsley@arm.com lsq.step(); 141410259SAndrew.Bardsley@arm.com 141511567Smitch.hayenga@arm.com /* Check interrupts first. Will halt commit if interrupt found */ 141610259SAndrew.Bardsley@arm.com bool interrupted = false; 141711567Smitch.hayenga@arm.com ThreadID interrupt_tid = checkInterrupts(branch, interrupted); 141810259SAndrew.Bardsley@arm.com 141911567Smitch.hayenga@arm.com if (interrupt_tid != InvalidThreadID) { 142011567Smitch.hayenga@arm.com /* Signalling an interrupt this cycle, not issuing/committing from 142111567Smitch.hayenga@arm.com * any other threads */ 142210259SAndrew.Bardsley@arm.com } else if (!branch.isBubble()) { 142310259SAndrew.Bardsley@arm.com /* It's important that this is here to carry Fetch1 wakeups to Fetch1 142410259SAndrew.Bardsley@arm.com * without overwriting them */ 142510259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Execute skipping a cycle to allow old" 142610259SAndrew.Bardsley@arm.com " branch to complete\n"); 142710259SAndrew.Bardsley@arm.com } else { 142811567Smitch.hayenga@arm.com ThreadID commit_tid = getCommittingThread(); 142911567Smitch.hayenga@arm.com 143011567Smitch.hayenga@arm.com if (commit_tid != InvalidThreadID) { 143111567Smitch.hayenga@arm.com ExecuteThreadInfo& commit_info = executeInfo[commit_tid]; 143211567Smitch.hayenga@arm.com 143311567Smitch.hayenga@arm.com DPRINTF(MinorExecute, "Attempting to commit [tid:%d]\n", 143411567Smitch.hayenga@arm.com commit_tid); 143511567Smitch.hayenga@arm.com /* commit can set stalled flags observable to issue and so *must* be 143611567Smitch.hayenga@arm.com * called first */ 143711567Smitch.hayenga@arm.com if (commit_info.drainState != NotDraining) { 143811567Smitch.hayenga@arm.com if (commit_info.drainState == DrainCurrentInst) { 143911567Smitch.hayenga@arm.com /* Commit only micro-ops, don't kill anything else */ 144011567Smitch.hayenga@arm.com commit(commit_tid, true, false, branch); 144111567Smitch.hayenga@arm.com 144211567Smitch.hayenga@arm.com if (isInbetweenInsts(commit_tid)) 144311567Smitch.hayenga@arm.com setDrainState(commit_tid, DrainHaltFetch); 144411567Smitch.hayenga@arm.com 144511567Smitch.hayenga@arm.com /* Discard any generated branch */ 144611567Smitch.hayenga@arm.com branch = BranchData::bubble(); 144711567Smitch.hayenga@arm.com } else if (commit_info.drainState == DrainAllInsts) { 144811567Smitch.hayenga@arm.com /* Kill all instructions */ 144911567Smitch.hayenga@arm.com while (getInput(commit_tid)) 145011567Smitch.hayenga@arm.com popInput(commit_tid); 145111567Smitch.hayenga@arm.com commit(commit_tid, false, true, branch); 145211567Smitch.hayenga@arm.com } 145310259SAndrew.Bardsley@arm.com } else { 145411567Smitch.hayenga@arm.com /* Commit micro-ops only if interrupted. Otherwise, commit 145511567Smitch.hayenga@arm.com * anything you like */ 145611567Smitch.hayenga@arm.com DPRINTF(MinorExecute, "Committing micro-ops for interrupt[tid:%d]\n", 145711567Smitch.hayenga@arm.com commit_tid); 145811567Smitch.hayenga@arm.com bool only_commit_microops = interrupted && 145911567Smitch.hayenga@arm.com hasInterrupt(commit_tid); 146011567Smitch.hayenga@arm.com commit(commit_tid, only_commit_microops, false, branch); 146111567Smitch.hayenga@arm.com } 146211567Smitch.hayenga@arm.com 146311567Smitch.hayenga@arm.com /* Halt fetch, but don't do it until we have the current instruction in 146411567Smitch.hayenga@arm.com * the bag */ 146511567Smitch.hayenga@arm.com if (commit_info.drainState == DrainHaltFetch) { 146611567Smitch.hayenga@arm.com updateBranchData(commit_tid, BranchData::HaltFetch, 146711567Smitch.hayenga@arm.com MinorDynInst::bubble(), TheISA::PCState(0), branch); 146811567Smitch.hayenga@arm.com 146911567Smitch.hayenga@arm.com cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 147011567Smitch.hayenga@arm.com setDrainState(commit_tid, DrainAllInsts); 147110259SAndrew.Bardsley@arm.com } 147210259SAndrew.Bardsley@arm.com } 147311567Smitch.hayenga@arm.com ThreadID issue_tid = getIssuingThread(); 147411567Smitch.hayenga@arm.com /* This will issue merrily even when interrupted in the sure and 147511567Smitch.hayenga@arm.com * certain knowledge that the interrupt with change the stream */ 147611567Smitch.hayenga@arm.com if (issue_tid != InvalidThreadID) { 147711567Smitch.hayenga@arm.com DPRINTF(MinorExecute, "Attempting to issue [tid:%d]\n", 147811567Smitch.hayenga@arm.com issue_tid); 147911567Smitch.hayenga@arm.com num_issued = issue(issue_tid); 148010259SAndrew.Bardsley@arm.com } 148110259SAndrew.Bardsley@arm.com 148210259SAndrew.Bardsley@arm.com } 148310259SAndrew.Bardsley@arm.com 148411567Smitch.hayenga@arm.com /* Run logic to step functional units + decide if we are active on the next 148511567Smitch.hayenga@arm.com * clock cycle */ 148611567Smitch.hayenga@arm.com std::vector<MinorDynInstPtr> next_issuable_insts; 148710259SAndrew.Bardsley@arm.com bool can_issue_next = false; 148810259SAndrew.Bardsley@arm.com 148911567Smitch.hayenga@arm.com for (ThreadID tid = 0; tid < cpu.numThreads; tid++) { 149011567Smitch.hayenga@arm.com /* Find the next issuable instruction for each thread and see if it can 149111567Smitch.hayenga@arm.com be issued */ 149211567Smitch.hayenga@arm.com if (getInput(tid)) { 149311567Smitch.hayenga@arm.com unsigned int input_index = executeInfo[tid].inputIndex; 149411567Smitch.hayenga@arm.com MinorDynInstPtr inst = getInput(tid)->insts[input_index]; 149511567Smitch.hayenga@arm.com if (inst->isFault()) { 149611567Smitch.hayenga@arm.com can_issue_next = true; 149711567Smitch.hayenga@arm.com } else if (!inst->isBubble()) { 149811568Smitch.hayenga@arm.com next_issuable_insts.push_back(inst); 149910259SAndrew.Bardsley@arm.com } 150010259SAndrew.Bardsley@arm.com } 150110259SAndrew.Bardsley@arm.com } 150210259SAndrew.Bardsley@arm.com 150310259SAndrew.Bardsley@arm.com bool becoming_stalled = true; 150410259SAndrew.Bardsley@arm.com 150510259SAndrew.Bardsley@arm.com /* Advance the pipelines and note whether they still need to be 150611567Smitch.hayenga@arm.com * advanced */ 150710259SAndrew.Bardsley@arm.com for (unsigned int i = 0; i < numFuncUnits; i++) { 150810259SAndrew.Bardsley@arm.com FUPipeline *fu = funcUnits[i]; 150910259SAndrew.Bardsley@arm.com fu->advance(); 151010259SAndrew.Bardsley@arm.com 151111567Smitch.hayenga@arm.com /* If we need to tick again, the pipeline will have been left or set 151211567Smitch.hayenga@arm.com * to be unstalled */ 151311567Smitch.hayenga@arm.com if (fu->occupancy !=0 && !fu->stalled) 151410259SAndrew.Bardsley@arm.com becoming_stalled = false; 151510259SAndrew.Bardsley@arm.com 151611567Smitch.hayenga@arm.com /* Could we possibly issue the next instruction from any thread? 151711567Smitch.hayenga@arm.com * This is quite an expensive test and is only used to determine 151811567Smitch.hayenga@arm.com * if the CPU should remain active, only run it if we aren't sure 151911567Smitch.hayenga@arm.com * we are active next cycle yet */ 152011567Smitch.hayenga@arm.com for (auto inst : next_issuable_insts) { 152111567Smitch.hayenga@arm.com if (!fu->stalled && fu->provides(inst->staticInst->opClass()) && 152211567Smitch.hayenga@arm.com scoreboard[inst->id.threadId].canInstIssue(inst, 152311567Smitch.hayenga@arm.com NULL, NULL, cpu.curCycle() + Cycles(1), 152411567Smitch.hayenga@arm.com cpu.getContext(inst->id.threadId))) { 152511567Smitch.hayenga@arm.com can_issue_next = true; 152611567Smitch.hayenga@arm.com break; 152711567Smitch.hayenga@arm.com } 152810259SAndrew.Bardsley@arm.com } 152910259SAndrew.Bardsley@arm.com } 153010259SAndrew.Bardsley@arm.com 153110259SAndrew.Bardsley@arm.com bool head_inst_might_commit = false; 153210259SAndrew.Bardsley@arm.com 153310259SAndrew.Bardsley@arm.com /* Could the head in flight insts be committed */ 153411567Smitch.hayenga@arm.com for (auto const &info : executeInfo) { 153511567Smitch.hayenga@arm.com if (!info.inFlightInsts->empty()) { 153611567Smitch.hayenga@arm.com const QueuedInst &head_inst = info.inFlightInsts->front(); 153710259SAndrew.Bardsley@arm.com 153811567Smitch.hayenga@arm.com if (head_inst.inst->isNoCostInst()) { 153910259SAndrew.Bardsley@arm.com head_inst_might_commit = true; 154011567Smitch.hayenga@arm.com } else { 154111567Smitch.hayenga@arm.com FUPipeline *fu = funcUnits[head_inst.inst->fuIndex]; 154211567Smitch.hayenga@arm.com if ((fu->stalled && 154311567Smitch.hayenga@arm.com fu->front().inst->id == head_inst.inst->id) || 154411567Smitch.hayenga@arm.com lsq.findResponse(head_inst.inst)) 154511567Smitch.hayenga@arm.com { 154611567Smitch.hayenga@arm.com head_inst_might_commit = true; 154711567Smitch.hayenga@arm.com break; 154811567Smitch.hayenga@arm.com } 154910259SAndrew.Bardsley@arm.com } 155010259SAndrew.Bardsley@arm.com } 155110259SAndrew.Bardsley@arm.com } 155210259SAndrew.Bardsley@arm.com 155310259SAndrew.Bardsley@arm.com DPRINTF(Activity, "Need to tick num issued insts: %s%s%s%s%s%s\n", 155410259SAndrew.Bardsley@arm.com (num_issued != 0 ? " (issued some insts)" : ""), 155511567Smitch.hayenga@arm.com (becoming_stalled ? "(becoming stalled)" : "(not becoming stalled)"), 155610259SAndrew.Bardsley@arm.com (can_issue_next ? " (can issued next inst)" : ""), 155710259SAndrew.Bardsley@arm.com (head_inst_might_commit ? "(head inst might commit)" : ""), 155810259SAndrew.Bardsley@arm.com (lsq.needsToTick() ? " (LSQ needs to tick)" : ""), 155910259SAndrew.Bardsley@arm.com (interrupted ? " (interrupted)" : "")); 156010259SAndrew.Bardsley@arm.com 156110259SAndrew.Bardsley@arm.com bool need_to_tick = 156210259SAndrew.Bardsley@arm.com num_issued != 0 || /* Issued some insts this cycle */ 156310259SAndrew.Bardsley@arm.com !becoming_stalled || /* Some FU pipelines can still move */ 156410259SAndrew.Bardsley@arm.com can_issue_next || /* Can still issue a new inst */ 156510259SAndrew.Bardsley@arm.com head_inst_might_commit || /* Could possible commit the next inst */ 156610259SAndrew.Bardsley@arm.com lsq.needsToTick() || /* Must step the dcache port */ 156710259SAndrew.Bardsley@arm.com interrupted; /* There are pending interrupts */ 156810259SAndrew.Bardsley@arm.com 156910259SAndrew.Bardsley@arm.com if (!need_to_tick) { 157010259SAndrew.Bardsley@arm.com DPRINTF(Activity, "The next cycle might be skippable as there are no" 157110259SAndrew.Bardsley@arm.com " advanceable FUs\n"); 157210259SAndrew.Bardsley@arm.com } 157310259SAndrew.Bardsley@arm.com 157410259SAndrew.Bardsley@arm.com /* Wake up if we need to tick again */ 157510259SAndrew.Bardsley@arm.com if (need_to_tick) 157610259SAndrew.Bardsley@arm.com cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 157710259SAndrew.Bardsley@arm.com 157810259SAndrew.Bardsley@arm.com /* Note activity of following buffer */ 157910259SAndrew.Bardsley@arm.com if (!branch.isBubble()) 158010259SAndrew.Bardsley@arm.com cpu.activityRecorder->activity(); 158110259SAndrew.Bardsley@arm.com 158210259SAndrew.Bardsley@arm.com /* Make sure the input (if any left) is pushed */ 158311567Smitch.hayenga@arm.com if (!inp.outputWire->isBubble()) 158411567Smitch.hayenga@arm.com inputBuffer[inp.outputWire->threadId].pushTail(); 158510259SAndrew.Bardsley@arm.com} 158610259SAndrew.Bardsley@arm.com 158711567Smitch.hayenga@arm.comThreadID 158811567Smitch.hayenga@arm.comExecute::checkInterrupts(BranchData& branch, bool& interrupted) 158910259SAndrew.Bardsley@arm.com{ 159011567Smitch.hayenga@arm.com ThreadID tid = interruptPriority; 159111567Smitch.hayenga@arm.com /* Evaluate interrupts in round-robin based upon service */ 159211567Smitch.hayenga@arm.com do { 159311567Smitch.hayenga@arm.com /* Has an interrupt been signalled? This may not be acted on 159411567Smitch.hayenga@arm.com * straighaway so this is different from took_interrupt */ 159511567Smitch.hayenga@arm.com bool thread_interrupted = false; 159610259SAndrew.Bardsley@arm.com 159711567Smitch.hayenga@arm.com if (FullSystem && cpu.getInterruptController(tid)) { 159811567Smitch.hayenga@arm.com /* This is here because it seems that after drainResume the 159911567Smitch.hayenga@arm.com * interrupt controller isn't always set */ 160011567Smitch.hayenga@arm.com thread_interrupted = executeInfo[tid].drainState == NotDraining && 160111567Smitch.hayenga@arm.com isInterrupted(tid); 160211567Smitch.hayenga@arm.com interrupted = interrupted || thread_interrupted; 160311567Smitch.hayenga@arm.com } else { 160411567Smitch.hayenga@arm.com DPRINTF(MinorInterrupt, "No interrupt controller\n"); 160511567Smitch.hayenga@arm.com } 160611567Smitch.hayenga@arm.com DPRINTF(MinorInterrupt, "[tid:%d] thread_interrupted?=%d isInbetweenInsts?=%d\n", 160711567Smitch.hayenga@arm.com tid, thread_interrupted, isInbetweenInsts(tid)); 160811567Smitch.hayenga@arm.com /* Act on interrupts */ 160911567Smitch.hayenga@arm.com if (thread_interrupted && isInbetweenInsts(tid)) { 161011567Smitch.hayenga@arm.com if (takeInterrupt(tid, branch)) { 161111567Smitch.hayenga@arm.com interruptPriority = tid; 161211567Smitch.hayenga@arm.com return tid; 161311567Smitch.hayenga@arm.com } 161411567Smitch.hayenga@arm.com } else { 161511567Smitch.hayenga@arm.com tid = (tid + 1) % cpu.numThreads; 161611567Smitch.hayenga@arm.com } 161711567Smitch.hayenga@arm.com } while (tid != interruptPriority); 161810259SAndrew.Bardsley@arm.com 161911567Smitch.hayenga@arm.com return InvalidThreadID; 162011567Smitch.hayenga@arm.com} 162110259SAndrew.Bardsley@arm.com 162211567Smitch.hayenga@arm.combool 162311567Smitch.hayenga@arm.comExecute::hasInterrupt(ThreadID thread_id) 162411567Smitch.hayenga@arm.com{ 162511567Smitch.hayenga@arm.com if (FullSystem && cpu.getInterruptController(thread_id)) { 162611567Smitch.hayenga@arm.com return executeInfo[thread_id].drainState == NotDraining && 162711567Smitch.hayenga@arm.com isInterrupted(thread_id); 162810259SAndrew.Bardsley@arm.com } 162910259SAndrew.Bardsley@arm.com 163011567Smitch.hayenga@arm.com return false; 163110259SAndrew.Bardsley@arm.com} 163210259SAndrew.Bardsley@arm.com 163310259SAndrew.Bardsley@arm.comvoid 163410259SAndrew.Bardsley@arm.comExecute::minorTrace() const 163510259SAndrew.Bardsley@arm.com{ 163610259SAndrew.Bardsley@arm.com std::ostringstream insts; 163710259SAndrew.Bardsley@arm.com std::ostringstream stalled; 163810259SAndrew.Bardsley@arm.com 163911567Smitch.hayenga@arm.com executeInfo[0].instsBeingCommitted.reportData(insts); 164010259SAndrew.Bardsley@arm.com lsq.minorTrace(); 164111567Smitch.hayenga@arm.com inputBuffer[0].minorTrace(); 164211567Smitch.hayenga@arm.com scoreboard[0].minorTrace(); 164310259SAndrew.Bardsley@arm.com 164410259SAndrew.Bardsley@arm.com /* Report functional unit stalling in one string */ 164510259SAndrew.Bardsley@arm.com unsigned int i = 0; 164610259SAndrew.Bardsley@arm.com while (i < numFuncUnits) 164710259SAndrew.Bardsley@arm.com { 164810259SAndrew.Bardsley@arm.com stalled << (funcUnits[i]->stalled ? '1' : 'E'); 164910259SAndrew.Bardsley@arm.com i++; 165010259SAndrew.Bardsley@arm.com if (i != numFuncUnits) 165110259SAndrew.Bardsley@arm.com stalled << ','; 165210259SAndrew.Bardsley@arm.com } 165310259SAndrew.Bardsley@arm.com 165410259SAndrew.Bardsley@arm.com MINORTRACE("insts=%s inputIndex=%d streamSeqNum=%d" 165510259SAndrew.Bardsley@arm.com " stalled=%s drainState=%d isInbetweenInsts=%d\n", 165611567Smitch.hayenga@arm.com insts.str(), executeInfo[0].inputIndex, executeInfo[0].streamSeqNum, 165711567Smitch.hayenga@arm.com stalled.str(), executeInfo[0].drainState, isInbetweenInsts(0)); 165810259SAndrew.Bardsley@arm.com 165910259SAndrew.Bardsley@arm.com std::for_each(funcUnits.begin(), funcUnits.end(), 166010259SAndrew.Bardsley@arm.com std::mem_fun(&FUPipeline::minorTrace)); 166110259SAndrew.Bardsley@arm.com 166211567Smitch.hayenga@arm.com executeInfo[0].inFlightInsts->minorTrace(); 166311567Smitch.hayenga@arm.com executeInfo[0].inFUMemInsts->minorTrace(); 166411567Smitch.hayenga@arm.com} 166511567Smitch.hayenga@arm.com 166611567Smitch.hayenga@arm.cominline ThreadID 166711567Smitch.hayenga@arm.comExecute::getCommittingThread() 166811567Smitch.hayenga@arm.com{ 166911567Smitch.hayenga@arm.com std::vector<ThreadID> priority_list; 167011567Smitch.hayenga@arm.com 167111567Smitch.hayenga@arm.com switch (cpu.threadPolicy) { 167211567Smitch.hayenga@arm.com case Enums::SingleThreaded: 167311567Smitch.hayenga@arm.com return 0; 167411567Smitch.hayenga@arm.com case Enums::RoundRobin: 167511567Smitch.hayenga@arm.com priority_list = cpu.roundRobinPriority(commitPriority); 167611567Smitch.hayenga@arm.com break; 167711567Smitch.hayenga@arm.com case Enums::Random: 167811567Smitch.hayenga@arm.com priority_list = cpu.randomPriority(); 167911567Smitch.hayenga@arm.com break; 168011567Smitch.hayenga@arm.com default: 168111567Smitch.hayenga@arm.com panic("Invalid thread policy"); 168211567Smitch.hayenga@arm.com } 168311567Smitch.hayenga@arm.com 168411567Smitch.hayenga@arm.com for (auto tid : priority_list) { 168511567Smitch.hayenga@arm.com ExecuteThreadInfo &ex_info = executeInfo[tid]; 168613646Sqtt2@cornell.edu 168713646Sqtt2@cornell.edu bool is_thread_active = 168813646Sqtt2@cornell.edu cpu.getContext(tid)->status() == ThreadContext::Active; 168913646Sqtt2@cornell.edu bool can_commit_insts = !ex_info.inFlightInsts->empty() && 169013646Sqtt2@cornell.edu is_thread_active; 169113646Sqtt2@cornell.edu 169211567Smitch.hayenga@arm.com if (can_commit_insts) { 169311567Smitch.hayenga@arm.com QueuedInst *head_inflight_inst = &(ex_info.inFlightInsts->front()); 169411567Smitch.hayenga@arm.com MinorDynInstPtr inst = head_inflight_inst->inst; 169511567Smitch.hayenga@arm.com 169611567Smitch.hayenga@arm.com can_commit_insts = can_commit_insts && 169711567Smitch.hayenga@arm.com (!inst->inLSQ || (lsq.findResponse(inst) != NULL)); 169811567Smitch.hayenga@arm.com 169911567Smitch.hayenga@arm.com if (!inst->inLSQ) { 170011567Smitch.hayenga@arm.com bool can_transfer_mem_inst = false; 170111567Smitch.hayenga@arm.com if (!ex_info.inFUMemInsts->empty() && lsq.canRequest()) { 170211567Smitch.hayenga@arm.com const MinorDynInstPtr head_mem_ref_inst = 170311567Smitch.hayenga@arm.com ex_info.inFUMemInsts->front().inst; 170411567Smitch.hayenga@arm.com FUPipeline *fu = funcUnits[head_mem_ref_inst->fuIndex]; 170511567Smitch.hayenga@arm.com const MinorDynInstPtr &fu_inst = fu->front().inst; 170611567Smitch.hayenga@arm.com can_transfer_mem_inst = 170711567Smitch.hayenga@arm.com !fu_inst->isBubble() && 170811567Smitch.hayenga@arm.com fu_inst->id.threadId == tid && 170911567Smitch.hayenga@arm.com !fu_inst->inLSQ && 171011567Smitch.hayenga@arm.com fu_inst->canEarlyIssue && 171111567Smitch.hayenga@arm.com inst->id.execSeqNum > fu_inst->instToWaitFor; 171211567Smitch.hayenga@arm.com } 171311567Smitch.hayenga@arm.com 171411567Smitch.hayenga@arm.com bool can_execute_fu_inst = inst->fuIndex == noCostFUIndex; 171511567Smitch.hayenga@arm.com if (can_commit_insts && !can_transfer_mem_inst && 171611567Smitch.hayenga@arm.com inst->fuIndex != noCostFUIndex) 171711567Smitch.hayenga@arm.com { 171811567Smitch.hayenga@arm.com QueuedInst& fu_inst = funcUnits[inst->fuIndex]->front(); 171911567Smitch.hayenga@arm.com can_execute_fu_inst = !fu_inst.inst->isBubble() && 172011567Smitch.hayenga@arm.com fu_inst.inst->id == inst->id; 172111567Smitch.hayenga@arm.com } 172211567Smitch.hayenga@arm.com 172311567Smitch.hayenga@arm.com can_commit_insts = can_commit_insts && 172411567Smitch.hayenga@arm.com (can_transfer_mem_inst || can_execute_fu_inst); 172511567Smitch.hayenga@arm.com } 172611567Smitch.hayenga@arm.com } 172711567Smitch.hayenga@arm.com 172811567Smitch.hayenga@arm.com 172911567Smitch.hayenga@arm.com if (can_commit_insts) { 173011567Smitch.hayenga@arm.com commitPriority = tid; 173111567Smitch.hayenga@arm.com return tid; 173211567Smitch.hayenga@arm.com } 173311567Smitch.hayenga@arm.com } 173411567Smitch.hayenga@arm.com 173511567Smitch.hayenga@arm.com return InvalidThreadID; 173611567Smitch.hayenga@arm.com} 173711567Smitch.hayenga@arm.com 173811567Smitch.hayenga@arm.cominline ThreadID 173911567Smitch.hayenga@arm.comExecute::getIssuingThread() 174011567Smitch.hayenga@arm.com{ 174111567Smitch.hayenga@arm.com std::vector<ThreadID> priority_list; 174211567Smitch.hayenga@arm.com 174311567Smitch.hayenga@arm.com switch (cpu.threadPolicy) { 174411567Smitch.hayenga@arm.com case Enums::SingleThreaded: 174511567Smitch.hayenga@arm.com return 0; 174611567Smitch.hayenga@arm.com case Enums::RoundRobin: 174711567Smitch.hayenga@arm.com priority_list = cpu.roundRobinPriority(issuePriority); 174811567Smitch.hayenga@arm.com break; 174911567Smitch.hayenga@arm.com case Enums::Random: 175011567Smitch.hayenga@arm.com priority_list = cpu.randomPriority(); 175111567Smitch.hayenga@arm.com break; 175211567Smitch.hayenga@arm.com default: 175311567Smitch.hayenga@arm.com panic("Invalid thread scheduling policy."); 175411567Smitch.hayenga@arm.com } 175511567Smitch.hayenga@arm.com 175611567Smitch.hayenga@arm.com for (auto tid : priority_list) { 175713646Sqtt2@cornell.edu if (cpu.getContext(tid)->status() == ThreadContext::Active && 175813646Sqtt2@cornell.edu getInput(tid)) { 175911567Smitch.hayenga@arm.com issuePriority = tid; 176011567Smitch.hayenga@arm.com return tid; 176111567Smitch.hayenga@arm.com } 176211567Smitch.hayenga@arm.com } 176311567Smitch.hayenga@arm.com 176411567Smitch.hayenga@arm.com return InvalidThreadID; 176510259SAndrew.Bardsley@arm.com} 176610259SAndrew.Bardsley@arm.com 176710259SAndrew.Bardsley@arm.comvoid 176810259SAndrew.Bardsley@arm.comExecute::drainResume() 176910259SAndrew.Bardsley@arm.com{ 177010259SAndrew.Bardsley@arm.com DPRINTF(Drain, "MinorExecute drainResume\n"); 177110259SAndrew.Bardsley@arm.com 177211567Smitch.hayenga@arm.com for (ThreadID tid = 0; tid < cpu.numThreads; tid++) { 177311567Smitch.hayenga@arm.com setDrainState(tid, NotDraining); 177411567Smitch.hayenga@arm.com } 177510259SAndrew.Bardsley@arm.com 177610259SAndrew.Bardsley@arm.com cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 177710259SAndrew.Bardsley@arm.com} 177810259SAndrew.Bardsley@arm.com 177910259SAndrew.Bardsley@arm.comstd::ostream &operator <<(std::ostream &os, Execute::DrainState state) 178010259SAndrew.Bardsley@arm.com{ 178110259SAndrew.Bardsley@arm.com switch (state) 178210259SAndrew.Bardsley@arm.com { 178310259SAndrew.Bardsley@arm.com case Execute::NotDraining: 178410259SAndrew.Bardsley@arm.com os << "NotDraining"; 178510259SAndrew.Bardsley@arm.com break; 178610259SAndrew.Bardsley@arm.com case Execute::DrainCurrentInst: 178710259SAndrew.Bardsley@arm.com os << "DrainCurrentInst"; 178810259SAndrew.Bardsley@arm.com break; 178910259SAndrew.Bardsley@arm.com case Execute::DrainHaltFetch: 179010259SAndrew.Bardsley@arm.com os << "DrainHaltFetch"; 179110259SAndrew.Bardsley@arm.com break; 179210259SAndrew.Bardsley@arm.com case Execute::DrainAllInsts: 179310259SAndrew.Bardsley@arm.com os << "DrainAllInsts"; 179410259SAndrew.Bardsley@arm.com break; 179510259SAndrew.Bardsley@arm.com default: 179610259SAndrew.Bardsley@arm.com os << "Drain-" << static_cast<int>(state); 179710259SAndrew.Bardsley@arm.com break; 179810259SAndrew.Bardsley@arm.com } 179910259SAndrew.Bardsley@arm.com 180010259SAndrew.Bardsley@arm.com return os; 180110259SAndrew.Bardsley@arm.com} 180210259SAndrew.Bardsley@arm.com 180310259SAndrew.Bardsley@arm.comvoid 180411567Smitch.hayenga@arm.comExecute::setDrainState(ThreadID thread_id, DrainState state) 180510259SAndrew.Bardsley@arm.com{ 180611567Smitch.hayenga@arm.com DPRINTF(Drain, "setDrainState[%d]: %s\n", thread_id, state); 180711567Smitch.hayenga@arm.com executeInfo[thread_id].drainState = state; 180810259SAndrew.Bardsley@arm.com} 180910259SAndrew.Bardsley@arm.com 181010259SAndrew.Bardsley@arm.comunsigned int 181110259SAndrew.Bardsley@arm.comExecute::drain() 181210259SAndrew.Bardsley@arm.com{ 181310259SAndrew.Bardsley@arm.com DPRINTF(Drain, "MinorExecute drain\n"); 181410259SAndrew.Bardsley@arm.com 181511567Smitch.hayenga@arm.com for (ThreadID tid = 0; tid < cpu.numThreads; tid++) { 181611567Smitch.hayenga@arm.com if (executeInfo[tid].drainState == NotDraining) { 181711567Smitch.hayenga@arm.com cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 181810259SAndrew.Bardsley@arm.com 181911567Smitch.hayenga@arm.com /* Go to DrainCurrentInst if we're between microops 182011567Smitch.hayenga@arm.com * or waiting on an unbufferable memory operation. 182111567Smitch.hayenga@arm.com * Otherwise we can go straight to DrainHaltFetch 182211567Smitch.hayenga@arm.com */ 182311567Smitch.hayenga@arm.com if (isInbetweenInsts(tid)) 182411567Smitch.hayenga@arm.com setDrainState(tid, DrainHaltFetch); 182511567Smitch.hayenga@arm.com else 182611567Smitch.hayenga@arm.com setDrainState(tid, DrainCurrentInst); 182711567Smitch.hayenga@arm.com } 182810259SAndrew.Bardsley@arm.com } 182910259SAndrew.Bardsley@arm.com return (isDrained() ? 0 : 1); 183010259SAndrew.Bardsley@arm.com} 183110259SAndrew.Bardsley@arm.com 183210259SAndrew.Bardsley@arm.combool 183310259SAndrew.Bardsley@arm.comExecute::isDrained() 183410259SAndrew.Bardsley@arm.com{ 183511567Smitch.hayenga@arm.com if (!lsq.isDrained()) 183611567Smitch.hayenga@arm.com return false; 183711567Smitch.hayenga@arm.com 183811567Smitch.hayenga@arm.com for (ThreadID tid = 0; tid < cpu.numThreads; tid++) { 183911568Smitch.hayenga@arm.com if (!inputBuffer[tid].empty() || 184011567Smitch.hayenga@arm.com !executeInfo[tid].inFlightInsts->empty()) { 184111567Smitch.hayenga@arm.com 184211567Smitch.hayenga@arm.com return false; 184311567Smitch.hayenga@arm.com } 184411567Smitch.hayenga@arm.com } 184511567Smitch.hayenga@arm.com 184611567Smitch.hayenga@arm.com return true; 184710259SAndrew.Bardsley@arm.com} 184810259SAndrew.Bardsley@arm.com 184910259SAndrew.Bardsley@arm.comExecute::~Execute() 185010259SAndrew.Bardsley@arm.com{ 185110259SAndrew.Bardsley@arm.com for (unsigned int i = 0; i < numFuncUnits; i++) 185210259SAndrew.Bardsley@arm.com delete funcUnits[i]; 185310259SAndrew.Bardsley@arm.com 185411567Smitch.hayenga@arm.com for (ThreadID tid = 0; tid < cpu.numThreads; tid++) 185511567Smitch.hayenga@arm.com delete executeInfo[tid].inFlightInsts; 185610259SAndrew.Bardsley@arm.com} 185710259SAndrew.Bardsley@arm.com 185810259SAndrew.Bardsley@arm.combool 185910259SAndrew.Bardsley@arm.comExecute::instIsRightStream(MinorDynInstPtr inst) 186010259SAndrew.Bardsley@arm.com{ 186111567Smitch.hayenga@arm.com return inst->id.streamSeqNum == executeInfo[inst->id.threadId].streamSeqNum; 186210259SAndrew.Bardsley@arm.com} 186310259SAndrew.Bardsley@arm.com 186410259SAndrew.Bardsley@arm.combool 186510259SAndrew.Bardsley@arm.comExecute::instIsHeadInst(MinorDynInstPtr inst) 186610259SAndrew.Bardsley@arm.com{ 186710259SAndrew.Bardsley@arm.com bool ret = false; 186810259SAndrew.Bardsley@arm.com 186911567Smitch.hayenga@arm.com if (!executeInfo[inst->id.threadId].inFlightInsts->empty()) 187011567Smitch.hayenga@arm.com ret = executeInfo[inst->id.threadId].inFlightInsts->front().inst->id == inst->id; 187110259SAndrew.Bardsley@arm.com 187210259SAndrew.Bardsley@arm.com return ret; 187310259SAndrew.Bardsley@arm.com} 187410259SAndrew.Bardsley@arm.com 187510259SAndrew.Bardsley@arm.comMinorCPU::MinorCPUPort & 187610259SAndrew.Bardsley@arm.comExecute::getDcachePort() 187710259SAndrew.Bardsley@arm.com{ 187810259SAndrew.Bardsley@arm.com return lsq.getDcachePort(); 187910259SAndrew.Bardsley@arm.com} 188010259SAndrew.Bardsley@arm.com 188110259SAndrew.Bardsley@arm.com} 1882