summaryrefslogtreecommitdiff
path: root/src/mem
diff options
context:
space:
mode:
authorSteve Reinhardt <stever@eecs.umich.edu>2006-10-08 10:53:24 -0700
committerSteve Reinhardt <stever@eecs.umich.edu>2006-10-08 10:53:24 -0700
commitd3fba5aa30adfb006b99895e869ed175213d0134 (patch)
tree461b216e3efae357acc2939fcc17d67bd5903e7c /src/mem
parentbe36c808f77cfcb001aacb8cb32f45fb5909e00e (diff)
downloadgem5-d3fba5aa30adfb006b99895e869ed175213d0134.tar.xz
Implement Alpha LL/SC support for SimpleCPU (Atomic & Timing)
and PhysicalMemory. *No* support for caches or O3CPU. Note that properly setting cpu_id on all CPUs is now required for correct operation. src/arch/SConscript: src/base/traceflags.py: src/cpu/base.hh: src/cpu/simple/atomic.cc: src/cpu/simple/timing.cc: src/cpu/simple/timing.hh: src/mem/physical.cc: src/mem/physical.hh: src/mem/request.hh: src/python/m5/objects/BaseCPU.py: tests/configs/simple-atomic.py: tests/configs/simple-timing.py: tests/configs/tsunami-simple-atomic-dual.py: tests/configs/tsunami-simple-atomic.py: tests/configs/tsunami-simple-timing-dual.py: tests/configs/tsunami-simple-timing.py: Implement Alpha LL/SC support for SimpleCPU (Atomic & Timing) and PhysicalMemory. *No* support for caches or O3CPU. --HG-- extra : convert_revision : 6ce982d44924cc477e049b9adf359818908e72be
Diffstat (limited to 'src/mem')
-rw-r--r--src/mem/physical.cc95
-rw-r--r--src/mem/physical.hh62
-rw-r--r--src/mem/request.hh6
3 files changed, 154 insertions, 9 deletions
diff --git a/src/mem/physical.cc b/src/mem/physical.cc
index 8fea733ec..23b1d5ffc 100644
--- a/src/mem/physical.cc
+++ b/src/mem/physical.cc
@@ -110,6 +110,88 @@ PhysicalMemory::calculateLatency(Packet *pkt)
return lat;
}
+
+
+// Add load-locked to tracking list. Should only be called if the
+// operation is a load and the LOCKED flag is set.
+void
+PhysicalMemory::trackLoadLocked(Request *req)
+{
+ Addr paddr = LockedAddr::mask(req->getPaddr());
+
+ // first we check if we already have a locked addr for this
+ // xc. Since each xc only gets one, we just update the
+ // existing record with the new address.
+ list<LockedAddr>::iterator i;
+
+ for (i = lockedAddrList.begin(); i != lockedAddrList.end(); ++i) {
+ if (i->matchesContext(req)) {
+ DPRINTF(LLSC, "Modifying lock record: cpu %d thread %d addr %#x\n",
+ req->getCpuNum(), req->getThreadNum(), paddr);
+ i->addr = paddr;
+ return;
+ }
+ }
+
+ // no record for this xc: need to allocate a new one
+ DPRINTF(LLSC, "Adding lock record: cpu %d thread %d addr %#x\n",
+ req->getCpuNum(), req->getThreadNum(), paddr);
+ lockedAddrList.push_front(LockedAddr(req));
+}
+
+
+// Called on *writes* only... both regular stores and
+// store-conditional operations. Check for conventional stores which
+// conflict with locked addresses, and for success/failure of store
+// conditionals.
+bool
+PhysicalMemory::checkLockedAddrList(Request *req)
+{
+ Addr paddr = LockedAddr::mask(req->getPaddr());
+ bool isLocked = req->isLocked();
+
+ // Initialize return value. Non-conditional stores always
+ // succeed. Assume conditional stores will fail until proven
+ // otherwise.
+ bool success = !isLocked;
+
+ // Iterate over list. Note that there could be multiple matching
+ // records, as more than one context could have done a load locked
+ // to this location.
+ list<LockedAddr>::iterator i = lockedAddrList.begin();
+
+ while (i != lockedAddrList.end()) {
+
+ if (i->addr == paddr) {
+ // we have a matching address
+
+ if (isLocked && i->matchesContext(req)) {
+ // it's a store conditional, and as far as the memory
+ // system can tell, the requesting context's lock is
+ // still valid.
+ DPRINTF(LLSC, "StCond success: cpu %d thread %d addr %#x\n",
+ req->getCpuNum(), req->getThreadNum(), paddr);
+ success = true;
+ }
+
+ // Get rid of our record of this lock and advance to next
+ DPRINTF(LLSC, "Erasing lock record: cpu %d thread %d addr %#x\n",
+ i->cpuNum, i->threadNum, paddr);
+ i = lockedAddrList.erase(i);
+ }
+ else {
+ // no match: advance to next record
+ ++i;
+ }
+ }
+
+ if (isLocked) {
+ req->setScResult(success ? 1 : 0);
+ }
+
+ return success;
+}
+
void
PhysicalMemory::doFunctionalAccess(Packet *pkt)
{
@@ -117,18 +199,17 @@ PhysicalMemory::doFunctionalAccess(Packet *pkt)
switch (pkt->cmd) {
case Packet::ReadReq:
+ if (pkt->req->isLocked()) {
+ trackLoadLocked(pkt->req);
+ }
memcpy(pkt->getPtr<uint8_t>(),
pmemAddr + pkt->getAddr() - params()->addrRange.start,
pkt->getSize());
break;
case Packet::WriteReq:
- memcpy(pmemAddr + pkt->getAddr() - params()->addrRange.start,
- pkt->getPtr<uint8_t>(),
- pkt->getSize());
- // temporary hack: will need to add real LL/SC implementation
- // for cacheless systems later.
- if (pkt->req->getFlags() & LOCKED) {
- pkt->req->setScResult(1);
+ if (writeOK(pkt->req)) {
+ memcpy(pmemAddr + pkt->getAddr() - params()->addrRange.start,
+ pkt->getPtr<uint8_t>(), pkt->getSize());
}
break;
default:
diff --git a/src/mem/physical.hh b/src/mem/physical.hh
index 02308b2ef..97bea2ec4 100644
--- a/src/mem/physical.hh
+++ b/src/mem/physical.hh
@@ -78,6 +78,68 @@ class PhysicalMemory : public MemObject
const PhysicalMemory &operator=(const PhysicalMemory &specmem);
protected:
+
+ class LockedAddr {
+ public:
+ // on alpha, minimum LL/SC granularity is 16 bytes, so lower
+ // bits need to masked off.
+ static const Addr Addr_Mask = 0xf;
+
+ static Addr mask(Addr paddr) { return (paddr & ~Addr_Mask); }
+
+ Addr addr; // locked address
+ int cpuNum; // locking CPU
+ int threadNum; // locking thread ID within CPU
+
+ // check for matching execution context
+ bool matchesContext(Request *req)
+ {
+ return (cpuNum == req->getCpuNum() &&
+ threadNum == req->getThreadNum());
+ }
+
+ LockedAddr(Request *req)
+ : addr(mask(req->getPaddr())),
+ cpuNum(req->getCpuNum()),
+ threadNum(req->getThreadNum())
+ {
+ }
+ };
+
+ std::list<LockedAddr> lockedAddrList;
+
+ // helper function for checkLockedAddrs(): we really want to
+ // inline a quick check for an empty locked addr list (hopefully
+ // the common case), and do the full list search (if necessary) in
+ // this out-of-line function
+ bool checkLockedAddrList(Request *req);
+
+ // Record the address of a load-locked operation so that we can
+ // clear the execution context's lock flag if a matching store is
+ // performed
+ void trackLoadLocked(Request *req);
+
+ // Compare a store address with any locked addresses so we can
+ // clear the lock flag appropriately. Return value set to 'false'
+ // if store operation should be suppressed (because it was a
+ // conditional store and the address was no longer locked by the
+ // requesting execution context), 'true' otherwise. Note that
+ // this method must be called on *all* stores since even
+ // non-conditional stores must clear any matching lock addresses.
+ bool writeOK(Request *req) {
+ if (lockedAddrList.empty()) {
+ // no locked addrs: nothing to check, store_conditional fails
+ bool isLocked = req->isLocked();
+ if (isLocked) {
+ req->setScResult(0);
+ }
+ return !isLocked; // only do write if not an sc
+ } else {
+ // iterate over list...
+ return checkLockedAddrList(req);
+ }
+ }
+
uint8_t *pmemAddr;
MemoryPort *port;
int pagePtr;
diff --git a/src/mem/request.hh b/src/mem/request.hh
index 6acd7526c..e54984fcd 100644
--- a/src/mem/request.hh
+++ b/src/mem/request.hh
@@ -232,9 +232,11 @@ class Request
Addr getPC() { assert(validPC); return pc; }
/** Accessor Function to Check Cacheability. */
- bool isUncacheable() { return getFlags() & UNCACHEABLE; }
+ bool isUncacheable() { return (getFlags() & UNCACHEABLE) != 0; }
- bool isInstRead() { return getFlags() & INST_READ; }
+ bool isInstRead() { return (getFlags() & INST_READ) != 0; }
+
+ bool isLocked() { return (getFlags() & LOCKED) != 0; }
friend class Packet;
};