| /* | 
 |  * Copyright (c) 2011-2019 ARM Limited | 
 |  * All rights reserved | 
 |  * | 
 |  * The license below extends only to copyright in the software and shall | 
 |  * not be construed as granting a license to any other intellectual | 
 |  * property including but not limited to intellectual property relating | 
 |  * to a hardware implementation of the functionality of the software | 
 |  * licensed hereunder.  You may use the software subject to the license | 
 |  * terms below provided that you ensure that this notice is replicated | 
 |  * unmodified and in its entirety in all distributions of the software, | 
 |  * modified or unmodified, in source code or in binary form. | 
 |  * | 
 |  * Copyright (c) 2006 The Regents of The University of Michigan | 
 |  * Copyright (c) 2010,2015 Advanced Micro Devices, Inc. | 
 |  * All rights reserved. | 
 |  * | 
 |  * Redistribution and use in source and binary forms, with or without | 
 |  * modification, are permitted provided that the following conditions are | 
 |  * met: redistributions of source code must retain the above copyright | 
 |  * notice, this list of conditions and the following disclaimer; | 
 |  * redistributions in binary form must reproduce the above copyright | 
 |  * notice, this list of conditions and the following disclaimer in the | 
 |  * documentation and/or other materials provided with the distribution; | 
 |  * neither the name of the copyright holders nor the names of its | 
 |  * contributors may be used to endorse or promote products derived from | 
 |  * this software without specific prior written permission. | 
 |  * | 
 |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
 |  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
 |  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
 |  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
 |  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
 |  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
 |  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
 |  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
 |  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
 |  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
 |  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
 |  */ | 
 |  | 
 | /** | 
 |  * @file | 
 |  * Definition of the Packet Class, a packet is a transaction occuring | 
 |  * between a single level of the memory heirarchy (ie L1->L2). | 
 |  */ | 
 |  | 
 | #include "mem/packet.hh" | 
 |  | 
 | #include <algorithm> | 
 | #include <cstring> | 
 | #include <iostream> | 
 | #include <sstream> | 
 | #include <string> | 
 |  | 
 | #include "base/cprintf.hh" | 
 | #include "base/logging.hh" | 
 | #include "base/trace.hh" | 
 | #include "mem/packet_access.hh" | 
 |  | 
 | namespace gem5 | 
 | { | 
 |  | 
 | const MemCmd::CommandInfo | 
 | MemCmd::commandInfo[] = | 
 | { | 
 |     /* InvalidCmd */ | 
 |     { {}, InvalidCmd, "InvalidCmd" }, | 
 |     /* ReadReq - Read issued by a non-caching agent such as a CPU or | 
 |      * device, with no restrictions on alignment. */ | 
 |     { {IsRead, IsRequest, NeedsResponse}, ReadResp, "ReadReq" }, | 
 |     /* ReadResp */ | 
 |     { {IsRead, IsResponse, HasData}, InvalidCmd, "ReadResp" }, | 
 |     /* ReadRespWithInvalidate */ | 
 |     { {IsRead, IsResponse, HasData, IsInvalidate}, | 
 |             InvalidCmd, "ReadRespWithInvalidate" }, | 
 |     /* WriteReq */ | 
 |     { {IsWrite, NeedsWritable, IsRequest, NeedsResponse, HasData}, | 
 |             WriteResp, "WriteReq" }, | 
 |     /* WriteResp */ | 
 |     { {IsWrite, IsResponse}, InvalidCmd, "WriteResp" }, | 
 |     /* WriteCompleteResp - The WriteCompleteResp command is needed | 
 |      * because in the GPU memory model we use a WriteResp to indicate | 
 |      * that a write has reached the cache controller so we can free | 
 |      * resources at the coalescer. Later, when the write succesfully | 
 |      * completes we send a WriteCompleteResp to the CU so its wait | 
 |      * counters can be updated. Wait counters in the CU is how memory | 
 |      * dependences are handled in the GPU ISA. */ | 
 |     { {IsWrite, IsResponse}, InvalidCmd, "WriteCompleteResp" }, | 
 |     /* WritebackDirty */ | 
 |     { {IsWrite, IsRequest, IsEviction, HasData, FromCache}, | 
 |             InvalidCmd, "WritebackDirty" }, | 
 |     /* WritebackClean - This allows the upstream cache to writeback a | 
 |      * line to the downstream cache without it being considered | 
 |      * dirty. */ | 
 |     { {IsWrite, IsRequest, IsEviction, HasData, FromCache}, | 
 |             InvalidCmd, "WritebackClean" }, | 
 |     /* WriteClean - This allows a cache to write a dirty block to a memory | 
 |        below without evicting its copy. */ | 
 |     { {IsWrite, IsRequest, HasData, FromCache}, InvalidCmd, "WriteClean" }, | 
 |     /* CleanEvict */ | 
 |     { {IsRequest, IsEviction, FromCache}, InvalidCmd, "CleanEvict" }, | 
 |     /* SoftPFReq */ | 
 |     { {IsRead, IsRequest, IsSWPrefetch, NeedsResponse}, | 
 |             SoftPFResp, "SoftPFReq" }, | 
 |     /* SoftPFExReq */ | 
 |     { {IsRead, NeedsWritable, IsInvalidate, IsRequest, | 
 |            IsSWPrefetch, NeedsResponse}, SoftPFResp, "SoftPFExReq" }, | 
 |     /* HardPFReq */ | 
 |     { {IsRead, IsRequest, IsHWPrefetch, NeedsResponse, FromCache}, | 
 |             HardPFResp, "HardPFReq" }, | 
 |     /* SoftPFResp */ | 
 |     { {IsRead, IsResponse, IsSWPrefetch, HasData}, InvalidCmd, "SoftPFResp" }, | 
 |     /* HardPFResp */ | 
 |     { {IsRead, IsResponse, IsHWPrefetch, HasData}, InvalidCmd, "HardPFResp" }, | 
 |     /* WriteLineReq */ | 
 |     { {IsWrite, NeedsWritable, IsRequest, NeedsResponse, HasData}, | 
 |             WriteResp, "WriteLineReq" }, | 
 |     /* UpgradeReq */ | 
 |     { {IsInvalidate, NeedsWritable, IsUpgrade, IsRequest, NeedsResponse, | 
 |             FromCache}, UpgradeResp, "UpgradeReq" }, | 
 |     /* SCUpgradeReq: response could be UpgradeResp or UpgradeFailResp */ | 
 |     { {IsInvalidate, NeedsWritable, IsUpgrade, IsLlsc, | 
 |            IsRequest, NeedsResponse, FromCache}, | 
 |             UpgradeResp, "SCUpgradeReq" }, | 
 |     /* UpgradeResp */ | 
 |     { {IsUpgrade, IsResponse}, InvalidCmd, "UpgradeResp" }, | 
 |     /* SCUpgradeFailReq: generates UpgradeFailResp but still gets the data */ | 
 |     { {IsRead, NeedsWritable, IsInvalidate, | 
 |            IsLlsc, IsRequest, NeedsResponse, FromCache}, | 
 |             UpgradeFailResp, "SCUpgradeFailReq" }, | 
 |     /* UpgradeFailResp - Behaves like a ReadExReq, but notifies an SC | 
 |      * that it has failed, acquires line as Dirty*/ | 
 |     { {IsRead, IsResponse, HasData}, InvalidCmd, "UpgradeFailResp" }, | 
 |     /* ReadExReq - Read issues by a cache, always cache-line aligned, | 
 |      * and the response is guaranteed to be writeable (exclusive or | 
 |      * even modified} */ | 
 |     { {IsRead, NeedsWritable, IsInvalidate, IsRequest, NeedsResponse, | 
 |           FromCache}, ReadExResp, "ReadExReq" }, | 
 |     /* ReadExResp - Response matching a read exclusive, as we check | 
 |      * the need for exclusive also on responses */ | 
 |     { {IsRead, IsResponse, HasData}, InvalidCmd, "ReadExResp" }, | 
 |     /* ReadCleanReq - Read issued by a cache, always cache-line | 
 |      * aligned, and the response is guaranteed to not contain dirty data | 
 |      * (exclusive or shared}.*/ | 
 |     { {IsRead, IsRequest, NeedsResponse, FromCache}, | 
 |             ReadResp, "ReadCleanReq" }, | 
 |     /* ReadSharedReq - Read issued by a cache, always cache-line | 
 |      * aligned, response is shared, possibly exclusive, owned or even | 
 |      * modified. */ | 
 |     { {IsRead, IsRequest, NeedsResponse, FromCache}, | 
 |             ReadResp, "ReadSharedReq" }, | 
 |     /* LoadLockedReq: note that we use plain ReadResp as response, so that | 
 |      *                we can also use ReadRespWithInvalidate when needed */ | 
 |     { {IsRead, IsLlsc, IsRequest, NeedsResponse}, | 
 |             ReadResp, "LoadLockedReq" }, | 
 |     /* StoreCondReq */ | 
 |     { {IsWrite, NeedsWritable, IsLlsc, | 
 |            IsRequest, NeedsResponse, HasData}, | 
 |             StoreCondResp, "StoreCondReq" }, | 
 |     /* StoreCondFailReq: generates failing StoreCondResp */ | 
 |     { {IsWrite, NeedsWritable, IsLlsc, IsRequest, NeedsResponse, HasData}, | 
 |             StoreCondResp, "StoreCondFailReq" }, | 
 |     /* StoreCondResp */ | 
 |     { {IsWrite, IsLlsc, IsResponse}, | 
 |             InvalidCmd, "StoreCondResp" }, | 
 |     /* SwapReq -- for Swap ldstub type operations */ | 
 |     { {IsRead, IsWrite, NeedsWritable, IsRequest, HasData, NeedsResponse}, | 
 |         SwapResp, "SwapReq" }, | 
 |     /* SwapResp -- for Swap ldstub type operations */ | 
 |     { {IsRead, IsWrite, IsResponse, HasData}, InvalidCmd, "SwapResp" }, | 
 |     { {}, InvalidCmd, "Deprecated_MessageReq" }, | 
 |     { {}, InvalidCmd, "Deprecated_MessageResp" }, | 
 |     /* MemFenceReq -- for synchronization requests */ | 
 |     {{IsRequest, NeedsResponse}, MemFenceResp, "MemFenceReq"}, | 
 |     /* MemSyncReq */ | 
 |     {{IsRequest, NeedsResponse}, MemSyncResp, "MemSyncReq"}, | 
 |     /* MemSyncResp */ | 
 |     {{IsResponse}, InvalidCmd, "MemSyncResp"}, | 
 |     /* MemFenceResp -- for synchronization responses */ | 
 |     {{IsResponse}, InvalidCmd, "MemFenceResp"}, | 
 |     /* Cache Clean Request -- Update with the latest data all existing | 
 |        copies of the block down to the point indicated by the | 
 |        request */ | 
 |     { {IsRequest, IsClean, NeedsResponse, FromCache}, | 
 |       CleanSharedResp, "CleanSharedReq" }, | 
 |     /* Cache Clean Response - Indicates that all caches up to the | 
 |        specified point of reference have a up-to-date copy of the | 
 |        cache block or no copy at all */ | 
 |     { {IsResponse, IsClean}, InvalidCmd, "CleanSharedResp" }, | 
 |     /* Cache Clean and Invalidate Request -- Invalidate all existing | 
 |        copies down to the point indicated by the request */ | 
 |     { {IsRequest, IsInvalidate, IsClean, NeedsResponse, FromCache}, | 
 |       CleanInvalidResp, "CleanInvalidReq" }, | 
 |      /* Cache Clean and Invalidate Respose -- Indicates that no cache | 
 |         above the specified point holds the block and that the block | 
 |         was written to a memory below the specified point. */ | 
 |     { {IsResponse, IsInvalidate, IsClean}, | 
 |       InvalidCmd, "CleanInvalidResp" }, | 
 |     /* InvalidDestError  -- packet dest field invalid */ | 
 |     { {IsResponse, IsError}, InvalidCmd, "InvalidDestError" }, | 
 |     /* BadAddressError   -- memory address invalid */ | 
 |     { {IsResponse, IsError}, InvalidCmd, "BadAddressError" }, | 
 |     /* FunctionalReadError */ | 
 |     { {IsRead, IsResponse, IsError}, InvalidCmd, "FunctionalReadError" }, | 
 |     /* FunctionalWriteError */ | 
 |     { {IsWrite, IsResponse, IsError}, InvalidCmd, "FunctionalWriteError" }, | 
 |     /* PrintReq */ | 
 |     { {IsRequest, IsPrint}, InvalidCmd, "PrintReq" }, | 
 |     /* Flush Request */ | 
 |     { {IsRequest, IsFlush, NeedsWritable}, InvalidCmd, "FlushReq" }, | 
 |     /* Invalidation Request */ | 
 |     { {IsInvalidate, IsRequest, NeedsWritable, NeedsResponse, FromCache}, | 
 |       InvalidateResp, "InvalidateReq" }, | 
 |     /* Invalidation Response */ | 
 |     { {IsInvalidate, IsResponse}, | 
 |       InvalidCmd, "InvalidateResp" }, | 
 |       // hardware transactional memory | 
 |     { {IsRead, IsRequest, NeedsResponse}, HTMReqResp, "HTMReq" }, | 
 |     { {IsRead, IsResponse}, InvalidCmd, "HTMReqResp" }, | 
 |     { {IsRead, IsRequest}, InvalidCmd, "HTMAbort" }, | 
 | }; | 
 |  | 
 | AddrRange | 
 | Packet::getAddrRange() const | 
 | { | 
 |     return RangeSize(getAddr(), getSize()); | 
 | } | 
 |  | 
 | bool | 
 | Packet::trySatisfyFunctional(Printable *obj, Addr addr, bool is_secure, int size, | 
 |                         uint8_t *_data) | 
 | { | 
 |     const Addr func_start = getAddr(); | 
 |     const Addr func_end   = getAddr() + getSize() - 1; | 
 |     const Addr val_start  = addr; | 
 |     const Addr val_end    = val_start + size - 1; | 
 |  | 
 |     if (is_secure != _isSecure || func_start > val_end || | 
 |         val_start > func_end) { | 
 |         // no intersection | 
 |         return false; | 
 |     } | 
 |  | 
 |     // check print first since it doesn't require data | 
 |     if (isPrint()) { | 
 |         assert(!_data); | 
 |         safe_cast<PrintReqState*>(senderState)->printObj(obj); | 
 |         return false; | 
 |     } | 
 |  | 
 |     // we allow the caller to pass NULL to signify the other packet | 
 |     // has no data | 
 |     if (!_data) { | 
 |         return false; | 
 |     } | 
 |  | 
 |     const Addr val_offset = func_start > val_start ? | 
 |         func_start - val_start : 0; | 
 |     const Addr func_offset = func_start < val_start ? | 
 |         val_start - func_start : 0; | 
 |     const Addr overlap_size = std::min(val_end, func_end)+1 - | 
 |         std::max(val_start, func_start); | 
 |  | 
 |     if (isRead()) { | 
 |         std::memcpy(getPtr<uint8_t>() + func_offset, | 
 |                _data + val_offset, | 
 |                overlap_size); | 
 |  | 
 |         // initialise the tracking of valid bytes if we have not | 
 |         // used it already | 
 |         if (bytesValid.empty()) | 
 |             bytesValid.resize(getSize(), false); | 
 |  | 
 |         // track if we are done filling the functional access | 
 |         bool all_bytes_valid = true; | 
 |  | 
 |         int i = 0; | 
 |  | 
 |         // check up to func_offset | 
 |         for (; all_bytes_valid && i < func_offset; ++i) | 
 |             all_bytes_valid &= bytesValid[i]; | 
 |  | 
 |         // update the valid bytes | 
 |         for (i = func_offset; i < func_offset + overlap_size; ++i) | 
 |             bytesValid[i] = true; | 
 |  | 
 |         // check the bit after the update we just made | 
 |         for (; all_bytes_valid && i < getSize(); ++i) | 
 |             all_bytes_valid &= bytesValid[i]; | 
 |  | 
 |         return all_bytes_valid; | 
 |     } else if (isWrite()) { | 
 |         std::memcpy(_data + val_offset, | 
 |                getConstPtr<uint8_t>() + func_offset, | 
 |                overlap_size); | 
 |     } else { | 
 |         panic("Don't know how to handle command %s\n", cmdString()); | 
 |     } | 
 |  | 
 |     // keep going with request by default | 
 |     return false; | 
 | } | 
 |  | 
 | void | 
 | Packet::copyResponderFlags(const PacketPtr pkt) | 
 | { | 
 |     assert(isRequest()); | 
 |     // If we have already found a responder, no other cache should | 
 |     // commit to responding | 
 |     assert(!pkt->cacheResponding() || !cacheResponding()); | 
 |     flags.set(pkt->flags & RESPONDER_FLAGS); | 
 | } | 
 |  | 
 | void | 
 | Packet::pushSenderState(Packet::SenderState *sender_state) | 
 | { | 
 |     assert(sender_state != NULL); | 
 |     sender_state->predecessor = senderState; | 
 |     senderState = sender_state; | 
 | } | 
 |  | 
 | Packet::SenderState * | 
 | Packet::popSenderState() | 
 | { | 
 |     assert(senderState != NULL); | 
 |     SenderState *sender_state = senderState; | 
 |     senderState = sender_state->predecessor; | 
 |     sender_state->predecessor = NULL; | 
 |     return sender_state; | 
 | } | 
 |  | 
 | uint64_t | 
 | Packet::getUintX(ByteOrder endian) const | 
 | { | 
 |     switch(getSize()) { | 
 |       case 1: | 
 |         return (uint64_t)get<uint8_t>(endian); | 
 |       case 2: | 
 |         return (uint64_t)get<uint16_t>(endian); | 
 |       case 4: | 
 |         return (uint64_t)get<uint32_t>(endian); | 
 |       case 8: | 
 |         return (uint64_t)get<uint64_t>(endian); | 
 |       default: | 
 |         panic("%i isn't a supported word size.\n", getSize()); | 
 |     } | 
 | } | 
 |  | 
 | void | 
 | Packet::setUintX(uint64_t w, ByteOrder endian) | 
 | { | 
 |     switch(getSize()) { | 
 |       case 1: | 
 |         set<uint8_t>((uint8_t)w, endian); | 
 |         break; | 
 |       case 2: | 
 |         set<uint16_t>((uint16_t)w, endian); | 
 |         break; | 
 |       case 4: | 
 |         set<uint32_t>((uint32_t)w, endian); | 
 |         break; | 
 |       case 8: | 
 |         set<uint64_t>((uint64_t)w, endian); | 
 |         break; | 
 |       default: | 
 |         panic("%i isn't a supported word size.\n", getSize()); | 
 |     } | 
 |  | 
 | } | 
 |  | 
 | void | 
 | Packet::print(std::ostream &o, const int verbosity, | 
 |               const std::string &prefix) const | 
 | { | 
 |     ccprintf(o, "%s%s [%x:%x]%s%s%s%s%s%s", prefix, cmdString(), | 
 |              getAddr(), getAddr() + getSize() - 1, | 
 |              req->isSecure() ? " (s)" : "", | 
 |              req->isInstFetch() ? " IF" : "", | 
 |              req->isUncacheable() ? " UC" : "", | 
 |              isExpressSnoop() ? " ES" : "", | 
 |              req->isToPOC() ? " PoC" : "", | 
 |              req->isToPOU() ? " PoU" : ""); | 
 | } | 
 |  | 
 | std::string | 
 | Packet::print() const { | 
 |     std::ostringstream str; | 
 |     print(str); | 
 |     return str.str(); | 
 | } | 
 |  | 
 | bool | 
 | Packet::matchBlockAddr(const Addr addr, const bool is_secure, | 
 |                        const int blk_size) const | 
 | { | 
 |     return (getBlockAddr(blk_size) == addr) && (isSecure() == is_secure); | 
 | } | 
 |  | 
 | bool | 
 | Packet::matchBlockAddr(const PacketPtr pkt, const int blk_size) const | 
 | { | 
 |     return matchBlockAddr(pkt->getBlockAddr(blk_size), pkt->isSecure(), | 
 |                           blk_size); | 
 | } | 
 |  | 
 | bool | 
 | Packet::matchAddr(const Addr addr, const bool is_secure) const | 
 | { | 
 |     return (getAddr() == addr) && (isSecure() == is_secure); | 
 | } | 
 |  | 
 | bool | 
 | Packet::matchAddr(const PacketPtr pkt) const | 
 | { | 
 |     return matchAddr(pkt->getAddr(), pkt->isSecure()); | 
 | } | 
 |  | 
 | Packet::PrintReqState::PrintReqState(std::ostream &_os, int _verbosity) | 
 |     : curPrefixPtr(new std::string("")), os(_os), verbosity(_verbosity) | 
 | { | 
 |     labelStack.push_back(LabelStackEntry("", curPrefixPtr)); | 
 | } | 
 |  | 
 | Packet::PrintReqState::~PrintReqState() | 
 | { | 
 |     labelStack.pop_back(); | 
 |     assert(labelStack.empty()); | 
 |     delete curPrefixPtr; | 
 | } | 
 |  | 
 | Packet::PrintReqState:: | 
 | LabelStackEntry::LabelStackEntry(const std::string &_label, | 
 |                                  std::string *_prefix) | 
 |     : label(_label), prefix(_prefix), labelPrinted(false) | 
 | { | 
 | } | 
 |  | 
 | void | 
 | Packet::PrintReqState::pushLabel(const std::string &lbl, | 
 |                                  const std::string &prefix) | 
 | { | 
 |     labelStack.push_back(LabelStackEntry(lbl, curPrefixPtr)); | 
 |     curPrefixPtr = new std::string(*curPrefixPtr); | 
 |     *curPrefixPtr += prefix; | 
 | } | 
 |  | 
 | void | 
 | Packet::PrintReqState::popLabel() | 
 | { | 
 |     delete curPrefixPtr; | 
 |     curPrefixPtr = labelStack.back().prefix; | 
 |     labelStack.pop_back(); | 
 |     assert(!labelStack.empty()); | 
 | } | 
 |  | 
 | void | 
 | Packet::PrintReqState::printLabels() | 
 | { | 
 |     if (!labelStack.back().labelPrinted) { | 
 |         LabelStack::iterator i = labelStack.begin(); | 
 |         LabelStack::iterator end = labelStack.end(); | 
 |         while (i != end) { | 
 |             if (!i->labelPrinted) { | 
 |                 ccprintf(os, "%s%s\n", *(i->prefix), i->label); | 
 |                 i->labelPrinted = true; | 
 |             } | 
 |             i++; | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 |  | 
 | void | 
 | 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; | 
 | } | 
 |  | 
 | } // namespace gem5 |