Tiago Mück has uploaded this change for review. ( https://gem5-review.googlesource.com/c/public/gem5/+/21579 )

Change subject: mem-ruby: Support for non-blocking aliased requests
......................................................................

mem-ruby: Support for non-blocking aliased requests

While there is an outstanding request for a cache line, any other request
for that same cache line will be rejected by the Sequencer. This may
significantly reduce throughput since it blocks requests to different
cache lines until a response for the aliased line is received.

This patch modifies RubyPort and Sequencer so it accepts aliased requests.
Aliased requests are handled according to the value returned by the
protocol-dependent aliasingMode() function:

RubyAliasingType_BLOCK:
  Rejects aliased requests. This maintains the original behavior and
  is returned by the default implementation of aliasingMode()

RubyAliasingType_BUFFER:
  The aliased requests are buffered internally at the RubyPort and are
  sent to the controller once a response for the aliased line address is
  received. The Sequencer class was also modified to count buffered
  aliased requests towards the outstanding requests limit.

RubyAliasingType_FORWARD:
  The aliased requests are accepted and sent to the controller. The
  protocol is responsible for ensuring the proper ordering of requests.
  This option allows protocols to implement coalescing at SLICC level.
  When using this mode, the protocol must pass the original packet ptr
  instead of the request address to the sequencer callback functions.

Change-Id: I70e3992632bf0e5fd2f2a457cfdebdf054639276
Signed-off-by: Tiago Mück <tiago.m...@arm.com>
---
M src/mem/ruby/protocol/RubySlicc_Exports.sm
M src/mem/ruby/protocol/RubySlicc_Types.sm
M src/mem/ruby/slicc_interface/AbstractController.hh
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
7 files changed, 353 insertions(+), 67 deletions(-)



diff --git a/src/mem/ruby/protocol/RubySlicc_Exports.sm b/src/mem/ruby/protocol/RubySlicc_Exports.sm
index 8e17f98..be0c7a7 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.
@@ -187,6 +199,27 @@
   NULL,        desc="Invalid request type";
 }

