mem-cache: Add match functions to QueueEntry
[gem5.git] / src / mem / packet_queue.hh
index 0171eb9a39d8e5738bfcec5bb82ee1f0ff711742..b9c5b7554943c83ce02035e2a30de96c19e54455 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 ARM Limited
+ * Copyright (c) 2012,2015,2018 ARM Limited
  * All rights reserved.
  *
  * The license below extends only to copyright in the software and shall
  * Declaration of a simple PacketQueue that is associated with
  * a port on which it attempts to send packets according to the time
  * stamp given to them at insertion. The packet queue is responsible
- * for the flow control of the port, but relies on the module
- * notifying the queue when a transfer ends.
+ * for the flow control of the port.
  */
 
 #include <list>
 
 #include "mem/port.hh"
-#include "sim/eventq.hh"
+#include "sim/drain.hh"
+#include "sim/eventq_impl.hh"
 
 /**
  * A packet queue is a class that holds deferred packets and later
  * sends them using the associated slave port or master port.
  */
-class PacketQueue
+class PacketQueue : public Drainable
 {
   private:
     /** A deferred packet, buffered to transmit later. */
@@ -70,89 +70,66 @@ class PacketQueue
       public:
         Tick tick;      ///< The tick when the packet is ready to transmit
         PacketPtr pkt;  ///< Pointer to the packet to transmit
-        bool sendAsSnoop; ///< Should it be sent as a snoop or not
-        DeferredPacket(Tick t, PacketPtr p, bool send_as_snoop)
-            : tick(t), pkt(p), sendAsSnoop(send_as_snoop)
+        DeferredPacket(Tick t, PacketPtr p)
+            : tick(t), pkt(p)
         {}
     };
 
     typedef std::list<DeferredPacket> DeferredPacketList;
-    typedef std::list<DeferredPacket>::iterator DeferredPacketIterator;
 
-    /** A list of outgoing timing response packets that haven't been
-     * serviced yet. */
+    /** A list of outgoing packets. */
     DeferredPacketList transmitList;
 
     /** The manager which is used for the event queue */
     EventManager& em;
 
-    /** This function attempts to send deferred packets.  Scheduled to
-     * be called in the future via SendEvent. */
+    /** Used to schedule sending of deferred packets. */
     void processSendEvent();
 
-    /**
-     * Event used to call processSendEvent.
-     **/
-    EventWrapper<PacketQueue, &PacketQueue::processSendEvent> sendEvent;
+    /** Event used to call processSendEvent. */
+    EventFunctionWrapper sendEvent;
+
+     /*
+      * Optionally disable the sanity check
+      * on the size of the transmitList. The
+      * sanity check will be enabled by default.
+      */
+    bool _disableSanityCheck;
 
-    /** If we need to drain, keep the drain event around until we're done
-     * here.*/
-    Event *drainEvent;
+    /**
+     * if true, inserted packets have to be unconditionally scheduled
+     * after the last packet in the queue that references the same
+     * address
+     */
+    bool forceOrder;
 
   protected:
 
     /** Label to use for print request packets label stack. */
     const std::string label;
 
-    /** Remember whether we're awaiting a retry from the bus. */
+    /** Remember whether we're awaiting a retry. */
     bool waitingOnRetry;
 
     /** Check whether we have a packet ready to go on the transmit list. */
-    bool deferredPacketReady()
+    bool deferredPacketReady() const
     { return !transmitList.empty() && transmitList.front().tick <= curTick(); }
 
-    Tick deferredPacketReadyTime()
-    { return transmitList.empty() ? MaxTick : transmitList.front().tick; }
-
     /**
-     * Attempt to send the packet at the head of the transmit
-     * list. Caller must guarantee that the list is non-empty and that
-     * the head packet is scheduled for curTick() (or earlier). Note
-     * that a subclass of the PacketQueue can override this method and
-     * thus change the behaviour (as done by the cache).
+     * Attempt to send a packet. Note that a subclass of the
+     * PacketQueue can override this method and thus change the
+     * behaviour (as done by the cache for the request queue). The
+     * default implementation sends the head of the transmit list. The
+     * caller must guarantee that the list is non-empty and that the
+     * head packet is scheduled for curTick() (or earlier).
      */
     virtual void sendDeferredPacket();
 
     /**
-     * Attempt to send the packet at the front of the transmit list,
-     * and set waitingOnRetry accordingly. The packet is temporarily
-     * taken off the list, but put back at the front if not
-     * successfully sent.
+     * Send a packet using the appropriate method for the specific
+     * subclass (reuest, response or snoop response).
      */
