From 3952e41ab1f1dfaa2f97a6a486528e4ea0bfc5a1 Mon Sep 17 00:00:00 2001 From: Steve Reinhardt Date: Wed, 2 Jan 2008 12:20:15 -0800 Subject: Add functional PrintReq command for memory-system debugging. --HG-- extra : convert_revision : 73b753e57c355b7e6873f047ddc8cb371c3136b7 --- src/mem/bridge.cc | 4 ++ src/mem/cache/SConscript | 1 + src/mem/cache/base_cache.cc | 28 +++++---- src/mem/cache/base_cache.hh | 7 ++- src/mem/cache/cache.hh | 5 +- src/mem/cache/cache_blk.cc | 41 +++++++++++++ src/mem/cache/cache_blk.hh | 13 +++++ src/mem/cache/cache_impl.hh | 54 +++++++++-------- src/mem/cache/miss/mshr.cc | 61 ++++++++++++++------ src/mem/cache/miss/mshr.hh | 21 ++++--- src/mem/cache/miss/mshr_queue.cc | 9 ++- src/mem/cache/miss/mshr_queue.hh | 6 +- src/mem/packet.cc | 121 +++++++++++++++++++++++++++++---------- src/mem/packet.hh | 72 ++++++++++++++++++++--- src/mem/physical.cc | 16 ++++-- src/mem/port.cc | 12 ++++ src/mem/port.hh | 5 ++ 17 files changed, 365 insertions(+), 111 deletions(-) create mode 100644 src/mem/cache/cache_blk.cc (limited to 'src/mem') 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::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 > filter_ranges) - : SimpleTimingPort(_name, _cache), cache(_cache), otherPort(NULL), + const std::string &_label, + std::vector > 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 > filter_ranges); + const std::string &_label, + std::vector > filter_ranges); virtual void recvStatusChange(Status status); @@ -111,6 +112,8 @@ class BaseCache : public MemObject typedef EventWrapper 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 *_cache, + const std::string &_label, std::vector > filterRanges); // BaseCache::CachePort just has a BaseCache *; this function @@ -97,6 +98,7 @@ class Cache : public BaseCache public: MemSidePort(const std::string &_name, Cache *_cache, + const std::string &_label, std::vector > 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 +#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::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::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 >()); + "CpuSideFuncPort", + std::vector >()); } else { panic("Port name %s unrecognized\n", if_name); } @@ -640,21 +643,27 @@ Cache::atomicAccess(PacketPtr pkt) template void Cache::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 void Cache::CpuSidePort::recvFunctional(PacketPtr pkt) { - if (!checkFunctional(pkt)) { - myCache()->functionalAccess(pkt, cache->memSidePort); - } + myCache()->functionalAccess(pkt, this, otherPort); } template Cache:: -CpuSidePort::CpuSidePort(const std::string &_name, - Cache *_cache, std::vector > - filterRanges) - : BaseCache::CachePort(_name, _cache, filterRanges) +CpuSidePort::CpuSidePort(const std::string &_name, Cache *_cache, + const std::string &_label, + std::vector > filterRanges) + : BaseCache::CachePort(_name, _cache, _label, filterRanges) { } @@ -1352,9 +1359,7 @@ template void Cache::MemSidePort::recvFunctional(PacketPtr pkt) { - if (!checkFunctional(pkt)) { - myCache()->functionalAccess(pkt, cache->cpuSidePort); - } + myCache()->functionalAccess(pkt, this, otherPort); } @@ -1439,8 +1444,9 @@ Cache::MemSidePort::processSendEvent() template Cache:: MemSidePort::MemSidePort(const std::string &_name, Cache *_cache, - std::vector > filterRanges) - : BaseCache::CachePort(_name, _cache, filterRanges) + const std::string &_label, + std::vector > 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 @@ -132,6 +132,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 +#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 list iterator. */ typedef std::list::iterator Iterator; + typedef std::list::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& 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 #include +#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(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() - 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 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())); + return checkFunctional(otherPkt, + otherPkt->getAddr(), otherPkt->getSize(), + otherPkt->hasData() ? + otherPkt->getPtr() : NULL); } -}; -std::ostream & operator<<(std::ostream &o, const Packet &p); + void pushLabel(const std::string &lbl) { + if (isPrint()) { + dynamic_cast(senderState)->pushLabel(lbl); + } + } + + void popLabel() { + if (isPrint()) { + dynamic_cast(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(), hostAddr, pkt->getSize()); TRACE_PACKET("Read"); - } else if (pkt->cmd == MemCmd::WriteReq) { + pkt->makeAtomicResponse(); + } else if (pkt->isWrite()) { memcpy(hostAddr, pkt->getPtr(), pkt->getSize()); TRACE_PACKET("Write"); + pkt->makeAtomicResponse(); + } else if (pkt->isPrint()) { + Packet::PrintReqState *prs = dynamic_cast(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(). -- cgit v1.2.3