execute.cc revision 13964
19883Sandreas@sandberg.pp.se/* 29883Sandreas@sandberg.pp.se * Copyright (c) 2013-2014,2018 ARM Limited 39883Sandreas@sandberg.pp.se * All rights reserved 49883Sandreas@sandberg.pp.se * 59883Sandreas@sandberg.pp.se * The license below extends only to copyright in the software and shall 69883Sandreas@sandberg.pp.se * not be construed as granting a license to any other intellectual 79883Sandreas@sandberg.pp.se * property including but not limited to intellectual property relating 89883Sandreas@sandberg.pp.se * to a hardware implementation of the functionality of the software 99883Sandreas@sandberg.pp.se * licensed hereunder. You may use the software subject to the license 109883Sandreas@sandberg.pp.se * terms below provided that you ensure that this notice is replicated 119883Sandreas@sandberg.pp.se * unmodified and in its entirety in all distributions of the software, 129883Sandreas@sandberg.pp.se * modified or unmodified, in source code or in binary form. 139883Sandreas@sandberg.pp.se * 149883Sandreas@sandberg.pp.se * Redistribution and use in source and binary forms, with or without 159883Sandreas@sandberg.pp.se * modification, are permitted provided that the following conditions are 169883Sandreas@sandberg.pp.se * met: redistributions of source code must retain the above copyright 179883Sandreas@sandberg.pp.se * notice, this list of conditions and the following disclaimer; 189883Sandreas@sandberg.pp.se * redistributions in binary form must reproduce the above copyright 199883Sandreas@sandberg.pp.se * notice, this list of conditions and the following disclaimer in the 209883Sandreas@sandberg.pp.se * documentation and/or other materials provided with the distribution; 219883Sandreas@sandberg.pp.se * neither the name of the copyright holders nor the names of its 229883Sandreas@sandberg.pp.se * contributors may be used to endorse or promote products derived from 239883Sandreas@sandberg.pp.se * this software without specific prior written permission. 249883Sandreas@sandberg.pp.se * 259883Sandreas@sandberg.pp.se * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 269883Sandreas@sandberg.pp.se * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 279883Sandreas@sandberg.pp.se * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 289883Sandreas@sandberg.pp.se * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 299883Sandreas@sandberg.pp.se * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 309883Sandreas@sandberg.pp.se * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3111793Sbrandon.potter@amd.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3211793Sbrandon.potter@amd.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 339883Sandreas@sandberg.pp.se * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 349883Sandreas@sandberg.pp.se * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 359883Sandreas@sandberg.pp.se * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 369883Sandreas@sandberg.pp.se * 379883Sandreas@sandberg.pp.se * Authors: Andrew Bardsley 389883Sandreas@sandberg.pp.se */ 3911793Sbrandon.potter@amd.com 4011793Sbrandon.potter@amd.com#include "cpu/minor/execute.hh" 419883Sandreas@sandberg.pp.se 429883Sandreas@sandberg.pp.se#include "arch/locked_mem.hh" 439883Sandreas@sandberg.pp.se#include "arch/registers.hh" 449883Sandreas@sandberg.pp.se#include "arch/utility.hh" 459883Sandreas@sandberg.pp.se#include "cpu/minor/cpu.hh" 469883Sandreas@sandberg.pp.se#include "cpu/minor/exec_context.hh" 479883Sandreas@sandberg.pp.se#include "cpu/minor/fetch1.hh" 489883Sandreas@sandberg.pp.se#include "cpu/minor/lsq.hh" 499883Sandreas@sandberg.pp.se#include "cpu/op_class.hh" 509883Sandreas@sandberg.pp.se#include "debug/Activity.hh" 519883Sandreas@sandberg.pp.se#include "debug/Branch.hh" 529883Sandreas@sandberg.pp.se#include "debug/Drain.hh" 539883Sandreas@sandberg.pp.se#include "debug/MinorExecute.hh" 549883Sandreas@sandberg.pp.se#include "debug/MinorInterrupt.hh" 559883Sandreas@sandberg.pp.se#include "debug/MinorMem.hh" 569883Sandreas@sandberg.pp.se#include "debug/MinorTrace.hh" 579886Sandreas@sandberg.pp.se#include "debug/PCEvent.hh" 589886Sandreas@sandberg.pp.se 599886Sandreas@sandberg.pp.senamespace Minor 609886Sandreas@sandberg.pp.se{ 619886Sandreas@sandberg.pp.se 629886Sandreas@sandberg.pp.seExecute::Execute(const std::string &name_, 639886Sandreas@sandberg.pp.se MinorCPU &cpu_, 649886Sandreas@sandberg.pp.se MinorCPUParams ¶ms, 659886Sandreas@sandberg.pp.se Latch<ForwardInstData>::Output inp_, 669886Sandreas@sandberg.pp.se Latch<BranchData>::Input out_) : 679886Sandreas@sandberg.pp.se Named(name_), 689886Sandreas@sandberg.pp.se inp(inp_), 699886Sandreas@sandberg.pp.se out(out_), 709886Sandreas@sandberg.pp.se cpu(cpu_), 719890Sandreas@sandberg.pp.se issueLimit(params.executeIssueLimit), 729890Sandreas@sandberg.pp.se memoryIssueLimit(params.executeMemoryIssueLimit), 739890Sandreas@sandberg.pp.se commitLimit(params.executeCommitLimit), 749890Sandreas@sandberg.pp.se memoryCommitLimit(params.executeMemoryCommitLimit), 759890Sandreas@sandberg.pp.se processMoreThanOneInput(params.executeCycleInput), 769890Sandreas@sandberg.pp.se fuDescriptions(*params.executeFuncUnits), 779890Sandreas@sandberg.pp.se numFuncUnits(fuDescriptions.funcUnits.size()), 789890Sandreas@sandberg.pp.se setTraceTimeOnCommit(params.executeSetTraceTimeOnCommit), 799890Sandreas@sandberg.pp.se setTraceTimeOnIssue(params.executeSetTraceTimeOnIssue), 809890Sandreas@sandberg.pp.se allowEarlyMemIssue(params.executeAllowEarlyMemoryIssue), 819890Sandreas@sandberg.pp.se noCostFUIndex(fuDescriptions.funcUnits.size() + 1), 829890Sandreas@sandberg.pp.se lsq(name_ + ".lsq", name_ + ".dcache_port", 839890Sandreas@sandberg.pp.se cpu_, *this, 849890Sandreas@sandberg.pp.se params.executeMaxAccessesInMemory, 859890Sandreas@sandberg.pp.se params.executeMemoryWidth, 869890Sandreas@sandberg.pp.se params.executeLSQRequestsQueueSize, 879890Sandreas@sandberg.pp.se params.executeLSQTransfersQueueSize, 889890Sandreas@sandberg.pp.se params.executeLSQStoreBufferSize, 899890Sandreas@sandberg.pp.se params.executeLSQMaxStoreBufferStoresPerCycle), 909890Sandreas@sandberg.pp.se executeInfo(params.numThreads, ExecuteThreadInfo(params.executeCommitLimit)), 919890Sandreas@sandberg.pp.se interruptPriority(0), 929890Sandreas@sandberg.pp.se issuePriority(0), 939890Sandreas@sandberg.pp.se commitPriority(0) 949890Sandreas@sandberg.pp.se{ 959890Sandreas@sandberg.pp.se if (commitLimit < 1) { 969890Sandreas@sandberg.pp.se fatal("%s: executeCommitLimit must be >= 1 (%d)\n", name_, 979890Sandreas@sandberg.pp.se commitLimit); 989890Sandreas@sandberg.pp.se } 999890Sandreas@sandberg.pp.se 1009890Sandreas@sandberg.pp.se if (issueLimit < 1) { 1019890Sandreas@sandberg.pp.se fatal("%s: executeCommitLimit must be >= 1 (%d)\n", name_, 1029890Sandreas@sandberg.pp.se issueLimit); 1039886Sandreas@sandberg.pp.se } 1049883Sandreas@sandberg.pp.se 1059883Sandreas@sandberg.pp.se if (memoryIssueLimit < 1) { 1069883Sandreas@sandberg.pp.se fatal("%s: executeMemoryIssueLimit must be >= 1 (%d)\n", name_, 1079883Sandreas@sandberg.pp.se memoryIssueLimit); 1089883Sandreas@sandberg.pp.se } 1099883Sandreas@sandberg.pp.se 1109883Sandreas@sandberg.pp.se if (memoryCommitLimit > commitLimit) { 1119883Sandreas@sandberg.pp.se fatal("%s: executeMemoryCommitLimit (%d) must be <=" 1129883Sandreas@sandberg.pp.se " executeCommitLimit (%d)\n", 1139883Sandreas@sandberg.pp.se name_, memoryCommitLimit, commitLimit); 1149883Sandreas@sandberg.pp.se } 1159883Sandreas@sandberg.pp.se 1169883Sandreas@sandberg.pp.se if (params.executeInputBufferSize < 1) { 1179883Sandreas@sandberg.pp.se fatal("%s: executeInputBufferSize must be >= 1 (%d)\n", name_, 1189883Sandreas@sandberg.pp.se params.executeInputBufferSize); 1199883Sandreas@sandberg.pp.se } 1209883Sandreas@sandberg.pp.se 1219883Sandreas@sandberg.pp.se if (params.executeInputBufferSize < 1) { 12211321Ssteve.reinhardt@amd.com fatal("%s: executeInputBufferSize must be >= 1 (%d)\n", name_, 1239883Sandreas@sandberg.pp.se params.executeInputBufferSize); 1249883Sandreas@sandberg.pp.se } 1259883Sandreas@sandberg.pp.se 1269883Sandreas@sandberg.pp.se /* This should be large enough to count all the in-FU instructions 1279883Sandreas@sandberg.pp.se * which need to be accounted for in the inFlightInsts 1289883Sandreas@sandberg.pp.se * queue */ 1299883Sandreas@sandberg.pp.se unsigned int total_slots = 0; 1309883Sandreas@sandberg.pp.se 1319883Sandreas@sandberg.pp.se /* Make FUPipelines for each MinorFU */ 1329883Sandreas@sandberg.pp.se for (unsigned int i = 0; i < numFuncUnits; i++) { 13311321Ssteve.reinhardt@amd.com std::ostringstream fu_name; 1349883Sandreas@sandberg.pp.se MinorFU *fu_description = fuDescriptions.funcUnits[i]; 1359883Sandreas@sandberg.pp.se 1369883Sandreas@sandberg.pp.se /* Note the total number of instruction slots (for sizing 1379883Sandreas@sandberg.pp.se * the inFlightInst queue) and the maximum latency of any FU 1389883Sandreas@sandberg.pp.se * (for sizing the activity recorder) */ 1399883Sandreas@sandberg.pp.se total_slots += fu_description->opLat; 1409883Sandreas@sandberg.pp.se 1419883Sandreas@sandberg.pp.se fu_name << name_ << ".fu." << i; 1429883Sandreas@sandberg.pp.se 14311321Ssteve.reinhardt@amd.com FUPipeline *fu = new FUPipeline(fu_name.str(), *fu_description, cpu); 1449883Sandreas@sandberg.pp.se 1459883Sandreas@sandberg.pp.se funcUnits.push_back(fu); 1469883Sandreas@sandberg.pp.se } 1479883Sandreas@sandberg.pp.se 1489883Sandreas@sandberg.pp.se /** Check that there is a functional unit for all operation classes */ 1499883Sandreas@sandberg.pp.se for (int op_class = No_OpClass + 1; op_class < Num_OpClasses; op_class++) { 1509883Sandreas@sandberg.pp.se bool found_fu = false; 1519883Sandreas@sandberg.pp.se unsigned int fu_index = 0; 1529883Sandreas@sandberg.pp.se 1539883Sandreas@sandberg.pp.se while (fu_index < numFuncUnits && !found_fu) 1549883Sandreas@sandberg.pp.se { 15511321Ssteve.reinhardt@amd.com if (funcUnits[fu_index]->provides( 1569883Sandreas@sandberg.pp.se static_cast<OpClass>(op_class))) 1579883Sandreas@sandberg.pp.se { 1589883Sandreas@sandberg.pp.se found_fu = true; 1599883Sandreas@sandberg.pp.se } 1609883Sandreas@sandberg.pp.se fu_index++; 16111321Ssteve.reinhardt@amd.com } 1629883Sandreas@sandberg.pp.se 1639883Sandreas@sandberg.pp.se if (!found_fu) { 1649883Sandreas@sandberg.pp.se warn("No functional unit for OpClass %s\n", 1659883Sandreas@sandberg.pp.se Enums::OpClassStrings[op_class]); 1669883Sandreas@sandberg.pp.se } 1679883Sandreas@sandberg.pp.se } 1689883Sandreas@sandberg.pp.se 1699883Sandreas@sandberg.pp.se /* Per-thread structures */ 1709883Sandreas@sandberg.pp.se for (ThreadID tid = 0; tid < params.numThreads; tid++) { 1719883Sandreas@sandberg.pp.se std::string tid_str = std::to_string(tid); 1729883Sandreas@sandberg.pp.se 1739883Sandreas@sandberg.pp.se /* Input Buffers */ 1749883Sandreas@sandberg.pp.se inputBuffer.push_back( 1759883Sandreas@sandberg.pp.se InputBuffer<ForwardInstData>( 1769883Sandreas@sandberg.pp.se name_ + ".inputBuffer" + tid_str, "insts", 1779883Sandreas@sandberg.pp.se params.executeInputBufferSize)); 1789883Sandreas@sandberg.pp.se 1799883Sandreas@sandberg.pp.se /* Scoreboards */ 1809883Sandreas@sandberg.pp.se scoreboard.push_back(Scoreboard(name_ + ".scoreboard" + tid_str)); 1819883Sandreas@sandberg.pp.se 1829883Sandreas@sandberg.pp.se /* In-flight instruction records */ 1839883Sandreas@sandberg.pp.se executeInfo[tid].inFlightInsts = new Queue<QueuedInst, 1849883Sandreas@sandberg.pp.se ReportTraitsAdaptor<QueuedInst> >( 1859883Sandreas@sandberg.pp.se name_ + ".inFlightInsts" + tid_str, "insts", total_slots); 1869883Sandreas@sandberg.pp.se 1879883Sandreas@sandberg.pp.se executeInfo[tid].inFUMemInsts = new Queue<QueuedInst, 1889883Sandreas@sandberg.pp.se ReportTraitsAdaptor<QueuedInst> >( 1899883Sandreas@sandberg.pp.se name_ + ".inFUMemInsts" + tid_str, "insts", total_slots); 1909883Sandreas@sandberg.pp.se } 1919883Sandreas@sandberg.pp.se} 1929883Sandreas@sandberg.pp.se 1939883Sandreas@sandberg.pp.seconst ForwardInstData * 1949883Sandreas@sandberg.pp.seExecute::getInput(ThreadID tid) 1959883Sandreas@sandberg.pp.se{ 1969883Sandreas@sandberg.pp.se /* Get a line from the inputBuffer to work with */ 1979883Sandreas@sandberg.pp.se if (!inputBuffer[tid].empty()) { 1989883Sandreas@sandberg.pp.se const ForwardInstData &head = inputBuffer[tid].front(); 1999883Sandreas@sandberg.pp.se 2009883Sandreas@sandberg.pp.se return (head.isBubble() ? NULL : &(inputBuffer[tid].front())); 2019883Sandreas@sandberg.pp.se } else { 2029883Sandreas@sandberg.pp.se return NULL; 2039883Sandreas@sandberg.pp.se } 2049883Sandreas@sandberg.pp.se} 2059883Sandreas@sandberg.pp.se 2069883Sandreas@sandberg.pp.sevoid 2079883Sandreas@sandberg.pp.seExecute::popInput(ThreadID tid) 2089883Sandreas@sandberg.pp.se{ 2099883Sandreas@sandberg.pp.se if (!inputBuffer[tid].empty()) 2109883Sandreas@sandberg.pp.se inputBuffer[tid].pop(); 2119883Sandreas@sandberg.pp.se 2129883Sandreas@sandberg.pp.se executeInfo[tid].inputIndex = 0; 2139883Sandreas@sandberg.pp.se} 2149883Sandreas@sandberg.pp.se 2159883Sandreas@sandberg.pp.sevoid 2169883Sandreas@sandberg.pp.seExecute::tryToBranch(MinorDynInstPtr inst, Fault fault, BranchData &branch) 2179883Sandreas@sandberg.pp.se{ 2189883Sandreas@sandberg.pp.se ThreadContext *thread = cpu.getContext(inst->id.threadId); 2199883Sandreas@sandberg.pp.se const TheISA::PCState &pc_before = inst->pc; 2209883Sandreas@sandberg.pp.se TheISA::PCState target = thread->pcState(); 2219883Sandreas@sandberg.pp.se 2229883Sandreas@sandberg.pp.se /* Force a branch for SerializeAfter/SquashAfter instructions 2239883Sandreas@sandberg.pp.se * at the end of micro-op sequence when we're not suspended */ 2249883Sandreas@sandberg.pp.se bool force_branch = thread->status() != ThreadContext::Suspended && 2259883Sandreas@sandberg.pp.se !inst->isFault() && 2269883Sandreas@sandberg.pp.se inst->isLastOpInInst() && 2279883Sandreas@sandberg.pp.se (inst->staticInst->isSerializeAfter() || 2289883Sandreas@sandberg.pp.se inst->staticInst->isSquashAfter() || 2299883Sandreas@sandberg.pp.se inst->staticInst->isIprAccess()); 2309883Sandreas@sandberg.pp.se 2319883Sandreas@sandberg.pp.se DPRINTF(Branch, "tryToBranch before: %s after: %s%s\n", 2329883Sandreas@sandberg.pp.se pc_before, target, (force_branch ? " (forcing)" : "")); 2339883Sandreas@sandberg.pp.se 2349883Sandreas@sandberg.pp.se /* Will we change the PC to something other than the next instruction? */ 2359883Sandreas@sandberg.pp.se bool must_branch = pc_before != target || 2369883Sandreas@sandberg.pp.se fault != NoFault || 2379883Sandreas@sandberg.pp.se force_branch; 2389883Sandreas@sandberg.pp.se 2399883Sandreas@sandberg.pp.se /* The reason for the branch data we're about to generate, set below */ 2409883Sandreas@sandberg.pp.se BranchData::Reason reason = BranchData::NoBranch; 2419883Sandreas@sandberg.pp.se 2429883Sandreas@sandberg.pp.se if (fault == NoFault) 2439883Sandreas@sandberg.pp.se { 2449890Sandreas@sandberg.pp.se TheISA::advancePC(target, inst->staticInst); 2459883Sandreas@sandberg.pp.se thread->pcState(target); 2469890Sandreas@sandberg.pp.se 2479890Sandreas@sandberg.pp.se DPRINTF(Branch, "Advancing current PC from: %s to: %s\n", 2489890Sandreas@sandberg.pp.se pc_before, target); 2499890Sandreas@sandberg.pp.se } 2509890Sandreas@sandberg.pp.se 2519890Sandreas@sandberg.pp.se if (inst->predictedTaken && !force_branch) { 2529890Sandreas@sandberg.pp.se /* Predicted to branch */ 2539890Sandreas@sandberg.pp.se if (!must_branch) { 2549890Sandreas@sandberg.pp.se /* No branch was taken, change stream to get us back to the 2559890Sandreas@sandberg.pp.se * intended PC value */ 2569890Sandreas@sandberg.pp.se DPRINTF(Branch, "Predicted a branch from 0x%x to 0x%x but" 2579890Sandreas@sandberg.pp.se " none happened inst: %s\n", 2589890Sandreas@sandberg.pp.se inst->pc.instAddr(), inst->predictedTarget.instAddr(), *inst); 2599890Sandreas@sandberg.pp.se 2609890Sandreas@sandberg.pp.se reason = BranchData::BadlyPredictedBranch; 2619890Sandreas@sandberg.pp.se } else if (inst->predictedTarget == target) { 2629890Sandreas@sandberg.pp.se /* Branch prediction got the right target, kill the branch and 2639883Sandreas@sandberg.pp.se * carry on. 2649890Sandreas@sandberg.pp.se * Note that this information to the branch predictor might get 2659890Sandreas@sandberg.pp.se * overwritten by a "real" branch during this cycle */ 2669890Sandreas@sandberg.pp.se DPRINTF(Branch, "Predicted a branch from 0x%x to 0x%x correctly" 2679890Sandreas@sandberg.pp.se " inst: %s\n", 2689890Sandreas@sandberg.pp.se inst->pc.instAddr(), inst->predictedTarget.instAddr(), *inst); 2699890Sandreas@sandberg.pp.se 2709890Sandreas@sandberg.pp.se reason = BranchData::CorrectlyPredictedBranch; 2719890Sandreas@sandberg.pp.se } else { 2729890Sandreas@sandberg.pp.se /* Branch prediction got the wrong target */ 2739890Sandreas@sandberg.pp.se DPRINTF(Branch, "Predicted a branch from 0x%x to 0x%x" 2749890Sandreas@sandberg.pp.se " but got the wrong target (actual: 0x%x) inst: %s\n", 2759890Sandreas@sandberg.pp.se inst->pc.instAddr(), inst->predictedTarget.instAddr(), 2769890Sandreas@sandberg.pp.se target.instAddr(), *inst); 2779890Sandreas@sandberg.pp.se 2789890Sandreas@sandberg.pp.se reason = BranchData::BadlyPredictedBranchTarget; 2799890Sandreas@sandberg.pp.se } 2809890Sandreas@sandberg.pp.se } else if (must_branch) { 2819890Sandreas@sandberg.pp.se /* Unpredicted branch */ 2829890Sandreas@sandberg.pp.se DPRINTF(Branch, "Unpredicted branch from 0x%x to 0x%x inst: %s\n", 2839890Sandreas@sandberg.pp.se inst->pc.instAddr(), target.instAddr(), *inst); 2849890Sandreas@sandberg.pp.se 2859883Sandreas@sandberg.pp.se reason = BranchData::UnpredictedBranch; 2869883Sandreas@sandberg.pp.se } else { 2879890Sandreas@sandberg.pp.se /* No branch at all */ 2889883Sandreas@sandberg.pp.se reason = BranchData::NoBranch; 2899883Sandreas@sandberg.pp.se } 2909883Sandreas@sandberg.pp.se 2919890Sandreas@sandberg.pp.se updateBranchData(inst->id.threadId, reason, inst, target, branch); 2929890Sandreas@sandberg.pp.se} 2939890Sandreas@sandberg.pp.se 2949883Sandreas@sandberg.pp.sevoid 2959890Sandreas@sandberg.pp.seExecute::updateBranchData( 2969883Sandreas@sandberg.pp.se ThreadID tid, 2979890Sandreas@sandberg.pp.se BranchData::Reason reason, 2989890Sandreas@sandberg.pp.se MinorDynInstPtr inst, const TheISA::PCState &target, 2999883Sandreas@sandberg.pp.se BranchData &branch) 3009883Sandreas@sandberg.pp.se{ 3019883Sandreas@sandberg.pp.se if (reason != BranchData::NoBranch) { 3029883Sandreas@sandberg.pp.se /* Bump up the stream sequence number on a real branch*/ 3039883Sandreas@sandberg.pp.se if (BranchData::isStreamChange(reason)) 3049883Sandreas@sandberg.pp.se executeInfo[tid].streamSeqNum++; 3059883Sandreas@sandberg.pp.se 3069883Sandreas@sandberg.pp.se /* Branches (even mis-predictions) don't change the predictionSeqNum, 3079883Sandreas@sandberg.pp.se * just the streamSeqNum */ 3089883Sandreas@sandberg.pp.se branch = BranchData(reason, tid, 3099883Sandreas@sandberg.pp.se executeInfo[tid].streamSeqNum, 3109890Sandreas@sandberg.pp.se /* Maintaining predictionSeqNum if there's no inst is just a 3119890Sandreas@sandberg.pp.se * courtesy and looks better on minorview */ 3129890Sandreas@sandberg.pp.se (inst->isBubble() ? executeInfo[tid].lastPredictionSeqNum 3139890Sandreas@sandberg.pp.se : inst->id.predictionSeqNum), 3149890Sandreas@sandberg.pp.se target, inst); 3159890Sandreas@sandberg.pp.se 3169890Sandreas@sandberg.pp.se DPRINTF(Branch, "Branch data signalled: %s\n", branch); 3179890Sandreas@sandberg.pp.se } 3189890Sandreas@sandberg.pp.se} 3199890Sandreas@sandberg.pp.se 3209890Sandreas@sandberg.pp.sevoid 3219890Sandreas@sandberg.pp.seExecute::handleMemResponse(MinorDynInstPtr inst, 3229890Sandreas@sandberg.pp.se LSQ::LSQRequestPtr response, BranchData &branch, Fault &fault) 3239890Sandreas@sandberg.pp.se{ 3249883Sandreas@sandberg.pp.se ThreadID thread_id = inst->id.threadId; 3259883Sandreas@sandberg.pp.se ThreadContext *thread = cpu.getContext(thread_id); 3269883Sandreas@sandberg.pp.se 3279883Sandreas@sandberg.pp.se ExecContext context(cpu, *cpu.threads[thread_id], *this, inst); 3289883Sandreas@sandberg.pp.se 3299883Sandreas@sandberg.pp.se PacketPtr packet = response->packet; 3309883Sandreas@sandberg.pp.se 3319883Sandreas@sandberg.pp.se bool is_load = inst->staticInst->isLoad(); 3329883Sandreas@sandberg.pp.se bool is_store = inst->staticInst->isStore(); 3339883Sandreas@sandberg.pp.se bool is_atomic = inst->staticInst->isAtomic(); 3349883Sandreas@sandberg.pp.se bool is_prefetch = inst->staticInst->isDataPrefetch(); 3359883Sandreas@sandberg.pp.se 3369883Sandreas@sandberg.pp.se /* If true, the trace's predicate value will be taken from the exec 3379883Sandreas@sandberg.pp.se * context predicate, otherwise, it will be set to false */ 3389883Sandreas@sandberg.pp.se bool use_context_predicate = true; 3399883Sandreas@sandberg.pp.se 3409883Sandreas@sandberg.pp.se if (response->fault != NoFault) { 3419883Sandreas@sandberg.pp.se /* Invoke memory faults. */ 3429883Sandreas@sandberg.pp.se DPRINTF(MinorMem, "Completing fault from DTLB access: %s\n", 3439883Sandreas@sandberg.pp.se response->fault->name()); 3449883Sandreas@sandberg.pp.se 3459883Sandreas@sandberg.pp.se if (inst->staticInst->isPrefetch()) { 3469883Sandreas@sandberg.pp.se DPRINTF(MinorMem, "Not taking fault on prefetch: %s\n", 3479883Sandreas@sandberg.pp.se response->fault->name()); 3489883Sandreas@sandberg.pp.se 3499883Sandreas@sandberg.pp.se /* Don't assign to fault */ 3509883Sandreas@sandberg.pp.se } else { 3519883Sandreas@sandberg.pp.se /* Take the fault raised during the TLB/memory access */ 3529883Sandreas@sandberg.pp.se fault = response->fault; 3539883Sandreas@sandberg.pp.se 3549883Sandreas@sandberg.pp.se fault->invoke(thread, inst->staticInst); 3559883Sandreas@sandberg.pp.se } 3569883Sandreas@sandberg.pp.se } else if (!packet) { 3579883Sandreas@sandberg.pp.se DPRINTF(MinorMem, "Completing failed request inst: %s\n", 3589883Sandreas@sandberg.pp.se *inst); 3599883Sandreas@sandberg.pp.se use_context_predicate = false; 3609883Sandreas@sandberg.pp.se if (!context.readMemAccPredicate()) 3619883Sandreas@sandberg.pp.se inst->staticInst->completeAcc(nullptr, &context, inst->traceData); 3629883Sandreas@sandberg.pp.se } else if (packet->isError()) { 3639883Sandreas@sandberg.pp.se DPRINTF(MinorMem, "Trying to commit error response: %s\n", 3649883Sandreas@sandberg.pp.se *inst); 3659883Sandreas@sandberg.pp.se 3669883Sandreas@sandberg.pp.se fatal("Received error response packet for inst: %s\n", *inst); 3679883Sandreas@sandberg.pp.se } else if (is_store || is_load || is_prefetch || is_atomic) { 3689883Sandreas@sandberg.pp.se assert(packet); 3699884Sandreas@sandberg.pp.se 3709884Sandreas@sandberg.pp.se DPRINTF(MinorMem, "Memory response inst: %s addr: 0x%x size: %d\n", 3719884Sandreas@sandberg.pp.se *inst, packet->getAddr(), packet->getSize()); 3729884Sandreas@sandberg.pp.se 3739884Sandreas@sandberg.pp.se if (is_load && packet->getSize() > 0) { 3749884Sandreas@sandberg.pp.se DPRINTF(MinorMem, "Memory data[0]: 0x%x\n", 3759884Sandreas@sandberg.pp.se static_cast<unsigned int>(packet->getConstPtr<uint8_t>()[0])); 3769884Sandreas@sandberg.pp.se } 3779884Sandreas@sandberg.pp.se 3789884Sandreas@sandberg.pp.se /* Complete the memory access instruction */ 3799884Sandreas@sandberg.pp.se fault = inst->staticInst->completeAcc(packet, &context, 3809884Sandreas@sandberg.pp.se inst->traceData); 3819884Sandreas@sandberg.pp.se 3829884Sandreas@sandberg.pp.se if (fault != NoFault) { 3839884Sandreas@sandberg.pp.se /* Invoke fault created by instruction completion */ 3849884Sandreas@sandberg.pp.se DPRINTF(MinorMem, "Fault in memory completeAcc: %s\n", 3859884Sandreas@sandberg.pp.se fault->name()); 3869884Sandreas@sandberg.pp.se fault->invoke(thread, inst->staticInst); 3879884Sandreas@sandberg.pp.se } else { 3889884Sandreas@sandberg.pp.se /* Stores need to be pushed into the store buffer to finish 3899884Sandreas@sandberg.pp.se * them off */ 3909884Sandreas@sandberg.pp.se if (response->needsToBeSentToStoreBuffer()) 3919884Sandreas@sandberg.pp.se lsq.sendStoreToStoreBuffer(response); 3929884Sandreas@sandberg.pp.se } 3939884Sandreas@sandberg.pp.se } else { 3949884Sandreas@sandberg.pp.se fatal("There should only ever be reads, " 3959884Sandreas@sandberg.pp.se "writes or faults at this point\n"); 3969884Sandreas@sandberg.pp.se } 3979884Sandreas@sandberg.pp.se 3989884Sandreas@sandberg.pp.se lsq.popResponse(response); 39912392Sjason@lowepower.com 4009884Sandreas@sandberg.pp.se if (inst->traceData) { 4019884Sandreas@sandberg.pp.se inst->traceData->setPredicate((use_context_predicate ? 4029884Sandreas@sandberg.pp.se context.readPredicate() : false)); 4039884Sandreas@sandberg.pp.se } 4049884Sandreas@sandberg.pp.se 4059884Sandreas@sandberg.pp.se doInstCommitAccounting(inst); 4069884Sandreas@sandberg.pp.se 4079884Sandreas@sandberg.pp.se /* Generate output to account for branches */ 4089884Sandreas@sandberg.pp.se tryToBranch(inst, fault, branch); 4099884Sandreas@sandberg.pp.se} 4109884Sandreas@sandberg.pp.se 4119884Sandreas@sandberg.pp.sebool 4129884Sandreas@sandberg.pp.seExecute::isInterrupted(ThreadID thread_id) const 4139884Sandreas@sandberg.pp.se{ 4149884Sandreas@sandberg.pp.se return cpu.checkInterrupts(cpu.getContext(thread_id)); 4159884Sandreas@sandberg.pp.se} 4169884Sandreas@sandberg.pp.se 4179884Sandreas@sandberg.pp.sebool 4189884Sandreas@sandberg.pp.seExecute::takeInterrupt(ThreadID thread_id, BranchData &branch) 4199884Sandreas@sandberg.pp.se{ 4209884Sandreas@sandberg.pp.se DPRINTF(MinorInterrupt, "Considering interrupt status from PC: %s\n", 4219884Sandreas@sandberg.pp.se cpu.getContext(thread_id)->pcState()); 4229884Sandreas@sandberg.pp.se 4239884Sandreas@sandberg.pp.se Fault interrupt = cpu.getInterruptController(thread_id)->getInterrupt 4249884Sandreas@sandberg.pp.se (cpu.getContext(thread_id)); 4259884Sandreas@sandberg.pp.se 4269884Sandreas@sandberg.pp.se if (interrupt != NoFault) { 4279884Sandreas@sandberg.pp.se /* The interrupt *must* set pcState */ 4289884Sandreas@sandberg.pp.se cpu.getInterruptController(thread_id)->updateIntrInfo 4299884Sandreas@sandberg.pp.se (cpu.getContext(thread_id)); 4309884Sandreas@sandberg.pp.se interrupt->invoke(cpu.getContext(thread_id)); 4319884Sandreas@sandberg.pp.se 4329884Sandreas@sandberg.pp.se assert(!lsq.accessesInFlight()); 4339884Sandreas@sandberg.pp.se 4349884Sandreas@sandberg.pp.se DPRINTF(MinorInterrupt, "Invoking interrupt: %s to PC: %s\n", 4359884Sandreas@sandberg.pp.se interrupt->name(), cpu.getContext(thread_id)->pcState()); 4369884Sandreas@sandberg.pp.se 43712392Sjason@lowepower.com /* Assume that an interrupt *must* cause a branch. Assert this? */ 4389884Sandreas@sandberg.pp.se 4399884Sandreas@sandberg.pp.se updateBranchData(thread_id, BranchData::Interrupt, 4409884Sandreas@sandberg.pp.se MinorDynInst::bubble(), cpu.getContext(thread_id)->pcState(), 4419884Sandreas@sandberg.pp.se branch); 4429884Sandreas@sandberg.pp.se } 4439884Sandreas@sandberg.pp.se 4449884Sandreas@sandberg.pp.se return interrupt != NoFault; 4459884Sandreas@sandberg.pp.se} 4469884Sandreas@sandberg.pp.se 4479884Sandreas@sandberg.pp.sebool 4489884Sandreas@sandberg.pp.seExecute::executeMemRefInst(MinorDynInstPtr inst, BranchData &branch, 4499884Sandreas@sandberg.pp.se bool &passed_predicate, Fault &fault) 4509884Sandreas@sandberg.pp.se{ 4519884Sandreas@sandberg.pp.se bool issued = false; 4529884Sandreas@sandberg.pp.se 4539884Sandreas@sandberg.pp.se /* Set to true if the mem op. is issued and sent to the mem system */ 4549884Sandreas@sandberg.pp.se passed_predicate = false; 4559884Sandreas@sandberg.pp.se 4569884Sandreas@sandberg.pp.se if (!lsq.canRequest()) { 4579884Sandreas@sandberg.pp.se /* Not acting on instruction yet as the memory 4589884Sandreas@sandberg.pp.se * queues are full */ 4599884Sandreas@sandberg.pp.se issued = false; 4609884Sandreas@sandberg.pp.se } else { 4619884Sandreas@sandberg.pp.se ThreadContext *thread = cpu.getContext(inst->id.threadId); 4629884Sandreas@sandberg.pp.se TheISA::PCState old_pc = thread->pcState(); 4639884Sandreas@sandberg.pp.se 4649884Sandreas@sandberg.pp.se ExecContext context(cpu, *cpu.threads[inst->id.threadId], 4659884Sandreas@sandberg.pp.se *this, inst); 4669884Sandreas@sandberg.pp.se 4679884Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Initiating memRef inst: %s\n", *inst); 4689884Sandreas@sandberg.pp.se 4699884Sandreas@sandberg.pp.se Fault init_fault = inst->staticInst->initiateAcc(&context, 4709884Sandreas@sandberg.pp.se inst->traceData); 4719884Sandreas@sandberg.pp.se 4729884Sandreas@sandberg.pp.se if (init_fault != NoFault) { 4739884Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Fault on memory inst: %s" 4749884Sandreas@sandberg.pp.se " initiateAcc: %s\n", *inst, init_fault->name()); 4759884Sandreas@sandberg.pp.se fault = init_fault; 4769884Sandreas@sandberg.pp.se } else { 4779884Sandreas@sandberg.pp.se /* Only set this if the instruction passed its 4789884Sandreas@sandberg.pp.se * predicate */ 4799884Sandreas@sandberg.pp.se if (!context.readMemAccPredicate()) { 4809884Sandreas@sandberg.pp.se DPRINTF(MinorMem, "No memory access for inst: %s\n", *inst); 48112392Sjason@lowepower.com assert(context.readPredicate()); 4829884Sandreas@sandberg.pp.se } 4839884Sandreas@sandberg.pp.se passed_predicate = context.readPredicate(); 4849884Sandreas@sandberg.pp.se 4859884Sandreas@sandberg.pp.se /* Set predicate in tracing */ 4869884Sandreas@sandberg.pp.se if (inst->traceData) 4879884Sandreas@sandberg.pp.se inst->traceData->setPredicate(passed_predicate); 4889884Sandreas@sandberg.pp.se 4899884Sandreas@sandberg.pp.se /* If the instruction didn't pass its predicate (and so will not 49012392Sjason@lowepower.com * progress from here) Try to branch to correct and branch 4919884Sandreas@sandberg.pp.se * mis-prediction. */ 4929884Sandreas@sandberg.pp.se if (!passed_predicate) { 4939884Sandreas@sandberg.pp.se /* Leave it up to commit to handle the fault */ 4949884Sandreas@sandberg.pp.se lsq.pushFailedRequest(inst); 4959884Sandreas@sandberg.pp.se } 4969884Sandreas@sandberg.pp.se } 4979884Sandreas@sandberg.pp.se 4989884Sandreas@sandberg.pp.se /* Restore thread PC */ 4999884Sandreas@sandberg.pp.se thread->pcState(old_pc); 5009884Sandreas@sandberg.pp.se issued = true; 5019884Sandreas@sandberg.pp.se } 5029884Sandreas@sandberg.pp.se 5039884Sandreas@sandberg.pp.se return issued; 5049884Sandreas@sandberg.pp.se} 5059884Sandreas@sandberg.pp.se 50612392Sjason@lowepower.com/** Increment a cyclic buffer index for indices [0, cycle_size-1] */ 5079884Sandreas@sandberg.pp.seinline unsigned int 5089884Sandreas@sandberg.pp.secyclicIndexInc(unsigned int index, unsigned int cycle_size) 5099884Sandreas@sandberg.pp.se{ 5109884Sandreas@sandberg.pp.se unsigned int ret = index + 1; 5119884Sandreas@sandberg.pp.se 5129884Sandreas@sandberg.pp.se if (ret == cycle_size) 5139884Sandreas@sandberg.pp.se ret = 0; 5149884Sandreas@sandberg.pp.se 5159884Sandreas@sandberg.pp.se return ret; 5169884Sandreas@sandberg.pp.se} 5179884Sandreas@sandberg.pp.se 5189884Sandreas@sandberg.pp.se/** Decrement a cyclic buffer index for indices [0, cycle_size-1] */ 5199884Sandreas@sandberg.pp.seinline unsigned int 5209884Sandreas@sandberg.pp.secyclicIndexDec(unsigned int index, unsigned int cycle_size) 5219884Sandreas@sandberg.pp.se{ 5229884Sandreas@sandberg.pp.se int ret = index - 1; 5239883Sandreas@sandberg.pp.se 5249890Sandreas@sandberg.pp.se if (ret < 0) 5259890Sandreas@sandberg.pp.se ret = cycle_size - 1; 5269883Sandreas@sandberg.pp.se 52711363Sandreas@sandberg.pp.se return ret; 5289883Sandreas@sandberg.pp.se} 5299883Sandreas@sandberg.pp.se 5309883Sandreas@sandberg.pp.seunsigned int 5319883Sandreas@sandberg.pp.seExecute::issue(ThreadID thread_id) 5329883Sandreas@sandberg.pp.se{ 5339883Sandreas@sandberg.pp.se const ForwardInstData *insts_in = getInput(thread_id); 5349883Sandreas@sandberg.pp.se ExecuteThreadInfo &thread = executeInfo[thread_id]; 5359883Sandreas@sandberg.pp.se 5369883Sandreas@sandberg.pp.se /* Early termination if we have no instructions */ 5379883Sandreas@sandberg.pp.se if (!insts_in) 5389883Sandreas@sandberg.pp.se return 0; 5399883Sandreas@sandberg.pp.se 5409883Sandreas@sandberg.pp.se /* Start from the first FU */ 5419890Sandreas@sandberg.pp.se unsigned int fu_index = 0; 5429890Sandreas@sandberg.pp.se 5439890Sandreas@sandberg.pp.se /* Remains true while instructions are still being issued. If any 5449890Sandreas@sandberg.pp.se * instruction fails to issue, this is set to false and we exit issue. 5459890Sandreas@sandberg.pp.se * This strictly enforces in-order issue. For other issue behaviours, 5469890Sandreas@sandberg.pp.se * a more complicated test in the outer while loop below is needed. */ 5479890Sandreas@sandberg.pp.se bool issued = true; 5489890Sandreas@sandberg.pp.se 5499883Sandreas@sandberg.pp.se /* Number of insts issues this cycle to check for issueLimit */ 5509883Sandreas@sandberg.pp.se unsigned num_insts_issued = 0; 5519883Sandreas@sandberg.pp.se 5529883Sandreas@sandberg.pp.se /* Number of memory ops issues this cycle to check for memoryIssueLimit */ 5539883Sandreas@sandberg.pp.se unsigned num_mem_insts_issued = 0; 5549883Sandreas@sandberg.pp.se 5559883Sandreas@sandberg.pp.se /* Number of instructions discarded this cycle in order to enforce a 5569883Sandreas@sandberg.pp.se * discardLimit. @todo, add that parameter? */ 5579883Sandreas@sandberg.pp.se unsigned num_insts_discarded = 0; 5589883Sandreas@sandberg.pp.se 5599883Sandreas@sandberg.pp.se do { 5609883Sandreas@sandberg.pp.se MinorDynInstPtr inst = insts_in->insts[thread.inputIndex]; 5619883Sandreas@sandberg.pp.se Fault fault = inst->fault; 5629883Sandreas@sandberg.pp.se bool discarded = false; 5639883Sandreas@sandberg.pp.se bool issued_mem_ref = false; 5649883Sandreas@sandberg.pp.se 5659883Sandreas@sandberg.pp.se if (inst->isBubble()) { 5669883Sandreas@sandberg.pp.se /* Skip */ 5679883Sandreas@sandberg.pp.se issued = true; 5689883Sandreas@sandberg.pp.se } else if (cpu.getContext(thread_id)->status() == 5699883Sandreas@sandberg.pp.se ThreadContext::Suspended) 57010905Sandreas.sandberg@arm.com { 5719883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Discarding inst: %s from suspended" 5729883Sandreas@sandberg.pp.se " thread\n", *inst); 5739890Sandreas@sandberg.pp.se 5749890Sandreas@sandberg.pp.se issued = true; 5759890Sandreas@sandberg.pp.se discarded = true; 5769890Sandreas@sandberg.pp.se } else if (inst->id.streamSeqNum != thread.streamSeqNum) { 5779883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Discarding inst: %s as its stream" 5789883Sandreas@sandberg.pp.se " state was unexpected, expected: %d\n", 5799883Sandreas@sandberg.pp.se *inst, thread.streamSeqNum); 5809883Sandreas@sandberg.pp.se issued = true; 5819883Sandreas@sandberg.pp.se discarded = true; 5829883Sandreas@sandberg.pp.se } else { 5839883Sandreas@sandberg.pp.se /* Try and issue an instruction into an FU, assume we didn't and 5849883Sandreas@sandberg.pp.se * fix that in the loop */ 5859883Sandreas@sandberg.pp.se issued = false; 5869883Sandreas@sandberg.pp.se 5879883Sandreas@sandberg.pp.se /* Try FU from 0 each instruction */ 5889883Sandreas@sandberg.pp.se fu_index = 0; 5899883Sandreas@sandberg.pp.se 5909883Sandreas@sandberg.pp.se /* Try and issue a single instruction stepping through the 5919883Sandreas@sandberg.pp.se * available FUs */ 5929883Sandreas@sandberg.pp.se do { 5939883Sandreas@sandberg.pp.se FUPipeline *fu = funcUnits[fu_index]; 5949883Sandreas@sandberg.pp.se 5959883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Trying to issue inst: %s to FU: %d\n", 5969883Sandreas@sandberg.pp.se *inst, fu_index); 5979883Sandreas@sandberg.pp.se 5989883Sandreas@sandberg.pp.se /* Does the examined fu have the OpClass-related capability 5999883Sandreas@sandberg.pp.se * needed to execute this instruction? Faults can always 6009883Sandreas@sandberg.pp.se * issue to any FU but probably should just 'live' in the 6019883Sandreas@sandberg.pp.se * inFlightInsts queue rather than having an FU. */ 6029883Sandreas@sandberg.pp.se bool fu_is_capable = (!inst->isFault() ? 6039883Sandreas@sandberg.pp.se fu->provides(inst->staticInst->opClass()) : true); 6049883Sandreas@sandberg.pp.se 6059883Sandreas@sandberg.pp.se if (inst->isNoCostInst()) { 6069883Sandreas@sandberg.pp.se /* Issue free insts. to a fake numbered FU */ 6079883Sandreas@sandberg.pp.se fu_index = noCostFUIndex; 6089883Sandreas@sandberg.pp.se 6099883Sandreas@sandberg.pp.se /* And start the countdown on activity to allow 6109883Sandreas@sandberg.pp.se * this instruction to get to the end of its FU */ 6119883Sandreas@sandberg.pp.se cpu.activityRecorder->activity(); 6129883Sandreas@sandberg.pp.se 6139883Sandreas@sandberg.pp.se /* Mark the destinations for this instruction as 6149883Sandreas@sandberg.pp.se * busy */ 6159883Sandreas@sandberg.pp.se scoreboard[thread_id].markupInstDests(inst, cpu.curCycle() + 6169883Sandreas@sandberg.pp.se Cycles(0), cpu.getContext(thread_id), false); 6179883Sandreas@sandberg.pp.se 6189883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Issuing %s to %d\n", inst->id, noCostFUIndex); 6199883Sandreas@sandberg.pp.se inst->fuIndex = noCostFUIndex; 6209883Sandreas@sandberg.pp.se inst->extraCommitDelay = Cycles(0); 6219883Sandreas@sandberg.pp.se inst->extraCommitDelayExpr = NULL; 6229883Sandreas@sandberg.pp.se 6239883Sandreas@sandberg.pp.se /* Push the instruction onto the inFlight queue so 6249883Sandreas@sandberg.pp.se * it can be committed in order */ 6259883Sandreas@sandberg.pp.se QueuedInst fu_inst(inst); 6269883Sandreas@sandberg.pp.se thread.inFlightInsts->push(fu_inst); 6279883Sandreas@sandberg.pp.se 6289883Sandreas@sandberg.pp.se issued = true; 6299883Sandreas@sandberg.pp.se 6309883Sandreas@sandberg.pp.se } else if (!fu_is_capable || fu->alreadyPushed()) { 6319883Sandreas@sandberg.pp.se /* Skip */ 6329883Sandreas@sandberg.pp.se if (!fu_is_capable) { 6339883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Can't issue as FU: %d isn't" 6349883Sandreas@sandberg.pp.se " capable\n", fu_index); 6359883Sandreas@sandberg.pp.se } else { 6369883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Can't issue as FU: %d is" 6379883Sandreas@sandberg.pp.se " already busy\n", fu_index); 6389883Sandreas@sandberg.pp.se } 6399883Sandreas@sandberg.pp.se } else if (fu->stalled) { 6409883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Can't issue inst: %s into FU: %d," 6419883Sandreas@sandberg.pp.se " it's stalled\n", 6429883Sandreas@sandberg.pp.se *inst, fu_index); 6439883Sandreas@sandberg.pp.se } else if (!fu->canInsert()) { 6449883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Can't issue inst: %s to busy FU" 6459883Sandreas@sandberg.pp.se " for another: %d cycles\n", 6469883Sandreas@sandberg.pp.se *inst, fu->cyclesBeforeInsert()); 6479883Sandreas@sandberg.pp.se } else { 6489883Sandreas@sandberg.pp.se MinorFUTiming *timing = (!inst->isFault() ? 6499883Sandreas@sandberg.pp.se fu->findTiming(inst->staticInst) : NULL); 6509883Sandreas@sandberg.pp.se 6519883Sandreas@sandberg.pp.se const std::vector<Cycles> *src_latencies = 6529883Sandreas@sandberg.pp.se (timing ? &(timing->srcRegsRelativeLats) 6539883Sandreas@sandberg.pp.se : NULL); 6549883Sandreas@sandberg.pp.se 6559883Sandreas@sandberg.pp.se const std::vector<bool> *cant_forward_from_fu_indices = 6569883Sandreas@sandberg.pp.se &(fu->cantForwardFromFUIndices); 65711363Sandreas@sandberg.pp.se 6589883Sandreas@sandberg.pp.se if (timing && timing->suppress) { 6599883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Can't issue inst: %s as extra" 6609883Sandreas@sandberg.pp.se " decoding is suppressing it\n", 6619883Sandreas@sandberg.pp.se *inst); 6629883Sandreas@sandberg.pp.se } else if (!scoreboard[thread_id].canInstIssue(inst, 6639883Sandreas@sandberg.pp.se src_latencies, cant_forward_from_fu_indices, 6649883Sandreas@sandberg.pp.se cpu.curCycle(), cpu.getContext(thread_id))) 6659883Sandreas@sandberg.pp.se { 6669883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Can't issue inst: %s yet\n", 6679883Sandreas@sandberg.pp.se *inst); 6689883Sandreas@sandberg.pp.se } else { 6699883Sandreas@sandberg.pp.se /* Can insert the instruction into this FU */ 6709883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Issuing inst: %s" 6719883Sandreas@sandberg.pp.se " into FU %d\n", *inst, 6729883Sandreas@sandberg.pp.se fu_index); 6739883Sandreas@sandberg.pp.se 6749883Sandreas@sandberg.pp.se Cycles extra_dest_retire_lat = Cycles(0); 6759883Sandreas@sandberg.pp.se TimingExpr *extra_dest_retire_lat_expr = NULL; 6769883Sandreas@sandberg.pp.se Cycles extra_assumed_lat = Cycles(0); 6779883Sandreas@sandberg.pp.se 6789883Sandreas@sandberg.pp.se /* Add the extraCommitDelay and extraAssumeLat to 6799883Sandreas@sandberg.pp.se * the FU pipeline timings */ 6809883Sandreas@sandberg.pp.se if (timing) { 6819883Sandreas@sandberg.pp.se extra_dest_retire_lat = 6829883Sandreas@sandberg.pp.se timing->extraCommitLat; 6839883Sandreas@sandberg.pp.se extra_dest_retire_lat_expr = 6849883Sandreas@sandberg.pp.se timing->extraCommitLatExpr; 6859883Sandreas@sandberg.pp.se extra_assumed_lat = 6869883Sandreas@sandberg.pp.se timing->extraAssumedLat; 6879883Sandreas@sandberg.pp.se } 6889883Sandreas@sandberg.pp.se 6899883Sandreas@sandberg.pp.se issued_mem_ref = inst->isMemRef(); 6909883Sandreas@sandberg.pp.se 6919883Sandreas@sandberg.pp.se QueuedInst fu_inst(inst); 6929883Sandreas@sandberg.pp.se 6939883Sandreas@sandberg.pp.se /* Decorate the inst with FU details */ 6949883Sandreas@sandberg.pp.se inst->fuIndex = fu_index; 6959883Sandreas@sandberg.pp.se inst->extraCommitDelay = extra_dest_retire_lat; 69610113Sandreas@sandberg.pp.se inst->extraCommitDelayExpr = 6979883Sandreas@sandberg.pp.se extra_dest_retire_lat_expr; 6989883Sandreas@sandberg.pp.se 6999883Sandreas@sandberg.pp.se if (issued_mem_ref) { 7009883Sandreas@sandberg.pp.se /* Remember which instruction this memory op 7019883Sandreas@sandberg.pp.se * depends on so that initiateAcc can be called 7029883Sandreas@sandberg.pp.se * early */ 7039883Sandreas@sandberg.pp.se if (allowEarlyMemIssue) { 7049883Sandreas@sandberg.pp.se inst->instToWaitFor = 7059883Sandreas@sandberg.pp.se scoreboard[thread_id].execSeqNumToWaitFor(inst, 7069883Sandreas@sandberg.pp.se cpu.getContext(thread_id)); 7079883Sandreas@sandberg.pp.se 7089883Sandreas@sandberg.pp.se if (lsq.getLastMemBarrier(thread_id) > 7099883Sandreas@sandberg.pp.se inst->instToWaitFor) 7109883Sandreas@sandberg.pp.se { 7119883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "A barrier will" 7129883Sandreas@sandberg.pp.se " cause a delay in mem ref issue of" 7139883Sandreas@sandberg.pp.se " inst: %s until after inst" 7149883Sandreas@sandberg.pp.se " %d(exec)\n", *inst, 7159883Sandreas@sandberg.pp.se lsq.getLastMemBarrier(thread_id)); 7169883Sandreas@sandberg.pp.se 7179883Sandreas@sandberg.pp.se inst->instToWaitFor = 7189883Sandreas@sandberg.pp.se lsq.getLastMemBarrier(thread_id); 7199883Sandreas@sandberg.pp.se } else { 7209883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Memory ref inst:" 7219883Sandreas@sandberg.pp.se " %s must wait for inst %d(exec)" 7229883Sandreas@sandberg.pp.se " before issuing\n", 7239883Sandreas@sandberg.pp.se *inst, inst->instToWaitFor); 7249883Sandreas@sandberg.pp.se } 7259883Sandreas@sandberg.pp.se 7269883Sandreas@sandberg.pp.se inst->canEarlyIssue = true; 72710099Sandreas@sandberg.pp.se } 72810099Sandreas@sandberg.pp.se /* Also queue this instruction in the memory ref 72910099Sandreas@sandberg.pp.se * queue to ensure in-order issue to the LSQ */ 73010099Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Pushing mem inst: %s\n", 73110099Sandreas@sandberg.pp.se *inst); 7329883Sandreas@sandberg.pp.se thread.inFUMemInsts->push(fu_inst); 7339883Sandreas@sandberg.pp.se } 7349883Sandreas@sandberg.pp.se 7359883Sandreas@sandberg.pp.se /* Issue to FU */ 7369883Sandreas@sandberg.pp.se fu->push(fu_inst); 7379883Sandreas@sandberg.pp.se /* And start the countdown on activity to allow 7389883Sandreas@sandberg.pp.se * this instruction to get to the end of its FU */ 7399883Sandreas@sandberg.pp.se cpu.activityRecorder->activity(); 7409883Sandreas@sandberg.pp.se 7419883Sandreas@sandberg.pp.se /* Mark the destinations for this instruction as 7429886Sandreas@sandberg.pp.se * busy */ 7439886Sandreas@sandberg.pp.se scoreboard[thread_id].markupInstDests(inst, cpu.curCycle() + 7449886Sandreas@sandberg.pp.se fu->description.opLat + 7459886Sandreas@sandberg.pp.se extra_dest_retire_lat + 7469886Sandreas@sandberg.pp.se extra_assumed_lat, 7479886Sandreas@sandberg.pp.se cpu.getContext(thread_id), 7489886Sandreas@sandberg.pp.se issued_mem_ref && extra_assumed_lat == Cycles(0)); 7499886Sandreas@sandberg.pp.se 7509886Sandreas@sandberg.pp.se /* Push the instruction onto the inFlight queue so 7519886Sandreas@sandberg.pp.se * it can be committed in order */ 7529886Sandreas@sandberg.pp.se thread.inFlightInsts->push(fu_inst); 7539886Sandreas@sandberg.pp.se 7549883Sandreas@sandberg.pp.se issued = true; 7559883Sandreas@sandberg.pp.se } 7569883Sandreas@sandberg.pp.se } 7579883Sandreas@sandberg.pp.se 7589883Sandreas@sandberg.pp.se fu_index++; 7599883Sandreas@sandberg.pp.se } while (fu_index != numFuncUnits && !issued); 7609883Sandreas@sandberg.pp.se 7619883Sandreas@sandberg.pp.se if (!issued) 7629883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Didn't issue inst: %s\n", *inst); 7639883Sandreas@sandberg.pp.se } 7649883Sandreas@sandberg.pp.se 7659883Sandreas@sandberg.pp.se if (issued) { 7669883Sandreas@sandberg.pp.se /* Generate MinorTrace's MinorInst lines. Do this at commit 7679883Sandreas@sandberg.pp.se * to allow better instruction annotation? */ 7689883Sandreas@sandberg.pp.se if (DTRACE(MinorTrace) && !inst->isBubble()) 7699883Sandreas@sandberg.pp.se inst->minorTraceInst(*this); 7709883Sandreas@sandberg.pp.se 7719883Sandreas@sandberg.pp.se /* Mark up barriers in the LSQ */ 7729883Sandreas@sandberg.pp.se if (!discarded && inst->isInst() && 7739883Sandreas@sandberg.pp.se inst->staticInst->isMemBarrier()) 7749886Sandreas@sandberg.pp.se { 7759886Sandreas@sandberg.pp.se DPRINTF(MinorMem, "Issuing memory barrier inst: %s\n", *inst); 7769886Sandreas@sandberg.pp.se lsq.issuedMemBarrierInst(inst); 7779886Sandreas@sandberg.pp.se } 7789886Sandreas@sandberg.pp.se 7799886Sandreas@sandberg.pp.se if (inst->traceData && setTraceTimeOnIssue) { 7809886Sandreas@sandberg.pp.se inst->traceData->setWhen(curTick()); 7819886Sandreas@sandberg.pp.se } 7829886Sandreas@sandberg.pp.se 7839886Sandreas@sandberg.pp.se if (issued_mem_ref) 7849886Sandreas@sandberg.pp.se num_mem_insts_issued++; 7859886Sandreas@sandberg.pp.se 7869886Sandreas@sandberg.pp.se if (discarded) { 7879886Sandreas@sandberg.pp.se num_insts_discarded++; 7889886Sandreas@sandberg.pp.se } else if (!inst->isBubble()) { 7899886Sandreas@sandberg.pp.se num_insts_issued++; 7909886Sandreas@sandberg.pp.se 7919886Sandreas@sandberg.pp.se if (num_insts_issued == issueLimit) 7929886Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Reached inst issue limit\n"); 7939886Sandreas@sandberg.pp.se } 7949886Sandreas@sandberg.pp.se 7959886Sandreas@sandberg.pp.se thread.inputIndex++; 7969886Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Stepping to next inst inputIndex: %d\n", 7979886Sandreas@sandberg.pp.se thread.inputIndex); 7989886Sandreas@sandberg.pp.se } 7999886Sandreas@sandberg.pp.se 8009886Sandreas@sandberg.pp.se /* Got to the end of a line */ 8019886Sandreas@sandberg.pp.se if (thread.inputIndex == insts_in->width()) { 8029886Sandreas@sandberg.pp.se popInput(thread_id); 8039886Sandreas@sandberg.pp.se /* Set insts_in to null to force us to leave the surrounding 8049886Sandreas@sandberg.pp.se * loop */ 8059886Sandreas@sandberg.pp.se insts_in = NULL; 8069884Sandreas@sandberg.pp.se 8079884Sandreas@sandberg.pp.se if (processMoreThanOneInput) { 8089884Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Wrapping\n"); 8099884Sandreas@sandberg.pp.se insts_in = getInput(thread_id); 8109884Sandreas@sandberg.pp.se } 8119884Sandreas@sandberg.pp.se } 8129884Sandreas@sandberg.pp.se } while (insts_in && thread.inputIndex < insts_in->width() && 8139884Sandreas@sandberg.pp.se /* We still have instructions */ 8149884Sandreas@sandberg.pp.se fu_index != numFuncUnits && /* Not visited all FUs */ 8159884Sandreas@sandberg.pp.se issued && /* We've not yet failed to issue an instruction */ 8169884Sandreas@sandberg.pp.se num_insts_issued != issueLimit && /* Still allowed to issue */ 8179884Sandreas@sandberg.pp.se num_mem_insts_issued != memoryIssueLimit); 8189886Sandreas@sandberg.pp.se 8199883Sandreas@sandberg.pp.se return num_insts_issued; 8209883Sandreas@sandberg.pp.se} 8219890Sandreas@sandberg.pp.se 8229890Sandreas@sandberg.pp.sebool 8239890Sandreas@sandberg.pp.seExecute::tryPCEvents(ThreadID thread_id) 8249890Sandreas@sandberg.pp.se{ 8259890Sandreas@sandberg.pp.se ThreadContext *thread = cpu.getContext(thread_id); 8269890Sandreas@sandberg.pp.se unsigned int num_pc_event_checks = 0; 8279890Sandreas@sandberg.pp.se 8289890Sandreas@sandberg.pp.se /* Handle PC events on instructions */ 8299890Sandreas@sandberg.pp.se Addr oldPC; 8309890Sandreas@sandberg.pp.se do { 8319890Sandreas@sandberg.pp.se oldPC = thread->instAddr(); 8329890Sandreas@sandberg.pp.se cpu.system->pcEventQueue.service(thread); 8339890Sandreas@sandberg.pp.se num_pc_event_checks++; 8349890Sandreas@sandberg.pp.se } while (oldPC != thread->instAddr()); 8359890Sandreas@sandberg.pp.se 8369890Sandreas@sandberg.pp.se if (num_pc_event_checks > 1) { 8379890Sandreas@sandberg.pp.se DPRINTF(PCEvent, "Acting on PC Event to PC: %s\n", 8389890Sandreas@sandberg.pp.se thread->pcState()); 8399890Sandreas@sandberg.pp.se } 8409890Sandreas@sandberg.pp.se 8419890Sandreas@sandberg.pp.se return num_pc_event_checks > 1; 8429890Sandreas@sandberg.pp.se} 8439890Sandreas@sandberg.pp.se 8449890Sandreas@sandberg.pp.sevoid 8459890Sandreas@sandberg.pp.seExecute::doInstCommitAccounting(MinorDynInstPtr inst) 8469890Sandreas@sandberg.pp.se{ 8479890Sandreas@sandberg.pp.se assert(!inst->isFault()); 8489890Sandreas@sandberg.pp.se 8499890Sandreas@sandberg.pp.se MinorThread *thread = cpu.threads[inst->id.threadId]; 8509890Sandreas@sandberg.pp.se 8519890Sandreas@sandberg.pp.se /* Increment the many and various inst and op counts in the 8529890Sandreas@sandberg.pp.se * thread and system */ 8539890Sandreas@sandberg.pp.se if (!inst->staticInst->isMicroop() || inst->staticInst->isLastMicroop()) 8549890Sandreas@sandberg.pp.se { 8559890Sandreas@sandberg.pp.se thread->numInst++; 8569890Sandreas@sandberg.pp.se thread->numInsts++; 8579890Sandreas@sandberg.pp.se cpu.stats.numInsts++; 8589890Sandreas@sandberg.pp.se cpu.system->totalNumInsts++; 8599890Sandreas@sandberg.pp.se 8609890Sandreas@sandberg.pp.se /* Act on events related to instruction counts */ 8619890Sandreas@sandberg.pp.se cpu.comInstEventQueue[inst->id.threadId]->serviceEvents(thread->numInst); 8629890Sandreas@sandberg.pp.se cpu.system->instEventQueue.serviceEvents(cpu.system->totalNumInsts); 8639890Sandreas@sandberg.pp.se } 8649890Sandreas@sandberg.pp.se thread->numOp++; 8659890Sandreas@sandberg.pp.se thread->numOps++; 8669890Sandreas@sandberg.pp.se cpu.stats.numOps++; 8679890Sandreas@sandberg.pp.se cpu.stats.committedInstType[inst->id.threadId] 8689890Sandreas@sandberg.pp.se [inst->staticInst->opClass()]++; 8699890Sandreas@sandberg.pp.se 8709890Sandreas@sandberg.pp.se /* Set the CP SeqNum to the numOps commit number */ 8719890Sandreas@sandberg.pp.se if (inst->traceData) 8729890Sandreas@sandberg.pp.se inst->traceData->setCPSeq(thread->numOp); 8739890Sandreas@sandberg.pp.se 8749890Sandreas@sandberg.pp.se cpu.probeInstCommit(inst->staticInst, inst->pc.instAddr()); 8759890Sandreas@sandberg.pp.se} 8769890Sandreas@sandberg.pp.se 8779890Sandreas@sandberg.pp.sebool 8789890Sandreas@sandberg.pp.seExecute::commitInst(MinorDynInstPtr inst, bool early_memory_issue, 8799890Sandreas@sandberg.pp.se BranchData &branch, Fault &fault, bool &committed, 8809890Sandreas@sandberg.pp.se bool &completed_mem_issue) 8819890Sandreas@sandberg.pp.se{ 8829890Sandreas@sandberg.pp.se ThreadID thread_id = inst->id.threadId; 8839890Sandreas@sandberg.pp.se ThreadContext *thread = cpu.getContext(thread_id); 8849890Sandreas@sandberg.pp.se 8859890Sandreas@sandberg.pp.se bool completed_inst = true; 8869890Sandreas@sandberg.pp.se fault = NoFault; 8879890Sandreas@sandberg.pp.se 8889890Sandreas@sandberg.pp.se /* Is the thread for this instruction suspended? In that case, just 8899890Sandreas@sandberg.pp.se * stall as long as there are no pending interrupts */ 8909890Sandreas@sandberg.pp.se if (thread->status() == ThreadContext::Suspended && 8919890Sandreas@sandberg.pp.se !isInterrupted(thread_id)) 8929890Sandreas@sandberg.pp.se { 8939890Sandreas@sandberg.pp.se panic("We should never hit the case where we try to commit from a " 8949890Sandreas@sandberg.pp.se "suspended thread as the streamSeqNum should not match"); 8959890Sandreas@sandberg.pp.se } else if (inst->isFault()) { 8969890Sandreas@sandberg.pp.se ExecContext context(cpu, *cpu.threads[thread_id], *this, inst); 8979890Sandreas@sandberg.pp.se 8989890Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Fault inst reached Execute: %s\n", 8999890Sandreas@sandberg.pp.se inst->fault->name()); 9009890Sandreas@sandberg.pp.se 9019890Sandreas@sandberg.pp.se fault = inst->fault; 9029890Sandreas@sandberg.pp.se inst->fault->invoke(thread, NULL); 9039890Sandreas@sandberg.pp.se 9049890Sandreas@sandberg.pp.se tryToBranch(inst, fault, branch); 9059890Sandreas@sandberg.pp.se } else if (inst->staticInst->isMemRef()) { 9069890Sandreas@sandberg.pp.se /* Memory accesses are executed in two parts: 9079890Sandreas@sandberg.pp.se * executeMemRefInst -- calculates the EA and issues the access 9089883Sandreas@sandberg.pp.se * to memory. This is done here. 9099883Sandreas@sandberg.pp.se * handleMemResponse -- handles the response packet, done by 9109883Sandreas@sandberg.pp.se * Execute::commit 9119890Sandreas@sandberg.pp.se * 9129890Sandreas@sandberg.pp.se * While the memory access is in its FU, the EA is being 9139890Sandreas@sandberg.pp.se * calculated. At the end of the FU, when it is ready to 9149890Sandreas@sandberg.pp.se * 'commit' (in this function), the access is presented to the 9159883Sandreas@sandberg.pp.se * memory queues. When a response comes back from memory, 9169883Sandreas@sandberg.pp.se * Execute::commit will commit it. 9179883Sandreas@sandberg.pp.se */ 9189883Sandreas@sandberg.pp.se bool predicate_passed = false; 9199883Sandreas@sandberg.pp.se bool completed_mem_inst = executeMemRefInst(inst, branch, 9209883Sandreas@sandberg.pp.se predicate_passed, fault); 9219883Sandreas@sandberg.pp.se 9229883Sandreas@sandberg.pp.se if (completed_mem_inst && fault != NoFault) { 9239883Sandreas@sandberg.pp.se if (early_memory_issue) { 9249883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Fault in early executing inst: %s\n", 9259883Sandreas@sandberg.pp.se fault->name()); 9269883Sandreas@sandberg.pp.se /* Don't execute the fault, just stall the instruction 9279883Sandreas@sandberg.pp.se * until it gets to the head of inFlightInsts */ 9289883Sandreas@sandberg.pp.se inst->canEarlyIssue = false; 9299883Sandreas@sandberg.pp.se /* Not completed as we'll come here again to pick up 9309883Sandreas@sandberg.pp.se * the fault when we get to the end of the FU */ 9319883Sandreas@sandberg.pp.se completed_inst = false; 9329883Sandreas@sandberg.pp.se } else { 9339883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Fault in execute: %s\n", 9349883Sandreas@sandberg.pp.se fault->name()); 9359883Sandreas@sandberg.pp.se fault->invoke(thread, NULL); 9369883Sandreas@sandberg.pp.se 9379883Sandreas@sandberg.pp.se tryToBranch(inst, fault, branch); 9389883Sandreas@sandberg.pp.se completed_inst = true; 9399883Sandreas@sandberg.pp.se } 9409883Sandreas@sandberg.pp.se } else { 9419883Sandreas@sandberg.pp.se completed_inst = completed_mem_inst; 94210113Sandreas@sandberg.pp.se } 94310113Sandreas@sandberg.pp.se completed_mem_issue = completed_inst; 94410113Sandreas@sandberg.pp.se } else if (inst->isInst() && inst->staticInst->isMemBarrier() && 94510113Sandreas@sandberg.pp.se !lsq.canPushIntoStoreBuffer()) 94610113Sandreas@sandberg.pp.se { 94710113Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Can't commit data barrier inst: %s yet as" 9489883Sandreas@sandberg.pp.se " there isn't space in the store buffer\n", *inst); 9499883Sandreas@sandberg.pp.se 9509883Sandreas@sandberg.pp.se completed_inst = false; 9519883Sandreas@sandberg.pp.se } else if (inst->isInst() && inst->staticInst->isQuiesce() 95210113Sandreas@sandberg.pp.se && !branch.isBubble()){ 95310113Sandreas@sandberg.pp.se /* This instruction can suspend, need to be able to communicate 95410113Sandreas@sandberg.pp.se * backwards, so no other branches may evaluate this cycle*/ 95510113Sandreas@sandberg.pp.se completed_inst = false; 95610113Sandreas@sandberg.pp.se } else { 95710113Sandreas@sandberg.pp.se ExecContext context(cpu, *cpu.threads[thread_id], *this, inst); 95810113Sandreas@sandberg.pp.se 95910113Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Committing inst: %s\n", *inst); 96010113Sandreas@sandberg.pp.se 96110113Sandreas@sandberg.pp.se fault = inst->staticInst->execute(&context, 96210113Sandreas@sandberg.pp.se inst->traceData); 96310113Sandreas@sandberg.pp.se 96410113Sandreas@sandberg.pp.se /* Set the predicate for tracing and dump */ 9659883Sandreas@sandberg.pp.se if (inst->traceData) 9669883Sandreas@sandberg.pp.se inst->traceData->setPredicate(context.readPredicate()); 9679883Sandreas@sandberg.pp.se 9689883Sandreas@sandberg.pp.se committed = true; 9699883Sandreas@sandberg.pp.se 9709883Sandreas@sandberg.pp.se if (fault != NoFault) { 9719883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Fault in execute of inst: %s fault: %s\n", 9729883Sandreas@sandberg.pp.se *inst, fault->name()); 9739883Sandreas@sandberg.pp.se fault->invoke(thread, inst->staticInst); 97410113Sandreas@sandberg.pp.se } 97510113Sandreas@sandberg.pp.se 9769883Sandreas@sandberg.pp.se doInstCommitAccounting(inst); 9779883Sandreas@sandberg.pp.se tryToBranch(inst, fault, branch); 9789883Sandreas@sandberg.pp.se } 9799883Sandreas@sandberg.pp.se 9809883Sandreas@sandberg.pp.se if (completed_inst) { 9819883Sandreas@sandberg.pp.se /* Keep a copy of this instruction's predictionSeqNum just in case 9829883Sandreas@sandberg.pp.se * we need to issue a branch without an instruction (such as an 98310113Sandreas@sandberg.pp.se * interrupt) */ 9849883Sandreas@sandberg.pp.se executeInfo[thread_id].lastPredictionSeqNum = inst->id.predictionSeqNum; 9859883Sandreas@sandberg.pp.se 9869883Sandreas@sandberg.pp.se /* Check to see if this instruction suspended the current thread. */ 9879883Sandreas@sandberg.pp.se if (!inst->isFault() && 9889883Sandreas@sandberg.pp.se thread->status() == ThreadContext::Suspended && 9899883Sandreas@sandberg.pp.se branch.isBubble() && /* It didn't branch too */ 9909883Sandreas@sandberg.pp.se !isInterrupted(thread_id)) /* Don't suspend if we have 9919883Sandreas@sandberg.pp.se interrupts */ 9929883Sandreas@sandberg.pp.se { 9939883Sandreas@sandberg.pp.se TheISA::PCState resume_pc = cpu.getContext(thread_id)->pcState(); 9949883Sandreas@sandberg.pp.se 9959883Sandreas@sandberg.pp.se assert(resume_pc.microPC() == 0); 9969883Sandreas@sandberg.pp.se 9979883Sandreas@sandberg.pp.se DPRINTF(MinorInterrupt, "Suspending thread: %d from Execute" 9989883Sandreas@sandberg.pp.se " inst: %s\n", thread_id, *inst); 9999883Sandreas@sandberg.pp.se 10009883Sandreas@sandberg.pp.se cpu.stats.numFetchSuspends++; 10019883Sandreas@sandberg.pp.se 10029883Sandreas@sandberg.pp.se updateBranchData(thread_id, BranchData::SuspendThread, inst, 10039883Sandreas@sandberg.pp.se resume_pc, branch); 10049883Sandreas@sandberg.pp.se } 10059883Sandreas@sandberg.pp.se } 10069883Sandreas@sandberg.pp.se 10079883Sandreas@sandberg.pp.se return completed_inst; 10089883Sandreas@sandberg.pp.se} 10099883Sandreas@sandberg.pp.se 10109883Sandreas@sandberg.pp.sevoid 10119883Sandreas@sandberg.pp.seExecute::commit(ThreadID thread_id, bool only_commit_microops, bool discard, 10129883Sandreas@sandberg.pp.se BranchData &branch) 10139883Sandreas@sandberg.pp.se{ 10149883Sandreas@sandberg.pp.se Fault fault = NoFault; 10159883Sandreas@sandberg.pp.se Cycles now = cpu.curCycle(); 10169883Sandreas@sandberg.pp.se ExecuteThreadInfo &ex_info = executeInfo[thread_id]; 10179883Sandreas@sandberg.pp.se 10189883Sandreas@sandberg.pp.se /** 10199883Sandreas@sandberg.pp.se * Try and execute as many instructions from the end of FU pipelines as 10209883Sandreas@sandberg.pp.se * possible. This *doesn't* include actually advancing the pipelines. 10219883Sandreas@sandberg.pp.se * 10229883Sandreas@sandberg.pp.se * We do this by looping on the front of the inFlightInsts queue for as 10239883Sandreas@sandberg.pp.se * long as we can find the desired instruction at the end of the 10249883Sandreas@sandberg.pp.se * functional unit it was issued to without seeing a branch or a fault. 10259883Sandreas@sandberg.pp.se * In this function, these terms are used: 10269883Sandreas@sandberg.pp.se * complete -- The instruction has finished its passage through 10279883Sandreas@sandberg.pp.se * its functional unit and its fate has been decided 102810113Sandreas@sandberg.pp.se * (committed, discarded, issued to the memory system) 10299883Sandreas@sandberg.pp.se * commit -- The instruction is complete(d), not discarded and has 10309883Sandreas@sandberg.pp.se * its effects applied to the CPU state 10319883Sandreas@sandberg.pp.se * discard(ed) -- The instruction is complete but not committed 10329883Sandreas@sandberg.pp.se * as its streamSeqNum disagrees with the current 10339883Sandreas@sandberg.pp.se * Execute::streamSeqNum 10349883Sandreas@sandberg.pp.se * 10359883Sandreas@sandberg.pp.se * Commits are also possible from two other places: 10369883Sandreas@sandberg.pp.se * 10379883Sandreas@sandberg.pp.se * 1) Responses returning from the LSQ 10389883Sandreas@sandberg.pp.se * 2) Mem ops issued to the LSQ ('committed' from the FUs) earlier 10399883Sandreas@sandberg.pp.se * than their position in the inFlightInsts queue, but after all 10409883Sandreas@sandberg.pp.se * their dependencies are resolved. 10419883Sandreas@sandberg.pp.se */ 10429883Sandreas@sandberg.pp.se 10439883Sandreas@sandberg.pp.se /* Has an instruction been completed? Once this becomes false, we stop 10449890Sandreas@sandberg.pp.se * trying to complete instructions. */ 10459890Sandreas@sandberg.pp.se bool completed_inst = true; 10469890Sandreas@sandberg.pp.se 10479890Sandreas@sandberg.pp.se /* Number of insts committed this cycle to check against commitLimit */ 10489890Sandreas@sandberg.pp.se unsigned int num_insts_committed = 0; 10499890Sandreas@sandberg.pp.se 10509890Sandreas@sandberg.pp.se /* Number of memory access instructions committed to check against 10519890Sandreas@sandberg.pp.se * memCommitLimit */ 10529890Sandreas@sandberg.pp.se unsigned int num_mem_refs_committed = 0; 10539890Sandreas@sandberg.pp.se 10549890Sandreas@sandberg.pp.se if (only_commit_microops && !ex_info.inFlightInsts->empty()) { 10559890Sandreas@sandberg.pp.se DPRINTF(MinorInterrupt, "Only commit microops %s %d\n", 10569890Sandreas@sandberg.pp.se *(ex_info.inFlightInsts->front().inst), 10579890Sandreas@sandberg.pp.se ex_info.lastCommitWasEndOfMacroop); 10589890Sandreas@sandberg.pp.se } 10599890Sandreas@sandberg.pp.se 10609890Sandreas@sandberg.pp.se while (!ex_info.inFlightInsts->empty() && /* Some more instructions to process */ 10619890Sandreas@sandberg.pp.se !branch.isStreamChange() && /* No real branch */ 10629890Sandreas@sandberg.pp.se fault == NoFault && /* No faults */ 10639890Sandreas@sandberg.pp.se completed_inst && /* Still finding instructions to execute */ 10649890Sandreas@sandberg.pp.se num_insts_committed != commitLimit && /* Not reached commit limit */ 10659890Sandreas@sandberg.pp.se cpu.getContext(thread_id)->status() != ThreadContext::Suspended 10669890Sandreas@sandberg.pp.se ) 10679890Sandreas@sandberg.pp.se { 10689890Sandreas@sandberg.pp.se if (only_commit_microops) { 10699890Sandreas@sandberg.pp.se DPRINTF(MinorInterrupt, "Committing tail of insts before" 10709890Sandreas@sandberg.pp.se " interrupt: %s\n", 10719890Sandreas@sandberg.pp.se *(ex_info.inFlightInsts->front().inst)); 10729890Sandreas@sandberg.pp.se } 10739890Sandreas@sandberg.pp.se 10749890Sandreas@sandberg.pp.se QueuedInst *head_inflight_inst = &(ex_info.inFlightInsts->front()); 10759890Sandreas@sandberg.pp.se 10769890Sandreas@sandberg.pp.se InstSeqNum head_exec_seq_num = 10779890Sandreas@sandberg.pp.se head_inflight_inst->inst->id.execSeqNum; 10789890Sandreas@sandberg.pp.se 10799890Sandreas@sandberg.pp.se /* The instruction we actually process if completed_inst 10809890Sandreas@sandberg.pp.se * remains true to the end of the loop body. 10819890Sandreas@sandberg.pp.se * Start by considering the the head of the in flight insts queue */ 10829890Sandreas@sandberg.pp.se MinorDynInstPtr inst = head_inflight_inst->inst; 10839883Sandreas@sandberg.pp.se 108410113Sandreas@sandberg.pp.se bool committed_inst = false; 10859883Sandreas@sandberg.pp.se bool discard_inst = false; 10869890Sandreas@sandberg.pp.se bool completed_mem_ref = false; 10879890Sandreas@sandberg.pp.se bool issued_mem_ref = false; 10889890Sandreas@sandberg.pp.se bool early_memory_issue = false; 10899890Sandreas@sandberg.pp.se 10909890Sandreas@sandberg.pp.se /* Must set this again to go around the loop */ 10919890Sandreas@sandberg.pp.se completed_inst = false; 10929890Sandreas@sandberg.pp.se 10939890Sandreas@sandberg.pp.se /* If we're just completing a macroop before an interrupt or drain, 10949890Sandreas@sandberg.pp.se * can we stil commit another microop (rather than a memory response) 109510113Sandreas@sandberg.pp.se * without crosing into the next full instruction? */ 10969890Sandreas@sandberg.pp.se bool can_commit_insts = !ex_info.inFlightInsts->empty() && 109710113Sandreas@sandberg.pp.se !(only_commit_microops && ex_info.lastCommitWasEndOfMacroop); 10989890Sandreas@sandberg.pp.se 10999890Sandreas@sandberg.pp.se /* Can we find a mem response for this inst */ 11009890Sandreas@sandberg.pp.se LSQ::LSQRequestPtr mem_response = 11019890Sandreas@sandberg.pp.se (inst->inLSQ ? lsq.findResponse(inst) : NULL); 11029890Sandreas@sandberg.pp.se 11039890Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Trying to commit canCommitInsts: %d\n", 11049890Sandreas@sandberg.pp.se can_commit_insts); 11059883Sandreas@sandberg.pp.se 11069883Sandreas@sandberg.pp.se /* Test for PC events after every instruction */ 11079883Sandreas@sandberg.pp.se if (isInbetweenInsts(thread_id) && tryPCEvents(thread_id)) { 11089883Sandreas@sandberg.pp.se ThreadContext *thread = cpu.getContext(thread_id); 11099883Sandreas@sandberg.pp.se 11109883Sandreas@sandberg.pp.se /* Branch as there was a change in PC */ 11119883Sandreas@sandberg.pp.se updateBranchData(thread_id, BranchData::UnpredictedBranch, 11129883Sandreas@sandberg.pp.se MinorDynInst::bubble(), thread->pcState(), branch); 11139883Sandreas@sandberg.pp.se } else if (mem_response && 11149883Sandreas@sandberg.pp.se num_mem_refs_committed < memoryCommitLimit) 11159883Sandreas@sandberg.pp.se { 11169883Sandreas@sandberg.pp.se /* Try to commit from the memory responses next */ 11179883Sandreas@sandberg.pp.se discard_inst = inst->id.streamSeqNum != 11189883Sandreas@sandberg.pp.se ex_info.streamSeqNum || discard; 11199883Sandreas@sandberg.pp.se 11209883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Trying to commit mem response: %s\n", 11219883Sandreas@sandberg.pp.se *inst); 11229883Sandreas@sandberg.pp.se 11239883Sandreas@sandberg.pp.se /* Complete or discard the response */ 11249883Sandreas@sandberg.pp.se if (discard_inst) { 11259883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Discarding mem inst: %s as its" 11269883Sandreas@sandberg.pp.se " stream state was unexpected, expected: %d\n", 11279883Sandreas@sandberg.pp.se *inst, ex_info.streamSeqNum); 11289883Sandreas@sandberg.pp.se 11299883Sandreas@sandberg.pp.se lsq.popResponse(mem_response); 11309883Sandreas@sandberg.pp.se } else { 11319883Sandreas@sandberg.pp.se handleMemResponse(inst, mem_response, branch, fault); 11329883Sandreas@sandberg.pp.se committed_inst = true; 11339883Sandreas@sandberg.pp.se } 11349883Sandreas@sandberg.pp.se 11359883Sandreas@sandberg.pp.se completed_mem_ref = true; 11369883Sandreas@sandberg.pp.se completed_inst = true; 11379883Sandreas@sandberg.pp.se } else if (can_commit_insts) { 11389883Sandreas@sandberg.pp.se /* If true, this instruction will, subject to timing tweaks, 11399883Sandreas@sandberg.pp.se * be considered for completion. try_to_commit flattens 114010157Sandreas@sandberg.pp.se * the `if' tree a bit and allows other tests for inst 114110157Sandreas@sandberg.pp.se * commit to be inserted here. */ 11429883Sandreas@sandberg.pp.se bool try_to_commit = false; 11439883Sandreas@sandberg.pp.se 114410157Sandreas@sandberg.pp.se /* Try and issue memory ops early if they: 114510157Sandreas@sandberg.pp.se * - Can push a request into the LSQ 114610157Sandreas@sandberg.pp.se * - Have reached the end of their FUs 114710157Sandreas@sandberg.pp.se * - Have had all their dependencies satisfied 114810157Sandreas@sandberg.pp.se * - Are from the right stream 114910157Sandreas@sandberg.pp.se * 115011150Smitch.hayenga@arm.com * For any other case, leave it to the normal instruction 115111150Smitch.hayenga@arm.com * issue below to handle them. 115211150Smitch.hayenga@arm.com */ 115310157Sandreas@sandberg.pp.se if (!ex_info.inFUMemInsts->empty() && lsq.canRequest()) { 11549883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Trying to commit from mem FUs\n"); 11559883Sandreas@sandberg.pp.se 115610112Sandreas@sandberg.pp.se const MinorDynInstPtr head_mem_ref_inst = 115710112Sandreas@sandberg.pp.se ex_info.inFUMemInsts->front().inst; 115810112Sandreas@sandberg.pp.se FUPipeline *fu = funcUnits[head_mem_ref_inst->fuIndex]; 115910112Sandreas@sandberg.pp.se const MinorDynInstPtr &fu_inst = fu->front().inst; 116010112Sandreas@sandberg.pp.se 116110112Sandreas@sandberg.pp.se /* Use this, possibly out of order, inst as the one 116210112Sandreas@sandberg.pp.se * to 'commit'/send to the LSQ */ 116310112Sandreas@sandberg.pp.se if (!fu_inst->isBubble() && 116410112Sandreas@sandberg.pp.se !fu_inst->inLSQ && 116510112Sandreas@sandberg.pp.se fu_inst->canEarlyIssue && 116610112Sandreas@sandberg.pp.se ex_info.streamSeqNum == fu_inst->id.streamSeqNum && 116710112Sandreas@sandberg.pp.se head_exec_seq_num > fu_inst->instToWaitFor) 116810112Sandreas@sandberg.pp.se { 116910112Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Issuing mem ref early" 117010112Sandreas@sandberg.pp.se " inst: %s instToWaitFor: %d\n", 117110112Sandreas@sandberg.pp.se *(fu_inst), fu_inst->instToWaitFor); 117210112Sandreas@sandberg.pp.se 117310112Sandreas@sandberg.pp.se inst = fu_inst; 117410112Sandreas@sandberg.pp.se try_to_commit = true; 117510112Sandreas@sandberg.pp.se early_memory_issue = true; 117610112Sandreas@sandberg.pp.se completed_inst = true; 11779883Sandreas@sandberg.pp.se } 11789883Sandreas@sandberg.pp.se } 11799883Sandreas@sandberg.pp.se 11809883Sandreas@sandberg.pp.se /* Try and commit FU-less insts */ 11819883Sandreas@sandberg.pp.se if (!completed_inst && inst->isNoCostInst()) { 11829883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Committing no cost inst: %s", *inst); 11839883Sandreas@sandberg.pp.se 11849883Sandreas@sandberg.pp.se try_to_commit = true; 11859883Sandreas@sandberg.pp.se completed_inst = true; 11869883Sandreas@sandberg.pp.se } 11879883Sandreas@sandberg.pp.se 11889883Sandreas@sandberg.pp.se /* Try to issue from the ends of FUs and the inFlightInsts 11899883Sandreas@sandberg.pp.se * queue */ 11909883Sandreas@sandberg.pp.se if (!completed_inst && !inst->inLSQ) { 11919883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Trying to commit from FUs\n"); 11929883Sandreas@sandberg.pp.se 11939883Sandreas@sandberg.pp.se /* Try to commit from a functional unit */ 11949883Sandreas@sandberg.pp.se /* Is the head inst of the expected inst's FU actually the 119511150Smitch.hayenga@arm.com * expected inst? */ 119611150Smitch.hayenga@arm.com QueuedInst &fu_inst = 119710112Sandreas@sandberg.pp.se funcUnits[inst->fuIndex]->front(); 119810112Sandreas@sandberg.pp.se InstSeqNum fu_inst_seq_num = fu_inst.inst->id.execSeqNum; 119910112Sandreas@sandberg.pp.se 120010112Sandreas@sandberg.pp.se if (fu_inst.inst->isBubble()) { 120110112Sandreas@sandberg.pp.se /* No instruction ready */ 12029883Sandreas@sandberg.pp.se completed_inst = false; 12039883Sandreas@sandberg.pp.se } else if (fu_inst_seq_num != head_exec_seq_num) { 12049883Sandreas@sandberg.pp.se /* Past instruction: we must have already executed it 12059883Sandreas@sandberg.pp.se * in the same cycle and so the head inst isn't 12069883Sandreas@sandberg.pp.se * actually at the end of its pipeline 12079883Sandreas@sandberg.pp.se * Future instruction: handled above and only for 120811150Smitch.hayenga@arm.com * mem refs on their way to the LSQ */ 12099883Sandreas@sandberg.pp.se } else if (fu_inst.inst->id == inst->id) { 12109883Sandreas@sandberg.pp.se /* All instructions can be committed if they have the 12119883Sandreas@sandberg.pp.se * right execSeqNum and there are no in-flight 12129883Sandreas@sandberg.pp.se * mem insts before us */ 12139883Sandreas@sandberg.pp.se try_to_commit = true; 12149883Sandreas@sandberg.pp.se completed_inst = true; 12159883Sandreas@sandberg.pp.se } 12169883Sandreas@sandberg.pp.se } 12179883Sandreas@sandberg.pp.se 12189883Sandreas@sandberg.pp.se if (try_to_commit) { 12199883Sandreas@sandberg.pp.se discard_inst = inst->id.streamSeqNum != 12209883Sandreas@sandberg.pp.se ex_info.streamSeqNum || discard; 12219883Sandreas@sandberg.pp.se 12229883Sandreas@sandberg.pp.se /* Is this instruction discardable as its streamSeqNum 12239883Sandreas@sandberg.pp.se * doesn't match? */ 12249883Sandreas@sandberg.pp.se if (!discard_inst) { 12259883Sandreas@sandberg.pp.se /* Try to commit or discard a non-memory instruction. 12269883Sandreas@sandberg.pp.se * Memory ops are actually 'committed' from this FUs 12279883Sandreas@sandberg.pp.se * and 'issued' into the memory system so we need to 122810112Sandreas@sandberg.pp.se * account for them later (commit_was_mem_issue gets 122910112Sandreas@sandberg.pp.se * set) */ 123010112Sandreas@sandberg.pp.se if (inst->extraCommitDelayExpr) { 123110112Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Evaluating expression for" 123210112Sandreas@sandberg.pp.se " extra commit delay inst: %s\n", *inst); 123310112Sandreas@sandberg.pp.se 12349883Sandreas@sandberg.pp.se ThreadContext *thread = cpu.getContext(thread_id); 12359883Sandreas@sandberg.pp.se 12369883Sandreas@sandberg.pp.se TimingExprEvalContext context(inst->staticInst, 12379883Sandreas@sandberg.pp.se thread, NULL); 12389883Sandreas@sandberg.pp.se 12399883Sandreas@sandberg.pp.se uint64_t extra_delay = inst->extraCommitDelayExpr-> 12409883Sandreas@sandberg.pp.se eval(context); 12419883Sandreas@sandberg.pp.se 12429883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Extra commit delay expr" 12439883Sandreas@sandberg.pp.se " result: %d\n", extra_delay); 12449883Sandreas@sandberg.pp.se 12459883Sandreas@sandberg.pp.se if (extra_delay < 128) { 12469883Sandreas@sandberg.pp.se inst->extraCommitDelay += Cycles(extra_delay); 12479883Sandreas@sandberg.pp.se } else { 12489883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Extra commit delay was" 12499883Sandreas@sandberg.pp.se " very long: %d\n", extra_delay); 12509883Sandreas@sandberg.pp.se } 12519883Sandreas@sandberg.pp.se inst->extraCommitDelayExpr = NULL; 12529883Sandreas@sandberg.pp.se } 12539883Sandreas@sandberg.pp.se 12549883Sandreas@sandberg.pp.se /* Move the extraCommitDelay from the instruction 12559883Sandreas@sandberg.pp.se * into the minimumCommitCycle */ 12569883Sandreas@sandberg.pp.se if (inst->extraCommitDelay != Cycles(0)) { 12579883Sandreas@sandberg.pp.se inst->minimumCommitCycle = cpu.curCycle() + 12589883Sandreas@sandberg.pp.se inst->extraCommitDelay; 12599883Sandreas@sandberg.pp.se inst->extraCommitDelay = Cycles(0); 12609883Sandreas@sandberg.pp.se } 12619883Sandreas@sandberg.pp.se 12629883Sandreas@sandberg.pp.se /* @todo Think about making lastMemBarrier be 12639883Sandreas@sandberg.pp.se * MAX_UINT_64 to avoid using 0 as a marker value */ 12649883Sandreas@sandberg.pp.se if (!inst->isFault() && inst->isMemRef() && 12659883Sandreas@sandberg.pp.se lsq.getLastMemBarrier(thread_id) < 12669883Sandreas@sandberg.pp.se inst->id.execSeqNum && 12679883Sandreas@sandberg.pp.se lsq.getLastMemBarrier(thread_id) != 0) 12689883Sandreas@sandberg.pp.se { 12699883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Not committing inst: %s yet" 12709883Sandreas@sandberg.pp.se " as there are incomplete barriers in flight\n", 12719883Sandreas@sandberg.pp.se *inst); 12729883Sandreas@sandberg.pp.se completed_inst = false; 12739883Sandreas@sandberg.pp.se } else if (inst->minimumCommitCycle > now) { 12749883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Not committing inst: %s yet" 12759883Sandreas@sandberg.pp.se " as it wants to be stalled for %d more cycles\n", 12769883Sandreas@sandberg.pp.se *inst, inst->minimumCommitCycle - now); 12779883Sandreas@sandberg.pp.se completed_inst = false; 12789883Sandreas@sandberg.pp.se } else { 12799883Sandreas@sandberg.pp.se completed_inst = commitInst(inst, 12809883Sandreas@sandberg.pp.se early_memory_issue, branch, fault, 12819883Sandreas@sandberg.pp.se committed_inst, issued_mem_ref); 12829883Sandreas@sandberg.pp.se } 12839883Sandreas@sandberg.pp.se } else { 12849883Sandreas@sandberg.pp.se /* Discard instruction */ 12859883Sandreas@sandberg.pp.se completed_inst = true; 12869883Sandreas@sandberg.pp.se } 12879883Sandreas@sandberg.pp.se 12889883Sandreas@sandberg.pp.se if (completed_inst) { 12899883Sandreas@sandberg.pp.se /* Allow the pipeline to advance. If the FU head 12909883Sandreas@sandberg.pp.se * instruction wasn't the inFlightInsts head 12919883Sandreas@sandberg.pp.se * but had already been committed, it would have 12929883Sandreas@sandberg.pp.se * unstalled the pipeline before here */ 12939883Sandreas@sandberg.pp.se if (inst->fuIndex != noCostFUIndex) { 12949883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Unstalling %d for inst %s\n", inst->fuIndex, inst->id); 12959883Sandreas@sandberg.pp.se funcUnits[inst->fuIndex]->stalled = false; 12969883Sandreas@sandberg.pp.se } 12979883Sandreas@sandberg.pp.se } 12989883Sandreas@sandberg.pp.se } 12999883Sandreas@sandberg.pp.se } else { 13009883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "No instructions to commit\n"); 13019883Sandreas@sandberg.pp.se completed_inst = false; 13029883Sandreas@sandberg.pp.se } 13039883Sandreas@sandberg.pp.se 13049883Sandreas@sandberg.pp.se /* All discardable instructions must also be 'completed' by now */ 13059883Sandreas@sandberg.pp.se assert(!(discard_inst && !completed_inst)); 13069883Sandreas@sandberg.pp.se 13079883Sandreas@sandberg.pp.se /* Instruction committed but was discarded due to streamSeqNum 13089883Sandreas@sandberg.pp.se * mismatch */ 13099883Sandreas@sandberg.pp.se if (discard_inst) { 13109883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Discarding inst: %s as its stream" 13119883Sandreas@sandberg.pp.se " state was unexpected, expected: %d\n", 13129883Sandreas@sandberg.pp.se *inst, ex_info.streamSeqNum); 13139883Sandreas@sandberg.pp.se 13149883Sandreas@sandberg.pp.se if (fault == NoFault) 13159883Sandreas@sandberg.pp.se cpu.stats.numDiscardedOps++; 13169883Sandreas@sandberg.pp.se } 13179883Sandreas@sandberg.pp.se 13189883Sandreas@sandberg.pp.se /* Mark the mem inst as being in the LSQ */ 13199883Sandreas@sandberg.pp.se if (issued_mem_ref) { 13209883Sandreas@sandberg.pp.se inst->fuIndex = 0; 13219883Sandreas@sandberg.pp.se inst->inLSQ = true; 13229883Sandreas@sandberg.pp.se } 13239883Sandreas@sandberg.pp.se 13249883Sandreas@sandberg.pp.se /* Pop issued (to LSQ) and discarded mem refs from the inFUMemInsts 13259883Sandreas@sandberg.pp.se * as they've *definitely* exited the FUs */ 13269883Sandreas@sandberg.pp.se if (completed_inst && inst->isMemRef()) { 13279883Sandreas@sandberg.pp.se /* The MemRef could have been discarded from the FU or the memory 13289883Sandreas@sandberg.pp.se * queue, so just check an FU instruction */ 13299883Sandreas@sandberg.pp.se if (!ex_info.inFUMemInsts->empty() && 13309883Sandreas@sandberg.pp.se ex_info.inFUMemInsts->front().inst == inst) 13319883Sandreas@sandberg.pp.se { 13329883Sandreas@sandberg.pp.se ex_info.inFUMemInsts->pop(); 13339883Sandreas@sandberg.pp.se } 13349883Sandreas@sandberg.pp.se } 13359883Sandreas@sandberg.pp.se 13369883Sandreas@sandberg.pp.se if (completed_inst && !(issued_mem_ref && fault == NoFault)) { 13379883Sandreas@sandberg.pp.se /* Note that this includes discarded insts */ 13389883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Completed inst: %s\n", *inst); 13399883Sandreas@sandberg.pp.se 13409883Sandreas@sandberg.pp.se /* Got to the end of a full instruction? */ 13419883Sandreas@sandberg.pp.se ex_info.lastCommitWasEndOfMacroop = inst->isFault() || 13429883Sandreas@sandberg.pp.se inst->isLastOpInInst(); 13439883Sandreas@sandberg.pp.se 13449883Sandreas@sandberg.pp.se /* lastPredictionSeqNum is kept as a convenience to prevent its 13459883Sandreas@sandberg.pp.se * value from changing too much on the minorview display */ 13469883Sandreas@sandberg.pp.se ex_info.lastPredictionSeqNum = inst->id.predictionSeqNum; 13479883Sandreas@sandberg.pp.se 13489883Sandreas@sandberg.pp.se /* Finished with the inst, remove it from the inst queue and 13499883Sandreas@sandberg.pp.se * clear its dependencies */ 13509883Sandreas@sandberg.pp.se ex_info.inFlightInsts->pop(); 13519883Sandreas@sandberg.pp.se 13529883Sandreas@sandberg.pp.se /* Complete barriers in the LSQ/move to store buffer */ 135312155Sandreas.sandberg@arm.com if (inst->isInst() && inst->staticInst->isMemBarrier()) { 135412155Sandreas.sandberg@arm.com DPRINTF(MinorMem, "Completing memory barrier" 135512155Sandreas.sandberg@arm.com " inst: %s committed: %d\n", *inst, committed_inst); 13569883Sandreas@sandberg.pp.se lsq.completeMemBarrierInst(inst, committed_inst); 135712749Sgiacomo.travaglini@arm.com } 135812749Sgiacomo.travaglini@arm.com 135912749Sgiacomo.travaglini@arm.com scoreboard[thread_id].clearInstDests(inst, inst->isMemRef()); 136012749Sgiacomo.travaglini@arm.com } 136111629Smichael.lebeane@amd.com 13629883Sandreas@sandberg.pp.se /* Handle per-cycle instruction counting */ 136311629Smichael.lebeane@amd.com if (committed_inst) { 136411629Smichael.lebeane@amd.com bool is_no_cost_inst = inst->isNoCostInst(); 136511629Smichael.lebeane@amd.com 136611629Smichael.lebeane@amd.com /* Don't show no cost instructions as having taken a commit 13679883Sandreas@sandberg.pp.se * slot */ 13689883Sandreas@sandberg.pp.se if (DTRACE(MinorTrace) && !is_no_cost_inst) 13699883Sandreas@sandberg.pp.se ex_info.instsBeingCommitted.insts[num_insts_committed] = inst; 13709883Sandreas@sandberg.pp.se 13719883Sandreas@sandberg.pp.se if (!is_no_cost_inst) 13729883Sandreas@sandberg.pp.se num_insts_committed++; 13739883Sandreas@sandberg.pp.se 13749883Sandreas@sandberg.pp.se if (num_insts_committed == commitLimit) 13759883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Reached inst commit limit\n"); 13769883Sandreas@sandberg.pp.se 13779883Sandreas@sandberg.pp.se /* Re-set the time of the instruction if that's required for 13789883Sandreas@sandberg.pp.se * tracing */ 13799883Sandreas@sandberg.pp.se if (inst->traceData) { 13809883Sandreas@sandberg.pp.se if (setTraceTimeOnCommit) 13819883Sandreas@sandberg.pp.se inst->traceData->setWhen(curTick()); 13829883Sandreas@sandberg.pp.se inst->traceData->dump(); 13839883Sandreas@sandberg.pp.se } 13849883Sandreas@sandberg.pp.se 13859883Sandreas@sandberg.pp.se if (completed_mem_ref) 13869883Sandreas@sandberg.pp.se num_mem_refs_committed++; 13879883Sandreas@sandberg.pp.se 13889883Sandreas@sandberg.pp.se if (num_mem_refs_committed == memoryCommitLimit) 13899883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Reached mem ref commit limit\n"); 13909883Sandreas@sandberg.pp.se } 13919883Sandreas@sandberg.pp.se } 13929883Sandreas@sandberg.pp.se} 13939883Sandreas@sandberg.pp.se 13949883Sandreas@sandberg.pp.sebool 13959883Sandreas@sandberg.pp.seExecute::isInbetweenInsts(ThreadID thread_id) const 13969883Sandreas@sandberg.pp.se{ 13979883Sandreas@sandberg.pp.se return executeInfo[thread_id].lastCommitWasEndOfMacroop && 13989883Sandreas@sandberg.pp.se !lsq.accessesInFlight(); 13999883Sandreas@sandberg.pp.se} 14009883Sandreas@sandberg.pp.se 14019883Sandreas@sandberg.pp.sevoid 14029883Sandreas@sandberg.pp.seExecute::evaluate() 14039883Sandreas@sandberg.pp.se{ 14049883Sandreas@sandberg.pp.se if (!inp.outputWire->isBubble()) 14059883Sandreas@sandberg.pp.se inputBuffer[inp.outputWire->threadId].setTail(*inp.outputWire); 14069883Sandreas@sandberg.pp.se 14079883Sandreas@sandberg.pp.se BranchData &branch = *out.inputWire; 14089883Sandreas@sandberg.pp.se 14099883Sandreas@sandberg.pp.se unsigned int num_issued = 0; 14109883Sandreas@sandberg.pp.se 14119883Sandreas@sandberg.pp.se /* Do all the cycle-wise activities for dcachePort here to potentially 14129883Sandreas@sandberg.pp.se * free up input spaces in the LSQ's requests queue */ 14139883Sandreas@sandberg.pp.se lsq.step(); 14149883Sandreas@sandberg.pp.se 14159883Sandreas@sandberg.pp.se /* Check interrupts first. Will halt commit if interrupt found */ 14169883Sandreas@sandberg.pp.se bool interrupted = false; 14179883Sandreas@sandberg.pp.se ThreadID interrupt_tid = checkInterrupts(branch, interrupted); 14189883Sandreas@sandberg.pp.se 14199883Sandreas@sandberg.pp.se if (interrupt_tid != InvalidThreadID) { 14209883Sandreas@sandberg.pp.se /* Signalling an interrupt this cycle, not issuing/committing from 14219883Sandreas@sandberg.pp.se * any other threads */ 14229883Sandreas@sandberg.pp.se } else if (!branch.isBubble()) { 14239883Sandreas@sandberg.pp.se /* It's important that this is here to carry Fetch1 wakeups to Fetch1 14249883Sandreas@sandberg.pp.se * without overwriting them */ 14259883Sandreas@sandberg.pp.se DPRINTF(MinorInterrupt, "Execute skipping a cycle to allow old" 14269883Sandreas@sandberg.pp.se " branch to complete\n"); 14279883Sandreas@sandberg.pp.se } else { 14289883Sandreas@sandberg.pp.se ThreadID commit_tid = getCommittingThread(); 14299883Sandreas@sandberg.pp.se 14309883Sandreas@sandberg.pp.se if (commit_tid != InvalidThreadID) { 14319883Sandreas@sandberg.pp.se ExecuteThreadInfo& commit_info = executeInfo[commit_tid]; 14329883Sandreas@sandberg.pp.se 14339883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Attempting to commit [tid:%d]\n", 14349883Sandreas@sandberg.pp.se commit_tid); 14359883Sandreas@sandberg.pp.se /* commit can set stalled flags observable to issue and so *must* be 14369883Sandreas@sandberg.pp.se * called first */ 14379883Sandreas@sandberg.pp.se if (commit_info.drainState != NotDraining) { 14389883Sandreas@sandberg.pp.se if (commit_info.drainState == DrainCurrentInst) { 14399883Sandreas@sandberg.pp.se /* Commit only micro-ops, don't kill anything else */ 14409883Sandreas@sandberg.pp.se commit(commit_tid, true, false, branch); 14419883Sandreas@sandberg.pp.se 14429883Sandreas@sandberg.pp.se if (isInbetweenInsts(commit_tid)) 14439883Sandreas@sandberg.pp.se setDrainState(commit_tid, DrainHaltFetch); 14449883Sandreas@sandberg.pp.se 14459883Sandreas@sandberg.pp.se /* Discard any generated branch */ 14469883Sandreas@sandberg.pp.se branch = BranchData::bubble(); 14479883Sandreas@sandberg.pp.se } else if (commit_info.drainState == DrainAllInsts) { 14489883Sandreas@sandberg.pp.se /* Kill all instructions */ 14499883Sandreas@sandberg.pp.se while (getInput(commit_tid)) 14509883Sandreas@sandberg.pp.se popInput(commit_tid); 14519883Sandreas@sandberg.pp.se commit(commit_tid, false, true, branch); 14529883Sandreas@sandberg.pp.se } 14539883Sandreas@sandberg.pp.se } else { 14549883Sandreas@sandberg.pp.se /* Commit micro-ops only if interrupted. Otherwise, commit 14559883Sandreas@sandberg.pp.se * anything you like */ 14569883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Committing micro-ops for interrupt[tid:%d]\n", 14579883Sandreas@sandberg.pp.se commit_tid); 14589883Sandreas@sandberg.pp.se bool only_commit_microops = interrupted && 14599883Sandreas@sandberg.pp.se hasInterrupt(commit_tid); 14609883Sandreas@sandberg.pp.se commit(commit_tid, only_commit_microops, false, branch); 14619883Sandreas@sandberg.pp.se } 14629883Sandreas@sandberg.pp.se 14639883Sandreas@sandberg.pp.se /* Halt fetch, but don't do it until we have the current instruction in 14649883Sandreas@sandberg.pp.se * the bag */ 14659883Sandreas@sandberg.pp.se if (commit_info.drainState == DrainHaltFetch) { 14669883Sandreas@sandberg.pp.se updateBranchData(commit_tid, BranchData::HaltFetch, 14679883Sandreas@sandberg.pp.se MinorDynInst::bubble(), TheISA::PCState(0), branch); 14689883Sandreas@sandberg.pp.se 14699883Sandreas@sandberg.pp.se cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 14709883Sandreas@sandberg.pp.se setDrainState(commit_tid, DrainAllInsts); 14719883Sandreas@sandberg.pp.se } 14729883Sandreas@sandberg.pp.se } 14739883Sandreas@sandberg.pp.se ThreadID issue_tid = getIssuingThread(); 14749883Sandreas@sandberg.pp.se /* This will issue merrily even when interrupted in the sure and 14759883Sandreas@sandberg.pp.se * certain knowledge that the interrupt with change the stream */ 14769883Sandreas@sandberg.pp.se if (issue_tid != InvalidThreadID) { 14779883Sandreas@sandberg.pp.se DPRINTF(MinorExecute, "Attempting to issue [tid:%d]\n", 14789883Sandreas@sandberg.pp.se issue_tid); 14799883Sandreas@sandberg.pp.se num_issued = issue(issue_tid); 14809883Sandreas@sandberg.pp.se } 14819883Sandreas@sandberg.pp.se 14829883Sandreas@sandberg.pp.se } 14839883Sandreas@sandberg.pp.se 14849883Sandreas@sandberg.pp.se /* Run logic to step functional units + decide if we are active on the next 14859883Sandreas@sandberg.pp.se * clock cycle */ 14869883Sandreas@sandberg.pp.se std::vector<MinorDynInstPtr> next_issuable_insts; 14879883Sandreas@sandberg.pp.se bool can_issue_next = false; 14889883Sandreas@sandberg.pp.se 14899883Sandreas@sandberg.pp.se for (ThreadID tid = 0; tid < cpu.numThreads; tid++) { 14909883Sandreas@sandberg.pp.se /* Find the next issuable instruction for each thread and see if it can 14919883Sandreas@sandberg.pp.se be issued */ 14929883Sandreas@sandberg.pp.se if (getInput(tid)) { 14939883Sandreas@sandberg.pp.se unsigned int input_index = executeInfo[tid].inputIndex; 14949883Sandreas@sandberg.pp.se MinorDynInstPtr inst = getInput(tid)->insts[input_index]; 14959883Sandreas@sandberg.pp.se if (inst->isFault()) { 14969883Sandreas@sandberg.pp.se can_issue_next = true; 14979883Sandreas@sandberg.pp.se } else if (!inst->isBubble()) { 14989883Sandreas@sandberg.pp.se next_issuable_insts.push_back(inst); 14999883Sandreas@sandberg.pp.se } 15009883Sandreas@sandberg.pp.se } 15019883Sandreas@sandberg.pp.se } 15029883Sandreas@sandberg.pp.se 15039883Sandreas@sandberg.pp.se bool becoming_stalled = true; 15049883Sandreas@sandberg.pp.se 15059883Sandreas@sandberg.pp.se /* Advance the pipelines and note whether they still need to be 15069883Sandreas@sandberg.pp.se * advanced */ 15079883Sandreas@sandberg.pp.se for (unsigned int i = 0; i < numFuncUnits; i++) { 15089883Sandreas@sandberg.pp.se FUPipeline *fu = funcUnits[i]; 15099883Sandreas@sandberg.pp.se fu->advance(); 15109883Sandreas@sandberg.pp.se 15119883Sandreas@sandberg.pp.se /* If we need to tick again, the pipeline will have been left or set 15129883Sandreas@sandberg.pp.se * to be unstalled */ 15139883Sandreas@sandberg.pp.se if (fu->occupancy !=0 && !fu->stalled) 15149883Sandreas@sandberg.pp.se becoming_stalled = false; 15159883Sandreas@sandberg.pp.se 15169883Sandreas@sandberg.pp.se /* Could we possibly issue the next instruction from any thread? 15179883Sandreas@sandberg.pp.se * This is quite an expensive test and is only used to determine 15189883Sandreas@sandberg.pp.se * if the CPU should remain active, only run it if we aren't sure 15199883Sandreas@sandberg.pp.se * we are active next cycle yet */ 15209883Sandreas@sandberg.pp.se for (auto inst : next_issuable_insts) { 15219883Sandreas@sandberg.pp.se if (!fu->stalled && fu->provides(inst->staticInst->opClass()) && 15229883Sandreas@sandberg.pp.se scoreboard[inst->id.threadId].canInstIssue(inst, 15239883Sandreas@sandberg.pp.se NULL, NULL, cpu.curCycle() + Cycles(1), 15249883Sandreas@sandberg.pp.se cpu.getContext(inst->id.threadId))) { 15259883Sandreas@sandberg.pp.se can_issue_next = true; 15269883Sandreas@sandberg.pp.se break; 15279883Sandreas@sandberg.pp.se } 15289883Sandreas@sandberg.pp.se } 15299883Sandreas@sandberg.pp.se } 15309883Sandreas@sandberg.pp.se 15319883Sandreas@sandberg.pp.se bool head_inst_might_commit = false; 15329883Sandreas@sandberg.pp.se 15339883Sandreas@sandberg.pp.se /* Could the head in flight insts be committed */ 15349883Sandreas@sandberg.pp.se for (auto const &info : executeInfo) { 15359883Sandreas@sandberg.pp.se if (!info.inFlightInsts->empty()) { 15369883Sandreas@sandberg.pp.se const QueuedInst &head_inst = info.inFlightInsts->front(); 15379883Sandreas@sandberg.pp.se 15389883Sandreas@sandberg.pp.se if (head_inst.inst->isNoCostInst()) { 15399883Sandreas@sandberg.pp.se head_inst_might_commit = true; 15409883Sandreas@sandberg.pp.se } else { 15419883Sandreas@sandberg.pp.se FUPipeline *fu = funcUnits[head_inst.inst->fuIndex]; 15429883Sandreas@sandberg.pp.se if ((fu->stalled && 15439883Sandreas@sandberg.pp.se fu->front().inst->id == head_inst.inst->id) || 15449883Sandreas@sandberg.pp.se lsq.findResponse(head_inst.inst)) 15459883Sandreas@sandberg.pp.se { 15469883Sandreas@sandberg.pp.se head_inst_might_commit = true; 15479883Sandreas@sandberg.pp.se break; 154811363Sandreas@sandberg.pp.se } 15499883Sandreas@sandberg.pp.se } 15509883Sandreas@sandberg.pp.se } 15519883Sandreas@sandberg.pp.se } 15529883Sandreas@sandberg.pp.se 15539883Sandreas@sandberg.pp.se DPRINTF(Activity, "Need to tick num issued insts: %s%s%s%s%s%s\n", 15549883Sandreas@sandberg.pp.se (num_issued != 0 ? " (issued some insts)" : ""), 15559883Sandreas@sandberg.pp.se (becoming_stalled ? "(becoming stalled)" : "(not becoming stalled)"), 15569883Sandreas@sandberg.pp.se (can_issue_next ? " (can issued next inst)" : ""), 15579883Sandreas@sandberg.pp.se (head_inst_might_commit ? "(head inst might commit)" : ""), 15589883Sandreas@sandberg.pp.se (lsq.needsToTick() ? " (LSQ needs to tick)" : ""), 15599883Sandreas@sandberg.pp.se (interrupted ? " (interrupted)" : "")); 15609883Sandreas@sandberg.pp.se 15619883Sandreas@sandberg.pp.se bool need_to_tick = 15629883Sandreas@sandberg.pp.se num_issued != 0 || /* Issued some insts this cycle */ 15639883Sandreas@sandberg.pp.se !becoming_stalled || /* Some FU pipelines can still move */ 15649883Sandreas@sandberg.pp.se can_issue_next || /* Can still issue a new inst */ 15659883Sandreas@sandberg.pp.se head_inst_might_commit || /* Could possible commit the next inst */ 15669883Sandreas@sandberg.pp.se lsq.needsToTick() || /* Must step the dcache port */ 15679883Sandreas@sandberg.pp.se interrupted; /* There are pending interrupts */ 15689883Sandreas@sandberg.pp.se 15699883Sandreas@sandberg.pp.se if (!need_to_tick) { 15709883Sandreas@sandberg.pp.se DPRINTF(Activity, "The next cycle might be skippable as there are no" 15719883Sandreas@sandberg.pp.se " advanceable FUs\n"); 15729883Sandreas@sandberg.pp.se } 15739883Sandreas@sandberg.pp.se 15749883Sandreas@sandberg.pp.se /* Wake up if we need to tick again */ 15759883Sandreas@sandberg.pp.se if (need_to_tick) 15769883Sandreas@sandberg.pp.se cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 15779883Sandreas@sandberg.pp.se 15789883Sandreas@sandberg.pp.se /* Note activity of following buffer */ 15799883Sandreas@sandberg.pp.se if (!branch.isBubble()) 15809883Sandreas@sandberg.pp.se cpu.activityRecorder->activity(); 15819883Sandreas@sandberg.pp.se 15829883Sandreas@sandberg.pp.se /* Make sure the input (if any left) is pushed */ 15839883Sandreas@sandberg.pp.se if (!inp.outputWire->isBubble()) 15849883Sandreas@sandberg.pp.se inputBuffer[inp.outputWire->threadId].pushTail(); 15859883Sandreas@sandberg.pp.se} 15869883Sandreas@sandberg.pp.se 15879883Sandreas@sandberg.pp.seThreadID 15889883Sandreas@sandberg.pp.seExecute::checkInterrupts(BranchData& branch, bool& interrupted) 15899883Sandreas@sandberg.pp.se{ 15909883Sandreas@sandberg.pp.se ThreadID tid = interruptPriority; 15919883Sandreas@sandberg.pp.se /* Evaluate interrupts in round-robin based upon service */ 15929883Sandreas@sandberg.pp.se do { 15939883Sandreas@sandberg.pp.se /* Has an interrupt been signalled? This may not be acted on 15949883Sandreas@sandberg.pp.se * straighaway so this is different from took_interrupt */ 15959883Sandreas@sandberg.pp.se bool thread_interrupted = false; 15969883Sandreas@sandberg.pp.se 15979883Sandreas@sandberg.pp.se if (FullSystem && cpu.getInterruptController(tid)) { 15989883Sandreas@sandberg.pp.se /* This is here because it seems that after drainResume the 15999883Sandreas@sandberg.pp.se * interrupt controller isn't always set */ 16009883Sandreas@sandberg.pp.se thread_interrupted = executeInfo[tid].drainState == NotDraining && 16019883Sandreas@sandberg.pp.se isInterrupted(tid); 16029883Sandreas@sandberg.pp.se interrupted = interrupted || thread_interrupted; 16039883Sandreas@sandberg.pp.se } else { 16049883Sandreas@sandberg.pp.se DPRINTF(MinorInterrupt, "No interrupt controller\n"); 16059883Sandreas@sandberg.pp.se } 16069883Sandreas@sandberg.pp.se DPRINTF(MinorInterrupt, "[tid:%d] thread_interrupted?=%d isInbetweenInsts?=%d\n", 16079883Sandreas@sandberg.pp.se tid, thread_interrupted, isInbetweenInsts(tid)); 16089883Sandreas@sandberg.pp.se /* Act on interrupts */ 16099883Sandreas@sandberg.pp.se if (thread_interrupted && isInbetweenInsts(tid)) { 16109883Sandreas@sandberg.pp.se if (takeInterrupt(tid, branch)) { 16119883Sandreas@sandberg.pp.se interruptPriority = tid; 16129883Sandreas@sandberg.pp.se return tid; 16139883Sandreas@sandberg.pp.se } 16149883Sandreas@sandberg.pp.se } else { 16159883Sandreas@sandberg.pp.se tid = (tid + 1) % cpu.numThreads; 16169883Sandreas@sandberg.pp.se } 16179883Sandreas@sandberg.pp.se } while (tid != interruptPriority); 16189883Sandreas@sandberg.pp.se 16199883Sandreas@sandberg.pp.se return InvalidThreadID; 16209883Sandreas@sandberg.pp.se} 16219883Sandreas@sandberg.pp.se 16229883Sandreas@sandberg.pp.sebool 16239883Sandreas@sandberg.pp.seExecute::hasInterrupt(ThreadID thread_id) 16249883Sandreas@sandberg.pp.se{ 16259883Sandreas@sandberg.pp.se if (FullSystem && cpu.getInterruptController(thread_id)) { 16269883Sandreas@sandberg.pp.se return executeInfo[thread_id].drainState == NotDraining && 16279883Sandreas@sandberg.pp.se isInterrupted(thread_id); 16289883Sandreas@sandberg.pp.se } 16299883Sandreas@sandberg.pp.se 16309883Sandreas@sandberg.pp.se return false; 16319883Sandreas@sandberg.pp.se} 16329883Sandreas@sandberg.pp.se 16339883Sandreas@sandberg.pp.sevoid 16349883Sandreas@sandberg.pp.seExecute::minorTrace() const 1635{ 1636 std::ostringstream insts; 1637 std::ostringstream stalled; 1638 1639 executeInfo[0].instsBeingCommitted.reportData(insts); 1640 lsq.minorTrace(); 1641 inputBuffer[0].minorTrace(); 1642 scoreboard[0].minorTrace(); 1643 1644 /* Report functional unit stalling in one string */ 1645 unsigned int i = 0; 1646 while (i < numFuncUnits) 1647 { 1648 stalled << (funcUnits[i]->stalled ? '1' : 'E'); 1649 i++; 1650 if (i != numFuncUnits) 1651 stalled << ','; 1652 } 1653 1654 MINORTRACE("insts=%s inputIndex=%d streamSeqNum=%d" 1655 " stalled=%s drainState=%d isInbetweenInsts=%d\n", 1656 insts.str(), executeInfo[0].inputIndex, executeInfo[0].streamSeqNum, 1657 stalled.str(), executeInfo[0].drainState, isInbetweenInsts(0)); 1658 1659 std::for_each(funcUnits.begin(), funcUnits.end(), 1660 std::mem_fun(&FUPipeline::minorTrace)); 1661 1662 executeInfo[0].inFlightInsts->minorTrace(); 1663 executeInfo[0].inFUMemInsts->minorTrace(); 1664} 1665 1666inline ThreadID 1667Execute::getCommittingThread() 1668{ 1669 std::vector<ThreadID> priority_list; 1670 1671 switch (cpu.threadPolicy) { 1672 case Enums::SingleThreaded: 1673 return 0; 1674 case Enums::RoundRobin: 1675 priority_list = cpu.roundRobinPriority(commitPriority); 1676 break; 1677 case Enums::Random: 1678 priority_list = cpu.randomPriority(); 1679 break; 1680 default: 1681 panic("Invalid thread policy"); 1682 } 1683 1684 for (auto tid : priority_list) { 1685 ExecuteThreadInfo &ex_info = executeInfo[tid]; 1686 1687 bool is_thread_active = 1688 cpu.getContext(tid)->status() == ThreadContext::Active; 1689 bool can_commit_insts = !ex_info.inFlightInsts->empty() && 1690 is_thread_active; 1691 1692 if (can_commit_insts) { 1693 QueuedInst *head_inflight_inst = &(ex_info.inFlightInsts->front()); 1694 MinorDynInstPtr inst = head_inflight_inst->inst; 1695 1696 can_commit_insts = can_commit_insts && 1697 (!inst->inLSQ || (lsq.findResponse(inst) != NULL)); 1698 1699 if (!inst->inLSQ) { 1700 bool can_transfer_mem_inst = false; 1701 if (!ex_info.inFUMemInsts->empty() && lsq.canRequest()) { 1702 const MinorDynInstPtr head_mem_ref_inst = 1703 ex_info.inFUMemInsts->front().inst; 1704 FUPipeline *fu = funcUnits[head_mem_ref_inst->fuIndex]; 1705 const MinorDynInstPtr &fu_inst = fu->front().inst; 1706 can_transfer_mem_inst = 1707 !fu_inst->isBubble() && 1708 fu_inst->id.threadId == tid && 1709 !fu_inst->inLSQ && 1710 fu_inst->canEarlyIssue && 1711 inst->id.execSeqNum > fu_inst->instToWaitFor; 1712 } 1713 1714 bool can_execute_fu_inst = inst->fuIndex == noCostFUIndex; 1715 if (can_commit_insts && !can_transfer_mem_inst && 1716 inst->fuIndex != noCostFUIndex) 1717 { 1718 QueuedInst& fu_inst = funcUnits[inst->fuIndex]->front(); 1719 can_execute_fu_inst = !fu_inst.inst->isBubble() && 1720 fu_inst.inst->id == inst->id; 1721 } 1722 1723 can_commit_insts = can_commit_insts && 1724 (can_transfer_mem_inst || can_execute_fu_inst); 1725 } 1726 } 1727 1728 1729 if (can_commit_insts) { 1730 commitPriority = tid; 1731 return tid; 1732 } 1733 } 1734 1735 return InvalidThreadID; 1736} 1737 1738inline ThreadID 1739Execute::getIssuingThread() 1740{ 1741 std::vector<ThreadID> priority_list; 1742 1743 switch (cpu.threadPolicy) { 1744 case Enums::SingleThreaded: 1745 return 0; 1746 case Enums::RoundRobin: 1747 priority_list = cpu.roundRobinPriority(issuePriority); 1748 break; 1749 case Enums::Random: 1750 priority_list = cpu.randomPriority(); 1751 break; 1752 default: 1753 panic("Invalid thread scheduling policy."); 1754 } 1755 1756 for (auto tid : priority_list) { 1757 if (cpu.getContext(tid)->status() == ThreadContext::Active && 1758 getInput(tid)) { 1759 issuePriority = tid; 1760 return tid; 1761 } 1762 } 1763 1764 return InvalidThreadID; 1765} 1766 1767void 1768Execute::drainResume() 1769{ 1770 DPRINTF(Drain, "MinorExecute drainResume\n"); 1771 1772 for (ThreadID tid = 0; tid < cpu.numThreads; tid++) { 1773 setDrainState(tid, NotDraining); 1774 } 1775 1776 cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 1777} 1778 1779std::ostream &operator <<(std::ostream &os, Execute::DrainState state) 1780{ 1781 switch (state) 1782 { 1783 case Execute::NotDraining: 1784 os << "NotDraining"; 1785 break; 1786 case Execute::DrainCurrentInst: 1787 os << "DrainCurrentInst"; 1788 break; 1789 case Execute::DrainHaltFetch: 1790 os << "DrainHaltFetch"; 1791 break; 1792 case Execute::DrainAllInsts: 1793 os << "DrainAllInsts"; 1794 break; 1795 default: 1796 os << "Drain-" << static_cast<int>(state); 1797 break; 1798 } 1799 1800 return os; 1801} 1802 1803void 1804Execute::setDrainState(ThreadID thread_id, DrainState state) 1805{ 1806 DPRINTF(Drain, "setDrainState[%d]: %s\n", thread_id, state); 1807 executeInfo[thread_id].drainState = state; 1808} 1809 1810unsigned int 1811Execute::drain() 1812{ 1813 DPRINTF(Drain, "MinorExecute drain\n"); 1814 1815 for (ThreadID tid = 0; tid < cpu.numThreads; tid++) { 1816 if (executeInfo[tid].drainState == NotDraining) { 1817 cpu.wakeupOnEvent(Pipeline::ExecuteStageId); 1818 1819 /* Go to DrainCurrentInst if we're between microops 1820 * or waiting on an unbufferable memory operation. 1821 * Otherwise we can go straight to DrainHaltFetch 1822 */ 1823 if (isInbetweenInsts(tid)) 1824 setDrainState(tid, DrainHaltFetch); 1825 else 1826 setDrainState(tid, DrainCurrentInst); 1827 } 1828 } 1829 return (isDrained() ? 0 : 1); 1830} 1831 1832bool 1833Execute::isDrained() 1834{ 1835 if (!lsq.isDrained()) 1836 return false; 1837 1838 for (ThreadID tid = 0; tid < cpu.numThreads; tid++) { 1839 if (!inputBuffer[tid].empty() || 1840 !executeInfo[tid].inFlightInsts->empty()) { 1841 1842 return false; 1843 } 1844 } 1845 1846 return true; 1847} 1848 1849Execute::~Execute() 1850{ 1851 for (unsigned int i = 0; i < numFuncUnits; i++) 1852 delete funcUnits[i]; 1853 1854 for (ThreadID tid = 0; tid < cpu.numThreads; tid++) 1855 delete executeInfo[tid].inFlightInsts; 1856} 1857 1858bool 1859Execute::instIsRightStream(MinorDynInstPtr inst) 1860{ 1861 return inst->id.streamSeqNum == executeInfo[inst->id.threadId].streamSeqNum; 1862} 1863 1864bool 1865Execute::instIsHeadInst(MinorDynInstPtr inst) 1866{ 1867 bool ret = false; 1868 1869 if (!executeInfo[inst->id.threadId].inFlightInsts->empty()) 1870 ret = executeInfo[inst->id.threadId].inFlightInsts->front().inst->id == inst->id; 1871 1872 return ret; 1873} 1874 1875MinorCPU::MinorCPUPort & 1876Execute::getDcachePort() 1877{ 1878 return lsq.getDcachePort(); 1879} 1880 1881} 1882