-    void trySendTiming();
-
-    /**
-     *
-     */
-    virtual bool sendTiming(PacketPtr pkt, bool send_as_snoop) = 0;
-
-    /**
-     * Based on the transmit list, or the provided time, schedule a
-     * send event if there are packets to send. If we are idle and
-     * asked to drain then do so.
-     *
-     * @param time an alternative time for the next send event
-     */
-    void scheduleSend(Tick time = MaxTick);
-
-    /**
-     * Simple ports are generally used as slave ports (i.e. the
-     * respond to requests) and thus do not expect to receive any
-     * range changes (as the neighbouring port has a master role and
-     * do not have any address ranges. A subclass can override the
-     * default behaviuor if needed.
-     */
-    virtual void recvRangeChange() { }
+    virtual bool sendTiming(PacketPtr pkt) = 0;
 
     /**
      * Create a packet queue, linked to an event manager, and a label
@@ -160,8 +137,14 @@ class PacketQueue
      *
      * @param _em Event manager used for scheduling this queue
      * @param _label Label to push on the label stack for print request packets
+     * @param force_order Force insertion order for packets with same address
+     * @param disable_sanity_check Flag used to disable the sanity check
+     *        on the size of the transmitList. The check is enabled by default.
      */
-    PacketQueue(EventManager& _em, const std::string& _label);
+    PacketQueue(EventManager& _em, const std::string& _label,
+                const std::string& _sendEventName,
+                bool force_order = false,
+                bool disable_sanity_check = false);
 
     /**
      * Virtual desctructor since the class may be used as a base class.
@@ -177,56 +160,85 @@ class PacketQueue
      */
     virtual const std::string name() const = 0;
 
+    /**
+     * Get the size of the queue.
+     */
+    size_t size() const { return transmitList.size(); }
+
+    /**
+     * Get the next packet ready time.
+     */
+    Tick deferredPacketReadyTime() const
+    { return transmitList.empty() ? MaxTick : transmitList.front().tick; }
+
+    /**
+     * Check if a packet corresponding to the same address exists in the
+     * queue.
+     *
+     * @param pkt The packet to compare against.
+     * @param blk_size Block size in bytes.
+     * @return Whether a corresponding packet is found.
+     */
+    bool checkConflict(const PacketPtr pkt, const int blk_size) const;
+
     /** Check the list of buffered packets against the supplied
      * functional request. */
-    bool checkFunctional(PacketPtr pkt);
+    bool trySatisfyFunctional(PacketPtr pkt);
 
     /**
-     * Schedule a send even if not already waiting for a retry. If the
-     * requested time is before an already scheduled send event it
-     * will be rescheduled.
+     * Schedule a send event if we are not already waiting for a
+     * retry. If the requested time is before an already scheduled
+     * send event, the event will be rescheduled. If MaxTick is
+     * passed, no event is scheduled. Instead, if we are idle and
+     * asked to drain then check and signal drained.
      *
-     * @param when
+     * @param when time to schedule an event
      */
     void schedSendEvent(Tick when);
 
     /**
-     * Add a packet to the transmit list, and ensure that a
-     * processSendEvent is called in the future.
+     * Add a packet to the transmit list, and schedule a send event.
      *
      * @param pkt Packet to send
      * @param when Absolute time (in ticks) to send packet
-     * @param send_as_snoop Send the packet as a snoop or not
      */
-    void schedSendTiming(PacketPtr pkt, Tick when, bool send_as_snoop = false);
+    void schedSendTiming(PacketPtr pkt, Tick when);
 
     /**
-     * Used by a port to notify the queue that a retry was received
-     * and that the queue can proceed and retry sending the packet
-     * that caused the wait.
+     * Retry sending a packet from the queue. Note that this is not
+     * necessarily the same packet if something has been added with an
+     * earlier time stamp.
      */
     void retry();
 
     /**
-     * Hook for draining the packet queue.
-     *
-     * @param de An event which is used to signal back to the caller
-     * @return A number indicating how many times process will be called
-     */
-    unsigned int drain(Event *de);
+      * This allows a user to explicitly disable the sanity check
+      * on the size of the transmitList, which is enabled by default.
+      * Users must use this function to explicitly disable the sanity
+      * check.
+      */
+    void disableSanityCheck() { _disableSanityCheck = true; }
+
+    DrainState drain() override;
 };
 
