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
slavePorts.push_back(bp);
respLayers.push_back(new RespLayer(*bp, *this,
csprintf(".respLayer%d", i)));
+ snoopRespPorts.push_back(new SnoopRespPort(*bp, *this));
}
clearPortCache();
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
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",
// currently it is illegal to block responses... can lead
// to deadlock
assert(success);
+
+ respLayers[dest_port_id]->succeededTiming(packetFinishTime);
}
// stats updates
};
+ /**
+ * 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;
/**
* 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