summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mem/bus.cc42
-rw-r--r--src/mem/bus.hh24
-rw-r--r--src/mem/coherent_bus.cc28
-rw-r--r--src/mem/coherent_bus.hh7
-rw-r--r--src/mem/noncoherent_bus.cc23
-rw-r--r--src/mem/noncoherent_bus.hh6
6 files changed, 82 insertions, 48 deletions
diff --git a/src/mem/bus.cc b/src/mem/bus.cc
index 16b581a7e..ab8b76594 100644
--- a/src/mem/bus.cc
+++ b/src/mem/bus.cc
@@ -137,13 +137,16 @@ BaseBus::calcPacketTiming(PacketPtr pkt)
return headerTime;
}
-BaseBus::Layer::Layer(BaseBus& _bus, const std::string& _name, Tick _clock) :
+template <typename PortClass>
+BaseBus::Layer<PortClass>::Layer(BaseBus& _bus, const std::string& _name,
+ Tick _clock) :
bus(_bus), _name(_name), state(IDLE), clock(_clock), drainEvent(NULL),
releaseEvent(this)
{
}
-void BaseBus::Layer::occupyLayer(Tick until)
+template <typename PortClass>
+void BaseBus::Layer<PortClass>::occupyLayer(Tick until)
{
// ensure the state is busy or in retry and never idle at this
// point, as the bus should transition from idle as soon as it has
@@ -164,8 +167,9 @@ void BaseBus::Layer::occupyLayer(Tick until)
curTick(), until);
}
+template <typename PortClass>
bool
-BaseBus::Layer::tryTiming(Port* port)
+BaseBus::Layer<PortClass>::tryTiming(PortClass* port)
{
// first we see if the bus is busy, next we check if we are in a
// retry with a port other than the current one
@@ -184,8 +188,9 @@ BaseBus::Layer::tryTiming(Port* port)
return true;
}
+template <typename PortClass>
void
-BaseBus::Layer::succeededTiming(Tick busy_time)
+BaseBus::Layer<PortClass>::succeededTiming(Tick busy_time)
{
// if a retrying port succeeded, also take it off the retry list
if (state == RETRY) {
@@ -203,8 +208,9 @@ BaseBus::Layer::succeededTiming(Tick busy_time)
occupyLayer(busy_time);
}
+template <typename PortClass>
void
-BaseBus::Layer::failedTiming(SlavePort* port, Tick busy_time)
+BaseBus::Layer<PortClass>::failedTiming(PortClass* port, Tick busy_time)
{
// if we are not in a retry, i.e. busy (but never idle), or we are
// in a retry but not for the current port, then add the port at
@@ -221,8 +227,9 @@ BaseBus::Layer::failedTiming(SlavePort* port, Tick busy_time)
occupyLayer(busy_time);
}
+template <typename PortClass>
void
-BaseBus::Layer::releaseLayer()
+BaseBus::Layer<PortClass>::releaseLayer()
{
// releasing the bus means we should now be idle
assert(state == BUSY);
@@ -246,8 +253,9 @@ BaseBus::Layer::releaseLayer()
}
}
+template <typename PortClass>
void
-BaseBus::Layer::retryWaiting()
+BaseBus::Layer<PortClass>::retryWaiting()
{
// this should never be called with an empty retry list
assert(!retryList.empty());
@@ -262,10 +270,7 @@ BaseBus::Layer::retryWaiting()
// note that we might have blocked on the receiving port being
// busy (rather than the bus itself) and now call retry before the
// destination called retry on the bus
- if (dynamic_cast<SlavePort*>(retryList.front()) != NULL)
- (dynamic_cast<SlavePort*>(retryList.front()))->sendRetry();
- else
- (dynamic_cast<MasterPort*>(retryList.front()))->sendRetry();
+ retryList.front()->sendRetry();
// If the bus is still in the retry state, sendTiming wasn't
// called in zero time (e.g. the cache does this)
@@ -286,8 +291,9 @@ BaseBus::Layer::retryWaiting()
}
}
+template <typename PortClass>
void
-BaseBus::Layer::recvRetry()
+BaseBus::Layer<PortClass>::recvRetry()
{
// we got a retry from a peer that we tried to send something to
// and failed, but we sent it on the account of someone else, and
@@ -484,9 +490,9 @@ BaseBus::findBlockSize()
return max_bs;
}
-
+template <typename PortClass>
unsigned int
-BaseBus::Layer::drain(Event * de)
+BaseBus::Layer<PortClass>::drain(Event * de)
{
//We should check that we're not "doing" anything, and that noone is
//waiting. We might be idle but have someone waiting if the device we
@@ -497,3 +503,11 @@ BaseBus::Layer::drain(Event * de)
}
return 0;
}
+
+/**
+ * Bus layer template instantiations. Could be removed with _impl.hh
+ * file, but since there are only two given options (MasterPort and
+ * SlavePort) it seems a bit excessive at this point.
+ */
+template class BaseBus::Layer<SlavePort>;
+template class BaseBus::Layer<MasterPort>;
diff --git a/src/mem/bus.hh b/src/mem/bus.hh
index c54532c65..d4c3b4724 100644
--- a/src/mem/bus.hh
+++ b/src/mem/bus.hh
@@ -82,11 +82,19 @@ 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.
*/
+ template <typename PortClass>
class Layer
{
@@ -129,7 +137,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 +156,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);
@@ -203,10 +211,10 @@ class BaseBus : public MemObject
Event * drainEvent;
/**
- * 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::list<PortClass*> retryList;
/**
* Release the bus layer after being occupied and return to an
diff --git a/src/mem/coherent_bus.cc b/src/mem/coherent_bus.cc
index 956654981..5bcb2f14f 100644
--- a/src/mem/coherent_bus.cc
+++ b/src/mem/coherent_bus.cc
@@ -54,7 +54,9 @@
#include "mem/coherent_bus.hh"
CoherentBus::CoherentBus(const CoherentBusParams *p)
- : BaseBus(p), layer(*this, ".layer", p->clock)
+ : BaseBus(p), reqLayer(*this, ".reqLayer", p->clock),
+ respLayer(*this, ".respLayer", p->clock),
+ snoopRespLayer(*this, ".snoopRespLayer", p->clock)
{
// create the ports based on the size of the master and slave
// vector ports, and the presence of the default port, the ports
@@ -115,7 +117,7 @@ CoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id)
// test if the bus should be considered occupied for the current
// port, and exclude express snoops from the check
- if (!is_express_snoop && !layer.tryTiming(src_port)) {
+ if (!is_express_snoop && !reqLayer.tryTiming(src_port)) {
DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x BUSY\n",
src_port->name(), pkt->cmdString(), pkt->getAddr());
return false;
@@ -176,10 +178,10 @@ CoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id)
src_port->name(), pkt->cmdString(), pkt->getAddr());
// update the bus state and schedule an idle event
- layer.failedTiming(src_port, headerFinishTime);
+ reqLayer.failedTiming(src_port, headerFinishTime);
} else {
// update the bus state and schedule an idle event
- layer.succeededTiming(packetFinishTime);
+ reqLayer.succeededTiming(packetFinishTime);
}
}
@@ -194,7 +196,7 @@ CoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id)
// test if the bus should be considered occupied for the current
// port
- if (!layer.tryTiming(src_port)) {
+ if (!respLayer.tryTiming(src_port)) {
DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x BUSY\n",
src_port->name(), pkt->cmdString(), pkt->getAddr());
return false;
@@ -221,7 +223,7 @@ CoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id)
// deadlock
assert(success);
- layer.succeededTiming(packetFinishTime);
+ respLayer.succeededTiming(packetFinishTime);
return true;
}
@@ -258,7 +260,7 @@ CoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id)
// test if the bus should be considered occupied for the current
// port
- if (!layer.tryTiming(src_port)) {
+ if (!snoopRespLayer.tryTiming(src_port)) {
DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n",
src_port->name(), pkt->cmdString(), pkt->getAddr());
return false;
@@ -309,7 +311,7 @@ CoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id)
assert(success);
}
- layer.succeededTiming(packetFinishTime);
+ snoopRespLayer.succeededTiming(packetFinishTime);
return true;
}
@@ -335,8 +337,10 @@ CoherentBus::forwardTiming(PacketPtr pkt, PortID exclude_slave_port_id)
void
CoherentBus::recvRetry()
{
- // only one layer that can deal with it
- layer.recvRetry();
+ // responses and snoop responses never block on forwarding them,
+ // so the retry will always be coming from a port to which we
+ // tried to forward a request
+ reqLayer.recvRetry();
}
Tick
@@ -503,8 +507,8 @@ CoherentBus::forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id)
unsigned int
CoherentBus::drain(Event *de)
{
- // only one layer to worry about at the moment
- return layer.drain(de);
+ // sum up the individual layers
+ return reqLayer.drain(de) + respLayer.drain(de) + snoopRespLayer.drain(de);
}
CoherentBus *
diff --git a/src/mem/coherent_bus.hh b/src/mem/coherent_bus.hh
index b5f0cdee5..a28b388d5 100644
--- a/src/mem/coherent_bus.hh
+++ b/src/mem/coherent_bus.hh
@@ -70,9 +70,12 @@ class CoherentBus : public BaseBus
protected:
/**
- * Declare the single layer of this bus.
+ * Declare the three layers of this bus, one for requests, one
+ * for responses, and one for snoop responses
*/
- Layer layer;
+ Layer<SlavePort> reqLayer;
+ Layer<MasterPort> respLayer;
+ Layer<SlavePort> snoopRespLayer;
/**
* Declaration of the coherent bus slave port type, one will be
diff --git a/src/mem/noncoherent_bus.cc b/src/mem/noncoherent_bus.cc
index e502a78a8..fb306bfeb 100644
--- a/src/mem/noncoherent_bus.cc
+++ b/src/mem/noncoherent_bus.cc
@@ -55,7 +55,8 @@
#include "mem/noncoherent_bus.hh"
NoncoherentBus::NoncoherentBus(const NoncoherentBusParams *p)
- : BaseBus(p), layer(*this, ".layer", p->clock)
+ : BaseBus(p), reqLayer(*this, ".reqLayer", p->clock),
+ respLayer(*this, ".respLayer", p->clock)
{
// create the ports based on the size of the master and slave
// vector ports, and the presence of the default port, the ports
@@ -97,7 +98,7 @@ NoncoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id)
// test if the bus should be considered occupied for the current
// port
- if (!layer.tryTiming(src_port)) {
+ if (!reqLayer.tryTiming(src_port)) {
DPRINTF(NoncoherentBus, "recvTimingReq: src %s %s 0x%x BUSY\n",
src_port->name(), pkt->cmdString(), pkt->getAddr());
return false;
@@ -123,12 +124,12 @@ NoncoherentBus::recvTimingReq(PacketPtr pkt, PortID slave_port_id)
DPRINTF(NoncoherentBus, "recvTimingReq: src %s %s 0x%x RETRY\n",
src_port->name(), pkt->cmdString(), pkt->getAddr());
- layer.failedTiming(src_port, headerFinishTime);
+ reqLayer.failedTiming(src_port, headerFinishTime);
return false;
}
- layer.succeededTiming(packetFinishTime);
+ reqLayer.succeededTiming(packetFinishTime);
return true;
}
@@ -141,7 +142,7 @@ NoncoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id)
// test if the bus should be considered occupied for the current
// port
- if (!layer.tryTiming(src_port)) {
+ if (!respLayer.tryTiming(src_port)) {
DPRINTF(NoncoherentBus, "recvTimingResp: src %s %s 0x%x BUSY\n",
src_port->name(), pkt->cmdString(), pkt->getAddr());
return false;
@@ -161,7 +162,7 @@ NoncoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id)
// deadlock
assert(success);
- layer.succeededTiming(packetFinishTime);
+ respLayer.succeededTiming(packetFinishTime);
return true;
}
@@ -169,8 +170,10 @@ NoncoherentBus::recvTimingResp(PacketPtr pkt, PortID master_port_id)
void
NoncoherentBus::recvRetry()
{
- // only one layer that can deal with it
- layer.recvRetry();
+ // responses never block on forwarding them, so the retry will
+ // always be coming from a port to which we tried to forward a
+ // request
+ reqLayer.recvRetry();
}
Tick
@@ -211,8 +214,8 @@ NoncoherentBus::recvFunctional(PacketPtr pkt, PortID slave_port_id)
unsigned int
NoncoherentBus::drain(Event *de)
{
- // only one layer to worry about at the moment
- return layer.drain(de);
+ // sum up the individual layers
+ return reqLayer.drain(de) + respLayer.drain(de);
}
NoncoherentBus*
diff --git a/src/mem/noncoherent_bus.hh b/src/mem/noncoherent_bus.hh
index dd43d8c19..e8c1ab57a 100644
--- a/src/mem/noncoherent_bus.hh
+++ b/src/mem/noncoherent_bus.hh
@@ -73,9 +73,11 @@ class NoncoherentBus : public BaseBus
protected:
/**
- * Declare the single layer of this bus.
+ * Declare the two layers of this bus, one for requests and one
+ * for responses.
*/
- Layer layer;
+ Layer<SlavePort> reqLayer;
+ Layer<MasterPort> respLayer;
/**
* Declaration of the non-coherent bus slave port type, one will