diff options
-rw-r--r-- | src/mem/cache/cache.cc | 44 | ||||
-rw-r--r-- | src/mem/cache/cache.hh | 3 | ||||
-rw-r--r-- | src/mem/coherent_xbar.cc | 40 | ||||
-rw-r--r-- | src/mem/coherent_xbar.hh | 23 | ||||
-rw-r--r-- | src/mem/packet.cc | 6 | ||||
-rw-r--r-- | src/mem/packet.hh | 19 | ||||
-rw-r--r-- | src/mem/request.hh | 24 |
7 files changed, 136 insertions, 23 deletions
diff --git a/src/mem/cache/cache.cc b/src/mem/cache/cache.cc index 74c488084..97df5625b 100644 --- a/src/mem/cache/cache.cc +++ b/src/mem/cache/cache.cc @@ -430,20 +430,26 @@ Cache::access(PacketPtr pkt, CacheBlk *&blk, Cycles &lat, assert(blkSize == pkt->getSize()); if (!blk) { - // a writeback that misses needs to allocate a new block - blk = allocateBlock(pkt->getAddr(), pkt->isSecure(), - writebacks); - if (!blk) { - // no replaceable block available: give up, fwd to - // next level. - incMissCount(pkt); + if (pkt->writeThrough()) { + // if this is a write through packet, we don't try to + // allocate if the block is not present return false; - } - tags->insertBlock(pkt, blk); + } else { + // a writeback that misses needs to allocate a new block + blk = allocateBlock(pkt->getAddr(), pkt->isSecure(), + writebacks); + if (!blk) { + // no replaceable block available: give up, fwd to + // next level. + incMissCount(pkt); + return false; + } + tags->insertBlock(pkt, blk); - blk->status = (BlkValid | BlkReadable); - if (pkt->isSecure()) { - blk->status |= BlkSecure; + blk->status = (BlkValid | BlkReadable); + if (pkt->isSecure()) { + blk->status |= BlkSecure; + } } } @@ -451,7 +457,9 @@ Cache::access(PacketPtr pkt, CacheBlk *&blk, Cycles &lat, // write clean operation and the block is already in this // cache, we need to update the data and the block flags assert(blk); - blk->status |= BlkDirty; + if (!pkt->writeThrough()) { + blk->status |= BlkDirty; + } // nothing else to do; writeback doesn't expect response assert(!pkt->needsResponse()); std::memcpy(blk->data, pkt->getConstPtr<uint8_t>(), blkSize); @@ -461,7 +469,9 @@ Cache::access(PacketPtr pkt, CacheBlk *&blk, Cycles &lat, // populate the time when the block will be ready to access. blk->whenReady = clockEdge(fillLatency) + pkt->headerDelay + pkt->payloadDelay; - return true; + // if this a write-through packet it will be sent to cache + // below + return !pkt->writeThrough(); } else if (blk && (pkt->needsWritable() ? blk->isWritable() : blk->isReadable())) { // OK to satisfy access @@ -1623,7 +1633,7 @@ Cache::writebackBlk(CacheBlk *blk) } PacketPtr -Cache::writecleanBlk(CacheBlk *blk) +Cache::writecleanBlk(CacheBlk *blk, Request::Flags dest) { Request *req = new Request(tags->regenerateBlkAddr(blk->tag, blk->set), blkSize, 0, Request::wbMasterId); @@ -1641,6 +1651,10 @@ Cache::writecleanBlk(CacheBlk *blk) // We inform the cache below that the block has sharers in the // system as we retain our copy. pkt->setHasSharers(); + if (dest) { + req->setFlags(dest); + pkt->setWriteThrough(); + } std::memcpy(pkt->getPtr<uint8_t>(), blk->data, blkSize); return pkt; } diff --git a/src/mem/cache/cache.hh b/src/mem/cache/cache.hh index bbbda500b..cd3a1d8e5 100644 --- a/src/mem/cache/cache.hh +++ b/src/mem/cache/cache.hh @@ -455,9 +455,10 @@ class Cache : public BaseCache /** * Create a writeclean request for the given block. * @param blk The block to write clean + * @param dest The destination of this clean operation * @return The write clean packet for the block. */ - PacketPtr writecleanBlk(CacheBlk *blk); + PacketPtr writecleanBlk(CacheBlk *blk, Request::Flags dest = 0); /** * Create a CleanEvict request for the given block. diff --git a/src/mem/coherent_xbar.cc b/src/mem/coherent_xbar.cc index 6aec0b335..e946134d3 100644 --- a/src/mem/coherent_xbar.cc +++ b/src/mem/coherent_xbar.cc @@ -183,6 +183,12 @@ CoherentXBar::recvTimingReq(PacketPtr pkt, PortID slave_port_id) // determine how long to be crossbar layer is busy Tick packetFinishTime = clockEdge(Cycles(1)) + pkt->payloadDelay; + // is this the destination point for this packet? (e.g. true if + // this xbar is the PoC for a cache maintenance operation to the + // PoC) otherwise the destination is any cache that can satisfy + // the request + const bool is_destination = isDestination(pkt); + const bool snoop_caches = !system->bypassCaches() && pkt->cmd != MemCmd::WriteClean; if (snoop_caches) { @@ -243,7 +249,7 @@ CoherentXBar::recvTimingReq(PacketPtr pkt, PortID slave_port_id) } else { // determine if we are forwarding the packet, or responding to // it - if (!pointOfCoherency || pkt->isRead() || pkt->isWrite()) { + if (forwardPacket(pkt)) { // if we are passing on, rather than sinking, a packet to // which an upstream cache has committed to responding, // the line was needs writable, and the responding only @@ -253,6 +259,13 @@ CoherentXBar::recvTimingReq(PacketPtr pkt, PortID slave_port_id) pkt->setExpressSnoop(); } + // make sure that the write request (e.g., WriteClean) + // will stop at the memory below if this crossbar is its + // destination + if (pkt->isWrite() && is_destination) { + pkt->clearWriteThrough(); + } + // since it is a normal request, attempt to send the packet success = masterPorts[master_port_id]->sendTimingReq(pkt); } else { @@ -646,6 +659,12 @@ CoherentXBar::recvAtomic(PacketPtr pkt, PortID slave_port_id) MemCmd snoop_response_cmd = MemCmd::InvalidCmd; Tick snoop_response_latency = 0; + // is this the destination point for this packet? (e.g. true if + // this xbar is the PoC for a cache maintenance operation to the + // PoC) otherwise the destination is any cache that can satisfy + // the request + const bool is_destination = isDestination(pkt); + const bool snoop_caches = !system->bypassCaches() && pkt->cmd != MemCmd::WriteClean; if (snoop_caches) { @@ -698,7 +717,14 @@ CoherentXBar::recvAtomic(PacketPtr pkt, PortID slave_port_id) DPRINTF(CoherentXBar, "%s: Not forwarding %s\n", __func__, pkt->print()); } else { - if (!pointOfCoherency || pkt->isRead() || pkt->isWrite()) { + if (forwardPacket(pkt)) { + // make sure that the write request (e.g., WriteClean) + // will stop at the memory below if this crossbar is its + // destination + if (pkt->isWrite() && is_destination) { + pkt->clearWriteThrough(); + } + // forward the request to the appropriate destination response_latency = masterPorts[master_port_id]->sendAtomic(pkt); } else { @@ -958,6 +984,16 @@ CoherentXBar::sinkPacket(const PacketPtr pkt) const (!pkt->needsWritable() || pkt->responderHadWritable())); } +bool +CoherentXBar::forwardPacket(const PacketPtr pkt) +{ + // we are forwarding the packet if: + // 1) this is a read or a write + // 2) this crossbar is above the point of coherency + return pkt->isRead() || pkt->isWrite() || !pointOfCoherency; +} + + void CoherentXBar::regStats() { diff --git a/src/mem/coherent_xbar.hh b/src/mem/coherent_xbar.hh index 214a29071..0c2907fa0 100644 --- a/src/mem/coherent_xbar.hh +++ b/src/mem/coherent_xbar.hh @@ -398,6 +398,29 @@ class CoherentXBar : public BaseXBar */ bool sinkPacket(const PacketPtr pkt) const; + /** + * Determine if the crossbar should forward the packet, as opposed to + * responding to it. + */ + bool forwardPacket(const PacketPtr pkt); + + /** + * Determine if the packet's destination is the memory below + * + * The memory below is the destination for a cache mainteance + * operation to the Point of Coherence/Unification if this is the + * Point of Coherence/Unification. + * + * @param pkt The processed packet + * + * @return Whether the memory below is the destination for the packet + */ + bool isDestination(const PacketPtr pkt) const + { + return (pkt->req->isToPOC() && pointOfCoherency) || + (pkt->req->isToPOU() && pointOfUnification); + } + Stats::Scalar snoops; Stats::Scalar snoopTraffic; Stats::Distribution snoopFanout; diff --git a/src/mem/packet.cc b/src/mem/packet.cc index 75dfb28cb..8c44172c3 100644 --- a/src/mem/packet.cc +++ b/src/mem/packet.cc @@ -349,12 +349,14 @@ Packet::popSenderState() void Packet::print(ostream &o, const int verbosity, const string &prefix) const { - ccprintf(o, "%s%s [%x:%x]%s%s%s%s", prefix, cmdString(), + 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" : ""); + isExpressSnoop() ? " ES" : "", + req->isToPOC() ? " PoC" : "", + req->isToPOU() ? " PoU" : ""); } std::string diff --git a/src/mem/packet.hh b/src/mem/packet.hh index 330e2ae5e..325cd3a60 100644 --- a/src/mem/packet.hh +++ b/src/mem/packet.hh @@ -253,7 +253,7 @@ class Packet : public Printable enum : FlagsType { // Flags to transfer across when copying a packet - COPY_FLAGS = 0x0000000F, + COPY_FLAGS = 0x0000001F, // Does this packet have sharers (which means it should not be // considered writable) or not. See setHasSharers below. @@ -272,6 +272,10 @@ class Packet : public Printable // responding to a snoop. See setCacheResponding below. CACHE_RESPONDING = 0x00000008, + // The writeback/writeclean should be propagated further + // downstream by the receiver + WRITE_THROUGH = 0x00000010, + /// Are the 'addr' and 'size' fields valid? VALID_ADDR = 0x00000100, VALID_SIZE = 0x00000200, @@ -619,6 +623,19 @@ class Packet : public Printable bool responderHadWritable() const { return flags.isSet(RESPONDER_HAD_WRITABLE); } + /** + * 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); } + void setSuppressFuncError() { flags.set(SUPPRESS_FUNC_ERROR); } bool suppressFuncError() const { return flags.isSet(SUPPRESS_FUNC_ERROR); } void setBlockCached() { flags.set(BLOCK_CACHED); } diff --git a/src/mem/request.hh b/src/mem/request.hh index aff13075b..6fc98506c 100644 --- a/src/mem/request.hh +++ b/src/mem/request.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 ARM Limited + * Copyright (c) 2012-2013,2017 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -87,7 +87,7 @@ typedef uint16_t MasterID; class Request { public: - typedef uint32_t FlagsType; + typedef uint64_t FlagsType; typedef uint8_t ArchFlagsType; typedef ::Flags<FlagsType> Flags; @@ -182,6 +182,15 @@ class Request /** The request is a page table walk */ PT_WALK = 0x20000000, + /** The request targets the point of unification */ + DST_POU = 0x0000001000000000, + + /** The request targets the point of coherence */ + DST_POC = 0x0000002000000000, + + /** Bits to define the destination of a request */ + DST_BITS = 0x0000003000000000, + /** * These flags are *not* cleared when a Request object is * reused (assigned a new address). @@ -790,6 +799,17 @@ class Request } /** + * Accessor functions for the destination of a memory request. The + * destination flag can specify a point of reference for the + * operation (e.g. a cache block clean to the the point of + * unification). At the moment the destination is only used by the + * cache maintenance operations. + */ + bool isToPOU() const { return _flags.isSet(DST_POU); } + bool isToPOC() const { return _flags.isSet(DST_POC); } + Flags getDest() const { return _flags & DST_BITS; } + + /** * Accessor functions for the memory space configuration flags and used by * GPU ISAs such as the Heterogeneous System Architecture (HSA). Note that * these are for testing only; setting extraFlags should be done via |