Make the Event::description() a const function
[gem5.git] / src / mem / bus.cc
index 34f7f4fd0181b2be666535edda98110598424aeb..66b20703f406b4405b9f252c6924379b06f15a28 100644 (file)
@@ -39,7 +39,6 @@
 #include "base/misc.hh"
 #include "base/trace.hh"
 #include "mem/bus.hh"
-#include "sim/builder.hh"
 
 Port *
 Bus::getPort(const std::string &if_name, int idx)
@@ -84,6 +83,7 @@ Bus::deletePortRefs(Port *p)
     if (funcPort == bp)
         return;
     interfaces.erase(bp->getId());
+    clearBusCache();
     delete bp;
 }
 
@@ -105,7 +105,7 @@ void Bus::BusFreeEvent::process()
     bus->recvRetry(-1);
 }
 
-const char * Bus::BusFreeEvent::description()
+const char * Bus::BusFreeEvent::description() const
 {
     return "bus became available";
 }
@@ -147,10 +147,7 @@ void Bus::occupyBus(PacketPtr pkt)
 
     // The first word will be delivered after the current tick, the delivery
     // of the address if any, and one bus cycle to deliver the data
-    pkt->firstWordTime =
-        tickNextIdle +
-        pkt->isRequest() ? clock : 0 +
-        clock;
+    pkt->firstWordTime = tickNextIdle + (pkt->isRequest() ? clock : 0) + clock;
 
     //Advance it numCycles bus cycles.
     //XXX Should this use the repeated addition trick as well?
@@ -172,83 +169,104 @@ 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\n",
-            pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
+    short src = pkt->getSrc();
 
-    BusPort *pktPort;
-    if (pkt->getSrc() == defaultId)
-        pktPort = defaultPort;
-    else pktPort = interfaces[pkt->getSrc()];
+    BusPort *src_port;
+    if (src == defaultId)
+        src_port = defaultPort;
+    else {
+        src_port = checkBusCache(src);
+        if (src_port == NULL) {
+            src_port = interfaces[src];
+            updateBusCache(src, src_port);
+        }
+    }
 
     // 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())))
+    if (!pkt->isExpressSnoop() &&
+        (tickNextIdle > curTick ||
+         (retryList.size() && (!inRetry || src_port != retryList.front()))))
     {
-        addToRetryList(pktPort);
-        DPRINTF(Bus, "recvTiming: Bus is busy, returning false\n");
+        addToRetryList(src_port);
+        DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x BUSY\n",
+                src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
         return false;
     }
 
+    DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x\n",
+            src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
+
+    if (!pkt->isExpressSnoop()) {
+        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());
-        timingSnoop(pkt, port ? port : interfaces[pkt->getSrc()]);
-
-        if (pkt->memInhibitAsserted()) {
-            //Cache-Cache transfer occuring
-            if (inRetry) {
-                retryList.front()->onRetryList(false);
-                retryList.pop_front();
-                inRetry = false;
+        dest_port_id = findPort(pkt->getAddr());
+        dest_port = (dest_port_id == defaultId) ?
+            defaultPort : interfaces[dest_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 != dest_port && p != src_port) {
+                // cache is not allowed to refuse snoop
+                bool success M5_VAR_USED = p->sendTiming(pkt);
+                assert(success);
             }
-            occupyBus(pkt);
-            DPRINTF(Bus, "recvTiming: Packet sucessfully sent\n");
-            return true;
         }
     } else {
         assert(dest >= 0 && dest < maxId);
-        assert(dest != pkt->getSrc()); // catch infinite loops
-        port = interfaces[dest];
-    }
-
-    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;
+        assert(dest != src); // catch infinite loops
+        dest_port_id = dest;
+        if (dest_port_id == defaultId)
+            dest_port = defaultPort;
+        else {
+            dest_port = checkBusCache(dest);
+            if (dest_port == NULL) {
+                dest_port = interfaces[dest_port_id];
+            // updateBusCache(dest_port_id, dest_port);
             }
-            return true;
         }
+        dest_port = (dest_port_id == defaultId) ?
+            defaultPort : interfaces[dest_port_id];
+    }
 
-        // 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;
+    if (dest_port_id == src) {
+        // Must be forwarded snoop up from below...
+        assert(dest == Packet::Broadcast);
+        assert(src != defaultId); // catch infinite loops
+    } 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, "recvTiming: src %d dst %d %s 0x%x TGT RETRY\n",
+                    src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
+            addToRetryList(src_port);
+            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
 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();
@@ -280,23 +298,27 @@ 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;
 
-    PortIter i = portMap.find(RangeSize(addr,1));
-    if (i != portMap.end())
-        dest_id = i->second;
+    dest_id = checkPortCache(addr);
+    if (dest_id == -1) {
+        PortIter i = portMap.find(RangeSize(addr,1));
+        if (i != portMap.end())
+          dest_id = i->second;
+        updatePortCache(dest_id, i->first.start, i->first.end);
+    }
 
     // Check if this matches the default range
     if (dest_id == -1) {
-        for (AddrRangeIter iter = defaultRange.begin();
-             iter != defaultRange.end(); iter++) {
-            if (*iter == addr) {
+        AddrRangeIter a_end = defaultRange.end();
+        for (AddrRangeIter i = defaultRange.begin(); i != a_end; i++) {
+            if (*i == addr) {
                 DPRINTF(Bus, "  found addr %#llx on default\n", addr);
-                return defaultPort;
+                return defaultId;
             }
         }
 
@@ -307,58 +329,11 @@ Bus::findPort(Addr addr, int id)
             DPRINTF(Bus, "Unable to find destination for addr: %#llx, will use "
                     "default port", addr);
 
-            return defaultPort;
-        }
-    }
-
-
-    // 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];
-}
-
-void
-Bus::functionalSnoop(PacketPtr pkt, Port *responder)
-{
-    // 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) {
-            p->sendFunctional(pkt);
-        }
-        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 defaultId;
         }
     }
 
