mem: Respond to InvalidateReq when the block is (pending) dirty
[gem5.git] / src / mem / cache / base.hh
index bda3df34a9e8825f4eb8b2479d81588cb821b6ee..4b89be967f916c9b6a4687b556ee6b6ff7ae7b3f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2013, 2015 ARM Limited
+ * Copyright (c) 2012-2013, 2015-2016 ARM Limited
  * All rights reserved.
  *
  * The license below extends only to copyright in the software and shall
@@ -47,8 +47,8 @@
  * Declares a basic cache interface BaseCache.
  */
 
-#ifndef __BASE_CACHE_HH__
-#define __BASE_CACHE_HH__
+#ifndef __MEM_CACHE_BASE_HH__
+#define __MEM_CACHE_BASE_HH__
 
 #include <algorithm>
 #include <list>
@@ -62,6 +62,7 @@
 #include "debug/Cache.hh"
 #include "debug/CachePort.hh"
 #include "mem/cache/mshr_queue.hh"
+#include "mem/cache/write_queue.hh"
 #include "mem/mem_object.hh"
 #include "mem/packet.hh"
 #include "mem/qport.hh"
 #include "sim/sim_exit.hh"
 #include "sim/system.hh"
 
-class MSHR;
 /**
  * A basic cache interface. Implements some common functions for speed.
  */
 class BaseCache : public MemObject
 {
+  protected:
     /**
      * Indexes to enumerate the MSHR queues.
      */
@@ -97,16 +98,6 @@ class BaseCache : public MemObject
         NUM_BLOCKED_CAUSES
     };
 
-    /**
-     * Reasons for cache to request a bus.
-     */
-    enum RequestCause {
-        Request_MSHR = MSHRQueue_MSHRs,
-        Request_WB = MSHRQueue_WriteBuffer,
-        Request_PF,
-        NUM_REQUEST_CAUSES
-    };
-
   protected:
 
     /**
@@ -114,7 +105,7 @@ class BaseCache : public MemObject
      * 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,
+     * writebacks). The send event is scheduled through schedSendEvent,
      * and the sendDeferredPacket of the timing port is modified to
      * consider both the transmit list and the requests from the MSHR.
      */
@@ -127,9 +118,9 @@ class BaseCache : public MemObject
          * Schedule a send of a request packet (from the MSHR). Note
          * that we could already have a retry outstanding.
          */
-        void requestBus(RequestCause cause, Tick time)
+        void schedSendEvent(Tick time)
         {
-            DPRINTF(CachePort, "Asserting bus request for cause %d\n", cause);
+            DPRINTF(CachePort, "Scheduling send event at %llu\n", time);
             reqQueue.schedSendEvent(time);
         }
 
@@ -200,45 +191,41 @@ class BaseCache : public MemObject
     MSHRQueue mshrQueue;
 
     /** Write/writeback buffer */
-    MSHRQueue writeBuffer;
+    WriteQueue writeBuffer;
 
     /**
-     * Allocate a buffer, passing the time indicating when schedule an
-     * event to the queued port to go and ask the MSHR and write queue
-     * if they have packets to send.
-     *
-     * allocateBufferInternal() function is called in:
-     * - MSHR allocateWriteBuffer (unchached write forwarded to WriteBuffer);
-     * - MSHR allocateMissBuffer (cacheable miss in MSHR queue);
-     * - MSHR allocateUncachedReadBuffer (unchached read allocated in MSHR
-     *   queue)
+     * Mark a request as in service (sent downstream in the memory
+     * system), effectively making this MSHR the ordering point.
      */
