Automated merge with ssh://daystrom.m5sim.org//repo/m5
[gem5.git] / src / mem / packet.hh
index 036bd3fd71ff031bfdfd0e4be2bb484bf241c167..05442b36982c6a2b6fe0c4d0a764b5e714fab370 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"
@@ -65,6 +66,7 @@ class MemCmd
         InvalidCmd,
         ReadReq,
         ReadResp,
+        ReadRespWithInvalidate,
         WriteReq,
         WriteResp,
         Writeback,
@@ -91,6 +93,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 +115,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 +155,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 +193,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:
 
@@ -256,7 +262,11 @@ class Packet : public FastAlloc
         MemInhibit,
         Shared,
         // Special control flags
+        /// Special timing-mode atomic snoop for multi-level coherence.
         ExpressSnoop,
+        /// Does supplier have exclusive copy?
+        /// Useful for multi-level coherence.
+        SupplyExclusive,
         NUM_PACKET_FLAGS
     };
 
@@ -290,6 +300,53 @@ class Packet : public FastAlloc
         virtual ~SenderState() {}
     };
 
+    /**
+     * Object used to maintain state of a PrintReq.  The senderState
+     * field of a PrintReq should always be of this type.
+     */
+    class PrintReqState : public SenderState {
+        /** An entry in the label stack. */
+        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();
+
+        /** Returns the current line prefix. */
+        const std::string &curPrefix() { return *curPrefixPtr; }
+
+        /** Push a label onto the label stack, and prepend the given
+         * prefix string onto the current prefix.  Labels will only be
+         * printed if an object within the label's scope is
+         * printed. */
+        void pushLabel(const std::string &lbl,
+                       const std::string &prefix = "  ");
+        /** Pop a label off the label stack. */
+        void popLabel();
+        /** Print all of the pending unprinted labels on the
+         * stack. Called by printObj(), so normally not called by
+         * users unless bypassing printObj(). */
+        void printLabels();
+        /** Print a Printable object to os, because it matched the
+         * address on a PrintReq. */
+        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;
@@ -312,24 +369,28 @@ 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; }
-    void assertShared()         { flags[Shared] = true; }
     bool memInhibitAsserted()   { return flags[MemInhibit]; }
+    void assertShared()         { flags[Shared] = true; }
     bool sharedAsserted()       { return flags[Shared]; }
 
     // Special control flags
     void setExpressSnoop()      { flags[ExpressSnoop] = true; }
     bool isExpressSnoop()       { return flags[ExpressSnoop]; }
+    void setSupplyExclusive()   { flags[SupplyExclusive] = true; }
+    bool isSupplyExclusive()    { return flags[SupplyExclusive]; }
 
     // Network error conditions... encapsulate them as methods since
     // their encoding keeps changing (from result field to command
     // field, etc.)
-    void setNacked()     { origCmd = cmd; cmd = MemCmd::NetworkNackError; }
-    void setBadAddress() { origCmd = cmd; cmd = MemCmd::BadAddressError; }
+    void setNacked()     { assert(isResponse()); cmd = MemCmd::NetworkNackError; }
+    void setBadAddress() { assert(isResponse()); cmd = MemCmd::BadAddressError; }
     bool wasNacked()     { return cmd == MemCmd::NetworkNackError; }
     bool hadBadAddress() { return cmd == MemCmd::BadAddressError; }
+    void copyError(Packet *pkt) { assert(pkt->isError()); cmd = pkt->cmd; }
 
     bool nic_pkt() { panic("Unimplemented"); M5_DUMMY_RETURN }
 
@@ -425,6 +486,7 @@ class Packet : public FastAlloc
     {
         assert(needsResponse());
         assert(isRequest());
+        origCmd = cmd;
         cmd = cmd.responseCommand();
         dest = src;
         destValid = srcValid;
@@ -558,9 +620,6 @@ class Packet : public FastAlloc
     /** If there isn't data in the packet, allocate some. */
     void allocate();
 
-    /** Do the packet modify the same addresses. */
-    bool intersect(PacketPtr p);
-
     /**
      * Check a functional request against a memory value represented
      * by a base/size pair and an associated data array.  If the
@@ -568,19 +627,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).
      */
     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);
+    /**
+     * Push label for PrintReq (safe to call unconditionally).
+     */
+    void pushLabel(const std::string &lbl) {
+        if (isPrint()) {
+            dynamic_cast<PrintReqState*>(senderState)->pushLabel(lbl);
+        }
+    }
+
+    /**
+     * Pop label for PrintReq (safe to call unconditionally).
+     */
+    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