summaryrefslogtreecommitdiff
path: root/src/mem
diff options
context:
space:
mode:
authorSteve Reinhardt <stever@gmail.com>2008-01-02 12:20:15 -0800
committerSteve Reinhardt <stever@gmail.com>2008-01-02 12:20:15 -0800
commit3952e41ab1f1dfaa2f97a6a486528e4ea0bfc5a1 (patch)
treee186dc9429d37ea5e9ca6657ce746e60447dee32 /src/mem
parent659aef3eb8ff2803601851b85347fee04c2721b8 (diff)
downloadgem5-3952e41ab1f1dfaa2f97a6a486528e4ea0bfc5a1.tar.xz
Add functional PrintReq command for memory-system debugging.
--HG-- extra : convert_revision : 73b753e57c355b7e6873f047ddc8cb371c3136b7
Diffstat (limited to 'src/mem')
-rw-r--r--src/mem/bridge.cc4
-rw-r--r--src/mem/cache/SConscript1
-rw-r--r--src/mem/cache/base_cache.cc28
-rw-r--r--src/mem/cache/base_cache.hh7
-rw-r--r--src/mem/cache/cache.hh5
-rw-r--r--src/mem/cache/cache_blk.cc41
-rw-r--r--src/mem/cache/cache_blk.hh13
-rw-r--r--src/mem/cache/cache_impl.hh54
-rw-r--r--src/mem/cache/miss/mshr.cc61
-rw-r--r--src/mem/cache/miss/mshr.hh21
-rw-r--r--src/mem/cache/miss/mshr_queue.cc9
-rw-r--r--src/mem/cache/miss/mshr_queue.hh6
-rw-r--r--src/mem/packet.cc121
-rw-r--r--src/mem/packet.hh72
-rw-r--r--src/mem/physical.cc16
-rw-r--r--src/mem/port.cc12
-rw-r--r--src/mem/port.hh5
17 files changed, 365 insertions, 111 deletions
diff --git a/src/mem/bridge.cc b/src/mem/bridge.cc
index aa059ad13..3d3966491 100644
--- a/src/mem/bridge.cc
+++ b/src/mem/bridge.cc
@@ -319,11 +319,15 @@ Bridge::BridgePort::recvFunctional(PacketPtr pkt)
{
std::list<PacketBuffer*>::iterator i;
+ pkt->pushLabel(name());
+
for (i = sendQueue.begin(); i != sendQueue.end(); ++i) {
if (pkt->checkFunctional((*i)->pkt))
return;
}
+ pkt->popLabel();
+
// fall through if pkt still not satisfied
otherPort->sendFunctional(pkt);
}
diff --git a/src/mem/cache/SConscript b/src/mem/cache/SConscript
index 5ac7e34ad..d5899b623 100644
--- a/src/mem/cache/SConscript
+++ b/src/mem/cache/SConscript
@@ -34,6 +34,7 @@ SimObject('BaseCache.py')
Source('base_cache.cc')
Source('cache.cc')
+Source('cache_blk.cc')
Source('cache_builder.cc')
TraceFlag('Cache')
diff --git a/src/mem/cache/base_cache.cc b/src/mem/cache/base_cache.cc
index c5632e89f..9fa9e2d29 100644
--- a/src/mem/cache/base_cache.cc
+++ b/src/mem/cache/base_cache.cc
@@ -41,8 +41,10 @@
using namespace std;
BaseCache::CachePort::CachePort(const std::string &_name, BaseCache *_cache,
- std::vector<Range<Addr> > filter_ranges)
- : SimpleTimingPort(_name, _cache), cache(_cache), otherPort(NULL),
+ const std::string &_label,
+ std::vector<Range<Addr> > filter_ranges)
+ : SimpleTimingPort(_name, _cache), cache(_cache),
+ label(_label), otherPort(NULL),
blocked(false), mustSendRetry(false), filterRanges(filter_ranges)
{
}
@@ -50,8 +52,8 @@ BaseCache::CachePort::CachePort(const std::string &_name, BaseCache *_cache,
BaseCache::BaseCache(const Params *p)
: MemObject(p),
- mshrQueue(p->mshrs, 4, MSHRQueue_MSHRs),
- writeBuffer(p->write_buffers, p->mshrs+1000,
+ mshrQueue("MSHRs", p->mshrs, 4, MSHRQueue_MSHRs),
+ writeBuffer("write buffer", p->write_buffers, p->mshrs+1000,
MSHRQueue_WriteBuffer),
blkSize(p->block_size),
hitLatency(p->latency),
@@ -71,19 +73,21 @@ BaseCache::CachePort::recvStatusChange(Port::Status status)
}
}
-int
-BaseCache::CachePort::deviceBlockSize()
+
+bool
+BaseCache::CachePort::checkFunctional(PacketPtr pkt)
{
- return cache->getBlockSize();
+ pkt->pushLabel(label);
+ bool done = SimpleTimingPort::checkFunctional(pkt);
+ pkt->popLabel();
+ return done;
}
-void
-BaseCache::CachePort::checkAndSendFunctional(PacketPtr pkt)
+int
+BaseCache::CachePort::deviceBlockSize()
{
- if (!checkFunctional(pkt)) {
- sendFunctional(pkt);
- }
+ return cache->getBlockSize();
}
diff --git a/src/mem/cache/base_cache.hh b/src/mem/cache/base_cache.hh
index 5049f68f1..604474524 100644
--- a/src/mem/cache/base_cache.hh
+++ b/src/mem/cache/base_cache.hh
@@ -100,7 +100,8 @@ class BaseCache : public MemObject
protected:
CachePort(const std::string &_name, BaseCache *_cache,
- std::vector<Range<Addr> > filter_ranges);
+ const std::string &_label,
+ std::vector<Range<Addr> > filter_ranges);
virtual void recvStatusChange(Status status);
@@ -111,6 +112,8 @@ class BaseCache : public MemObject
typedef EventWrapper<Port, &Port::sendRetry>
SendRetryEvent;
+ const std::string label;
+
public:
void setOtherPort(CachePort *_otherPort) { otherPort = _otherPort; }
@@ -118,7 +121,7 @@ class BaseCache : public MemObject
void clearBlocked();
- void checkAndSendFunctional(PacketPtr pkt);
+ bool checkFunctional(PacketPtr pkt);
CachePort *otherPort;
diff --git a/src/mem/cache/cache.hh b/src/mem/cache/cache.hh
index 037afd6ac..4602fd835 100644
--- a/src/mem/cache/cache.hh
+++ b/src/mem/cache/cache.hh
@@ -73,6 +73,7 @@ class Cache : public BaseCache
public:
CpuSidePort(const std::string &_name,
Cache<TagStore> *_cache,
+ const std::string &_label,
std::vector<Range<Addr> > filterRanges);
// BaseCache::CachePort just has a BaseCache *; this function
@@ -97,6 +98,7 @@ class Cache : public BaseCache
public:
MemSidePort(const std::string &_name,
Cache<TagStore> *_cache,
+ const std::string &_label,
std::vector<Range<Addr> > filterRanges);
// BaseCache::CachePort just has a BaseCache *; this function
@@ -229,7 +231,8 @@ class Cache : public BaseCache
* @param pkt The request to perform.
* @return The result of the access.
*/
- void functionalAccess(PacketPtr pkt, CachePort *otherSidePort);
+ void functionalAccess(PacketPtr pkt, CachePort *incomingPort,
+ CachePort *otherSidePort);
/**
* Handles a response (cache line fill/write ack) from the bus.
diff --git a/src/mem/cache/cache_blk.cc b/src/mem/cache/cache_blk.cc
new file mode 100644
index 000000000..d4a2eaee8
--- /dev/null
+++ b/src/mem/cache/cache_blk.cc
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2007 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.
+ */
+
+#include "base/cprintf.hh"
+#include "mem/cache/cache_blk.hh"
+
+void
+CacheBlkPrintWrapper::print(std::ostream &os, int verbosity,
+ const std::string &prefix) const
+{
+ ccprintf(os, "%sblk %c%c%c\n", prefix,
+ blk->isValid() ? 'V' : '-',
+ blk->isWritable() ? 'E' : '-',
+ blk->isDirty() ? 'M' : '-');
+}
+
diff --git a/src/mem/cache/cache_blk.hh b/src/mem/cache/cache_blk.hh
index d2aba9480..e7c2d1a02 100644
--- a/src/mem/cache/cache_blk.hh
+++ b/src/mem/cache/cache_blk.hh
@@ -37,6 +37,7 @@
#include <list>
+#include "base/printable.hh"
#include "sim/core.hh" // for Tick
#include "arch/isa_traits.hh" // for Addr
#include "mem/packet.hh"
@@ -252,4 +253,16 @@ class CacheBlk
}
};
+class CacheBlkPrintWrapper : public Printable
+{
+ CacheBlk *blk;
+ public:
+ CacheBlkPrintWrapper(CacheBlk *_blk) : blk(_blk) {}
+ virtual ~CacheBlkPrintWrapper() {}
+ void print(std::ostream &o, int verbosity = 0,
+ const std::string &prefix = "") const;
+};
+
+
+
#endif //__CACHE_BLK_HH__
diff --git a/src/mem/cache/cache_impl.hh b/src/mem/cache/cache_impl.hh
index 55301ecb5..257b3ef33 100644
--- a/src/mem/cache/cache_impl.hh
+++ b/src/mem/cache/cache_impl.hh
@@ -62,9 +62,11 @@ Cache<TagStore>::Cache(const Params *p, TagStore *tags, BasePrefetcher *pf)
tempBlock->data = new uint8_t[blkSize];
cpuSidePort = new CpuSidePort(p->name + "-cpu_side_port", this,
- p->cpu_side_filter_ranges);
+ "CpuSidePort",
+ p->cpu_side_filter_ranges);
memSidePort = new MemSidePort(p->name + "-mem_side_port", this,
- p->mem_side_filter_ranges);
+ "MemSidePort",
+ p->mem_side_filter_ranges);
cpuSidePort->setOtherPort(memSidePort);
memSidePort->setOtherPort(cpuSidePort);
@@ -91,7 +93,8 @@ Cache<TagStore>::getPort(const std::string &if_name, int idx)
return memSidePort;
} else if (if_name == "functional") {
return new CpuSidePort(name() + "-cpu_side_funcport", this,
- std::vector<Range<Addr> >());
+ "CpuSideFuncPort",
+ std::vector<Range<Addr> >());
} else {
panic("Port name %s unrecognized\n", if_name);
}
@@ -640,21 +643,27 @@ Cache<TagStore>::atomicAccess(PacketPtr pkt)
template<class TagStore>
void
Cache<TagStore>::functionalAccess(PacketPtr pkt,
+ CachePort *incomingPort,
CachePort *otherSidePort)
{
Addr blk_addr = pkt->getAddr() & ~(blkSize - 1);
BlkType *blk = tags->findBlock(pkt->getAddr());
- if (blk && pkt->checkFunctional(blk_addr, blkSize, blk->data)) {
- // request satisfied from block
- return;
- }
+ pkt->pushLabel(name());
+
+ CacheBlkPrintWrapper cbpw(blk);
+ bool done =
+ (blk && pkt->checkFunctional(&cbpw, blk_addr, blkSize, blk->data))
+ || incomingPort->checkFunctional(pkt)
+ || mshrQueue.checkFunctional(pkt, blk_addr)
+ || writeBuffer.checkFunctional(pkt, blk_addr)
+ || otherSidePort->checkFunctional(pkt);
- // Need to check for outstanding misses and writes; if neither one
- // satisfies, then forward to other side of cache.
- if (!(mshrQueue.checkFunctional(pkt, blk_addr) ||
- writeBuffer.checkFunctional(pkt, blk_addr))) {
- otherSidePort->checkAndSendFunctional(pkt);
+ // We're leaving the cache, so pop cache->name() label
+ pkt->popLabel();
+
+ if (!done) {
+ otherSidePort->sendFunctional(pkt);
}
}
@@ -1275,18 +1284,16 @@ template<class TagStore>
void
Cache<TagStore>::CpuSidePort::recvFunctional(PacketPtr pkt)
{
- if (!checkFunctional(pkt)) {
- myCache()->functionalAccess(pkt, cache->memSidePort);
- }
+ myCache()->functionalAccess(pkt, this, otherPort);
}
template<class TagStore>
Cache<TagStore>::
-CpuSidePort::CpuSidePort(const std::string &_name,
- Cache<TagStore> *_cache, std::vector<Range<Addr> >
- filterRanges)
- : BaseCache::CachePort(_name, _cache, filterRanges)
+CpuSidePort::CpuSidePort(const std::string &_name, Cache<TagStore> *_cache,
+ const std::string &_label,
+ std::vector<Range<Addr> > filterRanges)
+ : BaseCache::CachePort(_name, _cache, _label, filterRanges)
{
}
@@ -1352,9 +1359,7 @@ template<class TagStore>
void
Cache<TagStore>::MemSidePort::recvFunctional(PacketPtr pkt)
{
- if (!checkFunctional(pkt)) {
- myCache()->functionalAccess(pkt, cache->cpuSidePort);
- }
+ myCache()->functionalAccess(pkt, this, otherPort);
}
@@ -1439,8 +1444,9 @@ Cache<TagStore>::MemSidePort::processSendEvent()
template<class TagStore>
Cache<TagStore>::
MemSidePort::MemSidePort(const std::string &_name, Cache<TagStore> *_cache,
- std::vector<Range<Addr> > filterRanges)
- : BaseCache::CachePort(_name, _cache, filterRanges)
+ const std::string &_label,
+ std::vector<Range<Addr> > filterRanges)
+ : BaseCache::CachePort(_name, _cache, _label, filterRanges)
{
// override default send event from SimpleTimingPort
delete sendEvent;
diff --git a/src/mem/cache/miss/mshr.cc b/src/mem/cache/miss/mshr.cc
index e2ff444d5..88d2acea0 100644
--- a/src/mem/cache/miss/mshr.cc
+++ b/src/mem/cache/miss/mshr.cc
@@ -133,6 +133,18 @@ MSHR::TargetList::checkFunctional(PacketPtr pkt)
void
+MSHR::TargetList::
+print(std::ostream &os, int verbosity, const std::string &prefix) const
+{
+ ConstIterator end_i = end();
+ for (ConstIterator i = begin(); i != end_i; ++i) {
+ ccprintf(os, "%s%s: ", prefix, i->isCpuSide() ? "cpu" : "mem");
+ i->pkt->print(os, verbosity, "");
+ }
+}
+
+
+void
MSHR::allocate(Addr _addr, int _size, PacketPtr target,
Tick whenReady, Counter _order)
{
@@ -350,26 +362,41 @@ MSHR::handleFill(Packet *pkt, CacheBlk *blk)
}
+bool
+MSHR::checkFunctional(PacketPtr pkt)
+{
+ // For printing, we treat the MSHR as a whole as single entity.
+ // For other requests, we iterate over the individual targets
+ // since that's where the actual data lies.
+ if (pkt->isPrint()) {
+ pkt->checkFunctional(this, addr, size, NULL);
+ return false;
+ } else {
+ return (targets->checkFunctional(pkt) ||
+ deferredTargets->checkFunctional(pkt));
+ }
+}
+
+
void
-MSHR::dump()
+MSHR::print(std::ostream &os, int verbosity, const std::string &prefix) const
{
- ccprintf(cerr,
- "inService: %d thread: %d\n"
- "Addr: %x ntargets %d\n"
- "Targets:\n",
- inService, threadNum, addr, ntargets);
-#if 0
- TargetListIterator tar_it = targets->begin();
- for (int i = 0; i < ntargets; i++) {
- assert(tar_it != targets->end());
-
- ccprintf(cerr, "\t%d: Addr: %x cmd: %s\n",
- i, tar_it->pkt->getAddr(), tar_it->pkt->cmdString());
-
- tar_it++;
+ ccprintf(os, "%s[%x:%x] %s %s %s state: %s %s %s %s\n",
+ prefix, addr, addr+size-1,
+ isCacheFill ? "Fill" : "",
+ needsExclusive() ? "Excl" : "",
+ _isUncacheable ? "Unc" : "",
+ inService ? "InSvc" : "",
+ downstreamPending ? "DwnPend" : "",
+ pendingInvalidate ? "PendInv" : "",
+ pendingShared ? "PendShared" : "");
+
+ ccprintf(os, "%s Targets:\n", prefix);
+ targets->print(os, verbosity, prefix + " ");
+ if (!deferredTargets->empty()) {
+ ccprintf(os, "%s Deferred Targets:\n", prefix);
+ deferredTargets->print(os, verbosity, prefix + " ");
}
-#endif
- ccprintf(cerr, "\n");
}
MSHR::~MSHR()
diff --git a/src/mem/cache/miss/mshr.hh b/src/mem/cache/miss/mshr.hh
index c865ca3ac..0bc3c4480 100644
--- a/src/mem/cache/miss/mshr.hh
+++ b/src/mem/cache/miss/mshr.hh
@@ -38,6 +38,7 @@
#include <list>
+#include "base/printable.hh"
#include "mem/packet.hh"
class CacheBlk;
@@ -47,7 +48,7 @@ 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 : public Packet::SenderState
+class MSHR : public Packet::SenderState, public Printable
{
public:
@@ -60,7 +61,7 @@ class MSHR : public Packet::SenderState
PacketPtr pkt; //!< Pending request packet.
bool cpuSide; //!< Did request come from cpu side or mem side?
- bool isCpuSide() { return cpuSide; }
+ bool isCpuSide() const { return cpuSide; }
Target(PacketPtr _pkt, Tick _readyTime, Counter _order, bool _cpuSide)
: recvTime(curTick), readyTime(_readyTime), order(_order),
@@ -71,6 +72,7 @@ class MSHR : public Packet::SenderState
class TargetList : public std::list<Target> {
/** Target list iterator. */
typedef std::list<Target>::iterator Iterator;
+ typedef std::list<Target>::const_iterator ConstIterator;
public:
bool needsExclusive;
@@ -83,6 +85,8 @@ class MSHR : public Packet::SenderState
void replaceUpgrades();
void clearDownstreamPending();
bool checkFunctional(PacketPtr pkt);
+ void print(std::ostream &os, int verbosity,
+ const std::string &prefix) const;
};
/** A list of MSHRs. */
@@ -114,7 +118,7 @@ class MSHR : public Packet::SenderState
bool isCacheFill;
/** True if we need to get an exclusive copy of the block. */
- bool needsExclusive() { return targets->needsExclusive; }
+ bool needsExclusive() const { return targets->needsExclusive; }
/** True if the request is uncacheable */
bool _isUncacheable;
@@ -231,15 +235,14 @@ public:
void handleFill(Packet *pkt, CacheBlk *blk);
- bool checkFunctional(PacketPtr pkt) {
- return (targets->checkFunctional(pkt) ||
- deferredTargets->checkFunctional(pkt));
- }
+ bool checkFunctional(PacketPtr pkt);
/**
- * Prints the contents of this MSHR to stderr.
+ * Prints the contents of this MSHR for debugging.
*/
- void dump();
+ void print(std::ostream &os,
+ int verbosity = 0,
+ const std::string &prefix = "") const;
};
#endif //__MSHR_HH__
diff --git a/src/mem/cache/miss/mshr_queue.cc b/src/mem/cache/miss/mshr_queue.cc
index 911329e0c..71da7e4c1 100644
--- a/src/mem/cache/miss/mshr_queue.cc
+++ b/src/mem/cache/miss/mshr_queue.cc
@@ -36,8 +36,10 @@
using namespace std;
-MSHRQueue::MSHRQueue(int num_entries, int reserve, int _index)
- : numEntries(num_entries + reserve - 1), numReserve(reserve),
+MSHRQueue::MSHRQueue(const std::string &_label,
+ int num_entries, int reserve, int _index)
+ : label(_label),
+ numEntries(num_entries + reserve - 1), numReserve(reserve),
index(_index)
{
allocated = 0;
@@ -90,14 +92,17 @@ MSHRQueue::findMatches(Addr addr, vector<MSHR*>& matches) const
bool
MSHRQueue::checkFunctional(PacketPtr pkt, Addr blk_addr)
{
+ pkt->pushLabel(label);
MSHR::ConstIterator i = allocatedList.begin();
MSHR::ConstIterator end = allocatedList.end();
for (; i != end; ++i) {
MSHR *mshr = *i;
if (mshr->addr == blk_addr && mshr->checkFunctional(pkt)) {
+ pkt->popLabel();
return true;
}
}
+ pkt->popLabel();
return false;
}
diff --git a/src/mem/cache/miss/mshr_queue.hh b/src/mem/cache/miss/mshr_queue.hh
index 447ebfc5a..e04745087 100644
--- a/src/mem/cache/miss/mshr_queue.hh
+++ b/src/mem/cache/miss/mshr_queue.hh
@@ -46,6 +46,9 @@
class MSHRQueue
{
private:
+ /** Local label (for functional print requests) */
+ const std::string label;
+
/** MSHR storage. */
MSHR *registers;
/** Holds pointers to all allocated entries. */
@@ -87,7 +90,8 @@ class MSHRQueue
* @param reserve The minimum number of entries needed to satisfy
* any access.
*/
- MSHRQueue(int num_entries, int reserve, int index);
+ MSHRQueue(const std::string &_label, int num_entries, int reserve,
+ int index);
/** Destructor */
~MSHRQueue();
diff --git a/src/mem/packet.cc b/src/mem/packet.cc
index 7b36be599..164363860 100644
--- a/src/mem/packet.cc
+++ b/src/mem/packet.cc
@@ -37,6 +37,7 @@
#include <iostream>
#include <cstring>
+#include "base/cprintf.hh"
#include "base/misc.hh"
#include "base/trace.hh"
#include "mem/packet.hh"
@@ -121,7 +122,9 @@ MemCmd::commandInfo[] =
/* InvalidDestError -- packet dest field invalid */
{ SET2(IsResponse, IsError), InvalidCmd, "InvalidDestError" },
/* BadAddressError -- memory address invalid */
- { SET2(IsResponse, IsError), InvalidCmd, "BadAddressError" }
+ { SET2(IsResponse, IsError), InvalidCmd, "BadAddressError" },
+ /* PrintReq */
+ { SET2(IsRequest, IsPrint), InvalidCmd, "PrintReq" }
};
@@ -154,7 +157,7 @@ Packet::allocate()
bool
-Packet::checkFunctional(Addr addr, int size, uint8_t *data)
+Packet::checkFunctional(Printable *obj, Addr addr, int size, uint8_t *data)
{
Addr func_start = getAddr();
Addr func_end = getAddr() + getSize() - 1;
@@ -166,6 +169,17 @@ Packet::checkFunctional(Addr addr, int size, uint8_t *data)
return false;
}
+ // check print first since it doesn't require data
+ if (isPrint()) {
+ dynamic_cast<PrintReqState*>(senderState)->printObj(obj);
+ return false;
+ }
+
+ // if there's no data, there's no need to look further
+ if (!data) {
+ return false;
+ }
+
// offset of functional request into supplied value (could be
// negative if partial overlap)
int offset = func_start - val_start;
@@ -194,40 +208,85 @@ Packet::checkFunctional(Addr addr, int size, uint8_t *data)
std::memcpy(data, getPtr<uint8_t>() - offset,
(std::min(func_end, val_end) - val_start) + 1);
}
- // we always want to keep going with a write
- return false;
- } else
+ } else {
panic("Don't know how to handle command %s\n", cmdString());
+ }
+
+ // keep going with request by default
+ return false;
+}
+
+
+void
+Packet::print(std::ostream &o, const int verbosity,
+ const std::string &prefix) const
+{
+ ccprintf(o, "%s[%x:%x] %s\n", prefix,
+ getAddr(), getAddr() + getSize() - 1, cmdString());
+}
+
+
+Packet::PrintReqState::PrintReqState(std::ostream &_os, int _verbosity)
+ : curPrefixPtr(new std::string("")), os(_os), verbosity(_verbosity)
+{
+ labelStack.push_back(LabelStackEntry("", curPrefixPtr));
+}
+
+
+Packet::PrintReqState::~PrintReqState()
+{
+ labelStack.pop_back();
+ assert(labelStack.empty());
+ delete curPrefixPtr;
+}
+
+
+Packet::PrintReqState::
+LabelStackEntry::LabelStackEntry(const std::string &_label,
+ std::string *_prefix)
+ : label(_label), prefix(_prefix), labelPrinted(false)
+{
}
-std::ostream &
-operator<<(std::ostream &o, const Packet &p)
+void
+Packet::PrintReqState::pushLabel(const std::string &lbl,
+ const std::string &prefix)
+{
+ labelStack.push_back(LabelStackEntry(lbl, curPrefixPtr));
+ curPrefixPtr = new std::string(*curPrefixPtr);
+ *curPrefixPtr += prefix;
+}
+
+void
+Packet::PrintReqState::popLabel()
{
+ delete curPrefixPtr;
+ curPrefixPtr = labelStack.back().prefix;
+ labelStack.pop_back();
+ assert(!labelStack.empty());
+}
- o << "[0x";
- o.setf(std::ios_base::hex, std::ios_base::showbase);
- o << p.getAddr();
- o.unsetf(std::ios_base::hex| std::ios_base::showbase);
- o << ":";
- o.setf(std::ios_base::hex, std::ios_base::showbase);
- o << p.getAddr() + p.getSize() - 1 << "] ";
- o.unsetf(std::ios_base::hex| std::ios_base::showbase);
-
- if (p.isRead())
- o << "Read ";
- if (p.isWrite())
- o << "Write ";
- if (p.isInvalidate())
- o << "Invalidate ";
- if (p.isRequest())
- o << "Request ";
- if (p.isResponse())
- o << "Response ";
- if (p.hasData())
- o << "w/Data ";
-
- o << std::endl;
- return o;
+void
+Packet::PrintReqState::printLabels()
+{
+ if (!labelStack.back().labelPrinted) {
+ LabelStack::iterator i = labelStack.begin();
+ LabelStack::iterator end = labelStack.end();
+ while (i != end) {
+ if (!i->labelPrinted) {
+ ccprintf(os, "%s%s\n", *(i->prefix), i->label);
+ i->labelPrinted = true;
+ }
+ i++;
+ }
+ }
}
+
+void
+Packet::PrintReqState::printObj(Printable *obj)
+{
+ printLabels();
+ obj->print(os, verbosity, curPrefix());
+}
diff --git a/src/mem/packet.hh b/src/mem/packet.hh
index 9c366f9fc..c97413e85 100644
--- a/src/mem/packet.hh
+++ b/src/mem/packet.hh
@@ -45,6 +45,7 @@
#include "base/compiler.hh"
#include "base/fast_alloc.hh"
#include "base/misc.hh"
+#include "base/printable.hh"
#include "mem/request.hh"
#include "sim/host.hh"
#include "sim/core.hh"
@@ -91,6 +92,8 @@ class MemCmd
NetworkNackError, // nacked at network layer (not by protocol)
InvalidDestError, // packet dest field invalid
BadAddressError, // memory address invalid
+ // Fake simulator-only commands
+ PrintReq, // Print state matching address
NUM_MEM_CMDS
};
@@ -111,6 +114,7 @@ class MemCmd
IsLocked, //!< Alpha/MIPS LL or SC access
HasData, //!< There is an associated payload
IsError, //!< Error response
+ IsPrint, //!< Print state matching address (for debugging)
NUM_COMMAND_ATTRIBUTES
};
@@ -150,6 +154,7 @@ class MemCmd
bool isReadWrite() const { return isRead() && isWrite(); }
bool isLocked() const { return testCmdAttrib(IsLocked); }
bool isError() const { return testCmdAttrib(IsError); }
+ bool isPrint() const { return testCmdAttrib(IsPrint); }
const Command responseCommand() const {
return commandInfo[cmd].response;
@@ -187,7 +192,7 @@ class MemCmd
* ultimate destination and back, possibly being conveyed by several
* different Packets along the way.)
*/
-class Packet : public FastAlloc
+class Packet : public FastAlloc, public Printable
{
public:
@@ -294,6 +299,36 @@ class Packet : public FastAlloc
virtual ~SenderState() {}
};
+ class PrintReqState : public SenderState {
+ class LabelStackEntry {
+ public:
+ const std::string label;
+ std::string *prefix;
+ bool labelPrinted;
+ LabelStackEntry(const std::string &_label,
+ std::string *_prefix);
+ };
+
+ typedef std::list<LabelStackEntry> LabelStack;
+ LabelStack labelStack;
+
+ std::string *curPrefixPtr;
+
+ public:
+ std::ostream &os;
+ const int verbosity;
+
+ PrintReqState(std::ostream &os, int verbosity = 0);
+ ~PrintReqState();
+
+ const std::string &curPrefix() { return *curPrefixPtr; }
+ void pushLabel(const std::string &lbl,
+ const std::string &prefix = " ");
+ void popLabel();
+ void printLabels();
+ void printObj(Printable *obj);
+ };
+
/** This packet's sender state. Devices should use dynamic_cast<>
* to cast to the state appropriate to the sender. */
SenderState *senderState;
@@ -316,6 +351,7 @@ class Packet : public FastAlloc
bool isReadWrite() const { return cmd.isReadWrite(); }
bool isLocked() const { return cmd.isLocked(); }
bool isError() const { return cmd.isError(); }
+ bool isPrint() const { return cmd.isPrint(); }
// Snoop flags
void assertMemInhibit() { flags[MemInhibit] = true; }
@@ -573,19 +609,39 @@ class Packet : public FastAlloc
* value. If the functional request is a write, it may update the
* memory value.
*/
- bool checkFunctional(Addr base, int size, uint8_t *data);
+ bool checkFunctional(Printable *obj, Addr base, int size, uint8_t *data);
/**
* Check a functional request against a memory value stored in
- * another packet (i.e. an in-transit request or response).
+ * another packet (i.e. an in-transit request or response). If
+ * possible, the request will be satisfied and transformed
+ * in-place into a response (at which point no further checking
+ * need be done).
+ *
+ * @return True if the memory location addressed by the request
+ * overlaps with the location addressed by otherPkt.
*/
bool checkFunctional(PacketPtr otherPkt) {
- return (otherPkt->hasData() &&
- checkFunctional(otherPkt->getAddr(), otherPkt->getSize(),
- otherPkt->getPtr<uint8_t>()));
+ return checkFunctional(otherPkt,
+ otherPkt->getAddr(), otherPkt->getSize(),
+ otherPkt->hasData() ?
+ otherPkt->getPtr<uint8_t>() : NULL);
}
-};
-std::ostream & operator<<(std::ostream &o, const Packet &p);
+ void pushLabel(const std::string &lbl) {
+ if (isPrint()) {
+ dynamic_cast<PrintReqState*>(senderState)->pushLabel(lbl);
+ }
+ }
+
+ void popLabel() {
+ if (isPrint()) {
+ dynamic_cast<PrintReqState*>(senderState)->popLabel();
+ }
+ }
+
+ void print(std::ostream &o, int verbosity = 0,
+ const std::string &prefix = "") const;
+};
#endif //__MEM_PACKET_HH
diff --git a/src/mem/physical.cc b/src/mem/physical.cc
index a3a9df64e..40dc30afb 100644
--- a/src/mem/physical.cc
+++ b/src/mem/physical.cc
@@ -314,18 +314,22 @@ PhysicalMemory::doFunctionalAccess(PacketPtr pkt)
uint8_t *hostAddr = pmemAddr + pkt->getAddr() - start();
- if (pkt->cmd == MemCmd::ReadReq) {
+ if (pkt->isRead()) {
memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
TRACE_PACKET("Read");
- } else if (pkt->cmd == MemCmd::WriteReq) {
+ pkt->makeAtomicResponse();
+ } else if (pkt->isWrite()) {
memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize());
TRACE_PACKET("Write");
+ pkt->makeAtomicResponse();
+ } else if (pkt->isPrint()) {
+ Packet::PrintReqState *prs = dynamic_cast<Packet::PrintReqState*>(pkt->senderState);
+ prs->printLabels();
+ ccprintf(prs->os, "%s%#x\n", prs->curPrefix(), *hostAddr);
} else {
panic("PhysicalMemory: unimplemented functional command %s",
pkt->cmdString());
}
-
- pkt->makeAtomicResponse();
}
@@ -405,12 +409,16 @@ PhysicalMemory::MemoryPort::recvAtomic(PacketPtr pkt)
void
PhysicalMemory::MemoryPort::recvFunctional(PacketPtr pkt)
{
+ pkt->pushLabel(memory->name());
+
if (!checkFunctional(pkt)) {
// Default implementation of SimpleTimingPort::recvFunctional()
// calls recvAtomic() and throws away the latency; we can save a
// little here by just not calculating the latency.
memory->doFunctionalAccess(pkt);
}
+
+ pkt->popLabel();
}
unsigned int
diff --git a/src/mem/port.cc b/src/mem/port.cc
index 2e56d2486..ce3f6c74b 100644
--- a/src/mem/port.cc
+++ b/src/mem/port.cc
@@ -150,3 +150,15 @@ Port::memsetBlob(Addr addr, uint8_t val, int size)
delete [] buf;
}
+
+
+void
+Port::printAddr(Addr a)
+{
+ Request req(a, 1, 0);
+ Packet pkt(&req, MemCmd::PrintReq, Packet::Broadcast);
+ Packet::PrintReqState prs(std::cerr);
+ pkt.senderState = &prs;
+
+ sendFunctional(&pkt);
+}
diff --git a/src/mem/port.hh b/src/mem/port.hh
index cadf67260..f66b566ea 100644
--- a/src/mem/port.hh
+++ b/src/mem/port.hh
@@ -243,6 +243,11 @@ class Port
*/
virtual void memsetBlob(Addr addr, uint8_t val, int size);
+ /** Inject a PrintReq for the given address to print the state of
+ * that address throughout the memory system. For debugging.
+ */
+ void printAddr(Addr a);
+
private:
/** Internal helper function for read/writeBlob().