ruby: added Packet interface to makeRequest and isReady.
[gem5.git] / src / mem / bridge.hh
index 2672a6e8cd589b67eea519ade4e22f147940a861..40f033811277e5ac453b4807680045d1d2be0d94 100644 (file)
  * 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 Decleration of a simple bus bridge object with no buffering
+ * @file
+ * Declaration of a simple bus bridge object with no buffering
  */
 
 #ifndef __MEM_BRIDGE_HH__
 #include <inttypes.h>
 #include <queue>
 
-
+#include "base/fast_alloc.hh"
 #include "mem/mem_object.hh"
 #include "mem/packet.hh"
 #include "mem/port.hh"
+#include "params/Bridge.hh"
 #include "sim/eventq.hh"
 
 class Bridge : public MemObject
 {
-  public:
-    enum Side
+  protected:
+    /** Declaration of the buses port type, one will be instantiated for each
+        of the interfaces connecting to the bus. */
+    class BridgePort : public Port
     {
-        SideA,
-        SideB
-    };
+        /** A pointer to the bridge to which this port belongs. */
+        Bridge *bridge;
 
-  protected:
-    /** Function called by the port when the bus is recieving a Timing
-        transaction.*/
-    bool recvTiming(Packet *pkt, Side id);
+        /**
+         * Pointer to the port on the other side of the bridge
+         * (connected to the other bus).
+         */
+        BridgePort *otherPort;
 
-    /** Function called by the port when the bus is recieving a Atomic
-        transaction.*/
-    Tick recvAtomic(Packet *pkt, Side id);
+        /** Minimum delay though this bridge. */
+        Tick delay;
 
-    /** Function called by the port when the bus is recieving a Functional
-        transaction.*/
-    void recvFunctional(Packet *pkt, Side id);
+        /** Min delay to respond to a nack. */
+        Tick nackDelay;
 
-    /** Function called by the port when the bus is recieving a status change.*/
-    void recvStatusChange(Port::Status status, Side id);
+        /** Pass ranges from one side of the bridge to the other? */
+        std::vector<Range<Addr> > filterRanges;
 
-    /** Process address range request.
-     * @param resp addresses that we can respond to
-     * @param snoop addresses that we would like to snoop
-     * @param id ide of the busport that made the request.
-     */
-    void addressRanges(AddrRangeList &resp, AddrRangeList &snoop, Side id);
+        class PacketBuffer : public Packet::SenderState, public FastAlloc {
 
+          public:
+            Tick ready;
+            PacketPtr pkt;
+            bool nackedHere;
+            Packet::SenderState *origSenderState;
+            short origSrc;
+            bool expectResponse;
 
-    /** Event that the SendEvent calls when it fires. This code must reschedule
-     * the send event as required. */
-    void timerEvent();
+            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)
 
-    /** Decleration of the buses port type, one will be instantiated for each
-        of the interfaces connecting to the bus. */
-    class BridgePort : public Port
-    {
-        /** A pointer to the bus to which this port belongs. */
-        Bridge *bridge;
+            {
+                if (!pkt->isResponse() && !nack)
+                    pkt->senderState = this;
+            }
 
-        /** A id to keep track of the intercafe ID this port is connected to. */
-        Bridge::Side side;
+            void fixResponse(PacketPtr pkt)
+            {
+                assert(pkt->senderState == this);
+                pkt->setDest(origSrc);
+                pkt->senderState = origSenderState;
+            }
+        };
 
-      public:
+        /**
+         * Outbound packet queue.  Packets are held in this queue for a
+         * specified delay to model the processing delay of the
+         * bridge.
+         */
+        std::list<PacketBuffer*> sendQueue;
 
-        /** Constructor for the BusPort.*/
-        BridgePort(Bridge *_bridge, Side _side)
-            : Port(""), bridge(_bridge), side(_side)
-        { }
+        int outstandingResponses;
+        int queuedRequests;
 
-        int numQueued() { return outbound.size(); }
+        /** If we're waiting for a retry to happen.*/
+        bool inRetry;
 
-      protected:
-        /** Data this is waiting to be transmitted. */
-        std::list<std::pair<Packet*, Tick> > outbound;
+        /** Max queue size for outbound packets */
+        int reqQueueLimit;
 
-        void sendPkt(Packet *pkt);
-        void sendPkt(std::pair<Packet*, Tick> p);
+        /** Max queue size for reserved responses. */
+        int respQueueLimit;
 
-        /** When reciving a timing request from the peer port,
-            pass it to the bridge. */
-        virtual bool recvTiming(Packet *pkt)
-        { return bridge->recvTiming(pkt, side); }
+        /**
+         * Is this side blocked from accepting outbound packets?
+         */
+        bool respQueueFull();
+        bool reqQueueFull();
 
-        /** When reciving a retry request from the peer port,
-            pass it to the bridge. */
-        virtual Packet* recvRetry();
+        void queueForSendTiming(PacketPtr pkt);
 
-        /** When reciving a Atomic requestfrom the peer port,
-            pass it to the bridge. */
-        virtual Tick recvAtomic(Packet *pkt)
-        { return bridge->recvAtomic(pkt, side); }
+        void finishSend(PacketBuffer *buf);
 
-        /** When reciving a Functional request from the peer port,
-            pass it to the bridge. */
-        virtual void recvFunctional(Packet *pkt)
-        { bridge->recvFunctional(pkt, side); }
+        void nackRequest(PacketPtr pkt);
 
-        /** When reciving a status changefrom the peer port,
-            pass it to the bridge. */
-        virtual void recvStatusChange(Status status)
-        { bridge->recvStatusChange(status, side); }
+        /**
+         * Handle send event, scheduled when the packet at the head of
+         * the outbound queue is ready to transmit (for timing
+         * accesses only).
+         */
+        void trySend();
 
-        /** When reciving a address range request the peer port,
-            pass it to the bridge. */
-        virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
-        { bridge->addressRanges(resp, snoop, side); }
+        class SendEvent : public Event
+        {
+            BridgePort *port;
 
-        friend class Bridge;
-    };
+          public:
+            SendEvent(BridgePort *p) : port(p) {}
+            virtual void process() { port->trySend(); }
+            virtual const char *description() const { return "bridge send"; }
+        };
 
