Hello Timothy Hayes,

I'd like you to do a code review. Please visit

    https://gem5-review.googlesource.com/c/public/gem5/+/27103

to review the following change.


Change subject: mem-ruby: LL/SC fixes
......................................................................

mem-ruby: LL/SC fixes

The implementation for load-linked/store-conditional did not work
correctly for multi-core simulations. Since load-links were treated as
stores, it was not possible for a line to have multiple readers which
often resulted in livelock when using these instructions to implemented
mutexes. This improved implementation treats load-linked instructions
similarly to loads, but places the associated line's address into a
monitor visible to all devices on a system. Writes to a monitored
address ensure the 'linked' property is blown away and any subsequent
store-conditional will fail.

This patch introduces a new RubyRequestType 'Store_Conditional_Failed'
which is a store conditional that has checked the address monitor
and confirmed that it has already failed. For Gem5/Ruby correctness,
this request still needs to go into and return from the mandatory
queue, i.e. the cache controller. As such, the various protocols will
need to recognise this new type--this patch updates MESI_Three_Level,
MESI_Two_Level and MOESI_hammer. Additionally, the transitions of
MESI_Three_Level-L0cache are updated so that line invalidations also
trigger an update to the address monitor.

Change-Id: I19bd74459e26732c92c8b594901936e6439fb073
---
M src/mem/ruby/protocol/MESI_Three_Level-L0cache.sm
M src/mem/ruby/protocol/MESI_Two_Level-L1cache.sm
M src/mem/ruby/protocol/MOESI_hammer-cache.sm
M src/mem/ruby/protocol/RubySlicc_Exports.sm
M src/mem/ruby/protocol/RubySlicc_Types.sm
M src/mem/ruby/system/RubyPort.cc
M src/mem/ruby/system/RubyPort.hh
M src/mem/ruby/system/Sequencer.cc
M src/mem/ruby/system/Sequencer.hh
9 files changed, 333 insertions(+), 97 deletions(-)



diff --git a/src/mem/ruby/protocol/MESI_Three_Level-L0cache.sm b/src/mem/ruby/protocol/MESI_Three_Level-L0cache.sm
index b74a727..f31c0df 100644
--- a/src/mem/ruby/protocol/MESI_Three_Level-L0cache.sm
+++ b/src/mem/ruby/protocol/MESI_Three_Level-L0cache.sm
@@ -121,6 +121,8 @@
     Ack,        desc="Ack for processor";

     WB_Ack,        desc="Ack for replacement";
+
+    Failed_SC,        desc="Store conditional request that will fail";
   }

   // TYPES
