Merge zizzer.eecs.umich.edu:/bk/newmem/
[gem5.git] / src / mem / physical.cc
index 5eb89e1265f12858af2b739555a327eb8c4470ae..0302f7351f9b31655a439aa62d51509ceac8eb09 100644 (file)
 #include <iostream>
 #include <string>
 
-
+#include "arch/isa_traits.hh"
 #include "base/misc.hh"
 #include "config/full_system.hh"
-#include "mem/packet_impl.hh"
 #include "mem/physical.hh"
-#include "sim/host.hh"
 #include "sim/builder.hh"
 #include "sim/eventq.hh"
-#include "arch/isa_traits.hh"
-
+#include "sim/host.hh"
 
 using namespace std;
 using namespace TheISA;
 
-
 PhysicalMemory::PhysicalMemory(Params *p)
     : MemObject(p->name), pmemAddr(NULL), port(NULL), lat(p->latency), _params(p)
 {
@@ -105,38 +101,125 @@ PhysicalMemory::deviceBlockSize()
 }
 
 Tick
-PhysicalMemory::calculateLatency(Packet *pkt)
+PhysicalMemory::calculateLatency(PacketPtr pkt)
 {
     return lat;
 }
 
-Tick
-PhysicalMemory::doFunctionalAccess(Packet *pkt)
+
+
+// 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(PacketPtr pkt)
 {
-    assert(pkt->getAddr() + pkt->getSize() < params()->addrRange.size());
+    assert(pkt->getAddr() + pkt->getSize() <= params()->addrRange.size());
 
-    switch (pkt->cmd) {
-      case Packet::ReadReq:
+    if (pkt->isRead()) {
+        if (pkt->req->isLocked()) {
+            trackLoadLocked(pkt->req);
+        }
+        DPRINTF(MemoryAccess, "Performing Read of size %i on address 0x%x\n",
+                pkt->getSize(), pkt->getAddr());
         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);
+    }
+    else if (pkt->isWrite()) {
+        if (writeOK(pkt->req)) {
+            DPRINTF(MemoryAccess, "Performing Write of size %i on address 0x%x\n",
+                    pkt->getSize(), pkt->getAddr());
+            memcpy(pmemAddr + pkt->getAddr() - params()->addrRange.start,
+                   pkt->getPtr<uint8_t>(), pkt->getSize());
         }
-        break;
-      default:
+    }
+    else if (pkt->isInvalidate()) {
+        //upgrade or invalidate
+        pkt->flags |= SATISFIED;
+    }
+    else {
         panic("unimplemented");
     }
 
     pkt->result = Packet::Success;
-    return calculateLatency(pkt);
 }
 
 Port *
@@ -148,7 +231,7 @@ PhysicalMemory::getPort(const std::string &if_name, int idx)
         port = new MemoryPort(name() + "-port", this);
         return port;
     } else if (if_name == "functional") {
-        /* special port for functional writes at startup. */
+        /* special port for functional writes at startup. And for memtester */
         return new MemoryPort(name() + "-funcport", this);
     } else {
         panic("PhysicalMemory::getPort: unknown port %s requested", if_name);
@@ -183,7 +266,8 @@ PhysicalMemory::getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
 {
     snoop.clear();
     resp.clear();
-    resp.push_back(RangeSize(params()->addrRange.start, params()->addrRange.size()));
+    resp.push_back(RangeSize(params()->addrRange.start,
+                             params()->addrRange.size()));
 }
 
 int
@@ -192,28 +276,19 @@ PhysicalMemory::MemoryPort::deviceBlockSize()
     return memory->deviceBlockSize();
 }
 
-bool
-PhysicalMemory::MemoryPort::recvTiming(Packet *pkt)
-{
-    assert(pkt->result != Packet::Nacked);
-
-    Tick latency = memory->doFunctionalAccess(pkt);
-
-    pkt->makeTimingResponse();
-    sendTiming(pkt, latency);
-
-    return true;
-}
-
 Tick
-PhysicalMemory::MemoryPort::recvAtomic(Packet *pkt)
+PhysicalMemory::MemoryPort::recvAtomic(PacketPtr pkt)
 {
-    return memory->doFunctionalAccess(pkt);
+    memory->doFunctionalAccess(pkt);
+    return memory->calculateLatency(pkt);
 }
 
 void
-PhysicalMemory::MemoryPort::recvFunctional(Packet *pkt)
+PhysicalMemory::MemoryPort::recvFunctional(PacketPtr pkt)
 {
+    // Default implementation of SimpleTimingPort::recvFunctional()
+    // calls recvAtomic() and throws away the latency; we can save a
+    // little here by just not calculating the latency.
     memory->doFunctionalAccess(pkt);
 }