Make Bus::findPort() a little more useful.
[gem5.git] / src / mem / bus.cc
index 0c1f384b1cff1c6f0f63cb82acb9bf8ad46f783f..24a0c6f02319a19f32835438bbd2180f8164b960 100644 (file)
@@ -115,11 +115,14 @@ void Bus::occupyBus(PacketPtr pkt)
     //Bring tickNextIdle up to the present tick
     //There is some potential ambiguity where a cycle starts, which might make
     //a difference when devices are acting right around a cycle boundary. Using
-    //a < allows things which happen exactly on a cycle boundary to take up only
-    //the following cycle. Anthing that happens later will have to "wait" for
-    //the end of that cycle, and then start using the bus after that.
-    while (tickNextIdle < curTick)
-        tickNextIdle += clock;
+    //a < allows things which happen exactly on a cycle boundary to take up
+    //only the following cycle. Anything that happens later will have to "wait"
+    //for the end of that cycle, and then start using the bus after that.
+    if (tickNextIdle < curTick) {
+        tickNextIdle = curTick;
+        if (tickNextIdle % clock != 0)
+            tickNextIdle = curTick - (curTick % clock) + clock;
+    }
 
     // The packet will be sent. Figure out how long it occupies the bus, and
     // how much of that time is for the first "word", aka bus width.
@@ -132,10 +135,9 @@ void Bus::occupyBus(PacketPtr pkt)
         // We're using the "adding instead of dividing" trick again here
         if (pkt->hasData()) {
             int dataSize = pkt->getSize();
-            for (int transmitted = 0; transmitted < dataSize;
-                    transmitted += width) {
+            numCycles += dataSize/width;
+            if (dataSize % width)
                 numCycles++;
-            }
         } else {
             // If the packet didn't have data, it must have been a response.
             // Those use the bus for one cycle to send their data.
@@ -170,10 +172,9 @@ void Bus::occupyBus(PacketPtr pkt)
 bool
 Bus::recvTiming(PacketPtr pkt)
 {
-    Port *port;
-    DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s result %d\n",
-            pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString(),
-            pkt->result);
+    int port_id;
+    DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n",
+            pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
 
     BusPort *pktPort;
     if (pkt->getSrc() == defaultId)
@@ -195,8 +196,8 @@ Bus::recvTiming(PacketPtr pkt)
     // 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());
-        timingSnoop(pkt, port ? port : interfaces[pkt->getSrc()]);
+        port_id = findPort(pkt->getAddr());
+        timingSnoop(pkt, interfaces[port_id]);
 
         if (pkt->memInhibitAsserted()) {
             //Cache-Cache transfer occuring
@@ -212,13 +213,13 @@ Bus::recvTiming(PacketPtr pkt)
     } else {
         assert(dest >= 0 && dest < maxId);
         assert(dest != pkt->getSrc()); // catch infinite loops
-        port = interfaces[dest];
+        port_id = dest;
     }
 
     occupyBus(pkt);
 
-    if (port) {
-        if (port->sendTiming(pkt))  {
+    if (port_id != pkt->getSrc()) {
+        if (interfaces[port_id]->sendTiming(pkt))  {
             // Packet was successfully sent. Return true.
             // Also take care of retries
             if (inRetry) {
@@ -247,7 +248,6 @@ Bus::recvTiming(PacketPtr pkt)
 void
 Bus::recvRetry(int id)
 {
-    DPRINTF(Bus, "Received a retry from %s\n", id == -1 ? "self" : interfaces[id]->getPeer()->name());
     // If there's anything waiting, and the bus isn't busy...
     if (retryList.size() && curTick >= tickNextIdle) {
         //retryingPort = retryList.front();
@@ -279,8 +279,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;
@@ -295,7 +295,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;
             }
         }
 
@@ -306,18 +306,11 @@ 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;
 }
 
 void
@@ -327,6 +320,8 @@ Bus::functionalSnoop(PacketPtr pkt, Port *responder)
     // 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++) {
@@ -334,7 +329,7 @@ Bus::functionalSnoop(PacketPtr pkt, Port *responder)
         if (p != responder && p->getId() != src_id) {
             p->sendFunctional(pkt);
         }
-        if (pkt->result == Packet::Success) {
+        if (pkt->isResponse()) {
             break;
         }
         pkt->setSrc(src_id);
@@ -367,16 +362,19 @@ 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);
+    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;
-    Packet::Result response_result = Packet::Unknown;
-    MemCmd response_cmd = MemCmd::InvalidCmd;
+    MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
+    Tick snoop_response_latency = 0;
+    int orig_src = pkt->getSrc();
 
-    Port *target_port = findPort(pkt->getAddr(), pkt->getSrc());
+    int target_port_id = findPort(pkt->getAddr());
+    Port *target_port = interfaces[target_port_id];
 
     SnoopIter s_end = snoopPorts.end();
     for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
@@ -384,40 +382,44 @@ Bus::recvAtomic(PacketPtr pkt)
         // same port should not have both target addresses and snooping
         assert(p != target_port);
         if (p->getId() != pkt->getSrc()) {
-            p->sendAtomic(pkt);
-            if (pkt->result != Packet::Unknown) {
+            Tick latency = p->sendAtomic(pkt);
+            if (pkt->isResponse()) {
                 // response from snoop agent
                 assert(pkt->cmd != orig_cmd);
                 assert(pkt->memInhibitAsserted());
-                assert(pkt->isResponse());
                 // should only happen once
-                assert(response_result == Packet::Unknown);
-                assert(response_cmd == MemCmd::InvalidCmd);
+                assert(snoop_response_cmd == MemCmd::InvalidCmd);
                 // save response state
-                response_result = pkt->result;
-                response_cmd = pkt->cmd;
+                snoop_response_cmd = pkt->cmd;
+                snoop_response_latency = latency;
                 // restore original packet state for remaining snoopers
                 pkt->cmd = orig_cmd;
-                pkt->result = Packet::Unknown;
+                pkt->setSrc(orig_src);
+                pkt->setDest(Packet::Broadcast);
             }
         }
     }
 
-    Tick response_time = target_port->sendAtomic(pkt);
+    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 (response_result != Packet::Unknown) {
-        assert(response_cmd != MemCmd::InvalidCmd);
+    if (snoop_response_cmd != MemCmd::InvalidCmd) {
         // no one else should have responded
-        assert(pkt->result == Packet::Unknown);
+        assert(!pkt->isResponse());
         assert(pkt->cmd == orig_cmd);
-        pkt->cmd = response_cmd;
-        pkt->result = response_result;
+        pkt->cmd = snoop_response_cmd;
+        response_latency = snoop_response_latency;
     }
 
     // why do we have this packet field and the return value both???
-    pkt->finishTime = std::max(response_time, curTick + clock);
-    return pkt->finishTime;
+    pkt->finishTime = curTick + response_latency;
+    return response_latency;
 }
 
 /** Function called by the port when the bus is receiving a Functional
@@ -429,11 +431,12 @@ Bus::recvFunctional(PacketPtr pkt)
             pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
     assert(pkt->getDest() == Packet::Broadcast);
 
-    Port* port = findPort(pkt->getAddr(), pkt->getSrc());
-    functionalSnoop(pkt, port ? port : interfaces[pkt->getSrc()]);
+    int port_id = findPort(pkt->getAddr());
+    Port *port = interfaces[port_id];
+    functionalSnoop(pkt, port);
 
-    // 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);
     }
 }