-    MSHR *allocateBufferInternal(MSHRQueue *mq, Addr addr, int size,
-                                 PacketPtr pkt, Tick time, bool requestBus)
+    void markInService(MSHR *mshr, bool pending_modified_resp)
     {
-        MSHR *mshr = mq->allocate(addr, size, pkt, time, order++);
+        bool wasFull = mshrQueue.isFull();
+        mshrQueue.markInService(mshr, pending_modified_resp);
 
-        if (mq->isFull()) {
-            setBlocked((BlockedCause)mq->index);
+        if (wasFull && !mshrQueue.isFull()) {
+            clearBlocked(Blocked_NoMSHRs);
         }
-
-        if (requestBus) {
-            requestMemSideBus((RequestCause)mq->index, time);
-        }
-
-        return mshr;
     }
 
-    void markInServiceInternal(MSHR *mshr, bool pending_dirty_resp)
+    void markInService(WriteQueueEntry *entry)
     {
-        MSHRQueue *mq = mshr->queue;
-        bool wasFull = mq->isFull();
-        mq->markInService(mshr, pending_dirty_resp);
-        if (wasFull && !mq->isFull()) {
-            clearBlocked((BlockedCause)mq->index);
+        bool wasFull = writeBuffer.isFull();
+        writeBuffer.markInService(entry);
+
+        if (wasFull && !writeBuffer.isFull()) {
+            clearBlocked(Blocked_NoWBBuffers);
         }
     }
 
+    /**
+     * Determine if we should allocate on a fill or not.
+     *
+     * @param cmd Packet command being added as an MSHR target
+     *
+     * @return Whether we should allocate on a fill or not
+     */
+    virtual bool allocOnFill(MemCmd cmd) const = 0;
+
     /**
      * Write back dirty blocks in the cache using functional accesses.
      */
@@ -258,6 +245,16 @@ class BaseCache : public MemObject
      */
     virtual bool isDirty() const = 0;
 
+    /**
+     * Determine if an address is in the ranges covered by this
+     * cache. This is useful to filter snoops.
+     *
+     * @param addr Address to check against
+     *
+     * @return If the address in question is in range
+     */
+    bool inRange(Addr addr) const;
+
     /** Block size of this cache */
     const unsigned blkSize;
 
@@ -267,6 +264,12 @@ class BaseCache : public MemObject
      */
     const Cycles lookupLatency;
 
+    /**
+     * The latency of data access of a cache. It occurs when there is
+     * an access to the cache.
+     */
+    const Cycles dataLatency;
+
     /**
      * This is the forward latency of the cache. It occurs when there
      * is a cache miss and a request is forwarded downstream, in
@@ -288,12 +291,15 @@ class BaseCache : public MemObject
     const int numTarget;
 
     /** Do we forward snoops from mem side port through to cpu side port? */
-    const bool forwardSnoops;
+    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 */
-    const bool isTopLevel;
+    /**
+     * Is this cache read only, for example the instruction cache, or
+     * table-walker cache. A cache that is read only should never see
+     * any writes, and should never get any dirty data (and hence
+     * never have to do any writebacks).
+     */
+    const bool isReadOnly;
 
     /**
      * Bit vector of the blocking reasons for the access path.
@@ -328,14 +334,16 @@ class BaseCache : public MemObject
      * @{
      */
 
-    /** Number of hits per thread for each type of command. @sa Packet::Command */
+    /** Number of hits per thread for each type of command.
+        @sa Packet::Command */
     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 */
+    /** Number of misses per thread for each type of command.
+        @sa Packet::Command */
     Stats::Vector misses[MemCmd::NUM_MEM_CMDS];
     /** Number of misses for demand accesses. */
     Stats::Formula demandMisses;
@@ -381,11 +389,8 @@ class BaseCache : public MemObject
     /** The average number of cycles blocked for each blocked cause. */
     Stats::Formula avg_blocked;
 
-    /** The number of fast writes (WH64) performed. */
-    Stats::Scalar fastWrites;
-
-    /** The number of cache copies performed. */
-    Stats::Scalar cacheCopies;
+    /** The number of times a HW-prefetched block is evicted w/o reference. */
+    Stats::Scalar unusedPrefetches;
 
     /** Number of blocks written back per thread. */
     Stats::Vector writebacks;
@@ -449,13 +454,6 @@ class BaseCache : public MemObject
     /** The average overall latency of an MSHR miss. */
     Stats::Formula overallAvgMshrUncacheableLatency;
 
-    /** The number of times a thread hit its MSHR cap. */
-    Stats::Vector mshr_cap_events;
-    /** The number of times software prefetches caused the MSHR to block. */
-    Stats::Vector soft_prefetch_mshr_full;
-
-    Stats::Scalar mshr_no_allocate_misses;
-
     /**
      * @}
      */
@@ -466,8 +464,7 @@ class BaseCache : public MemObject
     virtual void regStats();
 
   public:
-    typedef BaseCacheParams Params;
-    BaseCache(const Params *p);
+    BaseCache(const BaseCacheParams *p, unsigned blk_size);
     ~BaseCache() {}
 
     virtual void init();
@@ -493,29 +490,45 @@ class BaseCache : public MemObject
 
     const AddrRangeList &getAddrRanges() const { return addrRanges; }
 
-    MSHR *allocateMissBuffer(PacketPtr pkt, Tick time, bool requestBus)
+    MSHR *allocateMissBuffer(PacketPtr pkt, Tick time, bool sched_send = true)
     {
-        assert(!pkt->req->isUncacheable());
-        return allocateBufferInternal(&mshrQueue,
-                                      blockAlign(pkt->getAddr()), blkSize,
-                                      pkt, time, requestBus);
-    }
+        MSHR *mshr = mshrQueue.allocate(blockAlign(pkt->getAddr()), blkSize,
+                                        pkt, time, order++,
+                                        allocOnFill(pkt->cmd));
 
-    MSHR *allocateWriteBuffer(PacketPtr pkt, Tick time, bool requestBus)
-    {
-        assert(pkt->isWrite() && !pkt->isRead());
-        return allocateBufferInternal(&writeBuffer,
-                                      pkt->getAddr(), pkt->getSize(),
-                                      pkt, time, requestBus);
+        if (mshrQueue.isFull()) {
+            setBlocked((BlockedCause)MSHRQueue_MSHRs);
+        }
+
+        if (sched_send) {
+            // schedule the send
+            schedMemSideSendEvent(time);
+        }
+
+        return mshr;
     }
 
-    MSHR *allocateUncachedReadBuffer(PacketPtr pkt, Tick time, bool requestBus)
+    void allocateWriteBuffer(PacketPtr pkt, Tick time)
     {
-        assert(pkt->req->isUncacheable());
-        assert(pkt->isRead());
-        return allocateBufferInternal(&mshrQueue,
-                                      pkt->getAddr(), pkt->getSize(),
-                                      pkt, time, requestBus);
+        // should only see writes or clean evicts here
+        assert(pkt->isWrite() || pkt->cmd == MemCmd::CleanEvict);
+
+        Addr blk_addr = blockAlign(pkt->getAddr());
+
+        WriteQueueEntry *wq_entry =
+            writeBuffer.findMatch(blk_addr, pkt->isSecure());
+        if (wq_entry && !wq_entry->inService) {
+            DPRINTF(Cache, "Potential to merge writeback %s", pkt->print());
+        }
+
+        writeBuffer.allocate(blk_addr, blkSize, pkt, time, order++);
+
+        if (writeBuffer.isFull()) {
+            setBlocked((BlockedCause)MSHRQueue_WriteBuffer);
+        }
+
+        // schedule the send
+        schedMemSideSendEvent(time);
     }
 
     /**
@@ -562,30 +575,18 @@ class BaseCache : public MemObject
     }
 
     /**
-     * Request the master bus for the given cause and time.
-     * @param cause The reason for the request.
-     * @param time The time to make the request.
-     */
-    void requestMemSideBus(RequestCause cause, Tick time)
-    {
-        memSidePort->requestBus(cause, time);
-    }
-
-    /**
-     * Clear the master bus request for the given cause.
-     * @param cause The request reason to clear.
+     * Schedule a send event for the memory-side port. If already
+     * scheduled, this may reschedule the event at an earlier
+     * time. When the specified time is reached, the port is free to
+     * send either a response, a request, or a prefetch request.
+     *
+     * @param time The time when to attempt sending a packet.
      */
-    void deassertMemSideBusRequest(RequestCause cause)
+    void schedMemSideSendEvent(Tick time)
     {
-        // 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.
+        memSidePort->schedSendEvent(time);
     }
 
-    virtual unsigned int drain(DrainManager *dm);
-
     virtual bool inCache(Addr addr, bool is_secure) const = 0;
 
     virtual bool inMissQueue(Addr addr, bool is_secure) const = 0;
@@ -610,4 +611,4 @@ class BaseCache : public MemObject
 
 };
 
-#endif //__BASE_CACHE_HH__
+#endif //__MEM_CACHE_BASE_HH__