-    return true;
+    return dest_id;
 }
 
 
@@ -381,7 +356,17 @@ Bus::recvAtomic(PacketPtr pkt)
     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());
+    BusPort *target_port;
+    if (target_port_id == defaultId)
+        target_port = defaultPort;
+    else {
+      target_port = checkBusCache(target_port_id);
+      if (target_port == NULL) {
+          target_port = interfaces[target_port_id];
+          updateBusCache(target_port_id, target_port);
+      }
+    }
 
     SnoopIter s_end = snoopPorts.end();
     for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
@@ -407,7 +392,13 @@ Bus::recvAtomic(PacketPtr pkt)
         }
     }
 
-    Tick response_latency = 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 (snoop_response_cmd != MemCmd::InvalidCmd) {
@@ -428,15 +419,37 @@ Bus::recvAtomic(PacketPtr pkt)
 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());
+    if (!pkt->isPrint()) {
+        // don't do DPRINTFs on PrintReq as it clutters up the output
+        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);
 
-    Port* port = findPort(pkt->getAddr(), pkt->getSrc());
-    functionalSnoop(pkt, port ? port : interfaces[pkt->getSrc()]);
+    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
+
+    SnoopIter s_end = snoopPorts.end();
+    for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
+        BusPort *p = *s_iter;
+        if (p != port && p->getId() != src_id) {
+            p->sendFunctional(pkt);
+        }
+        if (pkt->isResponse()) {
+            break;
+        }
+        pkt->setSrc(src_id);
+    }
 
     // If the snooping hasn't found what we were looking for, keep going.
-    if (!pkt->isResponse() && port) {
+    if (!pkt->isResponse() && port_id != pkt->getSrc()) {
         port->sendFunctional(pkt);
     }
 }
@@ -449,11 +462,16 @@ Bus::recvStatusChange(Port::Status status, int id)
     bool snoops;
     AddrRangeIter iter;
 
+    if (inRecvStatusChange.count(id))
+        return;
+    inRecvStatusChange.insert(id);
+
     assert(status == Port::RangeChange &&
            "The other statuses need to be implemented.");
 
     DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id);
 
+    clearPortCache();
     if (id == defaultId) {
         defaultRange.clear();
         // Only try to update these ranges if the user set a default responder.
@@ -515,6 +533,7 @@ Bus::recvStatusChange(Port::Status status, int id)
 
     if (id != defaultId && defaultPort)
         defaultPort->sendStatusChange(Port::RangeChange);
+    inRecvStatusChange.erase(id);
 }
 
 void
@@ -573,14 +592,14 @@ Bus::findBlockSize(int id)
 
     int max_bs = -1;
 
-    for (PortIter portIter = portMap.begin();
-         portIter != portMap.end(); portIter++) {
-        int tmp_bs = interfaces[portIter->second]->peerBlockSize();
+    PortIter p_end = portMap.end();
+    for (PortIter p_iter = portMap.begin(); p_iter != p_end; p_iter++) {
+        int tmp_bs = interfaces[p_iter->second]->peerBlockSize();
         if (tmp_bs > max_bs)
             max_bs = tmp_bs;
     }
-    for (SnoopIter s_iter = snoopPorts.begin();
-         s_iter != snoopPorts.end(); s_iter++) {
+    SnoopIter s_end = snoopPorts.end();
+    for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
         int tmp_bs = (*s_iter)->peerBlockSize();
         if (tmp_bs > max_bs)
             max_bs = tmp_bs;
@@ -602,12 +621,11 @@ Bus::drain(Event * de)
     //We should check that we're not "doing" anything, and that noone is
     //waiting. We might be idle but have someone waiting if the device we
     //contacted for a retry didn't actually retry.
-    if (curTick >= tickNextIdle && retryList.size() == 0) {
-        return 0;
-    } else {
+    if (retryList.size() || (curTick < tickNextIdle && busIdle.scheduled())) {
         drainEvent = de;
         return 1;
     }
+    return 0;
 }
 
 void
@@ -617,28 +635,8 @@ Bus::startup()
         tickNextIdle = (curTick / clock) * clock + clock;
 }
 
-BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus)
-
-    Param<int> bus_id;
-    Param<int> clock;
-    Param<int> width;
-    Param<bool> responder_set;
-    Param<int> block_size;
-
-END_DECLARE_SIM_OBJECT_PARAMS(Bus)
-
-BEGIN_INIT_SIM_OBJECT_PARAMS(Bus)
-    INIT_PARAM(bus_id, "a globally unique bus id"),
-    INIT_PARAM(clock, "bus clock speed"),
-    INIT_PARAM(width, "width of the bus (bits)"),
-    INIT_PARAM(responder_set, "Is a default responder set by the user"),
-    INIT_PARAM(block_size, "Default blocksize if no device has one")
-END_INIT_SIM_OBJECT_PARAMS(Bus)
-
-CREATE_SIM_OBJECT(Bus)
+Bus *
+BusParams::create()
 {
-    return new Bus(getInstanceName(), bus_id, clock, width, responder_set,
-            block_size);
+    return new Bus(this);
 }
-
-REGISTER_SIM_OBJECT("Bus", Bus)