@@ -257,7 +259,8 @@
       return Event:Load;
     } else if (type == RubyRequestType:IFETCH) {
       return Event:Ifetch;
- } else if ((type == RubyRequestType:ST) || (type == RubyRequestType:ATOMIC)) { + } else if ((type == RubyRequestType:ST) || (type == RubyRequestType:ATOMIC)
+               || (type == RubyRequestType:Store_Conditional)) {
       return Event:Store;
     } else {
       error("Invalid RubyRequestType");
@@ -349,36 +352,48 @@
             }
           }
         } else {
-
           // *** DATA ACCESS ***
           Entry Dcache_entry := getDCacheEntry(in_msg.LineAddress);
+
+          // early out for failed store conditionals
+          if (in_msg.Type == RubyRequestType:Store_Conditional_Failed) {
+              trigger(Event:Failed_SC, in_msg.LineAddress,
+                      Dcache_entry, TBEs[in_msg.LineAddress]);
+          }
+
           if (is_valid(Dcache_entry)) {
             // The tag matches for the L0, so the L0 ask the L1 for it
trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress,
                     Dcache_entry, TBEs[in_msg.LineAddress]);
           } else {
-
-            // Check to see if it is in the OTHER L0
-            Entry Icache_entry := getICacheEntry(in_msg.LineAddress);
-            if (is_valid(Icache_entry)) {
- // The block is in the wrong L0, put the request on the queue to the private L1
-              trigger(Event:L0_Replacement, in_msg.LineAddress,
-                      Icache_entry, TBEs[in_msg.LineAddress]);
-            }
-
-            if (Dcache.cacheAvail(in_msg.LineAddress)) {
-              // L1 does't have the line, but we have space for it
-              // in the L0 let's see if the L1 has it
- trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress,
-                      Dcache_entry, TBEs[in_msg.LineAddress]);
+            // if the request is not valid, the store conditional will fail
+            if (in_msg.Type == RubyRequestType:Store_Conditional) {
+                // if the line is not valid, it can't be locked
+                trigger(Event:Failed_SC, in_msg.LineAddress,
+                        Dcache_entry, TBEs[in_msg.LineAddress]);
             } else {
-              // No room in the L1, so we need to make room in the L0
-              // Check if the line we want to evict is not locked
-              Addr addr := Dcache.cacheProbe(in_msg.LineAddress);
-              check_on_cache_probe(mandatoryQueue_in, addr);
-              trigger(Event:L0_Replacement, addr,
-                      getDCacheEntry(addr),
-                      TBEs[addr]);
+              // Check to see if it is in the OTHER L0
+              Entry Icache_entry := getICacheEntry(in_msg.LineAddress);
+              if (is_valid(Icache_entry)) {
+ // The block is in the wrong L0, put the request on the queue to the private L1
+                trigger(Event:L0_Replacement, in_msg.LineAddress,
+                        Icache_entry, TBEs[in_msg.LineAddress]);
+              }
+
+              if (Dcache.cacheAvail(in_msg.LineAddress)) {
+                // L1 does't have the line, but we have space for it
+                // in the L0 let's see if the L1 has it
+ trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress,
+                        Dcache_entry, TBEs[in_msg.LineAddress]);
+              } else {
+                // No room in the L1, so we need to make room in the L0
+                // Check if the line we want to evict is not locked
+                Addr addr := Dcache.cacheProbe(in_msg.LineAddress);
+                check_on_cache_probe(mandatoryQueue_in, addr);
+                trigger(Event:L0_Replacement, addr,
+                        getDCacheEntry(addr),
+                        TBEs[addr]);
+              }
             }
           }
         }
@@ -629,6 +644,19 @@
         ++Dcache.demand_hits;
   }

+  // store conditionals
+
+  action(hhc_storec_fail, "\hc",
+         desc="Notify sequencer that store conditional failed") {
+    sequencer.writeCallbackScFail(address, cache_entry.DataBlk);
+  }
+
+  action(dg_invalidate_sc, "dg",
+ desc="Invalidate monitored address as the cache lost permissions") {
+    DPRINTF(RubySlicc, "dg_invalidate_sc: %#x\n", address);
+    sequencer.invalidateSC(address);
+  }
+
   //*****************************************************
   // TRANSITIONS
   //*****************************************************
@@ -664,12 +692,16 @@
   }

   transition({I, IS, IM, Inst_IS}, {InvOwn, InvElse}) {
+    forward_eviction_to_cpu;
     fi_sendInvAck;
+    dg_invalidate_sc;
     l_popRequestQueue;
   }

   transition(SM, {InvOwn, InvElse}, IM) {
+    forward_eviction_to_cpu;
     fi_sendInvAck;
+    dg_invalidate_sc;
     l_popRequestQueue;
   }

