From 7bab1d0aff897bc23b5677a51ae67b8cc32953dc Mon Sep 17 00:00:00 2001 From: Tuan Ta Date: Mon, 22 Jan 2018 12:54:14 -0500 Subject: [PATCH] base,mem: Support AtomicOpFunctor in the classic memory system 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 Maintainer: Nikos Nikoleris --- src/base/types.hh | 2 ++ src/mem/cache/base.cc | 17 ++++++++++++++++- src/mem/packet.hh | 2 +- src/mem/request.hh | 25 ++++++++++++++++++++++--- 4 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/base/types.hh b/src/base/types.hh index 05a29f8bd..d07c370ab 100644 --- a/src/base/types.hh +++ b/src/base/types.hh @@ -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 struct TypedAtomicOpFunctor : public AtomicOpFunctor { void operator()(uint8_t *p) { execute((T *)p); } + virtual AtomicOpFunctor* clone() = 0; virtual void execute(T * p) = 0; }; diff --git a/src/mem/cache/base.cc b/src/mem/cache/base.cc index e43c3d920..a510bac8a 100644 --- a/src/mem/cache/base.cc +++ b/src/mem/cache/base.cc @@ -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(), 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 diff --git a/src/mem/packet.hh b/src/mem/packet.hh index 5bc466bf1..5c041120a 100644 --- a/src/mem/packet.hh +++ b/src/mem/packet.hh @@ -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 : diff --git a/src/mem/request.hh b/src/mem/request.hh index 1615a644a..189d160ab 100644 --- a/src/mem/request.hh +++ b/src/mem/request.hh @@ -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; } /** -- 2.30.2