summaryrefslogtreecommitdiff
path: root/src/mem/cache/miss
diff options
context:
space:
mode:
authorRon Dreslinski <rdreslin@umich.edu>2006-06-28 11:02:14 -0400
committerRon Dreslinski <rdreslin@umich.edu>2006-06-28 11:02:14 -0400
commited8564a6b9f0702a40995d95cc4da54de3d35462 (patch)
tree156901f9e5a2e92ddfa44eea664103de5d210aa7 /src/mem/cache/miss
parentecab4b426c949dad797df0bde1c0c120b4b5fb00 (diff)
downloadgem5-ed8564a6b9f0702a40995d95cc4da54de3d35462.tar.xz
Was having difficulty with merging the cache, reverted to an early version and will add back in the patches to make it work soon.
src/mem/cache/prefetch/tagged_prefetcher_impl.hh: Trying to merge src/mem/cache/base_cache.cc: src/mem/cache/base_cache.hh: src/mem/cache/cache.cc: src/mem/cache/cache.hh: src/mem/cache/cache_blk.hh: src/mem/cache/cache_builder.cc: src/mem/cache/cache_impl.hh: src/mem/cache/coherence/coherence_protocol.cc: src/mem/cache/coherence/coherence_protocol.hh: src/mem/cache/coherence/simple_coherence.hh: src/mem/cache/coherence/uni_coherence.cc: src/mem/cache/coherence/uni_coherence.hh: src/mem/cache/miss/blocking_buffer.cc: src/mem/cache/miss/blocking_buffer.hh: src/mem/cache/miss/miss_queue.cc: src/mem/cache/miss/miss_queue.hh: src/mem/cache/miss/mshr.cc: src/mem/cache/miss/mshr.hh: src/mem/cache/miss/mshr_queue.cc: src/mem/cache/miss/mshr_queue.hh: src/mem/cache/prefetch/base_prefetcher.cc: src/mem/cache/prefetch/base_prefetcher.hh: src/mem/cache/prefetch/ghb_prefetcher.cc: src/mem/cache/prefetch/ghb_prefetcher.hh: src/mem/cache/prefetch/stride_prefetcher.cc: src/mem/cache/prefetch/stride_prefetcher.hh: src/mem/cache/prefetch/tagged_prefetcher.hh: src/mem/cache/tags/base_tags.cc: src/mem/cache/tags/base_tags.hh: src/mem/cache/tags/fa_lru.cc: src/mem/cache/tags/fa_lru.hh: src/mem/cache/tags/iic.cc: src/mem/cache/tags/iic.hh: src/mem/cache/tags/lru.cc: src/mem/cache/tags/lru.hh: src/mem/cache/tags/repl/gen.cc: src/mem/cache/tags/repl/gen.hh: src/mem/cache/tags/repl/repl.cc: src/mem/cache/tags/repl/repl.hh: src/mem/cache/tags/split.cc: src/mem/cache/tags/split.hh: src/mem/cache/tags/split_blk.hh: src/mem/cache/tags/split_lifo.cc: src/mem/cache/tags/split_lifo.hh: src/mem/cache/tags/split_lru.cc: src/mem/cache/tags/split_lru.hh: Pulling an early version of the cache into the tree due to merging issues. Will apply patches and push. --HG-- extra : convert_revision : 3276e5fb9a6272681a1690babf2b586dd0e1f380
Diffstat (limited to 'src/mem/cache/miss')
-rw-r--r--src/mem/cache/miss/blocking_buffer.cc261
-rw-r--r--src/mem/cache/miss/blocking_buffer.hh257
-rw-r--r--src/mem/cache/miss/miss_queue.cc736
-rw-r--r--src/mem/cache/miss/miss_queue.hh349
-rw-r--r--src/mem/cache/miss/mshr.cc182
-rw-r--r--src/mem/cache/miss/mshr.hh179
-rw-r--r--src/mem/cache/miss/mshr_queue.cc269
-rw-r--r--src/mem/cache/miss/mshr_queue.hh239
8 files changed, 2472 insertions, 0 deletions
diff --git a/src/mem/cache/miss/blocking_buffer.cc b/src/mem/cache/miss/blocking_buffer.cc
new file mode 100644
index 000000000..621855c3d
--- /dev/null
+++ b/src/mem/cache/miss/blocking_buffer.cc
@@ -0,0 +1,261 @@
+/*
+ * 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 "cpu/exec_context.hh"
+#include "cpu/smt.hh" //for maxThreadsPerCPU
+#include "mem/cache/base_cache.hh"
+#include "mem/cache/miss/blocking_buffer.hh"
+#include "mem/cache/prefetch/base_prefetcher.hh"
+#include "sim/eventq.hh" // for Event declaration.
+
+using namespace TheISA;
+
+/**
+ * @todo Move writebacks into shared BaseBuffer class.
+ */
+void
+BlockingBuffer::regStats(const std::string &name)
+{
+ using namespace Stats;
+ writebacks
+ .init(maxThreadsPerCPU)
+ .name(name + ".writebacks")
+ .desc("number of writebacks")
+ .flags(total)
+ ;
+}
+
+void
+BlockingBuffer::setCache(BaseCache *_cache)
+{
+ cache = _cache;
+ blkSize = cache->getBlockSize();
+}
+
+void
+BlockingBuffer::setPrefetcher(BasePrefetcher *_prefetcher)
+{
+ prefetcher = _prefetcher;
+}
+void
+BlockingBuffer::handleMiss(Packet * &pkt, int blk_size, Tick time)
+{
+ Addr blk_addr = pkt->paddr & ~(Addr)(blk_size - 1);
+ if (pkt->cmd.isWrite() && (pkt->isUncacheable() || !writeAllocate ||
+ pkt->cmd.isNoResponse())) {
+ if (pkt->cmd.isNoResponse()) {
+ wb.allocateAsBuffer(pkt);
+ } else {
+ wb.allocate(pkt->cmd, blk_addr, pkt->req->asid, blk_size, pkt);
+ }
+ if (cache->doData()) {
+ memcpy(wb.pkt->data, pkt->data, blk_size);
+ }
+ cache->setBlocked(Blocked_NoWBBuffers);
+ cache->setMasterRequest(Request_WB, time);
+ return;
+ }
+
+ if (pkt->cmd.isNoResponse()) {
+ miss.allocateAsBuffer(pkt);
+ } else {
+ miss.allocate(pkt->cmd, blk_addr, pkt->req->asid, blk_size, pkt);
+ }
+ if (!pkt->isUncacheable()) {
+ miss.pkt->flags |= CACHE_LINE_FILL;
+ }
+ cache->setBlocked(Blocked_NoMSHRs);
+ cache->setMasterRequest(Request_MSHR, time);
+}
+
+Packet *
+BlockingBuffer::getPacket()
+{
+ if (miss.pkt && !miss.inService) {
+ return miss.pkt;
+ }
+ return wb.pkt;
+}
+
+void
+BlockingBuffer::setBusCmd(Packet * &pkt, Packet::Command cmd)
+{
+ MSHR *mshr = pkt->senderState;
+ mshr->originalCmd = pkt->cmd;
+ if (pkt->isCacheFill())
+ pkt->cmd = cmd;
+}
+
+void
+BlockingBuffer::restoreOrigCmd(Packet * &pkt)
+{
+ pkt->cmd = pkt->senderState->originalCmd;
+}
+
+void
+BlockingBuffer::markInService(Packet * &pkt)
+{
+ if (!pkt->isCacheFill() && pkt->cmd.isWrite()) {
+ // Forwarding a write/ writeback, don't need to change
+ // the command
+ assert(pkt->senderState == &wb);
+ cache->clearMasterRequest(Request_WB);
+ if (pkt->cmd.isNoResponse()) {
+ assert(wb.getNumTargets() == 0);
+ wb.deallocate();
+ cache->clearBlocked(Blocked_NoWBBuffers);
+ } else {
+ wb.inService = true;
+ }
+ } else {
+ assert(pkt->senderState == &miss);
+ cache->clearMasterRequest(Request_MSHR);
+ if (pkt->cmd.isNoResponse()) {
+ assert(miss.getNumTargets() == 0);
+ miss.deallocate();
+ cache->clearBlocked(Blocked_NoMSHRs);
+ } else {
+ //mark in service
+ miss.inService = true;
+ }
+ }
+}
+
+void
+BlockingBuffer::handleResponse(Packet * &pkt, Tick time)
+{
+ if (pkt->isCacheFill()) {
+ // targets were handled in the cache tags
+ assert(pkt->senderState == &miss);
+ miss.deallocate();
+ cache->clearBlocked(Blocked_NoMSHRs);
+ } else {
+ if (pkt->senderState->hasTargets()) {
+ // Should only have 1 target if we had any
+ assert(pkt->senderState->getNumTargets() == 1);
+ Packet * target = pkt->senderState->getTarget();
+ pkt->senderState->popTarget();
+ if (cache->doData() && pkt->cmd.isRead()) {
+ memcpy(target->data, pkt->data, target->size);
+ }
+ cache->respond(target, time);
+ assert(!pkt->senderState->hasTargets());
+ }
+
+ if (pkt->cmd.isWrite()) {
+ assert(pkt->senderState == &wb);
+ wb.deallocate();
+ cache->clearBlocked(Blocked_NoWBBuffers);
+ } else {
+ miss.deallocate();
+ cache->clearBlocked(Blocked_NoMSHRs);
+ }
+ }
+}
+
+void
+BlockingBuffer::squash(int thread_number)
+{
+ if (miss.threadNum == thread_number) {
+ Packet * target = miss.getTarget();
+ miss.popTarget();
+ assert(target->thread_num == thread_number);
+ if (target->completionEvent != NULL) {
+ delete target->completionEvent;
+ }
+ 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 asid, ExecContext *xc,
+ int size, uint8_t *data, bool compressed)
+{
+
+ // Generate request
+ Packet * pkt = new Packet();
+ pkt->paddr = addr;
+ pkt->req->asid = asid;
+ pkt->size = size;
+ pkt->data = new uint8_t[size];
+ if (data) {
+ memcpy(pkt->data, data, size);
+ }
+ /**
+ * @todo Need to find a way to charge the writeback to the "correct"
+ * thread.
+ */
+ pkt->xc = xc;
+ if (xc)
+ pkt->thread_num = xc->getThreadNum();
+ else
+ pkt->thread_num = 0;
+
+ pkt->cmd = Writeback;
+ if (compressed) {
+ pkt->flags |= COMPRESSED;
+ }
+
+ writebacks[pkt->thread_num]++;
+
+ wb.allocateAsBuffer(pkt);
+ cache->setMasterRequest(Request_WB, curTick);
+ cache->setBlocked(Blocked_NoWBBuffers);
+}
+
+
+
+void
+BlockingBuffer::doWriteback(Packet * &pkt)
+{
+ writebacks[pkt->thread_num]++;
+
+ wb.allocateAsBuffer(pkt);
+
+ // Since allocate as buffer copies the request,
+ // need to copy data here.
+ if (cache->doData()) {
+ memcpy(wb.pkt->data, pkt->data, pkt->size);
+ }
+ cache->setBlocked(Blocked_NoWBBuffers);
+ cache->setMasterRequest(Request_WB, curTick);
+}
diff --git a/src/mem/cache/miss/blocking_buffer.hh b/src/mem/cache/miss/blocking_buffer.hh
new file mode 100644
index 000000000..52256be74
--- /dev/null
+++ b/src/mem/cache/miss/blocking_buffer.hh
@@ -0,0 +1,257 @@
+/*
+ * 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 "mem/cache/miss/mshr.hh"
+#include "base/statistics.hh"
+
+class BaseCache;
+class BasePrefetcher;
+
+/**
+ * Miss and writeback storage for a blocking cache.
+ */
+class BlockingBuffer
+{
+protected:
+ /** Miss storage. */
+ MSHR miss;
+ /** WB storage. */
+ MSHR wb;
+
+ //Params
+
+ /** Allocate on write misses. */
+ const bool writeAllocate;
+
+ /** Pointer to the parent cache. */
+ BaseCache* cache;
+
+ BasePrefetcher* prefetcher;
+
+ /** Block size of the parent cache. */
+ int blkSize;
+
+ // Statistics
+ /**
+ * @addtogroup CacheStatistics
+ * @{
+ */
+ /** Number of blocks written back per thread. */
+ Stats::Vector<> writebacks;
+
+ /**
+ * @}
+ */
+
+public:
+ /**
+ * Builds and initializes this buffer.
+ * @param write_allocate If true, treat write misses the same as reads.
+ */
+ BlockingBuffer(bool write_allocate)
+ : writeAllocate(write_allocate)
+ {
+ }
+
+ /**
+ * Register statistics for this object.
+ * @param name The name of the parent cache.
+ */
+ void regStats(const std::string &name);
+
+ /**
+ * 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);
+
+ /**
+ * Handle a cache miss properly. Requests the bus and marks the cache as
+ * blocked.
+ * @param req 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(Packet * &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 asid, int blk_size, Tick time,
+ Packet * &target)
+ {
+ fatal("Unimplemented");
+ }
+
+ /**
+ * Selects a outstanding request to service.
+ * @return The request to service, NULL if none found.
+ */
+ Packet * getPacket();
+
+ /**
+ * Set the command to the given bus command.
+ * @param req The request to update.
+ * @param cmd The bus command to use.
+ */
+ void setBusCmd(Packet * &pkt, Packet::Command cmd);
+
+ /**
+ * Restore the original command in case of a bus transmission error.
+ * @param req The request to reset.
+ */
+ void restoreOrigCmd(Packet * &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 req The request that was sent on the bus.
+ */
+ void markInService(Packet * &pkt);
+
+ /**
+ * Frees the resources of the request and unblock the cache.
+ * @param req The request that has been satisfied.
+ * @param time The time when the request is satisfied.
+ */
+ void handleResponse(Packet * &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 thread_number The thread number of the requests to squash.
+ */
+ void squash(int thread_number);
+
+ /**
+ * 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, int asid)
+ {
+ if (miss.addr == addr && miss.pkt)
+ return &miss;
+ return NULL;
+ }
+
+ /**
+ * 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, int asid, std::vector<MSHR*>& writes)
+ {
+ if (wb.addr == addr && wb.pkt) {
+ writes.push_back(&wb);
+ return true;
+ }
+ return false;
+ }
+
+
+
+ /**
+ * 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 asid, ExecContext *xc,
+ int size, uint8_t *data, bool compressed);
+
+ /**
+ * Perform a writeback request.
+ * @param req The writeback request.
+ */
+ void doWriteback(Packet * &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 req The target to add.
+ */
+ void addTarget(MSHR *mshr, Packet * &pkt)
+ {
+ fatal("Shouldn't call this on a blocking buffer.");
+ }
+
+ /**
+ * Dummy implmentation.
+ */
+ MSHR* allocateTargetList(Addr addr, int asid)
+ {
+ fatal("Unimplemented");
+ }
+};
+
+#endif // __BLOCKING_BUFFER_HH__
diff --git a/src/mem/cache/miss/miss_queue.cc b/src/mem/cache/miss/miss_queue.cc
new file mode 100644
index 000000000..7902fbcee
--- /dev/null
+++ b/src/mem/cache/miss/miss_queue.cc
@@ -0,0 +1,736 @@
+/*
+ * 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/exec_context.hh"
+#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)
+ : mq(numMSHRs, 4), wb(write_buffers,numMSHRs+1000), numMSHR(numMSHRs),
+ numTarget(numTargets), writeBuffers(write_buffers),
+ writeAllocate(write_allocate), order(0), prefetchMiss(prefetch_miss)
+{
+ noTargetMSHR = NULL;
+}
+
+void
+MissQueue::regStats(const string &name)
+{
+ using namespace Stats;
+
+ writebacks
+ .init(maxThreadsPerCPU)
+ .name(name + ".writebacks")
+ .desc("number of writebacks")
+ .flags(total)
+ ;
+
+ // MSHR hit statistics
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)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[Read] + mshr_hits[Write];
+
+ overallMshrHits
+ .name(name + ".overall_mshr_hits")
+ .desc("number of overall MSHR hits")
+ .flags(total)
+ ;
+ overallMshrHits = demandMshrHits + mshr_hits[Soft_Prefetch] +
+ mshr_hits[Hard_Prefetch];
+
+ // MSHR miss statistics
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::CommandEnum)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[Read] + mshr_misses[Write];
+
+ overallMshrMisses
+ .name(name + ".overall_mshr_misses")
+ .desc("number of overall MSHR misses")
+ .flags(total)
+ ;
+ overallMshrMisses = demandMshrMisses + mshr_misses[Soft_Prefetch] +
+ mshr_misses[Hard_Prefetch];
+
+ // MSHR miss latency statistics
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::CommandEnum)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[Read] + mshr_miss_latency[Write];
+
+ overallMshrMissLatency
+ .name(name + ".overall_mshr_miss_latency")
+ .desc("number of overall MSHR miss cycles")
+ .flags(total)
+ ;
+ overallMshrMissLatency = demandMshrMissLatency +
+ mshr_miss_latency[Soft_Prefetch] + mshr_miss_latency[Hard_Prefetch];
+
+ // MSHR uncacheable statistics
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::CommandEnum)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[Read] + mshr_uncacheable[Write]
+ + mshr_uncacheable[Soft_Prefetch] + mshr_uncacheable[Hard_Prefetch];
+
+ // MSHR miss latency statistics
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::CommandEnum)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[Read]
+ + mshr_uncacheable_lat[Write] + mshr_uncacheable_lat[Soft_Prefetch]
+ + mshr_uncacheable_lat[Hard_Prefetch];
+
+#if 0
+ // MSHR access formulas
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::CommandEnum)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 < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::CommandEnum)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 < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::CommandEnum)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 < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::CommandEnum)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")
+ ;
+
+}
+
+void
+MissQueue::setCache(BaseCache *_cache)
+{
+ cache = _cache;
+ blkSize = cache->getBlockSize();
+}
+
+void
+MissQueue::setPrefetcher(BasePrefetcher *_prefetcher)
+{
+ prefetcher = _prefetcher;
+}
+
+MSHR*
+MissQueue::allocateMiss(Packet * &pkt, int size, Tick time)
+{
+ MSHR* mshr = mq.allocate(pkt, size);
+ mshr->order = order++;
+ if (!pkt->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 != Hard_Prefetch) {
+ //If we need to request the bus (not on HW prefetch), do so
+ cache->setMasterRequest(Request_MSHR, time);
+ }
+ return mshr;
+}
+
+
+MSHR*
+MissQueue::allocateWrite(Packet * &pkt, int size, Tick time)
+{
+ MSHR* mshr = wb.allocate(pkt,pkt->size);
+ mshr->order = order++;
+ if (cache->doData()){
+ if (pkt->isCompressed()) {
+ delete [] mshr->pkt->data;
+ mshr->pkt->actualSize = pkt->actualSize;
+ mshr->pkt->data = new uint8_t[pkt->actualSize];
+ memcpy(mshr->pkt->data, pkt->data, pkt->actualSize);
+ } else {
+ memcpy(mshr->pkt->data, pkt->data, pkt->size);
+ }
+ }
+ if (wb.isFull()) {
+ cache->setBlocked(Blocked_NoWBBuffers);
+ }
+
+ cache->setMasterRequest(Request_WB, time);
+
+ return mshr;
+}
+
+
+/**
+ * @todo Remove SW prefetches on mshr hits.
+ */
+void
+MissQueue::handleMiss(Packet * &pkt, int blkSize, Tick time)
+{
+// if (!cache->isTopLevel())
+ if (prefetchMiss) prefetcher->handleMiss(pkt, time);
+
+ int size = blkSize;
+ Addr blkAddr = pkt->paddr & ~(Addr)(blkSize-1);
+ MSHR* mshr = NULL;
+ if (!pkt->isUncacheable()) {
+ mshr = mq.findMatch(blkAddr, pkt->req->asid);
+ if (mshr) {
+ //@todo remove hw_pf here
+ mshr_hits[pkt->cmd.toIndex()][pkt->thread_num]++;
+ if (mshr->threadNum != pkt->thread_num) {
+ 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->cmd.toIndex()][pkt->thread_num]++;
+ }
+ } else {
+ //Count uncacheable accesses
+ mshr_uncacheable[pkt->cmd.toIndex()][pkt->thread_num]++;
+ size = pkt->size;
+ }
+ if (pkt->cmd.isWrite() && (pkt->isUncacheable() || !writeAllocate ||
+ pkt->cmd.isNoResponse())) {
+ /**
+ * @todo Add write merging here.
+ */
+ mshr = allocateWrite(pkt, pkt->size, time);
+ return;
+ }
+
+ mshr = allocateMiss(pkt, size, time);
+}
+
+MSHR*
+MissQueue::fetchBlock(Addr addr, int asid, int blk_size, Tick time,
+ Packet * &target)
+{
+ Addr blkAddr = addr & ~(Addr)(blk_size - 1);
+ assert(mq.findMatch(addr, asid) == NULL);
+ MSHR *mshr = mq.allocateFetch(blkAddr, asid, 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;
+}
+
+Packet *
+MissQueue::getPacket()
+{
+ Packet * 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 < 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->cmd.toIndex()][pkt->thread_num]++;
+ //It will request the bus for the future, but should clear that immedieatley
+ allocateMiss(pkt, pkt->size, curTick);
+ pkt = mq.getReq();
+ assert(pkt); //We should get back a req b/c we just put one in
+ }
+ }
+ return pkt;
+}
+
+void
+MissQueue::setBusCmd(Packet * &pkt, Packet::Command cmd)
+{
+ assert(pkt->senderState != 0);
+ MSHR * mshr = pkt->senderState;
+ mshr->originalCmd = pkt->cmd;
+ if (pkt->isCacheFill() || pkt->isNoAllocate())
+ pkt->cmd = cmd;
+}
+
+void
+MissQueue::restoreOrigCmd(Packet * &pkt)
+{
+ pkt->cmd = pkt->senderState->originalCmd;
+}
+
+void
+MissQueue::markInService(Packet * &pkt)
+{
+ assert(pkt->senderState != 0);
+ bool unblock = false;
+ BlockedCause cause = NUM_BLOCKED_CAUSES;
+
+ /**
+ * @todo Should include MSHRQueue pointer in MSHR to select the correct
+ * one.
+ */
+ if ((!pkt->isCacheFill() && pkt->cmd.isWrite()) || pkt->cmd == Copy) {
+ // Forwarding a write/ writeback, don't need to change
+ // the command
+ unblock = wb.isFull();
+ wb.markInService(pkt->senderState);
+ 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(pkt->senderState);
+ if (!mq.havePending()){
+ cache->clearMasterRequest(Request_MSHR);
+ }
+ if (pkt->senderState->originalCmd == Hard_Prefetch) {
+ 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(Packet * &pkt, Tick time)
+{
+ MSHR* mshr = pkt->senderState;
+ if (pkt->senderState->originalCmd == Hard_Prefetch) {
+ 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][pkt->thread_num] +=
+ 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
+ Packet::Command cmd = mshr->getTarget()->cmd;
+ 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->isUncacheable()) {
+ mshr_uncacheable_lat[pkt->cmd][pkt->thread_num] +=
+ curTick - pkt->time;
+ }
+ if (mshr->hasTargets() && pkt->isUncacheable()) {
+ // Should only have 1 target if we had any
+ assert(num_targets == 1);
+ Packet * target = mshr->getTarget();
+ mshr->popTarget();
+ if (cache->doData() && pkt->cmd.isRead()) {
+ memcpy(target->data, pkt->data, target->size);
+ }
+ 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()) {
+ Packet * target = mshr->getTarget();
+ mshr->popTarget();
+ if (cache->doData() && pkt->cmd.isRead()) {
+ memcpy(target->data, pkt->data, target->size);
+ }
+ cache->respond(target, time);
+ }
+ }
+
+ if (pkt->cmd.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 thread_number)
+{
+ bool unblock = false;
+ BlockedCause cause = NUM_BLOCKED_CAUSES;
+
+ if (noTargetMSHR && noTargetMSHR->threadNum == thread_number) {
+ noTargetMSHR = NULL;
+ unblock = true;
+ cause = Blocked_NoTargets;
+ }
+ if (mq.isFull()) {
+ unblock = true;
+ cause = Blocked_NoMSHRs;
+ }
+ mq.squash(thread_number);
+ if (!mq.havePending()) {
+ cache->clearMasterRequest(Request_MSHR);
+ }
+ if (unblock && !mq.isFull()) {
+ cache->clearBlocked(cause);
+ }
+
+}
+
+MSHR*
+MissQueue::findMSHR(Addr addr, int asid) const
+{
+ return mq.findMatch(addr,asid);
+}
+
+bool
+MissQueue::findWrites(Addr addr, int asid, vector<MSHR*> &writes) const
+{
+ return wb.findMatches(addr,asid,writes);
+}
+
+void
+MissQueue::doWriteback(Addr addr, int asid,
+ int size, uint8_t *data, bool compressed)
+{
+ // Generate request
+ Packet * pkt = buildWritebackReq(addr, asid, size, data,
+ compressed);
+
+ writebacks[pkt->thread_num]++;
+
+ allocateWrite(pkt, 0, curTick);
+}
+
+
+void
+MissQueue::doWriteback(Packet * &pkt)
+{
+ writebacks[pkt->thread_num]++;
+ allocateWrite(pkt, 0, curTick);
+}
+
+
+MSHR*
+MissQueue::allocateTargetList(Addr addr, int asid)
+{
+ MSHR* mshr = mq.allocateTargetList(addr, asid, 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
new file mode 100644
index 000000000..ce827fe81
--- /dev/null
+++ b/src/mem/cache/miss/miss_queue.hh
@@ -0,0 +1,349 @@
+/*
+ * 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/mshr.hh"
+#include "mem/cache/miss/mshr_queue.hh"
+#include "base/statistics.hh"
+
+class BaseCache;
+class BasePrefetcher;
+/**
+ * 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
+{
+ 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;
+ /** True if the cache should allocate on a write miss. */
+ const bool writeAllocate;
+ /** Pointer to the parent cache. */
+ BaseCache* cache;
+
+ /** The Prefetcher */
+ BasePrefetcher *prefetcher;
+
+ /** The block size of the parent cache. */
+ int blkSize;
+
+ /** Increasing order number assigned to each incoming request. */
+ uint64_t order;
+
+ bool prefetchMiss;
+
+ // Statistics
+ /**
+ * @addtogroup CacheStatistics
+ * @{
+ */
+ /** Number of blocks written back per thread. */
+ Stats::Vector<> writebacks;
+
+ /** Number of misses that hit in the MSHRs per command and thread. */
+ Stats::Vector<> mshr_hits[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[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[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[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[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[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[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[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[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 req 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(Packet * &pkt, int size, Tick time);
+
+ /**
+ * Allocate a new WriteBuffer to handle the provided write.
+ * @param req 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(Packet * &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);
+
+ /**
+ * 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);
+
+ /**
+ * Handle a cache miss properly. Either allocate an MSHR for the request,
+ * or forward it through the write buffer.
+ * @param req 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(Packet * &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 asid, int blk_size, Tick time,
+ Packet * &target);
+
+ /**
+ * Selects a outstanding request to service.
+ * @return The request to service, NULL if none found.
+ */
+ Packet * getPacket();
+
+ /**
+ * Set the command to the given bus command.
+ * @param req The request to update.
+ * @param cmd The bus command to use.
+ */
+ void setBusCmd(Packet * &pkt, Packet::Command cmd);
+
+ /**
+ * Restore the original command in case of a bus transmission error.
+ * @param req The request to reset.
+ */
+ void restoreOrigCmd(Packet * &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 req The request that was sent on the bus.
+ */
+ void markInService(Packet * &pkt);
+
+ /**
+ * Collect statistics and free resources of a satisfied request.
+ * @param req The request that has been satisfied.
+ * @param time The time when the request is satisfied.
+ */
+ void handleResponse(Packet * &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 thread_number The thread number of the requests to squash.
+ */
+ void squash(int thread_number);
+
+ /**
+ * 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, int asid) const;
+
+ /**
+ * 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, int asid, std::vector<MSHR*>& writes) const;
+
+ /**
+ * 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 asid,
+ int size, uint8_t *data, bool compressed);
+
+ /**
+ * Perform the given writeback request.
+ * @param req The writeback request.
+ */
+ void doWriteback(Packet * &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 req The target to add.
+ */
+ void addTarget(MSHR *mshr, Packet * &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, int asid);
+
+};
+
+#endif //__MISS_QUEUE_HH__
diff --git a/src/mem/cache/miss/mshr.cc b/src/mem/cache/miss/mshr.cc
new file mode 100644
index 000000000..73aeaf6ca
--- /dev/null
+++ b/src/mem/cache/miss/mshr.cc
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2002-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
+ * Dave Greene
+ */
+
+/**
+ * @file
+ * Miss Status and Handling Register (MSHR) definitions.
+ */
+
+#include <assert.h>
+#include <string>
+#include <vector>
+
+#include "mem/cache/miss/mshr.hh"
+#include "sim/root.hh" // for curTick
+#include "sim/host.hh"
+#include "base/misc.hh"
+#include "mem/cache/cache.hh"
+
+using namespace std;
+
+MSHR::MSHR()
+{
+ inService = false;
+ ntargets = 0;
+ threadNum = -1;
+}
+
+void
+MSHR::allocate(Packet::Command cmd, Addr _addr, int _asid, int size,
+ Packet * &target)
+{
+ assert(targets.empty());
+ addr = _addr;
+ asid = _asid;
+
+ pkt = new Packet(); // allocate new memory request
+ pkt->addr = addr; //picked physical address for now
+ pkt->cmd = cmd;
+ pkt->size = size;
+ pkt->data = new uint8_t[size];
+ pkt->senderState = this;
+ //Set the time here for latency calculations
+ //pkt->time = curTick;
+
+ if (target) {
+ pkt->req = target->req;
+ allocateTarget(target);
+ }
+}
+
+// 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(Packet * &target)
+{
+ addr = target->paddr;
+ asid = target->req->asid;
+ threadNum = target->thread_num;
+ pkt = new Packet();
+ pkt->addr = target->addr;
+ pkt->dest = target->dest;
+ pkt->cmd = target->cmd;
+ pkt->size = target->size;
+ pkt->req = target->req;
+ pkt->data = new uint8_t[target->size];
+ pkt->senderState = this;
+}
+
+void
+MSHR::deallocate()
+{
+ assert(targets.empty());
+ assert(ntargets == 0);
+ pkt = NULL;
+ inService = false;
+ allocIter = NULL;
+ readyIter = NULL;
+}
+
+/*
+ * Adds a target to an MSHR
+ */
+void
+MSHR::allocateTarget(Packet * &target)
+{
+ //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->cmd.isRead() && target->cmd.isInvalidate()) {
+ std::list<Packet *> temp;
+
+ while (!targets.empty()) {
+ if (!targets.front()->cmd.isRead()) break;
+ //Place on top of temp stack
+ temp.push_front(targets.front());
+ //Remove from targets
+ targets.pop_front();
+ }
+
+ //Now that we have all the reads off until first non-read, we can
+ //place the invalidate on
+ targets.push_front(target);
+
+ //Now we pop off the temp_stack and put them back
+ while (!temp.empty()) {
+ targets.push_front(temp.front());
+ temp.pop_front();
+ }
+ }
+ else {
+ targets.push_back(target);
+ }
+
+ ++ntargets;
+ assert(targets.size() == ntargets);
+ /**
+ * @todo really prioritize the target commands.
+ */
+
+ if (!inService && target->cmd.isWrite()) {
+ pkt->cmd = WriteReq;
+ }
+}
+
+
+
+void
+MSHR::dump()
+{
+ ccprintf(cerr,
+ "inService: %d thread: %d\n"
+ "Addr: %x asid: %d ntargets %d\n"
+ "Targets:\n",
+ inService, threadNum, addr, asid, ntargets);
+
+ TargetListIterator tar_it = targets.begin();
+ for (int i = 0; i < ntargets; i++) {
+ assert(tar_it != targets.end());
+
+ ccprintf(cerr, "\t%d: Addr: %x cmd: %d\n",
+ i, (*tar_it)->paddr, (*tar_it)->cmd.toIndex());
+
+ tar_it++;
+ }
+ 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
new file mode 100644
index 000000000..167aa26cd
--- /dev/null
+++ b/src/mem/cache/miss/mshr.hh
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2002-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 Status and Handling Register (MSHR) declaration.
+ */
+
+#ifndef __MSHR_HH__
+#define __MSHR_HH__
+
+#include "mem/packet.hh"
+#include <list>
+#include <deque>
+
+class MSHR;
+
+/**
+ * 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 {
+ public:
+ /** Defines the Data structure of the MSHR targetlist. */
+ typedef std::list<Packet *> TargetList;
+ /** Target list iterator. */
+ typedef std::list<Packet *>::iterator TargetListIterator;
+ /** A list of MSHRs. */
+ typedef std::list<MSHR *> List;
+ /** MSHR list iterator. */
+ typedef List::iterator Iterator;
+ /** MSHR list const_iterator. */
+ typedef List::const_iterator ConstIterator;
+
+ /** Address of the miss. */
+ Addr addr;
+ /** Adress space id of the miss. */
+ short asid;
+ /** True if the request has been sent to the bus. */
+ bool inService;
+ /** Thread number of the miss. */
+ int threadNum;
+ /** The request that is forwarded to the next level of the hierarchy. */
+ Packet * pkt;
+ /** The number of currently allocated targets. */
+ short ntargets;
+ /** The original requesting command. */
+ Packet::Command originalCmd;
+ /** Order number of assigned by the miss queue. */
+ uint64_t order;
+
+ /**
+ * 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
+ */
+ Iterator allocIter;
+
+private:
+ /** List of all requests that match the address */
+ TargetList targets;
+
+public:
+ /**
+ * Allocate a miss to this MSHR.
+ * @param cmd The requesting command.
+ * @param addr The address of the miss.
+ * @param asid The address space id of the miss.
+ * @param size The number of bytes to request.
+ * @param req The original miss.
+ */
+ void allocate(Packet::Command cmd, Addr addr, int asid, int size,
+ Packet * &pkt);
+
+ /**
+ * Allocate this MSHR as a buffer for the given request.
+ * @param target The memory request to buffer.
+ */
+ void allocateAsBuffer(Packet * &target);
+
+ /**
+ * Mark this MSHR as free.
+ */
+ void deallocate();
+
+ /**
+ * Add a request to the list of targets.
+ * @param target The target.
+ */
+ void allocateTarget(Packet * &target);
+
+ /** A simple constructor. */
+ MSHR();
+ /** A simple destructor. */
+ ~MSHR();
+
+ /**
+ * Returns the current number of allocated targets.
+ * @return The current number of allocated targets.
+ */
+ int getNumTargets()
+ {
+ return(ntargets);
+ }
+
+ /**
+ * Returns a pointer to the target list.
+ * @return a pointer to the target list.
+ */
+ TargetList* getTargetList()
+ {
+ return &targets;
+ }
+
+ /**
+ * Returns a reference to the first target.
+ * @return A pointer to the first target.
+ */
+ Packet * getTarget()
+ {
+ return targets.front();
+ }
+
+ /**
+ * Pop first target.
+ */
+ void popTarget()
+ {
+ --ntargets;
+ targets.pop_front();
+ }
+
+ /**
+ * Returns true if there are targets left.
+ * @return true if there are targets
+ */
+ bool hasTargets()
+ {
+ return !targets.empty();
+ }
+
+ /**
+ * Prints the contents of this MSHR to stderr.
+ */
+ void dump();
+};
+
+#endif //__MSHR_HH__
diff --git a/src/mem/cache/miss/mshr_queue.cc b/src/mem/cache/miss/mshr_queue.cc
new file mode 100644
index 000000000..72c8cc498
--- /dev/null
+++ b/src/mem/cache/miss/mshr_queue.cc
@@ -0,0 +1,269 @@
+/*
+ * 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
+ * Definition of the MSHRQueue.
+ */
+
+#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)
+{
+ allocated = 0;
+ inServiceMSHRs = 0;
+ allocatedTargets = 0;
+ registers = new MSHR[numMSHRs];
+ for (int i = 0; i < numMSHRs; ++i) {
+ freeList.push_back(&registers[i]);
+ }
+}
+
+MSHRQueue::~MSHRQueue()
+{
+ delete [] registers;
+}
+
+MSHR*
+MSHRQueue::findMatch(Addr addr, int asid) const
+{
+ MSHR::ConstIterator i = allocatedList.begin();
+ MSHR::ConstIterator end = allocatedList.end();
+ for (; i != end; ++i) {
+ MSHR *mshr = *i;
+ if (mshr->addr == addr) {
+ return mshr;
+ }
+ }
+ return NULL;
+}
+
+bool
+MSHRQueue::findMatches(Addr addr, int asid, vector<MSHR*>& matches) const
+{
+ // Need an empty vector
+ assert(matches.empty());
+ bool retval = false;
+ MSHR::ConstIterator i = allocatedList.begin();
+ MSHR::ConstIterator end = allocatedList.end();
+ for (; i != end; ++i) {
+ MSHR *mshr = *i;
+ if (mshr->addr == addr) {
+ retval = true;
+ matches.push_back(mshr);
+ }
+ }
+ return retval;
+
+}
+
+MSHR*
+MSHRQueue::findPending(Packet * &pkt) const
+{
+ MSHR::ConstIterator i = pendingList.begin();
+ MSHR::ConstIterator end = pendingList.end();
+ for (; i != end; ++i) {
+ MSHR *mshr = *i;
+ if (mshr->addr < pkt->addr) {
+ if (mshr->addr + mshr->pkt->size > pkt->addr) {
+ return mshr;
+ }
+ } else {
+ if (pkt->addr + pkt->size > mshr->addr) {
+ return mshr;
+ }
+ }
+
+ //need to check destination address for copies.
+ if (mshr->pkt->cmd == Copy) {
+ Addr dest = mshr->pkt->dest;
+ if (dest < pkt->addr) {
+ if (dest + mshr->pkt->size > pkt->addr) {
+ return mshr;
+ }
+ } else {
+ if (pkt->addr + pkt->size > dest) {
+ return mshr;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+MSHR*
+MSHRQueue::allocate(Packet * &pkt, int size)
+{
+ Addr aligned_addr = pkt->addr & ~((Addr)size - 1);
+ MSHR *mshr = freeList.front();
+ assert(mshr->getNumTargets() == 0);
+ freeList.pop_front();
+
+ if (pkt->cmd.isNoResponse()) {
+ mshr->allocateAsBuffer(pkt);
+ } else {
+ assert(size !=0);
+ mshr->allocate(pkt->cmd, aligned_addr, pkt->req->req->asid, size, pkt);
+ allocatedTargets += 1;
+ }
+ mshr->allocIter = allocatedList.insert(allocatedList.end(), mshr);
+ mshr->readyIter = pendingList.insert(pendingList.end(), mshr);
+
+ allocated += 1;
+ return mshr;
+}
+
+MSHR*
+MSHRQueue::allocateFetch(Addr addr, int asid, int size, Packet * &target)
+{
+ MSHR *mshr = freeList.front();
+ assert(mshr->getNumTargets() == 0);
+ freeList.pop_front();
+ mshr->allocate(Read, addr, asid, size, target);
+ mshr->allocIter = allocatedList.insert(allocatedList.end(), mshr);
+ mshr->readyIter = pendingList.insert(pendingList.end(), mshr);
+
+ allocated += 1;
+ return mshr;
+}
+
+MSHR*
+MSHRQueue::allocateTargetList(Addr addr, int asid, int size)
+{
+ MSHR *mshr = freeList.front();
+ assert(mshr->getNumTargets() == 0);
+ freeList.pop_front();
+ Packet * dummy;
+ mshr->allocate(Read, addr, asid, size, dummy);
+ mshr->allocIter = allocatedList.insert(allocatedList.end(), mshr);
+ mshr->inService = true;
+ ++inServiceMSHRs;
+ ++allocated;
+ return mshr;
+}
+
+
+void
+MSHRQueue::deallocate(MSHR* mshr)
+{
+ deallocateOne(mshr);
+}
+
+MSHR::Iterator
+MSHRQueue::deallocateOne(MSHR* mshr)
+{
+ MSHR::Iterator retval = allocatedList.erase(mshr->allocIter);
+ freeList.push_front(mshr);
+ allocated--;
+ allocatedTargets -= mshr->getNumTargets();
+ if (mshr->inService) {
+ inServiceMSHRs--;
+ } else {
+ pendingList.erase(mshr->readyIter);
+ }
+ mshr->deallocate();
+ return retval;
+}
+
+void
+MSHRQueue::moveToFront(MSHR *mshr)
+{
+ if (!mshr->inService) {
+ assert(mshr == *(mshr->readyIter));
+ pendingList.erase(mshr->readyIter);
+ mshr->readyIter = pendingList.insert(pendingList.begin(), mshr);
+ }
+}
+
+void
+MSHRQueue::markInService(MSHR* mshr)
+{
+ //assert(mshr == pendingList.front());
+ if (mshr->pkt->cmd.isNoResponse()) {
+ assert(mshr->getNumTargets() == 0);
+ deallocate(mshr);
+ return;
+ }
+ mshr->inService = true;
+ pendingList.erase(mshr->readyIter);
+ mshr->readyIter = NULL;
+ inServiceMSHRs += 1;
+ //pendingList.pop_front();
+}
+
+void
+MSHRQueue::markPending(MSHR* mshr, Packet::Command cmd)
+{
+ assert(mshr->readyIter == NULL);
+ mshr->pkt->cmd = cmd;
+ mshr->pkt->flags &= ~SATISFIED;
+ mshr->inService = false;
+ --inServiceMSHRs;
+ /**
+ * @ todo might want to add rerequests to front of pending list for
+ * performance.
+ */
+ mshr->readyIter = pendingList.insert(pendingList.end(), mshr);
+}
+
+void
+MSHRQueue::squash(int thread_number)
+{
+ MSHR::Iterator i = allocatedList.begin();
+ MSHR::Iterator end = allocatedList.end();
+ for (; i != end;) {
+ MSHR *mshr = *i;
+ if (mshr->threadNum == thread_number) {
+ while (mshr->hasTargets()) {
+ Packet * target = mshr->getTarget();
+ mshr->popTarget();
+
+ assert(target->thread_num == thread_number);
+ if (target->completionEvent != NULL) {
+ delete target->completionEvent;
+ }
+ target = NULL;
+ }
+ assert(!mshr->hasTargets());
+ assert(mshr->ntargets==0);
+ if (!mshr->inService) {
+ i = deallocateOne(mshr);
+ } else {
+ //mshr->pkt->flags &= ~CACHE_LINE_FILL;
+ ++i;
+ }
+ } else {
+ ++i;
+ }
+ }
+}
diff --git a/src/mem/cache/miss/mshr_queue.hh b/src/mem/cache/miss/mshr_queue.hh
new file mode 100644
index 000000000..3e1d3f39f
--- /dev/null
+++ b/src/mem/cache/miss/mshr_queue.hh
@@ -0,0 +1,239 @@
+/*
+ * 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 structure to manage MSHRs.
+ */
+
+#ifndef __MSHR_QUEUE_HH__
+#define __MSHR_QUEUE_HH__
+
+#include <vector>
+#include "mem/cache/miss/mshr.hh"
+
+/**
+ * A Class for maintaining a list of pending and allocated memory requests.
+ */
+class MSHRQueue {
+ private:
+ /** MSHR storage. */
+ MSHR* registers;
+ /** Holds pointers to all allocated MSHRs. */
+ MSHR::List allocatedList;
+ /** Holds pointers to MSHRs that haven't been sent to the bus. */
+ MSHR::List pendingList;
+ /** Holds non allocated MSHRs. */
+ 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.
+ */
+ const int numMSHRs;
+
+ /**
+ * The number of MSHRs to hold in reserve. This is needed because copy
+ * operations can allocate upto 4 MSHRs at one time.
+ */
+ const int numReserve;
+
+ public:
+ /** The number of allocated MSHRs. */
+ int allocated;
+ /** The number of MSHRs that have been forwarded to the bus. */
+ int inServiceMSHRs;
+ /** The number of targets waiting for response. */
+ int allocatedTargets;
+
+ /**
+ * 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.
+ */
+ MSHRQueue(int num_mshrs, int reserve = 1);
+
+ /** Destructor */
+ ~MSHRQueue();
+
+ /**
+ * Find the first MSHR that matches the provide address and asid.
+ * @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, int asid) const;
+
+ /**
+ * Find and return all the matching MSHRs 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.
+ * @return True if any matches are found, false otherwise.
+ * @todo Typedef the vector??
+ */
+ bool findMatches(Addr addr, int asid, std::vector<MSHR*>& matches) const;
+
+ /**
+ * Find any pending requests that overlap the given request.
+ * @param req The request to find.
+ * @return A pointer to the earliest matching MSHR.
+ */
+ MSHR* findPending(Packet * &pkt) const;
+
+ /**
+ * Allocates a new MSHR for the request and size. This places the request
+ * as the first target in the MSHR.
+ * @param req The request to handle.
+ * @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(Packet * &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 asid, int size, Packet * &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.
+ */
+ MSHR* allocateTargetList(Addr addr, int asid, int size);
+
+ /**
+ * Removes the given MSHR from the queue. This places the MSHR on the
+ * free list.
+ * @param 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 req The target request.
+ */
+ void allocateTarget(MSHR* mshr, Packet * &pkt)
+ {
+ mshr->allocateTarget(pkt);
+ allocatedTargets += 1;
+ }
+
+ /**
+ * 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);
+
+ /**
+ * Moves the MSHR to the front of the pending list if it is not in service.
+ * @param mshr The mshr 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.
+ * @param mshr The MSHR to mark in service.
+ */
+ void markInService(MSHR* mshr);
+
+ /**
+ * Mark an in service mshr as pending, used to resend a request.
+ * @param mshr The MSHR to resend.
+ * @param cmd The command to resend.
+ */
+ void markPending(MSHR* mshr, Packet::Command cmd);
+
+ /**
+ * Squash outstanding requests with the given thread number. If a request
+ * is in service, just squashes the targets.
+ * @param thread_number The thread to squash.
+ */
+ void squash(int thread_number);
+
+ /**
+ * Returns true if the pending list is not empty.
+ * @return True if there are outstanding requests.
+ */
+ bool havePending() const
+ {
+ return !pendingList.empty();
+ }
+
+ /**
+ * Returns true if there are no free MSHRs.
+ * @return True if this queue is full.
+ */
+ bool isFull() const
+ {
+ return (allocated > numMSHRs - numReserve);
+ }
+
+ /**
+ * Returns the request at the head of the pendingList.
+ * @return The next request to service.
+ */
+ Packet * getReq() const
+ {
+ if (pendingList.empty()) {
+ return NULL;
+ }
+ MSHR* mshr = pendingList.front();
+ return mshr->pkt;
+ }
+
+ /**
+ * Returns the number of outstanding targets.
+ * @return the number of allocated targets.
+ */
+ int getAllocatedTargets() const
+ {
+ return allocatedTargets;
+ }
+
+};
+
+#endif //__MSHR_QUEUE_HH__