MEM: Introduce the master/slave port sub-classes in C++
[gem5.git] / src / mem / cache / base.hh
index 601e9bd485b7de40691f02c95cb64b7bcdfb866e..47cbaf7a0c0fc3dbf3700799e5ceb4beb281f5f0 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) 2003-2005 The Regents of The University of Michigan
  * All rights reserved.
  *
 #ifndef __BASE_CACHE_HH__
 #define __BASE_CACHE_HH__
 
-#include <vector>
-#include <string>
-#include <list>
 #include <algorithm>
-#include <inttypes.h>
+#include <list>
+#include <string>
+#include <vector>
 
 #include "base/misc.hh"
 #include "base/statistics.hh"
 #include "base/trace.hh"
+#include "base/types.hh"
+#include "debug/Cache.hh"
+#include "debug/CachePort.hh"
 #include "mem/cache/mshr_queue.hh"
 #include "mem/mem_object.hh"
 #include "mem/packet.hh"
-#include "mem/tport.hh"
+#include "mem/qport.hh"
 #include "mem/request.hh"
 #include "params/BaseCache.hh"
 #include "sim/eventq.hh"
+#include "sim/full_system.hh"
 #include "sim/sim_exit.hh"
+#include "sim/system.hh"
 
 class MSHR;
 /**
@@ -70,6 +86,7 @@ class BaseCache : public MemObject
         MSHRQueue_WriteBuffer
     };
 
+  public:
     /**
      * Reasons for caches to be blocked.
      */
@@ -80,7 +97,6 @@ class BaseCache : public MemObject
         NUM_BLOCKED_CAUSES
     };
 
-  public:
     /**
      * Reasons for cache to request a bus.
      */
@@ -91,63 +107,109 @@ class BaseCache : public MemObject
         NUM_REQUEST_CAUSES
     };
 
-  private:
+  protected:
 
-    class CachePort : public SimpleTimingPort
+    /**
+     * A cache master port is used for the memory-side port of the
+     * cache, and in addition to the basic timing port that only sends
+     * response packets through a transmit list, it also offers the
+     * ability to schedule and send request packets (requests &
+     * writebacks). The send event is scheduled through requestBus,
+     * and the sendDeferredPacket of the timing port is modified to
+     * consider both the transmit list and the requests from the MSHR.
+     */
+    class CacheMasterPort : public QueuedMasterPort
     {
-      public:
-        BaseCache *cache;
 
-      protected:
-        CachePort(const std::string &_name, BaseCache *_cache,
-                  const std::string &_label,
-                  std::vector<Range<Addr> > filter_ranges);
+      public:
 
-        virtual void recvStatusChange(Status status);
+        /**
+         * Schedule a send of a request packet (from the MSHR). Note
+         * that we could already have a retry or a transmit list of
+         * responses outstanding.
+         */
+        void requestBus(RequestCause cause, Tick time)
+        {
+            DPRINTF(CachePort, "Asserting bus request for cause %d\n", cause);
+            queue.schedSendEvent(time);
+        }
 
-        virtual int deviceBlockSize();
+        /**
+         * Schedule the transmissions of a response packet at a given
+         * point in time.
+         *
+         * @param pkt response packet
+         * @param when time to send the response
+         */
+        void respond(PacketPtr pkt, Tick time) {
+            queue.schedSendTiming(pkt, time);
+        }
 
-        bool recvRetryCommon();
+      protected:
 
-        typedef EventWrapper<Port, &Port::sendRetry>
-            SendRetryEvent;
+        CacheMasterPort(const std::string &_name, BaseCache *_cache,
+                        PacketQueue &_queue) :
+            QueuedMasterPort(_name, _cache, _queue)
+        { }
+
+        /**
+         * Memory-side port always snoops.
+         *
+         * @return always true
+         */
+        virtual bool isSnooping() const { return true; }
+    };
 
