/*
+ * Copyright (c) 2011-2012 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
+ * Andreas Hansson
*/
/**
- * @file Decleration of a simple bus bridge object with no buffering
+ * @file
+ * Declaration of a memory-mapped bus bridge that connects a master
+ * and a slave through a request and response queue.
*/
#ifndef __MEM_BRIDGE_HH__
#define __MEM_BRIDGE_HH__
-#include <string>
#include <list>
-#include <inttypes.h>
-#include <queue>
+#include "base/types.hh"
#include "mem/mem_object.hh"
-#include "mem/packet.hh"
-#include "mem/port.hh"
-#include "sim/eventq.hh"
+#include "params/Bridge.hh"
+/**
+ * A bridge is used to interface two different busses (or in general a
+ * memory-mapped master and slave), 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 slave port and a master 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 MemObject
{
protected:
- /** Decleration of the buses port type, one will be instantiated for each
- of the interfaces connecting to the bus. */
- class BridgePort : public Port
+
+ /**
+ * A bridge request state stores packets along with their sender
+ * state and original source. It has enough information to also
+ * restore the response once it comes back to the bridge.
+ */
+ class RequestState : public Packet::SenderState
{
- /** A pointer to 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).
- */
- BridgePort *otherPort;
+ public:
- /** 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;
- }
- };
+ Packet::SenderState *origSenderState;
+ PortID origSrc;
+
+ RequestState(PacketPtr _pkt)
+ : origSenderState(_pkt->senderState),
+ origSrc(_pkt->getSrc())
+ { }
+
+ void fixResponse(PacketPtr pkt)
+ {
+ assert(pkt->senderState == this);
+ pkt->setDest(origSrc);
+ pkt->senderState = origSenderState;
+ }
+ };
+
+ /**
+ * A deferred packet stores a packet along with its scheduled
+ * transmission time
+ */
+ class DeferredPacket
+ {
+
+ public:
+
+ Tick tick;
+ PacketPtr pkt;
+
+ DeferredPacket(PacketPtr _pkt, Tick _tick) : tick(_tick), pkt(_pkt)
+ { }
+ };
+
+ // Forward declaration to allow the slave port to have a pointer
+ class BridgeMasterPort;
+
+ /**
+ * The port on the side that receives requests and sends
+ * responses. The slave port has a set of address ranges that it
+ * is responsible for. The slave port also has a buffer for the
+ * responses not yet sent.
+ */
+ class BridgeSlavePort : public SlavePort
+ {
+
+ private:
+
+ /** The bridge to which this port belongs. */
+ Bridge& bridge;
/**
- * Outbound packet queue. Packets are held in this queue for a
- * specified delay to model the processing delay of the
- * bridge.
+ * Master port on the other side of the bridge (connected to
+ * the other bus).
*/
- std::list<PacketBuffer*> sendQueue;
+ BridgeMasterPort& masterPort;
- int outstandingResponses;
+ /** Minimum request delay though this bridge. */
+ Cycles delay;
- /** Max queue size for outbound packets */
- int queueLimit;
+ /** Address ranges to pass through the bridge */
+ AddrRangeList ranges;
/**
- * Is this side blocked from accepting outbound packets?
+ * Response packet queue. Response packets are held in this
+ * queue for a specified delay to model the processing delay
+ * of the bridge.
*/
- bool queueFull() { return (sendQueue.size() == queueLimit); }
+ std::list<DeferredPacket> transmitList;
+
+ /** Counter to track the outstanding responses. */
+ unsigned int outstandingResponses;
- bool queueForSendTiming(Packet *pkt);
+ /** If we should send a retry when space becomes available. */
+ bool retryReq;
- void finishSend(PacketBuffer *buf);
+ /** Max queue size for reserved responses. */
+ unsigned int respQueueLimit;
+
+ /**
+ * Is this side blocked from accepting new response packets.
+ *
+ * @return true if the reserved space has reached the set limit
+ */
+ bool respQueueFull();
/**
* 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;
-
- public:
- SendEvent(BridgePort *p)
- : Event(&mainEventQueue), port(p) {}
+ void trySendTiming();
- virtual void process() { port->trySend(); }
+ /** Send event for the response queue. */
+ EventWrapper<BridgeSlavePort,
+ &BridgeSlavePort::trySendTiming> sendEvent;
- virtual const char *description() { return "bridge send event"; }
- };
+ public:
- SendEvent sendEvent;
+ /**
+ * Constructor for the BridgeSlavePort.
+ *
+ * @param _name the port name including the owner
+ * @param _bridge the structural owner
+ * @param _masterPort the master 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
+ */
+ BridgeSlavePort(const std::string& _name, Bridge& _bridge,
+ BridgeMasterPort& _masterPort, 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 recvRetry();
/** 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 address range request the peer port,
+ pass it to the bridge. */
+ AddrRangeList getAddrRanges() const;
+ };
+
+
+ /**
+ * Port on the side that forwards requests and receives
+ * responses. The master port has a buffer for the requests not
+ * yet sent.
+ */
+ class BridgeMasterPort : public MasterPort
+ {
+
+ private:
+
+ /** The bridge to which this port belongs. */
+ Bridge& bridge;
+
+ /**
+ * The slave port on the other side of the bridge (connected
+ * to the other bus).
+ */
+ BridgeSlavePort& slavePort;
+
+ /** Minimum delay though this bridge. */
+ Cycles delay;
+
+ /**
+ * Request packet queue. Request packets are held in this
+ * queue for a specified delay to model the processing delay
+ * of the bridge.
+ */
+ std::list<DeferredPacket> transmitList;
+
+ /** Max queue size for request packets */
+ 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. */
+ EventWrapper<BridgeMasterPort,
+ &BridgeMasterPort::trySendTiming> sendEvent;
+
+ public:
+
+ /**
+ * Constructor for the BridgeMasterPort.
+ *
+ * @param _name the port name including the owner
+ * @param _bridge the structural owner
+ * @param _slavePort the slave 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
+ */
+ BridgeMasterPort(const std::string& _name, Bridge& _bridge,
+ BridgeSlavePort& _slavePort, 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();
+
+ /**
+ * 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 checkFunctional(PacketPtr pkt);
- /** When receiving a status changefrom the peer port,
+ protected:
+
+ /** When receiving a timing request from the peer port,
pass it to the bridge. */
- virtual void recvStatusChange(Status status);
+ bool recvTimingResp(PacketPtr pkt);
- /** When receiving a address range request the peer port,
+ /** When receiving a retry request from the peer port,
pass it to the bridge. */
- virtual void getDeviceAddressRanges(AddrRangeList &resp,
- AddrRangeList &snoop);
+ void recvRetry();
};
- BridgePort portA, portB;
+ /** Slave port of the bridge. */
+ BridgeSlavePort slavePort;
- /** If this bridge should acknowledge writes. */
- bool ackWrites;
+ /** Master port of the bridge. */
+ BridgeMasterPort masterPort;
public:
- /** A function used to return the port associated with this bus object. */
- virtual Port *getPort(const std::string &if_name);
+ virtual BaseMasterPort& getMasterPort(const std::string& if_name,
+ PortID idx = InvalidPortID);
+ virtual BaseSlavePort& getSlavePort(const std::string& if_name,
+ PortID idx = InvalidPortID);
virtual void init();
- Bridge(const std::string &n, int qsa, int qsb, Tick _delay, int write_ack);
+ typedef BridgeParams Params;
+
+ Bridge(Params *p);
};
#endif //__MEM_BUS_HH__