X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fmem%2Fcache%2Fmshr.hh;h=3e7b79ea0cd3c9331d35bf1461ae5e0e5b18bc24;hb=28059ffcdf50871b1be573c29a656da9473287d1;hp=437f8d4e4c95a570bd53a1ed39449f91cfa20164;hpb=d28c2906f4125ce8704ce9cefa471f1a5050eeae;p=gem5.git diff --git a/src/mem/cache/mshr.hh b/src/mem/cache/mshr.hh index 437f8d4e4..3e7b79ea0 100644 --- a/src/mem/cache/mshr.hh +++ b/src/mem/cache/mshr.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013, 2015-2016 ARM Limited + * Copyright (c) 2012-2013, 2015-2016, 2018 ARM Limited * All rights reserved. * * The license below extends only to copyright in the software and shall @@ -38,6 +38,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Erik Hallnor + * Nikos Nikoleris */ /** @@ -48,12 +49,20 @@ #ifndef __MEM_CACHE_MSHR_HH__ #define __MEM_CACHE_MSHR_HH__ +#include +#include #include +#include +#include #include "base/printable.hh" +#include "base/types.hh" #include "mem/cache/queue_entry.hh" +#include "mem/packet.hh" +#include "mem/request.hh" +#include "sim/core.hh" -class Cache; +class BaseCache; /** * Miss Status and handling Register. This class keeps all the information @@ -109,10 +118,13 @@ class MSHR : public QueueEntry, public Printable public: + /** Track if we sent this as a whole line write or not */ + bool wasWholeLineWrite; + /** True if the entry is just a simple forward from an upper level */ bool isForward; - class Target { + class Target : public QueueEntry::Target { public: enum Source { @@ -121,21 +133,32 @@ class MSHR : public QueueEntry, public Printable FromPrefetcher }; - const Tick recvTime; //!< Time when request was received (for stats) - const Tick readyTime; //!< Time when request is ready to be serviced - const Counter order; //!< Global order (for memory consistency mgmt) - const PacketPtr pkt; //!< Pending request packet. const Source source; //!< Request from cpu, memory, or prefetcher? - const bool markedPending; //!< Did we mark upstream MSHR - //!< as downstreamPending? + + /** + * We use this flag to track whether we have cleared the + * downstreamPending flag for the MSHR of the cache above + * where this packet originates from and guard noninitial + * attempts to clear it. + * + * The flag markedPending needs to be updated when the + * TargetList is in service which can be: + * 1) during the Target instantiation if the MSHR is in + * service and the target is not deferred, + * 2) when the MSHR becomes in service if the target is not + * deferred, + * 3) or when the TargetList is promoted (deferredTargets -> + * targets). + */ + bool markedPending; + const bool allocOnFill; //!< Should the response servicing this //!< target list allocate in the cache? Target(PacketPtr _pkt, Tick _readyTime, Counter _order, Source _source, bool _markedPending, bool alloc_on_fill) - : recvTime(curTick()), readyTime(_readyTime), order(_order), - pkt(_pkt), source(_source), markedPending(_markedPending), - allocOnFill(alloc_on_fill) + : QueueEntry::Target(_pkt, _readyTime, _order), source(_source), + markedPending(_markedPending), allocOnFill(alloc_on_fill) {} }; @@ -146,6 +169,11 @@ class MSHR : public QueueEntry, public Printable bool hasUpgrade; /** Set when the response should allocate on fill */ bool allocOnFill; + /** + * Determine whether there was at least one non-snooping + * target coming from another cache. + */ + bool hasFromCache; TargetList(); @@ -160,7 +188,29 @@ class MSHR : public QueueEntry, public Printable void updateFlags(PacketPtr pkt, Target::Source source, bool alloc_on_fill); - void resetFlags() { needsWritable = hasUpgrade = allocOnFill = false; } + /** + * Reset state + * + * @param blk_addr Address of the cache block + * @param blk_size Size of the cache block + */ + void init(Addr blk_addr, Addr blk_size) { + blkAddr = blk_addr; + blkSize = blk_size; + writesBitmap.resize(blk_size); + + resetFlags(); + } + + void resetFlags() { + onlyWrites = true; + std::fill(writesBitmap.begin(), writesBitmap.end(), false); + + needsWritable = false; + hasUpgrade = false; + allocOnFill = false; + hasFromCache = false; + } /** * Goes through the list of targets and uses them to populate @@ -170,12 +220,45 @@ class MSHR : public QueueEntry, public Printable */ void populateFlags(); + /** + * Add the specified packet in the TargetList. This function + * stores information related to the added packet and updates + * accordingly the flags. + * + * @param pkt Packet considered for adding + */ + void updateWriteFlags(PacketPtr pkt) { + const Request::FlagsType noMergeFlags = + Request::UNCACHEABLE | + Request::STRICT_ORDER | Request::MMAPPED_IPR | + Request::PRIVILEGED | Request::LLSC | + Request::MEM_SWAP | Request::MEM_SWAP_COND | + Request::SECURE; + + // if we have already seen writes for the full block stop + // here, this might be a full line write followed by + // other compatible requests (e.g., reads) + if (!isWholeLineWrite()) { + bool can_merge_write = pkt->isWrite() && + ((pkt->req->getFlags() & noMergeFlags) == 0); + onlyWrites &= can_merge_write; + if (onlyWrites) { + auto offset = pkt->getOffset(blkSize); + auto begin = writesBitmap.begin() + offset; + std::fill(begin, begin + pkt->getSize(), true); + } + } + } + /** * Tests if the flags of this TargetList have their default * values. + * + * @return True if the TargetList are reset, false otherwise. */ bool isReset() const { - return !needsWritable && !hasUpgrade && !allocOnFill; + return !needsWritable && !hasUpgrade && !allocOnFill && + !hasFromCache && onlyWrites; } /** @@ -191,8 +274,7 @@ class MSHR : public QueueEntry, public Printable * @param alloc_on_fill Whether it should allocate on a fill */ void add(PacketPtr pkt, Tick readyTime, Counter order, - Target::Source source, bool markPending, - bool alloc_on_fill); + Target::Source source, bool markPending, bool alloc_on_fill); /** * Convert upgrades to the equivalent request if the cache line they @@ -201,9 +283,43 @@ class MSHR : public QueueEntry, public Printable void replaceUpgrades(); void clearDownstreamPending(); - bool checkFunctional(PacketPtr pkt); + void clearDownstreamPending(iterator begin, iterator end); + bool trySatisfyFunctional(PacketPtr pkt); void print(std::ostream &os, int verbosity, const std::string &prefix) const; + + /** + * Check if this list contains only compatible writes, and if they + * span the entire cache line. This is used as part of the + * miss-packet creation. Note that new requests may arrive after a + * miss-packet has been created, and for the fill we therefore use + * the wasWholeLineWrite field. + */ + bool isWholeLineWrite() const + { + return onlyWrites && + std::all_of(writesBitmap.begin(), + writesBitmap.end(), [](bool i) { return i; }); + } + + private: + /** Address of the cache block for this list of targets. */ + Addr blkAddr; + + /** Size of the cache block. */ + Addr blkSize; + + /** Are we only dealing with writes. */ + bool onlyWrites; + + // NOTE: std::vector might not meet satisfy the + // ForwardIterator requirement and therefore cannot be used + // for writesBitmap. + /** + * Track which bytes are written by requests in this target + * list. + */ + std::vector writesBitmap; }; /** A list of MSHRs. */ @@ -219,6 +335,11 @@ class MSHR : public QueueEntry, public Printable /** True if we need to get a writable copy of the block. */ bool needsWritable() const { return targets.needsWritable; } + bool isCleaning() const { + PacketPtr pkt = targets.front().pkt; + return pkt->isClean(); + } + bool isPendingModified() const { assert(inService); return pendingModified; } @@ -231,12 +352,32 @@ class MSHR : public QueueEntry, public Printable assert(inService); return postDowngrade; } - bool sendPacket(Cache &cache); + bool sendPacket(BaseCache &cache) override; bool allocOnFill() const { return targets.allocOnFill; } + + /** + * Determine if there are non-deferred requests from other caches + * + * @return true if any of the targets is from another cache + */ + bool hasFromCache() const { + return targets.hasFromCache; + } + private: + /** + * Promotes deferred targets that satisfy a predicate + * + * Deferred targets are promoted to the target list if they + * satisfy a given condition. The operation stops at the first + * deferred target that doesn't satisfy the condition. + * + * @param pred A condition on a Target + */ + void promoteIf(const std::function& pred); /** * Pointer to this MSHR on the ready list. @@ -256,6 +397,16 @@ class MSHR : public QueueEntry, public Printable TargetList deferredTargets; public: + /** + * Check if this MSHR contains only compatible writes, and if they + * span the entire cache line. This is used as part of the + * miss-packet creation. Note that new requests may arrive after a + * miss-packet has been created, and for the fill we therefore use + * the wasWholeLineWrite field. + */ + bool isWholeLineWrite() const { + return targets.isWholeLineWrite(); + } /** * Allocate a miss to this MSHR. @@ -296,6 +447,20 @@ class MSHR : public QueueEntry, public Printable int getNumTargets() const { return targets.size() + deferredTargets.size(); } + /** + * Extracts the subset of the targets that can be serviced given a + * received response. This function returns the targets list + * unless the response is a ReadRespWithInvalidate. The + * ReadRespWithInvalidate is only invalidating response that its + * invalidation was not expected when the request (a + * ReadSharedReq) was sent out. For ReadRespWithInvalidate we can + * safely service only the first FromCPU target and all FromSnoop + * targets (inform all snoopers that we no longer have the block). + * + * @param pkt The response from the downstream memory + */ + TargetList extractServiceableTargets(PacketPtr pkt); + /** * Returns true if there are targets left. * @return true if there are targets @@ -306,7 +471,7 @@ class MSHR : public QueueEntry, public Printable * Returns a reference to the first target. * @return A pointer to the first target. */ - Target *getTarget() + QueueEntry::Target *getTarget() override { assert(hasTargets()); return &targets.front(); @@ -322,16 +487,43 @@ class MSHR : public QueueEntry, public Printable bool promoteDeferredTargets(); + /** + * Promotes deferred targets that do not require writable + * + * Move targets from the deferred targets list to the target list + * starting from the first deferred target until the first target + * that is a cache maintenance operation or needs a writable copy + * of the block + */ + void promoteReadable(); + + /** + * Promotes deferred targets that do not require writable + * + * Requests in the deferred target list are moved to the target + * list up until the first target that is a cache maintenance + * operation or needs a writable copy of the block + */ void promoteWritable(); - bool checkFunctional(PacketPtr pkt); + bool trySatisfyFunctional(PacketPtr pkt); + + /** + * Adds a delay relative to the current tick to the current MSHR + * @param delay_ticks the desired delay in ticks + */ + void delay(Tick delay_ticks) + { + assert(readyTime <= curTick()); + readyTime = curTick() + delay_ticks; + } /** * Prints the contents of this MSHR for debugging. */ void print(std::ostream &os, int verbosity = 0, - const std::string &prefix = "") const; + const std::string &prefix = "") const override; /** * A no-args wrapper of print(std::ostream...) meant to be * invoked from DPRINTFs avoiding string overheads in fast mode @@ -339,6 +531,10 @@ class MSHR : public QueueEntry, public Printable * @return string with mshr fields + [deferred]targets */ std::string print() const; + + bool matchBlockAddr(const Addr addr, const bool is_secure) const override; + bool matchBlockAddr(const PacketPtr pkt) const override; + bool conflictAddr(const QueueEntry* entry) const override; }; #endif // __MEM_CACHE_MSHR_HH__