mem-cache: Create Sector Cache
authorDaniel R. Carvalho <odanrc@yahoo.com.br>
Thu, 5 Apr 2018 09:54:39 +0000 (11:54 +0200)
committerDaniel Carvalho <odanrc@yahoo.com.br>
Wed, 13 Jun 2018 07:58:00 +0000 (07:58 +0000)
Implementation of Sector Caches, i.e., a cache with multiple
sequential data entries per tag entry for Set Associtive
placement policies.

Change-Id: I8e1e9448fa44ba308ccb16cd5bcc5fd36c988feb
Reviewed-on: https://gem5-review.googlesource.com/9741
Reviewed-by: Nikos Nikoleris <nikos.nikoleris@arm.com>
Maintainer: Nikos Nikoleris <nikos.nikoleris@arm.com>

src/mem/cache/SConscript
src/mem/cache/blk.hh
src/mem/cache/sector_blk.cc [new file with mode: 0644]
src/mem/cache/sector_blk.hh [new file with mode: 0644]
src/mem/cache/tags/SConscript
src/mem/cache/tags/Tags.py
src/mem/cache/tags/sector_tags.cc [new file with mode: 0644]
src/mem/cache/tags/sector_tags.hh [new file with mode: 0644]

index 244d61dc2ddc022ae41482e40d58c076bce88660..24eea960e9bff2e4b6a9c0c5ea377d5ecbc5851f 100644 (file)
@@ -38,6 +38,7 @@ Source('cache.cc')
 Source('mshr.cc')
 Source('mshr_queue.cc')
 Source('noncoherent_cache.cc')
+Source('sector_blk.cc')
 Source('write_queue.cc')
 Source('write_queue_entry.cc')
 
index 93189bd9734d5175384c2d4c5aaf22048d4d773d..1b796608f6d79d0082e335971b56f6894ffed30a 100644 (file)
@@ -260,8 +260,8 @@ class CacheBlk : public ReplaceableEntry
      * @param src_master_ID The source requestor ID.
      * @param task_ID The new task ID.
      */