+// Sequence handling of aliased request.
+// Each implemented protocol needs to support one the following methods for
+// handling aliased requests on top-level controllers
+// BLOCK:
+//    The sequencer will reject aliased requests. The original requestor
+//    is expected to block until the sequencer sends a retry.
+// BUFFER:
+//    The sequencer will accept the aliased request but will not
+//    not forward it to the controller. The request will be buffered
+//    internally until a response for the oustanding line is received.
+// FORWARD:
+//    The sequencer will accept and forward aliased requests to the
+//    controller. The protocol implementation must be able to
+//    prevent reordeing requests to the same line.
+enumeration(RubyAliasingType, desc="...", default="RubyAliasingType_NULL") {
+  BLOCK,    desc="Sequencer blocks on aliased requests";
+  BUFFER,   desc="Buffer aliased requests at the sequencer";
+  FORWARD,  desc="Forward aliased requests to the controller";
+  NULL,     desc="Invalid aliasing type";
+}
+
enumeration(CacheRequestType, desc="...", default="CacheRequestType_NULL") {
   DataArrayRead,    desc="Read access to the cache's data array";
   DataArrayWrite,   desc="Write access to the cache's data array";
diff --git a/src/mem/ruby/protocol/RubySlicc_Types.sm b/src/mem/ruby/protocol/RubySlicc_Types.sm
index 2d4c250..527bed8 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.
@@ -105,12 +117,22 @@
   void readCallback(Addr, DataBlock, bool, MachineType);
   void readCallback(Addr, DataBlock, bool, MachineType,
                     Cycles, Cycles, Cycles);
+  void readCallback(PacketPtr, DataBlock);
+  void readCallback(PacketPtr, DataBlock, bool);
+  void readCallback(PacketPtr, DataBlock, bool, MachineType);
+  void readCallback(PacketPtr, DataBlock, bool, MachineType,
+                    Cycles, Cycles, Cycles);

   void writeCallback(Addr, DataBlock);
   void writeCallback(Addr, DataBlock, bool);
   void writeCallback(Addr, DataBlock, bool, MachineType);
   void writeCallback(Addr, DataBlock, bool, MachineType,
                      Cycles, Cycles, Cycles);
+  void writeCallback(PacketPtr, DataBlock);
+  void writeCallback(PacketPtr, DataBlock, bool);
+  void writeCallback(PacketPtr, DataBlock, bool, MachineType);
+  void writeCallback(PacketPtr, DataBlock, bool, MachineType,
+                     Cycles, Cycles, Cycles);

   void checkCoherence(Addr);
   void evictionCallback(Addr);
diff --git a/src/mem/ruby/slicc_interface/AbstractController.hh b/src/mem/ruby/slicc_interface/AbstractController.hh
index 2007026..af1dc5c 100644
--- a/src/mem/ruby/slicc_interface/AbstractController.hh
+++ b/src/mem/ruby/slicc_interface/AbstractController.hh
@@ -56,6 +56,7 @@
 #include "mem/ruby/common/MachineID.hh"
 #include "mem/ruby/network/MessageBuffer.hh"
 #include "mem/ruby/protocol/AccessPermission.hh"
+#include "mem/ruby/protocol/RubyAliasingType.hh"
 #include "mem/ruby/system/CacheRecorder.hh"
 #include "params/RubyController.hh"
 #include "sim/clocked_object.hh"
@@ -146,6 +147,18 @@

     const AddrRangeList &getAddrRanges() const { return addrRanges; }

+    /**
+     * For top-level controllers, this function is used to inform the
+     * sequencer how to handle requests targeting a line for which we
+     * already have an outstanding request.
+     * See the definition of RubyAliasingType at
+     * src/mem/protocol/RubySlicc_Exports.sm for details.
+     * The default behavior is to reject/block aliased requests.
+     *
+     * @return the supported aliasing method
+     */
+ virtual RubyAliasingType aliasingMode() { return RubyAliasingType_BLOCK; }
+
   public:
     MachineID getMachineID() const { return m_machineID; }

diff --git a/src/mem/ruby/system/RubyPort.cc b/src/mem/ruby/system/RubyPort.cc
index 800046e..a263449 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
@@ -55,6 +55,7 @@
: ClockedObject(p), m_ruby_system(p->ruby_system), m_version(p->version),
       m_controller(NULL), m_mandatory_q_ptr(NULL),
       m_usingRubyTester(p->using_ruby_tester), system(p->system),
+      m_aliasing_mode(RubyAliasingType_NULL), _numAliasedRequests(0),
       pioMasterPort(csprintf("%s.pio-master-port", name()), this),
       pioSlavePort(csprintf("%s.pio-slave-port", name()), this),
       memMasterPort(csprintf("%s.mem-master-port", name()), this),
@@ -84,6 +85,7 @@
 RubyPort::init()
 {
     assert(m_controller != NULL);
+    m_aliasing_mode = m_controller->aliasingMode();
     m_mandatory_q_ptr = m_controller->getMandatoryQueue();
 }

@@ -273,16 +275,32 @@
     }

     // Submit the ruby request
-    RequestStatus requestStatus = ruby_port->makeRequest(pkt);
+    bool aliased = false;
+    if (ruby_port->submitRubyRequest(pkt, aliased)) {
+        // Save the port in the sender state object to be used later to
+        // route the response
+        pkt->pushSenderState(new SenderState(this));
+        return true;
+    }
+
+    addToRetryList();
+
+    return false;
+}
+
+bool
+RubyPort::submitRubyRequest(PacketPtr pkt, bool &aliased)
+{
+    bool was_aliased = aliased;
+    aliased = false;
+
+    // Submit the ruby request
+    RequestStatus requestStatus = makeRequest(pkt);

     // If the request successfully issued then we should return true.
     // Otherwise, we need to tell the port to retry at a later point
     // and return false.
     if (requestStatus == RequestStatus_Issued) {
-        // Save the port in the sender state object to be used later to
-        // route the response
-        pkt->pushSenderState(new SenderState(this));
-
DPRINTF(RubyPort, "Request %s address %#x issued\n", pkt->cmdString(),
                 pkt->getAddr());
         return true;
@@ -295,7 +313,26 @@
                 RequestStatus_to_string(requestStatus));
     }

-    addToRetryList();
+    if (requestStatus == RequestStatus_Aliased) {
+        if (m_aliasing_mode == RubyAliasingType_BLOCK)
+            return false;
+
+        assert(m_aliasing_mode == RubyAliasingType_BUFFER);
+
+        // Only add to the aliased list if it was not before
+        if (!was_aliased){
+            // We will retry this request once a response for this line
+            // is received
+            Addr line_addr = makeLineAddress(pkt->getAddr());
+            aliasedRequests[line_addr].push(pkt);
+            ++_numAliasedRequests;
+        }
+        aliased = true;
+
+        // From the perspective of the original requestor this is an
+        // accepted request
+        return true;
+    }

     return false;
 }
