ruby: rename ALPHA_Network_test protocol to Garnet_standalone.
[gem5.git] / src / mem / ruby / system / Sequencer.cc
index 1a0f8a66a93afae3c0ae4b3a877f3c559fdbf649..982c1c811dea1aac076ea3242b5549fc2fb98004 100644 (file)
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "base/str.hh"
+#include "arch/x86/ldstflags.hh"
 #include "base/misc.hh"
+#include "base/str.hh"
 #include "cpu/testers/rubytest/RubyTester.hh"
-#include "mem/protocol/CacheMsg.hh"
-#include "mem/protocol/Protocol.hh"
-#include "mem/protocol/Protocol.hh"
-#include "mem/ruby/buffers/MessageBuffer.hh"
-#include "mem/ruby/common/Global.hh"
-#include "mem/ruby/common/SubBlock.hh"
-#include "mem/ruby/libruby.hh"
+#include "debug/MemoryAccess.hh"
+#include "debug/ProtocolTrace.hh"
+#include "debug/RubySequencer.hh"
+#include "debug/RubyStats.hh"
+#include "mem/protocol/PrefetchBit.hh"
+#include "mem/protocol/RubyAccessMode.hh"
 #include "mem/ruby/profiler/Profiler.hh"
-#include "mem/ruby/recorder/Tracer.hh"
-#include "mem/ruby/slicc_interface/AbstractController.hh"
-#include "mem/ruby/system/CacheMemory.hh"
+#include "mem/ruby/slicc_interface/RubyRequest.hh"
+#include "mem/ruby/system/RubySystem.hh"
 #include "mem/ruby/system/Sequencer.hh"
-#include "mem/ruby/system/System.hh"
 #include "mem/packet.hh"
-#include "params/RubySequencer.hh"
+#include "sim/system.hh"
 
 using namespace std;
 
@@ -54,30 +52,26 @@ RubySequencerParams::create()
 }
 
 Sequencer::Sequencer(const Params *p)
-    : RubyPort(p), deadlockCheckEvent(this)
+    : RubyPort(p), m_IncompleteTimes(MachineType_NUM), deadlockCheckEvent(this)
 {
-    m_store_waiting_on_load_cycles = 0;
-    m_store_waiting_on_store_cycles = 0;
-    m_load_waiting_on_store_cycles = 0;
-    m_load_waiting_on_load_cycles = 0;
-
     m_outstanding_count = 0;
 
-    m_max_outstanding_requests = 0;
-    m_deadlock_threshold = 0;
-    m_instCache_ptr = NULL;
-    m_dataCache_ptr = NULL;
-
     m_instCache_ptr = p->icache;
     m_dataCache_ptr = p->dcache;
+    m_data_cache_hit_latency = p->dcache_hit_latency;
+    m_inst_cache_hit_latency = p->icache_hit_latency;
     m_max_outstanding_requests = p->max_outstanding_requests;
     m_deadlock_threshold = p->deadlock_threshold;
-    m_usingRubyTester = p->using_ruby_tester;
 
+    m_coreId = p->coreid; // for tracking the two CorePair sequencers
     assert(m_max_outstanding_requests > 0);
     assert(m_deadlock_threshold > 0);
     assert(m_instCache_ptr != NULL);
     assert(m_dataCache_ptr != NULL);
+    assert(m_data_cache_hit_latency > 0);
+    assert(m_inst_cache_hit_latency > 0);
+
+    m_runningGarnetStandalone = p->garnet_standalone;
 }
 
 Sequencer::~Sequencer()
@@ -87,8 +81,10 @@ Sequencer::~Sequencer()
 void
 Sequencer::wakeup()
 {
+    assert(drainState() != DrainState::Draining);
+
     // Check for deadlock of any of the requests
-    Time current_time = g_eventQueue_ptr->getTime();
+    Cycles current_time = curCycle();
 
     // Check across all outstanding requests
     int total_outstanding = 0;
@@ -101,11 +97,11 @@ Sequencer::wakeup()
             continue;
 
         panic("Possible Deadlock detected. Aborting!\n"
-             "version: %d request.paddr: %d m_readRequestTable: %d "
-             "current time: %u issue_time: %d difference: %d\n", m_version,
-             request->ruby_request.paddr, m_readRequestTable.size(),
-             current_time, request->issue_time,
-             current_time - request->issue_time);
+              "version: %d request.paddr: 0x%x m_readRequestTable: %d "
+              "current time: %u issue_time: %d difference: %d\n", m_version,
+              request->pkt->getAddr(), m_readRequestTable.size(),
+              current_time * clockPeriod(), request->issue_time * clockPeriod(),
+              (current_time * clockPeriod()) - (request->issue_time * clockPeriod()));
     }
 
     RequestTable::iterator write = m_writeRequestTable.begin();
@@ -116,11 +112,11 @@ Sequencer::wakeup()
             continue;
 
         panic("Possible Deadlock detected. Aborting!\n"
-             "version: %d request.paddr: %d m_writeRequestTable: %d "
-             "current time: %u issue_time: %d difference: %d\n", m_version,
-             request->ruby_request.paddr, m_writeRequestTable.size(),
-             current_time, request->issue_time,
-             current_time - request->issue_time);
+              "version: %d request.paddr: 0x%x m_writeRequestTable: %d "
+              "current time: %u issue_time: %d difference: %d\n", m_version,
+              request->pkt->getAddr(), m_writeRequestTable.size(),
+              current_time * clockPeriod(), request->issue_time * clockPeriod(),
+              (current_time * clockPeriod()) - (request->issue_time * clockPeriod()));
     }
 
     total_outstanding += m_writeRequestTable.size();
