Add functional PrintReq command for memory-system debugging.

--HG--
extra : convert_revision : 73b753e57c355b7e6873f047ddc8cb371c3136b7
This commit is contained in:
Steve Reinhardt
2008-01-02 12:20:15 -08:00
parent 659aef3eb8
commit 3952e41ab1
23 changed files with 458 additions and 123 deletions

50
src/base/printable.hh Normal file
View File

@@ -0,0 +1,50 @@
/*
* 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.
*/
/* @file
* Printable Object Base Class Declaration
*/
#ifndef __PRINTABLE_HH__
#define __PRINTABLE_HH__
#include <ostream>
#include <string>
class Printable
{
public:
Printable() {}
virtual ~Printable() {}
virtual void print(std::ostream &os,
int verbosity = 0,
const std::string &prefix = "") const = 0;
};
#endif // __PRINTABLE_HH__

View File

@@ -399,3 +399,10 @@ MemTestParams::create()
{
return new MemTest(this);
}
void
MemTest::printAddr(Addr a)
{
cachePort.printAddr(a);
}

View File

@@ -62,6 +62,8 @@ class MemTest : public MemObject
virtual Port *getPort(const std::string &if_name, int idx = -1);
void printAddr(Addr a);
protected:
class TickEvent : public Event
{

View File

@@ -52,7 +52,6 @@
#include "cpu/checker/cpu.hh"
#endif
using namespace std;
using namespace TheISA;
BaseO3CPU::BaseO3CPU(Params *params)
@@ -521,8 +520,8 @@ template <class Impl>
void
FullO3CPU<Impl>::activateThread(unsigned tid)
{
list<unsigned>::iterator isActive = find(
activeThreads.begin(), activeThreads.end(), tid);
std::list<unsigned>::iterator isActive =
std::find(activeThreads.begin(), activeThreads.end(), tid);
DPRINTF(O3CPU, "[tid:%i]: Calling activate thread.\n", tid);
@@ -539,8 +538,8 @@ void
FullO3CPU<Impl>::deactivateThread(unsigned tid)
{
//Remove From Active List, if Active
list<unsigned>::iterator thread_it =
find(activeThreads.begin(), activeThreads.end(), tid);
std::list<unsigned>::iterator thread_it =
std::find(activeThreads.begin(), activeThreads.end(), tid);
DPRINTF(O3CPU, "[tid:%i]: Calling deactivate thread.\n", tid);
@@ -959,8 +958,8 @@ FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
// the active threads list.
int tid = 0;
list<unsigned>::iterator isActive = find(
activeThreads.begin(), activeThreads.end(), tid);
std::list<unsigned>::iterator isActive =
std::find(activeThreads.begin(), activeThreads.end(), tid);
if (isActive == activeThreads.end()) {
//May Need to Re-code this if the delay variable is the delay
@@ -1454,8 +1453,8 @@ FullO3CPU<Impl>::updateThreadPriority()
{
//DEFAULT TO ROUND ROBIN SCHEME
//e.g. Move highest priority to end of thread list
list<unsigned>::iterator list_begin = activeThreads.begin();
list<unsigned>::iterator list_end = activeThreads.end();
std::list<unsigned>::iterator list_begin = activeThreads.begin();
std::list<unsigned>::iterator list_end = activeThreads.end();
unsigned high_thread = *list_begin;

View File

@@ -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);
}

View File

@@ -34,6 +34,7 @@ SimObject('BaseCache.py')
Source('base_cache.cc')
Source('cache.cc')
Source('cache_blk.cc')
Source('cache_builder.cc')
TraceFlag('Cache')

View File

@@ -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,6 +73,17 @@ BaseCache::CachePort::recvStatusChange(Port::Status status)
}
}
bool
BaseCache::CachePort::checkFunctional(PacketPtr pkt)
{
pkt->pushLabel(label);
bool done = SimpleTimingPort::checkFunctional(pkt);
pkt->popLabel();
return done;
}
int
BaseCache::CachePort::deviceBlockSize()
{
@@ -78,15 +91,6 @@ BaseCache::CachePort::deviceBlockSize()
}
void
BaseCache::CachePort::checkAndSendFunctional(PacketPtr pkt)
{
if (!checkFunctional(pkt)) {
sendFunctional(pkt);
}
}
bool
BaseCache::CachePort::recvRetryCommon()
{

View File

@@ -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;

View File

@@ -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.

41
src/mem/cache/cache_blk.cc vendored Normal file
View File

@@ -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' : '-');
}

View File

@@ -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__

View File

@@ -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());
// 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);
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);
// 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;

View File

@@ -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)
}
void
MSHR::dump()
bool
MSHR::checkFunctional(PacketPtr pkt)
{
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++;
// 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::print(std::ostream &os, int verbosity, const std::string &prefix) const
{
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()

View File

@@ -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__

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -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;
}
std::ostream &
operator<<(std::ostream &o, const Packet &p)
void
Packet::print(std::ostream &o, const int verbosity,
const std::string &prefix) const
{
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;
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)
{
}
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());
}
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());
}

View File

@@ -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);
}
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;
};
std::ostream & operator<<(std::ostream &o, const Packet &p);
#endif //__MEM_PACKET_HH

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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().

View File

@@ -264,3 +264,19 @@ SimObject::takeOverFrom(BaseCPU *cpu)
{
panic("Unimplemented!");
}
SimObject *
SimObject::find(const char *name)
{
SimObjectList::const_iterator i = simObjectList.begin();
SimObjectList::const_iterator end = simObjectList.end();
for (; i != end; ++i) {
SimObject *obj = *i;
if (obj->name() == name)
return obj;
}
return NULL;
}

View File

@@ -131,6 +131,13 @@ class SimObject : public Serializable, protected StartupCallback
static void debugObjectBreak(const std::string &objs);
#endif
/**
* Find the SimObject with the given name and return a pointer to
* it. Priarily used for interactive debugging. Argument is
* char* rather than std::string to make it callable from gdb.
*/
static SimObject *find(const char *name);
public:
void recordEvent(const std::string &stat);
};