Merge ktlim@zizzer:/bk/newmem
[gem5.git] / src / mem / cache / base_cache.hh
index 0170b0249448f69509621072df1c9cbc3f79eb44..ea7544fbb00ce87f5cdc98cb288f40caae44fe3f 100644 (file)
 #include <list>
 #include <inttypes.h>
 
+#include "base/misc.hh"
 #include "base/statistics.hh"
 #include "base/trace.hh"
 #include "mem/mem_object.hh"
 #include "mem/packet.hh"
 #include "mem/port.hh"
 #include "mem/request.hh"
+#include "sim/eventq.hh"
 
 /**
  * Reasons for Caches to be Blocked.
@@ -56,7 +58,6 @@ enum BlockedCause{
     Blocked_NoTargets,
     Blocked_NoWBBuffers,
     Blocked_Coherence,
-    Blocked_Copy,
     NUM_BLOCKED_CAUSES
 };
 
@@ -70,6 +71,7 @@ enum RequestCause{
     Request_PF
 };
 
+class MSHR;
 /**
  * A basic cache interface. Implements some common functions for speed.
  */
@@ -77,17 +79,17 @@ class BaseCache : public MemObject
 {
     class CachePort : public Port
     {
+      public:
         BaseCache *cache;
 
-      public:
         CachePort(const std::string &_name, BaseCache *_cache, bool _isCpuSide);
 
-      private:
-        virtual bool recvTiming(Packet *pkt);
+      protected:
+        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);
 
@@ -96,38 +98,103 @@ class BaseCache : public MemObject
 
         virtual int deviceBlockSize();
 
+        virtual void recvRetry();
+
+      public:
         void setBlocked();
 
         void clearBlocked();
 
+        bool canDrain() { return drainList.empty(); }
+
         bool blocked;
 
+        bool mustSendRetry;
+
         bool isCpuSide;
+
+        bool waitingOnRetry;
+
+        std::list<PacketPtr> drainList;
+
     };
 
     struct CacheEvent : public Event
     {
-        Packet *pkt;
         CachePort *cachePort;
+        PacketPtr pkt;
 
-        CacheResponseEvent(Packet *pkt, CachePort *cachePort);
+        CacheEvent(CachePort *_cachePort);
+        CacheEvent(CachePort *_cachePort, PacketPtr _pkt);
         void process();
         const char *description();
-    }
+    };
 
-  protected:
+  public: //Made public so coherence can get at it.
     CachePort *cpuSidePort;
+
+  protected:
     CachePort *memSidePort;
 
+    bool snoopRangesSent;
+
   public:
-    virtual Port *getPort(const std::string &if_name);
+    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, MemoryPort *memoryPort, bool isCpuSide);
-    virtual Tick doAtomicAccess(Packet *pkt, bool isCpuSide);
-    virtual void doFunctionalAccess(Packet *pkt, bool isCpuSide);
-    virtual void recvStatusChange(Port::Status status, bool isCpuSide);
+    virtual bool doTimingAccess(PacketPtr pkt, CachePort *cachePort, bool isCpuSide)
+    {
+        fatal("No implementation");
+    }
+
+    virtual Tick doAtomicAccess(PacketPtr pkt, bool isCpuSide)
+    {
+        fatal("No implementation");
+    }
+
+    virtual void doFunctionalAccess(PacketPtr pkt, bool isCpuSide)
+    {
+        fatal("No implementation");
+    }
+
+    void recvStatusChange(Port::Status status, bool isCpuSide)
+    {
+        if (status == Port::RangeChange){
+            if (!isCpuSide) {
+                cpuSidePort->sendStatusChange(Port::RangeChange);
+                if (!snoopRangesSent) {
+                    snoopRangesSent = true;
+                    memSidePort->sendStatusChange(Port::RangeChange);
+                }
+            }
+            else {
+                memSidePort->sendStatusChange(Port::RangeChange);
+            }
+        }
+    }
+
+    virtual PacketPtr getPacket()
+    {
+        fatal("No implementation");
+    }
+
+    virtual PacketPtr getCoherencePacket()
+    {
+        fatal("No implementation");
+    }
+
+    virtual void sendResult(PacketPtr &pkt, MSHR* mshr, bool success)
+    {
+
+        fatal("No implementation");
+    }
+
+    virtual void sendCoherenceResult(PacketPtr &pkt, MSHR* mshr, bool success)
+    {
+
+        fatal("No implementation");
+    }
 
     /**
      * Bit vector of the blocking reasons for the access path.
@@ -153,9 +220,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;
 
@@ -165,6 +229,9 @@ class BaseCache : public MemObject
     /** The number of misses to trigger an exit event. */
     Counter missCount;
 
