Source('mshr.cc')
Source('mshr_queue.cc')
Source('noncoherent_cache.cc')
+Source('sector_blk.cc')
Source('write_queue.cc')
Source('write_queue_entry.cc')
* @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
--- /dev/null
+/**
+ * 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;
+}
--- /dev/null
+/**
+ * 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__
Source('base.cc')
Source('base_set_assoc.cc')
Source('fa_lru.cc')
+Source('sector_tags.cc')
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'
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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__