322 lines
12 KiB
C++
322 lines
12 KiB
C++
|
/*
|
||
|
* Copyright (c) 2013-2014 ARM Limited
|
||
|
* All rights reserved
|
||
|
*
|
||
|
* The license below extends only to copyright in the software and shall
|
||
|
* not be construed as granting a license to any other intellectual
|
||
|
* property including but not limited to intellectual property relating
|
||
|
* to a hardware implementation of the functionality of the software
|
||
|
* licensed hereunder. You may use the software subject to the license
|
||
|
* terms below provided that you ensure that this notice is replicated
|
||
|
* unmodified and in its entirety in all distributions of the software,
|
||
|
* modified or unmodified, in source code or in binary form.
|
||
|
*
|
||
|
* Redistribution and use in source and binary forms, with or without
|
||
|
* modification, are permitted provided that the following conditions are
|
||
|
* met: redistributions of source code must retain the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer;
|
||
|
* redistributions in binary form must reproduce the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer in the
|
||
|
* documentation and/or other materials provided with the distribution;
|
||
|
* neither the name of the copyright holders nor the names of its
|
||
|
* contributors may be used to endorse or promote products derived from
|
||
|
* this software without specific prior written permission.
|
||
|
*
|
||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
|
*
|
||
|
* Authors: Andrew Bardsley
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @file
|
||
|
*
|
||
|
* All the fun of executing instructions from Decode and sending branch/new
|
||
|
* instruction stream info. to Fetch1.
|
||
|
*/
|
||
|
|
||
|
#ifndef __CPU_MINOR_EXECUTE_HH__
|
||
|
#define __CPU_MINOR_EXECUTE_HH__
|
||
|
|
||
|
#include "cpu/minor/buffers.hh"
|
||
|
#include "cpu/minor/cpu.hh"
|
||
|
#include "cpu/minor/func_unit.hh"
|
||
|
#include "cpu/minor/lsq.hh"
|
||
|
#include "cpu/minor/pipe_data.hh"
|
||
|
#include "cpu/minor/scoreboard.hh"
|
||
|
|
||
|
namespace Minor
|
||
|
{
|
||
|
|
||
|
/** Execute stage. Everything apart from fetching and decoding instructions.
|
||
|
* The LSQ lives here too. */
|
||
|
class Execute : public Named
|
||
|
{
|
||
|
protected:
|
||
|
/** Input port carrying instructions from Decode */
|
||
|
Latch<ForwardInstData>::Output inp;
|
||
|
|
||
|
/** Input port carrying stream changes to Fetch1 */
|
||
|
Latch<BranchData>::Input out;
|
||
|
|
||
|
/** Pointer back to the containing CPU */
|
||
|
MinorCPU &cpu;
|
||
|
|
||
|
/** Number of instructions that can be issued per cycle */
|
||
|
unsigned int issueLimit;
|
||
|
|
||
|
/** Number of memory ops that can be issued per cycle */
|
||
|
unsigned int memoryIssueLimit;
|
||
|
|
||
|
/** Number of instructions that can be committed per cycle */
|
||
|
unsigned int commitLimit;
|
||
|
|
||
|
/** Number of memory instructions that can be committed per cycle */
|
||
|
unsigned int memoryCommitLimit;
|
||
|
|
||
|
/** If true, more than one input line can be processed each cycle if
|
||
|
* there is room to execute more instructions than taken from the first
|
||
|
* line */
|
||
|
bool processMoreThanOneInput;
|
||
|
|
||
|
/** Descriptions of the functional units we want to generate */
|
||
|
MinorFUPool &fuDescriptions;
|
||
|
|
||
|
/** Number of functional units to produce */
|
||
|
unsigned int numFuncUnits;
|
||
|
|
||
|
/** Longest latency of any FU, useful for setting up the activity
|
||
|
* recoder */
|
||
|
Cycles longestFuLatency;
|
||
|
|
||
|
/** Modify instruction trace times on commit */
|
||
|
bool setTraceTimeOnCommit;
|
||
|
|
||
|
/** Modify instruction trace times on issue */
|
||
|
bool setTraceTimeOnIssue;
|
||
|
|
||
|
/** Allow mem refs to leave their FUs before reaching the head
|
||
|
* of the in flight insts queue if their dependencies are met */
|
||
|
bool allowEarlyMemIssue;
|
||
|
|
||
|
/** The FU index of the non-existent costless FU for instructions
|
||
|
* which pass the MinorDynInst::isNoCostInst test */
|
||
|
unsigned int noCostFUIndex;
|
||
|
|
||
|
/** Dcache port to pass on to the CPU. Execute owns this */
|
||
|
LSQ lsq;
|
||
|
|
||
|
/** Scoreboard of instruction dependencies */
|
||
|
Scoreboard scoreboard;
|
||
|
|
||
|
/** The execution functional units */
|
||
|
std::vector<FUPipeline *> funcUnits;
|
||
|
|
||
|
public: /* Public for Pipeline to be able to pass it to Decode */
|
||
|
InputBuffer<ForwardInstData> inputBuffer;
|
||
|
|
||
|
protected:
|
||
|
/** Stage cycle-by-cycle state */
|
||
|
|
||
|
/** State that drain passes through (in order). On a drain request,
|
||
|
* Execute transitions into either DrainCurrentInst (if between
|
||
|
* microops) or DrainHaltFetch.
|
||
|
*
|
||
|
* Note that Execute doesn't actually have * a 'Drained' state, only
|
||
|
* an indication that it's currently draining and isDrained that can't
|
||
|
* tell if there are insts still in the pipeline leading up to
|
||
|
* Execute */
|
||
|
enum DrainState
|
||
|
{
|
||
|
NotDraining, /* Not draining, possibly running */
|
||
|
DrainCurrentInst, /* Draining to end of inst/macroop */
|
||
|
DrainHaltFetch, /* Halting Fetch after completing current inst */
|
||
|
DrainAllInsts /* Discarding all remaining insts */
|
||
|
};
|
||
|
|
||
|
/** In-order instructions either in FUs or the LSQ */
|
||
|
Queue<QueuedInst, ReportTraitsAdaptor<QueuedInst> > *inFlightInsts;
|
||
|
|
||
|
/** Memory ref instructions still in the FUs */
|
||
|
Queue<QueuedInst, ReportTraitsAdaptor<QueuedInst> > *inFUMemInsts;
|
||
|
|
||
|
/** Index that we've completed upto in getInput data. We can say we're
|
||
|
* popInput when this equals getInput()->width() */
|
||
|
unsigned int inputIndex;
|
||
|
|
||
|
/** The last commit was the end of a full instruction so an interrupt
|
||
|
* can safely happen */
|
||
|
bool lastCommitWasEndOfMacroop;
|
||
|
|
||
|
/** Structure for reporting insts currently being processed/retired
|
||
|
* for MinorTrace */
|
||
|
ForwardInstData instsBeingCommitted;
|
||
|
|
||
|
/** Source of sequence number for instuction streams. Increment this and
|
||
|
* pass to fetch whenever an instruction stream needs to be changed.
|
||
|
* For any more complicated behaviour (e.g. speculation) there'll need
|
||
|
* to be another plan. THREAD, need one for each thread */
|
||
|
InstSeqNum streamSeqNum;
|
||
|
|
||
|
/** A prediction number for use where one isn't available from an
|
||
|
* instruction. This is harvested from committed instructions.
|
||
|
* This isn't really needed as the streamSeqNum will change on
|
||
|
* a branch, but it minimises disruption in stream identification */
|
||
|
InstSeqNum lastPredictionSeqNum;
|
||
|
|
||
|
/** State progression for draining NotDraining -> ... -> DrainAllInsts */
|
||
|
DrainState drainState;
|
||
|
|
||
|
protected:
|
||
|
friend std::ostream &operator <<(std::ostream &os, DrainState state);
|
||
|
|
||
|
/** Get a piece of data to work on from the inputBuffer, or 0 if there
|
||
|
* is no data. */
|
||
|
const ForwardInstData *getInput();
|
||
|
|
||
|
/** Pop an element off the input buffer, if there are any */
|
||
|
void popInput();
|
||
|
|
||
|
/** Generate Branch data based (into branch) on an observed (or not)
|
||
|
* change in PC while executing an instruction.
|
||
|
* Also handles branch prediction information within the inst. */
|
||
|
void tryToBranch(MinorDynInstPtr inst, Fault fault, BranchData &branch);
|
||
|
|
||
|
/** Actually create a branch to communicate to Fetch1/Fetch2 and,
|
||
|
* if that is a stream-changing branch update the streamSeqNum */
|
||
|
void updateBranchData(BranchData::Reason reason,
|
||
|
MinorDynInstPtr inst, const TheISA::PCState &target,
|
||
|
BranchData &branch);
|
||
|
|
||
|
/** Handle extracting mem ref responses from the memory queues and
|
||
|
* completing the associated instructions.
|
||
|
* Fault is an output and will contain any fault caused (and already
|
||
|
* invoked by the function)
|
||
|
* Sets branch to any branch generated by the instruction. */
|
||
|
void handleMemResponse(MinorDynInstPtr inst,
|
||
|
LSQ::LSQRequestPtr response, BranchData &branch,
|
||
|
Fault &fault);
|
||
|
|
||
|
/** Execute a memory reference instruction. This calls initiateAcc on
|
||
|
* the instruction which will then call writeMem or readMem to issue a
|
||
|
* memory access to the LSQ.
|
||
|
* Returns true if the instruction was executed rather than stalled
|
||
|
* because of a lack of LSQ resources and false otherwise.
|
||
|
* branch is set to any branch raised by the instruction.
|
||
|
* failed_predicate is set to false if the instruction passed its
|
||
|
* predicate and so will access memory or true if the instruction
|
||
|
* *failed* its predicate and is now complete.
|
||
|
* fault is set if any non-NoFault fault is raised.
|
||
|
* Any faults raised are actually invoke-d by this function. */
|
||
|
bool executeMemRefInst(MinorDynInstPtr inst, BranchData &branch,
|
||
|
bool &failed_predicate, Fault &fault);
|
||
|
|
||
|
/** Has an interrupt been raised */
|
||
|
bool isInterrupted(ThreadID thread_id) const;
|
||
|
|
||
|
/** Are we between instructions? Can we be interrupted? */
|
||
|
bool isInbetweenInsts() const;
|
||
|
|
||
|
/** Act on an interrupt. Returns true if an interrupt was actually
|
||
|
* signalled and invoked */
|
||
|
bool takeInterrupt(ThreadID thread_id, BranchData &branch);
|
||
|
|
||
|
/** Try and issue instructions from the inputBuffer */
|
||
|
unsigned int issue(bool only_issue_microops);
|
||
|
|
||
|
/** Try to act on PC-related events. Returns true if any were
|
||
|
* executed */
|
||
|
bool tryPCEvents();
|
||
|
|
||
|
/** Do the stats handling and instruction count and PC event events
|
||
|
* related to the new instruction/op counts */
|
||
|
void doInstCommitAccounting(MinorDynInstPtr inst);
|
||
|
|
||
|
/** Commit a single instruction. Returns true if the instruction being
|
||
|
* examined was completed (fully executed, discarded, or initiated a
|
||
|
* memory access), false if there is still some processing to do.
|
||
|
* fu_index is the index of the functional unit this instruction is
|
||
|
* being executed in into for funcUnits
|
||
|
* If early_memory_issue is true then this is an early execution
|
||
|
* of a mem ref and so faults will not be processed.
|
||
|
* If the return value is true:
|
||
|
* fault is set if a fault happened,
|
||
|
* branch is set to indicate any branch that occurs
|
||
|
* committed is set to true if this instruction is committed
|
||
|
* (and so needs to be traced and accounted for)
|
||
|
* completed_mem_issue is set if the instruction was a
|
||
|
* memory access that was issued */
|
||
|
bool commitInst(MinorDynInstPtr inst, bool early_memory_issue,
|
||
|
BranchData &branch, Fault &fault, bool &committed,
|
||
|
bool &completed_mem_issue);
|
||
|
|
||
|
/** Try and commit instructions from the ends of the functional unit
|
||
|
* pipelines.
|
||
|
* If only_commit_microops is true then only commit upto the
|
||
|
* end of the currect full instruction.
|
||
|
* If discard is true then discard all instructions rather than
|
||
|
* committing.
|
||
|
* branch is set to any branch raised during commit. */
|
||
|
void commit(bool only_commit_microops, bool discard, BranchData &branch);
|
||
|
|
||
|
/** Set the drain state (with useful debugging messages) */
|
||
|
void setDrainState(DrainState state);
|
||
|
|
||
|
public:
|
||
|
Execute(const std::string &name_,
|
||
|
MinorCPU &cpu_,
|
||
|
MinorCPUParams ¶ms,
|
||
|
Latch<ForwardInstData>::Output inp_,
|
||
|
Latch<BranchData>::Input out_);
|
||
|
|
||
|
~Execute();
|
||
|
|
||
|
public:
|
||
|
|
||
|
/** Cause Execute to issue an UnpredictedBranch (or WakeupFetch if
|
||
|
* that was passed as the reason) to Fetch1 to wake the
|
||
|
* system up (using the PC from the thread context). */
|
||
|
void wakeupFetch(BranchData::Reason reason =
|
||
|
BranchData::UnpredictedBranch);
|
||
|
|
||
|
/** Returns the DcachePort owned by this Execute to pass upwards */
|
||
|
MinorCPU::MinorCPUPort &getDcachePort();
|
||
|
|
||
|
/** To allow ExecContext to find the LSQ */
|
||
|
LSQ &getLSQ() { return lsq; }
|
||
|
|
||
|
/** Does the given instruction have the right stream sequence number
|
||
|
* to be committed? */
|
||
|
bool instIsRightStream(MinorDynInstPtr inst);
|
||
|
|
||
|
/** Returns true if the given instruction is at the head of the
|
||
|
* inFlightInsts instruction queue */
|
||
|
bool instIsHeadInst(MinorDynInstPtr inst);
|
||
|
|
||
|
/** Pass on input/buffer data to the output if you can */
|
||
|
void evaluate();
|
||
|
|
||
|
void minorTrace() const;
|
||
|
|
||
|
/** After thread suspension, has Execute been drained of in-flight
|
||
|
* instructions and memory accesses. */
|
||
|
bool isDrained();
|
||
|
|
||
|
/** Like the drain interface on SimObject */
|
||
|
unsigned int drain();
|
||
|
void drainResume();
|
||
|
};
|
||
|
|
||
|
}
|
||
|
|
||
|
#endif /* __CPU_MINOR_EXECUTE_HH__ */
|