mem: Introduce a variable for the retrying port
[gem5.git] / src / mem / bus.hh
index c54532c6566e8747b0904012d67c8fb6aef8ae18..2cd21ff85a640c3c6bbfdbe0e3fecd3fde2604ea 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012 ARM Limited
+ * Copyright (c) 2011-2013 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
 #ifndef __MEM_BUS_HH__
 #define __MEM_BUS_HH__
 
-#include <list>
+#include <deque>
 #include <set>
 
-#include "base/range.hh"
-#include "base/range_map.hh"
+#include "base/addr_range_map.hh"
 #include "base/types.hh"
 #include "mem/mem_object.hh"
 #include "params/BaseBus.hh"
@@ -82,12 +81,20 @@ class BaseBus : public MemObject
      * point is to have three layers, for requests, responses, and
      * snoop responses respectively (snoop requests are instantaneous
      * and do not need any flow control or arbitration). This case is
-     * similar to AHB and some OCP configurations. As a further
-     * extensions beyond the three-layer bus, a future multi-layer bus
-     * has with one layer per connected slave port provides a full or
-     * partial crossbar, like AXI, OCP, PCIe etc.
+     * similar to AHB and some OCP configurations.
+     *
+     * As a further extensions beyond the three-layer bus, a future
+     * multi-layer bus has with one layer per connected slave port
+     * provides a full or partial crossbar, like AXI, OCP, PCIe etc.
+     *
+     * The template parameter, PortClass, indicates the destination
+     * port type for the bus. The retry list holds either master ports
+     * or slave ports, depending on the direction of the layer. Thus,
+     * a request layer has a retry list containing slave ports,
+     * whereas a response layer holds master ports.
      */
