mem-cache: Add match functions to QueueEntry
[gem5.git] / src / mem / packet_queue.hh
index ac868802b40d68f1a375fc48ae09166225e49a32..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. */
@@ -76,123 +76,128 @@ class PacketQueue
     };
 
     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;
 
-    /** Label to use for print request packets label stack. */
-    const std::string label;
-
-    /** 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;
 
-    /** If we need to drain, keep the drain event around until we're done
-     * here.*/
-    Event *drainEvent;
+     /*
+      * Optionally disable the sanity check
+      * on the size of the transmitList. The
+      * sanity check will be enabled by default.
+      */
+    bool _disableSanityCheck;
+
+    /**
+     * if true, inserted packets have to be unconditionally scheduled
+     * after the last packet in the queue that references the same
+     * address
+     */
+    bool forceOrder;
 
   protected:
 
-    /** The port used to send the packets. */
-    Port& port;
+    /** 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) = 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.
+     * Create a packet queue, linked to an event manager, and a label
+     * that will be used for functional print request packets.
      *
-     * @param time an alternative time for the next send event
+     * @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.
      */
-    void scheduleSend(Tick time = MaxTick);
+    PacketQueue(EventManager& _em, const std::string& _label,
+                const std::string& _sendEventName,
+                bool force_order = false,
+                bool disable_sanity_check = false);
 
     /**
-     * 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 desctructor since the class may be used as a base class.
      */
-    virtual void recvRangeChange() { }
+    virtual ~PacketQueue();
 
   public:
 
     /**
-     * Create a packet queue, linked to an event manager, a port used
-     * to send the packets, and potentially give it a label that will
-     * be used for functional print request packets.
+     * Provide a name to simplify debugging.
      *
-     * @param _em Event manager used for scheduling this queue
-     * @param _port Port used to send the packets
-     * @param _label Label to push on the label stack for print request packets
+     * @return A complete name, appended to module and port
      */
-    PacketQueue(EventManager& _em, Port& _port,
-                const std::string _label = "PacketQueue");
+    virtual const std::string name() const = 0;
 
     /**
-     * Virtual desctructor since the class may be used as a base class.
+     * Get the size of the queue.
      */
-    virtual ~PacketQueue();
+    size_t size() const { return transmitList.size(); }
 
     /**
-     * Provide a name to simplify debugging. Base it on the port.
+     * 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.
      *
-     * @return A complete name, appended to module and port
+     * @param pkt The packet to compare against.
+     * @param blk_size Block size in bytes.
+     * @return Whether a corresponding packet is found.
      */
-    const std::string name() const { return port.name() + "-queue"; }
+    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
@@ -200,19 +205,133 @@ class PacketQueue
     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.
+      * 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 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 request packet queue, linked to an event manager, a
+     * master port, and a label that will be used for functional print
+     * request packets.
      *
-     * @param de An event which is used to signal back to the caller
-     * @return A number indicating how many times process will be called
+     * @param _em Event manager used for scheduling this queue
+     * @param _masterPort Master port used to send the packets
+     * @param _label Label to push on the label stack for print request packets
      */
-    unsigned int drain(Event *de);
+    ReqPacketQueue(EventManager& _em, MasterPort& _masterPort,
+                   const std::string _label = "ReqPacketQueue");
+
+    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; }
+
+  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 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 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
+     */
+    RespPacketQueue(EventManager& _em, SlavePort& _slavePort,
+                    bool force_order = false,
+                    const std::string _label = "RespPacketQueue");
+
+    virtual ~RespPacketQueue() { }
+
+    const std::string name() const
+    { return name(slavePort, label); }
+
+    bool sendTiming(PacketPtr pkt);
+
 };
 
-#endif // __MEM_TPORT_HH__
+#endif // __MEM_PACKET_QUEUE_HH__