ruby: Ruby support for LLSC
authorBrad Beckmann <Brad.Beckmann@amd.com>
Mon, 22 Mar 2010 04:22:21 +0000 (21:22 -0700)
committerBrad Beckmann <Brad.Beckmann@amd.com>
Mon, 22 Mar 2010 04:22:21 +0000 (21:22 -0700)
src/mem/ruby/system/CacheMemory.cc
src/mem/ruby/system/RubyPort.cc
src/mem/ruby/system/SConscript
src/mem/ruby/system/Sequencer.cc

index 110dce2d0af5489d1c668b77e2707db030758ddd..35625245a4af65dc2525a28a9d4cd1bb23e92d46 100644 (file)
@@ -252,6 +252,7 @@ void CacheMemory::allocate(const Address& address, AbstractCacheEntry* entry)
       m_cache[cacheSet][i] = entry;  // Init entry
       m_cache[cacheSet][i]->m_Address = address;
       m_cache[cacheSet][i]->m_Permission = AccessPermission_Invalid;
+      DPRINTF(RubyCache, "Allocate clearing lock for addr: %llx\n", address);
       m_locked[cacheSet][i] = -1;
       m_tag_index[address] = i;
 
@@ -273,6 +274,7 @@ void CacheMemory::deallocate(const Address& address)
   if (location != -1){
     delete m_cache[cacheSet][location];
     m_cache[cacheSet][location] = NULL;
+    DPRINTF(RubyCache, "Deallocate clearing lock for addr: %llx\n", address);
     m_locked[cacheSet][location] = -1;
     m_tag_index.erase(address);
   }
@@ -320,7 +322,10 @@ void CacheMemory::changePermission(const Address& address, AccessPermission new_
   lookup(address).m_Permission = new_perm;
   Index cacheSet = addressToCacheSet(address);
   int loc = findTagInSet(cacheSet, address);
-  m_locked[cacheSet][loc] = -1; 
+  if (new_perm != AccessPermission_Read_Write) {
+      DPRINTF(RubyCache, "Permission clearing lock for addr: %llx\n", address);
+      m_locked[cacheSet][loc] = -1; 
+  }
   assert(getPermission(address) == new_perm);
 }
 
