summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mem/bus.cc20
-rw-r--r--src/mem/coherent_bus.cc13
-rw-r--r--src/mem/coherent_bus.hh51
-rw-r--r--src/mem/port.hh2
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