-        const std::string label;
+    /**
+     * A cache slave port is used for the CPU-side port of the cache,
+     * and it is basically a simple timing port that uses a transmit
+     * list for responses to the CPU (or connected master). In
+     * addition, it has the functionality to block the port for
+     * incoming requests. If blocked, the port will issue a retry once
+     * unblocked.
+     */
+    class CacheSlavePort : public QueuedSlavePort
+    {
 
       public:
-        void setOtherPort(CachePort *_otherPort) { otherPort = _otherPort; }
 
+        /** Do not accept any new requests. */
         void setBlocked();
 
+        /** Return to normal operation and accept new requests. */
         void clearBlocked();
 
-        bool checkFunctional(PacketPtr pkt);
+        /**
+         * Schedule the transmissions of a response packet at a given
+         * point in time.
+         *
+         * @param pkt response packet
+         * @param when time to send the response
+         */
+        void respond(PacketPtr pkt, Tick time) {
+            queue.schedSendTiming(pkt, time);
+        }
+
+      protected:
 
-        CachePort *otherPort;
+        CacheSlavePort(const std::string &_name, BaseCache *_cache,
+                       const std::string &_label);
+
+        /** A normal packet queue used to store responses. */
+        PacketQueue queue;
 
         bool blocked;
 
         bool mustSendRetry;
 
-        /** filter ranges */
-        std::vector<Range<Addr> > filterRanges;
+      private:
 
-        void requestBus(RequestCause cause, Tick time)
-        {
-            DPRINTF(CachePort, "Asserting bus request for cause %d\n", cause);
-            if (!waitingOnRetry) {
-                schedSendEvent(time);
-            }
-        }
+        EventWrapper<Port, &Port::sendRetry> sendRetryEvent;
 
-        void respond(PacketPtr pkt, Tick time) {
-            schedSendTiming(pkt, time);
-        }
     };
 
-  public: //Made public so coherence can get at it.
-    CachePort *cpuSidePort;
-    CachePort *memSidePort;
+    CacheSlavePort *cpuSidePort;
+    CacheMasterPort *memSidePort;
 
   protected:
 
@@ -173,18 +235,18 @@ class BaseCache : public MemObject
         return mshr;
     }
 
-    void markInServiceInternal(MSHR *mshr)
+    void markInServiceInternal(MSHR *mshr, PacketPtr pkt)
     {
         MSHRQueue *mq = mshr->queue;
         bool wasFull = mq->isFull();
-        mq->markInService(mshr);
+        mq->markInService(mshr, pkt);
         if (wasFull && !mq->isFull()) {
             clearBlocked((BlockedCause)mq->index);
         }
     }
 
     /** Block size of this cache */
-    const int blkSize;
+    const unsigned blkSize;
 
     /**
      * The latency of a hit in this device.
@@ -194,8 +256,13 @@ class BaseCache : public MemObject
     /** The number of targets for each MSHR. */
     const int numTarget;
 
-    /** Increasing order number assigned to each incoming request. */
-    uint64_t order;
+    /** Do we forward snoops from mem side port through to cpu side port? */
+    bool forwardSnoops;
+
+    /** Is this cache a toplevel cache (e.g. L1, I/O cache). If so we should
+     * never try to forward ownership and similar optimizations to the cpu
+     * side */
+    bool isTopLevel;
 
     /**
      * Bit vector of the blocking reasons for the access path.
@@ -203,6 +270,9 @@ class BaseCache : public MemObject
      */
     uint8_t blocked;
 
+    /** Increasing order number assigned to each incoming request. */
+    uint64_t order;
+
     /** Stores time the cache blocked for statistics. */
     Tick blockedCycle;
 
@@ -215,7 +285,15 @@ class BaseCache : public MemObject
     /** The drain event. */
     Event *drainEvent;
 
+    /**
+     * The address range to which the cache responds on the CPU side.
+     * Normally this is all possible memory addresses. */
+    AddrRangeList addrRanges;
+
   public:
+    /** System we are currently operating in. */
+    System *system;
+
     // Statistics
     /**
      * @addtogroup CacheStatistics
@@ -223,14 +301,14 @@ class BaseCache : public MemObject
      */
 
     /** Number of hits per thread for each type of command. @sa Packet::Command */
-    Stats::Vector<> hits[MemCmd::NUM_MEM_CMDS];
+    Stats::Vector hits[MemCmd::NUM_MEM_CMDS];
     /** Number of hits for demand accesses. */
     Stats::Formula demandHits;
     /** Number of hit for all accesses. */
     Stats::Formula overallHits;
 
     /** Number of misses per thread for each type of command. @sa Packet::Command */
