/*
- * Copyright (c) 2011-2014 ARM Limited
+ * Copyright (c) 2011-2015, 2018-2020 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* 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: Ron Dreslinski
- * Ali Saidi
- * Andreas Hansson
- * William Wang
*/
/**
#define __MEM_XBAR_HH__
#include <deque>
+#include <unordered_map>
#include "base/addr_range_map.hh"
-#include "base/hashmap.hh"
#include "base/types.hh"
-#include "mem/mem_object.hh"
+#include "mem/qport.hh"
#include "params/BaseXBar.hh"
+#include "sim/clocked_object.hh"
#include "sim/stats.hh"
/**
* The BaseXBar is responsible for the basic flow control (busy or
* not), the administration of retries, and the address decoding.
*/
-class BaseXBar : public MemObject
+class BaseXBar : public ClockedObject
{
protected:
* PCIe, etc.
*
* The template parameter, PortClass, indicates the destination
- * port type for the layer. 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.
+ * port type for the layer. The retry list holds either memory-side ports
+ * or CPU-side ports, depending on the direction of the
+ * layer. Thus, a request layer has a retry list containing
+ * CPU-side ports, whereas a response layer holds memory-side ports.
*/
template <typename SrcType, typename DstType>
- class Layer : public Drainable
+ class Layer : public Drainable, public Stats::Group
{
public:
*
* @return 1 if busy or waiting to retry, or 0 if idle
*/
- unsigned int drain(DrainManager *dm);
+ DrainState drain() override;
- /**
- * Get the crossbar layer's name
- */
- const std::string name() const { return xbar.name() + _name; }
+ const std::string name() const { return _name; }
/**
*/
void failedTiming(SrcType* src_port, Tick busy_time);
- /** Occupy the layer until until */
void occupyLayer(Tick until);
/**
*/
void recvRetry();
+ protected:
+
/**
- * Register stats for the layer
+ * Sending the actual retry, in a manner specific to the
+ * individual layers. Note that for a RequestPort, there is
+ * both a RequestLayer and a SnoopResponseLayer using the same
+ * port, but using different functions for the flow control.
*/
- void regStats();
+ virtual void sendRetry(SrcType* retry_port) = 0;
private:
/** The crossbar this layer is a part of. */
BaseXBar& xbar;
- /** A name for this layer. */
std::string _name;
/**
*/
enum State { IDLE, BUSY, RETRY };
- /** track the state of the layer */
State state;
- /** manager to signal when drained */
- DrainManager *drainManager;
-
/**
* A deque of ports that retry should be called on because
* the original send was delayed due to a busy layer.
* potential waiting port, or drain if asked to do so.
*/
void releaseLayer();
-
- /** event used to schedule a release of the layer */
- EventWrapper<Layer, &Layer::releaseLayer> releaseEvent;
+ EventFunctionWrapper releaseEvent;
/**
* Stats for occupancy and utilization. These stats capture
};
- /** cycles of overhead per transaction */
- const Cycles headerCycles;
+ class ReqLayer : public Layer<ResponsePort, RequestPort>
+ {
+ public:
+ /**
+ * Create a request layer and give it a name.
+ *
+ * @param _port destination port the layer converges at
+ * @param _xbar the crossbar this layer belongs to
+ * @param _name the layer's name
+ */
+ ReqLayer(RequestPort& _port, BaseXBar& _xbar,
+ const std::string& _name) :
+ Layer(_port, _xbar, _name)
+ {}
+
+ protected:
+ void
+ sendRetry(ResponsePort* retry_port) override
+ {
+ retry_port->sendRetryReq();
+ }
+ };
+
+ class RespLayer : public Layer<RequestPort, ResponsePort>
+ {
+ public:
+ /**
+ * Create a response layer and give it a name.
+ *
+ * @param _port destination port the layer converges at
+ * @param _xbar the crossbar this layer belongs to
+ * @param _name the layer's name
+ */
+ RespLayer(ResponsePort& _port, BaseXBar& _xbar,
+ const std::string& _name) :
+ Layer(_port, _xbar, _name)
+ {}
+
+ protected:
+ void
+ sendRetry(RequestPort* retry_port) override
+ {
+ retry_port->sendRetryResp();
+ }
+ };
+
+ class SnoopRespLayer : public Layer<ResponsePort, RequestPort>
+ {
+ public:
+ /**
+ * Create a snoop response layer and give it a name.
+ *
+ * @param _port destination port the layer converges at
+ * @param _xbar the crossbar this layer belongs to
+ * @param _name the layer's name
+ */
+ SnoopRespLayer(RequestPort& _port, BaseXBar& _xbar,
+ const std::string& _name) :
+ Layer(_port, _xbar, _name)
+ {}
+
+ protected:
+
+ void
+ sendRetry(ResponsePort* retry_port) override
+ {
+ retry_port->sendRetrySnoopResp();
+ }
+ };
+
+ /**
+ * Cycles of front-end pipeline including the delay to accept the request
+ * and to decode the address.
+ */
+ const Cycles frontendLatency;
+ const Cycles forwardLatency;
+ const Cycles responseLatency;
+ /** Cycles the layer is occupied processing the packet header */
+ const Cycles headerLatency;
/** the width of the xbar in bytes */
const uint32_t width;
- AddrRangeMap<PortID> portMap;
+ AddrRangeMap<PortID, 3> portMap;
/**
* Remember where request packets came from so that we can route
* the underlying Request pointer inside the Packet stays
* constant.
*/
- m5::unordered_map<RequestPtr, PortID> routeTo;
+ std::unordered_map<RequestPtr, PortID> routeTo;
/** all contigous ranges seen by this crossbar */
AddrRangeList xbarRanges;
* Function called by the port when the crossbar is recieving a
* range change.
*
- * @param master_port_id id of the port that received the change
+ * @param mem_side_port_id id of the port that received the change
*/
- void recvRangeChange(PortID master_port_id);
+ virtual void recvRangeChange(PortID mem_side_port_id);
- /** Find which port connected to this crossbar (if any) should be
- * given a packet with this address.
+ /**
+ * Find which port connected to this crossbar (if any) should be
+ * given a packet with this address range.
*
- * @param addr Address to find port for.
+ * @param addr_range Address range to find port for.
* @return id of port that the packet should be sent out of.
*/
- PortID findPort(Addr addr);
-
- // Cache for the findPort function storing recently used ports from portMap
- struct PortCache {
- bool valid;
- PortID id;
- 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) const {
- if (portCache[0].valid && portCache[0].range.contains(addr)) {
- return portCache[0].id;
- }
- if (portCache[1].valid && portCache[1].range.contains(addr)) {
- return portCache[1].id;
- }
- if (portCache[2].valid && portCache[2].range.contains(addr)) {
- return portCache[2].id;
- }
-
- return InvalidPortID;
- }
-
- // Clears the earliest entry of the cache and inserts a new port entry
- inline void updatePortCache(short id, const AddrRange& range) {
- portCache[2].valid = portCache[1].valid;
- portCache[2].id = portCache[1].id;
- portCache[2].range = portCache[1].range;
-
- portCache[1].valid = portCache[0].valid;
- portCache[1].id = portCache[0].id;
- portCache[1].range = portCache[0].range;
-
- portCache[0].valid = true;
- portCache[0].id = id;
- portCache[0].range = range;
- }
-
- // Clears the cache. Needs to be called in constructor.
- inline void clearPortCache() {
- portCache[2].valid = false;
- portCache[1].valid = false;
- portCache[0].valid = false;
- }
+ PortID findPort(AddrRange addr_range);
/**
* Return the address ranges the crossbar is responsible for.
/**
* Calculate the timing parameters for the packet. Updates the
- * firstWordDelay and lastWordDelay fields of the packet
+ * headerDelay and payloadDelay 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.
+ * the header and the payload, respectively.
+ *
+ * @param pkt Packet to populate with timings
+ * @param header_delay Header delay to be added
*/
- void calcPacketTiming(PacketPtr pkt);
+ void calcPacketTiming(PacketPtr pkt, Tick header_delay);
/**
- * Remember for each of the master ports of the crossbar 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
+ * Remember for each of the memory-side ports of the crossbar if we got
+ * an address range from the connected CPU-side ports. For convenience,
+ * also keep track of if we got ranges from all the CPU-side-port modules
* or not.
*/
std::vector<bool> gotAddrRanges;
bool gotAllAddrRanges;
- /** The master and slave ports of the crossbar */
- std::vector<SlavePort*> slavePorts;
- std::vector<MasterPort*> masterPorts;
+ /** The memory-side ports and CPU-side ports of the crossbar */
+ std::vector<QueuedResponsePort*> cpuSidePorts;
+ std::vector<RequestPort*> memSidePorts;
/** Port that handles requests that don't match any of the interfaces.*/
PortID defaultPortID;
BaseXBar(const BaseXBarParams *p);
- virtual ~BaseXBar();
-
/**
* Stats for transaction distribution and data passing through the
* crossbar. The transaction distribution is globally counting
* different types of commands. The packet count and total packet
* size are two-dimensional vectors that are indexed by the
- * slave port and master port id (thus the neighbouring master and
- * neighbouring slave), summing up both directions (request and
- * response).
+ * CPU-side port and memory-side port id (thus the neighbouring memory-side
+ * ports and neighbouring CPU-side ports), summing up both directions
+ * (request and response).
*/
Stats::Vector transDist;
Stats::Vector2d pktCount;
public:
- virtual void init();
+ virtual ~BaseXBar();
/** A function used to return the port associated with this object. */
- BaseMasterPort& getMasterPort(const std::string& if_name,
- PortID idx = InvalidPortID);
- BaseSlavePort& getSlavePort(const std::string& if_name,
- PortID idx = InvalidPortID);
-
- virtual unsigned int drain(DrainManager *dm) = 0;
-
- virtual void regStats();
+ Port &getPort(const std::string &if_name,
+ PortID idx=InvalidPortID) override;
+ void regStats() override;
};
#endif //__MEM_XBAR_HH__