MEM: Separate snoops and normal memory requests/responses
authorAndreas Hansson <andreas.hansson@arm.com>
Sat, 14 Apr 2012 09:45:07 +0000 (05:45 -0400)
committerAndreas Hansson <andreas.hansson@arm.com>
Sat, 14 Apr 2012 09:45:07 +0000 (05:45 -0400)
This patch introduces port access methods that separates snoop
request/responses from normal memory request/responses. The
differentiation is made for functional, atomic and timing accesses and
builds on the introduction of master and slave ports.

Before the introduction of this patch, the packets belonging to the
different phases of the protocol (request -> [forwarded snoop request
-> snoop response]* -> response) all use the same port access
functions, even though the snoop packets flow in the opposite
direction to the normal packet. That is, a coherent master sends
normal request and receives responses, but receives snoop requests and
sends snoop responses (vice versa for the slave). These two distinct
phases now use different access functions, as described below.

Starting with the functional access, a master sends a request to a
slave through sendFunctional, and the request packet is turned into a
response before the call returns. In a system without cache coherence,
this is all that is needed from the functional interface. For the
cache-coherent scenario, a slave also sends snoop requests to coherent
masters through sendFunctionalSnoop, with responses returned within
the same packet pointer. This is currently used by the bus and caches,
and the LSQ of the O3 CPU. The send/recvFunctional and
send/recvFunctionalSnoop are moved from the Port super class to the
appropriate subclass.

Atomic accesses follow the same flow as functional accesses, with
request being sent from master to slave through sendAtomic. In the
case of cache-coherent ports, a slave can send snoop requests to a
master through sendAtomicSnoop. Just as for the functional access
methods, the atomic send and receive member functions are moved to the
appropriate subclasses.

The timing access methods are different from the functional and atomic
in that requests and responses are separated in time and
send/recvTiming are used for both directions. Hence, a master uses
sendTiming to send a request to a slave, and a slave uses sendTiming
to send a response back to a master, at a later point in time. Snoop
requests and responses travel in the opposite direction, similar to
what happens in functional and atomic accesses. With the introduction
of this patch, it is possible to determine the direction of packets in
the bus, and no longer necessary to look for both a master and a slave
port with the requested port id.

In contrast to the normal recvFunctional, recvAtomic and recvTiming
that are pure virtual functions, the recvFunctionalSnoop,
recvAtomicSnoop and recvTimingSnoop have a default implementation that
calls panic. This is to allow non-coherent master and slave ports to
not implement these functions.

39 files changed:
src/arch/x86/pagetable_walker.cc
src/arch/x86/pagetable_walker.hh
src/cpu/base.cc
src/cpu/base.hh
src/cpu/inorder/cpu.cc
src/cpu/inorder/cpu.hh
src/cpu/o3/cpu.cc
src/cpu/o3/cpu.hh
src/cpu/o3/lsq.hh
src/cpu/o3/lsq_impl.hh
src/cpu/simple/atomic.hh
src/cpu/simple/timing.cc
src/cpu/simple/timing.hh
src/cpu/testers/directedtest/RubyDirectedTester.cc
src/cpu/testers/directedtest/RubyDirectedTester.hh
src/cpu/testers/memtest/memtest.cc
src/cpu/testers/memtest/memtest.hh
src/cpu/testers/networktest/networktest.cc
src/cpu/testers/networktest/networktest.hh
src/cpu/testers/rubytest/RubyTester.cc
src/cpu/testers/rubytest/RubyTester.hh
src/dev/io_device.cc
src/dev/io_device.hh
src/mem/bridge.cc
src/mem/bridge.hh
src/mem/bus.cc
src/mem/bus.hh
src/mem/cache/base.hh
src/mem/cache/cache.hh
src/mem/cache/cache_impl.hh
src/mem/mport.cc
src/mem/mport.hh
src/mem/packet_queue.cc
src/mem/packet_queue.hh
src/mem/port.cc
src/mem/port.hh
src/mem/ruby/system/RubyPort.cc
src/mem/ruby/system/RubyPort.hh
src/sim/system.hh

index 87505f4df4e1ecb1ef0b5ee5622b3bde9e141751..c07af0c83437d3de60f58af45d69dbc56db626de 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2012 ARM Limited
+ * All rights reserved.
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 2007 The Hewlett-Packard Development Company
  * All rights reserved.
  *
