InvalidateResp, "InvalidateReq" },
/* Invalidation Response */
{ SET2(IsInvalidate, IsResponse),
- InvalidCmd, "InvalidateResp" }
+ InvalidCmd, "InvalidateResp" },
+ // hardware transactional memory
+ { SET3(IsRead, IsRequest, NeedsResponse), HTMReqResp, "HTMReq" },
+ { SET2(IsRead, IsResponse), InvalidCmd, "HTMReqResp" },
+ { SET2(IsRead, IsRequest), InvalidCmd, "HTMAbort" },
};
AddrRange
printLabels();
obj->print(os, verbosity, curPrefix());
}
+
+void
+Packet::makeHtmTransactionalReqResponse(
+ const HtmCacheFailure htm_return_code)
+{
+ assert(needsResponse());
+ assert(isRequest());
+
+ cmd = cmd.responseCommand();
+
+ setHtmTransactionFailedInCache(htm_return_code);
+
+ // responses are never express, even if the snoop that
+ // triggered them was
+ flags.clear(EXPRESS_SNOOP);
+}
+
+void
+Packet::setHtmTransactionFailedInCache(
+ const HtmCacheFailure htm_return_code)
+{
+ if (htm_return_code != HtmCacheFailure::NO_FAIL)
+ flags.set(FAILS_TRANSACTION);
+
+ htmReturnReason = htm_return_code;
+}
+
+bool
+Packet::htmTransactionFailedInCache() const
+{
+ return flags.isSet(FAILS_TRANSACTION);
+}
+
+HtmCacheFailure
+Packet::getHtmTransactionFailedInCacheRC() const
+{
+ assert(htmTransactionFailedInCache());
+ return htmReturnReason;
+}
+
+void
+Packet::setHtmTransactional(uint64_t htm_uid)
+{
+ flags.set(FROM_TRANSACTION);
+ htmTransactionUid = htm_uid;
+}
+
+bool
+Packet::isHtmTransactional() const
+{
+ return flags.isSet(FROM_TRANSACTION);
+}
+
+uint64_t
+Packet::getHtmTransactionUid() const
+{
+ assert(flags.isSet(FROM_TRANSACTION));
+ return htmTransactionUid;
+}
#include "base/logging.hh"
#include "base/printable.hh"
#include "base/types.hh"
+#include "mem/htm.hh"
#include "mem/request.hh"
#include "sim/core.hh"
FlushReq, //request for a cache flush
InvalidateReq, // request for address to be invalidated
InvalidateResp,
+ // hardware transactional memory
+ HTMReq,
+ HTMReqResp,
+ HTMAbort,
NUM_MEM_CMDS
};
enum : FlagsType {
// Flags to transfer across when copying a packet
- COPY_FLAGS = 0x0000003F,
+ COPY_FLAGS = 0x000000FF,
// Flags that are used to create reponse packets
RESPONDER_FLAGS = 0x00000009,
// operations
SATISFIED = 0x00000020,
+ // hardware transactional memory
+
+ // Indicates that this packet/request has returned from the
+ // cache hierarchy in a failed transaction. The core is
+ // notified like this.
+ FAILS_TRANSACTION = 0x00000040,
+
+ // Indicates that this packet/request originates in the CPU executing
+ // in transactional mode, i.e. in a transaction.
+ FROM_TRANSACTION = 0x00000080,
+
/// Are the 'addr' and 'size' fields valid?
VALID_ADDR = 0x00000100,
VALID_SIZE = 0x00000200,
// Quality of Service priority value
uint8_t _qosValue;
+ // hardware transactional memory
+
+ /**
+ * Holds the return status of the transaction.
+ * The default case will be NO_FAIL, otherwise this will specify the
+ * reason for the transaction's failure in the memory subsystem.
+ */
+ HtmCacheFailure htmReturnReason;
+
+ /**
+ * A global unique identifier of the transaction.
+ * This is used for correctness/debugging only.
+ */
+ uint64_t htmTransactionUid;
+
public:
/**
Packet(const RequestPtr &_req, MemCmd _cmd)
: cmd(_cmd), id((PacketId)_req.get()), req(_req),
data(nullptr), addr(0), _isSecure(false), size(0),
- _qosValue(0), headerDelay(0), snoopDelay(0),
+ _qosValue(0),
+ htmReturnReason(HtmCacheFailure::NO_FAIL),
+ htmTransactionUid(0),
+ headerDelay(0), snoopDelay(0),
payloadDelay(0), senderState(NULL)
{
+ flags.clear();
if (req->hasPaddr()) {
addr = req->getPaddr();
flags.set(VALID_ADDR);
_isSecure = req->isSecure();
}
+
+ /**
+ * hardware transactional memory
+ *
+ * This is a bit of a hack!
+ * Technically the address of a HTM command is set to zero
+ * but is not valid. The reason that we pretend it's valid is
+ * to void the getAddr() function from failing. It would be
+ * cumbersome to add control flow in many places to check if the
+ * packet represents a HTM command before calling getAddr().
+ */
+ if (req->isHTMCmd()) {
+ flags.set(VALID_ADDR);
+ assert(addr == 0x0);
+ }
if (req->hasSize()) {
size = req->getSize();
flags.set(VALID_SIZE);
Packet(const RequestPtr &_req, MemCmd _cmd, int _blkSize, PacketId _id = 0)
: cmd(_cmd), id(_id ? _id : (PacketId)_req.get()), req(_req),
data(nullptr), addr(0), _isSecure(false),
- _qosValue(0), headerDelay(0),
+ _qosValue(0),
+ htmReturnReason(HtmCacheFailure::NO_FAIL),
+ htmTransactionUid(0),
+ headerDelay(0),
snoopDelay(0), payloadDelay(0), senderState(NULL)
{
+ flags.clear();
if (req->hasPaddr()) {
addr = req->getPaddr() & ~(_blkSize - 1);
flags.set(VALID_ADDR);
addr(pkt->addr), _isSecure(pkt->_isSecure), size(pkt->size),
bytesValid(pkt->bytesValid),
_qosValue(pkt->qosValue()),
+ htmReturnReason(HtmCacheFailure::NO_FAIL),
+ htmTransactionUid(0),
headerDelay(pkt->headerDelay),
snoopDelay(0),
payloadDelay(pkt->payloadDelay),
flags.set(pkt->flags & (VALID_ADDR|VALID_SIZE));
+ if (pkt->isHtmTransactional())
+ setHtmTransactional(pkt->getHtmTransactionUid());
+
+ if (pkt->htmTransactionFailedInCache()) {
+ setHtmTransactionFailedInCache(
+ pkt->getHtmTransactionFailedInCacheRC()
+ );
+ }
+
// should we allocate space for data, or not, the express
// snoops do not need to carry any data as they only serve to
// co-ordinate state changes
static MemCmd
makeReadCmd(const RequestPtr &req)
{
- if (req->isLLSC())
+ if (req->isHTMCmd()) {
+ if (req->isHTMAbort())
+ return MemCmd::HTMAbort;
+ else
+ return MemCmd::HTMReq;
+ } else if (req->isLLSC())
return MemCmd::LoadLockedReq;
else if (req->isPrefetchEx())
return MemCmd::SoftPFExReq;
* @return string with the request's type and start<->end addresses
*/
std::string print() const;
+
+ // hardware transactional memory
+
+ /**
+ * Communicates to the core that a packet was processed by the memory
+ * subsystem while running in transactional mode.
+ * It may happen that the transaction has failed at the memory subsystem
+ * and this needs to be communicated to the core somehow.
+ * This function decorates the response packet with flags to indicate
+ * such a situation has occurred.
+ */
+ void makeHtmTransactionalReqResponse(const HtmCacheFailure ret_code);
+
+ /**
+ * Stipulates that this packet/request originates in the CPU executing
+ * in transactional mode, i.e. within a transaction.
+ */
+ void setHtmTransactional(uint64_t val);
+
+ /**
+ * Returns whether or not this packet/request originates in the CPU
+ * executing in transactional mode, i.e. within a transaction.
+ */
+ bool isHtmTransactional() const;
+
+ /**
+ * If a packet/request originates in a CPU executing in transactional
+ * mode, i.e. within a transaction, this function returns the unique ID
+ * of the transaction. This is used for verifying correctness
+ * and debugging.
+ */
+ uint64_t getHtmTransactionUid() const;
+
+ /**
+ * Stipulates that this packet/request has returned from the
+ * cache hierarchy in a failed transaction. The core is
+ * notified like this.
+ */
+ void setHtmTransactionFailedInCache(const HtmCacheFailure ret_code);
+
+ /**
+ * Returns whether or not this packet/request has returned from the
+ * cache hierarchy in a failed transaction. The core is
+ * notified liked this.
+ */
+ bool htmTransactionFailedInCache() const;
+
+ /**
+ * If a packet/request has returned from the cache hierarchy in a
+ * failed transaction, this function returns the failure reason.
+ */
+ HtmCacheFailure getHtmTransactionFailedInCacheRC() const;
};
#endif //__MEM_PACKET_HH