-    class SendEvent : public Event
-    {
-        Bridge *bridge;
+        SendEvent sendEvent;
 
-        SendEvent(Bridge *b)
-            : Event(&mainEventQueue), bridge(b) {}
+      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);
 
-        virtual void process() { bridge->timerEvent(); }
+      protected:
 
-        virtual const char *description() { return "bridge delay event"; }
-        friend class Bridge;
-    };
+        /** When receiving a timing request from the peer port,
+            pass it to the bridge. */
+        virtual bool recvTiming(PacketPtr pkt);
 
-    SendEvent sendEvent;
+        /** When receiving a retry request from the peer port,
+            pass it to the bridge. */
+        virtual void recvRetry();
 
-    /** Sides of the bus bridges. */
-    BridgePort* sideA;
-    BridgePort* sideB;
+        /** When receiving a Atomic requestfrom the peer port,
+            pass it to the bridge. */
+        virtual Tick recvAtomic(PacketPtr pkt);
 
-    /** inbound queues on both sides. */
-    std::list<std::pair<Packet*, Tick> > inboundA;
-    std::list<std::pair<Packet*, Tick> > inboundB;
+        /** When receiving a Functional request from the peer port,
+            pass it to the bridge. */
+        virtual void recvFunctional(PacketPtr pkt);
 
-    /** The size of the queue for data coming into side a */
-    int queueSizeA;
-    int queueSizeB;
+        /** When receiving a status changefrom the peer port,
+            pass it to the bridge. */
+        virtual void recvStatusChange(Status status);
 
-    /* if the side is blocked or not. */
-    bool blockedA;
-    bool blockedB;
+        /** When receiving a address range request the peer port,
+            pass it to the bridge. */
+        virtual void getDeviceAddressRanges(AddrRangeList &resp,
+                                            bool &snoop);
+    };
 
-    /** Miminum delay though this bridge. */
-    Tick delay;
+    BridgePort portA, portB;
 
     /** If this bridge should acknowledge writes. */
     bool ackWrites;
 
   public:
+    typedef BridgeParams Params;
 
-    /** A function used to return the port associated with this bus object. */
-    virtual Port *getPort(const std::string &if_name)
-    {
-        if (if_name == "side_a") {
-            if (sideA != NULL)
-                panic("bridge side a already connected to.");
-            sideA = new BridgePort(this, SideA);
-            return sideA;
-        } else if (if_name == "side_b") {
-            if (sideB != NULL)
-                panic("bridge side b already connected to.");
-            sideB = new BridgePort(this, SideB);
-            return sideB;
-        } else
-            return NULL;
-    }
-
-    virtual void init();
+  protected:
+    Params *_params;
 
-    Bridge(const std::string &n, int qsa, int qsb, Tick _delay, int write_ack)
-        : MemObject(n), sendEvent(this), sideA(NULL), sideB(NULL),
-          queueSizeA(qsa), queueSizeB(qsb), blockedA(false), blockedB(false),
-          delay(_delay), ackWrites(write_ack)
-          {}
+  public:
+    const Params *params() const { return _params; }
 
-    /** Check if the port should block/unblock after recieving/sending a packet.
-     * */
-    void blockCheck(Side id);
+    /** A function used to return the port associated with this bus object. */
+    virtual Port *getPort(const std::string &if_name, int idx = -1);
 
-    friend class Bridge::SendEvent;
+    virtual void init();
 
+    Bridge(Params *p);
 };
 
 #endif //__MEM_BUS_HH__