execute.cc revision 13632
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 25110259SAndrew.Bardsley@arm.com if (inst->predictedTaken && !force_branch) { 25210259SAndrew.Bardsley@arm.com /* Predicted to branch */ 25310259SAndrew.Bardsley@arm.com if (!must_branch) { 25410259SAndrew.Bardsley@arm.com /* No branch was taken, change stream to get us back to the 25510259SAndrew.Bardsley@arm.com * intended PC value */ 25610259SAndrew.Bardsley@arm.com DPRINTF(Branch, "Predicted a branch from 0x%x to 0x%x but" 25710259SAndrew.Bardsley@arm.com " none happened inst: %s\n", 25810259SAndrew.Bardsley@arm.com inst->pc.instAddr(), inst->predictedTarget.instAddr(), *inst); 25910259SAndrew.Bardsley@arm.com 26010259SAndrew.Bardsley@arm.com reason = BranchData::BadlyPredictedBranch; 26110259SAndrew.Bardsley@arm.com } else if (inst->predictedTarget == target) { 26210259SAndrew.Bardsley@arm.com /* Branch prediction got the right target, kill the branch and 26310259SAndrew.Bardsley@arm.com * carry on. 26410259SAndrew.Bardsley@arm.com * Note that this information to the branch predictor might get 26510259SAndrew.Bardsley@arm.com * overwritten by a "real" branch during this cycle */ 26610259SAndrew.Bardsley@arm.com DPRINTF(Branch, "Predicted a branch from 0x%x to 0x%x correctly" 26710259SAndrew.Bardsley@arm.com " inst: %s\n", 26810259SAndrew.Bardsley@arm.com inst->pc.instAddr(), inst->predictedTarget.instAddr(), *inst); 26910259SAndrew.Bardsley@arm.com 27010259SAndrew.Bardsley@arm.com reason = BranchData::CorrectlyPredictedBranch; 27110259SAndrew.Bardsley@arm.com } else { 27210259SAndrew.Bardsley@arm.com /* Branch prediction got the wrong target */ 27310259SAndrew.Bardsley@arm.com DPRINTF(Branch, "Predicted a branch from 0x%x to 0x%x" 27410366Sandreas.hansson@arm.com " but got the wrong target (actual: 0x%x) inst: %s\n", 27510366Sandreas.hansson@arm.com inst->pc.instAddr(), inst->predictedTarget.instAddr(), 27610366Sandreas.hansson@arm.com target.instAddr(), *inst); 27710259SAndrew.Bardsley@arm.com 27810259SAndrew.Bardsley@arm.com reason = BranchData::BadlyPredictedBranchTarget; 27910259SAndrew.Bardsley@arm.com } 28010259SAndrew.Bardsley@arm.com } else if (must_branch) { 28110259SAndrew.Bardsley@arm.com /* Unpredicted branch */ 28210259SAndrew.Bardsley@arm.com DPRINTF(Branch, "Unpredicted branch from 0x%x to 0x%x inst: %s\n", 28310259SAndrew.Bardsley@arm.com inst->pc.instAddr(), target.instAddr(), *inst); 28410259SAndrew.Bardsley@arm.com 28510259SAndrew.Bardsley@arm.com reason = BranchData::UnpredictedBranch; 28610259SAndrew.Bardsley@arm.com } else { 28710259SAndrew.Bardsley@arm.com /* No branch at all */ 28810259SAndrew.Bardsley@arm.com reason = BranchData::NoBranch; 28910259SAndrew.Bardsley@arm.com } 29010259SAndrew.Bardsley@arm.com 29111567Smitch.hayenga@arm.com updateBranchData(inst->id.threadId, reason, inst, target, branch); 29210259SAndrew.Bardsley@arm.com} 29310259SAndrew.Bardsley@arm.com 29410259SAndrew.Bardsley@arm.comvoid 29510259SAndrew.Bardsley@arm.comExecute::updateBranchData( 29611567Smitch.hayenga@arm.com ThreadID tid, 29710259SAndrew.Bardsley@arm.com BranchData::Reason reason, 29810259SAndrew.Bardsley@arm.com MinorDynInstPtr inst, const TheISA::PCState &target, 29910259SAndrew.Bardsley@arm.com BranchData &branch) 30010259SAndrew.Bardsley@arm.com{ 30110259SAndrew.Bardsley@arm.com if (reason != BranchData::NoBranch) { 30210259SAndrew.Bardsley@arm.com /* Bump up the stream sequence number on a real branch*/ 30310259SAndrew.Bardsley@arm.com if (BranchData::isStreamChange(reason)) 30411567Smitch.hayenga@arm.com executeInfo[tid].streamSeqNum++; 30510259SAndrew.Bardsley@arm.com 30610259SAndrew.Bardsley@arm.com /* Branches (even mis-predictions) don't change the predictionSeqNum, 30710259SAndrew.Bardsley@arm.com * just the streamSeqNum */ 30811567Smitch.hayenga@arm.com branch = BranchData(reason, tid, 30911567Smitch.hayenga@arm.com executeInfo[tid].streamSeqNum, 31010259SAndrew.Bardsley@arm.com /* Maintaining predictionSeqNum if there's no inst is just a 31110259SAndrew.Bardsley@arm.com * courtesy and looks better on minorview */ 31211567Smitch.hayenga@arm.com (inst->isBubble() ? executeInfo[tid].lastPredictionSeqNum 31310259SAndrew.Bardsley@arm.com : inst->id.predictionSeqNum), 31410259SAndrew.Bardsley@arm.com target, inst); 31510259SAndrew.Bardsley@arm.com 31610259SAndrew.Bardsley@arm.com DPRINTF(Branch, "Branch data signalled: %s\n", branch); 31710259SAndrew.Bardsley@arm.com } 31810259SAndrew.Bardsley@arm.com} 31910259SAndrew.Bardsley@arm.com 32010259SAndrew.Bardsley@arm.comvoid 32110259SAndrew.Bardsley@arm.comExecute::handleMemResponse(MinorDynInstPtr inst, 32210259SAndrew.Bardsley@arm.com LSQ::LSQRequestPtr response, BranchData &branch, Fault &fault) 32310259SAndrew.Bardsley@arm.com{ 32410259SAndrew.Bardsley@arm.com ThreadID thread_id = inst->id.threadId; 32510259SAndrew.Bardsley@arm.com ThreadContext *thread = cpu.getContext(thread_id); 32610259SAndrew.Bardsley@arm.com 32710259SAndrew.Bardsley@arm.com ExecContext context(cpu, *cpu.threads[thread_id], *this, inst); 32810259SAndrew.Bardsley@arm.com 32910259SAndrew.Bardsley@arm.com PacketPtr packet = response->packet; 33010259SAndrew.Bardsley@arm.com 33110259SAndrew.Bardsley@arm.com bool is_load = inst->staticInst->isLoad(); 33210259SAndrew.Bardsley@arm.com bool is_store = inst->staticInst->isStore(); 33310259SAndrew.Bardsley@arm.com bool is_prefetch = inst->staticInst->isDataPrefetch(); 33410259SAndrew.Bardsley@arm.com 33510259SAndrew.Bardsley@arm.com /* If true, the trace's predicate value will be taken from the exec 33610259SAndrew.Bardsley@arm.com * context predicate, otherwise, it will be set to false */ 33710259SAndrew.Bardsley@arm.com bool use_context_predicate = true; 33810259SAndrew.Bardsley@arm.com 33910259SAndrew.Bardsley@arm.com if (response->fault != NoFault) { 34010259SAndrew.Bardsley@arm.com /* Invoke memory faults. */ 34110259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Completing fault from DTLB access: %s\n", 34210259SAndrew.Bardsley@arm.com response->fault->name()); 34310259SAndrew.Bardsley@arm.com 34410259SAndrew.Bardsley@arm.com if (inst->staticInst->isPrefetch()) { 34510259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Not taking fault on prefetch: %s\n", 34610259SAndrew.Bardsley@arm.com response->fault->name()); 34710259SAndrew.Bardsley@arm.com 34810259SAndrew.Bardsley@arm.com /* Don't assign to fault */ 34910259SAndrew.Bardsley@arm.com } else { 35010259SAndrew.Bardsley@arm.com /* Take the fault raised during the TLB/memory access */ 35110259SAndrew.Bardsley@arm.com fault = response->fault; 35210259SAndrew.Bardsley@arm.com 35310259SAndrew.Bardsley@arm.com fault->invoke(thread, inst->staticInst); 35410259SAndrew.Bardsley@arm.com } 35510259SAndrew.Bardsley@arm.com } else if (!packet) { 35610259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Completing failed request inst: %s\n", 35710259SAndrew.Bardsley@arm.com *inst); 35810259SAndrew.Bardsley@arm.com use_context_predicate = false; 35910259SAndrew.Bardsley@arm.com } else if (packet->isError()) { 36010259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Trying to commit error response: %s\n", 36110259SAndrew.Bardsley@arm.com *inst); 36210259SAndrew.Bardsley@arm.com 36310259SAndrew.Bardsley@arm.com fatal("Received error response packet for inst: %s\n", *inst); 36410259SAndrew.Bardsley@arm.com } else if (is_store || is_load || is_prefetch) { 36510259SAndrew.Bardsley@arm.com assert(packet); 36610259SAndrew.Bardsley@arm.com 36710259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Memory response inst: %s addr: 0x%x size: %d\n", 36810259SAndrew.Bardsley@arm.com *inst, packet->getAddr(), packet->getSize()); 36910259SAndrew.Bardsley@arm.com 37010259SAndrew.Bardsley@arm.com if (is_load && packet->getSize() > 0) { 37110259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Memory data[0]: 0x%x\n", 37210563Sandreas.hansson@arm.com static_cast<unsigned int>(packet->getConstPtr<uint8_t>()[0])); 37310259SAndrew.Bardsley@arm.com } 37410259SAndrew.Bardsley@arm.com 37510259SAndrew.Bardsley@arm.com /* Complete the memory access instruction */ 37610259SAndrew.Bardsley@arm.com fault = inst->staticInst->completeAcc(packet, &context, 37710259SAndrew.Bardsley@arm.com inst->traceData); 37810259SAndrew.Bardsley@arm.com 37910259SAndrew.Bardsley@arm.com if (fault != NoFault) { 38010259SAndrew.Bardsley@arm.com /* Invoke fault created by instruction completion */ 38110259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Fault in memory completeAcc: %s\n", 38210259SAndrew.Bardsley@arm.com fault->name()); 38310259SAndrew.Bardsley@arm.com fault->invoke(thread, inst->staticInst); 38410259SAndrew.Bardsley@arm.com } else { 38510259SAndrew.Bardsley@arm.com /* Stores need to be pushed into the store buffer to finish 38610259SAndrew.Bardsley@arm.com * them off */ 38710259SAndrew.Bardsley@arm.com if (response->needsToBeSentToStoreBuffer()) 38810259SAndrew.Bardsley@arm.com lsq.sendStoreToStoreBuffer(response); 38910259SAndrew.Bardsley@arm.com } 39010259SAndrew.Bardsley@arm.com } else { 39110259SAndrew.Bardsley@arm.com fatal("There should only ever be reads, " 39210259SAndrew.Bardsley@arm.com "writes or faults at this point\n"); 39310259SAndrew.Bardsley@arm.com } 39410259SAndrew.Bardsley@arm.com 39510259SAndrew.Bardsley@arm.com lsq.popResponse(response); 39610259SAndrew.Bardsley@arm.com 39710259SAndrew.Bardsley@arm.com if (inst->traceData) { 39810259SAndrew.Bardsley@arm.com inst->traceData->setPredicate((use_context_predicate ? 39910259SAndrew.Bardsley@arm.com context.readPredicate() : false)); 40010259SAndrew.Bardsley@arm.com } 40110259SAndrew.Bardsley@arm.com 40210259SAndrew.Bardsley@arm.com doInstCommitAccounting(inst); 40310259SAndrew.Bardsley@arm.com 40410259SAndrew.Bardsley@arm.com /* Generate output to account for branches */ 40510259SAndrew.Bardsley@arm.com tryToBranch(inst, fault, branch); 40610259SAndrew.Bardsley@arm.com} 40710259SAndrew.Bardsley@arm.com 40810259SAndrew.Bardsley@arm.combool 40910259SAndrew.Bardsley@arm.comExecute::isInterrupted(ThreadID thread_id) const 41010259SAndrew.Bardsley@arm.com{ 41110259SAndrew.Bardsley@arm.com return cpu.checkInterrupts(cpu.getContext(thread_id)); 41210259SAndrew.Bardsley@arm.com} 41310259SAndrew.Bardsley@arm.com 41410259SAndrew.Bardsley@arm.combool 41510259SAndrew.Bardsley@arm.comExecute::takeInterrupt(ThreadID thread_id, BranchData &branch) 41610259SAndrew.Bardsley@arm.com{ 41710259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Considering interrupt status from PC: %s\n", 41810259SAndrew.Bardsley@arm.com cpu.getContext(thread_id)->pcState()); 41910259SAndrew.Bardsley@arm.com 42011150Smitch.hayenga@arm.com Fault interrupt = cpu.getInterruptController(thread_id)->getInterrupt 42110259SAndrew.Bardsley@arm.com (cpu.getContext(thread_id)); 42210259SAndrew.Bardsley@arm.com 42310259SAndrew.Bardsley@arm.com if (interrupt != NoFault) { 42410259SAndrew.Bardsley@arm.com /* The interrupt *must* set pcState */ 42511150Smitch.hayenga@arm.com cpu.getInterruptController(thread_id)->updateIntrInfo 42610259SAndrew.Bardsley@arm.com (cpu.getContext(thread_id)); 42710259SAndrew.Bardsley@arm.com interrupt->invoke(cpu.getContext(thread_id)); 42810259SAndrew.Bardsley@arm.com 42910259SAndrew.Bardsley@arm.com assert(!lsq.accessesInFlight()); 43010259SAndrew.Bardsley@arm.com 43110259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Invoking interrupt: %s to PC: %s\n", 43210259SAndrew.Bardsley@arm.com interrupt->name(), cpu.getContext(thread_id)->pcState()); 43310259SAndrew.Bardsley@arm.com 43410259SAndrew.Bardsley@arm.com /* Assume that an interrupt *must* cause a branch. Assert this? */ 43510259SAndrew.Bardsley@arm.com 43611567Smitch.hayenga@arm.com updateBranchData(thread_id, BranchData::Interrupt, 43711567Smitch.hayenga@arm.com MinorDynInst::bubble(), cpu.getContext(thread_id)->pcState(), 43811567Smitch.hayenga@arm.com branch); 43910259SAndrew.Bardsley@arm.com } 44010259SAndrew.Bardsley@arm.com 44110259SAndrew.Bardsley@arm.com return interrupt != NoFault; 44210259SAndrew.Bardsley@arm.com} 44310259SAndrew.Bardsley@arm.com 44410259SAndrew.Bardsley@arm.combool 44510259SAndrew.Bardsley@arm.comExecute::executeMemRefInst(MinorDynInstPtr inst, BranchData &branch, 44610259SAndrew.Bardsley@arm.com bool &passed_predicate, Fault &fault) 44710259SAndrew.Bardsley@arm.com{ 44810259SAndrew.Bardsley@arm.com bool issued = false; 44910259SAndrew.Bardsley@arm.com 45010259SAndrew.Bardsley@arm.com /* Set to true if the mem op. is issued and sent to the mem system */ 45110259SAndrew.Bardsley@arm.com passed_predicate = false; 45210259SAndrew.Bardsley@arm.com 45310259SAndrew.Bardsley@arm.com if (!lsq.canRequest()) { 45410259SAndrew.Bardsley@arm.com /* Not acting on instruction yet as the memory 45510259SAndrew.Bardsley@arm.com * queues are full */ 45610259SAndrew.Bardsley@arm.com issued = false; 45710259SAndrew.Bardsley@arm.com } else { 45810259SAndrew.Bardsley@arm.com ThreadContext *thread = cpu.getContext(inst->id.threadId); 45910259SAndrew.Bardsley@arm.com TheISA::PCState old_pc = thread->pcState(); 46010259SAndrew.Bardsley@arm.com 46110259SAndrew.Bardsley@arm.com ExecContext context(cpu, *cpu.threads[inst->id.threadId], 46210259SAndrew.Bardsley@arm.com *this, inst); 46310259SAndrew.Bardsley@arm.com 46410259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Initiating memRef inst: %s\n", *inst); 46510259SAndrew.Bardsley@arm.com 46610259SAndrew.Bardsley@arm.com Fault init_fault = inst->staticInst->initiateAcc(&context, 46710259SAndrew.Bardsley@arm.com inst->traceData); 46810259SAndrew.Bardsley@arm.com 46910259SAndrew.Bardsley@arm.com if (init_fault != NoFault) { 47010259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Fault on memory inst: %s" 47110259SAndrew.Bardsley@arm.com " initiateAcc: %s\n", *inst, init_fault->name()); 47210259SAndrew.Bardsley@arm.com fault = init_fault; 47310259SAndrew.Bardsley@arm.com } else { 47410259SAndrew.Bardsley@arm.com /* Only set this if the instruction passed its 47510259SAndrew.Bardsley@arm.com * predicate */ 47610259SAndrew.Bardsley@arm.com passed_predicate = context.readPredicate(); 47710259SAndrew.Bardsley@arm.com 47810259SAndrew.Bardsley@arm.com /* Set predicate in tracing */ 47910259SAndrew.Bardsley@arm.com if (inst->traceData) 48010259SAndrew.Bardsley@arm.com inst->traceData->setPredicate(passed_predicate); 48110259SAndrew.Bardsley@arm.com 48210259SAndrew.Bardsley@arm.com /* If the instruction didn't pass its predicate (and so will not 48310259SAndrew.Bardsley@arm.com * progress from here) Try to branch to correct and branch 48410259SAndrew.Bardsley@arm.com * mis-prediction. */ 48510259SAndrew.Bardsley@arm.com if (!passed_predicate) { 48610259SAndrew.Bardsley@arm.com /* Leave it up to commit to handle the fault */ 48710259SAndrew.Bardsley@arm.com lsq.pushFailedRequest(inst); 48810259SAndrew.Bardsley@arm.com } 48910259SAndrew.Bardsley@arm.com } 49010259SAndrew.Bardsley@arm.com 49110259SAndrew.Bardsley@arm.com /* Restore thread PC */ 49210259SAndrew.Bardsley@arm.com thread->pcState(old_pc); 49310259SAndrew.Bardsley@arm.com issued = true; 49410259SAndrew.Bardsley@arm.com } 49510259SAndrew.Bardsley@arm.com 49610259SAndrew.Bardsley@arm.com return issued; 49710259SAndrew.Bardsley@arm.com} 49810259SAndrew.Bardsley@arm.com 49910259SAndrew.Bardsley@arm.com/** Increment a cyclic buffer index for indices [0, cycle_size-1] */ 50010259SAndrew.Bardsley@arm.cominline unsigned int 50110259SAndrew.Bardsley@arm.comcyclicIndexInc(unsigned int index, unsigned int cycle_size) 50210259SAndrew.Bardsley@arm.com{ 50310259SAndrew.Bardsley@arm.com unsigned int ret = index + 1; 50410259SAndrew.Bardsley@arm.com 50510259SAndrew.Bardsley@arm.com if (ret == cycle_size) 50610259SAndrew.Bardsley@arm.com ret = 0; 50710259SAndrew.Bardsley@arm.com 50810259SAndrew.Bardsley@arm.com return ret; 50910259SAndrew.Bardsley@arm.com} 51010259SAndrew.Bardsley@arm.com 51110259SAndrew.Bardsley@arm.com/** Decrement a cyclic buffer index for indices [0, cycle_size-1] */ 51210259SAndrew.Bardsley@arm.cominline unsigned int 51310259SAndrew.Bardsley@arm.comcyclicIndexDec(unsigned int index, unsigned int cycle_size) 51410259SAndrew.Bardsley@arm.com{ 51510259SAndrew.Bardsley@arm.com int ret = index - 1; 51610259SAndrew.Bardsley@arm.com 51710259SAndrew.Bardsley@arm.com if (ret < 0) 51810259SAndrew.Bardsley@arm.com ret = cycle_size - 1; 51910259SAndrew.Bardsley@arm.com 52010259SAndrew.Bardsley@arm.com return ret; 52110259SAndrew.Bardsley@arm.com} 52210259SAndrew.Bardsley@arm.com 52310259SAndrew.Bardsley@arm.comunsigned int 52411567Smitch.hayenga@arm.comExecute::issue(ThreadID thread_id) 52510259SAndrew.Bardsley@arm.com{ 52611567Smitch.hayenga@arm.com const ForwardInstData *insts_in = getInput(thread_id); 52711567Smitch.hayenga@arm.com ExecuteThreadInfo &thread = executeInfo[thread_id]; 52810259SAndrew.Bardsley@arm.com 52910259SAndrew.Bardsley@arm.com /* Early termination if we have no instructions */ 53010259SAndrew.Bardsley@arm.com if (!insts_in) 53110259SAndrew.Bardsley@arm.com return 0; 53210259SAndrew.Bardsley@arm.com 53310259SAndrew.Bardsley@arm.com /* Start from the first FU */ 53410259SAndrew.Bardsley@arm.com unsigned int fu_index = 0; 53510259SAndrew.Bardsley@arm.com 53610259SAndrew.Bardsley@arm.com /* Remains true while instructions are still being issued. If any 53710259SAndrew.Bardsley@arm.com * instruction fails to issue, this is set to false and we exit issue. 53810259SAndrew.Bardsley@arm.com * This strictly enforces in-order issue. For other issue behaviours, 53910259SAndrew.Bardsley@arm.com * a more complicated test in the outer while loop below is needed. */ 54010259SAndrew.Bardsley@arm.com bool issued = true; 54110259SAndrew.Bardsley@arm.com 54210259SAndrew.Bardsley@arm.com /* Number of insts issues this cycle to check for issueLimit */ 54310259SAndrew.Bardsley@arm.com unsigned num_insts_issued = 0; 54410259SAndrew.Bardsley@arm.com 54510259SAndrew.Bardsley@arm.com /* Number of memory ops issues this cycle to check for memoryIssueLimit */ 54610259SAndrew.Bardsley@arm.com unsigned num_mem_insts_issued = 0; 54710259SAndrew.Bardsley@arm.com 54810259SAndrew.Bardsley@arm.com /* Number of instructions discarded this cycle in order to enforce a 54910259SAndrew.Bardsley@arm.com * discardLimit. @todo, add that parameter? */ 55010259SAndrew.Bardsley@arm.com unsigned num_insts_discarded = 0; 55110259SAndrew.Bardsley@arm.com 55210259SAndrew.Bardsley@arm.com do { 55311567Smitch.hayenga@arm.com MinorDynInstPtr inst = insts_in->insts[thread.inputIndex]; 55410259SAndrew.Bardsley@arm.com Fault fault = inst->fault; 55510259SAndrew.Bardsley@arm.com bool discarded = false; 55610259SAndrew.Bardsley@arm.com bool issued_mem_ref = false; 55710259SAndrew.Bardsley@arm.com 55810259SAndrew.Bardsley@arm.com if (inst->isBubble()) { 55910259SAndrew.Bardsley@arm.com /* Skip */ 56010259SAndrew.Bardsley@arm.com issued = true; 56110259SAndrew.Bardsley@arm.com } else if (cpu.getContext(thread_id)->status() == 56210259SAndrew.Bardsley@arm.com ThreadContext::Suspended) 56310259SAndrew.Bardsley@arm.com { 56411568Smitch.hayenga@arm.com DPRINTF(MinorExecute, "Discarding inst: %s from suspended" 56510259SAndrew.Bardsley@arm.com " thread\n", *inst); 56610259SAndrew.Bardsley@arm.com 56711568Smitch.hayenga@arm.com issued = true; 56811568Smitch.hayenga@arm.com discarded = true; 56911567Smitch.hayenga@arm.com } else if (inst->id.streamSeqNum != thread.streamSeqNum) { 57010259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Discarding inst: %s as its stream" 57110259SAndrew.Bardsley@arm.com " state was unexpected, expected: %d\n", 57211567Smitch.hayenga@arm.com *inst, thread.streamSeqNum); 57310259SAndrew.Bardsley@arm.com issued = true; 57410259SAndrew.Bardsley@arm.com discarded = true; 57510259SAndrew.Bardsley@arm.com } else { 57610259SAndrew.Bardsley@arm.com /* Try and issue an instruction into an FU, assume we didn't and 57710259SAndrew.Bardsley@arm.com * fix that in the loop */ 57810259SAndrew.Bardsley@arm.com issued = false; 57910259SAndrew.Bardsley@arm.com 58010259SAndrew.Bardsley@arm.com /* Try FU from 0 each instruction */ 58110259SAndrew.Bardsley@arm.com fu_index = 0; 58210259SAndrew.Bardsley@arm.com 58310259SAndrew.Bardsley@arm.com /* Try and issue a single instruction stepping through the 58410259SAndrew.Bardsley@arm.com * available FUs */ 58510259SAndrew.Bardsley@arm.com do { 58610259SAndrew.Bardsley@arm.com FUPipeline *fu = funcUnits[fu_index]; 58710259SAndrew.Bardsley@arm.com 58810259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Trying to issue inst: %s to FU: %d\n", 58910259SAndrew.Bardsley@arm.com *inst, fu_index); 59010259SAndrew.Bardsley@arm.com 59110259SAndrew.Bardsley@arm.com /* Does the examined fu have the OpClass-related capability 59210259SAndrew.Bardsley@arm.com * needed to execute this instruction? Faults can always 59310259SAndrew.Bardsley@arm.com * issue to any FU but probably should just 'live' in the 59410259SAndrew.Bardsley@arm.com * inFlightInsts queue rather than having an FU. */ 59510259SAndrew.Bardsley@arm.com bool fu_is_capable = (!inst->isFault() ? 59610259SAndrew.Bardsley@arm.com fu->provides(inst->staticInst->opClass()) : true); 59710259SAndrew.Bardsley@arm.com 59810259SAndrew.Bardsley@arm.com if (inst->isNoCostInst()) { 59910259SAndrew.Bardsley@arm.com /* Issue free insts. to a fake numbered FU */ 60010259SAndrew.Bardsley@arm.com fu_index = noCostFUIndex; 60110259SAndrew.Bardsley@arm.com 60210259SAndrew.Bardsley@arm.com /* And start the countdown on activity to allow 60310259SAndrew.Bardsley@arm.com * this instruction to get to the end of its FU */ 60410259SAndrew.Bardsley@arm.com cpu.activityRecorder->activity(); 60510259SAndrew.Bardsley@arm.com 60610259SAndrew.Bardsley@arm.com /* Mark the destinations for this instruction as 60710259SAndrew.Bardsley@arm.com * busy */ 60811567Smitch.hayenga@arm.com scoreboard[thread_id].markupInstDests(inst, cpu.curCycle() + 60910259SAndrew.Bardsley@arm.com Cycles(0), cpu.getContext(thread_id), false); 61010259SAndrew.Bardsley@arm.com 61111567Smitch.hayenga@arm.com DPRINTF(MinorExecute, "Issuing %s to %d\n", inst->id, noCostFUIndex); 61210259SAndrew.Bardsley@arm.com inst->fuIndex = noCostFUIndex; 61310259SAndrew.Bardsley@arm.com inst->extraCommitDelay = Cycles(0); 61410259SAndrew.Bardsley@arm.com inst->extraCommitDelayExpr = NULL; 61510259SAndrew.Bardsley@arm.com 61610259SAndrew.Bardsley@arm.com /* Push the instruction onto the inFlight queue so 61710259SAndrew.Bardsley@arm.com * it can be committed in order */ 61810259SAndrew.Bardsley@arm.com QueuedInst fu_inst(inst); 61911567Smitch.hayenga@arm.com thread.inFlightInsts->push(fu_inst); 62010259SAndrew.Bardsley@arm.com 62110259SAndrew.Bardsley@arm.com issued = true; 62210259SAndrew.Bardsley@arm.com 62310259SAndrew.Bardsley@arm.com } else if (!fu_is_capable || fu->alreadyPushed()) { 62410259SAndrew.Bardsley@arm.com /* Skip */ 62510259SAndrew.Bardsley@arm.com if (!fu_is_capable) { 62610259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue as FU: %d isn't" 62710259SAndrew.Bardsley@arm.com " capable\n", fu_index); 62810259SAndrew.Bardsley@arm.com } else { 62910259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue as FU: %d is" 63010259SAndrew.Bardsley@arm.com " already busy\n", fu_index); 63110259SAndrew.Bardsley@arm.com } 63210259SAndrew.Bardsley@arm.com } else if (fu->stalled) { 63310259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue inst: %s into FU: %d," 63410259SAndrew.Bardsley@arm.com " it's stalled\n", 63510259SAndrew.Bardsley@arm.com *inst, fu_index); 63610259SAndrew.Bardsley@arm.com } else if (!fu->canInsert()) { 63710259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue inst: %s to busy FU" 63810259SAndrew.Bardsley@arm.com " for another: %d cycles\n", 63910259SAndrew.Bardsley@arm.com *inst, fu->cyclesBeforeInsert()); 64010259SAndrew.Bardsley@arm.com } else { 64110259SAndrew.Bardsley@arm.com MinorFUTiming *timing = (!inst->isFault() ? 64210259SAndrew.Bardsley@arm.com fu->findTiming(inst->staticInst) : NULL); 64310259SAndrew.Bardsley@arm.com 64410259SAndrew.Bardsley@arm.com const std::vector<Cycles> *src_latencies = 64510259SAndrew.Bardsley@arm.com (timing ? &(timing->srcRegsRelativeLats) 64610259SAndrew.Bardsley@arm.com : NULL); 64710259SAndrew.Bardsley@arm.com 64810259SAndrew.Bardsley@arm.com const std::vector<bool> *cant_forward_from_fu_indices = 64910259SAndrew.Bardsley@arm.com &(fu->cantForwardFromFUIndices); 65010259SAndrew.Bardsley@arm.com 65110259SAndrew.Bardsley@arm.com if (timing && timing->suppress) { 65210259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue inst: %s as extra" 65310259SAndrew.Bardsley@arm.com " decoding is suppressing it\n", 65410259SAndrew.Bardsley@arm.com *inst); 65511567Smitch.hayenga@arm.com } else if (!scoreboard[thread_id].canInstIssue(inst, 65611567Smitch.hayenga@arm.com src_latencies, cant_forward_from_fu_indices, 65710259SAndrew.Bardsley@arm.com cpu.curCycle(), cpu.getContext(thread_id))) 65810259SAndrew.Bardsley@arm.com { 65910259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue inst: %s yet\n", 66010259SAndrew.Bardsley@arm.com *inst); 66110259SAndrew.Bardsley@arm.com } else { 66210259SAndrew.Bardsley@arm.com /* Can insert the instruction into this FU */ 66310259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Issuing inst: %s" 66410259SAndrew.Bardsley@arm.com " into FU %d\n", *inst, 66510259SAndrew.Bardsley@arm.com fu_index); 66610259SAndrew.Bardsley@arm.com 66710259SAndrew.Bardsley@arm.com Cycles extra_dest_retire_lat = Cycles(0); 66810259SAndrew.Bardsley@arm.com TimingExpr *extra_dest_retire_lat_expr = NULL; 66910259SAndrew.Bardsley@arm.com Cycles extra_assumed_lat = Cycles(0); 67010259SAndrew.Bardsley@arm.com 67110259SAndrew.Bardsley@arm.com /* Add the extraCommitDelay and extraAssumeLat to 67210259SAndrew.Bardsley@arm.com * the FU pipeline timings */ 67310259SAndrew.Bardsley@arm.com if (timing) { 67410259SAndrew.Bardsley@arm.com extra_dest_retire_lat = 67510259SAndrew.Bardsley@arm.com timing->extraCommitLat; 67610259SAndrew.Bardsley@arm.com extra_dest_retire_lat_expr = 67710259SAndrew.Bardsley@arm.com timing->extraCommitLatExpr; 67810259SAndrew.Bardsley@arm.com extra_assumed_lat = 67910259SAndrew.Bardsley@arm.com timing->extraAssumedLat; 68010259SAndrew.Bardsley@arm.com } 68110259SAndrew.Bardsley@arm.com 68210580SAndrew.Bardsley@arm.com issued_mem_ref = inst->isMemRef(); 68310259SAndrew.Bardsley@arm.com 68410259SAndrew.Bardsley@arm.com QueuedInst fu_inst(inst); 68510259SAndrew.Bardsley@arm.com 68610259SAndrew.Bardsley@arm.com /* Decorate the inst with FU details */ 68710259SAndrew.Bardsley@arm.com inst->fuIndex = fu_index; 68810259SAndrew.Bardsley@arm.com inst->extraCommitDelay = extra_dest_retire_lat; 68910259SAndrew.Bardsley@arm.com inst->extraCommitDelayExpr = 69010259SAndrew.Bardsley@arm.com extra_dest_retire_lat_expr; 69110259SAndrew.Bardsley@arm.com 69210259SAndrew.Bardsley@arm.com if (issued_mem_ref) { 69310259SAndrew.Bardsley@arm.com /* Remember which instruction this memory op 69410259SAndrew.Bardsley@arm.com * depends on so that initiateAcc can be called 69510259SAndrew.Bardsley@arm.com * early */ 69610259SAndrew.Bardsley@arm.com if (allowEarlyMemIssue) { 69710259SAndrew.Bardsley@arm.com inst->instToWaitFor = 69811567Smitch.hayenga@arm.com scoreboard[thread_id].execSeqNumToWaitFor(inst, 69910259SAndrew.Bardsley@arm.com cpu.getContext(thread_id)); 70010259SAndrew.Bardsley@arm.com 70111567Smitch.hayenga@arm.com if (lsq.getLastMemBarrier(thread_id) > 70210259SAndrew.Bardsley@arm.com inst->instToWaitFor) 70310259SAndrew.Bardsley@arm.com { 70410259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "A barrier will" 70510259SAndrew.Bardsley@arm.com " cause a delay in mem ref issue of" 70610259SAndrew.Bardsley@arm.com " inst: %s until after inst" 70710259SAndrew.Bardsley@arm.com " %d(exec)\n", *inst, 70811567Smitch.hayenga@arm.com lsq.getLastMemBarrier(thread_id)); 70910259SAndrew.Bardsley@arm.com 71010259SAndrew.Bardsley@arm.com inst->instToWaitFor = 71111567Smitch.hayenga@arm.com lsq.getLastMemBarrier(thread_id); 71210259SAndrew.Bardsley@arm.com } else { 71310259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Memory ref inst:" 71410259SAndrew.Bardsley@arm.com " %s must wait for inst %d(exec)" 71510259SAndrew.Bardsley@arm.com " before issuing\n", 71610259SAndrew.Bardsley@arm.com *inst, inst->instToWaitFor); 71710259SAndrew.Bardsley@arm.com } 71810259SAndrew.Bardsley@arm.com 71910259SAndrew.Bardsley@arm.com inst->canEarlyIssue = true; 72010259SAndrew.Bardsley@arm.com } 72110259SAndrew.Bardsley@arm.com /* Also queue this instruction in the memory ref 72210259SAndrew.Bardsley@arm.com * queue to ensure in-order issue to the LSQ */ 72310259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Pushing mem inst: %s\n", 72410259SAndrew.Bardsley@arm.com *inst); 72511567Smitch.hayenga@arm.com thread.inFUMemInsts->push(fu_inst); 72610259SAndrew.Bardsley@arm.com } 72710259SAndrew.Bardsley@arm.com 72810259SAndrew.Bardsley@arm.com /* Issue to FU */ 72910259SAndrew.Bardsley@arm.com fu->push(fu_inst); 73010259SAndrew.Bardsley@arm.com /* And start the countdown on activity to allow 73110259SAndrew.Bardsley@arm.com * this instruction to get to the end of its FU */ 73210259SAndrew.Bardsley@arm.com cpu.activityRecorder->activity(); 73310259SAndrew.Bardsley@arm.com 73410259SAndrew.Bardsley@arm.com /* Mark the destinations for this instruction as 73510259SAndrew.Bardsley@arm.com * busy */ 73611567Smitch.hayenga@arm.com scoreboard[thread_id].markupInstDests(inst, cpu.curCycle() + 73710259SAndrew.Bardsley@arm.com fu->description.opLat + 73810259SAndrew.Bardsley@arm.com extra_dest_retire_lat + 73910259SAndrew.Bardsley@arm.com extra_assumed_lat, 74010259SAndrew.Bardsley@arm.com cpu.getContext(thread_id), 74110259SAndrew.Bardsley@arm.com issued_mem_ref && extra_assumed_lat == Cycles(0)); 74210259SAndrew.Bardsley@arm.com 74310259SAndrew.Bardsley@arm.com /* Push the instruction onto the inFlight queue so 74410259SAndrew.Bardsley@arm.com * it can be committed in order */ 74511567Smitch.hayenga@arm.com thread.inFlightInsts->push(fu_inst); 74610259SAndrew.Bardsley@arm.com 74710259SAndrew.Bardsley@arm.com issued = true; 74810259SAndrew.Bardsley@arm.com } 74910259SAndrew.Bardsley@arm.com } 75010259SAndrew.Bardsley@arm.com 75110259SAndrew.Bardsley@arm.com fu_index++; 75210259SAndrew.Bardsley@arm.com } while (fu_index != numFuncUnits && !issued); 75310259SAndrew.Bardsley@arm.com 75410259SAndrew.Bardsley@arm.com if (!issued) 75510259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Didn't issue inst: %s\n", *inst); 75610259SAndrew.Bardsley@arm.com } 75710259SAndrew.Bardsley@arm.com 75810259SAndrew.Bardsley@arm.com if (issued) { 75910259SAndrew.Bardsley@arm.com /* Generate MinorTrace's MinorInst lines. Do this at commit 76010259SAndrew.Bardsley@arm.com * to allow better instruction annotation? */ 76110259SAndrew.Bardsley@arm.com if (DTRACE(MinorTrace) && !inst->isBubble()) 76210259SAndrew.Bardsley@arm.com inst->minorTraceInst(*this); 76310259SAndrew.Bardsley@arm.com 76410259SAndrew.Bardsley@arm.com /* Mark up barriers in the LSQ */ 76510259SAndrew.Bardsley@arm.com if (!discarded && inst->isInst() && 76610259SAndrew.Bardsley@arm.com inst->staticInst->isMemBarrier()) 76710259SAndrew.Bardsley@arm.com { 76810259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Issuing memory barrier inst: %s\n", *inst); 76910259SAndrew.Bardsley@arm.com lsq.issuedMemBarrierInst(inst); 77010259SAndrew.Bardsley@arm.com } 77110259SAndrew.Bardsley@arm.com 77210259SAndrew.Bardsley@arm.com if (inst->traceData && setTraceTimeOnIssue) { 77310259SAndrew.Bardsley@arm.com inst->traceData->setWhen(curTick()); 77410259SAndrew.Bardsley@arm.com } 77510259SAndrew.Bardsley@arm.com 77610259SAndrew.Bardsley@arm.com if (issued_mem_ref) 77710259SAndrew.Bardsley@arm.com num_mem_insts_issued++; 77810259SAndrew.Bardsley@arm.com 77910259SAndrew.Bardsley@arm.com if (discarded) { 78010259SAndrew.Bardsley@arm.com num_insts_discarded++; 78110851SAndrew.Bardsley@arm.com } else if (!inst->isBubble()) { 78210259SAndrew.Bardsley@arm.com num_insts_issued++; 78310259SAndrew.Bardsley@arm.com 78410259SAndrew.Bardsley@arm.com if (num_insts_issued == issueLimit) 78510259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Reached inst issue limit\n"); 78610259SAndrew.Bardsley@arm.com } 78710259SAndrew.Bardsley@arm.com 78811567Smitch.hayenga@arm.com thread.inputIndex++; 78910259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Stepping to next inst inputIndex: %d\n", 79011567Smitch.hayenga@arm.com thread.inputIndex); 79110259SAndrew.Bardsley@arm.com } 79210259SAndrew.Bardsley@arm.com 79310259SAndrew.Bardsley@arm.com /* Got to the end of a line */ 79411567Smitch.hayenga@arm.com if (thread.inputIndex == insts_in->width()) { 79511567Smitch.hayenga@arm.com popInput(thread_id); 79610259SAndrew.Bardsley@arm.com /* Set insts_in to null to force us to leave the surrounding 79710259SAndrew.Bardsley@arm.com * loop */ 79810259SAndrew.Bardsley@arm.com insts_in = NULL; 79910259SAndrew.Bardsley@arm.com 80010259SAndrew.Bardsley@arm.com if (processMoreThanOneInput) { 80110259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Wrapping\n"); 80211567Smitch.hayenga@arm.com insts_in = getInput(thread_id); 80310259SAndrew.Bardsley@arm.com } 80410259SAndrew.Bardsley@arm.com } 80511567Smitch.hayenga@arm.com } while (insts_in && thread.inputIndex < insts_in->width() && 80610259SAndrew.Bardsley@arm.com /* We still have instructions */ 80710259SAndrew.Bardsley@arm.com fu_index != numFuncUnits && /* Not visited all FUs */ 80810259SAndrew.Bardsley@arm.com issued && /* We've not yet failed to issue an instruction */ 80910259SAndrew.Bardsley@arm.com num_insts_issued != issueLimit && /* Still allowed to issue */ 81010259SAndrew.Bardsley@arm.com num_mem_insts_issued != memoryIssueLimit); 81110259SAndrew.Bardsley@arm.com 81210259SAndrew.Bardsley@arm.com return num_insts_issued; 81310259SAndrew.Bardsley@arm.com} 81410259SAndrew.Bardsley@arm.com 81510259SAndrew.Bardsley@arm.combool 81611567Smitch.hayenga@arm.comExecute::tryPCEvents(ThreadID thread_id) 81710259SAndrew.Bardsley@arm.com{ 81811567Smitch.hayenga@arm.com ThreadContext *thread = cpu.getContext(thread_id); 81910259SAndrew.Bardsley@arm.com unsigned int num_pc_event_checks = 0; 82010259SAndrew.Bardsley@arm.com 82110259SAndrew.Bardsley@arm.com /* Handle PC events on instructions */ 82210259SAndrew.Bardsley@arm.com Addr oldPC; 82310259SAndrew.Bardsley@arm.com do { 82410259SAndrew.Bardsley@arm.com oldPC = thread->instAddr(); 82510259SAndrew.Bardsley@arm.com cpu.system->pcEventQueue.service(thread); 82610259SAndrew.Bardsley@arm.com num_pc_event_checks++; 82710259SAndrew.Bardsley@arm.com } while (oldPC != thread->instAddr()); 82810259SAndrew.Bardsley@arm.com 82910259SAndrew.Bardsley@arm.com if (num_pc_event_checks > 1) { 83010259SAndrew.Bardsley@arm.com DPRINTF(PCEvent, "Acting on PC Event to PC: %s\n", 83110259SAndrew.Bardsley@arm.com thread->pcState()); 83210259SAndrew.Bardsley@arm.com } 83310259SAndrew.Bardsley@arm.com 83410259SAndrew.Bardsley@arm.com return num_pc_event_checks > 1; 83510259SAndrew.Bardsley@arm.com} 83610259SAndrew.Bardsley@arm.com 83710259SAndrew.Bardsley@arm.comvoid 83810259SAndrew.Bardsley@arm.comExecute::doInstCommitAccounting(MinorDynInstPtr inst) 83910259SAndrew.Bardsley@arm.com{ 84010259SAndrew.Bardsley@arm.com assert(!inst->isFault()); 84110259SAndrew.Bardsley@arm.com 84210259SAndrew.Bardsley@arm.com MinorThread *thread = cpu.threads[inst->id.threadId]; 84310259SAndrew.Bardsley@arm.com 84410259SAndrew.Bardsley@arm.com /* Increment the many and various inst and op counts in the 84510259SAndrew.Bardsley@arm.com * thread and system */ 84610259SAndrew.Bardsley@arm.com if (!inst->staticInst->isMicroop() || inst->staticInst->isLastMicroop()) 84710259SAndrew.Bardsley@arm.com { 84810259SAndrew.Bardsley@arm.com thread->numInst++; 84910259SAndrew.Bardsley@arm.com thread->numInsts++; 85010259SAndrew.Bardsley@arm.com cpu.stats.numInsts++; 85110774Snikos.nikoleris@gmail.com cpu.system->totalNumInsts++; 85210774Snikos.nikoleris@gmail.com 85310774Snikos.nikoleris@gmail.com /* Act on events related to instruction counts */ 85410774Snikos.nikoleris@gmail.com cpu.comInstEventQueue[inst->id.threadId]->serviceEvents(thread->numInst); 85510774Snikos.nikoleris@gmail.com cpu.system->instEventQueue.serviceEvents(cpu.system->totalNumInsts); 85610259SAndrew.Bardsley@arm.com } 85710259SAndrew.Bardsley@arm.com thread->numOp++; 85810259SAndrew.Bardsley@arm.com thread->numOps++; 85910259SAndrew.Bardsley@arm.com cpu.stats.numOps++; 86011419Smitch.hayenga@arm.com cpu.stats.committedInstType[inst->id.threadId] 86111419Smitch.hayenga@arm.com [inst->staticInst->opClass()]++; 86210259SAndrew.Bardsley@arm.com 86310259SAndrew.Bardsley@arm.com /* Set the CP SeqNum to the numOps commit number */ 86410259SAndrew.Bardsley@arm.com if (inst->traceData) 86510259SAndrew.Bardsley@arm.com inst->traceData->setCPSeq(thread->numOp); 86610464SAndreas.Sandberg@ARM.com 86710464SAndreas.Sandberg@ARM.com cpu.probeInstCommit(inst->staticInst); 86810259SAndrew.Bardsley@arm.com} 86910259SAndrew.Bardsley@arm.com 87010259SAndrew.Bardsley@arm.combool 87110259SAndrew.Bardsley@arm.comExecute::commitInst(MinorDynInstPtr inst, bool early_memory_issue, 87210259SAndrew.Bardsley@arm.com BranchData &branch, Fault &fault, bool &committed, 87310259SAndrew.Bardsley@arm.com bool &completed_mem_issue) 87410259SAndrew.Bardsley@arm.com{ 87510259SAndrew.Bardsley@arm.com ThreadID thread_id = inst->id.threadId; 87610259SAndrew.Bardsley@arm.com ThreadContext *thread = cpu.getContext(thread_id); 87710259SAndrew.Bardsley@arm.com 87810259SAndrew.Bardsley@arm.com bool completed_inst = true; 87910259SAndrew.Bardsley@arm.com fault = NoFault; 88010259SAndrew.Bardsley@arm.com 88110259SAndrew.Bardsley@arm.com /* Is the thread for this instruction suspended? In that case, just 88210259SAndrew.Bardsley@arm.com * stall as long as there are no pending interrupts */ 88310259SAndrew.Bardsley@arm.com if (thread->status() == ThreadContext::Suspended && 88410259SAndrew.Bardsley@arm.com !isInterrupted(thread_id)) 88510259SAndrew.Bardsley@arm.com { 88611568Smitch.hayenga@arm.com panic("We should never hit the case where we try to commit from a " 88711568Smitch.hayenga@arm.com "suspended thread as the streamSeqNum should not match"); 88810259SAndrew.Bardsley@arm.com } else if (inst->isFault()) { 88910259SAndrew.Bardsley@arm.com ExecContext context(cpu, *cpu.threads[thread_id], *this, inst); 89010259SAndrew.Bardsley@arm.com 89110259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Fault inst reached Execute: %s\n", 89210259SAndrew.Bardsley@arm.com inst->fault->name()); 89310259SAndrew.Bardsley@arm.com 89410259SAndrew.Bardsley@arm.com fault = inst->fault; 89510259SAndrew.Bardsley@arm.com inst->fault->invoke(thread, NULL); 89610259SAndrew.Bardsley@arm.com 89710259SAndrew.Bardsley@arm.com tryToBranch(inst, fault, branch); 89810259SAndrew.Bardsley@arm.com } else if (inst->staticInst->isMemRef()) { 89910259SAndrew.Bardsley@arm.com /* Memory accesses are executed in two parts: 90010259SAndrew.Bardsley@arm.com * executeMemRefInst -- calculates the EA and issues the access 90110259SAndrew.Bardsley@arm.com * to memory. This is done here. 90210259SAndrew.Bardsley@arm.com * handleMemResponse -- handles the response packet, done by 90310259SAndrew.Bardsley@arm.com * Execute::commit 90410259SAndrew.Bardsley@arm.com * 90510259SAndrew.Bardsley@arm.com * While the memory access is in its FU, the EA is being 90610259SAndrew.Bardsley@arm.com * calculated. At the end of the FU, when it is ready to 90710259SAndrew.Bardsley@arm.com * 'commit' (in this function), the access is presented to the 90810259SAndrew.Bardsley@arm.com * memory queues. When a response comes back from memory, 90910259SAndrew.Bardsley@arm.com * Execute::commit will commit it. 91010259SAndrew.Bardsley@arm.com */ 91110259SAndrew.Bardsley@arm.com bool predicate_passed = false; 91210259SAndrew.Bardsley@arm.com bool completed_mem_inst = executeMemRefInst(inst, branch, 91310259SAndrew.Bardsley@arm.com predicate_passed, fault); 91410259SAndrew.Bardsley@arm.com 91510259SAndrew.Bardsley@arm.com if (completed_mem_inst && fault != NoFault) { 91610259SAndrew.Bardsley@arm.com if (early_memory_issue) { 91710259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Fault in early executing inst: %s\n", 91810259SAndrew.Bardsley@arm.com fault->name()); 91910259SAndrew.Bardsley@arm.com /* Don't execute the fault, just stall the instruction 92010259SAndrew.Bardsley@arm.com * until it gets to the head of inFlightInsts */ 92110259SAndrew.Bardsley@arm.com inst->canEarlyIssue = false; 92210259SAndrew.Bardsley@arm.com /* Not completed as we'll come here again to pick up 92310259SAndrew.Bardsley@arm.com * the fault when we get to the end of the FU */ 92410259SAndrew.Bardsley@arm.com completed_inst = false; 92510259SAndrew.Bardsley@arm.com } else { 92610259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Fault in execute: %s\n", 92710259SAndrew.Bardsley@arm.com fault->name()); 92810259SAndrew.Bardsley@arm.com fault->invoke(thread, NULL); 92910259SAndrew.Bardsley@arm.com 93010259SAndrew.Bardsley@arm.com tryToBranch(inst, fault, branch); 93110259SAndrew.Bardsley@arm.com completed_inst = true; 93210259SAndrew.Bardsley@arm.com } 93310259SAndrew.Bardsley@arm.com } else { 93410259SAndrew.Bardsley@arm.com completed_inst = completed_mem_inst; 93510259SAndrew.Bardsley@arm.com } 93610259SAndrew.Bardsley@arm.com completed_mem_issue = completed_inst; 93710259SAndrew.Bardsley@arm.com } else if (inst->isInst() && inst->staticInst->isMemBarrier() && 93810259SAndrew.Bardsley@arm.com !lsq.canPushIntoStoreBuffer()) 93910259SAndrew.Bardsley@arm.com { 94010259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't commit data barrier inst: %s yet as" 94110259SAndrew.Bardsley@arm.com " there isn't space in the store buffer\n", *inst); 94210259SAndrew.Bardsley@arm.com 94310259SAndrew.Bardsley@arm.com completed_inst = false; 94411567Smitch.hayenga@arm.com } else if (inst->isInst() && inst->staticInst->isQuiesce() 94511567Smitch.hayenga@arm.com && !branch.isBubble()){ 94611567Smitch.hayenga@arm.com /* This instruction can suspend, need to be able to communicate 94711567Smitch.hayenga@arm.com * backwards, so no other branches may evaluate this cycle*/ 94811567Smitch.hayenga@arm.com completed_inst = false; 94910259SAndrew.Bardsley@arm.com } else { 95010259SAndrew.Bardsley@arm.com ExecContext context(cpu, *cpu.threads[thread_id], *this, inst); 95110259SAndrew.Bardsley@arm.com 95210259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Committing inst: %s\n", *inst); 95310259SAndrew.Bardsley@arm.com 95410259SAndrew.Bardsley@arm.com fault = inst->staticInst->execute(&context, 95510259SAndrew.Bardsley@arm.com inst->traceData); 95610259SAndrew.Bardsley@arm.com 95710259SAndrew.Bardsley@arm.com /* Set the predicate for tracing and dump */ 95810259SAndrew.Bardsley@arm.com if (inst->traceData) 95910259SAndrew.Bardsley@arm.com inst->traceData->setPredicate(context.readPredicate()); 96010259SAndrew.Bardsley@arm.com 96110259SAndrew.Bardsley@arm.com committed = true; 96210259SAndrew.Bardsley@arm.com 96310259SAndrew.Bardsley@arm.com if (fault != NoFault) { 96410259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Fault in execute of inst: %s fault: %s\n", 96510259SAndrew.Bardsley@arm.com *inst, fault->name()); 96610259SAndrew.Bardsley@arm.com fault->invoke(thread, inst->staticInst); 96710259SAndrew.Bardsley@arm.com } 96810259SAndrew.Bardsley@arm.com 96910259SAndrew.Bardsley@arm.com doInstCommitAccounting(inst); 97010259SAndrew.Bardsley@arm.com tryToBranch(inst, fault, branch); 97110259SAndrew.Bardsley@arm.com } 97210259SAndrew.Bardsley@arm.com 97310259SAndrew.Bardsley@arm.com if (completed_inst) { 97410259SAndrew.Bardsley@arm.com /* Keep a copy of this instruction's predictionSeqNum just in case 97510259SAndrew.Bardsley@arm.com * we need to issue a branch without an instruction (such as an 97610259SAndrew.Bardsley@arm.com * interrupt) */ 97711567Smitch.hayenga@arm.com executeInfo[thread_id].lastPredictionSeqNum = inst->id.predictionSeqNum; 97810259SAndrew.Bardsley@arm.com 97910259SAndrew.Bardsley@arm.com /* Check to see if this instruction suspended the current thread. */ 98010259SAndrew.Bardsley@arm.com if (!inst->isFault() && 98110259SAndrew.Bardsley@arm.com thread->status() == ThreadContext::Suspended && 98210259SAndrew.Bardsley@arm.com branch.isBubble() && /* It didn't branch too */ 98310259SAndrew.Bardsley@arm.com !isInterrupted(thread_id)) /* Don't suspend if we have 98410259SAndrew.Bardsley@arm.com interrupts */ 98510259SAndrew.Bardsley@arm.com { 98611567Smitch.hayenga@arm.com TheISA::PCState resume_pc = cpu.getContext(thread_id)->pcState(); 98710259SAndrew.Bardsley@arm.com 98810259SAndrew.Bardsley@arm.com assert(resume_pc.microPC() == 0); 98910259SAndrew.Bardsley@arm.com 99010259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Suspending thread: %d from Execute" 99111567Smitch.hayenga@arm.com " inst: %s\n", thread_id, *inst); 99210259SAndrew.Bardsley@arm.com 99310259SAndrew.Bardsley@arm.com cpu.stats.numFetchSuspends++; 99410259SAndrew.Bardsley@arm.com 99511567Smitch.hayenga@arm.com updateBranchData(thread_id, BranchData::SuspendThread, inst, 99611567Smitch.hayenga@arm.com resume_pc, branch); 99710259SAndrew.Bardsley@arm.com } 99810259SAndrew.Bardsley@arm.com } 99910259SAndrew.Bardsley@arm.com 100010259SAndrew.Bardsley@arm.com return completed_inst; 100110259SAndrew.Bardsley@arm.com} 100210259SAndrew.Bardsley@arm.com 100310259SAndrew.Bardsley@arm.comvoid 100411567Smitch.hayenga@arm.comExecute::commit(ThreadID thread_id, bool only_commit_microops, bool discard, 100511567Smitch.hayenga@arm.com BranchData &branch) 100610259SAndrew.Bardsley@arm.com{ 100710259SAndrew.Bardsley@arm.com Fault fault = NoFault; 100810259SAndrew.Bardsley@arm.com Cycles now = cpu.curCycle(); 100911567Smitch.hayenga@arm.com ExecuteThreadInfo &ex_info = executeInfo[thread_id]; 101010259SAndrew.Bardsley@arm.com 101110259SAndrew.Bardsley@arm.com /** 101210259SAndrew.Bardsley@arm.com * Try and execute as many instructions from the end of FU pipelines as 101310259SAndrew.Bardsley@arm.com * possible. This *doesn't* include actually advancing the pipelines. 101410259SAndrew.Bardsley@arm.com * 101510259SAndrew.Bardsley@arm.com * We do this by looping on the front of the inFlightInsts queue for as 101610259SAndrew.Bardsley@arm.com * long as we can find the desired instruction at the end of the 101710259SAndrew.Bardsley@arm.com * functional unit it was issued to without seeing a branch or a fault. 101810259SAndrew.Bardsley@arm.com * In this function, these terms are used: 101910259SAndrew.Bardsley@arm.com * complete -- The instruction has finished its passage through 102010259SAndrew.Bardsley@arm.com * its functional unit and its fate has been decided 102110259SAndrew.Bardsley@arm.com * (committed, discarded, issued to the memory system) 102210259SAndrew.Bardsley@arm.com * commit -- The instruction is complete(d), not discarded and has 102310259SAndrew.Bardsley@arm.com * its effects applied to the CPU state 102410259SAndrew.Bardsley@arm.com * discard(ed) -- The instruction is complete but not committed 102510259SAndrew.Bardsley@arm.com * as its streamSeqNum disagrees with the current 102610259SAndrew.Bardsley@arm.com * Execute::streamSeqNum 102710259SAndrew.Bardsley@arm.com * 102810259SAndrew.Bardsley@arm.com * Commits are also possible from two other places: 102910259SAndrew.Bardsley@arm.com * 103010259SAndrew.Bardsley@arm.com * 1) Responses returning from the LSQ 103110259SAndrew.Bardsley@arm.com * 2) Mem ops issued to the LSQ ('committed' from the FUs) earlier 103210259SAndrew.Bardsley@arm.com * than their position in the inFlightInsts queue, but after all 103310259SAndrew.Bardsley@arm.com * their dependencies are resolved. 103410259SAndrew.Bardsley@arm.com */ 103510259SAndrew.Bardsley@arm.com 103610259SAndrew.Bardsley@arm.com /* Has an instruction been completed? Once this becomes false, we stop 103710259SAndrew.Bardsley@arm.com * trying to complete instructions. */ 103810259SAndrew.Bardsley@arm.com bool completed_inst = true; 103910259SAndrew.Bardsley@arm.com 104010259SAndrew.Bardsley@arm.com /* Number of insts committed this cycle to check against commitLimit */ 104110259SAndrew.Bardsley@arm.com unsigned int num_insts_committed = 0; 104210259SAndrew.Bardsley@arm.com 104310259SAndrew.Bardsley@arm.com /* Number of memory access instructions committed to check against 104410259SAndrew.Bardsley@arm.com * memCommitLimit */ 104510259SAndrew.Bardsley@arm.com unsigned int num_mem_refs_committed = 0; 104610259SAndrew.Bardsley@arm.com 104711567Smitch.hayenga@arm.com if (only_commit_microops && !ex_info.inFlightInsts->empty()) { 104810259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Only commit microops %s %d\n", 104911567Smitch.hayenga@arm.com *(ex_info.inFlightInsts->front().inst), 105011567Smitch.hayenga@arm.com ex_info.lastCommitWasEndOfMacroop); 105110259SAndrew.Bardsley@arm.com } 105210259SAndrew.Bardsley@arm.com 105311567Smitch.hayenga@arm.com while (!ex_info.inFlightInsts->empty() && /* Some more instructions to process */ 105410259SAndrew.Bardsley@arm.com !branch.isStreamChange() && /* No real branch */ 105510259SAndrew.Bardsley@arm.com fault == NoFault && /* No faults */ 105610259SAndrew.Bardsley@arm.com completed_inst && /* Still finding instructions to execute */ 105713632Sqtt2@cornell.edu num_insts_committed != commitLimit && /* Not reached commit limit */ 105813632Sqtt2@cornell.edu cpu.getContext(thread_id)->status() != ThreadContext::Suspended 105910259SAndrew.Bardsley@arm.com ) 106010259SAndrew.Bardsley@arm.com { 106110259SAndrew.Bardsley@arm.com if (only_commit_microops) { 106210259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Committing tail of insts before" 106310259SAndrew.Bardsley@arm.com " interrupt: %s\n", 106411567Smitch.hayenga@arm.com *(ex_info.inFlightInsts->front().inst)); 106510259SAndrew.Bardsley@arm.com } 106610259SAndrew.Bardsley@arm.com 106711567Smitch.hayenga@arm.com QueuedInst *head_inflight_inst = &(ex_info.inFlightInsts->front()); 106810259SAndrew.Bardsley@arm.com 106910259SAndrew.Bardsley@arm.com InstSeqNum head_exec_seq_num = 107010259SAndrew.Bardsley@arm.com head_inflight_inst->inst->id.execSeqNum; 107110259SAndrew.Bardsley@arm.com 107210259SAndrew.Bardsley@arm.com /* The instruction we actually process if completed_inst 107310259SAndrew.Bardsley@arm.com * remains true to the end of the loop body. 107410259SAndrew.Bardsley@arm.com * Start by considering the the head of the in flight insts queue */ 107510259SAndrew.Bardsley@arm.com MinorDynInstPtr inst = head_inflight_inst->inst; 107610259SAndrew.Bardsley@arm.com 107710259SAndrew.Bardsley@arm.com bool committed_inst = false; 107810259SAndrew.Bardsley@arm.com bool discard_inst = false; 107910259SAndrew.Bardsley@arm.com bool completed_mem_ref = false; 108010259SAndrew.Bardsley@arm.com bool issued_mem_ref = false; 108110259SAndrew.Bardsley@arm.com bool early_memory_issue = false; 108210259SAndrew.Bardsley@arm.com 108310259SAndrew.Bardsley@arm.com /* Must set this again to go around the loop */ 108410259SAndrew.Bardsley@arm.com completed_inst = false; 108510259SAndrew.Bardsley@arm.com 108610259SAndrew.Bardsley@arm.com /* If we're just completing a macroop before an interrupt or drain, 108710259SAndrew.Bardsley@arm.com * can we stil commit another microop (rather than a memory response) 108810259SAndrew.Bardsley@arm.com * without crosing into the next full instruction? */ 108911567Smitch.hayenga@arm.com bool can_commit_insts = !ex_info.inFlightInsts->empty() && 109011567Smitch.hayenga@arm.com !(only_commit_microops && ex_info.lastCommitWasEndOfMacroop); 109110259SAndrew.Bardsley@arm.com 109210259SAndrew.Bardsley@arm.com /* Can we find a mem response for this inst */ 109310259SAndrew.Bardsley@arm.com LSQ::LSQRequestPtr mem_response = 109410259SAndrew.Bardsley@arm.com (inst->inLSQ ? lsq.findResponse(inst) : NULL); 109510259SAndrew.Bardsley@arm.com 109610259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Trying to commit canCommitInsts: %d\n", 109710259SAndrew.Bardsley@arm.com can_commit_insts); 109810259SAndrew.Bardsley@arm.com 109910259SAndrew.Bardsley@arm.com /* Test for PC events after every instruction */ 110011567Smitch.hayenga@arm.com if (isInbetweenInsts(thread_id) && tryPCEvents(thread_id)) { 110111567Smitch.hayenga@arm.com ThreadContext *thread = cpu.getContext(thread_id); 110210259SAndrew.Bardsley@arm.com 110310259SAndrew.Bardsley@arm.com /* Branch as there was a change in PC */ 110411567Smitch.hayenga@arm.com updateBranchData(thread_id, BranchData::UnpredictedBranch, 110510259SAndrew.Bardsley@arm.com MinorDynInst::bubble(), thread->pcState(), branch); 110610259SAndrew.Bardsley@arm.com } else if (mem_response && 110710259SAndrew.Bardsley@arm.com num_mem_refs_committed < memoryCommitLimit) 110810259SAndrew.Bardsley@arm.com { 110910259SAndrew.Bardsley@arm.com /* Try to commit from the memory responses next */ 111011567Smitch.hayenga@arm.com discard_inst = inst->id.streamSeqNum != 111111567Smitch.hayenga@arm.com ex_info.streamSeqNum || discard; 111210259SAndrew.Bardsley@arm.com 111310259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Trying to commit mem response: %s\n", 111410259SAndrew.Bardsley@arm.com *inst); 111510259SAndrew.Bardsley@arm.com 111610259SAndrew.Bardsley@arm.com /* Complete or discard the response */ 111710259SAndrew.Bardsley@arm.com if (discard_inst) { 111810259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Discarding mem inst: %s as its" 111910259SAndrew.Bardsley@arm.com " stream state was unexpected, expected: %d\n", 112011567Smitch.hayenga@arm.com *inst, ex_info.streamSeqNum); 112110259SAndrew.Bardsley@arm.com 112210259SAndrew.Bardsley@arm.com lsq.popResponse(mem_response); 112310259SAndrew.Bardsley@arm.com } else { 112410259SAndrew.Bardsley@arm.com handleMemResponse(inst, mem_response, branch, fault); 112510259SAndrew.Bardsley@arm.com committed_inst = true; 112610259SAndrew.Bardsley@arm.com } 112710259SAndrew.Bardsley@arm.com 112810259SAndrew.Bardsley@arm.com completed_mem_ref = true; 112910259SAndrew.Bardsley@arm.com completed_inst = true; 113010259SAndrew.Bardsley@arm.com } else if (can_commit_insts) { 113110259SAndrew.Bardsley@arm.com /* If true, this instruction will, subject to timing tweaks, 113210259SAndrew.Bardsley@arm.com * be considered for completion. try_to_commit flattens 113310259SAndrew.Bardsley@arm.com * the `if' tree a bit and allows other tests for inst 113410259SAndrew.Bardsley@arm.com * commit to be inserted here. */ 113510259SAndrew.Bardsley@arm.com bool try_to_commit = false; 113610259SAndrew.Bardsley@arm.com 113710259SAndrew.Bardsley@arm.com /* Try and issue memory ops early if they: 113810259SAndrew.Bardsley@arm.com * - Can push a request into the LSQ 113910259SAndrew.Bardsley@arm.com * - Have reached the end of their FUs 114010259SAndrew.Bardsley@arm.com * - Have had all their dependencies satisfied 114110259SAndrew.Bardsley@arm.com * - Are from the right stream 114210259SAndrew.Bardsley@arm.com * 114310259SAndrew.Bardsley@arm.com * For any other case, leave it to the normal instruction 114410259SAndrew.Bardsley@arm.com * issue below to handle them. 114510259SAndrew.Bardsley@arm.com */ 114611567Smitch.hayenga@arm.com if (!ex_info.inFUMemInsts->empty() && lsq.canRequest()) { 114710259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Trying to commit from mem FUs\n"); 114810259SAndrew.Bardsley@arm.com 114910259SAndrew.Bardsley@arm.com const MinorDynInstPtr head_mem_ref_inst = 115011567Smitch.hayenga@arm.com ex_info.inFUMemInsts->front().inst; 115110259SAndrew.Bardsley@arm.com FUPipeline *fu = funcUnits[head_mem_ref_inst->fuIndex]; 115210259SAndrew.Bardsley@arm.com const MinorDynInstPtr &fu_inst = fu->front().inst; 115310259SAndrew.Bardsley@arm.com 115410259SAndrew.Bardsley@arm.com /* Use this, possibly out of order, inst as the one 115510259SAndrew.Bardsley@arm.com * to 'commit'/send to the LSQ */ 115610259SAndrew.Bardsley@arm.com if (!fu_inst->isBubble() && 115710259SAndrew.Bardsley@arm.com !fu_inst->inLSQ && 115810259SAndrew.Bardsley@arm.com fu_inst->canEarlyIssue && 115911567Smitch.hayenga@arm.com ex_info.streamSeqNum == fu_inst->id.streamSeqNum && 116010259SAndrew.Bardsley@arm.com head_exec_seq_num > fu_inst->instToWaitFor) 116110259SAndrew.Bardsley@arm.com { 116210259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Issuing mem ref early" 116310259SAndrew.Bardsley@arm.com " inst: %s instToWaitFor: %d\n", 116410259SAndrew.Bardsley@arm.com *(fu_inst), fu_inst->instToWaitFor); 116510259SAndrew.Bardsley@arm.com 116610259SAndrew.Bardsley@arm.com inst = fu_inst; 116710259SAndrew.Bardsley@arm.com try_to_commit = true; 116810259SAndrew.Bardsley@arm.com early_memory_issue = true; 116910259SAndrew.Bardsley@arm.com completed_inst = true; 117010259SAndrew.Bardsley@arm.com } 117110259SAndrew.Bardsley@arm.com } 117210259SAndrew.Bardsley@arm.com 117310259SAndrew.Bardsley@arm.com /* Try and commit FU-less insts */ 117410259SAndrew.Bardsley@arm.com if (!completed_inst && inst->isNoCostInst()) { 117510259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Committing no cost inst: %s", *inst); 117610259SAndrew.Bardsley@arm.com 117710259SAndrew.Bardsley@arm.com try_to_commit = true; 117810259SAndrew.Bardsley@arm.com completed_inst = true; 117910259SAndrew.Bardsley@arm.com } 118010259SAndrew.Bardsley@arm.com 118110259SAndrew.Bardsley@arm.com /* Try to issue from the ends of FUs and the inFlightInsts 118210259SAndrew.Bardsley@arm.com * queue */ 118310259SAndrew.Bardsley@arm.com if (!completed_inst && !inst->inLSQ) { 118410259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Trying to commit from FUs\n"); 118510259SAndrew.Bardsley@arm.com 118610259SAndrew.Bardsley@arm.com /* Try to commit from a functional unit */ 118710259SAndrew.Bardsley@arm.com /* Is the head inst of the expected inst's FU actually the 118810259SAndrew.Bardsley@arm.com * expected inst? */ 118910259SAndrew.Bardsley@arm.com QueuedInst &fu_inst = 119010259SAndrew.Bardsley@arm.com funcUnits[inst->fuIndex]->front(); 119110259SAndrew.Bardsley@arm.com InstSeqNum fu_inst_seq_num = fu_inst.inst->id.execSeqNum; 119210259SAndrew.Bardsley@arm.com 119310259SAndrew.Bardsley@arm.com if (fu_inst.inst->isBubble()) { 119410259SAndrew.Bardsley@arm.com /* No instruction ready */ 119510259SAndrew.Bardsley@arm.com completed_inst = false; 119610259SAndrew.Bardsley@arm.com } else if (fu_inst_seq_num != head_exec_seq_num) { 119710259SAndrew.Bardsley@arm.com /* Past instruction: we must have already executed it 119810259SAndrew.Bardsley@arm.com * in the same cycle and so the head inst isn't 119910259SAndrew.Bardsley@arm.com * actually at the end of its pipeline 120010259SAndrew.Bardsley@arm.com * Future instruction: handled above and only for 120110259SAndrew.Bardsley@arm.com * mem refs on their way to the LSQ */ 120211567Smitch.hayenga@arm.com } else if (fu_inst.inst->id == inst->id) { 120310259SAndrew.Bardsley@arm.com /* All instructions can be committed if they have the 120410259SAndrew.Bardsley@arm.com * right execSeqNum and there are no in-flight 120510259SAndrew.Bardsley@arm.com * mem insts before us */ 120610259SAndrew.Bardsley@arm.com try_to_commit = true; 120710259SAndrew.Bardsley@arm.com completed_inst = true; 120810259SAndrew.Bardsley@arm.com } 120910259SAndrew.Bardsley@arm.com } 121010259SAndrew.Bardsley@arm.com 121110259SAndrew.Bardsley@arm.com if (try_to_commit) { 121211567Smitch.hayenga@arm.com discard_inst = inst->id.streamSeqNum != 121311567Smitch.hayenga@arm.com ex_info.streamSeqNum || discard; 121410259SAndrew.Bardsley@arm.com 121510259SAndrew.Bardsley@arm.com /* Is this instruction discardable as its streamSeqNum 121610259SAndrew.Bardsley@arm.com * doesn't match? */ 121710259SAndrew.Bardsley@arm.com if (!discard_inst) { 121810259SAndrew.Bardsley@arm.com /* Try to commit or discard a non-memory instruction. 121910259SAndrew.Bardsley@arm.com * Memory ops are actually 'committed' from this FUs 122010259SAndrew.Bardsley@arm.com * and 'issued' into the memory system so we need to 122110259SAndrew.Bardsley@arm.com * account for them later (commit_was_mem_issue gets 122210259SAndrew.Bardsley@arm.com * set) */ 122310259SAndrew.Bardsley@arm.com if (inst->extraCommitDelayExpr) { 122410259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Evaluating expression for" 122510259SAndrew.Bardsley@arm.com " extra commit delay inst: %s\n", *inst); 122610259SAndrew.Bardsley@arm.com 122711567Smitch.hayenga@arm.com ThreadContext *thread = cpu.getContext(thread_id); 122810259SAndrew.Bardsley@arm.com 122910259SAndrew.Bardsley@arm.com TimingExprEvalContext context(inst->staticInst, 123010259SAndrew.Bardsley@arm.com thread, NULL); 123110259SAndrew.Bardsley@arm.com 123210259SAndrew.Bardsley@arm.com uint64_t extra_delay = inst->extraCommitDelayExpr-> 123310259SAndrew.Bardsley@arm.com eval(context); 123410259SAndrew.Bardsley@arm.com 123510259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Extra commit delay expr" 123610259SAndrew.Bardsley@arm.com " result: %d\n", extra_delay); 123710259SAndrew.Bardsley@arm.com 123810259SAndrew.Bardsley@arm.com if (extra_delay < 128) { 123910259SAndrew.Bardsley@arm.com inst->extraCommitDelay += Cycles(extra_delay); 124010259SAndrew.Bardsley@arm.com } else { 124110259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Extra commit delay was" 124210259SAndrew.Bardsley@arm.com " very long: %d\n", extra_delay); 124310259SAndrew.Bardsley@arm.com } 124410259SAndrew.Bardsley@arm.com inst->extraCommitDelayExpr = NULL; 124510259SAndrew.Bardsley@arm.com } 124610259SAndrew.Bardsley@arm.com 124710259SAndrew.Bardsley@arm.com /* Move the extraCommitDelay from the instruction 124810259SAndrew.Bardsley@arm.com * into the minimumCommitCycle */ 124910259SAndrew.Bardsley@arm.com if (inst->extraCommitDelay != Cycles(0)) { 125010259SAndrew.Bardsley@arm.com inst->minimumCommitCycle = cpu.curCycle() + 125110259SAndrew.Bardsley@arm.com inst->extraCommitDelay; 125210259SAndrew.Bardsley@arm.com inst->extraCommitDelay = Cycles(0); 125310259SAndrew.Bardsley@arm.com } 125410259SAndrew.Bardsley@arm.com 125510259SAndrew.Bardsley@arm.com /* @todo Think about making lastMemBarrier be 125610259SAndrew.Bardsley@arm.com * MAX_UINT_64 to avoid using 0 as a marker value */ 125710259SAndrew.Bardsley@arm.com if (!inst->isFault() && inst->isMemRef() && 125811567Smitch.hayenga@arm.com lsq.getLastMemBarrier(thread_id) < 125910259SAndrew.Bardsley@arm.com inst->id.execSeqNum && 126011567Smitch.hayenga@arm.com lsq.getLastMemBarrier(thread_id) != 0) 126110259SAndrew.Bardsley@arm.com { 126210259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Not committing inst: %s yet" 126310259SAndrew.Bardsley@arm.com " as there are incomplete barriers in flight\n", 126410259SAndrew.Bardsley@arm.com *inst); 126510259SAndrew.Bardsley@arm.com completed_inst = false; 126610259SAndrew.Bardsley@arm.com } else if (inst->minimumCommitCycle > now) { 126710259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Not committing inst: %s yet" 126810259SAndrew.Bardsley@arm.com " as it wants to be stalled for %d more cycles\n", 126910259SAndrew.Bardsley@arm.com *inst, inst->minimumCommitCycle - now); 127010259SAndrew.Bardsley@arm.com completed_inst = false; 127110259SAndrew.Bardsley@arm.com } else { 127210259SAndrew.Bardsley@arm.com completed_inst = commitInst(inst, 127310259SAndrew.Bardsley@arm.com early_memory_issue, branch, fault, 127410259SAndrew.Bardsley@arm.com committed_inst, issued_mem_ref); 127510259SAndrew.Bardsley@arm.com } 127610259SAndrew.Bardsley@arm.com } else { 127710259SAndrew.Bardsley@arm.com /* Discard instruction */ 127810259SAndrew.Bardsley@arm.com completed_inst = true; 127910259SAndrew.Bardsley@arm.com } 128010259SAndrew.Bardsley@arm.com 128110259SAndrew.Bardsley@arm.com if (completed_inst) { 128210259SAndrew.Bardsley@arm.com /* Allow the pipeline to advance. If the FU head 128310259SAndrew.Bardsley@arm.com * instruction wasn't the inFlightInsts head 128410259SAndrew.Bardsley@arm.com * but had already been committed, it would have 128510259SAndrew.Bardsley@arm.com * unstalled the pipeline before here */ 128611567Smitch.hayenga@arm.com if (inst->fuIndex != noCostFUIndex) { 128711567Smitch.hayenga@arm.com DPRINTF(MinorExecute, "Unstalling %d for inst %s\n", inst->fuIndex, inst->id); 128810259SAndrew.Bardsley@arm.com funcUnits[inst->fuIndex]->stalled = false; 128911567Smitch.hayenga@arm.com } 129010259SAndrew.Bardsley@arm.com } 129110259SAndrew.Bardsley@arm.com } 129210259SAndrew.Bardsley@arm.com } else { 129310259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "No instructions to commit\n"); 129410259SAndrew.Bardsley@arm.com completed_inst = false; 129510259SAndrew.Bardsley@arm.com } 129610259SAndrew.Bardsley@arm.com 129710259SAndrew.Bardsley@arm.com /* All discardable instructions must also be 'completed' by now */ 129810259SAndrew.Bardsley@arm.com assert(!(discard_inst && !completed_inst)); 129910259SAndrew.Bardsley@arm.com 130010259SAndrew.Bardsley@arm.com /* Instruction committed but was discarded due to streamSeqNum 130110259SAndrew.Bardsley@arm.com * mismatch */ 130210259SAndrew.Bardsley@arm.com if (discard_inst) { 130310259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Discarding inst: %s as its stream" 130410259SAndrew.Bardsley@arm.com " state was unexpected, expected: %d\n", 130511567Smitch.hayenga@arm.com *inst, ex_info.streamSeqNum); 130610259SAndrew.Bardsley@arm.com 130710259SAndrew.Bardsley@arm.com if (fault == NoFault) 130810259SAndrew.Bardsley@arm.com cpu.stats.numDiscardedOps++; 130910259SAndrew.Bardsley@arm.com } 131010259SAndrew.Bardsley@arm.com 131110259SAndrew.Bardsley@arm.com /* Mark the mem inst as being in the LSQ */ 131210259SAndrew.Bardsley@arm.com if (issued_mem_ref) { 131310259SAndrew.Bardsley@arm.com inst->fuIndex = 0; 131410259SAndrew.Bardsley@arm.com inst->inLSQ = true; 131510259SAndrew.Bardsley@arm.com } 131610259SAndrew.Bardsley@arm.com 131710259SAndrew.Bardsley@arm.com /* Pop issued (to LSQ) and discarded mem refs from the inFUMemInsts 131810259SAndrew.Bardsley@arm.com * as they've *definitely* exited the FUs */ 131910259SAndrew.Bardsley@arm.com if (completed_inst && inst->isMemRef()) { 132010259SAndrew.Bardsley@arm.com /* The MemRef could have been discarded from the FU or the memory 132110259SAndrew.Bardsley@arm.com * queue, so just check an FU instruction */ 132211567Smitch.hayenga@arm.com if (!ex_info.inFUMemInsts->empty() && 132311567Smitch.hayenga@arm.com ex_info.inFUMemInsts->front().inst == inst) 132410259SAndrew.Bardsley@arm.com { 132511567Smitch.hayenga@arm.com ex_info.inFUMemInsts->pop(); 132610259SAndrew.Bardsley@arm.com } 132710259SAndrew.Bardsley@arm.com } 132810259SAndrew.Bardsley@arm.com 132910259SAndrew.Bardsley@arm.com if (completed_inst && !(issued_mem_ref && fault == NoFault)) { 133010259SAndrew.Bardsley@arm.com /* Note that this includes discarded insts */ 133110259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Completed inst: %s\n", *inst); 133210259SAndrew.Bardsley@arm.com 133310259SAndrew.Bardsley@arm.com /* Got to the end of a full instruction? */ 133411567Smitch.hayenga@arm.com ex_info.lastCommitWasEndOfMacroop = inst->isFault() || 133510259SAndrew.Bardsley@arm.com inst->isLastOpInInst(); 133610259SAndrew.Bardsley@arm.com 133710259SAndrew.Bardsley@arm.com /* lastPredictionSeqNum is kept as a convenience to prevent its 133810259SAndrew.Bardsley@arm.com * value from changing too much on the minorview display */ 133911567Smitch.hayenga@arm.com ex_info.lastPredictionSeqNum = inst->id.predictionSeqNum; 134010259SAndrew.Bardsley@arm.com 134110259SAndrew.Bardsley@arm.com /* Finished with the inst, remove it from the inst queue and 134210259SAndrew.Bardsley@arm.com * clear its dependencies */ 134311567Smitch.hayenga@arm.com ex_info.inFlightInsts->pop(); 134410259SAndrew.Bardsley@arm.com 134510259SAndrew.Bardsley@arm.com /* Complete barriers in the LSQ/move to store buffer */ 134610259SAndrew.Bardsley@arm.com if (inst->isInst() && inst->staticInst->isMemBarrier()) { 134710259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Completing memory barrier" 134810259SAndrew.Bardsley@arm.com " inst: %s committed: %d\n", *inst, committed_inst); 134910259SAndrew.Bardsley@arm.com lsq.completeMemBarrierInst(inst, committed_inst); 135010259SAndrew.Bardsley@arm.com } 135110259SAndrew.Bardsley@arm.com 135211567Smitch.hayenga@arm.com scoreboard[thread_id].clearInstDests(inst, inst->isMemRef()); 135310259SAndrew.Bardsley@arm.com } 135410259SAndrew.Bardsley@arm.com 135510259SAndrew.Bardsley@arm.com /* Handle per-cycle instruction counting */ 135610259SAndrew.Bardsley@arm.com if (committed_inst) { 135710259SAndrew.Bardsley@arm.com bool is_no_cost_inst = inst->isNoCostInst(); 135810259SAndrew.Bardsley@arm.com 135910259SAndrew.Bardsley@arm.com /* Don't show no cost instructions as having taken a commit 136010259SAndrew.Bardsley@arm.com * slot */ 136110259SAndrew.Bardsley@arm.com if (DTRACE(MinorTrace) && !is_no_cost_inst) 136211567Smitch.hayenga@arm.com ex_info.instsBeingCommitted.insts[num_insts_committed] = inst; 136310259SAndrew.Bardsley@arm.com 136410259SAndrew.Bardsley@arm.com if (!is_no_cost_inst) 136510259SAndrew.Bardsley@arm.com num_insts_committed++; 136610259SAndrew.Bardsley@arm.com 136710259SAndrew.Bardsley@arm.com if (num_insts_committed == commitLimit) 136810259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Reached inst commit limit\n"); 136910259SAndrew.Bardsley@arm.com 137010259SAndrew.Bardsley@arm.com /* Re-set the time of the instruction if that's required for 137110259SAndrew.Bardsley@arm.com * tracing */ 137210259SAndrew.Bardsley@arm.com if (inst->traceData) { 137310259SAndrew.Bardsley@arm.com if (setTraceTimeOnCommit) 137410259SAndrew.Bardsley@arm.com inst->traceData->setWhen(curTick()); 137510259SAndrew.Bardsley@arm.com inst->traceData->dump(); 137610259SAndrew.Bardsley@arm.com } 137710259SAndrew.Bardsley@arm.com 137810259SAndrew.Bardsley@arm.com if (completed_mem_ref) 137910259SAndrew.Bardsley@arm.com num_mem_refs_committed++; 138010259SAndrew.Bardsley@arm.com 138110259SAndrew.Bardsley@arm.com if (num_mem_refs_committed == memoryCommitLimit) 138210259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Reached mem ref commit limit\n"); 138310259SAndrew.Bardsley@arm.com } 138410259SAndrew.Bardsley@arm.com } 138510259SAndrew.Bardsley@arm.com} 138610259SAndrew.Bardsley@arm.com 138710259SAndrew.Bardsley@arm.combool 138811567Smitch.hayenga@arm.comExecute::isInbetweenInsts(ThreadID thread_id) const 138910259SAndrew.Bardsley@arm.com{ 139011567Smitch.hayenga@arm.com return executeInfo[thread_id].lastCommitWasEndOfMacroop && 139110259SAndrew.Bardsley@arm.com !lsq.accessesInFlight(); 139210259SAndrew.Bardsley@arm.com} 139310259SAndrew.Bardsley@arm.com 139410259SAndrew.Bardsley@arm.comvoid 139510259SAndrew.Bardsley@arm.comExecute::evaluate() 139610259SAndrew.Bardsley@arm.com{ 139711567Smitch.hayenga@arm.com if (!inp.outputWire->isBubble()) 139811567Smitch.hayenga@arm.com inputBuffer[inp.outputWire->threadId].setTail(*inp.outputWire); 139911567Smitch.hayenga@arm.com 140010259SAndrew.Bardsley@arm.com BranchData &branch = *out.inputWire; 140110259SAndrew.Bardsley@arm.com 140211567Smitch.hayenga@arm.com unsigned int num_issued = 0; 140310259SAndrew.Bardsley@arm.com 140410259SAndrew.Bardsley@arm.com /* Do all the cycle-wise activities for dcachePort here to potentially 140510259SAndrew.Bardsley@arm.com * free up input spaces in the LSQ's requests queue */ 140610259SAndrew.Bardsley@arm.com lsq.step(); 140710259SAndrew.Bardsley@arm.com 140811567Smitch.hayenga@arm.com /* Check interrupts first. Will halt commit if interrupt found */ 140910259SAndrew.Bardsley@arm.com bool interrupted = false; 141011567Smitch.hayenga@arm.com ThreadID interrupt_tid = checkInterrupts(branch, interrupted); 141110259SAndrew.Bardsley@arm.com 141211567Smitch.hayenga@arm.com if (interrupt_tid != InvalidThreadID) { 141311567Smitch.hayenga@arm.com /* Signalling an interrupt this cycle, not issuing/committing from 141411567Smitch.hayenga@arm.com * any other threads */ 141510259SAndrew.Bardsley@arm.com } else if (!branch.isBubble()) { 141610259SAndrew.Bardsley@arm.com /* It's important that this is here to carry Fetch1 wakeups to Fetch1 141710259SAndrew.Bardsley@arm.com * without overwriting them */ 141810259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Execute skipping a cycle to allow old" 141910259SAndrew.Bardsley@arm.com " branch to complete\n"); 142010259SAndrew.Bardsley@arm.com } else { 142111567Smitch.hayenga@arm.com ThreadID commit_tid = getCommittingThread(); 142211567Smitch.hayenga@arm.com 142311567Smitch.hayenga@arm.com if (commit_tid != InvalidThreadID) { 142411567Smitch.hayenga@arm.com ExecuteThreadInfo& commit_info = executeInfo[commit_tid]; 142511567Smitch.hayenga@arm.com 142611567Smitch.hayenga@arm.com DPRINTF(MinorExecute, "Attempting to commit [tid:%d]\n", 142711567Smitch.hayenga@arm.com commit_tid); 142811567Smitch.hayenga@arm.com /* commit can set stalled flags observable to issue and so *must* be 142911567Smitch.hayenga@arm.com * called first */ 143011567Smitch.hayenga@arm.com if (commit_info.drainState != NotDraining) { 143111567Smitch.hayenga@arm.com if (commit_info.drainState == DrainCurrentInst) { 143211567Smitch.hayenga@arm.com /* Commit only micro-ops, don't kill anything else */ 143311567Smitch.hayenga@arm.com commit(commit_tid, true, false, branch); 143411567Smitch.hayenga@arm.com 143511567Smitch.hayenga@arm.com if (isInbetweenInsts(commit_tid)) 143611567Smitch.hayenga@arm.com setDrainState(commit_tid, DrainHaltFetch); 143711567Smitch.hayenga@arm.com 143811567Smitch.hayenga@arm.com /* Discard any generated branch */ 143911567Smitch.hayenga@arm.com branch = BranchData::bubble(); 144011567Smitch.hayenga@arm.com } else if (commit_info.drainState == DrainAllInsts) { 144111567Smitch.hayenga@arm.com /* Kill all instructions */ 144211567Smitch.hayenga@arm.com while (getInput(commit_tid)) 144311567Smitch.hayenga@arm.com popInput(commit_tid); 144411567Smitch.hayenga@arm.com commit(commit_tid, false, true, branch); 144511567Smitch.hayenga@arm.com } 144610259SAndrew.Bardsley@arm.com } else { 144711567Smitch.hayenga@arm.com /* Commit micro-ops only if interrupted. Otherwise, commit 144811567Smitch.hayenga@arm.com * anything you like */ 144911567Smitch.hayenga@arm.com DPRINTF(MinorExecute, "Committing micro-ops for interrupt[tid:%d]\n", 145011567Smitch.hayenga@arm.com commit_tid); 145111567Smitch.hayenga@arm.com bool only_commit_microops = interrupted && 145211567Smitch.hayenga@arm.com hasInterrupt(commit_tid); 145311567Smitch.hayenga@arm.com commit(commit_tid, only_commit_microops, false, branch); 145411567Smitch.hayenga@arm.com } 145511567Smitch.hayenga@arm.com 145611567Smitch.hayenga@arm.com /* Halt fetch, but don't do it until we have the current instruction in 145711567Smitch.hayenga@arm.com * the bag */ 145811567Smitch.hayenga@arm.com if (commit_info.drainState == DrainHaltFetch) { 145911567Smitch.hayenga@arm.com updateBranchData(commit_tid, BranchData::HaltFetch, 146011567Smitch.hayenga@arm.com MinorDynInst::bubble(), TheISA::PCState(0), branch); 146111567Smitch.hayenga@arm.com 146211567Smitch.hayenga@arm.com cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 146311567Smitch.hayenga@arm.com setDrainState(commit_tid, DrainAllInsts); 146410259SAndrew.Bardsley@arm.com } 146510259SAndrew.Bardsley@arm.com } 146611567Smitch.hayenga@arm.com ThreadID issue_tid = getIssuingThread(); 146711567Smitch.hayenga@arm.com /* This will issue merrily even when interrupted in the sure and 146811567Smitch.hayenga@arm.com * certain knowledge that the interrupt with change the stream */ 146911567Smitch.hayenga@arm.com if (issue_tid != InvalidThreadID) { 147011567Smitch.hayenga@arm.com DPRINTF(MinorExecute, "Attempting to issue [tid:%d]\n", 147111567Smitch.hayenga@arm.com issue_tid); 147211567Smitch.hayenga@arm.com num_issued = issue(issue_tid); 147310259SAndrew.Bardsley@arm.com } 147410259SAndrew.Bardsley@arm.com 147510259SAndrew.Bardsley@arm.com } 147610259SAndrew.Bardsley@arm.com 147711567Smitch.hayenga@arm.com /* Run logic to step functional units + decide if we are active on the next 147811567Smitch.hayenga@arm.com * clock cycle */ 147911567Smitch.hayenga@arm.com std::vector<MinorDynInstPtr> next_issuable_insts; 148010259SAndrew.Bardsley@arm.com bool can_issue_next = false; 148110259SAndrew.Bardsley@arm.com 148211567Smitch.hayenga@arm.com for (ThreadID tid = 0; tid < cpu.numThreads; tid++) { 148311567Smitch.hayenga@arm.com /* Find the next issuable instruction for each thread and see if it can 148411567Smitch.hayenga@arm.com be issued */ 148511567Smitch.hayenga@arm.com if (getInput(tid)) { 148611567Smitch.hayenga@arm.com unsigned int input_index = executeInfo[tid].inputIndex; 148711567Smitch.hayenga@arm.com MinorDynInstPtr inst = getInput(tid)->insts[input_index]; 148811567Smitch.hayenga@arm.com if (inst->isFault()) { 148911567Smitch.hayenga@arm.com can_issue_next = true; 149011567Smitch.hayenga@arm.com } else if (!inst->isBubble()) { 149111568Smitch.hayenga@arm.com next_issuable_insts.push_back(inst); 149210259SAndrew.Bardsley@arm.com } 149310259SAndrew.Bardsley@arm.com } 149410259SAndrew.Bardsley@arm.com } 149510259SAndrew.Bardsley@arm.com 149610259SAndrew.Bardsley@arm.com bool becoming_stalled = true; 149710259SAndrew.Bardsley@arm.com 149810259SAndrew.Bardsley@arm.com /* Advance the pipelines and note whether they still need to be 149911567Smitch.hayenga@arm.com * advanced */ 150010259SAndrew.Bardsley@arm.com for (unsigned int i = 0; i < numFuncUnits; i++) { 150110259SAndrew.Bardsley@arm.com FUPipeline *fu = funcUnits[i]; 150210259SAndrew.Bardsley@arm.com fu->advance(); 150310259SAndrew.Bardsley@arm.com 150411567Smitch.hayenga@arm.com /* If we need to tick again, the pipeline will have been left or set 150511567Smitch.hayenga@arm.com * to be unstalled */ 150611567Smitch.hayenga@arm.com if (fu->occupancy !=0 && !fu->stalled) 150710259SAndrew.Bardsley@arm.com becoming_stalled = false; 150810259SAndrew.Bardsley@arm.com 150911567Smitch.hayenga@arm.com /* Could we possibly issue the next instruction from any thread? 151011567Smitch.hayenga@arm.com * This is quite an expensive test and is only used to determine 151111567Smitch.hayenga@arm.com * if the CPU should remain active, only run it if we aren't sure 151211567Smitch.hayenga@arm.com * we are active next cycle yet */ 151311567Smitch.hayenga@arm.com for (auto inst : next_issuable_insts) { 151411567Smitch.hayenga@arm.com if (!fu->stalled && fu->provides(inst->staticInst->opClass()) && 151511567Smitch.hayenga@arm.com scoreboard[inst->id.threadId].canInstIssue(inst, 151611567Smitch.hayenga@arm.com NULL, NULL, cpu.curCycle() + Cycles(1), 151711567Smitch.hayenga@arm.com cpu.getContext(inst->id.threadId))) { 151811567Smitch.hayenga@arm.com can_issue_next = true; 151911567Smitch.hayenga@arm.com break; 152011567Smitch.hayenga@arm.com } 152110259SAndrew.Bardsley@arm.com } 152210259SAndrew.Bardsley@arm.com } 152310259SAndrew.Bardsley@arm.com 152410259SAndrew.Bardsley@arm.com bool head_inst_might_commit = false; 152510259SAndrew.Bardsley@arm.com 152610259SAndrew.Bardsley@arm.com /* Could the head in flight insts be committed */ 152711567Smitch.hayenga@arm.com for (auto const &info : executeInfo) { 152811567Smitch.hayenga@arm.com if (!info.inFlightInsts->empty()) { 152911567Smitch.hayenga@arm.com const QueuedInst &head_inst = info.inFlightInsts->front(); 153010259SAndrew.Bardsley@arm.com 153111567Smitch.hayenga@arm.com if (head_inst.inst->isNoCostInst()) { 153210259SAndrew.Bardsley@arm.com head_inst_might_commit = true; 153311567Smitch.hayenga@arm.com } else { 153411567Smitch.hayenga@arm.com FUPipeline *fu = funcUnits[head_inst.inst->fuIndex]; 153511567Smitch.hayenga@arm.com if ((fu->stalled && 153611567Smitch.hayenga@arm.com fu->front().inst->id == head_inst.inst->id) || 153711567Smitch.hayenga@arm.com lsq.findResponse(head_inst.inst)) 153811567Smitch.hayenga@arm.com { 153911567Smitch.hayenga@arm.com head_inst_might_commit = true; 154011567Smitch.hayenga@arm.com break; 154111567Smitch.hayenga@arm.com } 154210259SAndrew.Bardsley@arm.com } 154310259SAndrew.Bardsley@arm.com } 154410259SAndrew.Bardsley@arm.com } 154510259SAndrew.Bardsley@arm.com 154610259SAndrew.Bardsley@arm.com DPRINTF(Activity, "Need to tick num issued insts: %s%s%s%s%s%s\n", 154710259SAndrew.Bardsley@arm.com (num_issued != 0 ? " (issued some insts)" : ""), 154811567Smitch.hayenga@arm.com (becoming_stalled ? "(becoming stalled)" : "(not becoming stalled)"), 154910259SAndrew.Bardsley@arm.com (can_issue_next ? " (can issued next inst)" : ""), 155010259SAndrew.Bardsley@arm.com (head_inst_might_commit ? "(head inst might commit)" : ""), 155110259SAndrew.Bardsley@arm.com (lsq.needsToTick() ? " (LSQ needs to tick)" : ""), 155210259SAndrew.Bardsley@arm.com (interrupted ? " (interrupted)" : "")); 155310259SAndrew.Bardsley@arm.com 155410259SAndrew.Bardsley@arm.com bool need_to_tick = 155510259SAndrew.Bardsley@arm.com num_issued != 0 || /* Issued some insts this cycle */ 155610259SAndrew.Bardsley@arm.com !becoming_stalled || /* Some FU pipelines can still move */ 155710259SAndrew.Bardsley@arm.com can_issue_next || /* Can still issue a new inst */ 155810259SAndrew.Bardsley@arm.com head_inst_might_commit || /* Could possible commit the next inst */ 155910259SAndrew.Bardsley@arm.com lsq.needsToTick() || /* Must step the dcache port */ 156010259SAndrew.Bardsley@arm.com interrupted; /* There are pending interrupts */ 156110259SAndrew.Bardsley@arm.com 156210259SAndrew.Bardsley@arm.com if (!need_to_tick) { 156310259SAndrew.Bardsley@arm.com DPRINTF(Activity, "The next cycle might be skippable as there are no" 156410259SAndrew.Bardsley@arm.com " advanceable FUs\n"); 156510259SAndrew.Bardsley@arm.com } 156610259SAndrew.Bardsley@arm.com 156710259SAndrew.Bardsley@arm.com /* Wake up if we need to tick again */ 156810259SAndrew.Bardsley@arm.com if (need_to_tick) 156910259SAndrew.Bardsley@arm.com cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 157010259SAndrew.Bardsley@arm.com 157110259SAndrew.Bardsley@arm.com /* Note activity of following buffer */ 157210259SAndrew.Bardsley@arm.com if (!branch.isBubble()) 157310259SAndrew.Bardsley@arm.com cpu.activityRecorder->activity(); 157410259SAndrew.Bardsley@arm.com 157510259SAndrew.Bardsley@arm.com /* Make sure the input (if any left) is pushed */ 157611567Smitch.hayenga@arm.com if (!inp.outputWire->isBubble()) 157711567Smitch.hayenga@arm.com inputBuffer[inp.outputWire->threadId].pushTail(); 157810259SAndrew.Bardsley@arm.com} 157910259SAndrew.Bardsley@arm.com 158011567Smitch.hayenga@arm.comThreadID 158111567Smitch.hayenga@arm.comExecute::checkInterrupts(BranchData& branch, bool& interrupted) 158210259SAndrew.Bardsley@arm.com{ 158311567Smitch.hayenga@arm.com ThreadID tid = interruptPriority; 158411567Smitch.hayenga@arm.com /* Evaluate interrupts in round-robin based upon service */ 158511567Smitch.hayenga@arm.com do { 158611567Smitch.hayenga@arm.com /* Has an interrupt been signalled? This may not be acted on 158711567Smitch.hayenga@arm.com * straighaway so this is different from took_interrupt */ 158811567Smitch.hayenga@arm.com bool thread_interrupted = false; 158910259SAndrew.Bardsley@arm.com 159011567Smitch.hayenga@arm.com if (FullSystem && cpu.getInterruptController(tid)) { 159111567Smitch.hayenga@arm.com /* This is here because it seems that after drainResume the 159211567Smitch.hayenga@arm.com * interrupt controller isn't always set */ 159311567Smitch.hayenga@arm.com thread_interrupted = executeInfo[tid].drainState == NotDraining && 159411567Smitch.hayenga@arm.com isInterrupted(tid); 159511567Smitch.hayenga@arm.com interrupted = interrupted || thread_interrupted; 159611567Smitch.hayenga@arm.com } else { 159711567Smitch.hayenga@arm.com DPRINTF(MinorInterrupt, "No interrupt controller\n"); 159811567Smitch.hayenga@arm.com } 159911567Smitch.hayenga@arm.com DPRINTF(MinorInterrupt, "[tid:%d] thread_interrupted?=%d isInbetweenInsts?=%d\n", 160011567Smitch.hayenga@arm.com tid, thread_interrupted, isInbetweenInsts(tid)); 160111567Smitch.hayenga@arm.com /* Act on interrupts */ 160211567Smitch.hayenga@arm.com if (thread_interrupted && isInbetweenInsts(tid)) { 160311567Smitch.hayenga@arm.com if (takeInterrupt(tid, branch)) { 160411567Smitch.hayenga@arm.com interruptPriority = tid; 160511567Smitch.hayenga@arm.com return tid; 160611567Smitch.hayenga@arm.com } 160711567Smitch.hayenga@arm.com } else { 160811567Smitch.hayenga@arm.com tid = (tid + 1) % cpu.numThreads; 160911567Smitch.hayenga@arm.com } 161011567Smitch.hayenga@arm.com } while (tid != interruptPriority); 161110259SAndrew.Bardsley@arm.com 161211567Smitch.hayenga@arm.com return InvalidThreadID; 161311567Smitch.hayenga@arm.com} 161410259SAndrew.Bardsley@arm.com 161511567Smitch.hayenga@arm.combool 161611567Smitch.hayenga@arm.comExecute::hasInterrupt(ThreadID thread_id) 161711567Smitch.hayenga@arm.com{ 161811567Smitch.hayenga@arm.com if (FullSystem && cpu.getInterruptController(thread_id)) { 161911567Smitch.hayenga@arm.com return executeInfo[thread_id].drainState == NotDraining && 162011567Smitch.hayenga@arm.com isInterrupted(thread_id); 162110259SAndrew.Bardsley@arm.com } 162210259SAndrew.Bardsley@arm.com 162311567Smitch.hayenga@arm.com return false; 162410259SAndrew.Bardsley@arm.com} 162510259SAndrew.Bardsley@arm.com 162610259SAndrew.Bardsley@arm.comvoid 162710259SAndrew.Bardsley@arm.comExecute::minorTrace() const 162810259SAndrew.Bardsley@arm.com{ 162910259SAndrew.Bardsley@arm.com std::ostringstream insts; 163010259SAndrew.Bardsley@arm.com std::ostringstream stalled; 163110259SAndrew.Bardsley@arm.com 163211567Smitch.hayenga@arm.com executeInfo[0].instsBeingCommitted.reportData(insts); 163310259SAndrew.Bardsley@arm.com lsq.minorTrace(); 163411567Smitch.hayenga@arm.com inputBuffer[0].minorTrace(); 163511567Smitch.hayenga@arm.com scoreboard[0].minorTrace(); 163610259SAndrew.Bardsley@arm.com 163710259SAndrew.Bardsley@arm.com /* Report functional unit stalling in one string */ 163810259SAndrew.Bardsley@arm.com unsigned int i = 0; 163910259SAndrew.Bardsley@arm.com while (i < numFuncUnits) 164010259SAndrew.Bardsley@arm.com { 164110259SAndrew.Bardsley@arm.com stalled << (funcUnits[i]->stalled ? '1' : 'E'); 164210259SAndrew.Bardsley@arm.com i++; 164310259SAndrew.Bardsley@arm.com if (i != numFuncUnits) 164410259SAndrew.Bardsley@arm.com stalled << ','; 164510259SAndrew.Bardsley@arm.com } 164610259SAndrew.Bardsley@arm.com 164710259SAndrew.Bardsley@arm.com MINORTRACE("insts=%s inputIndex=%d streamSeqNum=%d" 164810259SAndrew.Bardsley@arm.com " stalled=%s drainState=%d isInbetweenInsts=%d\n", 164911567Smitch.hayenga@arm.com insts.str(), executeInfo[0].inputIndex, executeInfo[0].streamSeqNum, 165011567Smitch.hayenga@arm.com stalled.str(), executeInfo[0].drainState, isInbetweenInsts(0)); 165110259SAndrew.Bardsley@arm.com 165210259SAndrew.Bardsley@arm.com std::for_each(funcUnits.begin(), funcUnits.end(), 165310259SAndrew.Bardsley@arm.com std::mem_fun(&FUPipeline::minorTrace)); 165410259SAndrew.Bardsley@arm.com 165511567Smitch.hayenga@arm.com executeInfo[0].inFlightInsts->minorTrace(); 165611567Smitch.hayenga@arm.com executeInfo[0].inFUMemInsts->minorTrace(); 165711567Smitch.hayenga@arm.com} 165811567Smitch.hayenga@arm.com 165911567Smitch.hayenga@arm.cominline ThreadID 166011567Smitch.hayenga@arm.comExecute::getCommittingThread() 166111567Smitch.hayenga@arm.com{ 166211567Smitch.hayenga@arm.com std::vector<ThreadID> priority_list; 166311567Smitch.hayenga@arm.com 166411567Smitch.hayenga@arm.com switch (cpu.threadPolicy) { 166511567Smitch.hayenga@arm.com case Enums::SingleThreaded: 166611567Smitch.hayenga@arm.com return 0; 166711567Smitch.hayenga@arm.com case Enums::RoundRobin: 166811567Smitch.hayenga@arm.com priority_list = cpu.roundRobinPriority(commitPriority); 166911567Smitch.hayenga@arm.com break; 167011567Smitch.hayenga@arm.com case Enums::Random: 167111567Smitch.hayenga@arm.com priority_list = cpu.randomPriority(); 167211567Smitch.hayenga@arm.com break; 167311567Smitch.hayenga@arm.com default: 167411567Smitch.hayenga@arm.com panic("Invalid thread policy"); 167511567Smitch.hayenga@arm.com } 167611567Smitch.hayenga@arm.com 167711567Smitch.hayenga@arm.com for (auto tid : priority_list) { 167811567Smitch.hayenga@arm.com ExecuteThreadInfo &ex_info = executeInfo[tid]; 167911567Smitch.hayenga@arm.com bool can_commit_insts = !ex_info.inFlightInsts->empty(); 168011567Smitch.hayenga@arm.com if (can_commit_insts) { 168111567Smitch.hayenga@arm.com QueuedInst *head_inflight_inst = &(ex_info.inFlightInsts->front()); 168211567Smitch.hayenga@arm.com MinorDynInstPtr inst = head_inflight_inst->inst; 168311567Smitch.hayenga@arm.com 168411567Smitch.hayenga@arm.com can_commit_insts = can_commit_insts && 168511567Smitch.hayenga@arm.com (!inst->inLSQ || (lsq.findResponse(inst) != NULL)); 168611567Smitch.hayenga@arm.com 168711567Smitch.hayenga@arm.com if (!inst->inLSQ) { 168811567Smitch.hayenga@arm.com bool can_transfer_mem_inst = false; 168911567Smitch.hayenga@arm.com if (!ex_info.inFUMemInsts->empty() && lsq.canRequest()) { 169011567Smitch.hayenga@arm.com const MinorDynInstPtr head_mem_ref_inst = 169111567Smitch.hayenga@arm.com ex_info.inFUMemInsts->front().inst; 169211567Smitch.hayenga@arm.com FUPipeline *fu = funcUnits[head_mem_ref_inst->fuIndex]; 169311567Smitch.hayenga@arm.com const MinorDynInstPtr &fu_inst = fu->front().inst; 169411567Smitch.hayenga@arm.com can_transfer_mem_inst = 169511567Smitch.hayenga@arm.com !fu_inst->isBubble() && 169611567Smitch.hayenga@arm.com fu_inst->id.threadId == tid && 169711567Smitch.hayenga@arm.com !fu_inst->inLSQ && 169811567Smitch.hayenga@arm.com fu_inst->canEarlyIssue && 169911567Smitch.hayenga@arm.com inst->id.execSeqNum > fu_inst->instToWaitFor; 170011567Smitch.hayenga@arm.com } 170111567Smitch.hayenga@arm.com 170211567Smitch.hayenga@arm.com bool can_execute_fu_inst = inst->fuIndex == noCostFUIndex; 170311567Smitch.hayenga@arm.com if (can_commit_insts && !can_transfer_mem_inst && 170411567Smitch.hayenga@arm.com inst->fuIndex != noCostFUIndex) 170511567Smitch.hayenga@arm.com { 170611567Smitch.hayenga@arm.com QueuedInst& fu_inst = funcUnits[inst->fuIndex]->front(); 170711567Smitch.hayenga@arm.com can_execute_fu_inst = !fu_inst.inst->isBubble() && 170811567Smitch.hayenga@arm.com fu_inst.inst->id == inst->id; 170911567Smitch.hayenga@arm.com } 171011567Smitch.hayenga@arm.com 171111567Smitch.hayenga@arm.com can_commit_insts = can_commit_insts && 171211567Smitch.hayenga@arm.com (can_transfer_mem_inst || can_execute_fu_inst); 171311567Smitch.hayenga@arm.com } 171411567Smitch.hayenga@arm.com } 171511567Smitch.hayenga@arm.com 171611567Smitch.hayenga@arm.com 171711567Smitch.hayenga@arm.com if (can_commit_insts) { 171811567Smitch.hayenga@arm.com commitPriority = tid; 171911567Smitch.hayenga@arm.com return tid; 172011567Smitch.hayenga@arm.com } 172111567Smitch.hayenga@arm.com } 172211567Smitch.hayenga@arm.com 172311567Smitch.hayenga@arm.com return InvalidThreadID; 172411567Smitch.hayenga@arm.com} 172511567Smitch.hayenga@arm.com 172611567Smitch.hayenga@arm.cominline ThreadID 172711567Smitch.hayenga@arm.comExecute::getIssuingThread() 172811567Smitch.hayenga@arm.com{ 172911567Smitch.hayenga@arm.com std::vector<ThreadID> priority_list; 173011567Smitch.hayenga@arm.com 173111567Smitch.hayenga@arm.com switch (cpu.threadPolicy) { 173211567Smitch.hayenga@arm.com case Enums::SingleThreaded: 173311567Smitch.hayenga@arm.com return 0; 173411567Smitch.hayenga@arm.com case Enums::RoundRobin: 173511567Smitch.hayenga@arm.com priority_list = cpu.roundRobinPriority(issuePriority); 173611567Smitch.hayenga@arm.com break; 173711567Smitch.hayenga@arm.com case Enums::Random: 173811567Smitch.hayenga@arm.com priority_list = cpu.randomPriority(); 173911567Smitch.hayenga@arm.com break; 174011567Smitch.hayenga@arm.com default: 174111567Smitch.hayenga@arm.com panic("Invalid thread scheduling policy."); 174211567Smitch.hayenga@arm.com } 174311567Smitch.hayenga@arm.com 174411567Smitch.hayenga@arm.com for (auto tid : priority_list) { 174511568Smitch.hayenga@arm.com if (getInput(tid)) { 174611567Smitch.hayenga@arm.com issuePriority = tid; 174711567Smitch.hayenga@arm.com return tid; 174811567Smitch.hayenga@arm.com } 174911567Smitch.hayenga@arm.com } 175011567Smitch.hayenga@arm.com 175111567Smitch.hayenga@arm.com return InvalidThreadID; 175210259SAndrew.Bardsley@arm.com} 175310259SAndrew.Bardsley@arm.com 175410259SAndrew.Bardsley@arm.comvoid 175510259SAndrew.Bardsley@arm.comExecute::drainResume() 175610259SAndrew.Bardsley@arm.com{ 175710259SAndrew.Bardsley@arm.com DPRINTF(Drain, "MinorExecute drainResume\n"); 175810259SAndrew.Bardsley@arm.com 175911567Smitch.hayenga@arm.com for (ThreadID tid = 0; tid < cpu.numThreads; tid++) { 176011567Smitch.hayenga@arm.com setDrainState(tid, NotDraining); 176111567Smitch.hayenga@arm.com } 176210259SAndrew.Bardsley@arm.com 176310259SAndrew.Bardsley@arm.com cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 176410259SAndrew.Bardsley@arm.com} 176510259SAndrew.Bardsley@arm.com 176610259SAndrew.Bardsley@arm.comstd::ostream &operator <<(std::ostream &os, Execute::DrainState state) 176710259SAndrew.Bardsley@arm.com{ 176810259SAndrew.Bardsley@arm.com switch (state) 176910259SAndrew.Bardsley@arm.com { 177010259SAndrew.Bardsley@arm.com case Execute::NotDraining: 177110259SAndrew.Bardsley@arm.com os << "NotDraining"; 177210259SAndrew.Bardsley@arm.com break; 177310259SAndrew.Bardsley@arm.com case Execute::DrainCurrentInst: 177410259SAndrew.Bardsley@arm.com os << "DrainCurrentInst"; 177510259SAndrew.Bardsley@arm.com break; 177610259SAndrew.Bardsley@arm.com case Execute::DrainHaltFetch: 177710259SAndrew.Bardsley@arm.com os << "DrainHaltFetch"; 177810259SAndrew.Bardsley@arm.com break; 177910259SAndrew.Bardsley@arm.com case Execute::DrainAllInsts: 178010259SAndrew.Bardsley@arm.com os << "DrainAllInsts"; 178110259SAndrew.Bardsley@arm.com break; 178210259SAndrew.Bardsley@arm.com default: 178310259SAndrew.Bardsley@arm.com os << "Drain-" << static_cast<int>(state); 178410259SAndrew.Bardsley@arm.com break; 178510259SAndrew.Bardsley@arm.com } 178610259SAndrew.Bardsley@arm.com 178710259SAndrew.Bardsley@arm.com return os; 178810259SAndrew.Bardsley@arm.com} 178910259SAndrew.Bardsley@arm.com 179010259SAndrew.Bardsley@arm.comvoid 179111567Smitch.hayenga@arm.comExecute::setDrainState(ThreadID thread_id, DrainState state) 179210259SAndrew.Bardsley@arm.com{ 179311567Smitch.hayenga@arm.com DPRINTF(Drain, "setDrainState[%d]: %s\n", thread_id, state); 179411567Smitch.hayenga@arm.com executeInfo[thread_id].drainState = state; 179510259SAndrew.Bardsley@arm.com} 179610259SAndrew.Bardsley@arm.com 179710259SAndrew.Bardsley@arm.comunsigned int 179810259SAndrew.Bardsley@arm.comExecute::drain() 179910259SAndrew.Bardsley@arm.com{ 180010259SAndrew.Bardsley@arm.com DPRINTF(Drain, "MinorExecute drain\n"); 180110259SAndrew.Bardsley@arm.com 180211567Smitch.hayenga@arm.com for (ThreadID tid = 0; tid < cpu.numThreads; tid++) { 180311567Smitch.hayenga@arm.com if (executeInfo[tid].drainState == NotDraining) { 180411567Smitch.hayenga@arm.com cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 180510259SAndrew.Bardsley@arm.com 180611567Smitch.hayenga@arm.com /* Go to DrainCurrentInst if we're between microops 180711567Smitch.hayenga@arm.com * or waiting on an unbufferable memory operation. 180811567Smitch.hayenga@arm.com * Otherwise we can go straight to DrainHaltFetch 180911567Smitch.hayenga@arm.com */ 181011567Smitch.hayenga@arm.com if (isInbetweenInsts(tid)) 181111567Smitch.hayenga@arm.com setDrainState(tid, DrainHaltFetch); 181211567Smitch.hayenga@arm.com else 181311567Smitch.hayenga@arm.com setDrainState(tid, DrainCurrentInst); 181411567Smitch.hayenga@arm.com } 181510259SAndrew.Bardsley@arm.com } 181610259SAndrew.Bardsley@arm.com return (isDrained() ? 0 : 1); 181710259SAndrew.Bardsley@arm.com} 181810259SAndrew.Bardsley@arm.com 181910259SAndrew.Bardsley@arm.combool 182010259SAndrew.Bardsley@arm.comExecute::isDrained() 182110259SAndrew.Bardsley@arm.com{ 182211567Smitch.hayenga@arm.com if (!lsq.isDrained()) 182311567Smitch.hayenga@arm.com return false; 182411567Smitch.hayenga@arm.com 182511567Smitch.hayenga@arm.com for (ThreadID tid = 0; tid < cpu.numThreads; tid++) { 182611568Smitch.hayenga@arm.com if (!inputBuffer[tid].empty() || 182711567Smitch.hayenga@arm.com !executeInfo[tid].inFlightInsts->empty()) { 182811567Smitch.hayenga@arm.com 182911567Smitch.hayenga@arm.com return false; 183011567Smitch.hayenga@arm.com } 183111567Smitch.hayenga@arm.com } 183211567Smitch.hayenga@arm.com 183311567Smitch.hayenga@arm.com return true; 183410259SAndrew.Bardsley@arm.com} 183510259SAndrew.Bardsley@arm.com 183610259SAndrew.Bardsley@arm.comExecute::~Execute() 183710259SAndrew.Bardsley@arm.com{ 183810259SAndrew.Bardsley@arm.com for (unsigned int i = 0; i < numFuncUnits; i++) 183910259SAndrew.Bardsley@arm.com delete funcUnits[i]; 184010259SAndrew.Bardsley@arm.com 184111567Smitch.hayenga@arm.com for (ThreadID tid = 0; tid < cpu.numThreads; tid++) 184211567Smitch.hayenga@arm.com delete executeInfo[tid].inFlightInsts; 184310259SAndrew.Bardsley@arm.com} 184410259SAndrew.Bardsley@arm.com 184510259SAndrew.Bardsley@arm.combool 184610259SAndrew.Bardsley@arm.comExecute::instIsRightStream(MinorDynInstPtr inst) 184710259SAndrew.Bardsley@arm.com{ 184811567Smitch.hayenga@arm.com return inst->id.streamSeqNum == executeInfo[inst->id.threadId].streamSeqNum; 184910259SAndrew.Bardsley@arm.com} 185010259SAndrew.Bardsley@arm.com 185110259SAndrew.Bardsley@arm.combool 185210259SAndrew.Bardsley@arm.comExecute::instIsHeadInst(MinorDynInstPtr inst) 185310259SAndrew.Bardsley@arm.com{ 185410259SAndrew.Bardsley@arm.com bool ret = false; 185510259SAndrew.Bardsley@arm.com 185611567Smitch.hayenga@arm.com if (!executeInfo[inst->id.threadId].inFlightInsts->empty()) 185711567Smitch.hayenga@arm.com ret = executeInfo[inst->id.threadId].inFlightInsts->front().inst->id == inst->id; 185810259SAndrew.Bardsley@arm.com 185910259SAndrew.Bardsley@arm.com return ret; 186010259SAndrew.Bardsley@arm.com} 186110259SAndrew.Bardsley@arm.com 186210259SAndrew.Bardsley@arm.comMinorCPU::MinorCPUPort & 186310259SAndrew.Bardsley@arm.comExecute::getDcachePort() 186410259SAndrew.Bardsley@arm.com{ 186510259SAndrew.Bardsley@arm.com return lsq.getDcachePort(); 186610259SAndrew.Bardsley@arm.com} 186710259SAndrew.Bardsley@arm.com 186810259SAndrew.Bardsley@arm.com} 1869