@@ -110,49 +122,34 @@ Walker::WalkerPort::recvTiming(PacketPtr pkt)
 bool
 Walker::recvTiming(PacketPtr pkt)
 {
-    if (pkt->isResponse() || pkt->wasNacked()) {
-        WalkerSenderState * senderState =
-                dynamic_cast<WalkerSenderState *>(pkt->senderState);
-        pkt->senderState = senderState->saved;
-        WalkerState * senderWalk = senderState->senderWalk;
-        bool walkComplete = senderWalk->recvPacket(pkt);
-        delete senderState;
-        if (walkComplete) {
-            std::list<WalkerState *>::iterator iter;
-            for (iter = currStates.begin(); iter != currStates.end(); iter++) {
-                WalkerState * walkerState = *(iter);
-                if (walkerState == senderWalk) {
-                    iter = currStates.erase(iter);
-                    break;
-                }
-            }
-            delete senderWalk;
-            // Since we block requests when another is outstanding, we
-            // need to check if there is a waiting request to be serviced
-            if (currStates.size()) {
-                WalkerState * newState = currStates.front();
-                if (!newState->wasStarted())
-                    newState->startWalk();
+    assert(pkt->isResponse());
+    WalkerSenderState * senderState =
+        dynamic_cast<WalkerSenderState *>(pkt->senderState);
+    pkt->senderState = senderState->saved;
+    WalkerState * senderWalk = senderState->senderWalk;
+    bool walkComplete = senderWalk->recvPacket(pkt);
+    delete senderState;
+    if (walkComplete) {
+        std::list<WalkerState *>::iterator iter;
+        for (iter = currStates.begin(); iter != currStates.end(); iter++) {
+            WalkerState * walkerState = *(iter);
+            if (walkerState == senderWalk) {
+                iter = currStates.erase(iter);
+                break;
             }
         }
-    } else {
-        DPRINTF(PageTableWalker, "Received strange packet\n");
+        delete senderWalk;
+        // Since we block requests when another is outstanding, we
+        // need to check if there is a waiting request to be serviced
+        if (currStates.size()) {
+            WalkerState * newState = currStates.front();
+            if (!newState->wasStarted())
+                newState->startWalk();
+        }
     }
     return true;
 }
 
-Tick
-Walker::WalkerPort::recvAtomic(PacketPtr pkt)
-{
-    return 0;
-}
-
-void
-Walker::WalkerPort::recvFunctional(PacketPtr pkt)
-{
-    return;
-}
-
 void
 Walker::WalkerPort::recvRetry()
 {
@@ -572,7 +569,8 @@ Walker::WalkerState::setupWalk(Addr vaddr)
 bool
 Walker::WalkerState::recvPacket(PacketPtr pkt)
 {
-    if (pkt->isResponse() && !pkt->wasNacked()) {
+    assert(pkt->isResponse());
+    if (!pkt->wasNacked()) {
         assert(inflight);
         assert(state == Waiting);
         assert(!read);
@@ -615,7 +613,7 @@ Walker::WalkerState::recvPacket(PacketPtr pkt)
             }
             return true;
         }
-    } else if (pkt->wasNacked()) {
+    } else {
         DPRINTF(PageTableWalker, "Request was nacked. Entering retry state\n");
         pkt->reinitNacked();
         if (!walker->sendTiming(this, pkt)) {
index bf7a9e6150d8a06628ff459ba8594be38490fb9b..3cc20b6cdc0623987b0640075ffcbd9e73997af0 100644 (file)
@@ -71,8 +71,13 @@ namespace X86ISA
             Walker *walker;
 
             bool recvTiming(PacketPtr pkt);
-            Tick recvAtomic(PacketPtr pkt);
-            void recvFunctional(PacketPtr pkt);
+
+            /**
+             * Snooping a coherence request, do nothing.
+             */
+            bool recvTimingSnoop(PacketPtr pkt) { return true; }
+            Tick recvAtomicSnoop(PacketPtr pkt) { return 0; }
+            void recvFunctionalSnoop(PacketPtr pkt) { }
             void recvRetry();
             bool isSnooping() const { return true; }
         };
index d01dcbef3982dcd0346ad54eac74744a161eaa86..edbec8c80d1b93e7d820703dbf37d6c17404eb53 100644 (file)
@@ -534,27 +534,20 @@ BaseCPU::traceFunctionsInternal(Addr pc)
 bool
 BaseCPU::CpuPort::recvTiming(PacketPtr pkt)
 {
-    panic("BaseCPU doesn't expect recvTiming callback!");
+    panic("BaseCPU doesn't expect recvTiming!\n");
     return true;
 }
 
 void
 BaseCPU::CpuPort::recvRetry()
 {
-    panic("BaseCPU doesn't expect recvRetry callback!");
-}
-
-Tick
-BaseCPU::CpuPort::recvAtomic(PacketPtr pkt)
-{
-    panic("BaseCPU doesn't expect recvAtomic callback!");
-    return curTick();
+    panic("BaseCPU doesn't expect recvRetry!\n");
 }
 
 void
-BaseCPU::CpuPort::recvFunctional(PacketPtr pkt)
+BaseCPU::CpuPort::recvFunctionalSnoop(PacketPtr pkt)
 {
-    // No internal storage to update (in the general case). In the
-    // long term this should never be called, but that assumed a split
-    // into master/slave and request/response.
+    // No internal storage to update (in the general case). A CPU with
+    // internal storage, e.g. an LSQ that should be part of the
+    // coherent memory has to check against stored data.
 }
index 3fb0f648b1585d9c0998e4244addac77038a8c18..f94c5e0a4c13f53cd3c1695ad754606f3ce03822 100644 (file)
@@ -135,11 +135,9 @@ class BaseCPU : public MemObject
 
         virtual bool recvTiming(PacketPtr pkt);
 
-        virtual Tick recvAtomic(PacketPtr pkt);
-
         virtual void recvRetry();
 
-        void recvFunctional(PacketPtr pkt);
+        virtual void recvFunctionalSnoop(PacketPtr pkt);
 
     };
 
index 8dab82d7184bdf02b7847ae9c36c4937ef7deabd..04176c54f9489f16c9c015bf70ee38eb9e3a3f29 100644 (file)
@@ -90,16 +90,13 @@ InOrderCPU::CachePort::CachePort(CacheUnit *_cacheUnit) :
 bool
 InOrderCPU::CachePort::recvTiming(Packet *pkt)
 {
+    assert(pkt->isResponse());
+
     if (pkt->isError())
         DPRINTF(InOrderCachePort, "Got error packet back for address: %x\n",
                 pkt->getAddr());
-    else if (pkt->isResponse())
+    else
         cacheUnit->processCacheCompletion(pkt);
-    else {
-        //@note: depending on consistency model, update here
-        DPRINTF(InOrderCachePort, "Received snoop pkt %x,Ignoring\n",
-                pkt->getAddr());
-    }
 
     return true;
 }
index d8fe5c0573d44f0a8db00362bae2c14db47411cd..06d733d8576050c95dcdfb8e4af11c1a73c9b84f 100644 (file)
@@ -174,6 +174,9 @@ class InOrderCPU : public BaseCPU
 
         /** Handles doing a retry of a failed timing request. */
         void recvRetry();
+
+        /** Ignoring snoops for now. */
+        bool recvTimingSnoop(PacketPtr pkt) { return true; }
     };
 
     /** Define TickEvent for the CPU */
index bfc9438d309a8ff3811867040ce0231ba0d9c1be..fe70c3fcf95227b0248eeae6e2c646757de99758 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 ARM Limited
+ * Copyright (c) 2011-2012 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -89,14 +89,12 @@ template<class Impl>
 bool
 FullO3CPU<Impl>::IcachePort::recvTiming(PacketPtr pkt)
 {
+    assert(pkt->isResponse());
     DPRINTF(O3CPU, "Fetch unit received timing\n");
-    if (pkt->isResponse()) {
-        // We shouldn't ever get a block in ownership state
-        assert(!(pkt->memInhibitAsserted() && !pkt->sharedAsserted()));
+    // We shouldn't ever get a block in ownership state
+    assert(!(pkt->memInhibitAsserted() && !pkt->sharedAsserted()));
+    fetch->processCacheCompletion(pkt);
 
-        fetch->processCacheCompletion(pkt);
-    }
-    //else Snooped a coherence request, just return
     return true;
 }
 
@@ -111,9 +109,18 @@ template <class Impl>
 bool
 FullO3CPU<Impl>::DcachePort::recvTiming(PacketPtr pkt)
 {
+    assert(pkt->isResponse());
     return lsq->recvTiming(pkt);
 }
 
+template <class Impl>
+bool
+FullO3CPU<Impl>::DcachePort::recvTimingSnoop(PacketPtr pkt)
+{
+    assert(pkt->isRequest());
+    return lsq->recvTimingSnoop(pkt);
+}
+
 template <class Impl>
 void
 FullO3CPU<Impl>::DcachePort::recvRetry()
index 4937304587eb93ccc33144ec27798500bdf340d7..be51f415fe2217291d928976bba84b574b4168ad 100644 (file)
@@ -149,6 +149,7 @@ class FullO3CPU : public BaseO3CPU
         /** Timing version of receive.  Handles setting fetch to the
          * proper status to start fetching. */
         virtual bool recvTiming(PacketPtr pkt);
+        virtual bool recvTimingSnoop(PacketPtr pkt) { return true; }
 
         /** Handles doing a retry of a failed fetch. */
         virtual void recvRetry();
@@ -176,6 +177,7 @@ class FullO3CPU : public BaseO3CPU
          * completing the load or store that has returned from
          * memory. */
         virtual bool recvTiming(PacketPtr pkt);
+        virtual bool recvTimingSnoop(PacketPtr pkt);
 
         /** Handles doing a retry of the previous send. */
         virtual void recvRetry();
index b821dd3f9c6fd93b03890a69e35150e6298a9d57..dac5fab187eec7f3630f5cfbd51ba6cb4a99aee6 100644 (file)
@@ -299,6 +299,8 @@ class LSQ {
      */
     bool recvTiming(PacketPtr pkt);
 
+    bool recvTimingSnoop(PacketPtr pkt);
+
     /** The CPU pointer. */
     O3CPU *cpu;
 
index 02758f212350d768b8db949bc37b5caabb4412b0..c2f410e37c4f00a2516da7caad47a4cace1497d5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 ARM Limited
+ * Copyright (c) 2011-2012 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -321,25 +321,32 @@ template <class Impl>
 bool
 LSQ<Impl>::recvTiming(PacketPtr pkt)
 {
+    assert(pkt->isResponse());
     if (pkt->isError())
         DPRINTF(LSQ, "Got error packet back for address: %#X\n",
                 pkt->getAddr());
-    if (pkt->isResponse()) {
-        thread[pkt->req->threadId()].completeDataAccess(pkt);
-    } else {
-        DPRINTF(LSQ, "received pkt for addr:%#x %s\n", pkt->getAddr(),
-                pkt->cmdString());
-
-        // must be a snoop
-        if (pkt->isInvalidate()) {
-            DPRINTF(LSQ, "received invalidation for addr:%#x\n",
-                    pkt->getAddr());
-            for (ThreadID tid = 0; tid < numThreads; tid++) {
-                thread[tid].checkSnoop(pkt);
-            }
+    thread[pkt->req->threadId()].completeDataAccess(pkt);
+    return true;
+}
+
+template <class Impl>
+bool
+LSQ<Impl>::recvTimingSnoop(PacketPtr pkt)
+{
+    assert(pkt->isRequest());
+    DPRINTF(LSQ, "received pkt for addr:%#x %s\n", pkt->getAddr(),
+            pkt->cmdString());
+
+    // must be a snoop
+    if (pkt->isInvalidate()) {
+        DPRINTF(LSQ, "received invalidation for addr:%#x\n",
+                pkt->getAddr());
+        for (ThreadID tid = 0; tid < numThreads; tid++) {
+            thread[tid].checkSnoop(pkt);
         }
-        // to provide stronger consistency model
     }
+
+    // to provide stronger consistency model
     return true;
 }
 
index 3e6238f7decd4453666625696979de3886605caa..e88c93cce4edd9df8af5a9c39784dbdfb3f02ff3 100644 (file)
@@ -91,7 +91,7 @@ class AtomicSimpleCPU : public BaseSimpleCPU
 
       protected:
 
-        virtual Tick recvAtomic(PacketPtr pkt)
+        virtual Tick recvAtomicSnoop(PacketPtr pkt)
         {
             // Snooping a coherence request, just return
             return 0;
index f661756dab4616c8097da2417a4e1c3f83286854..d52003f19fc9e0677401f1bbc1345d54a3a5a0f3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 ARM Limited
+ * Copyright (c) 2010-2012 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -718,7 +718,8 @@ TimingSimpleCPU::IcachePort::ITickEvent::process()
 bool
 TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt)
 {
-    if (pkt->isResponse() && !pkt->wasNacked()) {
+    assert(pkt->isResponse());
+    if (!pkt->wasNacked()) {
         DPRINTF(SimpleCPU, "Received timing response %#x\n", pkt->getAddr());
         // delay processing of returned data until next CPU clock edge
         Tick next_tick = cpu->nextCycle(curTick());
@@ -729,7 +730,7 @@ TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt)
             tickEvent.schedule(pkt, next_tick);
 
         return true;
-    } else if (pkt->wasNacked()) {
+    } else {
         assert(cpu->_status == IcacheWaitResponse);
         pkt->reinitNacked();
         if (!sendTiming(pkt)) {
@@ -737,7 +738,7 @@ TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt)
             cpu->ifetch_pkt = pkt;
         }
     }
-    //Snooping a Coherence Request, do nothing
+
     return true;
 }
 
@@ -838,7 +839,8 @@ TimingSimpleCPU::completeDrain()
 bool
 TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt)
 {
-    if (pkt->isResponse() && !pkt->wasNacked()) {
+    assert(pkt->isResponse());
+    if (!pkt->wasNacked()) {
         // delay processing of returned data until next CPU clock edge
         Tick next_tick = cpu->nextCycle(curTick());
 
@@ -858,8 +860,7 @@ TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt)
         }
 
         return true;
-    }
-    else if (pkt->wasNacked()) {
+    } else  {
         assert(cpu->_status == DcacheWaitResponse);
         pkt->reinitNacked();
         if (!sendTiming(pkt)) {
@@ -867,7 +868,7 @@ TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt)
             cpu->dcache_pkt = pkt;
         }
     }
-    //Snooping a Coherence Request, do nothing
+
     return true;
 }
 
index e0c5c89f79f4c8360fa3da556a7d8895c3add2ec..4c23391d922945366678f18f96b27de7353edebd 100644 (file)
@@ -153,6 +153,11 @@ class TimingSimpleCPU : public BaseSimpleCPU
 
       protected:
 
+        /**
+         * Snooping a coherence request, do nothing.
+         */
+        virtual bool recvTimingSnoop(PacketPtr pkt) { return true; }
+
         TimingSimpleCPU* cpu;
 
         struct TickEvent : public Event
index bfdd28e0893ec44d401acd76e405c63c0f373123..a6dc257d5c251b2d667b2515376a1ee2817ec1f2 100644 (file)
@@ -90,13 +90,6 @@ RubyDirectedTester::getMasterPort(const std::string &if_name, int idx)
     }
 }
 
-Tick
-RubyDirectedTester::CpuPort::recvAtomic(PacketPtr pkt)
-{
-    panic("RubyDirectedTester::CpuPort::recvAtomic() not implemented!\n");
-    return 0;
-}
-
 bool
 RubyDirectedTester::CpuPort::recvTiming(PacketPtr pkt)
 {
index cb207ff8078acf5818db30f1c2703bd2ee8feac5..0965fb7861263da180b2027013edb012ac1e8f64 100644 (file)
@@ -64,8 +64,6 @@ class RubyDirectedTester : public MemObject
         virtual bool recvTiming(PacketPtr pkt);
         virtual void recvRetry()
         { panic("%s does not expect a retry\n", name()); }
-        virtual Tick recvAtomic(PacketPtr pkt);
-        virtual void recvFunctional(PacketPtr pkt) { }
     };
 
     typedef RubyDirectedTesterParams Params;
