Merge zizzer.eecs.umich.edu:/z/m5/Bitkeeper/newmem
[gem5.git] / src / mem / physical.cc
index 2d66602ab480fcded1a3756940799ee9458a0808..0302f7351f9b31655a439aa62d51509ceac8eb09 100644 (file)
@@ -26,6 +26,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * Authors: Ron Dreslinski
+ *          Ali Saidi
  */
 
 #include <sys/types.h>
 #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::MemResponseEvent::MemResponseEvent(Packet *pkt, MemoryPort* _m)
-    : Event(&mainEventQueue, CPU_Tick_Pri), pkt(pkt), memoryPort(_m)
-{
-
-    this->setFlags(AutoDelete);
-}
-
-void
-PhysicalMemory::MemResponseEvent::process()
-{
-    memoryPort->sendTiming(pkt);
-}
-
-const char *
-PhysicalMemory::MemResponseEvent::description()
+PhysicalMemory::PhysicalMemory(Params *p)
+    : MemObject(p->name), pmemAddr(NULL), port(NULL), lat(p->latency), _params(p)
 {
-    return "Physical Memory Timing Access respnse event";
-}
-
-PhysicalMemory::PhysicalMemory(const string &n, Tick latency)
-    : MemObject(n),base_addr(0), pmem_addr(NULL), port(NULL), lat(latency)
-{
-    // Hardcoded to 128 MB for now.
-    pmem_size = 1 << 27;
-
-    if (pmem_size % TheISA::PageBytes != 0)
+    if (params()->addrRange.size() % TheISA::PageBytes != 0)
         panic("Memory Size not divisible by page size\n");
 
     int map_flags = MAP_ANON | MAP_PRIVATE;
-    pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
+    pmemAddr = (uint8_t *)mmap(NULL, params()->addrRange.size(), PROT_READ | PROT_WRITE,
                                 map_flags, -1, 0);
 
-    if (pmem_addr == (void *)MAP_FAILED) {
+    if (pmemAddr == (void *)MAP_FAILED) {
         perror("mmap");
         fatal("Could not mmap!\n");
     }
 
-    page_ptr = 0;
+    pagePtr = 0;
 }
 
 void
@@ -102,18 +78,18 @@ PhysicalMemory::init()
 
 PhysicalMemory::~PhysicalMemory()
 {
-    if (pmem_addr)
-        munmap(pmem_addr, pmem_size);
+    if (pmemAddr)
+        munmap(pmemAddr, params()->addrRange.size());
     //Remove memPorts?
 }
 
 Addr
 PhysicalMemory::new_page()
 {
-    Addr return_addr = page_ptr << LogVMPageSize;
-    return_addr += base_addr;
+    Addr return_addr = pagePtr << LogVMPageSize;
+    return_addr += params()->addrRange.start;
 
-    ++page_ptr;
+    ++pagePtr;
     return return_addr;
 }
 
@@ -124,48 +100,122 @@ PhysicalMemory::deviceBlockSize()
     return 0;
 }
 
-bool
-PhysicalMemory::doTimingAccess (Packet *pkt, MemoryPort* memoryPort)
+Tick
+PhysicalMemory::calculateLatency(PacketPtr pkt)
 {
-    doFunctionalAccess(pkt);
+    return lat;
+}
+
 
-    // turn packet around to go back to requester
-    pkt->makeTimingResponse();
-    MemResponseEvent* response = new MemResponseEvent(pkt, memoryPort);
-    response->schedule(curTick + lat);
 
-    return true;
+// 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));
 }
 
-Tick
-PhysicalMemory::doAtomicAccess(Packet *pkt)
+
+// 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)
 {
-    doFunctionalAccess(pkt);
-    return lat;
+    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)
+PhysicalMemory::doFunctionalAccess(PacketPtr pkt)
 {
-    assert(pkt->getAddr() + pkt->getSize() < pmem_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>(),
-               pmem_addr + pkt->getAddr() - base_addr,
+               pmemAddr + pkt->getAddr() - params()->addrRange.start,
                pkt->getSize());
-        break;
-      case Packet::WriteReq:
-        memcpy(pmem_addr + pkt->getAddr() - base_addr,
-               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");
     }
 
@@ -181,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);
@@ -195,7 +245,7 @@ PhysicalMemory::recvStatusChange(Port::Status status)
 
 PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name,
                                        PhysicalMemory *_memory)
-    : Port(_name), memory(_memory)
+    : SimpleTimingPort(_name), memory(_memory)
 { }
 
 void
@@ -216,7 +266,8 @@ PhysicalMemory::getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
 {
     snoop.clear();
     resp.clear();
-    resp.push_back(RangeSize(base_addr, pmem_size));
+    resp.push_back(RangeSize(params()->addrRange.start,
+                             params()->addrRange.size()));
 }
 
 int