@@ -416,12 +453,13 @@
 void
 RubyPort::ruby_hit_callback(PacketPtr pkt)
 {
+    Addr pkt_addr = pkt->getAddr();
     DPRINTF(RubyPort, "Hit callback for %s 0x%x\n", pkt->cmdString(),
-            pkt->getAddr());
+            pkt_addr);

     // The packet was destined for memory and has not yet been turned
     // into a response
-    assert(system->isMemAddr(pkt->getAddr()));
+    assert(system->isMemAddr(pkt_addr));
     assert(pkt->isRequest());

     // First we must retrieve the request port from the sender State
@@ -433,7 +471,49 @@

     port->hitCallback(pkt);

-    trySendRetries();
+    // try to send the aliased first
+    bool busy = retryAliasedRequests(pkt_addr);
+
+    // if it got busy no point sending retries now
+    if (!busy)
+        trySendRetries();
+}
+
+bool
+RubyPort::retryAliasedRequests(Addr addr)
+{
+    Addr line_addr = makeLineAddress(addr);
+    auto iter = aliasedRequests.find(line_addr);
+    if (iter == aliasedRequests.end())
+        return false;
+
+    assert(m_aliasing_mode == RubyAliasingType_BUFFER);
+
+    DPRINTF(RubyPort, "Retrying aliased requests for line address %#x\n",
+            line_addr);
+
+    std::queue<PacketPtr> &req_queue = iter->second;
+    assert(req_queue.size() > 0);
+
+    while (req_queue.size() > 0) {
+        PacketPtr pkt = req_queue.front();
+        bool aliased = true;
+
+        if (!submitRubyRequest(pkt, aliased))
+            return true;
+
+        // Stop if aliased
+        if (aliased)
+            break;
+
+        req_queue.pop();
+        --_numAliasedRequests;
+    }
+    if (req_queue.size() == 0)
+        aliasedRequests.erase(iter);
+
+    // Not busy yet; may keep trying to send requests
+    return false;
 }

 void
