Since cpus now send out snoop ranges, remove it from the cache.
[gem5.git] / src / mem / cache / base_cache.hh
index 2e92e77300bfdcb9284115f0b3f1d848ffbc015e..ef4955432d4b75897faa31bf0df6e4e018929c18 100644 (file)
@@ -58,7 +58,6 @@ enum BlockedCause{
     Blocked_NoTargets,
     Blocked_NoWBBuffers,
     Blocked_Coherence,
-    Blocked_Copy,
     NUM_BLOCKED_CAUSES
 };
 
@@ -72,6 +71,7 @@ enum RequestCause{
     Request_PF
 };
 
+class MSHR;
 /**
  * A basic cache interface. Implements some common functions for speed.
  */
@@ -85,11 +85,11 @@ class BaseCache : public MemObject
         CachePort(const std::string &_name, BaseCache *_cache, bool _isCpuSide);
 
       protected:
-        virtual bool recvTiming(Packet *pkt);
+        virtual bool recvTiming(PacketPtr pkt);
 
-        virtual Tick recvAtomic(Packet *pkt);
+        virtual Tick recvAtomic(PacketPtr pkt);
 
-        virtual void recvFunctional(Packet *pkt);
+        virtual void recvFunctional(PacketPtr pkt);
 
         virtual void recvStatusChange(Status status);
 
@@ -105,48 +105,61 @@ class BaseCache : public MemObject
 
         void clearBlocked();
 
+        bool checkFunctional(PacketPtr pkt);
+
+        void checkAndSendFunctional(PacketPtr pkt);
+
+        bool canDrain() { return drainList.empty() && transmitList.empty(); }
+
         bool blocked;
 
         bool mustSendRetry;
 
         bool isCpuSide;
 
-        std::list<Packet *> drainList;
+        bool waitingOnRetry;
+
+        std::list<PacketPtr> drainList;
+
+        std::list<std::pair<Tick,PacketPtr> > transmitList;
     };
 
     struct CacheEvent : public Event
     {
         CachePort *cachePort;
-        Packet *pkt;
+        PacketPtr pkt;
+        bool newResponse;
 
-        CacheEvent(CachePort *_cachePort);
-        CacheEvent(CachePort *_cachePort, Packet *_pkt);
+        CacheEvent(CachePort *_cachePort, bool response);
         void process();
         const char *description();
     };
 
-  protected:
+  public: //Made public so coherence can get at it.
     CachePort *cpuSidePort;
-    CachePort *memSidePort;
 
-    bool snoopRangesSent;
+    CacheEvent *sendEvent;
+    CacheEvent *memSendEvent;
+
+  protected:
+    CachePort *memSidePort;
 
   public:
     virtual Port *getPort(const std::string &if_name, int idx = -1);
 
   private:
     //To be defined in cache_impl.hh not in base class
-    virtual bool doTimingAccess(Packet *pkt, CachePort *cachePort, bool isCpuSide)
+    virtual bool doTimingAccess(PacketPtr pkt, CachePort *cachePort, bool isCpuSide)
     {
         fatal("No implementation");
     }
 
-    virtual Tick doAtomicAccess(Packet *pkt, bool isCpuSide)
+    virtual Tick doAtomicAccess(PacketPtr pkt, bool isCpuSide)
     {
         fatal("No implementation");
     }
 
-    virtual void doFunctionalAccess(Packet *pkt, bool isCpuSide)
+    virtual void doFunctionalAccess(PacketPtr pkt, bool isCpuSide)
     {
         fatal("No implementation");
     }
@@ -156,10 +169,6 @@ class BaseCache : public MemObject
         if (status == Port::RangeChange){
             if (!isCpuSide) {
                 cpuSidePort->sendStatusChange(Port::RangeChange);
-                if (topLevelCache && !snoopRangesSent) {
-                    snoopRangesSent = true;
-                    memSidePort->sendStatusChange(Port::RangeChange);
-                }
             }
             else {
                 memSidePort->sendStatusChange(Port::RangeChange);
@@ -167,17 +176,23 @@ class BaseCache : public MemObject
         }
     }
 
