execute.hh revision 11567
1/* 2 * Copyright (c) 2013-2014 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions are 16 * met: redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer; 18 * redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution; 21 * neither the name of the copyright holders nor the names of its 22 * contributors may be used to endorse or promote products derived from 23 * this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * Authors: Andrew Bardsley 38 */ 39 40/** 41 * @file 42 * 43 * All the fun of executing instructions from Decode and sending branch/new 44 * instruction stream info. to Fetch1. 45 */ 46 47#ifndef __CPU_MINOR_EXECUTE_HH__ 48#define __CPU_MINOR_EXECUTE_HH__ 49 50#include "cpu/minor/buffers.hh" 51#include "cpu/minor/cpu.hh" 52#include "cpu/minor/func_unit.hh" 53#include "cpu/minor/lsq.hh" 54#include "cpu/minor/pipe_data.hh" 55#include "cpu/minor/scoreboard.hh" 56 57namespace Minor 58{ 59 60/** Execute stage. Everything apart from fetching and decoding instructions. 61 * The LSQ lives here too. */ 62class Execute : public Named 63{ 64 protected: 65 /** Input port carrying instructions from Decode */ 66 Latch<ForwardInstData>::Output inp; 67 68 /** Input port carrying stream changes to Fetch1 */ 69 Latch<BranchData>::Input out; 70 71 /** Pointer back to the containing CPU */ 72 MinorCPU &cpu; 73 74 /** Number of instructions that can be issued per cycle */ 75 unsigned int issueLimit; 76 77 /** Number of memory ops that can be issued per cycle */ 78 unsigned int memoryIssueLimit; 79 80 /** Number of instructions that can be committed per cycle */ 81 unsigned int commitLimit; 82 83 /** Number of memory instructions that can be committed per cycle */ 84 unsigned int memoryCommitLimit; 85 86 /** If true, more than one input line can be processed each cycle if 87 * there is room to execute more instructions than taken from the first 88 * line */ 89 bool processMoreThanOneInput; 90 91 /** Descriptions of the functional units we want to generate */ 92 MinorFUPool &fuDescriptions; 93 94 /** Number of functional units to produce */ 95 unsigned int numFuncUnits; 96 97 /** Longest latency of any FU, useful for setting up the activity 98 * recoder */ 99 Cycles longestFuLatency; 100 101 /** Modify instruction trace times on commit */ 102 bool setTraceTimeOnCommit; 103 104 /** Modify instruction trace times on issue */ 105 bool setTraceTimeOnIssue; 106 107 /** Allow mem refs to leave their FUs before reaching the head 108 * of the in flight insts queue if their dependencies are met */ 109 bool allowEarlyMemIssue; 110 111 /** The FU index of the non-existent costless FU for instructions 112 * which pass the MinorDynInst::isNoCostInst test */ 113 unsigned int noCostFUIndex; 114 115 /** Dcache port to pass on to the CPU. Execute owns this */ 116 LSQ lsq; 117 118 /** Scoreboard of instruction dependencies */ 119 std::vector<Scoreboard> scoreboard; 120 121 /** The execution functional units */ 122 std::vector<FUPipeline *> funcUnits; 123 124 public: /* Public for Pipeline to be able to pass it to Decode */ 125 std::vector<InputBuffer<ForwardInstData>> inputBuffer; 126 127 protected: 128 /** Stage cycle-by-cycle state */ 129 130 /** State that drain passes through (in order). On a drain request, 131 * Execute transitions into either DrainCurrentInst (if between 132 * microops) or DrainHaltFetch. 133 * 134 * Note that Execute doesn't actually have * a 'Drained' state, only 135 * an indication that it's currently draining and isDrained that can't 136 * tell if there are insts still in the pipeline leading up to 137 * Execute */ 138 enum DrainState 139 { 140 NotDraining, /* Not draining, possibly running */ 141 DrainCurrentInst, /* Draining to end of inst/macroop */ 142 DrainHaltFetch, /* Halting Fetch after completing current inst */ 143 DrainAllInsts /* Discarding all remaining insts */ 144 }; 145 146 struct ExecuteThreadInfo { 147 /** Constructor */ 148 ExecuteThreadInfo(unsigned int insts_committed) : 149 inputIndex(0), 150 lastCommitWasEndOfMacroop(true), 151 instsBeingCommitted(insts_committed), 152 streamSeqNum(InstId::firstStreamSeqNum), 153 lastPredictionSeqNum(InstId::firstPredictionSeqNum), 154 drainState(NotDraining) 155 { } 156 157 ExecuteThreadInfo(const ExecuteThreadInfo& other) : 158 inputIndex(other.inputIndex), 159 lastCommitWasEndOfMacroop(other.lastCommitWasEndOfMacroop), 160 instsBeingCommitted(other.instsBeingCommitted), 161 streamSeqNum(other.streamSeqNum), 162 lastPredictionSeqNum(other.lastPredictionSeqNum), 163 drainState(other.drainState) 164 { } 165 166 /** In-order instructions either in FUs or the LSQ */ 167 Queue<QueuedInst, ReportTraitsAdaptor<QueuedInst> > *inFlightInsts; 168 169 /** Memory ref instructions still in the FUs */ 170 Queue<QueuedInst, ReportTraitsAdaptor<QueuedInst> > *inFUMemInsts; 171 172 /** Index that we've completed upto in getInput data. We can say we're 173 * popInput when this equals getInput()->width() */ 174 unsigned int inputIndex; 175 176 /** The last commit was the end of a full instruction so an interrupt 177 * can safely happen */ 178 bool lastCommitWasEndOfMacroop; 179 180 /** Structure for reporting insts currently being processed/retired 181 * for MinorTrace */ 182 ForwardInstData instsBeingCommitted; 183 184 /** Source of sequence number for instuction streams. Increment this and 185 * pass to fetch whenever an instruction stream needs to be changed. 186 * For any more complicated behaviour (e.g. speculation) there'll need 187 * to be another plan. */ 188 InstSeqNum streamSeqNum; 189 190 /** A prediction number for use where one isn't available from an 191 * instruction. This is harvested from committed instructions. 192 * This isn't really needed as the streamSeqNum will change on 193 * a branch, but it minimises disruption in stream identification */ 194 InstSeqNum lastPredictionSeqNum; 195 196 /** State progression for draining NotDraining -> ... -> DrainAllInsts */ 197 DrainState drainState; 198 }; 199 200 std::vector<ExecuteThreadInfo> executeInfo; 201 202 ThreadID interruptPriority; 203 ThreadID issuePriority; 204 ThreadID commitPriority; 205 206 protected: 207 friend std::ostream &operator <<(std::ostream &os, DrainState state); 208 209 /** Get a piece of data to work on from the inputBuffer, or 0 if there 210 * is no data. */ 211 const ForwardInstData *getInput(ThreadID tid); 212 213 /** Pop an element off the input buffer, if there are any */ 214 void popInput(ThreadID tid); 215 216 /** Generate Branch data based (into branch) on an observed (or not) 217 * change in PC while executing an instruction. 218 * Also handles branch prediction information within the inst. */ 219 void tryToBranch(MinorDynInstPtr inst, Fault fault, BranchData &branch); 220 221 /** Actually create a branch to communicate to Fetch1/Fetch2 and, 222 * if that is a stream-changing branch update the streamSeqNum */ 223 void updateBranchData(ThreadID tid, BranchData::Reason reason, 224 MinorDynInstPtr inst, const TheISA::PCState &target, 225 BranchData &branch); 226 227 /** Handle extracting mem ref responses from the memory queues and 228 * completing the associated instructions. 229 * Fault is an output and will contain any fault caused (and already 230 * invoked by the function) 231 * Sets branch to any branch generated by the instruction. */ 232 void handleMemResponse(MinorDynInstPtr inst, 233 LSQ::LSQRequestPtr response, BranchData &branch, 234 Fault &fault); 235 236 /** Execute a memory reference instruction. This calls initiateAcc on 237 * the instruction which will then call writeMem or readMem to issue a 238 * memory access to the LSQ. 239 * Returns true if the instruction was executed rather than stalled 240 * because of a lack of LSQ resources and false otherwise. 241 * branch is set to any branch raised by the instruction. 242 * failed_predicate is set to false if the instruction passed its 243 * predicate and so will access memory or true if the instruction 244 * *failed* its predicate and is now complete. 245 * fault is set if any non-NoFault fault is raised. 246 * Any faults raised are actually invoke-d by this function. */ 247 bool executeMemRefInst(MinorDynInstPtr inst, BranchData &branch, 248 bool &failed_predicate, Fault &fault); 249 250 /** Has an interrupt been raised */ 251 bool isInterrupted(ThreadID thread_id) const; 252 253 /** Are we between instructions? Can we be interrupted? */ 254 bool isInbetweenInsts(ThreadID thread_id) const; 255 256 /** Act on an interrupt. Returns true if an interrupt was actually 257 * signalled and invoked */ 258 bool takeInterrupt(ThreadID thread_id, BranchData &branch); 259 260 /** Try and issue instructions from the inputBuffer */ 261 unsigned int issue(ThreadID thread_id); 262 263 /** Try to act on PC-related events. Returns true if any were 264 * executed */ 265 bool tryPCEvents(ThreadID thread_id); 266 267 /** Do the stats handling and instruction count and PC event events 268 * related to the new instruction/op counts */ 269 void doInstCommitAccounting(MinorDynInstPtr inst); 270 271 /** Check all threads for possible interrupts. If interrupt is taken, 272 * returns the tid of the thread. interrupted is set if any thread 273 * has an interrupt, irrespective of if it is taken */ 274 ThreadID checkInterrupts(BranchData& branch, bool& interrupted); 275 276 /** Checks if a specific thread has an interrupt. No action is taken. 277 * this is used for determining if a thread should only commit microops */ 278 bool hasInterrupt(ThreadID thread_id); 279 280 /** Commit a single instruction. Returns true if the instruction being 281 * examined was completed (fully executed, discarded, or initiated a 282 * memory access), false if there is still some processing to do. 283 * fu_index is the index of the functional unit this instruction is 284 * being executed in into for funcUnits 285 * If early_memory_issue is true then this is an early execution 286 * of a mem ref and so faults will not be processed. 287 * If the return value is true: 288 * fault is set if a fault happened, 289 * branch is set to indicate any branch that occurs 290 * committed is set to true if this instruction is committed 291 * (and so needs to be traced and accounted for) 292 * completed_mem_issue is set if the instruction was a 293 * memory access that was issued */ 294 bool commitInst(MinorDynInstPtr inst, bool early_memory_issue, 295 BranchData &branch, Fault &fault, bool &committed, 296 bool &completed_mem_issue); 297 298 /** Try and commit instructions from the ends of the functional unit 299 * pipelines. 300 * If only_commit_microops is true then only commit upto the 301 * end of the currect full instruction. 302 * If discard is true then discard all instructions rather than 303 * committing. 304 * branch is set to any branch raised during commit. */ 305 void commit(ThreadID thread_id, bool only_commit_microops, bool discard, 306 BranchData &branch); 307 308 /** Set the drain state (with useful debugging messages) */ 309 void setDrainState(ThreadID thread_id, DrainState state); 310 311 /** Use the current threading policy to determine the next thread to 312 * decode from. */ 313 ThreadID getCommittingThread(); 314 ThreadID getIssuingThread(); 315 316 public: 317 Execute(const std::string &name_, 318 MinorCPU &cpu_, 319 MinorCPUParams ¶ms, 320 Latch<ForwardInstData>::Output inp_, 321 Latch<BranchData>::Input out_); 322 323 ~Execute(); 324 325 public: 326 327 /** Returns the DcachePort owned by this Execute to pass upwards */ 328 MinorCPU::MinorCPUPort &getDcachePort(); 329 330 /** To allow ExecContext to find the LSQ */ 331 LSQ &getLSQ() { return lsq; } 332 333 /** Does the given instruction have the right stream sequence number 334 * to be committed? */ 335 bool instIsRightStream(MinorDynInstPtr inst); 336 337 /** Returns true if the given instruction is at the head of the 338 * inFlightInsts instruction queue */ 339 bool instIsHeadInst(MinorDynInstPtr inst); 340 341 /** Pass on input/buffer data to the output if you can */ 342 void evaluate(); 343 344 void minorTrace() const; 345 346 /** After thread suspension, has Execute been drained of in-flight 347 * instructions and memory accesses. */ 348 bool isDrained(); 349 350 /** Like the drain interface on SimObject */ 351 unsigned int drain(); 352 void drainResume(); 353}; 354 355} 356 357#endif /* __CPU_MINOR_EXECUTE_HH__ */ 358