ruby: Added merge GETS optimization to hammer
[gem5.git] / src / mem / bridge.cc
index eebf91a859edd4573c5726d7c8400fad637cb58b..d0135fc9d107e55e4fbf5a2414f1bd69936adbca 100644 (file)
 
 #include <algorithm>
 
+#include "base/range_ops.hh"
 #include "base/trace.hh"
 #include "mem/bridge.hh"
-#include "sim/builder.hh"
+#include "params/Bridge.hh"
 
 Bridge::BridgePort::BridgePort(const std::string &_name,
                                Bridge *_bridge, BridgePort *_otherPort,
                                int _delay, int _nack_delay, int _req_limit,
-                               int _resp_limit, bool fix_partial_write)
-    : Port(_name), bridge(_bridge), otherPort(_otherPort),
-      delay(_delay), nackDelay(_nack_delay), fixPartialWrite(fix_partial_write),
+                               int _resp_limit,
+                               std::vector<Range<Addr> > filter_ranges)
+    : Port(_name, _bridge), bridge(_bridge), otherPort(_otherPort),
+      delay(_delay), nackDelay(_nack_delay), filterRanges(filter_ranges),
       outstandingResponses(0), queuedRequests(0), inRetry(false),
       reqQueueLimit(_req_limit), respQueueLimit(_resp_limit), sendEvent(this)
 {
 }
 
 Bridge::Bridge(Params *p)
-    : MemObject(p->name),
+    : MemObject(p),
       portA(p->name + "-portA", this, &portB, p->delay, p->nack_delay,
-              p->req_size_a, p->resp_size_a, p->fix_partial_write_a),
+              p->req_size_a, p->resp_size_a, p->filter_ranges_a),
       portB(p->name + "-portB", this, &portA, p->delay, p->nack_delay,
-              p->req_size_b, p->resp_size_b, p->fix_partial_write_b),
+              p->req_size_b, p->resp_size_b, p->filter_ranges_b),
       ackWrites(p->write_ack), _params(p)
 {
     if (ackWrites)
@@ -76,8 +78,9 @@ Bridge::getPort(const std::string &if_name, int idx)
     else
         return NULL;
 
-    if (port->getPeer() != NULL)
-        panic("bridge side %s already connected to.", if_name);
+    if (port->getPeer() != NULL && !port->getPeer()->isDefaultPort())
+        panic("bridge side %s already connected to %s.",
+                if_name, port->getPeer()->name());
     return port;
 }
 
@@ -86,11 +89,13 @@ void
 Bridge::init()
 {
     // Make sure that both sides are connected to.
-    if (portA.getPeer() == NULL || portB.getPeer() == NULL)
+    if (!portA.isConnected() || !portB.isConnected())
         fatal("Both ports of bus bridge are not connected to a bus.\n");
 
     if (portA.peerBlockSize() != portB.peerBlockSize())
-        fatal("Busses don't have the same block size... Not supported.\n");
+        fatal("port A size %d, port B size %d \n " \
+              "Busses don't have the same block size... Not supported.\n",
+              portA.peerBlockSize(), portB.peerBlockSize());
 }
 
 bool
@@ -117,18 +122,17 @@ Bridge::BridgePort::recvTiming(PacketPtr pkt)
 
     DPRINTF(BusBridge, "Local queue size: %d outreq: %d outresp: %d\n",
                     sendQueue.size(), queuedRequests, outstandingResponses);
