style: clean up the Packet stuff
[gem5.git] / src / mem / packet.cc
index 3b415d77f1dc83b40cd59946486f57d53814c680..17e58859a1bfc72a08d7cae7d20709bd64e85b4d 100644 (file)
@@ -24,6 +24,9 @@
  * 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.
+ *
+ * Authors: Ali Saidi
+ *          Steve Reinhardt
  */
 
 /**
  * Definition of the Packet Class, a packet is a transaction occuring
  * between a single level of the memory heirarchy (ie L1->L2).
  */
+
+#include <iostream>
+#include <cstring>
+#include "base/cprintf.hh"
 #include "base/misc.hh"
+#include "base/trace.hh"
 #include "mem/packet.hh"
 
-static const std::string ReadReqString("ReadReq");
-static const std::string WriteReqString("WriteReq");
-static const std::string WriteReqNoAckString("WriteReqNoAck");
-static const std::string ReadRespString("ReadResp");
-static const std::string WriteRespString("WriteResp");
-static const std::string OtherCmdString("<other>");
+using namespace std;
+
+// The one downside to bitsets is that static initializers can get ugly.
+#define SET1(a1)                     (1 << (a1))
+#define SET2(a1, a2)                 (SET1(a1) | SET1(a2))
+#define SET3(a1, a2, a3)             (SET2(a1, a2) | SET1(a3))
+#define SET4(a1, a2, a3, a4)         (SET3(a1, a2, a3) | SET1(a4))
+#define SET5(a1, a2, a3, a4, a5)     (SET4(a1, a2, a3, a4) | SET1(a5))
+#define SET6(a1, a2, a3, a4, a5, a6) (SET5(a1, a2, a3, a4, a5) | SET1(a6))
+
+const MemCmd::CommandInfo
+MemCmd::commandInfo[] =
+{
+    /* InvalidCmd */
+    { 0, InvalidCmd, "InvalidCmd" },
+    /* ReadReq */
+    { SET3(IsRead, IsRequest, NeedsResponse), ReadResp, "ReadReq" },
+    /* ReadResp */
+    { SET3(IsRead, IsResponse, HasData), InvalidCmd, "ReadResp" },
+    /* ReadRespWithInvalidate */
+    { SET4(IsRead, IsResponse, HasData, IsInvalidate),
+            InvalidCmd, "ReadRespWithInvalidate" },
+    /* WriteReq */
+    { SET5(IsWrite, NeedsExclusive, IsRequest, NeedsResponse, HasData),
+            WriteResp, "WriteReq" },
+    /* WriteResp */
+    { SET3(IsWrite, NeedsExclusive, IsResponse), InvalidCmd, "WriteResp" },
+    /* Writeback */
+    { SET4(IsWrite, NeedsExclusive, IsRequest, HasData),
+            InvalidCmd, "Writeback" },
+    /* SoftPFReq */
+    { SET4(IsRead, IsRequest, IsSWPrefetch, NeedsResponse),
+            SoftPFResp, "SoftPFReq" },
+    /* HardPFReq */
+    { SET4(IsRead, IsRequest, IsHWPrefetch, NeedsResponse),
+            HardPFResp, "HardPFReq" },
+    /* SoftPFResp */
+    { SET4(IsRead, IsResponse, IsSWPrefetch, HasData),
+            InvalidCmd, "SoftPFResp" },
+    /* HardPFResp */
+    { SET4(IsRead, IsResponse, IsHWPrefetch, HasData),
+            InvalidCmd, "HardPFResp" },
+    /* WriteInvalidateReq */
+    { SET6(IsWrite, NeedsExclusive, IsInvalidate,
+           IsRequest, HasData, NeedsResponse),
+            WriteInvalidateResp, "WriteInvalidateReq" },
+    /* WriteInvalidateResp */
+    { SET3(IsWrite, NeedsExclusive, IsResponse),
+            InvalidCmd, "WriteInvalidateResp" },
+    /* UpgradeReq */
+    { SET4(IsInvalidate, NeedsExclusive, IsRequest, NeedsResponse),
+            UpgradeResp, "UpgradeReq" },
+    /* UpgradeResp */
+    { SET2(NeedsExclusive, IsResponse),
+            InvalidCmd, "UpgradeResp" },
+    /* ReadExReq */
+    { SET5(IsRead, NeedsExclusive, IsInvalidate, IsRequest, NeedsResponse),
+            ReadExResp, "ReadExReq" },
+    /* ReadExResp */
+    { SET4(IsRead, NeedsExclusive, IsResponse, HasData),
+            InvalidCmd, "ReadExResp" },
+    /* LoadLockedReq: note that we use plain ReadResp as response, so that
+     *                we can also use ReadRespWithInvalidate when needed */
+    { SET4(IsRead, IsLocked, IsRequest, NeedsResponse),
+            ReadResp, "LoadLockedReq" },
+    /* StoreCondReq */
+    { SET6(IsWrite, NeedsExclusive, IsLocked,
+           IsRequest, NeedsResponse, HasData),
+            StoreCondResp, "StoreCondReq" },
+    /* StoreCondResp */
+    { SET4(IsWrite, NeedsExclusive, IsLocked, IsResponse),
+            InvalidCmd, "StoreCondResp" },
+    /* SwapReq -- for Swap ldstub type operations */
+    { SET6(IsRead, IsWrite, NeedsExclusive, IsRequest, HasData, NeedsResponse),
+        SwapResp, "SwapReq" },
+    /* SwapResp -- for Swap ldstub type operations */
+    { SET5(IsRead, IsWrite, NeedsExclusive, IsResponse, HasData),
+            InvalidCmd, "SwapResp" },
+    /* IntReq -- for interrupts */
+    { SET4(IsWrite, IsRequest, NeedsResponse, HasData),
+        MessageReq, "MessageReq" },
+    /* IntResp -- for interrupts */
+    { SET2(IsWrite, IsResponse), MessageResp, "MessageResp" },
+    /* NetworkNackError  -- nacked at network layer (not by protocol) */
+    { SET2(IsResponse, IsError), InvalidCmd, "NetworkNackError" },
+    /* InvalidDestError  -- packet dest field invalid */
+    { SET2(IsResponse, IsError), InvalidCmd, "InvalidDestError" },
+    /* BadAddressError   -- memory address invalid */
+    { SET2(IsResponse, IsError), InvalidCmd, "BadAddressError" },
+    /* PrintReq */
+    { SET2(IsRequest, IsPrint), InvalidCmd, "PrintReq" }
+};
 
