summaryrefslogtreecommitdiff
path: root/src/mem/bus.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/mem/bus.cc')
-rw-r--r--src/mem/bus.cc285
1 files changed, 136 insertions, 149 deletions
diff --git a/src/mem/bus.cc b/src/mem/bus.cc
index bd098d496..518c9dbfa 100644
--- a/src/mem/bus.cc
+++ b/src/mem/bus.cc
@@ -33,7 +33,7 @@
* Definition of a bus object.
*/
-
+#include <algorithm>
#include <limits>
#include "base/misc.hh"
@@ -172,89 +172,81 @@ void Bus::occupyBus(PacketPtr pkt)
bool
Bus::recvTiming(PacketPtr pkt)
{
- Port *port;
+ short src = pkt->getSrc();
DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n",
- pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
+ src, pkt->getDest(), pkt->getAddr(), pkt->cmdString());
- BusPort *pktPort;
- if (pkt->getSrc() == defaultId)
- pktPort = defaultPort;
- else pktPort = interfaces[pkt->getSrc()];
+ BusPort *src_port = (src == defaultId) ? defaultPort : interfaces[src];
// If the bus is busy, or other devices are in line ahead of the current
// one, put this device on the retry list.
- if (tickNextIdle > curTick ||
- (retryList.size() && (!inRetry || pktPort != retryList.front()))) {
- addToRetryList(pktPort);
+ if (!(pkt->isResponse() || pkt->isExpressSnoop()) &&
+ (tickNextIdle > curTick ||
+ (retryList.size() && (!inRetry || src_port != retryList.front()))))
+ {
+ addToRetryList(src_port);
DPRINTF(Bus, "recvTiming: Bus is busy, returning false\n");
return false;
}
+ occupyBus(pkt);
+
short dest = pkt->getDest();
+ int dest_port_id;
+ Port *dest_port;
- // Make sure to clear the snoop commit flag so it doesn't think an
- // access has been handled twice.
if (dest == Packet::Broadcast) {
- port = findPort(pkt->getAddr(), pkt->getSrc());
- pkt->flags &= ~SNOOP_COMMIT;
- if (timingSnoop(pkt, port ? port : interfaces[pkt->getSrc()])) {
- bool success;
-
- pkt->flags |= SNOOP_COMMIT;
- success = timingSnoop(pkt, port ? port : interfaces[pkt->getSrc()]);
- assert(success);
-
- if (pkt->flags & SATISFIED) {
- //Cache-Cache transfer occuring
- if (inRetry) {
- retryList.front()->onRetryList(false);
- retryList.pop_front();
- inRetry = false;
- }
- occupyBus(pkt);
- DPRINTF(Bus, "recvTiming: Packet sucessfully sent\n");
- return true;
+ dest_port_id = findPort(pkt->getAddr());
+ dest_port = (dest_port_id == defaultId) ?
+ defaultPort : interfaces[dest_port_id];
+ for (SnoopIter s_iter = snoopPorts.begin();
+ s_iter != snoopPorts.end();
+ s_iter++) {
+ BusPort *p = *s_iter;
+ if (p != dest_port && p != src_port) {
+#ifndef NDEBUG
+ // cache is not allowed to refuse snoop
+ bool success = p->sendTiming(pkt);
+ assert(success);
+#else
+ // avoid unused variable warning
+ p->sendTiming(pkt);
+#endif
}
- } else {
- //Snoop didn't succeed
- DPRINTF(Bus, "Adding1 a retry to RETRY list %d\n",
- pktPort->getId());
- addToRetryList(pktPort);
- return false;
}
} else {
assert(dest >= 0 && dest < maxId);
- assert(dest != pkt->getSrc()); // catch infinite loops
- port = interfaces[dest];
+ assert(dest != src); // catch infinite loops
+ dest_port_id = dest;
+ dest_port = (dest_port_id == defaultId) ?
+ defaultPort : interfaces[dest_port_id];
}
- occupyBus(pkt);
-
- if (port) {
- if (port->sendTiming(pkt)) {
- // Packet was successfully sent. Return true.
- // Also take care of retries
- if (inRetry) {
- DPRINTF(Bus, "Remove retry from list %d\n",
- retryList.front()->getId());
- retryList.front()->onRetryList(false);
- retryList.pop_front();
- inRetry = false;
- }
- return true;
+ if (dest_port_id == src) {
+ // Must be forwarded snoop up from below...
+ assert(dest == Packet::Broadcast);
+ } else {
+ // send to actual target
+ if (!dest_port->sendTiming(pkt)) {
+ // Packet not successfully sent. Leave or put it on the retry list.
+ // illegal to block responses... can lead to deadlock
+ assert(!pkt->isResponse());
+ DPRINTF(Bus, "Adding2 a retry to RETRY list %d\n", src);
+ addToRetryList(src_port);
+ return false;
}
-
- // Packet not successfully sent. Leave or put it on the retry list.
- DPRINTF(Bus, "Adding2 a retry to RETRY list %d\n",
- pktPort->getId());
- addToRetryList(pktPort);
- return false;
+ // send OK, fall through
}
- else {
- //Forwarding up from responder, just return true;
- DPRINTF(Bus, "recvTiming: can we be here?\n");
- return true;
+
+ // Packet was successfully sent.
+ // Also take care of retries
+ if (inRetry) {
+ DPRINTF(Bus, "Remove retry from list %d\n", src);
+ retryList.front()->onRetryList(false);
+ retryList.pop_front();
+ inRetry = false;
}
+ return true;
}
void
@@ -291,8 +283,8 @@ Bus::recvRetry(int id)
}
}
-Port *
-Bus::findPort(Addr addr, int id)
+int
+Bus::findPort(Addr addr)
{
/* An interval tree would be a better way to do this. --ali. */
int dest_id = -1;
@@ -307,7 +299,7 @@ Bus::findPort(Addr addr, int id)
iter != defaultRange.end(); iter++) {
if (*iter == addr) {
DPRINTF(Bus, " found addr %#llx on default\n", addr);
- return defaultPort;
+ return defaultId;
}
}
@@ -318,120 +310,115 @@ Bus::findPort(Addr addr, int id)
DPRINTF(Bus, "Unable to find destination for addr: %#llx, will use "
"default port", addr);
- return defaultPort;
+ return defaultId;
}
}
-
- // we shouldn't be sending this back to where it came from
- // do the snoop access and then we should terminate
- // the cyclical call.
- if (dest_id == id)
- return 0;
-
- return interfaces[dest_id];
+ return dest_id;
}
+
+/** Function called by the port when the bus is receiving a Atomic
+ * transaction.*/
Tick
-Bus::atomicSnoop(PacketPtr pkt, Port *responder)
+Bus::recvAtomic(PacketPtr pkt)
{
- Tick response_time = 0;
-
- for (SnoopIter s_iter = snoopPorts.begin();
- s_iter != snoopPorts.end();
- s_iter++) {
+ DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n",
+ pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
+ assert(pkt->getDest() == Packet::Broadcast);
+ assert(pkt->isRequest());
+
+ // Variables for recording original command and snoop response (if
+ // any)... if a snooper respondes, we will need to restore
+ // original command so that additional snoops can take place
+ // properly
+ MemCmd orig_cmd = pkt->cmd;
+ MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
+ Tick snoop_response_latency = 0;
+ int orig_src = pkt->getSrc();
+
+ int target_port_id = findPort(pkt->getAddr());
+ Port *target_port = (target_port_id == defaultId) ?
+ defaultPort : interfaces[target_port_id];
+
+ SnoopIter s_end = snoopPorts.end();
+ for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
BusPort *p = *s_iter;
- if (p != responder && p->getId() != pkt->getSrc()) {
- Tick response = p->sendAtomic(pkt);
- if (response) {
- assert(!response_time); //Multiple responders
- response_time = response;
+ // same port should not have both target addresses and snooping
+ assert(p != target_port);
+ if (p->getId() != pkt->getSrc()) {
+ Tick latency = p->sendAtomic(pkt);
+ if (pkt->isResponse()) {
+ // response from snoop agent
+ assert(pkt->cmd != orig_cmd);
+ assert(pkt->memInhibitAsserted());
+ // should only happen once
+ assert(snoop_response_cmd == MemCmd::InvalidCmd);
+ // save response state
+ snoop_response_cmd = pkt->cmd;
+ snoop_response_latency = latency;
+ // restore original packet state for remaining snoopers
+ pkt->cmd = orig_cmd;
+ pkt->setSrc(orig_src);
+ pkt->setDest(Packet::Broadcast);
}
}
}
- return response_time;
+ Tick response_latency = 0;
+
+ // we can get requests sent up from the memory side of the bus for
+ // snooping... don't send them back down!
+ if (target_port_id != pkt->getSrc()) {
+ response_latency = target_port->sendAtomic(pkt);
+ }
+
+ // if we got a response from a snooper, restore it here
+ if (snoop_response_cmd != MemCmd::InvalidCmd) {
+ // no one else should have responded
+ assert(!pkt->isResponse());
+ assert(pkt->cmd == orig_cmd);
+ pkt->cmd = snoop_response_cmd;
+ response_latency = snoop_response_latency;
+ }
+
+ // why do we have this packet field and the return value both???
+ pkt->finishTime = curTick + response_latency;
+ return response_latency;
}
+/** Function called by the port when the bus is receiving a Functional
+ * transaction.*/
void
-Bus::functionalSnoop(PacketPtr pkt, Port *responder)
+Bus::recvFunctional(PacketPtr pkt)
{
+ DPRINTF(Bus, "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n",
+ pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
+ assert(pkt->getDest() == Packet::Broadcast);
+
+ int port_id = findPort(pkt->getAddr());
+ Port *port = (port_id == defaultId) ? defaultPort : interfaces[port_id];
// The packet may be changed by another bus on snoops, restore the
// id after each
int src_id = pkt->getSrc();
+ assert(pkt->isRequest()); // hasn't already been satisfied
+
for (SnoopIter s_iter = snoopPorts.begin();
s_iter != snoopPorts.end();
s_iter++) {
BusPort *p = *s_iter;
- if (p != responder && p->getId() != src_id) {
+ if (p != port && p->getId() != src_id) {
p->sendFunctional(pkt);
}
- if (pkt->result == Packet::Success) {
+ if (pkt->isResponse()) {
break;
}
pkt->setSrc(src_id);
}
-}
-
-bool
-Bus::timingSnoop(PacketPtr pkt, Port* responder)
-{
- for (SnoopIter s_iter = snoopPorts.begin();
- s_iter != snoopPorts.end();
- s_iter++) {
- BusPort *p = *s_iter;
- if (p != responder && p->getId() != pkt->getSrc()) {
- bool success = p->sendTiming(pkt);
- if (!success)
- return false;
- }
- }
-
- return true;
-}
-
-
-/** Function called by the port when the bus is receiving a Atomic
- * transaction.*/
-Tick
-Bus::recvAtomic(PacketPtr pkt)
-{
- DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n",
- pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
- assert(pkt->getDest() == Packet::Broadcast);
- pkt->flags |= SNOOP_COMMIT;
-
- // Assume one bus cycle in order to get through. This may have
- // some clock skew issues yet again...
- pkt->finishTime = curTick + clock;
-
- Port *port = findPort(pkt->getAddr(), pkt->getSrc());
- Tick snoopTime = atomicSnoop(pkt, port ? port : interfaces[pkt->getSrc()]);
-
- if (snoopTime)
- return snoopTime; //Snoop satisfies it
- else if (port)
- return port->sendAtomic(pkt);
- else
- return 0;
-}
-
-/** Function called by the port when the bus is receiving a Functional
- * transaction.*/
-void
-Bus::recvFunctional(PacketPtr pkt)
-{
- DPRINTF(Bus, "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n",
- pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
- assert(pkt->getDest() == Packet::Broadcast);
- pkt->flags |= SNOOP_COMMIT;
-
- Port* port = findPort(pkt->getAddr(), pkt->getSrc());
- functionalSnoop(pkt, port ? port : interfaces[pkt->getSrc()]);
- // If the snooping found what we were looking for, we're done.
- if (pkt->result != Packet::Success && port) {
+ // If the snooping hasn't found what we were looking for, keep going.
+ if (!pkt->isResponse() && port_id != pkt->getSrc()) {
port->sendFunctional(pkt);
}
}