From: Daniel R. Carvalho Date: Thu, 5 Apr 2018 09:54:39 +0000 (+0200) Subject: mem-cache: Create Sector Cache X-Git-Tag: v19.0.0.0~2067 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=5bb8643808e81412ef634c142a9a403032d9141f;p=gem5.git mem-cache: Create Sector Cache 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 Maintainer: Nikos Nikoleris --- diff --git a/src/mem/cache/SConscript b/src/mem/cache/SConscript index 244d61dc2..24eea960e 100644 --- a/src/mem/cache/SConscript +++ b/src/mem/cache/SConscript @@ -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') diff --git a/src/mem/cache/blk.hh b/src/mem/cache/blk.hh index 93189bd97..1b796608f 100644 --- a/src/mem/cache/blk.hh +++ b/src/mem/cache/blk.hh @@ -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 index 000000000..07d9e9543 --- /dev/null +++ b/src/mem/cache/sector_blk.cc @@ -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 + +#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 index 000000000..f8f8cd5e6 --- /dev/null +++ b/src/mem/cache/sector_blk.hh @@ -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 + +#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 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__ diff --git a/src/mem/cache/tags/SConscript b/src/mem/cache/tags/SConscript index 9758b566e..136abac2c 100644 --- a/src/mem/cache/tags/SConscript +++ b/src/mem/cache/tags/SConscript @@ -35,3 +35,4 @@ SimObject('Tags.py') 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 76cd8d6b9..8fdfdce61 100644 --- a/src/mem/cache/tags/Tags.py +++ b/src/mem/cache/tags/Tags.py @@ -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 index 000000000..27e89829d --- /dev/null +++ b/src/mem/cache/tags/sector_tags.cc @@ -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 +#include +#include + +#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(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(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 +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(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 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& evict_blks) const +{ + // Get all possible locations of this sector + const std::vector 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(replacementPolicy->getVictim( + std::vector( + 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(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(blk); + return ((blk_cast->getTag() << tagShift) | ((Addr)blk->set << setShift) | + ((Addr)blk_cast->getSectorOffset() << sectorShift)); +} + +void +SectorTags::forEachBlk(std::function visitor) +{ + for (SectorSubBlk& blk : blks) { + visitor(blk); + } +} + +bool +SectorTags::anyBlk(std::function 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 index 000000000..3fc8ae476 --- /dev/null +++ b/src/mem/cache/tags/sector_tags.hh @@ -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 +#include + +#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 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 blks; + /** The cache sector blocks. */ + std::vector secBlks; + /** The cache sets. */ + std::vector 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 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& 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 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 visitor) override; +}; + +#endif //__MEM_CACHE_TAGS_SECTOR_TAGS_HH__