diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/mem/bus.cc | 20 | ||||
-rw-r--r-- | src/mem/coherent_bus.cc | 13 | ||||
-rw-r--r-- | src/mem/coherent_bus.hh | 51 | ||||
-rw-r--r-- | src/mem/port.hh | 2 |
4 files changed, 79 insertions, 7 deletions
diff --git a/src/mem/bus.cc b/src/mem/bus.cc index 855f82db4..d94bd6a28 100644 --- a/src/mem/bus.cc +++ b/src/mem/bus.cc @@ -189,12 +189,20 @@ template <typename SrcType, typename DstType> bool BaseBus::Layer<SrcType,DstType>::tryTiming(SrcType* src_port) { - // first we see if the layer is busy, next we check if we are in a - // retry with a port other than the current one, lastly we check - // if the destination port is already engaged in a transaction - // waiting for a retry from the peer - if (state == BUSY || (state == RETRY && src_port != retryingPort) || - waitingForPeer != NULL) { + // if we are in the retry state, we will not see anything but the + // retrying port (or in the case of the snoop ports the snoop + // response port that mirrors the actual slave port) as we leave + // this state again in zero time if the peer does not immediately + // call the bus when receiving the retry + + // first we see if the layer is busy, next we check if the + // destination port is already engaged in a transaction waiting + // for a retry from the peer + if (state == BUSY || waitingForPeer != NULL) { + // the port should not be waiting already + assert(std::find(waitingForLayer.begin(), waitingForLayer.end(), + src_port) == waitingForLayer.end()); + // put the port at the end of the retry list waiting for the // layer to be freed up (and in the case of a busy peer, for // that transaction to go through, and then the bus to free diff --git a/src/mem/coherent_bus.cc b/src/mem/coherent_bus.cc index 20597bc3a..756d4c05c 100644 --- a/src/mem/coherent_bus.cc +++ b/src/mem/coherent_bus.cc @@ -92,6 +92,7 @@ CoherentBus::CoherentBus(const CoherentBusParams *p) slavePorts.push_back(bp); respLayers.push_back(new RespLayer(*bp, *this, csprintf(".respLayer%d", i))); + snoopRespPorts.push_back(new SnoopRespPort(*bp, *this)); } clearPortCache(); @@ -105,6 +106,8 @@ CoherentBus::~CoherentBus() delete *l; for (auto l = snoopLayers.begin(); l != snoopLayers.end(); ++l) delete *l; + for (auto p = snoopRespPorts.begin(); p != snoopRespPorts.end(); ++p) + delete *p; } void @@ -338,6 +341,14 @@ CoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id) src_port->name(), pkt->cmdString(), pkt->getAddr()); return false; } + } else { + // get the master port that mirrors this slave port internally + MasterPort* snoop_port = snoopRespPorts[slave_port_id]; + if (!respLayers[dest_port_id]->tryTiming(snoop_port)) { + DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x BUSY\n", + snoop_port->name(), pkt->cmdString(), pkt->getAddr()); + return false; + } } DPRINTF(CoherentBus, "recvTimingSnoopResp: src %s %s 0x%x\n", @@ -393,6 +404,8 @@ CoherentBus::recvTimingSnoopResp(PacketPtr pkt, PortID slave_port_id) // currently it is illegal to block responses... can lead // to deadlock assert(success); + + respLayers[dest_port_id]->succeededTiming(packetFinishTime); } // stats updates diff --git a/src/mem/coherent_bus.hh b/src/mem/coherent_bus.hh index d8ddd507c..49f7ae698 100644 --- a/src/mem/coherent_bus.hh +++ b/src/mem/coherent_bus.hh @@ -219,6 +219,57 @@ class CoherentBus : public BaseBus }; + /** + * Internal class to bridge between an incoming snoop response + * from a slave port and forwarding it through an outgoing slave + * port. It is effectively a dangling master port. + */ + class SnoopRespPort : public MasterPort + { + + private: + + /** The port which we mirror internally. */ + SlavePort& slavePort; + + /** The bus to which this port belongs. */ + CoherentBus &bus; + + public: + + /** + * Create a snoop response port that mirrors a given slave port. + */ + SnoopRespPort(SlavePort& slave_port, CoherentBus& _bus) : + MasterPort(slave_port.name() + ".snoopRespPort", &_bus), + slavePort(slave_port), bus(_bus) { } + + /** + * Override the sending of retries and pass them on through + * the mirrored slave port. + */ + void sendRetry() { + slavePort.sendRetry(); + } + + /** + * Provided as necessary. + */ + void recvRetry() { panic("SnoopRespPort should never see retry\n"); } + + /** + * Provided as necessary. + */ + bool recvTimingResp(PacketPtr pkt) + { + panic("SnoopRespPort should never see timing response\n"); + return false; + } + + }; + + std::vector<SnoopRespPort*> snoopRespPorts; + std::vector<SlavePort*> snoopPorts; /** diff --git a/src/mem/port.hh b/src/mem/port.hh index a4e823796..18db800b6 100644 --- a/src/mem/port.hh +++ b/src/mem/port.hh @@ -251,7 +251,7 @@ class MasterPort : public BaseMasterPort * Send a retry to the slave port that previously attempted a * sendTimingResp to this master port and failed. */ - void sendRetry(); + virtual void sendRetry(); /** * Determine if this master port is snooping or not. The default |