@@ -225,25 +276,32 @@ PhysicalMemory::MemoryPort::deviceBlockSize()
     return memory->deviceBlockSize();
 }
 
-bool
-PhysicalMemory::MemoryPort::recvTiming(Packet *pkt)
-{
-    return memory->doTimingAccess(pkt, this);
-}
-
 Tick
-PhysicalMemory::MemoryPort::recvAtomic(Packet *pkt)
+PhysicalMemory::MemoryPort::recvAtomic(PacketPtr pkt)
 {
-    return memory->doAtomicAccess(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);
 }
 
-
+unsigned int
+PhysicalMemory::drain(Event *de)
+{
+    int count = port->drain(de);
+    if (count)
+        changeState(Draining);
+    else
+        changeState(Drained);
+    return count;
+}
 
 void
 PhysicalMemory::serialize(ostream &os)
@@ -251,7 +309,6 @@ PhysicalMemory::serialize(ostream &os)
     gzFile compressedMem;
     string filename = name() + ".physmem";
 
-    SERIALIZE_SCALAR(pmem_size);
     SERIALIZE_SCALAR(filename);
 
     // write memory file
@@ -267,7 +324,7 @@ PhysicalMemory::serialize(ostream &os)
         fatal("Insufficient memory to allocate compression state for %s\n",
                 filename);
 
-    if (gzwrite(compressedMem, pmem_addr, pmem_size) != pmem_size) {
+    if (gzwrite(compressedMem, pmemAddr, params()->addrRange.size()) != params()->addrRange.size()) {
         fatal("Write failed on physical memory checkpoint file '%s'\n",
               filename);
     }
@@ -288,12 +345,8 @@ PhysicalMemory::unserialize(Checkpoint *cp, const string &section)
     const int chunkSize = 16384;
 
 
-    // unmap file that was mmaped in the constructor
-    munmap(pmem_addr, pmem_size);
-
     string filename;
 
-    UNSERIALIZE_SCALAR(pmem_size);
     UNSERIALIZE_SCALAR(filename);
 
     filename = cp->cptDir + "/" + filename;
@@ -310,11 +363,15 @@ PhysicalMemory::unserialize(Checkpoint *cp, const string &section)
         fatal("Insufficient memory to allocate compression state for %s\n",
                 filename);
 
+    // unmap file that was mmaped in the constructor
+    // This is done here to make sure that gzip and open don't muck with our
+    // nice large space of memory before we reallocate it
+    munmap(pmemAddr, params()->addrRange.size());
 
-    pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
+    pmemAddr = (uint8_t *)mmap(NULL, params()->addrRange.size(), PROT_READ | PROT_WRITE,
                                 MAP_ANON | MAP_PRIVATE, -1, 0);
 
-    if (pmem_addr == (void *)MAP_FAILED) {
+    if (pmemAddr == (void *)MAP_FAILED) {
         perror("mmap");
         fatal("Could not mmap physical memory!\n");
     }
@@ -325,19 +382,19 @@ PhysicalMemory::unserialize(Checkpoint *cp, const string &section)
         fatal("Unable to malloc memory to read file %s\n", filename);
 
     /* Only copy bytes that are non-zero, so we don't give the VM system hell */
-    while (curSize < pmem_size) {
+    while (curSize < params()->addrRange.size()) {
         bytesRead = gzread(compressedMem, tempPage, chunkSize);
-        if (bytesRead != chunkSize && bytesRead != pmem_size - curSize)
+        if (bytesRead != chunkSize && bytesRead != params()->addrRange.size() - curSize)
             fatal("Read failed on physical memory checkpoint file '%s'"
                   " got %d bytes, expected %d or %d bytes\n",
-                  filename, bytesRead, chunkSize, pmem_size-curSize);
+                  filename, bytesRead, chunkSize, params()->addrRange.size()-curSize);
 
         assert(bytesRead % sizeof(long) == 0);
 
         for (int x = 0; x < bytesRead/sizeof(long); x++)
         {
              if (*(tempPage+x) != 0) {
-                 pmem_current = (long*)(pmem_addr + curSize + x * sizeof(long));
+                 pmem_current = (long*)(pmemAddr + curSize + x * sizeof(long));
                  *pmem_current = *(tempPage+x);
              }
         }
@@ -371,8 +428,11 @@ END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
 
 CREATE_SIM_OBJECT(PhysicalMemory)
 {
-
-    return new PhysicalMemory(getInstanceName(), latency);
+    PhysicalMemory::Params *p = new PhysicalMemory::Params;
+    p->name = getInstanceName();
+    p->addrRange = range;
+    p->latency = latency;
+    return new PhysicalMemory(p);
 }
 
 REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory)