53,54c53
< #include <list>
< #include <string>
---
> #include "mem/qport.hh"
56,58d54
< #include "mem/port.hh"
< #include "sim/eventq.hh"
<
60,70c56,58
< * A simple port for interfacing objects that basically have only
< * functional memory behavior (e.g. I/O devices) to the memory system.
< * Both timing and functional accesses are implemented in terms of
< * atomic accesses. A derived port class thus only needs to provide
< * recvAtomic() to support all memory access modes.
< *
< * The tricky part is handling recvTiming(), where the response must
< * be scheduled separately via a later call to sendTiming(). This
< * feature is handled by scheduling an internal event that calls
< * sendTiming() after a delay, and optionally rescheduling the
< * response if it is nacked.
---
> * The simple timing port uses a queued port to implement
> * recvFunctional and recvTiming through recvAtomic. It is always a
> * slave port.
72c60
< class SimpleTimingPort : public Port
---
> class SimpleTimingPort : public QueuedPort
73a62
>
75,83d63
< /** 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)
< {}
< };
85,86c65,66
< typedef std::list<DeferredPacket> DeferredPacketList;
< typedef std::list<DeferredPacket>::iterator DeferredPacketIterator;
---
> /** The packet queue used to store outgoing responses. */
> PacketQueue queue;
88,164d67
< /** A list of outgoing timing response packets that haven't been
< * serviced yet. */
< DeferredPacketList transmitList;
<
< /** 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. */
< void processSendEvent();
<
< /**
< * This class is used to implemented sendTiming() with a delay. When
< * 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.
< **/
< EventWrapper<SimpleTimingPort,
< &SimpleTimingPort::processSendEvent> sendEvent;
<
< /** If we need to drain, keep the drain event around until we're done
< * here.*/
< Event *drainEvent;
<
< /** Remember whether we're awaiting a retry from the bus. */
< bool waitingOnRetry;
<
< /** Check whether we have a packet ready to go on the transmit list. */
< bool deferredPacketReady()
< { return !transmitList.empty() && transmitList.front().tick <= curTick(); }
<
< Tick deferredPacketReadyTime()
< { return transmitList.empty() ? MaxTick : transmitList.front().tick; }
<
< /**
< * 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.
< *
< * @param when
< */
< void schedSendEvent(Tick 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);
<
< /** 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).
< */
< 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.
< */
< void trySendTiming();
<
< /**
< * 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);
<
< /** This function is notification that the device should attempt to send a
< * packet again. */
< virtual void recvRetry();
<
171,178c74
< /**
< * 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 Tick recvAtomic(PacketPtr pkt) = 0;
180d75
<
182,184d76
< SimpleTimingPort(const std::string &_name, MemObject *_owner,
< const std::string _label = "SimpleTimingPort");
< ~SimpleTimingPort();
186,188c78,89
< /** Check the list of buffered packets against the supplied
< * functional request. */
< bool checkFunctional(PacketPtr pkt);
---
> /**
> * Create a new SimpleTimingPort that relies on a packet queue to
> * hold responses, and implements recvTiming and recvFunctional
> * through calls to recvAtomic. Once a request arrives, it is
> * passed to recvAtomic, and in the case of a timing access any
> * response is scheduled to be sent after the delay of the atomic
> * operation.
> *
> * @param name port name
> * @param owner structural owner
> */
> SimpleTimingPort(const std::string& name, MemObject* owner);
190,206c91,92
< /** Hook for draining timing accesses from the system. The
< * associated SimObject's drain() functions should be implemented
< * something like this when this class is used:
< \code
< PioDevice::drain(Event *de)
< {
< unsigned int count;
< count = SimpleTimingPort->drain(de);
< if (count)
< changeState(Draining);
< else
< changeState(Drained);
< return count;
< }
< \endcode
< */
< unsigned int drain(Event *de);
---
> virtual ~SimpleTimingPort() { }
>