execute.cc revision 11567
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 4010259SAndrew.Bardsley@arm.com#include "arch/locked_mem.hh" 4110259SAndrew.Bardsley@arm.com#include "arch/registers.hh" 4210259SAndrew.Bardsley@arm.com#include "arch/utility.hh" 4310259SAndrew.Bardsley@arm.com#include "cpu/minor/cpu.hh" 4410259SAndrew.Bardsley@arm.com#include "cpu/minor/exec_context.hh" 4510259SAndrew.Bardsley@arm.com#include "cpu/minor/execute.hh" 4610259SAndrew.Bardsley@arm.com#include "cpu/minor/fetch1.hh" 4710259SAndrew.Bardsley@arm.com#include "cpu/minor/lsq.hh" 4810259SAndrew.Bardsley@arm.com#include "cpu/op_class.hh" 4910259SAndrew.Bardsley@arm.com#include "debug/Activity.hh" 5010259SAndrew.Bardsley@arm.com#include "debug/Branch.hh" 5110259SAndrew.Bardsley@arm.com#include "debug/Drain.hh" 5210259SAndrew.Bardsley@arm.com#include "debug/MinorExecute.hh" 5310259SAndrew.Bardsley@arm.com#include "debug/MinorInterrupt.hh" 5410259SAndrew.Bardsley@arm.com#include "debug/MinorMem.hh" 5510259SAndrew.Bardsley@arm.com#include "debug/MinorTrace.hh" 5610259SAndrew.Bardsley@arm.com#include "debug/PCEvent.hh" 5710259SAndrew.Bardsley@arm.com 5810259SAndrew.Bardsley@arm.comnamespace Minor 5910259SAndrew.Bardsley@arm.com{ 6010259SAndrew.Bardsley@arm.com 6110259SAndrew.Bardsley@arm.comExecute::Execute(const std::string &name_, 6210259SAndrew.Bardsley@arm.com MinorCPU &cpu_, 6310259SAndrew.Bardsley@arm.com MinorCPUParams ¶ms, 6410259SAndrew.Bardsley@arm.com Latch<ForwardInstData>::Output inp_, 6510259SAndrew.Bardsley@arm.com Latch<BranchData>::Input out_) : 6610259SAndrew.Bardsley@arm.com Named(name_), 6710259SAndrew.Bardsley@arm.com inp(inp_), 6810259SAndrew.Bardsley@arm.com out(out_), 6910259SAndrew.Bardsley@arm.com cpu(cpu_), 7010259SAndrew.Bardsley@arm.com issueLimit(params.executeIssueLimit), 7110259SAndrew.Bardsley@arm.com memoryIssueLimit(params.executeMemoryIssueLimit), 7210259SAndrew.Bardsley@arm.com commitLimit(params.executeCommitLimit), 7310259SAndrew.Bardsley@arm.com memoryCommitLimit(params.executeMemoryCommitLimit), 7410259SAndrew.Bardsley@arm.com processMoreThanOneInput(params.executeCycleInput), 7510259SAndrew.Bardsley@arm.com fuDescriptions(*params.executeFuncUnits), 7610259SAndrew.Bardsley@arm.com numFuncUnits(fuDescriptions.funcUnits.size()), 7710259SAndrew.Bardsley@arm.com setTraceTimeOnCommit(params.executeSetTraceTimeOnCommit), 7810259SAndrew.Bardsley@arm.com setTraceTimeOnIssue(params.executeSetTraceTimeOnIssue), 7910259SAndrew.Bardsley@arm.com allowEarlyMemIssue(params.executeAllowEarlyMemoryIssue), 8010259SAndrew.Bardsley@arm.com noCostFUIndex(fuDescriptions.funcUnits.size() + 1), 8110259SAndrew.Bardsley@arm.com lsq(name_ + ".lsq", name_ + ".dcache_port", 8210259SAndrew.Bardsley@arm.com cpu_, *this, 8310259SAndrew.Bardsley@arm.com params.executeMaxAccessesInMemory, 8410259SAndrew.Bardsley@arm.com params.executeMemoryWidth, 8510259SAndrew.Bardsley@arm.com params.executeLSQRequestsQueueSize, 8610259SAndrew.Bardsley@arm.com params.executeLSQTransfersQueueSize, 8710259SAndrew.Bardsley@arm.com params.executeLSQStoreBufferSize, 8810259SAndrew.Bardsley@arm.com params.executeLSQMaxStoreBufferStoresPerCycle), 8911567Smitch.hayenga@arm.com executeInfo(params.numThreads, ExecuteThreadInfo(params.executeCommitLimit)), 9011567Smitch.hayenga@arm.com interruptPriority(0), 9111567Smitch.hayenga@arm.com issuePriority(0), 9211567Smitch.hayenga@arm.com commitPriority(0) 9310259SAndrew.Bardsley@arm.com{ 9410259SAndrew.Bardsley@arm.com if (commitLimit < 1) { 9510259SAndrew.Bardsley@arm.com fatal("%s: executeCommitLimit must be >= 1 (%d)\n", name_, 9610259SAndrew.Bardsley@arm.com commitLimit); 9710259SAndrew.Bardsley@arm.com } 9810259SAndrew.Bardsley@arm.com 9910259SAndrew.Bardsley@arm.com if (issueLimit < 1) { 10010259SAndrew.Bardsley@arm.com fatal("%s: executeCommitLimit must be >= 1 (%d)\n", name_, 10110259SAndrew.Bardsley@arm.com issueLimit); 10210259SAndrew.Bardsley@arm.com } 10310259SAndrew.Bardsley@arm.com 10410259SAndrew.Bardsley@arm.com if (memoryIssueLimit < 1) { 10510259SAndrew.Bardsley@arm.com fatal("%s: executeMemoryIssueLimit must be >= 1 (%d)\n", name_, 10610259SAndrew.Bardsley@arm.com memoryIssueLimit); 10710259SAndrew.Bardsley@arm.com } 10810259SAndrew.Bardsley@arm.com 10910259SAndrew.Bardsley@arm.com if (memoryCommitLimit > commitLimit) { 11010259SAndrew.Bardsley@arm.com fatal("%s: executeMemoryCommitLimit (%d) must be <=" 11110259SAndrew.Bardsley@arm.com " executeCommitLimit (%d)\n", 11210259SAndrew.Bardsley@arm.com name_, memoryCommitLimit, commitLimit); 11310259SAndrew.Bardsley@arm.com } 11410259SAndrew.Bardsley@arm.com 11510259SAndrew.Bardsley@arm.com if (params.executeInputBufferSize < 1) { 11610259SAndrew.Bardsley@arm.com fatal("%s: executeInputBufferSize must be >= 1 (%d)\n", name_, 11710259SAndrew.Bardsley@arm.com params.executeInputBufferSize); 11810259SAndrew.Bardsley@arm.com } 11910259SAndrew.Bardsley@arm.com 12010259SAndrew.Bardsley@arm.com if (params.executeInputBufferSize < 1) { 12110259SAndrew.Bardsley@arm.com fatal("%s: executeInputBufferSize must be >= 1 (%d)\n", name_, 12210259SAndrew.Bardsley@arm.com params.executeInputBufferSize); 12310259SAndrew.Bardsley@arm.com } 12410259SAndrew.Bardsley@arm.com 12510259SAndrew.Bardsley@arm.com /* This should be large enough to count all the in-FU instructions 12610259SAndrew.Bardsley@arm.com * which need to be accounted for in the inFlightInsts 12710259SAndrew.Bardsley@arm.com * queue */ 12810259SAndrew.Bardsley@arm.com unsigned int total_slots = 0; 12910259SAndrew.Bardsley@arm.com 13010259SAndrew.Bardsley@arm.com /* Make FUPipelines for each MinorFU */ 13110259SAndrew.Bardsley@arm.com for (unsigned int i = 0; i < numFuncUnits; i++) { 13210259SAndrew.Bardsley@arm.com std::ostringstream fu_name; 13310259SAndrew.Bardsley@arm.com MinorFU *fu_description = fuDescriptions.funcUnits[i]; 13410259SAndrew.Bardsley@arm.com 13510259SAndrew.Bardsley@arm.com /* Note the total number of instruction slots (for sizing 13610259SAndrew.Bardsley@arm.com * the inFlightInst queue) and the maximum latency of any FU 13710259SAndrew.Bardsley@arm.com * (for sizing the activity recorder) */ 13810259SAndrew.Bardsley@arm.com total_slots += fu_description->opLat; 13910259SAndrew.Bardsley@arm.com 14010259SAndrew.Bardsley@arm.com fu_name << name_ << ".fu." << i; 14110259SAndrew.Bardsley@arm.com 14210259SAndrew.Bardsley@arm.com FUPipeline *fu = new FUPipeline(fu_name.str(), *fu_description, cpu); 14310259SAndrew.Bardsley@arm.com 14410259SAndrew.Bardsley@arm.com funcUnits.push_back(fu); 14510259SAndrew.Bardsley@arm.com } 14610259SAndrew.Bardsley@arm.com 14710259SAndrew.Bardsley@arm.com /** Check that there is a functional unit for all operation classes */ 14810814Sandreas.hansson@arm.com for (int op_class = No_OpClass + 1; op_class < Num_OpClasses; op_class++) { 14910259SAndrew.Bardsley@arm.com bool found_fu = false; 15010259SAndrew.Bardsley@arm.com unsigned int fu_index = 0; 15110259SAndrew.Bardsley@arm.com 15210259SAndrew.Bardsley@arm.com while (fu_index < numFuncUnits && !found_fu) 15310259SAndrew.Bardsley@arm.com { 15410259SAndrew.Bardsley@arm.com if (funcUnits[fu_index]->provides( 15510259SAndrew.Bardsley@arm.com static_cast<OpClass>(op_class))) 15610259SAndrew.Bardsley@arm.com { 15710259SAndrew.Bardsley@arm.com found_fu = true; 15810259SAndrew.Bardsley@arm.com } 15910259SAndrew.Bardsley@arm.com fu_index++; 16010259SAndrew.Bardsley@arm.com } 16110259SAndrew.Bardsley@arm.com 16210259SAndrew.Bardsley@arm.com if (!found_fu) { 16310259SAndrew.Bardsley@arm.com warn("No functional unit for OpClass %s\n", 16410259SAndrew.Bardsley@arm.com Enums::OpClassStrings[op_class]); 16510259SAndrew.Bardsley@arm.com } 16610259SAndrew.Bardsley@arm.com } 16710259SAndrew.Bardsley@arm.com 16811567Smitch.hayenga@arm.com /* Per-thread structures */ 16911567Smitch.hayenga@arm.com for (ThreadID tid = 0; tid < params.numThreads; tid++) { 17011567Smitch.hayenga@arm.com std::string tid_str = std::to_string(tid); 17110259SAndrew.Bardsley@arm.com 17211567Smitch.hayenga@arm.com /* Input Buffers */ 17311567Smitch.hayenga@arm.com inputBuffer.push_back( 17411567Smitch.hayenga@arm.com InputBuffer<ForwardInstData>( 17511567Smitch.hayenga@arm.com name_ + ".inputBuffer" + tid_str, "insts", 17611567Smitch.hayenga@arm.com params.executeInputBufferSize)); 17711567Smitch.hayenga@arm.com 17811567Smitch.hayenga@arm.com /* Scoreboards */ 17911567Smitch.hayenga@arm.com scoreboard.push_back(Scoreboard(name_ + ".scoreboard" + tid_str)); 18011567Smitch.hayenga@arm.com 18111567Smitch.hayenga@arm.com /* In-flight instruction records */ 18211567Smitch.hayenga@arm.com executeInfo[tid].inFlightInsts = new Queue<QueuedInst, 18311567Smitch.hayenga@arm.com ReportTraitsAdaptor<QueuedInst> >( 18411567Smitch.hayenga@arm.com name_ + ".inFlightInsts" + tid_str, "insts", total_slots); 18511567Smitch.hayenga@arm.com 18611567Smitch.hayenga@arm.com executeInfo[tid].inFUMemInsts = new Queue<QueuedInst, 18711567Smitch.hayenga@arm.com ReportTraitsAdaptor<QueuedInst> >( 18811567Smitch.hayenga@arm.com name_ + ".inFUMemInsts" + tid_str, "insts", total_slots); 18911567Smitch.hayenga@arm.com } 19010259SAndrew.Bardsley@arm.com} 19110259SAndrew.Bardsley@arm.com 19210259SAndrew.Bardsley@arm.comconst ForwardInstData * 19311567Smitch.hayenga@arm.comExecute::getInput(ThreadID tid) 19410259SAndrew.Bardsley@arm.com{ 19510259SAndrew.Bardsley@arm.com /* Get a line from the inputBuffer to work with */ 19611567Smitch.hayenga@arm.com if (!inputBuffer[tid].empty()) { 19711567Smitch.hayenga@arm.com const ForwardInstData &head = inputBuffer[tid].front(); 19810259SAndrew.Bardsley@arm.com 19911567Smitch.hayenga@arm.com return (head.isBubble() ? NULL : &(inputBuffer[tid].front())); 20010259SAndrew.Bardsley@arm.com } else { 20110259SAndrew.Bardsley@arm.com return NULL; 20210259SAndrew.Bardsley@arm.com } 20310259SAndrew.Bardsley@arm.com} 20410259SAndrew.Bardsley@arm.com 20510259SAndrew.Bardsley@arm.comvoid 20611567Smitch.hayenga@arm.comExecute::popInput(ThreadID tid) 20710259SAndrew.Bardsley@arm.com{ 20811567Smitch.hayenga@arm.com if (!inputBuffer[tid].empty()) 20911567Smitch.hayenga@arm.com inputBuffer[tid].pop(); 21010259SAndrew.Bardsley@arm.com 21111567Smitch.hayenga@arm.com executeInfo[tid].inputIndex = 0; 21210259SAndrew.Bardsley@arm.com} 21310259SAndrew.Bardsley@arm.com 21410259SAndrew.Bardsley@arm.comvoid 21510259SAndrew.Bardsley@arm.comExecute::tryToBranch(MinorDynInstPtr inst, Fault fault, BranchData &branch) 21610259SAndrew.Bardsley@arm.com{ 21710259SAndrew.Bardsley@arm.com ThreadContext *thread = cpu.getContext(inst->id.threadId); 21810259SAndrew.Bardsley@arm.com const TheISA::PCState &pc_before = inst->pc; 21910259SAndrew.Bardsley@arm.com TheISA::PCState target = thread->pcState(); 22010259SAndrew.Bardsley@arm.com 22110259SAndrew.Bardsley@arm.com /* Force a branch for SerializeAfter instructions at the end of micro-op 22210259SAndrew.Bardsley@arm.com * sequence when we're not suspended */ 22310259SAndrew.Bardsley@arm.com bool force_branch = thread->status() != ThreadContext::Suspended && 22410259SAndrew.Bardsley@arm.com !inst->isFault() && 22510259SAndrew.Bardsley@arm.com inst->isLastOpInInst() && 22610259SAndrew.Bardsley@arm.com (inst->staticInst->isSerializeAfter() || 22710259SAndrew.Bardsley@arm.com inst->staticInst->isIprAccess()); 22810259SAndrew.Bardsley@arm.com 22910259SAndrew.Bardsley@arm.com DPRINTF(Branch, "tryToBranch before: %s after: %s%s\n", 23010259SAndrew.Bardsley@arm.com pc_before, target, (force_branch ? " (forcing)" : "")); 23110259SAndrew.Bardsley@arm.com 23210259SAndrew.Bardsley@arm.com /* Will we change the PC to something other than the next instruction? */ 23310259SAndrew.Bardsley@arm.com bool must_branch = pc_before != target || 23410259SAndrew.Bardsley@arm.com fault != NoFault || 23510259SAndrew.Bardsley@arm.com force_branch; 23610259SAndrew.Bardsley@arm.com 23710259SAndrew.Bardsley@arm.com /* The reason for the branch data we're about to generate, set below */ 23810259SAndrew.Bardsley@arm.com BranchData::Reason reason = BranchData::NoBranch; 23910259SAndrew.Bardsley@arm.com 24010259SAndrew.Bardsley@arm.com if (fault == NoFault) 24110259SAndrew.Bardsley@arm.com { 24210259SAndrew.Bardsley@arm.com TheISA::advancePC(target, inst->staticInst); 24310259SAndrew.Bardsley@arm.com thread->pcState(target); 24410259SAndrew.Bardsley@arm.com 24510259SAndrew.Bardsley@arm.com DPRINTF(Branch, "Advancing current PC from: %s to: %s\n", 24610259SAndrew.Bardsley@arm.com pc_before, target); 24710259SAndrew.Bardsley@arm.com } 24810259SAndrew.Bardsley@arm.com 24910259SAndrew.Bardsley@arm.com if (inst->predictedTaken && !force_branch) { 25010259SAndrew.Bardsley@arm.com /* Predicted to branch */ 25110259SAndrew.Bardsley@arm.com if (!must_branch) { 25210259SAndrew.Bardsley@arm.com /* No branch was taken, change stream to get us back to the 25310259SAndrew.Bardsley@arm.com * intended PC value */ 25410259SAndrew.Bardsley@arm.com DPRINTF(Branch, "Predicted a branch from 0x%x to 0x%x but" 25510259SAndrew.Bardsley@arm.com " none happened inst: %s\n", 25610259SAndrew.Bardsley@arm.com inst->pc.instAddr(), inst->predictedTarget.instAddr(), *inst); 25710259SAndrew.Bardsley@arm.com 25810259SAndrew.Bardsley@arm.com reason = BranchData::BadlyPredictedBranch; 25910259SAndrew.Bardsley@arm.com } else if (inst->predictedTarget == target) { 26010259SAndrew.Bardsley@arm.com /* Branch prediction got the right target, kill the branch and 26110259SAndrew.Bardsley@arm.com * carry on. 26210259SAndrew.Bardsley@arm.com * Note that this information to the branch predictor might get 26310259SAndrew.Bardsley@arm.com * overwritten by a "real" branch during this cycle */ 26410259SAndrew.Bardsley@arm.com DPRINTF(Branch, "Predicted a branch from 0x%x to 0x%x correctly" 26510259SAndrew.Bardsley@arm.com " inst: %s\n", 26610259SAndrew.Bardsley@arm.com inst->pc.instAddr(), inst->predictedTarget.instAddr(), *inst); 26710259SAndrew.Bardsley@arm.com 26810259SAndrew.Bardsley@arm.com reason = BranchData::CorrectlyPredictedBranch; 26910259SAndrew.Bardsley@arm.com } else { 27010259SAndrew.Bardsley@arm.com /* Branch prediction got the wrong target */ 27110259SAndrew.Bardsley@arm.com DPRINTF(Branch, "Predicted a branch from 0x%x to 0x%x" 27210366Sandreas.hansson@arm.com " but got the wrong target (actual: 0x%x) inst: %s\n", 27310366Sandreas.hansson@arm.com inst->pc.instAddr(), inst->predictedTarget.instAddr(), 27410366Sandreas.hansson@arm.com target.instAddr(), *inst); 27510259SAndrew.Bardsley@arm.com 27610259SAndrew.Bardsley@arm.com reason = BranchData::BadlyPredictedBranchTarget; 27710259SAndrew.Bardsley@arm.com } 27810259SAndrew.Bardsley@arm.com } else if (must_branch) { 27910259SAndrew.Bardsley@arm.com /* Unpredicted branch */ 28010259SAndrew.Bardsley@arm.com DPRINTF(Branch, "Unpredicted branch from 0x%x to 0x%x inst: %s\n", 28110259SAndrew.Bardsley@arm.com inst->pc.instAddr(), target.instAddr(), *inst); 28210259SAndrew.Bardsley@arm.com 28310259SAndrew.Bardsley@arm.com reason = BranchData::UnpredictedBranch; 28410259SAndrew.Bardsley@arm.com } else { 28510259SAndrew.Bardsley@arm.com /* No branch at all */ 28610259SAndrew.Bardsley@arm.com reason = BranchData::NoBranch; 28710259SAndrew.Bardsley@arm.com } 28810259SAndrew.Bardsley@arm.com 28911567Smitch.hayenga@arm.com updateBranchData(inst->id.threadId, reason, inst, target, branch); 29010259SAndrew.Bardsley@arm.com} 29110259SAndrew.Bardsley@arm.com 29210259SAndrew.Bardsley@arm.comvoid 29310259SAndrew.Bardsley@arm.comExecute::updateBranchData( 29411567Smitch.hayenga@arm.com ThreadID tid, 29510259SAndrew.Bardsley@arm.com BranchData::Reason reason, 29610259SAndrew.Bardsley@arm.com MinorDynInstPtr inst, const TheISA::PCState &target, 29710259SAndrew.Bardsley@arm.com BranchData &branch) 29810259SAndrew.Bardsley@arm.com{ 29910259SAndrew.Bardsley@arm.com if (reason != BranchData::NoBranch) { 30010259SAndrew.Bardsley@arm.com /* Bump up the stream sequence number on a real branch*/ 30110259SAndrew.Bardsley@arm.com if (BranchData::isStreamChange(reason)) 30211567Smitch.hayenga@arm.com executeInfo[tid].streamSeqNum++; 30310259SAndrew.Bardsley@arm.com 30410259SAndrew.Bardsley@arm.com /* Branches (even mis-predictions) don't change the predictionSeqNum, 30510259SAndrew.Bardsley@arm.com * just the streamSeqNum */ 30611567Smitch.hayenga@arm.com branch = BranchData(reason, tid, 30711567Smitch.hayenga@arm.com executeInfo[tid].streamSeqNum, 30810259SAndrew.Bardsley@arm.com /* Maintaining predictionSeqNum if there's no inst is just a 30910259SAndrew.Bardsley@arm.com * courtesy and looks better on minorview */ 31011567Smitch.hayenga@arm.com (inst->isBubble() ? executeInfo[tid].lastPredictionSeqNum 31110259SAndrew.Bardsley@arm.com : inst->id.predictionSeqNum), 31210259SAndrew.Bardsley@arm.com target, inst); 31310259SAndrew.Bardsley@arm.com 31410259SAndrew.Bardsley@arm.com DPRINTF(Branch, "Branch data signalled: %s\n", branch); 31510259SAndrew.Bardsley@arm.com } 31610259SAndrew.Bardsley@arm.com} 31710259SAndrew.Bardsley@arm.com 31810259SAndrew.Bardsley@arm.comvoid 31910259SAndrew.Bardsley@arm.comExecute::handleMemResponse(MinorDynInstPtr inst, 32010259SAndrew.Bardsley@arm.com LSQ::LSQRequestPtr response, BranchData &branch, Fault &fault) 32110259SAndrew.Bardsley@arm.com{ 32210259SAndrew.Bardsley@arm.com ThreadID thread_id = inst->id.threadId; 32310259SAndrew.Bardsley@arm.com ThreadContext *thread = cpu.getContext(thread_id); 32410259SAndrew.Bardsley@arm.com 32510259SAndrew.Bardsley@arm.com ExecContext context(cpu, *cpu.threads[thread_id], *this, inst); 32610259SAndrew.Bardsley@arm.com 32710259SAndrew.Bardsley@arm.com PacketPtr packet = response->packet; 32810259SAndrew.Bardsley@arm.com 32910259SAndrew.Bardsley@arm.com bool is_load = inst->staticInst->isLoad(); 33010259SAndrew.Bardsley@arm.com bool is_store = inst->staticInst->isStore(); 33110259SAndrew.Bardsley@arm.com bool is_prefetch = inst->staticInst->isDataPrefetch(); 33210259SAndrew.Bardsley@arm.com 33310259SAndrew.Bardsley@arm.com /* If true, the trace's predicate value will be taken from the exec 33410259SAndrew.Bardsley@arm.com * context predicate, otherwise, it will be set to false */ 33510259SAndrew.Bardsley@arm.com bool use_context_predicate = true; 33610259SAndrew.Bardsley@arm.com 33710259SAndrew.Bardsley@arm.com if (response->fault != NoFault) { 33810259SAndrew.Bardsley@arm.com /* Invoke memory faults. */ 33910259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Completing fault from DTLB access: %s\n", 34010259SAndrew.Bardsley@arm.com response->fault->name()); 34110259SAndrew.Bardsley@arm.com 34210259SAndrew.Bardsley@arm.com if (inst->staticInst->isPrefetch()) { 34310259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Not taking fault on prefetch: %s\n", 34410259SAndrew.Bardsley@arm.com response->fault->name()); 34510259SAndrew.Bardsley@arm.com 34610259SAndrew.Bardsley@arm.com /* Don't assign to fault */ 34710259SAndrew.Bardsley@arm.com } else { 34810259SAndrew.Bardsley@arm.com /* Take the fault raised during the TLB/memory access */ 34910259SAndrew.Bardsley@arm.com fault = response->fault; 35010259SAndrew.Bardsley@arm.com 35110259SAndrew.Bardsley@arm.com fault->invoke(thread, inst->staticInst); 35210259SAndrew.Bardsley@arm.com } 35310259SAndrew.Bardsley@arm.com } else if (!packet) { 35410259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Completing failed request inst: %s\n", 35510259SAndrew.Bardsley@arm.com *inst); 35610259SAndrew.Bardsley@arm.com use_context_predicate = false; 35710259SAndrew.Bardsley@arm.com } else if (packet->isError()) { 35810259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Trying to commit error response: %s\n", 35910259SAndrew.Bardsley@arm.com *inst); 36010259SAndrew.Bardsley@arm.com 36110259SAndrew.Bardsley@arm.com fatal("Received error response packet for inst: %s\n", *inst); 36210259SAndrew.Bardsley@arm.com } else if (is_store || is_load || is_prefetch) { 36310259SAndrew.Bardsley@arm.com assert(packet); 36410259SAndrew.Bardsley@arm.com 36510259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Memory response inst: %s addr: 0x%x size: %d\n", 36610259SAndrew.Bardsley@arm.com *inst, packet->getAddr(), packet->getSize()); 36710259SAndrew.Bardsley@arm.com 36810259SAndrew.Bardsley@arm.com if (is_load && packet->getSize() > 0) { 36910259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Memory data[0]: 0x%x\n", 37010563Sandreas.hansson@arm.com static_cast<unsigned int>(packet->getConstPtr<uint8_t>()[0])); 37110259SAndrew.Bardsley@arm.com } 37210259SAndrew.Bardsley@arm.com 37310259SAndrew.Bardsley@arm.com /* Complete the memory access instruction */ 37410259SAndrew.Bardsley@arm.com fault = inst->staticInst->completeAcc(packet, &context, 37510259SAndrew.Bardsley@arm.com inst->traceData); 37610259SAndrew.Bardsley@arm.com 37710259SAndrew.Bardsley@arm.com if (fault != NoFault) { 37810259SAndrew.Bardsley@arm.com /* Invoke fault created by instruction completion */ 37910259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Fault in memory completeAcc: %s\n", 38010259SAndrew.Bardsley@arm.com fault->name()); 38110259SAndrew.Bardsley@arm.com fault->invoke(thread, inst->staticInst); 38210259SAndrew.Bardsley@arm.com } else { 38310259SAndrew.Bardsley@arm.com /* Stores need to be pushed into the store buffer to finish 38410259SAndrew.Bardsley@arm.com * them off */ 38510259SAndrew.Bardsley@arm.com if (response->needsToBeSentToStoreBuffer()) 38610259SAndrew.Bardsley@arm.com lsq.sendStoreToStoreBuffer(response); 38710259SAndrew.Bardsley@arm.com } 38810259SAndrew.Bardsley@arm.com } else { 38910259SAndrew.Bardsley@arm.com fatal("There should only ever be reads, " 39010259SAndrew.Bardsley@arm.com "writes or faults at this point\n"); 39110259SAndrew.Bardsley@arm.com } 39210259SAndrew.Bardsley@arm.com 39310259SAndrew.Bardsley@arm.com lsq.popResponse(response); 39410259SAndrew.Bardsley@arm.com 39510259SAndrew.Bardsley@arm.com if (inst->traceData) { 39610259SAndrew.Bardsley@arm.com inst->traceData->setPredicate((use_context_predicate ? 39710259SAndrew.Bardsley@arm.com context.readPredicate() : false)); 39810259SAndrew.Bardsley@arm.com } 39910259SAndrew.Bardsley@arm.com 40010259SAndrew.Bardsley@arm.com doInstCommitAccounting(inst); 40110259SAndrew.Bardsley@arm.com 40210259SAndrew.Bardsley@arm.com /* Generate output to account for branches */ 40310259SAndrew.Bardsley@arm.com tryToBranch(inst, fault, branch); 40410259SAndrew.Bardsley@arm.com} 40510259SAndrew.Bardsley@arm.com 40610259SAndrew.Bardsley@arm.combool 40710259SAndrew.Bardsley@arm.comExecute::isInterrupted(ThreadID thread_id) const 40810259SAndrew.Bardsley@arm.com{ 40910259SAndrew.Bardsley@arm.com return cpu.checkInterrupts(cpu.getContext(thread_id)); 41010259SAndrew.Bardsley@arm.com} 41110259SAndrew.Bardsley@arm.com 41210259SAndrew.Bardsley@arm.combool 41310259SAndrew.Bardsley@arm.comExecute::takeInterrupt(ThreadID thread_id, BranchData &branch) 41410259SAndrew.Bardsley@arm.com{ 41510259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Considering interrupt status from PC: %s\n", 41610259SAndrew.Bardsley@arm.com cpu.getContext(thread_id)->pcState()); 41710259SAndrew.Bardsley@arm.com 41811150Smitch.hayenga@arm.com Fault interrupt = cpu.getInterruptController(thread_id)->getInterrupt 41910259SAndrew.Bardsley@arm.com (cpu.getContext(thread_id)); 42010259SAndrew.Bardsley@arm.com 42110259SAndrew.Bardsley@arm.com if (interrupt != NoFault) { 42210259SAndrew.Bardsley@arm.com /* The interrupt *must* set pcState */ 42311150Smitch.hayenga@arm.com cpu.getInterruptController(thread_id)->updateIntrInfo 42410259SAndrew.Bardsley@arm.com (cpu.getContext(thread_id)); 42510259SAndrew.Bardsley@arm.com interrupt->invoke(cpu.getContext(thread_id)); 42610259SAndrew.Bardsley@arm.com 42710259SAndrew.Bardsley@arm.com assert(!lsq.accessesInFlight()); 42810259SAndrew.Bardsley@arm.com 42910259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Invoking interrupt: %s to PC: %s\n", 43010259SAndrew.Bardsley@arm.com interrupt->name(), cpu.getContext(thread_id)->pcState()); 43110259SAndrew.Bardsley@arm.com 43210259SAndrew.Bardsley@arm.com /* Assume that an interrupt *must* cause a branch. Assert this? */ 43310259SAndrew.Bardsley@arm.com 43411567Smitch.hayenga@arm.com updateBranchData(thread_id, BranchData::Interrupt, 43511567Smitch.hayenga@arm.com MinorDynInst::bubble(), cpu.getContext(thread_id)->pcState(), 43611567Smitch.hayenga@arm.com branch); 43710259SAndrew.Bardsley@arm.com } 43810259SAndrew.Bardsley@arm.com 43910259SAndrew.Bardsley@arm.com return interrupt != NoFault; 44010259SAndrew.Bardsley@arm.com} 44110259SAndrew.Bardsley@arm.com 44210259SAndrew.Bardsley@arm.combool 44310259SAndrew.Bardsley@arm.comExecute::executeMemRefInst(MinorDynInstPtr inst, BranchData &branch, 44410259SAndrew.Bardsley@arm.com bool &passed_predicate, Fault &fault) 44510259SAndrew.Bardsley@arm.com{ 44610259SAndrew.Bardsley@arm.com bool issued = false; 44710259SAndrew.Bardsley@arm.com 44810259SAndrew.Bardsley@arm.com /* Set to true if the mem op. is issued and sent to the mem system */ 44910259SAndrew.Bardsley@arm.com passed_predicate = false; 45010259SAndrew.Bardsley@arm.com 45110259SAndrew.Bardsley@arm.com if (!lsq.canRequest()) { 45210259SAndrew.Bardsley@arm.com /* Not acting on instruction yet as the memory 45310259SAndrew.Bardsley@arm.com * queues are full */ 45410259SAndrew.Bardsley@arm.com issued = false; 45510259SAndrew.Bardsley@arm.com } else { 45610259SAndrew.Bardsley@arm.com ThreadContext *thread = cpu.getContext(inst->id.threadId); 45710259SAndrew.Bardsley@arm.com TheISA::PCState old_pc = thread->pcState(); 45810259SAndrew.Bardsley@arm.com 45910259SAndrew.Bardsley@arm.com ExecContext context(cpu, *cpu.threads[inst->id.threadId], 46010259SAndrew.Bardsley@arm.com *this, inst); 46110259SAndrew.Bardsley@arm.com 46210259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Initiating memRef inst: %s\n", *inst); 46310259SAndrew.Bardsley@arm.com 46410259SAndrew.Bardsley@arm.com Fault init_fault = inst->staticInst->initiateAcc(&context, 46510259SAndrew.Bardsley@arm.com inst->traceData); 46610259SAndrew.Bardsley@arm.com 46710259SAndrew.Bardsley@arm.com if (init_fault != NoFault) { 46810259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Fault on memory inst: %s" 46910259SAndrew.Bardsley@arm.com " initiateAcc: %s\n", *inst, init_fault->name()); 47010259SAndrew.Bardsley@arm.com fault = init_fault; 47110259SAndrew.Bardsley@arm.com } else { 47210259SAndrew.Bardsley@arm.com /* Only set this if the instruction passed its 47310259SAndrew.Bardsley@arm.com * predicate */ 47410259SAndrew.Bardsley@arm.com passed_predicate = context.readPredicate(); 47510259SAndrew.Bardsley@arm.com 47610259SAndrew.Bardsley@arm.com /* Set predicate in tracing */ 47710259SAndrew.Bardsley@arm.com if (inst->traceData) 47810259SAndrew.Bardsley@arm.com inst->traceData->setPredicate(passed_predicate); 47910259SAndrew.Bardsley@arm.com 48010259SAndrew.Bardsley@arm.com /* If the instruction didn't pass its predicate (and so will not 48110259SAndrew.Bardsley@arm.com * progress from here) Try to branch to correct and branch 48210259SAndrew.Bardsley@arm.com * mis-prediction. */ 48310259SAndrew.Bardsley@arm.com if (!passed_predicate) { 48410259SAndrew.Bardsley@arm.com /* Leave it up to commit to handle the fault */ 48510259SAndrew.Bardsley@arm.com lsq.pushFailedRequest(inst); 48610259SAndrew.Bardsley@arm.com } 48710259SAndrew.Bardsley@arm.com } 48810259SAndrew.Bardsley@arm.com 48910259SAndrew.Bardsley@arm.com /* Restore thread PC */ 49010259SAndrew.Bardsley@arm.com thread->pcState(old_pc); 49110259SAndrew.Bardsley@arm.com issued = true; 49210259SAndrew.Bardsley@arm.com } 49310259SAndrew.Bardsley@arm.com 49410259SAndrew.Bardsley@arm.com return issued; 49510259SAndrew.Bardsley@arm.com} 49610259SAndrew.Bardsley@arm.com 49710259SAndrew.Bardsley@arm.com/** Increment a cyclic buffer index for indices [0, cycle_size-1] */ 49810259SAndrew.Bardsley@arm.cominline unsigned int 49910259SAndrew.Bardsley@arm.comcyclicIndexInc(unsigned int index, unsigned int cycle_size) 50010259SAndrew.Bardsley@arm.com{ 50110259SAndrew.Bardsley@arm.com unsigned int ret = index + 1; 50210259SAndrew.Bardsley@arm.com 50310259SAndrew.Bardsley@arm.com if (ret == cycle_size) 50410259SAndrew.Bardsley@arm.com ret = 0; 50510259SAndrew.Bardsley@arm.com 50610259SAndrew.Bardsley@arm.com return ret; 50710259SAndrew.Bardsley@arm.com} 50810259SAndrew.Bardsley@arm.com 50910259SAndrew.Bardsley@arm.com/** Decrement a cyclic buffer index for indices [0, cycle_size-1] */ 51010259SAndrew.Bardsley@arm.cominline unsigned int 51110259SAndrew.Bardsley@arm.comcyclicIndexDec(unsigned int index, unsigned int cycle_size) 51210259SAndrew.Bardsley@arm.com{ 51310259SAndrew.Bardsley@arm.com int ret = index - 1; 51410259SAndrew.Bardsley@arm.com 51510259SAndrew.Bardsley@arm.com if (ret < 0) 51610259SAndrew.Bardsley@arm.com ret = cycle_size - 1; 51710259SAndrew.Bardsley@arm.com 51810259SAndrew.Bardsley@arm.com return ret; 51910259SAndrew.Bardsley@arm.com} 52010259SAndrew.Bardsley@arm.com 52110259SAndrew.Bardsley@arm.comunsigned int 52211567Smitch.hayenga@arm.comExecute::issue(ThreadID thread_id) 52310259SAndrew.Bardsley@arm.com{ 52411567Smitch.hayenga@arm.com const ForwardInstData *insts_in = getInput(thread_id); 52511567Smitch.hayenga@arm.com ExecuteThreadInfo &thread = executeInfo[thread_id]; 52610259SAndrew.Bardsley@arm.com 52710259SAndrew.Bardsley@arm.com /* Early termination if we have no instructions */ 52810259SAndrew.Bardsley@arm.com if (!insts_in) 52910259SAndrew.Bardsley@arm.com return 0; 53010259SAndrew.Bardsley@arm.com 53110259SAndrew.Bardsley@arm.com /* Start from the first FU */ 53210259SAndrew.Bardsley@arm.com unsigned int fu_index = 0; 53310259SAndrew.Bardsley@arm.com 53410259SAndrew.Bardsley@arm.com /* Remains true while instructions are still being issued. If any 53510259SAndrew.Bardsley@arm.com * instruction fails to issue, this is set to false and we exit issue. 53610259SAndrew.Bardsley@arm.com * This strictly enforces in-order issue. For other issue behaviours, 53710259SAndrew.Bardsley@arm.com * a more complicated test in the outer while loop below is needed. */ 53810259SAndrew.Bardsley@arm.com bool issued = true; 53910259SAndrew.Bardsley@arm.com 54010259SAndrew.Bardsley@arm.com /* Number of insts issues this cycle to check for issueLimit */ 54110259SAndrew.Bardsley@arm.com unsigned num_insts_issued = 0; 54210259SAndrew.Bardsley@arm.com 54310259SAndrew.Bardsley@arm.com /* Number of memory ops issues this cycle to check for memoryIssueLimit */ 54410259SAndrew.Bardsley@arm.com unsigned num_mem_insts_issued = 0; 54510259SAndrew.Bardsley@arm.com 54610259SAndrew.Bardsley@arm.com /* Number of instructions discarded this cycle in order to enforce a 54710259SAndrew.Bardsley@arm.com * discardLimit. @todo, add that parameter? */ 54810259SAndrew.Bardsley@arm.com unsigned num_insts_discarded = 0; 54910259SAndrew.Bardsley@arm.com 55010259SAndrew.Bardsley@arm.com do { 55111567Smitch.hayenga@arm.com MinorDynInstPtr inst = insts_in->insts[thread.inputIndex]; 55210259SAndrew.Bardsley@arm.com Fault fault = inst->fault; 55310259SAndrew.Bardsley@arm.com bool discarded = false; 55410259SAndrew.Bardsley@arm.com bool issued_mem_ref = false; 55510259SAndrew.Bardsley@arm.com 55610259SAndrew.Bardsley@arm.com if (inst->isBubble()) { 55710259SAndrew.Bardsley@arm.com /* Skip */ 55810259SAndrew.Bardsley@arm.com issued = true; 55910259SAndrew.Bardsley@arm.com } else if (cpu.getContext(thread_id)->status() == 56010259SAndrew.Bardsley@arm.com ThreadContext::Suspended) 56110259SAndrew.Bardsley@arm.com { 56210259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Not issuing inst: %s from suspended" 56310259SAndrew.Bardsley@arm.com " thread\n", *inst); 56410259SAndrew.Bardsley@arm.com 56510259SAndrew.Bardsley@arm.com issued = false; 56611567Smitch.hayenga@arm.com } else if (inst->id.streamSeqNum != thread.streamSeqNum) { 56710259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Discarding inst: %s as its stream" 56810259SAndrew.Bardsley@arm.com " state was unexpected, expected: %d\n", 56911567Smitch.hayenga@arm.com *inst, thread.streamSeqNum); 57010259SAndrew.Bardsley@arm.com issued = true; 57110259SAndrew.Bardsley@arm.com discarded = true; 57210259SAndrew.Bardsley@arm.com } else { 57310259SAndrew.Bardsley@arm.com /* Try and issue an instruction into an FU, assume we didn't and 57410259SAndrew.Bardsley@arm.com * fix that in the loop */ 57510259SAndrew.Bardsley@arm.com issued = false; 57610259SAndrew.Bardsley@arm.com 57710259SAndrew.Bardsley@arm.com /* Try FU from 0 each instruction */ 57810259SAndrew.Bardsley@arm.com fu_index = 0; 57910259SAndrew.Bardsley@arm.com 58010259SAndrew.Bardsley@arm.com /* Try and issue a single instruction stepping through the 58110259SAndrew.Bardsley@arm.com * available FUs */ 58210259SAndrew.Bardsley@arm.com do { 58310259SAndrew.Bardsley@arm.com FUPipeline *fu = funcUnits[fu_index]; 58410259SAndrew.Bardsley@arm.com 58510259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Trying to issue inst: %s to FU: %d\n", 58610259SAndrew.Bardsley@arm.com *inst, fu_index); 58710259SAndrew.Bardsley@arm.com 58810259SAndrew.Bardsley@arm.com /* Does the examined fu have the OpClass-related capability 58910259SAndrew.Bardsley@arm.com * needed to execute this instruction? Faults can always 59010259SAndrew.Bardsley@arm.com * issue to any FU but probably should just 'live' in the 59110259SAndrew.Bardsley@arm.com * inFlightInsts queue rather than having an FU. */ 59210259SAndrew.Bardsley@arm.com bool fu_is_capable = (!inst->isFault() ? 59310259SAndrew.Bardsley@arm.com fu->provides(inst->staticInst->opClass()) : true); 59410259SAndrew.Bardsley@arm.com 59510259SAndrew.Bardsley@arm.com if (inst->isNoCostInst()) { 59610259SAndrew.Bardsley@arm.com /* Issue free insts. to a fake numbered FU */ 59710259SAndrew.Bardsley@arm.com fu_index = noCostFUIndex; 59810259SAndrew.Bardsley@arm.com 59910259SAndrew.Bardsley@arm.com /* And start the countdown on activity to allow 60010259SAndrew.Bardsley@arm.com * this instruction to get to the end of its FU */ 60110259SAndrew.Bardsley@arm.com cpu.activityRecorder->activity(); 60210259SAndrew.Bardsley@arm.com 60310259SAndrew.Bardsley@arm.com /* Mark the destinations for this instruction as 60410259SAndrew.Bardsley@arm.com * busy */ 60511567Smitch.hayenga@arm.com scoreboard[thread_id].markupInstDests(inst, cpu.curCycle() + 60610259SAndrew.Bardsley@arm.com Cycles(0), cpu.getContext(thread_id), false); 60710259SAndrew.Bardsley@arm.com 60811567Smitch.hayenga@arm.com DPRINTF(MinorExecute, "Issuing %s to %d\n", inst->id, noCostFUIndex); 60910259SAndrew.Bardsley@arm.com inst->fuIndex = noCostFUIndex; 61010259SAndrew.Bardsley@arm.com inst->extraCommitDelay = Cycles(0); 61110259SAndrew.Bardsley@arm.com inst->extraCommitDelayExpr = NULL; 61210259SAndrew.Bardsley@arm.com 61310259SAndrew.Bardsley@arm.com /* Push the instruction onto the inFlight queue so 61410259SAndrew.Bardsley@arm.com * it can be committed in order */ 61510259SAndrew.Bardsley@arm.com QueuedInst fu_inst(inst); 61611567Smitch.hayenga@arm.com thread.inFlightInsts->push(fu_inst); 61710259SAndrew.Bardsley@arm.com 61810259SAndrew.Bardsley@arm.com issued = true; 61910259SAndrew.Bardsley@arm.com 62010259SAndrew.Bardsley@arm.com } else if (!fu_is_capable || fu->alreadyPushed()) { 62110259SAndrew.Bardsley@arm.com /* Skip */ 62210259SAndrew.Bardsley@arm.com if (!fu_is_capable) { 62310259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue as FU: %d isn't" 62410259SAndrew.Bardsley@arm.com " capable\n", fu_index); 62510259SAndrew.Bardsley@arm.com } else { 62610259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue as FU: %d is" 62710259SAndrew.Bardsley@arm.com " already busy\n", fu_index); 62810259SAndrew.Bardsley@arm.com } 62910259SAndrew.Bardsley@arm.com } else if (fu->stalled) { 63010259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue inst: %s into FU: %d," 63110259SAndrew.Bardsley@arm.com " it's stalled\n", 63210259SAndrew.Bardsley@arm.com *inst, fu_index); 63310259SAndrew.Bardsley@arm.com } else if (!fu->canInsert()) { 63410259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue inst: %s to busy FU" 63510259SAndrew.Bardsley@arm.com " for another: %d cycles\n", 63610259SAndrew.Bardsley@arm.com *inst, fu->cyclesBeforeInsert()); 63710259SAndrew.Bardsley@arm.com } else { 63810259SAndrew.Bardsley@arm.com MinorFUTiming *timing = (!inst->isFault() ? 63910259SAndrew.Bardsley@arm.com fu->findTiming(inst->staticInst) : NULL); 64010259SAndrew.Bardsley@arm.com 64110259SAndrew.Bardsley@arm.com const std::vector<Cycles> *src_latencies = 64210259SAndrew.Bardsley@arm.com (timing ? &(timing->srcRegsRelativeLats) 64310259SAndrew.Bardsley@arm.com : NULL); 64410259SAndrew.Bardsley@arm.com 64510259SAndrew.Bardsley@arm.com const std::vector<bool> *cant_forward_from_fu_indices = 64610259SAndrew.Bardsley@arm.com &(fu->cantForwardFromFUIndices); 64710259SAndrew.Bardsley@arm.com 64810259SAndrew.Bardsley@arm.com if (timing && timing->suppress) { 64910259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue inst: %s as extra" 65010259SAndrew.Bardsley@arm.com " decoding is suppressing it\n", 65110259SAndrew.Bardsley@arm.com *inst); 65211567Smitch.hayenga@arm.com } else if (!scoreboard[thread_id].canInstIssue(inst, 65311567Smitch.hayenga@arm.com src_latencies, cant_forward_from_fu_indices, 65410259SAndrew.Bardsley@arm.com cpu.curCycle(), cpu.getContext(thread_id))) 65510259SAndrew.Bardsley@arm.com { 65610259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue inst: %s yet\n", 65710259SAndrew.Bardsley@arm.com *inst); 65810259SAndrew.Bardsley@arm.com } else { 65910259SAndrew.Bardsley@arm.com /* Can insert the instruction into this FU */ 66010259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Issuing inst: %s" 66110259SAndrew.Bardsley@arm.com " into FU %d\n", *inst, 66210259SAndrew.Bardsley@arm.com fu_index); 66310259SAndrew.Bardsley@arm.com 66410259SAndrew.Bardsley@arm.com Cycles extra_dest_retire_lat = Cycles(0); 66510259SAndrew.Bardsley@arm.com TimingExpr *extra_dest_retire_lat_expr = NULL; 66610259SAndrew.Bardsley@arm.com Cycles extra_assumed_lat = Cycles(0); 66710259SAndrew.Bardsley@arm.com 66810259SAndrew.Bardsley@arm.com /* Add the extraCommitDelay and extraAssumeLat to 66910259SAndrew.Bardsley@arm.com * the FU pipeline timings */ 67010259SAndrew.Bardsley@arm.com if (timing) { 67110259SAndrew.Bardsley@arm.com extra_dest_retire_lat = 67210259SAndrew.Bardsley@arm.com timing->extraCommitLat; 67310259SAndrew.Bardsley@arm.com extra_dest_retire_lat_expr = 67410259SAndrew.Bardsley@arm.com timing->extraCommitLatExpr; 67510259SAndrew.Bardsley@arm.com extra_assumed_lat = 67610259SAndrew.Bardsley@arm.com timing->extraAssumedLat; 67710259SAndrew.Bardsley@arm.com } 67810259SAndrew.Bardsley@arm.com 67910580SAndrew.Bardsley@arm.com issued_mem_ref = inst->isMemRef(); 68010259SAndrew.Bardsley@arm.com 68110259SAndrew.Bardsley@arm.com QueuedInst fu_inst(inst); 68210259SAndrew.Bardsley@arm.com 68310259SAndrew.Bardsley@arm.com /* Decorate the inst with FU details */ 68410259SAndrew.Bardsley@arm.com inst->fuIndex = fu_index; 68510259SAndrew.Bardsley@arm.com inst->extraCommitDelay = extra_dest_retire_lat; 68610259SAndrew.Bardsley@arm.com inst->extraCommitDelayExpr = 68710259SAndrew.Bardsley@arm.com extra_dest_retire_lat_expr; 68810259SAndrew.Bardsley@arm.com 68910259SAndrew.Bardsley@arm.com if (issued_mem_ref) { 69010259SAndrew.Bardsley@arm.com /* Remember which instruction this memory op 69110259SAndrew.Bardsley@arm.com * depends on so that initiateAcc can be called 69210259SAndrew.Bardsley@arm.com * early */ 69310259SAndrew.Bardsley@arm.com if (allowEarlyMemIssue) { 69410259SAndrew.Bardsley@arm.com inst->instToWaitFor = 69511567Smitch.hayenga@arm.com scoreboard[thread_id].execSeqNumToWaitFor(inst, 69610259SAndrew.Bardsley@arm.com cpu.getContext(thread_id)); 69710259SAndrew.Bardsley@arm.com 69811567Smitch.hayenga@arm.com if (lsq.getLastMemBarrier(thread_id) > 69910259SAndrew.Bardsley@arm.com inst->instToWaitFor) 70010259SAndrew.Bardsley@arm.com { 70110259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "A barrier will" 70210259SAndrew.Bardsley@arm.com " cause a delay in mem ref issue of" 70310259SAndrew.Bardsley@arm.com " inst: %s until after inst" 70410259SAndrew.Bardsley@arm.com " %d(exec)\n", *inst, 70511567Smitch.hayenga@arm.com lsq.getLastMemBarrier(thread_id)); 70610259SAndrew.Bardsley@arm.com 70710259SAndrew.Bardsley@arm.com inst->instToWaitFor = 70811567Smitch.hayenga@arm.com lsq.getLastMemBarrier(thread_id); 70910259SAndrew.Bardsley@arm.com } else { 71010259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Memory ref inst:" 71110259SAndrew.Bardsley@arm.com " %s must wait for inst %d(exec)" 71210259SAndrew.Bardsley@arm.com " before issuing\n", 71310259SAndrew.Bardsley@arm.com *inst, inst->instToWaitFor); 71410259SAndrew.Bardsley@arm.com } 71510259SAndrew.Bardsley@arm.com 71610259SAndrew.Bardsley@arm.com inst->canEarlyIssue = true; 71710259SAndrew.Bardsley@arm.com } 71810259SAndrew.Bardsley@arm.com /* Also queue this instruction in the memory ref 71910259SAndrew.Bardsley@arm.com * queue to ensure in-order issue to the LSQ */ 72010259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Pushing mem inst: %s\n", 72110259SAndrew.Bardsley@arm.com *inst); 72211567Smitch.hayenga@arm.com thread.inFUMemInsts->push(fu_inst); 72310259SAndrew.Bardsley@arm.com } 72410259SAndrew.Bardsley@arm.com 72510259SAndrew.Bardsley@arm.com /* Issue to FU */ 72610259SAndrew.Bardsley@arm.com fu->push(fu_inst); 72710259SAndrew.Bardsley@arm.com /* And start the countdown on activity to allow 72810259SAndrew.Bardsley@arm.com * this instruction to get to the end of its FU */ 72910259SAndrew.Bardsley@arm.com cpu.activityRecorder->activity(); 73010259SAndrew.Bardsley@arm.com 73110259SAndrew.Bardsley@arm.com /* Mark the destinations for this instruction as 73210259SAndrew.Bardsley@arm.com * busy */ 73311567Smitch.hayenga@arm.com scoreboard[thread_id].markupInstDests(inst, cpu.curCycle() + 73410259SAndrew.Bardsley@arm.com fu->description.opLat + 73510259SAndrew.Bardsley@arm.com extra_dest_retire_lat + 73610259SAndrew.Bardsley@arm.com extra_assumed_lat, 73710259SAndrew.Bardsley@arm.com cpu.getContext(thread_id), 73810259SAndrew.Bardsley@arm.com issued_mem_ref && extra_assumed_lat == Cycles(0)); 73910259SAndrew.Bardsley@arm.com 74010259SAndrew.Bardsley@arm.com /* Push the instruction onto the inFlight queue so 74110259SAndrew.Bardsley@arm.com * it can be committed in order */ 74211567Smitch.hayenga@arm.com thread.inFlightInsts->push(fu_inst); 74310259SAndrew.Bardsley@arm.com 74410259SAndrew.Bardsley@arm.com issued = true; 74510259SAndrew.Bardsley@arm.com } 74610259SAndrew.Bardsley@arm.com } 74710259SAndrew.Bardsley@arm.com 74810259SAndrew.Bardsley@arm.com fu_index++; 74910259SAndrew.Bardsley@arm.com } while (fu_index != numFuncUnits && !issued); 75010259SAndrew.Bardsley@arm.com 75110259SAndrew.Bardsley@arm.com if (!issued) 75210259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Didn't issue inst: %s\n", *inst); 75310259SAndrew.Bardsley@arm.com } 75410259SAndrew.Bardsley@arm.com 75510259SAndrew.Bardsley@arm.com if (issued) { 75610259SAndrew.Bardsley@arm.com /* Generate MinorTrace's MinorInst lines. Do this at commit 75710259SAndrew.Bardsley@arm.com * to allow better instruction annotation? */ 75810259SAndrew.Bardsley@arm.com if (DTRACE(MinorTrace) && !inst->isBubble()) 75910259SAndrew.Bardsley@arm.com inst->minorTraceInst(*this); 76010259SAndrew.Bardsley@arm.com 76110259SAndrew.Bardsley@arm.com /* Mark up barriers in the LSQ */ 76210259SAndrew.Bardsley@arm.com if (!discarded && inst->isInst() && 76310259SAndrew.Bardsley@arm.com inst->staticInst->isMemBarrier()) 76410259SAndrew.Bardsley@arm.com { 76510259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Issuing memory barrier inst: %s\n", *inst); 76610259SAndrew.Bardsley@arm.com lsq.issuedMemBarrierInst(inst); 76710259SAndrew.Bardsley@arm.com } 76810259SAndrew.Bardsley@arm.com 76910259SAndrew.Bardsley@arm.com if (inst->traceData && setTraceTimeOnIssue) { 77010259SAndrew.Bardsley@arm.com inst->traceData->setWhen(curTick()); 77110259SAndrew.Bardsley@arm.com } 77210259SAndrew.Bardsley@arm.com 77310259SAndrew.Bardsley@arm.com if (issued_mem_ref) 77410259SAndrew.Bardsley@arm.com num_mem_insts_issued++; 77510259SAndrew.Bardsley@arm.com 77610259SAndrew.Bardsley@arm.com if (discarded) { 77710259SAndrew.Bardsley@arm.com num_insts_discarded++; 77810851SAndrew.Bardsley@arm.com } else if (!inst->isBubble()) { 77910259SAndrew.Bardsley@arm.com num_insts_issued++; 78010259SAndrew.Bardsley@arm.com 78110259SAndrew.Bardsley@arm.com if (num_insts_issued == issueLimit) 78210259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Reached inst issue limit\n"); 78310259SAndrew.Bardsley@arm.com } 78410259SAndrew.Bardsley@arm.com 78511567Smitch.hayenga@arm.com thread.inputIndex++; 78610259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Stepping to next inst inputIndex: %d\n", 78711567Smitch.hayenga@arm.com thread.inputIndex); 78810259SAndrew.Bardsley@arm.com } 78910259SAndrew.Bardsley@arm.com 79010259SAndrew.Bardsley@arm.com /* Got to the end of a line */ 79111567Smitch.hayenga@arm.com if (thread.inputIndex == insts_in->width()) { 79211567Smitch.hayenga@arm.com popInput(thread_id); 79310259SAndrew.Bardsley@arm.com /* Set insts_in to null to force us to leave the surrounding 79410259SAndrew.Bardsley@arm.com * loop */ 79510259SAndrew.Bardsley@arm.com insts_in = NULL; 79610259SAndrew.Bardsley@arm.com 79710259SAndrew.Bardsley@arm.com if (processMoreThanOneInput) { 79810259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Wrapping\n"); 79911567Smitch.hayenga@arm.com insts_in = getInput(thread_id); 80010259SAndrew.Bardsley@arm.com } 80110259SAndrew.Bardsley@arm.com } 80211567Smitch.hayenga@arm.com } while (insts_in && thread.inputIndex < insts_in->width() && 80310259SAndrew.Bardsley@arm.com /* We still have instructions */ 80410259SAndrew.Bardsley@arm.com fu_index != numFuncUnits && /* Not visited all FUs */ 80510259SAndrew.Bardsley@arm.com issued && /* We've not yet failed to issue an instruction */ 80610259SAndrew.Bardsley@arm.com num_insts_issued != issueLimit && /* Still allowed to issue */ 80710259SAndrew.Bardsley@arm.com num_mem_insts_issued != memoryIssueLimit); 80810259SAndrew.Bardsley@arm.com 80910259SAndrew.Bardsley@arm.com return num_insts_issued; 81010259SAndrew.Bardsley@arm.com} 81110259SAndrew.Bardsley@arm.com 81210259SAndrew.Bardsley@arm.combool 81311567Smitch.hayenga@arm.comExecute::tryPCEvents(ThreadID thread_id) 81410259SAndrew.Bardsley@arm.com{ 81511567Smitch.hayenga@arm.com ThreadContext *thread = cpu.getContext(thread_id); 81610259SAndrew.Bardsley@arm.com unsigned int num_pc_event_checks = 0; 81710259SAndrew.Bardsley@arm.com 81810259SAndrew.Bardsley@arm.com /* Handle PC events on instructions */ 81910259SAndrew.Bardsley@arm.com Addr oldPC; 82010259SAndrew.Bardsley@arm.com do { 82110259SAndrew.Bardsley@arm.com oldPC = thread->instAddr(); 82210259SAndrew.Bardsley@arm.com cpu.system->pcEventQueue.service(thread); 82310259SAndrew.Bardsley@arm.com num_pc_event_checks++; 82410259SAndrew.Bardsley@arm.com } while (oldPC != thread->instAddr()); 82510259SAndrew.Bardsley@arm.com 82610259SAndrew.Bardsley@arm.com if (num_pc_event_checks > 1) { 82710259SAndrew.Bardsley@arm.com DPRINTF(PCEvent, "Acting on PC Event to PC: %s\n", 82810259SAndrew.Bardsley@arm.com thread->pcState()); 82910259SAndrew.Bardsley@arm.com } 83010259SAndrew.Bardsley@arm.com 83110259SAndrew.Bardsley@arm.com return num_pc_event_checks > 1; 83210259SAndrew.Bardsley@arm.com} 83310259SAndrew.Bardsley@arm.com 83410259SAndrew.Bardsley@arm.comvoid 83510259SAndrew.Bardsley@arm.comExecute::doInstCommitAccounting(MinorDynInstPtr inst) 83610259SAndrew.Bardsley@arm.com{ 83710259SAndrew.Bardsley@arm.com assert(!inst->isFault()); 83810259SAndrew.Bardsley@arm.com 83910259SAndrew.Bardsley@arm.com MinorThread *thread = cpu.threads[inst->id.threadId]; 84010259SAndrew.Bardsley@arm.com 84110259SAndrew.Bardsley@arm.com /* Increment the many and various inst and op counts in the 84210259SAndrew.Bardsley@arm.com * thread and system */ 84310259SAndrew.Bardsley@arm.com if (!inst->staticInst->isMicroop() || inst->staticInst->isLastMicroop()) 84410259SAndrew.Bardsley@arm.com { 84510259SAndrew.Bardsley@arm.com thread->numInst++; 84610259SAndrew.Bardsley@arm.com thread->numInsts++; 84710259SAndrew.Bardsley@arm.com cpu.stats.numInsts++; 84810774Snikos.nikoleris@gmail.com cpu.system->totalNumInsts++; 84910774Snikos.nikoleris@gmail.com 85010774Snikos.nikoleris@gmail.com /* Act on events related to instruction counts */ 85110774Snikos.nikoleris@gmail.com cpu.comInstEventQueue[inst->id.threadId]->serviceEvents(thread->numInst); 85210774Snikos.nikoleris@gmail.com cpu.system->instEventQueue.serviceEvents(cpu.system->totalNumInsts); 85310259SAndrew.Bardsley@arm.com } 85410259SAndrew.Bardsley@arm.com thread->numOp++; 85510259SAndrew.Bardsley@arm.com thread->numOps++; 85610259SAndrew.Bardsley@arm.com cpu.stats.numOps++; 85711419Smitch.hayenga@arm.com cpu.stats.committedInstType[inst->id.threadId] 85811419Smitch.hayenga@arm.com [inst->staticInst->opClass()]++; 85910259SAndrew.Bardsley@arm.com 86010259SAndrew.Bardsley@arm.com /* Set the CP SeqNum to the numOps commit number */ 86110259SAndrew.Bardsley@arm.com if (inst->traceData) 86210259SAndrew.Bardsley@arm.com inst->traceData->setCPSeq(thread->numOp); 86310464SAndreas.Sandberg@ARM.com 86410464SAndreas.Sandberg@ARM.com cpu.probeInstCommit(inst->staticInst); 86510259SAndrew.Bardsley@arm.com} 86610259SAndrew.Bardsley@arm.com 86710259SAndrew.Bardsley@arm.combool 86810259SAndrew.Bardsley@arm.comExecute::commitInst(MinorDynInstPtr inst, bool early_memory_issue, 86910259SAndrew.Bardsley@arm.com BranchData &branch, Fault &fault, bool &committed, 87010259SAndrew.Bardsley@arm.com bool &completed_mem_issue) 87110259SAndrew.Bardsley@arm.com{ 87210259SAndrew.Bardsley@arm.com ThreadID thread_id = inst->id.threadId; 87310259SAndrew.Bardsley@arm.com ThreadContext *thread = cpu.getContext(thread_id); 87410259SAndrew.Bardsley@arm.com 87510259SAndrew.Bardsley@arm.com bool completed_inst = true; 87610259SAndrew.Bardsley@arm.com fault = NoFault; 87710259SAndrew.Bardsley@arm.com 87810259SAndrew.Bardsley@arm.com /* Is the thread for this instruction suspended? In that case, just 87910259SAndrew.Bardsley@arm.com * stall as long as there are no pending interrupts */ 88010259SAndrew.Bardsley@arm.com if (thread->status() == ThreadContext::Suspended && 88110259SAndrew.Bardsley@arm.com !isInterrupted(thread_id)) 88210259SAndrew.Bardsley@arm.com { 88310259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Not committing inst from suspended thread" 88410259SAndrew.Bardsley@arm.com " inst: %s\n", *inst); 88510259SAndrew.Bardsley@arm.com completed_inst = false; 88610259SAndrew.Bardsley@arm.com } else if (inst->isFault()) { 88710259SAndrew.Bardsley@arm.com ExecContext context(cpu, *cpu.threads[thread_id], *this, inst); 88810259SAndrew.Bardsley@arm.com 88910259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Fault inst reached Execute: %s\n", 89010259SAndrew.Bardsley@arm.com inst->fault->name()); 89110259SAndrew.Bardsley@arm.com 89210259SAndrew.Bardsley@arm.com fault = inst->fault; 89310259SAndrew.Bardsley@arm.com inst->fault->invoke(thread, NULL); 89410259SAndrew.Bardsley@arm.com 89510259SAndrew.Bardsley@arm.com tryToBranch(inst, fault, branch); 89610259SAndrew.Bardsley@arm.com } else if (inst->staticInst->isMemRef()) { 89710259SAndrew.Bardsley@arm.com /* Memory accesses are executed in two parts: 89810259SAndrew.Bardsley@arm.com * executeMemRefInst -- calculates the EA and issues the access 89910259SAndrew.Bardsley@arm.com * to memory. This is done here. 90010259SAndrew.Bardsley@arm.com * handleMemResponse -- handles the response packet, done by 90110259SAndrew.Bardsley@arm.com * Execute::commit 90210259SAndrew.Bardsley@arm.com * 90310259SAndrew.Bardsley@arm.com * While the memory access is in its FU, the EA is being 90410259SAndrew.Bardsley@arm.com * calculated. At the end of the FU, when it is ready to 90510259SAndrew.Bardsley@arm.com * 'commit' (in this function), the access is presented to the 90610259SAndrew.Bardsley@arm.com * memory queues. When a response comes back from memory, 90710259SAndrew.Bardsley@arm.com * Execute::commit will commit it. 90810259SAndrew.Bardsley@arm.com */ 90910259SAndrew.Bardsley@arm.com bool predicate_passed = false; 91010259SAndrew.Bardsley@arm.com bool completed_mem_inst = executeMemRefInst(inst, branch, 91110259SAndrew.Bardsley@arm.com predicate_passed, fault); 91210259SAndrew.Bardsley@arm.com 91310259SAndrew.Bardsley@arm.com if (completed_mem_inst && fault != NoFault) { 91410259SAndrew.Bardsley@arm.com if (early_memory_issue) { 91510259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Fault in early executing inst: %s\n", 91610259SAndrew.Bardsley@arm.com fault->name()); 91710259SAndrew.Bardsley@arm.com /* Don't execute the fault, just stall the instruction 91810259SAndrew.Bardsley@arm.com * until it gets to the head of inFlightInsts */ 91910259SAndrew.Bardsley@arm.com inst->canEarlyIssue = false; 92010259SAndrew.Bardsley@arm.com /* Not completed as we'll come here again to pick up 92110259SAndrew.Bardsley@arm.com * the fault when we get to the end of the FU */ 92210259SAndrew.Bardsley@arm.com completed_inst = false; 92310259SAndrew.Bardsley@arm.com } else { 92410259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Fault in execute: %s\n", 92510259SAndrew.Bardsley@arm.com fault->name()); 92610259SAndrew.Bardsley@arm.com fault->invoke(thread, NULL); 92710259SAndrew.Bardsley@arm.com 92810259SAndrew.Bardsley@arm.com tryToBranch(inst, fault, branch); 92910259SAndrew.Bardsley@arm.com completed_inst = true; 93010259SAndrew.Bardsley@arm.com } 93110259SAndrew.Bardsley@arm.com } else { 93210259SAndrew.Bardsley@arm.com completed_inst = completed_mem_inst; 93310259SAndrew.Bardsley@arm.com } 93410259SAndrew.Bardsley@arm.com completed_mem_issue = completed_inst; 93510259SAndrew.Bardsley@arm.com } else if (inst->isInst() && inst->staticInst->isMemBarrier() && 93610259SAndrew.Bardsley@arm.com !lsq.canPushIntoStoreBuffer()) 93710259SAndrew.Bardsley@arm.com { 93810259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't commit data barrier inst: %s yet as" 93910259SAndrew.Bardsley@arm.com " there isn't space in the store buffer\n", *inst); 94010259SAndrew.Bardsley@arm.com 94110259SAndrew.Bardsley@arm.com completed_inst = false; 94211567Smitch.hayenga@arm.com } else if (inst->isInst() && inst->staticInst->isQuiesce() 94311567Smitch.hayenga@arm.com && !branch.isBubble()){ 94411567Smitch.hayenga@arm.com /* This instruction can suspend, need to be able to communicate 94511567Smitch.hayenga@arm.com * backwards, so no other branches may evaluate this cycle*/ 94611567Smitch.hayenga@arm.com completed_inst = false; 94710259SAndrew.Bardsley@arm.com } else { 94810259SAndrew.Bardsley@arm.com ExecContext context(cpu, *cpu.threads[thread_id], *this, inst); 94910259SAndrew.Bardsley@arm.com 95010259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Committing inst: %s\n", *inst); 95110259SAndrew.Bardsley@arm.com 95210259SAndrew.Bardsley@arm.com fault = inst->staticInst->execute(&context, 95310259SAndrew.Bardsley@arm.com inst->traceData); 95410259SAndrew.Bardsley@arm.com 95510259SAndrew.Bardsley@arm.com /* Set the predicate for tracing and dump */ 95610259SAndrew.Bardsley@arm.com if (inst->traceData) 95710259SAndrew.Bardsley@arm.com inst->traceData->setPredicate(context.readPredicate()); 95810259SAndrew.Bardsley@arm.com 95910259SAndrew.Bardsley@arm.com committed = true; 96010259SAndrew.Bardsley@arm.com 96110259SAndrew.Bardsley@arm.com if (fault != NoFault) { 96210259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Fault in execute of inst: %s fault: %s\n", 96310259SAndrew.Bardsley@arm.com *inst, fault->name()); 96410259SAndrew.Bardsley@arm.com fault->invoke(thread, inst->staticInst); 96510259SAndrew.Bardsley@arm.com } 96610259SAndrew.Bardsley@arm.com 96710259SAndrew.Bardsley@arm.com doInstCommitAccounting(inst); 96810259SAndrew.Bardsley@arm.com tryToBranch(inst, fault, branch); 96910259SAndrew.Bardsley@arm.com } 97010259SAndrew.Bardsley@arm.com 97110259SAndrew.Bardsley@arm.com if (completed_inst) { 97210259SAndrew.Bardsley@arm.com /* Keep a copy of this instruction's predictionSeqNum just in case 97310259SAndrew.Bardsley@arm.com * we need to issue a branch without an instruction (such as an 97410259SAndrew.Bardsley@arm.com * interrupt) */ 97511567Smitch.hayenga@arm.com executeInfo[thread_id].lastPredictionSeqNum = inst->id.predictionSeqNum; 97610259SAndrew.Bardsley@arm.com 97710259SAndrew.Bardsley@arm.com /* Check to see if this instruction suspended the current thread. */ 97810259SAndrew.Bardsley@arm.com if (!inst->isFault() && 97910259SAndrew.Bardsley@arm.com thread->status() == ThreadContext::Suspended && 98010259SAndrew.Bardsley@arm.com branch.isBubble() && /* It didn't branch too */ 98110259SAndrew.Bardsley@arm.com !isInterrupted(thread_id)) /* Don't suspend if we have 98210259SAndrew.Bardsley@arm.com interrupts */ 98310259SAndrew.Bardsley@arm.com { 98411567Smitch.hayenga@arm.com TheISA::PCState resume_pc = cpu.getContext(thread_id)->pcState(); 98510259SAndrew.Bardsley@arm.com 98610259SAndrew.Bardsley@arm.com assert(resume_pc.microPC() == 0); 98710259SAndrew.Bardsley@arm.com 98810259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Suspending thread: %d from Execute" 98911567Smitch.hayenga@arm.com " inst: %s\n", thread_id, *inst); 99010259SAndrew.Bardsley@arm.com 99110259SAndrew.Bardsley@arm.com cpu.stats.numFetchSuspends++; 99210259SAndrew.Bardsley@arm.com 99311567Smitch.hayenga@arm.com updateBranchData(thread_id, BranchData::SuspendThread, inst, 99411567Smitch.hayenga@arm.com resume_pc, branch); 99510259SAndrew.Bardsley@arm.com } 99610259SAndrew.Bardsley@arm.com } 99710259SAndrew.Bardsley@arm.com 99810259SAndrew.Bardsley@arm.com return completed_inst; 99910259SAndrew.Bardsley@arm.com} 100010259SAndrew.Bardsley@arm.com 100110259SAndrew.Bardsley@arm.comvoid 100211567Smitch.hayenga@arm.comExecute::commit(ThreadID thread_id, bool only_commit_microops, bool discard, 100311567Smitch.hayenga@arm.com BranchData &branch) 100410259SAndrew.Bardsley@arm.com{ 100510259SAndrew.Bardsley@arm.com Fault fault = NoFault; 100610259SAndrew.Bardsley@arm.com Cycles now = cpu.curCycle(); 100711567Smitch.hayenga@arm.com ExecuteThreadInfo &ex_info = executeInfo[thread_id]; 100810259SAndrew.Bardsley@arm.com 100910259SAndrew.Bardsley@arm.com /** 101010259SAndrew.Bardsley@arm.com * Try and execute as many instructions from the end of FU pipelines as 101110259SAndrew.Bardsley@arm.com * possible. This *doesn't* include actually advancing the pipelines. 101210259SAndrew.Bardsley@arm.com * 101310259SAndrew.Bardsley@arm.com * We do this by looping on the front of the inFlightInsts queue for as 101410259SAndrew.Bardsley@arm.com * long as we can find the desired instruction at the end of the 101510259SAndrew.Bardsley@arm.com * functional unit it was issued to without seeing a branch or a fault. 101610259SAndrew.Bardsley@arm.com * In this function, these terms are used: 101710259SAndrew.Bardsley@arm.com * complete -- The instruction has finished its passage through 101810259SAndrew.Bardsley@arm.com * its functional unit and its fate has been decided 101910259SAndrew.Bardsley@arm.com * (committed, discarded, issued to the memory system) 102010259SAndrew.Bardsley@arm.com * commit -- The instruction is complete(d), not discarded and has 102110259SAndrew.Bardsley@arm.com * its effects applied to the CPU state 102210259SAndrew.Bardsley@arm.com * discard(ed) -- The instruction is complete but not committed 102310259SAndrew.Bardsley@arm.com * as its streamSeqNum disagrees with the current 102410259SAndrew.Bardsley@arm.com * Execute::streamSeqNum 102510259SAndrew.Bardsley@arm.com * 102610259SAndrew.Bardsley@arm.com * Commits are also possible from two other places: 102710259SAndrew.Bardsley@arm.com * 102810259SAndrew.Bardsley@arm.com * 1) Responses returning from the LSQ 102910259SAndrew.Bardsley@arm.com * 2) Mem ops issued to the LSQ ('committed' from the FUs) earlier 103010259SAndrew.Bardsley@arm.com * than their position in the inFlightInsts queue, but after all 103110259SAndrew.Bardsley@arm.com * their dependencies are resolved. 103210259SAndrew.Bardsley@arm.com */ 103310259SAndrew.Bardsley@arm.com 103410259SAndrew.Bardsley@arm.com /* Has an instruction been completed? Once this becomes false, we stop 103510259SAndrew.Bardsley@arm.com * trying to complete instructions. */ 103610259SAndrew.Bardsley@arm.com bool completed_inst = true; 103710259SAndrew.Bardsley@arm.com 103810259SAndrew.Bardsley@arm.com /* Number of insts committed this cycle to check against commitLimit */ 103910259SAndrew.Bardsley@arm.com unsigned int num_insts_committed = 0; 104010259SAndrew.Bardsley@arm.com 104110259SAndrew.Bardsley@arm.com /* Number of memory access instructions committed to check against 104210259SAndrew.Bardsley@arm.com * memCommitLimit */ 104310259SAndrew.Bardsley@arm.com unsigned int num_mem_refs_committed = 0; 104410259SAndrew.Bardsley@arm.com 104511567Smitch.hayenga@arm.com if (only_commit_microops && !ex_info.inFlightInsts->empty()) { 104610259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Only commit microops %s %d\n", 104711567Smitch.hayenga@arm.com *(ex_info.inFlightInsts->front().inst), 104811567Smitch.hayenga@arm.com ex_info.lastCommitWasEndOfMacroop); 104910259SAndrew.Bardsley@arm.com } 105010259SAndrew.Bardsley@arm.com 105111567Smitch.hayenga@arm.com while (!ex_info.inFlightInsts->empty() && /* Some more instructions to process */ 105210259SAndrew.Bardsley@arm.com !branch.isStreamChange() && /* No real branch */ 105310259SAndrew.Bardsley@arm.com fault == NoFault && /* No faults */ 105410259SAndrew.Bardsley@arm.com completed_inst && /* Still finding instructions to execute */ 105510259SAndrew.Bardsley@arm.com num_insts_committed != commitLimit /* Not reached commit limit */ 105610259SAndrew.Bardsley@arm.com ) 105710259SAndrew.Bardsley@arm.com { 105810259SAndrew.Bardsley@arm.com if (only_commit_microops) { 105910259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Committing tail of insts before" 106010259SAndrew.Bardsley@arm.com " interrupt: %s\n", 106111567Smitch.hayenga@arm.com *(ex_info.inFlightInsts->front().inst)); 106210259SAndrew.Bardsley@arm.com } 106310259SAndrew.Bardsley@arm.com 106411567Smitch.hayenga@arm.com QueuedInst *head_inflight_inst = &(ex_info.inFlightInsts->front()); 106510259SAndrew.Bardsley@arm.com 106610259SAndrew.Bardsley@arm.com InstSeqNum head_exec_seq_num = 106710259SAndrew.Bardsley@arm.com head_inflight_inst->inst->id.execSeqNum; 106810259SAndrew.Bardsley@arm.com 106910259SAndrew.Bardsley@arm.com /* The instruction we actually process if completed_inst 107010259SAndrew.Bardsley@arm.com * remains true to the end of the loop body. 107110259SAndrew.Bardsley@arm.com * Start by considering the the head of the in flight insts queue */ 107210259SAndrew.Bardsley@arm.com MinorDynInstPtr inst = head_inflight_inst->inst; 107310259SAndrew.Bardsley@arm.com 107410259SAndrew.Bardsley@arm.com bool committed_inst = false; 107510259SAndrew.Bardsley@arm.com bool discard_inst = false; 107610259SAndrew.Bardsley@arm.com bool completed_mem_ref = false; 107710259SAndrew.Bardsley@arm.com bool issued_mem_ref = false; 107810259SAndrew.Bardsley@arm.com bool early_memory_issue = false; 107910259SAndrew.Bardsley@arm.com 108010259SAndrew.Bardsley@arm.com /* Must set this again to go around the loop */ 108110259SAndrew.Bardsley@arm.com completed_inst = false; 108210259SAndrew.Bardsley@arm.com 108310259SAndrew.Bardsley@arm.com /* If we're just completing a macroop before an interrupt or drain, 108410259SAndrew.Bardsley@arm.com * can we stil commit another microop (rather than a memory response) 108510259SAndrew.Bardsley@arm.com * without crosing into the next full instruction? */ 108611567Smitch.hayenga@arm.com bool can_commit_insts = !ex_info.inFlightInsts->empty() && 108711567Smitch.hayenga@arm.com !(only_commit_microops && ex_info.lastCommitWasEndOfMacroop); 108810259SAndrew.Bardsley@arm.com 108910259SAndrew.Bardsley@arm.com /* Can we find a mem response for this inst */ 109010259SAndrew.Bardsley@arm.com LSQ::LSQRequestPtr mem_response = 109110259SAndrew.Bardsley@arm.com (inst->inLSQ ? lsq.findResponse(inst) : NULL); 109210259SAndrew.Bardsley@arm.com 109310259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Trying to commit canCommitInsts: %d\n", 109410259SAndrew.Bardsley@arm.com can_commit_insts); 109510259SAndrew.Bardsley@arm.com 109610259SAndrew.Bardsley@arm.com /* Test for PC events after every instruction */ 109711567Smitch.hayenga@arm.com if (isInbetweenInsts(thread_id) && tryPCEvents(thread_id)) { 109811567Smitch.hayenga@arm.com ThreadContext *thread = cpu.getContext(thread_id); 109910259SAndrew.Bardsley@arm.com 110010259SAndrew.Bardsley@arm.com /* Branch as there was a change in PC */ 110111567Smitch.hayenga@arm.com updateBranchData(thread_id, BranchData::UnpredictedBranch, 110210259SAndrew.Bardsley@arm.com MinorDynInst::bubble(), thread->pcState(), branch); 110310259SAndrew.Bardsley@arm.com } else if (mem_response && 110410259SAndrew.Bardsley@arm.com num_mem_refs_committed < memoryCommitLimit) 110510259SAndrew.Bardsley@arm.com { 110610259SAndrew.Bardsley@arm.com /* Try to commit from the memory responses next */ 110711567Smitch.hayenga@arm.com discard_inst = inst->id.streamSeqNum != 110811567Smitch.hayenga@arm.com ex_info.streamSeqNum || discard; 110910259SAndrew.Bardsley@arm.com 111010259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Trying to commit mem response: %s\n", 111110259SAndrew.Bardsley@arm.com *inst); 111210259SAndrew.Bardsley@arm.com 111310259SAndrew.Bardsley@arm.com /* Complete or discard the response */ 111410259SAndrew.Bardsley@arm.com if (discard_inst) { 111510259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Discarding mem inst: %s as its" 111610259SAndrew.Bardsley@arm.com " stream state was unexpected, expected: %d\n", 111711567Smitch.hayenga@arm.com *inst, ex_info.streamSeqNum); 111810259SAndrew.Bardsley@arm.com 111910259SAndrew.Bardsley@arm.com lsq.popResponse(mem_response); 112010259SAndrew.Bardsley@arm.com } else { 112110259SAndrew.Bardsley@arm.com handleMemResponse(inst, mem_response, branch, fault); 112210259SAndrew.Bardsley@arm.com committed_inst = true; 112310259SAndrew.Bardsley@arm.com } 112410259SAndrew.Bardsley@arm.com 112510259SAndrew.Bardsley@arm.com completed_mem_ref = true; 112610259SAndrew.Bardsley@arm.com completed_inst = true; 112710259SAndrew.Bardsley@arm.com } else if (can_commit_insts) { 112810259SAndrew.Bardsley@arm.com /* If true, this instruction will, subject to timing tweaks, 112910259SAndrew.Bardsley@arm.com * be considered for completion. try_to_commit flattens 113010259SAndrew.Bardsley@arm.com * the `if' tree a bit and allows other tests for inst 113110259SAndrew.Bardsley@arm.com * commit to be inserted here. */ 113210259SAndrew.Bardsley@arm.com bool try_to_commit = false; 113310259SAndrew.Bardsley@arm.com 113410259SAndrew.Bardsley@arm.com /* Try and issue memory ops early if they: 113510259SAndrew.Bardsley@arm.com * - Can push a request into the LSQ 113610259SAndrew.Bardsley@arm.com * - Have reached the end of their FUs 113710259SAndrew.Bardsley@arm.com * - Have had all their dependencies satisfied 113810259SAndrew.Bardsley@arm.com * - Are from the right stream 113910259SAndrew.Bardsley@arm.com * 114010259SAndrew.Bardsley@arm.com * For any other case, leave it to the normal instruction 114110259SAndrew.Bardsley@arm.com * issue below to handle them. 114210259SAndrew.Bardsley@arm.com */ 114311567Smitch.hayenga@arm.com if (!ex_info.inFUMemInsts->empty() && lsq.canRequest()) { 114410259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Trying to commit from mem FUs\n"); 114510259SAndrew.Bardsley@arm.com 114610259SAndrew.Bardsley@arm.com const MinorDynInstPtr head_mem_ref_inst = 114711567Smitch.hayenga@arm.com ex_info.inFUMemInsts->front().inst; 114810259SAndrew.Bardsley@arm.com FUPipeline *fu = funcUnits[head_mem_ref_inst->fuIndex]; 114910259SAndrew.Bardsley@arm.com const MinorDynInstPtr &fu_inst = fu->front().inst; 115010259SAndrew.Bardsley@arm.com 115110259SAndrew.Bardsley@arm.com /* Use this, possibly out of order, inst as the one 115210259SAndrew.Bardsley@arm.com * to 'commit'/send to the LSQ */ 115310259SAndrew.Bardsley@arm.com if (!fu_inst->isBubble() && 115410259SAndrew.Bardsley@arm.com !fu_inst->inLSQ && 115510259SAndrew.Bardsley@arm.com fu_inst->canEarlyIssue && 115611567Smitch.hayenga@arm.com ex_info.streamSeqNum == fu_inst->id.streamSeqNum && 115710259SAndrew.Bardsley@arm.com head_exec_seq_num > fu_inst->instToWaitFor) 115810259SAndrew.Bardsley@arm.com { 115910259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Issuing mem ref early" 116010259SAndrew.Bardsley@arm.com " inst: %s instToWaitFor: %d\n", 116110259SAndrew.Bardsley@arm.com *(fu_inst), fu_inst->instToWaitFor); 116210259SAndrew.Bardsley@arm.com 116310259SAndrew.Bardsley@arm.com inst = fu_inst; 116410259SAndrew.Bardsley@arm.com try_to_commit = true; 116510259SAndrew.Bardsley@arm.com early_memory_issue = true; 116610259SAndrew.Bardsley@arm.com completed_inst = true; 116710259SAndrew.Bardsley@arm.com } 116810259SAndrew.Bardsley@arm.com } 116910259SAndrew.Bardsley@arm.com 117010259SAndrew.Bardsley@arm.com /* Try and commit FU-less insts */ 117110259SAndrew.Bardsley@arm.com if (!completed_inst && inst->isNoCostInst()) { 117210259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Committing no cost inst: %s", *inst); 117310259SAndrew.Bardsley@arm.com 117410259SAndrew.Bardsley@arm.com try_to_commit = true; 117510259SAndrew.Bardsley@arm.com completed_inst = true; 117610259SAndrew.Bardsley@arm.com } 117710259SAndrew.Bardsley@arm.com 117810259SAndrew.Bardsley@arm.com /* Try to issue from the ends of FUs and the inFlightInsts 117910259SAndrew.Bardsley@arm.com * queue */ 118010259SAndrew.Bardsley@arm.com if (!completed_inst && !inst->inLSQ) { 118110259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Trying to commit from FUs\n"); 118210259SAndrew.Bardsley@arm.com 118310259SAndrew.Bardsley@arm.com /* Try to commit from a functional unit */ 118410259SAndrew.Bardsley@arm.com /* Is the head inst of the expected inst's FU actually the 118510259SAndrew.Bardsley@arm.com * expected inst? */ 118610259SAndrew.Bardsley@arm.com QueuedInst &fu_inst = 118710259SAndrew.Bardsley@arm.com funcUnits[inst->fuIndex]->front(); 118810259SAndrew.Bardsley@arm.com InstSeqNum fu_inst_seq_num = fu_inst.inst->id.execSeqNum; 118910259SAndrew.Bardsley@arm.com 119010259SAndrew.Bardsley@arm.com if (fu_inst.inst->isBubble()) { 119110259SAndrew.Bardsley@arm.com /* No instruction ready */ 119210259SAndrew.Bardsley@arm.com completed_inst = false; 119310259SAndrew.Bardsley@arm.com } else if (fu_inst_seq_num != head_exec_seq_num) { 119410259SAndrew.Bardsley@arm.com /* Past instruction: we must have already executed it 119510259SAndrew.Bardsley@arm.com * in the same cycle and so the head inst isn't 119610259SAndrew.Bardsley@arm.com * actually at the end of its pipeline 119710259SAndrew.Bardsley@arm.com * Future instruction: handled above and only for 119810259SAndrew.Bardsley@arm.com * mem refs on their way to the LSQ */ 119911567Smitch.hayenga@arm.com } else if (fu_inst.inst->id == inst->id) { 120010259SAndrew.Bardsley@arm.com /* All instructions can be committed if they have the 120110259SAndrew.Bardsley@arm.com * right execSeqNum and there are no in-flight 120210259SAndrew.Bardsley@arm.com * mem insts before us */ 120310259SAndrew.Bardsley@arm.com try_to_commit = true; 120410259SAndrew.Bardsley@arm.com completed_inst = true; 120510259SAndrew.Bardsley@arm.com } 120610259SAndrew.Bardsley@arm.com } 120710259SAndrew.Bardsley@arm.com 120810259SAndrew.Bardsley@arm.com if (try_to_commit) { 120911567Smitch.hayenga@arm.com discard_inst = inst->id.streamSeqNum != 121011567Smitch.hayenga@arm.com ex_info.streamSeqNum || discard; 121110259SAndrew.Bardsley@arm.com 121210259SAndrew.Bardsley@arm.com /* Is this instruction discardable as its streamSeqNum 121310259SAndrew.Bardsley@arm.com * doesn't match? */ 121410259SAndrew.Bardsley@arm.com if (!discard_inst) { 121510259SAndrew.Bardsley@arm.com /* Try to commit or discard a non-memory instruction. 121610259SAndrew.Bardsley@arm.com * Memory ops are actually 'committed' from this FUs 121710259SAndrew.Bardsley@arm.com * and 'issued' into the memory system so we need to 121810259SAndrew.Bardsley@arm.com * account for them later (commit_was_mem_issue gets 121910259SAndrew.Bardsley@arm.com * set) */ 122010259SAndrew.Bardsley@arm.com if (inst->extraCommitDelayExpr) { 122110259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Evaluating expression for" 122210259SAndrew.Bardsley@arm.com " extra commit delay inst: %s\n", *inst); 122310259SAndrew.Bardsley@arm.com 122411567Smitch.hayenga@arm.com ThreadContext *thread = cpu.getContext(thread_id); 122510259SAndrew.Bardsley@arm.com 122610259SAndrew.Bardsley@arm.com TimingExprEvalContext context(inst->staticInst, 122710259SAndrew.Bardsley@arm.com thread, NULL); 122810259SAndrew.Bardsley@arm.com 122910259SAndrew.Bardsley@arm.com uint64_t extra_delay = inst->extraCommitDelayExpr-> 123010259SAndrew.Bardsley@arm.com eval(context); 123110259SAndrew.Bardsley@arm.com 123210259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Extra commit delay expr" 123310259SAndrew.Bardsley@arm.com " result: %d\n", extra_delay); 123410259SAndrew.Bardsley@arm.com 123510259SAndrew.Bardsley@arm.com if (extra_delay < 128) { 123610259SAndrew.Bardsley@arm.com inst->extraCommitDelay += Cycles(extra_delay); 123710259SAndrew.Bardsley@arm.com } else { 123810259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Extra commit delay was" 123910259SAndrew.Bardsley@arm.com " very long: %d\n", extra_delay); 124010259SAndrew.Bardsley@arm.com } 124110259SAndrew.Bardsley@arm.com inst->extraCommitDelayExpr = NULL; 124210259SAndrew.Bardsley@arm.com } 124310259SAndrew.Bardsley@arm.com 124410259SAndrew.Bardsley@arm.com /* Move the extraCommitDelay from the instruction 124510259SAndrew.Bardsley@arm.com * into the minimumCommitCycle */ 124610259SAndrew.Bardsley@arm.com if (inst->extraCommitDelay != Cycles(0)) { 124710259SAndrew.Bardsley@arm.com inst->minimumCommitCycle = cpu.curCycle() + 124810259SAndrew.Bardsley@arm.com inst->extraCommitDelay; 124910259SAndrew.Bardsley@arm.com inst->extraCommitDelay = Cycles(0); 125010259SAndrew.Bardsley@arm.com } 125110259SAndrew.Bardsley@arm.com 125210259SAndrew.Bardsley@arm.com /* @todo Think about making lastMemBarrier be 125310259SAndrew.Bardsley@arm.com * MAX_UINT_64 to avoid using 0 as a marker value */ 125410259SAndrew.Bardsley@arm.com if (!inst->isFault() && inst->isMemRef() && 125511567Smitch.hayenga@arm.com lsq.getLastMemBarrier(thread_id) < 125610259SAndrew.Bardsley@arm.com inst->id.execSeqNum && 125711567Smitch.hayenga@arm.com lsq.getLastMemBarrier(thread_id) != 0) 125810259SAndrew.Bardsley@arm.com { 125910259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Not committing inst: %s yet" 126010259SAndrew.Bardsley@arm.com " as there are incomplete barriers in flight\n", 126110259SAndrew.Bardsley@arm.com *inst); 126210259SAndrew.Bardsley@arm.com completed_inst = false; 126310259SAndrew.Bardsley@arm.com } else if (inst->minimumCommitCycle > now) { 126410259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Not committing inst: %s yet" 126510259SAndrew.Bardsley@arm.com " as it wants to be stalled for %d more cycles\n", 126610259SAndrew.Bardsley@arm.com *inst, inst->minimumCommitCycle - now); 126710259SAndrew.Bardsley@arm.com completed_inst = false; 126810259SAndrew.Bardsley@arm.com } else { 126910259SAndrew.Bardsley@arm.com completed_inst = commitInst(inst, 127010259SAndrew.Bardsley@arm.com early_memory_issue, branch, fault, 127110259SAndrew.Bardsley@arm.com committed_inst, issued_mem_ref); 127210259SAndrew.Bardsley@arm.com } 127310259SAndrew.Bardsley@arm.com } else { 127410259SAndrew.Bardsley@arm.com /* Discard instruction */ 127510259SAndrew.Bardsley@arm.com completed_inst = true; 127610259SAndrew.Bardsley@arm.com } 127710259SAndrew.Bardsley@arm.com 127810259SAndrew.Bardsley@arm.com if (completed_inst) { 127910259SAndrew.Bardsley@arm.com /* Allow the pipeline to advance. If the FU head 128010259SAndrew.Bardsley@arm.com * instruction wasn't the inFlightInsts head 128110259SAndrew.Bardsley@arm.com * but had already been committed, it would have 128210259SAndrew.Bardsley@arm.com * unstalled the pipeline before here */ 128311567Smitch.hayenga@arm.com if (inst->fuIndex != noCostFUIndex) { 128411567Smitch.hayenga@arm.com DPRINTF(MinorExecute, "Unstalling %d for inst %s\n", inst->fuIndex, inst->id); 128510259SAndrew.Bardsley@arm.com funcUnits[inst->fuIndex]->stalled = false; 128611567Smitch.hayenga@arm.com } 128710259SAndrew.Bardsley@arm.com } 128810259SAndrew.Bardsley@arm.com } 128910259SAndrew.Bardsley@arm.com } else { 129010259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "No instructions to commit\n"); 129110259SAndrew.Bardsley@arm.com completed_inst = false; 129210259SAndrew.Bardsley@arm.com } 129310259SAndrew.Bardsley@arm.com 129410259SAndrew.Bardsley@arm.com /* All discardable instructions must also be 'completed' by now */ 129510259SAndrew.Bardsley@arm.com assert(!(discard_inst && !completed_inst)); 129610259SAndrew.Bardsley@arm.com 129710259SAndrew.Bardsley@arm.com /* Instruction committed but was discarded due to streamSeqNum 129810259SAndrew.Bardsley@arm.com * mismatch */ 129910259SAndrew.Bardsley@arm.com if (discard_inst) { 130010259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Discarding inst: %s as its stream" 130110259SAndrew.Bardsley@arm.com " state was unexpected, expected: %d\n", 130211567Smitch.hayenga@arm.com *inst, ex_info.streamSeqNum); 130310259SAndrew.Bardsley@arm.com 130410259SAndrew.Bardsley@arm.com if (fault == NoFault) 130510259SAndrew.Bardsley@arm.com cpu.stats.numDiscardedOps++; 130610259SAndrew.Bardsley@arm.com } 130710259SAndrew.Bardsley@arm.com 130810259SAndrew.Bardsley@arm.com /* Mark the mem inst as being in the LSQ */ 130910259SAndrew.Bardsley@arm.com if (issued_mem_ref) { 131010259SAndrew.Bardsley@arm.com inst->fuIndex = 0; 131110259SAndrew.Bardsley@arm.com inst->inLSQ = true; 131210259SAndrew.Bardsley@arm.com } 131310259SAndrew.Bardsley@arm.com 131410259SAndrew.Bardsley@arm.com /* Pop issued (to LSQ) and discarded mem refs from the inFUMemInsts 131510259SAndrew.Bardsley@arm.com * as they've *definitely* exited the FUs */ 131610259SAndrew.Bardsley@arm.com if (completed_inst && inst->isMemRef()) { 131710259SAndrew.Bardsley@arm.com /* The MemRef could have been discarded from the FU or the memory 131810259SAndrew.Bardsley@arm.com * queue, so just check an FU instruction */ 131911567Smitch.hayenga@arm.com if (!ex_info.inFUMemInsts->empty() && 132011567Smitch.hayenga@arm.com ex_info.inFUMemInsts->front().inst == inst) 132110259SAndrew.Bardsley@arm.com { 132211567Smitch.hayenga@arm.com ex_info.inFUMemInsts->pop(); 132310259SAndrew.Bardsley@arm.com } 132410259SAndrew.Bardsley@arm.com } 132510259SAndrew.Bardsley@arm.com 132610259SAndrew.Bardsley@arm.com if (completed_inst && !(issued_mem_ref && fault == NoFault)) { 132710259SAndrew.Bardsley@arm.com /* Note that this includes discarded insts */ 132810259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Completed inst: %s\n", *inst); 132910259SAndrew.Bardsley@arm.com 133010259SAndrew.Bardsley@arm.com /* Got to the end of a full instruction? */ 133111567Smitch.hayenga@arm.com ex_info.lastCommitWasEndOfMacroop = inst->isFault() || 133210259SAndrew.Bardsley@arm.com inst->isLastOpInInst(); 133310259SAndrew.Bardsley@arm.com 133410259SAndrew.Bardsley@arm.com /* lastPredictionSeqNum is kept as a convenience to prevent its 133510259SAndrew.Bardsley@arm.com * value from changing too much on the minorview display */ 133611567Smitch.hayenga@arm.com ex_info.lastPredictionSeqNum = inst->id.predictionSeqNum; 133710259SAndrew.Bardsley@arm.com 133810259SAndrew.Bardsley@arm.com /* Finished with the inst, remove it from the inst queue and 133910259SAndrew.Bardsley@arm.com * clear its dependencies */ 134011567Smitch.hayenga@arm.com ex_info.inFlightInsts->pop(); 134110259SAndrew.Bardsley@arm.com 134210259SAndrew.Bardsley@arm.com /* Complete barriers in the LSQ/move to store buffer */ 134310259SAndrew.Bardsley@arm.com if (inst->isInst() && inst->staticInst->isMemBarrier()) { 134410259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Completing memory barrier" 134510259SAndrew.Bardsley@arm.com " inst: %s committed: %d\n", *inst, committed_inst); 134610259SAndrew.Bardsley@arm.com lsq.completeMemBarrierInst(inst, committed_inst); 134710259SAndrew.Bardsley@arm.com } 134810259SAndrew.Bardsley@arm.com 134911567Smitch.hayenga@arm.com scoreboard[thread_id].clearInstDests(inst, inst->isMemRef()); 135010259SAndrew.Bardsley@arm.com } 135110259SAndrew.Bardsley@arm.com 135210259SAndrew.Bardsley@arm.com /* Handle per-cycle instruction counting */ 135310259SAndrew.Bardsley@arm.com if (committed_inst) { 135410259SAndrew.Bardsley@arm.com bool is_no_cost_inst = inst->isNoCostInst(); 135510259SAndrew.Bardsley@arm.com 135610259SAndrew.Bardsley@arm.com /* Don't show no cost instructions as having taken a commit 135710259SAndrew.Bardsley@arm.com * slot */ 135810259SAndrew.Bardsley@arm.com if (DTRACE(MinorTrace) && !is_no_cost_inst) 135911567Smitch.hayenga@arm.com ex_info.instsBeingCommitted.insts[num_insts_committed] = inst; 136010259SAndrew.Bardsley@arm.com 136110259SAndrew.Bardsley@arm.com if (!is_no_cost_inst) 136210259SAndrew.Bardsley@arm.com num_insts_committed++; 136310259SAndrew.Bardsley@arm.com 136410259SAndrew.Bardsley@arm.com if (num_insts_committed == commitLimit) 136510259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Reached inst commit limit\n"); 136610259SAndrew.Bardsley@arm.com 136710259SAndrew.Bardsley@arm.com /* Re-set the time of the instruction if that's required for 136810259SAndrew.Bardsley@arm.com * tracing */ 136910259SAndrew.Bardsley@arm.com if (inst->traceData) { 137010259SAndrew.Bardsley@arm.com if (setTraceTimeOnCommit) 137110259SAndrew.Bardsley@arm.com inst->traceData->setWhen(curTick()); 137210259SAndrew.Bardsley@arm.com inst->traceData->dump(); 137310259SAndrew.Bardsley@arm.com } 137410259SAndrew.Bardsley@arm.com 137510259SAndrew.Bardsley@arm.com if (completed_mem_ref) 137610259SAndrew.Bardsley@arm.com num_mem_refs_committed++; 137710259SAndrew.Bardsley@arm.com 137810259SAndrew.Bardsley@arm.com if (num_mem_refs_committed == memoryCommitLimit) 137910259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Reached mem ref commit limit\n"); 138010259SAndrew.Bardsley@arm.com } 138110259SAndrew.Bardsley@arm.com } 138210259SAndrew.Bardsley@arm.com} 138310259SAndrew.Bardsley@arm.com 138410259SAndrew.Bardsley@arm.combool 138511567Smitch.hayenga@arm.comExecute::isInbetweenInsts(ThreadID thread_id) const 138610259SAndrew.Bardsley@arm.com{ 138711567Smitch.hayenga@arm.com return executeInfo[thread_id].lastCommitWasEndOfMacroop && 138810259SAndrew.Bardsley@arm.com !lsq.accessesInFlight(); 138910259SAndrew.Bardsley@arm.com} 139010259SAndrew.Bardsley@arm.com 139110259SAndrew.Bardsley@arm.comvoid 139210259SAndrew.Bardsley@arm.comExecute::evaluate() 139310259SAndrew.Bardsley@arm.com{ 139411567Smitch.hayenga@arm.com if (!inp.outputWire->isBubble()) 139511567Smitch.hayenga@arm.com inputBuffer[inp.outputWire->threadId].setTail(*inp.outputWire); 139611567Smitch.hayenga@arm.com 139710259SAndrew.Bardsley@arm.com BranchData &branch = *out.inputWire; 139810259SAndrew.Bardsley@arm.com 139911567Smitch.hayenga@arm.com unsigned int num_issued = 0; 140010259SAndrew.Bardsley@arm.com 140110259SAndrew.Bardsley@arm.com /* Do all the cycle-wise activities for dcachePort here to potentially 140210259SAndrew.Bardsley@arm.com * free up input spaces in the LSQ's requests queue */ 140310259SAndrew.Bardsley@arm.com lsq.step(); 140410259SAndrew.Bardsley@arm.com 140511567Smitch.hayenga@arm.com /* Check interrupts first. Will halt commit if interrupt found */ 140610259SAndrew.Bardsley@arm.com bool interrupted = false; 140711567Smitch.hayenga@arm.com ThreadID interrupt_tid = checkInterrupts(branch, interrupted); 140810259SAndrew.Bardsley@arm.com 140911567Smitch.hayenga@arm.com if (interrupt_tid != InvalidThreadID) { 141011567Smitch.hayenga@arm.com /* Signalling an interrupt this cycle, not issuing/committing from 141111567Smitch.hayenga@arm.com * any other threads */ 141210259SAndrew.Bardsley@arm.com } else if (!branch.isBubble()) { 141310259SAndrew.Bardsley@arm.com /* It's important that this is here to carry Fetch1 wakeups to Fetch1 141410259SAndrew.Bardsley@arm.com * without overwriting them */ 141510259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Execute skipping a cycle to allow old" 141610259SAndrew.Bardsley@arm.com " branch to complete\n"); 141710259SAndrew.Bardsley@arm.com } else { 141811567Smitch.hayenga@arm.com ThreadID commit_tid = getCommittingThread(); 141911567Smitch.hayenga@arm.com 142011567Smitch.hayenga@arm.com if (commit_tid != InvalidThreadID) { 142111567Smitch.hayenga@arm.com ExecuteThreadInfo& commit_info = executeInfo[commit_tid]; 142211567Smitch.hayenga@arm.com 142311567Smitch.hayenga@arm.com DPRINTF(MinorExecute, "Attempting to commit [tid:%d]\n", 142411567Smitch.hayenga@arm.com commit_tid); 142511567Smitch.hayenga@arm.com /* commit can set stalled flags observable to issue and so *must* be 142611567Smitch.hayenga@arm.com * called first */ 142711567Smitch.hayenga@arm.com if (commit_info.drainState != NotDraining) { 142811567Smitch.hayenga@arm.com if (commit_info.drainState == DrainCurrentInst) { 142911567Smitch.hayenga@arm.com /* Commit only micro-ops, don't kill anything else */ 143011567Smitch.hayenga@arm.com commit(commit_tid, true, false, branch); 143111567Smitch.hayenga@arm.com 143211567Smitch.hayenga@arm.com if (isInbetweenInsts(commit_tid)) 143311567Smitch.hayenga@arm.com setDrainState(commit_tid, DrainHaltFetch); 143411567Smitch.hayenga@arm.com 143511567Smitch.hayenga@arm.com /* Discard any generated branch */ 143611567Smitch.hayenga@arm.com branch = BranchData::bubble(); 143711567Smitch.hayenga@arm.com } else if (commit_info.drainState == DrainAllInsts) { 143811567Smitch.hayenga@arm.com /* Kill all instructions */ 143911567Smitch.hayenga@arm.com while (getInput(commit_tid)) 144011567Smitch.hayenga@arm.com popInput(commit_tid); 144111567Smitch.hayenga@arm.com commit(commit_tid, false, true, branch); 144211567Smitch.hayenga@arm.com } 144310259SAndrew.Bardsley@arm.com } else { 144411567Smitch.hayenga@arm.com /* Commit micro-ops only if interrupted. Otherwise, commit 144511567Smitch.hayenga@arm.com * anything you like */ 144611567Smitch.hayenga@arm.com DPRINTF(MinorExecute, "Committing micro-ops for interrupt[tid:%d]\n", 144711567Smitch.hayenga@arm.com commit_tid); 144811567Smitch.hayenga@arm.com bool only_commit_microops = interrupted && 144911567Smitch.hayenga@arm.com hasInterrupt(commit_tid); 145011567Smitch.hayenga@arm.com commit(commit_tid, only_commit_microops, false, branch); 145111567Smitch.hayenga@arm.com } 145211567Smitch.hayenga@arm.com 145311567Smitch.hayenga@arm.com /* Halt fetch, but don't do it until we have the current instruction in 145411567Smitch.hayenga@arm.com * the bag */ 145511567Smitch.hayenga@arm.com if (commit_info.drainState == DrainHaltFetch) { 145611567Smitch.hayenga@arm.com updateBranchData(commit_tid, BranchData::HaltFetch, 145711567Smitch.hayenga@arm.com MinorDynInst::bubble(), TheISA::PCState(0), branch); 145811567Smitch.hayenga@arm.com 145911567Smitch.hayenga@arm.com cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 146011567Smitch.hayenga@arm.com setDrainState(commit_tid, DrainAllInsts); 146110259SAndrew.Bardsley@arm.com } 146210259SAndrew.Bardsley@arm.com } 146311567Smitch.hayenga@arm.com ThreadID issue_tid = getIssuingThread(); 146411567Smitch.hayenga@arm.com /* This will issue merrily even when interrupted in the sure and 146511567Smitch.hayenga@arm.com * certain knowledge that the interrupt with change the stream */ 146611567Smitch.hayenga@arm.com if (issue_tid != InvalidThreadID) { 146711567Smitch.hayenga@arm.com DPRINTF(MinorExecute, "Attempting to issue [tid:%d]\n", 146811567Smitch.hayenga@arm.com issue_tid); 146911567Smitch.hayenga@arm.com num_issued = issue(issue_tid); 147010259SAndrew.Bardsley@arm.com } 147110259SAndrew.Bardsley@arm.com 147210259SAndrew.Bardsley@arm.com } 147310259SAndrew.Bardsley@arm.com 147411567Smitch.hayenga@arm.com /* Run logic to step functional units + decide if we are active on the next 147511567Smitch.hayenga@arm.com * clock cycle */ 147611567Smitch.hayenga@arm.com std::vector<MinorDynInstPtr> next_issuable_insts; 147710259SAndrew.Bardsley@arm.com bool can_issue_next = false; 147810259SAndrew.Bardsley@arm.com 147911567Smitch.hayenga@arm.com for (ThreadID tid = 0; tid < cpu.numThreads; tid++) { 148011567Smitch.hayenga@arm.com /* Find the next issuable instruction for each thread and see if it can 148111567Smitch.hayenga@arm.com be issued */ 148211567Smitch.hayenga@arm.com if (getInput(tid)) { 148311567Smitch.hayenga@arm.com unsigned int input_index = executeInfo[tid].inputIndex; 148411567Smitch.hayenga@arm.com MinorDynInstPtr inst = getInput(tid)->insts[input_index]; 148511567Smitch.hayenga@arm.com if (inst->isFault()) { 148611567Smitch.hayenga@arm.com can_issue_next = true; 148711567Smitch.hayenga@arm.com } else if (!inst->isBubble()) { 148811567Smitch.hayenga@arm.com if (cpu.getContext(tid)->status() != ThreadContext::Suspended) { 148911567Smitch.hayenga@arm.com next_issuable_insts.push_back(inst); 149011567Smitch.hayenga@arm.com } 149110259SAndrew.Bardsley@arm.com } 149210259SAndrew.Bardsley@arm.com } 149310259SAndrew.Bardsley@arm.com } 149410259SAndrew.Bardsley@arm.com 149510259SAndrew.Bardsley@arm.com bool becoming_stalled = true; 149610259SAndrew.Bardsley@arm.com 149710259SAndrew.Bardsley@arm.com /* Advance the pipelines and note whether they still need to be 149811567Smitch.hayenga@arm.com * advanced */ 149910259SAndrew.Bardsley@arm.com for (unsigned int i = 0; i < numFuncUnits; i++) { 150010259SAndrew.Bardsley@arm.com FUPipeline *fu = funcUnits[i]; 150110259SAndrew.Bardsley@arm.com fu->advance(); 150210259SAndrew.Bardsley@arm.com 150311567Smitch.hayenga@arm.com /* If we need to tick again, the pipeline will have been left or set 150411567Smitch.hayenga@arm.com * to be unstalled */ 150511567Smitch.hayenga@arm.com if (fu->occupancy !=0 && !fu->stalled) 150610259SAndrew.Bardsley@arm.com becoming_stalled = false; 150710259SAndrew.Bardsley@arm.com 150811567Smitch.hayenga@arm.com /* Could we possibly issue the next instruction from any thread? 150911567Smitch.hayenga@arm.com * This is quite an expensive test and is only used to determine 151011567Smitch.hayenga@arm.com * if the CPU should remain active, only run it if we aren't sure 151111567Smitch.hayenga@arm.com * we are active next cycle yet */ 151211567Smitch.hayenga@arm.com for (auto inst : next_issuable_insts) { 151311567Smitch.hayenga@arm.com if (!fu->stalled && fu->provides(inst->staticInst->opClass()) && 151411567Smitch.hayenga@arm.com scoreboard[inst->id.threadId].canInstIssue(inst, 151511567Smitch.hayenga@arm.com NULL, NULL, cpu.curCycle() + Cycles(1), 151611567Smitch.hayenga@arm.com cpu.getContext(inst->id.threadId))) { 151711567Smitch.hayenga@arm.com can_issue_next = true; 151811567Smitch.hayenga@arm.com break; 151911567Smitch.hayenga@arm.com } 152010259SAndrew.Bardsley@arm.com } 152110259SAndrew.Bardsley@arm.com } 152210259SAndrew.Bardsley@arm.com 152310259SAndrew.Bardsley@arm.com bool head_inst_might_commit = false; 152410259SAndrew.Bardsley@arm.com 152510259SAndrew.Bardsley@arm.com /* Could the head in flight insts be committed */ 152611567Smitch.hayenga@arm.com for (auto const &info : executeInfo) { 152711567Smitch.hayenga@arm.com if (!info.inFlightInsts->empty()) { 152811567Smitch.hayenga@arm.com const QueuedInst &head_inst = info.inFlightInsts->front(); 152910259SAndrew.Bardsley@arm.com 153011567Smitch.hayenga@arm.com if (head_inst.inst->isNoCostInst()) { 153110259SAndrew.Bardsley@arm.com head_inst_might_commit = true; 153211567Smitch.hayenga@arm.com } else { 153311567Smitch.hayenga@arm.com FUPipeline *fu = funcUnits[head_inst.inst->fuIndex]; 153411567Smitch.hayenga@arm.com if ((fu->stalled && 153511567Smitch.hayenga@arm.com fu->front().inst->id == head_inst.inst->id) || 153611567Smitch.hayenga@arm.com lsq.findResponse(head_inst.inst)) 153711567Smitch.hayenga@arm.com { 153811567Smitch.hayenga@arm.com head_inst_might_commit = true; 153911567Smitch.hayenga@arm.com break; 154011567Smitch.hayenga@arm.com } 154110259SAndrew.Bardsley@arm.com } 154210259SAndrew.Bardsley@arm.com } 154310259SAndrew.Bardsley@arm.com } 154410259SAndrew.Bardsley@arm.com 154510259SAndrew.Bardsley@arm.com DPRINTF(Activity, "Need to tick num issued insts: %s%s%s%s%s%s\n", 154610259SAndrew.Bardsley@arm.com (num_issued != 0 ? " (issued some insts)" : ""), 154711567Smitch.hayenga@arm.com (becoming_stalled ? "(becoming stalled)" : "(not becoming stalled)"), 154810259SAndrew.Bardsley@arm.com (can_issue_next ? " (can issued next inst)" : ""), 154910259SAndrew.Bardsley@arm.com (head_inst_might_commit ? "(head inst might commit)" : ""), 155010259SAndrew.Bardsley@arm.com (lsq.needsToTick() ? " (LSQ needs to tick)" : ""), 155110259SAndrew.Bardsley@arm.com (interrupted ? " (interrupted)" : "")); 155210259SAndrew.Bardsley@arm.com 155310259SAndrew.Bardsley@arm.com bool need_to_tick = 155410259SAndrew.Bardsley@arm.com num_issued != 0 || /* Issued some insts this cycle */ 155510259SAndrew.Bardsley@arm.com !becoming_stalled || /* Some FU pipelines can still move */ 155610259SAndrew.Bardsley@arm.com can_issue_next || /* Can still issue a new inst */ 155710259SAndrew.Bardsley@arm.com head_inst_might_commit || /* Could possible commit the next inst */ 155810259SAndrew.Bardsley@arm.com lsq.needsToTick() || /* Must step the dcache port */ 155910259SAndrew.Bardsley@arm.com interrupted; /* There are pending interrupts */ 156010259SAndrew.Bardsley@arm.com 156110259SAndrew.Bardsley@arm.com if (!need_to_tick) { 156210259SAndrew.Bardsley@arm.com DPRINTF(Activity, "The next cycle might be skippable as there are no" 156310259SAndrew.Bardsley@arm.com " advanceable FUs\n"); 156410259SAndrew.Bardsley@arm.com } 156510259SAndrew.Bardsley@arm.com 156610259SAndrew.Bardsley@arm.com /* Wake up if we need to tick again */ 156710259SAndrew.Bardsley@arm.com if (need_to_tick) 156810259SAndrew.Bardsley@arm.com cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 156910259SAndrew.Bardsley@arm.com 157010259SAndrew.Bardsley@arm.com /* Note activity of following buffer */ 157110259SAndrew.Bardsley@arm.com if (!branch.isBubble()) 157210259SAndrew.Bardsley@arm.com cpu.activityRecorder->activity(); 157310259SAndrew.Bardsley@arm.com 157410259SAndrew.Bardsley@arm.com /* Make sure the input (if any left) is pushed */ 157511567Smitch.hayenga@arm.com if (!inp.outputWire->isBubble()) 157611567Smitch.hayenga@arm.com inputBuffer[inp.outputWire->threadId].pushTail(); 157710259SAndrew.Bardsley@arm.com} 157810259SAndrew.Bardsley@arm.com 157911567Smitch.hayenga@arm.comThreadID 158011567Smitch.hayenga@arm.comExecute::checkInterrupts(BranchData& branch, bool& interrupted) 158110259SAndrew.Bardsley@arm.com{ 158211567Smitch.hayenga@arm.com ThreadID tid = interruptPriority; 158311567Smitch.hayenga@arm.com /* Evaluate interrupts in round-robin based upon service */ 158411567Smitch.hayenga@arm.com do { 158511567Smitch.hayenga@arm.com /* Has an interrupt been signalled? This may not be acted on 158611567Smitch.hayenga@arm.com * straighaway so this is different from took_interrupt */ 158711567Smitch.hayenga@arm.com bool thread_interrupted = false; 158810259SAndrew.Bardsley@arm.com 158911567Smitch.hayenga@arm.com if (FullSystem && cpu.getInterruptController(tid)) { 159011567Smitch.hayenga@arm.com /* This is here because it seems that after drainResume the 159111567Smitch.hayenga@arm.com * interrupt controller isn't always set */ 159211567Smitch.hayenga@arm.com thread_interrupted = executeInfo[tid].drainState == NotDraining && 159311567Smitch.hayenga@arm.com isInterrupted(tid); 159411567Smitch.hayenga@arm.com interrupted = interrupted || thread_interrupted; 159511567Smitch.hayenga@arm.com } else { 159611567Smitch.hayenga@arm.com DPRINTF(MinorInterrupt, "No interrupt controller\n"); 159711567Smitch.hayenga@arm.com } 159811567Smitch.hayenga@arm.com DPRINTF(MinorInterrupt, "[tid:%d] thread_interrupted?=%d isInbetweenInsts?=%d\n", 159911567Smitch.hayenga@arm.com tid, thread_interrupted, isInbetweenInsts(tid)); 160011567Smitch.hayenga@arm.com /* Act on interrupts */ 160111567Smitch.hayenga@arm.com if (thread_interrupted && isInbetweenInsts(tid)) { 160211567Smitch.hayenga@arm.com if (takeInterrupt(tid, branch)) { 160311567Smitch.hayenga@arm.com interruptPriority = tid; 160411567Smitch.hayenga@arm.com return tid; 160511567Smitch.hayenga@arm.com } 160611567Smitch.hayenga@arm.com } else { 160711567Smitch.hayenga@arm.com tid = (tid + 1) % cpu.numThreads; 160811567Smitch.hayenga@arm.com } 160911567Smitch.hayenga@arm.com } while (tid != interruptPriority); 161010259SAndrew.Bardsley@arm.com 161111567Smitch.hayenga@arm.com return InvalidThreadID; 161211567Smitch.hayenga@arm.com} 161310259SAndrew.Bardsley@arm.com 161411567Smitch.hayenga@arm.combool 161511567Smitch.hayenga@arm.comExecute::hasInterrupt(ThreadID thread_id) 161611567Smitch.hayenga@arm.com{ 161711567Smitch.hayenga@arm.com if (FullSystem && cpu.getInterruptController(thread_id)) { 161811567Smitch.hayenga@arm.com return executeInfo[thread_id].drainState == NotDraining && 161911567Smitch.hayenga@arm.com isInterrupted(thread_id); 162010259SAndrew.Bardsley@arm.com } 162110259SAndrew.Bardsley@arm.com 162211567Smitch.hayenga@arm.com return false; 162310259SAndrew.Bardsley@arm.com} 162410259SAndrew.Bardsley@arm.com 162510259SAndrew.Bardsley@arm.comvoid 162610259SAndrew.Bardsley@arm.comExecute::minorTrace() const 162710259SAndrew.Bardsley@arm.com{ 162810259SAndrew.Bardsley@arm.com std::ostringstream insts; 162910259SAndrew.Bardsley@arm.com std::ostringstream stalled; 163010259SAndrew.Bardsley@arm.com 163111567Smitch.hayenga@arm.com executeInfo[0].instsBeingCommitted.reportData(insts); 163210259SAndrew.Bardsley@arm.com lsq.minorTrace(); 163311567Smitch.hayenga@arm.com inputBuffer[0].minorTrace(); 163411567Smitch.hayenga@arm.com scoreboard[0].minorTrace(); 163510259SAndrew.Bardsley@arm.com 163610259SAndrew.Bardsley@arm.com /* Report functional unit stalling in one string */ 163710259SAndrew.Bardsley@arm.com unsigned int i = 0; 163810259SAndrew.Bardsley@arm.com while (i < numFuncUnits) 163910259SAndrew.Bardsley@arm.com { 164010259SAndrew.Bardsley@arm.com stalled << (funcUnits[i]->stalled ? '1' : 'E'); 164110259SAndrew.Bardsley@arm.com i++; 164210259SAndrew.Bardsley@arm.com if (i != numFuncUnits) 164310259SAndrew.Bardsley@arm.com stalled << ','; 164410259SAndrew.Bardsley@arm.com } 164510259SAndrew.Bardsley@arm.com 164610259SAndrew.Bardsley@arm.com MINORTRACE("insts=%s inputIndex=%d streamSeqNum=%d" 164710259SAndrew.Bardsley@arm.com " stalled=%s drainState=%d isInbetweenInsts=%d\n", 164811567Smitch.hayenga@arm.com insts.str(), executeInfo[0].inputIndex, executeInfo[0].streamSeqNum, 164911567Smitch.hayenga@arm.com stalled.str(), executeInfo[0].drainState, isInbetweenInsts(0)); 165010259SAndrew.Bardsley@arm.com 165110259SAndrew.Bardsley@arm.com std::for_each(funcUnits.begin(), funcUnits.end(), 165210259SAndrew.Bardsley@arm.com std::mem_fun(&FUPipeline::minorTrace)); 165310259SAndrew.Bardsley@arm.com 165411567Smitch.hayenga@arm.com executeInfo[0].inFlightInsts->minorTrace(); 165511567Smitch.hayenga@arm.com executeInfo[0].inFUMemInsts->minorTrace(); 165611567Smitch.hayenga@arm.com} 165711567Smitch.hayenga@arm.com 165811567Smitch.hayenga@arm.cominline ThreadID 165911567Smitch.hayenga@arm.comExecute::getCommittingThread() 166011567Smitch.hayenga@arm.com{ 166111567Smitch.hayenga@arm.com std::vector<ThreadID> priority_list; 166211567Smitch.hayenga@arm.com 166311567Smitch.hayenga@arm.com switch (cpu.threadPolicy) { 166411567Smitch.hayenga@arm.com case Enums::SingleThreaded: 166511567Smitch.hayenga@arm.com return 0; 166611567Smitch.hayenga@arm.com case Enums::RoundRobin: 166711567Smitch.hayenga@arm.com priority_list = cpu.roundRobinPriority(commitPriority); 166811567Smitch.hayenga@arm.com break; 166911567Smitch.hayenga@arm.com case Enums::Random: 167011567Smitch.hayenga@arm.com priority_list = cpu.randomPriority(); 167111567Smitch.hayenga@arm.com break; 167211567Smitch.hayenga@arm.com default: 167311567Smitch.hayenga@arm.com panic("Invalid thread policy"); 167411567Smitch.hayenga@arm.com } 167511567Smitch.hayenga@arm.com 167611567Smitch.hayenga@arm.com for (auto tid : priority_list) { 167711567Smitch.hayenga@arm.com ExecuteThreadInfo &ex_info = executeInfo[tid]; 167811567Smitch.hayenga@arm.com bool can_commit_insts = !ex_info.inFlightInsts->empty(); 167911567Smitch.hayenga@arm.com if (can_commit_insts) { 168011567Smitch.hayenga@arm.com QueuedInst *head_inflight_inst = &(ex_info.inFlightInsts->front()); 168111567Smitch.hayenga@arm.com MinorDynInstPtr inst = head_inflight_inst->inst; 168211567Smitch.hayenga@arm.com 168311567Smitch.hayenga@arm.com can_commit_insts = can_commit_insts && 168411567Smitch.hayenga@arm.com (!inst->inLSQ || (lsq.findResponse(inst) != NULL)); 168511567Smitch.hayenga@arm.com 168611567Smitch.hayenga@arm.com if (!inst->inLSQ) { 168711567Smitch.hayenga@arm.com bool can_transfer_mem_inst = false; 168811567Smitch.hayenga@arm.com if (!ex_info.inFUMemInsts->empty() && lsq.canRequest()) { 168911567Smitch.hayenga@arm.com const MinorDynInstPtr head_mem_ref_inst = 169011567Smitch.hayenga@arm.com ex_info.inFUMemInsts->front().inst; 169111567Smitch.hayenga@arm.com FUPipeline *fu = funcUnits[head_mem_ref_inst->fuIndex]; 169211567Smitch.hayenga@arm.com const MinorDynInstPtr &fu_inst = fu->front().inst; 169311567Smitch.hayenga@arm.com can_transfer_mem_inst = 169411567Smitch.hayenga@arm.com !fu_inst->isBubble() && 169511567Smitch.hayenga@arm.com fu_inst->id.threadId == tid && 169611567Smitch.hayenga@arm.com !fu_inst->inLSQ && 169711567Smitch.hayenga@arm.com fu_inst->canEarlyIssue && 169811567Smitch.hayenga@arm.com inst->id.execSeqNum > fu_inst->instToWaitFor; 169911567Smitch.hayenga@arm.com } 170011567Smitch.hayenga@arm.com 170111567Smitch.hayenga@arm.com bool can_execute_fu_inst = inst->fuIndex == noCostFUIndex; 170211567Smitch.hayenga@arm.com if (can_commit_insts && !can_transfer_mem_inst && 170311567Smitch.hayenga@arm.com inst->fuIndex != noCostFUIndex) 170411567Smitch.hayenga@arm.com { 170511567Smitch.hayenga@arm.com QueuedInst& fu_inst = funcUnits[inst->fuIndex]->front(); 170611567Smitch.hayenga@arm.com can_execute_fu_inst = !fu_inst.inst->isBubble() && 170711567Smitch.hayenga@arm.com fu_inst.inst->id == inst->id; 170811567Smitch.hayenga@arm.com } 170911567Smitch.hayenga@arm.com 171011567Smitch.hayenga@arm.com can_commit_insts = can_commit_insts && 171111567Smitch.hayenga@arm.com (can_transfer_mem_inst || can_execute_fu_inst); 171211567Smitch.hayenga@arm.com } 171311567Smitch.hayenga@arm.com } 171411567Smitch.hayenga@arm.com 171511567Smitch.hayenga@arm.com 171611567Smitch.hayenga@arm.com if (can_commit_insts) { 171711567Smitch.hayenga@arm.com commitPriority = tid; 171811567Smitch.hayenga@arm.com return tid; 171911567Smitch.hayenga@arm.com } 172011567Smitch.hayenga@arm.com } 172111567Smitch.hayenga@arm.com 172211567Smitch.hayenga@arm.com return InvalidThreadID; 172311567Smitch.hayenga@arm.com} 172411567Smitch.hayenga@arm.com 172511567Smitch.hayenga@arm.cominline ThreadID 172611567Smitch.hayenga@arm.comExecute::getIssuingThread() 172711567Smitch.hayenga@arm.com{ 172811567Smitch.hayenga@arm.com std::vector<ThreadID> priority_list; 172911567Smitch.hayenga@arm.com 173011567Smitch.hayenga@arm.com switch (cpu.threadPolicy) { 173111567Smitch.hayenga@arm.com case Enums::SingleThreaded: 173211567Smitch.hayenga@arm.com return 0; 173311567Smitch.hayenga@arm.com case Enums::RoundRobin: 173411567Smitch.hayenga@arm.com priority_list = cpu.roundRobinPriority(issuePriority); 173511567Smitch.hayenga@arm.com break; 173611567Smitch.hayenga@arm.com case Enums::Random: 173711567Smitch.hayenga@arm.com priority_list = cpu.randomPriority(); 173811567Smitch.hayenga@arm.com break; 173911567Smitch.hayenga@arm.com default: 174011567Smitch.hayenga@arm.com panic("Invalid thread scheduling policy."); 174111567Smitch.hayenga@arm.com } 174211567Smitch.hayenga@arm.com 174311567Smitch.hayenga@arm.com for (auto tid : priority_list) { 174411567Smitch.hayenga@arm.com if (cpu.getContext(tid)->status() == ThreadContext::Active && 174511567Smitch.hayenga@arm.com 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++) { 182611567Smitch.hayenga@arm.com if (executeInfo[tid].drainState != DrainAllInsts || 182711567Smitch.hayenga@arm.com !inputBuffer[tid].empty() || 182811567Smitch.hayenga@arm.com !executeInfo[tid].inFlightInsts->empty()) { 182911567Smitch.hayenga@arm.com 183011567Smitch.hayenga@arm.com return false; 183111567Smitch.hayenga@arm.com } 183211567Smitch.hayenga@arm.com } 183311567Smitch.hayenga@arm.com 183411567Smitch.hayenga@arm.com return true; 183510259SAndrew.Bardsley@arm.com} 183610259SAndrew.Bardsley@arm.com 183710259SAndrew.Bardsley@arm.comExecute::~Execute() 183810259SAndrew.Bardsley@arm.com{ 183910259SAndrew.Bardsley@arm.com for (unsigned int i = 0; i < numFuncUnits; i++) 184010259SAndrew.Bardsley@arm.com delete funcUnits[i]; 184110259SAndrew.Bardsley@arm.com 184211567Smitch.hayenga@arm.com for (ThreadID tid = 0; tid < cpu.numThreads; tid++) 184311567Smitch.hayenga@arm.com delete executeInfo[tid].inFlightInsts; 184410259SAndrew.Bardsley@arm.com} 184510259SAndrew.Bardsley@arm.com 184610259SAndrew.Bardsley@arm.combool 184710259SAndrew.Bardsley@arm.comExecute::instIsRightStream(MinorDynInstPtr inst) 184810259SAndrew.Bardsley@arm.com{ 184911567Smitch.hayenga@arm.com return inst->id.streamSeqNum == executeInfo[inst->id.threadId].streamSeqNum; 185010259SAndrew.Bardsley@arm.com} 185110259SAndrew.Bardsley@arm.com 185210259SAndrew.Bardsley@arm.combool 185310259SAndrew.Bardsley@arm.comExecute::instIsHeadInst(MinorDynInstPtr inst) 185410259SAndrew.Bardsley@arm.com{ 185510259SAndrew.Bardsley@arm.com bool ret = false; 185610259SAndrew.Bardsley@arm.com 185711567Smitch.hayenga@arm.com if (!executeInfo[inst->id.threadId].inFlightInsts->empty()) 185811567Smitch.hayenga@arm.com ret = executeInfo[inst->id.threadId].inFlightInsts->front().inst->id == inst->id; 185910259SAndrew.Bardsley@arm.com 186010259SAndrew.Bardsley@arm.com return ret; 186110259SAndrew.Bardsley@arm.com} 186210259SAndrew.Bardsley@arm.com 186310259SAndrew.Bardsley@arm.comMinorCPU::MinorCPUPort & 186410259SAndrew.Bardsley@arm.comExecute::getDcachePort() 186510259SAndrew.Bardsley@arm.com{ 186610259SAndrew.Bardsley@arm.com return lsq.getDcachePort(); 186710259SAndrew.Bardsley@arm.com} 186810259SAndrew.Bardsley@arm.com 186910259SAndrew.Bardsley@arm.com} 1870