-    void insert(const Addr tag, const bool is_secure, const int src_master_ID,
-                const uint32_t task_ID);
+    virtual void insert(const Addr tag, const bool is_secure,
+                        const int src_master_ID, const uint32_t task_ID);
 
     /**
      * Track the fact that a local locked was issued to the
diff --git a/src/mem/cache/sector_blk.cc b/src/mem/cache/sector_blk.cc
new file mode 100644 (file)
index 0000000..07d9e95
--- /dev/null
@@ -0,0 +1,123 @@
+/**
+ * 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
+ * Implementation 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.
+ */
+
+#include "mem/cache/sector_blk.hh"
+
+#include <cassert>
+
+#include "base/logging.hh"
+
+void
+SectorSubBlk::setSectorBlock(SectorBlk* sector_blk)
+{
+    assert(sector_blk != nullptr);
+    _sectorBlk = sector_blk;
+}
+
+const SectorBlk*
+SectorSubBlk::getSectorBlock() const
+{
+    return _sectorBlk;
+}
+
+void
+SectorSubBlk::setSectorOffset(const int sector_offset)
+{
+    _sectorOffset = sector_offset;
+}
+
+int
+SectorSubBlk::getSectorOffset() const
+{
+    return _sectorOffset;
+}
+
+Addr
+SectorSubBlk::getTag() const
+{
+    return _sectorBlk->getTag();
+}
+
+void
+SectorSubBlk::insert(const Addr tag, const bool is_secure,
+                     const int src_master_ID, const uint32_t task_ID)
+{
+    // Make sure it is not overwriting another sector
+    panic_if((_sectorBlk && _sectorBlk->isValid()) &&
+             ((_sectorBlk->getTag() != tag) ||
+              (_sectorBlk->isSecure() != is_secure)),
+              "Overwriting valid sector!");
+
+    CacheBlk::insert(tag, is_secure, src_master_ID, task_ID);
+
+    // Set sector tag
+    _sectorBlk->setTag(tag);
+}
+
+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;
+}
+
+bool
+SectorBlk::isSecure() const
+{
+    // If any of the valid blocks in the sector is secure, so is the sector
+    for (const auto& blk : blks) {
+        if (blk->isValid()) {
+            return blk->isSecure();
+        }
+    }
+    return false;
+}
+
+void
+SectorBlk::setTag(const Addr tag)
+{
+    _tag = tag;
+}
+
+Addr
+SectorBlk::getTag() const
+{
+    return _tag;
+}
diff --git a/src/mem/cache/sector_blk.hh b/src/mem/cache/sector_blk.hh
new file mode 100644 (file)
index 0000000..f8f8cd5
--- /dev/null
@@ -0,0 +1,171 @@
+/**
+ * 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
+ * Definition 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"
+#include "mem/cache/replacement_policies/base.hh"
+
+class SectorBlk;
+
+/**
+ * A sector is composed of sub-blocks, and each sub-block has information
+ * regarding its sector and a pointer to its sector tag.
+ */
+class SectorSubBlk : public CacheBlk
+{
+  private:
+    /**
+     * Sector block associated to this block.
+     */
+    SectorBlk* _sectorBlk;
+
+    /**
+     * The offset of this sub-block in the sector.
+     */
+    int _sectorOffset;
+
+  public:
+    SectorSubBlk() : CacheBlk(), _sectorBlk(nullptr), _sectorOffset(0) {}
+    SectorSubBlk(const SectorSubBlk&) = delete;
+    SectorSubBlk& operator=(const SectorSubBlk&) = delete;
+    ~SectorSubBlk() {};
+
+    /**
+     * Set sector block associated to this block.
+     *
+     * @param sector_blk The sector block pointer.
+     */
+    void setSectorBlock(SectorBlk* sector_blk);
+
+    /**
+     * Get sector block associated to this block.
+     *
+     * @return The sector block pointer.
+     */
+    const SectorBlk* getSectorBlock() const;
+
+    /**
+     * Set offset of this sub-block within the sector.
+     *
+     * @param sector_offset The block's offset.
+     */
+    void setSectorOffset(const int sector_offset);
+
+    /**
+     * Get offset of this sub-block within the sector.
+     *
+     * @return sector_offset The block's offset.
+     */
+    int getSectorOffset() const;
+
+    /**
+     * Get tag associated to this block.
+     *
+     * @return The tag value.
+     */
+    Addr getTag() const;
+
+    /**
+     * Set member variables when a block insertion occurs. Resets reference
+     * count to 1 (the insertion counts as a reference), and touch block if
+     * it hadn't been touched previously. Sets the insertion tick to the
+     * current tick. Does not make block valid.
+     *
+     * @param tag Block address tag.
+     * @param is_secure Whether the block is in secure space or not.
+     * @param src_master_ID The source requestor ID.
+     * @param task_ID The new task ID.
+     */
+    void insert(const Addr tag, const bool is_secure, const int src_master_ID,
+                const uint32_t task_ID) override;
+};
+
+/**
+ * A Basic Sector block.
+ * Contains the tag and a list of blocks associated to this sector.
+ */
+class SectorBlk : public ReplaceableEntry
+{
+  private:
+    /**
+     * Sector tag value. A sector's tag is the tag of all its sub-blocks.
+     */
+    Addr _tag;
+
+  public:
+    SectorBlk() : ReplaceableEntry(), _tag(MaxAddr) {}
+    SectorBlk(const SectorBlk&) = delete;
+    SectorBlk& operator=(const SectorBlk&) = delete;
+    ~SectorBlk() {};
+
+    /** List of blocks associated to this sector. */
+    std::vector<SectorSubBlk*> blks;
+
+    /**
+     * Checks that a sector block is valid.
+     *
+     * @return True if any of the blocks in the sector is valid.
+     */
+    bool isValid() const;
+
+    /**
+     * Checks that a sector block is secure. A single secure block suffices
+     * to imply that the whole sector is secure, as the insertion proccess
+     * asserts that different secure spaces can't coexist in the same sector.
+     *
+     * @return True if any of the blocks in the sector is secure.
+     */
+    bool isSecure() const;
+
+    /**
+     * Set tag associated to this block.
+     *
+     * @param The tag value.
+     */
+    void setTag(const Addr tag);
+
+    /**
+     * Get tag associated to this block.
+     *
+     * @return The tag value.
+     */
+    Addr getTag() const;
+};
+
+#endif //__MEM_CACHE_SECTOR_BLK_HH__
index 9758b566e44de8aa05983f731594bb88402926c5..136abac2cca8e90a035158f5f1121b1c9910d28d 100644 (file)
@@ -35,3 +35,4 @@ SimObject('Tags.py')
 Source('base.cc')
 Source('base_set_assoc.cc')
 Source('fa_lru.cc')