-    Stats::Vector<> misses[MemCmd::NUM_MEM_CMDS];
+    Stats::Vector misses[MemCmd::NUM_MEM_CMDS];
     /** Number of misses for demand accesses. */
     Stats::Formula demandMisses;
     /** Number of misses for all accesses. */
@@ -240,7 +318,7 @@ class BaseCache : public MemObject
      * Total number of cycles per thread/command spent waiting for a miss.
      * Used to calculate the average miss latency.
      */
-    Stats::Vector<> missLatency[MemCmd::NUM_MEM_CMDS];
+    Stats::Vector missLatency[MemCmd::NUM_MEM_CMDS];
     /** Total number of cycles spent waiting for demand misses. */
     Stats::Formula demandMissLatency;
     /** Total number of cycles spent waiting for all misses. */
@@ -268,59 +346,61 @@ class BaseCache : public MemObject
     Stats::Formula overallAvgMissLatency;
 
     /** The total number of cycles blocked for each blocked cause. */
-    Stats::Vector<> blocked_cycles;
+    Stats::Vector blocked_cycles;
     /** The number of times this cache blocked for each blocked cause. */
-    Stats::Vector<> blocked_causes;
+    Stats::Vector blocked_causes;
 
     /** The average number of cycles blocked for each blocked cause. */
     Stats::Formula avg_blocked;
 
     /** The number of fast writes (WH64) performed. */
-    Stats::Scalar<> fastWrites;
+    Stats::Scalar fastWrites;
 
     /** The number of cache copies performed. */
-    Stats::Scalar<> cacheCopies;
+    Stats::Scalar cacheCopies;
 
     /** Number of blocks written back per thread. */
-    Stats::Vector<> writebacks;
+    Stats::Vector writebacks;
 
     /** Number of misses that hit in the MSHRs per command and thread. */
-    Stats::Vector<> mshr_hits[MemCmd::NUM_MEM_CMDS];
+    Stats::Vector mshr_hits[MemCmd::NUM_MEM_CMDS];
     /** Demand misses that hit in the MSHRs. */
     Stats::Formula demandMshrHits;
     /** Total number of misses that hit in the MSHRs. */
     Stats::Formula overallMshrHits;
 
     /** Number of misses that miss in the MSHRs, per command and thread. */
-    Stats::Vector<> mshr_misses[MemCmd::NUM_MEM_CMDS];
+    Stats::Vector mshr_misses[MemCmd::NUM_MEM_CMDS];
     /** Demand misses that miss in the MSHRs. */
     Stats::Formula demandMshrMisses;
     /** Total number of misses that miss in the MSHRs. */
     Stats::Formula overallMshrMisses;
 
     /** Number of misses that miss in the MSHRs, per command and thread. */
-    Stats::Vector<> mshr_uncacheable[MemCmd::NUM_MEM_CMDS];
+    Stats::Vector mshr_uncacheable[MemCmd::NUM_MEM_CMDS];
     /** Total number of misses that miss in the MSHRs. */
     Stats::Formula overallMshrUncacheable;
 
     /** Total cycle latency of each MSHR miss, per command and thread. */
-    Stats::Vector<> mshr_miss_latency[MemCmd::NUM_MEM_CMDS];
+    Stats::Vector mshr_miss_latency[MemCmd::NUM_MEM_CMDS];
     /** Total cycle latency of demand MSHR misses. */
     Stats::Formula demandMshrMissLatency;
     /** Total cycle latency of overall MSHR misses. */
     Stats::Formula overallMshrMissLatency;
 
     /** Total cycle latency of each MSHR miss, per command and thread. */
-    Stats::Vector<> mshr_uncacheable_lat[MemCmd::NUM_MEM_CMDS];
+    Stats::Vector mshr_uncacheable_lat[MemCmd::NUM_MEM_CMDS];
     /** Total cycle latency of overall MSHR misses. */
     Stats::Formula overallMshrUncacheableLatency;
 
+#if 0
     /** The total number of MSHR accesses per command and thread. */
     Stats::Formula mshrAccesses[MemCmd::NUM_MEM_CMDS];
     /** The total number of demand MSHR accesses. */
     Stats::Formula demandMshrAccesses;
     /** The total number of MSHR accesses. */
     Stats::Formula overallMshrAccesses;