-class MasterPacketQueue : public PacketQueue
+class ReqPacketQueue : public PacketQueue
 {
 
   protected:
 
     MasterPort& masterPort;
 
+    // Static definition so it can be called when constructing the parent
+    // without us being completely initialized.
+    static const std::string name(const MasterPort& masterPort,
+                                  const std::string& label)
+    { return masterPort.name() + "-" + label; }
+
   public:
 
     /**
-     * Create a master packet queue, linked to an event manager, a
+     * Create a request packet queue, linked to an event manager, a
      * master port, and a label that will be used for functional print
      * request packets.
      *
@@ -234,44 +246,91 @@ class MasterPacketQueue : public PacketQueue
      * @param _masterPort Master port used to send the packets
      * @param _label Label to push on the label stack for print request packets
      */
-    MasterPacketQueue(EventManager& _em, MasterPort& _masterPort,
-                      const std::string _label = "MasterPacketQueue");
+    ReqPacketQueue(EventManager& _em, MasterPort& _masterPort,
+                   const std::string _label = "ReqPacketQueue");
 
-    virtual ~MasterPacketQueue() { }
+    virtual ~ReqPacketQueue() { }
 
     const std::string name() const
+    { return name(masterPort, label); }
+
+    bool sendTiming(PacketPtr pkt);
+
+};
+
+class SnoopRespPacketQueue : public PacketQueue
+{
+
+  protected:
+
+    MasterPort& masterPort;
+
+    // Static definition so it can be called when constructing the parent
+    // without us being completely initialized.
+    static const std::string name(const MasterPort& masterPort,
+                                  const std::string& label)
     { return masterPort.name() + "-" + label; }
 
-    bool sendTiming(PacketPtr pkt, bool send_as_snoop);
+  public:
+
+    /**
+     * Create a snoop response packet queue, linked to an event
+     * manager, a master port, and a label that will be used for
+     * functional print request packets.
+     *
+     * @param _em Event manager used for scheduling this queue
+     * @param _masterPort Master port used to send the packets
+     * @param force_order Force insertion order for packets with same address
+     * @param _label Label to push on the label stack for print request packets
+     */
+    SnoopRespPacketQueue(EventManager& _em, MasterPort& _masterPort,
+                         bool force_order = false,
+                         const std::string _label = "SnoopRespPacketQueue");
+
+    virtual ~SnoopRespPacketQueue() { }
+
+    const std::string name() const
+    { return name(masterPort, label); }
+
+    bool sendTiming(PacketPtr pkt);
+
 };
 
-class SlavePacketQueue : public PacketQueue
+class RespPacketQueue : public PacketQueue
 {
 
   protected:
 
     SlavePort& slavePort;
 
+    // Static definition so it can be called when constructing the parent
+    // without us being completely initialized.
+    static const std::string name(const SlavePort& slavePort,
+                                  const std::string& label)
+    { return slavePort.name() + "-" + label; }
+
   public:
 
     /**
-     * Create a slave packet queue, linked to an event manager, a
+     * Create a response packet queue, linked to an event manager, a
      * slave port, and a label that will be used for functional print
      * request packets.
      *
      * @param _em Event manager used for scheduling this queue
      * @param _slavePort Slave port used to send the packets
+     * @param force_order Force insertion order for packets with same address
      * @param _label Label to push on the label stack for print request packets
      */
-    SlavePacketQueue(EventManager& _em, SlavePort& _slavePort,
-                     const std::string _label = "SlavePacketQueue");
+    RespPacketQueue(EventManager& _em, SlavePort& _slavePort,
+                    bool force_order = false,
+                    const std::string _label = "RespPacketQueue");
 
-    virtual ~SlavePacketQueue() { }
+    virtual ~RespPacketQueue() { }
 
     const std::string name() const
-    { return slavePort.name() + "-" + label; }
+    { return name(slavePort, label); }
 
-    bool sendTiming(PacketPtr pkt, bool send_as_snoop);
+    bool sendTiming(PacketPtr pkt);
 
 };