-    virtual Packet *getPacket()
+    virtual PacketPtr getPacket()
     {
         fatal("No implementation");
     }
 
-    virtual Packet *getCoherencePacket()
+    virtual PacketPtr getCoherencePacket()
     {
         fatal("No implementation");
     }
 
-    virtual void sendResult(Packet* &pkt, bool success)
+    virtual void sendResult(PacketPtr &pkt, MSHR* mshr, bool success)
+    {
+
+        fatal("No implementation");
+    }
+
+    virtual void sendCoherenceResult(PacketPtr &pkt, MSHR* mshr, bool success)
     {
 
         fatal("No implementation");
@@ -207,10 +222,6 @@ class BaseCache : public MemObject
 
   protected:
 
-    /** True if this cache is connected to the CPU. */
-    bool topLevelCache;
-
-
     /** Stores time the cache blocked for statistics. */
     Tick blockedCycle;
 
@@ -220,6 +231,9 @@ class BaseCache : public MemObject
     /** The number of misses to trigger an exit event. */
     Counter missCount;
 
+    /** The drain event. */
+    Event *drainEvent;
+
   public:
     // Statistics
     /**
@@ -332,13 +346,18 @@ class BaseCache : public MemObject
      */
     BaseCache(const std::string &name, Params &params)
         : MemObject(name), blocked(0), blockedSnoop(0), masterRequests(0),
-          slaveRequests(0), topLevelCache(false),  blkSize(params.blkSize),
-          missCount(params.maxMisses)
+          slaveRequests(0), blkSize(params.blkSize),
+          missCount(params.maxMisses), drainEvent(NULL)
     {
         //Start ports at null if more than one is created we should panic
         cpuSidePort = NULL;
         memSidePort = NULL;
-        snoopRangesSent = false;
+    }
+
+    ~BaseCache()
+    {
+        delete sendEvent;
+        delete memSendEvent;
     }
 
     virtual void init();
@@ -352,15 +371,6 @@ class BaseCache : public MemObject
         return blkSize;
     }
 
-    /**
-     * Returns true if this cache is connect to the CPU.
-     * @return True if this is a L1 cache.
-     */
-    bool isTopLevel()
-    {
-        return topLevelCache;
-    }
-
     /**
      * Returns true if the cache is blocked for accesses.
      */
@@ -389,11 +399,13 @@ class BaseCache : public MemObject
             blocked_causes[cause]++;
             blockedCycle = curTick;
         }
+        int old_state = blocked;
         if (!(blocked & flag)) {
             //Wasn't already blocked for this cause
             blocked |= flag;
             DPRINTF(Cache,"Blocking for cause %s\n", cause);
-            cpuSidePort->setBlocked();
+            if (!old_state)
+                cpuSidePort->setBlocked();
         }
     }
 