+    /** The drain event. */
+    Event *drainEvent;
+
   public:
     // Statistics
     /**
@@ -275,14 +342,19 @@ class BaseCache : public MemObject
      * of this cache.
      * @param params The parameter object for this BaseCache.
      */
-    BaseCache(const std::string &name, HierParams *hier_params, Params &params)
-        : BaseMem(name, hier_params, params.hitLatency, params.addrRange),
-          blocked(0), blockedSnoop(0), masterRequests(0), slaveRequests(0),
-          topLevelCache(false),  blkSize(params.blkSize),
-          missCount(params.maxMisses)
+    BaseCache(const std::string &name, Params &params)
+        : MemObject(name), blocked(0), blockedSnoop(0), masterRequests(0),
+          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;
     }
 
+    virtual void init();
+
     /**
      * Query block size of a cache.
      * @return  The block size
@@ -292,15 +364,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.
      */
@@ -329,9 +392,14 @@ class BaseCache : public MemObject
             blocked_causes[cause]++;
             blockedCycle = curTick;
         }
-        blocked |= flag;
-        DPRINTF(Cache,"Blocking for cause %s\n", cause);
-        cpuSidePort->setBlocked();
+        int old_state = blocked;
+        if (!(blocked & flag)) {
+            //Wasn't already blocked for this cause
+            blocked |= flag;
+            DPRINTF(Cache,"Blocking for cause %s\n", cause);
+            if (!old_state)
+                cpuSidePort->setBlocked();
+        }
     }
 
     /**
@@ -342,8 +410,13 @@ class BaseCache : public MemObject
     void setBlockedForSnoop(BlockedCause cause)
     {
         uint8_t flag = 1 << cause;
-        blockedSnoop |= flag;
-        memSidePort->setBlocked();
+        uint8_t old_state = blockedSnoop;
+        if (!(blockedSnoop & flag)) {
+            //Wasn't already blocked for this cause
+            blockedSnoop |= flag;
+            if (!old_state)
+                memSidePort->setBlocked();
+        }
     }
 
     /**
@@ -356,19 +429,24 @@ class BaseCache : public MemObject
     void clearBlocked(BlockedCause cause)
     {
         uint8_t flag = 1 << cause;
-        blocked &= ~flag;
-        blockedSnoop &= ~flag;
         DPRINTF(Cache,"Unblocking for cause %s, causes left=%i\n",
                 cause, blocked);
-        if (!isBlocked()) {
-            blocked_cycles[cause] += curTick - blockedCycle;
-            DPRINTF(Cache,"Unblocking from all causes\n");
-            cpuSidePort->clearBlocked();
+        if (blocked & flag)
+        {
+            blocked &= ~flag;
+            if (!isBlocked()) {
+                blocked_cycles[cause] += curTick - blockedCycle;
+                DPRINTF(Cache,"Unblocking from all causes\n");
+                cpuSidePort->clearBlocked();
+            }
         }
-        if (!isBlockedForSnoop()) {
-           memSidePort->clearBlocked();
+        if (blockedSnoop & flag)
+        {
+            blockedSnoop &= ~flag;
+            if (!isBlockedForSnoop()) {
+                memSidePort->clearBlocked();
+            }
         }
-
     }
 
     /**
@@ -387,10 +465,13 @@ class BaseCache : public MemObject
      */
     void setMasterRequest(RequestCause cause, Tick time)
     {
+        if (!doMasterRequest() && !memSidePort->waitingOnRetry)
+        {
+            BaseCache::CacheEvent * reqCpu = new BaseCache::CacheEvent(memSidePort);
+            reqCpu->schedule(time);
+        }
         uint8_t flag = 1<<cause;
         masterRequests |= flag;
-        assert("Implement\n" && 0);
-//     mi->pktuest(time);
     }
 
     /**
@@ -401,6 +482,7 @@ class BaseCache : public MemObject
     {
         uint8_t flag = 1<<cause;
         masterRequests &= ~flag;
+        checkDrain();
     }
 
     /**
@@ -419,10 +501,13 @@ class BaseCache : public MemObject
      */
     void setSlaveRequest(RequestCause cause, Tick time)
     {
+        if (!doSlaveRequest() && !cpuSidePort->waitingOnRetry)
+        {
+            BaseCache::CacheEvent * reqCpu = new BaseCache::CacheEvent(cpuSidePort);
+            reqCpu->schedule(time);
+        }
         uint8_t flag = 1<<cause;
         slaveRequests |= flag;
-        assert("Implement\n" && 0);
-//     si->pktuest(time);
     }
 
     /**
@@ -433,41 +518,61 @@ class BaseCache : public MemObject
     {
         uint8_t flag = 1<<cause;
         slaveRequests &= ~flag;
+        checkDrain();
     }
 
     /**
      * Send a response to the slave interface.
-     * @param req The request being responded to.
+     * @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("Implement\n" && 0);
-//     si->respond(pkt,time);
+        if (pkt->needsResponse()) {
+            CacheEvent *reqCpu = new CacheEvent(cpuSidePort, pkt);
+            reqCpu->schedule(time);
+        }
+        else {
+            if (pkt->cmd != Packet::UpgradeReq)
+            {
+                delete pkt->req;
+                delete pkt;
+            }
+        }
     }
 
     /**
      * Send a reponse to the slave interface and calculate miss latency.
-     * @param req The request to respond to.
+     * @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)
     {
-        if (!pkt->isUncacheable()) {
-            missLatency[pkt->cmd.toIndex()][pkt->thread_num] += time - pkt->time;
+        if (!pkt->req->isUncacheable()) {
+            missLatency[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/] += time - pkt->time;
+        }
+        if (pkt->needsResponse()) {
+            CacheEvent *reqCpu = new CacheEvent(cpuSidePort, pkt);
+            reqCpu->schedule(time);
+        }
+        else {
+            if (pkt->cmd != Packet::UpgradeReq)
+            {
+                delete pkt->req;
+                delete pkt;
+            }
         }
-        assert("Implement\n" && 0);
-//     si->respond(pkt,time);
     }
 
     /**
      * Suppliess the data if cache to cache transfers are enabled.
-     * @param req The bus transaction to fulfill.
+     * @param pkt The bus transaction to fulfill.
      */
-    void respondToSnoop(Packet *pkt)
+    void respondToSnoop(PacketPtr pkt, Tick time)
     {
-        assert("Implement\n" && 0);
-//     mi->respond(pkt,curTick + hitLatency);
+        assert (pkt->needsResponse());
+        CacheEvent *reqMem = new CacheEvent(memSidePort, pkt);
+        reqMem->schedule(time);
     }
 
     /**
@@ -475,6 +580,46 @@ class BaseCache : public MemObject
      * to do for a cache.
      */
     void rangeChange() {}
+
+    void getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop, bool isCpuSide)
+    {
+        if (isCpuSide)
+        {
+            AddrRangeList dummy;
+            memSidePort->getPeerAddressRanges(resp, dummy);
+        }
+        else
+        {
+            //This is where snoops get updated
+            AddrRangeList dummy;
+            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__