mem-cache: Forward declare ReplaceableEntry
[gem5.git] / src / mem / cache / base.cc
index efdb3be2ca8ae663abc8acad75a217aba60b0026..a510bac8ae11bba7025d37e4cebca2024a713766 100644 (file)
@@ -810,7 +810,6 @@ BaseCache::getNextQueueEntry()
                 return allocateMissBuffer(pkt, curTick(), false);
             } else {
                 // free the request and packet
-                delete pkt->req;
                 delete pkt;
             }
         }
@@ -837,7 +836,22 @@ BaseCache::satisfyRequest(PacketPtr pkt, CacheBlk *blk, bool, bool)
     // Check RMW operations first since both isRead() and
     // isWrite() will be true for them
     if (pkt->cmd == MemCmd::SwapReq) {
-        cmpAndSwap(blk, pkt);
+        if (pkt->isAtomicOp()) {
+            // extract data from cache and save it into the data field in
+            // the packet as a return value from this atomic op
+
+            int offset = tags->extractBlkOffset(pkt->getAddr());
+            uint8_t *blk_data = blk->data + offset;
+            std::memcpy(pkt->getPtr<uint8_t>(), blk_data, pkt->getSize());
+
+            // execute AMO operation
+            (*(pkt->getAtomicOp()))(blk_data);
+
+            // set block status to dirty
+            blk->status |= BlkDirty;
+        } else {
+            cmpAndSwap(blk, pkt);
+        }
     } else if (pkt->isWrite()) {
         // we have the block in a writable state and can go ahead,
         // note that the line may be also be considered writable in
@@ -971,13 +985,12 @@ BaseCache::access(PacketPtr pkt, CacheBlk *&blk, Cycles &lat,
 
         if (!blk) {
             // need to do a replacement
-            blk = allocateBlock(pkt->getAddr(), pkt->isSecure(), writebacks);
+            blk = allocateBlock(pkt, writebacks);
             if (!blk) {
                 // no replaceable block available: give up, fwd to next level.
                 incMissCount(pkt);
                 return false;
             }
-            tags->insertBlock(pkt, blk);
 
             blk->status |= (BlkValid | BlkReadable);
         }
@@ -1029,15 +1042,13 @@ BaseCache::access(PacketPtr pkt, CacheBlk *&blk, Cycles &lat,
                 return false;
             } else {
                 // a writeback that misses needs to allocate a new block
-                blk = allocateBlock(pkt->getAddr(), pkt->isSecure(),
-                                    writebacks);
+                blk = allocateBlock(pkt, writebacks);
                 if (!blk) {
                     // no replaceable block available: give up, fwd to
                     // next level.
                     incMissCount(pkt);
                     return false;
                 }
-                tags->insertBlock(pkt, blk);
 
                 blk->status |= (BlkValid | BlkReadable);
             }
@@ -1125,7 +1136,7 @@ BaseCache::handleFill(PacketPtr pkt, CacheBlk *blk, PacketList &writebacks,
 
         // need to do a replacement if allocating, otherwise we stick
         // with the temporary storage
-        blk = allocate ? allocateBlock(addr, is_secure, writebacks) : nullptr;
+        blk = allocate ? allocateBlock(pkt, writebacks) : nullptr;
 
         if (!blk) {
             // No replaceable block or a mostly exclusive
@@ -1136,15 +1147,13 @@ BaseCache::handleFill(PacketPtr pkt, CacheBlk *blk, PacketList &writebacks,
             tempBlock->insert(addr, is_secure);
             DPRINTF(Cache, "using temp block for %#llx (%s)\n", addr,
                     is_secure ? "s" : "ns");
-        } else {
-            tags->insertBlock(pkt, blk);
         }
 
         // we should never be overwriting a valid block
         assert(!blk->isValid());
     } else {
         // existing block... probably an upgrade
-        assert(blk->tag == tags->extractTag(addr));
+        assert(regenerateBlkAddr(blk) == addr);
         assert(blk->isSecure() == is_secure);
         // either we're getting new data or the block should already be valid
         assert(pkt->hasData() || blk->isValid());
@@ -1206,41 +1215,68 @@ BaseCache::handleFill(PacketPtr pkt, CacheBlk *blk, PacketList &writebacks,
 }
 
 CacheBlk*
-BaseCache::allocateBlock(Addr addr, bool is_secure, PacketList &writebacks)
+BaseCache::allocateBlock(const PacketPtr pkt, PacketList &writebacks)
 {
+    // Get address
+    const Addr addr = pkt->getAddr();
+
+    // Get secure bit
+    const bool is_secure = pkt->isSecure();
+
     // Find replacement victim
-    CacheBlk *blk = tags->findVictim(addr);
+    std::vector<CacheBlk*> evict_blks;
+    CacheBlk *victim = tags->findVictim(addr, is_secure, evict_blks);
 
     // It is valid to return nullptr if there is no victim
-    if (!blk)
+    if (!victim)
         return nullptr;
 
-    if (blk->isValid()) {
-        Addr repl_addr = regenerateBlkAddr(blk);
-        MSHR *repl_mshr = mshrQueue.findMatch(repl_addr, blk->isSecure());
-        if (repl_mshr) {
-            // must be an outstanding upgrade or clean request
-            // on a block we're about to replace...
-            assert((!blk->isWritable() && repl_mshr->needsWritable()) ||
-                   repl_mshr->isCleaning());
-            // too hard to replace block with transient state
-            // allocation failed, block not inserted
-            return nullptr;
-        } else {
-            DPRINTF(Cache, "replacement: replacing %#llx (%s) with %#llx "
-                    "(%s): %s\n", repl_addr, blk->isSecure() ? "s" : "ns",
-                    addr, is_secure ? "s" : "ns",
-                    blk->isDirty() ? "writeback" : "clean");
+    // Check for transient state allocations. If any of the entries listed
+    // for eviction has a transient state, the allocation fails
+    for (const auto& blk : evict_blks) {
+        if (blk->isValid()) {
+            Addr repl_addr = regenerateBlkAddr(blk);
+            MSHR *repl_mshr = mshrQueue.findMatch(repl_addr, blk->isSecure());
+            if (repl_mshr) {
+                // must be an outstanding upgrade or clean request
+                // on a block we're about to replace...
+                assert((!blk->isWritable() && repl_mshr->needsWritable()) ||
+                       repl_mshr->isCleaning());
+
+                // too hard to replace block with transient state
+                // allocation failed, block not inserted
+                return nullptr;
+            }
+        }
+    }
+
+    // The victim will be replaced by a new entry, so increase the replacement
+    // counter if a valid block is being replaced
+    if (victim->isValid()) {
+        DPRINTF(Cache, "replacement: replacing %#llx (%s) with %#llx "
+                "(%s): %s\n", regenerateBlkAddr(victim),
+                victim->isSecure() ? "s" : "ns",
+                addr, is_secure ? "s" : "ns",
+                victim->isDirty() ? "writeback" : "clean");
 
+        replacements++;
+    }
+
+    // Evict valid blocks associated to this victim block
+    for (const auto& blk : evict_blks) {
+        if (blk->isValid()) {
             if (blk->wasPrefetched()) {
                 unusedPrefetches++;
             }
+
             evictBlock(blk, writebacks);
-            replacements++;
         }
     }
 
-    return blk;
+    // Insert new block at victimized entry
+    tags->insertBlock(pkt, victim);
+
+    return victim;
 }
 
 void
@@ -1260,8 +1296,9 @@ BaseCache::writebackBlk(CacheBlk *blk)
 
     writebacks[Request::wbMasterId]++;
 
-    Request *req = new Request(regenerateBlkAddr(blk), blkSize, 0,
-                               Request::wbMasterId);
+    RequestPtr req = std::make_shared<Request>(
+        regenerateBlkAddr(blk), blkSize, 0, Request::wbMasterId);
+
     if (blk->isSecure())
         req->setFlags(Request::SECURE);
 
@@ -1295,8 +1332,9 @@ BaseCache::writebackBlk(CacheBlk *blk)
 PacketPtr
 BaseCache::writecleanBlk(CacheBlk *blk, Request::Flags dest, PacketId id)
 {
-    Request *req = new Request(regenerateBlkAddr(blk), blkSize, 0,
-                               Request::wbMasterId);
+    RequestPtr req = std::make_shared<Request>(
+        regenerateBlkAddr(blk), blkSize, 0, Request::wbMasterId);
+
     if (blk->isSecure()) {
         req->setFlags(Request::SECURE);
     }
@@ -1355,14 +1393,15 @@ BaseCache::writebackVisitor(CacheBlk &blk)
     if (blk.isDirty()) {
         assert(blk.isValid());
 
-        Request request(regenerateBlkAddr(&blk),
-                        blkSize, 0, Request::funcMasterId);
-        request.taskId(blk.task_id);
+        RequestPtr request = std::make_shared<Request>(
+            regenerateBlkAddr(&blk), blkSize, 0, Request::funcMasterId);
+
+        request->taskId(blk.task_id);
         if (blk.isSecure()) {
-            request.setFlags(Request::SECURE);
+            request->setFlags(Request::SECURE);
         }
 
-        Packet packet(&request, MemCmd::WriteReq);
+        Packet packet(request, MemCmd::WriteReq);
         packet.dataStatic(blk.data);
 
         memSidePort.sendFunctional(&packet);