@@ -405,10 +417,12 @@ class BaseCache : public MemObject
     void setBlockedForSnoop(BlockedCause cause)
     {
         uint8_t flag = 1 << cause;
-        if (!(blocked & flag)) {
+        uint8_t old_state = blockedSnoop;
+        if (!(blockedSnoop & flag)) {
             //Wasn't already blocked for this cause
             blockedSnoop |= flag;
-            memSidePort->setBlocked();
+            if (!old_state)
+                memSidePort->setBlocked();
         }
     }
 
@@ -458,9 +472,10 @@ class BaseCache : public MemObject
      */
     void setMasterRequest(RequestCause cause, Tick time)
     {
-        if (!doMasterRequest())
+        if (!doMasterRequest() && !memSidePort->waitingOnRetry)
         {
-            BaseCache::CacheEvent * reqCpu = new BaseCache::CacheEvent(memSidePort);
+            BaseCache::CacheEvent * reqCpu =
+                new BaseCache::CacheEvent(memSidePort, false);
             reqCpu->schedule(time);
         }
         uint8_t flag = 1<<cause;
@@ -475,6 +490,7 @@ class BaseCache : public MemObject
     {
         uint8_t flag = 1<<cause;
         masterRequests &= ~flag;
+        checkDrain();
     }
 
     /**
@@ -493,10 +509,14 @@ class BaseCache : public MemObject
      */
     void setSlaveRequest(RequestCause cause, Tick time)
     {
+        if (!doSlaveRequest() && !cpuSidePort->waitingOnRetry)
+        {
+            BaseCache::CacheEvent * reqCpu =
+                new BaseCache::CacheEvent(cpuSidePort, false);
+            reqCpu->schedule(time);
+        }
         uint8_t flag = 1<<cause;
         slaveRequests |= flag;
-        assert("Implement\n" && 0);
-//     si->pktuest(time);
     }
 
     /**
@@ -507,6 +527,7 @@ class BaseCache : public MemObject
     {
         uint8_t flag = 1<<cause;
         slaveRequests &= ~flag;
+        checkDrain();
     }
 
     /**
@@ -514,11 +535,53 @@ class BaseCache : public MemObject
      * @param pkt The request being responded to.
      * @param time The time the response is ready.
      */
-    void respond(Packet *pkt, Tick time)
+    void respond(PacketPtr pkt, Tick time)
     {
+        assert(time >= curTick);
         if (pkt->needsResponse()) {
-            CacheEvent *reqCpu = new CacheEvent(cpuSidePort, pkt);
+/*            CacheEvent *reqCpu = new CacheEvent(cpuSidePort, pkt);
             reqCpu->schedule(time);
+*/
+            if (cpuSidePort->transmitList.empty()) {
+                assert(!sendEvent->scheduled());
+                sendEvent->schedule(time);
+                cpuSidePort->transmitList.push_back(std::pair<Tick,PacketPtr>
+                                                    (time,pkt));
+                return;
+            }
+
+            // something is on the list and this belongs at the end
+            if (time >= cpuSidePort->transmitList.back().first) {
+                cpuSidePort->transmitList.push_back(std::pair<Tick,PacketPtr>
+                                                    (time,pkt));
+                return;
+            }
+            // Something is on the list and this belongs somewhere else
+            std::list<std::pair<Tick,PacketPtr> >::iterator i =
+                cpuSidePort->transmitList.begin();
+            std::list<std::pair<Tick,PacketPtr> >::iterator end =
+                cpuSidePort->transmitList.end();
+            bool done = false;
+
+            while (i != end && !done) {
+                if (time < i->first) {
+                    if (i == cpuSidePort->transmitList.begin()) {
+                        //Inserting at begining, reschedule
+                        sendEvent->reschedule(time);
+                    }
+                    cpuSidePort->transmitList.insert(i,std::pair<Tick,PacketPtr>
+                                                     (time,pkt));
+                    done = true;
+                }
+                i++;
+            }
+        }
+        else {
+            if (pkt->cmd != Packet::UpgradeReq)
+            {
+                delete pkt->req;
+                delete pkt;
+            }
         }
     }
 
@@ -527,14 +590,57 @@ class BaseCache : public MemObject
      * @param pkt The request to respond to.
      * @param time The time the response is ready.
      */
-    void respondToMiss(Packet *pkt, Tick time)
+    void respondToMiss(PacketPtr pkt, Tick time)
     {
+        assert(time >= curTick);
         if (!pkt->req->isUncacheable()) {
-            missLatency[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/] += time - pkt->time;
+            missLatency[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/] +=
+                time - pkt->time;
         }
         if (pkt->needsResponse()) {
-            CacheEvent *reqCpu = new CacheEvent(cpuSidePort, pkt);
+/*            CacheEvent *reqCpu = new CacheEvent(cpuSidePort, pkt);
             reqCpu->schedule(time);
+*/
+            if (cpuSidePort->transmitList.empty()) {
+                assert(!sendEvent->scheduled());
+                sendEvent->schedule(time);
+                cpuSidePort->transmitList.push_back(std::pair<Tick,PacketPtr>
+                                                    (time,pkt));
+                return;
+            }
+
+            // something is on the list and this belongs at the end
+            if (time >= cpuSidePort->transmitList.back().first) {
+                cpuSidePort->transmitList.push_back(std::pair<Tick,PacketPtr>
+                                                    (time,pkt));
+                return;
+            }
+            // Something is on the list and this belongs somewhere else
+            std::list<std::pair<Tick,PacketPtr> >::iterator i =
+                cpuSidePort->transmitList.begin();
+            std::list<std::pair<Tick,PacketPtr> >::iterator end =
+                cpuSidePort->transmitList.end();
+            bool done = false;
+
+            while (i != end && !done) {
+                if (time < i->first) {
+                    if (i == cpuSidePort->transmitList.begin()) {
+                        //Inserting at begining, reschedule
+                        sendEvent->reschedule(time);
+                    }
+                    cpuSidePort->transmitList.insert(i,std::pair<Tick,PacketPtr>
+                                                     (time,pkt));
+                    done = true;
+                }
+                i++;
+            }
+        }
+        else {
+            if (pkt->cmd != Packet::UpgradeReq)
+            {
+                delete pkt->req;
+                delete pkt;
+            }
         }
     }
 
@@ -542,13 +648,45 @@ class BaseCache : public MemObject
      * Suppliess the data if cache to cache transfers are enabled.
      * @param pkt The bus transaction to fulfill.
      */
-    void respondToSnoop(Packet *pkt, Tick time)
+    void respondToSnoop(PacketPtr pkt, Tick time)
     {
-//        assert("Implement\n" && 0);
-//     mi->respond(pkt,curTick + hitLatency);
+        assert(time >= curTick);
         assert (pkt->needsResponse());
-        CacheEvent *reqMem = new CacheEvent(memSidePort, pkt);
+/*        CacheEvent *reqMem = new CacheEvent(memSidePort, pkt);
         reqMem->schedule(time);
+*/
+        if (memSidePort->transmitList.empty()) {
+            assert(!memSendEvent->scheduled());
+            memSendEvent->schedule(time);
+            memSidePort->transmitList.push_back(std::pair<Tick,PacketPtr>
+                                                (time,pkt));
+            return;
+        }
+
+        // something is on the list and this belongs at the end
+        if (time >= memSidePort->transmitList.back().first) {
+            memSidePort->transmitList.push_back(std::pair<Tick,PacketPtr>
+                                                (time,pkt));
+            return;
+        }
+        // Something is on the list and this belongs somewhere else
+        std::list<std::pair<Tick,PacketPtr> >::iterator i =
+            memSidePort->transmitList.begin();
+        std::list<std::pair<Tick,PacketPtr> >::iterator end =
+            memSidePort->transmitList.end();
+        bool done = false;
+
+        while (i != end && !done) {
+            if (time < i->first) {
+                if (i == memSidePort->transmitList.begin()) {
+                    //Inserting at begining, reschedule
+                    memSendEvent->reschedule(time);
+                }
+                memSidePort->transmitList.insert(i,std::pair<Tick,PacketPtr>(time,pkt));
+                done = true;
+            }
+            i++;
+        }
     }
 
     /**
@@ -568,18 +706,34 @@ class BaseCache : public MemObject
         {
             //This is where snoops get updated
             AddrRangeList dummy;
-            if (!topLevelCache)
-            {
-                cpuSidePort->getPeerAddressRanges(dummy, snoop);
-            }
-            else
-            {
-                snoop.push_back(RangeSize(0,-1));
-            }
-
+            cpuSidePort->getPeerAddressRanges(dummy, snoop);
             return;
         }
     }
+
+    virtual unsigned int drain(Event *de);
+
+    void checkDrain()
+    {
+        if (drainEvent && canDrain()) {
+            drainEvent->process();
+            changeState(SimObject::Drained);
+            // Clear the drain event
+            drainEvent = NULL;
+        }
+    }
+
+    bool canDrain()
+    {
+        if (doMasterRequest() || doSlaveRequest()) {
+            return false;
+        } else if (memSidePort && !memSidePort->canDrain()) {
+            return false;
+        } else if (cpuSidePort && !cpuSidePort->canDrain()) {
+            return false;
+        }
+        return true;
+    }
 };
 
 #endif //__BASE_CACHE_HH__