@@ -695,11 +727,13 @@

   transition(S, L0_Replacement, I) {
     forward_eviction_to_cpu;
+    dg_invalidate_sc;
     ff_deallocateCacheBlock;
   }

   transition(S, {InvOwn, InvElse}, I) {
     forward_eviction_to_cpu;
+    dg_invalidate_sc;
     fi_sendInvAck;
     ff_deallocateCacheBlock;
     l_popRequestQueue;
@@ -714,6 +748,7 @@

   transition(E, L0_Replacement, I) {
     forward_eviction_to_cpu;
+    dg_invalidate_sc;
     g_issuePUTX;
     ff_deallocateCacheBlock;
   }
@@ -721,6 +756,7 @@
   transition(E, {InvOwn, InvElse, Fwd_GETX}, I) {
     // don't send data
     forward_eviction_to_cpu;
+    dg_invalidate_sc;
     fi_sendInvAck;
     ff_deallocateCacheBlock;
     l_popRequestQueue;
@@ -734,12 +770,14 @@
   // Transitions from Modified
   transition(M, L0_Replacement, I) {
     forward_eviction_to_cpu;
+    dg_invalidate_sc;
     g_issuePUTX;
     ff_deallocateCacheBlock;
   }

   transition(M, {InvOwn, InvElse, Fwd_GETX}, I) {
     forward_eviction_to_cpu;
+    dg_invalidate_sc;
     f_sendDataToL1;
     ff_deallocateCacheBlock;
     l_popRequestQueue;
@@ -768,6 +806,8 @@

   transition(IS, Data_Stale, I) {
     u_writeDataToCache;
+    forward_eviction_to_cpu;
+    dg_invalidate_sc;
     hx_load_hit;
     s_deallocateTBE;
     ff_deallocateCacheBlock;
@@ -807,4 +847,12 @@
     o_popIncomingResponseQueue;
     kd_wakeUpDependents;
   }
+
+  // store conditionals
+
+  transition({I,S,E,M}, Failed_SC) {
+    // IS,IM,SM don't handle store conditionals
+    hhc_storec_fail;
+    k_popMandatoryQueue;
+  }
 }
diff --git a/src/mem/ruby/protocol/MESI_Two_Level-L1cache.sm b/src/mem/ruby/protocol/MESI_Two_Level-L1cache.sm
index 7c83478..7402c1f 100644
--- a/src/mem/ruby/protocol/MESI_Two_Level-L1cache.sm
+++ b/src/mem/ruby/protocol/MESI_Two_Level-L1cache.sm
@@ -1,4 +1,18 @@
 /*
+ * Copyright (c) 2019 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ * Copyright (c) 2013 Mark D. Hill and David A. Wood
+ * All rights reserved.
+ *
  * Copyright (c) 1999-2013 Mark D. Hill and David A. Wood
  * All rights reserved.
  *
@@ -263,7 +277,9 @@
       return Event:Load;
     } else if (type == RubyRequestType:IFETCH) {
       return Event:Ifetch;
- } else if ((type == RubyRequestType:ST) || (type == RubyRequestType:ATOMIC)) { + } else if ((type == RubyRequestType:ST) || (type == RubyRequestType:ATOMIC)
+               || (type == RubyRequestType:Store_Conditional)
+               || (type == RubyRequestType:Store_Conditional_Failed)) {
       return Event:Store;
     } else {
       error("Invalid RubyRequestType");
diff --git a/src/mem/ruby/protocol/MOESI_hammer-cache.sm b/src/mem/ruby/protocol/MOESI_hammer-cache.sm
index 8541f35..353ece6 100644
--- a/src/mem/ruby/protocol/MOESI_hammer-cache.sm
+++ b/src/mem/ruby/protocol/MOESI_hammer-cache.sm
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2019 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 1999-2013 Mark D. Hill and David A. Wood
  * Copyright (c) 2009 Advanced Micro Devices, Inc.
  * All rights reserved.
@@ -295,7 +307,9 @@
       return Event:Load;
     } else if (type == RubyRequestType:IFETCH) {
       return Event:Ifetch;
- } else if ((type == RubyRequestType:ST) || (type == RubyRequestType:ATOMIC)) { + } else if ((type == RubyRequestType:ST) || (type == RubyRequestType:ATOMIC)
+               || (type == RubyRequestType:Store_Conditional)
+               || (type == RubyRequestType:Store_Conditional_Failed)) {
       return Event:Store;
     } else if ((type == RubyRequestType:FLUSH)) {
       return Event:Flush_line;
@@ -1262,6 +1276,8 @@
     if (send_evictions) {
DPRINTF(RubySlicc, "Sending invalidation for %#x to the CPU\n", address);
       sequencer.evictionCallback(address);
+      // make this work with LL/SC
+      sequencer.invalidateSC(address);
     }
   }

@@ -1290,7 +1306,7 @@
   }

action(zz_stallAndWaitMandatoryQueue, "\z", desc="Send the head of the mandatory queue to the back of the queue.") {
-    stall_and_wait(mandatoryQueue_in, address);
+    stall_and_wait(mandatoryQueue_in, address);
   }

   action(z_stall, "z", desc="stall") {
diff --git a/src/mem/ruby/protocol/RubySlicc_Exports.sm b/src/mem/ruby/protocol/RubySlicc_Exports.sm
index 8e17f98..db12ace 100644
--- a/src/mem/ruby/protocol/RubySlicc_Exports.sm
+++ b/src/mem/ruby/protocol/RubySlicc_Exports.sm
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2019 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 1999-2012 Mark D. Hill and David A. Wood
  * Copyright (c) 2011 Advanced Micro Devices, Inc.
  * All rights reserved.
@@ -165,6 +177,7 @@
   REPLACEMENT,       desc="Replacement";
   Load_Linked,       desc="";
   Store_Conditional, desc="";
+ Store_Conditional_Failed, desc="SC that is guaranteed to fail at time of Sequencer issue";
   RMW_Read,          desc="";
   RMW_Write,         desc="";
   Locked_RMW_Read,   desc="";
diff --git a/src/mem/ruby/protocol/RubySlicc_Types.sm b/src/mem/ruby/protocol/RubySlicc_Types.sm
index fd76289..eeb38ca 100644
--- a/src/mem/ruby/protocol/RubySlicc_Types.sm
+++ b/src/mem/ruby/protocol/RubySlicc_Types.sm
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2019 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
  * Copyright (c) 2013 Advanced Micro Devices, Inc.
  * All rights reserved.
@@ -112,6 +124,10 @@
   void writeCallback(Addr, DataBlock, bool, MachineType,
                      Cycles, Cycles, Cycles);

+  // ll/sc support
+  void writeCallbackScFail(Addr, DataBlock);
+  void clearLocalMonitor();
+
   void checkCoherence(Addr);
   void evictionCallback(Addr);
   void recordRequestType(SequencerRequestType);
diff --git a/src/mem/ruby/system/RubyPort.cc b/src/mem/ruby/system/RubyPort.cc
index a6cee05..c5ea16b 100644
--- a/src/mem/ruby/system/RubyPort.cc
+++ b/src/mem/ruby/system/RubyPort.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2013 ARM Limited
+ * Copyright (c) 2012-2013, 2019 ARM Limited
  * All rights reserved.
  *
  * The license below extends only to copyright in the software and shall
@@ -53,6 +53,7 @@

 RubyPort::RubyPort(const Params *p)
: ClockedObject(p), m_ruby_system(p->ruby_system), m_version(p->version),
+      m_nodeSet({m_version}),
       m_controller(NULL), m_mandatory_q_ptr(NULL),
       m_usingRubyTester(p->using_ruby_tester), system(p->system),
       pioMasterPort(csprintf("%s.pio-master-port", name()), this),
diff --git a/src/mem/ruby/system/RubyPort.hh b/src/mem/ruby/system/RubyPort.hh
index b57828d..d843988 100644
--- a/src/mem/ruby/system/RubyPort.hh
+++ b/src/mem/ruby/system/RubyPort.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2013 ARM Limited
+ * Copyright (c) 2012-2013, 2019 ARM Limited
  * All rights reserved.
  *
  * The license below extends only to copyright in the software and shall
@@ -43,6 +43,7 @@
 #define __MEM_RUBY_SYSTEM_RUBYPORT_HH__

 #include <cassert>
+#include <set>
 #include <string>

 #include "mem/ruby/common/MachineID.hh"
@@ -184,6 +185,7 @@

     RubySystem *m_ruby_system;
     uint32_t m_version;
+    const std::set<NodeID> m_nodeSet;
     AbstractController* m_controller;
     MessageBuffer* m_mandatory_q_ptr;
     bool m_usingRubyTester;
diff --git a/src/mem/ruby/system/Sequencer.cc b/src/mem/ruby/system/Sequencer.cc
index a90523e..fa4708a 100644
--- a/src/mem/ruby/system/Sequencer.cc
+++ b/src/mem/ruby/system/Sequencer.cc
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2019 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
  * Copyright (c) 2013 Advanced Micro Devices, Inc.
  * All rights reserved.
@@ -33,6 +45,7 @@
 #include "base/logging.hh"
 #include "base/str.hh"
 #include "cpu/testers/rubytest/RubyTester.hh"
+#include "debug/LLSC.hh"
 #include "debug/MemoryAccess.hh"
 #include "debug/ProtocolTrace.hh"
 #include "debug/RubySequencer.hh"
@@ -77,6 +90,106 @@
 {
 }

+// Support for LL/SC instructions
+void
+Sequencer::clearLocalMonitor()
+{
+    auto it = Sequencer::global_monitor.begin();
+    while (it != Sequencer::global_monitor.end()) {
+        if (it->second.count(m_version)) {
+            it->second.erase(m_version);
+ DPRINTF(LLSC, "LLSC Monitor - deleting - addr=0x%lx - cpu=%u\n",
+                          it->first, m_version);
+            if (it->second.empty()) {
+                it = Sequencer::global_monitor.erase(it);
+            } else {
+                ++it;
+            }
+        } else {
+            ++it;
+        }
+    }
+}
+
+void
+Sequencer::invalidateSC(Addr address)
+{
+    const Addr claddr = makeLineAddress(address);
+    assert(claddr == address); // just in case...
+    auto gm = Sequencer::global_monitor.find(claddr);
+    if (gm != Sequencer::global_monitor.end()) {
+        if (gm->second.count(m_version)) {
+            gm->second.erase(m_version);
+            if (gm->second.empty())
+                Sequencer::global_monitor.erase(gm);
+            DPRINTF(LLSC, "LLSC Monitor - invalidating - ",
+                "addr=0x%lx - cpu=%u\n", claddr, m_version);
+        }
+    }
+}
+
+void
+Sequencer::llsc_load_linked(const Addr claddr)
+{
+    auto gm = Sequencer::global_monitor.find(claddr);
+    if (gm == Sequencer::global_monitor.end()) {
+        Sequencer::global_monitor.insert(
+          std::make_pair(claddr, m_nodeSet));
+    } else {
+        gm->second.insert(m_version);
+    }
+    assert(Sequencer::global_monitor[claddr].count(m_version));
+    DPRINTF(LLSC, "LLSC Monitor - inserting load linked - "
+                  "addr=0x%lx - cpu=%u - numEntries=%d\n",
+                  claddr, m_version, Sequencer::global_monitor.size());
+}
+
+void
+Sequencer::llsc_clear_monitor(const Addr address)
+{
+    auto gm = Sequencer::global_monitor.find(address);
+    if (gm != Sequencer::global_monitor.end()) {
+        Sequencer::global_monitor.erase(gm);
+        DPRINTF(LLSC, "LLSC Monitor - clearing due to store - "
+                      "addr=0x%lx - cpu=%u\n", address, m_version);
+    }
+}
+
+bool
+Sequencer::llsc_store_conditional(const Addr address)
+{
+    bool success = false;
+    auto gm = Sequencer::global_monitor.find(address);
+    if (gm != Sequencer::global_monitor.end()) {
+        // check if NodeID is still in the set
+        if (gm->second.count(m_version))
+        {
+            success = true;
+            // The first successful SC clears the monitor
+            // for all other cores.
+            Sequencer::global_monitor.erase(gm);
+            DPRINTF(LLSC, "LLSC Monitor - clearing due to "
+                          "store exclusive - "
+                          "addr=0x%lx - cpu=%u - success=%d\n",
+                          address, m_version, success);
+        }
+    }
+    return success;
+}
+
+bool
+Sequencer::llsc_check_monitor(const Addr claddr)
+{
+    bool in_mon = false;
+    auto gm = Sequencer::global_monitor.find(claddr);
+    if (gm != Sequencer::global_monitor.end()) {
+        // check if NodeID is still in the set
+        if (gm->second.count(m_version))
+            in_mon = true;
+    }
+    return in_mon;
+}
+
 void
 Sequencer::wakeup()
 {
@@ -160,6 +273,12 @@
seq_req_list.emplace_back(pkt, primary_type, secondary_type, curCycle());
     m_outstanding_count++;

+    // Load-linked handling
+    if (primary_type == RubyRequestType_Load_Linked) {
+        clearLocalMonitor();
+        llsc_load_linked(line_addr);
+    }
+
     if (seq_req_list.size() > 1) {
         return RequestStatus_Aliased;
     }
@@ -176,62 +295,6 @@
 }

 void
-Sequencer::invalidateSC(Addr address)
-{
-    AbstractCacheEntry *e = m_dataCache_ptr->lookup(address);
-    // The controller has lost the coherence permissions, hence the lock
-    // on the cache line maintained by the cache should be cleared.
-    if (e && e->isLocked(m_version)) {
-        e->clearLocked();
-    }
-}
-
-bool
-Sequencer::handleLlsc(Addr address, SequencerRequest* request)
-{
-    AbstractCacheEntry *e = m_dataCache_ptr->lookup(address);
-    if (!e)
-        return true;
-
- // The success flag indicates whether the LLSC operation was successful.
-    // LL ops will always succeed, but SC may fail if the cache line is no
-    // longer locked.
-    bool success = true;
-    if (request->m_type == RubyRequestType_Store_Conditional) {
-        if (!e->isLocked(m_version)) {
-            //
-            // For failed SC requests, indicate the failure to the cpu by
-            // setting the extra data to zero.
-            //
-            request->pkt->req->setExtraData(0);
-            success = false;
-        } else {
-            //
- // For successful SC requests, indicate the success to the cpu by
-            // setting the extra data to one.
-            //
-            request->pkt->req->setExtraData(1);
-        }
-        //
-        // Independent of success, all SC operations must clear the lock
-        //
-        e->clearLocked();
-    } else if (request->m_type == RubyRequestType_Load_Linked) {
-        //
- // Note: To fully follow Alpha LLSC semantics, should the LL clear any
-        // previously locked cache lines?
-        //
-        e->setLocked(m_version);
-    } else if (e->isLocked(m_version)) {
-        //
-        // Normal writes should clear the locked address
-        //
-        e->clearLocked();
-    }
-    return success;
-}
-
-void
 Sequencer::recordMissLatency(SequencerRequest* srequest, bool llscSuccess,
                              const MachineType respondingMach,
                              bool isExternalHit, Cycles initialRequestTime,
@@ -298,6 +361,15 @@
 }

 void
+Sequencer::writeCallbackScFail(Addr address, DataBlock& data)
+{
+    assert(address == makeLineAddress(address));
+
+    invalidateSC(address);
+    writeCallback(address, data);
+}
+
+void
 Sequencer::writeCallback(Addr address, DataBlock& data,
                          const bool externalHit, const MachineType mach,
                          const Cycles initialRequestTime,
@@ -322,21 +394,33 @@
         SequencerRequest &seq_req = seq_req_list.front();
         if (ruby_request) {
             assert(seq_req.m_type != RubyRequestType_LD);
+            assert(seq_req.m_type != RubyRequestType_Load_Linked);
             assert(seq_req.m_type != RubyRequestType_IFETCH);
         }

         // handle write request
         if ((seq_req.m_type != RubyRequestType_LD) &&
+            (seq_req.m_type != RubyRequestType_Load_Linked) &&
             (seq_req.m_type != RubyRequestType_IFETCH)) {
-            //
-            // For Alpha, properly handle LL, SC, and write requests with
-            // respect to locked cache blocks.
-            //
-            // Not valid for Garnet_standalone protocl
-            //
-            bool success = true;
-            if (!m_runningGarnetStandalone)
-                success = handleLlsc(address, &seq_req);
+            // LL/SC support (tested with ARMv8)
+
+            // Regular stores to addresses being monitored
+            // will fail (remove) the monitor entry.
+            if (seq_req.m_type != RubyRequestType_Store_Conditional) {
+                llsc_clear_monitor(address);
+            }
+
+            // Store conditionals must first check the monitor
+            // if they will succeed or not
+            bool success = false;
+            if (seq_req.m_type == RubyRequestType_Store_Conditional) {
+                success = llsc_store_conditional(address);
+
+                if (success)
+                    seq_req.pkt->req->setExtraData(1);
+                else
+                    seq_req.pkt->req->setExtraData(0);
+            }

// Handle SLICC block_on behavior for Locked_RMW accesses. NOTE: the // address variable here is assumed to be a line address, so when
@@ -406,11 +490,13 @@
         SequencerRequest &seq_req = seq_req_list.front();
         if (ruby_request) {
             assert((seq_req.m_type == RubyRequestType_LD) ||
+                   (seq_req.m_type == RubyRequestType_Load_Linked) ||
                    (seq_req.m_type == RubyRequestType_IFETCH));
         } else {
             aliased_loads++;
         }
         if ((seq_req.m_type != RubyRequestType_LD) &&
+            (seq_req.m_type != RubyRequestType_Load_Linked) &&
             (seq_req.m_type != RubyRequestType_IFETCH)) {
             // Write request: reissue request to the cache hierarchy
             issueRequest(seq_req.pkt, seq_req.m_second_type);
@@ -534,13 +620,24 @@
         //
         if (pkt->isWrite()) {
             DPRINTF(RubySequencer, "Issuing SC\n");
-            primary_type = RubyRequestType_Store_Conditional;
+            // check first if the monitor cleared
+            const Addr claddr = makeLineAddress(pkt->getAddr());
+            bool in_mon = llsc_check_monitor(claddr);
+            if (in_mon) {
+                primary_type = secondary_type
+                  = RubyRequestType_Store_Conditional;
+            } else {
+                // tell the cache coherence protocol that
+                // the SC has already failed.
+                primary_type = RubyRequestType_Store_Conditional;
+                secondary_type = RubyRequestType_Store_Conditional_Failed;
+            }
         } else {
             DPRINTF(RubySequencer, "Issuing LL\n");
             assert(pkt->isRead());
             primary_type = RubyRequestType_Load_Linked;
+            secondary_type = RubyRequestType_LD;
         }
-        secondary_type = RubyRequestType_ATOMIC;
     } else if (pkt->req->isLockedRMW()) {
         //
         // x86 locked instructions are translated to store cache coherence
@@ -755,3 +852,6 @@
         }
     }
 }
+
+// global monitor structure for supporting load linked / store conditional
+std::unordered_map<Addr, std::set<NodeID>> Sequencer::global_monitor = {};
diff --git a/src/mem/ruby/system/Sequencer.hh b/src/mem/ruby/system/Sequencer.hh
index 71ffa99..80055b6 100644
--- a/src/mem/ruby/system/Sequencer.hh
+++ b/src/mem/ruby/system/Sequencer.hh
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2019 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
  * All rights reserved.
  *
@@ -29,6 +41,7 @@
 #ifndef __MEM_RUBY_SYSTEM_SEQUENCER_HH__
 #define __MEM_RUBY_SYSTEM_SEQUENCER_HH__

+#include <deque>
 #include <iostream>
 #include <list>
 #include <unordered_map>
@@ -63,6 +76,12 @@
     Sequencer(const Params *);
     ~Sequencer();

+    // support for LL/SC
+    void clearLocalMonitor();
+    void invalidateSC(Addr address);
+    void writeCallbackScFail(Addr address,
+                       DataBlock& data);
+
     // Public Methods
     void wakeup(); // Used only for deadlock detection
     void resetStats();
@@ -100,7 +119,6 @@

     void markRemoved();
     void evictionCallback(Addr address);
-    void invalidateSC(Addr address);
     int coreId() const { return m_coreId; }

     void recordRequestType(SequencerRequestType requestType);
@@ -168,7 +186,6 @@

RequestStatus insertRequest(PacketPtr pkt, RubyRequestType primary_type,
                                 RubyRequestType secondary_type);
-    bool handleLlsc(Addr address, SequencerRequest* request);

     // Private copy constructor and assignment operator
     Sequencer(const Sequencer& obj);
@@ -234,6 +251,13 @@
     std::vector<Stats::Counter> m_IncompleteTimes;

     EventFunctionWrapper deadlockCheckEvent;
+
+    // support for ll/sc
+    static std::unordered_map<Addr, std::set<NodeID>> global_monitor;
+    void llsc_load_linked(const Addr);
+    void llsc_clear_monitor(const Addr);
+    bool llsc_store_conditional(const Addr);
+    bool llsc_check_monitor(const Addr);
 };

 inline std::ostream&

--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/27103
To unsubscribe, or for help writing mail filters, visit https://gem5-review.googlesource.com/settings

Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: I19bd74459e26732c92c8b594901936e6439fb073
Gerrit-Change-Number: 27103
Gerrit-PatchSet: 1
Gerrit-Owner: Giacomo Travaglini <giacomo.travagl...@arm.com>
Gerrit-Reviewer: Timothy Hayes <timothy.ha...@arm.com>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list
gem5-dev@gem5.org
http://m5sim.org/mailman/listinfo/gem5-dev

Reply via email to