@@ -422,6 +427,10 @@ void CacheMemory::setMemoryValue(const Address& addr, char* value,
 void 
 CacheMemory::setLocked(const Address& address, int context) 
 {  
+    DPRINTF(RubyCache, 
+            "Setting Lock for addr: %llx to %d\n", 
+            address,
+            context);
   assert(address == line_address(address));
   Index cacheSet = addressToCacheSet(address);
   int loc = findTagInSet(cacheSet, address);
@@ -432,6 +441,7 @@ CacheMemory::setLocked(const Address& address, int context)
 void 
 CacheMemory::clearLocked(const Address& address) 
 {
+    DPRINTF(RubyCache, "Clear Lock for addr: %llx\n", address);
   assert(address == line_address(address));
   Index cacheSet = addressToCacheSet(address);
   int loc = findTagInSet(cacheSet, address);
@@ -446,6 +456,11 @@ CacheMemory::isLocked(const Address& address, int context)
   Index cacheSet = addressToCacheSet(address);
   int loc = findTagInSet(cacheSet, address);
   assert(loc != -1);
+    DPRINTF(RubyCache, 
+            "Testing Lock for addr: %llx cur %d con %d\n", 
+            address,
+            m_locked[cacheSet][loc],
+            context);
   return m_locked[cacheSet][loc] == context; 
 }
 
index 07a06bd072146ddc4c2c0ba104a82c02e0283016..314f551d1d2b44ea32b7edfb377234efe46adf6a 100644 (file)
@@ -210,18 +210,33 @@ RubyPort::M5Port::recvTiming(PacketPtr pkt)
         pc = pkt->req->getPC();
     }
 
-    if (pkt->isRead()) {
-        if (pkt->req->isInstFetch()) {
-            type = RubyRequestType_IFETCH;
+    if (pkt->isLLSC()) {
+        if (pkt->isWrite()) {
+            DPRINTF(MemoryAccess, "Issuing SC\n");
+            type = RubyRequestType_Locked_Write;
         } else {
-            type = RubyRequestType_LD; 
+            DPRINTF(MemoryAccess, "Issuing LL\n");
+            assert(pkt->isRead());
+            type = RubyRequestType_Locked_Read;
         }
-    } else if (pkt->isWrite()) {
-        type = RubyRequestType_ST;
-    } else if (pkt->isReadWrite()) {
-        type = RubyRequestType_RMW_Write;
     } else {
-      panic("Unsupported ruby packet type\n");
+        if (pkt->isRead()) {
+            if (pkt->req->isInstFetch()) {
+                type = RubyRequestType_IFETCH;
+            } else {
+                type = RubyRequestType_LD; 
+            }
+        } else if (pkt->isWrite()) {
+            type = RubyRequestType_ST;
+        } else if (pkt->isReadWrite()) {
+            //
+            // Fix me. Just because the packet is a read/write request does not
+            // necessary mean it is a read-modify-write atomic operation.
+            //
+            type = RubyRequestType_RMW_Write;
+        } else {
+            panic("Unsupported ruby packet type\n");
+        }
     }
 
     RubyRequest ruby_request(pkt->getAddr(), 
@@ -234,10 +249,31 @@ RubyPort::M5Port::recvTiming(PacketPtr pkt)
 
     // Submit the ruby request
     RequestStatus requestStatus = ruby_port->makeRequest(ruby_request);
-    if (requestStatus == RequestStatus_Issued) {
+
+    //
+    // If the request successfully issued or the SC request completed because
+    // exclusive permission was lost, then we should return true.
+    // Otherwise, we need to delete the senderStatus we just created and return
+    // false.
+    //
+    if ((requestStatus == RequestStatus_Issued) ||
+        (requestStatus == RequestStatus_LlscFailed)) {
+
+        //
+        // The communicate to M5 whether the SC command succeeded by seting the
+        // packet's extra data.
+        //
+        if (pkt->isLLSC() && pkt->isWrite()) {
+            if (requestStatus == RequestStatus_LlscFailed) {
+                DPRINTF(MemoryAccess, "SC failed and request completed\n");
+                pkt->req->setExtraData(0);
+            } else {
+                pkt->req->setExtraData(1);
+            }
+        }
         return true;
     }
-     
+
     DPRINTF(MemoryAccess, 
             "Request for address #x did not issue because %s\n",
             pkt->getAddr(),
index bd721e83d5fc24f9e75feef3962fec928a6e1ed9..715c9fb862706ffff8683abc903487b97964d470 100644 (file)
@@ -49,3 +49,5 @@ Source('RubyPort.cc')
 Source('Sequencer.cc', Werror=False)
 Source('System.cc')
 Source('TimerTable.cc')
+
+TraceFlag('RubyCache')
index b471a4b8b862fc8d69f9b97206fefc7258ec64ba..d6dba08f96976daa3ad5b73b29834baf5582d6ca 100644 (file)
@@ -334,11 +334,24 @@ void Sequencer::hitCallback(SequencerRequest* srequest, DataBlock& data) {
   if (ruby_request.data != NULL) {
     if ((type == RubyRequestType_LD) ||
         (type == RubyRequestType_IFETCH) ||
-        (type == RubyRequestType_RMW_Read)) {
-      memcpy(ruby_request.data, data.getData(request_address.getOffset(), ruby_request.len), ruby_request.len);
+        (type == RubyRequestType_RMW_Read) ||
+        (type == RubyRequestType_Locked_Read)) {
+
+        memcpy(ruby_request.data, 
+               data.getData(request_address.getOffset(), ruby_request.len), 
+               ruby_request.len);
+        
     } else {
-      data.setData(ruby_request.data, request_address.getOffset(), ruby_request.len);
+
+        data.setData(ruby_request.data, 
+                     request_address.getOffset(), 
+                     ruby_request.len);
+
     }
+  } else {
+      DPRINTF(MemoryAccess, 
+              "WARNING.  Data not transfered from Ruby to M5 for type %s\n",
+              RubyRequestType_to_string(type));
   }
 
   //
@@ -403,11 +416,27 @@ RequestStatus Sequencer::makeRequest(const RubyRequest & request)
     bool found = insertRequest(srequest);
     if (!found) {
       if (request.type == RubyRequestType_Locked_Write) {
-        // NOTE: it is OK to check the locked flag here as the mandatory queue will be checked first
-        // ensuring that nothing comes between checking the flag and servicing the store
-        if (!m_dataCache_ptr->isLocked(line_address(Address(request.paddr)), m_version)) {
-          return RequestStatus_LlscFailed;
-        }
+          //
+          // NOTE: it is OK to check the locked flag here as the mandatory queue
+          // will be checked first ensuring that nothing comes between checking 
+          // the flag and servicing the store.
+          //
+          if (!m_dataCache_ptr->isLocked(line_address(Address(request.paddr)), 
+                                         m_version)) {
+              removeRequest(srequest);
+              if (Debug::getProtocolTrace()) {
+
+                  g_system_ptr->getProfiler()->profileTransition("Seq", 
+                                     m_version, 
+                                     Address(request.paddr),
+                                     "", 
+                                     "SC Fail", 
+                                     "", 
+                                     RubyRequestType_to_string(request.type));
+
+            }
+            return RequestStatus_LlscFailed;
+       }
         else {
           m_dataCache_ptr->clearLocked(line_address(Address(request.paddr)));
         }