-    class Layer
+    template <typename PortClass>
+    class Layer : public Drainable
     {
 
       public:
@@ -98,9 +105,8 @@ class BaseBus : public MemObject
          *
          * @param _bus the bus this layer belongs to
          * @param _name the layer's name
-         * @param _clock clock period in ticks
          */
-        Layer(BaseBus& _bus, const std::string& _name, Tick _clock);
+        Layer(BaseBus& _bus, const std::string& _name);
 
         /**
          * Drain according to the normal semantics, so that the bus
@@ -111,7 +117,7 @@ class BaseBus : public MemObject
          *
          * @return 1 if busy or waiting to retry, or 0 if idle
          */
-        unsigned int drain(Event *de);
+        unsigned int drain(DrainManager *dm);
 
         /**
          * Get the bus layer's name
@@ -129,7 +135,7 @@ class BaseBus : public MemObject
          *
          * @return True if the bus layer accepts the packet
          */
-        bool tryTiming(Port* port);
+        bool tryTiming(PortClass* port);
 
         /**
          * Deal with a destination port accepting a packet by potentially
@@ -148,7 +154,7 @@ class BaseBus : public MemObject
          *
          * @param busy_time Time to spend as a result of a failed send
          */
-        void failedTiming(SlavePort* port, Tick busy_time);
+        void failedTiming(PortClass* port, Tick busy_time);
 
         /** Occupy the bus layer until until */
         void occupyLayer(Tick until);
@@ -196,17 +202,22 @@ class BaseBus : public MemObject
         /** track the state of the bus layer */
         State state;
 
-        /** the clock speed for the bus layer */
-        Tick clock;
-
-        /** event for signalling when drained */
-        Event * drainEvent;
+        /** manager to signal when drained */
+        DrainManager *drainManager;
 
         /**
-         * An array of pointers to ports that retry should be called
+         * An array of ports that retry should be called
          * on because the original send failed for whatever reason.
          */
-        std::list<Port*> retryList;
+        std::deque<PortClass*> retryList;
+
+        /**
+         * Port that we are currently in the process of telling to
+         * retry a previously failed attempt to perform a timing
+         * transaction. This is a valid port when in the retry state,
+         * and NULL when in busy or idle.
+         */
+        PortClass* retryingPort;
 
         /**
          * Release the bus layer after being occupied and return to an
@@ -220,18 +231,19 @@ class BaseBus : public MemObject
 
     };
 
-    /** the clock speed for the bus */
-    Tick clock;
     /** cycles of overhead per transaction */
-    int headerCycles;
+    const Cycles headerCycles;
     /** the width of the bus in bytes */
-    int width;
+    const uint32_t width;
 
-    typedef range_map<Addr, PortID>::iterator PortMapIter;
-    typedef range_map<Addr, PortID>::const_iterator PortMapConstIter;
-    range_map<Addr, PortID> portMap;
+    typedef AddrRangeMap<PortID>::iterator PortMapIter;
+    typedef AddrRangeMap<PortID>::const_iterator PortMapConstIter;
+    AddrRangeMap<PortID> portMap;
 
-    AddrRangeList defaultRange;
+    /** all contigous ranges seen by this bus */
+    AddrRangeList busRanges;
+
+    AddrRange defaultRange;
 
     /**
      * Function called by the port when the bus is recieving a range change.
@@ -251,25 +263,21 @@ class BaseBus : public MemObject
     struct PortCache {
         bool valid;
         PortID id;
-        Addr start;
-        Addr end;
+        AddrRange range;
     };
 
     PortCache portCache[3];
 
     // Checks the cache and returns the id of the port that has the requested
     // address within its range
-    inline PortID checkPortCache(Addr addr) {
-        if (portCache[0].valid && addr >= portCache[0].start &&
-            addr < portCache[0].end) {
+    inline PortID checkPortCache(Addr addr) const {
+        if (portCache[0].valid && portCache[0].range.contains(addr)) {
             return portCache[0].id;
         }
-        if (portCache[1].valid && addr >= portCache[1].start &&
-                   addr < portCache[1].end) {
+        if (portCache[1].valid && portCache[1].range.contains(addr)) {
             return portCache[1].id;
         }
-        if (portCache[2].valid && addr >= portCache[2].start &&
-            addr < portCache[2].end) {
+        if (portCache[2].valid && portCache[2].range.contains(addr)) {
             return portCache[2].id;
         }
 
@@ -277,21 +285,18 @@ class BaseBus : public MemObject
     }
 
     // Clears the earliest entry of the cache and inserts a new port entry
-    inline void updatePortCache(short id, Addr start, Addr end) {
+    inline void updatePortCache(short id, const AddrRange& range) {
         portCache[2].valid = portCache[1].valid;
         portCache[2].id    = portCache[1].id;
-        portCache[2].start = portCache[1].start;
-        portCache[2].end   = portCache[1].end;
+        portCache[2].range = portCache[1].range;
 
         portCache[1].valid = portCache[0].valid;
         portCache[1].id    = portCache[0].id;
-        portCache[1].start = portCache[0].start;
-        portCache[1].end   = portCache[0].end;
+        portCache[1].range = portCache[0].range;
 
         portCache[0].valid = true;
         portCache[0].id    = id;
-        portCache[0].start = start;
-        portCache[0].end   = end;
+        portCache[0].range = range;
     }
 
     // Clears the cache. Needs to be called in constructor.
@@ -308,21 +313,31 @@ class BaseBus : public MemObject
      */
     AddrRangeList getAddrRanges() const;
 
-    /** Calculate the timing parameters for the packet.  Updates the
-     * firstWordTime and finishTime fields of the packet object.
-     * Returns the tick at which the packet header is completed (which
-     * will be all that is sent if the target rejects the packet).
+    /**
+     * Calculate the timing parameters for the packet. Updates the
+     * busFirstWordDelay and busLastWordDelay fields of the packet
+     * object with the relative number of ticks required to transmit
+     * the header and the first word, and the last word, respectively.
      */
-    Tick calcPacketTiming(PacketPtr pkt);
+    void calcPacketTiming(PacketPtr pkt);
 
     /**
-     * Ask everyone on the bus what their size is
+     * Ask everyone on the bus what their size is and determine the
+     * bus size as either the maximum, or if no device specifies a
+     * block size return the default.
      *
-     * @return the max of all the sizes
+     * @return the max of all the sizes or the default if none is set
      */
-    unsigned findBlockSize();
+    unsigned deviceBlockSize() const;
 
-    std::set<PortID> inRecvRangeChange;
+    /**
+     * Remember for each of the master ports of the bus if we got an
+     * address range from the connected slave. For convenience, also
+     * keep track of if we got ranges from all the slave modules or
+     * not.
+     */
+    std::vector<bool> gotAddrRanges;
+    bool gotAllAddrRanges;
 
     /** The master and slave ports of the bus */
     std::vector<SlavePort*> slavePorts;
@@ -341,11 +356,9 @@ class BaseBus : public MemObject
        address not handled by another port and not in default device's
        range will cause a fatal error.  If false, just send all
        addresses not handled by another port to default device. */
-    bool useDefaultRange;
+    const bool useDefaultRange;
 
-    unsigned defaultBlockSize;
-    unsigned cachedBlockSize;
-    bool cachedBlockSizeValid;
+    uint32_t blockSize;
 
     BaseBus(const BaseBusParams *p);
 
@@ -353,11 +366,15 @@ class BaseBus : public MemObject
 
   public:
 
+    virtual void init();
+
     /** A function used to return the port associated with this bus object. */
-    virtual MasterPort& getMasterPort(const std::string& if_name, int idx = -1);
-    virtual SlavePort& getSlavePort(const std::string& if_name, int idx = -1);
+    BaseMasterPort& getMasterPort(const std::string& if_name,
+                                  PortID idx = InvalidPortID);
+    BaseSlavePort& getSlavePort(const std::string& if_name,
+                                PortID idx = InvalidPortID);
 
-    virtual unsigned int drain(Event *de) = 0;
+    virtual unsigned int drain(DrainManager *dm) = 0;
 
 };