class SimpleTimingPort : public Port
{
protected:
+ /** A deferred packet, buffered to transmit later. */
+ class DeferredPacket {
+ public:
+ Tick tick; ///< The tick when the packet is ready to transmit
+ PacketPtr pkt; ///< Pointer to the packet to transmit
+ 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. */
- std::list<Packet*> transmitList;
+ DeferredPacketList transmitList;
+
+ /** This function attempts to send deferred packets. Scheduled to
+ * be called in the future via SendEvent. */
+ void processSendEvent();
/**
* This class is used to implemented sendTiming() with a delay. When
- * a delay is requested a new event is created. When the event time
- * expires it attempts to send the packet. If it cannot, the packet
- * is pushed onto the transmit list to be sent when recvRetry() is
- * called. */
- class SendEvent : public Event
- {
- SimpleTimingPort *port;
- Packet *packet;
+ * a delay is requested a the event is scheduled if it isn't already.
+ * When the event time expires it attempts to send the packet.
+ * If it cannot, the packet sent when recvRetry() is called.
+ **/
+ Event *sendEvent;
- public:
- SendEvent(SimpleTimingPort *p, Packet *pkt, Tick t)
- : Event(&mainEventQueue), port(p), packet(pkt)
- { setFlags(AutoDelete); schedule(curTick + t); }
+ /** If we need to drain, keep the drain event around until we're done
+ * here.*/
+ Event *drainEvent;
- virtual void process();
+ /** Remember whether we're awaiting a retry from the bus. */
+ bool waitingOnRetry;
- virtual const char *description()
- { return "Future scheduled sendTiming event"; }
- };
+ /** Check the list of buffered packets against the supplied
+ * functional request. */
+ bool checkFunctional(PacketPtr funcPkt);
+ /** Check whether we have a packet ready to go on the transmit list. */
+ bool deferredPacketReady()
+ { return !transmitList.empty() && transmitList.front().tick <= curTick(); }
- /** Number of timing requests that are emulating the device timing before
- * attempting to end up on the bus.
- */
- int outTiming;
+ Tick deferredPacketReadyTime()
+ { return transmitList.empty() ? MaxTick : transmitList.front().tick; }
- /** If we need to drain, keep the drain event around until we're done
- * here.*/
- Event *drainEvent;
+ void
+ schedSendEvent(Tick when)
+ {
+ if (waitingOnRetry) {
+ assert(!sendEvent->scheduled());
+ return;
+ }
+
+ if (!sendEvent->scheduled()) {
+ schedule(sendEvent, when);
+ } else if (sendEvent->when() > when) {
+ reschedule(sendEvent, when);
+ }
+ }
+
+
+ /** Schedule a sendTiming() event to be called in the future.
+ * @param pkt packet to send
+ * @param absolute time (in ticks) to send packet
+ */
+ void schedSendTiming(PacketPtr pkt, Tick when);
- /** Schedule a sendTiming() event to be called in the future. */
- void sendTimingLater(Packet *pkt, Tick time)
- { outTiming++; new SendEvent(this, pkt, time); }
+ /** Attempt to send the packet at the head of the deferred packet
+ * list. Caller must guarantee that the deferred packet list is
+ * non-empty and that the head packet is scheduled for curTick() (or
+ * earlier).
+ */
+ void sendDeferredPacket();
/** This function is notification that the device should attempt to send a
* packet again. */
virtual void recvRetry();
/** Implemented using recvAtomic(). */
- void recvFunctional(Packet *pkt);
+ void recvFunctional(PacketPtr pkt);
/** Implemented using recvAtomic(). */
- bool recvTiming(Packet *pkt);
+ bool recvTiming(PacketPtr pkt);
/**
* Simple ports generally don't care about any status
public:
-
- SimpleTimingPort(std::string pname)
- : Port(pname), outTiming(0), drainEvent(NULL)
- {}
+ SimpleTimingPort(std::string pname, MemObject *_owner);
+ ~SimpleTimingPort();
/** Hook for draining timing accesses from the system. The
* associated SimObject's drain() functions should be implemented