mem-cache: Add setters to validate and secure block
[gem5.git] / src / mem / xbar.cc
index d56e726d56ba10e096de97632c0ab198e653c3bb..b139cdc9b9dabd2a5b366b7e0007438bb60d4dde 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2014 ARM Limited
+ * Copyright (c) 2011-2015, 2018 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
  * Definition of a crossbar object.
  */
 
-#include "base/misc.hh"
+#include "mem/xbar.hh"
+
+#include "base/logging.hh"
 #include "base/trace.hh"
 #include "debug/AddrRanges.hh"
 #include "debug/Drain.hh"
 #include "debug/XBar.hh"
-#include "mem/xbar.hh"
 
 BaseXBar::BaseXBar(const BaseXBarParams *p)
     : MemObject(p),
-      headerCycles(p->header_cycles), width(p->width),
+      frontendLatency(p->frontend_latency),
+      forwardLatency(p->forward_latency),
+      responseLatency(p->response_latency),
+      width(p->width),
       gotAddrRanges(p->port_default_connection_count +
                           p->port_master_connection_count, false),
       gotAllAddrRanges(false), defaultPortID(InvalidPortID),
@@ -102,37 +106,48 @@ BaseXBar::getSlavePort(const std::string &if_name, PortID idx)
 }
 
 void
-BaseXBar::calcPacketTiming(PacketPtr pkt)
+BaseXBar::calcPacketTiming(PacketPtr pkt, Tick header_delay)
 {
     // the crossbar will be called at a time that is not necessarily
     // coinciding with its own clock, so start by determining how long
     // until the next clock edge (could be zero)
     Tick offset = clockEdge() - curTick();
 
-    // determine how many cycles are needed to send the data
-    unsigned dataCycles = pkt->hasData() ? divCeil(pkt->getSize(), width) : 0;
-
-    // before setting the bus delay fields of the packet, ensure that
-    // the delay from any previous crossbar has been accounted for
-    if (pkt->firstWordDelay != 0 || pkt->lastWordDelay != 0)
-        panic("Packet %s already has delay (%d, %d) that should be "
-              "accounted for.\n", pkt->cmdString(), pkt->firstWordDelay,
-              pkt->lastWordDelay);
-
-    // The first word will be delivered on the cycle after the header.
-    pkt->firstWordDelay = (headerCycles + 1) * clockPeriod() + offset;
+    // the header delay depends on the path through the crossbar, and
+    // we therefore rely on the caller to provide the actual
+    // value
+    pkt->headerDelay += offset + header_delay;
+
+    // note that we add the header delay to the existing value, and
+    // align it to the crossbar clock
+
+    // do a quick sanity check to ensure the timings are not being
+    // ignored, note that this specific value may cause problems for
+    // slower interconnects
+    panic_if(pkt->headerDelay > SimClock::Int::us,
+             "Encountered header delay exceeding 1 us\n");
+
+    if (pkt->hasData()) {
+        // the payloadDelay takes into account the relative time to
+        // deliver the payload of the packet, after the header delay,
+        // we take the maximum since the payload delay could already
+        // be longer than what this parcitular crossbar enforces.
+        pkt->payloadDelay = std::max<Tick>(pkt->payloadDelay,
+                                           divCeil(pkt->getSize(), width) *
+                                           clockPeriod());
+    }
 
-    // Note that currently lastWordDelay can be smaller than
-    // firstWordDelay if the packet has no data
-    pkt->lastWordDelay = (headerCycles + dataCycles) * clockPeriod() +
-        offset;
+    // the payload delay is not paying for the clock offset as that is
+    // already done using the header delay, and the payload delay is
+    // also used to determine how long the crossbar layer is busy and
+    // thus regulates throughput
 }
 
 template <typename SrcType, typename DstType>
 BaseXBar::Layer<SrcType,DstType>::Layer(DstType& _port, BaseXBar& _xbar,
                                        const std::string& _name) :
-    port(_port), xbar(_xbar), _name(_name), state(IDLE), drainManager(NULL),
-    waitingForPeer(NULL), releaseEvent(this)
+    port(_port), xbar(_xbar), _name(_name), state(IDLE),
+    waitingForPeer(NULL), releaseEvent([this]{ releaseLayer(); }, name())
 {
 }
 
@@ -238,12 +253,10 @@ BaseXBar::Layer<SrcType,DstType>::releaseLayer()
         // waiting for the peer
         if (waitingForPeer == NULL)
             retryWaiting();
-    } else if (waitingForPeer == NULL && drainManager) {
+    } else if (waitingForPeer == NULL && drainState() == DrainState::Draining) {
         DPRINTF(Drain, "Crossbar done draining, signaling drain manager\n");
         //If we weren't able to drain before, do it now.
-        drainManager->signalDrainDone();
-        // Clear the drain event once we're done with it.
-        drainManager = NULL;
+        signalDrainDone();
     }
 }
 
