mem-cache: Create an address aware TempCacheBlk
[gem5.git] / src / mem / snoop_filter.hh
old mode 100755 (executable)
new mode 100644 (file)
index c1bb65d..85cc75e
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013 ARM Limited
+ * Copyright (c) 2013-2016 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -34,7 +34,7 @@
  * (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: Stephan Diestelhorst <stephan.diestelhorst@arm.com>
+ * Authors: Stephan Diestelhorst
  */
 
 /**
 #ifndef __MEM_SNOOP_FILTER_HH__
 #define __MEM_SNOOP_FILTER_HH__
 
+#include <unordered_map>
 #include <utility>
 
-#include "base/hashmap.hh"
 #include "mem/packet.hh"
 #include "mem/port.hh"
+#include "mem/qport.hh"
 #include "params/SnoopFilter.hh"
 #include "sim/sim_object.hh"
 #include "sim/system.hh"
  */
 class SnoopFilter : public SimObject {
   public:
-    typedef std::vector<SlavePort*> SnoopList;
+    typedef std::vector<QueuedSlavePort*> SnoopList;
 
-    SnoopFilter (const SnoopFilterParams *p) : SimObject(p),
-        linesize(p->system->cacheLineSize()), lookupLatency(p->lookup_latency)
+    SnoopFilter (const SnoopFilterParams *p) :
+        SimObject(p), reqLookupResult(cachedLocations.end()), retryItem{0, 0},
+        linesize(p->system->cacheLineSize()), lookupLatency(p->lookup_latency),
+        maxEntryCount(p->max_capacity / p->system->cacheLineSize())
     {
     }
 
     /**
-     * Init a new snoop filter and tell it about all the slave ports of the
-     * enclosing bus.
+     * Init a new snoop filter and tell it about all the slave ports
+     * of the enclosing bus.
      *
-     * @param bus_slave_ports Vector of slave ports that the bus is attached to.
+     * @param slave_ports Slave ports that the bus is attached to.
      */
-    void setSlavePorts(const std::vector<SlavePort*>& bus_slave_ports) {
-        slavePorts = bus_slave_ports;
+    void setSlavePorts(const SnoopList& slave_ports) {
+        localSlavePortIds.resize(slave_ports.size(), InvalidPortID);
+
+        PortID id = 0;
+        for (const auto& p : slave_ports) {
+            // no need to track this port if it is not snooping
+            if (p->isSnooping()) {
+                slavePorts.push_back(p);
+                localSlavePortIds[p->getId()] = id++;
+            }
+        }
+
+        // make sure we can deal with this many ports
+        fatal_if(id > 8 * sizeof(SnoopMask),
+                 "Snoop filter only supports %d snooping ports, got %d\n",
+                 8 * sizeof(SnoopMask), id);
     }
 
     /**
-     * Lookup a request (from a slave port) in the snoop filter and return a
-     * list of other slave ports that need forwarding of the resulting snoops.
-     * Additionally, update the tracking structures with new request
-     * information.
+     * Lookup a request (from a slave port) in the snoop filter and
+     * return a list of other slave ports that need forwarding of the
+     * resulting snoops.  Additionally, update the tracking structures
+     * with new request information. Note that the caller must also
+     * call finishRequest once it is known if the request needs to
+     * retry or not.
      *
-     * @param cpkt          Pointer to the request packet.  Not changed.
+     * @param cpkt          Pointer to the request packet. Not changed.
      * @param slave_port    Slave port where the request came from.
      * @return Pair of a vector of snoop target ports and lookup latency.
      */
@@ -116,20 +135,21 @@ class SnoopFilter : public SimObject {
                                                const SlavePort& slave_port);
 
     /**
-     * For a successful request, update all data structures in the snoop filter
-     * reflecting the changes caused by that request
+     * For an un-successful request, revert the change to the snoop
+     * filter. Also take care of erasing any null entries. This method
+     * relies on the result from lookupRequest being stored in
+     * reqLookupResult.
      *
-     * @param cpkt          Pointer to the request packet.  Not changed.
-     * @param slave_port    Slave port where the request came from.
      * @param will_retry    This request will retry on this bus / snoop filter
+     * @param addr          Packet address, merely for sanity checking
      */
-    void updateRequest(const Packet* cpkt, const SlavePort& slave_port,
-                       bool will_retry);
+    void finishRequest(bool will_retry, Addr addr, bool is_secure);
 
     /**
-     * Handle an incoming snoop from below (the master port).  These can upgrade the
-     * tracking logic and may also benefit from additional steering thanks to the
-     * snoop filter.
+     * Handle an incoming snoop from below (the master port). These
+     * can upgrade the tracking logic and may also benefit from
+     * additional steering thanks to the snoop filter.
+     *
      * @param cpkt Pointer to const Packet containing the snoop.
      * @return Pair with a vector of SlavePorts that need snooping and a lookup
      *         latency.
@@ -137,9 +157,9 @@ class SnoopFilter : public SimObject {
     std::pair<SnoopList, Cycles> lookupSnoop(const Packet* cpkt);
 
     /**
-     * Let the snoop filter see any snoop responses that turn into request responses
-     * and indicate cache to cache transfers.  These will update the corresponding
-     * state in the filter.
+     * Let the snoop filter see any snoop responses that turn into
+     * request responses and indicate cache to cache transfers. These
+     * will update the corresponding state in the filter.
      *
      * @param cpkt     Pointer to const Packet holding the snoop response.
      * @param rsp_port SlavePort that sends the response.
@@ -150,28 +170,58 @@ class SnoopFilter : public SimObject {
                              const SlavePort& req_port);
 
     /**
-     * Pass snoop responses that travel downward through the snoop filter and let
-     * them update the snoop filter state.  No additional routing happens.
+     * Pass snoop responses that travel downward through the snoop
+     * filter and let them update the snoop filter state.  No
+     * additional routing happens.
      *
      * @param cpkt     Pointer to const Packet holding the snoop response.
      * @param rsp_port SlavePort that sends the response.
-     * @param req_port MasterPort through which the response leaves this cluster.
+     * @param req_port MasterPort through which the response is forwarded.
      */
     void updateSnoopForward(const Packet *cpkt, const SlavePort& rsp_port,
                             const MasterPort& req_port);
 
     /**
-     * Update the snoop filter with a response from below (outer / other cache,
-     * or memory) and update the tracking information in the snoop filter.
+     * Update the snoop filter with a response from below (outer /
+     * other cache, or memory) and update the tracking information in
+     * the snoop filter.
      *
      * @param cpkt       Pointer to const Packet holding the snoop response.
-     * @param slave_port SlavePort that made the original request and is the target
-     *                   of this response.
+     * @param slave_port SlavePort that made the original request and
+     *                   is the target of this response.
      */
     void updateResponse(const Packet *cpkt, const SlavePort& slave_port);
 
+    virtual void regStats();
+
+  protected:
+
+    /**
+     * The underlying type for the bitmask we use for tracking. This
+     * limits the number of snooping ports supported per crossbar. For
+     * the moment it is an uint64_t to offer maximum
+     * scalability. However, it is possible to use e.g. a uint16_t or
+     * uint32_to slim down the footprint of the hash map (and
+     * ultimately improve the simulation performance).
+     */
+    typedef uint64_t SnoopMask;
+
+    /**
+    * Per cache line item tracking a bitmask of SlavePorts who have an
+    * outstanding request to this line (requested) or already share a
+    * cache line with this address (holder).
+    */
+    struct SnoopItem {
+        SnoopMask requested;
+        SnoopMask holder;
+    };
+    /**
+     * HashMap of SnoopItems indexed by line address
+     */
+    typedef std::unordered_map<Addr, SnoopItem> SnoopFilterCache;
+
     /**
-     * Simple factory methods for standard return values for lookupRequest
+     * Simple factory methods for standard return values.
      */
     std::pair<SnoopList, Cycles> snoopAll(Cycles latency) const
     {
@@ -188,29 +238,12 @@ class SnoopFilter : public SimObject {
         return std::make_pair(empty , latency);
     }
 
-  protected:
-    typedef uint64_t SnoopMask;
-   /**
-    * Per cache line item tracking a bitmask of SlavePorts who have an
-    * outstanding request to this line (requested) or already share a cache line
-    * with this address (holder).
-    */
-    struct SnoopItem {
-        SnoopMask requested;
-        SnoopMask holder;
-    };
     /**
      * Convert a single port to a corresponding, one-hot bitmask
      * @param port SlavePort that should be converted.
      * @return One-hot bitmask corresponding to the port.
      */
     SnoopMask portToMask(const SlavePort& port) const;
-    /**
-     * Convert multiple ports to a corresponding bitmask
-     * @param ports SnoopList that should be converted.
-     * @return Bitmask corresponding to the ports in the list.
-     */
-    SnoopMask portListToMask(const SnoopList& ports) const;
     /**
      * Converts a bitmask of ports into the corresponing list of ports
      * @param ports SnoopMask of the requested ports
@@ -219,42 +252,71 @@ class SnoopFilter : public SimObject {
     SnoopList maskToPortList(SnoopMask ports) const;
 
   private:
+
+    /**
+     * Removes snoop filter items which have no requesters and no holders.
+     */
+    void eraseIfNullEntry(SnoopFilterCache::iterator& sf_it);
+
     /** Simple hash set of cached addresses. */
-    m5::hash_map<Addr, SnoopItem> cachedLocations;
-    /** List of all attached slave ports. */
+    SnoopFilterCache cachedLocations;
+    /**
+     * Iterator used to store the result from lookupRequest until we
+     * call finishRequest.
+     */
+    SnoopFilterCache::iterator reqLookupResult;
+    /**
+     * Variable to temporarily store value of snoopfilter entry
+     * incase finishRequest needs to undo changes made in lookupRequest
+     * (because of crossbar retry)
+     */
+    SnoopItem retryItem;
+    /** List of all attached snooping slave ports. */
     SnoopList slavePorts;
+    /** Track the mapping from port ids to the local mask ids. */
+    std::vector<PortID> localSlavePortIds;
     /** Cache line size. */
     const unsigned linesize;
     /** Latency for doing a lookup in the filter */
     const Cycles lookupLatency;
-};
+    /** Max capacity in terms of cache blocks tracked, for sanity checking */
+    const unsigned maxEntryCount;
 
-inline SnoopFilter::SnoopMask
-SnoopFilter::portToMask(const SlavePort& port) const
-{
-    unsigned id = (unsigned)port.getId();
-    assert(id != (unsigned)InvalidPortID);
-    assert((int)id < 8 * sizeof(SnoopMask));
+    /**
+     * Use the lower bits of the address to keep track of the line status
+     */
+    enum LineStatus {
+        /** block holds data from the secure memory space */
+        LineSecure = 0x01,
+    };
 
-    return ((SnoopMask)1) << id;
-}
+    /** Statistics */
+    Stats::Scalar totRequests;
+    Stats::Scalar hitSingleRequests;
+    Stats::Scalar hitMultiRequests;
+
+    Stats::Scalar totSnoops;
+    Stats::Scalar hitSingleSnoops;
+    Stats::Scalar hitMultiSnoops;
+};
 
 inline SnoopFilter::SnoopMask
-SnoopFilter::portListToMask(const SnoopList& ports) const
+SnoopFilter::portToMask(const SlavePort& port) const
 {
-    SnoopMask m = 0;
-    for (auto port = ports.begin(); port != ports.end(); ++port)
-        m |= portToMask(**port);
-    return m;
+    assert(port.getId() != InvalidPortID);
+    // if this is not a snooping port, return a zero mask
+    return !port.isSnooping() ? 0 :
+        ((SnoopMask)1) << localSlavePortIds[port.getId()];
 }
 
 inline SnoopFilter::SnoopList
 SnoopFilter::maskToPortList(SnoopMask port_mask) const
 {
     SnoopList res;
-    for (auto port = slavePorts.begin(); port != slavePorts.end(); ++port)
-        if (port_mask & portToMask(**port))
-            res.push_back(*port);
+    for (const auto& p : slavePorts)
+        if (port_mask & portToMask(*p))
+            res.push_back(p);
     return res;
 }
+
 #endif // __MEM_SNOOP_FILTER_HH__