@@ -130,144 +126,122 @@ Sequencer::wakeup()
 
     if (m_outstanding_count > 0) {
         // If there are still outstanding requests, keep checking
-        schedule(deadlockCheckEvent,
-                 m_deadlock_threshold * g_eventQueue_ptr->getClock() +
-                 curTick);
+        schedule(deadlockCheckEvent, clockEdge(m_deadlock_threshold));
     }
 }
 
-void
-Sequencer::printStats(ostream & out) const
-{
-    out << "Sequencer: " << m_name << endl
-        << "  store_waiting_on_load_cycles: "
-        << m_store_waiting_on_load_cycles << endl
-        << "  store_waiting_on_store_cycles: "
-        << m_store_waiting_on_store_cycles << endl
-        << "  load_waiting_on_load_cycles: "
-        << m_load_waiting_on_load_cycles << endl
-        << "  load_waiting_on_store_cycles: "
-        << m_load_waiting_on_store_cycles << endl;
-}
-
-void
-Sequencer::printProgress(ostream& out) const
+void Sequencer::resetStats()
 {
-#if 0
-    int total_demand = 0;
-    out << "Sequencer Stats Version " << m_version << endl;
-    out << "Current time = " << g_eventQueue_ptr->getTime() << endl;
-    out << "---------------" << endl;
-    out << "outstanding requests" << endl;
-
-    out << "proc " << m_Read
-        << " version Requests = " << m_readRequestTable.size() << endl;
-
-    // print the request table
-    RequestTable::iterator read = m_readRequestTable.begin();
-    RequestTable::iterator read_end = m_readRequestTable.end();
-    for (; read != read_end; ++read) {
-        SequencerRequest* request = read->second;
-        out << "\tRequest[ " << i << " ] = " << request->type
-            << " Address " << rkeys[i]
-            << " Posted " << request->issue_time
-            << " PF " << PrefetchBit_No << endl;
-        total_demand++;
-    }
-
-    out << "proc " << m_version
-        << " Write Requests = " << m_writeRequestTable.size << endl;
-
-    // print the request table
-    RequestTable::iterator write = m_writeRequestTable.begin();
-    RequestTable::iterator write_end = m_writeRequestTable.end();
-    for (; write != write_end; ++write) {
-        SequencerRequest* request = write->second;
-        out << "\tRequest[ " << i << " ] = " << request.getType()
-            << " Address " << wkeys[i]
-            << " Posted " << request.getTime()
-            << " PF " << request.getPrefetch() << endl;
-        if (request.getPrefetch() == PrefetchBit_No) {
-            total_demand++;
+    m_latencyHist.reset();
+    m_hitLatencyHist.reset();
+    m_missLatencyHist.reset();
+    for (int i = 0; i < RubyRequestType_NUM; i++) {
+        m_typeLatencyHist[i]->reset();
+        m_hitTypeLatencyHist[i]->reset();
+        m_missTypeLatencyHist[i]->reset();
+        for (int j = 0; j < MachineType_NUM; j++) {
+            m_hitTypeMachLatencyHist[i][j]->reset();
+            m_missTypeMachLatencyHist[i][j]->reset();
         }
     }
 
-    out << endl;
+    for (int i = 0; i < MachineType_NUM; i++) {
+        m_missMachLatencyHist[i]->reset();
+        m_hitMachLatencyHist[i]->reset();
 
-    out << "Total Number Outstanding: " << m_outstanding_count << endl
-        << "Total Number Demand     : " << total_demand << endl
-        << "Total Number Prefetches : " << m_outstanding_count - total_demand
-        << endl << endl << endl;
-#endif
-}
+        m_IssueToInitialDelayHist[i]->reset();
+        m_InitialToForwardDelayHist[i]->reset();
+        m_ForwardToFirstResponseDelayHist[i]->reset();
+        m_FirstResponseToCompletionDelayHist[i]->reset();
 
-void
-Sequencer::printConfig(ostream& out) const
-{
-    out << "Seqeuncer config: " << m_name << endl
-        << "  controller: " << m_controller->getName() << endl
-        << "  version: " << m_version << endl
-        << "  max_outstanding_requests: " << m_max_outstanding_requests << endl
-        << "  deadlock_threshold: " << m_deadlock_threshold << endl;
+        m_IncompleteTimes[i] = 0;
+    }
 }
 
 // Insert the request on the correct request table.  Return true if
 // the entry was already present.
-bool
-Sequencer::insertRequest(SequencerRequest* request)
+RequestStatus
+Sequencer::insertRequest(PacketPtr pkt, RubyRequestType request_type)
 {
-    int total_outstanding =
-        m_writeRequestTable.size() + m_readRequestTable.size();
-
-    assert(m_outstanding_count == total_outstanding);
+    assert(m_outstanding_count ==
+        (m_writeRequestTable.size() + m_readRequestTable.size()));
 
     // See if we should schedule a deadlock check
-    if (deadlockCheckEvent.scheduled() == false) {
-        schedule(deadlockCheckEvent, m_deadlock_threshold + curTick);
+    if (!deadlockCheckEvent.scheduled() &&
+        drainState() != DrainState::Draining) {
+        schedule(deadlockCheckEvent, clockEdge(m_deadlock_threshold));
+    }
+
+    Addr line_addr = makeLineAddress(pkt->getAddr());
+
+    // Check if the line is blocked for a Locked_RMW
+    if (m_controller->isBlocked(line_addr) &&
+        (request_type != RubyRequestType_Locked_RMW_Write)) {
+        // Return that this request's cache line address aliases with
+        // a prior request that locked the cache line. The request cannot
+        // proceed until the cache line is unlocked by a Locked_RMW_Write
+        return RequestStatus_Aliased;
     }
 
-    Address line_addr(request->ruby_request.paddr);
-    line_addr.makeLineAddress();
-    if ((request->ruby_request.type == RubyRequestType_ST) ||
-        (request->ruby_request.type == RubyRequestType_RMW_Read) ||
-        (request->ruby_request.type == RubyRequestType_RMW_Write) ||
-        (request->ruby_request.type == RubyRequestType_Locked_Read) ||
-        (request->ruby_request.type == RubyRequestType_Locked_Write)) {
+    // 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) ||
+        (request_type == RubyRequestType_Load_Linked) ||
+        (request_type == RubyRequestType_Store_Conditional) ||
+        (request_type == RubyRequestType_Locked_RMW_Read) ||
+        (request_type == RubyRequestType_Locked_RMW_Write) ||
+        (request_type == RubyRequestType_FLUSH)) {
+
+        // Check if there is any outstanding read request for the same
+        // cache line.
+        if (m_readRequestTable.count(line_addr) > 0) {
+            m_store_waiting_on_load++;
+            return RequestStatus_Aliased;
+        }
+
         pair<RequestTable::iterator, bool> r =
-            m_writeRequestTable.insert(RequestTable::value_type(line_addr, 0));
-        bool success = r.second;
-        RequestTable::iterator i = r.first;
-        if (!success) {
-            i->second = request;
-            // return true;
-
-            // drh5: isn't this an error?  do you lose the initial request?
-            assert(0);
+            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;
         }
-        i->second = request;
-        m_outstanding_count++;
     } 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(RequestTable::value_type(line_addr, 0));
-        bool success = r.second;
-        RequestTable::iterator i = r.first;
-        if (!success) {
-            i->second = request;
-            // return true;
-
-            // drh5: isn't this an error?  do you lose the initial request?
-            assert(0);
+            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
+            m_load_waiting_on_load++;
+            return RequestStatus_Aliased;
         }
-        i->second = request;
-        m_outstanding_count++;
     }
 
-    g_system_ptr->getProfiler()->sequencerRequests(m_outstanding_count);
-
-    total_outstanding = m_writeRequestTable.size() + m_readRequestTable.size();
-    assert(m_outstanding_count == total_outstanding);
+    m_outstandReqHist.sample(m_outstanding_count);
+    assert(m_outstanding_count ==
+        (m_writeRequestTable.size() + m_readRequestTable.size()));
 
-    return false;
+    return RequestStatus_Ready;
 }
 
 void
@@ -279,94 +253,117 @@ Sequencer::markRemoved()
 }
 
 void
-Sequencer::removeRequest(SequencerRequest* srequest)
+Sequencer::invalidateSC(Addr address)
 {
-    assert(m_outstanding_count ==
-           m_writeRequestTable.size() + m_readRequestTable.size());
-
-    const RubyRequest & ruby_request = srequest->ruby_request;
-    Address line_addr(ruby_request.paddr);
-    line_addr.makeLineAddress();
-    if ((ruby_request.type == RubyRequestType_ST) ||
-        (ruby_request.type == RubyRequestType_RMW_Read) ||
-        (ruby_request.type == RubyRequestType_RMW_Write) ||
-        (ruby_request.type == RubyRequestType_Locked_Read) ||
-        (ruby_request.type == RubyRequestType_Locked_Write)) {
-        m_writeRequestTable.erase(line_addr);
-    } else {
-        m_readRequestTable.erase(line_addr);
+    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();
     }
-
-    markRemoved();
 }
 
 bool
-Sequencer::handleLlsc(const Address& address, SequencerRequest* request)
+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->ruby_request.type == RubyRequestType_Locked_Write) {
-        if (!m_dataCache_ptr->isLocked(address, m_version)) {
+    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->ruby_request.pkt->req->setExtraData(0);
+            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.  
+            // setting the extra data to one.
             //
-            request->ruby_request.pkt->req->setExtraData(1);
+            request->pkt->req->setExtraData(1);
         }
         //
         // Independent of success, all SC operations must clear the lock
         //
-        m_dataCache_ptr->clearLocked(address);
-    } else if (request->ruby_request.type == RubyRequestType_Locked_Read) {
+        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?
         //
-        m_dataCache_ptr->setLocked(address, m_version);
-    } else if (m_dataCache_ptr->isLocked(address, m_version)) {
+        e->setLocked(m_version);
+    } else if (e->isLocked(m_version)) {
         //
         // Normal writes should clear the locked address
         //
-        m_dataCache_ptr->clearLocked(address);
+        e->clearLocked();
     }
     return success;
 }
 
 void