@@ -467,9 +547,9 @@
 {
     //If we weren't able to drain before, we might be able to now.
     if (drainState() == DrainState::Draining) {
-        unsigned int drainCount = outstandingCount();
-        DPRINTF(Drain, "Drain count: %u\n", drainCount);
-        if (drainCount == 0) {
+ unsigned int drain_count = outstandingCount() + numAliasedRequests();
+        DPRINTF(Drain, "Drain count: %u\n", drain_count);
+        if (drain_count == 0) {
DPRINTF(Drain, "RubyPort done draining, signaling drain done\n");
             signalDrainDone();
         }
@@ -487,8 +567,9 @@
     // If the RubyPort is not empty, then it needs to clear all outstanding
     // requests before it should call signalDrainDone()
     //
-    DPRINTF(Config, "outstanding count %d\n", outstandingCount());
-    if (outstandingCount() > 0) {
+    unsigned int drain_count = outstandingCount() + numAliasedRequests();
+    DPRINTF(Config, "outstanding count %d\n", drain_count);
+    if (drain_count > 0) {
         DPRINTF(Drain, "RubyPort not drained\n");
         return DrainState::Draining;
     } else {
diff --git a/src/mem/ruby/system/RubyPort.hh b/src/mem/ruby/system/RubyPort.hh
index b57828d..edfa1ba 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,11 +43,14 @@
 #define __MEM_RUBY_SYSTEM_RUBYPORT_HH__

 #include <cassert>
+#include <queue>
 #include <string>
+#include <unordered_map>

 #include "mem/ruby/common/MachineID.hh"
 #include "mem/ruby/network/MessageBuffer.hh"
 #include "mem/ruby/protocol/RequestStatus.hh"
+#include "mem/ruby/protocol/RubyAliasingType.hh"
 #include "mem/ruby/system/RubySystem.hh"
 #include "mem/tport.hh"
 #include "params/RubyPort.hh"
@@ -171,6 +174,7 @@
     void ruby_hit_callback(PacketPtr pkt);
     void testDrainComplete();
     void ruby_eviction_callback(Addr address);
+    unsigned int numAliasedRequests() { return _numAliasedRequests; }

     /**
      * Called by the PIO port when receiving a timing response.
@@ -191,7 +195,21 @@

     std::vector<MemSlavePort *> slave_ports;

+    // Aliasing method supported by the controller attached to this port
+    RubyAliasingType m_aliasing_mode;
+
   private:
+    std::unordered_map<Addr, std::queue<PacketPtr>> aliasedRequests;
+
+    unsigned int  _numAliasedRequests;
+
+    // Returns true if the request was successfully submitted;
+    // false if we need to retry
+    bool submitRubyRequest(PacketPtr pkt, bool &aliased);
+
+    // Returns true if sequencer busy
+    bool retryAliasedRequests(Addr addr);
+
     bool onRetryList(MemSlavePort * port)
     {
         return (std::find(retryList.begin(), retryList.end(), port) !=
diff --git a/src/mem/ruby/system/Sequencer.cc b/src/mem/ruby/system/Sequencer.cc
index 9d317aa..aaaed7e 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
  * All rights reserved.
  *
@@ -181,11 +193,6 @@
         return RequestStatus_Aliased;
     }

-    // Create a default entry, mapping the address to NULL, the cast is
-    // there to make gcc 4.4 happy
-    RequestTable::value_type default_entry(line_addr,
-                                           (SequencerRequest*) NULL);
-
     if ((request_type == RubyRequestType_ST) ||
         (request_type == RubyRequestType_RMW_Read) ||
         (request_type == RubyRequestType_RMW_Write) ||
@@ -195,45 +202,33 @@
         (request_type == RubyRequestType_Locked_RMW_Write) ||
         (request_type == RubyRequestType_FLUSH)) {

-        // Check if there is any outstanding read request for the same
+        // Check if there is any outstanding request for the same
         // cache line.
-        if (m_readRequestTable.count(line_addr) > 0) {
+        if (m_readRequestTable.count(line_addr) > 0 && !fwdAliased()) {
             m_store_waiting_on_load++;
             return RequestStatus_Aliased;
         }
-
-        pair<RequestTable::iterator, bool> r =
-            m_writeRequestTable.insert(default_entry);
-        if (r.second) {
-            RequestTable::iterator i = r.first;
- i->second = new SequencerRequest(pkt, request_type, curCycle());
-            m_outstanding_count++;
-        } else {
-          // There is an outstanding write request for the cache line
-          m_store_waiting_on_store++;
-          return RequestStatus_Aliased;
+        if (m_writeRequestTable.count(line_addr) > 0 && !fwdAliased()){
+            m_store_waiting_on_store++;
+            return RequestStatus_Aliased;
         }
+        m_writeRequestTable.emplace(line_addr,
+ new SequencerRequest(pkt, request_type, curCycle()));
     } else {
         // Check if there is any outstanding write request for the same
         // cache line.
-        if (m_writeRequestTable.count(line_addr) > 0) {
-            m_load_waiting_on_store++;
-            return RequestStatus_Aliased;
-        }
-
-        pair<RequestTable::iterator, bool> r =
-            m_readRequestTable.insert(default_entry);
-
-        if (r.second) {
-            RequestTable::iterator i = r.first;
- i->second = new SequencerRequest(pkt, request_type, curCycle());
-            m_outstanding_count++;
-        } else {
-            // There is an outstanding read request for the cache line
+        if (m_readRequestTable.count(line_addr) > 0 && !fwdAliased()) {
             m_load_waiting_on_load++;
             return RequestStatus_Aliased;
         }
+        if (m_writeRequestTable.count(line_addr) > 0 && !fwdAliased()){
+            m_load_waiting_on_store++;
+            return RequestStatus_Aliased;
+        }
+        m_readRequestTable.emplace(line_addr,
+ new SequencerRequest(pkt, request_type, curCycle()));
     }
+    m_outstanding_count++;

     m_outstandReqHist.sample(m_outstanding_count);
     assert(m_outstanding_count ==
@@ -242,6 +237,41 @@
     return RequestStatus_Ready;
 }

+SequencerRequest*
+Sequencer::findAndRemoveRequest(Addr address, RequestTable &rt)
+{
+    assert(address == makeLineAddress(address));
+ // Protocol must used the pkt version if accepting multiple requests for
+    // the same line
+    assert(rt.count(makeLineAddress(address)) == 1);
+
+    RequestTable::iterator i = rt.find(address);
+    assert(i != rt.end());
+    SequencerRequest* request = i->second;
+
+    rt.erase(i);
+    markRemoved();
+
+    return request;
+}
+
+SequencerRequest*
+Sequencer::findAndRemoveRequest(PacketPtr pkt, RequestTable &rt)
+{
+    Addr lineaddr = makeLineAddress(pkt->getAddr());
+    auto range = rt.equal_range(lineaddr);
+    for (auto it = range.first; it != range.second; ++it) {
+        SequencerRequest* request = it->second;
+        if (request->pkt == pkt) {
+            rt.erase(it);
+            markRemoved();
+            return request;
+        }
+    }
+    panic("Request not found");
+    return nullptr;
+}
+
 void
 Sequencer::markRemoved()
 {
@@ -360,16 +390,34 @@
                          const Cycles forwardRequestTime,
                          const Cycles firstResponseTime)
 {
-    assert(address == makeLineAddress(address));
-    assert(m_writeRequestTable.count(makeLineAddress(address)));
+    SequencerRequest* request = findAndRemoveRequest(address,
+                                                     m_writeRequestTable);

-    RequestTable::iterator i = m_writeRequestTable.find(address);
-    assert(i != m_writeRequestTable.end());
-    SequencerRequest* request = i->second;
+    writeCallbackImpl(request, data, externalHit, mach,
+ initialRequestTime, forwardRequestTime, firstResponseTime);
+}

-    m_writeRequestTable.erase(i);
-    markRemoved();
+void
+Sequencer::writeCallback(PacketPtr pkt, DataBlock& data,
+                         const bool externalHit, const MachineType mach,
+                         const Cycles initialRequestTime,
+                         const Cycles forwardRequestTime,
+                         const Cycles firstResponseTime)
+{
+    SequencerRequest* request = findAndRemoveRequest(pkt,
+                                                     m_writeRequestTable);

+    writeCallbackImpl(request, data, externalHit, mach,
+ initialRequestTime, forwardRequestTime, firstResponseTime);
+}
+
+void
+Sequencer::writeCallbackImpl(SequencerRequest* request, DataBlock& data,
+                         const bool externalHit, const MachineType mach,
+                         const Cycles initialRequestTime,
+                         const Cycles forwardRequestTime,
+                         const Cycles firstResponseTime)
+{
     assert((request->m_type == RubyRequestType_ST) ||
            (request->m_type == RubyRequestType_ATOMIC) ||
            (request->m_type == RubyRequestType_RMW_Read) ||
@@ -386,6 +434,7 @@
     //
     // Not valid for Garnet_standalone protocl
     //
+    Addr address = makeLineAddress(request->pkt->getAddr());
     bool success = true;
     if (!m_runningGarnetStandalone)
         success = handleLlsc(address, request);
@@ -415,16 +464,32 @@
                         Cycles forwardRequestTime,
                         Cycles firstResponseTime)
 {
-    assert(address == makeLineAddress(address));
-    assert(m_readRequestTable.count(makeLineAddress(address)));
+    SequencerRequest* request = findAndRemoveRequest(address,
+                                                     m_readRequestTable);
+    readCallbackImpl(request, data, externalHit, mach,
+ initialRequestTime, forwardRequestTime, firstResponseTime);
+}

-    RequestTable::iterator i = m_readRequestTable.find(address);
-    assert(i != m_readRequestTable.end());
-    SequencerRequest* request = i->second;
+void
+Sequencer::readCallback(PacketPtr pkt, DataBlock& data,
+                        bool externalHit, const MachineType mach,
+                        Cycles initialRequestTime,
+                        Cycles forwardRequestTime,
+                        Cycles firstResponseTime)
+{
+    SequencerRequest* request = findAndRemoveRequest(pkt,
+                                                     m_readRequestTable);
+    readCallbackImpl(request, data, externalHit, mach,
+ initialRequestTime, forwardRequestTime, firstResponseTime);
+}

-    m_readRequestTable.erase(i);
-    markRemoved();
-
+void
+Sequencer::readCallbackImpl(SequencerRequest* request, DataBlock& data,
+                        bool externalHit, const MachineType mach,
+                        Cycles initialRequestTime,
+                        Cycles forwardRequestTime,
+                        Cycles firstResponseTime)
+{
     assert((request->m_type == RubyRequestType_LD) ||
            (request->m_type == RubyRequestType_IFETCH));

@@ -529,10 +594,16 @@
 RequestStatus
 Sequencer::makeRequest(PacketPtr pkt)
 {
-    if (m_outstanding_count >= m_max_outstanding_requests) {
+ // Count towards the limit the number of aliased request waiting for retry
+    if ((m_outstanding_count + numAliasedRequests()) >=
+        m_max_outstanding_requests) {
         return RequestStatus_BufferFull;
     }

+    // Also check if we can enqueue the request
+    if (!m_mandatory_q_ptr->areNSlotsAvailable(1, curTick()))
+        return RequestStatus_BufferFull;
+
     RubyRequestType primary_type = RubyRequestType_NULL;
     RubyRequestType secondary_type = RubyRequestType_NULL;

@@ -656,7 +727,7 @@

 template <class KEY, class VALUE>
 std::ostream &
-operator<<(ostream &out, const std::unordered_map<KEY, VALUE> &map)
+operator<<(ostream &out, const std::unordered_multimap<KEY, VALUE> &map)
 {
     auto i = map.begin();
     auto end = map.end();
diff --git a/src/mem/ruby/system/Sequencer.hh b/src/mem/ruby/system/Sequencer.hh
index 33fd530..076a122 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.
  *
@@ -83,6 +95,22 @@
                       const Cycles forwardRequestTime = Cycles(0),
                       const Cycles firstResponseTime = Cycles(0));

+    void writeCallback(PacketPtr pkt,
+                       DataBlock& data,
+                       const bool externalHit = false,
+                       const MachineType mach = MachineType_NUM,
+                       const Cycles initialRequestTime = Cycles(0),
+                       const Cycles forwardRequestTime = Cycles(0),
+                       const Cycles firstResponseTime = Cycles(0));
+
+    void readCallback(PacketPtr pkt,
+                      DataBlock& data,
+                      const bool externalHit = false,
+                      const MachineType mach = MachineType_NUM,
+                      const Cycles initialRequestTime = Cycles(0),
+                      const Cycles forwardRequestTime = Cycles(0),
+                      const Cycles firstResponseTime = Cycles(0));
+
     RequestStatus makeRequest(PacketPtr pkt);
     bool empty() const;
     int outstandingCount() const { return m_outstanding_count; }
@@ -96,7 +124,6 @@
     void print(std::ostream& out) const;
     void checkCoherence(Addr address);

-    void markRemoved();
     void evictionCallback(Addr address);
     void invalidateSC(Addr address);
     int coreId() const { return m_coreId; }
@@ -151,6 +178,20 @@
   private:
     void issueRequest(PacketPtr pkt, RubyRequestType type);

+    void writeCallbackImpl(SequencerRequest *req, DataBlock& data,
+                       const bool externalHit,
+                       const MachineType mach,
+                       const Cycles initialRequestTime,
+                       const Cycles forwardRequestTime,
+                       const Cycles firstResponseTime);
+
+    void readCallbackImpl(SequencerRequest *req, DataBlock& data,
+                       const bool externalHit,
+                       const MachineType mach,
+                       const Cycles initialRequestTime,
+                       const Cycles forwardRequestTime,
+                       const Cycles firstResponseTime);
+
     void hitCallback(SequencerRequest* request, DataBlock& data,
                      bool llscSuccess,
                      const MachineType mach, const bool externalHit,
@@ -168,6 +209,8 @@
RequestStatus insertRequest(PacketPtr pkt, RubyRequestType request_type);
     bool handleLlsc(Addr address, SequencerRequest* request);

+ bool fwdAliased() { return m_aliasing_mode == RubyAliasingType_FORWARD; }
+
     // Private copy constructor and assignment operator
     Sequencer(const Sequencer& obj);
     Sequencer& operator=(const Sequencer& obj);
@@ -186,13 +229,18 @@
     Cycles m_data_cache_hit_latency;
     Cycles m_inst_cache_hit_latency;

-    typedef std::unordered_map<Addr, SequencerRequest*> RequestTable;
+    typedef std::unordered_multimap<Addr, SequencerRequest*> RequestTable;
     RequestTable m_writeRequestTable;
     RequestTable m_readRequestTable;
     // Global outstanding request count, across all request tables
     int m_outstanding_count;
     bool m_deadlock_check_scheduled;

+    // Removes requests from a request table
+    SequencerRequest* findAndRemoveRequest(Addr addr, RequestTable &rt);
+ SequencerRequest* findAndRemoveRequest(PacketPtr pkt, RequestTable &rt);
+    void markRemoved();
+
     //! Counters for recording aliasing information.
     Stats::Scalar m_store_waiting_on_load;
     Stats::Scalar m_store_waiting_on_store;

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

Gerrit-Project: public/gem5
Gerrit-Branch: master
Gerrit-Change-Id: I70e3992632bf0e5fd2f2a457cfdebdf054639276
Gerrit-Change-Number: 21579
Gerrit-PatchSet: 1
Gerrit-Owner: Tiago Mück <tiago.m...@arm.com>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list
gem5-dev@gem5.org
http://m5sim.org/mailman/listinfo/gem5-dev

Reply via email to