+Source('sector_tags.cc')
index 76cd8d6b963c02687a73c24f005138fc57f78a2a..8fdfdce610fca49e7e75e4fcbdbfd816c55925df 100644 (file)
@@ -67,12 +67,28 @@ class BaseTags(ClockedObject):
 class BaseSetAssoc(BaseTags):
     type = 'BaseSetAssoc'
     cxx_header = "mem/cache/tags/base_set_assoc.hh"
+
+    # Get the cache associativity
     assoc = Param.Int(Parent.assoc, "associativity")
 
     # Get replacement policy from the parent (cache)
     replacement_policy = Param.BaseReplacementPolicy(
         Parent.replacement_policy, "Replacement policy")
 
+class SectorTags(BaseTags):
+    type = 'SectorTags'
+    cxx_header = "mem/cache/tags/sector_tags.hh"
+
+    # Get the cache associativity
+    assoc = Param.Int(Parent.assoc, "associativity")
+
+    # Number of sub-sectors (data blocks) per sector
+    num_blocks_per_sector = Param.Int(1, "Number of sub-sectors 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/sector_tags.cc b/src/mem/cache/tags/sector_tags.cc
new file mode 100644 (file)
index 0000000..27e8982
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * 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 <memory>
+#include <string>
+
+#include "base/intmath.hh"
+#include "base/logging.hh"
+#include "base/types.hh"
+#include "debug/CacheRepl.hh"
+#include "mem/cache/base.hh"
+#include "mem/cache/replacement_policies/base.hh"
+
+SectorTags::SectorTags(const SectorTagsParams *p)
+    : BaseTags(p), assoc(p->assoc), allocAssoc(p->assoc),
+      sequentialAccess(p->sequential_access),
+      replacementPolicy(p->replacement_policy),
+      numBlocksPerSector(p->num_blocks_per_sector),
+      numSectors(numBlocks / p->num_blocks_per_sector),
+      numSets(numSectors / p->assoc),
+      blks(numBlocks), secBlks(numSectors), sets(numSets),
+      sectorShift(floorLog2(blkSize)),
+      setShift(sectorShift + floorLog2(numBlocksPerSector)),
+      tagShift(setShift + floorLog2(numSets)),
+      sectorMask(numBlocksPerSector - 1), setMask(numSets - 1)
+{
+    // Check parameters
+    fatal_if(blkSize < 4 || !isPowerOf2(blkSize),
+             "Block size must be at least 4 and a power of 2");
+    fatal_if(!isPowerOf2(numSets),
+             "# of sets must be non-zero and a power of 2");
+    fatal_if(!isPowerOf2(numBlocksPerSector),
+             "# of blocks per sector must be non-zero and a power of 2");
+    fatal_if(assoc <= 0, "associativity must be greater than zero");
+
+    // Initialize all sets
+    unsigned sec_blk_index = 0;   // index into sector blks array
+    unsigned blk_index = 0;       // index into blks array
+    for (unsigned i = 0; i < numSets; ++i) {
+        sets[i].resize(assoc);
+
+        // Initialize all sectors in this set
+        for (unsigned j = 0; j < assoc; ++j) {
+            // Select block within the set to be linked
+            SectorBlk*& sec_blk = sets[i][j];
+
+            // Locate next cache sector
+            sec_blk = &secBlks[sec_blk_index];
+
+            // Associate a replacement data entry to the sector
+            sec_blk->replacementData = replacementPolicy->instantiateEntry();
+
+            // Initialize all blocks in this sector
+            sec_blk->blks.resize(numBlocksPerSector);
+            for (unsigned k = 0; k < numBlocksPerSector; ++k){
+                // Select block within the set to be linked
+                SectorSubBlk*& blk = sec_blk->blks[k];
+
+                // Locate next cache block
+                blk = &blks[blk_index];
+
+                // Associate a data chunk to the block
+                blk->data = &dataBlks[blkSize*blk_index];
+
+                // Associate sector block to this block
+                blk->setSectorBlock(sec_blk);
+
+                // Associate the sector replacement data to this block
+                blk->replacementData = sec_blk->replacementData;
+
+                // Set its set, way and sector offset
+                blk->set = i;
+                blk->way = j;
+                blk->setSectorOffset(k);
+
+                // Update block index
+                ++blk_index;
+            }
+
+            // Update sector block index
+            ++sec_blk_index;
+        }
+    }
+}
+
+void
+SectorTags::invalidate(CacheBlk *blk)
+{
+    BaseTags::invalidate(blk);
+
+    // Get block's sector
+    SectorSubBlk* sub_blk = static_cast<SectorSubBlk*>(blk);
+    const SectorBlk* sector_blk = sub_blk->getSectorBlock();
+
+    // When a block in a sector is invalidated, it does not make the tag
+    // invalid automatically, as there might be other blocks in the sector
+    // using it. The tag is invalidated only when there is a single block
+    // in the sector.
+    if (!sector_blk->isValid()) {
+        // Decrease the number of tags in use
+        tagsInUse--;
+
+        // Invalidate replacement data, as we're invalidating the sector
+        replacementPolicy->invalidate(sector_blk->replacementData);
+    }
+}
+
+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*numBlocksPerSector;
+    }
+
+    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 number of references to accessed block
+        blk->refCount++;
+
+        // Get block's sector
+        SectorSubBlk* sub_blk = static_cast<SectorSubBlk*>(blk);
+        const SectorBlk* sector_blk = sub_blk->getSectorBlock();
+
+        // Update replacement data of accessed block, which is shared with
+        // the whole sector it belongs to
+        replacementPolicy->touch(sector_blk->replacementData);
+    } else {
+        // If a cache miss
+        lat = lookupLatency;
+    }
+
+    return blk;
+}
+
+const std::vector<SectorBlk*>
+SectorTags::getPossibleLocations(Addr addr) const
+{
+    return sets[extractSet(addr)];
+}
+
+void
+SectorTags::insertBlock(PacketPtr pkt, CacheBlk *blk)
+{
+    // Insert block
+    BaseTags::insertBlock(pkt, blk);
+
+    // Get block's sector
+    SectorSubBlk* sub_blk = static_cast<SectorSubBlk*>(blk);
+    const SectorBlk* sector_blk = sub_blk->getSectorBlock();
+
+    // When a block is inserted, the tag is only a newly used tag if the
+    // sector was not previously present in the cache.
+    // This assumes BaseTags::insertBlock does not set the valid bit.
+    if (sector_blk->isValid()) {
+        // An existing entry's replacement data is just updated
+        replacementPolicy->touch(sector_blk->replacementData);
+    } else {
+        // Increment tag counter
+        tagsInUse++;
+
+        // A new entry resets the replacement data
+        replacementPolicy->reset(sector_blk->replacementData);
+    }
+}
+
+CacheBlk*
+SectorTags::findBlock(Addr addr, bool is_secure) const
+{
+    // Extract sector tag
+    const Addr tag = extractTag(addr);
+
+    // The address can only be mapped to a specific location of a sector
+    // due to sectors being composed of contiguous-address entries
+    const Addr offset = extractSectorOffset(addr);
+
+    // Find all possible sector locations for the given address
+    const std::vector<SectorBlk*> locations = getPossibleLocations(addr);
+
+    // Search for block
+    for (const auto& sector : locations) {
+        auto blk = sector->blks[offset];
+        if (blk->getTag() == tag && blk->isValid() &&
+            blk->isSecure() == is_secure) {
+            return blk;
+        }
+    }
+
+    // Did not find block
+    return nullptr;
+}
+
+ReplaceableEntry*
+SectorTags::findBlockBySetAndWay(int set, int way) const
+{
+    return sets[set][way];
+}
+
+CacheBlk*
+SectorTags::findVictim(Addr addr, const bool is_secure,
+                       std::vector<CacheBlk*>& evict_blks) const
+{
+    // Get all possible locations of this sector
+    const std::vector<SectorBlk*> sector_locations =
+        getPossibleLocations(addr);
+
+    // Check if the sector this address belongs to has been allocated
+    Addr tag = extractTag(addr);
+    SectorBlk* victim_sector = nullptr;
+    for (const auto& sector : sector_locations){
+        if ((tag == sector->getTag()) && sector->isValid() &&
+            (is_secure == sector->isSecure())){
+            victim_sector = sector;
+            break;
+        }
+    }
+
+    // If the sector is not present
+    if (victim_sector == nullptr){
+        // Choose replacement victim from replacement candidates
+        victim_sector = static_cast<SectorBlk*>(replacementPolicy->getVictim(
+                          std::vector<ReplaceableEntry*>(
+                          sector_locations.begin(), sector_locations.end())));
+    }
+
+    // Get the location of the victim block within the sector
+    CacheBlk* victim = victim_sector->blks[extractSectorOffset(addr)];
+
+    // Get evicted blocks. Blocks are only evicted if the sectors mismatch and
+    // the currently existing sector is valid.
+    if ((tag == victim_sector->getTag()) &&
+        (is_secure == victim_sector->isSecure())){
+        // It would be a hit if victim was valid, and upgrades do not call
+        // findVictim, so it cannot happen
+        assert(!victim->isValid());
+    } else {
+        // The whole sector must be evicted to make room for the new sector
+        for (const auto& blk : victim_sector->blks){
+            evict_blks.push_back(blk);
+        }
+    }
+
+    SectorSubBlk* victim_cast = static_cast<SectorSubBlk*>(victim);
+    DPRINTF(CacheRepl, "set %x, way %x, sector offset %x: %s\n",
+            "selecting blk for replacement\n", victim->set, victim->way,
+            victim_cast->getSectorOffset());
+
+    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
+{
+    const SectorSubBlk* blk_cast = static_cast<const SectorSubBlk*>(blk);
+    return ((blk_cast->getTag() << tagShift) | ((Addr)blk->set << setShift) |
+            ((Addr)blk_cast->getSectorOffset() << sectorShift));
+}
+
+void
+SectorTags::forEachBlk(std::function<void(CacheBlk &)> visitor)
+{
+    for (SectorSubBlk& blk : blks) {
+        visitor(blk);
+    }
+}
+
+bool
+SectorTags::anyBlk(std::function<bool(CacheBlk &)> visitor)
+{
+    for (SectorSubBlk& blk : blks) {
+        if (visitor(blk)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+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 (file)
index 0000000..3fc8ae4
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * 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 <string>
+#include <vector>
+
+#include "mem/cache/sector_blk.hh"
+#include "mem/cache/tags/base.hh"
+#include "mem/packet.hh"
+#include "params/SectorTags.hh"
+
+class BaseReplacementPolicy;
+
+/**
+ * A SectorTags cache tag store.
+ * @sa  \ref gem5MemorySystem "gem5 Memory System"
+ *
+ * The SectorTags placement policy divides the cache into s sectors of w
+ * consecutive sectors (ways). Each sector then consists of a number of
+ * sequential cache lines that may or may not be present.
+ */
+class SectorTags : public BaseTags
+{
+  protected:
+    /** Typedef the set type used in this tag store. */
+    typedef std::vector<SectorBlk*> SetType;
+
+    /** The associativity of the cache. */
+    const unsigned assoc;
+    /** The allocatable associativity of the cache (alloc mask). */
+    unsigned allocAssoc;
+
+    /** Whether tags and data are accessed sequentially. */
+    const bool sequentialAccess;
+
+    /** Replacement policy */
+    BaseReplacementPolicy *replacementPolicy;
+
+    /** Number of data blocks per sector. */
+    const unsigned numBlocksPerSector;
+
+    /** The number of sectors in the cache. */
+    const unsigned numSectors;
+    /** The number of sets in the cache. */
+    const unsigned numSets;
+
+    /** The cache blocks. */
+    std::vector<SectorSubBlk> blks;
+    /** The cache sector blocks. */
+    std::vector<SectorBlk> secBlks;
+    /** The cache sets. */
+    std::vector<SetType> sets;
+
+    // Organization of an address: Tag | Set # | Sector Offset # | Offset #
+    /** The amount to shift the address to get the sector tag. */
+    const int sectorShift;
+    /** The amount to shift the address to get the set. */
+    const int setShift;
+    /** The amount to shift the address to get the tag. */
+    const int tagShift;
+
+    /** Mask out all bits that aren't part of the sector tag. */
+    const unsigned sectorMask;
+    /** Mask out all bits that aren't part of the set index. */
+    const unsigned setMask;
+
+  public:
+    /** Convenience typedef. */
+     typedef SectorTagsParams Params;
+
+    /**
+     * Construct and initialize this tag store.
+     */
+    SectorTags(const Params *p);
+
+    /**
+     * Destructor.
+     */
+    virtual ~SectorTags() {};
+
+    /**
+     * This function updates the tags when a block is invalidated but does
+     * not invalidate the block itself. It also updates the replacement data.
+     *
+     * @param blk The block to invalidate.
+     */
+    void invalidate(CacheBlk *blk) 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;
+
+    /**
+     * 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 sector 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.
+     */
+    virtual const std::vector<SectorBlk*> getPossibleLocations(Addr addr)
+                                                                   const;
+
+    /**
+     * Insert the new block into the cache and update replacement data.
+     *
+     * @param pkt Packet holding the address to update
+     * @param blk The block to update.
+     */
+    void insertBlock(PacketPtr pkt, CacheBlk *blk) 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.
+     * @return Pointer to the cache block if found.
+     */
+    CacheBlk* findBlock(Addr addr, bool is_secure) const override;
+
+    /**
+     * Find a sector block given set and way.
+     *
+     * @param set The set of the block.
+     * @param way The way of the block.
+     * @return The block.
+     */
+    ReplaceableEntry* findBlockBySetAndWay(int set, int way) const override;
+
+    /**
+     * Find replacement victim based on address.
+     *
+     * @param addr Address to find a victim for.
+     * @param is_secure True if the target memory space is secure.
+     * @param evict_blks Cache blocks to be evicted.
+     * @return Cache block to be replaced.
+     */
+    CacheBlk* findVictim(Addr addr, const bool is_secure,
+                         std::vector<CacheBlk*>& evict_blks) const 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;
+
+    /**
+     * 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;
+
+    /**
+     * Regenerate the block address from the tag and set.
+     *
+     * @param block The block.
+     * @return the block address.
+     */
+    Addr regenerateBlkAddr(const CacheBlk* blk) const override;
+
+    /**
+     * Visit each sub-block in the tags and apply a visitor.
+     *
+     * The visitor should be a std::function that takes a cache block.
+     * reference as its parameter.
+     *
+     * @param visitor Visitor to call on each block.
+     */
+    void forEachBlk(std::function<void(CacheBlk &)> visitor) override;
+
+    /**
+     * Find if any of the sub-blocks satisfies a condition.
+     *
+     * The visitor should be a std::function that takes a cache block
+     * reference as its parameter. The visitor will terminate the
+     * traversal early if the condition is satisfied.
+     *
+     * @param visitor Visitor to call on each block.
+     */
+    bool anyBlk(std::function<bool(CacheBlk &)> visitor) override;
+};
+
+#endif //__MEM_CACHE_TAGS_SECTOR_TAGS_HH__