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 + -
显示快捷键?