-Sequencer::writeCallback(const Address& address, DataBlock& data)
+Sequencer::recordMissLatency(const Cycles cycles, const RubyRequestType type,
+                             const MachineType respondingMach,
+                             bool isExternalHit, Cycles issuedTime,
+                             Cycles initialRequestTime,
+                             Cycles forwardRequestTime,
+                             Cycles firstResponseTime, Cycles completionTime)
 {
-    writeCallback(address, GenericMachineType_NULL, data);
-}
+    m_latencyHist.sample(cycles);
+    m_typeLatencyHist[type]->sample(cycles);
+
+    if (isExternalHit) {
+        m_missLatencyHist.sample(cycles);
+        m_missTypeLatencyHist[type]->sample(cycles);
+
+        if (respondingMach != MachineType_NUM) {
+            m_missMachLatencyHist[respondingMach]->sample(cycles);
+            m_missTypeMachLatencyHist[type][respondingMach]->sample(cycles);
+
+            if ((issuedTime <= initialRequestTime) &&
+                (initialRequestTime <= forwardRequestTime) &&
+                (forwardRequestTime <= firstResponseTime) &&
+                (firstResponseTime <= completionTime)) {
+
+                m_IssueToInitialDelayHist[respondingMach]->sample(
+                    initialRequestTime - issuedTime);
+                m_InitialToForwardDelayHist[respondingMach]->sample(
+                    forwardRequestTime - initialRequestTime);
+                m_ForwardToFirstResponseDelayHist[respondingMach]->sample(
+                    firstResponseTime - forwardRequestTime);
+                m_FirstResponseToCompletionDelayHist[respondingMach]->sample(
+                    completionTime - firstResponseTime);
+            } else {
+                m_IncompleteTimes[respondingMach]++;
+            }
+        }
+    } else {
+        m_hitLatencyHist.sample(cycles);
+        m_hitTypeLatencyHist[type]->sample(cycles);
 
-void
-Sequencer::writeCallback(const Address& address,
-                         GenericMachineType mach, 
-                         DataBlock& data)
-{
-    writeCallback(address, mach, data, 0, 0, 0);
+        if (respondingMach != MachineType_NUM) {
+            m_hitMachLatencyHist[respondingMach]->sample(cycles);
+            m_hitTypeMachLatencyHist[type][respondingMach]->sample(cycles);
+        }
+    }
 }
 
 void