-    DPRINTF(BusBridge, "Remove queue size: %d outreq: %d outresp: %d\n",
+    DPRINTF(BusBridge, "Remote queue size: %d outreq: %d outresp: %d\n",
                     otherPort->sendQueue.size(), otherPort->queuedRequests,
                     otherPort->outstandingResponses);
 
-    if (pkt->isRequest() && otherPort->reqQueueFull() && pkt->result !=
-            Packet::Nacked) {
+    if (pkt->isRequest() && otherPort->reqQueueFull()) {
         DPRINTF(BusBridge, "Remote queue full, nacking\n");
         nackRequest(pkt);
         return true;
     }
 
-    if (pkt->needsResponse() && pkt->result != Packet::Nacked)
+    if (pkt->needsResponse()) {
         if (respQueueFull()) {
             DPRINTF(BusBridge, "Local queue full, no space for response, nacking\n");
             DPRINTF(BusBridge, "queue size: %d outreq: %d outstanding resp: %d\n",
@@ -139,6 +143,7 @@ Bridge::BridgePort::recvTiming(PacketPtr pkt)
             DPRINTF(BusBridge, "Request Needs response, reserving space\n");
             ++outstandingResponses;
         }
+    }
 
     otherPort->queueForSendTiming(pkt);
 
@@ -149,8 +154,8 @@ void
 Bridge::BridgePort::nackRequest(PacketPtr pkt)
 {
     // Nack the packet
-    pkt->result = Packet::Nacked;
-    pkt->setDest(pkt->getSrc());
+    pkt->makeTimingResponse();
+    pkt->setNacked();
 
     //put it on the list to send
     Tick readyTime = curTick + nackDelay;
@@ -159,7 +164,7 @@ Bridge::BridgePort::nackRequest(PacketPtr pkt)
     // nothing on the list, add it and we're done
     if (sendQueue.empty()) {
         assert(!sendEvent.scheduled());
-        sendEvent.schedule(readyTime);
+        schedule(sendEvent, readyTime);
         sendQueue.push_back(buf);
         return;
     }
@@ -181,7 +186,7 @@ Bridge::BridgePort::nackRequest(PacketPtr pkt)
     while (i != end && !done) {
         if (readyTime < (*i)->ready) {
             if (i == begin)
-                sendEvent.reschedule(readyTime);
+                reschedule(sendEvent, readyTime);
             sendQueue.insert(i,buf);
             done = true;
         }
@@ -194,30 +199,23 @@ Bridge::BridgePort::nackRequest(PacketPtr pkt)
 void
 Bridge::BridgePort::queueForSendTiming(PacketPtr pkt)
 {
-    if (pkt->isResponse() || pkt->result == Packet::Nacked) {
+    if (pkt->isResponse()) {
         // This is a response for a request we forwarded earlier.  The
         // corresponding PacketBuffer should be stored in the packet's
         // senderState field.
+
         PacketBuffer *buf = dynamic_cast<PacketBuffer*>(pkt->senderState);
         assert(buf != NULL);
         // set up new packet dest & senderState based on values saved
         // from original request
         buf->fixResponse(pkt);
 
-        // Check if this packet was expecting a response and it's a nacked
-        // packet, in which case we will never being seeing it
-        if (buf->expectResponse && pkt->result == Packet::Nacked)
-            --outstandingResponses;
-
-
-        DPRINTF(BusBridge, "restoring  sender state: %#X, from packet buffer: %#X\n",
-                        pkt->senderState, buf);
-        DPRINTF(BusBridge, "  is response, new dest %d\n", pkt->getDest());
+        DPRINTF(BusBridge, "response, new dest %d\n", pkt->getDest());
         delete buf;
     }
 
 
-    if (pkt->isRequest() && pkt->result != Packet::Nacked) {
+    if (pkt->isRequest()) {
         ++queuedRequests;
     }
 
@@ -225,15 +223,13 @@ Bridge::BridgePort::queueForSendTiming(PacketPtr pkt)
 
     Tick readyTime = curTick + delay;
     PacketBuffer *buf = new PacketBuffer(pkt, readyTime);
-    DPRINTF(BusBridge, "old sender state: %#X, new sender state: %#X\n",
-            buf->origSenderState, buf);
 
     // If we're about to put this packet at the head of the queue, we
     // need to schedule an event to do the transmit.  Otherwise there
     // should already be an event scheduled for sending the head
     // packet.
     if (sendQueue.empty()) {
-        sendEvent.schedule(readyTime);
+        schedule(sendEvent, readyTime);
     }
     sendQueue.push_back(buf);
 }
@@ -249,22 +245,19 @@ Bridge::BridgePort::trySend()
 
     PacketPtr pkt = buf->pkt;
 
-    // Ugly! @todo When multilevel coherence works this will be removed
-    if (pkt->cmd == MemCmd::WriteInvalidateReq && fixPartialWrite &&
-            pkt->result != Packet::Nacked) {
-        PacketPtr funcPkt = new Packet(pkt->req, MemCmd::WriteReq,
-                            Packet::Broadcast);
-        funcPkt->dataStatic(pkt->getPtr<uint8_t>());
-        sendFunctional(funcPkt);
-        pkt->cmd = MemCmd::WriteReq;
-        delete funcPkt;
-    }
-
     DPRINTF(BusBridge, "trySend: origSrc %d dest %d addr 0x%x\n",
             buf->origSrc, pkt->getDest(), pkt->getAddr());
 
     bool wasReq = pkt->isRequest();
-    bool wasNacked = pkt->result == Packet::Nacked;
+    bool was_nacked_here = buf->nackedHere;
+
+    // If the send was successful, make sure sender state was set to NULL
+    // otherwise we could get a NACK back of a packet that didn't expect a
+    // response and we would try to use freed memory.
+
+    Packet::SenderState *old_sender_state = pkt->senderState;
+    if (pkt->isRequest() && !buf->expectResponse)
+        pkt->senderState = NULL;
 
     if (sendTiming(pkt)) {
         // send successful
@@ -281,23 +274,23 @@ Bridge::BridgePort::trySend()
             delete buf;
         }
 
-        if (!wasNacked) {
-            if (wasReq)
-                --queuedRequests;
-            else
-                --outstandingResponses;
-        }
+        if (wasReq)
+            --queuedRequests;
+        else if (!was_nacked_here)
+            --outstandingResponses;
 
         // If there are more packets to send, schedule event to try again.
         if (!sendQueue.empty()) {
             buf = sendQueue.front();
             DPRINTF(BusBridge, "Scheduling next send\n");
-            sendEvent.schedule(std::max(buf->ready, curTick + 1));
+            schedule(sendEvent, std::max(buf->ready, curTick + 1));
         }
     } else {
         DPRINTF(BusBridge, "  unsuccessful\n");
+        pkt->senderState = old_sender_state;
         inRetry = true;
     }
+
     DPRINTF(BusBridge, "trySend: queue size: %d outreq: %d outstanding resp: %d\n",
                     sendQueue.size(), queuedRequests, outstandingResponses);
 }
@@ -311,7 +304,7 @@ Bridge::BridgePort::recvRetry()
     if (nextReady <= curTick)
         trySend();
     else
-        sendEvent.schedule(nextReady);
+        schedule(sendEvent, nextReady);
 }
 
 /** Function called by the port when the bus is receiving a Atomic
@@ -319,17 +312,6 @@ Bridge::BridgePort::recvRetry()
 Tick
 Bridge::BridgePort::recvAtomic(PacketPtr pkt)
 {
-    // fix partial atomic writes... similar to the timing code that does the
-    // same... will be removed once our code gets this right
-    if (pkt->cmd == MemCmd::WriteInvalidateReq && fixPartialWrite) {
-
-        PacketPtr funcPkt = new Packet(pkt->req, MemCmd::WriteReq,
-                         Packet::Broadcast);
-        funcPkt->dataStatic(pkt->getPtr<uint8_t>());
-        otherPort->sendFunctional(funcPkt);
-        delete funcPkt;
-        pkt->cmd = MemCmd::WriteReq;
-    }
     return delay + otherPort->sendAtomic(pkt);
 }
 
@@ -339,17 +321,18 @@ void
 Bridge::BridgePort::recvFunctional(PacketPtr pkt)
 {
     std::list<PacketBuffer*>::iterator i;
-    bool pktContinue = true;
+
+    pkt->pushLabel(name());
 
     for (i = sendQueue.begin();  i != sendQueue.end(); ++i) {
-        if (pkt->intersect((*i)->pkt)) {
-            pktContinue &= fixPacket(pkt, (*i)->pkt);
-        }
+        if (pkt->checkFunctional((*i)->pkt))
+            return;
     }
 
-    if (pktContinue) {
-        otherPort->sendFunctional(pkt);
-    }
+    pkt->popLabel();
+
+    // fall through if pkt still not satisfied
+    otherPort->sendFunctional(pkt);
 }
 
 /** Function called by the port when the bus is receiving a status change.*/
@@ -364,52 +347,13 @@ Bridge::BridgePort::getDeviceAddressRanges(AddrRangeList &resp,
                                            bool &snoop)
 {
     otherPort->getPeerAddressRanges(resp, snoop);
+    FilterRangeList(filterRanges, resp);
+    // we don't allow snooping across bridges
+    snoop = false;
 }
 
-BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bridge)
-
-   Param<int> req_size_a;
-   Param<int> req_size_b;
-   Param<int> resp_size_a;
-   Param<int> resp_size_b;
-   Param<Tick> delay;
-   Param<Tick> nack_delay;
-   Param<bool> write_ack;
-   Param<bool> fix_partial_write_a;
-   Param<bool> fix_partial_write_b;
-
-END_DECLARE_SIM_OBJECT_PARAMS(Bridge)
-
-BEGIN_INIT_SIM_OBJECT_PARAMS(Bridge)
-
-    INIT_PARAM(req_size_a, "The size of the queue for requests coming into side a"),
-    INIT_PARAM(req_size_b, "The size of the queue for requests coming into side b"),
-    INIT_PARAM(resp_size_a, "The size of the queue for responses coming into side a"),
-    INIT_PARAM(resp_size_b, "The size of the queue for responses coming into side b"),
-    INIT_PARAM(delay, "The miminum delay to cross this bridge"),
-    INIT_PARAM(nack_delay, "The minimum delay to nack a packet"),
-    INIT_PARAM(write_ack, "Acknowledge any writes that are received."),
-    INIT_PARAM(fix_partial_write_a, "Fixup any partial block writes that are received"),
-    INIT_PARAM(fix_partial_write_b, "Fixup any partial block writes that are received")
-
-END_INIT_SIM_OBJECT_PARAMS(Bridge)
-
-CREATE_SIM_OBJECT(Bridge)
+Bridge *
+BridgeParams::create()
 {
-    Bridge::Params *p = new Bridge::Params;
-    p->name = getInstanceName();
-    p->req_size_a = req_size_a;
-    p->req_size_b = req_size_b;
-    p->resp_size_a = resp_size_a;
-    p->resp_size_b = resp_size_b;
-    p->delay = delay;
-    p->nack_delay = nack_delay;
-    p->write_ack = write_ack;
-    p->fix_partial_write_a = fix_partial_write_a;
-    p->fix_partial_write_b = fix_partial_write_b;
-    return new Bridge(p);
+    return new Bridge(this);
 }
-
-REGISTER_SIM_OBJECT("Bridge", Bridge)
-
-