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 +BaseBus::Layer::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 +void BaseBus::Layer::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 bool -BaseBus::Layer::tryTiming(Port* port) +BaseBus::Layer::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 void -BaseBus::Layer::succeededTiming(Tick busy_time) +BaseBus::Layer::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 void -BaseBus::Layer::failedTiming(SlavePort* port, Tick busy_time) +BaseBus::Layer::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 void -BaseBus::Layer::releaseLayer() +BaseBus::Layer::releaseLayer() { // releasing the bus means we should now be idle assert(state == BUSY); @@ -246,8 +253,9 @@ BaseBus::Layer::releaseLayer() } } +template void -BaseBus::Layer::retryWaiting() +BaseBus::Layer::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(retryList.front()) != NULL) - (dynamic_cast(retryList.front()))->sendRetry(); - else - (dynamic_cast(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 void -BaseBus::Layer::recvRetry() +BaseBus::Layer::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 unsigned int -BaseBus::Layer::drain(Event * de) +BaseBus::Layer::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; +template class BaseBus::Layer; 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 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 retryList; + std::list 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 reqLayer; + Layer respLayer; + Layer 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 reqLayer; + Layer respLayer; /** * Declaration of the non-coherent bus slave port type, one will