+#endif
 
     /** The miss rate in the MSHRs pre command and thread. */
     Stats::Formula mshrMissRate[MemCmd::NUM_MEM_CMDS];
@@ -342,11 +422,11 @@ class BaseCache : public MemObject
     Stats::Formula overallAvgMshrUncacheableLatency;
 
     /** The number of times a thread hit its MSHR cap. */
-    Stats::Vector<> mshr_cap_events;
+    Stats::Vector mshr_cap_events;
     /** The number of times software prefetches caused the MSHR to block. */
-    Stats::Vector<> soft_prefetch_mshr_full;
+    Stats::Vector soft_prefetch_mshr_full;
 
-    Stats::Scalar<> mshr_no_allocate_misses;
+    Stats::Scalar mshr_no_allocate_misses;
 
     /**
      * @}
@@ -364,19 +444,25 @@ class BaseCache : public MemObject
 
     virtual void init();
 
+    virtual MasterPort &getMasterPort(const std::string &if_name, int idx = -1);
+    virtual SlavePort &getSlavePort(const std::string &if_name, int idx = -1);
+
     /**
      * Query block size of a cache.
      * @return  The block size
      */
-    int getBlockSize() const
+    unsigned
+    getBlockSize() const
     {
         return blkSize;
     }
 
 
-    Addr blockAlign(Addr addr) const { return (addr & ~(blkSize - 1)); }
+    Addr blockAlign(Addr addr) const { return (addr & ~(Addr(blkSize - 1))); }
 
 
+    const AddrRangeList &getAddrRanges() const { return addrRanges; }
+
     MSHR *allocateMissBuffer(PacketPtr pkt, Tick time, bool requestBus)
     {
         assert(!pkt->req->isUncacheable());
@@ -420,7 +506,7 @@ class BaseCache : public MemObject
         uint8_t flag = 1 << cause;
         if (blocked == 0) {
             blocked_causes[cause]++;
-            blockedCycle = curTick;
+            blockedCycle = curTick();
             cpuSidePort->setBlocked();
         }
         blocked |= flag;
@@ -440,17 +526,11 @@ class BaseCache : public MemObject
         blocked &= ~flag;
         DPRINTF(Cache,"Unblocking for cause %d, mask=%d\n", cause, blocked);
         if (blocked == 0) {
-            blocked_cycles[cause] += curTick - blockedCycle;
+            blocked_cycles[cause] += curTick() - blockedCycle;
             cpuSidePort->clearBlocked();
         }
     }
 
-    Tick nextMSHRReadyTime()
-    {
-        return std::min(mshrQueue.nextMSHRReadyTime(),
-                        writeBuffer.nextMSHRReadyTime());
-    }
-
     /**
      * Request the master bus for the given cause and time.
      * @param cause The reason for the request.
@@ -467,10 +547,11 @@ class BaseCache : public MemObject
      */
     void deassertMemSideBusRequest(RequestCause cause)
     {
-        // obsolete!!
-        assert(false);
-        // memSidePort->deassertBusRequest(cause);
-        // checkDrain();
+        // Obsolete... we no longer signal bus requests explicitly so
+        // we can't deassert them.  Leaving this in as a no-op since
+        // the prefetcher calls it to indicate that it no longer wants
+        // to request a prefetch, and someday that might be
+        // interesting again.
     }
 
     virtual unsigned int drain(Event *de);
@@ -481,7 +562,8 @@ class BaseCache : public MemObject
 
     void incMissCount(PacketPtr pkt)
     {
-        misses[pkt->cmdToIndex()][0/*pkt->req->threadId()*/]++;
+        assert(pkt->req->masterId() < system->maxMasters());
+        misses[pkt->cmdToIndex()][pkt->req->masterId()]++;
 
         if (missCount) {
             --missCount;
@@ -489,6 +571,12 @@ class BaseCache : public MemObject
                 exitSimLoop("A cache reached the maximum miss count");
         }
     }
+    void incHitCount(PacketPtr pkt)
+    {
+        assert(pkt->req->masterId() < system->maxMasters());
+        hits[pkt->cmdToIndex()][pkt->req->masterId()]++;
+
+    }
 
 };