| /* |
| * Copyright (c) 2006 The Regents of The University of Michigan |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer; |
| * redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution; |
| * neither the name of the copyright holders nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| * Authors: Ali Saidi |
| */ |
| |
| #ifndef __MEM_TPORT_HH__ |
| #define __MEM_TPORT_HH__ |
| |
| /** |
| * @file |
| * |
| * Declaration of SimpleTimingPort. |
| */ |
| |
| #include <list> |
| #include <string> |
| |
| #include "mem/port.hh" |
| #include "sim/eventq.hh" |
| |
| /** |
| * 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. |
| */ |
| 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. */ |
| 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 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; |
| |
| /** 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 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(); } |
| |
| Tick deferredPacketReadyTime() |
| { return transmitList.empty() ? MaxTick : transmitList.front().tick; } |
| |
| 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); |
| |
| /** 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(PacketPtr pkt); |
| |
| /** Implemented using recvAtomic(). */ |
| bool recvTiming(PacketPtr pkt); |
| |
| /** |
| * Simple ports generally don't care about any status |
| * changes... can always override this in cases where that's not |
| * true. */ |
| virtual void recvStatusChange(Status status) { } |
| |
| |
| public: |
| SimpleTimingPort(std::string pname, MemObject *_owner); |
| ~SimpleTimingPort(); |
| |
| /** 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); |
| }; |
| |
| #endif // __MEM_TPORT_HH__ |