index 07cdf73a6920a1a1df8da92a55ecbe025d90a683..7e34c2833a49645f9a6fbb011b6587752d743b98 100644 (file)
@@ -55,35 +55,11 @@ int TESTER_ALLOCATOR=0;
 bool
 MemTest::CpuPort::recvTiming(PacketPtr pkt)
 {
-    if (pkt->isResponse()) {
-        memtest->completeRequest(pkt);
-    } else {
-        // must be snoop upcall
-        assert(pkt->isRequest());
-        assert(pkt->getDest() == Packet::Broadcast);
-    }
+    assert(pkt->isResponse());
+    memtest->completeRequest(pkt);
     return true;
 }
 
-Tick
-MemTest::CpuPort::recvAtomic(PacketPtr pkt)
-{
-    // must be snoop upcall
-    assert(pkt->isRequest());
-    assert(pkt->getDest() == Packet::Broadcast);
-    return curTick();
-}
-
-void
-MemTest::CpuPort::recvFunctional(PacketPtr pkt)
-{
-    //Do nothing if we see one come through
-//    if (curTick() != 0)//Supress warning durring initialization
-//        warn("Functional Writes not implemented in MemTester\n");
-    //Need to find any response values that intersect and update
-    return;
-}
-
 void
 MemTest::CpuPort::recvRetry()
 {
index d179fa5302ecf8271ec7ab9a4047a23a2d0e8544..8dccfdc807852bbd3a39670329597c6b106837a3 100644 (file)
@@ -99,9 +99,11 @@ class MemTest : public MemObject
 
         virtual bool recvTiming(PacketPtr pkt);
 
-        virtual Tick recvAtomic(PacketPtr pkt);
+        virtual bool recvTimingSnoop(PacketPtr pkt) { return true; }
 
-        virtual void recvFunctional(PacketPtr pkt);
+        virtual Tick recvAtomicSnoop(PacketPtr pkt) { return 0; }
+
+        virtual void recvFunctionalSnoop(PacketPtr pkt) { }
 
         virtual void recvRetry();
     };
index c4d44b1ab5377f81a5d963e8c74dae4037d8ea8f..45a414539094d9171132a63348ffc91c0895bce6 100644 (file)
@@ -53,34 +53,11 @@ int TESTER_NETWORK=0;
 bool
 NetworkTest::CpuPort::recvTiming(PacketPtr pkt)
 {
-    if (pkt->isResponse()) {
-        networktest->completeRequest(pkt);
-    } else {
-        // must be snoop upcall
-        assert(pkt->isRequest());
-        assert(pkt->getDest() == Packet::Broadcast);
-    }
+    assert(pkt->isResponse());
+    networktest->completeRequest(pkt);
     return true;
 }
 
-Tick
-NetworkTest::CpuPort::recvAtomic(PacketPtr pkt)
-{
-    panic("NetworkTest doesn't expect recvAtomic call!");
-    // Will not be used
-    assert(pkt->isRequest());
-    assert(pkt->getDest() == Packet::Broadcast);
-    return curTick();
-}
-
-void
-NetworkTest::CpuPort::recvFunctional(PacketPtr pkt)
-{
-    panic("NetworkTest doesn't expect recvFunctional call!");
-    // Will not be used
-    return;
-}
-
 void
 NetworkTest::CpuPort::recvRetry()
 {
index 21984f45d05e10b71ba5469e9d379551e9964ba5..36d311aa8f06b2301521a6dc68f2a5cd3de6ce55 100644 (file)
@@ -94,10 +94,6 @@ class NetworkTest : public MemObject
 
         virtual bool recvTiming(PacketPtr pkt);
 
-        virtual Tick recvAtomic(PacketPtr pkt);
-
-        virtual void recvFunctional(PacketPtr pkt);
-
         virtual void recvRetry();
     };
 
index 65716739471322432c989b650ee0655b8523015d..67f4c372a5c96e0886a8ce8e6c6671c2a2957748 100644 (file)
@@ -146,13 +146,6 @@ RubyTester::getMasterPort(const std::string &if_name, int idx)
     }
 }
 
-Tick
-RubyTester::CpuPort::recvAtomic(PacketPtr pkt)
-{
-    panic("RubyTester::CpuPort::recvAtomic() not implemented!\n");
-    return 0;
-}
-
 bool
 RubyTester::CpuPort::recvTiming(PacketPtr pkt)
 {
index 82698f201a803e6040b7f21182ccf61a7af56e7f..aaf609e1eb3cf7388a3e29f1cdf2d877935a9930 100644 (file)
@@ -78,8 +78,6 @@ class RubyTester : public MemObject
         virtual bool recvTiming(PacketPtr pkt);
         virtual void recvRetry()
         { panic("%s does not expect a retry\n", name()); }
-        virtual Tick recvAtomic(PacketPtr pkt);
-        virtual void recvFunctional(PacketPtr pkt) { }
     };
 
     struct SenderState : public Packet::SenderState
index 2937c66b188974d48af45e80afd7e6c44a116190..e1fc28949947007f8d2942e2b5d1d158dda3a889 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2012 ARM Limited
+ * All rights reserved.
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 2006 The Regents of The University of Michigan
  * All rights reserved.
  *
