diff options
Diffstat (limited to 'src/mem/cache/miss')
-rw-r--r-- | src/mem/cache/miss/SConscript | 3 | ||||
-rw-r--r-- | src/mem/cache/miss/blocking_buffer.cc | 245 | ||||
-rw-r--r-- | src/mem/cache/miss/blocking_buffer.hh | 209 | ||||
-rw-r--r-- | src/mem/cache/miss/miss_buffer.cc | 62 | ||||
-rw-r--r-- | src/mem/cache/miss/miss_buffer.hh | 223 | ||||
-rw-r--r-- | src/mem/cache/miss/miss_queue.cc | 752 | ||||
-rw-r--r-- | src/mem/cache/miss/miss_queue.hh | 327 | ||||
-rw-r--r-- | src/mem/cache/miss/mshr.cc | 308 | ||||
-rw-r--r-- | src/mem/cache/miss/mshr.hh | 152 | ||||
-rw-r--r-- | src/mem/cache/miss/mshr_queue.cc | 132 | ||||
-rw-r--r-- | src/mem/cache/miss/mshr_queue.hh | 151 |
11 files changed, 455 insertions, 2109 deletions
diff --git a/src/mem/cache/miss/SConscript b/src/mem/cache/miss/SConscript index 0f81a2570..376d670cd 100644 --- a/src/mem/cache/miss/SConscript +++ b/src/mem/cache/miss/SConscript @@ -30,8 +30,5 @@ Import('*') -Source('blocking_buffer.cc') -Source('miss_buffer.cc') -Source('miss_queue.cc') Source('mshr.cc') Source('mshr_queue.cc') diff --git a/src/mem/cache/miss/blocking_buffer.cc b/src/mem/cache/miss/blocking_buffer.cc deleted file mode 100644 index e8ff26880..000000000 --- a/src/mem/cache/miss/blocking_buffer.cc +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * 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: Erik Hallnor - */ - -/** - * @file - * Definitions of a simple buffer for a blocking cache. - */ -#include <cstring> - -#include "mem/cache/base_cache.hh" -#include "mem/cache/miss/blocking_buffer.hh" -#include "mem/cache/prefetch/base_prefetcher.hh" -#include "mem/request.hh" - -/** - * @todo Move writebacks into shared BaseBuffer class. - */ -void -BlockingBuffer::regStats(const std::string &name) -{ - MissBuffer::regStats(name); -} - - -void -BlockingBuffer::handleMiss(PacketPtr &pkt, int blk_size, Tick time) -{ - Addr blk_addr = pkt->getAddr() & ~(Addr)(blk_size - 1); - if (pkt->isWrite() && (pkt->req->isUncacheable() || !writeAllocate || - !pkt->needsResponse())) { - if (!pkt->needsResponse()) { - wb.allocateAsBuffer(pkt); - } else { - wb.allocate(pkt->cmd, blk_addr, blk_size, pkt); - } - - std::memcpy(wb.pkt->getPtr<uint8_t>(), pkt->getPtr<uint8_t>(), blk_size); - - cache->setBlocked(Blocked_NoWBBuffers); - cache->setMasterRequest(Request_WB, time); - return; - } - - if (!pkt->needsResponse()) { - miss.allocateAsBuffer(pkt); - } else { - miss.allocate(pkt->cmd, blk_addr, blk_size, pkt); - } - if (!pkt->req->isUncacheable()) { - miss.pkt->flags |= CACHE_LINE_FILL; - } - cache->setBlocked(Blocked_NoMSHRs); - cache->setMasterRequest(Request_MSHR, time); -} - -PacketPtr -BlockingBuffer::getPacket() -{ - if (miss.pkt && !miss.inService) { - return miss.pkt; - } - return wb.pkt; -} - -void -BlockingBuffer::setBusCmd(PacketPtr &pkt, MemCmd cmd) -{ - MSHR *mshr = (MSHR*) pkt->senderState; - mshr->originalCmd = pkt->cmd; - if (pkt->isCacheFill()) - pkt->cmdOverride(cmd); -} - -void -BlockingBuffer::restoreOrigCmd(PacketPtr &pkt) -{ - pkt->cmdOverride(((MSHR*)(pkt->senderState))->originalCmd); -} - -void -BlockingBuffer::markInService(PacketPtr &pkt, MSHR* mshr) -{ - if (!pkt->isCacheFill() && pkt->isWrite()) { - // Forwarding a write/ writeback, don't need to change - // the command - assert(mshr == &wb); - cache->clearMasterRequest(Request_WB); - if (!pkt->needsResponse()) { - assert(wb.getNumTargets() == 0); - wb.deallocate(); - cache->clearBlocked(Blocked_NoWBBuffers); - } else { - wb.inService = true; - } - } else { - assert(mshr == &miss); - cache->clearMasterRequest(Request_MSHR); - if (!pkt->needsResponse()) { - assert(miss.getNumTargets() == 0); - miss.deallocate(); - cache->clearBlocked(Blocked_NoMSHRs); - } else { - //mark in service - miss.inService = true; - } - } -} - -void -BlockingBuffer::handleResponse(PacketPtr &pkt, Tick time) -{ - if (pkt->isCacheFill()) { - // targets were handled in the cache tags - assert((MSHR*)pkt->senderState == &miss); - miss.deallocate(); - cache->clearBlocked(Blocked_NoMSHRs); - } else { - if (((MSHR*)(pkt->senderState))->hasTargets()) { - // Should only have 1 target if we had any - assert(((MSHR*)(pkt->senderState))->getNumTargets() == 1); - PacketPtr target = ((MSHR*)(pkt->senderState))->getTarget(); - ((MSHR*)(pkt->senderState))->popTarget(); - if (pkt->isRead()) { - std::memcpy(target->getPtr<uint8_t>(), pkt->getPtr<uint8_t>(), target->getSize()); - } - cache->respond(target, time); - assert(!((MSHR*)(pkt->senderState))->hasTargets()); - } - - if (pkt->isWrite()) { - assert(((MSHR*)(pkt->senderState)) == &wb); - wb.deallocate(); - cache->clearBlocked(Blocked_NoWBBuffers); - } else { - miss.deallocate(); - cache->clearBlocked(Blocked_NoMSHRs); - } - } -} - -void -BlockingBuffer::squash(int threadNum) -{ - if (miss.threadNum == threadNum) { - PacketPtr target = miss.getTarget(); - miss.popTarget(); - assert(0/*target->req->getThreadNum()*/ == threadNum); - target = NULL; - assert(!miss.hasTargets()); - miss.ntargets=0; - if (!miss.inService) { - miss.deallocate(); - cache->clearBlocked(Blocked_NoMSHRs); - cache->clearMasterRequest(Request_MSHR); - } - } -} - -void -BlockingBuffer::doWriteback(Addr addr, - int size, uint8_t *data, bool compressed) -{ - // Generate request - Request * req = new Request(addr, size, 0); - PacketPtr pkt = new Packet(req, MemCmd::Writeback, -1); - pkt->allocate(); - if (data) { - std::memcpy(pkt->getPtr<uint8_t>(), data, size); - } - - if (compressed) { - pkt->flags |= COMPRESSED; - } - - ///All writebacks charged to same thread @todo figure this out - writebacks[0/*pkt->req->getThreadNum()*/]++; - - wb.allocateAsBuffer(pkt); - cache->setMasterRequest(Request_WB, curTick); - cache->setBlocked(Blocked_NoWBBuffers); -} - - - -void -BlockingBuffer::doWriteback(PacketPtr &pkt) -{ - writebacks[0/*pkt->req->getThreadNum()*/]++; - - wb.allocateAsBuffer(pkt); - - // Since allocate as buffer copies the request, - // need to copy data here. - std::memcpy(wb.pkt->getPtr<uint8_t>(), pkt->getPtr<uint8_t>(), pkt->getSize()); - - cache->setBlocked(Blocked_NoWBBuffers); - cache->setMasterRequest(Request_WB, curTick); -} - - -MSHR * -BlockingBuffer::findMSHR(Addr addr) -{ - if (miss.addr == addr && miss.pkt) - return &miss; - return NULL; -} - - -bool -BlockingBuffer::findWrites(Addr addr, std::vector<MSHR*>& writes) -{ - if (wb.addr == addr && wb.pkt) { - writes.push_back(&wb); - return true; - } - return false; -} diff --git a/src/mem/cache/miss/blocking_buffer.hh b/src/mem/cache/miss/blocking_buffer.hh deleted file mode 100644 index 86b24d539..000000000 --- a/src/mem/cache/miss/blocking_buffer.hh +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * 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: Erik Hallnor - */ - -/** - * @file - * Declaration of a simple buffer for a blocking cache. - */ - -#ifndef __BLOCKING_BUFFER_HH__ -#define __BLOCKING_BUFFER_HH__ - -#include <vector> - -#include "base/misc.hh" // for fatal() -#include "mem/cache/miss/miss_buffer.hh" -#include "mem/cache/miss/mshr.hh" - -/** - * Miss and writeback storage for a blocking cache. - */ -class BlockingBuffer : public MissBuffer -{ -protected: - /** Miss storage. */ - MSHR miss; - /** WB storage. */ - MSHR wb; - -public: - /** - * Builds and initializes this buffer. - * @param write_allocate If true, treat write misses the same as reads. - */ - BlockingBuffer(bool write_allocate) - : MissBuffer(write_allocate) - { - } - - /** - * Register statistics for this object. - * @param name The name of the parent cache. - */ - void regStats(const std::string &name); - - /** - * Handle a cache miss properly. Requests the bus and marks the cache as - * blocked. - * @param pkt The request that missed in the cache. - * @param blk_size The block size of the cache. - * @param time The time the miss is detected. - */ - void handleMiss(PacketPtr &pkt, int blk_size, Tick time); - - /** - * Fetch the block for the given address and buffer the given target. - * @param addr The address to fetch. - * @param asid The address space of the address. - * @param blk_size The block size of the cache. - * @param time The time the miss is detected. - * @param target The target for the fetch. - */ - MSHR* fetchBlock(Addr addr, int blk_size, Tick time, - PacketPtr &target) - { - fatal("Unimplemented"); - M5_DUMMY_RETURN - } - - /** - * Selects a outstanding request to service. - * @return The request to service, NULL if none found. - */ - PacketPtr getPacket(); - - /** - * Set the command to the given bus command. - * @param pkt The request to update. - * @param cmd The bus command to use. - */ - void setBusCmd(PacketPtr &pkt, MemCmd cmd); - - /** - * Restore the original command in case of a bus transmission error. - * @param pkt The request to reset. - */ - void restoreOrigCmd(PacketPtr &pkt); - - /** - * Marks a request as in service (sent on the bus). This can have side - * effect since storage for no response commands is deallocated once they - * are successfully sent. - * @param pkt The request that was sent on the bus. - */ - void markInService(PacketPtr &pkt, MSHR* mshr); - - /** - * Frees the resources of the request and unblock the cache. - * @param pkt The request that has been satisfied. - * @param time The time when the request is satisfied. - */ - void handleResponse(PacketPtr &pkt, Tick time); - - /** - * Removes all outstanding requests for a given thread number. If a request - * has been sent to the bus, this function removes all of its targets. - * @param threadNum The thread number of the requests to squash. - */ - void squash(int threadNum); - - /** - * Return the current number of outstanding misses. - * @return the number of outstanding misses. - */ - int getMisses() - { - return miss.getNumTargets(); - } - - /** - * Searches for the supplied address in the miss "queue". - * @param addr The address to look for. - * @param asid The address space id. - * @return A pointer to miss if it matches. - */ - MSHR* findMSHR(Addr addr); - - /** - * Searches for the supplied address in the write buffer. - * @param addr The address to look for. - * @param asid The address space id. - * @param writes List of pointers to the matching writes. - * @return True if there is a matching write. - */ - bool findWrites(Addr addr, std::vector<MSHR*>& writes); - - /** - * Perform a writeback of dirty data to the given address. - * @param addr The address to write to. - * @param asid The address space id. - * @param size The number of bytes to write. - * @param data The data to write, can be NULL. - * @param compressed True if the data is compressed. - */ - void doWriteback(Addr addr, - int size, uint8_t *data, bool compressed); - - /** - * Perform a writeback request. - * @param pkt The writeback request. - */ - void doWriteback(PacketPtr &pkt); - - /** - * Returns true if there are outstanding requests. - * @return True if there are outstanding requests. - */ - bool havePending() - { - return !miss.inService || !wb.inService; - } - - /** - * Add a target to the given MSHR. This assumes it is in the miss queue. - * @param mshr The mshr to add a target to. - * @param pkt The target to add. - */ - void addTarget(MSHR *mshr, PacketPtr &pkt) - { - fatal("Shouldn't call this on a blocking buffer."); - } - - /** - * Dummy implmentation. - */ - MSHR* allocateTargetList(Addr addr) - { - fatal("Unimplemented"); - M5_DUMMY_RETURN - } -}; - -#endif // __BLOCKING_BUFFER_HH__ diff --git a/src/mem/cache/miss/miss_buffer.cc b/src/mem/cache/miss/miss_buffer.cc deleted file mode 100644 index 4d9cd0958..000000000 --- a/src/mem/cache/miss/miss_buffer.cc +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2003-2006 The Regents of The University of Michigan - * 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: Erik Hallnor - */ - -#include "cpu/smt.hh" //for maxThreadsPerCPU -#include "mem/cache/base_cache.hh" -#include "mem/cache/miss/miss_buffer.hh" -#include "mem/cache/prefetch/base_prefetcher.hh" - -/** - * @todo Move writebacks into shared BaseBuffer class. - */ -void -MissBuffer::regStats(const std::string &name) -{ - using namespace Stats; - writebacks - .init(maxThreadsPerCPU) - .name(name + ".writebacks") - .desc("number of writebacks") - .flags(total) - ; -} - -void -MissBuffer::setCache(BaseCache *_cache) -{ - cache = _cache; - blkSize = cache->getBlockSize(); -} - -void -MissBuffer::setPrefetcher(BasePrefetcher *_prefetcher) -{ - prefetcher = _prefetcher; -} diff --git a/src/mem/cache/miss/miss_buffer.hh b/src/mem/cache/miss/miss_buffer.hh deleted file mode 100644 index 9a86db304..000000000 --- a/src/mem/cache/miss/miss_buffer.hh +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (c) 2003-2006 The Regents of The University of Michigan - * 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: Steve Reinhardt - */ - -/** - * @file - * MissBuffer declaration. - */ - -#ifndef __MISS_BUFFER_HH__ -#define __MISS_BUFFER_HH__ - -class BaseCache; -class BasePrefetcher; -class MSHR; - -/** - * Abstract base class for cache miss buffering. - */ -class MissBuffer -{ - protected: - /** True if the cache should allocate on a write miss. */ - const bool writeAllocate; - - /** Pointer to the parent cache. */ - BaseCache *cache; - - /** The Prefetcher */ - BasePrefetcher *prefetcher; - - /** Block size of the parent cache. */ - int blkSize; - - // Statistics - /** - * @addtogroup CacheStatistics - * @{ - */ - /** Number of blocks written back per thread. */ - Stats::Vector<> writebacks; - - /** - * @} - */ - - public: - MissBuffer(bool write_allocate) - : writeAllocate(write_allocate) - { - } - - virtual ~MissBuffer() {} - - /** - * Called by the parent cache to set the back pointer. - * @param _cache A pointer to the parent cache. - */ - void setCache(BaseCache *_cache); - - void setPrefetcher(BasePrefetcher *_prefetcher); - - /** - * Register statistics for this object. - * @param name The name of the parent cache. - */ - virtual void regStats(const std::string &name); - - /** - * Handle a cache miss properly. Either allocate an MSHR for the request, - * or forward it through the write buffer. - * @param pkt The request that missed in the cache. - * @param blk_size The block size of the cache. - * @param time The time the miss is detected. - */ - virtual void handleMiss(PacketPtr &pkt, int blk_size, Tick time) = 0; - - /** - * Fetch the block for the given address and buffer the given target. - * @param addr The address to fetch. - * @param asid The address space of the address. - * @param blk_size The block size of the cache. - * @param time The time the miss is detected. - * @param target The target for the fetch. - */ - virtual MSHR *fetchBlock(Addr addr, int blk_size, Tick time, - PacketPtr &target) = 0; - - /** - * Selects a outstanding request to service. - * @return The request to service, NULL if none found. - */ - virtual PacketPtr getPacket() = 0; - - /** - * Set the command to the given bus command. - * @param pkt The request to update. - * @param cmd The bus command to use. - */ - virtual void setBusCmd(PacketPtr &pkt, MemCmd cmd) = 0; - - /** - * Restore the original command in case of a bus transmission error. - * @param pkt The request to reset. - */ - virtual void restoreOrigCmd(PacketPtr &pkt) = 0; - - /** - * Marks a request as in service (sent on the bus). This can have side - * effect since storage for no response commands is deallocated once they - * are successfully sent. - * @param pkt The request that was sent on the bus. - */ - virtual void markInService(PacketPtr &pkt, MSHR* mshr) = 0; - - /** - * Collect statistics and free resources of a satisfied request. - * @param pkt The request that has been satisfied. - * @param time The time when the request is satisfied. - */ - virtual void handleResponse(PacketPtr &pkt, Tick time) = 0; - - /** - * Removes all outstanding requests for a given thread number. If a request - * has been sent to the bus, this function removes all of its targets. - * @param threadNum The thread number of the requests to squash. - */ - virtual void squash(int threadNum) = 0; - - /** - * Return the current number of outstanding misses. - * @return the number of outstanding misses. - */ - virtual int getMisses() = 0; - - /** - * Searches for the supplied address in the miss queue. - * @param addr The address to look for. - * @param asid The address space id. - * @return The MSHR that contains the address, NULL if not found. - * @warning Currently only searches the miss queue. If non write allocate - * might need to search the write buffer for coherence. - */ - virtual MSHR* findMSHR(Addr addr) = 0; - - /** - * Searches for the supplied address in the write buffer. - * @param addr The address to look for. - * @param asid The address space id. - * @param writes The list of writes that match the address. - * @return True if any writes are found - */ - virtual bool findWrites(Addr addr, std::vector<MSHR*>& writes) = 0; - - /** - * Perform a writeback of dirty data to the given address. - * @param addr The address to write to. - * @param asid The address space id. - * @param xc The execution context of the address space. - * @param size The number of bytes to write. - * @param data The data to write, can be NULL. - * @param compressed True if the data is compressed. - */ - virtual void doWriteback(Addr addr, int size, uint8_t *data, - bool compressed) = 0; - - /** - * Perform the given writeback request. - * @param pkt The writeback request. - */ - virtual void doWriteback(PacketPtr &pkt) = 0; - - /** - * Returns true if there are outstanding requests. - * @return True if there are outstanding requests. - */ - virtual bool havePending() = 0; - - /** - * Add a target to the given MSHR. This assumes it is in the miss queue. - * @param mshr The mshr to add a target to. - * @param pkt The target to add. - */ - virtual void addTarget(MSHR *mshr, PacketPtr &pkt) = 0; - - /** - * Allocate a MSHR to hold a list of targets to a block involved in a copy. - * If the block is marked done then the MSHR already holds the data to - * fill the block. Otherwise the block needs to be fetched. - * @param addr The address to buffer. - * @param asid The address space ID. - * @return A pointer to the allocated MSHR. - */ - virtual MSHR* allocateTargetList(Addr addr) = 0; -}; - -#endif //__MISS_BUFFER_HH__ diff --git a/src/mem/cache/miss/miss_queue.cc b/src/mem/cache/miss/miss_queue.cc deleted file mode 100644 index 24ca9cfa2..000000000 --- a/src/mem/cache/miss/miss_queue.cc +++ /dev/null @@ -1,752 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * 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: Erik Hallnor - * Ron Dreslinski - */ - -/** - * @file - * Miss and writeback queue definitions. - */ - -#include "cpu/smt.hh" //for maxThreadsPerCPU -#include "mem/cache/base_cache.hh" -#include "mem/cache/miss/miss_queue.hh" -#include "mem/cache/prefetch/base_prefetcher.hh" - -using namespace std; - -// simple constructor -/** - * @todo Remove the +16 from the write buffer constructor once we handle - * stalling on writebacks do to compression writes. - */ -MissQueue::MissQueue(int numMSHRs, int numTargets, int write_buffers, - bool write_allocate, bool prefetch_miss) - : MissBuffer(write_allocate), - mq(numMSHRs, 4), wb(write_buffers,numMSHRs+1000), numMSHR(numMSHRs), - numTarget(numTargets), writeBuffers(write_buffers), - order(0), prefetchMiss(prefetch_miss) -{ - noTargetMSHR = NULL; -} - - -MissQueue::~MissQueue() -{ -} - - -void -MissQueue::regStats(const string &name) -{ - MissBuffer::regStats(name); - - using namespace Stats; - - // MSHR hit statistics - for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) { - MemCmd cmd(access_idx); - const string &cstr = cmd.toString(); - - mshr_hits[access_idx] - .init(maxThreadsPerCPU) - .name(name + "." + cstr + "_mshr_hits") - .desc("number of " + cstr + " MSHR hits") - .flags(total | nozero | nonan) - ; - } - - demandMshrHits - .name(name + ".demand_mshr_hits") - .desc("number of demand (read+write) MSHR hits") - .flags(total) - ; - demandMshrHits = mshr_hits[MemCmd::ReadReq] + mshr_hits[MemCmd::WriteReq]; - - overallMshrHits - .name(name + ".overall_mshr_hits") - .desc("number of overall MSHR hits") - .flags(total) - ; - overallMshrHits = demandMshrHits + mshr_hits[MemCmd::SoftPFReq] + - mshr_hits[MemCmd::HardPFReq]; - - // MSHR miss statistics - for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) { - MemCmd cmd(access_idx); - const string &cstr = cmd.toString(); - - mshr_misses[access_idx] - .init(maxThreadsPerCPU) - .name(name + "." + cstr + "_mshr_misses") - .desc("number of " + cstr + " MSHR misses") - .flags(total | nozero | nonan) - ; - } - - demandMshrMisses - .name(name + ".demand_mshr_misses") - .desc("number of demand (read+write) MSHR misses") - .flags(total) - ; - demandMshrMisses = mshr_misses[MemCmd::ReadReq] + mshr_misses[MemCmd::WriteReq]; - - overallMshrMisses - .name(name + ".overall_mshr_misses") - .desc("number of overall MSHR misses") - .flags(total) - ; - overallMshrMisses = demandMshrMisses + mshr_misses[MemCmd::SoftPFReq] + - mshr_misses[MemCmd::HardPFReq]; - - // MSHR miss latency statistics - for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) { - MemCmd cmd(access_idx); - const string &cstr = cmd.toString(); - - mshr_miss_latency[access_idx] - .init(maxThreadsPerCPU) - .name(name + "." + cstr + "_mshr_miss_latency") - .desc("number of " + cstr + " MSHR miss cycles") - .flags(total | nozero | nonan) - ; - } - - demandMshrMissLatency - .name(name + ".demand_mshr_miss_latency") - .desc("number of demand (read+write) MSHR miss cycles") - .flags(total) - ; - demandMshrMissLatency = mshr_miss_latency[MemCmd::ReadReq] - + mshr_miss_latency[MemCmd::WriteReq]; - - overallMshrMissLatency - .name(name + ".overall_mshr_miss_latency") - .desc("number of overall MSHR miss cycles") - .flags(total) - ; - overallMshrMissLatency = demandMshrMissLatency + - mshr_miss_latency[MemCmd::SoftPFReq] + mshr_miss_latency[MemCmd::HardPFReq]; - - // MSHR uncacheable statistics - for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) { - MemCmd cmd(access_idx); - const string &cstr = cmd.toString(); - - mshr_uncacheable[access_idx] - .init(maxThreadsPerCPU) - .name(name + "." + cstr + "_mshr_uncacheable") - .desc("number of " + cstr + " MSHR uncacheable") - .flags(total | nozero | nonan) - ; - } - - overallMshrUncacheable - .name(name + ".overall_mshr_uncacheable_misses") - .desc("number of overall MSHR uncacheable misses") - .flags(total) - ; - overallMshrUncacheable = mshr_uncacheable[MemCmd::ReadReq] - + mshr_uncacheable[MemCmd::WriteReq] + mshr_uncacheable[MemCmd::SoftPFReq] - + mshr_uncacheable[MemCmd::HardPFReq]; - - // MSHR miss latency statistics - for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) { - MemCmd cmd(access_idx); - const string &cstr = cmd.toString(); - - mshr_uncacheable_lat[access_idx] - .init(maxThreadsPerCPU) - .name(name + "." + cstr + "_mshr_uncacheable_latency") - .desc("number of " + cstr + " MSHR uncacheable cycles") - .flags(total | nozero | nonan) - ; - } - - overallMshrUncacheableLatency - .name(name + ".overall_mshr_uncacheable_latency") - .desc("number of overall MSHR uncacheable cycles") - .flags(total) - ; - overallMshrUncacheableLatency = mshr_uncacheable_lat[MemCmd::ReadReq] - + mshr_uncacheable_lat[MemCmd::WriteReq] - + mshr_uncacheable_lat[MemCmd::SoftPFReq] - + mshr_uncacheable_lat[MemCmd::HardPFReq]; - -#if 0 - // MSHR access formulas - for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) { - MemCmd cmd(access_idx); - const string &cstr = cmd.toString(); - - mshrAccesses[access_idx] - .name(name + "." + cstr + "_mshr_accesses") - .desc("number of " + cstr + " mshr accesses(hits+misses)") - .flags(total | nozero | nonan) - ; - mshrAccesses[access_idx] = - mshr_hits[access_idx] + mshr_misses[access_idx] - + mshr_uncacheable[access_idx]; - } - - demandMshrAccesses - .name(name + ".demand_mshr_accesses") - .desc("number of demand (read+write) mshr accesses") - .flags(total | nozero | nonan) - ; - demandMshrAccesses = demandMshrHits + demandMshrMisses; - - overallMshrAccesses - .name(name + ".overall_mshr_accesses") - .desc("number of overall (read+write) mshr accesses") - .flags(total | nozero | nonan) - ; - overallMshrAccesses = overallMshrHits + overallMshrMisses - + overallMshrUncacheable; -#endif - - // MSHR miss rate formulas - for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) { - MemCmd cmd(access_idx); - const string &cstr = cmd.toString(); - - mshrMissRate[access_idx] - .name(name + "." + cstr + "_mshr_miss_rate") - .desc("mshr miss rate for " + cstr + " accesses") - .flags(total | nozero | nonan) - ; - - mshrMissRate[access_idx] = - mshr_misses[access_idx] / cache->accesses[access_idx]; - } - - demandMshrMissRate - .name(name + ".demand_mshr_miss_rate") - .desc("mshr miss rate for demand accesses") - .flags(total) - ; - demandMshrMissRate = demandMshrMisses / cache->demandAccesses; - - overallMshrMissRate - .name(name + ".overall_mshr_miss_rate") - .desc("mshr miss rate for overall accesses") - .flags(total) - ; - overallMshrMissRate = overallMshrMisses / cache->overallAccesses; - - // mshrMiss latency formulas - for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) { - MemCmd cmd(access_idx); - const string &cstr = cmd.toString(); - - avgMshrMissLatency[access_idx] - .name(name + "." + cstr + "_avg_mshr_miss_latency") - .desc("average " + cstr + " mshr miss latency") - .flags(total | nozero | nonan) - ; - - avgMshrMissLatency[access_idx] = - mshr_miss_latency[access_idx] / mshr_misses[access_idx]; - } - - demandAvgMshrMissLatency - .name(name + ".demand_avg_mshr_miss_latency") - .desc("average overall mshr miss latency") - .flags(total) - ; - demandAvgMshrMissLatency = demandMshrMissLatency / demandMshrMisses; - - overallAvgMshrMissLatency - .name(name + ".overall_avg_mshr_miss_latency") - .desc("average overall mshr miss latency") - .flags(total) - ; - overallAvgMshrMissLatency = overallMshrMissLatency / overallMshrMisses; - - // mshrUncacheable latency formulas - for (int access_idx = 0; access_idx < MemCmd::NUM_MEM_CMDS; ++access_idx) { - MemCmd cmd(access_idx); - const string &cstr = cmd.toString(); - - avgMshrUncacheableLatency[access_idx] - .name(name + "." + cstr + "_avg_mshr_uncacheable_latency") - .desc("average " + cstr + " mshr uncacheable latency") - .flags(total | nozero | nonan) - ; - - avgMshrUncacheableLatency[access_idx] = - mshr_uncacheable_lat[access_idx] / mshr_uncacheable[access_idx]; - } - - overallAvgMshrUncacheableLatency - .name(name + ".overall_avg_mshr_uncacheable_latency") - .desc("average overall mshr uncacheable latency") - .flags(total) - ; - overallAvgMshrUncacheableLatency = overallMshrUncacheableLatency / overallMshrUncacheable; - - mshr_cap_events - .init(maxThreadsPerCPU) - .name(name + ".mshr_cap_events") - .desc("number of times MSHR cap was activated") - .flags(total) - ; - - //software prefetching stats - soft_prefetch_mshr_full - .init(maxThreadsPerCPU) - .name(name + ".soft_prefetch_mshr_full") - .desc("number of mshr full events for SW prefetching instrutions") - .flags(total) - ; - - mshr_no_allocate_misses - .name(name +".no_allocate_misses") - .desc("Number of misses that were no-allocate") - ; - -} - - -MSHR* -MissQueue::allocateMiss(PacketPtr &pkt, int size, Tick time) -{ - MSHR* mshr = mq.allocate(pkt, size); - mshr->order = order++; - if (!pkt->req->isUncacheable() ){//&& !pkt->isNoAllocate()) { - // Mark this as a cache line fill - mshr->pkt->flags |= CACHE_LINE_FILL; - } - if (mq.isFull()) { - cache->setBlocked(Blocked_NoMSHRs); - } - if (pkt->cmd != MemCmd::HardPFReq) { - //If we need to request the bus (not on HW prefetch), do so - cache->setMasterRequest(Request_MSHR, time); - } - return mshr; -} - - -MSHR* -MissQueue::allocateWrite(PacketPtr &pkt, int size, Tick time) -{ - MSHR* mshr = wb.allocate(pkt,size); - mshr->order = order++; - -//REMOVING COMPRESSION FOR NOW -#if 0 - if (pkt->isCompressed()) { - mshr->pkt->deleteData(); - mshr->pkt->actualSize = pkt->actualSize; - mshr->pkt->data = new uint8_t[pkt->actualSize]; - memcpy(mshr->pkt->data, pkt->data, pkt->actualSize); - } else { -#endif - memcpy(mshr->pkt->getPtr<uint8_t>(), pkt->getPtr<uint8_t>(), pkt->getSize()); - //{ - - if (wb.isFull()) { - cache->setBlocked(Blocked_NoWBBuffers); - } - - cache->setMasterRequest(Request_WB, time); - - return mshr; -} - - -/** - * @todo Remove SW prefetches on mshr hits. - */ -void -MissQueue::handleMiss(PacketPtr &pkt, int blkSize, Tick time) -{ -// if (!cache->isTopLevel()) - if (prefetchMiss) prefetcher->handleMiss(pkt, time); - - int size = blkSize; - Addr blkAddr = pkt->getAddr() & ~(Addr)(blkSize-1); - MSHR* mshr = NULL; - if (!pkt->req->isUncacheable()) { - mshr = mq.findMatch(blkAddr); - if (mshr) { - //@todo remove hw_pf here - mshr_hits[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++; - if (mshr->threadNum != 0/*pkt->req->getThreadNum()*/) { - mshr->threadNum = -1; - } - mq.allocateTarget(mshr, pkt); - if (mshr->pkt->isNoAllocate() && !pkt->isNoAllocate()) { - //We are adding an allocate after a no-allocate - mshr->pkt->flags &= ~NO_ALLOCATE; - } - if (mshr->getNumTargets() == numTarget) { - noTargetMSHR = mshr; - cache->setBlocked(Blocked_NoTargets); - mq.moveToFront(mshr); - } - return; - } - if (pkt->isNoAllocate()) { - //Count no-allocate requests differently - mshr_no_allocate_misses++; - } - else { - mshr_misses[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++; - } - } else { - //Count uncacheable accesses - mshr_uncacheable[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++; - size = pkt->getSize(); - } - if (pkt->isWrite() && (pkt->req->isUncacheable() || !writeAllocate || - !pkt->needsResponse())) { - /** - * @todo Add write merging here. - */ - mshr = allocateWrite(pkt, pkt->getSize(), time); - return; - } - - mshr = allocateMiss(pkt, blkSize, time); -} - -MSHR* -MissQueue::fetchBlock(Addr addr, int blk_size, Tick time, - PacketPtr &target) -{ - Addr blkAddr = addr & ~(Addr)(blk_size - 1); - assert(mq.findMatch(addr) == NULL); - MSHR *mshr = mq.allocateFetch(blkAddr, blk_size, target); - mshr->order = order++; - mshr->pkt->flags |= CACHE_LINE_FILL; - if (mq.isFull()) { - cache->setBlocked(Blocked_NoMSHRs); - } - cache->setMasterRequest(Request_MSHR, time); - return mshr; -} - -PacketPtr -MissQueue::getPacket() -{ - PacketPtr pkt = mq.getReq(); - if (((wb.isFull() && wb.inServiceMSHRs == 0) || !pkt || - pkt->time > curTick) && wb.havePending()) { - pkt = wb.getReq(); - // Need to search for earlier miss. - MSHR *mshr = mq.findPending(pkt); - if (mshr && mshr->order < ((MSHR*)(pkt->senderState))->order) { - // Service misses in order until conflict is cleared. - return mq.getReq(); - } - } - if (pkt) { - MSHR* mshr = wb.findPending(pkt); - if (mshr /*&& mshr->order < pkt->senderState->order*/) { - // 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 - return wb.getReq(); - } - } - else if (!mq.isFull()){ - //If we have a miss queue slot, we can try a prefetch - pkt = prefetcher->getPacket(); - if (pkt) { - //Update statistic on number of prefetches issued (hwpf_mshr_misses) - mshr_misses[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++; - //It will request the bus for the future, but should clear that immedieatley - allocateMiss(pkt, pkt->getSize(), curTick); - pkt = mq.getReq(); - assert(pkt); //We should get back a req b/c we just put one in - } - } - return pkt; -} - -void -MissQueue::setBusCmd(PacketPtr &pkt, MemCmd cmd) -{ - assert(pkt->senderState != 0); - MSHR * mshr = (MSHR*)pkt->senderState; - mshr->originalCmd = pkt->cmd; - if (cmd == MemCmd::UpgradeReq || cmd == MemCmd::InvalidateReq) { - pkt->flags |= NO_ALLOCATE; - pkt->flags &= ~CACHE_LINE_FILL; - } - else if (!pkt->req->isUncacheable() && !pkt->isNoAllocate() && - cmd.needsResponse()) { - pkt->flags |= CACHE_LINE_FILL; - } - if (pkt->isCacheFill() || pkt->isNoAllocate()) - pkt->cmd = cmd; -} - -void -MissQueue::restoreOrigCmd(PacketPtr &pkt) -{ - pkt->cmd = ((MSHR*)(pkt->senderState))->originalCmd; -} - -void -MissQueue::markInService(PacketPtr &pkt, MSHR* mshr) -{ - bool unblock = false; - BlockedCause cause = NUM_BLOCKED_CAUSES; - - /** - * @todo Should include MSHRQueue pointer in MSHR to select the correct - * one. - */ - if ((!pkt->isCacheFill() && pkt->isWrite())) { - // Forwarding a write/ writeback, don't need to change - // the command - unblock = wb.isFull(); - wb.markInService(mshr); - if (!wb.havePending()){ - cache->clearMasterRequest(Request_WB); - } - if (unblock) { - // Do we really unblock? - unblock = !wb.isFull(); - cause = Blocked_NoWBBuffers; - } - } else { - unblock = mq.isFull(); - mq.markInService(mshr); - if (!mq.havePending()){ - cache->clearMasterRequest(Request_MSHR); - } - if (mshr->originalCmd == MemCmd::HardPFReq) { - DPRINTF(HWPrefetch, "%s:Marking a HW_PF in service\n", - cache->name()); - //Also clear pending if need be - if (!prefetcher->havePending()) - { - cache->clearMasterRequest(Request_PF); - } - } - if (unblock) { - unblock = !mq.isFull(); - cause = Blocked_NoMSHRs; - } - } - if (unblock) { - cache->clearBlocked(cause); - } -} - - -void -MissQueue::handleResponse(PacketPtr &pkt, Tick time) -{ - MSHR* mshr = (MSHR*)pkt->senderState; - if (((MSHR*)(pkt->senderState))->originalCmd == MemCmd::HardPFReq) { - DPRINTF(HWPrefetch, "%s:Handling the response to a HW_PF\n", - cache->name()); - } -#ifndef NDEBUG - int num_targets = mshr->getNumTargets(); -#endif - - bool unblock = false; - bool unblock_target = false; - BlockedCause cause = NUM_BLOCKED_CAUSES; - - if (pkt->isCacheFill() && !pkt->isNoAllocate()) { - mshr_miss_latency[mshr->originalCmd.toInt()][0/*pkt->req->getThreadNum()*/] += - curTick - pkt->time; - // targets were handled in the cache tags - if (mshr == noTargetMSHR) { - // we always clear at least one target - unblock_target = true; - cause = Blocked_NoTargets; - noTargetMSHR = NULL; - } - - if (mshr->hasTargets()) { - // Didn't satisfy all the targets, need to resend - MemCmd cmd = mshr->getTarget()->cmd; - mshr->pkt->setDest(Packet::Broadcast); - mshr->pkt->result = Packet::Unknown; - mshr->pkt->req = mshr->getTarget()->req; - mq.markPending(mshr, cmd); - mshr->order = order++; - cache->setMasterRequest(Request_MSHR, time); - } - else { - unblock = mq.isFull(); - mq.deallocate(mshr); - if (unblock) { - unblock = !mq.isFull(); - cause = Blocked_NoMSHRs; - } - } - } else { - if (pkt->req->isUncacheable()) { - mshr_uncacheable_lat[pkt->cmd.toInt()][0/*pkt->req->getThreadNum()*/] += - curTick - pkt->time; - } - if (mshr->hasTargets() && pkt->req->isUncacheable()) { - // Should only have 1 target if we had any - assert(num_targets == 1); - PacketPtr target = mshr->getTarget(); - mshr->popTarget(); - if (pkt->isRead()) { - memcpy(target->getPtr<uint8_t>(), pkt->getPtr<uint8_t>(), - target->getSize()); - } - cache->respond(target, time); - assert(!mshr->hasTargets()); - } - else if (mshr->hasTargets()) { - //Must be a no_allocate with possibly more than one target - assert(mshr->pkt->isNoAllocate()); - while (mshr->hasTargets()) { - PacketPtr target = mshr->getTarget(); - mshr->popTarget(); - if (pkt->isRead()) { - memcpy(target->getPtr<uint8_t>(), pkt->getPtr<uint8_t>(), - target->getSize()); - } - cache->respond(target, time); - } - } - - if (pkt->isWrite()) { - // If the wrtie buffer is full, we might unblock now - unblock = wb.isFull(); - wb.deallocate(mshr); - if (unblock) { - // Did we really unblock? - unblock = !wb.isFull(); - cause = Blocked_NoWBBuffers; - } - } else { - unblock = mq.isFull(); - mq.deallocate(mshr); - if (unblock) { - unblock = !mq.isFull(); - cause = Blocked_NoMSHRs; - } - } - } - if (unblock || unblock_target) { - cache->clearBlocked(cause); - } -} - -void -MissQueue::squash(int threadNum) -{ - bool unblock = false; - BlockedCause cause = NUM_BLOCKED_CAUSES; - - if (noTargetMSHR && noTargetMSHR->threadNum == threadNum) { - noTargetMSHR = NULL; - unblock = true; - cause = Blocked_NoTargets; - } - if (mq.isFull()) { - unblock = true; - cause = Blocked_NoMSHRs; - } - mq.squash(threadNum); - if (!mq.havePending()) { - cache->clearMasterRequest(Request_MSHR); - } - if (unblock && !mq.isFull()) { - cache->clearBlocked(cause); - } - -} - -MSHR* -MissQueue::findMSHR(Addr addr) -{ - return mq.findMatch(addr); -} - -bool -MissQueue::findWrites(Addr addr, vector<MSHR*> &writes) -{ - return wb.findMatches(addr,writes); -} - -void -MissQueue::doWriteback(Addr addr, - int size, uint8_t *data, bool compressed) -{ - // Generate request - Request * req = new Request(addr, size, 0); - PacketPtr pkt = new Packet(req, MemCmd::Writeback, -1); - pkt->allocate(); - if (data) { - memcpy(pkt->getPtr<uint8_t>(), data, size); - } - - if (compressed) { - pkt->flags |= COMPRESSED; - } - - ///All writebacks charged to same thread @todo figure this out - writebacks[0/*pkt->req->getThreadNum()*/]++; - - allocateWrite(pkt, 0, curTick); -} - - -void -MissQueue::doWriteback(PacketPtr &pkt) -{ - writebacks[0/*pkt->req->getThreadNum()*/]++; - allocateWrite(pkt, 0, curTick); -} - - -MSHR* -MissQueue::allocateTargetList(Addr addr) -{ - MSHR* mshr = mq.allocateTargetList(addr, blkSize); - mshr->pkt->flags |= CACHE_LINE_FILL; - if (mq.isFull()) { - cache->setBlocked(Blocked_NoMSHRs); - } - return mshr; -} - -bool -MissQueue::havePending() -{ - return mq.havePending() || wb.havePending() || prefetcher->havePending(); -} diff --git a/src/mem/cache/miss/miss_queue.hh b/src/mem/cache/miss/miss_queue.hh deleted file mode 100644 index d3560ff36..000000000 --- a/src/mem/cache/miss/miss_queue.hh +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Copyright (c) 2003-2005 The Regents of The University of Michigan - * 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: Erik Hallnor - */ - -/** - * @file - * Miss and writeback queue declarations. - */ - -#ifndef __MISS_QUEUE_HH__ -#define __MISS_QUEUE_HH__ - -#include <vector> - -#include "mem/cache/miss/miss_buffer.hh" -#include "mem/cache/miss/mshr.hh" -#include "mem/cache/miss/mshr_queue.hh" -#include "base/statistics.hh" - -/** - * Manages cache misses and writebacks. Contains MSHRs to store miss data - * and the writebuffer for writes/writebacks. - * @todo need to handle data on writes better (encapsulate). - * @todo need to make replacements/writebacks happen in Cache::access - */ -class MissQueue : public MissBuffer -{ - protected: - /** The MSHRs. */ - MSHRQueue mq; - /** Write Buffer. */ - MSHRQueue wb; - - // PARAMTERS - - /** The number of MSHRs in the miss queue. */ - const int numMSHR; - /** The number of targets for each MSHR. */ - const int numTarget; - /** The number of write buffers. */ - const int writeBuffers; - - /** Increasing order number assigned to each incoming request. */ - uint64_t order; - - bool prefetchMiss; - - // Statistics - /** - * @addtogroup CacheStatistics - * @{ - */ - /** Number of misses that hit in the MSHRs per command and thread. */ - Stats::Vector<> mshr_hits[MemCmd::NUM_MEM_CMDS]; - /** Demand misses that hit in the MSHRs. */ - Stats::Formula demandMshrHits; - /** Total number of misses that hit in the MSHRs. */ - Stats::Formula overallMshrHits; - - /** Number of misses that miss in the MSHRs, per command and thread. */ - Stats::Vector<> mshr_misses[MemCmd::NUM_MEM_CMDS]; - /** Demand misses that miss in the MSHRs. */ - Stats::Formula demandMshrMisses; - /** Total number of misses that miss in the MSHRs. */ - Stats::Formula overallMshrMisses; - - /** Number of misses that miss in the MSHRs, per command and thread. */ - Stats::Vector<> mshr_uncacheable[MemCmd::NUM_MEM_CMDS]; - /** Total number of misses that miss in the MSHRs. */ - Stats::Formula overallMshrUncacheable; - - /** Total cycle latency of each MSHR miss, per command and thread. */ - Stats::Vector<> mshr_miss_latency[MemCmd::NUM_MEM_CMDS]; - /** Total cycle latency of demand MSHR misses. */ - Stats::Formula demandMshrMissLatency; - /** Total cycle latency of overall MSHR misses. */ - Stats::Formula overallMshrMissLatency; - - /** Total cycle latency of each MSHR miss, per command and thread. */ - Stats::Vector<> mshr_uncacheable_lat[MemCmd::NUM_MEM_CMDS]; - /** Total cycle latency of overall MSHR misses. */ - Stats::Formula overallMshrUncacheableLatency; - - /** The total number of MSHR accesses per command and thread. */ - Stats::Formula mshrAccesses[MemCmd::NUM_MEM_CMDS]; - /** The total number of demand MSHR accesses. */ - Stats::Formula demandMshrAccesses; - /** The total number of MSHR accesses. */ - Stats::Formula overallMshrAccesses; - - /** The miss rate in the MSHRs pre command and thread. */ - Stats::Formula mshrMissRate[MemCmd::NUM_MEM_CMDS]; - /** The demand miss rate in the MSHRs. */ - Stats::Formula demandMshrMissRate; - /** The overall miss rate in the MSHRs. */ - Stats::Formula overallMshrMissRate; - - /** The average latency of an MSHR miss, per command and thread. */ - Stats::Formula avgMshrMissLatency[MemCmd::NUM_MEM_CMDS]; - /** The average latency of a demand MSHR miss. */ - Stats::Formula demandAvgMshrMissLatency; - /** The average overall latency of an MSHR miss. */ - Stats::Formula overallAvgMshrMissLatency; - - /** The average latency of an MSHR miss, per command and thread. */ - Stats::Formula avgMshrUncacheableLatency[MemCmd::NUM_MEM_CMDS]; - /** The average overall latency of an MSHR miss. */ - Stats::Formula overallAvgMshrUncacheableLatency; - - /** The number of times a thread hit its MSHR cap. */ - Stats::Vector<> mshr_cap_events; - /** The number of times software prefetches caused the MSHR to block. */ - Stats::Vector<> soft_prefetch_mshr_full; - - Stats::Scalar<> mshr_no_allocate_misses; - - /** - * @} - */ - - private: - /** Pointer to the MSHR that has no targets. */ - MSHR* noTargetMSHR; - - /** - * Allocate a new MSHR to handle the provided miss. - * @param pkt The miss to buffer. - * @param size The number of bytes to fetch. - * @param time The time the miss occurs. - * @return A pointer to the new MSHR. - */ - MSHR* allocateMiss(PacketPtr &pkt, int size, Tick time); - - /** - * Allocate a new WriteBuffer to handle the provided write. - * @param pkt The write to handle. - * @param size The number of bytes to write. - * @param time The time the write occurs. - * @return A pointer to the new write buffer. - */ - MSHR* allocateWrite(PacketPtr &pkt, int size, Tick time); - - public: - /** - * Simple Constructor. Initializes all needed internal storage and sets - * parameters. - * @param numMSHRs The number of outstanding misses to handle. - * @param numTargets The number of outstanding targets to each miss. - * @param write_buffers The number of outstanding writes to handle. - * @param write_allocate If true, treat write misses the same as reads. - */ - MissQueue(int numMSHRs, int numTargets, int write_buffers, - bool write_allocate, bool prefetch_miss); - - /** - * Deletes all allocated internal storage. - */ - ~MissQueue(); - - /** - * Register statistics for this object. - * @param name The name of the parent cache. - */ - void regStats(const std::string &name); - - /** - * Handle a cache miss properly. Either allocate an MSHR for the request, - * or forward it through the write buffer. - * @param pkt The request that missed in the cache. - * @param blk_size The block size of the cache. - * @param time The time the miss is detected. - */ - void handleMiss(PacketPtr &pkt, int blk_size, Tick time); - - /** - * Fetch the block for the given address and buffer the given target. - * @param addr The address to fetch. - * @param asid The address space of the address. - * @param blk_size The block size of the cache. - * @param time The time the miss is detected. - * @param target The target for the fetch. - */ - MSHR* fetchBlock(Addr addr, int blk_size, Tick time, - PacketPtr &target); - - /** - * Selects a outstanding request to service. - * @return The request to service, NULL if none found. - */ - PacketPtr getPacket(); - - /** - * Set the command to the given bus command. - * @param pkt The request to update. - * @param cmd The bus command to use. - */ - void setBusCmd(PacketPtr &pkt, MemCmd cmd); - - /** - * Restore the original command in case of a bus transmission error. - * @param pkt The request to reset. - */ - void restoreOrigCmd(PacketPtr &pkt); - - /** - * Marks a request as in service (sent on the bus). This can have side - * effect since storage for no response commands is deallocated once they - * are successfully sent. - * @param pkt The request that was sent on the bus. - */ - void markInService(PacketPtr &pkt, MSHR* mshr); - - /** - * Collect statistics and free resources of a satisfied request. - * @param pkt The request that has been satisfied. - * @param time The time when the request is satisfied. - */ - void handleResponse(PacketPtr &pkt, Tick time); - - /** - * Removes all outstanding requests for a given thread number. If a request - * has been sent to the bus, this function removes all of its targets. - * @param threadNum The thread number of the requests to squash. - */ - void squash(int threadNum); - - /** - * Return the current number of outstanding misses. - * @return the number of outstanding misses. - */ - int getMisses() - { - return mq.getAllocatedTargets(); - } - - /** - * Searches for the supplied address in the miss queue. - * @param addr The address to look for. - * @param asid The address space id. - * @return The MSHR that contains the address, NULL if not found. - * @warning Currently only searches the miss queue. If non write allocate - * might need to search the write buffer for coherence. - */ - MSHR* findMSHR(Addr addr); - - /** - * Searches for the supplied address in the write buffer. - * @param addr The address to look for. - * @param asid The address space id. - * @param writes The list of writes that match the address. - * @return True if any writes are found - */ - bool findWrites(Addr addr, std::vector<MSHR*>& writes); - - /** - * Perform a writeback of dirty data to the given address. - * @param addr The address to write to. - * @param asid The address space id. - * @param xc The execution context of the address space. - * @param size The number of bytes to write. - * @param data The data to write, can be NULL. - * @param compressed True if the data is compressed. - */ - void doWriteback(Addr addr, - int size, uint8_t *data, bool compressed); - - /** - * Perform the given writeback request. - * @param pkt The writeback request. - */ - void doWriteback(PacketPtr &pkt); - - /** - * Returns true if there are outstanding requests. - * @return True if there are outstanding requests. - */ - bool havePending(); - - /** - * Add a target to the given MSHR. This assumes it is in the miss queue. - * @param mshr The mshr to add a target to. - * @param pkt The target to add. - */ - void addTarget(MSHR *mshr, PacketPtr &pkt) - { - mq.allocateTarget(mshr, pkt); - } - - /** - * Allocate a MSHR to hold a list of targets to a block involved in a copy. - * If the block is marked done then the MSHR already holds the data to - * fill the block. Otherwise the block needs to be fetched. - * @param addr The address to buffer. - * @param asid The address space ID. - * @return A pointer to the allocated MSHR. - */ - MSHR* allocateTargetList(Addr addr); - -}; - -#endif //__MISS_QUEUE_HH__ diff --git a/src/mem/cache/miss/mshr.cc b/src/mem/cache/miss/mshr.cc index 74dad658b..5ba3d1ec5 100644 --- a/src/mem/cache/miss/mshr.cc +++ b/src/mem/cache/miss/mshr.cc @@ -37,6 +37,7 @@ #include <assert.h> #include <string> #include <vector> +#include <algorithm> #include "mem/cache/miss/mshr.hh" #include "sim/core.hh" // for curTick @@ -51,57 +52,126 @@ MSHR::MSHR() inService = false; ntargets = 0; threadNum = -1; + targets = new TargetList(); + deferredTargets = new TargetList(); } + +MSHR::TargetList::TargetList() + : needsExclusive(false), hasUpgrade(false) +{} + + +inline void +MSHR::TargetList::add(PacketPtr pkt, Tick readyTime, + Counter order, bool cpuSide) +{ + if (cpuSide) { + if (pkt->needsExclusive()) { + needsExclusive = true; + } + + if (pkt->cmd == MemCmd::UpgradeReq) { + hasUpgrade = true; + } + + MSHR *mshr = dynamic_cast<MSHR*>(pkt->senderState); + if (mshr != NULL) { + assert(!mshr->downstreamPending); + mshr->downstreamPending = true; + } + } + + push_back(Target(pkt, readyTime, order, cpuSide)); +} + + void -MSHR::allocate(MemCmd cmd, Addr _addr, int size, - PacketPtr &target) +MSHR::TargetList::replaceUpgrades() { - addr = _addr; - if (target) - { - //Have a request, just use it - pkt = new Packet(target->req, cmd, Packet::Broadcast, size); - pkt->time = curTick; - pkt->allocate(); - pkt->senderState = (Packet::SenderState *)this; - allocateTarget(target); + if (!hasUpgrade) + return; + + Iterator end_i = end(); + for (Iterator i = begin(); i != end_i; ++i) { + if (i->pkt->cmd == MemCmd::UpgradeReq) { + i->pkt->cmd = MemCmd::ReadExReq; + DPRINTF(Cache, "Replacing UpgradeReq with ReadExReq\n"); + } } - else - { - //need a request first - Request * req = new Request(); - req->setPhys(addr, size, 0); - //Thread context?? - pkt = new Packet(req, cmd, Packet::Broadcast, size); - pkt->time = curTick; - pkt->allocate(); - pkt->senderState = (Packet::SenderState *)this; + + hasUpgrade = false; +} + + +void +MSHR::TargetList::clearDownstreamPending() +{ + Iterator end_i = end(); + for (Iterator i = begin(); i != end_i; ++i) { + MSHR *mshr = dynamic_cast<MSHR*>(i->pkt->senderState); + if (mshr != NULL) { + assert(mshr->downstreamPending); + mshr->downstreamPending = false; + } } } -// Since we aren't sure if data is being used, don't copy here. -/** - * @todo When we have a "global" data flag, might want to copy data here. - */ + void -MSHR::allocateAsBuffer(PacketPtr &target) +MSHR::allocate(Addr _addr, int _size, PacketPtr target, + Tick whenReady, Counter _order) { - addr = target->getAddr(); - threadNum = 0/*target->req->getThreadNum()*/; - pkt = new Packet(target->req, target->cmd, -1); - pkt->allocate(); - pkt->senderState = (Packet::SenderState*)this; - pkt->time = curTick; + addr = _addr; + size = _size; + readyTime = whenReady; + order = _order; + assert(target); + isCacheFill = false; + _isUncacheable = target->req->isUncacheable(); + inService = false; + downstreamPending = false; + threadNum = 0; + ntargets = 1; + // Don't know of a case where we would allocate a new MSHR for a + // snoop (mem-side request), so set cpuSide to true here. + assert(targets->isReset()); + targets->add(target, whenReady, _order, true); + assert(deferredTargets->isReset()); + pendingInvalidate = false; + pendingShared = false; + data = NULL; } + +bool +MSHR::markInService() +{ + assert(!inService); + if (isSimpleForward()) { + // we just forwarded the request packet & don't expect a + // response, so get rid of it + assert(getNumTargets() == 1); + popTarget(); + return true; + } + inService = true; + if (!downstreamPending) { + // let upstream caches know that the request has made it to a + // level where it's going to get a response + targets->clearDownstreamPending(); + } + return false; +} + + void MSHR::deallocate() { - assert(targets.empty()); + assert(targets->empty()); + targets->resetFlags(); + assert(deferredTargets->isReset()); assert(ntargets == 0); - delete pkt; - pkt = NULL; inService = false; //allocIter = NULL; //readyIter = NULL; @@ -111,48 +181,143 @@ MSHR::deallocate() * Adds a target to an MSHR */ void -MSHR::allocateTarget(PacketPtr &target) +MSHR::allocateTarget(PacketPtr pkt, Tick whenReady, Counter _order) { - //If we append an invalidate and we issued a read to the bus, - //but now have some pending writes, we need to move - //the invalidate to before the first non-read - if (inService && pkt->isRead() && target->isInvalidate()) { - std::list<PacketPtr> temp; - - while (!targets.empty()) { - if (!targets.front()->isRead()) break; - //Place on top of temp stack - temp.push_front(targets.front()); - //Remove from targets - targets.pop_front(); - } + // if there's a request already in service for this MSHR, we will + // have to defer the new target until after the response if any of + // the following are true: + // - there are other targets already deferred + // - there's a pending invalidate to be applied after the response + // comes back (but before this target is processed) + // - the outstanding request is for a non-exclusive block and this + // target requires an exclusive block + if (inService && + (!deferredTargets->empty() || pendingInvalidate || + (!targets->needsExclusive && pkt->needsExclusive()))) { + // need to put on deferred list + deferredTargets->add(pkt, whenReady, _order, true); + } else { + // no request outstanding, or still OK to append to + // outstanding request + targets->add(pkt, whenReady, _order, true); + } - //Now that we have all the reads off until first non-read, we can - //place the invalidate on - targets.push_front(target); + ++ntargets; +} - //Now we pop off the temp_stack and put them back - while (!temp.empty()) { - targets.push_front(temp.front()); - temp.pop_front(); +bool +MSHR::handleSnoop(PacketPtr pkt, Counter _order) +{ + if (!inService || (pkt->isExpressSnoop() && downstreamPending)) { + // Request has not been issued yet, or it's been issued + // locally but is buffered unissued at some downstream cache + // which is forwarding us this snoop. Either way, the packet + // we're snooping logically precedes this MSHR's request, so + // the snoop has no impact on the MSHR, but must be processed + // in the standard way by the cache. The only exception is + // that if we're an L2+ cache buffering an UpgradeReq from a + // higher-level cache, and the snoop is invalidating, then our + // buffered upgrades must be converted to read exclusives, + // since the upper-level cache no longer has a valid copy. + // That is, even though the upper-level cache got out on its + // local bus first, some other invalidating transaction + // reached the global bus before the upgrade did. + if (pkt->needsExclusive()) { + targets->replaceUpgrades(); + deferredTargets->replaceUpgrades(); } + + return false; } - else { - targets.push_back(target); + + // From here on down, the request issued by this MSHR logically + // precedes the request we're snooping. + + if (pkt->needsExclusive()) { + // snooped request still precedes the re-request we'll have to + // issue for deferred targets, if any... + deferredTargets->replaceUpgrades(); } - ++ntargets; - assert(targets.size() == ntargets); - /** - * @todo really prioritize the target commands. - */ + if (pendingInvalidate) { + // a prior snoop has already appended an invalidation, so + // logically we don't have the block anymore; no need for + // further snooping. + return true; + } + + if (targets->needsExclusive || pkt->needsExclusive()) { + // actual target device (typ. PhysicalMemory) will delete the + // packet on reception, so we need to save a copy here + PacketPtr cp_pkt = new Packet(pkt); + targets->add(cp_pkt, curTick, _order, false); + ++ntargets; - if (!inService && target->isWrite()) { - pkt->cmd = MemCmd::WriteReq; + if (targets->needsExclusive) { + // We're awaiting an exclusive copy, so ownership is pending. + // It's up to us to respond once the data arrives. + pkt->assertMemInhibit(); + pkt->setSupplyExclusive(); + } else { + // Someone else may respond before we get around to + // processing this snoop, which means the copied request + // pointer will no longer be valid + cp_pkt->req = NULL; + } + + if (pkt->needsExclusive()) { + // This transaction will take away our pending copy + pendingInvalidate = true; + } + } else { + // Read to a read: no conflict, so no need to record as + // target, but make sure neither reader thinks he's getting an + // exclusive copy + pendingShared = true; + pkt->assertShared(); } + + return true; } +bool +MSHR::promoteDeferredTargets() +{ + assert(targets->empty()); + if (deferredTargets->empty()) { + return false; + } + + // swap targets & deferredTargets lists + TargetList *tmp = targets; + targets = deferredTargets; + deferredTargets = tmp; + + assert(targets->size() == ntargets); + + // clear deferredTargets flags + deferredTargets->resetFlags(); + + pendingInvalidate = false; + pendingShared = false; + order = targets->front().order; + readyTime = std::max(curTick, targets->front().readyTime); + + return true; +} + + +void +MSHR::handleFill(Packet *pkt, CacheBlk *blk) +{ + if (pendingShared) { + // we snooped another read while this read was in + // service... assert shared line on its behalf + pkt->assertShared(); + } +} + void MSHR::dump() @@ -162,21 +327,20 @@ MSHR::dump() "Addr: %x ntargets %d\n" "Targets:\n", inService, threadNum, addr, ntargets); - - TargetListIterator tar_it = targets.begin(); +#if 0 + TargetListIterator tar_it = targets->begin(); for (int i = 0; i < ntargets; i++) { - assert(tar_it != targets.end()); + assert(tar_it != targets->end()); - ccprintf(cerr, "\t%d: Addr: %x cmd: %d\n", - i, (*tar_it)->getAddr(), (*tar_it)->cmdToIndex()); + ccprintf(cerr, "\t%d: Addr: %x cmd: %s\n", + i, tar_it->pkt->getAddr(), tar_it->pkt->cmdString()); tar_it++; } +#endif ccprintf(cerr, "\n"); } MSHR::~MSHR() { - if (pkt) - pkt = NULL; } diff --git a/src/mem/cache/miss/mshr.hh b/src/mem/cache/miss/mshr.hh index d0410acda..e850a8633 100644 --- a/src/mem/cache/miss/mshr.hh +++ b/src/mem/cache/miss/mshr.hh @@ -36,22 +36,54 @@ #ifndef __MSHR_HH__ #define __MSHR_HH__ -#include "mem/packet.hh" #include <list> -#include <deque> -class MSHR; +#include "mem/packet.hh" + +class CacheBlk; +class MSHRQueue; /** * Miss Status and handling Register. This class keeps all the information * needed to handle a cache miss including a list of target requests. */ -class MSHR { +class MSHR : public Packet::SenderState +{ + public: - /** Defines the Data structure of the MSHR targetlist. */ - typedef std::list<PacketPtr> TargetList; - /** Target list iterator. */ - typedef std::list<PacketPtr>::iterator TargetListIterator; + + class Target { + public: + Tick recvTime; //!< Time when request was received (for stats) + Tick readyTime; //!< Time when request is ready to be serviced + Counter order; //!< Global order (for memory consistency mgmt) + PacketPtr pkt; //!< Pending request packet. + bool cpuSide; //!< Did request come from cpu side or mem side? + + bool isCpuSide() { return cpuSide; } + + Target(PacketPtr _pkt, Tick _readyTime, Counter _order, bool _cpuSide) + : recvTime(curTick), readyTime(_readyTime), order(_order), + pkt(_pkt), cpuSide(_cpuSide) + {} + }; + + class TargetList : public std::list<Target> { + /** Target list iterator. */ + typedef std::list<Target>::iterator Iterator; + + public: + bool needsExclusive; + bool hasUpgrade; + + TargetList(); + void resetFlags() { needsExclusive = hasUpgrade = false; } + bool isReset() { return !needsExclusive && !hasUpgrade; } + void add(PacketPtr pkt, Tick readyTime, Counter order, bool cpuSide); + void replaceUpgrades(); + void clearDownstreamPending(); + }; + /** A list of MSHRs. */ typedef std::list<MSHR *> List; /** MSHR list iterator. */ @@ -59,28 +91,54 @@ class MSHR { /** MSHR list const_iterator. */ typedef List::const_iterator ConstIterator; - /** Address of the miss. */ + /** Pointer to queue containing this MSHR. */ + MSHRQueue *queue; + + /** Cycle when ready to issue */ + Tick readyTime; + + /** Order number assigned by the miss queue. */ + Counter order; + + /** Address of the request. */ Addr addr; - /** Adress space id of the miss. */ - short asid; + + /** Size of the request. */ + int size; + /** True if the request has been sent to the bus. */ bool inService; + + /** True if we will be putting the returned block in the cache */ + bool isCacheFill; + + /** True if we need to get an exclusive copy of the block. */ + bool needsExclusive() { return targets->needsExclusive; } + + /** True if the request is uncacheable */ + bool _isUncacheable; + + bool downstreamPending; + + bool pendingInvalidate; + bool pendingShared; + /** Thread number of the miss. */ - int threadNum; - /** The request that is forwarded to the next level of the hierarchy. */ - PacketPtr pkt; + short threadNum; /** The number of currently allocated targets. */ short ntargets; - /** The original requesting command. */ - MemCmd originalCmd; - /** Order number of assigned by the miss queue. */ - uint64_t order; + + + /** Data buffer (if needed). Currently used only for pending + * upgrade handling. */ + uint8_t *data; /** * Pointer to this MSHR on the ready list. * @sa MissQueue, MSHRQueue::readyList */ Iterator readyIter; + /** * Pointer to this MSHR on the allocated list. * @sa MissQueue, MSHRQueue::allocatedList @@ -89,9 +147,14 @@ class MSHR { private: /** List of all requests that match the address */ - TargetList targets; + TargetList *targets; + + TargetList *deferredTargets; public: + + bool isUncacheable() { return _isUncacheable; } + /** * Allocate a miss to this MSHR. * @param cmd The requesting command. @@ -100,14 +163,10 @@ public: * @param size The number of bytes to request. * @param pkt The original miss. */ - void allocate(MemCmd cmd, Addr addr, int size, - PacketPtr &pkt); + void allocate(Addr addr, int size, PacketPtr pkt, + Tick when, Counter _order); - /** - * Allocate this MSHR as a buffer for the given request. - * @param target The memory request to buffer. - */ - void allocateAsBuffer(PacketPtr &target); + bool markInService(); /** * Mark this MSHR as free. @@ -118,7 +177,8 @@ public: * Add a request to the list of targets. * @param target The target. */ - void allocateTarget(PacketPtr &target); + void allocateTarget(PacketPtr target, Tick when, Counter order); + bool handleSnoop(PacketPtr target, Counter order); /** A simple constructor. */ MSHR(); @@ -129,28 +189,25 @@ public: * Returns the current number of allocated targets. * @return The current number of allocated targets. */ - int getNumTargets() - { - return(ntargets); - } + int getNumTargets() { return ntargets; } /** * Returns a pointer to the target list. * @return a pointer to the target list. */ - TargetList* getTargetList() - { - return &targets; - } + TargetList *getTargetList() { return targets; } + + /** + * Returns true if there are targets left. + * @return true if there are targets + */ + bool hasTargets() { return !targets->empty(); } /** * Returns a reference to the first target. * @return A pointer to the first target. */ - PacketPtr getTarget() - { - return targets.front(); - } + Target *getTarget() { assert(hasTargets()); return &targets->front(); } /** * Pop first target. @@ -158,18 +215,21 @@ public: void popTarget() { --ntargets; - targets.pop_front(); + targets->pop_front(); } - /** - * Returns true if there are targets left. - * @return true if there are targets - */ - bool hasTargets() + bool isSimpleForward() { - return !targets.empty(); + if (getNumTargets() != 1) + return false; + Target *tgt = getTarget(); + return tgt->isCpuSide() && !tgt->pkt->needsResponse(); } + bool promoteDeferredTargets(); + + void handleFill(Packet *pkt, CacheBlk *blk); + /** * Prints the contents of this MSHR to stderr. */ diff --git a/src/mem/cache/miss/mshr_queue.cc b/src/mem/cache/miss/mshr_queue.cc index add11dfe7..50a28fb3c 100644 --- a/src/mem/cache/miss/mshr_queue.cc +++ b/src/mem/cache/miss/mshr_queue.cc @@ -29,22 +29,22 @@ */ /** @file - * Definition of the MSHRQueue. + * Definition of MSHRQueue class functions. */ #include "mem/cache/miss/mshr_queue.hh" -#include "sim/eventq.hh" using namespace std; -MSHRQueue::MSHRQueue(int num_mshrs, int reserve) - : numMSHRs(num_mshrs + reserve - 1), numReserve(reserve) +MSHRQueue::MSHRQueue(int num_entries, int reserve, int _index) + : numEntries(num_entries + reserve - 1), numReserve(reserve), + index(_index) { allocated = 0; - inServiceMSHRs = 0; - allocatedTargets = 0; - registers = new MSHR[numMSHRs]; - for (int i = 0; i < numMSHRs; ++i) { + inServiceEntries = 0; + registers = new MSHR[numEntries]; + for (int i = 0; i < numEntries; ++i) { + registers[i].queue = this; freeList.push_back(®isters[i]); } } @@ -54,7 +54,7 @@ MSHRQueue::~MSHRQueue() delete [] registers; } -MSHR* +MSHR * MSHRQueue::findMatch(Addr addr) const { MSHR::ConstIterator i = allocatedList.begin(); @@ -87,19 +87,19 @@ MSHRQueue::findMatches(Addr addr, vector<MSHR*>& matches) const } -MSHR* -MSHRQueue::findPending(PacketPtr &pkt) const +MSHR * +MSHRQueue::findPending(Addr addr, int size) const { - MSHR::ConstIterator i = pendingList.begin(); - MSHR::ConstIterator end = pendingList.end(); + MSHR::ConstIterator i = readyList.begin(); + MSHR::ConstIterator end = readyList.end(); for (; i != end; ++i) { MSHR *mshr = *i; - if (mshr->addr < pkt->getAddr()) { - if (mshr->addr + mshr->pkt->getSize() > pkt->getAddr()) { + if (mshr->addr < addr) { + if (mshr->addr + mshr->size > addr) { return mshr; } } else { - if (pkt->getAddr() + pkt->getSize() > mshr->addr) { + if (addr + size > mshr->addr) { return mshr; } } @@ -107,76 +107,60 @@ MSHRQueue::findPending(PacketPtr &pkt) const return NULL; } -MSHR* -MSHRQueue::allocate(PacketPtr &pkt, int size) -{ - Addr aligned_addr = pkt->getAddr() & ~((Addr)size - 1); - assert(!freeList.empty()); - MSHR *mshr = freeList.front(); - assert(mshr->getNumTargets() == 0); - freeList.pop_front(); - if (!pkt->needsResponse()) { - mshr->allocateAsBuffer(pkt); - } else { - assert(size !=0); - mshr->allocate(pkt->cmd, aligned_addr, size, pkt); - allocatedTargets += 1; +MSHR::Iterator +MSHRQueue::addToReadyList(MSHR *mshr) +{ + if (readyList.empty() || readyList.back()->readyTime <= mshr->readyTime) { + return readyList.insert(readyList.end(), mshr); } - mshr->allocIter = allocatedList.insert(allocatedList.end(), mshr); - mshr->readyIter = pendingList.insert(pendingList.end(), mshr); - allocated += 1; - return mshr; + MSHR::Iterator i = readyList.begin(); + MSHR::Iterator end = readyList.end(); + for (; i != end; ++i) { + if ((*i)->readyTime > mshr->readyTime) { + return readyList.insert(i, mshr); + } + } + assert(false); + return end; // keep stupid compilers happy } -MSHR* -MSHRQueue::allocateFetch(Addr addr, int size, PacketPtr &target) + +MSHR * +MSHRQueue::allocate(Addr addr, int size, PacketPtr &pkt, + Tick when, Counter order) { + assert(!freeList.empty()); MSHR *mshr = freeList.front(); assert(mshr->getNumTargets() == 0); freeList.pop_front(); - mshr->allocate(MemCmd::ReadReq, addr, size, target); + + mshr->allocate(addr, size, pkt, when, order); mshr->allocIter = allocatedList.insert(allocatedList.end(), mshr); - mshr->readyIter = pendingList.insert(pendingList.end(), mshr); + mshr->readyIter = addToReadyList(mshr); allocated += 1; return mshr; } -MSHR* -MSHRQueue::allocateTargetList(Addr addr, int size) -{ - MSHR *mshr = freeList.front(); - assert(mshr->getNumTargets() == 0); - freeList.pop_front(); - PacketPtr dummy; - mshr->allocate(MemCmd::ReadReq, addr, size, dummy); - mshr->allocIter = allocatedList.insert(allocatedList.end(), mshr); - mshr->inService = true; - ++inServiceMSHRs; - ++allocated; - return mshr; -} - void -MSHRQueue::deallocate(MSHR* mshr) +MSHRQueue::deallocate(MSHR *mshr) { deallocateOne(mshr); } MSHR::Iterator -MSHRQueue::deallocateOne(MSHR* mshr) +MSHRQueue::deallocateOne(MSHR *mshr) { MSHR::Iterator retval = allocatedList.erase(mshr->allocIter); freeList.push_front(mshr); allocated--; - allocatedTargets -= mshr->getNumTargets(); if (mshr->inService) { - inServiceMSHRs--; + inServiceEntries--; } else { - pendingList.erase(mshr->readyIter); + readyList.erase(mshr->readyIter); } mshr->deallocate(); return retval; @@ -187,40 +171,33 @@ MSHRQueue::moveToFront(MSHR *mshr) { if (!mshr->inService) { assert(mshr == *(mshr->readyIter)); - pendingList.erase(mshr->readyIter); - mshr->readyIter = pendingList.insert(pendingList.begin(), mshr); + readyList.erase(mshr->readyIter); + mshr->readyIter = readyList.insert(readyList.begin(), mshr); } } void -MSHRQueue::markInService(MSHR* mshr) +MSHRQueue::markInService(MSHR *mshr) { - //assert(mshr == pendingList.front()); - if (!mshr->pkt->needsResponse() && !(mshr->pkt->cmd == MemCmd::UpgradeReq)) { - assert(mshr->getNumTargets() == 0); + if (mshr->markInService()) { deallocate(mshr); - return; + } else { + readyList.erase(mshr->readyIter); + inServiceEntries += 1; } - mshr->inService = true; - pendingList.erase(mshr->readyIter); - //mshr->readyIter = NULL; - inServiceMSHRs += 1; - //pendingList.pop_front(); } void -MSHRQueue::markPending(MSHR* mshr, MemCmd cmd) +MSHRQueue::markPending(MSHR *mshr) { - //assert(mshr->readyIter == NULL); - mshr->pkt->cmd = cmd; - mshr->pkt->flags &= ~SATISFIED; + assert(mshr->inService); mshr->inService = false; - --inServiceMSHRs; + --inServiceEntries; /** * @ todo might want to add rerequests to front of pending list for * performance. */ - mshr->readyIter = pendingList.insert(pendingList.end(), mshr); + mshr->readyIter = addToReadyList(mshr); } void @@ -232,11 +209,8 @@ MSHRQueue::squash(int threadNum) MSHR *mshr = *i; if (mshr->threadNum == threadNum) { while (mshr->hasTargets()) { - PacketPtr target = mshr->getTarget(); mshr->popTarget(); - assert(0/*target->req->getThreadNum()*/ == threadNum); - target = NULL; } assert(!mshr->hasTargets()); assert(mshr->ntargets==0); diff --git a/src/mem/cache/miss/mshr_queue.hh b/src/mem/cache/miss/mshr_queue.hh index 5069db661..1f1d59e98 100644 --- a/src/mem/cache/miss/mshr_queue.hh +++ b/src/mem/cache/miss/mshr_queue.hh @@ -32,71 +32,77 @@ * Declaration of a structure to manage MSHRs. */ -#ifndef __MSHR_QUEUE_HH__ -#define __MSHR_QUEUE_HH__ +#ifndef __MEM__CACHE__MISS__MSHR_QUEUE_HH__ +#define __MEM__CACHE__MISS__MSHR_QUEUE_HH__ #include <vector> + +#include "mem/packet.hh" #include "mem/cache/miss/mshr.hh" /** * A Class for maintaining a list of pending and allocated memory requests. */ -class MSHRQueue { +class MSHRQueue +{ private: /** MSHR storage. */ - MSHR* registers; - /** Holds pointers to all allocated MSHRs. */ + MSHR *registers; + /** Holds pointers to all allocated entries. */ MSHR::List allocatedList; - /** Holds pointers to MSHRs that haven't been sent to the bus. */ - MSHR::List pendingList; - /** Holds non allocated MSHRs. */ + /** Holds pointers to entries that haven't been sent to the bus. */ + MSHR::List readyList; + /** Holds non allocated entries. */ MSHR::List freeList; // Parameters /** - * The total number of MSHRs in this queue. This number is set as the - * number of MSHRs requested plus (numReserve - 1). This allows for - * the same number of effective MSHRs while still maintaining the reserve. + * The total number of entries in this queue. This number is set as the + * number of entries requested plus (numReserve - 1). This allows for + * the same number of effective entries while still maintaining the reserve. */ - const int numMSHRs; + const int numEntries; /** - * The number of MSHRs to hold in reserve. This is needed because copy - * operations can allocate upto 4 MSHRs at one time. + * The number of entries to hold in reserve. This is needed because copy + * operations can allocate upto 4 entries at one time. */ const int numReserve; + MSHR::Iterator addToReadyList(MSHR *mshr); + + public: - /** The number of allocated MSHRs. */ + /** The number of allocated entries. */ int allocated; - /** The number of MSHRs that have been forwarded to the bus. */ - int inServiceMSHRs; - /** The number of targets waiting for response. */ - int allocatedTargets; + /** The number of entries that have been forwarded to the bus. */ + int inServiceEntries; + /** The index of this queue within the cache (MSHR queue vs. write + * buffer). */ + const int index; /** - * Create a queue with a given number of MSHRs. - * @param num_mshrs The number of MSHRs in this queue. - * @param reserve The minimum number of MSHRs needed to satisfy any access. + * Create a queue with a given number of entries. + * @param num_entrys The number of entries in this queue. + * @param reserve The minimum number of entries needed to satisfy + * any access. */ - MSHRQueue(int num_mshrs, int reserve = 1); + MSHRQueue(int num_entries, int reserve, int index); /** Destructor */ ~MSHRQueue(); /** - * Find the first MSHR that matches the provide address and asid. + * Find the first MSHR that matches the provided address. * @param addr The address to find. - * @param asid The address space id. * @return Pointer to the matching MSHR, null if not found. */ - MSHR* findMatch(Addr addr) const; + MSHR *findMatch(Addr addr) const; /** - * Find and return all the matching MSHRs in the provided vector. + * Find and return all the matching entries in the provided vector. * @param addr The address to find. - * @param asid The address space ID. - * @param matches The vector to return pointers to the matching MSHRs. + * @param matches The vector to return pointers to the matching entries. * @return True if any matches are found, false otherwise. * @todo Typedef the vector?? */ @@ -107,7 +113,7 @@ class MSHRQueue { * @param pkt The request to find. * @return A pointer to the earliest matching MSHR. */ - MSHR* findPending(PacketPtr &pkt) const; + MSHR *findPending(Addr addr, int size) const; /** * Allocates a new MSHR for the request and size. This places the request @@ -116,76 +122,45 @@ class MSHRQueue { * @param size The number in bytes to fetch from memory. * @return The a pointer to the MSHR allocated. * - * @pre There are free MSHRs. - */ - MSHR* allocate(PacketPtr &pkt, int size = 0); - - /** - * Allocate a read request for the given address, and places the given - * target on the target list. - * @param addr The address to fetch. - * @param asid The address space for the fetch. - * @param size The number of bytes to request. - * @param target The first target for the request. - * @return Pointer to the new MSHR. - */ - MSHR* allocateFetch(Addr addr, int size, PacketPtr &target); - - /** - * Allocate a target list for the given address. - * @param addr The address to fetch. - * @param asid The address space for the fetch. - * @param size The number of bytes to request. - * @return Pointer to the new MSHR. + * @pre There are free entries. */ - MSHR* allocateTargetList(Addr addr, int size); + MSHR *allocate(Addr addr, int size, PacketPtr &pkt, + Tick when, Counter order); /** * Removes the given MSHR from the queue. This places the MSHR on the * free list. * @param mshr */ - void deallocate(MSHR* mshr); + void deallocate(MSHR *mshr); /** - * Allocates a target to the given MSHR. Used to keep track of the number - * of outstanding targets. - * @param mshr The MSHR to allocate the target to. - * @param pkt The target request. - */ - void allocateTarget(MSHR* mshr, PacketPtr &pkt) - { - mshr->allocateTarget(pkt); - allocatedTargets += 1; - } - - /** - * Remove a MSHR from the queue. Returns an iterator into the allocatedList - * for faster squash implementation. + * Remove a MSHR from the queue. Returns an iterator into the + * allocatedList for faster squash implementation. * @param mshr The MSHR to remove. * @return An iterator to the next entry in the allocatedList. */ - MSHR::Iterator deallocateOne(MSHR* mshr); + MSHR::Iterator deallocateOne(MSHR *mshr); /** - * Moves the MSHR to the front of the pending list if it is not in service. - * @param mshr The mshr to move. + * Moves the MSHR to the front of the pending list if it is not + * in service. + * @param mshr The entry to move. */ void moveToFront(MSHR *mshr); /** * Mark the given MSHR as in service. This removes the MSHR from the - * pendingList. Deallocates the MSHR if it does not expect a response. + * readyList. Deallocates the MSHR if it does not expect a response. * @param mshr The MSHR to mark in service. */ - void markInService(MSHR* mshr); + void markInService(MSHR *mshr); /** - * Mark an in service mshr as pending, used to resend a request. + * Mark an in service entry as pending, used to resend a request. * @param mshr The MSHR to resend. - * @param cmd The command to resend. */ - void markPending(MSHR* mshr, MemCmd cmd); + void markPending(MSHR *mshr); /** * Squash outstanding requests with the given thread number. If a request @@ -200,40 +175,34 @@ class MSHRQueue { */ bool havePending() const { - return !pendingList.empty(); + return !readyList.empty(); } /** - * Returns true if there are no free MSHRs. + * Returns true if there are no free entries. * @return True if this queue is full. */ bool isFull() const { - return (allocated > numMSHRs - numReserve); + return (allocated > numEntries - numReserve); } /** - * Returns the request at the head of the pendingList. + * Returns the MSHR at the head of the readyList. * @return The next request to service. */ - PacketPtr getReq() const + MSHR *getNextMSHR() const { - if (pendingList.empty()) { + if (readyList.empty() || readyList.front()->readyTime > curTick) { return NULL; } - MSHR* mshr = pendingList.front(); - return mshr->pkt; + return readyList.front(); } - /** - * Returns the number of outstanding targets. - * @return the number of allocated targets. - */ - int getAllocatedTargets() const + Tick nextMSHRReadyTime() const { - return allocatedTargets; + return readyList.empty() ? MaxTick : readyList.front()->readyTime; } - }; -#endif //__MSHR_QUEUE_HH__ +#endif //__MEM__CACHE__MISS__MSHR_QUEUE_HH__ |