Simple CPU: Added code that will split requests that cross block boundaries into...
authorGabe Black <gblack@eecs.umich.edu>
Mon, 27 Aug 2007 03:27:11 +0000 (20:27 -0700)
committerGabe Black <gblack@eecs.umich.edu>
Mon, 27 Aug 2007 03:27:11 +0000 (20:27 -0700)
--HG--
extra : convert_revision : 600f79f32ef30a6e1db951503bcfe8cd332858d1

src/cpu/simple/atomic.cc

index 86deb84e61d28ea218a73a5fa101dc914e9a7c29..8a05d800eeaf69c492aab9fdd9e9c05ad91047bc 100644 (file)
@@ -285,46 +285,81 @@ AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
 {
     // use the CPU's statically allocated read request and packet objects
     Request *req = &data_read_req;
-    req->setVirt(0, addr, sizeof(T), flags, thread->readPC());
 
     if (traceData) {
         traceData->setAddr(addr);
     }
 
-    // translate to physical address
-    Fault fault = thread->translateDataReadReq(req);
-
-    // Now do the access.
-    if (fault == NoFault) {
-        Packet pkt =
-            Packet(req,
-                   req->isLocked() ? MemCmd::LoadLockedReq : MemCmd::ReadReq,
-                   Packet::Broadcast);
-        pkt.dataStatic(&data);
-
-        if (req->isMmapedIpr())
-            dcache_latency = TheISA::handleIprRead(thread->getTC(), &pkt);
-        else {
-            if (hasPhysMemPort && pkt.getAddr() == physMemAddr)
-                dcache_latency = physmemPort.sendAtomic(&pkt);
-            else
-                dcache_latency = dcachePort.sendAtomic(&pkt);
-        }
-        dcache_access = true;
-        assert(!pkt.isError());
+    //The block size of our peer.
+    int blockSize = dcachePort.peerBlockSize();
+    //The size of the data we're trying to read.
+    int dataSize = sizeof(T);
+
+    uint8_t * dataPtr = (uint8_t *)&data;
+
+    //The address of the second part of this access if it needs to be split
+    //across a cache line boundary.
+    Addr secondAddr = roundDown(addr + dataSize - 1, blockSize);
+
+    if(secondAddr > addr)
+        dataSize = secondAddr - addr;
+
+    dcache_latency = 0;
 
-        data = gtoh(data);
+    while(1) {
+        req->setVirt(0, addr, dataSize, flags, thread->readPC());
 
-        if (req->isLocked()) {
-            TheISA::handleLockedRead(thread, req);
+        // translate to physical address
+        Fault fault = thread->translateDataReadReq(req);
+
+        // Now do the access.
+        if (fault == NoFault) {
+            Packet pkt = Packet(req,
+                    req->isLocked() ? MemCmd::LoadLockedReq : MemCmd::ReadReq,
+                    Packet::Broadcast);
+            pkt.dataStatic(dataPtr);
+
+            if (req->isMmapedIpr())
+                dcache_latency += TheISA::handleIprRead(thread->getTC(), &pkt);
+            else {
+                if (hasPhysMemPort && pkt.getAddr() == physMemAddr)
+                    dcache_latency += physmemPort.sendAtomic(&pkt);
+                else
+                    dcache_latency += dcachePort.sendAtomic(&pkt);
+            }
+            dcache_access = true;
+            assert(!pkt.isError());
+
+            if (req->isLocked()) {
+                TheISA::handleLockedRead(thread, req);
+            }
+        }
+
+        // This will need a new way to tell if it has a dcache attached.
+        if (req->isUncacheable())
+            recordEvent("Uncached Read");
+
+        //If there's a fault, return it
+        if (fault != NoFault)
+            return fault;
+        //If we don't need to access a second cache line, stop now.
+        if (secondAddr <= addr)
+        {
+            data = gtoh(data);
+            return fault;
         }
-    }
 
-    // This will need a new way to tell if it has a dcache attached.
-    if (req->isUncacheable())
-        recordEvent("Uncached Read");
+        /*
+         * Set up for accessing the second cache line.
+         */
 
-    return fault;
+        //Move the pointer we're reading into to the correct location.
+        dataPtr += dataSize;
+        //Adjust the size to get the remaining bytes.
+        dataSize = addr + sizeof(T) - secondAddr;
+        //And access the right address.
+        addr = secondAddr;
+    }
 }
 
 #ifndef DOXYGEN_SHOULD_SKIP_THIS
@@ -384,65 +419,105 @@ AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
 {
     // use the CPU's statically allocated write request and packet objects
     Request *req = &data_write_req;
-    req->setVirt(0, addr, sizeof(T), flags, thread->readPC());
 
     if (traceData) {
         traceData->setAddr(addr);
     }
 
-    // translate to physical address
-    Fault fault = thread->translateDataWriteReq(req);
-
-    // Now do the access.
-    if (fault == NoFault) {
-        MemCmd cmd = MemCmd::WriteReq; // default
-        bool do_access = true;  // flag to suppress cache access
-
-        if (req->isLocked()) {
-            cmd = MemCmd::StoreCondReq;
-            do_access = TheISA::handleLockedWrite(thread, req);
-        } else if (req->isSwap()) {
-            cmd = MemCmd::SwapReq;
-            if (req->isCondSwap()) {
-                assert(res);
-                req->setExtraData(*res);
-            }
-        }
+    //The block size of our peer.
+    int blockSize = dcachePort.peerBlockSize();
+    //The size of the data we're trying to read.
+    int dataSize = sizeof(T);
 
-        if (do_access) {
-            Packet pkt = Packet(req, cmd, Packet::Broadcast);
-            pkt.dataStatic(&data);
+    uint8_t * dataPtr = (uint8_t *)&data;
 
-            if (req->isMmapedIpr()) {
-                dcache_latency = TheISA::handleIprWrite(thread->getTC(), &pkt);
-            } else {
-                data = htog(data);
-                if (hasPhysMemPort && pkt.getAddr() == physMemAddr)
-                    dcache_latency = physmemPort.sendAtomic(&pkt);
-                else
-                    dcache_latency = dcachePort.sendAtomic(&pkt);
+    //The address of the second part of this access if it needs to be split
+    //across a cache line boundary.
+    Addr secondAddr = roundDown(addr + dataSize - 1, blockSize);
+
+    if(secondAddr > addr)
+        dataSize = secondAddr - addr;
+
+    dcache_latency = 0;
+
+    while(1) {
+        req->setVirt(0, addr, dataSize, flags, thread->readPC());
+
+        // translate to physical address
+        Fault fault = thread->translateDataWriteReq(req);
+
+        // Now do the access.
+        if (fault == NoFault) {
+            MemCmd cmd = MemCmd::WriteReq; // default
+            bool do_access = true;  // flag to suppress cache access
+
+            if (req->isLocked()) {
+                cmd = MemCmd::StoreCondReq;
+                do_access = TheISA::handleLockedWrite(thread, req);
+            } else if (req->isSwap()) {
+                cmd = MemCmd::SwapReq;
+                if (req->isCondSwap()) {
+                    assert(res);
+                    req->setExtraData(*res);
+                }
             }
-            dcache_access = true;
-            assert(!pkt.isError());
 
-            if (req->isSwap()) {
-                assert(res);
-                *res = pkt.get<T>();
+            if (do_access) {
+                Packet pkt = Packet(req, cmd, Packet::Broadcast);
+                pkt.dataStatic(dataPtr);
+
+                if (req->isMmapedIpr()) {
+                    dcache_latency +=
+                        TheISA::handleIprWrite(thread->getTC(), &pkt);
+                } else {
+                    //XXX This needs to be outside of the loop in order to
+                    //work properly for cache line boundary crossing
+                    //accesses in transendian simulations.
+                    data = htog(data);
+                    if (hasPhysMemPort && pkt.getAddr() == physMemAddr)
+                        dcache_latency += physmemPort.sendAtomic(&pkt);
+                    else
+                        dcache_latency += dcachePort.sendAtomic(&pkt);
+                }
+                dcache_access = true;
+                assert(!pkt.isError());
+
+                if (req->isSwap()) {
+                    assert(res);
+                    *res = pkt.get<T>();
+                }
+            }
+
+            if (res && !req->isSwap()) {
+                *res = req->getExtraData();
             }
         }
 
-        if (res && !req->isSwap()) {
-            *res = req->getExtraData();
+        // This will need a new way to tell if it's hooked up to a cache or not.
+        if (req->isUncacheable())
+            recordEvent("Uncached Write");
+
+        //If there's a fault or we don't need to access a second cache line,
+        //stop now.
+        if (fault != NoFault || secondAddr <= addr)
+        {
+            // If the write needs to have a fault on the access, consider
+            // calling changeStatus() and changing it to "bad addr write"
+            // or something.
+            return fault;
         }
-    }
 
-    // This will need a new way to tell if it's hooked up to a cache or not.
-    if (req->isUncacheable())
-        recordEvent("Uncached Write");
+        /*
+         * Set up for accessing the second cache line.
+         */
 
-    // If the write needs to have a fault on the access, consider calling
-    // changeStatus() and changing it to "bad addr write" or something.
-    return fault;
+        //Move the pointer we're reading into to the correct location.
+        dataPtr += dataSize;
+        //Adjust the size to get the remaining bytes.
+        dataSize = addr + sizeof(T) - secondAddr;
+        //And access the right address.
+        addr = secondAddr;
+    }
 }