#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"
* 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:
*
* @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
*
* @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
*
* @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);
/** 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;
/**
* Release the bus layer after being occupied and return to an
};
- /** 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;
+ AddrRange defaultRange;
/**
* Function called by the port when the bus is recieving a range change.
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;
}
}
// 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.
Tick 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;
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);
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;
};