Cache: Remove dangling doWriteback declaration
[gem5.git] / src / mem / packet.cc
index 7b36be599e45dea4040c291e2969fe709d78fdcf..69cf36a5c63914dd6bb78db2c332a570d897dc2b 100644 (file)
@@ -1,5 +1,18 @@
 /*
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 2006 The Regents of The University of Michigan
+ * Copyright (c) 2010 Advanced Micro Devices, Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * between a single level of the memory heirarchy (ie L1->L2).
  */
 
-#include <iostream>
 #include <cstring>
+#include <iostream>
+
+#include "base/cprintf.hh"
 #include "base/misc.hh"
 #include "base/trace.hh"
 #include "mem/packet.hh"
 
+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))
@@ -58,6 +75,9 @@ MemCmd::commandInfo[] =
     { 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" },
@@ -78,37 +98,50 @@ MemCmd::commandInfo[] =
     /* HardPFResp */
     { SET4(IsRead, IsResponse, IsHWPrefetch, HasData),
             InvalidCmd, "HardPFResp" },
-    /* WriteInvalidateReq */
+    /* WriteInvalidateReq (currently unused, see packet.hh) */
     { SET6(IsWrite, NeedsExclusive, IsInvalidate,
            IsRequest, HasData, NeedsResponse),
             WriteInvalidateResp, "WriteInvalidateReq" },
-    /* WriteInvalidateResp */
-    { SET4(IsWrite, NeedsExclusive, IsInvalidate, IsResponse),
+    /* WriteInvalidateResp (currently unused, see packet.hh) */
+    { SET3(IsWrite, NeedsExclusive, IsResponse),
             InvalidCmd, "WriteInvalidateResp" },
     /* UpgradeReq */
-    { SET4(IsInvalidate, NeedsExclusive, IsRequest, NeedsResponse),
+    { SET5(IsInvalidate, NeedsExclusive, IsUpgrade, IsRequest, NeedsResponse),
             UpgradeResp, "UpgradeReq" },
+    /* SCUpgradeReq: response could be UpgradeResp or UpgradeFailResp */
+    { SET6(IsInvalidate, NeedsExclusive, IsUpgrade, IsLlsc,
+           IsRequest, NeedsResponse),
+            UpgradeResp, "SCUpgradeReq" },
     /* UpgradeResp */
-    { SET3(IsInvalidate, NeedsExclusive, IsResponse),
+    { SET3(NeedsExclusive, IsUpgrade, IsResponse),
             InvalidCmd, "UpgradeResp" },
+    /* SCUpgradeFailReq: generates UpgradeFailResp ASAP */
+    { SET5(IsInvalidate, NeedsExclusive, IsLlsc,
+           IsRequest, NeedsResponse),
+            UpgradeFailResp, "SCUpgradeFailReq" },
+    /* UpgradeFailResp */
+    { SET2(NeedsExclusive, IsResponse),
+            InvalidCmd, "UpgradeFailResp" },
     /* ReadExReq */
     { SET5(IsRead, NeedsExclusive, IsInvalidate, IsRequest, NeedsResponse),
             ReadExResp, "ReadExReq" },
     /* ReadExResp */
-    { SET5(IsRead, NeedsExclusive, IsInvalidate, IsResponse, HasData),
+    { SET4(IsRead, NeedsExclusive, IsResponse, HasData),
             InvalidCmd, "ReadExResp" },
-    /* LoadLockedReq */
-    { SET4(IsRead, IsLocked, IsRequest, NeedsResponse),
-            LoadLockedResp, "LoadLockedReq" },
-    /* LoadLockedResp */
-    { SET4(IsRead, IsLocked, IsResponse, HasData),
-            InvalidCmd, "LoadLockedResp" },
+    /* LoadLockedReq: note that we use plain ReadResp as response, so that
+     *                we can also use ReadRespWithInvalidate when needed */
+    { SET4(IsRead, IsLlsc, IsRequest, NeedsResponse),
+            ReadResp, "LoadLockedReq" },
     /* StoreCondReq */
-    { SET6(IsWrite, NeedsExclusive, IsLocked,
+    { SET6(IsWrite, NeedsExclusive, IsLlsc,
            IsRequest, NeedsResponse, HasData),
             StoreCondResp, "StoreCondReq" },
+    /* StoreCondFailReq: generates failing StoreCondResp ASAP */
+    { SET6(IsWrite, NeedsExclusive, IsLlsc,
+           IsRequest, NeedsResponse, HasData),
+            StoreCondResp, "StoreCondFailReq" },
     /* StoreCondResp */
-    { SET4(IsWrite, NeedsExclusive, IsLocked, IsResponse),
+    { SET4(IsWrite, NeedsExclusive, IsLlsc, IsResponse),
             InvalidCmd, "StoreCondResp" },
     /* SwapReq -- for Swap ldstub type operations */
     { SET6(IsRead, IsWrite, NeedsExclusive, IsRequest, HasData, NeedsResponse),
@@ -116,45 +149,32 @@ MemCmd::commandInfo[] =
     /* SwapResp -- for Swap ldstub type operations */
     { SET5(IsRead, IsWrite, NeedsExclusive, IsResponse, HasData),
             InvalidCmd, "SwapResp" },
+    /* IntReq -- for interrupts */
+    { SET4(IsWrite, IsRequest, NeedsResponse, HasData),
+        MessageResp, "MessageReq" },
+    /* IntResp -- for interrupts */
+    { SET2(IsWrite, IsResponse), InvalidCmd, "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" }
+    { SET2(IsResponse, IsError), InvalidCmd, "BadAddressError" },
+    /* FunctionalReadError */
+    { SET3(IsRead, IsResponse, IsError), InvalidCmd, "FunctionalReadError" },
+    /* FunctionalWriteError */
+    { SET3(IsWrite, IsResponse, IsError), InvalidCmd, "FunctionalWriteError" },
+    /* PrintReq */
+    { SET2(IsRequest, IsPrint), InvalidCmd, "PrintReq" },
+    /* Flush Request */
+    { SET3(IsRequest, IsFlush, NeedsExclusive), InvalidCmd, "FlushReq" },
+    /* Invalidation Request */
+    { SET3(NeedsExclusive, IsInvalidate, IsRequest),
+      InvalidCmd, "InvalidationReq" },
 };
 
-
-/** delete the data pointed to in the data pointer. Ok to call to matter how
- * data was allocted. */
-void
-Packet::deleteData()
-{
-    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()
-{
-    if (data)
-        return;
-    assert(!staticData);
-    dynamicData = true;
-    arrayData = true;
-    data = new uint8_t[getSize()];
-}
-
-
 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 +186,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;
@@ -173,61 +204,182 @@ Packet::checkFunctional(Addr addr, int size, uint8_t *data)
     if (isRead()) {
         if (func_start >= val_start && func_end <= val_end) {
             allocate();
-            std::memcpy(getPtr<uint8_t>(), data + offset, getSize());
-            makeResponse();
+            memcpy(getPtr<uint8_t>(), data + offset, getSize());
             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?");
+            // Offsets and sizes to copy in case of partial overlap
+            int func_offset;
+            int val_offset;
+            int overlap_size;
+
+            // calculate offsets and copy sizes for the two byte arrays
+            if (val_start < func_start && val_end <= func_end) {
+                val_offset = func_start - val_start;
+                func_offset = 0;
+                overlap_size = val_end - func_start;
+            } else if (val_start >= func_start && val_end > func_end) {
+                val_offset = 0;
+                func_offset = val_start - func_start;
+                overlap_size = func_end - val_start;
+            } else if (val_start >= func_start && val_end <= func_end) {
+                val_offset = 0;
+                func_offset = val_start - func_start;
+                overlap_size = size;
+            } else {
+                panic("BUG: Missed a case for a partial functional request");
+            }
+
+            // Figure out how much of the partial overlap should be copied
+            // into the packet and not overwrite previously found bytes.
+            if (bytesValidStart == 0 && bytesValidEnd == 0) {
+                // No bytes have been copied yet, just set indices
+                // to found range
+                bytesValidStart = func_offset;
+                bytesValidEnd = func_offset + overlap_size;
+            } else {
+                // Some bytes have already been copied. Use bytesValid
+                // indices and offset values to figure out how much data
+                // to copy and where to copy it to.
+
+                // Indice overlap conditions to check
+                int a = func_offset - bytesValidStart;
+                int b = (func_offset + overlap_size) - bytesValidEnd;
+                int c = func_offset - bytesValidEnd;
+                int d = (func_offset + overlap_size) - bytesValidStart;
+
+                if (a >= 0 && b <= 0) {
+                    // bytes already in pkt data array are superset of
+                    // found bytes, will not copy any bytes
+                    overlap_size = 0;
+                } else if (a < 0 && d >= 0 && b <= 0) {
+                    // found bytes will move bytesValidStart towards 0
+                    overlap_size = bytesValidStart - func_offset;
+                    bytesValidStart = func_offset;
+                } else if (b > 0 && c <= 0 && a >= 0) {
+                    // found bytes will move bytesValidEnd
+                    // towards end of pkt data array
+                    overlap_size =
+                        (func_offset + overlap_size) - bytesValidEnd;
+                    val_offset += bytesValidEnd - func_offset;
+                    func_offset = bytesValidEnd;
+                    bytesValidEnd += overlap_size;
+                } else if (a < 0 && b > 0) {
+                    // Found bytes are superset of copied range. Will move
+                    // bytesValidStart towards 0 and bytesValidEnd towards
+                    // end of pkt data array.  Need to break copy into two
+                    // pieces so as to not overwrite previously found data.
+
+                    // copy the first half
+                    uint8_t *dest = getPtr<uint8_t>() + func_offset;
+                    uint8_t *src = data + val_offset;
+                    memcpy(dest, src, (bytesValidStart - func_offset));
+
+                    // re-calc the offsets and indices to do the copy
+                    // required for the second half
+                    val_offset += (bytesValidEnd - func_offset);
+                    bytesValidStart = func_offset;
+                    overlap_size =
+                        (func_offset + overlap_size) - bytesValidEnd;
+                    func_offset = bytesValidEnd;
+                    bytesValidEnd += overlap_size;
+                } else if ((c > 0 && b > 0)
+                           || (a < 0 && d < 0)) {
+                    // region to be copied is discontiguous! Not supported.
+                    panic("BUG: Discontiguous bytes found"
+                          "for functional copying!");
+                }
+            }
+            assert(bytesValidEnd <= getSize());
+
+            // copy partial data into the packet's data array
+            uint8_t *dest = getPtr<uint8_t>() + func_offset;
+            uint8_t *src = data + val_offset;
+            memcpy(dest, src, overlap_size);
+
+            // check if we're done filling the functional access
+            bool done = (bytesValidStart == 0) && (bytesValidEnd == getSize());
+            return done;
         }
     } else if (isWrite()) {
         if (offset >= 0) {
-            std::memcpy(data + offset, getPtr<uint8_t>(),
-                        (std::min(func_end, val_end) - func_start) + 1);
-        } else { // val_start > func_start
-            std::memcpy(data, getPtr<uint8_t>() - offset,
-                        (std::min(func_end, val_end) - val_start) + 1);
+            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);
         }
-        // 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(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)
+{
 }
 
+void
+Packet::PrintReqState::pushLabel(const string &lbl, const string &prefix)
+{
+    labelStack.push_back(LabelStackEntry(lbl, curPrefixPtr));
+    curPrefixPtr = new string(*curPrefixPtr);
+    *curPrefixPtr += prefix;
+}
 
-std::ostream &
-operator<<(std::ostream &o, const Packet &p)
+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());
+}