* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2006 The Regents of The University of Michigan
- * Copyright (c) 2010 Advanced Micro Devices, Inc.
+ * Copyright (c) 2010,2015 Advanced Micro Devices, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
ReadRespWithInvalidate,
WriteReq,
WriteResp,
- Writeback,
+ WritebackDirty,
+ WritebackClean,
CleanEvict,
SoftPFReq,
HardPFReq,
SwapResp,
MessageReq,
MessageResp,
+ MemFenceReq,
+ MemFenceResp,
// Error responses
// @TODO these should be classified as responses rather than
// requests; coding them as requests initially for backwards
IsWrite, //!< Data flows from requester to responder
IsUpgrade,
IsInvalidate,
- NeedsExclusive, //!< Requires exclusive copy to complete in-cache
+ NeedsWritable, //!< Requires writable copy to complete in-cache
IsRequest, //!< Issued by requester
IsResponse, //!< Issue by responder
NeedsResponse, //!< Requester needs response from target
+ IsEviction,
IsSWPrefetch,
IsHWPrefetch,
IsLlsc, //!< Alpha/MIPS LL or SC access
bool isUpgrade() const { return testCmdAttrib(IsUpgrade); }
bool isRequest() const { return testCmdAttrib(IsRequest); }
bool isResponse() const { return testCmdAttrib(IsResponse); }
- bool needsExclusive() const { return testCmdAttrib(NeedsExclusive); }
+ bool needsWritable() const { return testCmdAttrib(NeedsWritable); }
bool needsResponse() const { return testCmdAttrib(NeedsResponse); }
bool isInvalidate() const { return testCmdAttrib(IsInvalidate); }
+ bool isEviction() const { return testCmdAttrib(IsEviction); }
+
+ /**
+ * A writeback is an eviction that carries data.
+ */
+ bool isWriteback() const { return testCmdAttrib(IsEviction) &&
+ testCmdAttrib(HasData); }
/**
* Check if this particular packet type carries payload data. Note
bool isPrint() const { return testCmdAttrib(IsPrint); }
bool isFlush() const { return testCmdAttrib(IsFlush); }
- const Command
+ Command
responseCommand() const
{
return commandInfo[cmd].response;
// Flags to transfer across when copying a packet
COPY_FLAGS = 0x0000000F,
- SHARED = 0x00000001,
+ // Does this packet have sharers (which means it should not be
+ // considered writable) or not. See setHasSharers below.
+ HAS_SHARERS = 0x00000001,
+
// Special control flags
/// Special timing-mode atomic snoop for multi-level coherence.
EXPRESS_SNOOP = 0x00000002,
- /// Does supplier have exclusive copy?
- /// Useful for multi-level coherence.
- SUPPLY_EXCLUSIVE = 0x00000004,
- // Snoop response flags
- MEM_INHIBIT = 0x00000008,
+
+ /// Allow a responding cache to inform the cache hierarchy
+ /// that it had a writable copy before responding. See
+ /// setResponderHadWritable below.
+ RESPONDER_HAD_WRITABLE = 0x00000004,
+
+ // Snoop co-ordination flag to indicate that a cache is
+ // responding to a snoop. See setCacheResponding below.
+ CACHE_RESPONDING = 0x00000008,
/// Are the 'addr' and 'size' fields valid?
VALID_ADDR = 0x00000100,
*/
uint32_t headerDelay;
+ /**
+ * Keep track of the extra delay incurred by snooping upwards
+ * before sending a request down the memory system. This is used
+ * by the coherent crossbar to account for the additional request
+ * delay.
+ */
+ uint32_t snoopDelay;
+
/**
* The extra pipelining delay from seeing the packet until the end of
* payload is transmitted by the component that provided it (if
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 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 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(); }
- // Snoop flags
- void assertMemInhibit()
+ //@{
+ /// 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(MEM_INHIBIT));
- 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); }
- bool isSupplyExclusive() const { return flags.isSet(SUPPLY_EXCLUSIVE); }
+ 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());
+ flags.set(RESPONDER_HAD_WRITABLE);
+ }
+ bool responderHadWritable() const
+ { return flags.isSet(RESPONDER_HAD_WRITABLE); }
+
void setSuppressFuncError() { flags.set(SUPPRESS_FUNC_ERROR); }
bool suppressFuncError() const { return flags.isSet(SUPPRESS_FUNC_ERROR); }
void setBlockCached() { flags.set(BLOCK_CACHED); }
return _isSecure;
}
+ /**
+ * Accessor function to atomic op.
+ */
+ AtomicOpFunctor *getAtomicOp() const { return req->getAtomicOpFunctor(); }
+ bool isAtomicOp() const { return req->isAtomic(); }
+
/**
* It has been determined that the SC packet should successfully update
* memory. Therefore, convert this SC packet to a normal write.
*/
Packet(const RequestPtr _req, MemCmd _cmd)
: cmd(_cmd), req(_req), data(nullptr), addr(0), _isSecure(false),
- size(0), headerDelay(0), payloadDelay(0),
+ size(0), headerDelay(0), snoopDelay(0), payloadDelay(0),
senderState(NULL)
{
if (req->hasPaddr()) {
*/
Packet(const RequestPtr _req, MemCmd _cmd, int _blkSize)
: cmd(_cmd), req(_req), data(nullptr), addr(0), _isSecure(false),
- headerDelay(0), payloadDelay(0),
+ headerDelay(0), snoopDelay(0), payloadDelay(0),
senderState(NULL)
{
if (req->hasPaddr()) {
addr(pkt->addr), _isSecure(pkt->_isSecure), size(pkt->size),
bytesValid(pkt->bytesValid),
headerDelay(pkt->headerDelay),
+ snoopDelay(0),
payloadDelay(pkt->payloadDelay),
senderState(pkt->senderState)
{
}
+ public:
+ /**
+ * @{
+ * @name Data accessor mehtods
+ */
+
/**
* Set the data pointer to the following value that should not be
* freed. Static data allows us to do a single memcpy even if
}
/**
- * return the value of what is pointed to in the packet.
+ * Get the data in the packet byte swapped from big endian to
+ * host endian.
+ */
+ template <typename T>
+ T getBE() const;
+
+ /**
+ * Get the data in the packet byte swapped from little endian to
+ * host endian.
+ */
+ template <typename T>
+ T getLE() const;
+
+ /**
+ * Get the data in the packet byte swapped from the specified
+ * endianness.
+ */
+ template <typename T>
+ T get(ByteOrder endian) const;
+
+ /**
+ * Get the data in the packet byte swapped from guest to host
+ * endian.
*/
template <typename T>
T get() const;
+ /** Set the value in the data pointer to v as big endian. */
+ template <typename T>
+ void setBE(T v);
+
+ /** Set the value in the data pointer to v as little endian. */
+ template <typename T>
+ void setLE(T v);
+
/**
- * set the value in the data pointer to v.
+ * Set the value in the data pointer to v using the specified
+ * endianness.
*/
template <typename T>
+ void set(T v, ByteOrder endian);
+
+ /** Set the value in the data pointer to v as guest endian. */
+ template <typename T>
void set(T v);
/**
void
allocate()
{
- assert(flags.noneSet(STATIC_DATA|DYNAMIC_DATA));
- flags.set(DYNAMIC_DATA);
- data = new uint8_t[getSize()];
+ // if either this command or the response command has a data
+ // payload, actually allocate space
+ if (hasData() || hasRespData()) {
+ assert(flags.noneSet(STATIC_DATA|DYNAMIC_DATA));
+ flags.set(DYNAMIC_DATA);
+ data = new uint8_t[getSize()];
+ }
}
+ /** @} */
+
+ private: // Private data accessor methods
+ /** Get the data in the packet without byte swapping. */
+ template <typename T>
+ T getRaw() const;
+
+ /** Set the value in the data pointer to v without byte swapping. */
+ template <typename T>
+ void setRaw(T v);
+
+ public:
/**
* Check a functional request against a memory value stored in
* another packet (i.e. an in-transit request or
}
/**
- * Is this request notification of a clean or dirty eviction from the cache.
+ * Does the request need to check for cached copies of the same block
+ * in the memory hierarchy above.
**/
bool
- evictingBlock() const
+ mustCheckAbove() const
{
- return (cmd == MemCmd::Writeback ||
- cmd == MemCmd::CleanEvict);
+ return cmd == MemCmd::HardPFReq || isEviction();
}
/**
- * Does the request need to check for cached copies of the same block
- * in the memory hierarchy above.
- **/
+ * Is this packet a clean eviction, including both actual clean
+ * evict packets, but also clean writebacks.
+ */
bool
- mustCheckAbove() const
+ isCleanEviction() const
{
- return (cmd == MemCmd::HardPFReq ||
- evictingBlock());
+ return cmd == MemCmd::CleanEvict || cmd == MemCmd::WritebackClean;
}
/**