@@ -121,6 +133,7 @@ DmaPort::DmaPort(MemObject *dev, System *s, Tick min_backoff, Tick max_backoff,
 bool
 DmaPort::recvTiming(PacketPtr pkt)
 {
+    assert(pkt->isResponse());
     if (pkt->wasNacked()) {
         DPRINTF(DMA, "Received nacked %s addr %#x\n",
                 pkt->cmdString(), pkt->getAddr());
@@ -136,8 +149,6 @@ DmaPort::recvTiming(PacketPtr pkt)
 
         pkt->reinitNacked();
         queueDma(pkt, true);
-    } else if (pkt->isRequest() && recvSnoops) {
-        return true; 
     } else if (pkt->senderState) {
         DmaReqState *state;
         backoffTime >>= 2;
index 9bb2c3d87253bea7053c9e1a6a773c795f62995b..b113f4379015adbb5d31b4f85a111714c358cce5 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2012 ARM Limited
+ * All rights reserved.
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 2004-2005 The Regents of The University of Michigan
  * All rights reserved.
  *
@@ -135,17 +147,25 @@ class DmaPort : public MasterPort
     bool recvSnoops;
 
     virtual bool recvTiming(PacketPtr pkt);
-    virtual Tick recvAtomic(PacketPtr pkt)
-    {
-        if (recvSnoops) return 0;
 
-        panic("dma port shouldn't be used for pio access."); M5_DUMMY_RETURN
+    virtual bool recvTimingSnoop(PacketPtr pkt)
+    {
+        if (!recvSnoops)
+            panic("%s was not expecting a snoop\n", name());
+        return true;
     }
-    virtual void recvFunctional(PacketPtr pkt)
+
+    virtual Tick recvAtomicSnoop(PacketPtr pkt)
     {
-        if (recvSnoops) return;
+        if (!recvSnoops)
+            panic("%s was not expecting a snoop\n", name());
+        return 0;
+    }
 
-        panic("dma port shouldn't be used for pio access.");
+    virtual void recvFunctionalSnoop(PacketPtr pkt)
+    {
+        if (!recvSnoops)
+            panic("%s was not expecting a snoop\n", name());
     }
 
     virtual void recvRetry() ;
index ebb37e79202475a9cd476c2eb70f6f353283ee6e..4dcb2a537672ca5823d3f01a4dfa4fb08d6d85b9 100644 (file)
@@ -411,31 +411,12 @@ Bridge::BridgeSlavePort::recvRetry()
         bridge->schedule(sendEvent, nextReady);
 }
 
-Tick
-Bridge::BridgeMasterPort::recvAtomic(PacketPtr pkt)
-{
-    // master port should never receive any atomic access (panic only
-    // works once the other side, i.e. the busses, respects this)
-    //
-    //panic("Master port on %s got a recvAtomic\n", bridge->name());
-    return 0;
-}
-
 Tick
 Bridge::BridgeSlavePort::recvAtomic(PacketPtr pkt)
 {
     return delay + masterPort.sendAtomic(pkt);
 }
 
-void
-Bridge::BridgeMasterPort::recvFunctional(PacketPtr pkt)
-{
-    // master port should never receive any functional access (panic
-    // only works once the other side, i.e. the busses, respect this)
-
-    // panic("Master port on %s got a recvFunctional\n", bridge->name());
-}
-
 void
 Bridge::BridgeSlavePort::recvFunctional(PacketPtr pkt)
 {
index e7dbc0a288a9076b34404cd73b788438c8045f82..87b327ca367f2252bf25208cf493f2b7f30dc51c 100644 (file)
@@ -358,14 +358,6 @@ class Bridge : public MemObject
         /** When receiving a retry request from the peer port,
             pass it to the bridge. */
         virtual void recvRetry();
-
-        /** When receiving a Atomic requestfrom the peer port,
-            pass it to the bridge. */
-        virtual Tick recvAtomic(PacketPtr pkt);
-
-        /** When receiving a Functional request from the peer port,
-            pass it to the bridge. */
-        virtual void recvFunctional(PacketPtr pkt);
     };
 
     /** Slave port of the bridge. */
index c89455f02ca39079f85f0fc4a52f32dc8f11327f..eb26e268b6853b12a3498322586be09373b78ffe 100644 (file)
@@ -57,7 +57,6 @@ Bus::Bus(const BusParams *p)
     : MemObject(p), clock(p->clock),
       headerCycles(p->header_cycles), width(p->width), tickNextIdle(0),
       drainEvent(NULL), busIdleEvent(this), inRetry(false),
-      nbrMasterPorts(p->port_master_connection_count),
       defaultPortId(INVALID_PORT_ID), useDefaultRange(p->use_default_range),
       defaultBlockSize(p->block_size),
       cachedBlockSize(0), cachedBlockSizeValid(false)
@@ -71,40 +70,28 @@ Bus::Bus(const BusParams *p)
         fatal("Number of header cycles must be positive\n");
 
     // create the ports based on the size of the master and slave
-    // vector ports, and the presence of the default master
-
-    // id used to index into master and slave ports, that currently
-    // has holes to be able to use the id to index into either
-    int id = 0;
+    // vector ports, and the presence of the default port, the ports
+    // are enumerated starting from zero
     for (int i = 0; i < p->port_master_connection_count; ++i) {
-        std::string portName = csprintf("%s-p%d", name(), id);
-        BusMasterPort* bp = new BusMasterPort(portName, this, id);
+        std::string portName = csprintf("%s-p%d", name(), i);
+        BusMasterPort* bp = new BusMasterPort(portName, this, i);
         masterPorts.push_back(bp);
-        slavePorts.push_back(NULL);
-        ++id;
     }
 
-    // see if we have a default master connected and if so add the
-    // port
+    // see if we have a default slave device connected and if so add
+    // our corresponding master port
     if (p->port_default_connection_count) {
-        defaultPortId = id;
+        defaultPortId = masterPorts.size();
         std::string portName = csprintf("%s-default", name());
-        BusMasterPort* bp = new BusMasterPort(portName, this, id);
+        BusMasterPort* bp = new BusMasterPort(portName, this, defaultPortId);
         masterPorts.push_back(bp);
-        slavePorts.push_back(NULL);
-        ++id;
-        // this is an additional master port
-        ++nbrMasterPorts;
     }
 
-    // note that the first slave port is now stored on index
-    // nbrMasterPorts in the vector
+    // create the slave ports, once again starting at zero
     for (int i = 0; i < p->port_slave_connection_count; ++i) {
-        std::string portName = csprintf("%s-p%d", name(), id);
-        BusSlavePort* bp = new BusSlavePort(portName, this, id);
-        masterPorts.push_back(NULL);
+        std::string portName = csprintf("%s-p%d", name(), i);
+        BusSlavePort* bp = new BusSlavePort(portName, this, i);
         slavePorts.push_back(bp);
-        ++id;
     }
 
     clearPortCache();
@@ -113,9 +100,8 @@ Bus::Bus(const BusParams *p)
 MasterPort &
 Bus::getMasterPort(const std::string &if_name, int idx)
 {
-    if (if_name == "master") {
-        // the master index translates directly to the interfaces
-        // vector as they are stored first
+    if (if_name == "master" && idx < masterPorts.size()) {
+        // the master port index translates directly to the vector position
         return *masterPorts[idx];
     } else  if (if_name == "default") {
         return *masterPorts[defaultPortId];
@@ -127,8 +113,9 @@ Bus::getMasterPort(const std::string &if_name, int idx)
 SlavePort &
 Bus::getSlavePort(const std::string &if_name, int idx)
 {
-    if (if_name == "slave") {
-        return *slavePorts[nbrMasterPorts + idx];
+    if (if_name == "slave" && idx < slavePorts.size()) {
+        // the slave port index translates directly to the vector position
+        return *slavePorts[idx];
     } else {
         return MemObject::getSlavePort(if_name, idx);
     }
@@ -137,19 +124,15 @@ Bus::getSlavePort(const std::string &if_name, int idx)
 void
 Bus::init()
 {
-    std::vector<BusSlavePort*>::iterator intIter;
-
-    // iterate over our interfaces and determine which of our neighbours
-    // are snooping and add them as snoopers
-    for (intIter = slavePorts.begin(); intIter != slavePorts.end();
-         intIter++) {
-        // since there are holes in the vector, check for NULL
-        if (*intIter != NULL) {
-            if ((*intIter)->getMasterPort().isSnooping()) {
-                DPRINTF(BusAddrRanges, "Adding snooping neighbour %s\n",
-                        (*intIter)->getMasterPort().name());
-                snoopPorts.push_back(*intIter);
-            }
+    std::vector<BusSlavePort*>::iterator p;
+
+    // iterate over our slave ports and determine which of our
+    // neighbouring master ports are snooping and add them as snoopers
+    for (p = slavePorts.begin(); p != slavePorts.end(); ++p) {
+        if ((*p)->getMasterPort().isSnooping()) {
+            DPRINTF(BusAddrRanges, "Adding snooping neighbour %s\n",
+                    (*p)->getMasterPort().name());
+            snoopPorts.push_back(*p);
         }
     }
 }
@@ -200,27 +183,36 @@ void Bus::occupyBus(Tick until)
             curTick(), tickNextIdle);
 }
 
-/** Function called by the port when the bus is receiving a Timing
- * transaction.*/
 bool
-Bus::recvTiming(PacketPtr pkt)
+Bus::isOccupied(PacketPtr pkt, Port* port)
 {
-    // called for both requests and responses
+    // first we see if the next idle tick is in the future, next the
+    // bus is considered occupied if there are ports on the retry list
+    // and we are not in a retry with the current port
+    if (tickNextIdle > curTick() ||
+        (!retryList.empty() && !(inRetry && port == retryList.front()))) {
+        addToRetryList(port);
+        return true;
+    }
+    return false;
+}
 
-    // get the source id and port
+bool
+Bus::recvTiming(PacketPtr pkt)
+{
+    // get the source id
     Packet::NodeID src_id = pkt->getSrc();
 
-    // determine the source port based on the id
-    Port *src_port = slavePorts[src_id] ?
-        (Port*) slavePorts[src_id] : (Port*) masterPorts[src_id];
-
-    // If the bus is busy, or other devices are in line ahead of the current
-    // one, put this device on the retry list.
-    if (!pkt->isExpressSnoop() &&
-        (tickNextIdle > curTick() ||
-         (!retryList.empty() && (!inRetry || src_port != retryList.front()))))
-    {
-        addToRetryList(src_port);
+    // determine the source port based on the id and direction
+    Port *src_port = NULL;
+    if (pkt->isRequest())
+        src_port = slavePorts[src_id];
+    else
+        src_port = masterPorts[src_id];
+
+    // test if the bus should be considered occupied for the current
+    // packet, and exclude express snoops from the check
+    if (!pkt->isExpressSnoop() && isOccupied(pkt, src_port)) {
         DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x BUSY\n",
                 src_id, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
         return false;
@@ -232,89 +224,196 @@ Bus::recvTiming(PacketPtr pkt)
     Tick headerFinishTime = pkt->isExpressSnoop() ? 0 : calcPacketTiming(pkt);
     Tick packetFinishTime = pkt->isExpressSnoop() ? 0 : pkt->finishTime;
 
-    Packet::NodeID dest = pkt->getDest();
-    int dest_id;
-    Port *dest_port;
-
+    // decide what to do based on the direction
     if (pkt->isRequest()) {
         // the packet is a memory-mapped request and should be broadcasted to
         // our snoopers
-        assert(dest == Packet::Broadcast);
-
-        SnoopIter s_end = snoopPorts.end();
-        for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
-            BusSlavePort *p = *s_iter;
-            // we got this request from a snooping master
-            // (corresponding to our own slave port that is also in
-            // snoopPorts) and should not send it back to where it
-            // came from
-            if (p->getId() != src_id) {
-                // cache is not allowed to refuse snoop
-                bool success M5_VAR_USED = p->sendTiming(pkt);
-                assert(success);
-            }
+        assert(pkt->getDest() == Packet::Broadcast);
+
+        // forward to all snoopers but the source
+        forwardTiming(pkt, src_id);
+
+        // remember if we add an outstanding req so we can undo it if
+        // necessary, if the packet needs a response, we should add it
+        // as outstanding and express snoops never fail so there is
+        // not need to worry about them
+        bool add_outstanding = !pkt->isExpressSnoop() && pkt->needsResponse();
+
+        // keep track that we have an outstanding request packet
+        // matching this request, this is used by the coherency
+        // mechanism in determining what to do with snoop responses
+        // (in recvTimingSnoop)
+        if (add_outstanding) {
+            // we should never have an exsiting request outstanding
+            assert(outstandingReq.find(pkt->req) == outstandingReq.end());
+            outstandingReq.insert(pkt->req);
         }
 
-        // since it is a request, similar to functional and atomic,
-        // determine the destination based on the address and forward
-        // through the corresponding master port
-        dest_id = findPort(pkt->getAddr());
-        dest_port = masterPorts[dest_id];
-    } else {
-        // the packet is a response, and it should always go back to
-        // the port determined by the destination field
-        dest_id = dest;
-        assert(dest_id != src_id); // catch infinite loops
-        dest_port = slavePorts[dest_id] ?
-            (Port*) slavePorts[dest_id] : (Port*) masterPorts[dest_id];
-
-            // a normal response from the memory system (i.e. from a
-            // connected slave) should always go back to the master
-            // that issued it through one of our slave ports, however
-            // if this is a snoop response it could go either way, for
-            // example, it could be coming from a slave port
-            // connecting an L1 with a coherent master and another L1
-            // coherent master (one of our slave ports), or coming
-            // from the L1 and going to the L2 slave port (through one
-            // of our master ports)
-    }
-
-    assert(dest_port != NULL);
-
-    // if this is a snoop from a slave (corresponding to our own
-    // master), i.e. the memory side of the bus, then do not send it
-    // back to where it came from
-    if (dest_id != src_id) {
-        // 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());
-            // It's also illegal to force a transaction to retry after
-            // someone else has committed to respond.
+        // since it is a normal request, determine the destination
+        // based on the address and attempt to send the packet
+        bool success = masterPorts[findPort(pkt->getAddr())]->sendTiming(pkt);
+
+        if (!success)  {
+            // inhibited packets should never be forced to retry
             assert(!pkt->memInhibitAsserted());
-            DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x TGT RETRY\n",
+
+            // if it was added as outstanding and the send failed, then
+            // erase it again
+            if (add_outstanding)
+                outstandingReq.erase(pkt->req);
+
+            DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x RETRY\n",
                     src_id, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
+
             addToRetryList(src_port);
             occupyBus(headerFinishTime);
+
             return false;
         }
-        // send OK, fall through... pkt may have been deleted by
-        // target at this point, so it should *not* be referenced
-        // again.  We'll set it to NULL here just to be safe.
-        pkt = NULL;
+    } else {
+        // the packet is a normal response to a request that we should
+        // have seen passing through the bus
+        assert(outstandingReq.find(pkt->req) != outstandingReq.end());
+
+        // remove it as outstanding
+        outstandingReq.erase(pkt->req);
+
+        // send the packet to the destination through one of our slave
+        // ports, as determined by the destination field
+        bool success M5_VAR_USED = slavePorts[pkt->getDest()]->sendTiming(pkt);
+
+        // currently it is illegal to block responses... can lead to
+        // deadlock
+        assert(success);
     }
 
-    occupyBus(packetFinishTime);
+    succeededTiming(packetFinishTime);
+
+    return true;
+}
+
+bool
+Bus::recvTimingSnoop(PacketPtr pkt)
+{
+    // get the source id
+    Packet::NodeID src_id = pkt->getSrc();
+
+    if (pkt->isRequest()) {
+        DPRINTF(Bus, "recvTimingSnoop: src %d dst %d %s 0x%x\n",
+                src_id, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
+
+        // the packet is an express snoop request and should be
+        // broadcasted to our snoopers
+        assert(pkt->getDest() == Packet::Broadcast);
+        assert(pkt->isExpressSnoop());
+
+        // forward to all snoopers
+        forwardTiming(pkt, INVALID_PORT_ID);
+
+        // a snoop request came from a connected slave device (one of
+        // our master ports), and if it is not coming from the slave
+        // device responsible for the address range something is
+        // wrong, hence there is nothing further to do as the packet
+        // would be going back to where it came from
+        assert(src_id == findPort(pkt->getAddr()));
+
+        // this is an express snoop and is never forced to retry
+        assert(!inRetry);
+
+        return true;
+    } else {
+        // determine the source port based on the id
+        SlavePort* src_port = slavePorts[src_id];
 
-    // Packet was successfully sent.
-    // Also take care of retries
+        if (isOccupied(pkt, src_port)) {
+            DPRINTF(Bus, "recvTimingSnoop: src %d dst %d %s 0x%x BUSY\n",
+                    src_id, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
+            return false;
+        }
+
+        DPRINTF(Bus, "recvTimingSnoop: src %d dst %d %s 0x%x\n",
+                src_id, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
+
+        // get the destination from the packet
+        Packet::NodeID dest = pkt->getDest();
+
+        // responses are never express snoops
+        assert(!pkt->isExpressSnoop());
+
+        calcPacketTiming(pkt);
+        Tick packetFinishTime = pkt->finishTime;
+
+        // determine if the response is from a snoop request we
+        // created as the result of a normal request (in which case it
+        // should be in the outstandingReq), or if we merely forwarded
+        // someone else's snoop request
+        if (outstandingReq.find(pkt->req) == outstandingReq.end()) {
+            // this is a snoop response to a snoop request we
+            // forwarded, e.g. coming from the L1 and going to the L2
+            // this should be forwarded as a snoop response
+            bool success M5_VAR_USED = masterPorts[dest]->sendTimingSnoop(pkt);
+            assert(success);
+        } else {
+            // we got a snoop response on one of our slave ports,
+            // i.e. from a coherent master connected to the bus, and
+            // since we created the snoop request as part of
+            // recvTiming, this should now be a normal response again
+            outstandingReq.erase(pkt->req);
+
+            // this is a snoop response from a coherent master, with a
+            // destination field set on its way through the bus as
+            // request, hence it should never go back to where the
+            // snoop response came from, but instead to where the
+            // original request came from
+            assert(src_id != dest);
+
+            // as a normal response, it should go back to a master
+            // through one of our slave ports
+            bool success M5_VAR_USED = slavePorts[dest]->sendTiming(pkt);
+
+            // currently it is illegal to block responses... can lead
+            // to deadlock
+            assert(success);
+        }
+
+        succeededTiming(packetFinishTime);
+
+        return true;
+    }
+}
+
+void
+Bus::succeededTiming(Tick busy_time)
+{
+    // occupy the bus accordingly
+    occupyBus(busy_time);
+
+    // if a retrying port succeeded, also take it off the retry list
     if (inRetry) {
-        DPRINTF(Bus, "Remove retry from list %d\n", src_id);
+        DPRINTF(Bus, "Remove retry from list %s\n",
+                retryList.front()->name());
         retryList.pop_front();
         inRetry = false;
     }
-    return true;
+}
+
+void
+Bus::forwardTiming(PacketPtr pkt, int exclude_slave_port_id)
+{
+    SnoopIter s_end = snoopPorts.end();
+    for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
+        BusSlavePort *p = *s_iter;
+        // we could have gotten this request from a snooping master
+        // (corresponding to our own slave port that is also in
+        // snoopPorts) and should not send it back to where it came
+        // from
+        if (exclude_slave_port_id == INVALID_PORT_ID ||
+            p->getId() != exclude_slave_port_id) {
+            // cache is not allowed to refuse snoop
+            bool success M5_VAR_USED = p->sendTimingSnoop(pkt);
+            assert(success);
+        }
+    }
 }
 
 void
@@ -430,9 +529,6 @@ Bus::findPort(Addr addr)
           name());
 }
 
-
-/** Function called by the port when the bus is receiving a Atomic
- * transaction.*/
 Tick
 Bus::recvAtomic(PacketPtr pkt)
 {
@@ -443,12 +539,59 @@ Bus::recvAtomic(PacketPtr pkt)
     assert(pkt->getDest() == Packet::Broadcast);
     assert(pkt->isRequest());
 
-    // the packet may be changed by another bus on snoops, record the
-    // source id here
-    Packet::NodeID src_id = pkt->getSrc();
+    // forward to all snoopers but the source
+    std::pair<MemCmd, Tick> snoop_result = forwardAtomic(pkt, pkt->getSrc());
+    MemCmd snoop_response_cmd = snoop_result.first;
+    Tick snoop_response_latency = snoop_result.second;
 
-    // record the original command to enable us to restore it between
-    // snoops so that additional snoops can take place properly
+    // even if we had a snoop response, we must continue and also
+    // perform the actual request at the destination
+    int dest_id = findPort(pkt->getAddr());
+
+    // forward the request to the appropriate destination
+    Tick response_latency = masterPorts[dest_id]->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());
+        pkt->cmd = snoop_response_cmd;
+        response_latency = snoop_response_latency;
+    }
+
+    pkt->finishTime = curTick() + response_latency;
+    return response_latency;
+}
+
+Tick
+Bus::recvAtomicSnoop(PacketPtr pkt)
+{
+    DPRINTF(Bus, "recvAtomicSnoop: packet src %d dest %d addr 0x%x cmd %s\n",
+            pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
+
+    // we should always see a request routed based on the address
+    assert(pkt->getDest() == Packet::Broadcast);
+    assert(pkt->isRequest());
+
+    // forward to all snoopers
+    std::pair<MemCmd, Tick> snoop_result = forwardAtomic(pkt, INVALID_PORT_ID);
+    MemCmd snoop_response_cmd = snoop_result.first;
+    Tick snoop_response_latency = snoop_result.second;
+
+    if (snoop_response_cmd != MemCmd::InvalidCmd)
+        pkt->cmd = snoop_response_cmd;
+
+    pkt->finishTime = curTick() + snoop_response_latency;
+    return snoop_response_latency;
+}
+
+std::pair<MemCmd, Tick>
+Bus::forwardAtomic(PacketPtr pkt, int exclude_slave_port_id)
+{
+    // the packet may be changed on snoops, record the original source
+    // and command to enable us to restore it between snoops so that
+    // additional snoops can take place properly
+    Packet::NodeID orig_src_id = pkt->getSrc();
     MemCmd orig_cmd = pkt->cmd;
     MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
     Tick snoop_response_latency = 0;
@@ -460,8 +603,9 @@ Bus::recvAtomic(PacketPtr pkt)
         // (corresponding to our own slave port that is also in
         // snoopPorts) and should not send it back to where it came
         // from
-        if (p->getId() != src_id) {
-            Tick latency = p->sendAtomic(pkt);
+        if (exclude_slave_port_id == INVALID_PORT_ID ||
+            p->getId() != exclude_slave_port_id) {
+            Tick latency = p->sendAtomicSnoop(pkt);
             // in contrast to a functional access, we have to keep on
             // going as all snoopers must be updated even if we get a
             // response
@@ -476,48 +620,51 @@ Bus::recvAtomic(PacketPtr pkt)
                 snoop_response_latency = latency;
                 // restore original packet state for remaining snoopers
                 pkt->cmd = orig_cmd;
-                pkt->setSrc(src_id);
+                pkt->setSrc(orig_src_id);
                 pkt->setDest(Packet::Broadcast);
             }
         }
     }
 
-    // even if we had a snoop response, we must continue and also
-    // perform the actual request at the destination
-    int dest_id = findPort(pkt->getAddr());
-
-    Tick response_latency = 0;
+    // the packet is restored as part of the loop and any potential
+    // snoop response is part of the returned pair
+    return std::make_pair(snoop_response_cmd, snoop_response_latency);
+}
 
-    // if this is a snoop from a slave (corresponding to our own
-    // master), i.e. the memory side of the bus, then do not send it
-    // back to where it came from
-    if (dest_id != src_id) {
-        response_latency = masterPorts[dest_id]->sendAtomic(pkt);
+void
+Bus::recvFunctional(PacketPtr pkt)
+{
+    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());
     }
 
-    // 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;
-    }
+    // we should always see a request routed based on the address
+    assert(pkt->getDest() == Packet::Broadcast);
+    assert(pkt->isRequest());
 
-    // why do we have this packet field and the return value both???
-    pkt->finishTime = curTick() + response_latency;
-    return response_latency;
+    // forward to all snoopers but the source
+    forwardFunctional(pkt, pkt->getSrc());
+
+    // there is no need to continue if the snooping has found what we
+    // were looking for and the packet is already a response
+    if (!pkt->isResponse()) {
+        int dest_id = findPort(pkt->getAddr());
+
+        masterPorts[dest_id]->sendFunctional(pkt);
+    }
 }
 
-/** Function called by the port when the bus is receiving a Functional
- * transaction.*/
 void
-Bus::recvFunctional(PacketPtr pkt)
+Bus::recvFunctionalSnoop(PacketPtr pkt)
 {
     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",
+                "recvFunctionalSnoop: packet src %d dest %d addr 0x%x cmd %s\n",
                 pkt->getSrc(), pkt->getDest(), pkt->getAddr(),
                 pkt->cmdString());
     }
@@ -526,10 +673,13 @@ Bus::recvFunctional(PacketPtr pkt)
     assert(pkt->getDest() == Packet::Broadcast);
     assert(pkt->isRequest());
 
-    // the packet may be changed by another bus on snoops, record the
-    // source id here
-    Packet::NodeID src_id = pkt->getSrc();
+    // forward to all snoopers
+    forwardFunctional(pkt, INVALID_PORT_ID);
+}
 
+void
+Bus::forwardFunctional(PacketPtr pkt, int exclude_slave_port_id)
+{
     SnoopIter s_end = snoopPorts.end();
     for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
         BusSlavePort *p = *s_iter;
@@ -537,26 +687,13 @@ Bus::recvFunctional(PacketPtr pkt)
         // (corresponding to our own slave port that is also in
         // snoopPorts) and should not send it back to where it came
         // from
-        if (p->getId() != src_id) {
-            p->sendFunctional(pkt);
-
-            // if we get a response we are done
-            if (pkt->isResponse()) {
-                break;
-            }
-        }
-    }
-
-    // there is no need to continue if the snooping has found what we
-    // were looking for and the packet is already a response
-    if (!pkt->isResponse()) {
-        int dest_id = findPort(pkt->getAddr());
+        if (exclude_slave_port_id == INVALID_PORT_ID ||
+            p->getId() != exclude_slave_port_id)
+            p->sendFunctionalSnoop(pkt);
 
-        // if this is a snoop from a slave (corresponding to our own
-        // master), i.e. the memory side of the bus, then do not send
-        // it back to where it came from,
-        if (dest_id != src_id) {
-            masterPorts[dest_id]->sendFunctional(pkt);
+        // if we get a response we are done
+        if (pkt->isResponse()) {
+            break;
         }
     }
 }
@@ -621,8 +758,7 @@ Bus::recvRangeChange(int id)
     std::vector<BusSlavePort*>::const_iterator intIter;
 
     for (intIter = slavePorts.begin(); intIter != slavePorts.end(); intIter++)
-        if (*intIter != NULL && (*intIter)->getId() != id)
-            (*intIter)->sendRangeChange();
+        (*intIter)->sendRangeChange();
 
     inRecvRangeChange.erase(id);
 }
index e79e9df9eb5cc173c09eab8181209a0cfc304525..8a06763531f7ed240e6585b03f95b825e68b24a6 100644 (file)
@@ -91,25 +91,35 @@ class Bus : public MemObject
 
       protected:
 
-        /** When reciving a timing request from the peer port (at id),
-            pass it to the bus. */
+        /**
+         * When receiving a timing request, pass it to the bus.
+         */
         virtual bool recvTiming(PacketPtr pkt)
         { pkt->setSrc(id); return bus->recvTiming(pkt); }
 
-        /** When reciving a Atomic requestfrom the peer port (at id),
-            pass it to the bus. */
+        /**
+         * When receiving a timing snoop response, pass it to the bus.
+         */
+        virtual bool recvTimingSnoop(PacketPtr pkt)
+        { pkt->setSrc(id); return bus->recvTimingSnoop(pkt); }
+
+        /**
+         * When receiving an atomic request, pass it to the bus.
+         */
         virtual Tick recvAtomic(PacketPtr pkt)
         { pkt->setSrc(id); return bus->recvAtomic(pkt); }
 
-        /** When reciving a Functional requestfrom the peer port (at id),
-            pass it to the bus. */
+        /**
+         * When receiving a functional request, pass it to the bus.
+         */
         virtual void recvFunctional(PacketPtr pkt)
         { pkt->setSrc(id); bus->recvFunctional(pkt); }
 
-        /** When reciving a retry from the peer port (at id),
-            pass it to the bus. */
+        /**
+         * When receiving a retry, pass it to the bus.
+         */
         virtual void recvRetry()
-        { bus->recvRetry(id); }
+        { panic("Bus slave ports always succeed and should never retry.\n"); }
 
         // This should return all the 'owned' addresses that are
         // downstream from this bus, yes?  That is, the union of all
@@ -160,20 +170,29 @@ class Bus : public MemObject
 
       protected:
 
-        /** When reciving a timing request from the peer port (at id),
-            pass it to the bus. */
+        /**
+         * When receiving a timing response, pass it to the bus.
+         */
         virtual bool recvTiming(PacketPtr pkt)
         { pkt->setSrc(id); return bus->recvTiming(pkt); }
 
-        /** When reciving a Atomic requestfrom the peer port (at id),
-            pass it to the bus. */
-        virtual Tick recvAtomic(PacketPtr pkt)
-        { pkt->setSrc(id); return bus->recvAtomic(pkt); }
+        /**
+         * When receiving a timing snoop request, pass it to the bus.
+         */
+        virtual bool recvTimingSnoop(PacketPtr pkt)
+        { pkt->setSrc(id); return bus->recvTimingSnoop(pkt); }
 
-        /** When reciving a Functional requestfrom the peer port (at id),
-            pass it to the bus. */
-        virtual void recvFunctional(PacketPtr pkt)
-        { pkt->setSrc(id); bus->recvFunctional(pkt); }
+        /**
+         * When receiving an atomic snoop request, pass it to the bus.
+         */
+        virtual Tick recvAtomicSnoop(PacketPtr pkt)
+        { pkt->setSrc(id); return bus->recvAtomicSnoop(pkt); }
+
+        /**
+         * When receiving a functional snoop request, pass it to the bus.
+         */
+        virtual void recvFunctionalSnoop(PacketPtr pkt)
+        { pkt->setSrc(id); bus->recvFunctionalSnoop(pkt); }
 
         /** When reciving a range change from the peer port (at id),
             pass it to the bus. */
@@ -212,18 +231,91 @@ class Bus : public MemObject
     typedef std::vector<BusSlavePort*>::iterator SnoopIter;
     std::vector<BusSlavePort*> snoopPorts;
 
+    /**
+     * Store the outstanding requests so we can determine which ones
+     * we generated and which ones were merely forwarded. This is used
+     * in the coherent bus when coherency responses come back.
+     */
+    std::set<RequestPtr> outstandingReq;
+
     /** Function called by the port when the bus is recieving a Timing
       transaction.*/
     bool recvTiming(PacketPtr pkt);
 
+    /** Function called by the port when the bus is recieving a timing
+        snoop transaction.*/
+    bool recvTimingSnoop(PacketPtr pkt);
+
+    /**
+     * Forward a timing packet to our snoopers, potentially excluding
+     * one of the connected coherent masters to avoid sending a packet
+     * back to where it came from.
+     *
+     * @param pkt Packet to forward
+     * @param exclude_slave_port_id Id of slave port to exclude
+     */
+    void forwardTiming(PacketPtr pkt, int exclude_slave_port_id);
+
+    /**
+     * Determine if the bus is to be considered occupied when being
+     * presented with a packet from a specific port. If so, the port
+     * in question is also added to the retry list.
+     *
+     * @param pkt Incoming packet
+     * @param port Source port on the bus presenting the packet
+     *
+     * @return True if the bus is to be considered occupied
+     */
+    bool isOccupied(PacketPtr pkt, Port* port);
+
+    /**
+     * Deal with a destination port accepting a packet by potentially
+     * removing the source port from the retry list (if retrying) and
+     * occupying the bus accordingly.
+     *
+     * @param busy_time Time to spend as a result of a successful send
+     */
+    void succeededTiming(Tick busy_time);
+
     /** Function called by the port when the bus is recieving a Atomic
       transaction.*/
     Tick recvAtomic(PacketPtr pkt);
 
+    /** Function called by the port when the bus is recieving an
+        atomic snoop transaction.*/
+    Tick recvAtomicSnoop(PacketPtr pkt);
+
+    /**
+     * Forward an atomic packet to our snoopers, potentially excluding
+     * one of the connected coherent masters to avoid sending a packet
+     * back to where it came from.
+     *
+     * @param pkt Packet to forward
+     * @param exclude_slave_port_id Id of slave port to exclude
+     *
+     * @return a pair containing the snoop response and snoop latency
+     */
+    std::pair<MemCmd, Tick> forwardAtomic(PacketPtr pkt,
+                                          int exclude_slave_port_id);
+
     /** Function called by the port when the bus is recieving a Functional
         transaction.*/
     void recvFunctional(PacketPtr pkt);
 
+    /** Function called by the port when the bus is recieving a functional
+        snoop transaction.*/
+    void recvFunctionalSnoop(PacketPtr pkt);
+
+    /**
+     * Forward a functional packet to our snoopers, potentially
+     * excluding one of the connected coherent masters to avoid
+     * sending a packet back to where it came from.
+     *
+     * @param pkt Packet to forward
+     * @param exclude_slave_port_id Id of slave port to exclude
+     */
+    void forwardFunctional(PacketPtr pkt, int exclude_slave_port_id);
+
     /** Timing function called by port when it is once again able to process
      * requests. */
     void recvRetry(int id);
@@ -345,11 +437,6 @@ class Bus : public MemObject
     bool inRetry;
     std::set<int> inRecvRangeChange;
 
-    // keep track of the number of master ports (not counting the
-    // default master) since we need this as an offset into the
-    // interfaces vector
-    unsigned int nbrMasterPorts;
-
     /** The master and slave ports of the bus */
     std::vector<BusSlavePort*> slavePorts;
     std::vector<BusMasterPort*> masterPorts;
index 47cbaf7a0c0fc3dbf3700799e5ceb4beb281f5f0..b24e595b7175c909fe4c57ce97109b30c3cd463e 100644 (file)
@@ -142,7 +142,7 @@ class BaseCache : public MemObject
          * @param when time to send the response
          */
         void respond(PacketPtr pkt, Tick time) {
-            queue.schedSendTiming(pkt, time);
+            queue.schedSendTiming(pkt, time, true);
         }
 
       protected:
index e745529a75f4bb0f82a846e74b97fcbf49b1872a..a774a356ccb3d5664aa795c2f3dc4053779cacb1 100644 (file)
@@ -90,6 +90,8 @@ class Cache : public BaseCache
 
       protected:
 
+        virtual bool recvTimingSnoop(PacketPtr pkt);
+
         virtual bool recvTiming(PacketPtr pkt);
 
         virtual Tick recvAtomic(PacketPtr pkt);
@@ -152,11 +154,13 @@ class Cache : public BaseCache
 
       protected:
 
+        virtual bool recvTimingSnoop(PacketPtr pkt);
+
         virtual bool recvTiming(PacketPtr pkt);
 
-        virtual Tick recvAtomic(PacketPtr pkt);
+        virtual Tick recvAtomicSnoop(PacketPtr pkt);
 
-        virtual void recvFunctional(PacketPtr pkt);
+        virtual void recvFunctionalSnoop(PacketPtr pkt);
 
         virtual unsigned deviceBlockSize() const
         { return cache->getBlockSize(); }
index 3525e0777c92b6881876633fb12feec1f3fbc57c..fa6f6c8604e8513d0082f6ad936f8813d6b314e6 100644 (file)
@@ -785,7 +785,7 @@ Cache<TagStore>::functionalAccess(PacketPtr pkt, bool fromCpuSide)
         } else if (forwardSnoops && cpuSidePort->getMasterPort().isSnooping()) {
             // if it came from the memory side, it must be a snoop request
             // and we should only forward it if we are forwarding snoops
-            cpuSidePort->sendFunctional(pkt);
+            cpuSidePort->sendFunctionalSnoop(pkt);
         }
     }
 }
