base,mem: Support AtomicOpFunctor in the classic memory system
authorTuan Ta <qtt2@cornell.edu>
Mon, 22 Jan 2018 17:54:14 +0000 (12:54 -0500)
committerTuan Ta <qtt2@cornell.edu>
Thu, 14 Jun 2018 22:41:11 +0000 (22:41 +0000)
AtomicOpFunctor can be used to implement atomic memory operations.
AtomicOpFunctor is captured inside a memory request and executed directly
in the memory hierarchy in a single step.

This patch enables AtomicOpFunctor pointers to be included in a memory
request and executed in a single step in the classic cache system.

This patch also makes the copy constructor of Request class do a deep
copy of AtomicOpFunctor object. This prevents a copy of a Request object
from accessing a deleted AtomicOpFunctor object.

Change-Id: I6649532b37f711e55f4552ad26893efeb300dd37
Reviewed-on: https://gem5-review.googlesource.com/8185
Reviewed-by: Nikos Nikoleris <nikos.nikoleris@arm.com>
Maintainer: Nikos Nikoleris <nikos.nikoleris@arm.com>

src/base/types.hh
src/mem/cache/base.cc
src/mem/packet.hh
src/mem/request.hh

index 05a29f8bdb33515d148199289fa34454e550dd4a..d07c370ab514d0ebe00d5c97ae632e467474ac6a 100644 (file)
@@ -191,6 +191,7 @@ constexpr decltype(nullptr) NoFault = nullptr;
 struct AtomicOpFunctor
 {
     virtual void operator()(uint8_t *p) = 0;
+    virtual AtomicOpFunctor* clone() = 0;
     virtual ~AtomicOpFunctor() {}
 };
 
@@ -198,6 +199,7 @@ template <class T>
 struct TypedAtomicOpFunctor : public AtomicOpFunctor
 {
     void operator()(uint8_t *p) { execute((T *)p); }
+    virtual AtomicOpFunctor* clone() = 0;
     virtual void execute(T * p) = 0;
 };
 
index e43c3d9200d969c882e0266691d68d99fc82f87f..a510bac8ae11bba7025d37e4cebca2024a713766 100644 (file)
@@ -836,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
index 5bc466bf117bb63f41954a6f93a7a05cf6b13bfc..5c041120aab78c82ed3023e6725a87ae54f20e39 100644 (file)
@@ -841,7 +841,7 @@ class Packet : public Printable
     {
         if (req->isLLSC())
             return MemCmd::StoreCondReq;
-        else if (req->isSwap())
+        else if (req->isSwap() || req->isAtomic())
             return MemCmd::SwapReq;
         else if (req->isCacheInvalidate()) {
           return req->isCacheClean() ? MemCmd::CleanInvalidReq :
index 1615a644acbbd691e20b1c61ea42c61fcf6e34ff..189d160ab90dea26bb080c4f68b2149570e00fde 100644 (file)
@@ -445,12 +445,30 @@ class Request
 
     Request(int asid, Addr vaddr, unsigned size, Flags flags, MasterID mid,
             Addr pc, ContextID cid, AtomicOpFunctor *atomic_op)
-        : atomicOpFunctor(atomic_op)
     {
-        setVirt(asid, vaddr, size, flags, mid, pc);
+        setVirt(asid, vaddr, size, flags, mid, pc, atomic_op);
         setContext(cid);
     }
 
+    Request(const Request& other)
+        : _paddr(other._paddr), _size(other._size),
+          _masterId(other._masterId),
+          _flags(other._flags),
+          _memSpaceConfigFlags(other._memSpaceConfigFlags),
+          privateFlags(other.privateFlags),
+          _time(other._time),
+          _taskId(other._taskId), _asid(other._asid), _vaddr(other._vaddr),
+          _extraData(other._extraData), _contextId(other._contextId),
+          _pc(other._pc), _reqInstSeqNum(other._reqInstSeqNum),
+          translateDelta(other.translateDelta),
+          accessDelta(other.accessDelta), depth(other.depth)
+    {
+        if (other.atomicOpFunctor)
+            atomicOpFunctor = (other.atomicOpFunctor)->clone();
+        else
+            atomicOpFunctor = nullptr;
+    }
+
     ~Request()
     {
         if (hasAtomicOpFunctor()) {
@@ -474,7 +492,7 @@ class Request
      */
     void
     setVirt(int asid, Addr vaddr, unsigned size, Flags flags, MasterID mid,
-            Addr pc)
+            Addr pc, AtomicOpFunctor *amo_op = nullptr)
     {
         _asid = asid;
         _vaddr = vaddr;
@@ -490,6 +508,7 @@ class Request
         depth = 0;
         accessDelta = 0;
         translateDelta = 0;
+        atomicOpFunctor = amo_op;
     }
 
     /**