ruby: fix ruby llsc support to sync sc outcomes
authorBrad Beckmann <Brad.Beckmann@amd.com>
Fri, 20 Aug 2010 18:46:12 +0000 (11:46 -0700)
committerBrad Beckmann <Brad.Beckmann@amd.com>
Fri, 20 Aug 2010 18:46:12 +0000 (11:46 -0700)
Added support so that ruby can determine the outcome of store conditional
operations and reflect that outcome to M5 physical memory and cpus.

src/mem/packet.hh
src/mem/protocol/RubySlicc_Exports.sm
src/mem/ruby/system/CacheMemory.cc
src/mem/ruby/system/RubyPort.cc
src/mem/ruby/system/Sequencer.cc
src/mem/ruby/system/Sequencer.hh

index 2c94da8bd3a5df86e6dfd7f96d4cbf69990a7f6c..390d9672f81755f44af2c82ddb356f925882a0eb 100644 (file)
@@ -462,6 +462,30 @@ class Packet : public FastAlloc, public Printable
     unsigned getSize() const  { assert(flags.isSet(VALID_SIZE)); return size; }
     Addr getOffset(int blkSize) const { return getAddr() & (Addr)(blkSize - 1); }
 
+    /**
+     * It has been determined that the SC packet should successfully update
+     * memory.  Therefore, convert this SC packet to a normal write.
+     */
+    void
+    convertScToWrite()
+    {
+        assert(isLLSC());
+        assert(isWrite());
+        cmd = MemCmd::WriteReq;
+    }
+
+    /**
+     * When ruby is in use, Ruby will monitor the cache line and thus M5 
+     * phys memory should treat LL ops as normal reads. 
+     */
+    void
+    convertLlToRead()
+    {
+        assert(isLLSC());
+        assert(isRead());
+        cmd = MemCmd::ReadReq;
+    }
+
     /**
      * Constructor.  Note that a Request object must be constructed
      * first, but the Requests's physical address and size fields need
index d29620d16163b373ac26e59e4b9a7524b59e7bd9..4cea7c379f9ebb3a13f4f893364edb91628b0b0f 100644 (file)
@@ -53,7 +53,6 @@ enumeration(AccessPermission, desc="...", default="AccessPermission_NotPresent")
   Read_Write, desc="Read/Write";
   Invalid,    desc="Invalid";
   NotPresent, desc="NotPresent";
-  OnHold,     desc="Holding a place in dnuca cache";
   ReadUpgradingToWrite, desc="Read only, but trying to get Read/Write";
   Stale,      desc="local L1 has a modified copy, assume L2 copy is stale data";
 }
@@ -345,6 +344,5 @@ enumeration(RequestStatus, desc="...", default="RequestStatus_NULL")  {
   Issued, desc="The sequencer successfully issued the request";
   BufferFull, desc="Can not issue because the sequencer is full";
   Aliased, desc="This request aliased with a currently outstanding request";
-  LlscFailed, desc="The write failed in the Load-Link Store-Conditional pair";
   NULL, desc="";
 }
index 9102d19631bb873e56639cb08e9cf34fd489e544..604113238f29eaea601953cfbd38e3577186acd0 100644 (file)
@@ -353,7 +353,9 @@ CacheMemory::changePermission(const Address& address,
     lookup(address).m_Permission = new_perm;
     Index cacheSet = addressToCacheSet(address);
     int loc = findTagInSet(cacheSet, address);
-    if (new_perm != AccessPermission_Read_Write) {
+    if ((new_perm == AccessPermission_Invalid) ||
+        (new_perm == AccessPermission_NotPresent) ||
+        (new_perm == AccessPermission_Stale)) {
         DPRINTF(RubyCache, "Permission clearing lock for addr: %x\n", address);
         m_locked[cacheSet][loc] = -1;
     }
index 87a98185c8995a665213d2bb05e73ed00eac5ef6..a8edb03b2e6eb6b6446efcadf3112e614e013e62 100644 (file)
@@ -229,23 +229,10 @@ RubyPort::M5Port::recvTiming(PacketPtr pkt)
     // Submit the ruby request
     RequestStatus requestStatus = ruby_port->makeRequest(ruby_request);
 
-    // If the request successfully issued or the SC request completed because
-    // exclusive permission was lost, then we should return true.
+    // If the request successfully issued 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);
-            }
-        }
+    if (requestStatus == RequestStatus_Issued) {
         return true;
     }
 
@@ -280,9 +267,39 @@ RubyPort::M5Port::hitCallback(PacketPtr pkt)
 {
     bool needsResponse = pkt->needsResponse();
 
+    //
+    // All responses except failed SC operations access M5 physical memory
+    //
+    bool accessPhysMem = true;
+
+    if (pkt->isLLSC()) {
+        if (pkt->isWrite()) {
+            if (pkt->req->getExtraData() != 0) {
+                //
+                // Successful SC packets convert to normal writes
+                //
+                pkt->convertScToWrite();
+            } else {
+                //
+                // Failed SC packets don't access physical memory and thus
+                // the RubyPort itself must convert it to a response.
+                //
+                accessPhysMem = false;
+                pkt->makeAtomicResponse();
+            }
+        } else {
+            //
+            // All LL packets convert to normal loads so that M5 PhysMem does
+            // not lock the blocks.
+            //
+            pkt->convertLlToRead();
+        }
+    }
     DPRINTF(MemoryAccess, "Hit callback needs response %d\n", needsResponse);
 
-    ruby_port->physMemPort->sendAtomic(pkt);
+    if (accessPhysMem) {
+        ruby_port->physMemPort->sendAtomic(pkt);
+    }
 
     // turn packet around to go back to requester if response expected
     if (needsResponse) {
index e4f85908fc3dd9336dc7b053a1f1aba456c99d96..600f95d10b8d442af73b6de5534d62d3f5a9afab 100644 (file)
@@ -41,6 +41,7 @@
 #include "mem/ruby/system/CacheMemory.hh"
 #include "mem/ruby/system/Sequencer.hh"
 #include "mem/ruby/system/System.hh"
+#include "mem/packet.hh"
 #include "params/RubySequencer.hh"
 
 using namespace std;
@@ -302,6 +303,38 @@ Sequencer::removeRequest(SequencerRequest* srequest)
     markRemoved();
 }
 
+void
+Sequencer::handleLlscWrites(const Address& address, SequencerRequest* request)
+{
+    if (request->ruby_request.type == RubyRequestType_Locked_Write) {
+        if (!m_dataCache_ptr->isLocked(address, m_version)) {
+            //
+            // For failed SC requests, indicate the failure to the cpu by
+            // setting the extra data to zero.
+            //
+            request->ruby_request.pkt->req->setExtraData(0);
+        } else {
+            //
+            // For successful SC requests, indicate the success to the cpu by
+            // setting the extra data to one.  
+            //
+            request->ruby_request.pkt->req->setExtraData(1);
+        }
+        m_dataCache_ptr->clearLocked(address);
+    } else if (request->ruby_request.type == RubyRequestType_Locked_Read) {
+        //
+        // Note: To fully follow Alpha LLSC semantics, should the LL clear any
+        // previously locked cache lines?
+        //
+        m_dataCache_ptr->setLocked(address, m_version);
+    } else if (m_dataCache_ptr->isLocked(address, m_version)) {
+        //
+        // Normal writes should clear the locked address
+        //
+        m_dataCache_ptr->clearLocked(address);
+    }
+}
+
 void
 Sequencer::writeCallback(const Address& address, DataBlock& data)
 {
@@ -329,9 +362,13 @@ Sequencer::writeCallback(const Address& address,
            (request->ruby_request.type == RubyRequestType_Locked_Read) ||
            (request->ruby_request.type == RubyRequestType_Locked_Write));
 
-    if (request->ruby_request.type == RubyRequestType_Locked_Read) {
-        m_dataCache_ptr->setLocked(address, m_version);
-    } else if (request->ruby_request.type == RubyRequestType_RMW_Read) {
+    //
+    // For Alpha, properly handle LL, SC, and write requests with respect to
+    // locked cache blocks.
+    //
+    handleLlscWrites(address, request);
+
+    if (request->ruby_request.type == RubyRequestType_RMW_Read) {
         m_controller->blockOnQueue(address, m_mandatory_q_ptr);
     } else if (request->ruby_request.type == RubyRequestType_RMW_Write) {
         m_controller->unblock(address);
@@ -504,26 +541,6 @@ Sequencer::makeRequest(const RubyRequest &request)
         return RequestStatus_NULL;
     }
 
-    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.
-
-        Address line_addr = line_address(Address(request.paddr));
-        if (!m_dataCache_ptr->isLocked(line_addr, 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_addr);
-        }
-    }
     issueRequest(request);
 
     // TODO: issue hardware prefetches here
index fd6b390c25cc2aa37c27ea24dc1324ed317aa152..c298e27dddd4e209ead5fed0deefd3846feeee46 100644 (file)
@@ -109,6 +109,7 @@ class Sequencer : public RubyPort, public Consumer
 
     bool insertRequest(SequencerRequest* request);
 
+    void handleLlscWrites(const Address& address, SequencerRequest* request);
 
     // Private copy constructor and assignment operator
     Sequencer(const Sequencer& obj);