- bool isRead() const { return cmd.isRead(); }
- bool isWrite() const { return cmd.isWrite(); }
- bool isUpgrade() const { return cmd.isUpgrade(); }
- bool isRequest() const { return cmd.isRequest(); }
- bool isResponse() const { return cmd.isResponse(); }
- bool needsExclusive() const { return cmd.needsExclusive(); }
- bool needsResponse() const { return cmd.needsResponse(); }
- bool isInvalidate() const { return cmd.isInvalidate(); }
- bool hasData() const { return cmd.hasData(); }
- bool isReadWrite() const { return cmd.isReadWrite(); }
- bool isLLSC() const { return cmd.isLLSC(); }
- bool isError() const { return cmd.isError(); }
- bool isPrint() const { return cmd.isPrint(); }
- bool isFlush() const { return cmd.isFlush(); }
-
- // Snoop flags
- void assertMemInhibit() { flags.set(MEM_INHIBIT); }
- bool memInhibitAsserted() const { return flags.isSet(MEM_INHIBIT); }
- void assertShared() { flags.set(SHARED); }
- bool sharedAsserted() const { return flags.isSet(SHARED); }
-
- // Special control flags
- void setExpressSnoop() { flags.set(EXPRESS_SNOOP); }
- bool isExpressSnoop() const { return flags.isSet(EXPRESS_SNOOP); }
- void setSupplyExclusive() { flags.set(SUPPLY_EXCLUSIVE); }
- void clearSupplyExclusive() { flags.clear(SUPPLY_EXCLUSIVE); }
- bool isSupplyExclusive() const { return flags.isSet(SUPPLY_EXCLUSIVE); }
+ bool isRead() const { return cmd.isRead(); }
+ bool isWrite() const { return cmd.isWrite(); }
+ bool isUpgrade() const { return cmd.isUpgrade(); }
+ bool isRequest() const { return cmd.isRequest(); }
+ bool isResponse() const { return cmd.isResponse(); }
+ bool needsWritable() const
+ {
+ // we should never check if a response needsWritable, the
+ // request has this flag, and for a response we should rather
+ // look at the hasSharers flag (if not set, the response is to
+ // be considered writable)
+ assert(isRequest());
+ return cmd.needsWritable();
+ }
+ bool needsResponse() const { return cmd.needsResponse(); }
+ bool isInvalidate() const { return cmd.isInvalidate(); }
+ bool isEviction() const { return cmd.isEviction(); }
+ bool isClean() const { return cmd.isClean(); }
+ bool fromCache() const { return cmd.fromCache(); }
+ bool isWriteback() const { return cmd.isWriteback(); }
+ bool hasData() const { return cmd.hasData(); }
+ bool hasRespData() const
+ {
+ MemCmd resp_cmd = cmd.responseCommand();
+ return resp_cmd.hasData();
+ }
+ bool isLLSC() const { return cmd.isLLSC(); }
+ bool isError() const { return cmd.isError(); }
+ bool isPrint() const { return cmd.isPrint(); }
+ bool isFlush() const { return cmd.isFlush(); }
+
+ bool isWholeLineWrite(unsigned blk_size)
+ {
+ return (cmd == MemCmd::WriteReq || cmd == MemCmd::WriteLineReq) &&
+ getOffset(blk_size) == 0 && getSize() == blk_size;
+ }
+
+ //@{
+ /// Snoop flags
+ /**
+ * Set the cacheResponding flag. This is used by the caches to
+ * signal another cache that they are responding to a request. A
+ * cache will only respond to snoops if it has the line in either
+ * Modified or Owned state. Note that on snoop hits we always pass
+ * the line as Modified and never Owned. In the case of an Owned
+ * line we proceed to invalidate all other copies.
+ *
+ * On a cache fill (see Cache::handleFill), we check hasSharers
+ * first, ignoring the cacheResponding flag if hasSharers is set.
+ * A line is consequently allocated as:
+ *
+ * hasSharers cacheResponding state
+ * true false Shared
+ * true true Shared
+ * false false Exclusive
+ * false true Modified
+ */
+ void setCacheResponding()
+ {
+ assert(isRequest());
+ assert(!flags.isSet(CACHE_RESPONDING));
+ flags.set(CACHE_RESPONDING);
+ }
+ bool cacheResponding() const { return flags.isSet(CACHE_RESPONDING); }
+ /**
+ * On fills, the hasSharers flag is used by the caches in
+ * combination with the cacheResponding flag, as clarified
+ * above. If the hasSharers flag is not set, the packet is passing
+ * writable. Thus, a response from a memory passes the line as
+ * writable by default.
+ *
+ * The hasSharers flag is also used by upstream caches to inform a
+ * downstream cache that they have the block (by calling
+ * setHasSharers on snoop request packets that hit in upstream
+ * cachs tags or MSHRs). If the snoop packet has sharers, a
+ * downstream cache is prevented from passing a dirty line upwards
+ * if it was not explicitly asked for a writable copy. See
+ * Cache::satisfyCpuSideRequest.
+ *
+ * The hasSharers flag is also used on writebacks, in
+ * combination with the WritbackClean or WritebackDirty commands,
+ * to allocate the block downstream either as:
+ *
+ * command hasSharers state
+ * WritebackDirty false Modified
+ * WritebackDirty true Owned
+ * WritebackClean false Exclusive
+ * WritebackClean true Shared
+ */
+ void setHasSharers() { flags.set(HAS_SHARERS); }
+ bool hasSharers() const { return flags.isSet(HAS_SHARERS); }
+ //@}
+
+ /**
+ * The express snoop flag is used for two purposes. Firstly, it is
+ * used to bypass flow control for normal (non-snoop) requests
+ * going downstream in the memory system. In cases where a cache
+ * is responding to a snoop from another cache (it had a dirty
+ * line), but the line is not writable (and there are possibly
+ * other copies), the express snoop flag is set by the downstream
+ * cache to invalidate all other copies in zero time. Secondly,
+ * the express snoop flag is also set to be able to distinguish
+ * snoop packets that came from a downstream cache, rather than
+ * snoop packets from neighbouring caches.
+ */
+ void setExpressSnoop() { flags.set(EXPRESS_SNOOP); }
+ bool isExpressSnoop() const { return flags.isSet(EXPRESS_SNOOP); }
+
+ /**
+ * On responding to a snoop request (which only happens for
+ * Modified or Owned lines), make sure that we can transform an
+ * Owned response to a Modified one. If this flag is not set, the
+ * responding cache had the line in the Owned state, and there are
+ * possibly other Shared copies in the memory system. A downstream
+ * cache helps in orchestrating the invalidation of these copies
+ * by sending out the appropriate express snoops.
+ */
+ void setResponderHadWritable()
+ {
+ assert(cacheResponding());
+ assert(!responderHadWritable());
+ flags.set(RESPONDER_HAD_WRITABLE);
+ }
+ bool responderHadWritable() const
+ { return flags.isSet(RESPONDER_HAD_WRITABLE); }
+
+ /**
+ * Copy the reponse flags from an input packet to this packet. The
+ * reponse flags determine whether a responder has been found and
+ * the state at which the block will be at the destination.
+ *
+ * @pkt The packet that we will copy flags from
+ */
+ void copyResponderFlags(const PacketPtr pkt);
+
+ /**
+ * A writeback/writeclean cmd gets propagated further downstream
+ * by the receiver when the flag is set.
+ */
+ void setWriteThrough()
+ {
+ assert(cmd.isWrite() &&
+ (cmd.isEviction() || cmd == MemCmd::WriteClean));
+ flags.set(WRITE_THROUGH);
+ }
+ void clearWriteThrough() { flags.clear(WRITE_THROUGH); }
+ bool writeThrough() const { return flags.isSet(WRITE_THROUGH); }
+
+ /**
+ * Set when a request hits in a cache and the cache is not going
+ * to respond. This is used by the crossbar to coordinate
+ * responses for cache maintenance operations.
+ */
+ void setSatisfied()
+ {
+ assert(cmd.isClean());
+ assert(!flags.isSet(SATISFIED));
+ flags.set(SATISFIED);
+ }
+ bool satisfied() const { return flags.isSet(SATISFIED); }
+