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

Reply via email to