From 1c61dae99b27380d9d5230b1b66cf3e54c7da663 Mon Sep 17 00:00:00 2001 From: Timothy Hayes Date: Mon, 6 Apr 2020 15:37:25 +0100 Subject: [PATCH 1/1] mem: Add HTM fields to the Packet object JIRA: https://gem5.atlassian.net/browse/GEM5-587 Change-Id: I39268825327f2387ca7e622093fdb42c24a6c82c Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/30318 Reviewed-by: Jason Lowe-Power Maintainer: Jason Lowe-Power Tested-by: kokoro --- src/mem/SConscript | 1 + src/mem/packet.cc | 65 ++++++++++++++++++++++- src/mem/packet.hh | 130 +++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 191 insertions(+), 5 deletions(-) diff --git a/src/mem/SConscript b/src/mem/SConscript index 07e197b9e..2fe179d37 100644 --- a/src/mem/SConscript +++ b/src/mem/SConscript @@ -114,6 +114,7 @@ DebugFlag('DRAM') DebugFlag('DRAMPower') DebugFlag('DRAMState') DebugFlag('ExternalPort') +DebugFlag('HtmMem', 'Hardware Transactional Memory (Mem side)') DebugFlag('LLSC') DebugFlag('MMU') DebugFlag('MemoryAccess') diff --git a/src/mem/packet.cc b/src/mem/packet.cc index b009cc5f6..0783e0f24 100644 --- a/src/mem/packet.cc +++ b/src/mem/packet.cc @@ -230,7 +230,11 @@ MemCmd::commandInfo[] = 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 @@ -489,3 +493,62 @@ Packet::PrintReqState::printObj(Printable *obj) 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; +} diff --git a/src/mem/packet.hh b/src/mem/packet.hh index 4af0d0b1c..4ded3b360 100644 --- a/src/mem/packet.hh +++ b/src/mem/packet.hh @@ -58,6 +58,7 @@ #include "base/logging.hh" #include "base/printable.hh" #include "base/types.hh" +#include "mem/htm.hh" #include "mem/request.hh" #include "sim/core.hh" @@ -131,6 +132,10 @@ class MemCmd FlushReq, //request for a cache flush InvalidateReq, // request for address to be invalidated InvalidateResp, + // hardware transactional memory + HTMReq, + HTMReqResp, + HTMAbort, NUM_MEM_CMDS }; @@ -259,7 +264,7 @@ class Packet : public Printable 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, @@ -289,6 +294,17 @@ class Packet : public Printable // 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, @@ -351,6 +367,21 @@ class Packet : public Printable // 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: /** @@ -793,14 +824,33 @@ class Packet : public Printable 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); @@ -815,9 +865,13 @@ class Packet : public Printable 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); @@ -840,6 +894,8 @@ class Packet : public Printable 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), @@ -850,6 +906,15 @@ class Packet : public Printable 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 @@ -873,7 +938,12 @@ class Packet : public Printable 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; @@ -1346,6 +1416,58 @@ class Packet : public Printable * @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 -- 2.30.2