Daniel Carvalho has uploaded this change for review. ( https://gem5-review.googlesource.com/9741

Change subject: mem-cache: Create Sector Cache
......................................................................

mem-cache: Create Sector Cache

Implementation of Sector Caches, i.e., a cache with multiple data
entries per tag entry.

Change-Id: I8e1e9448fa44ba308ccb16cd5bcc5fd36c988feb
---
M src/mem/cache/Cache.py
M src/mem/cache/SConscript
M src/mem/cache/blk.hh
M src/mem/cache/cache.cc
A src/mem/cache/sector_blk.cc
A src/mem/cache/sector_blk.hh
M src/mem/cache/tags/SConscript
M src/mem/cache/tags/Tags.py
M src/mem/cache/tags/base.cc
M src/mem/cache/tags/base.hh
M src/mem/cache/tags/base_set_assoc.cc
M src/mem/cache/tags/base_set_assoc.hh
M src/mem/cache/tags/cacheset.hh
M src/mem/cache/tags/fa_lru.cc
M src/mem/cache/tags/fa_lru.hh
A src/mem/cache/tags/sector_tags.cc
A src/mem/cache/tags/sector_tags.hh
17 files changed, 870 insertions(+), 51 deletions(-)



diff --git a/src/mem/cache/Cache.py b/src/mem/cache/Cache.py
index faee092..657be53 100644
--- a/src/mem/cache/Cache.py
+++ b/src/mem/cache/Cache.py
@@ -75,7 +75,7 @@
     prefetch_on_access = Param.Bool(False,
"Notify the hardware prefetcher on every access (not just misses)")

-    tags = Param.BaseTags(BaseSetAssoc(), "Tag store")
+    tags = Param.BaseTags(SectorTags(), "Tag store")
     replacement_policy = Param.BaseReplacementPolicy(LRURP(),
         "Replacement policy")

diff --git a/src/mem/cache/SConscript b/src/mem/cache/SConscript
index 1c9b002..5547024 100644
--- a/src/mem/cache/SConscript
+++ b/src/mem/cache/SConscript
@@ -37,6 +37,7 @@
 Source('blk.cc')
 Source('mshr.cc')
 Source('mshr_queue.cc')
+Source('sector_blk.cc')
 Source('write_queue.cc')
 Source('write_queue_entry.cc')

diff --git a/src/mem/cache/blk.hh b/src/mem/cache/blk.hh
index 83807b7..dc3c523 100644
--- a/src/mem/cache/blk.hh
+++ b/src/mem/cache/blk.hh
@@ -73,9 +73,11 @@
     BlkSecure =         0x40,
 };

