Add functional PrintReq command for memory-system debugging.
authorSteve Reinhardt <stever@gmail.com>
Wed, 2 Jan 2008 20:20:15 +0000 (12:20 -0800)
committerSteve Reinhardt <stever@gmail.com>
Wed, 2 Jan 2008 20:20:15 +0000 (12:20 -0800)
--HG--
extra : convert_revision : 73b753e57c355b7e6873f047ddc8cb371c3136b7

23 files changed:
src/base/printable.hh [new file with mode: 0644]
src/cpu/memtest/memtest.cc
src/cpu/memtest/memtest.hh
src/cpu/o3/cpu.cc
src/mem/bridge.cc
src/mem/cache/SConscript
src/mem/cache/base_cache.cc
src/mem/cache/base_cache.hh
src/mem/cache/cache.hh
src/mem/cache/cache_blk.cc [new file with mode: 0644]
src/mem/cache/cache_blk.hh
src/mem/cache/cache_impl.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/packet.cc
src/mem/packet.hh
src/mem/physical.cc
src/mem/port.cc
src/mem/port.hh
src/sim/sim_object.cc
src/sim/sim_object.hh

diff --git a/src/base/printable.hh b/src/base/printable.hh
new file mode 100644 (file)
index 0000000..1f71cce
--- /dev/null
@@ -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__
index f8c8a0547d82bebe4aeea7c9227a5153af2a2722..e2acff4ca031a23cd1f77c2ba5a6f5ddf776f368 100644 (file)
@@ -399,3 +399,10 @@ MemTestParams::create()
 {
     return new MemTest(this);
 }
+
+
+void
+MemTest::printAddr(Addr a)
+{
+    cachePort.printAddr(a);
+}
index 1c918df330ba2776da9bec9c994da5a66cd62bc7..eb0c822f1c9b0065c0518d50c551e1e6607656e3 100644 (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
     {
index 3842d27bdab0b0ac96d051a58a1ac93caaafb361..5908062aae2c8509a8eb7cedcf67cd540af88e45 100644 (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;
 
index aa059ad13d0cd9ef592e4a19a0a7db37c202cc67..3d396649182c37ec37438cd62489c8e7a7ce6ac2 100644 (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);
 }
index 5ac7e34ad8b155bd9cfad7f974849e959a9cf5bb..d5899b6232302c7c2915fec9ec213491c1964b4a 100644 (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')
index c5632e89fc1ef989b74770b08ea305f2a1077b28..9fa9e2d29ac9eae429ecb551e528b92dd35918e4 100644 (file)
 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();
 }
 
 
index 5049f68f1ecc73960a9ae59762df569b627554ac..604474524350448e6c40c88ddf9902f4fbd23a69 100644 (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;
 
index 037afd6ac1824b7a0b5876d3efb5b463167d7f25..4602fd835f00d18867ea456f4c8a8af6b695a4ae 100644 (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.
diff --git a/src/mem/cache/cache_blk.cc b/src/mem/cache/cache_blk.cc
new file mode 100644 (file)
index 0000000..d4a2eae
--- /dev/null
@@ -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' : '-');
+}
+
index d2aba948022ae94411075c526a92589cabd9b718..e7c2d1a024eca66c95885dbad3ded15a7071834f 100644 (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__
index 55301ecb5f8e5dce90926443038421eb7c79acc5..257b3ef33ec8ba2c12284138d8e9ad99129329b2 100644 (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());
+
+    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;
index e2ff444d570c0b6098b1e5bff689bfdc42f6a3cf..88d2acea0cc1e216df73ff78735efb2ac9abd90b 100644 (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)
 }
 
 
+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()
index c865ca3acb59fbef778c3b1f26bde088a8d804bd..0bc3c44806faf52dc46b75fb3be4a883487d72f5 100644 (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__
index 911329e0cb345f1cdb603d6fbd252bc4be3c87f4..71da7e4c16aa68368e2488ece4571390af901e04 100644 (file)
 
 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;
 }
 
index 447ebfc5a92a31d1df2e0102cd6beb33e327de0d..e0474508784e027f4506de4333dab5a542dc6fd5 100644 (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();
index 7b36be599e45dea4040c291e2969fe709d78fdcf..164363860dcd6d6068f35f1b22d8c84a574eddd7 100644 (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;
+}
+
+
+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());
+}
index 9c366f9fc68485e6602852c07e5829908b07cac4..c97413e85d629f3cf228b2a862b388afd6780a30 100644 (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);
     }
-};
 
-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
index a3a9df64e8906059a74052fd4c11563f27405846..40dc30afb08c050b3e695047c68dfd323f83a254 100644 (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
index 2e56d2486e66d9e698c0aa1de489dfaeeb84fe44..ce3f6c74b5648b02e660c04da7ec63efa35bd23a 100644 (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);
+}
index cadf67260cae4eb55b11206d94ea0e9f32a123a4..f66b566eabdb1c3b6af5f06746241e65b2da3df8 100644 (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().
index 907f015dc4927d4179f572f5345cc20520ce6f0f..a835aee5b2d0de17fdd36f9013bd9b02daf5decc 100644 (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;
+}
index b70f1d5d3f282528e73f4cf78b289ceb55910690..20a35a32b9a229859d4cd920f38a0ebf5f0566b5 100644 (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);
 };