From 07cf9d914b292008ead7021182ec2ef8fc4671f1 Mon Sep 17 00:00:00 2001 From: Andreas Hansson Date: Tue, 17 Jan 2012 12:55:09 -0600 Subject: MEM: Separate queries for snooping and address ranges This patch simplifies the address-range determination mechanism and also unifies the naming across ports and devices. It further splits the queries for determining if a port is snooping and what address ranges it responds to (aiming towards a separation of cache-maintenance ports and pure memory-mapped ports). Default behaviours are such that most ports do not have to define isSnooping, and master ports need not implement getAddrRanges. --- src/mem/bridge.hh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/mem/bridge.hh') diff --git a/src/mem/bridge.hh b/src/mem/bridge.hh index 732717dd4..a3fa1f8f6 100644 --- a/src/mem/bridge.hh +++ b/src/mem/bridge.hh @@ -178,14 +178,14 @@ class Bridge : public MemObject 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); + /** + * When receiving a range change, pass it through the bridge. + */ + virtual void recvRangeChange(); /** When receiving a address range request the peer port, pass it to the bridge. */ - virtual void getDeviceAddressRanges(AddrRangeList &resp, - bool &snoop); + virtual AddrRangeList getAddrRanges(); }; BridgePort portA, portB; -- cgit v1.2.3 From 2208ea049f60618e432c69c065926bcbc810581a Mon Sep 17 00:00:00 2001 From: Andreas Hansson Date: Tue, 17 Jan 2012 12:55:09 -0600 Subject: MEM: Make the bus bridge unidirectional and fixed address range This patch makes the bus bridge uni-directional and specialises the bus ports to be a master port and a slave port. This greatly simplifies the assumptions on both sides as either port only has to deal with requests or responses. The following patches introduce the notion of master and slave ports, and would not be possible without this split of responsibilities. In making the bridge unidirectional, the address range mechanism of the bridge is also changed. For the cases where communication is taking place both ways, an additional bridge is needed. This causes issues with the existing mechanism, as the busses cannot determine when to stop iterating the address updates from the two bridges. To avoid this issue, and also greatly simplify the specification, the bridge now has a fixed set of address ranges, specified at creation time. --- src/mem/bridge.hh | 324 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 259 insertions(+), 65 deletions(-) (limited to 'src/mem/bridge.hh') diff --git a/src/mem/bridge.hh b/src/mem/bridge.hh index a3fa1f8f6..d389c0a5e 100644 --- a/src/mem/bridge.hh +++ b/src/mem/bridge.hh @@ -1,4 +1,16 @@ /* + * Copyright (c) 2011 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,11 +39,13 @@ * * Authors: Ali Saidi * Steve Reinhardt + * Andreas Hansson */ /** * @file - * Declaration of a simple bus bridge object with no buffering + * Declaration of a memory-mapped bus bridge that connects a master + * and a slave through a request and response queue. */ #ifndef __MEM_BRIDGE_HH__ @@ -49,90 +63,232 @@ #include "params/Bridge.hh" #include "sim/eventq.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. An incoming request is always + * accepted (recvTiming returns true), but is potentially NACKed if + * there is no request space or response space. + */ 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 packet buffer stores packets along with their sender state + * and scheduled time for transmission. + */ + class PacketBuffer : public Packet::SenderState, public FastAlloc { + + public: + Tick ready; + PacketPtr pkt; + bool nackedHere; + Packet::SenderState *origSenderState; + short origSrc; + bool expectResponse; + + PacketBuffer(PacketPtr _pkt, Tick t, bool nack = false) + : ready(t), pkt(_pkt), nackedHere(nack), + origSenderState(_pkt->senderState), + origSrc(nack ? _pkt->getDest() : _pkt->getSrc() ), + expectResponse(_pkt->needsResponse() && !nack) + + { + if (!pkt->isResponse() && !nack) + pkt->senderState = this; + } + + void fixResponse(PacketPtr pkt) + { + assert(pkt->senderState == this); + pkt->setDest(origSrc); + pkt->senderState = origSenderState; + } + }; + + // 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 Port { + + private: + /** A pointer to the bridge to which this port belongs. */ Bridge *bridge; /** - * Pointer to the port on the other side of the bridge + * Pointer to the master port on the other side of the bridge * (connected to the other bus). */ - BridgePort *otherPort; + BridgeMasterPort* masterPort; - /** Minimum delay though this bridge. */ + /** Minimum request delay though this bridge. */ Tick delay; - /** Min delay to respond to a nack. */ + /** Min delay to respond with a nack. */ Tick nackDelay; - /** Pass ranges from one side of the bridge to the other? */ - std::vector > filterRanges; + /** Address ranges to pass through the bridge */ + AddrRangeList ranges; + + /** + * Response packet queue. Response packets are held in this + * queue for a specified delay to model the processing delay + * of the bridge. + */ + std::list responseQueue; - class PacketBuffer : public Packet::SenderState, public FastAlloc { + /** Counter to track the outstanding responses. */ + unsigned int outstandingResponses; + + /** If we're waiting for a retry to happen. */ + bool inRetry; + + /** 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(); + + /** + * Turn the request packet into a NACK response and put it in + * the response queue and schedule its transmission. + * + * @param pkt the request packet to NACK + */ + void nackRequest(PacketPtr pkt); + + /** + * Handle send event, scheduled when the packet at the head of + * the response queue is ready to transmit (for timing + * accesses only). + */ + void trySend(); + + /** + * Private class for scheduling sending of responses from the + * response queue. + */ + class SendEvent : public Event + { + BridgeSlavePort *port; public: - Tick ready; - PacketPtr pkt; - bool nackedHere; - Packet::SenderState *origSenderState; - short origSrc; - bool expectResponse; - - PacketBuffer(PacketPtr _pkt, Tick t, bool nack = false) - : ready(t), pkt(_pkt), nackedHere(nack), - origSenderState(_pkt->senderState), - origSrc(nack ? _pkt->getDest() : _pkt->getSrc() ), - expectResponse(_pkt->needsResponse() && !nack) - - { - if (!pkt->isResponse() && !nack) - pkt->senderState = this; - } - - void fixResponse(PacketPtr pkt) - { - assert(pkt->senderState == this); - pkt->setDest(origSrc); - pkt->senderState = origSenderState; - } + SendEvent(BridgeSlavePort *p) : port(p) {} + virtual void process() { port->trySend(); } + virtual const char *description() const { return "bridge send"; } }; + /** Send event for the response queue. */ + SendEvent sendEvent; + + public: + /** - * Outbound packet queue. Packets are held in this queue for a - * specified delay to model the processing delay of the - * bridge. + * 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 from seeing a response to sending it + * @param _nack_delay the delay from a NACK to sending the response + * @param _resp_limit the size of the response queue + * @param _ranges a number of address ranges to forward */ - std::list sendQueue; + BridgeSlavePort(const std::string &_name, Bridge *_bridge, + BridgeMasterPort* _masterPort, int _delay, + int _nack_delay, int _resp_limit, + std::vector > _ranges); - int outstandingResponses; - int queuedRequests; + /** + * 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 + */ + void queueForSendTiming(PacketPtr pkt); - /** If we're waiting for a retry to happen.*/ - bool inRetry; + protected: - /** Max queue size for outbound packets */ - int reqQueueLimit; + /** When receiving a timing request from the peer port, + pass it to the bridge. */ + virtual bool recvTiming(PacketPtr pkt); - /** Max queue size for reserved responses. */ - int respQueueLimit; + /** When receiving a retry request from the peer port, + pass it to the bridge. */ + virtual void recvRetry(); + + /** When receiving a Atomic requestfrom the peer port, + pass it to the bridge. */ + virtual Tick recvAtomic(PacketPtr pkt); + + /** When receiving a Functional request from the peer port, + pass it to the bridge. */ + virtual void recvFunctional(PacketPtr pkt); /** - * Is this side blocked from accepting outbound packets? + * When receiving a range change on the slave side do nothing. */ - bool respQueueFull(); - bool reqQueueFull(); + virtual void recvRangeChange(); - void queueForSendTiming(PacketPtr pkt); + /** When receiving a address range request the peer port, + pass it to the bridge. */ + virtual AddrRangeList getAddrRanges(); + }; - void finishSend(PacketBuffer *buf); - void nackRequest(PacketPtr pkt); + /** + * 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 Port + { + + private: + + /** A pointer to the bridge to which this port belongs. */ + Bridge* bridge; + + /** + * Pointer to the slave port on the other side of the bridge + * (connected to the other bus). + */ + BridgeSlavePort* slavePort; + + /** Minimum delay though this bridge. */ + Tick 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 requestQueue; + + /** If we're waiting for a retry to happen. */ + bool inRetry; + + /** Max queue size for request packets */ + unsigned int reqQueueLimit; /** * Handle send event, scheduled when the packet at the head of @@ -141,24 +297,62 @@ class Bridge : public MemObject */ void trySend(); + /** + * Private class for scheduling sending of requests from the + * request queue. + */ class SendEvent : public Event { - BridgePort *port; + BridgeMasterPort *port; public: - SendEvent(BridgePort *p) : port(p) {} + SendEvent(BridgeMasterPort *p) : port(p) {} virtual void process() { port->trySend(); } virtual const char *description() const { return "bridge send"; } }; + /** Send event for the request queue. */ SendEvent sendEvent; 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 > filter_ranges); + + /** + * 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 from seeing a request to sending it + * @param _req_limit the size of the request queue + */ + BridgeMasterPort(const std::string &_name, Bridge *_bridge, + BridgeSlavePort* _slavePort, int _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 + */ + void queueForSendTiming(PacketPtr pkt); + + /** + * 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: @@ -182,13 +376,13 @@ class Bridge : public MemObject * When receiving a range change, pass it through the bridge. */ virtual void recvRangeChange(); - - /** When receiving a address range request the peer port, - pass it to the bridge. */ - virtual AddrRangeList getAddrRanges(); }; - BridgePort portA, portB; + /** Slave port of the bridge. */ + BridgeSlavePort slavePort; + + /** Master port of the bridge. */ + BridgeMasterPort masterPort; /** If this bridge should acknowledge writes. */ bool ackWrites; -- cgit v1.2.3