/*
+ * Copyright (c) 2011-2013 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
* 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
- * Steve Reinhardt
*/
/**
* @file
- * Declaration of a simple bus bridge object with no buffering
+ * Declaration of a memory-mapped bridge that connects a requestor
+ * and a responder through a request and response queue.
*/
#ifndef __MEM_BRIDGE_HH__
#define __MEM_BRIDGE_HH__
-#include <string>
-#include <list>
-#include <inttypes.h>
-#include <queue>
+#include <deque>
-#include "mem/mem_object.hh"
-#include "mem/packet.hh"
+#include "base/types.hh"
#include "mem/port.hh"
-#include "sim/eventq.hh"
+#include "params/Bridge.hh"
+#include "sim/clocked_object.hh"
-class Bridge : public MemObject
+/**
+ * A bridge is used to interface two different crossbars (or in general a
+ * memory-mapped requestor and responder), with buffering for requests and
+ * responses. The bridge has a fixed delay for packets passing through
+ * it and responds to a fixed set of address ranges.
+ *
+ * The bridge comprises a response port and a request port, that buffer
+ * outgoing responses and requests respectively. Buffer space is
+ * reserved when a request arrives, also reserving response space
+ * before forwarding the request. If there is no space present, then
+ * the bridge will delay accepting the packet until space becomes
+ * available.
+ */
+class Bridge : public ClockedObject
{
protected:
- /** Declaration of the buses port type, one will be instantiated for each
- of the interfaces connecting to the bus. */
- class BridgePort : public Port
+
+ /**
+ * A deferred packet stores a packet along with its scheduled
+ * transmission time
+ */
+ class DeferredPacket
+ {
+
+ public:
+
+ const Tick tick;
+ const PacketPtr pkt;
+
+ DeferredPacket(PacketPtr _pkt, Tick _tick) : tick(_tick), pkt(_pkt)
+ { }
+ };
+
+ // Forward declaration to allow the response port to have a pointer
+ class BridgeRequestPort;
+
+ /**
+ * The port on the side that receives requests and sends
+ * responses. The response port has a set of address ranges that it
+ * is responsible for. The response port also has a buffer for the
+ * responses not yet sent.
+ */
+ class BridgeResponsePort : public ResponsePort
{
- /** A pointer to the bridge to which this port belongs. */
- Bridge *bridge;
+
+ private:
+
+ /** The bridge to which this port belongs. */
+ Bridge& bridge;
/**
- * Pointer to the port on the other side of the bridge
- * (connected to the other bus).
+ * Request port on the other side of the bridge.
*/
- BridgePort *otherPort;
+ BridgeRequestPort& memSidePort;
- /** Minimum delay though this bridge. */
- Tick delay;
-
- class PacketBuffer : public Packet::SenderState {
-
- public:
- Tick ready;
- Packet *pkt;
- Packet::SenderState *origSenderState;
- short origSrc;
- bool expectResponse;
-
- PacketBuffer(Packet *_pkt, Tick t)
- : ready(t), pkt(_pkt),
- origSenderState(_pkt->senderState), origSrc(_pkt->getSrc()),
- expectResponse(_pkt->needsResponse())
- {
- if (!pkt->isResponse())
- pkt->senderState = this;
- }
-
- void fixResponse(Packet *pkt)
- {
- assert(pkt->senderState == this);
- pkt->setDest(origSrc);
- pkt->senderState = origSenderState;
- }
- };
+ /** Minimum request delay though this bridge. */
+ const Cycles delay;
+
+ /** Address ranges to pass through the bridge */
+ const AddrRangeList ranges;
/**
- * Outbound packet queue. Packets are held in this queue for a
- * specified delay to model the processing delay of the
- * bridge.
+ * Response packet queue. Response packets are held in this
+ * queue for a specified delay to model the processing delay
+ * of the bridge. We use a deque as we need to iterate over
+ * the items for functional accesses.
*/
- std::list<PacketBuffer*> sendQueue;
+ std::deque<DeferredPacket> transmitList;
+
+ /** Counter to track the outstanding responses. */
+ unsigned int outstandingResponses;
- int outstandingResponses;
+ /** If we should send a retry when space becomes available. */
+ bool retryReq;
- /** Max queue size for outbound packets */
- int queueLimit;
+ /** Max queue size for reserved responses. */
+ unsigned int respQueueLimit;
/**
- * Is this side blocked from accepting outbound packets?
+ * Upstream caches need this packet until true is returned, so
+ * hold it for deletion until a subsequent call
*/
- bool queueFull() { return (sendQueue.size() == queueLimit); }
+ std::unique_ptr<Packet> pendingDelete;
- bool queueForSendTiming(Packet *pkt);
-
- void finishSend(PacketBuffer *buf);
+ /**
+ * Is this side blocked from accepting new response packets.
+ *
+ * @return true if the reserved space has reached the set limit
+ */
+ bool respQueueFull() const;
/**
* Handle send event, scheduled when the packet at the head of
- * the outbound queue is ready to transmit (for timing
+ * the response queue is ready to transmit (for timing
* accesses only).
*/
- void trySend();
-
- class SendEvent : public Event
- {
- BridgePort *port;
+ void trySendTiming();
- public:
- SendEvent(BridgePort *p)
- : Event(&mainEventQueue), port(p) {}
+ /** Send event for the response queue. */
+ EventFunctionWrapper sendEvent;
- virtual void process() { port->trySend(); }
-
- virtual const char *description() { return "bridge send event"; }
- };
+ public:
- SendEvent sendEvent;
+ /**
+ * Constructor for the BridgeResponsePort.
+ *
+ * @param _name the port name including the owner
+ * @param _bridge the structural owner
+ * @param _memSidePort the request port on the other
+ * side of the bridge
+ * @param _delay the delay in cycles from receiving to sending
+ * @param _resp_limit the size of the response queue
+ * @param _ranges a number of address ranges to forward
+ */
+ BridgeResponsePort(const std::string& _name, Bridge& _bridge,
+ BridgeRequestPort& _memSidePort, Cycles _delay,
+ int _resp_limit, std::vector<AddrRange> _ranges);
- public:
+ /**
+ * Queue a response packet to be sent out later and also schedule
+ * a send if necessary.
+ *
+ * @param pkt a response to send out after a delay
+ * @param when tick when response packet should be sent
+ */
+ void schedTimingResp(PacketPtr pkt, Tick when);
- /** Constructor for the BusPort.*/
- BridgePort(const std::string &_name,
- Bridge *_bridge, BridgePort *_otherPort,
- int _delay, int _queueLimit);
+ /**
+ * Retry any stalled request that we have failed to accept at
+ * an earlier point in time. This call will do nothing if no
+ * request is waiting.
+ */
+ void retryStalledReq();
protected:
/** When receiving a timing request from the peer port,
pass it to the bridge. */
- virtual bool recvTiming(Packet *pkt);
+ bool recvTimingReq(PacketPtr pkt);
/** When receiving a retry request from the peer port,
pass it to the bridge. */
- virtual void recvRetry();
+ void recvRespRetry();
/** When receiving a Atomic requestfrom the peer port,
pass it to the bridge. */
- virtual Tick recvAtomic(Packet *pkt);
+ Tick recvAtomic(PacketPtr pkt);
/** When receiving a Functional request from the peer port,
pass it to the bridge. */
- virtual void recvFunctional(Packet *pkt);
+ void recvFunctional(PacketPtr pkt);
- /** When receiving a status changefrom the peer port,
+ /** When receiving a address range request the peer port,
pass it to the bridge. */
- virtual void recvStatusChange(Status status);
+ AddrRangeList getAddrRanges() const;
+ };
- /** When receiving a address range request the peer port,
+
+ /**
+ * Port on the side that forwards requests and receives
+ * responses. The request port has a buffer for the requests not
+ * yet sent.
+ */
+ class BridgeRequestPort : public RequestPort
+ {
+
+ private:
+
+ /** The bridge to which this port belongs. */
+ Bridge& bridge;
+
+ /**
+ * The response port on the other side of the bridge.
+ */
+ BridgeResponsePort& cpuSidePort;
+
+ /** Minimum delay though this bridge. */
+ const Cycles delay;
+
+ /**
+ * Request packet queue. Request packets are held in this
+ * queue for a specified delay to model the processing delay
+ * of the bridge. We use a deque as we need to iterate over
+ * the items for functional accesses.
+ */
+ std::deque<DeferredPacket> transmitList;
+
+ /** Max queue size for request packets */
+ const unsigned int reqQueueLimit;
+
+ /**
+ * Handle send event, scheduled when the packet at the head of
+ * the outbound queue is ready to transmit (for timing
+ * accesses only).
+ */
+ void trySendTiming();
+
+ /** Send event for the request queue. */
+ EventFunctionWrapper sendEvent;
+
+ public:
+
+ /**
+ * Constructor for the BridgeRequestPort.
+ *
+ * @param _name the port name including the owner
+ * @param _bridge the structural owner
+ * @param _cpuSidePort the response port on the other side of
+ * the bridge
+ * @param _delay the delay in cycles from receiving to sending
+ * @param _req_limit the size of the request queue
+ */
+ BridgeRequestPort(const std::string& _name, Bridge& _bridge,
+ BridgeResponsePort& _cpuSidePort, Cycles _delay,
+ int _req_limit);
+
+ /**
+ * Is this side blocked from accepting new request packets.
+ *
+ * @return true if the occupied space has reached the set limit
+ */
+ bool reqQueueFull() const;
+
+ /**
+ * Queue a request packet to be sent out later and also schedule
+ * a send if necessary.
+ *
+ * @param pkt a request to send out after a delay
+ * @param when tick when response packet should be sent
+ */
+ void schedTimingReq(PacketPtr pkt, Tick when);
+
+ /**
+ * Check a functional request against the packets in our
+ * request queue.
+ *
+ * @param pkt packet to check against
+ *
+ * @return true if we find a match
+ */
+ bool trySatisfyFunctional(PacketPtr pkt);
+
+ protected:
+
+ /** When receiving a timing request from the peer port,
pass it to the bridge. */
- virtual void getDeviceAddressRanges(AddrRangeList &resp,
- AddrRangeList &snoop);
+ bool recvTimingResp(PacketPtr pkt);
+
+ /** When receiving a retry request from the peer port,
+ pass it to the bridge. */
+ void recvReqRetry();
};
- BridgePort portA, portB;
+ /** Response port of the bridge. */
+ BridgeResponsePort cpuSidePort;
- /** If this bridge should acknowledge writes. */
- bool ackWrites;
+ /** Request port of the bridge. */
+ BridgeRequestPort memSidePort;
public:
- /** A function used to return the port associated with this bus object. */
- virtual Port *getPort(const std::string &if_name, int idx = -1);
+ Port &getPort(const std::string &if_name,
+ PortID idx=InvalidPortID) override;
+
+ void init() override;
- virtual void init();
+ typedef BridgeParams Params;
- Bridge(const std::string &n, int qsa, int qsb, Tick _delay, int write_ack);
+ Bridge(const Params &p);
};
-#endif //__MEM_BUS_HH__
+#endif //__MEM_BRIDGE_HH__