lsq_unit.hh

来自「M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作」· HH 代码 · 共 724 行 · 第 1/2 页

HH
724
字号
/* * Copyright (c) 2004, 2005, 2006 * The Regents of The University of Michigan * All Rights Reserved * * This code is part of the M5 simulator. * * Permission is granted to use, copy, create derivative works and * redistribute this software and such derivative works for any * purpose, so long as the copyright notice above, this grant of * permission, and the disclaimer below appear in all copies made; and * so long as the name of The University of Michigan is not used in * any advertising or publicity pertaining to the use or distribution * of this software without specific, written prior authorization. * * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT, * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH * DAMAGES. * * Authors: Kevin T. Lim *          Korey L. Sewell */#ifndef __CPU_O3_LSQ_UNIT_HH__#define __CPU_O3_LSQ_UNIT_HH__#include <algorithm>#include <cstring>#include <map>#include <queue>#include "arch/faults.hh"#include "arch/locked_mem.hh"#include "config/full_system.hh"#include "base/hashmap.hh"#include "cpu/inst_seq.hh"#include "mem/packet.hh"#include "mem/port.hh"/** * Class that implements the actual LQ and SQ for each specific * thread.  Both are circular queues; load entries are freed upon * committing, while store entries are freed once they writeback. The * LSQUnit tracks if there are memory ordering violations, and also * detects partial load to store forwarding cases (a store only has * part of a load's data) that requires the load to wait until the * store writes back. In the former case it holds onto the instruction * until the dependence unit looks at it, and in the latter it stalls * the LSQ until the store writes back. At that point the load is * replayed. */template <class Impl>class LSQUnit {  protected:    typedef TheISA::IntReg IntReg;  public:    typedef typename Impl::Params Params;    typedef typename Impl::O3CPU O3CPU;    typedef typename Impl::DynInstPtr DynInstPtr;    typedef typename Impl::CPUPol::IEW IEW;    typedef typename Impl::CPUPol::LSQ LSQ;    typedef typename Impl::CPUPol::IssueStruct IssueStruct;  public:    /** Constructs an LSQ unit. init() must be called prior to use. */    LSQUnit();    /** Initializes the LSQ unit with the specified number of entries. */    void init(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params, LSQ *lsq_ptr,              unsigned maxLQEntries, unsigned maxSQEntries, unsigned id);    /** Returns the name of the LSQ unit. */    std::string name() const;    /** Registers statistics. */    void regStats();    /** Sets the pointer to the dcache port. */    void setDcachePort(Port *dcache_port);    /** Switches out LSQ unit. */    void switchOut();    /** Takes over from another CPU's thread. */    void takeOverFrom();    /** Returns if the LSQ is switched out. */    bool isSwitchedOut() { return switchedOut; }    /** Ticks the LSQ unit, which in this case only resets the number of     * used cache ports.     * @todo: Move the number of used ports up to the LSQ level so it can     * be shared by all LSQ units.     */    void tick() { usedPorts = 0; }    /** Inserts an instruction. */    void insert(DynInstPtr &inst);    /** Inserts a load instruction. */    void insertLoad(DynInstPtr &load_inst);    /** Inserts a store instruction. */    void insertStore(DynInstPtr &store_inst);    /** Executes a load instruction. */    Fault executeLoad(DynInstPtr &inst);    Fault executeLoad(int lq_idx) { panic("Not implemented"); return NoFault; }    /** Executes a store instruction. */    Fault executeStore(DynInstPtr &inst);    /** Commits the head load. */    void commitLoad();    /** Commits loads older than a specific sequence number. */    void commitLoads(InstSeqNum &youngest_inst);    /** Commits stores older than a specific sequence number. */    void commitStores(InstSeqNum &youngest_inst);    /** Writes back stores. */    void writebackStores();    /** Completes the data access that has been returned from the     * memory system. */    void completeDataAccess(PacketPtr pkt);    /** Clears all the entries in the LQ. */    void clearLQ();    /** Clears all the entries in the SQ. */    void clearSQ();    /** Resizes the LQ to a given size. */    void resizeLQ(unsigned size);    /** Resizes the SQ to a given size. */    void resizeSQ(unsigned size);    /** Squashes all instructions younger than a specific sequence number. */    void squash(const InstSeqNum &squashed_num);    /** Returns if there is a memory ordering violation. Value is reset upon     * call to getMemDepViolator().     */    bool violation() { return memDepViolator; }    /** Returns the memory ordering violator. */    DynInstPtr getMemDepViolator();    /** Returns if a load became blocked due to the memory system. */    bool loadBlocked()    { return isLoadBlocked; }    /** Clears the signal that a load became blocked. */    void clearLoadBlocked()    { isLoadBlocked = false; }    /** Returns if the blocked load was handled. */    bool isLoadBlockedHandled()    { return loadBlockedHandled; }    /** Records the blocked load as being handled. */    void setLoadBlockedHandled()    { loadBlockedHandled = true; }    /** Returns the number of free entries (min of free LQ and SQ entries). */    unsigned numFreeEntries();    /** Returns the number of loads ready to execute. */    int numLoadsReady();    /** Returns the number of loads in the LQ. */    int numLoads() { return loads; }    /** Returns the number of stores in the SQ. */    int numStores() { return stores; }    /** Returns if either the LQ or SQ is full. */    bool isFull() { return lqFull() || sqFull(); }    /** Returns if the LQ is full. */    bool lqFull() { return loads >= (LQEntries - 1); }    /** Returns if the SQ is full. */    bool sqFull() { return stores >= (SQEntries - 1); }    /** Returns the number of instructions in the LSQ. */    unsigned getCount() { return loads + stores; }    /** Returns if there are any stores to writeback. */    bool hasStoresToWB() { return storesToWB; }    /** Returns the number of stores to writeback. */    int numStoresToWB() { return storesToWB; }    /** Returns if the LSQ unit will writeback on this cycle. */    bool willWB() { return storeQueue[storeWBIdx].canWB &&                        !storeQueue[storeWBIdx].completed &&                        !isStoreBlocked; }    /** Handles doing the retry. */    void recvRetry();  private:    /** Writes back the instruction, sending it to IEW. */    void writeback(DynInstPtr &inst, PacketPtr pkt);    /** Handles completing the send of a store to memory. */    void storePostSend(PacketPtr pkt);    /** Completes the store at the specified index. */    void completeStore(int store_idx);    /** Increments the given store index (circular queue). */    inline void incrStIdx(int &store_idx);    /** Decrements the given store index (circular queue). */    inline void decrStIdx(int &store_idx);    /** Increments the given load index (circular queue). */    inline void incrLdIdx(int &load_idx);    /** Decrements the given load index (circular queue). */    inline void decrLdIdx(int &load_idx);  public:    /** Debugging function to dump instructions in the LSQ. */    void dumpInsts();  private:    /** Pointer to the CPU. */    O3CPU *cpu;    /** Pointer to the IEW stage. */    IEW *iewStage;    /** Pointer to the LSQ. */    LSQ *lsq;    /** Pointer to the dcache port.  Used only for sending. */    Port *dcachePort;    /** Derived class to hold any sender state the LSQ needs. */    class LSQSenderState : public Packet::SenderState    {      public:        /** Default constructor. */        LSQSenderState()            : noWB(false)        { }        /** Instruction who initiated the access to memory. */        DynInstPtr inst;        /** Whether or not it is a load. */        bool isLoad;        /** The LQ/SQ index of the instruction. */        int idx;        /** Whether or not the instruction will need to writeback. */        bool noWB;    };    /** Writeback event, specifically for when stores forward data to loads. */    class WritebackEvent : public Event {      public:        /** Constructs a writeback event. */        WritebackEvent(DynInstPtr &_inst, PacketPtr pkt, LSQUnit *lsq_ptr);        /** Processes the writeback event. */        void process();        /** Returns the description of this event. */        const char *description() const;      private:        /** Instruction whose results are being written back. */        DynInstPtr inst;        /** The packet that would have been sent to memory. */        PacketPtr pkt;        /** The pointer to the LSQ unit that issued the store. */        LSQUnit<Impl> *lsqPtr;    };  public:    struct SQEntry {        /** Constructs an empty store queue entry. */        SQEntry()            : inst(NULL), req(NULL), size(0),              canWB(0), committed(0), completed(0)        {            std::memset(data, 0, sizeof(data));        }        /** Constructs a store queue entry for a given instruction. */        SQEntry(DynInstPtr &_inst)            : inst(_inst), req(NULL), size(0),              canWB(0), committed(0), completed(0)        {            std::memset(data, 0, sizeof(data));        }        /** The store instruction. */        DynInstPtr inst;        /** The request for the store. */        RequestPtr req;        /** The size of the store. */        int size;        /** The store data. */        char data[sizeof(IntReg)];        /** Whether or not the store can writeback. */        bool canWB;        /** Whether or not the store is committed. */        bool committed;        /** Whether or not the store is completed. */        bool completed;    };  private:    /** The LSQUnit thread id. */    unsigned lsqID;    /** The store queue. */    std::vector<SQEntry> storeQueue;    /** The load queue. */    std::vector<DynInstPtr> loadQueue;    /** The number of LQ entries, plus a sentinel entry (circular queue).     *  @todo: Consider having var that records the true number of LQ entries.     */    unsigned LQEntries;    /** The number of SQ entries, plus a sentinel entry (circular queue).     *  @todo: Consider having var that records the true number of SQ entries.     */    unsigned SQEntries;    /** The number of load instructions in the LQ. */    int loads;    /** The number of store instructions in the SQ. */    int stores;    /** The number of store instructions in the SQ waiting to writeback. */    int storesToWB;    /** The index of the head instruction in the LQ. */    int loadHead;    /** The index of the tail instruction in the LQ. */    int loadTail;    /** The index of the head instruction in the SQ. */    int storeHead;    /** The index of the first instruction that may be ready to be     * written back, and has not yet been written back.     */    int storeWBIdx;    /** The index of the tail instruction in the SQ. */    int storeTail;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?