execute.cc revision 10851
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), 8910259SAndrew.Bardsley@arm.com scoreboard(name_ + ".scoreboard"), 9010259SAndrew.Bardsley@arm.com inputBuffer(name_ + ".inputBuffer", "insts", 9110259SAndrew.Bardsley@arm.com params.executeInputBufferSize), 9210259SAndrew.Bardsley@arm.com inputIndex(0), 9310259SAndrew.Bardsley@arm.com lastCommitWasEndOfMacroop(true), 9410259SAndrew.Bardsley@arm.com instsBeingCommitted(params.executeCommitLimit), 9510259SAndrew.Bardsley@arm.com streamSeqNum(InstId::firstStreamSeqNum), 9610259SAndrew.Bardsley@arm.com lastPredictionSeqNum(InstId::firstPredictionSeqNum), 9710259SAndrew.Bardsley@arm.com drainState(NotDraining) 9810259SAndrew.Bardsley@arm.com{ 9910259SAndrew.Bardsley@arm.com if (commitLimit < 1) { 10010259SAndrew.Bardsley@arm.com fatal("%s: executeCommitLimit must be >= 1 (%d)\n", name_, 10110259SAndrew.Bardsley@arm.com commitLimit); 10210259SAndrew.Bardsley@arm.com } 10310259SAndrew.Bardsley@arm.com 10410259SAndrew.Bardsley@arm.com if (issueLimit < 1) { 10510259SAndrew.Bardsley@arm.com fatal("%s: executeCommitLimit must be >= 1 (%d)\n", name_, 10610259SAndrew.Bardsley@arm.com issueLimit); 10710259SAndrew.Bardsley@arm.com } 10810259SAndrew.Bardsley@arm.com 10910259SAndrew.Bardsley@arm.com if (memoryIssueLimit < 1) { 11010259SAndrew.Bardsley@arm.com fatal("%s: executeMemoryIssueLimit must be >= 1 (%d)\n", name_, 11110259SAndrew.Bardsley@arm.com memoryIssueLimit); 11210259SAndrew.Bardsley@arm.com } 11310259SAndrew.Bardsley@arm.com 11410259SAndrew.Bardsley@arm.com if (memoryCommitLimit > commitLimit) { 11510259SAndrew.Bardsley@arm.com fatal("%s: executeMemoryCommitLimit (%d) must be <=" 11610259SAndrew.Bardsley@arm.com " executeCommitLimit (%d)\n", 11710259SAndrew.Bardsley@arm.com name_, memoryCommitLimit, commitLimit); 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 if (params.executeInputBufferSize < 1) { 12610259SAndrew.Bardsley@arm.com fatal("%s: executeInputBufferSize must be >= 1 (%d)\n", name_, 12710259SAndrew.Bardsley@arm.com params.executeInputBufferSize); 12810259SAndrew.Bardsley@arm.com } 12910259SAndrew.Bardsley@arm.com 13010259SAndrew.Bardsley@arm.com /* This should be large enough to count all the in-FU instructions 13110259SAndrew.Bardsley@arm.com * which need to be accounted for in the inFlightInsts 13210259SAndrew.Bardsley@arm.com * queue */ 13310259SAndrew.Bardsley@arm.com unsigned int total_slots = 0; 13410259SAndrew.Bardsley@arm.com 13510259SAndrew.Bardsley@arm.com /* Make FUPipelines for each MinorFU */ 13610259SAndrew.Bardsley@arm.com for (unsigned int i = 0; i < numFuncUnits; i++) { 13710259SAndrew.Bardsley@arm.com std::ostringstream fu_name; 13810259SAndrew.Bardsley@arm.com MinorFU *fu_description = fuDescriptions.funcUnits[i]; 13910259SAndrew.Bardsley@arm.com 14010259SAndrew.Bardsley@arm.com /* Note the total number of instruction slots (for sizing 14110259SAndrew.Bardsley@arm.com * the inFlightInst queue) and the maximum latency of any FU 14210259SAndrew.Bardsley@arm.com * (for sizing the activity recorder) */ 14310259SAndrew.Bardsley@arm.com total_slots += fu_description->opLat; 14410259SAndrew.Bardsley@arm.com 14510259SAndrew.Bardsley@arm.com fu_name << name_ << ".fu." << i; 14610259SAndrew.Bardsley@arm.com 14710259SAndrew.Bardsley@arm.com FUPipeline *fu = new FUPipeline(fu_name.str(), *fu_description, cpu); 14810259SAndrew.Bardsley@arm.com 14910259SAndrew.Bardsley@arm.com funcUnits.push_back(fu); 15010259SAndrew.Bardsley@arm.com } 15110259SAndrew.Bardsley@arm.com 15210259SAndrew.Bardsley@arm.com /** Check that there is a functional unit for all operation classes */ 15310814Sandreas.hansson@arm.com for (int op_class = No_OpClass + 1; op_class < Num_OpClasses; op_class++) { 15410259SAndrew.Bardsley@arm.com bool found_fu = false; 15510259SAndrew.Bardsley@arm.com unsigned int fu_index = 0; 15610259SAndrew.Bardsley@arm.com 15710259SAndrew.Bardsley@arm.com while (fu_index < numFuncUnits && !found_fu) 15810259SAndrew.Bardsley@arm.com { 15910259SAndrew.Bardsley@arm.com if (funcUnits[fu_index]->provides( 16010259SAndrew.Bardsley@arm.com static_cast<OpClass>(op_class))) 16110259SAndrew.Bardsley@arm.com { 16210259SAndrew.Bardsley@arm.com found_fu = true; 16310259SAndrew.Bardsley@arm.com } 16410259SAndrew.Bardsley@arm.com fu_index++; 16510259SAndrew.Bardsley@arm.com } 16610259SAndrew.Bardsley@arm.com 16710259SAndrew.Bardsley@arm.com if (!found_fu) { 16810259SAndrew.Bardsley@arm.com warn("No functional unit for OpClass %s\n", 16910259SAndrew.Bardsley@arm.com Enums::OpClassStrings[op_class]); 17010259SAndrew.Bardsley@arm.com } 17110259SAndrew.Bardsley@arm.com } 17210259SAndrew.Bardsley@arm.com 17310259SAndrew.Bardsley@arm.com inFlightInsts = new Queue<QueuedInst, 17410259SAndrew.Bardsley@arm.com ReportTraitsAdaptor<QueuedInst> >( 17510259SAndrew.Bardsley@arm.com name_ + ".inFlightInsts", "insts", total_slots); 17610259SAndrew.Bardsley@arm.com 17710259SAndrew.Bardsley@arm.com inFUMemInsts = new Queue<QueuedInst, 17810259SAndrew.Bardsley@arm.com ReportTraitsAdaptor<QueuedInst> >( 17910259SAndrew.Bardsley@arm.com name_ + ".inFUMemInsts", "insts", total_slots); 18010259SAndrew.Bardsley@arm.com} 18110259SAndrew.Bardsley@arm.com 18210259SAndrew.Bardsley@arm.comconst ForwardInstData * 18310259SAndrew.Bardsley@arm.comExecute::getInput() 18410259SAndrew.Bardsley@arm.com{ 18510259SAndrew.Bardsley@arm.com /* Get a line from the inputBuffer to work with */ 18610259SAndrew.Bardsley@arm.com if (!inputBuffer.empty()) { 18710259SAndrew.Bardsley@arm.com const ForwardInstData &head = inputBuffer.front(); 18810259SAndrew.Bardsley@arm.com 18910259SAndrew.Bardsley@arm.com return (head.isBubble() ? NULL : &(inputBuffer.front())); 19010259SAndrew.Bardsley@arm.com } else { 19110259SAndrew.Bardsley@arm.com return NULL; 19210259SAndrew.Bardsley@arm.com } 19310259SAndrew.Bardsley@arm.com} 19410259SAndrew.Bardsley@arm.com 19510259SAndrew.Bardsley@arm.comvoid 19610259SAndrew.Bardsley@arm.comExecute::popInput() 19710259SAndrew.Bardsley@arm.com{ 19810259SAndrew.Bardsley@arm.com if (!inputBuffer.empty()) 19910259SAndrew.Bardsley@arm.com inputBuffer.pop(); 20010259SAndrew.Bardsley@arm.com 20110259SAndrew.Bardsley@arm.com inputIndex = 0; 20210259SAndrew.Bardsley@arm.com} 20310259SAndrew.Bardsley@arm.com 20410259SAndrew.Bardsley@arm.comvoid 20510259SAndrew.Bardsley@arm.comExecute::tryToBranch(MinorDynInstPtr inst, Fault fault, BranchData &branch) 20610259SAndrew.Bardsley@arm.com{ 20710259SAndrew.Bardsley@arm.com ThreadContext *thread = cpu.getContext(inst->id.threadId); 20810259SAndrew.Bardsley@arm.com const TheISA::PCState &pc_before = inst->pc; 20910259SAndrew.Bardsley@arm.com TheISA::PCState target = thread->pcState(); 21010259SAndrew.Bardsley@arm.com 21110259SAndrew.Bardsley@arm.com /* Force a branch for SerializeAfter instructions at the end of micro-op 21210259SAndrew.Bardsley@arm.com * sequence when we're not suspended */ 21310259SAndrew.Bardsley@arm.com bool force_branch = thread->status() != ThreadContext::Suspended && 21410259SAndrew.Bardsley@arm.com !inst->isFault() && 21510259SAndrew.Bardsley@arm.com inst->isLastOpInInst() && 21610259SAndrew.Bardsley@arm.com (inst->staticInst->isSerializeAfter() || 21710259SAndrew.Bardsley@arm.com inst->staticInst->isIprAccess()); 21810259SAndrew.Bardsley@arm.com 21910259SAndrew.Bardsley@arm.com DPRINTF(Branch, "tryToBranch before: %s after: %s%s\n", 22010259SAndrew.Bardsley@arm.com pc_before, target, (force_branch ? " (forcing)" : "")); 22110259SAndrew.Bardsley@arm.com 22210259SAndrew.Bardsley@arm.com /* Will we change the PC to something other than the next instruction? */ 22310259SAndrew.Bardsley@arm.com bool must_branch = pc_before != target || 22410259SAndrew.Bardsley@arm.com fault != NoFault || 22510259SAndrew.Bardsley@arm.com force_branch; 22610259SAndrew.Bardsley@arm.com 22710259SAndrew.Bardsley@arm.com /* The reason for the branch data we're about to generate, set below */ 22810259SAndrew.Bardsley@arm.com BranchData::Reason reason = BranchData::NoBranch; 22910259SAndrew.Bardsley@arm.com 23010259SAndrew.Bardsley@arm.com if (fault == NoFault) 23110259SAndrew.Bardsley@arm.com { 23210259SAndrew.Bardsley@arm.com TheISA::advancePC(target, inst->staticInst); 23310259SAndrew.Bardsley@arm.com thread->pcState(target); 23410259SAndrew.Bardsley@arm.com 23510259SAndrew.Bardsley@arm.com DPRINTF(Branch, "Advancing current PC from: %s to: %s\n", 23610259SAndrew.Bardsley@arm.com pc_before, target); 23710259SAndrew.Bardsley@arm.com } 23810259SAndrew.Bardsley@arm.com 23910259SAndrew.Bardsley@arm.com if (inst->predictedTaken && !force_branch) { 24010259SAndrew.Bardsley@arm.com /* Predicted to branch */ 24110259SAndrew.Bardsley@arm.com if (!must_branch) { 24210259SAndrew.Bardsley@arm.com /* No branch was taken, change stream to get us back to the 24310259SAndrew.Bardsley@arm.com * intended PC value */ 24410259SAndrew.Bardsley@arm.com DPRINTF(Branch, "Predicted a branch from 0x%x to 0x%x but" 24510259SAndrew.Bardsley@arm.com " none happened inst: %s\n", 24610259SAndrew.Bardsley@arm.com inst->pc.instAddr(), inst->predictedTarget.instAddr(), *inst); 24710259SAndrew.Bardsley@arm.com 24810259SAndrew.Bardsley@arm.com reason = BranchData::BadlyPredictedBranch; 24910259SAndrew.Bardsley@arm.com } else if (inst->predictedTarget == target) { 25010259SAndrew.Bardsley@arm.com /* Branch prediction got the right target, kill the branch and 25110259SAndrew.Bardsley@arm.com * carry on. 25210259SAndrew.Bardsley@arm.com * Note that this information to the branch predictor might get 25310259SAndrew.Bardsley@arm.com * overwritten by a "real" branch during this cycle */ 25410259SAndrew.Bardsley@arm.com DPRINTF(Branch, "Predicted a branch from 0x%x to 0x%x correctly" 25510259SAndrew.Bardsley@arm.com " inst: %s\n", 25610259SAndrew.Bardsley@arm.com inst->pc.instAddr(), inst->predictedTarget.instAddr(), *inst); 25710259SAndrew.Bardsley@arm.com 25810259SAndrew.Bardsley@arm.com reason = BranchData::CorrectlyPredictedBranch; 25910259SAndrew.Bardsley@arm.com } else { 26010259SAndrew.Bardsley@arm.com /* Branch prediction got the wrong target */ 26110259SAndrew.Bardsley@arm.com DPRINTF(Branch, "Predicted a branch from 0x%x to 0x%x" 26210366Sandreas.hansson@arm.com " but got the wrong target (actual: 0x%x) inst: %s\n", 26310366Sandreas.hansson@arm.com inst->pc.instAddr(), inst->predictedTarget.instAddr(), 26410366Sandreas.hansson@arm.com target.instAddr(), *inst); 26510259SAndrew.Bardsley@arm.com 26610259SAndrew.Bardsley@arm.com reason = BranchData::BadlyPredictedBranchTarget; 26710259SAndrew.Bardsley@arm.com } 26810259SAndrew.Bardsley@arm.com } else if (must_branch) { 26910259SAndrew.Bardsley@arm.com /* Unpredicted branch */ 27010259SAndrew.Bardsley@arm.com DPRINTF(Branch, "Unpredicted branch from 0x%x to 0x%x inst: %s\n", 27110259SAndrew.Bardsley@arm.com inst->pc.instAddr(), target.instAddr(), *inst); 27210259SAndrew.Bardsley@arm.com 27310259SAndrew.Bardsley@arm.com reason = BranchData::UnpredictedBranch; 27410259SAndrew.Bardsley@arm.com } else { 27510259SAndrew.Bardsley@arm.com /* No branch at all */ 27610259SAndrew.Bardsley@arm.com reason = BranchData::NoBranch; 27710259SAndrew.Bardsley@arm.com } 27810259SAndrew.Bardsley@arm.com 27910259SAndrew.Bardsley@arm.com updateBranchData(reason, inst, target, branch); 28010259SAndrew.Bardsley@arm.com} 28110259SAndrew.Bardsley@arm.com 28210259SAndrew.Bardsley@arm.comvoid 28310259SAndrew.Bardsley@arm.comExecute::updateBranchData( 28410259SAndrew.Bardsley@arm.com BranchData::Reason reason, 28510259SAndrew.Bardsley@arm.com MinorDynInstPtr inst, const TheISA::PCState &target, 28610259SAndrew.Bardsley@arm.com BranchData &branch) 28710259SAndrew.Bardsley@arm.com{ 28810259SAndrew.Bardsley@arm.com if (reason != BranchData::NoBranch) { 28910259SAndrew.Bardsley@arm.com /* Bump up the stream sequence number on a real branch*/ 29010259SAndrew.Bardsley@arm.com if (BranchData::isStreamChange(reason)) 29110259SAndrew.Bardsley@arm.com streamSeqNum++; 29210259SAndrew.Bardsley@arm.com 29310259SAndrew.Bardsley@arm.com /* Branches (even mis-predictions) don't change the predictionSeqNum, 29410259SAndrew.Bardsley@arm.com * just the streamSeqNum */ 29510259SAndrew.Bardsley@arm.com branch = BranchData(reason, streamSeqNum, 29610259SAndrew.Bardsley@arm.com /* Maintaining predictionSeqNum if there's no inst is just a 29710259SAndrew.Bardsley@arm.com * courtesy and looks better on minorview */ 29810259SAndrew.Bardsley@arm.com (inst->isBubble() ? lastPredictionSeqNum 29910259SAndrew.Bardsley@arm.com : inst->id.predictionSeqNum), 30010259SAndrew.Bardsley@arm.com target, inst); 30110259SAndrew.Bardsley@arm.com 30210259SAndrew.Bardsley@arm.com DPRINTF(Branch, "Branch data signalled: %s\n", branch); 30310259SAndrew.Bardsley@arm.com } 30410259SAndrew.Bardsley@arm.com} 30510259SAndrew.Bardsley@arm.com 30610259SAndrew.Bardsley@arm.comvoid 30710259SAndrew.Bardsley@arm.comExecute::handleMemResponse(MinorDynInstPtr inst, 30810259SAndrew.Bardsley@arm.com LSQ::LSQRequestPtr response, BranchData &branch, Fault &fault) 30910259SAndrew.Bardsley@arm.com{ 31010259SAndrew.Bardsley@arm.com ThreadID thread_id = inst->id.threadId; 31110259SAndrew.Bardsley@arm.com ThreadContext *thread = cpu.getContext(thread_id); 31210259SAndrew.Bardsley@arm.com 31310259SAndrew.Bardsley@arm.com ExecContext context(cpu, *cpu.threads[thread_id], *this, inst); 31410259SAndrew.Bardsley@arm.com 31510259SAndrew.Bardsley@arm.com PacketPtr packet = response->packet; 31610259SAndrew.Bardsley@arm.com 31710259SAndrew.Bardsley@arm.com bool is_load = inst->staticInst->isLoad(); 31810259SAndrew.Bardsley@arm.com bool is_store = inst->staticInst->isStore(); 31910259SAndrew.Bardsley@arm.com bool is_prefetch = inst->staticInst->isDataPrefetch(); 32010259SAndrew.Bardsley@arm.com 32110259SAndrew.Bardsley@arm.com /* If true, the trace's predicate value will be taken from the exec 32210259SAndrew.Bardsley@arm.com * context predicate, otherwise, it will be set to false */ 32310259SAndrew.Bardsley@arm.com bool use_context_predicate = true; 32410259SAndrew.Bardsley@arm.com 32510259SAndrew.Bardsley@arm.com if (response->fault != NoFault) { 32610259SAndrew.Bardsley@arm.com /* Invoke memory faults. */ 32710259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Completing fault from DTLB access: %s\n", 32810259SAndrew.Bardsley@arm.com response->fault->name()); 32910259SAndrew.Bardsley@arm.com 33010259SAndrew.Bardsley@arm.com if (inst->staticInst->isPrefetch()) { 33110259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Not taking fault on prefetch: %s\n", 33210259SAndrew.Bardsley@arm.com response->fault->name()); 33310259SAndrew.Bardsley@arm.com 33410259SAndrew.Bardsley@arm.com /* Don't assign to fault */ 33510259SAndrew.Bardsley@arm.com } else { 33610259SAndrew.Bardsley@arm.com /* Take the fault raised during the TLB/memory access */ 33710259SAndrew.Bardsley@arm.com fault = response->fault; 33810259SAndrew.Bardsley@arm.com 33910259SAndrew.Bardsley@arm.com fault->invoke(thread, inst->staticInst); 34010259SAndrew.Bardsley@arm.com } 34110259SAndrew.Bardsley@arm.com } else if (!packet) { 34210259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Completing failed request inst: %s\n", 34310259SAndrew.Bardsley@arm.com *inst); 34410259SAndrew.Bardsley@arm.com use_context_predicate = false; 34510259SAndrew.Bardsley@arm.com } else if (packet->isError()) { 34610259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Trying to commit error response: %s\n", 34710259SAndrew.Bardsley@arm.com *inst); 34810259SAndrew.Bardsley@arm.com 34910259SAndrew.Bardsley@arm.com fatal("Received error response packet for inst: %s\n", *inst); 35010259SAndrew.Bardsley@arm.com } else if (is_store || is_load || is_prefetch) { 35110259SAndrew.Bardsley@arm.com assert(packet); 35210259SAndrew.Bardsley@arm.com 35310259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Memory response inst: %s addr: 0x%x size: %d\n", 35410259SAndrew.Bardsley@arm.com *inst, packet->getAddr(), packet->getSize()); 35510259SAndrew.Bardsley@arm.com 35610259SAndrew.Bardsley@arm.com if (is_load && packet->getSize() > 0) { 35710259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Memory data[0]: 0x%x\n", 35810563Sandreas.hansson@arm.com static_cast<unsigned int>(packet->getConstPtr<uint8_t>()[0])); 35910259SAndrew.Bardsley@arm.com } 36010259SAndrew.Bardsley@arm.com 36110259SAndrew.Bardsley@arm.com /* Complete the memory access instruction */ 36210259SAndrew.Bardsley@arm.com fault = inst->staticInst->completeAcc(packet, &context, 36310259SAndrew.Bardsley@arm.com inst->traceData); 36410259SAndrew.Bardsley@arm.com 36510259SAndrew.Bardsley@arm.com if (fault != NoFault) { 36610259SAndrew.Bardsley@arm.com /* Invoke fault created by instruction completion */ 36710259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Fault in memory completeAcc: %s\n", 36810259SAndrew.Bardsley@arm.com fault->name()); 36910259SAndrew.Bardsley@arm.com fault->invoke(thread, inst->staticInst); 37010259SAndrew.Bardsley@arm.com } else { 37110259SAndrew.Bardsley@arm.com /* Stores need to be pushed into the store buffer to finish 37210259SAndrew.Bardsley@arm.com * them off */ 37310259SAndrew.Bardsley@arm.com if (response->needsToBeSentToStoreBuffer()) 37410259SAndrew.Bardsley@arm.com lsq.sendStoreToStoreBuffer(response); 37510259SAndrew.Bardsley@arm.com } 37610259SAndrew.Bardsley@arm.com } else { 37710259SAndrew.Bardsley@arm.com fatal("There should only ever be reads, " 37810259SAndrew.Bardsley@arm.com "writes or faults at this point\n"); 37910259SAndrew.Bardsley@arm.com } 38010259SAndrew.Bardsley@arm.com 38110259SAndrew.Bardsley@arm.com lsq.popResponse(response); 38210259SAndrew.Bardsley@arm.com 38310259SAndrew.Bardsley@arm.com if (inst->traceData) { 38410259SAndrew.Bardsley@arm.com inst->traceData->setPredicate((use_context_predicate ? 38510259SAndrew.Bardsley@arm.com context.readPredicate() : false)); 38610259SAndrew.Bardsley@arm.com } 38710259SAndrew.Bardsley@arm.com 38810259SAndrew.Bardsley@arm.com doInstCommitAccounting(inst); 38910259SAndrew.Bardsley@arm.com 39010259SAndrew.Bardsley@arm.com /* Generate output to account for branches */ 39110259SAndrew.Bardsley@arm.com tryToBranch(inst, fault, branch); 39210259SAndrew.Bardsley@arm.com} 39310259SAndrew.Bardsley@arm.com 39410259SAndrew.Bardsley@arm.combool 39510259SAndrew.Bardsley@arm.comExecute::isInterrupted(ThreadID thread_id) const 39610259SAndrew.Bardsley@arm.com{ 39710259SAndrew.Bardsley@arm.com return cpu.checkInterrupts(cpu.getContext(thread_id)); 39810259SAndrew.Bardsley@arm.com} 39910259SAndrew.Bardsley@arm.com 40010259SAndrew.Bardsley@arm.combool 40110259SAndrew.Bardsley@arm.comExecute::takeInterrupt(ThreadID thread_id, BranchData &branch) 40210259SAndrew.Bardsley@arm.com{ 40310259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Considering interrupt status from PC: %s\n", 40410259SAndrew.Bardsley@arm.com cpu.getContext(thread_id)->pcState()); 40510259SAndrew.Bardsley@arm.com 40610259SAndrew.Bardsley@arm.com Fault interrupt = cpu.getInterruptController()->getInterrupt 40710259SAndrew.Bardsley@arm.com (cpu.getContext(thread_id)); 40810259SAndrew.Bardsley@arm.com 40910259SAndrew.Bardsley@arm.com if (interrupt != NoFault) { 41010259SAndrew.Bardsley@arm.com /* The interrupt *must* set pcState */ 41110259SAndrew.Bardsley@arm.com cpu.getInterruptController()->updateIntrInfo 41210259SAndrew.Bardsley@arm.com (cpu.getContext(thread_id)); 41310259SAndrew.Bardsley@arm.com interrupt->invoke(cpu.getContext(thread_id)); 41410259SAndrew.Bardsley@arm.com 41510259SAndrew.Bardsley@arm.com assert(!lsq.accessesInFlight()); 41610259SAndrew.Bardsley@arm.com 41710259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Invoking interrupt: %s to PC: %s\n", 41810259SAndrew.Bardsley@arm.com interrupt->name(), cpu.getContext(thread_id)->pcState()); 41910259SAndrew.Bardsley@arm.com 42010259SAndrew.Bardsley@arm.com /* Assume that an interrupt *must* cause a branch. Assert this? */ 42110259SAndrew.Bardsley@arm.com 42210259SAndrew.Bardsley@arm.com updateBranchData(BranchData::Interrupt, MinorDynInst::bubble(), 42310259SAndrew.Bardsley@arm.com cpu.getContext(thread_id)->pcState(), branch); 42410259SAndrew.Bardsley@arm.com } 42510259SAndrew.Bardsley@arm.com 42610259SAndrew.Bardsley@arm.com return interrupt != NoFault; 42710259SAndrew.Bardsley@arm.com} 42810259SAndrew.Bardsley@arm.com 42910259SAndrew.Bardsley@arm.combool 43010259SAndrew.Bardsley@arm.comExecute::executeMemRefInst(MinorDynInstPtr inst, BranchData &branch, 43110259SAndrew.Bardsley@arm.com bool &passed_predicate, Fault &fault) 43210259SAndrew.Bardsley@arm.com{ 43310259SAndrew.Bardsley@arm.com bool issued = false; 43410259SAndrew.Bardsley@arm.com 43510259SAndrew.Bardsley@arm.com /* Set to true if the mem op. is issued and sent to the mem system */ 43610259SAndrew.Bardsley@arm.com passed_predicate = false; 43710259SAndrew.Bardsley@arm.com 43810259SAndrew.Bardsley@arm.com if (!lsq.canRequest()) { 43910259SAndrew.Bardsley@arm.com /* Not acting on instruction yet as the memory 44010259SAndrew.Bardsley@arm.com * queues are full */ 44110259SAndrew.Bardsley@arm.com issued = false; 44210259SAndrew.Bardsley@arm.com } else { 44310259SAndrew.Bardsley@arm.com ThreadContext *thread = cpu.getContext(inst->id.threadId); 44410259SAndrew.Bardsley@arm.com TheISA::PCState old_pc = thread->pcState(); 44510259SAndrew.Bardsley@arm.com 44610259SAndrew.Bardsley@arm.com ExecContext context(cpu, *cpu.threads[inst->id.threadId], 44710259SAndrew.Bardsley@arm.com *this, inst); 44810259SAndrew.Bardsley@arm.com 44910259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Initiating memRef inst: %s\n", *inst); 45010259SAndrew.Bardsley@arm.com 45110259SAndrew.Bardsley@arm.com Fault init_fault = inst->staticInst->initiateAcc(&context, 45210259SAndrew.Bardsley@arm.com inst->traceData); 45310259SAndrew.Bardsley@arm.com 45410259SAndrew.Bardsley@arm.com if (init_fault != NoFault) { 45510259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Fault on memory inst: %s" 45610259SAndrew.Bardsley@arm.com " initiateAcc: %s\n", *inst, init_fault->name()); 45710259SAndrew.Bardsley@arm.com fault = init_fault; 45810259SAndrew.Bardsley@arm.com } else { 45910259SAndrew.Bardsley@arm.com /* Only set this if the instruction passed its 46010259SAndrew.Bardsley@arm.com * predicate */ 46110259SAndrew.Bardsley@arm.com passed_predicate = context.readPredicate(); 46210259SAndrew.Bardsley@arm.com 46310259SAndrew.Bardsley@arm.com /* Set predicate in tracing */ 46410259SAndrew.Bardsley@arm.com if (inst->traceData) 46510259SAndrew.Bardsley@arm.com inst->traceData->setPredicate(passed_predicate); 46610259SAndrew.Bardsley@arm.com 46710259SAndrew.Bardsley@arm.com /* If the instruction didn't pass its predicate (and so will not 46810259SAndrew.Bardsley@arm.com * progress from here) Try to branch to correct and branch 46910259SAndrew.Bardsley@arm.com * mis-prediction. */ 47010259SAndrew.Bardsley@arm.com if (!passed_predicate) { 47110259SAndrew.Bardsley@arm.com /* Leave it up to commit to handle the fault */ 47210259SAndrew.Bardsley@arm.com lsq.pushFailedRequest(inst); 47310259SAndrew.Bardsley@arm.com } 47410259SAndrew.Bardsley@arm.com } 47510259SAndrew.Bardsley@arm.com 47610259SAndrew.Bardsley@arm.com /* Restore thread PC */ 47710259SAndrew.Bardsley@arm.com thread->pcState(old_pc); 47810259SAndrew.Bardsley@arm.com issued = true; 47910259SAndrew.Bardsley@arm.com } 48010259SAndrew.Bardsley@arm.com 48110259SAndrew.Bardsley@arm.com return issued; 48210259SAndrew.Bardsley@arm.com} 48310259SAndrew.Bardsley@arm.com 48410259SAndrew.Bardsley@arm.com/** Increment a cyclic buffer index for indices [0, cycle_size-1] */ 48510259SAndrew.Bardsley@arm.cominline unsigned int 48610259SAndrew.Bardsley@arm.comcyclicIndexInc(unsigned int index, unsigned int cycle_size) 48710259SAndrew.Bardsley@arm.com{ 48810259SAndrew.Bardsley@arm.com unsigned int ret = index + 1; 48910259SAndrew.Bardsley@arm.com 49010259SAndrew.Bardsley@arm.com if (ret == cycle_size) 49110259SAndrew.Bardsley@arm.com ret = 0; 49210259SAndrew.Bardsley@arm.com 49310259SAndrew.Bardsley@arm.com return ret; 49410259SAndrew.Bardsley@arm.com} 49510259SAndrew.Bardsley@arm.com 49610259SAndrew.Bardsley@arm.com/** Decrement a cyclic buffer index for indices [0, cycle_size-1] */ 49710259SAndrew.Bardsley@arm.cominline unsigned int 49810259SAndrew.Bardsley@arm.comcyclicIndexDec(unsigned int index, unsigned int cycle_size) 49910259SAndrew.Bardsley@arm.com{ 50010259SAndrew.Bardsley@arm.com int ret = index - 1; 50110259SAndrew.Bardsley@arm.com 50210259SAndrew.Bardsley@arm.com if (ret < 0) 50310259SAndrew.Bardsley@arm.com ret = cycle_size - 1; 50410259SAndrew.Bardsley@arm.com 50510259SAndrew.Bardsley@arm.com return ret; 50610259SAndrew.Bardsley@arm.com} 50710259SAndrew.Bardsley@arm.com 50810259SAndrew.Bardsley@arm.comunsigned int 50910259SAndrew.Bardsley@arm.comExecute::issue(bool only_issue_microops) 51010259SAndrew.Bardsley@arm.com{ 51110259SAndrew.Bardsley@arm.com const ForwardInstData *insts_in = getInput(); 51210259SAndrew.Bardsley@arm.com 51310259SAndrew.Bardsley@arm.com /* Early termination if we have no instructions */ 51410259SAndrew.Bardsley@arm.com if (!insts_in) 51510259SAndrew.Bardsley@arm.com return 0; 51610259SAndrew.Bardsley@arm.com 51710259SAndrew.Bardsley@arm.com /* Start from the first FU */ 51810259SAndrew.Bardsley@arm.com unsigned int fu_index = 0; 51910259SAndrew.Bardsley@arm.com 52010259SAndrew.Bardsley@arm.com /* Remains true while instructions are still being issued. If any 52110259SAndrew.Bardsley@arm.com * instruction fails to issue, this is set to false and we exit issue. 52210259SAndrew.Bardsley@arm.com * This strictly enforces in-order issue. For other issue behaviours, 52310259SAndrew.Bardsley@arm.com * a more complicated test in the outer while loop below is needed. */ 52410259SAndrew.Bardsley@arm.com bool issued = true; 52510259SAndrew.Bardsley@arm.com 52610259SAndrew.Bardsley@arm.com /* Number of insts issues this cycle to check for issueLimit */ 52710259SAndrew.Bardsley@arm.com unsigned num_insts_issued = 0; 52810259SAndrew.Bardsley@arm.com 52910259SAndrew.Bardsley@arm.com /* Number of memory ops issues this cycle to check for memoryIssueLimit */ 53010259SAndrew.Bardsley@arm.com unsigned num_mem_insts_issued = 0; 53110259SAndrew.Bardsley@arm.com 53210259SAndrew.Bardsley@arm.com /* Number of instructions discarded this cycle in order to enforce a 53310259SAndrew.Bardsley@arm.com * discardLimit. @todo, add that parameter? */ 53410259SAndrew.Bardsley@arm.com unsigned num_insts_discarded = 0; 53510259SAndrew.Bardsley@arm.com 53610259SAndrew.Bardsley@arm.com do { 53710259SAndrew.Bardsley@arm.com MinorDynInstPtr inst = insts_in->insts[inputIndex]; 53810259SAndrew.Bardsley@arm.com ThreadID thread_id = inst->id.threadId; 53910259SAndrew.Bardsley@arm.com Fault fault = inst->fault; 54010259SAndrew.Bardsley@arm.com bool discarded = false; 54110259SAndrew.Bardsley@arm.com bool issued_mem_ref = false; 54210259SAndrew.Bardsley@arm.com 54310259SAndrew.Bardsley@arm.com if (inst->isBubble()) { 54410259SAndrew.Bardsley@arm.com /* Skip */ 54510259SAndrew.Bardsley@arm.com issued = true; 54610259SAndrew.Bardsley@arm.com } else if (cpu.getContext(thread_id)->status() == 54710259SAndrew.Bardsley@arm.com ThreadContext::Suspended) 54810259SAndrew.Bardsley@arm.com { 54910259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Not issuing inst: %s from suspended" 55010259SAndrew.Bardsley@arm.com " thread\n", *inst); 55110259SAndrew.Bardsley@arm.com 55210259SAndrew.Bardsley@arm.com issued = false; 55310259SAndrew.Bardsley@arm.com } else if (inst->id.streamSeqNum != streamSeqNum) { 55410259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Discarding inst: %s as its stream" 55510259SAndrew.Bardsley@arm.com " state was unexpected, expected: %d\n", 55610259SAndrew.Bardsley@arm.com *inst, streamSeqNum); 55710259SAndrew.Bardsley@arm.com issued = true; 55810259SAndrew.Bardsley@arm.com discarded = true; 55910259SAndrew.Bardsley@arm.com } else if (fault == NoFault && only_issue_microops && 56010259SAndrew.Bardsley@arm.com /* Is this anything other than a non-first microop */ 56110259SAndrew.Bardsley@arm.com (!inst->staticInst->isMicroop() || 56210259SAndrew.Bardsley@arm.com !inst->staticInst->isFirstMicroop())) 56310259SAndrew.Bardsley@arm.com { 56410259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Not issuing new non-microop inst: %s\n", 56510259SAndrew.Bardsley@arm.com *inst); 56610259SAndrew.Bardsley@arm.com 56710259SAndrew.Bardsley@arm.com issued = false; 56810259SAndrew.Bardsley@arm.com } else { 56910259SAndrew.Bardsley@arm.com /* Try and issue an instruction into an FU, assume we didn't and 57010259SAndrew.Bardsley@arm.com * fix that in the loop */ 57110259SAndrew.Bardsley@arm.com issued = false; 57210259SAndrew.Bardsley@arm.com 57310259SAndrew.Bardsley@arm.com /* Try FU from 0 each instruction */ 57410259SAndrew.Bardsley@arm.com fu_index = 0; 57510259SAndrew.Bardsley@arm.com 57610259SAndrew.Bardsley@arm.com /* Try and issue a single instruction stepping through the 57710259SAndrew.Bardsley@arm.com * available FUs */ 57810259SAndrew.Bardsley@arm.com do { 57910259SAndrew.Bardsley@arm.com FUPipeline *fu = funcUnits[fu_index]; 58010259SAndrew.Bardsley@arm.com 58110259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Trying to issue inst: %s to FU: %d\n", 58210259SAndrew.Bardsley@arm.com *inst, fu_index); 58310259SAndrew.Bardsley@arm.com 58410259SAndrew.Bardsley@arm.com /* Does the examined fu have the OpClass-related capability 58510259SAndrew.Bardsley@arm.com * needed to execute this instruction? Faults can always 58610259SAndrew.Bardsley@arm.com * issue to any FU but probably should just 'live' in the 58710259SAndrew.Bardsley@arm.com * inFlightInsts queue rather than having an FU. */ 58810259SAndrew.Bardsley@arm.com bool fu_is_capable = (!inst->isFault() ? 58910259SAndrew.Bardsley@arm.com fu->provides(inst->staticInst->opClass()) : true); 59010259SAndrew.Bardsley@arm.com 59110259SAndrew.Bardsley@arm.com if (inst->isNoCostInst()) { 59210259SAndrew.Bardsley@arm.com /* Issue free insts. to a fake numbered FU */ 59310259SAndrew.Bardsley@arm.com fu_index = noCostFUIndex; 59410259SAndrew.Bardsley@arm.com 59510259SAndrew.Bardsley@arm.com /* And start the countdown on activity to allow 59610259SAndrew.Bardsley@arm.com * this instruction to get to the end of its FU */ 59710259SAndrew.Bardsley@arm.com cpu.activityRecorder->activity(); 59810259SAndrew.Bardsley@arm.com 59910259SAndrew.Bardsley@arm.com /* Mark the destinations for this instruction as 60010259SAndrew.Bardsley@arm.com * busy */ 60110259SAndrew.Bardsley@arm.com scoreboard.markupInstDests(inst, cpu.curCycle() + 60210259SAndrew.Bardsley@arm.com Cycles(0), cpu.getContext(thread_id), false); 60310259SAndrew.Bardsley@arm.com 60410259SAndrew.Bardsley@arm.com inst->fuIndex = noCostFUIndex; 60510259SAndrew.Bardsley@arm.com inst->extraCommitDelay = Cycles(0); 60610259SAndrew.Bardsley@arm.com inst->extraCommitDelayExpr = NULL; 60710259SAndrew.Bardsley@arm.com 60810259SAndrew.Bardsley@arm.com /* Push the instruction onto the inFlight queue so 60910259SAndrew.Bardsley@arm.com * it can be committed in order */ 61010259SAndrew.Bardsley@arm.com QueuedInst fu_inst(inst); 61110259SAndrew.Bardsley@arm.com inFlightInsts->push(fu_inst); 61210259SAndrew.Bardsley@arm.com 61310259SAndrew.Bardsley@arm.com issued = true; 61410259SAndrew.Bardsley@arm.com 61510259SAndrew.Bardsley@arm.com } else if (!fu_is_capable || fu->alreadyPushed()) { 61610259SAndrew.Bardsley@arm.com /* Skip */ 61710259SAndrew.Bardsley@arm.com if (!fu_is_capable) { 61810259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue as FU: %d isn't" 61910259SAndrew.Bardsley@arm.com " capable\n", fu_index); 62010259SAndrew.Bardsley@arm.com } else { 62110259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue as FU: %d is" 62210259SAndrew.Bardsley@arm.com " already busy\n", fu_index); 62310259SAndrew.Bardsley@arm.com } 62410259SAndrew.Bardsley@arm.com } else if (fu->stalled) { 62510259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue inst: %s into FU: %d," 62610259SAndrew.Bardsley@arm.com " it's stalled\n", 62710259SAndrew.Bardsley@arm.com *inst, fu_index); 62810259SAndrew.Bardsley@arm.com } else if (!fu->canInsert()) { 62910259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue inst: %s to busy FU" 63010259SAndrew.Bardsley@arm.com " for another: %d cycles\n", 63110259SAndrew.Bardsley@arm.com *inst, fu->cyclesBeforeInsert()); 63210259SAndrew.Bardsley@arm.com } else { 63310259SAndrew.Bardsley@arm.com MinorFUTiming *timing = (!inst->isFault() ? 63410259SAndrew.Bardsley@arm.com fu->findTiming(inst->staticInst) : NULL); 63510259SAndrew.Bardsley@arm.com 63610259SAndrew.Bardsley@arm.com const std::vector<Cycles> *src_latencies = 63710259SAndrew.Bardsley@arm.com (timing ? &(timing->srcRegsRelativeLats) 63810259SAndrew.Bardsley@arm.com : NULL); 63910259SAndrew.Bardsley@arm.com 64010259SAndrew.Bardsley@arm.com const std::vector<bool> *cant_forward_from_fu_indices = 64110259SAndrew.Bardsley@arm.com &(fu->cantForwardFromFUIndices); 64210259SAndrew.Bardsley@arm.com 64310259SAndrew.Bardsley@arm.com if (timing && timing->suppress) { 64410259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue inst: %s as extra" 64510259SAndrew.Bardsley@arm.com " decoding is suppressing it\n", 64610259SAndrew.Bardsley@arm.com *inst); 64710259SAndrew.Bardsley@arm.com } else if (!scoreboard.canInstIssue(inst, src_latencies, 64810259SAndrew.Bardsley@arm.com cant_forward_from_fu_indices, 64910259SAndrew.Bardsley@arm.com cpu.curCycle(), cpu.getContext(thread_id))) 65010259SAndrew.Bardsley@arm.com { 65110259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't issue inst: %s yet\n", 65210259SAndrew.Bardsley@arm.com *inst); 65310259SAndrew.Bardsley@arm.com } else { 65410259SAndrew.Bardsley@arm.com /* Can insert the instruction into this FU */ 65510259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Issuing inst: %s" 65610259SAndrew.Bardsley@arm.com " into FU %d\n", *inst, 65710259SAndrew.Bardsley@arm.com fu_index); 65810259SAndrew.Bardsley@arm.com 65910259SAndrew.Bardsley@arm.com Cycles extra_dest_retire_lat = Cycles(0); 66010259SAndrew.Bardsley@arm.com TimingExpr *extra_dest_retire_lat_expr = NULL; 66110259SAndrew.Bardsley@arm.com Cycles extra_assumed_lat = Cycles(0); 66210259SAndrew.Bardsley@arm.com 66310259SAndrew.Bardsley@arm.com /* Add the extraCommitDelay and extraAssumeLat to 66410259SAndrew.Bardsley@arm.com * the FU pipeline timings */ 66510259SAndrew.Bardsley@arm.com if (timing) { 66610259SAndrew.Bardsley@arm.com extra_dest_retire_lat = 66710259SAndrew.Bardsley@arm.com timing->extraCommitLat; 66810259SAndrew.Bardsley@arm.com extra_dest_retire_lat_expr = 66910259SAndrew.Bardsley@arm.com timing->extraCommitLatExpr; 67010259SAndrew.Bardsley@arm.com extra_assumed_lat = 67110259SAndrew.Bardsley@arm.com timing->extraAssumedLat; 67210259SAndrew.Bardsley@arm.com } 67310259SAndrew.Bardsley@arm.com 67410580SAndrew.Bardsley@arm.com issued_mem_ref = inst->isMemRef(); 67510259SAndrew.Bardsley@arm.com 67610259SAndrew.Bardsley@arm.com QueuedInst fu_inst(inst); 67710259SAndrew.Bardsley@arm.com 67810259SAndrew.Bardsley@arm.com /* Decorate the inst with FU details */ 67910259SAndrew.Bardsley@arm.com inst->fuIndex = fu_index; 68010259SAndrew.Bardsley@arm.com inst->extraCommitDelay = extra_dest_retire_lat; 68110259SAndrew.Bardsley@arm.com inst->extraCommitDelayExpr = 68210259SAndrew.Bardsley@arm.com extra_dest_retire_lat_expr; 68310259SAndrew.Bardsley@arm.com 68410259SAndrew.Bardsley@arm.com if (issued_mem_ref) { 68510259SAndrew.Bardsley@arm.com /* Remember which instruction this memory op 68610259SAndrew.Bardsley@arm.com * depends on so that initiateAcc can be called 68710259SAndrew.Bardsley@arm.com * early */ 68810259SAndrew.Bardsley@arm.com if (allowEarlyMemIssue) { 68910259SAndrew.Bardsley@arm.com inst->instToWaitFor = 69010259SAndrew.Bardsley@arm.com scoreboard.execSeqNumToWaitFor(inst, 69110259SAndrew.Bardsley@arm.com cpu.getContext(thread_id)); 69210259SAndrew.Bardsley@arm.com 69310259SAndrew.Bardsley@arm.com if (lsq.getLastMemBarrier() > 69410259SAndrew.Bardsley@arm.com inst->instToWaitFor) 69510259SAndrew.Bardsley@arm.com { 69610259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "A barrier will" 69710259SAndrew.Bardsley@arm.com " cause a delay in mem ref issue of" 69810259SAndrew.Bardsley@arm.com " inst: %s until after inst" 69910259SAndrew.Bardsley@arm.com " %d(exec)\n", *inst, 70010259SAndrew.Bardsley@arm.com lsq.getLastMemBarrier()); 70110259SAndrew.Bardsley@arm.com 70210259SAndrew.Bardsley@arm.com inst->instToWaitFor = 70310259SAndrew.Bardsley@arm.com lsq.getLastMemBarrier(); 70410259SAndrew.Bardsley@arm.com } else { 70510259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Memory ref inst:" 70610259SAndrew.Bardsley@arm.com " %s must wait for inst %d(exec)" 70710259SAndrew.Bardsley@arm.com " before issuing\n", 70810259SAndrew.Bardsley@arm.com *inst, inst->instToWaitFor); 70910259SAndrew.Bardsley@arm.com } 71010259SAndrew.Bardsley@arm.com 71110259SAndrew.Bardsley@arm.com inst->canEarlyIssue = true; 71210259SAndrew.Bardsley@arm.com } 71310259SAndrew.Bardsley@arm.com /* Also queue this instruction in the memory ref 71410259SAndrew.Bardsley@arm.com * queue to ensure in-order issue to the LSQ */ 71510259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Pushing mem inst: %s\n", 71610259SAndrew.Bardsley@arm.com *inst); 71710259SAndrew.Bardsley@arm.com inFUMemInsts->push(fu_inst); 71810259SAndrew.Bardsley@arm.com } 71910259SAndrew.Bardsley@arm.com 72010259SAndrew.Bardsley@arm.com /* Issue to FU */ 72110259SAndrew.Bardsley@arm.com fu->push(fu_inst); 72210259SAndrew.Bardsley@arm.com /* And start the countdown on activity to allow 72310259SAndrew.Bardsley@arm.com * this instruction to get to the end of its FU */ 72410259SAndrew.Bardsley@arm.com cpu.activityRecorder->activity(); 72510259SAndrew.Bardsley@arm.com 72610259SAndrew.Bardsley@arm.com /* Mark the destinations for this instruction as 72710259SAndrew.Bardsley@arm.com * busy */ 72810259SAndrew.Bardsley@arm.com scoreboard.markupInstDests(inst, cpu.curCycle() + 72910259SAndrew.Bardsley@arm.com fu->description.opLat + 73010259SAndrew.Bardsley@arm.com extra_dest_retire_lat + 73110259SAndrew.Bardsley@arm.com extra_assumed_lat, 73210259SAndrew.Bardsley@arm.com cpu.getContext(thread_id), 73310259SAndrew.Bardsley@arm.com issued_mem_ref && extra_assumed_lat == Cycles(0)); 73410259SAndrew.Bardsley@arm.com 73510259SAndrew.Bardsley@arm.com /* Push the instruction onto the inFlight queue so 73610259SAndrew.Bardsley@arm.com * it can be committed in order */ 73710259SAndrew.Bardsley@arm.com inFlightInsts->push(fu_inst); 73810259SAndrew.Bardsley@arm.com 73910259SAndrew.Bardsley@arm.com issued = true; 74010259SAndrew.Bardsley@arm.com } 74110259SAndrew.Bardsley@arm.com } 74210259SAndrew.Bardsley@arm.com 74310259SAndrew.Bardsley@arm.com fu_index++; 74410259SAndrew.Bardsley@arm.com } while (fu_index != numFuncUnits && !issued); 74510259SAndrew.Bardsley@arm.com 74610259SAndrew.Bardsley@arm.com if (!issued) 74710259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Didn't issue inst: %s\n", *inst); 74810259SAndrew.Bardsley@arm.com } 74910259SAndrew.Bardsley@arm.com 75010259SAndrew.Bardsley@arm.com if (issued) { 75110259SAndrew.Bardsley@arm.com /* Generate MinorTrace's MinorInst lines. Do this at commit 75210259SAndrew.Bardsley@arm.com * to allow better instruction annotation? */ 75310259SAndrew.Bardsley@arm.com if (DTRACE(MinorTrace) && !inst->isBubble()) 75410259SAndrew.Bardsley@arm.com inst->minorTraceInst(*this); 75510259SAndrew.Bardsley@arm.com 75610259SAndrew.Bardsley@arm.com /* Mark up barriers in the LSQ */ 75710259SAndrew.Bardsley@arm.com if (!discarded && inst->isInst() && 75810259SAndrew.Bardsley@arm.com inst->staticInst->isMemBarrier()) 75910259SAndrew.Bardsley@arm.com { 76010259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Issuing memory barrier inst: %s\n", *inst); 76110259SAndrew.Bardsley@arm.com lsq.issuedMemBarrierInst(inst); 76210259SAndrew.Bardsley@arm.com } 76310259SAndrew.Bardsley@arm.com 76410259SAndrew.Bardsley@arm.com if (inst->traceData && setTraceTimeOnIssue) { 76510259SAndrew.Bardsley@arm.com inst->traceData->setWhen(curTick()); 76610259SAndrew.Bardsley@arm.com } 76710259SAndrew.Bardsley@arm.com 76810259SAndrew.Bardsley@arm.com if (issued_mem_ref) 76910259SAndrew.Bardsley@arm.com num_mem_insts_issued++; 77010259SAndrew.Bardsley@arm.com 77110259SAndrew.Bardsley@arm.com if (discarded) { 77210259SAndrew.Bardsley@arm.com num_insts_discarded++; 77310851SAndrew.Bardsley@arm.com } else if (!inst->isBubble()) { 77410259SAndrew.Bardsley@arm.com num_insts_issued++; 77510259SAndrew.Bardsley@arm.com 77610259SAndrew.Bardsley@arm.com if (num_insts_issued == issueLimit) 77710259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Reached inst issue limit\n"); 77810259SAndrew.Bardsley@arm.com } 77910259SAndrew.Bardsley@arm.com 78010259SAndrew.Bardsley@arm.com inputIndex++; 78110259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Stepping to next inst inputIndex: %d\n", 78210259SAndrew.Bardsley@arm.com inputIndex); 78310259SAndrew.Bardsley@arm.com } 78410259SAndrew.Bardsley@arm.com 78510259SAndrew.Bardsley@arm.com /* Got to the end of a line */ 78610259SAndrew.Bardsley@arm.com if (inputIndex == insts_in->width()) { 78710259SAndrew.Bardsley@arm.com popInput(); 78810259SAndrew.Bardsley@arm.com /* Set insts_in to null to force us to leave the surrounding 78910259SAndrew.Bardsley@arm.com * loop */ 79010259SAndrew.Bardsley@arm.com insts_in = NULL; 79110259SAndrew.Bardsley@arm.com 79210259SAndrew.Bardsley@arm.com if (processMoreThanOneInput) { 79310259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Wrapping\n"); 79410259SAndrew.Bardsley@arm.com insts_in = getInput(); 79510259SAndrew.Bardsley@arm.com } 79610259SAndrew.Bardsley@arm.com } 79710259SAndrew.Bardsley@arm.com } while (insts_in && inputIndex < insts_in->width() && 79810259SAndrew.Bardsley@arm.com /* We still have instructions */ 79910259SAndrew.Bardsley@arm.com fu_index != numFuncUnits && /* Not visited all FUs */ 80010259SAndrew.Bardsley@arm.com issued && /* We've not yet failed to issue an instruction */ 80110259SAndrew.Bardsley@arm.com num_insts_issued != issueLimit && /* Still allowed to issue */ 80210259SAndrew.Bardsley@arm.com num_mem_insts_issued != memoryIssueLimit); 80310259SAndrew.Bardsley@arm.com 80410259SAndrew.Bardsley@arm.com return num_insts_issued; 80510259SAndrew.Bardsley@arm.com} 80610259SAndrew.Bardsley@arm.com 80710259SAndrew.Bardsley@arm.combool 80810259SAndrew.Bardsley@arm.comExecute::tryPCEvents() 80910259SAndrew.Bardsley@arm.com{ 81010259SAndrew.Bardsley@arm.com ThreadContext *thread = cpu.getContext(0); 81110259SAndrew.Bardsley@arm.com unsigned int num_pc_event_checks = 0; 81210259SAndrew.Bardsley@arm.com 81310259SAndrew.Bardsley@arm.com /* Handle PC events on instructions */ 81410259SAndrew.Bardsley@arm.com Addr oldPC; 81510259SAndrew.Bardsley@arm.com do { 81610259SAndrew.Bardsley@arm.com oldPC = thread->instAddr(); 81710259SAndrew.Bardsley@arm.com cpu.system->pcEventQueue.service(thread); 81810259SAndrew.Bardsley@arm.com num_pc_event_checks++; 81910259SAndrew.Bardsley@arm.com } while (oldPC != thread->instAddr()); 82010259SAndrew.Bardsley@arm.com 82110259SAndrew.Bardsley@arm.com if (num_pc_event_checks > 1) { 82210259SAndrew.Bardsley@arm.com DPRINTF(PCEvent, "Acting on PC Event to PC: %s\n", 82310259SAndrew.Bardsley@arm.com thread->pcState()); 82410259SAndrew.Bardsley@arm.com } 82510259SAndrew.Bardsley@arm.com 82610259SAndrew.Bardsley@arm.com return num_pc_event_checks > 1; 82710259SAndrew.Bardsley@arm.com} 82810259SAndrew.Bardsley@arm.com 82910259SAndrew.Bardsley@arm.comvoid 83010259SAndrew.Bardsley@arm.comExecute::doInstCommitAccounting(MinorDynInstPtr inst) 83110259SAndrew.Bardsley@arm.com{ 83210259SAndrew.Bardsley@arm.com assert(!inst->isFault()); 83310259SAndrew.Bardsley@arm.com 83410259SAndrew.Bardsley@arm.com MinorThread *thread = cpu.threads[inst->id.threadId]; 83510259SAndrew.Bardsley@arm.com 83610259SAndrew.Bardsley@arm.com /* Increment the many and various inst and op counts in the 83710259SAndrew.Bardsley@arm.com * thread and system */ 83810259SAndrew.Bardsley@arm.com if (!inst->staticInst->isMicroop() || inst->staticInst->isLastMicroop()) 83910259SAndrew.Bardsley@arm.com { 84010259SAndrew.Bardsley@arm.com thread->numInst++; 84110259SAndrew.Bardsley@arm.com thread->numInsts++; 84210259SAndrew.Bardsley@arm.com cpu.stats.numInsts++; 84310774Snikos.nikoleris@gmail.com cpu.system->totalNumInsts++; 84410774Snikos.nikoleris@gmail.com 84510774Snikos.nikoleris@gmail.com /* Act on events related to instruction counts */ 84610774Snikos.nikoleris@gmail.com cpu.comInstEventQueue[inst->id.threadId]->serviceEvents(thread->numInst); 84710774Snikos.nikoleris@gmail.com cpu.system->instEventQueue.serviceEvents(cpu.system->totalNumInsts); 84810259SAndrew.Bardsley@arm.com } 84910259SAndrew.Bardsley@arm.com thread->numOp++; 85010259SAndrew.Bardsley@arm.com thread->numOps++; 85110259SAndrew.Bardsley@arm.com cpu.stats.numOps++; 85210259SAndrew.Bardsley@arm.com 85310259SAndrew.Bardsley@arm.com /* Set the CP SeqNum to the numOps commit number */ 85410259SAndrew.Bardsley@arm.com if (inst->traceData) 85510259SAndrew.Bardsley@arm.com inst->traceData->setCPSeq(thread->numOp); 85610464SAndreas.Sandberg@ARM.com 85710464SAndreas.Sandberg@ARM.com cpu.probeInstCommit(inst->staticInst); 85810259SAndrew.Bardsley@arm.com} 85910259SAndrew.Bardsley@arm.com 86010259SAndrew.Bardsley@arm.combool 86110259SAndrew.Bardsley@arm.comExecute::commitInst(MinorDynInstPtr inst, bool early_memory_issue, 86210259SAndrew.Bardsley@arm.com BranchData &branch, Fault &fault, bool &committed, 86310259SAndrew.Bardsley@arm.com bool &completed_mem_issue) 86410259SAndrew.Bardsley@arm.com{ 86510259SAndrew.Bardsley@arm.com ThreadID thread_id = inst->id.threadId; 86610259SAndrew.Bardsley@arm.com ThreadContext *thread = cpu.getContext(thread_id); 86710259SAndrew.Bardsley@arm.com 86810259SAndrew.Bardsley@arm.com bool completed_inst = true; 86910259SAndrew.Bardsley@arm.com fault = NoFault; 87010259SAndrew.Bardsley@arm.com 87110259SAndrew.Bardsley@arm.com /* Is the thread for this instruction suspended? In that case, just 87210259SAndrew.Bardsley@arm.com * stall as long as there are no pending interrupts */ 87310259SAndrew.Bardsley@arm.com if (thread->status() == ThreadContext::Suspended && 87410259SAndrew.Bardsley@arm.com !isInterrupted(thread_id)) 87510259SAndrew.Bardsley@arm.com { 87610259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Not committing inst from suspended thread" 87710259SAndrew.Bardsley@arm.com " inst: %s\n", *inst); 87810259SAndrew.Bardsley@arm.com completed_inst = false; 87910259SAndrew.Bardsley@arm.com } else if (inst->isFault()) { 88010259SAndrew.Bardsley@arm.com ExecContext context(cpu, *cpu.threads[thread_id], *this, inst); 88110259SAndrew.Bardsley@arm.com 88210259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Fault inst reached Execute: %s\n", 88310259SAndrew.Bardsley@arm.com inst->fault->name()); 88410259SAndrew.Bardsley@arm.com 88510259SAndrew.Bardsley@arm.com fault = inst->fault; 88610259SAndrew.Bardsley@arm.com inst->fault->invoke(thread, NULL); 88710259SAndrew.Bardsley@arm.com 88810259SAndrew.Bardsley@arm.com tryToBranch(inst, fault, branch); 88910259SAndrew.Bardsley@arm.com } else if (inst->staticInst->isMemRef()) { 89010259SAndrew.Bardsley@arm.com /* Memory accesses are executed in two parts: 89110259SAndrew.Bardsley@arm.com * executeMemRefInst -- calculates the EA and issues the access 89210259SAndrew.Bardsley@arm.com * to memory. This is done here. 89310259SAndrew.Bardsley@arm.com * handleMemResponse -- handles the response packet, done by 89410259SAndrew.Bardsley@arm.com * Execute::commit 89510259SAndrew.Bardsley@arm.com * 89610259SAndrew.Bardsley@arm.com * While the memory access is in its FU, the EA is being 89710259SAndrew.Bardsley@arm.com * calculated. At the end of the FU, when it is ready to 89810259SAndrew.Bardsley@arm.com * 'commit' (in this function), the access is presented to the 89910259SAndrew.Bardsley@arm.com * memory queues. When a response comes back from memory, 90010259SAndrew.Bardsley@arm.com * Execute::commit will commit it. 90110259SAndrew.Bardsley@arm.com */ 90210259SAndrew.Bardsley@arm.com bool predicate_passed = false; 90310259SAndrew.Bardsley@arm.com bool completed_mem_inst = executeMemRefInst(inst, branch, 90410259SAndrew.Bardsley@arm.com predicate_passed, fault); 90510259SAndrew.Bardsley@arm.com 90610259SAndrew.Bardsley@arm.com if (completed_mem_inst && fault != NoFault) { 90710259SAndrew.Bardsley@arm.com if (early_memory_issue) { 90810259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Fault in early executing inst: %s\n", 90910259SAndrew.Bardsley@arm.com fault->name()); 91010259SAndrew.Bardsley@arm.com /* Don't execute the fault, just stall the instruction 91110259SAndrew.Bardsley@arm.com * until it gets to the head of inFlightInsts */ 91210259SAndrew.Bardsley@arm.com inst->canEarlyIssue = false; 91310259SAndrew.Bardsley@arm.com /* Not completed as we'll come here again to pick up 91410259SAndrew.Bardsley@arm.com * the fault when we get to the end of the FU */ 91510259SAndrew.Bardsley@arm.com completed_inst = false; 91610259SAndrew.Bardsley@arm.com } else { 91710259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Fault in execute: %s\n", 91810259SAndrew.Bardsley@arm.com fault->name()); 91910259SAndrew.Bardsley@arm.com fault->invoke(thread, NULL); 92010259SAndrew.Bardsley@arm.com 92110259SAndrew.Bardsley@arm.com tryToBranch(inst, fault, branch); 92210259SAndrew.Bardsley@arm.com completed_inst = true; 92310259SAndrew.Bardsley@arm.com } 92410259SAndrew.Bardsley@arm.com } else { 92510259SAndrew.Bardsley@arm.com completed_inst = completed_mem_inst; 92610259SAndrew.Bardsley@arm.com } 92710259SAndrew.Bardsley@arm.com completed_mem_issue = completed_inst; 92810259SAndrew.Bardsley@arm.com } else if (inst->isInst() && inst->staticInst->isMemBarrier() && 92910259SAndrew.Bardsley@arm.com !lsq.canPushIntoStoreBuffer()) 93010259SAndrew.Bardsley@arm.com { 93110259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Can't commit data barrier inst: %s yet as" 93210259SAndrew.Bardsley@arm.com " there isn't space in the store buffer\n", *inst); 93310259SAndrew.Bardsley@arm.com 93410259SAndrew.Bardsley@arm.com completed_inst = false; 93510259SAndrew.Bardsley@arm.com } else { 93610259SAndrew.Bardsley@arm.com ExecContext context(cpu, *cpu.threads[thread_id], *this, inst); 93710259SAndrew.Bardsley@arm.com 93810259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Committing inst: %s\n", *inst); 93910259SAndrew.Bardsley@arm.com 94010259SAndrew.Bardsley@arm.com fault = inst->staticInst->execute(&context, 94110259SAndrew.Bardsley@arm.com inst->traceData); 94210259SAndrew.Bardsley@arm.com 94310259SAndrew.Bardsley@arm.com /* Set the predicate for tracing and dump */ 94410259SAndrew.Bardsley@arm.com if (inst->traceData) 94510259SAndrew.Bardsley@arm.com inst->traceData->setPredicate(context.readPredicate()); 94610259SAndrew.Bardsley@arm.com 94710259SAndrew.Bardsley@arm.com committed = true; 94810259SAndrew.Bardsley@arm.com 94910259SAndrew.Bardsley@arm.com if (fault != NoFault) { 95010259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Fault in execute of inst: %s fault: %s\n", 95110259SAndrew.Bardsley@arm.com *inst, fault->name()); 95210259SAndrew.Bardsley@arm.com fault->invoke(thread, inst->staticInst); 95310259SAndrew.Bardsley@arm.com } 95410259SAndrew.Bardsley@arm.com 95510259SAndrew.Bardsley@arm.com doInstCommitAccounting(inst); 95610259SAndrew.Bardsley@arm.com tryToBranch(inst, fault, branch); 95710259SAndrew.Bardsley@arm.com } 95810259SAndrew.Bardsley@arm.com 95910259SAndrew.Bardsley@arm.com if (completed_inst) { 96010259SAndrew.Bardsley@arm.com /* Keep a copy of this instruction's predictionSeqNum just in case 96110259SAndrew.Bardsley@arm.com * we need to issue a branch without an instruction (such as an 96210259SAndrew.Bardsley@arm.com * interrupt) */ 96310259SAndrew.Bardsley@arm.com lastPredictionSeqNum = inst->id.predictionSeqNum; 96410259SAndrew.Bardsley@arm.com 96510259SAndrew.Bardsley@arm.com /* Check to see if this instruction suspended the current thread. */ 96610259SAndrew.Bardsley@arm.com if (!inst->isFault() && 96710259SAndrew.Bardsley@arm.com thread->status() == ThreadContext::Suspended && 96810259SAndrew.Bardsley@arm.com branch.isBubble() && /* It didn't branch too */ 96910259SAndrew.Bardsley@arm.com !isInterrupted(thread_id)) /* Don't suspend if we have 97010259SAndrew.Bardsley@arm.com interrupts */ 97110259SAndrew.Bardsley@arm.com { 97210259SAndrew.Bardsley@arm.com TheISA::PCState resume_pc = cpu.getContext(0)->pcState(); 97310259SAndrew.Bardsley@arm.com 97410259SAndrew.Bardsley@arm.com assert(resume_pc.microPC() == 0); 97510259SAndrew.Bardsley@arm.com 97610259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Suspending thread: %d from Execute" 97710259SAndrew.Bardsley@arm.com " inst: %s\n", inst->id.threadId, *inst); 97810259SAndrew.Bardsley@arm.com 97910259SAndrew.Bardsley@arm.com cpu.stats.numFetchSuspends++; 98010259SAndrew.Bardsley@arm.com 98110259SAndrew.Bardsley@arm.com updateBranchData(BranchData::SuspendThread, inst, resume_pc, 98210259SAndrew.Bardsley@arm.com branch); 98310259SAndrew.Bardsley@arm.com } 98410259SAndrew.Bardsley@arm.com } 98510259SAndrew.Bardsley@arm.com 98610259SAndrew.Bardsley@arm.com return completed_inst; 98710259SAndrew.Bardsley@arm.com} 98810259SAndrew.Bardsley@arm.com 98910259SAndrew.Bardsley@arm.comvoid 99010259SAndrew.Bardsley@arm.comExecute::commit(bool only_commit_microops, bool discard, BranchData &branch) 99110259SAndrew.Bardsley@arm.com{ 99210259SAndrew.Bardsley@arm.com Fault fault = NoFault; 99310259SAndrew.Bardsley@arm.com Cycles now = cpu.curCycle(); 99410259SAndrew.Bardsley@arm.com 99510259SAndrew.Bardsley@arm.com /** 99610259SAndrew.Bardsley@arm.com * Try and execute as many instructions from the end of FU pipelines as 99710259SAndrew.Bardsley@arm.com * possible. This *doesn't* include actually advancing the pipelines. 99810259SAndrew.Bardsley@arm.com * 99910259SAndrew.Bardsley@arm.com * We do this by looping on the front of the inFlightInsts queue for as 100010259SAndrew.Bardsley@arm.com * long as we can find the desired instruction at the end of the 100110259SAndrew.Bardsley@arm.com * functional unit it was issued to without seeing a branch or a fault. 100210259SAndrew.Bardsley@arm.com * In this function, these terms are used: 100310259SAndrew.Bardsley@arm.com * complete -- The instruction has finished its passage through 100410259SAndrew.Bardsley@arm.com * its functional unit and its fate has been decided 100510259SAndrew.Bardsley@arm.com * (committed, discarded, issued to the memory system) 100610259SAndrew.Bardsley@arm.com * commit -- The instruction is complete(d), not discarded and has 100710259SAndrew.Bardsley@arm.com * its effects applied to the CPU state 100810259SAndrew.Bardsley@arm.com * discard(ed) -- The instruction is complete but not committed 100910259SAndrew.Bardsley@arm.com * as its streamSeqNum disagrees with the current 101010259SAndrew.Bardsley@arm.com * Execute::streamSeqNum 101110259SAndrew.Bardsley@arm.com * 101210259SAndrew.Bardsley@arm.com * Commits are also possible from two other places: 101310259SAndrew.Bardsley@arm.com * 101410259SAndrew.Bardsley@arm.com * 1) Responses returning from the LSQ 101510259SAndrew.Bardsley@arm.com * 2) Mem ops issued to the LSQ ('committed' from the FUs) earlier 101610259SAndrew.Bardsley@arm.com * than their position in the inFlightInsts queue, but after all 101710259SAndrew.Bardsley@arm.com * their dependencies are resolved. 101810259SAndrew.Bardsley@arm.com */ 101910259SAndrew.Bardsley@arm.com 102010259SAndrew.Bardsley@arm.com /* Has an instruction been completed? Once this becomes false, we stop 102110259SAndrew.Bardsley@arm.com * trying to complete instructions. */ 102210259SAndrew.Bardsley@arm.com bool completed_inst = true; 102310259SAndrew.Bardsley@arm.com 102410259SAndrew.Bardsley@arm.com /* Number of insts committed this cycle to check against commitLimit */ 102510259SAndrew.Bardsley@arm.com unsigned int num_insts_committed = 0; 102610259SAndrew.Bardsley@arm.com 102710259SAndrew.Bardsley@arm.com /* Number of memory access instructions committed to check against 102810259SAndrew.Bardsley@arm.com * memCommitLimit */ 102910259SAndrew.Bardsley@arm.com unsigned int num_mem_refs_committed = 0; 103010259SAndrew.Bardsley@arm.com 103110259SAndrew.Bardsley@arm.com if (only_commit_microops && !inFlightInsts->empty()) { 103210259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Only commit microops %s %d\n", 103310259SAndrew.Bardsley@arm.com *(inFlightInsts->front().inst), 103410259SAndrew.Bardsley@arm.com lastCommitWasEndOfMacroop); 103510259SAndrew.Bardsley@arm.com } 103610259SAndrew.Bardsley@arm.com 103710259SAndrew.Bardsley@arm.com while (!inFlightInsts->empty() && /* Some more instructions to process */ 103810259SAndrew.Bardsley@arm.com !branch.isStreamChange() && /* No real branch */ 103910259SAndrew.Bardsley@arm.com fault == NoFault && /* No faults */ 104010259SAndrew.Bardsley@arm.com completed_inst && /* Still finding instructions to execute */ 104110259SAndrew.Bardsley@arm.com num_insts_committed != commitLimit /* Not reached commit limit */ 104210259SAndrew.Bardsley@arm.com ) 104310259SAndrew.Bardsley@arm.com { 104410259SAndrew.Bardsley@arm.com if (only_commit_microops) { 104510259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Committing tail of insts before" 104610259SAndrew.Bardsley@arm.com " interrupt: %s\n", 104710259SAndrew.Bardsley@arm.com *(inFlightInsts->front().inst)); 104810259SAndrew.Bardsley@arm.com } 104910259SAndrew.Bardsley@arm.com 105010259SAndrew.Bardsley@arm.com QueuedInst *head_inflight_inst = &(inFlightInsts->front()); 105110259SAndrew.Bardsley@arm.com 105210259SAndrew.Bardsley@arm.com InstSeqNum head_exec_seq_num = 105310259SAndrew.Bardsley@arm.com head_inflight_inst->inst->id.execSeqNum; 105410259SAndrew.Bardsley@arm.com 105510259SAndrew.Bardsley@arm.com /* The instruction we actually process if completed_inst 105610259SAndrew.Bardsley@arm.com * remains true to the end of the loop body. 105710259SAndrew.Bardsley@arm.com * Start by considering the the head of the in flight insts queue */ 105810259SAndrew.Bardsley@arm.com MinorDynInstPtr inst = head_inflight_inst->inst; 105910259SAndrew.Bardsley@arm.com 106010259SAndrew.Bardsley@arm.com bool committed_inst = false; 106110259SAndrew.Bardsley@arm.com bool discard_inst = false; 106210259SAndrew.Bardsley@arm.com bool completed_mem_ref = false; 106310259SAndrew.Bardsley@arm.com bool issued_mem_ref = false; 106410259SAndrew.Bardsley@arm.com bool early_memory_issue = false; 106510259SAndrew.Bardsley@arm.com 106610259SAndrew.Bardsley@arm.com /* Must set this again to go around the loop */ 106710259SAndrew.Bardsley@arm.com completed_inst = false; 106810259SAndrew.Bardsley@arm.com 106910259SAndrew.Bardsley@arm.com /* If we're just completing a macroop before an interrupt or drain, 107010259SAndrew.Bardsley@arm.com * can we stil commit another microop (rather than a memory response) 107110259SAndrew.Bardsley@arm.com * without crosing into the next full instruction? */ 107210259SAndrew.Bardsley@arm.com bool can_commit_insts = !inFlightInsts->empty() && 107310259SAndrew.Bardsley@arm.com !(only_commit_microops && lastCommitWasEndOfMacroop); 107410259SAndrew.Bardsley@arm.com 107510259SAndrew.Bardsley@arm.com /* Can we find a mem response for this inst */ 107610259SAndrew.Bardsley@arm.com LSQ::LSQRequestPtr mem_response = 107710259SAndrew.Bardsley@arm.com (inst->inLSQ ? lsq.findResponse(inst) : NULL); 107810259SAndrew.Bardsley@arm.com 107910259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Trying to commit canCommitInsts: %d\n", 108010259SAndrew.Bardsley@arm.com can_commit_insts); 108110259SAndrew.Bardsley@arm.com 108210259SAndrew.Bardsley@arm.com /* Test for PC events after every instruction */ 108310259SAndrew.Bardsley@arm.com if (isInbetweenInsts() && tryPCEvents()) { 108410259SAndrew.Bardsley@arm.com ThreadContext *thread = cpu.getContext(0); 108510259SAndrew.Bardsley@arm.com 108610259SAndrew.Bardsley@arm.com /* Branch as there was a change in PC */ 108710259SAndrew.Bardsley@arm.com updateBranchData(BranchData::UnpredictedBranch, 108810259SAndrew.Bardsley@arm.com MinorDynInst::bubble(), thread->pcState(), branch); 108910259SAndrew.Bardsley@arm.com } else if (mem_response && 109010259SAndrew.Bardsley@arm.com num_mem_refs_committed < memoryCommitLimit) 109110259SAndrew.Bardsley@arm.com { 109210259SAndrew.Bardsley@arm.com /* Try to commit from the memory responses next */ 109310259SAndrew.Bardsley@arm.com discard_inst = inst->id.streamSeqNum != streamSeqNum || 109410259SAndrew.Bardsley@arm.com discard; 109510259SAndrew.Bardsley@arm.com 109610259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Trying to commit mem response: %s\n", 109710259SAndrew.Bardsley@arm.com *inst); 109810259SAndrew.Bardsley@arm.com 109910259SAndrew.Bardsley@arm.com /* Complete or discard the response */ 110010259SAndrew.Bardsley@arm.com if (discard_inst) { 110110259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Discarding mem inst: %s as its" 110210259SAndrew.Bardsley@arm.com " stream state was unexpected, expected: %d\n", 110310259SAndrew.Bardsley@arm.com *inst, streamSeqNum); 110410259SAndrew.Bardsley@arm.com 110510259SAndrew.Bardsley@arm.com lsq.popResponse(mem_response); 110610259SAndrew.Bardsley@arm.com } else { 110710259SAndrew.Bardsley@arm.com handleMemResponse(inst, mem_response, branch, fault); 110810259SAndrew.Bardsley@arm.com committed_inst = true; 110910259SAndrew.Bardsley@arm.com } 111010259SAndrew.Bardsley@arm.com 111110259SAndrew.Bardsley@arm.com completed_mem_ref = true; 111210259SAndrew.Bardsley@arm.com completed_inst = true; 111310259SAndrew.Bardsley@arm.com } else if (can_commit_insts) { 111410259SAndrew.Bardsley@arm.com /* If true, this instruction will, subject to timing tweaks, 111510259SAndrew.Bardsley@arm.com * be considered for completion. try_to_commit flattens 111610259SAndrew.Bardsley@arm.com * the `if' tree a bit and allows other tests for inst 111710259SAndrew.Bardsley@arm.com * commit to be inserted here. */ 111810259SAndrew.Bardsley@arm.com bool try_to_commit = false; 111910259SAndrew.Bardsley@arm.com 112010259SAndrew.Bardsley@arm.com /* Try and issue memory ops early if they: 112110259SAndrew.Bardsley@arm.com * - Can push a request into the LSQ 112210259SAndrew.Bardsley@arm.com * - Have reached the end of their FUs 112310259SAndrew.Bardsley@arm.com * - Have had all their dependencies satisfied 112410259SAndrew.Bardsley@arm.com * - Are from the right stream 112510259SAndrew.Bardsley@arm.com * 112610259SAndrew.Bardsley@arm.com * For any other case, leave it to the normal instruction 112710259SAndrew.Bardsley@arm.com * issue below to handle them. 112810259SAndrew.Bardsley@arm.com */ 112910259SAndrew.Bardsley@arm.com if (!inFUMemInsts->empty() && lsq.canRequest()) { 113010259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Trying to commit from mem FUs\n"); 113110259SAndrew.Bardsley@arm.com 113210259SAndrew.Bardsley@arm.com const MinorDynInstPtr head_mem_ref_inst = 113310259SAndrew.Bardsley@arm.com inFUMemInsts->front().inst; 113410259SAndrew.Bardsley@arm.com FUPipeline *fu = funcUnits[head_mem_ref_inst->fuIndex]; 113510259SAndrew.Bardsley@arm.com const MinorDynInstPtr &fu_inst = fu->front().inst; 113610259SAndrew.Bardsley@arm.com 113710259SAndrew.Bardsley@arm.com /* Use this, possibly out of order, inst as the one 113810259SAndrew.Bardsley@arm.com * to 'commit'/send to the LSQ */ 113910259SAndrew.Bardsley@arm.com if (!fu_inst->isBubble() && 114010259SAndrew.Bardsley@arm.com !fu_inst->inLSQ && 114110259SAndrew.Bardsley@arm.com fu_inst->canEarlyIssue && 114210259SAndrew.Bardsley@arm.com streamSeqNum == fu_inst->id.streamSeqNum && 114310259SAndrew.Bardsley@arm.com head_exec_seq_num > fu_inst->instToWaitFor) 114410259SAndrew.Bardsley@arm.com { 114510259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Issuing mem ref early" 114610259SAndrew.Bardsley@arm.com " inst: %s instToWaitFor: %d\n", 114710259SAndrew.Bardsley@arm.com *(fu_inst), fu_inst->instToWaitFor); 114810259SAndrew.Bardsley@arm.com 114910259SAndrew.Bardsley@arm.com inst = fu_inst; 115010259SAndrew.Bardsley@arm.com try_to_commit = true; 115110259SAndrew.Bardsley@arm.com early_memory_issue = true; 115210259SAndrew.Bardsley@arm.com completed_inst = true; 115310259SAndrew.Bardsley@arm.com } 115410259SAndrew.Bardsley@arm.com } 115510259SAndrew.Bardsley@arm.com 115610259SAndrew.Bardsley@arm.com /* Try and commit FU-less insts */ 115710259SAndrew.Bardsley@arm.com if (!completed_inst && inst->isNoCostInst()) { 115810259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Committing no cost inst: %s", *inst); 115910259SAndrew.Bardsley@arm.com 116010259SAndrew.Bardsley@arm.com try_to_commit = true; 116110259SAndrew.Bardsley@arm.com completed_inst = true; 116210259SAndrew.Bardsley@arm.com } 116310259SAndrew.Bardsley@arm.com 116410259SAndrew.Bardsley@arm.com /* Try to issue from the ends of FUs and the inFlightInsts 116510259SAndrew.Bardsley@arm.com * queue */ 116610259SAndrew.Bardsley@arm.com if (!completed_inst && !inst->inLSQ) { 116710259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Trying to commit from FUs\n"); 116810259SAndrew.Bardsley@arm.com 116910259SAndrew.Bardsley@arm.com /* Try to commit from a functional unit */ 117010259SAndrew.Bardsley@arm.com /* Is the head inst of the expected inst's FU actually the 117110259SAndrew.Bardsley@arm.com * expected inst? */ 117210259SAndrew.Bardsley@arm.com QueuedInst &fu_inst = 117310259SAndrew.Bardsley@arm.com funcUnits[inst->fuIndex]->front(); 117410259SAndrew.Bardsley@arm.com InstSeqNum fu_inst_seq_num = fu_inst.inst->id.execSeqNum; 117510259SAndrew.Bardsley@arm.com 117610259SAndrew.Bardsley@arm.com if (fu_inst.inst->isBubble()) { 117710259SAndrew.Bardsley@arm.com /* No instruction ready */ 117810259SAndrew.Bardsley@arm.com completed_inst = false; 117910259SAndrew.Bardsley@arm.com } else if (fu_inst_seq_num != head_exec_seq_num) { 118010259SAndrew.Bardsley@arm.com /* Past instruction: we must have already executed it 118110259SAndrew.Bardsley@arm.com * in the same cycle and so the head inst isn't 118210259SAndrew.Bardsley@arm.com * actually at the end of its pipeline 118310259SAndrew.Bardsley@arm.com * Future instruction: handled above and only for 118410259SAndrew.Bardsley@arm.com * mem refs on their way to the LSQ */ 118510259SAndrew.Bardsley@arm.com } else /* if (fu_inst_seq_num == head_exec_seq_num) */ { 118610259SAndrew.Bardsley@arm.com /* All instructions can be committed if they have the 118710259SAndrew.Bardsley@arm.com * right execSeqNum and there are no in-flight 118810259SAndrew.Bardsley@arm.com * mem insts before us */ 118910259SAndrew.Bardsley@arm.com try_to_commit = true; 119010259SAndrew.Bardsley@arm.com completed_inst = true; 119110259SAndrew.Bardsley@arm.com } 119210259SAndrew.Bardsley@arm.com } 119310259SAndrew.Bardsley@arm.com 119410259SAndrew.Bardsley@arm.com if (try_to_commit) { 119510259SAndrew.Bardsley@arm.com discard_inst = inst->id.streamSeqNum != streamSeqNum || 119610259SAndrew.Bardsley@arm.com discard; 119710259SAndrew.Bardsley@arm.com 119810259SAndrew.Bardsley@arm.com /* Is this instruction discardable as its streamSeqNum 119910259SAndrew.Bardsley@arm.com * doesn't match? */ 120010259SAndrew.Bardsley@arm.com if (!discard_inst) { 120110259SAndrew.Bardsley@arm.com /* Try to commit or discard a non-memory instruction. 120210259SAndrew.Bardsley@arm.com * Memory ops are actually 'committed' from this FUs 120310259SAndrew.Bardsley@arm.com * and 'issued' into the memory system so we need to 120410259SAndrew.Bardsley@arm.com * account for them later (commit_was_mem_issue gets 120510259SAndrew.Bardsley@arm.com * set) */ 120610259SAndrew.Bardsley@arm.com if (inst->extraCommitDelayExpr) { 120710259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Evaluating expression for" 120810259SAndrew.Bardsley@arm.com " extra commit delay inst: %s\n", *inst); 120910259SAndrew.Bardsley@arm.com 121010259SAndrew.Bardsley@arm.com ThreadContext *thread = 121110259SAndrew.Bardsley@arm.com cpu.getContext(inst->id.threadId); 121210259SAndrew.Bardsley@arm.com 121310259SAndrew.Bardsley@arm.com TimingExprEvalContext context(inst->staticInst, 121410259SAndrew.Bardsley@arm.com thread, NULL); 121510259SAndrew.Bardsley@arm.com 121610259SAndrew.Bardsley@arm.com uint64_t extra_delay = inst->extraCommitDelayExpr-> 121710259SAndrew.Bardsley@arm.com eval(context); 121810259SAndrew.Bardsley@arm.com 121910259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Extra commit delay expr" 122010259SAndrew.Bardsley@arm.com " result: %d\n", extra_delay); 122110259SAndrew.Bardsley@arm.com 122210259SAndrew.Bardsley@arm.com if (extra_delay < 128) { 122310259SAndrew.Bardsley@arm.com inst->extraCommitDelay += Cycles(extra_delay); 122410259SAndrew.Bardsley@arm.com } else { 122510259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Extra commit delay was" 122610259SAndrew.Bardsley@arm.com " very long: %d\n", extra_delay); 122710259SAndrew.Bardsley@arm.com } 122810259SAndrew.Bardsley@arm.com inst->extraCommitDelayExpr = NULL; 122910259SAndrew.Bardsley@arm.com } 123010259SAndrew.Bardsley@arm.com 123110259SAndrew.Bardsley@arm.com /* Move the extraCommitDelay from the instruction 123210259SAndrew.Bardsley@arm.com * into the minimumCommitCycle */ 123310259SAndrew.Bardsley@arm.com if (inst->extraCommitDelay != Cycles(0)) { 123410259SAndrew.Bardsley@arm.com inst->minimumCommitCycle = cpu.curCycle() + 123510259SAndrew.Bardsley@arm.com inst->extraCommitDelay; 123610259SAndrew.Bardsley@arm.com inst->extraCommitDelay = Cycles(0); 123710259SAndrew.Bardsley@arm.com } 123810259SAndrew.Bardsley@arm.com 123910259SAndrew.Bardsley@arm.com /* @todo Think about making lastMemBarrier be 124010259SAndrew.Bardsley@arm.com * MAX_UINT_64 to avoid using 0 as a marker value */ 124110259SAndrew.Bardsley@arm.com if (!inst->isFault() && inst->isMemRef() && 124210259SAndrew.Bardsley@arm.com lsq.getLastMemBarrier() < 124310259SAndrew.Bardsley@arm.com inst->id.execSeqNum && 124410259SAndrew.Bardsley@arm.com lsq.getLastMemBarrier() != 0) 124510259SAndrew.Bardsley@arm.com { 124610259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Not committing inst: %s yet" 124710259SAndrew.Bardsley@arm.com " as there are incomplete barriers in flight\n", 124810259SAndrew.Bardsley@arm.com *inst); 124910259SAndrew.Bardsley@arm.com completed_inst = false; 125010259SAndrew.Bardsley@arm.com } else if (inst->minimumCommitCycle > now) { 125110259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Not committing inst: %s yet" 125210259SAndrew.Bardsley@arm.com " as it wants to be stalled for %d more cycles\n", 125310259SAndrew.Bardsley@arm.com *inst, inst->minimumCommitCycle - now); 125410259SAndrew.Bardsley@arm.com completed_inst = false; 125510259SAndrew.Bardsley@arm.com } else { 125610259SAndrew.Bardsley@arm.com completed_inst = commitInst(inst, 125710259SAndrew.Bardsley@arm.com early_memory_issue, branch, fault, 125810259SAndrew.Bardsley@arm.com committed_inst, issued_mem_ref); 125910259SAndrew.Bardsley@arm.com } 126010259SAndrew.Bardsley@arm.com } else { 126110259SAndrew.Bardsley@arm.com /* Discard instruction */ 126210259SAndrew.Bardsley@arm.com completed_inst = true; 126310259SAndrew.Bardsley@arm.com } 126410259SAndrew.Bardsley@arm.com 126510259SAndrew.Bardsley@arm.com if (completed_inst) { 126610259SAndrew.Bardsley@arm.com /* Allow the pipeline to advance. If the FU head 126710259SAndrew.Bardsley@arm.com * instruction wasn't the inFlightInsts head 126810259SAndrew.Bardsley@arm.com * but had already been committed, it would have 126910259SAndrew.Bardsley@arm.com * unstalled the pipeline before here */ 127010259SAndrew.Bardsley@arm.com if (inst->fuIndex != noCostFUIndex) 127110259SAndrew.Bardsley@arm.com funcUnits[inst->fuIndex]->stalled = false; 127210259SAndrew.Bardsley@arm.com } 127310259SAndrew.Bardsley@arm.com } 127410259SAndrew.Bardsley@arm.com } else { 127510259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "No instructions to commit\n"); 127610259SAndrew.Bardsley@arm.com completed_inst = false; 127710259SAndrew.Bardsley@arm.com } 127810259SAndrew.Bardsley@arm.com 127910259SAndrew.Bardsley@arm.com /* All discardable instructions must also be 'completed' by now */ 128010259SAndrew.Bardsley@arm.com assert(!(discard_inst && !completed_inst)); 128110259SAndrew.Bardsley@arm.com 128210259SAndrew.Bardsley@arm.com /* Instruction committed but was discarded due to streamSeqNum 128310259SAndrew.Bardsley@arm.com * mismatch */ 128410259SAndrew.Bardsley@arm.com if (discard_inst) { 128510259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Discarding inst: %s as its stream" 128610259SAndrew.Bardsley@arm.com " state was unexpected, expected: %d\n", 128710259SAndrew.Bardsley@arm.com *inst, streamSeqNum); 128810259SAndrew.Bardsley@arm.com 128910259SAndrew.Bardsley@arm.com if (fault == NoFault) 129010259SAndrew.Bardsley@arm.com cpu.stats.numDiscardedOps++; 129110259SAndrew.Bardsley@arm.com } 129210259SAndrew.Bardsley@arm.com 129310259SAndrew.Bardsley@arm.com /* Mark the mem inst as being in the LSQ */ 129410259SAndrew.Bardsley@arm.com if (issued_mem_ref) { 129510259SAndrew.Bardsley@arm.com inst->fuIndex = 0; 129610259SAndrew.Bardsley@arm.com inst->inLSQ = true; 129710259SAndrew.Bardsley@arm.com } 129810259SAndrew.Bardsley@arm.com 129910259SAndrew.Bardsley@arm.com /* Pop issued (to LSQ) and discarded mem refs from the inFUMemInsts 130010259SAndrew.Bardsley@arm.com * as they've *definitely* exited the FUs */ 130110259SAndrew.Bardsley@arm.com if (completed_inst && inst->isMemRef()) { 130210259SAndrew.Bardsley@arm.com /* The MemRef could have been discarded from the FU or the memory 130310259SAndrew.Bardsley@arm.com * queue, so just check an FU instruction */ 130410259SAndrew.Bardsley@arm.com if (!inFUMemInsts->empty() && 130510259SAndrew.Bardsley@arm.com inFUMemInsts->front().inst == inst) 130610259SAndrew.Bardsley@arm.com { 130710259SAndrew.Bardsley@arm.com inFUMemInsts->pop(); 130810259SAndrew.Bardsley@arm.com } 130910259SAndrew.Bardsley@arm.com } 131010259SAndrew.Bardsley@arm.com 131110259SAndrew.Bardsley@arm.com if (completed_inst && !(issued_mem_ref && fault == NoFault)) { 131210259SAndrew.Bardsley@arm.com /* Note that this includes discarded insts */ 131310259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Completed inst: %s\n", *inst); 131410259SAndrew.Bardsley@arm.com 131510259SAndrew.Bardsley@arm.com /* Got to the end of a full instruction? */ 131610259SAndrew.Bardsley@arm.com lastCommitWasEndOfMacroop = inst->isFault() || 131710259SAndrew.Bardsley@arm.com inst->isLastOpInInst(); 131810259SAndrew.Bardsley@arm.com 131910259SAndrew.Bardsley@arm.com /* lastPredictionSeqNum is kept as a convenience to prevent its 132010259SAndrew.Bardsley@arm.com * value from changing too much on the minorview display */ 132110259SAndrew.Bardsley@arm.com lastPredictionSeqNum = inst->id.predictionSeqNum; 132210259SAndrew.Bardsley@arm.com 132310259SAndrew.Bardsley@arm.com /* Finished with the inst, remove it from the inst queue and 132410259SAndrew.Bardsley@arm.com * clear its dependencies */ 132510259SAndrew.Bardsley@arm.com inFlightInsts->pop(); 132610259SAndrew.Bardsley@arm.com 132710259SAndrew.Bardsley@arm.com /* Complete barriers in the LSQ/move to store buffer */ 132810259SAndrew.Bardsley@arm.com if (inst->isInst() && inst->staticInst->isMemBarrier()) { 132910259SAndrew.Bardsley@arm.com DPRINTF(MinorMem, "Completing memory barrier" 133010259SAndrew.Bardsley@arm.com " inst: %s committed: %d\n", *inst, committed_inst); 133110259SAndrew.Bardsley@arm.com lsq.completeMemBarrierInst(inst, committed_inst); 133210259SAndrew.Bardsley@arm.com } 133310259SAndrew.Bardsley@arm.com 133410259SAndrew.Bardsley@arm.com scoreboard.clearInstDests(inst, inst->isMemRef()); 133510259SAndrew.Bardsley@arm.com } 133610259SAndrew.Bardsley@arm.com 133710259SAndrew.Bardsley@arm.com /* Handle per-cycle instruction counting */ 133810259SAndrew.Bardsley@arm.com if (committed_inst) { 133910259SAndrew.Bardsley@arm.com bool is_no_cost_inst = inst->isNoCostInst(); 134010259SAndrew.Bardsley@arm.com 134110259SAndrew.Bardsley@arm.com /* Don't show no cost instructions as having taken a commit 134210259SAndrew.Bardsley@arm.com * slot */ 134310259SAndrew.Bardsley@arm.com if (DTRACE(MinorTrace) && !is_no_cost_inst) 134410259SAndrew.Bardsley@arm.com instsBeingCommitted.insts[num_insts_committed] = inst; 134510259SAndrew.Bardsley@arm.com 134610259SAndrew.Bardsley@arm.com if (!is_no_cost_inst) 134710259SAndrew.Bardsley@arm.com num_insts_committed++; 134810259SAndrew.Bardsley@arm.com 134910259SAndrew.Bardsley@arm.com if (num_insts_committed == commitLimit) 135010259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Reached inst commit limit\n"); 135110259SAndrew.Bardsley@arm.com 135210259SAndrew.Bardsley@arm.com /* Re-set the time of the instruction if that's required for 135310259SAndrew.Bardsley@arm.com * tracing */ 135410259SAndrew.Bardsley@arm.com if (inst->traceData) { 135510259SAndrew.Bardsley@arm.com if (setTraceTimeOnCommit) 135610259SAndrew.Bardsley@arm.com inst->traceData->setWhen(curTick()); 135710259SAndrew.Bardsley@arm.com inst->traceData->dump(); 135810259SAndrew.Bardsley@arm.com } 135910259SAndrew.Bardsley@arm.com 136010259SAndrew.Bardsley@arm.com if (completed_mem_ref) 136110259SAndrew.Bardsley@arm.com num_mem_refs_committed++; 136210259SAndrew.Bardsley@arm.com 136310259SAndrew.Bardsley@arm.com if (num_mem_refs_committed == memoryCommitLimit) 136410259SAndrew.Bardsley@arm.com DPRINTF(MinorExecute, "Reached mem ref commit limit\n"); 136510259SAndrew.Bardsley@arm.com } 136610259SAndrew.Bardsley@arm.com } 136710259SAndrew.Bardsley@arm.com} 136810259SAndrew.Bardsley@arm.com 136910259SAndrew.Bardsley@arm.combool 137010259SAndrew.Bardsley@arm.comExecute::isInbetweenInsts() const 137110259SAndrew.Bardsley@arm.com{ 137210259SAndrew.Bardsley@arm.com return lastCommitWasEndOfMacroop && 137310259SAndrew.Bardsley@arm.com !lsq.accessesInFlight(); 137410259SAndrew.Bardsley@arm.com} 137510259SAndrew.Bardsley@arm.com 137610259SAndrew.Bardsley@arm.comvoid 137710259SAndrew.Bardsley@arm.comExecute::evaluate() 137810259SAndrew.Bardsley@arm.com{ 137910259SAndrew.Bardsley@arm.com inputBuffer.setTail(*inp.outputWire); 138010259SAndrew.Bardsley@arm.com BranchData &branch = *out.inputWire; 138110259SAndrew.Bardsley@arm.com 138210259SAndrew.Bardsley@arm.com const ForwardInstData *insts_in = getInput(); 138310259SAndrew.Bardsley@arm.com 138410259SAndrew.Bardsley@arm.com /* Do all the cycle-wise activities for dcachePort here to potentially 138510259SAndrew.Bardsley@arm.com * free up input spaces in the LSQ's requests queue */ 138610259SAndrew.Bardsley@arm.com lsq.step(); 138710259SAndrew.Bardsley@arm.com 138810259SAndrew.Bardsley@arm.com /* Has an interrupt been signalled? This may not be acted on 138910259SAndrew.Bardsley@arm.com * straighaway so this is different from took_interrupt below */ 139010259SAndrew.Bardsley@arm.com bool interrupted = false; 139110259SAndrew.Bardsley@arm.com /* If there was an interrupt signalled, was it acted on now? */ 139210259SAndrew.Bardsley@arm.com bool took_interrupt = false; 139310259SAndrew.Bardsley@arm.com 139410259SAndrew.Bardsley@arm.com if (cpu.getInterruptController()) { 139510259SAndrew.Bardsley@arm.com /* This is here because it seems that after drainResume the 139610259SAndrew.Bardsley@arm.com * interrupt controller isn't always set */ 139710259SAndrew.Bardsley@arm.com interrupted = drainState == NotDraining && isInterrupted(0); 139810259SAndrew.Bardsley@arm.com } else { 139910259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "No interrupt controller\n"); 140010259SAndrew.Bardsley@arm.com } 140110259SAndrew.Bardsley@arm.com 140210259SAndrew.Bardsley@arm.com unsigned int num_issued = 0; 140310259SAndrew.Bardsley@arm.com 140410259SAndrew.Bardsley@arm.com if (DTRACE(MinorTrace)) { 140510259SAndrew.Bardsley@arm.com /* Empty the instsBeingCommitted for MinorTrace */ 140610259SAndrew.Bardsley@arm.com instsBeingCommitted.bubbleFill(); 140710259SAndrew.Bardsley@arm.com } 140810259SAndrew.Bardsley@arm.com 140910259SAndrew.Bardsley@arm.com /* THREAD threadId on isInterrupted */ 141010259SAndrew.Bardsley@arm.com /* Act on interrupts */ 141110259SAndrew.Bardsley@arm.com if (interrupted && isInbetweenInsts()) { 141210259SAndrew.Bardsley@arm.com took_interrupt = takeInterrupt(0, branch); 141310259SAndrew.Bardsley@arm.com /* Clear interrupted if no interrupt was actually waiting */ 141410259SAndrew.Bardsley@arm.com interrupted = took_interrupt; 141510259SAndrew.Bardsley@arm.com } 141610259SAndrew.Bardsley@arm.com 141710259SAndrew.Bardsley@arm.com if (took_interrupt) { 141810259SAndrew.Bardsley@arm.com /* Do no commit/issue this cycle */ 141910259SAndrew.Bardsley@arm.com } else if (!branch.isBubble()) { 142010259SAndrew.Bardsley@arm.com /* It's important that this is here to carry Fetch1 wakeups to Fetch1 142110259SAndrew.Bardsley@arm.com * without overwriting them */ 142210259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Execute skipping a cycle to allow old" 142310259SAndrew.Bardsley@arm.com " branch to complete\n"); 142410259SAndrew.Bardsley@arm.com } else { 142510259SAndrew.Bardsley@arm.com if (interrupted) { 142610259SAndrew.Bardsley@arm.com if (inFlightInsts->empty()) { 142710259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Waiting but no insts\n"); 142810259SAndrew.Bardsley@arm.com } else { 142910259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Waiting for end of inst before" 143010259SAndrew.Bardsley@arm.com " signalling interrupt\n"); 143110259SAndrew.Bardsley@arm.com } 143210259SAndrew.Bardsley@arm.com } 143310259SAndrew.Bardsley@arm.com 143410259SAndrew.Bardsley@arm.com /* commit can set stalled flags observable to issue and so *must* be 143510259SAndrew.Bardsley@arm.com * called first */ 143610259SAndrew.Bardsley@arm.com if (drainState != NotDraining) { 143710259SAndrew.Bardsley@arm.com if (drainState == DrainCurrentInst) { 143810259SAndrew.Bardsley@arm.com /* Commit only micro-ops, don't kill anything else */ 143910259SAndrew.Bardsley@arm.com commit(true, false, branch); 144010259SAndrew.Bardsley@arm.com 144110259SAndrew.Bardsley@arm.com if (isInbetweenInsts()) 144210259SAndrew.Bardsley@arm.com setDrainState(DrainHaltFetch); 144310259SAndrew.Bardsley@arm.com 144410259SAndrew.Bardsley@arm.com /* Discard any generated branch */ 144510259SAndrew.Bardsley@arm.com branch = BranchData::bubble(); 144610259SAndrew.Bardsley@arm.com } else if (drainState == DrainAllInsts) { 144710259SAndrew.Bardsley@arm.com /* Kill all instructions */ 144810259SAndrew.Bardsley@arm.com while (getInput()) 144910259SAndrew.Bardsley@arm.com popInput(); 145010259SAndrew.Bardsley@arm.com commit(false, true, branch); 145110259SAndrew.Bardsley@arm.com } 145210259SAndrew.Bardsley@arm.com } else { 145310259SAndrew.Bardsley@arm.com /* Commit micro-ops only if interrupted. Otherwise, commit 145410259SAndrew.Bardsley@arm.com * anything you like */ 145510259SAndrew.Bardsley@arm.com commit(interrupted, false, branch); 145610259SAndrew.Bardsley@arm.com } 145710259SAndrew.Bardsley@arm.com 145810259SAndrew.Bardsley@arm.com /* This will issue merrily even when interrupted in the sure and 145910259SAndrew.Bardsley@arm.com * certain knowledge that the interrupt with change the stream */ 146010259SAndrew.Bardsley@arm.com if (insts_in) 146110259SAndrew.Bardsley@arm.com num_issued = issue(false); 146210259SAndrew.Bardsley@arm.com } 146310259SAndrew.Bardsley@arm.com 146410259SAndrew.Bardsley@arm.com /* Halt fetch, but don't do it until we have the current instruction in 146510259SAndrew.Bardsley@arm.com * the bag */ 146610259SAndrew.Bardsley@arm.com if (drainState == DrainHaltFetch) { 146710259SAndrew.Bardsley@arm.com updateBranchData(BranchData::HaltFetch, MinorDynInst::bubble(), 146810259SAndrew.Bardsley@arm.com TheISA::PCState(0), branch); 146910259SAndrew.Bardsley@arm.com 147010259SAndrew.Bardsley@arm.com cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 147110259SAndrew.Bardsley@arm.com setDrainState(DrainAllInsts); 147210259SAndrew.Bardsley@arm.com } 147310259SAndrew.Bardsley@arm.com 147410259SAndrew.Bardsley@arm.com MinorDynInstPtr next_issuable_inst = NULL; 147510259SAndrew.Bardsley@arm.com bool can_issue_next = false; 147610259SAndrew.Bardsley@arm.com 147710259SAndrew.Bardsley@arm.com /* Find the next issuable instruction and see if it can be issued */ 147810259SAndrew.Bardsley@arm.com if (getInput()) { 147910259SAndrew.Bardsley@arm.com MinorDynInstPtr inst = getInput()->insts[inputIndex]; 148010259SAndrew.Bardsley@arm.com 148110259SAndrew.Bardsley@arm.com if (inst->isFault()) { 148210259SAndrew.Bardsley@arm.com can_issue_next = true; 148310259SAndrew.Bardsley@arm.com } else if (!inst->isBubble()) { 148410259SAndrew.Bardsley@arm.com if (cpu.getContext(inst->id.threadId)->status() != 148510259SAndrew.Bardsley@arm.com ThreadContext::Suspended) 148610259SAndrew.Bardsley@arm.com { 148710259SAndrew.Bardsley@arm.com next_issuable_inst = inst; 148810259SAndrew.Bardsley@arm.com } 148910259SAndrew.Bardsley@arm.com } 149010259SAndrew.Bardsley@arm.com } 149110259SAndrew.Bardsley@arm.com 149210259SAndrew.Bardsley@arm.com bool becoming_stalled = true; 149310259SAndrew.Bardsley@arm.com 149410259SAndrew.Bardsley@arm.com /* Advance the pipelines and note whether they still need to be 149510259SAndrew.Bardsley@arm.com * advanced */ 149610259SAndrew.Bardsley@arm.com for (unsigned int i = 0; i < numFuncUnits; i++) { 149710259SAndrew.Bardsley@arm.com FUPipeline *fu = funcUnits[i]; 149810259SAndrew.Bardsley@arm.com 149910259SAndrew.Bardsley@arm.com fu->advance(); 150010259SAndrew.Bardsley@arm.com 150110259SAndrew.Bardsley@arm.com /* If we need to go again, the pipeline will have been left or set 150210259SAndrew.Bardsley@arm.com * to be unstalled */ 150310259SAndrew.Bardsley@arm.com if (fu->occupancy != 0 && !fu->stalled) 150410259SAndrew.Bardsley@arm.com becoming_stalled = false; 150510259SAndrew.Bardsley@arm.com 150610259SAndrew.Bardsley@arm.com /* Could we possibly issue the next instruction? This is quite 150710259SAndrew.Bardsley@arm.com * an expensive test */ 150810259SAndrew.Bardsley@arm.com if (next_issuable_inst && !fu->stalled && 150910259SAndrew.Bardsley@arm.com scoreboard.canInstIssue(next_issuable_inst, 151010259SAndrew.Bardsley@arm.com NULL, NULL, cpu.curCycle() + Cycles(1), 151110259SAndrew.Bardsley@arm.com cpu.getContext(next_issuable_inst->id.threadId)) && 151210259SAndrew.Bardsley@arm.com fu->provides(next_issuable_inst->staticInst->opClass())) 151310259SAndrew.Bardsley@arm.com { 151410259SAndrew.Bardsley@arm.com can_issue_next = true; 151510259SAndrew.Bardsley@arm.com } 151610259SAndrew.Bardsley@arm.com } 151710259SAndrew.Bardsley@arm.com 151810259SAndrew.Bardsley@arm.com bool head_inst_might_commit = false; 151910259SAndrew.Bardsley@arm.com 152010259SAndrew.Bardsley@arm.com /* Could the head in flight insts be committed */ 152110259SAndrew.Bardsley@arm.com if (!inFlightInsts->empty()) { 152210259SAndrew.Bardsley@arm.com const QueuedInst &head_inst = inFlightInsts->front(); 152310259SAndrew.Bardsley@arm.com 152410259SAndrew.Bardsley@arm.com if (head_inst.inst->isNoCostInst()) { 152510259SAndrew.Bardsley@arm.com head_inst_might_commit = true; 152610259SAndrew.Bardsley@arm.com } else { 152710259SAndrew.Bardsley@arm.com FUPipeline *fu = funcUnits[head_inst.inst->fuIndex]; 152810259SAndrew.Bardsley@arm.com 152910259SAndrew.Bardsley@arm.com /* Head inst is commitable */ 153010259SAndrew.Bardsley@arm.com if ((fu->stalled && 153110259SAndrew.Bardsley@arm.com fu->front().inst->id == head_inst.inst->id) || 153210259SAndrew.Bardsley@arm.com lsq.findResponse(head_inst.inst)) 153310259SAndrew.Bardsley@arm.com { 153410259SAndrew.Bardsley@arm.com head_inst_might_commit = true; 153510259SAndrew.Bardsley@arm.com } 153610259SAndrew.Bardsley@arm.com } 153710259SAndrew.Bardsley@arm.com } 153810259SAndrew.Bardsley@arm.com 153910259SAndrew.Bardsley@arm.com DPRINTF(Activity, "Need to tick num issued insts: %s%s%s%s%s%s\n", 154010259SAndrew.Bardsley@arm.com (num_issued != 0 ? " (issued some insts)" : ""), 154110259SAndrew.Bardsley@arm.com (becoming_stalled ? " (becoming stalled)" : "(not becoming stalled)"), 154210259SAndrew.Bardsley@arm.com (can_issue_next ? " (can issued next inst)" : ""), 154310259SAndrew.Bardsley@arm.com (head_inst_might_commit ? "(head inst might commit)" : ""), 154410259SAndrew.Bardsley@arm.com (lsq.needsToTick() ? " (LSQ needs to tick)" : ""), 154510259SAndrew.Bardsley@arm.com (interrupted ? " (interrupted)" : "")); 154610259SAndrew.Bardsley@arm.com 154710259SAndrew.Bardsley@arm.com bool need_to_tick = 154810259SAndrew.Bardsley@arm.com num_issued != 0 || /* Issued some insts this cycle */ 154910259SAndrew.Bardsley@arm.com !becoming_stalled || /* Some FU pipelines can still move */ 155010259SAndrew.Bardsley@arm.com can_issue_next || /* Can still issue a new inst */ 155110259SAndrew.Bardsley@arm.com head_inst_might_commit || /* Could possible commit the next inst */ 155210259SAndrew.Bardsley@arm.com lsq.needsToTick() || /* Must step the dcache port */ 155310259SAndrew.Bardsley@arm.com interrupted; /* There are pending interrupts */ 155410259SAndrew.Bardsley@arm.com 155510259SAndrew.Bardsley@arm.com if (!need_to_tick) { 155610259SAndrew.Bardsley@arm.com DPRINTF(Activity, "The next cycle might be skippable as there are no" 155710259SAndrew.Bardsley@arm.com " advanceable FUs\n"); 155810259SAndrew.Bardsley@arm.com } 155910259SAndrew.Bardsley@arm.com 156010259SAndrew.Bardsley@arm.com /* Wake up if we need to tick again */ 156110259SAndrew.Bardsley@arm.com if (need_to_tick) 156210259SAndrew.Bardsley@arm.com cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 156310259SAndrew.Bardsley@arm.com 156410259SAndrew.Bardsley@arm.com /* Note activity of following buffer */ 156510259SAndrew.Bardsley@arm.com if (!branch.isBubble()) 156610259SAndrew.Bardsley@arm.com cpu.activityRecorder->activity(); 156710259SAndrew.Bardsley@arm.com 156810259SAndrew.Bardsley@arm.com /* Make sure the input (if any left) is pushed */ 156910259SAndrew.Bardsley@arm.com inputBuffer.pushTail(); 157010259SAndrew.Bardsley@arm.com} 157110259SAndrew.Bardsley@arm.com 157210259SAndrew.Bardsley@arm.comvoid 157310259SAndrew.Bardsley@arm.comExecute::wakeupFetch(BranchData::Reason reason) 157410259SAndrew.Bardsley@arm.com{ 157510259SAndrew.Bardsley@arm.com BranchData branch; 157610259SAndrew.Bardsley@arm.com assert(branch.isBubble()); 157710259SAndrew.Bardsley@arm.com 157810259SAndrew.Bardsley@arm.com /* THREAD thread id */ 157910259SAndrew.Bardsley@arm.com ThreadContext *thread = cpu.getContext(0); 158010259SAndrew.Bardsley@arm.com 158110259SAndrew.Bardsley@arm.com /* Force a branch to the current PC (which should be the next inst.) to 158210259SAndrew.Bardsley@arm.com * wake up Fetch1 */ 158310259SAndrew.Bardsley@arm.com if (!branch.isStreamChange() /* No real branch already happened */) { 158410259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Waking up Fetch (via Execute) by issuing" 158510259SAndrew.Bardsley@arm.com " a branch: %s\n", thread->pcState()); 158610259SAndrew.Bardsley@arm.com 158710259SAndrew.Bardsley@arm.com assert(thread->pcState().microPC() == 0); 158810259SAndrew.Bardsley@arm.com 158910259SAndrew.Bardsley@arm.com updateBranchData(reason, 159010259SAndrew.Bardsley@arm.com MinorDynInst::bubble(), thread->pcState(), branch); 159110259SAndrew.Bardsley@arm.com } else { 159210259SAndrew.Bardsley@arm.com DPRINTF(MinorInterrupt, "Already branching, no need for wakeup\n"); 159310259SAndrew.Bardsley@arm.com } 159410259SAndrew.Bardsley@arm.com 159510259SAndrew.Bardsley@arm.com *out.inputWire = branch; 159610259SAndrew.Bardsley@arm.com 159710259SAndrew.Bardsley@arm.com /* Make sure we get ticked */ 159810259SAndrew.Bardsley@arm.com cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 159910259SAndrew.Bardsley@arm.com} 160010259SAndrew.Bardsley@arm.com 160110259SAndrew.Bardsley@arm.comvoid 160210259SAndrew.Bardsley@arm.comExecute::minorTrace() const 160310259SAndrew.Bardsley@arm.com{ 160410259SAndrew.Bardsley@arm.com std::ostringstream insts; 160510259SAndrew.Bardsley@arm.com std::ostringstream stalled; 160610259SAndrew.Bardsley@arm.com 160710259SAndrew.Bardsley@arm.com instsBeingCommitted.reportData(insts); 160810259SAndrew.Bardsley@arm.com lsq.minorTrace(); 160910259SAndrew.Bardsley@arm.com inputBuffer.minorTrace(); 161010259SAndrew.Bardsley@arm.com scoreboard.minorTrace(); 161110259SAndrew.Bardsley@arm.com 161210259SAndrew.Bardsley@arm.com /* Report functional unit stalling in one string */ 161310259SAndrew.Bardsley@arm.com unsigned int i = 0; 161410259SAndrew.Bardsley@arm.com while (i < numFuncUnits) 161510259SAndrew.Bardsley@arm.com { 161610259SAndrew.Bardsley@arm.com stalled << (funcUnits[i]->stalled ? '1' : 'E'); 161710259SAndrew.Bardsley@arm.com i++; 161810259SAndrew.Bardsley@arm.com if (i != numFuncUnits) 161910259SAndrew.Bardsley@arm.com stalled << ','; 162010259SAndrew.Bardsley@arm.com } 162110259SAndrew.Bardsley@arm.com 162210259SAndrew.Bardsley@arm.com MINORTRACE("insts=%s inputIndex=%d streamSeqNum=%d" 162310259SAndrew.Bardsley@arm.com " stalled=%s drainState=%d isInbetweenInsts=%d\n", 162410259SAndrew.Bardsley@arm.com insts.str(), inputIndex, streamSeqNum, stalled.str(), drainState, 162510259SAndrew.Bardsley@arm.com isInbetweenInsts()); 162610259SAndrew.Bardsley@arm.com 162710259SAndrew.Bardsley@arm.com std::for_each(funcUnits.begin(), funcUnits.end(), 162810259SAndrew.Bardsley@arm.com std::mem_fun(&FUPipeline::minorTrace)); 162910259SAndrew.Bardsley@arm.com 163010259SAndrew.Bardsley@arm.com inFlightInsts->minorTrace(); 163110259SAndrew.Bardsley@arm.com inFUMemInsts->minorTrace(); 163210259SAndrew.Bardsley@arm.com} 163310259SAndrew.Bardsley@arm.com 163410259SAndrew.Bardsley@arm.comvoid 163510259SAndrew.Bardsley@arm.comExecute::drainResume() 163610259SAndrew.Bardsley@arm.com{ 163710259SAndrew.Bardsley@arm.com DPRINTF(Drain, "MinorExecute drainResume\n"); 163810259SAndrew.Bardsley@arm.com 163910259SAndrew.Bardsley@arm.com setDrainState(NotDraining); 164010259SAndrew.Bardsley@arm.com 164110259SAndrew.Bardsley@arm.com /* Wakeup fetch and keep the pipeline running until that branch takes 164210259SAndrew.Bardsley@arm.com * effect */ 164310259SAndrew.Bardsley@arm.com wakeupFetch(BranchData::WakeupFetch); 164410259SAndrew.Bardsley@arm.com cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 164510259SAndrew.Bardsley@arm.com} 164610259SAndrew.Bardsley@arm.com 164710259SAndrew.Bardsley@arm.comstd::ostream &operator <<(std::ostream &os, Execute::DrainState state) 164810259SAndrew.Bardsley@arm.com{ 164910259SAndrew.Bardsley@arm.com switch (state) 165010259SAndrew.Bardsley@arm.com { 165110259SAndrew.Bardsley@arm.com case Execute::NotDraining: 165210259SAndrew.Bardsley@arm.com os << "NotDraining"; 165310259SAndrew.Bardsley@arm.com break; 165410259SAndrew.Bardsley@arm.com case Execute::DrainCurrentInst: 165510259SAndrew.Bardsley@arm.com os << "DrainCurrentInst"; 165610259SAndrew.Bardsley@arm.com break; 165710259SAndrew.Bardsley@arm.com case Execute::DrainHaltFetch: 165810259SAndrew.Bardsley@arm.com os << "DrainHaltFetch"; 165910259SAndrew.Bardsley@arm.com break; 166010259SAndrew.Bardsley@arm.com case Execute::DrainAllInsts: 166110259SAndrew.Bardsley@arm.com os << "DrainAllInsts"; 166210259SAndrew.Bardsley@arm.com break; 166310259SAndrew.Bardsley@arm.com default: 166410259SAndrew.Bardsley@arm.com os << "Drain-" << static_cast<int>(state); 166510259SAndrew.Bardsley@arm.com break; 166610259SAndrew.Bardsley@arm.com } 166710259SAndrew.Bardsley@arm.com 166810259SAndrew.Bardsley@arm.com return os; 166910259SAndrew.Bardsley@arm.com} 167010259SAndrew.Bardsley@arm.com 167110259SAndrew.Bardsley@arm.comvoid 167210259SAndrew.Bardsley@arm.comExecute::setDrainState(DrainState state) 167310259SAndrew.Bardsley@arm.com{ 167410259SAndrew.Bardsley@arm.com DPRINTF(Drain, "setDrainState: %s\n", state); 167510259SAndrew.Bardsley@arm.com drainState = state; 167610259SAndrew.Bardsley@arm.com} 167710259SAndrew.Bardsley@arm.com 167810259SAndrew.Bardsley@arm.comunsigned int 167910259SAndrew.Bardsley@arm.comExecute::drain() 168010259SAndrew.Bardsley@arm.com{ 168110259SAndrew.Bardsley@arm.com DPRINTF(Drain, "MinorExecute drain\n"); 168210259SAndrew.Bardsley@arm.com 168310259SAndrew.Bardsley@arm.com if (drainState == NotDraining) { 168410259SAndrew.Bardsley@arm.com cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 168510259SAndrew.Bardsley@arm.com 168610527Slukefahr@umich.edu /* Go to DrainCurrentInst if we're between microops 168710527Slukefahr@umich.edu * or waiting on an unbufferable memory operation. 168810527Slukefahr@umich.edu * Otherwise we can go straight to DrainHaltFetch 168910527Slukefahr@umich.edu */ 169010527Slukefahr@umich.edu if (isInbetweenInsts()) 169110259SAndrew.Bardsley@arm.com setDrainState(DrainHaltFetch); 169210259SAndrew.Bardsley@arm.com else 169310259SAndrew.Bardsley@arm.com setDrainState(DrainCurrentInst); 169410259SAndrew.Bardsley@arm.com } 169510259SAndrew.Bardsley@arm.com 169610259SAndrew.Bardsley@arm.com return (isDrained() ? 0 : 1); 169710259SAndrew.Bardsley@arm.com} 169810259SAndrew.Bardsley@arm.com 169910259SAndrew.Bardsley@arm.combool 170010259SAndrew.Bardsley@arm.comExecute::isDrained() 170110259SAndrew.Bardsley@arm.com{ 170210259SAndrew.Bardsley@arm.com return drainState == DrainAllInsts && 170310259SAndrew.Bardsley@arm.com inputBuffer.empty() && 170410259SAndrew.Bardsley@arm.com inFlightInsts->empty() && 170510259SAndrew.Bardsley@arm.com lsq.isDrained(); 170610259SAndrew.Bardsley@arm.com} 170710259SAndrew.Bardsley@arm.com 170810259SAndrew.Bardsley@arm.comExecute::~Execute() 170910259SAndrew.Bardsley@arm.com{ 171010259SAndrew.Bardsley@arm.com for (unsigned int i = 0; i < numFuncUnits; i++) 171110259SAndrew.Bardsley@arm.com delete funcUnits[i]; 171210259SAndrew.Bardsley@arm.com 171310259SAndrew.Bardsley@arm.com delete inFlightInsts; 171410259SAndrew.Bardsley@arm.com} 171510259SAndrew.Bardsley@arm.com 171610259SAndrew.Bardsley@arm.combool 171710259SAndrew.Bardsley@arm.comExecute::instIsRightStream(MinorDynInstPtr inst) 171810259SAndrew.Bardsley@arm.com{ 171910259SAndrew.Bardsley@arm.com return inst->id.streamSeqNum == streamSeqNum; 172010259SAndrew.Bardsley@arm.com} 172110259SAndrew.Bardsley@arm.com 172210259SAndrew.Bardsley@arm.combool 172310259SAndrew.Bardsley@arm.comExecute::instIsHeadInst(MinorDynInstPtr inst) 172410259SAndrew.Bardsley@arm.com{ 172510259SAndrew.Bardsley@arm.com bool ret = false; 172610259SAndrew.Bardsley@arm.com 172710259SAndrew.Bardsley@arm.com if (!inFlightInsts->empty()) 172810259SAndrew.Bardsley@arm.com ret = inFlightInsts->front().inst->id == inst->id; 172910259SAndrew.Bardsley@arm.com 173010259SAndrew.Bardsley@arm.com return ret; 173110259SAndrew.Bardsley@arm.com} 173210259SAndrew.Bardsley@arm.com 173310259SAndrew.Bardsley@arm.comMinorCPU::MinorCPUPort & 173410259SAndrew.Bardsley@arm.comExecute::getDcachePort() 173510259SAndrew.Bardsley@arm.com{ 173610259SAndrew.Bardsley@arm.com return lsq.getDcachePort(); 173710259SAndrew.Bardsley@arm.com} 173810259SAndrew.Bardsley@arm.com 173910259SAndrew.Bardsley@arm.com} 1740