/*
+ * 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.
*
*
* Authors: Ali Saidi
* Steve Reinhardt
+ * Andreas Hansson
*/
/**
* @file
- * Declaration of a simple bus bridge object with no buffering
+ * Declaration of a memory-mapped 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 <deque>
+#include "base/types.hh"
#include "mem/mem_object.hh"
-#include "mem/packet.hh"
-#include "mem/port.hh"
#include "params/Bridge.hh"
-#include "sim/eventq.hh"
+/**
+ * A bridge is used to interface two different crossbars (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:
- /** 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
{
- /** 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;
+ const Tick tick;
+ const PacketPtr pkt;
- /** Min delay to respond to a nack. */
- Tick nackDelay;
+ DeferredPacket(PacketPtr _pkt, Tick _tick) : tick(_tick), pkt(_pkt)
+ { }
+ };
+
+ // Forward declaration to allow the slave port to have a pointer
+ class BridgeMasterPort;
- /** Pass ranges from one side of the bridge to the other? */
- std::vector<Range<Addr> > filterRanges;
+ /**
+ * 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
+ {
- class PacketBuffer : public Packet::SenderState {
+ private:
- public:
- Tick ready;
- PacketPtr pkt;
- Packet::SenderState *origSenderState;
- short origSrc;
- bool expectResponse;
+ /** The bridge to which this port belongs. */
+ Bridge& bridge;
- PacketBuffer(PacketPtr _pkt, Tick t, bool nack = false)
- : ready(t), pkt(_pkt),
- origSenderState(_pkt->senderState), origSrc(_pkt->getSrc()),
- expectResponse(_pkt->needsResponse() && !nack)
+ /**
+ * Master port on the other side of the bridge.
+ */
+ BridgeMasterPort& masterPort;
- {
- if (!pkt->isResponse() && !nack && !pkt->wasNacked())
- pkt->senderState = this;
- }
+ /** Minimum request delay though this bridge. */
+ const Cycles delay;
- void fixResponse(PacketPtr pkt)
- {
- assert(pkt->senderState == this);
- pkt->setDest(origSrc);
- pkt->senderState = origSenderState;
- }
- };
+ /** 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;
- int outstandingResponses;
- int queuedRequests;
+ /** Counter to track the outstanding responses. */
+ unsigned int outstandingResponses;
- /** If we're waiting for a retry to happen.*/
- bool inRetry;
-
- /** Max queue size for outbound packets */
- int reqQueueLimit;
+ /** If we should send a retry when space becomes available. */
+ bool retryReq;
/** Max queue size for reserved responses. */
- int respQueueLimit;
+ unsigned int respQueueLimit;
/**
- * Is this side blocked from accepting outbound packets?
+ * Is this side blocked from accepting new response packets.
+ *
+ * @return true if the reserved space has reached the set limit
*/
- bool respQueueFull();
- bool reqQueueFull();
-
- void queueForSendTiming(PacketPtr pkt);
-
- void finishSend(PacketBuffer *buf);
-
- void nackRequest(PacketPtr pkt);
+ 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();
+ void trySendTiming();
- class SendEvent : public Event
- {
- BridgePort *port;
+ /** Send event for the response queue. */
+ EventWrapper<BridgeSlavePort,
+ &BridgeSlavePort::trySendTiming> sendEvent;
- public:
- SendEvent(BridgePort *p)
- : Event(&mainEventQueue), port(p) {}
-
- virtual void process() { port->trySend(); }
+ public:
- virtual const char *description() { return "bridge send"; }
- };
+ /**
+ * 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);
- SendEvent sendEvent;
+ /**
+ * 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);
- public:
- /** Constructor for the BusPort.*/
- BridgePort(const std::string &_name, Bridge *_bridge,
- BridgePort *_otherPort, int _delay, int _nack_delay,
- int _req_limit, int _resp_limit,
- std::vector<Range<Addr> > filter_ranges);
+ /**
+ * 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(PacketPtr 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(PacketPtr pkt);
+ Tick recvAtomic(PacketPtr pkt);
/** When receiving a Functional request from the peer port,
pass it to the bridge. */
- virtual void recvFunctional(PacketPtr pkt);
-
- /** When receiving a status changefrom the peer port,
- pass it to the bridge. */
- virtual void recvStatusChange(Status status);
+ void recvFunctional(PacketPtr pkt);
/** When receiving a address range request the peer port,
pass it to the bridge. */
- virtual void getDeviceAddressRanges(AddrRangeList &resp,
- bool &snoop);
+ AddrRangeList getAddrRanges() const;
};
- BridgePort portA, portB;
- /** If this bridge should acknowledge writes. */
- bool ackWrites;
+ /**
+ * 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
+ {
- public:
- typedef BridgeParams Params;
+ private:
- protected:
- Params *_params;
+ /** The bridge to which this port belongs. */
+ Bridge& bridge;
+
+ /**
+ * The slave port on the other side of the bridge.
+ */
+ BridgeSlavePort& slavePort;
+
+ /** 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. */
+ 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() 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 checkFunctional(PacketPtr pkt);
+
+ protected:
+
+ /** When receiving a timing request from the peer port,
+ pass it to the bridge. */
+ bool recvTimingResp(PacketPtr pkt);
+
+ /** When receiving a retry request from the peer port,
+ pass it to the bridge. */
+ void recvReqRetry();
+ };
+
+ /** Slave port of the bridge. */
+ BridgeSlavePort slavePort;
+
+ /** Master port of the bridge. */
+ BridgeMasterPort masterPort;
public:
- const Params *params() const { return _params; }
- /** A function used to return the port associated with this bus object. */
- virtual Port *getPort(const std::string &if_name, int idx = -1);
+ 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();
+ typedef BridgeParams Params;
+
Bridge(Params *p);
};
-#endif //__MEM_BUS_HH__
+#endif //__MEM_BRIDGE_HH__