X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmem%2Fbridge.hh;h=16b21addf4132bb4f98228b72785fc0918f9fe9d;hb=e33b3aa6692b172f6db5957774a9e0289e81fa5b;hp=7af764437ffa82eef73cb9d8c3992acb584c05cf;hpb=6ab53415efe3e06c06589a8a6ef38185ff6f94b7;p=gem5.git diff --git a/src/mem/bridge.hh b/src/mem/bridge.hh index 7af764437..16b21addf 100644 --- a/src/mem/bridge.hh +++ b/src/mem/bridge.hh @@ -1,4 +1,16 @@ /* + * 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. * @@ -27,196 +39,292 @@ * * 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 -#include -#include -#include +#include -#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 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 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 { - /** 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; - bool fixPartialWrite; + /** + * 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 sendQueue; + std::deque 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? + * Upstream caches need this packet until true is returned, so + * hold it for deletion until a subsequent call */ - bool respQueueFull(); - bool reqQueueFull(); - - void queueForSendTiming(PacketPtr pkt); - - void finishSend(PacketBuffer *buf); + std::unique_ptr pendingDelete; - void nackRequest(PacketPtr pkt); + /** + * 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(); } + public: - virtual const char *description() { return "bridge send event"; } - }; + /** + * 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 _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, bool fix_partial_write); + /** + * 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; - public: - struct Params + /** + * 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 { - std::string name; - int req_size_a; - int req_size_b; - int resp_size_a; - int resp_size_b; - Tick delay; - Tick nack_delay; - bool write_ack; - bool fix_partial_write_a; - bool fix_partial_write_b; + + private: + + /** 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 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 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 trySatisfyFunctional(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(); }; - protected: - Params *_params; + /** 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); + Port &getPort(const std::string &if_name, + PortID idx=InvalidPortID) override; + + void init() override; - virtual void init(); + typedef BridgeParams Params; Bridge(Params *p); }; -#endif //__MEM_BUS_HH__ +#endif //__MEM_BRIDGE_HH__