@@ -267,17 +280,18 @@ BaseXBar::Layer<SrcType,DstType>::retryWaiting()
 
     // tell the port to retry, which in some cases ends up calling the
     // layer again
-    retryingPort->sendRetry();
+    sendRetry(retryingPort);
 
     // If the layer is still in the retry state, sendTiming wasn't
-    // called in zero time (e.g. the cache does this), burn a cycle
+    // called in zero time (e.g. the cache does this when a writeback
+    // is squashed)
     if (state == RETRY) {
         // update the state to busy and reset the retrying port, we
         // have done our bit and sent the retry
         state = BUSY;
 
-        // occupy the crossbar layer until the next cycle ends
-        occupyLayer(xbar.clockEdge(Cycles(1)));
+        // occupy the crossbar layer until the next clock edge
+        occupyLayer(xbar.clockEdge());
     }
 }
 
@@ -307,41 +321,34 @@ BaseXBar::Layer<SrcType,DstType>::recvRetry()
 }
 
 PortID
-BaseXBar::findPort(Addr addr)
+BaseXBar::findPort(AddrRange addr_range)
 {
     // we should never see any address lookups before we've got the
     // ranges of all connected slave modules
     assert(gotAllAddrRanges);
 
-    // Check the cache
-    PortID dest_id = checkPortCache(addr);
-    if (dest_id != InvalidPortID)
-        return dest_id;
-
     // Check the address map interval tree
-    auto i = portMap.find(addr);
+    auto i = portMap.contains(addr_range);
     if (i != portMap.end()) {
-        dest_id = i->second;
-        updatePortCache(dest_id, i->first);
-        return dest_id;
+        return i->second;
     }
 
     // Check if this matches the default range
     if (useDefaultRange) {
-        if (defaultRange.contains(addr)) {
-            DPRINTF(AddrRanges, "  found addr %#llx on default\n",
-                    addr);
+        if (addr_range.isSubset(defaultRange)) {
+            DPRINTF(AddrRanges, "  found addr %s on default\n",
+                    addr_range.to_string());
             return defaultPortID;
         }
     } else if (defaultPortID != InvalidPortID) {
-        DPRINTF(AddrRanges, "Unable to find destination for addr %#llx, "
-                "will use default port\n", addr);
+        DPRINTF(AddrRanges, "Unable to find destination for %s, "
+                "will use default port\n", addr_range.to_string());
         return defaultPortID;
     }
 
     // we should use the range for the default port and it did not
     // match, or the default port is not set
-    fatal("Unable to find destination for addr %#llx on %s\n", addr,
+    fatal("Unable to find destination for %s on %s\n", addr_range.to_string(),
           name());
 }
 
@@ -406,8 +413,9 @@ BaseXBar::recvRangeChange(PortID master_port_id)
             DPRINTF(AddrRanges, "Adding range %s for id %d\n",
                     r.to_string(), master_port_id);
             if (portMap.insert(r, master_port_id) == portMap.end()) {
-                PortID conflict_id = portMap.find(r)->second;
-                fatal("%s has two ports responding within range %s:\n\t%s\n\t%s\n",
+                PortID conflict_id = portMap.intersects(r)->second;
+                fatal("%s has two ports responding within range "
+                      "%s:\n\t%s\n\t%s\n",
                       name(),
                       r.to_string(),
                       masterPorts[master_port_id]->getSlavePort().name(),
@@ -482,7 +490,7 @@ BaseXBar::recvRangeChange(PortID master_port_id)
             }
         }
 
-        // also check that no range partially overlaps with the
+        // also check that no range partially intersects with the
         // default range, this has to be done after all ranges are set
         // as there are no guarantees for when the default range is
         // update with respect to the other ones
@@ -503,8 +511,6 @@ BaseXBar::recvRangeChange(PortID master_port_id)
         for (const auto& s: slavePorts)
             s->sendRangeChange();
     }
-
-    clearPortCache();
 }
 
 AddrRangeList
@@ -528,6 +534,8 @@ BaseXBar::getAddrRanges() const
 void
 BaseXBar::regStats()
 {
+    ClockedObject::regStats();
+
     using namespace Stats;
 
     transDist
@@ -572,18 +580,18 @@ BaseXBar::regStats()
 }
 
 template <typename SrcType, typename DstType>
-unsigned int
-BaseXBar::Layer<SrcType,DstType>::drain(DrainManager *dm)
+DrainState
+BaseXBar::Layer<SrcType,DstType>::drain()
 {
     //We should check that we're not "doing" anything, and that noone is
     //waiting. We might be idle but have someone waiting if the device we
     //contacted for a retry didn't actually retry.
     if (state != IDLE) {
         DPRINTF(Drain, "Crossbar not drained\n");
-        drainManager = dm;
-        return 1;
+        return DrainState::Draining;
+    } else {
+        return DrainState::Drained;
     }
-    return 0;
 }
 
 template <typename SrcType, typename DstType>