@@ -1178,24 +1178,23 @@ Cache<TagStore>::handleSnoop(PacketPtr pkt, BlkType *blk,
         // rewritten to be relative to cpu-side bus (if any)
         bool alreadyResponded = pkt->memInhibitAsserted();
         if (is_timing) {
-            Packet *snoopPkt = new Packet(pkt, true);  // clear flags
-            snoopPkt->setExpressSnoop();
-            snoopPkt->senderState = new ForwardResponseRecord(pkt, this);
-            cpuSidePort->sendTiming(snoopPkt);
-            if (snoopPkt->memInhibitAsserted()) {
+            Packet snoopPkt(pkt, true);  // clear flags
+            snoopPkt.setExpressSnoop();
+            snoopPkt.senderState = new ForwardResponseRecord(pkt, this);
+            cpuSidePort->sendTimingSnoop(&snoopPkt);
+            if (snoopPkt.memInhibitAsserted()) {
                 // cache-to-cache response from some upper cache
                 assert(!alreadyResponded);
                 pkt->assertMemInhibit();
             } else {
-                delete snoopPkt->senderState;
+                delete snoopPkt.senderState;
             }
-            if (snoopPkt->sharedAsserted()) {
+            if (snoopPkt.sharedAsserted()) {
                 pkt->assertShared();
             }
-            delete snoopPkt;
         } else {
-            int origSrc = pkt->getSrc();
-            cpuSidePort->sendAtomic(pkt);
+            Packet::NodeID origSrc = pkt->getSrc();
+            cpuSidePort->sendAtomicSnoop(pkt);
             if (!alreadyResponded && pkt->memInhibitAsserted()) {
                 // cache-to-cache response from some upper cache:
                 // forward response to original requester
@@ -1335,6 +1334,16 @@ Cache<TagStore>::snoopTiming(PacketPtr pkt)
     handleSnoop(pkt, blk, true, false, false);
 }
 
+template<class TagStore>
+bool
+Cache<TagStore>::CpuSidePort::recvTimingSnoop(PacketPtr pkt)
+{
+    // Express snoop responses from master to slave, e.g., from L1 to L2
+    assert(pkt->isResponse());
+
+    cache->timingAccess(pkt);
+    return true;
+}
 
 template<class TagStore>
 Tick
@@ -1483,7 +1492,7 @@ Cache<TagStore>::getTimingPacket()
             PacketPtr snoop_pkt = new Packet(tgt_pkt, true);
             snoop_pkt->setExpressSnoop();
             snoop_pkt->senderState = mshr;
-            cpuSidePort->sendTiming(snoop_pkt);
+            cpuSidePort->sendTimingSnoop(snoop_pkt);
 
             if (snoop_pkt->memInhibitAsserted()) {
                 markInService(mshr, snoop_pkt);
@@ -1550,8 +1559,9 @@ template<class TagStore>
 bool
 Cache<TagStore>::CpuSidePort::recvTiming(PacketPtr pkt)
 {
-    // illegal to block responses... can lead to deadlock
-    if (pkt->isRequest() && !pkt->memInhibitAsserted() && blocked) {
+    assert(pkt->isRequest());
+    // always let inhibited requests through even if blocked
+    if (!pkt->memInhibitAsserted() && blocked) {
         DPRINTF(Cache,"Scheduling a retry while blocked\n");
         mustSendRetry = true;
         return false;
@@ -1603,17 +1613,25 @@ Cache<TagStore>::MemSidePort::recvTiming(PacketPtr pkt)
     if (pkt->wasNacked())
         panic("Need to implement cache resending nacked packets!\n");
 
-    if (pkt->isResponse()) {
-        cache->handleResponse(pkt);
-    } else {
-        cache->snoopTiming(pkt);
-    }
+    assert(pkt->isResponse());
+    cache->handleResponse(pkt);
+    return true;
+}
+
+// Express snooping requests to memside port
+template<class TagStore>
+bool
+Cache<TagStore>::MemSidePort::recvTimingSnoop(PacketPtr pkt)
+{
+    // handle snooping requests
+    assert(pkt->isRequest());
+    cache->snoopTiming(pkt);
     return true;
 }
 
 template<class TagStore>
 Tick
-Cache<TagStore>::MemSidePort::recvAtomic(PacketPtr pkt)
+Cache<TagStore>::MemSidePort::recvAtomicSnoop(PacketPtr pkt)
 {
     assert(pkt->isRequest());
     // atomic snoop
@@ -1622,7 +1640,7 @@ Cache<TagStore>::MemSidePort::recvAtomic(PacketPtr pkt)
 
 template<class TagStore>
 void
-Cache<TagStore>::MemSidePort::recvFunctional(PacketPtr pkt)
+Cache<TagStore>::MemSidePort::recvFunctionalSnoop(PacketPtr pkt)
 {
     assert(pkt->isRequest());
     // functional snoop (note that in contrast to atomic we don't have
index 9af394d27713110a05f1081f41ff9ccf9bc373a8..5678f87d79b2b7ce034147010901192073cb9f63 100644 (file)
@@ -52,17 +52,3 @@ MessageSlavePort::recvAtomic(PacketPtr pkt)
               name(), pkt->cmd.toString(), getMasterPort().name());
     }
 }
-
-Tick
-MessageMasterPort::recvAtomic(PacketPtr pkt)
-{
-    if (pkt->cmd == MemCmd::MessageResp) {
-        // normally we would never see responses in recvAtomic, but
-        // since the timing port uses recvAtomic to implement
-        // recvTiming we have to deal with them here
-        return recvResponse(pkt);
-    } else {
-        panic("%s received unexpected atomic command %s from %s.\n",
-              name(), pkt->cmd.toString(), getSlavePort().name());
-    }
-}
index 664acc559cddf7caf5a8fce3ff29504ec414b1de..7f9e8f4e0889eb7f9cf5313a84da7ea2aee206cf 100644 (file)
@@ -82,11 +82,7 @@ class MessageMasterPort : public QueuedMasterPort
     virtual ~MessageMasterPort()
     {}
 
-    void recvFunctional(PacketPtr pkt) { assert(false); }
-
-    Tick recvAtomic(PacketPtr pkt);
-
-    bool recvTiming(PacketPtr pkt) { recvAtomic(pkt); return true; }
+    bool recvTiming(PacketPtr pkt) { recvResponse(pkt); return true; }
 
   protected:
 
index 29914bea2adb88d734fd78b25aefa4eebcd6d288..bffae56742ad719473af3276cf9849eee7c64190 100644 (file)
@@ -104,7 +104,7 @@ PacketQueue::schedSendEvent(Tick when)
 }
 
 void
-PacketQueue::schedSendTiming(PacketPtr pkt, Tick when)
+PacketQueue::schedSendTiming(PacketPtr pkt, Tick when, bool send_as_snoop)
 {
     assert(when > curTick());
 
@@ -114,14 +114,14 @@ PacketQueue::schedSendTiming(PacketPtr pkt, Tick when)
         // note that currently we ignore a potentially outstanding retry
         // and could in theory put a new packet at the head of the
         // transmit list before retrying the existing packet
-        transmitList.push_front(DeferredPacket(when, pkt));
+        transmitList.push_front(DeferredPacket(when, pkt, send_as_snoop));
         schedSendEvent(when);
         return;
     }
 
     // list is non-empty and this belongs at the end
     if (when >= transmitList.back().tick) {
-        transmitList.push_back(DeferredPacket(when, pkt));
+        transmitList.push_back(DeferredPacket(when, pkt, send_as_snoop));
         return;
     }
 
@@ -130,7 +130,7 @@ PacketQueue::schedSendTiming(PacketPtr pkt, Tick when)
     ++i; // already checked for insertion at front
     while (i != transmitList.end() && when >= i->tick)
         ++i;
-    transmitList.insert(i, DeferredPacket(when, pkt));
+    transmitList.insert(i, DeferredPacket(when, pkt, send_as_snoop));
 }
 
 void PacketQueue::trySendTiming()
@@ -143,7 +143,10 @@ void PacketQueue::trySendTiming()
     transmitList.pop_front();
 
     // attempt to send the packet and remember the outcome
-    waitingOnRetry = !port.sendTiming(dp.pkt);
+    if (!dp.sendAsSnoop)
+        waitingOnRetry = !port.sendTiming(dp.pkt);
+    else
+        waitingOnRetry = !port.sendTimingSnoop(dp.pkt);
 
     if (waitingOnRetry) {
         // put the packet back at the front of the list (packet should
index ac868802b40d68f1a375fc48ae09166225e49a32..fbcd7d4495cf09b804fb2f7ef58af513c1eaed93 100644 (file)
@@ -70,8 +70,9 @@ class PacketQueue
       public:
         Tick tick;      ///< The tick when the packet is ready to transmit
         PacketPtr pkt;  ///< Pointer to the packet to transmit
-        DeferredPacket(Tick t, PacketPtr p)
-            : tick(t), pkt(p)
+        bool sendAsSnoop; ///< Should it be sent as a snoop or not
+        DeferredPacket(Tick t, PacketPtr p, bool send_as_snoop)
+            : tick(t), pkt(p), sendAsSnoop(send_as_snoop)
         {}
     };
 
@@ -196,8 +197,9 @@ class PacketQueue
      *
      * @param pkt Packet to send
      * @param when Absolute time (in ticks) to send packet
+     * @param send_as_snoop Send the packet as a snoop or not
      */
-    void schedSendTiming(PacketPtr pkt, Tick when);
+    void schedSendTiming(PacketPtr pkt, Tick when, bool send_as_snoop = false);
 
     /**
      * Used by a port to notify the queue that a retry was received
@@ -215,4 +217,4 @@ class PacketQueue
     unsigned int drain(Event *de);
 };
 
-#endif // __MEM_TPORT_HH__
+#endif // __MEM_PACKET_QUEUE_HH__
index 3305541c72b5e2b00698f6b859e6c917dd768d68..92c6aaab8464d044147337346589bd2487e07c08 100644 (file)
@@ -104,7 +104,19 @@ MasterPort::peerBlockSize() const
     return _slavePort->deviceBlockSize();
 }
 
- void
+Tick
+MasterPort::sendAtomic(PacketPtr pkt)
+{
+    return _slavePort->recvAtomic(pkt);
+}
+
+void
+MasterPort::sendFunctional(PacketPtr pkt)
+{
+    return _slavePort->recvFunctional(pkt);
+}
+
+void
 MasterPort::printAddr(Addr a)
 {
     Request req(a, 1, 0, Request::funcMasterId);
@@ -155,3 +167,15 @@ SlavePort::isConnected() const
 {
     return _masterPort != NULL;
 }
+
+Tick
+SlavePort::sendAtomicSnoop(PacketPtr pkt)
+{
+    return _masterPort->recvAtomicSnoop(pkt);
+}
+
+void
+SlavePort::sendFunctionalSnoop(PacketPtr pkt)
+{
+    return _masterPort->recvFunctionalSnoop(pkt);
+}
index 80bb3b085c09844d35d9c3be923c204cbdaf6a33..61c92d8e4388654e9d513474602deec2c803e58f 100644 (file)
@@ -115,28 +115,35 @@ class Port
     /** These functions are protected because they should only be
      * called by a peer port, never directly by any outside object. */
 
-    /** Called to recive a timing call from the peer port. */
+    /**
+     * Receive a timing request or response packet from the peer port.
+     */
     virtual bool recvTiming(PacketPtr pkt) = 0;
 
-    /** Called to recive a atomic call from the peer port. */
-    virtual Tick recvAtomic(PacketPtr pkt) = 0;
-
-    /** Called to recive a functional call from the peer port. */
-    virtual void recvFunctional(PacketPtr pkt) = 0;
+    /**
+     * Receive a timing snoop request or snoop response packet from
+     * the peer port.
+     */
+    virtual bool recvTimingSnoop(PacketPtr pkt)
+    {
+        panic("%s was not expecting a timing snoop\n", name());
+        return false;
+    }
 
     /**
-     * Called by a peer port if sendTiming was unsuccesful, and had to
-     * wait.
+     * Called by a peer port if sendTiming or sendTimingSnoop was
+     * unsuccesful, and had to wait.
      */
     virtual void recvRetry() = 0;
 
   public:
 
     /**
-     * Attempt to send a timing packet to the peer port by calling its
-     * receive function. If the send does not succeed, as indicated by
-     * the return value, then the sender must wait for a recvRetry at
-     * which point it can re-issue a sendTiming.
+     * Attempt to send a timing request or response packet to the peer
+     * port by calling its receive function. If the send does not
+     * succeed, as indicated by the return value, then the sender must
+     * wait for a recvRetry at which point it can re-issue a
+     * sendTiming.
      *
      * @param pkt Packet to send.
      *
@@ -145,30 +152,23 @@ class Port
     bool sendTiming(PacketPtr pkt) { return peer->recvTiming(pkt); }
 
     /**
-     * Send a retry to a peer port that previously attempted a sendTiming
-     * which was unsuccessful.
-     */
-    void sendRetry() { return peer->recvRetry(); }
-
-    /**
-     * Send an atomic packet, where the data is moved and the state
-     * is updated in zero time, without interleaving with other
-     * memory accesses.
+     * Attempt to send a timing snoop request or snoop response packet
+     * to the peer port by calling its receive function. If the send
+     * does not succeed, as indicated by the return value, then the
+     * sender must wait for a recvRetry at which point it can re-issue
+     * a sendTimingSnoop.
      *
      * @param pkt Packet to send.
      *
-     * @return Estimated latency of access.
-     */
-    Tick sendAtomic(PacketPtr pkt) { return peer->recvAtomic(pkt); }
+     * @return If the send was succesful or not.
+    */
+    bool sendTimingSnoop(PacketPtr pkt) { return peer->recvTimingSnoop(pkt); }
 
     /**
-     * Send a functional packet, where the data is instantly updated
-     * everywhere in the memory system, without affecting the current
-     * state of any block or moving the block.
-     *
-     * @param pkt Packet to send.
+     * Send a retry to a peer port that previously attempted a
+     * sendTiming or sendTimingSnoop which was unsuccessful.
      */
-    void sendFunctional(PacketPtr pkt) { return peer->recvFunctional(pkt); }
+    void sendRetry() { return peer->recvRetry(); }
 
 };
 
@@ -197,6 +197,43 @@ class MasterPort : public Port
     SlavePort& getSlavePort() const;
     bool isConnected() const;
 
+    /**
+     * Send an atomic request packet, where the data is moved and the
+     * state is updated in zero time, without interleaving with other
+     * memory accesses.
+     *
+     * @param pkt Packet to send.
+     *
+     * @return Estimated latency of access.
+     */
+    Tick sendAtomic(PacketPtr pkt);
+
+    /**
+     * Send a functional request packet, where the data is instantly
+     * updated everywhere in the memory system, without affecting the
+     * current state of any block or moving the block.
+     *
+     * @param pkt Packet to send.
+     */
+    void sendFunctional(PacketPtr pkt);
+
+    /**
+     * Receive an atomic snoop request packet from the slave port.
+     */
+    virtual Tick recvAtomicSnoop(PacketPtr pkt)
+    {
+        panic("%s was not expecting an atomic snoop\n", name());
+        return 0;
+    }
+
+    /**
+     * Receive a functional snoop request packet from the slave port.
+     */
+    virtual void recvFunctionalSnoop(PacketPtr pkt)
+    {
+        panic("%s was not expecting a functional snoop\n", name());
+    }
+
     /**
      * Called to receive an address range change from the peer slave
      * port. the default implementation ignored the change and does
@@ -256,6 +293,36 @@ class SlavePort : public Port
     MasterPort& getMasterPort() const;
     bool isConnected() const;
 
+    /**
+     * Send an atomic snoop request packet, where the data is moved
+     * and the state is updated in zero time, without interleaving
+     * with other memory accesses.
+     *
+     * @param pkt Snoop packet to send.
+     *
+     * @return Estimated latency of access.
+     */
+    Tick sendAtomicSnoop(PacketPtr pkt);
+
+    /**
+     * Send a functional snoop request packet, where the data is
+     * instantly updated everywhere in the memory system, without
+     * affecting the current state of any block or moving the block.
+     *
+     * @param pkt Snoop packet to send.
+     */
+    void sendFunctionalSnoop(PacketPtr pkt);
+
+    /**
+     * Receive an atomic request packet from the master port.
+     */
+    virtual Tick recvAtomic(PacketPtr pkt) = 0;
+
+    /**
+     * Receive a functional request packet from the master port.
+     */
+    virtual void recvFunctional(PacketPtr pkt) = 0;
+
     /**
      * Called by a peer port in order to determine the block size of
      * the owner of this port.
index 0cdb919b138ac956694faf87318fcd17b6733e4f..74a60f86338e8f303b677ab70cdcd519eae54434 100644 (file)
@@ -132,13 +132,6 @@ RubyPort::M5Port::M5Port(const std::string &_name, RubyPort *_port,
     DPRINTF(RubyPort, "creating slave port on ruby sequencer %s\n", _name);
 }
 
-Tick
-RubyPort::PioPort::recvAtomic(PacketPtr pkt)
-{
-    panic("RubyPort::PioPort::recvAtomic() not implemented!\n");
-    return 0;
-}
-
 Tick
 RubyPort::M5Port::recvAtomic(PacketPtr pkt)
 {
@@ -662,10 +655,11 @@ RubyPort::M5Port::hitCallback(PacketPtr pkt)
 }
 
 bool
-RubyPort::M5Port::sendNextCycle(PacketPtr pkt)
+RubyPort::M5Port::sendNextCycle(PacketPtr pkt, bool send_as_snoop)
 {
     //minimum latency, must be > 0
-    queue.schedSendTiming(pkt, curTick() + (1 * g_eventQueue_ptr->getClock()));
+    queue.schedSendTiming(pkt, curTick() + (1 * g_eventQueue_ptr->getClock()),
+                          send_as_snoop);
     return true;
 }
 
@@ -706,7 +700,8 @@ RubyPort::ruby_eviction_callback(const Address& address)
     for (CpuPortIter p = slave_ports.begin(); p != slave_ports.end(); ++p) {
         if ((*p)->getMasterPort().isSnooping()) {
             Packet *pkt = new Packet(&req, MemCmd::InvalidationReq, -1);
-            (*p)->sendNextCycle(pkt);
+            // send as a snoop request
+            (*p)->sendNextCycle(pkt, true);
         }
     }
 }
index 553614021b563f97a3176c3376e37f981a789a4b..f41c98f55820b5180523f5919e723baff6065939 100644 (file)
@@ -71,7 +71,7 @@ class RubyPort : public MemObject
       public:
         M5Port(const std::string &_name, RubyPort *_port,
                RubySystem*_system, bool _access_phys_mem);
-        bool sendNextCycle(PacketPtr pkt);
+        bool sendNextCycle(PacketPtr pkt, bool send_as_snoop = false);
         void hitCallback(PacketPtr pkt);
         void evictionCallback(const Address& address);
         unsigned deviceBlockSize() const;
@@ -110,8 +110,6 @@ class RubyPort : public MemObject
 
       protected:
         virtual bool recvTiming(PacketPtr pkt);
-        virtual Tick recvAtomic(PacketPtr pkt);
-        virtual void recvFunctional(PacketPtr pkt) { }
     };
 
     friend class PioPort;
index 7b5ba998ebda8ef2c884456e36adc03a58f3dc82..f7831d09c976b1c3916c109a32e7390fad1f1e25 100644 (file)
@@ -92,10 +92,6 @@ class System : public MemObject
         { panic("SystemPort does not receive timing!\n"); return false; }
         void recvRetry()
         { panic("SystemPort does not expect retry!\n"); }
-        Tick recvAtomic(PacketPtr pkt)
-        { panic("SystemPort does not receive atomic!\n"); return 0; }
-        void recvFunctional(PacketPtr pkt)
-        { panic("SystemPort does not receive functional!\n"); }
     };
 
     SystemPort _systemPort;