/*
- * 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
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Erik Hallnor
+ * Nikos Nikoleris
*/
/**
#ifndef __MEM_CACHE_MSHR_HH__
#define __MEM_CACHE_MSHR_HH__
+#include <cassert>
+#include <iosfwd>
#include <list>
+#include <string>
+#include <vector>
#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
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 {
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)
{}
};
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();
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
*/
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;
}
/**
* @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
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<bool> 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<char> writesBitmap;
};
/** A list of MSHRs. */
/** 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;
}
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<bool (Target &)>& pred);
/**
* Pointer to this MSHR on the ready list.
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.
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
* 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();
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
* @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__