-Sequencer::writeCallback(const Address& address,
-                         GenericMachineType mach, 
-                         DataBlock& data,
-                         Time initialRequestTime,
-                         Time forwardRequestTime,
-                         Time firstResponseTime)
+Sequencer::writeCallback(Addr address, DataBlock& data,
+                         const bool externalHit, const MachineType mach,
+                         const Cycles initialRequestTime,
+                         const Cycles forwardRequestTime,
+                         const Cycles firstResponseTime)
 {
-    assert(address == line_address(address));
-    assert(m_writeRequestTable.count(line_address(address)));
+    assert(address == makeLineAddress(address));
+    assert(m_writeRequestTable.count(makeLineAddress(address)));
 
     RequestTable::iterator i = m_writeRequestTable.find(address);
     assert(i != m_writeRequestTable.end());
@@ -375,52 +372,53 @@ Sequencer::writeCallback(const Address& address,
     m_writeRequestTable.erase(i);
     markRemoved();
 
-    assert((request->ruby_request.type == RubyRequestType_ST) ||
-           (request->ruby_request.type == RubyRequestType_RMW_Read) ||
-           (request->ruby_request.type == RubyRequestType_RMW_Write) ||
-           (request->ruby_request.type == RubyRequestType_Locked_Read) ||
-           (request->ruby_request.type == RubyRequestType_Locked_Write));
+    assert((request->m_type == RubyRequestType_ST) ||
+           (request->m_type == RubyRequestType_ATOMIC) ||
+           (request->m_type == RubyRequestType_RMW_Read) ||
+           (request->m_type == RubyRequestType_RMW_Write) ||
+           (request->m_type == RubyRequestType_Load_Linked) ||
+           (request->m_type == RubyRequestType_Store_Conditional) ||
+           (request->m_type == RubyRequestType_Locked_RMW_Read) ||
+           (request->m_type == RubyRequestType_Locked_RMW_Write) ||
+           (request->m_type == RubyRequestType_FLUSH));
 
     //
     // For Alpha, properly handle LL, SC, and write requests with respect to
     // locked cache blocks.
     //
-    bool success = handleLlsc(address, request);
-
-    if (request->ruby_request.type == RubyRequestType_RMW_Read) {
+    // Not valid for Garnet_standalone protocl
+    //
+    bool success = true;
+    if (!m_runningGarnetStandalone)
+        success = handleLlsc(address, request);
+
+    // Handle SLICC block_on behavior for Locked_RMW accesses. NOTE: the
+    // address variable here is assumed to be a line address, so when
+    // blocking buffers, must check line addresses.
+    if (request->m_type == RubyRequestType_Locked_RMW_Read) {
+        // blockOnQueue blocks all first-level cache controller queues
+        // waiting on memory accesses for the specified address that go to
+        // the specified queue. In this case, a Locked_RMW_Write must go to
+        // the mandatory_q before unblocking the first-level controller.
+        // This will block standard loads, stores, ifetches, etc.
         m_controller->blockOnQueue(address, m_mandatory_q_ptr);
-    } else if (request->ruby_request.type == RubyRequestType_RMW_Write) {
+    } else if (request->m_type == RubyRequestType_Locked_RMW_Write) {
         m_controller->unblock(address);
     }
 
-    hitCallback(request, mach, data, success, 
+    hitCallback(request, data, success, mach, externalHit,
                 initialRequestTime, forwardRequestTime, firstResponseTime);
 }
 
 void
-Sequencer::readCallback(const Address& address, DataBlock& data)
+Sequencer::readCallback(Addr address, DataBlock& data,
+                        bool externalHit, const MachineType mach,
+                        Cycles initialRequestTime,
+                        Cycles forwardRequestTime,
+                        Cycles firstResponseTime)
 {
-    readCallback(address, GenericMachineType_NULL, data);
-}
-
-void
-Sequencer::readCallback(const Address& address,
-                        GenericMachineType mach,
-                        DataBlock& data)
-{
-    readCallback(address, mach, data, 0, 0, 0);
-}
-
-void
-Sequencer::readCallback(const Address& address,
-                        GenericMachineType mach,
-                        DataBlock& data,
-                        Time initialRequestTime,
-                        Time forwardRequestTime,
-                        Time firstResponseTime)
-{
-    assert(address == line_address(address));
-    assert(m_readRequestTable.count(line_address(address)));
+    assert(address == makeLineAddress(address));
+    assert(m_readRequestTable.count(makeLineAddress(address)));
 
     RequestTable::iterator i = m_readRequestTable.find(address);
     assert(i != m_readRequestTable.end());
@@ -429,151 +427,101 @@ Sequencer::readCallback(const Address& address,
     m_readRequestTable.erase(i);
     markRemoved();
 
-    assert((request->ruby_request.type == RubyRequestType_LD) ||
-           (request->ruby_request.type == RubyRequestType_RMW_Read) ||
-           (request->ruby_request.type == RubyRequestType_IFETCH));
+    assert((request->m_type == RubyRequestType_LD) ||
+           (request->m_type == RubyRequestType_IFETCH));
 
-    hitCallback(request, mach, data, true, 
+    hitCallback(request, data, true, mach, externalHit,
                 initialRequestTime, forwardRequestTime, firstResponseTime);
 }
 
 void
-Sequencer::hitCallback(SequencerRequest* srequest,
-                       GenericMachineType mach,
-                       DataBlock& data,
-                       bool success,
-                       Time initialRequestTime,
-                       Time forwardRequestTime,
-                       Time firstResponseTime)
+Sequencer::hitCallback(SequencerRequest* srequest, DataBlock& data,
+                       bool llscSuccess,
+                       const MachineType mach, const bool externalHit,
+                       const Cycles initialRequestTime,
+                       const Cycles forwardRequestTime,
+                       const Cycles firstResponseTime)
 {
-    const RubyRequest & ruby_request = srequest->ruby_request;
-    Address request_address(ruby_request.paddr);
-    Address request_line_address(ruby_request.paddr);
-    request_line_address.makeLineAddress();
-    RubyRequestType type = ruby_request.type;
-    Time issued_time = srequest->issue_time;
-
-    // Set this cache entry to the most recently used
-    if (type == RubyRequestType_IFETCH) {
-        if (m_instCache_ptr->isTagPresent(request_line_address))
-            m_instCache_ptr->setMRU(request_line_address);
-    } else {
-        if (m_dataCache_ptr->isTagPresent(request_line_address))
-            m_dataCache_ptr->setMRU(request_line_address);
-    }
-
-    assert(g_eventQueue_ptr->getTime() >= issued_time);
-    Time miss_latency = g_eventQueue_ptr->getTime() - issued_time;
-
-    // Profile the miss latency for all non-zero demand misses
-    if (miss_latency != 0) {
-        g_system_ptr->getProfiler()->missLatency(miss_latency, type, mach);
-
-        if (mach == GenericMachineType_L1Cache_wCC) {
-            g_system_ptr->getProfiler()->missLatencyWcc(issued_time,
-                                                   initialRequestTime,
-                                                   forwardRequestTime,
-                                                   firstResponseTime,
-                                                   g_eventQueue_ptr->getTime());
-        }
-
-        if (mach == GenericMachineType_Directory) {
-            g_system_ptr->getProfiler()->missLatencyDir(issued_time,
-                                                   initialRequestTime,
-                                                   forwardRequestTime,
-                                                   firstResponseTime,
-                                                   g_eventQueue_ptr->getTime());
-        }
-
-        if (Debug::getProtocolTrace()) {
-            if (success) {
-                g_system_ptr->getProfiler()->
-                    profileTransition("Seq", m_version,
-                                      Address(ruby_request.paddr), "", "Done", "",
-                                      csprintf("%d cycles", miss_latency));
-            } else {
-                g_system_ptr->getProfiler()->
-                    profileTransition("Seq", m_version,
-                                      Address(ruby_request.paddr), "", "SC_Failed", "",
-                                      csprintf("%d cycles", miss_latency));
-            }
-        }
-    }
-#if 0
-    if (request.getPrefetch() == PrefetchBit_Yes) {
-        return; // Ignore the prefetch
-    }
-#endif
-
-    // update the data
-    if (ruby_request.data != NULL) {
+    warn_once("Replacement policy updates recently became the responsibility "
+              "of SLICC state machines. Make sure to setMRU() near callbacks "
+              "in .sm files!");
+
+    PacketPtr pkt = srequest->pkt;
+    Addr request_address(pkt->getAddr());
+    RubyRequestType type = srequest->m_type;
+    Cycles issued_time = srequest->issue_time;
+
+    assert(curCycle() >= issued_time);
+    Cycles total_latency = curCycle() - issued_time;
+
+    // Profile the latency for all demand accesses.
+    recordMissLatency(total_latency, type, mach, externalHit, issued_time,
+                      initialRequestTime, forwardRequestTime,
+                      firstResponseTime, curCycle());
+
+    DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %#x %d cycles\n",
+             curTick(), m_version, "Seq",
+             llscSuccess ? "Done" : "SC_Failed", "", "",
+             printAddress(request_address), total_latency);
+
+    // update the data unless it is a non-data-carrying flush
+    if (RubySystem::getWarmupEnabled()) {
+        data.setData(pkt->getConstPtr<uint8_t>(),
+                     getOffset(request_address), pkt->getSize());
+    } else if (!pkt->isFlush()) {
         if ((type == RubyRequestType_LD) ||
             (type == RubyRequestType_IFETCH) ||
             (type == RubyRequestType_RMW_Read) ||
-            (type == RubyRequestType_Locked_Read)) {
-
-            memcpy(ruby_request.data,
-                   data.getData(request_address.getOffset(), ruby_request.len),
-                   ruby_request.len);
+            (type == RubyRequestType_Locked_RMW_Read) ||
+            (type == RubyRequestType_Load_Linked)) {
+            memcpy(pkt->getPtr<uint8_t>(),
+                   data.getData(getOffset(request_address), pkt->getSize()),
+                   pkt->getSize());
+            DPRINTF(RubySequencer, "read data %s\n", data);
+        } else if (pkt->req->isSwap()) {
+            std::vector<uint8_t> overwrite_val(pkt->getSize());
+            memcpy(&overwrite_val[0], pkt->getConstPtr<uint8_t>(),
+                   pkt->getSize());
+            memcpy(pkt->getPtr<uint8_t>(),
+                   data.getData(getOffset(request_address), pkt->getSize()),
+                   pkt->getSize());
+            data.setData(&overwrite_val[0],
+                         getOffset(request_address), pkt->getSize());
+            DPRINTF(RubySequencer, "swap data %s\n", data);
         } else {
-            data.setData(ruby_request.data, request_address.getOffset(),
-                         ruby_request.len);
+            data.setData(pkt->getConstPtr<uint8_t>(),
+                         getOffset(request_address), pkt->getSize());
+            DPRINTF(RubySequencer, "set data %s\n", data);
         }
-    } else {
-        DPRINTF(MemoryAccess,
-                "WARNING.  Data not transfered from Ruby to M5 for type %s\n",
-                RubyRequestType_to_string(type));
     }
 
     // If using the RubyTester, update the RubyTester sender state's
     // subBlock with the recieved data.  The tester will later access
     // this state.
-    // Note: RubyPort will access it's sender state before the
-    // RubyTester.
     if (m_usingRubyTester) {
-        RubyPort::SenderState *requestSenderState =
-            safe_cast<RubyPort::SenderState*>(ruby_request.pkt->senderState);
+        DPRINTF(RubySequencer, "hitCallback %s 0x%x using RubyTester\n",
+                pkt->cmdString(), pkt->getAddr());
         RubyTester::SenderState* testerSenderState =
-            safe_cast<RubyTester::SenderState*>(requestSenderState->saved);
-        testerSenderState->subBlock->mergeFrom(data);
+            pkt->findNextSenderState<RubyTester::SenderState>();
+        assert(testerSenderState);
+        testerSenderState->subBlock.mergeFrom(data);
     }
 
-    ruby_hit_callback(ruby_request.pkt);
     delete srequest;
-}
-
-// Returns true if the sequencer already has a load or store outstanding
-RequestStatus
-Sequencer::getRequestStatus(const RubyRequest& request)
-{
-    bool is_outstanding_store =
-        !!m_writeRequestTable.count(line_address(Address(request.paddr)));
-    bool is_outstanding_load =
-        !!m_readRequestTable.count(line_address(Address(request.paddr)));
-    if (is_outstanding_store) {
-        if ((request.type == RubyRequestType_LD) ||
-            (request.type == RubyRequestType_IFETCH) ||
-            (request.type == RubyRequestType_RMW_Read)) {
-            m_store_waiting_on_load_cycles++;
-        } else {
-            m_store_waiting_on_store_cycles++;
-        }
-        return RequestStatus_Aliased;
-    } else if (is_outstanding_load) {
-        if ((request.type == RubyRequestType_ST) ||
-            (request.type == RubyRequestType_RMW_Write)) {
-            m_load_waiting_on_store_cycles++;
-        } else {
-            m_load_waiting_on_load_cycles++;
-        }
-        return RequestStatus_Aliased;
-    }
 
-    if (m_outstanding_count >= m_max_outstanding_requests) {
-        return RequestStatus_BufferFull;
+    RubySystem *rs = m_ruby_system;
+    if (RubySystem::getWarmupEnabled()) {
+        assert(pkt->req);
+        delete pkt->req;
+        delete pkt;
+        rs->m_cache_recorder->enqueueNextFetchRequest();
+    } else if (RubySystem::getCooldownEnabled()) {
+        delete pkt;
+        rs->m_cache_recorder->enqueueNextFlushRequest();
+    } else {
+        ruby_hit_callback(pkt);
+        testDrainComplete();
     }
-
-    return RequestStatus_Ready;
 }
 
 bool
@@ -583,127 +531,150 @@ Sequencer::empty() const
 }
 
 RequestStatus
-Sequencer::makeRequest(const RubyRequest &request)
+Sequencer::makeRequest(PacketPtr pkt)
 {
-    assert(Address(request.paddr).getOffset() + request.len <=
-           RubySystem::getBlockSizeBytes());
-    RequestStatus status = getRequestStatus(request);
-    if (status != RequestStatus_Ready)
-        return status;
+    if (m_outstanding_count >= m_max_outstanding_requests) {
+        return RequestStatus_BufferFull;
+    }
+
+    RubyRequestType primary_type = RubyRequestType_NULL;
+    RubyRequestType secondary_type = RubyRequestType_NULL;
 
-    SequencerRequest *srequest =
-        new SequencerRequest(request, g_eventQueue_ptr->getTime());
-    bool found = insertRequest(srequest);
-    if (found) {
-        panic("Sequencer::makeRequest should never be called if the "
-              "request is already outstanding\n");
-        return RequestStatus_NULL;
+    if (pkt->isLLSC()) {
+        //
+        // Alpha LL/SC instructions need to be handled carefully by the cache
+        // coherence protocol to ensure they follow the proper semantics. In
+        // particular, by identifying the operations as atomic, the protocol
+        // should understand that migratory sharing optimizations should not
+        // be performed (i.e. a load between the LL and SC should not steal
+        // away exclusive permission).
+        //
+        if (pkt->isWrite()) {
+            DPRINTF(RubySequencer, "Issuing SC\n");
+            primary_type = RubyRequestType_Store_Conditional;
+        } else {
+            DPRINTF(RubySequencer, "Issuing LL\n");
+            assert(pkt->isRead());
+            primary_type = RubyRequestType_Load_Linked;
+        }
+        secondary_type = RubyRequestType_ATOMIC;
+    } else if (pkt->req->isLockedRMW()) {
+        //
+        // x86 locked instructions are translated to store cache coherence
+        // requests because these requests should always be treated as read
+        // exclusive operations and should leverage any migratory sharing
+        // optimization built into the protocol.
+        //
+        if (pkt->isWrite()) {
+            DPRINTF(RubySequencer, "Issuing Locked RMW Write\n");
+            primary_type = RubyRequestType_Locked_RMW_Write;
+        } else {
+            DPRINTF(RubySequencer, "Issuing Locked RMW Read\n");
+            assert(pkt->isRead());
+            primary_type = RubyRequestType_Locked_RMW_Read;
+        }
+        secondary_type = RubyRequestType_ST;
+    } else {
+        //
+        // To support SwapReq, we need to check isWrite() first: a SwapReq
+        // should always be treated like a write, but since a SwapReq implies
+        // both isWrite() and isRead() are true, check isWrite() first here.
+        //
+        if (pkt->isWrite()) {
+            //
+            // Note: M5 packets do not differentiate ST from RMW_Write
+            //
+            primary_type = secondary_type = RubyRequestType_ST;
+        } else if (pkt->isRead()) {
+            if (pkt->req->isInstFetch()) {
+                primary_type = secondary_type = RubyRequestType_IFETCH;
+            } else {
+                bool storeCheck = false;
+                // only X86 need the store check
+                if (system->getArch() == Arch::X86ISA) {
+                    uint32_t flags = pkt->req->getFlags();
+                    storeCheck = flags &
+                        (X86ISA::StoreCheck << X86ISA::FlagShift);
+                }
+                if (storeCheck) {
+                    primary_type = RubyRequestType_RMW_Read;
+                    secondary_type = RubyRequestType_ST;
+                } else {
+                    primary_type = secondary_type = RubyRequestType_LD;
+                }
+            }
+        } else if (pkt->isFlush()) {
+          primary_type = secondary_type = RubyRequestType_FLUSH;
+        } else {
+            panic("Unsupported ruby packet type\n");
+        }
     }
 
-    issueRequest(request);
+    RequestStatus status = insertRequest(pkt, primary_type);
+    if (status != RequestStatus_Ready)
+        return status;
+
+    issueRequest(pkt, secondary_type);
 
     // TODO: issue hardware prefetches here
     return RequestStatus_Issued;
 }
 
 void
-Sequencer::issueRequest(const RubyRequest& request)
+Sequencer::issueRequest(PacketPtr pkt, RubyRequestType secondary_type)
 {
-    // TODO: get rid of CacheMsg, CacheRequestType, and
-    // AccessModeTYpe, & have SLICC use RubyRequest and subtypes
-    // natively
-    CacheRequestType ctype;
-    switch(request.type) {
-      case RubyRequestType_IFETCH:
-        ctype = CacheRequestType_IFETCH;
-        break;
-      case RubyRequestType_LD:
-        ctype = CacheRequestType_LD;
-        break;
-      case RubyRequestType_ST:
-        ctype = CacheRequestType_ST;
-        break;
-      case RubyRequestType_Locked_Read:
-      case RubyRequestType_Locked_Write:
-        ctype = CacheRequestType_ATOMIC;
-        break;
-      case RubyRequestType_RMW_Read:
-        ctype = CacheRequestType_ATOMIC;
-        break;
-      case RubyRequestType_RMW_Write:
-        ctype = CacheRequestType_ATOMIC;
-        break;
-      default:
-        assert(0);
-    }
+    assert(pkt != NULL);
+    ContextID proc_id = pkt->req->hasContextId() ?
+        pkt->req->contextId() : InvalidContextID;
 
-    AccessModeType amtype;
-    switch(request.access_mode){
-      case RubyAccessMode_User:
-        amtype = AccessModeType_UserMode;
-        break;
-      case RubyAccessMode_Supervisor:
-        amtype = AccessModeType_SupervisorMode;
-        break;
-      case RubyAccessMode_Device:
-        amtype = AccessModeType_UserMode;
-        break;
-      default:
-        assert(0);
-    }
-
-    Address line_addr(request.paddr);
-    line_addr.makeLineAddress();
-    CacheMsg *msg = new CacheMsg(line_addr, Address(request.paddr), ctype,
-        Address(request.pc), amtype, request.len, PrefetchBit_No,
-        request.proc_id);
-
-    if (Debug::getProtocolTrace()) {
-        g_system_ptr->getProfiler()->
-            profileTransition("Seq", m_version, Address(request.paddr),
-                              "", "Begin", "",
-                              RubyRequestType_to_string(request.type));
-    }
+    ContextID core_id = coreId();
 
-    if (g_system_ptr->getTracer()->traceEnabled()) {
-        g_system_ptr->getTracer()->
-            traceRequest(this, line_addr, Address(request.pc),
-                         request.type, g_eventQueue_ptr->getTime());
+    // If valid, copy the pc to the ruby request
+    Addr pc = 0;
+    if (pkt->req->hasPC()) {
+        pc = pkt->req->getPC();
     }
 
-    Time latency = 0;  // initialzed to an null value
-
-    if (request.type == RubyRequestType_IFETCH)
-        latency = m_instCache_ptr->getLatency();
+    // check if the packet has data as for example prefetch and flush
+    // requests do not
+    std::shared_ptr<RubyRequest> msg =
+        std::make_shared<RubyRequest>(clockEdge(), pkt->getAddr(),
+                                      pkt->isFlush() ?
+                                      nullptr : pkt->getPtr<uint8_t>(),
+                                      pkt->getSize(), pc, secondary_type,
+                                      RubyAccessMode_Supervisor, pkt,
+                                      PrefetchBit_No, proc_id, core_id);
+
+    DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %#x %s\n",
+            curTick(), m_version, "Seq", "Begin", "", "",
+            printAddress(msg->getPhysicalAddress()),
+            RubyRequestType_to_string(secondary_type));
+
+    // The Sequencer currently assesses instruction and data cache hit latency
+    // for the top-level caches at the beginning of a memory access.
+    // TODO: Eventually, this latency should be moved to represent the actual
+    // cache access latency portion of the memory access. This will require
+    // changing cache controller protocol files to assess the latency on the
+    // access response path.
+    Cycles latency(0);  // Initialize to zero to catch misconfigured latency
+    if (secondary_type == RubyRequestType_IFETCH)
+        latency = m_inst_cache_hit_latency;
     else
-        latency = m_dataCache_ptr->getLatency();
+        latency = m_data_cache_hit_latency;
 
     // Send the message to the cache controller
     assert(latency > 0);
 
     assert(m_mandatory_q_ptr != NULL);
-    m_mandatory_q_ptr->enqueue(msg, latency);
+    m_mandatory_q_ptr->enqueue(msg, clockEdge(), cyclesToTicks(latency));
 }
 
-#if 0
-bool
-Sequencer::tryCacheAccess(const Address& addr, CacheRequestType type,
-                          AccessModeType access_mode,
-                          int size, DataBlock*& data_ptr)
-{
-    CacheMemory *cache =
-        (type == CacheRequestType_IFETCH) ? m_instCache_ptr : m_dataCache_ptr;
-
-    return cache->tryCacheAccess(line_address(addr), type, data_ptr);
-}
-#endif
-
 template <class KEY, class VALUE>
 std::ostream &
-operator<<(ostream &out, const m5::hash_map<KEY, VALUE> &map)
+operator<<(ostream &out, const std::unordered_map<KEY, VALUE> &map)
 {
-    typename m5::hash_map<KEY, VALUE>::const_iterator i = map.begin();
-    typename m5::hash_map<KEY, VALUE>::const_iterator end = map.end();
+    auto i = map.begin();
+    auto end = map.end();
 
     out << "[";
     for (; i != end; ++i)
@@ -727,9 +698,97 @@ Sequencer::print(ostream& out) const
 // upgraded when invoked, coherence violations will be checked for the
 // given block
 void
-Sequencer::checkCoherence(const Address& addr)
+Sequencer::checkCoherence(Addr addr)
 {
 #ifdef CHECK_COHERENCE
-    g_system_ptr->checkGlobalCoherenceInvariant(addr);
+    m_ruby_system->checkGlobalCoherenceInvariant(addr);
 #endif
 }
+
+void
+Sequencer::recordRequestType(SequencerRequestType requestType) {
+    DPRINTF(RubyStats, "Recorded statistic: %s\n",
+            SequencerRequestType_to_string(requestType));
+}
+
+
+void
+Sequencer::evictionCallback(Addr address)
+{
+    ruby_eviction_callback(address);
+}
+
+void
+Sequencer::regStats()
+{
+    RubyPort::regStats();
+
+    m_store_waiting_on_load
+        .name(name() + ".store_waiting_on_load")
+        .desc("Number of times a store aliased with a pending load")
+        .flags(Stats::nozero);
+    m_store_waiting_on_store
+        .name(name() + ".store_waiting_on_store")
+        .desc("Number of times a store aliased with a pending store")
+        .flags(Stats::nozero);
+    m_load_waiting_on_load
+        .name(name() + ".load_waiting_on_load")
+        .desc("Number of times a load aliased with a pending load")
+        .flags(Stats::nozero);
+    m_load_waiting_on_store
+        .name(name() + ".load_waiting_on_store")
+        .desc("Number of times a load aliased with a pending store")
+        .flags(Stats::nozero);
+
+    // These statistical variables are not for display.
+    // The profiler will collate these across different
+    // sequencers and display those collated statistics.
+    m_outstandReqHist.init(10);
+    m_latencyHist.init(10);
+    m_hitLatencyHist.init(10);
+    m_missLatencyHist.init(10);
+
+    for (int i = 0; i < RubyRequestType_NUM; i++) {
+        m_typeLatencyHist.push_back(new Stats::Histogram());
+        m_typeLatencyHist[i]->init(10);
+
+        m_hitTypeLatencyHist.push_back(new Stats::Histogram());
+        m_hitTypeLatencyHist[i]->init(10);
+
+        m_missTypeLatencyHist.push_back(new Stats::Histogram());
+        m_missTypeLatencyHist[i]->init(10);
+    }
+
+    for (int i = 0; i < MachineType_NUM; i++) {
+        m_hitMachLatencyHist.push_back(new Stats::Histogram());
+        m_hitMachLatencyHist[i]->init(10);
+
+        m_missMachLatencyHist.push_back(new Stats::Histogram());
+        m_missMachLatencyHist[i]->init(10);
+
+        m_IssueToInitialDelayHist.push_back(new Stats::Histogram());
+        m_IssueToInitialDelayHist[i]->init(10);
+
+        m_InitialToForwardDelayHist.push_back(new Stats::Histogram());
+        m_InitialToForwardDelayHist[i]->init(10);
+
+        m_ForwardToFirstResponseDelayHist.push_back(new Stats::Histogram());
+        m_ForwardToFirstResponseDelayHist[i]->init(10);
+
+        m_FirstResponseToCompletionDelayHist.push_back(new Stats::Histogram());
+        m_FirstResponseToCompletionDelayHist[i]->init(10);
+    }
+
+    for (int i = 0; i < RubyRequestType_NUM; i++) {
+        m_hitTypeMachLatencyHist.push_back(std::vector<Stats::Histogram *>());
+        m_missTypeMachLatencyHist.push_back(std::vector<Stats::Histogram *>());
+
+        for (int j = 0; j < MachineType_NUM; j++) {
+            m_hitTypeMachLatencyHist[i].push_back(new Stats::Histogram());
+            m_hitTypeMachLatencyHist[i][j]->init(10);
+
+            m_missTypeMachLatencyHist[i].push_back(new Stats::Histogram());
+            m_missTypeMachLatencyHist[i][j]->init(10);
+        }
+    }
+}