-const std::string &
-Packet::cmdString() const
+bool
+Packet::checkFunctional(Printable *obj, Addr addr, int size, uint8_t *data)
 {
-    switch (cmd) {
-      case ReadReq:         return ReadReqString;
-      case WriteReq:        return WriteReqString;
-      case WriteReqNoAck:   return WriteReqNoAckString;
-      case ReadResp:        return ReadRespString;
-      case WriteResp:       return WriteRespString;
-      default:              return OtherCmdString;
+    Addr func_start = getAddr();
+    Addr func_end   = getAddr() + getSize() - 1;
+    Addr val_start  = addr;
+    Addr val_end    = val_start + size - 1;
+
+    if (func_start > val_end || val_start > func_end) {
+        // no intersection
+        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;
+
+    if (isRead()) {
+        if (func_start >= val_start && func_end <= val_end) {
+            allocate();
+            memcpy(getPtr<uint8_t>(), data + offset, getSize());
+            makeResponse();
+            return true;
+        } else {
+            // In this case the timing packet only partially satisfies
+            // the request, so we would need more information to make
+            // this work.  Like bytes valid in the packet or
+            // something, so the request could continue and get this
+            // bit of possibly newer data along with the older data
+            // not written to yet.
+            panic("Memory value only partially satisfies the functional "
+                  "request. Now what?");
+        }
+    } else if (isWrite()) {
+        if (offset >= 0) {
+            memcpy(data + offset, getPtr<uint8_t>(),
+                   (min(func_end, val_end) - func_start) + 1);
+        } else {
+            // val_start > func_start
+            memcpy(data, getPtr<uint8_t>() - offset,
+                   (min(func_end, val_end) - val_start) + 1);
+        }
+    } else {
+        panic("Don't know how to handle command %s\n", cmdString());
+    }
+
+    // keep going with request by default
+    return false;
 }
 
-/** delete the data pointed to in the data pointer. Ok to call to matter how
- * data was allocted. */
 void
-Packet::deleteData()
+Packet::print(ostream &o, const int verbosity, const string &prefix) const
+{
+    ccprintf(o, "%s[%x:%x] %s\n", prefix,
+             getAddr(), getAddr() + getSize() - 1, cmdString());
+}
+
+Packet::PrintReqState::PrintReqState(ostream &_os, int _verbosity)
+    : curPrefixPtr(new 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 string &_label, string *_prefix)
+    : label(_label), prefix(_prefix), labelPrinted(false)
 {
-    assert(staticData || dynamicData);
-    if (staticData)
-        return;
-
-    if (arrayData)
-        delete [] data;
-    else
-        delete data;
 }
 
-/** If there isn't data in the packet, allocate some. */
 void
-Packet::allocate()
+Packet::PrintReqState::pushLabel(const string &lbl, const string &prefix)
 {
-    if (data)
-        return;
-    assert(!staticData);
-    dynamicData = true;
-    arrayData = true;
-    data = new uint8_t[getSize()];
+    labelStack.push_back(LabelStackEntry(lbl, curPrefixPtr));
+    curPrefixPtr = new string(*curPrefixPtr);
+    *curPrefixPtr += prefix;
 }
 
-/** Do the packet modify the same addresses. */
-bool
-Packet::intersect(Packet *p)
+void
+Packet::PrintReqState::popLabel()
 {
-    Addr s1 = getAddr();
-    Addr e1 = getAddr() + getSize();
-    Addr s2 = p->getAddr();
-    Addr e2 = p->getAddr() + p->getSize();
-
-    if (s1 >= s2 && s1 < e2)
-        return true;
-    if (e1 >= s2 && e1 < e2)
-        return true;
-    return false;
+    delete curPrefixPtr;
+    curPrefixPtr = labelStack.back().prefix;
+    labelStack.pop_back();
+    assert(!labelStack.empty());
 }
 
-/** Minimally reset a packet so something like simple cpu can reuse it. */
 void
-Packet::reset()
+Packet::PrintReqState::printLabels()
 {
-    result = Unknown;
-    if (dynamicData) {
-       deleteData();
-       dynamicData = false;
-       arrayData = false;
-       time = curTick;
+    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++;
+        }
     }
 }
 
 
-bool
-fixPacket(Packet *func, Packet *timing)
+void
+Packet::PrintReqState::printObj(Printable *obj)
 {
-    panic("Need to implement!");
+    printLabels();
+    obj->print(os, verbosity, curPrefix());
 }