+class SectorBlk;
+
 /**
  * A Basic Cache block.
- * Contains the tag, status, and a pointer to data.
+ * Contains a pointer to its tag, its status, and a pointer to its data.
  */
 class CacheBlk
 {
@@ -83,8 +85,23 @@
     /** Task Id associated with this block */
     uint32_t task_id;

-    /** Data block tag value. */
-    Addr tag;
+    /**
+     * Data block tag pointer.
+ * A block may share its tag with many other blocks when used compressed
+     * or sectored caches.
+     * @sa BaseSetAssoc
+     */
+    std::shared_ptr<Addr> tag;
+
+    /**
+     * Sector block associated to this block.
+     * @sa SectorTags
+     */
+    SectorBlk* secBlk;
+
+    /** Copy of the block's address, for debugging reasons. */
+    Addr addr;
+
     /**
* Contains a copy of the data in this block for easy access. This is used
      * for efficient execution when the data could be actually stored in
@@ -104,10 +121,10 @@
     Tick whenReady;

     /**
-     * The set and way this block belongs to.
+     * The set, way and sector offset this block belongs to.
      * @todo Move this into subclasses when we fix CacheTags to use them.
      */
-    int set, way;
+    int set, way, sectorOffset;

     /** holds the source requestor ID for this block. */
     int srcMasterId;
@@ -116,7 +133,7 @@
      * Replacement data associated to this block.
      * It is instantiated by the replacement policy.
      */
-    std::unique_ptr<ReplacementData> replacementData;
+    std::shared_ptr<ReplacementData> replacementData;

   protected:
     /**
@@ -161,8 +178,7 @@
     std::list<Lock> lockList;

   public:
-
-    CacheBlk()
+    CacheBlk() : tag(nullptr), secBlk(nullptr)
     {
         invalidate();
     }
@@ -197,7 +213,7 @@
      * Checks that a block is valid.
      * @return True if the block is valid.
      */
-    bool isValid() const
+    virtual bool isValid() const
     {
         return (status & BlkValid) != 0;
     }
@@ -207,7 +223,11 @@
      */
     virtual void invalidate()
     {
-        tag = MaxAddr;
+ // The first invalidate is called before a tag is instantiated by tags
+        if (tag) {
+            *tag = MaxAddr;
+        }
+
         task_id = ContextSwitchTaskId::Unknown;
         status = 0;
         whenReady = MaxTick;
@@ -251,6 +271,19 @@
     }

     /**
+     * Check if block corresponds to given tag. For a match to happen, the
+     * must be valid and belong to the same secure space.
+     *
+     * @param The tag to be matched.
+     * @param is_secure True if the target memory space is secure.
+     * @return True if block matches tag.
+     */
+    bool match(const Addr tag, const bool is_secure) const
+    {
+ return (*(this->tag) == tag) && isValid() && (isSecure() == is_secure);
+    }
+
+    /**
      * Track the fact that a local locked was issued to the
      * block. Invalidate any previous LL to the same address.
      */
diff --git a/src/mem/cache/cache.cc b/src/mem/cache/cache.cc
index 28c4343..f1b4c42 100644
--- a/src/mem/cache/cache.cc
+++ b/src/mem/cache/cache.cc
@@ -80,6 +80,7 @@
 {
     tempBlock = new CacheBlk();
     tempBlock->data = new uint8_t[blkSize];
+    tempBlock->tag = std::unique_ptr<Addr>(new Addr());

     cpuSidePort = new CpuSidePort(p->name + ".cpu_side", this,
                                   "CpuSidePort");
@@ -1815,26 +1816,36 @@
 Cache::allocateBlock(Addr addr, bool is_secure, PacketList &writebacks)
 {
     // Find replacement victim
-    CacheBlk *blk = tags->findVictim(addr);
+    std::vector<CacheBlk*> evictBlks;
+    CacheBlk *victim = tags->findVictim(addr, evictBlks);

     // It is valid to return nullptr if there is no victim
-    if (!blk)
+    if (!victim)
         return nullptr;

-    if (blk->isValid()) {
-        Addr repl_addr = tags->regenerateBlkAddr(blk);
-        MSHR *repl_mshr = mshrQueue.findMatch(repl_addr, blk->isSecure());
-        if (repl_mshr) {
-            // must be an outstanding upgrade or clean request
-            // on a block we're about to replace...
-            assert((!blk->isWritable() && repl_mshr->needsWritable()) ||
-                   repl_mshr->isCleaning());
-            // too hard to replace block with transient state
-            // allocation failed, block not inserted
-            return nullptr;
-        } else {
+    // Check for transient state allocations
+    for (const auto& blk : evictBlks){
+        if (blk->isValid()) {
+            Addr repl_addr = tags->regenerateBlkAddr(blk);
+ MSHR *repl_mshr = mshrQueue.findMatch(repl_addr, blk->isSecure());
+            if (repl_mshr) {
+                // must be an outstanding upgrade or clean request
+                // on a block we're about to replace...
+ assert((!blk->isWritable() && repl_mshr->needsWritable()) | |
+                       repl_mshr->isCleaning());
+                // too hard to replace block with transient state
+                // allocation failed, block not inserted
+                return nullptr;
+            }
+        }
+    }
+
+    // Evict valid blocks associated to this victim block
+    for (const auto& blk : evictBlks){
+        if (blk->isValid()) {
             DPRINTF(Cache, "replacement: replacing %#llx (%s) with %#llx "
-                    "(%s): %s\n", repl_addr, blk->isSecure() ? "s" : "ns",
+                    "(%s): %s\n", tags->regenerateBlkAddr(blk),
+                    blk->isSecure() ? "s" : "ns",
                     addr, is_secure ? "s" : "ns",
                     blk->isDirty() ? "writeback" : "clean");

@@ -1849,10 +1860,22 @@
             } else {
                 writebacks.push_back(cleanEvictBlk(blk));
             }
+
+ // A successful block allocation is followed by an insertion to the + // victim block. If multiple blocks are evicted, that means that
+            // we are evicting all blocks co-associated to this victim, and
+            // they should be invalidated after writeback/evict
+            if (blk != victim) {
+                tags->invalidate(blk);
+                blk->task_id = ContextSwitchTaskId::Unknown;
+                blk->status = 0;
+                blk->whenReady = MaxTick;
+                blk->srcMasterId = Request::invldMasterId;
+            }
         }
     }

-    return blk;
+    return victim;
 }

 void
@@ -1902,8 +1925,9 @@
             // current request and then get rid of it
             assert(!tempBlock->isValid());
             blk = tempBlock;
+            tempBlock->sectorOffset = tags->extractSectorOffset(addr);
             tempBlock->set = tags->extractSet(addr);
-            tempBlock->tag = tags->extractTag(addr);
+            *(tempBlock->tag) = tags->extractTag(addr);
             if (is_secure) {
                 tempBlock->status |= BlkSecure;
             }
@@ -1917,7 +1941,7 @@
         assert(!blk->isValid());
     } else {
         // existing block... probably an upgrade
-        assert(blk->tag == tags->extractTag(addr));
+        assert(*(blk->tag) == tags->extractTag(addr));
// either we're getting new data or the block should already be valid
         assert(pkt->hasData() || blk->isValid());
         // don't clear block status... if block is already dirty we
diff --git a/src/mem/cache/sector_blk.cc b/src/mem/cache/sector_blk.cc
new file mode 100644
index 0000000..ddaaba2
--- /dev/null
+++ b/src/mem/cache/sector_blk.cc
@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2018 Inria
+ * 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.
+ *
+ * Authors: Daniel Carvalho
+ */
+
+#include "mem/cache/sector_blk.hh"
+
+SectorBlk::SectorBlk() : CacheBlk()
+{
+    // A sector does not contain data
+    data = nullptr;
+}
+
+bool
+SectorBlk::isValid() const
+{
+    // If any of the blocks in the sector is valid, so is the sector
+    for (const auto& blk : blks) {
+        if (blk->isValid()) {
+            return true;
+        }
+    }
+    return false;
+}
+
diff --git a/src/mem/cache/sector_blk.hh b/src/mem/cache/sector_blk.hh
new file mode 100644
index 0000000..f0aa85f
--- /dev/null
+++ b/src/mem/cache/sector_blk.hh
@@ -0,0 +1,66 @@
+/**
+ * Copyright (c) 2018 Inria
+ * 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.
+ *
+ * Authors: Daniel Carvalho
+ */
+
+/** @file
+ * Definitions of a simple sector block class. Each sector consists of a
+ * sequence of cache blocks that may or may not be present in the cache.
+ */
+
+#ifndef __MEM_CACHE_SECTOR_BLK_HH__
+#define __MEM_CACHE_SECTOR_BLK_HH__
+
+#include <vector>
+
+#include "mem/cache/blk.hh"
+
+/**
+ * A Basic Sector block.
+ * Contains the tag and a list of blocks associated to this sector.
+ */
+class SectorBlk : public CacheBlk
+{
+  public:
+    /** List of blocks associated to this sector. */
+    std::vector<CacheBlk*> blks;
+
+    /** Default constructor. */
+    SectorBlk();
+    SectorBlk(const SectorBlk&) = delete;
+    SectorBlk& operator=(const SectorBlk&) = delete;
+    ~SectorBlk(){}
+
+    /**
+     * Checks that a sector block is valid.
+     * @return True if any of the blocks in the sector is valid.
+     */
+    bool isValid() const override;
+};
+
+#endif //__MEM_CACHE_SECTOR_BLK_HH__
diff --git a/src/mem/cache/tags/SConscript b/src/mem/cache/tags/SConscript
index 9758b56..136abac 100644
--- a/src/mem/cache/tags/SConscript
+++ b/src/mem/cache/tags/SConscript
@@ -35,3 +35,4 @@
 Source('base.cc')
 Source('base_set_assoc.cc')
 Source('fa_lru.cc')
+Source('sector_tags.cc')
diff --git a/src/mem/cache/tags/Tags.py b/src/mem/cache/tags/Tags.py
index ff4eff4..7f06070 100644
--- a/src/mem/cache/tags/Tags.py
+++ b/src/mem/cache/tags/Tags.py
@@ -73,6 +73,18 @@
     replacement_policy = Param.BaseReplacementPolicy(
         Parent.replacement_policy, "Replacement policy")

+class SectorTags(BaseTags):
+    type = 'SectorTags'
+    cxx_header = "mem/cache/tags/sector_tags.hh"
+    assoc = Param.Int(Parent.assoc, "associativity")
+
+    # Get the size of a sector, in number of data blocks
+    sector_size = Param.Int(1, "Number of data blocks per sector");
+
+    # Get replacement policy from the parent (cache)
+    replacement_policy = Param.BaseReplacementPolicy(
+        Parent.replacement_policy, "Replacement policy")
+
 class FALRU(BaseTags):
     type = 'FALRU'
     cxx_class = 'FALRU'
diff --git a/src/mem/cache/tags/base.cc b/src/mem/cache/tags/base.cc
index 91f922a..050bd03 100644
--- a/src/mem/cache/tags/base.cc
+++ b/src/mem/cache/tags/base.cc
@@ -50,6 +50,7 @@

 #include "cpu/smt.hh" //maxThreadsPerCPU
 #include "mem/cache/base.hh"
+#include "mem/cache/sector_blk.hh" // TODO remove
 #include "sim/sim_exit.hh"

 BaseTags::BaseTags(const Params *p)
@@ -79,6 +80,9 @@
     // Get address
     Addr addr = pkt->getAddr();

+    // Store address in block for debugging
+    blk->addr = addr;
+
     // Update warmup data
     if (!blk->replacementData->isTouched) {
         if (!warmedUp && tagsInUse.value() >= warmupBound) {
@@ -104,8 +108,14 @@
     // to insert the new one
     tagsInUse++;

-    // Set tag for new block.  Caller is responsible for setting status.
-    blk->tag = extractTag(addr);
+    // Check if it is overwriting a sector
+    if (blk->secBlk && blk->secBlk->isValid() &&
+        (*(blk->secBlk->tag) != extractTag(addr))){
+        panic("Overwriting valid sector!");
+    }
+
+    // Set tag for new block. Caller is responsible for setting status.
+    *(blk->tag) = extractTag(addr);

     // Deal with what we are bringing in
     MasterID master_id = pkt->req->masterId();
diff --git a/src/mem/cache/tags/base.hh b/src/mem/cache/tags/base.hh
index 4cf6774..6e4cd1f 100644
--- a/src/mem/cache/tags/base.hh
+++ b/src/mem/cache/tags/base.hh
@@ -257,9 +257,11 @@
      * Find replacement victim based on address.
      *
      * @param addr Address to find a victim for.
+     * @param evictBlks Cache blocks to be evicted.
      * @return Cache block to be replaced.
      */
-    virtual CacheBlk* findVictim(Addr addr) = 0;
+ virtual CacheBlk* findVictim(Addr addr, std::vector<CacheBlk*>& evictBlks) + const = 0;

virtual CacheBlk* accessBlock(Addr addr, bool is_secure, Cycles &lat) = 0;

@@ -283,6 +285,8 @@

     virtual int extractSet(Addr addr) const = 0;

+    virtual int extractSectorOffset(Addr addr) const { return 0; };
+
     virtual void forEachBlk(CacheBlkVisitor &visitor) = 0;
 };

diff --git a/src/mem/cache/tags/base_set_assoc.cc b/src/mem/cache/tags/base_set_assoc.cc
index 41ccbc6..ca4c1d8 100644
--- a/src/mem/cache/tags/base_set_assoc.cc
+++ b/src/mem/cache/tags/base_set_assoc.cc
@@ -96,7 +96,8 @@

             // Setting the tag to j is just to prevent long chains in the
             // hash table; won't matter because the block is invalid
-            blk->tag = j;
+            blk->tag = std::unique_ptr<Addr>(new Addr());
+            *(blk->tag) = j;

             // Set its set and way
             blk->set = i;
@@ -111,10 +112,21 @@
 CacheBlk*
 BaseSetAssoc::findBlock(Addr addr, bool is_secure) const
 {
+    // Extract block tag
     Addr tag = extractTag(addr);
-    unsigned set = extractSet(addr);
-    BlkType *blk = sets[set].findBlk(tag, is_secure);
-    return blk;
+
+    // Find possible locations for the given address
+    std::vector<CacheBlk*> locations = getPossibleLocations(addr);
+
+    // Search for block
+    for (const auto& blk : locations) {
+        if (blk->match(tag, is_secure)) {
+            return blk;
+        }
+    }
+
+    // Did not find block
+    return nullptr;
 }

 CacheBlk*
diff --git a/src/mem/cache/tags/base_set_assoc.hh b/src/mem/cache/tags/base_set_assoc.hh
index 21613a4..6bb29dc 100644
--- a/src/mem/cache/tags/base_set_assoc.hh
+++ b/src/mem/cache/tags/base_set_assoc.hh
@@ -187,15 +187,18 @@
     /**
      * Find replacement victim based on address.
      *
-     * @param addr Address to find a victim for.
+     * @param evictBlks Cache blocks to be evicted.
      * @return Cache block to be replaced.
      */
-    CacheBlk* findVictim(Addr addr) override
+ CacheBlk* findVictim(Addr addr, std::vector<CacheBlk*>& evictBlks) const + override
     {
         // Choose replacement victim from replacement candidates
         CacheBlk* victim = replacementPolicy->getVictim(
                                getPossibleLocations(addr));

+        evictBlks.push_back(victim);
+
DPRINTF(CacheRepl, "set %x, way %x: selecting blk for replacement\n",
             victim->set, victim->way);

@@ -211,7 +214,7 @@
      * @param addr The addr to a find possible locations for.
      * @return The possible locations.
      */
-    const std::vector<CacheBlk*> getPossibleLocations(Addr addr)
+    const std::vector<CacheBlk*> getPossibleLocations(Addr addr) const
     {
         return sets[extractSet(addr)].blks;
     }
@@ -278,7 +281,7 @@
      */
     Addr regenerateBlkAddr(const CacheBlk* blk) const override
     {
-        return ((blk->tag << tagShift) | ((Addr)blk->set << setShift));
+        return ((*(blk->tag) << tagShift) | ((Addr)blk->set << setShift));
     }

     /**
diff --git a/src/mem/cache/tags/cacheset.hh b/src/mem/cache/tags/cacheset.hh
index 5a34456..0ace837 100644
--- a/src/mem/cache/tags/cacheset.hh
+++ b/src/mem/cache/tags/cacheset.hh
@@ -95,14 +95,13 @@
      * Way_id returns the id of the way that matches the block
      * If no block is found way_id is set to assoc.
      */
-    way_id = assoc;
+    /*way_id = assoc;
     for (int i = 0; i < assoc; ++i) {
-        if (blks[i]->tag == tag && blks[i]->isValid() &&
-            blks[i]->isSecure() == is_secure) {
+        if (blks[i]->match(tag, is_secure)) {
             way_id = i;
             return blks[i];
         }
-    }
+    }*/
     return nullptr;
 }

diff --git a/src/mem/cache/tags/fa_lru.cc b/src/mem/cache/tags/fa_lru.cc
index f02b55a..66a86f1 100644
--- a/src/mem/cache/tags/fa_lru.cc
+++ b/src/mem/cache/tags/fa_lru.cc
@@ -168,7 +168,7 @@
     BaseTags::invalidate(blk);

     // Erase block entry in the hash table
-    tagHash.erase(blk->tag);
+    tagHash.erase(*(blk->tag));
 }

 CacheBlk*
@@ -196,7 +196,7 @@
             lat = cache->ticksToCycles(blk->whenReady - curTick()) +
             accessLatency;
         }
-        assert(blk->tag == blkAddr);
+        assert(*(blk->tag) == blkAddr);
         tmp_in_cache = blk->inCache;
         for (unsigned i = 0; i < numCaches; i++) {
             if (1<<i & blk->inCache) {
@@ -233,7 +233,7 @@
     FALRUBlk* blk = hashLookup(blkAddr);

     if (blk && blk->isValid()) {
-        assert(blk->tag == blkAddr);
+        assert(*(blk->tag) == blkAddr);
     } else {
         blk = nullptr;
     }
@@ -248,8 +248,9 @@
 }

 CacheBlk*
-FALRU::findVictim(Addr addr)
+FALRU::findVictim(Addr addr, std::vector<CacheBlk*>& evictBlks) const
 {
+    evictBlks.push_back(tail);
     return tail;
 }

@@ -268,7 +269,7 @@
     moveToHead(falruBlk);

     // Insert new block in the hash table
-    tagHash[falruBlk->tag] = falruBlk;
+    tagHash[*(falruBlk->tag)] = falruBlk;

     //assert(check());
 }
diff --git a/src/mem/cache/tags/fa_lru.hh b/src/mem/cache/tags/fa_lru.hh
index 129af9f..0cc67fa 100644
--- a/src/mem/cache/tags/fa_lru.hh
+++ b/src/mem/cache/tags/fa_lru.hh
@@ -204,9 +204,11 @@
      * Find replacement victim based on address.
      *
      * @param addr Address to find a victim for.
+     * @param evictBlks Cache blocks to be evicted.
      * @return Cache block to be replaced.
      */
-    CacheBlk* findVictim(Addr addr) override;
+ CacheBlk* findVictim(Addr addr, std::vector<CacheBlk*>& evictBlks) const + override;

     /**
      * Insert the new block into the cache and update replacement data.
@@ -253,7 +255,7 @@
      */
     Addr regenerateBlkAddr(const CacheBlk* blk) const override
     {
-        return blk->tag;
+        return *(blk->tag);
     }

     /**
diff --git a/src/mem/cache/tags/sector_tags.cc b/src/mem/cache/tags/sector_tags.cc
new file mode 100644
index 0000000..ef11417
--- /dev/null
+++ b/src/mem/cache/tags/sector_tags.cc
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2018 Inria
+ * 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.
+ *
+ * Authors: Daniel Carvalho
+ */
+
+/**
+ * @file
+ * Definitions of a base set associative sector tag store.
+ */
+
+#include "mem/cache/tags/sector_tags.hh"
+
+#include <cassert>
+#include <string>
+
+#include "base/intmath.hh"
+#include "debug/CacheRepl.hh"
+
+SectorTags::SectorTags(const Params *p)
+    :BaseTags(p), assoc(p->assoc), allocAssoc(p->assoc),
+     sectorSize(p->sector_size),
+     blks(p->size / p->block_size),
+     secBlks(p->size / (p->block_size * p->sector_size)),
+     numSets(p->size / (p->block_size * p->assoc * p->sector_size)),
+     numSectors(p->size / (p->block_size * p->sector_size)),
+     sequentialAccess(p->sequential_access),
+     sets(p->size / (p->block_size * p->assoc * p->sector_size)),
+     replacementPolicy(p->replacement_policy)
+{
+    // Check parameters
+    if (blkSize < 4 || !isPowerOf2(blkSize)) {
+        fatal("Block size must be at least 4 and a power of 2");
+    }
+    if (!isPowerOf2(numSets)) {
+        fatal("# of sets must be non-zero and a power of 2");
+    }
+    if (!isPowerOf2(sectorSize)) {
+        fatal("# of blocks per sector must be non-zero and a power of 2");
+    }
+    if (assoc <= 0) {
+        fatal("associativity must be greater than zero");
+    }
+
+    // Calculate masks
+    // Tag | Set # | Sector Offset # | Offset #
+    sectorShift = floorLog2(blkSize);
+    sectorMask = sectorSize - 1;
+    setShift = sectorShift + floorLog2(sectorSize);
+    setMask = numSets - 1;
+    tagShift = sectorShift + floorLog2(numSets);
+
+    // Initialize all sets
+    unsigned secBlkIndex = 0;       // index into sector blks array
+    unsigned blkIndex = 0;       // index into blks array
+    for (unsigned i = 0; i < numSets; ++i) {
+        sets[i].assoc = assoc;
+
+        sets[i].blks.resize(assoc);
+
+        // Initialize all sectors in this set
+        for (unsigned j = 0; j < assoc; ++j) {
+            // Select block within the set to be linked
+            SectorBlk*& secBlk = sets[i].blks[j];
+
+            // Locate next cache sector
+            secBlk = &secBlks[secBlkIndex];
+
+            // Associate a replacement data entry to the sector
+ secBlk->replacementData = replacementPolicy->instantiateEntry();
+
+            // Setting the tag to j is just to prevent long chains in the
+            // hash table; won't matter because the block is invalid
+            secBlk->tag = std::shared_ptr<Addr>(new Addr());
+            *(secBlk->tag) = j;
+
+            // Initialize all blocks in this sector
+            secBlk->blks.resize(sectorSize);
+            for (unsigned k = 0; k < sectorSize; ++k){
+                // Select block within the set to be linked
+                CacheBlk*& blk = secBlk->blks[k];
+
+                // Locate next cache block
+                blk = &blks[blkIndex];
+
+                // Associate a data chunk to the block
+                blk->data = &dataBlks[blkSize*blkIndex];
+
+                // Associate sector block to this block
+                blk->secBlk = secBlk;
+
+                // Associate the sector replacement data to this block
+                blk->replacementData = secBlk->replacementData;
+
+                // Associate sector tag to this block
+                blk->tag = secBlk->tag;
+
+                // Set its set, way and sector offset
+                blk->set = i;
+                blk->way = j;
+                blk->sectorOffset = k;
+
+                // Update block index
+                ++blkIndex;
+            }
+
+            // Update sector block index
+            ++secBlkIndex;
+        }
+    }
+}
+
+CacheBlk*
+SectorTags::findBlock(Addr addr, bool is_secure) const
+{
+    // Extract sector tag
+    const Addr tag = extractTag(addr);
+    const Addr offset = extractSectorOffset(addr);
+
+    // Find possible locations for the given address
+    const std::vector<SectorBlk*> locations = getPossibleLocations(addr);
+
+    // Search for block
+    for (const auto& sector : locations) {
+        if (sector->blks[offset]->match(tag, is_secure)) {
+            return sector->blks[offset];
+        }
+    }
+
+    // Did not find block
+    return nullptr;
+}
+
+CacheBlk*
+SectorTags::findVictim(Addr addr, std::vector<CacheBlk*>& evictBlks) const
+{
+    // Get all possible locations of this sector
+ const std::vector<SectorBlk*> sectorLocations = getPossibleLocations(addr);
+
+    SectorBlk* victimSector = nullptr;
+
+    // Check if the sector this address belongs to has been allocated
+    Addr tag = extractTag(addr);
+    for (const auto& sector : sectorLocations){
+        if (tag == *(sector->tag)){
+            victimSector = sector;
+            break;
+        }
+    }
+
+    // If the sector is not present
+    if (victimSector == nullptr){
+        // Choose replacement victim from replacement candidates
+ victimSector = static_cast<SectorBlk*>(replacementPolicy->getVictim( + std::vector<CacheBlk*>(sectorLocations.begin(), + sectorLocations.end())));
+    }
+
+    // Get the location of the victim block within the sector
+    CacheBlk* victim = victimSector->blks[extractSectorOffset(addr)];
+
+    // Get evicted blocks
+    if (tag == *(victimSector->tag)){
+ // If new block belongs to the same sector we just need to evict the
+        // block at its final location. This block will be invalid, as only
+        // one block can map to a specific offset of a sector
+        assert(!victim->isValid());
+
+        evictBlks.push_back(victim);
+    } else {
+        // The whole sector must be evicted to make room for the new sector
+        evictBlks = victimSector->blks;
+    }
+
+    DPRINTF(CacheRepl, "set %x, way %x, sector offset %x: %s\n",
+            "selecting blk for replacement\n", victim->set, victim->way,
+            victim->sectorOffset);
+
+    return victim;
+}
+
+Addr
+SectorTags::extractTag(Addr addr) const
+{
+    return addr >> tagShift;
+}
+
+int
+SectorTags::extractSet(Addr addr) const
+{
+    return (addr >> setShift) & setMask;
+}
+
+int
+SectorTags::extractSectorOffset(Addr addr) const
+{
+    return (addr >> sectorShift) & sectorMask;
+}
+
+Addr
+SectorTags::regenerateBlkAddr(const CacheBlk* blk) const
+{
+    Addr addr = ((*(blk->tag) << tagShift) |
+            ((Addr)blk->set << setShift) |
+            ((Addr)blk->sectorOffset << sectorShift));
+    assert(blk->addr == addr);
+    return addr;
+}
+
+CacheBlk*
+SectorTags::findBlockBySetAndWay(int set, int way) const
+{
+    return sets[set].blks[way];
+}
+
+const std::vector<SectorBlk*>
+SectorTags::getPossibleLocations(Addr addr) const
+{
+    return sets[extractSet(addr)].blks;
+}
+
+CacheBlk*
+SectorTags::accessBlock(Addr addr, bool is_secure, Cycles &lat)
+{
+    CacheBlk *blk = findBlock(addr, is_secure);
+
+    // Access all tags in parallel, hence one in each way.  The data side
+    // either accesses all blocks in parallel, or one block sequentially on
+    // a hit.  Sequential access with a miss doesn't access data.
+    tagAccesses += allocAssoc;
+    if (sequentialAccess) {
+        if (blk != nullptr) {
+            dataAccesses += 1;
+        }
+    } else {
+        dataAccesses += allocAssoc;
+    }
+
+    if (blk != nullptr) {
+        // If a cache hit
+        lat = accessLatency;
+        // Check if the block to be accessed is available. If not,
+        // apply the accessLatency on top of block->whenReady.
+        if (blk->whenReady > curTick() &&
+            cache->ticksToCycles(blk->whenReady - curTick()) >
+            accessLatency) {
+            lat = cache->ticksToCycles(blk->whenReady - curTick()) +
+            accessLatency;
+        }
+
+        // Update replacement data of accessed block
+        replacementPolicy->touch(blk->replacementData.get());
+    } else {
+        // If a cache miss
+        lat = lookupLatency;
+    }
+
+    return blk;
+}
+
+void
+SectorTags::insertBlock(PacketPtr pkt, CacheBlk *blk)
+{
+    // Insert block
+    BaseTags::insertBlock(pkt, blk);
+
+    // Update replacement policy
+    replacementPolicy->reset(blk->replacementData.get());
+}
+
+void
+SectorTags::cleanupRefs()
+{
+    for (unsigned i = 0; i < numSets*assoc; ++i) {
+        if (blks[i].isValid()) {
+            totalRefs += blks[i].replacementData->refCount;
+            ++sampledRefs;
+        }
+    }
+}
+
+std::string
+SectorTags::print() const {
+    std::string cache_state;
+    for (unsigned i = 0; i < numSets; ++i) {
+        // link in the data blocks
+        for (unsigned j = 0; j < assoc; ++j) {
+            SectorBlk* sectorBlk = sets[i].blks[j];
+            // Print all blocks in the sector
+            for (const auto& blk : sectorBlk->blks){
+                if (blk->isValid())
+ cache_state += csprintf("\tset: %d block: %d %s\n", i, j,
+                            blk->print());
+            }
+        }
+    }
+    if (cache_state.empty())
+        cache_state = "no valid tags\n";
+    return cache_state;
+}
+
+void
+SectorTags::computeStats()
+{
+    for (unsigned i = 0; i < ContextSwitchTaskId::NumTaskId; ++i) {
+        occupanciesTaskId[i] = 0;
+        for (unsigned j = 0; j < 5; ++j) {
+            ageTaskId[i][j] = 0;
+        }
+    }
+
+    for (unsigned i = 0; i < numSets * assoc; ++i) {
+        if (blks[i].isValid()) {
+            assert(blks[i].task_id < ContextSwitchTaskId::NumTaskId);
+            occupanciesTaskId[blks[i].task_id]++;
+            assert(blks[i].replacementData->tickInserted <= curTick());
+            Tick age = curTick() - blks[i].replacementData->tickInserted;
+
+            int age_index;
+            if (age / SimClock::Int::us < 10) { // <10us
+                age_index = 0;
+            } else if (age / SimClock::Int::us < 100) { // <100us
+                age_index = 1;
+            } else if (age / SimClock::Int::ms < 1) { // <1ms
+                age_index = 2;
+            } else if (age / SimClock::Int::ms < 10) { // <10ms
+                age_index = 3;
+            } else
+                age_index = 4; // >10ms
+
+            ageTaskId[blks[i].task_id][age_index]++;
+        }
+    }
+}
+
+SectorTags *
+SectorTagsParams::create()
+{
+    return new SectorTags(this);
+}
diff --git a/src/mem/cache/tags/sector_tags.hh b/src/mem/cache/tags/sector_tags.hh
new file mode 100644
index 0000000..53fd75c
--- /dev/null
+++ b/src/mem/cache/tags/sector_tags.hh
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2018 Inria
+ * 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.
+ *
+ * Authors: Daniel Carvalho
+ */
+
+/**
+ * @file
+ * Declaration of a sector set associative tag store.
+ */
+
+#ifndef __MEM_CACHE_TAGS_SECTOR_TAGS_HH__
+#define __MEM_CACHE_TAGS_SECTOR_TAGS_HH__
+
+#include <vector>
+
+#include "mem/cache/base.hh"
+#include "mem/cache/sector_blk.hh"
+#include "mem/cache/tags/base.hh"
+#include "mem/cache/tags/cacheset.hh"
+#include "mem/packet.hh"
+#include "params/SectorTags.hh"
+
+/**
+ * A SectorTags cache tag store.
+ * @sa  \ref gem5MemorySystem "gem5 Memory System"
+ *
+ * The SectorTags placement policy divides the cache into s sectors of w
+ * consecutive cache lines (ways) that may or may not be present.
+ */
+class SectorTags : public BaseTags
+{
+  private:
+    /**
+     * Calculate a block's offset in a sector from the address.
+     * @param addr The address to get the offset from.
+     * @return Offset of the corresponding block within its sector.
+     */
+    int extractSectorOffset(Addr addr) const;
+
+  public:
+    /** Typedef the set type used in this tag store. */
+    typedef CacheSet<SectorBlk> SetType;
+
+  protected:
+    /** The associativity of the cache. */
+    const unsigned assoc;
+    /** The allocatable associativity of the cache (alloc mask). */
+    unsigned allocAssoc;
+
+    /** Number of cache lines per sector. */
+    const unsigned sectorSize;
+
+    /** The cache blocks. */
+    std::vector<CacheBlk> blks;
+    /** The cache sector blocks. */
+    std::vector<SectorBlk> secBlks;
+
+    /** The number of sets in the cache. */
+    const unsigned numSets;
+    /** The number of sectors in the cache. */
+    const unsigned numSectors;
+
+    /** Whether tags and data are accessed sequentially. */
+    const bool sequentialAccess;
+
+    /** The cache sets. */
+    std::vector<SetType> sets;
+
+    /** The amount to shift the address to get the set. */
+    int setShift;
+    /** The amount to shift the address to get the tag. */
+    int tagShift;
+    /** Mask out all bits that aren't part of the set index. */
+    unsigned setMask;
+    /** The amount to shift the address to get the sector tag. */
+    int sectorShift;
+    /** Mask out all bits that aren't part of the sector tag. */
+    unsigned sectorMask;
+
+    /** Replacement policy */
+    BaseReplacementPolicy *replacementPolicy;
+
+  public:
+    /** Convenience typedef. */
+     typedef SectorTagsParams Params;
+
+    /**
+     * Construct and initialize this tag store.
+     */
+    SectorTags(const Params *p);
+
+    /**
+     * Destructor.
+     */
+    ~SectorTags() {};
+
+    /**
+     * Find the cache sector block given set and way.
+     * @param set The set of the block.
+     * @param way The way of the block.
+     * @return The cache block.
+     */
+    CacheBlk *findBlockBySetAndWay(int set, int way) const override;
+
+    /**
+ * Access block and update replacement data. May not succeed, in which case
+     * nullptr is returned. This has all the implications of a cache
+ * access and should only be used as such. Returns the access latency as a
+     * side effect.
+     * @param addr The address to find.
+     * @param is_secure True if the target memory space is secure.
+     * @param lat The access latency.
+     * @return Pointer to the cache block if found.
+     */
+    CacheBlk* accessBlock(Addr addr, bool is_secure, Cycles &lat) override;
+
+    /**
+ * Finds the given address in the cache, do not update replacement data.
+     * i.e. This is a no-side-effect find of a block.
+     * @param addr The address to find.
+     * @param is_secure True if the target memory space is secure.
+     * @param asid The address space ID.
+     * @return Pointer to the cache block if found.
+     */
+    CacheBlk* findBlock(Addr addr, bool is_secure) const override;
+
+    /**
+     * Find replacement victim based on address.
+     *
+     * @param addr Address to find a victim for.
+     * @param evictBlks Cache blocks to be evicted.
+     * @return Cache block to be replaced.
+     */
+ CacheBlk* findVictim(Addr addr, std::vector<CacheBlk*>& evictBlks) const + override;
+
+    /**
+     * Find all possible block locations for insertion and replacement of
+     * an address. Should be called immediately before ReplacementPolicy's
+     * findVictim() not to break cache resizing.
+     * Returns blocks in all ways belonging to the set of the address.
+     *
+     * @param addr The addr to a find possible locations for.
+     * @return The possible locations.
+     */
+    const std::vector<SectorBlk*> getPossibleLocations(Addr addr) const;
+
+    /**
+     * Insert the new block into the cache.
+     * @param pkt Packet holding the address to update
+     * @param blk The block to update.
+     */
+    void insertBlock(PacketPtr pkt, CacheBlk *blk) override;
+
+    /**
+     * Generate the sector tag from the given address.
+     * @param addr The address to get the sector tag from.
+     * @return The sector tag of the address.
+     */
+    Addr extractTag(Addr addr) const override;
+
+    /**
+     * Calculate the set index from the address.
+     * @param addr The address to get the set from.
+     * @return The set index of the address.
+     */
+    int extractSet(Addr addr) const override;
+
+    /**
+     * Regenerate the block address from the tag and set.
+     *
+     * @param block The block.
+     * @return the block address.
+     */
+    Addr regenerateBlkAddr(const CacheBlk* blk) const override;
+
+    /**
+ * Called at end of simulation to complete average block reference stats.
+     */
+    void cleanupRefs() override;
+
+    /**
+     * Print all tags used
+     */
+    std::string print() const override;
+
+    /**
+     * Called prior to dumping stats to compute task occupancy
+     */
+    void computeStats() override;
+
+    /**
+     * Visit each block in the tag store and apply a visitor to the
+     * block.
+     *
+     * The visitor should be a function (or object that behaves like a
+     * function) that takes a cache block reference as its parameter
+     * and returns a bool. A visitor can request the traversal to be
+     * stopped by returning false, returning true causes it to be
+     * called for the next block in the tag store.
+     *
+     * \param visitor Visitor to call on each block.
+     */
+    void forEachBlk(CacheBlkVisitor &visitor) override {
+        for (unsigned i = 0; i < numSets * assoc; ++i) {
+            if (!visitor(blks[i]))
+                return;
+        }
+    }
+};
+
+#endif //__MEM_CACHE_TAGS_SECTOR_TAGS_HH__

--
To view, visit https://gem5-review.googlesource.com/9741
To unsubscribe, or for help writing mail filters, visit https://gem5-review.googlesource.com/settings

Gerrit-Project: public/gem5
Gerrit-Branch: master
Gerrit-Change-Id: I8e1e9448fa44ba308ccb16cd5bcc5fd36c988feb
Gerrit-Change-Number: 9741
Gerrit-PatchSet: 1
Gerrit-Owner: Daniel Carvalho <[email protected]>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list
[email protected]
http://m5sim.org/mailman/listinfo/gem5-dev

Reply via email to