diff -r b25ca3acdefb -r 69b4e4d3876f src/mem/cache/base.hh --- a/src/mem/cache/base.hh Wed Feb 24 09:24:18 2016 +0000 +++ b/src/mem/cache/base.hh Wed Feb 24 09:24:28 2016 +0000 @@ -40,6 +40,7 @@ * Authors: Erik Hallnor * Steve Reinhardt * Ron Dreslinski + * Andreas Hansson */ /** @@ -50,26 +51,21 @@ #ifndef __MEM_CACHE_BASE_HH__ #define __MEM_CACHE_BASE_HH__ -#include -#include -#include -#include +#include #include "base/misc.hh" #include "base/statistics.hh" #include "base/trace.hh" -#include "base/types.hh" #include "debug/Cache.hh" #include "debug/CachePort.hh" +#include "mem/cache/blk.hh" #include "mem/cache/mshr_queue.hh" +#include "mem/cache/tags/base.hh" #include "mem/cache/write_queue.hh" #include "mem/mem_object.hh" -#include "mem/packet.hh" #include "mem/qport.hh" -#include "mem/request.hh" #include "params/BaseCache.hh" #include "sim/eventq.hh" -#include "sim/full_system.hh" #include "sim/sim_exit.hh" #include "sim/system.hh" @@ -193,6 +189,20 @@ /** Write/writeback buffer */ WriteQueue writeBuffer; + /** Tag and data Storage */ + BaseTags *tags; + + /** Prefetcher */ + BasePrefetcher *prefetcher; + + /** + * Notify the prefetcher on every access, not just misses. + */ + const bool prefetchOnAccess; + + /** Temporary cache block for occasional transitory use */ + CacheBlk *tempBlock; + /** * Mark a request as in service (sent downstream in the memory * system), effectively making this MSHR the ordering point. @@ -227,9 +237,29 @@ virtual bool allocOnFill(MemCmd cmd) const = 0; /** + *Handle doing the Compare and Swap function for SPARC. + */ + void cmpAndSwap(CacheBlk *blk, PacketPtr pkt); + + /** + * Return the next queue entry to service, either a pending miss + * from the MSHR queue, a buffered write from the write buffer, or + * something from the prefetcher. This function is responsible + * for prioritizing among those sources on the fly. + */ + std::tuple getNextQueueEntry(); + + /** + * Invalidate a cache block. + * + * @param blk Block to invalidate + */ + void invalidateBlock(CacheBlk *blk); + + /** * Write back dirty blocks in the cache using functional accesses. */ - virtual void memWriteback() = 0; + void memWriteback() override; /** * Invalidates all blocks in the cache. * @@ -237,13 +267,13 @@ * memory. Make sure to call functionalWriteback() first if you * want the to write them to memory. */ - virtual void memInvalidate() = 0; + void memInvalidate() override; /** * Determine if there are any dirty blocks in the cache. * * \return true if at least one block is dirty, false otherwise. */ - virtual bool isDirty() const = 0; + bool isDirty() const; /** * Determine if an address is in the ranges covered by this @@ -255,6 +285,11 @@ */ bool inRange(Addr addr) const; + /** + * Find next request ready time from among possible sources. + */ + Tick nextQueueReadyTime() const; + /** Block size of this cache */ const unsigned blkSize; @@ -463,18 +498,18 @@ /** * Register stats for this object. */ - virtual void regStats(); + void regStats() override; public: BaseCache(const BaseCacheParams *p, unsigned blk_size); - ~BaseCache() {} + ~BaseCache(); - virtual void init(); + void init() override; - virtual BaseMasterPort &getMasterPort(const std::string &if_name, - PortID idx = InvalidPortID); - virtual BaseSlavePort &getSlavePort(const std::string &if_name, - PortID idx = InvalidPortID); + BaseMasterPort &getMasterPort(const std::string &if_name, + PortID idx = InvalidPortID) override; + BaseSlavePort &getSlavePort(const std::string &if_name, + PortID idx = InvalidPortID) override; /** * Query block size of a cache. @@ -590,9 +625,13 @@ memSidePort->schedSendEvent(time); } - virtual bool inCache(Addr addr, bool is_secure) const = 0; + bool inCache(Addr addr, bool is_secure) const { + return (tags->findBlock(addr, is_secure) != 0); + } - virtual bool inMissQueue(Addr addr, bool is_secure) const = 0; + bool inMissQueue(Addr addr, bool is_secure) const { + return (mshrQueue.findMatch(addr, is_secure) != 0); + } void incMissCount(PacketPtr pkt) { @@ -612,6 +651,86 @@ } + /** + * Cache block visitor that writes back dirty cache blocks using + * functional writes. + * + * \return Always returns true. + */ + bool writebackVisitor(CacheBlk &blk); + /** + * Cache block visitor that invalidates all blocks in the cache. + * + * @warn Dirty cache lines will not be written back to memory. + * + * \return Always returns true. + */ + bool invalidateVisitor(CacheBlk &blk); + + /** serialize the state of the caches + * We currently don't support checkpointing cache state, so this panics. + */ + void serialize(CheckpointOut &cp) const override; + void unserialize(CheckpointIn &cp) override; + +}; + +/** + * Wrap a method and present it as a cache block visitor. + * + * For example the forEachBlk method in the tag arrays expects a + * callable object/function as their parameter. This class wraps a + * method in an object and presents callable object that adheres to + * the cache block visitor protocol. + */ +class CacheBlkVisitorWrapper : public CacheBlkVisitor +{ + public: + typedef bool (BaseCache::*VisitorPtr)(CacheBlk &blk); + + CacheBlkVisitorWrapper(BaseCache &_cache, VisitorPtr _visitor) + : cache(_cache), visitor(_visitor) {} + + bool operator()(CacheBlk &blk) override { + return (cache.*visitor)(blk); + } + + private: + BaseCache &cache; + VisitorPtr visitor; +}; + +/** + * Cache block visitor that determines if there are dirty blocks in a + * cache. + * + * Use with the forEachBlk method in the tag array to determine if the + * array contains dirty blocks. + */ +class CacheBlkIsDirtyVisitor : public CacheBlkVisitor +{ + public: + CacheBlkIsDirtyVisitor() + : _isDirty(false) {} + + bool operator()(CacheBlk &blk) override { + if (blk.isDirty()) { + _isDirty = true; + return false; + } else { + return true; + } + } + + /** + * Does the array contain a dirty line? + * + * \return true if yes, false otherwise. + */ + bool isDirty() const { return _isDirty; }; + + private: + bool _isDirty; }; #endif //__MEM_CACHE_BASE_HH__ diff -r b25ca3acdefb -r 69b4e4d3876f src/mem/cache/base.cc --- a/src/mem/cache/base.cc Wed Feb 24 09:24:18 2016 +0000 +++ b/src/mem/cache/base.cc Wed Feb 24 09:24:28 2016 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 ARM Limited + * Copyright (c) 2012-2013, 2016 ARM Limited * All rights reserved. * * The license below extends only to copyright in the software and shall @@ -45,15 +45,12 @@ * Definition of BaseCache functions. */ +#include "mem/cache/base.hh" + #include "debug/Cache.hh" #include "debug/Drain.hh" -#include "mem/cache/tags/fa_lru.hh" -#include "mem/cache/tags/lru.hh" -#include "mem/cache/tags/random_repl.hh" -#include "mem/cache/base.hh" -#include "mem/cache/cache.hh" #include "mem/cache/mshr.hh" -#include "sim/full_system.hh" +#include "mem/cache/prefetch/base.hh" using namespace std; @@ -70,6 +67,9 @@ cpuSidePort(nullptr), memSidePort(nullptr), mshrQueue("MSHRs", p->mshrs, 1, p->demand_mshr_reserve), writeBuffer("write buffer", p->write_buffers, p->mshrs + 1), + tags(p->tags), + prefetcher(p->prefetcher), + prefetchOnAccess(p->prefetch_on_access), blkSize(blk_size), lookupLatency(p->hit_latency), forwardLatency(p->hit_latency), @@ -93,6 +93,19 @@ // forward snoops is overridden in init() once we can query // whether the connected master is actually snooping or not + + tempBlock = new CacheBlk(); + tempBlock->data = new uint8_t[blkSize]; + + tags->setCache(this); + if (prefetcher) + prefetcher->setCache(this); +} + +BaseCache::~BaseCache() +{ + delete [] tempBlock->data; + delete tempBlock; } void @@ -173,6 +186,250 @@ } void +BaseCache::cmpAndSwap(CacheBlk *blk, PacketPtr pkt) +{ + assert(pkt->isRequest()); + + uint64_t overwrite_val; + bool overwrite_mem; + uint64_t condition_val64; + uint32_t condition_val32; + + int offset = tags->extractBlkOffset(pkt->getAddr()); + uint8_t *blk_data = blk->data + offset; + + assert(sizeof(uint64_t) >= pkt->getSize()); + + overwrite_mem = true; + // keep a copy of our possible write value, and copy what is at the + // memory address into the packet + pkt->writeData((uint8_t *)&overwrite_val); + pkt->setData(blk_data); + + if (pkt->req->isCondSwap()) { + if (pkt->getSize() == sizeof(uint64_t)) { + condition_val64 = pkt->req->getExtraData(); + overwrite_mem = !std::memcmp(&condition_val64, blk_data, + sizeof(uint64_t)); + } else if (pkt->getSize() == sizeof(uint32_t)) { + condition_val32 = (uint32_t)pkt->req->getExtraData(); + overwrite_mem = !std::memcmp(&condition_val32, blk_data, + sizeof(uint32_t)); + } else + panic("Invalid size for conditional read/write\n"); + } + + if (overwrite_mem) { + std::memcpy(blk_data, &overwrite_val, pkt->getSize()); + blk->status |= BlkDirty; + } +} + +std::tuple +BaseCache::getNextQueueEntry() +{ + // Check both MSHR queue and write buffer for potential requests, + // note that null does not mean there is no request, it could + // simply be that it is not ready + MSHR *miss_mshr = mshrQueue.getNext(); + WriteQueueEntry *write_mshr = writeBuffer.getNext(); + + // If we got a write buffer request ready, first priority is a + // full write buffer (but ony if we have no uncacheable write + // responses outstanding, possibly revisit this last part), + // otherwhise we favour the miss requests + if (write_mshr && + ((writeBuffer.isFull() && writeBuffer.numInService() == 0) || + !miss_mshr)) { + // need to search MSHR queue for conflicting earlier miss. + MSHR *conflict_mshr = + mshrQueue.findPending(write_mshr->blkAddr, + write_mshr->isSecure); + + if (conflict_mshr && conflict_mshr->order < write_mshr->order) { + // Service misses in order until conflict is cleared. + return std::make_tuple(conflict_mshr, nullptr); + + // @todo Note that we ignore the ready time of the conflict here + } + + // No conflicts; issue write + return std::make_tuple(nullptr, write_mshr); + } else if (miss_mshr) { + // need to check for conflicting earlier writeback + WriteQueueEntry *conflict_mshr = + writeBuffer.findPending(miss_mshr->blkAddr, + miss_mshr->isSecure); + if (conflict_mshr) { + // not sure why we don't check order here... it was in the + // original code but commented out. + + // The only way this happens is if we are + // doing a write and we didn't have permissions + // then subsequently saw a writeback (owned got evicted) + // We need to make sure to perform the writeback first + // To preserve the dirty data, then we can issue the write + + // should we return write_mshr here instead? I.e. do we + // have to flush writes in order? I don't think so... not + // for Alpha anyway. Maybe for x86? + return std::make_tuple(nullptr, conflict_mshr); + + // @todo Note that we ignore the ready time of the conflict here + } + + // No conflicts; issue read + return std::make_tuple(miss_mshr, nullptr); + } + + // fall through... no pending requests. Try a prefetch. + assert(!miss_mshr && !write_mshr); + if (prefetcher && mshrQueue.canPrefetch()) { + // If we have a miss queue slot, we can try a prefetch + PacketPtr pkt = prefetcher->getPacket(); + if (pkt) { + Addr pf_addr = blockAlign(pkt->getAddr()); + if (!tags->findBlock(pf_addr, pkt->isSecure()) && + !mshrQueue.findMatch(pf_addr, pkt->isSecure()) && + !writeBuffer.findMatch(pf_addr, pkt->isSecure())) { + // Update statistic on number of prefetches issued + // (hwpf_mshr_misses) + assert(pkt->req->masterId() < system->maxMasters()); + mshr_misses[pkt->cmdToIndex()][pkt->req->masterId()]++; + + // allocate an MSHR and return it, note + // that we send the packet straight away, so do not + // schedule the send + MSHR* pf_mshr = allocateMissBuffer(pkt, curTick(), false); + return std::make_tuple(pf_mshr, nullptr); + } else { + // free the request and packet + delete pkt->req; + delete pkt; + } + } + } + + return std::make_tuple(nullptr, nullptr); +} + +void +BaseCache::invalidateBlock(CacheBlk *blk) +{ + if (blk != tempBlock) + tags->invalidate(blk); + blk->invalidate(); +} + +void +BaseCache::memWriteback() +{ + CacheBlkVisitorWrapper visitor(*this, &BaseCache::writebackVisitor); + tags->forEachBlk(visitor); +} + +void +BaseCache::memInvalidate() +{ + CacheBlkVisitorWrapper visitor(*this, &BaseCache::invalidateVisitor); + tags->forEachBlk(visitor); +} + +bool +BaseCache::isDirty() const +{ + CacheBlkIsDirtyVisitor visitor; + tags->forEachBlk(visitor); + + return visitor.isDirty(); +} + +bool +BaseCache::writebackVisitor(CacheBlk &blk) +{ + if (blk.isDirty()) { + assert(blk.isValid()); + + Request request(tags->regenerateBlkAddr(blk.tag, blk.set), + blkSize, 0, Request::funcMasterId); + request.taskId(blk.task_id); + + Packet packet(&request, MemCmd::WriteReq); + packet.dataStatic(blk.data); + + memSidePort->sendFunctional(&packet); + + blk.status &= ~BlkDirty; + } + + return true; +} + +bool +BaseCache::invalidateVisitor(CacheBlk &blk) +{ + if (blk.isDirty()) + warn_once("Invalidating dirty cache lines. " \ + "Expect things to break.\n"); + + if (blk.isValid()) { + assert(!blk.isDirty()); + tags->invalidate(&blk); + blk.invalidate(); + } + + return true; +} + +Tick +BaseCache::nextQueueReadyTime() const +{ + Tick nextReady = std::min(mshrQueue.nextReadyTime(), + writeBuffer.nextReadyTime()); + + // Don't signal prefetch ready time if no MSHRs available + // Will signal once enoguh MSHRs are deallocated + if (prefetcher && mshrQueue.canPrefetch()) { + nextReady = std::min(nextReady, + prefetcher->nextPrefetchReadyTime()); + } + + return nextReady; +} + +void +BaseCache::serialize(CheckpointOut &cp) const +{ + bool dirty(isDirty()); + + if (dirty) { + warn("*** The cache still contains dirty data. ***\n"); + warn(" Make sure to drain the system using the correct flags.\n"); + warn(" This checkpoint will not restore correctly " \ + "and dirty data in the cache will be lost!\n"); + } + + // Since we don't checkpoint the data in the cache, any dirty data + // will be lost when restoring from a checkpoint of a system that + // wasn't drained properly. Flag the checkpoint as invalid if the + // cache contains dirty data. + bool bad_checkpoint(dirty); + SERIALIZE_SCALAR(bad_checkpoint); +} + +void +BaseCache::unserialize(CheckpointIn &cp) +{ + bool bad_checkpoint; + UNSERIALIZE_SCALAR(bad_checkpoint); + if (bad_checkpoint) { + fatal("Restoring from checkpoints with dirty caches is not " + "supported in the classic memory system. Please remove any " + "caches or drain them properly before taking checkpoints.\n"); + } +} + +void BaseCache::regStats() { using namespace Stats; diff -r b25ca3acdefb -r 69b4e4d3876f src/mem/cache/cache.hh --- a/src/mem/cache/cache.hh Wed Feb 24 09:24:18 2016 +0000 +++ b/src/mem/cache/cache.hh Wed Feb 24 09:24:28 2016 +0000 @@ -46,38 +46,21 @@ /** * @file - * Describes a cache based on template policies. + * Describes a cache */ #ifndef __MEM_CACHE_CACHE_HH__ #define __MEM_CACHE_CACHE_HH__ -#include - -#include "base/misc.hh" // fatal, panic, and warn #include "enums/Clusivity.hh" #include "mem/cache/base.hh" -#include "mem/cache/blk.hh" -#include "mem/cache/mshr.hh" -#include "mem/cache/tags/base.hh" #include "params/Cache.hh" -#include "sim/eventq.hh" - -//Forward decleration -class BasePrefetcher; /** - * A template-policy based cache. The behavior of the cache can be altered by - * supplying different template policies. TagStore handles all tag and data - * storage @sa TagStore, \ref gem5MemorySystem "gem5 Memory System" + * A coherent cache that can be arranged in flexible topologies. */ class Cache : public BaseCache { - public: - - /** A typedef for a list of CacheBlk pointers. */ - typedef std::list BlkList; - protected: /** @@ -173,15 +156,6 @@ const std::string &_label); }; - /** Tag and data Storage */ - BaseTags *tags; - - /** Prefetcher */ - BasePrefetcher *prefetcher; - - /** Temporary cache block for occasional transitory use */ - CacheBlk *tempBlock; - /** * This cache should allocate a block on a line-sized write miss. */ @@ -192,11 +166,6 @@ */ void promoteWholeLineWrites(PacketPtr pkt); - /** - * Notify the prefetcher on every access, not just misses. - */ - const bool prefetchOnAccess; - /** * Clusivity with respect to the upstream cache, determining if we * fill into both this cache and the cache above on a miss. Note @@ -267,11 +236,6 @@ Cycles &lat, PacketList &writebacks); /** - *Handle doing the Compare and Swap function for SPARC. - */ - void cmpAndSwap(CacheBlk *blk, PacketPtr pkt); - - /** * Find a block frame for new block at address addr targeting the * given security space, assuming that the block is not currently * in the cache. Append writebacks if any to provided packet @@ -281,13 +245,6 @@ CacheBlk *allocateBlock(Addr addr, bool is_secure, PacketList &writebacks); /** - * Invalidate a cache block. - * - * @param blk Block to invalidate - */ - void invalidateBlock(CacheBlk *blk); - - /** * Populates a cache block and handles all outstanding requests for the * satisfied fill request. This version takes two memory requests. One * contains the fill data, the other is an optional target to satisfy. @@ -423,27 +380,6 @@ */ PacketPtr cleanEvictBlk(CacheBlk *blk); - - void memWriteback() override; - void memInvalidate() override; - bool isDirty() const override; - - /** - * Cache block visitor that writes back dirty cache blocks using - * functional writes. - * - * \return Always returns true. - */ - bool writebackVisitor(CacheBlk &blk); - /** - * Cache block visitor that invalidates all blocks in the cache. - * - * @warn Dirty cache lines will not be written back to memory. - * - * \return Always returns true. - */ - bool invalidateVisitor(CacheBlk &blk); - /** * Generate an appropriate downstream bus request packet for the * given parameters. @@ -459,14 +395,6 @@ bool needsExclusive) const; /** - * Return the next queue entry to service, either a pending miss - * from the MSHR queue, a buffered write from the write buffer, or - * something from the prefetcher. This function is responsible - * for prioritizing among those sources on the fly. - */ - std::tuple getNextQueueEntry(); - - /** * Send up a snoop request and find cached copies. If cached copies are * found, set the BLOCK_CACHED flag in pkt. */ @@ -483,31 +411,6 @@ */ std::tuple getTimingPacket(); - /** - * Return whether there are any outstanding misses. - */ - bool outstandingMisses() const - { - return !mshrQueue.isEmpty(); - } - - CacheBlk *findBlock(Addr addr, bool is_secure) const { - return tags->findBlock(addr, is_secure); - } - - bool inCache(Addr addr, bool is_secure) const override { - return (tags->findBlock(addr, is_secure) != 0); - } - - bool inMissQueue(Addr addr, bool is_secure) const override { - return (mshrQueue.findMatch(addr, is_secure) != 0); - } - - /** - * Find next request ready time from among possible sources. - */ - Tick nextQueueReadyTime() const; - public: /** Instantiates a basic cache object. */ Cache(const CacheParams *p); @@ -515,71 +418,6 @@ /** Non-default destructor is needed to deallocate memory. */ virtual ~Cache(); - void regStats() override; - - /** serialize the state of the caches - * We currently don't support checkpointing cache state, so this panics. - */ - void serialize(CheckpointOut &cp) const override; - void unserialize(CheckpointIn &cp) override; -}; - -/** - * Wrap a method and present it as a cache block visitor. - * - * For example the forEachBlk method in the tag arrays expects a - * callable object/function as their parameter. This class wraps a - * method in an object and presents callable object that adheres to - * the cache block visitor protocol. - */ -class CacheBlkVisitorWrapper : public CacheBlkVisitor -{ - public: - typedef bool (Cache::*VisitorPtr)(CacheBlk &blk); - - CacheBlkVisitorWrapper(Cache &_cache, VisitorPtr _visitor) - : cache(_cache), visitor(_visitor) {} - - bool operator()(CacheBlk &blk) override { - return (cache.*visitor)(blk); - } - - private: - Cache &cache; - VisitorPtr visitor; -}; - -/** - * Cache block visitor that determines if there are dirty blocks in a - * cache. - * - * Use with the forEachBlk method in the tag array to determine if the - * array contains dirty blocks. - */ -class CacheBlkIsDirtyVisitor : public CacheBlkVisitor -{ - public: - CacheBlkIsDirtyVisitor() - : _isDirty(false) {} - - bool operator()(CacheBlk &blk) override { - if (blk.isDirty()) { - _isDirty = true; - return false; - } else { - return true; - } - } - - /** - * Does the array contain a dirty line? - * - * \return true if yes, false otherwise. - */ - bool isDirty() const { return _isDirty; }; - - private: - bool _isDirty; }; #endif // __MEM_CACHE_CACHE_HH__ diff -r b25ca3acdefb -r 69b4e4d3876f src/mem/cache/cache.cc --- a/src/mem/cache/cache.cc Wed Feb 24 09:24:18 2016 +0000 +++ b/src/mem/cache/cache.cc Wed Feb 24 09:24:28 2016 +0000 @@ -66,86 +66,26 @@ Cache::Cache(const CacheParams *p) : BaseCache(p, p->system->cacheLineSize()), - tags(p->tags), - prefetcher(p->prefetcher), doFastWrites(true), - prefetchOnAccess(p->prefetch_on_access), clusivity(p->clusivity), writebackClean(p->writeback_clean), tempBlockWriteback(nullptr), writebackTempBlockAtomicEvent(this, false, EventBase::Delayed_Writeback_Pri) { - tempBlock = new CacheBlk(); - tempBlock->data = new uint8_t[blkSize]; - cpuSidePort = new CpuSidePort(p->name + ".cpu_side", this, "CpuSidePort"); memSidePort = new MemSidePort(p->name + ".mem_side", this, "MemSidePort"); - - tags->setCache(this); - if (prefetcher) - prefetcher->setCache(this); } Cache::~Cache() { - delete [] tempBlock->data; - delete tempBlock; - delete cpuSidePort; delete memSidePort; } void -Cache::regStats() -{ - BaseCache::regStats(); -} - -void -Cache::cmpAndSwap(CacheBlk *blk, PacketPtr pkt) -{ - assert(pkt->isRequest()); - - uint64_t overwrite_val; - bool overwrite_mem; - uint64_t condition_val64; - uint32_t condition_val32; - - int offset = tags->extractBlkOffset(pkt->getAddr()); - uint8_t *blk_data = blk->data + offset; - - assert(sizeof(uint64_t) >= pkt->getSize()); - - overwrite_mem = true; - // keep a copy of our possible write value, and copy what is at the - // memory address into the packet - pkt->writeData((uint8_t *)&overwrite_val); - pkt->setData(blk_data); - - if (pkt->req->isCondSwap()) { - if (pkt->getSize() == sizeof(uint64_t)) { - condition_val64 = pkt->req->getExtraData(); - overwrite_mem = !std::memcmp(&condition_val64, blk_data, - sizeof(uint64_t)); - } else if (pkt->getSize() == sizeof(uint32_t)) { - condition_val32 = (uint32_t)pkt->req->getExtraData(); - overwrite_mem = !std::memcmp(&condition_val32, blk_data, - sizeof(uint32_t)); - } else - panic("Invalid size for conditional read/write\n"); - } - - if (overwrite_mem) { - std::memcpy(blk_data, &overwrite_val, pkt->getSize()); - blk->status |= BlkDirty; - } -} - - -void Cache::satisfyCpuSideRequest(PacketPtr pkt, CacheBlk *blk, bool deferred_response, bool pending_downgrade) { @@ -1622,66 +1562,6 @@ return pkt; } -void -Cache::memWriteback() -{ - CacheBlkVisitorWrapper visitor(*this, &Cache::writebackVisitor); - tags->forEachBlk(visitor); -} - -void -Cache::memInvalidate() -{ - CacheBlkVisitorWrapper visitor(*this, &Cache::invalidateVisitor); - tags->forEachBlk(visitor); -} - -bool -Cache::isDirty() const -{ - CacheBlkIsDirtyVisitor visitor; - tags->forEachBlk(visitor); - - return visitor.isDirty(); -} - -bool -Cache::writebackVisitor(CacheBlk &blk) -{ - if (blk.isDirty()) { - assert(blk.isValid()); - - Request request(tags->regenerateBlkAddr(blk.tag, blk.set), - blkSize, 0, Request::funcMasterId); - request.taskId(blk.task_id); - - Packet packet(&request, MemCmd::WriteReq); - packet.dataStatic(blk.data); - - memSidePort->sendFunctional(&packet); - - blk.status &= ~BlkDirty; - } - - return true; -} - -bool -Cache::invalidateVisitor(CacheBlk &blk) -{ - - if (blk.isDirty()) - warn_once("Invalidating dirty cache lines. Expect things to break.\n"); - - if (blk.isValid()) { - assert(!blk.isDirty()); - tags->invalidate(&blk); - blk.invalidate(); - } - - return true; -} - CacheBlk* Cache::allocateBlock(Addr addr, bool is_secure, PacketList &writebacks) { @@ -1722,14 +1602,6 @@ return blk; } -void -Cache::invalidateBlock(CacheBlk *blk) -{ - if (blk != tempBlock) - tags->invalidate(blk); - blk->invalidate(); -} - // Note that the reason we return a list of writebacks rather than // inserting them directly in the write buffer is that this function // is called by both atomic and timing-mode accesses, and in atomic @@ -2233,94 +2105,6 @@ } -std::tuple -Cache::getNextQueueEntry() -{ - // Check both MSHR queue and write buffer for potential requests, - // note that null does not mean there is no request, it could - // simply be that it is not ready - MSHR *miss_mshr = mshrQueue.getNext(); - WriteQueueEntry *write_mshr = writeBuffer.getNext(); - - // If we got a write buffer request ready, first priority is a - // full write buffer (but only if we have no uncacheable write - // responses outstanding, possibly revisit this last part), - // otherwhise we favour the miss requests - if (write_mshr && - ((writeBuffer.isFull() && writeBuffer.numInService() == 0) || - !miss_mshr)) { - // need to search MSHR queue for conflicting earlier miss. - MSHR *conflict_mshr = - mshrQueue.findPending(write_mshr->blkAddr, - write_mshr->isSecure); - - if (conflict_mshr && conflict_mshr->order < write_mshr->order) { - // Service misses in order until conflict is cleared. - return std::make_tuple(conflict_mshr, nullptr); - - // @todo Note that we ignore the ready time of the conflict here - } - - // No conflicts; issue write - return std::make_tuple(nullptr, write_mshr); - } else if (miss_mshr) { - // need to check for conflicting earlier writeback - WriteQueueEntry *conflict_mshr = - writeBuffer.findPending(miss_mshr->blkAddr, - miss_mshr->isSecure); - if (conflict_mshr) { - // not sure why we don't check order here... it was in the - // original code but commented out. - - // The only way this happens is if we are - // doing a write and we didn't have permissions - // then subsequently saw a writeback (owned got evicted) - // We need to make sure to perform the writeback first - // To preserve the dirty data, then we can issue the write - - // should we return write_mshr here instead? I.e. do we - // have to flush writes in order? I don't think so... not - // for Alpha anyway. Maybe for x86? - return std::make_tuple(nullptr, conflict_mshr); - - // @todo Note that we ignore the ready time of the conflict here - } - - // No conflicts; issue read - return std::make_tuple(miss_mshr, nullptr); - } - - // fall through... no pending requests. Try a prefetch. - assert(!miss_mshr && !write_mshr); - if (prefetcher && mshrQueue.canPrefetch()) { - // If we have a miss queue slot, we can try a prefetch - PacketPtr pkt = prefetcher->getPacket(); - if (pkt) { - Addr pf_addr = blockAlign(pkt->getAddr()); - if (!tags->findBlock(pf_addr, pkt->isSecure()) && - !mshrQueue.findMatch(pf_addr, pkt->isSecure()) && - !writeBuffer.findMatch(pf_addr, pkt->isSecure())) { - // Update statistic on number of prefetches issued - // (hwpf_mshr_misses) - assert(pkt->req->masterId() < system->maxMasters()); - mshr_misses[pkt->cmdToIndex()][pkt->req->masterId()]++; - - // allocate an MSHR and return it, note - // that we send the packet straight away, so do not - // schedule the send - MSHR* pf_mshr = allocateMissBuffer(pkt, curTick(), false); - return std::make_tuple(pf_mshr, nullptr); - } else { - // free the request and packet - delete pkt->req; - delete pkt; - } - } - } - - return std::make_tuple(nullptr, nullptr); -} - bool Cache::isCachedAbove(PacketPtr pkt, bool is_timing) const { @@ -2485,54 +2269,6 @@ return std::make_tuple(pkt, mshr, wq_entry); } -Tick -Cache::nextQueueReadyTime() const -{ - Tick nextReady = std::min(mshrQueue.nextReadyTime(), - writeBuffer.nextReadyTime()); - - // Don't signal prefetch ready time if no MSHRs available - // Will signal once enoguh MSHRs are deallocated - if (prefetcher && mshrQueue.canPrefetch()) { - nextReady = std::min(nextReady, - prefetcher->nextPrefetchReadyTime()); - } - - return nextReady; -} - -void -Cache::serialize(CheckpointOut &cp) const -{ - bool dirty(isDirty()); - - if (dirty) { - warn("*** The cache still contains dirty data. ***\n"); - warn(" Make sure to drain the system using the correct flags.\n"); - warn(" This checkpoint will not restore correctly and dirty data in " - "the cache will be lost!\n"); - } - - // Since we don't checkpoint the data in the cache, any dirty data - // will be lost when restoring from a checkpoint of a system that - // wasn't drained properly. Flag the checkpoint as invalid if the - // cache contains dirty data. - bool bad_checkpoint(dirty); - SERIALIZE_SCALAR(bad_checkpoint); -} - -void -Cache::unserialize(CheckpointIn &cp) -{ - bool bad_checkpoint; - UNSERIALIZE_SCALAR(bad_checkpoint); - if (bad_checkpoint) { - fatal("Restoring from checkpoints with dirty caches is not supported " - "in the classic memory system. Please remove any caches or " - " drain them properly before taking checkpoints.\n"); - } -} - /////////////// // // CpuSidePort