Nikos Nikoleris has uploaded this change for review. (
https://gem5-review.googlesource.com/8290
Change subject: mem-cache: Adopt a more sensible cache class hierarchy
......................................................................
mem-cache: Adopt a more sensible cache class hierarchy
This patch changes what goes into the BaseCache and what goes into the
Cache, to make it easier to add a NoncoherentCache with as much re-use
as possible. A number of redundant members and definitions are also
removed in the process.
This is a modified version of a changeset originally put together by
Andreas Hansson <andreas.hans...@arm.com>
Change-Id: I56cef203728e500f74e9e7599fe307f366dfb753
---
M src/mem/cache/base.cc
M src/mem/cache/base.hh
M src/mem/cache/cache.cc
M src/mem/cache/cache.hh
M src/mem/cache/mshr.cc
M src/mem/cache/mshr.hh
M src/mem/cache/queue_entry.hh
M src/mem/cache/write_queue_entry.cc
M src/mem/cache/write_queue_entry.hh
9 files changed, 449 insertions(+), 447 deletions(-)
diff --git a/src/mem/cache/base.cc b/src/mem/cache/base.cc
index 6f25323..d2a3931 100644
--- a/src/mem/cache/base.cc
+++ b/src/mem/cache/base.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2013 ARM Limited
+ * Copyright (c) 2012-2013, 2018 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
@@ -48,13 +48,10 @@
#include "mem/cache/base.hh"
#include "debug/Cache.hh"
+#include "debug/CachePort.hh"
#include "debug/Drain.hh"
-#include "mem/cache/cache.hh"
#include "mem/cache/mshr.hh"
-#include "mem/cache/tags/fa_lru.hh"
-#include "mem/cache/tags/lru.hh"
-#include "mem/cache/tags/random_repl.hh"
-#include "sim/full_system.hh"
+#include "mem/cache/prefetch/base.hh"
using namespace std;
@@ -72,6 +69,9 @@
cpuSidePort(nullptr), memSidePort(nullptr),
mshrQueue("MSHRs", p->mshrs, 0, p->demand_mshr_reserve), // see below
writeBuffer("write buffer", p->write_buffers, p->mshrs), // see below
+ tags(p->tags),
+ prefetcher(p->prefetcher),
+ prefetchOnAccess(p->prefetch_on_access),
blkSize(blk_size),
lookupLatency(p->tag_latency),
dataLatency(p->data_latency),
@@ -96,6 +96,19 @@
// forward snoops is overridden in init() once we can query
// whether the connected master is actually snooping or not
+
+ tempBlock = new CacheBlk();
+ tempBlock->data = new uint8_t[blkSize];
+
+ tags->setCache(this);
+ if (prefetcher)
+ prefetcher->setCache(this);
+}
+
+BaseCache::~BaseCache()
+{
+ delete [] tempBlock->data;
+ delete tempBlock;
}
void
@@ -176,6 +189,247 @@
}
void
+BaseCache::cmpAndSwap(CacheBlk *blk, PacketPtr pkt)
+{
+ assert(pkt->isRequest());
+
+ uint64_t overwrite_val;
+ bool overwrite_mem;
+ uint64_t condition_val64;
+ uint32_t condition_val32;
+
+ int offset = pkt->getOffset(blkSize);
+ uint8_t *blk_data = blk->data + offset;
+
+ assert(sizeof(uint64_t) >= pkt->getSize());
+
+ overwrite_mem = true;
+ // keep a copy of our possible write value, and copy what is at the
+ // memory address into the packet
+ pkt->writeData((uint8_t *)&overwrite_val);
+ pkt->setData(blk_data);
+
+ if (pkt->req->isCondSwap()) {
+ if (pkt->getSize() == sizeof(uint64_t)) {
+ condition_val64 = pkt->req->getExtraData();
+ overwrite_mem = !std::memcmp(&condition_val64, blk_data,
+ sizeof(uint64_t));
+ } else if (pkt->getSize() == sizeof(uint32_t)) {
+ condition_val32 = (uint32_t)pkt->req->getExtraData();
+ overwrite_mem = !std::memcmp(&condition_val32, blk_data,
+ sizeof(uint32_t));
+ } else
+ panic("Invalid size for conditional read/write\n");
+ }
+
+ if (overwrite_mem) {
+ std::memcpy(blk_data, &overwrite_val, pkt->getSize());
+ blk->status |= BlkDirty;
+ }
+}
+
+QueueEntry*
+BaseCache::getNextQueueEntry()
+{
+ // Check both MSHR queue and write buffer for potential requests,
+ // note that null does not mean there is no request, it could
+ // simply be that it is not ready
+ MSHR *miss_mshr = mshrQueue.getNext();
+ WriteQueueEntry *wq_entry = writeBuffer.getNext();
+
+ // If we got a write buffer request ready, first priority is a
+ // full write buffer, otherwise we favour the miss requests
+ if (wq_entry && (writeBuffer.isFull() || !miss_mshr)) {
+ // need to search MSHR queue for conflicting earlier miss.
+ MSHR *conflict_mshr =
+ mshrQueue.findPending(wq_entry->blkAddr,
+ wq_entry->isSecure);
+
+ if (conflict_mshr && conflict_mshr->order < wq_entry->order) {
+ // Service misses in order until conflict is cleared.
+ return conflict_mshr;
+
+ // @todo Note that we ignore the ready time of the conflict
here
+ }
+
+ // No conflicts; issue write
+ return wq_entry;
+ } else if (miss_mshr) {
+ // need to check for conflicting earlier writeback
+ WriteQueueEntry *conflict_mshr =
+ writeBuffer.findPending(miss_mshr->blkAddr,
+ miss_mshr->isSecure);
+ if (conflict_mshr) {
+ // not sure why we don't check order here... it was in the
+ // original code but commented out.
+
+ // The only way this happens is if we are
+ // doing a write and we didn't have permissions
+ // then subsequently saw a writeback (owned got evicted)
+ // We need to make sure to perform the writeback first
+ // To preserve the dirty data, then we can issue the write
+
+ // should we return wq_entry here instead? I.e. do we
+ // have to flush writes in order? I don't think so... not
+ // for Alpha anyway. Maybe for x86?
+ return conflict_mshr;
+
+ // @todo Note that we ignore the ready time of the conflict
here
+ }
+
+ // No conflicts; issue read
+ return miss_mshr;
+ }
+
+ // fall through... no pending requests. Try a prefetch.
+ assert(!miss_mshr && !wq_entry);
+ if (prefetcher && mshrQueue.canPrefetch()) {
+ // If we have a miss queue slot, we can try a prefetch
+ PacketPtr pkt = prefetcher->getPacket();
+ if (pkt) {
+ Addr pf_addr = pkt->getBlockAddr(blkSize);
+ if (!tags->findBlock(pf_addr, pkt->isSecure()) &&
+ !mshrQueue.findMatch(pf_addr, pkt->isSecure()) &&
+ !writeBuffer.findMatch(pf_addr, pkt->isSecure())) {
+ // Update statistic on number of prefetches issued
+ // (hwpf_mshr_misses)
+ assert(pkt->req->masterId() < system->maxMasters());
+ mshr_misses[pkt->cmdToIndex()][pkt->req->masterId()]++;
+
+ // allocate an MSHR and return it, note
+ // that we send the packet straight away, so do not
+ // schedule the send
+ return allocateMissBuffer(pkt, curTick(), false);
+ } else {
+ // free the request and packet
+ delete pkt->req;
+ delete pkt;
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+void
+BaseCache::invalidateBlock(CacheBlk *blk)
+{
+ if (blk != tempBlock)
+ tags->invalidate(blk);
+ blk->invalidate();
+}
+
+void
+BaseCache::memWriteback()
+{
+ CacheBlkVisitorWrapper visitor(*this, &BaseCache::writebackVisitor);
+ tags->forEachBlk(visitor);
+}
+
+void
+BaseCache::memInvalidate()
+{
+ CacheBlkVisitorWrapper visitor(*this, &BaseCache::invalidateVisitor);
+ tags->forEachBlk(visitor);
+}
+
+bool
+BaseCache::isDirty() const
+{
+ CacheBlkIsDirtyVisitor visitor;
+ tags->forEachBlk(visitor);
+
+ return visitor.isDirty();
+}
+
+bool
+BaseCache::writebackVisitor(CacheBlk &blk)
+{
+ if (blk.isDirty()) {
+ assert(blk.isValid());
+
+ Request request(tags->regenerateBlkAddr(blk.tag, blk.set),
+ blkSize, 0, Request::funcMasterId);
+ request.taskId(blk.task_id);
+ if (blk.isSecure()) {
+ request.setFlags(Request::SECURE);
+ }
+
+ Packet packet(&request, MemCmd::WriteReq);
+ packet.dataStatic(blk.data);
+
+ memSidePort->sendFunctional(&packet);
+
+ blk.status &= ~BlkDirty;
+ }
+
+ return true;
+}
+
+bool
+BaseCache::invalidateVisitor(CacheBlk &blk)
+{
+ if (blk.isDirty())
+ warn_once("Invalidating dirty cache lines. " \
+ "Expect things to break.\n");
+
+ if (blk.isValid()) {
+ assert(!blk.isDirty());
+ invalidateBlock(&blk);
+ }
+
+ return true;
+}
+
+Tick
+BaseCache::nextQueueReadyTime() const
+{
+ Tick nextReady = std::min(mshrQueue.nextReadyTime(),
+ writeBuffer.nextReadyTime());
+
+ // Don't signal prefetch ready time if no MSHRs available
+ // Will signal once enoguh MSHRs are deallocated
+ if (prefetcher && mshrQueue.canPrefetch()) {
+ nextReady = std::min(nextReady,
+ prefetcher->nextPrefetchReadyTime());
+ }
+
+ return nextReady;
+}
+
+void
+BaseCache::serialize(CheckpointOut &cp) const
+{
+ bool dirty(isDirty());
+
+ if (dirty) {
+ warn("*** The cache still contains dirty data. ***\n");
+ warn(" Make sure to drain the system using the correct
flags.\n");
+ warn(" This checkpoint will not restore correctly " \
+ "and dirty data in the cache will be lost!\n");
+ }
+
+ // Since we don't checkpoint the data in the cache, any dirty data
+ // will be lost when restoring from a checkpoint of a system that
+ // wasn't drained properly. Flag the checkpoint as invalid if the
+ // cache contains dirty data.
+ bool bad_checkpoint(dirty);
+ SERIALIZE_SCALAR(bad_checkpoint);
+}
+
+void
+BaseCache::unserialize(CheckpointIn &cp)
+{
+ bool bad_checkpoint;
+ UNSERIALIZE_SCALAR(bad_checkpoint);
+ if (bad_checkpoint) {
+ fatal("Restoring from checkpoints with dirty caches is not "
+ "supported in the classic memory system. Please remove any "
+ "caches or drain them properly before taking
checkpoints.\n");
+ }
+}
+
+void
BaseCache::regStats()
{
MemObject::regStats();
diff --git a/src/mem/cache/base.hh b/src/mem/cache/base.hh
index b006d4b..eb6b5f9 100644
--- a/src/mem/cache/base.hh
+++ b/src/mem/cache/base.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2013, 2015-2016 ARM Limited
+ * Copyright (c) 2012-2013, 2015-2016, 2018 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
@@ -40,6 +40,7 @@
* Authors: Erik Hallnor
* Steve Reinhardt
* Ron Dreslinski
+ * Andreas Hansson
*/
/**
@@ -61,7 +62,9 @@
#include "base/types.hh"
#include "debug/Cache.hh"
#include "debug/CachePort.hh"
+#include "mem/cache/blk.hh"
#include "mem/cache/mshr_queue.hh"
+#include "mem/cache/tags/base.hh"
#include "mem/cache/write_queue.hh"
#include "mem/mem_object.hh"
#include "mem/packet.hh"
@@ -192,6 +195,20 @@
/** Write/writeback buffer */
WriteQueue writeBuffer;
+ /** Tag and data Storage */
+ BaseTags *tags;
+
+ /** Prefetcher */
+ BasePrefetcher *prefetcher;
+
+ /**
+ * Notify the prefetcher on every access, not just misses.
+ */
+ const bool prefetchOnAccess;
+
+ /** Temporary cache block for occasional transitory use */
+ CacheBlk *tempBlock;
+
/**
* Mark a request as in service (sent downstream in the memory
* system), effectively making this MSHR the ordering point.
@@ -226,9 +243,30 @@
virtual bool allocOnFill(MemCmd cmd) const = 0;
/**
+ * Handle doing the Compare and Swap function for SPARC.
+ */
+ void cmpAndSwap(CacheBlk *blk, PacketPtr pkt);
+
+ /**
+ * Return the next queue entry to service, either a pending miss
+ * from the MSHR queue, a buffered write from the write buffer, or
+ * something from the prefetcher. This function is responsible
+ * for prioritizing among those sources on the fly.
+ */
+ QueueEntry* getNextQueueEntry();
+
+ /**
+ * Invalidate a cache block.
+ *
+ * @param blk Block to invalidate
+ */
+ void invalidateBlock(CacheBlk *blk);
+
+ /**
* Write back dirty blocks in the cache using functional accesses.
*/
- virtual void memWriteback() override = 0;
+ virtual void memWriteback() override;
+
/**
* Invalidates all blocks in the cache.
*
@@ -236,13 +274,14 @@
* memory. Make sure to call functionalWriteback() first if you
* want the to write them to memory.
*/
- virtual void memInvalidate() override = 0;
+ virtual void memInvalidate() override;
+
/**
* Determine if there are any dirty blocks in the cache.
*
- * \return true if at least one block is dirty, false otherwise.
+ * @return true if at least one block is dirty, false otherwise.
*/
- virtual bool isDirty() const = 0;
+ bool isDirty() const;
/**
* Determine if an address is in the ranges covered by this
@@ -254,6 +293,11 @@
*/
bool inRange(Addr addr) const;
+ /**
+ * Find next request ready time from among possible sources.
+ */
+ Tick nextQueueReadyTime() const;
+
/** Block size of this cache */
const unsigned blkSize;
@@ -460,18 +504,18 @@
/**
* Register stats for this object.
*/
- virtual void regStats() override;
+ void regStats() override;
public:
BaseCache(const BaseCacheParams *p, unsigned blk_size);
- ~BaseCache() {}
+ ~BaseCache();
- virtual void init() override;
+ void init() override;
- virtual BaseMasterPort &getMasterPort(const std::string &if_name,
- PortID idx = InvalidPortID)
override;
- virtual BaseSlavePort &getSlavePort(const std::string &if_name,
- PortID idx = InvalidPortID)
override;
+ BaseMasterPort &getMasterPort(const std::string &if_name,
+ PortID idx = InvalidPortID) override;
+ BaseSlavePort &getSlavePort(const std::string &if_name,
+ PortID idx = InvalidPortID) override;
/**
* Query block size of a cache.
@@ -582,9 +626,13 @@
memSidePort->schedSendEvent(time);
}
- virtual bool inCache(Addr addr, bool is_secure) const = 0;
+ bool inCache(Addr addr, bool is_secure) const {
+ return tags->findBlock(addr, is_secure);
+ }
- virtual bool inMissQueue(Addr addr, bool is_secure) const = 0;
+ bool inMissQueue(Addr addr, bool is_secure) const {
+ return mshrQueue.findMatch(addr, is_secure);
+ }
void incMissCount(PacketPtr pkt)
{
@@ -604,6 +652,109 @@
}
+ /**
+ * Cache block visitor that writes back dirty cache blocks using
+ * functional writes.
+ *
+ * @return Always returns true.
+ */
+ bool writebackVisitor(CacheBlk &blk);
+
+ /**
+ * Cache block visitor that invalidates all blocks in the cache.
+ *
+ * @warn Dirty cache lines will not be written back to memory.
+ *
+ * @return Always returns true.
+ */
+ bool invalidateVisitor(CacheBlk &blk);
+
+ /**
+ * Take an MSHR, turn it into a suitable downstream packet, and
+ * send it out. This construct allows a queue entry to choose a
suitable
+ * approach based on its type.
+ *
+ * @param mshr The MSHR to turn into a packet and send
+ * @return True if the port is waiting for a retry
+ */
+ virtual bool sendMSHRQueuePacket(MSHR* mshr) = 0;
+
+ /**
+ * Similar to sendMSHR, but for a write-queue entry
+ * instead. Create the packet, and send it, and if successful also
+ * mark the entry in service.
+ *
+ * @param wq_entry The write-queue entry to turn into a packet and send
+ * @return True if the port is waiting for a retry
+ */
+ virtual bool sendWriteQueuePacket(WriteQueueEntry* wq_entry) = 0;
+
+ /**
+ * Serialize the state of the caches
+ *
+ * We currently don't support checkpointing cache state, so this
panics.
+ */
+ void serialize(CheckpointOut &cp) const override;
+ void unserialize(CheckpointIn &cp) override;
+
+};
+
+/**
+ * Wrap a method and present it as a cache block visitor.
+ *
+ * For example the forEachBlk method in the tag arrays expects a
+ * callable object/function as their parameter. This class wraps a
+ * method in an object and presents callable object that adheres to
+ * the cache block visitor protocol.
+ */
+class CacheBlkVisitorWrapper : public CacheBlkVisitor
+{
+ public:
+ typedef bool (BaseCache::*VisitorPtr)(CacheBlk &blk);
+
+ CacheBlkVisitorWrapper(BaseCache &_cache, VisitorPtr _visitor)
+ : cache(_cache), visitor(_visitor) {}
+
+ bool operator()(CacheBlk &blk) override {
+ return (cache.*visitor)(blk);
+ }
+
+ private:
+ BaseCache &cache;
+ VisitorPtr visitor;
+};
+
+/**
+ * Cache block visitor that determines if there are dirty blocks in a
+ * cache.
+ *
+ * Use with the forEachBlk method in the tag array to determine if the
+ * array contains dirty blocks.
+ */
+class CacheBlkIsDirtyVisitor : public CacheBlkVisitor
+{
+ public:
+ CacheBlkIsDirtyVisitor()
+ : _isDirty(false) {}
+
+ bool operator()(CacheBlk &blk) override {
+ if (blk.isDirty()) {
+ _isDirty = true;
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Does the array contain a dirty line?
+ *
+ * @return true if yes, false otherwise.
+ */
+ bool isDirty() const { return _isDirty; };
+
+ private:
+ bool _isDirty;
};
#endif //__MEM_CACHE_BASE_HH__
diff --git a/src/mem/cache/cache.cc b/src/mem/cache/cache.cc
index 2ab6b41..5d78c5a 100644
--- a/src/mem/cache/cache.cc
+++ b/src/mem/cache/cache.cc
@@ -67,10 +67,7 @@
Cache::Cache(const CacheParams *p)
: BaseCache(p, p->system->cacheLineSize()),
- tags(p->tags),
- prefetcher(p->prefetcher),
doFastWrites(true),
- prefetchOnAccess(p->prefetch_on_access),
clusivity(p->clusivity),
writebackClean(p->writeback_clean),
tempBlockWriteback(nullptr),
@@ -78,24 +75,14 @@
name(), false,
EventBase::Delayed_Writeback_Pri)
{
- tempBlock = new CacheBlk();
- tempBlock->data = new uint8_t[blkSize];
-
cpuSidePort = new CpuSidePort(p->name + ".cpu_side", this,
"CpuSidePort");
memSidePort = new MemSidePort(p->name + ".mem_side", this,
"MemSidePort");
-
- tags->setCache(this);
- if (prefetcher)
- prefetcher->setCache(this);
}
Cache::~Cache()
{
- delete [] tempBlock->data;
- delete tempBlock;
-
delete cpuSidePort;
delete memSidePort;
}
@@ -107,47 +94,6 @@
}
void
-Cache::cmpAndSwap(CacheBlk *blk, PacketPtr pkt)
-{
- assert(pkt->isRequest());
-
- uint64_t overwrite_val;
- bool overwrite_mem;
- uint64_t condition_val64;
- uint32_t condition_val32;
-
- int offset = tags->extractBlkOffset(pkt->getAddr());
- uint8_t *blk_data = blk->data + offset;
-
- assert(sizeof(uint64_t) >= pkt->getSize());
-
- overwrite_mem = true;
- // keep a copy of our possible write value, and copy what is at the
- // memory address into the packet
- pkt->writeData((uint8_t *)&overwrite_val);
- pkt->setData(blk_data);
-
- if (pkt->req->isCondSwap()) {
- if (pkt->getSize() == sizeof(uint64_t)) {
- condition_val64 = pkt->req->getExtraData();
- overwrite_mem = !std::memcmp(&condition_val64, blk_data,
- sizeof(uint64_t));
- } else if (pkt->getSize() == sizeof(uint32_t)) {
- condition_val32 = (uint32_t)pkt->req->getExtraData();
- overwrite_mem = !std::memcmp(&condition_val32, blk_data,
- sizeof(uint32_t));
- } else
- panic("Invalid size for conditional read/write\n");
- }
-
- if (overwrite_mem) {
- std::memcpy(blk_data, &overwrite_val, pkt->getSize());
- blk->status |= BlkDirty;
- }
-}
-
-
-void
Cache::satisfyRequest(PacketPtr pkt, CacheBlk *blk,
bool deferred_response, bool pending_downgrade)
{
@@ -889,6 +835,14 @@
assert(pkt->req->masterId() < system->maxMasters());
mshr_hits[pkt->cmdToIndex()][pkt->req->masterId()]++;
+
+ // uncacheable accesses always allocate a new
+ // MSHR, and cacheable accesses ignore any
+ // uncacheable MSHRs, thus we should never have
+ // targets addded if originally allocated
+ // uncacheable
+ assert(!mshr->isUncacheable());
+
// We use forward_time here because it is the same
// considering new targets. We have multiple
// requests for the same address here. It
@@ -1749,68 +1703,6 @@
return pkt;
}
-void
-Cache::memWriteback()
-{
- CacheBlkVisitorWrapper visitor(*this, &Cache::writebackVisitor);
- tags->forEachBlk(visitor);
-}
-
-void
-Cache::memInvalidate()
-{
- CacheBlkVisitorWrapper visitor(*this, &Cache::invalidateVisitor);
- tags->forEachBlk(visitor);
-}
-
-bool
-Cache::isDirty() const
-{
- CacheBlkIsDirtyVisitor visitor;
- tags->forEachBlk(visitor);
-
- return visitor.isDirty();
-}
-
-bool
-Cache::writebackVisitor(CacheBlk &blk)
-{
- if (blk.isDirty()) {
- assert(blk.isValid());
-
- Request request(tags->regenerateBlkAddr(blk.tag, blk.set),
- blkSize, 0, Request::funcMasterId);
- request.taskId(blk.task_id);
- if (blk.isSecure()) {
- request.setFlags(Request::SECURE);
- }
-
- Packet packet(&request, MemCmd::WriteReq);
- packet.dataStatic(blk.data);
-
- memSidePort->sendFunctional(&packet);
-
- blk.status &= ~BlkDirty;
- }
-
- return true;
-}
-
-bool
-Cache::invalidateVisitor(CacheBlk &blk)
-{
-
- if (blk.isDirty())
- warn_once("Invalidating dirty cache lines. Expect things to
break.\n");
-
- if (blk.isValid()) {
- assert(!blk.isDirty());
- invalidateBlock(&blk);
- }
-
- return true;
-}
-
CacheBlk*
Cache::allocateBlock(Addr addr, bool is_secure, PacketList &writebacks)
{
@@ -1854,14 +1746,6 @@
return blk;
}
-void
-Cache::invalidateBlock(CacheBlk *blk)
-{
- if (blk != tempBlock)
- tags->invalidate(blk);
- blk->invalidate();
-}
-
// Note that the reason we return a list of writebacks rather than
// inserting them directly in the write buffer is that this function
// is called by both atomic and timing-mode accesses, and in atomic
@@ -2404,90 +2288,6 @@
return snoop_delay + lookupLatency * clockPeriod();
}
-
-QueueEntry*
-Cache::getNextQueueEntry()
-{
- // Check both MSHR queue and write buffer for potential requests,
- // note that null does not mean there is no request, it could
- // simply be that it is not ready
- MSHR *miss_mshr = mshrQueue.getNext();
- WriteQueueEntry *wq_entry = writeBuffer.getNext();
-
- // If we got a write buffer request ready, first priority is a
- // full write buffer, otherwise we favour the miss requests
- if (wq_entry && (writeBuffer.isFull() || !miss_mshr)) {
- // need to search MSHR queue for conflicting earlier miss.
- MSHR *conflict_mshr =
- mshrQueue.findPending(wq_entry->blkAddr,
- wq_entry->isSecure);
-
- if (conflict_mshr && conflict_mshr->order < wq_entry->order) {
- // Service misses in order until conflict is cleared.
- return conflict_mshr;
-
- // @todo Note that we ignore the ready time of the conflict
here
- }
-
- // No conflicts; issue write
- return wq_entry;
- } else if (miss_mshr) {
- // need to check for conflicting earlier writeback
- WriteQueueEntry *conflict_mshr =
- writeBuffer.findPending(miss_mshr->blkAddr,
- miss_mshr->isSecure);
- if (conflict_mshr) {
- // not sure why we don't check order here... it was in the
- // original code but commented out.
-
- // The only way this happens is if we are
- // doing a write and we didn't have permissions
- // then subsequently saw a writeback (owned got evicted)
- // We need to make sure to perform the writeback first
- // To preserve the dirty data, then we can issue the write
-
- // should we return wq_entry here instead? I.e. do we
- // have to flush writes in order? I don't think so... not
- // for Alpha anyway. Maybe for x86?
- return conflict_mshr;
-
- // @todo Note that we ignore the ready time of the conflict
here
- }
-
- // No conflicts; issue read
- return miss_mshr;
- }
-
- // fall through... no pending requests. Try a prefetch.
- assert(!miss_mshr && !wq_entry);
- if (prefetcher && mshrQueue.canPrefetch()) {
- // If we have a miss queue slot, we can try a prefetch
- PacketPtr pkt = prefetcher->getPacket();
- if (pkt) {
- Addr pf_addr = pkt->getBlockAddr(blkSize);
- if (!tags->findBlock(pf_addr, pkt->isSecure()) &&
- !mshrQueue.findMatch(pf_addr, pkt->isSecure()) &&
- !writeBuffer.findMatch(pf_addr, pkt->isSecure())) {
- // Update statistic on number of prefetches issued
- // (hwpf_mshr_misses)
- assert(pkt->req->masterId() < system->maxMasters());
- mshr_misses[pkt->cmdToIndex()][pkt->req->masterId()]++;
-
- // allocate an MSHR and return it, note
- // that we send the packet straight away, so do not
- // schedule the send
- return allocateMissBuffer(pkt, curTick(), false);
- } else {
- // free the request and packet
- delete pkt->req;
- delete pkt;
- }
- }
- }
-
- return nullptr;
-}
-
bool
Cache::isCachedAbove(PacketPtr pkt, bool is_timing) const
{
@@ -2516,22 +2316,6 @@
}
}
-Tick
-Cache::nextQueueReadyTime() const
-{
- Tick nextReady = std::min(mshrQueue.nextReadyTime(),
- writeBuffer.nextReadyTime());
-
- // Don't signal prefetch ready time if no MSHRs available
- // Will signal once enoguh MSHRs are deallocated
- if (prefetcher && mshrQueue.canPrefetch()) {
- nextReady = std::min(nextReady,
- prefetcher->nextPrefetchReadyTime());
- }
-
- return nextReady;
-}
-
bool
Cache::sendMSHRQueuePacket(MSHR* mshr)
{
@@ -2700,38 +2484,6 @@
}
}
-void
-Cache::serialize(CheckpointOut &cp) const
-{
- bool dirty(isDirty());
-
- if (dirty) {
- warn("*** The cache still contains dirty data. ***\n");
- warn(" Make sure to drain the system using the correct
flags.\n");
- warn(" This checkpoint will not restore correctly and dirty
data "
- " in the cache will be lost!\n");
- }
-
- // Since we don't checkpoint the data in the cache, any dirty data
- // will be lost when restoring from a checkpoint of a system that
- // wasn't drained properly. Flag the checkpoint as invalid if the
- // cache contains dirty data.
- bool bad_checkpoint(dirty);
- SERIALIZE_SCALAR(bad_checkpoint);
-}
-
-void
-Cache::unserialize(CheckpointIn &cp)
-{
- bool bad_checkpoint;
- UNSERIALIZE_SCALAR(bad_checkpoint);
- if (bad_checkpoint) {
- fatal("Restoring from checkpoints with dirty caches is not
supported "
- "in the classic memory system. Please remove any caches or "
- " drain them properly before taking checkpoints.\n");
- }
-}
-
///////////////
//
// CpuSidePort
diff --git a/src/mem/cache/cache.hh b/src/mem/cache/cache.hh
index 7d28279..54154df 100644
--- a/src/mem/cache/cache.hh
+++ b/src/mem/cache/cache.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2017 ARM Limited
+ * Copyright (c) 2012-2018 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
@@ -46,7 +46,7 @@
/**
* @file
- * Describes a cache based on template policies.
+ * Describes a cache
*/
#ifndef __MEM_CACHE_CACHE_HH__
@@ -57,19 +57,10 @@
#include "base/logging.hh" // fatal, panic, and warn
#include "enums/Clusivity.hh"
#include "mem/cache/base.hh"
-#include "mem/cache/blk.hh"
-#include "mem/cache/mshr.hh"
-#include "mem/cache/tags/base.hh"
#include "params/Cache.hh"
-#include "sim/eventq.hh"
-
-//Forward decleration
-class BasePrefetcher;
/**
- * A template-policy based cache. The behavior of the cache can be altered
by
- * supplying different template policies. TagStore handles all tag and data
- * storage @sa TagStore, \ref gem5MemorySystem "gem5 Memory System"
+ * A coherent cache that can be arranged in flexible topologies.
*/
class Cache : public BaseCache
{
@@ -187,15 +178,6 @@
const std::string &_label);
};
- /** Tag and data Storage */
- BaseTags *tags;
-
- /** Prefetcher */
- BasePrefetcher *prefetcher;
-
- /** Temporary cache block for occasional transitory use */
- CacheBlk *tempBlock;
-
/**
* This cache should allocate a block on a line-sized write miss.
*/
@@ -206,11 +188,6 @@
*/
void promoteWholeLineWrites(PacketPtr pkt);
- /**
- * Notify the prefetcher on every access, not just misses.
- */
- const bool prefetchOnAccess;
-
/**
* Clusivity with respect to the upstream cache, determining if we
* fill into both this cache and the cache above on a miss. Note
@@ -280,11 +257,6 @@
Cycles &lat, PacketList &writebacks);
/**
- *Handle doing the Compare and Swap function for SPARC.
- */
- void cmpAndSwap(CacheBlk *blk, PacketPtr pkt);
-
- /**
* Find a block frame for new block at address addr targeting the
* given security space, assuming that the block is not currently
* in the cache. Append writebacks if any to provided packet
@@ -294,13 +266,6 @@
CacheBlk *allocateBlock(Addr addr, bool is_secure, PacketList
&writebacks);
/**
- * Invalidate a cache block.
- *
- * @param blk Block to invalidate
- */
- void invalidateBlock(CacheBlk *blk);
-
- /**
* Maintain the clusivity of this cache by potentially
* invalidating a block. This method works in conjunction with
* satisfyRequest, but is separate to allow us to handle all MSHR
@@ -466,27 +431,6 @@
*/
PacketPtr cleanEvictBlk(CacheBlk *blk);
-
- void memWriteback() override;
- void memInvalidate() override;
- bool isDirty() const override;
-
- /**
- * Cache block visitor that writes back dirty cache blocks using
- * functional writes.
- *
- * \return Always returns true.
- */
- bool writebackVisitor(CacheBlk &blk);
- /**
- * Cache block visitor that invalidates all blocks in the cache.
- *
- * @warn Dirty cache lines will not be written back to memory.
- *
- * \return Always returns true.
- */
- bool invalidateVisitor(CacheBlk &blk);
-
/**
* Create an appropriate downstream bus request packet for the
* given parameters.
@@ -502,44 +446,11 @@
bool needsWritable) const;
/**
- * Return the next queue entry to service, either a pending miss
- * from the MSHR queue, a buffered write from the write buffer, or
- * something from the prefetcher. This function is responsible
- * for prioritizing among those sources on the fly.
- */
- QueueEntry* getNextQueueEntry();
-
- /**
* Send up a snoop request and find cached copies. If cached copies are
* found, set the BLOCK_CACHED flag in pkt.
*/
bool isCachedAbove(PacketPtr pkt, bool is_timing = true) const;
- /**
- * Return whether there are any outstanding misses.
- */
- bool outstandingMisses() const
- {
- return !mshrQueue.isEmpty();
- }
-
- CacheBlk *findBlock(Addr addr, bool is_secure) const {
- return tags->findBlock(addr, is_secure);
- }
-
- bool inCache(Addr addr, bool is_secure) const override {
- return (tags->findBlock(addr, is_secure) != 0);
- }
-
- bool inMissQueue(Addr addr, bool is_secure) const override {
- return (mshrQueue.findMatch(addr, is_secure) != 0);
- }
-
- /**
- * Find next request ready time from among possible sources.
- */
- Tick nextQueueReadyTime() const;
-
public:
/** Instantiates a basic cache object. */
Cache(const CacheParams *p);
@@ -547,6 +458,9 @@
/** Non-default destructor is needed to deallocate memory. */
virtual ~Cache();
+ /**
+ * Register stats for this object.
+ */
void regStats() override;
/**
@@ -557,7 +471,7 @@
* @param mshr The MSHR to turn into a packet and send
* @return True if the port is waiting for a retry
*/
- bool sendMSHRQueuePacket(MSHR* mshr);
+ bool sendMSHRQueuePacket(MSHR* mshr) override;
/**
* Similar to sendMSHR, but for a write-queue entry
@@ -567,71 +481,7 @@
* @param wq_entry The write-queue entry to turn into a packet and send
* @return True if the port is waiting for a retry
*/
- bool sendWriteQueuePacket(WriteQueueEntry* wq_entry);
-
- /** serialize the state of the caches
- * We currently don't support checkpointing cache state, so this
panics.
- */
- void serialize(CheckpointOut &cp) const override;
- void unserialize(CheckpointIn &cp) override;
-};
-
-/**
- * Wrap a method and present it as a cache block visitor.
- *
- * For example the forEachBlk method in the tag arrays expects a
- * callable object/function as their parameter. This class wraps a
- * method in an object and presents callable object that adheres to
- * the cache block visitor protocol.
- */
-class CacheBlkVisitorWrapper : public CacheBlkVisitor
-{
- public:
- typedef bool (Cache::*VisitorPtr)(CacheBlk &blk);
-
- CacheBlkVisitorWrapper(Cache &_cache, VisitorPtr _visitor)
- : cache(_cache), visitor(_visitor) {}
-
- bool operator()(CacheBlk &blk) override {
- return (cache.*visitor)(blk);
- }
-
- private:
- Cache &cache;
- VisitorPtr visitor;
-};
-
-/**
- * Cache block visitor that determines if there are dirty blocks in a
- * cache.
- *
- * Use with the forEachBlk method in the tag array to determine if the
- * array contains dirty blocks.
- */
-class CacheBlkIsDirtyVisitor : public CacheBlkVisitor
-{
- public:
- CacheBlkIsDirtyVisitor()
- : _isDirty(false) {}
-
- bool operator()(CacheBlk &blk) override {
- if (blk.isDirty()) {
- _isDirty = true;
- return false;
- } else {
- return true;
- }
- }
-
- /**
- * Does the array contain a dirty line?
- *
- * \return true if yes, false otherwise.
- */
- bool isDirty() const { return _isDirty; };
-
- private:
- bool _isDirty;
+ bool sendWriteQueuePacket(WriteQueueEntry* wq_entry) override;
};
#endif // __MEM_CACHE_CACHE_HH__
diff --git a/src/mem/cache/mshr.cc b/src/mem/cache/mshr.cc
index 493b7f0..28bf075 100644
--- a/src/mem/cache/mshr.cc
+++ b/src/mem/cache/mshr.cc
@@ -307,11 +307,6 @@
// outstanding miss
assert(pkt->cmd != MemCmd::HardPFReq);
- // uncacheable accesses always allocate a new MSHR, and cacheable
- // accesses ignore any uncacheable MSHRs, thus we should never
- // have targets addded if originally allocated uncacheable
- assert(!_isUncacheable);
-
// if there's a request already in service for this MSHR, we will
// have to defer the new target until after the response if any of
// the following are true:
@@ -584,7 +579,7 @@
}
bool
-MSHR::sendPacket(Cache &cache)
+MSHR::sendPacket(BaseCache &cache)
{
return cache.sendMSHRQueuePacket(this);
}
diff --git a/src/mem/cache/mshr.hh b/src/mem/cache/mshr.hh
index 1f59607..f9299d7 100644
--- a/src/mem/cache/mshr.hh
+++ b/src/mem/cache/mshr.hh
@@ -53,7 +53,7 @@
#include "base/printable.hh"
#include "mem/cache/queue_entry.hh"
-class Cache;
+class BaseCache;
/**
* Miss Status and handling Register. This class keeps all the information
@@ -247,7 +247,7 @@
assert(inService); return postDowngrade;
}
- bool sendPacket(Cache &cache);
+ bool sendPacket(BaseCache &cache);
bool allocOnFill() const {
return targets.allocOnFill;
diff --git a/src/mem/cache/queue_entry.hh b/src/mem/cache/queue_entry.hh
index 02daee0..8923d86 100644
--- a/src/mem/cache/queue_entry.hh
+++ b/src/mem/cache/queue_entry.hh
@@ -51,7 +51,7 @@
#include "mem/packet.hh"
-class Cache;
+class BaseCache;
/**
* A queue entry base class, to be used by both the MSHRs and
@@ -102,7 +102,7 @@
* Send this queue entry as a downstream packet, with the exact
* behaviour depending on the specific entry type.
*/
- virtual bool sendPacket(Cache &cache) = 0;
+ virtual bool sendPacket(BaseCache &cache) = 0;
};
diff --git a/src/mem/cache/write_queue_entry.cc
b/src/mem/cache/write_queue_entry.cc
index 663c231..f35fa12 100644
--- a/src/mem/cache/write_queue_entry.cc
+++ b/src/mem/cache/write_queue_entry.cc
@@ -141,7 +141,7 @@
}
bool
-WriteQueueEntry::sendPacket(Cache &cache)
+WriteQueueEntry::sendPacket(BaseCache &cache)
{
return cache.sendWriteQueuePacket(this);
}
diff --git a/src/mem/cache/write_queue_entry.hh
b/src/mem/cache/write_queue_entry.hh
index 13dd09b..40079b4 100644
--- a/src/mem/cache/write_queue_entry.hh
+++ b/src/mem/cache/write_queue_entry.hh
@@ -54,7 +54,7 @@
#include "base/printable.hh"
#include "mem/cache/queue_entry.hh"
-class Cache;
+class BaseCache;
/**
* Write queue entry
@@ -101,7 +101,7 @@
/** WriteQueueEntry list iterator. */
typedef List::iterator Iterator;
- bool sendPacket(Cache &cache);
+ bool sendPacket(BaseCache &cache);
private:
--
To view, visit https://gem5-review.googlesource.com/8290
To unsubscribe, or for help writing mail filters, visit
https://gem5-review.googlesource.com/settings
Gerrit-Project: public/gem5
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I56cef203728e500f74e9e7599fe307f366dfb753
Gerrit-Change-Number: 8290
Gerrit-PatchSet: 1
Gerrit-Owner: Nikos Nikoleris <nikos.nikole...@arm.com>
_______________________________________________
gem5-dev mailing list
gem5-dev@gem5.org
http://m5sim.org/mailman/listinfo/gem5-dev