/*
- * 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. */
};
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
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__