mem-ruby: Support atomic_noncaching acceses in ruby
authorSwapnil Haria <swapnilster@gmail.com>
Thu, 9 Nov 2017 19:04:39 +0000 (13:04 -0600)
committerSwapnil Haria <swapnilster@gmail.com>
Fri, 15 Dec 2017 00:50:32 +0000 (00:50 +0000)
Ruby has no support for atomic_noncaching accesses, which prevents using
it with kvm-cpu. This patch fixes this by directly forwarding atomic
requests from the ruby port/sequencer to the corresponding directory
based on the destination address of the packet.

Change-Id: I0b4928bfda44fd9e5e48583c51d1ea422800da2d
Reviewed-on: https://gem5-review.googlesource.com/5601
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-by: Jason Lowe-Power <jason@lowepower.com>
Reviewed-by: Bradford Beckmann <brad.beckmann@amd.com>
Maintainer: Jason Lowe-Power <jason@lowepower.com>
Maintainer: Bradford Beckmann <brad.beckmann@amd.com>

configs/common/Simulation.py
configs/example/fs.py
configs/example/se.py
src/mem/ruby/slicc_interface/AbstractController.cc
src/mem/ruby/slicc_interface/AbstractController.hh
src/mem/ruby/system/RubyPort.cc
src/mem/ruby/system/RubyPort.hh

index 71a982af97d3120c1bf8c3f55886e90848801779..7c949b972c451ce60c5b2609a54c761d83e00234 100644 (file)
@@ -83,6 +83,11 @@ def setCPUClass(options):
         TmpClass = AtomicSimpleCPU
         test_mem_mode = 'atomic'
 
+    # Ruby only supports atomic accesses in noncaching mode
+    if test_mem_mode == 'atomic' and options.ruby:
+        warn("Memory mode will be changed to atomic_noncaching")
+        test_mem_mode = 'atomic_noncaching'
+
     return (TmpClass, test_mem_mode, CPUClass)
 
 def setMemClass(options):
index 65079372c5b5ac9891f1711151a073a9d73c713b..351d1c0167c41a918f16581eeab7d7e5c8fbdcca 100644 (file)
@@ -47,7 +47,7 @@ import sys
 import m5
 from m5.defines import buildEnv
 from m5.objects import *
-from m5.util import addToPath, fatal
+from m5.util import addToPath, fatal, warn
 
 addToPath('../')
 
@@ -147,12 +147,6 @@ def build_test_system(np):
         test_sys.kvm_vm = KvmVM()
 
     if options.ruby:
-        # Check for timing mode because ruby does not support atomic accesses
-        if not (options.cpu_type == "DerivO3CPU" or
-                options.cpu_type == "TimingSimpleCPU"):
-            print >> sys.stderr, "Ruby requires TimingSimpleCPU or O3CPU!!"
-            sys.exit(1)
-
         Ruby.create_system(options, True, test_sys, test_sys.iobus,
                            test_sys._dma_ports)
 
index 7a19e5aef12ec9f75611a7c52a137d0d1bbc1441..56e4753b9d304641d168e8cffb4ec24e1e4f29e8 100644 (file)
@@ -49,7 +49,7 @@ import os
 import m5
 from m5.defines import buildEnv
 from m5.objects import *
-from m5.util import addToPath, fatal
+from m5.util import addToPath, fatal, warn
 
 addToPath('../')
 
@@ -250,10 +250,6 @@ for i in xrange(np):
     system.cpu[i].createThreads()
 
 if options.ruby:
-    if options.cpu_type == "AtomicSimpleCPU":
-        print >> sys.stderr, "Ruby does not work with atomic cpu!!"
-        sys.exit(1)
-
     Ruby.create_system(options, False, system)
     assert(options.num_cpus == len(system.ruby._cpu_ports))
 
index 0bc88eefa53ed385c8495495205e81724c982e0b..b920ff7b0aa42b8010537203527bfb5ba02d008a 100644 (file)
@@ -360,6 +360,12 @@ AbstractController::recvTimingResp(PacketPtr pkt)
     delete pkt;
 }
 
+Tick
+AbstractController::recvAtomic(PacketPtr pkt)
+{
+   return ticksToCycles(memoryPort.sendAtomic(pkt));
+}
+
 MachineID
 AbstractController::mapAddressToMachine(Addr addr, MachineType mtype) const
 {
index 354dc80aa14dd83de995d543cc211a0ea08b96e1..35cd3d2a55b75134a7f304f1f29b9f52e67fba65 100644 (file)
@@ -135,6 +135,7 @@ class AbstractController : public MemObject, public Consumer
     void queueMemoryWritePartial(const MachineID &id, Addr addr, Cycles latency,
                                  const DataBlock &block, int size);
     void recvTimingResp(PacketPtr pkt);
+    Tick recvAtomic(PacketPtr pkt);
 
     const AddrRangeList &getAddrRanges() const { return addrRanges; }
 
index fd535cca25408167c32dd952b5deb795fd77f414..5977ce9efc8ca548f59d037ddc0b443224f5ad1c 100644 (file)
@@ -226,6 +226,26 @@ RubyPort::PioSlavePort::recvTimingReq(PacketPtr pkt)
     panic("Should never reach here!\n");
 }
 
+Tick
+RubyPort::PioSlavePort::recvAtomic(PacketPtr pkt)
+{
+    RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
+    // Only atomic_noncaching mode supported!
+    if (!ruby_port->system->bypassCaches()) {
+        panic("Ruby supports atomic accesses only in noncaching mode\n");
+    }
+
+    for (size_t i = 0; i < ruby_port->master_ports.size(); ++i) {
+        AddrRangeList l = ruby_port->master_ports[i]->getAddrRanges();
+        for (auto it = l.begin(); it != l.end(); ++it) {
+            if (it->contains(pkt->getAddr())) {
+                return ruby_port->master_ports[i]->sendAtomic(pkt);
+            }
+        }
+    }
+    panic("Could not find address in Ruby PIO address ranges!\n");
+}
+
 bool
 RubyPort::MemSlavePort::recvTimingReq(PacketPtr pkt)
 {
@@ -295,6 +315,48 @@ RubyPort::MemSlavePort::recvTimingReq(PacketPtr pkt)
     return false;
 }
 
+Tick
+RubyPort::MemSlavePort::recvAtomic(PacketPtr pkt)
+{
+    RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
+    // Only atomic_noncaching mode supported!
+    if (!ruby_port->system->bypassCaches()) {
+        panic("Ruby supports atomic accesses only in noncaching mode\n");
+    }
+
+    // Check for pio requests and directly send them to the dedicated
+    // pio port.
+    if (pkt->cmd != MemCmd::MemFenceReq) {
+        if (!isPhysMemAddress(pkt->getAddr())) {
+            assert(ruby_port->memMasterPort.isConnected());
+            DPRINTF(RubyPort, "Request address %#x assumed to be a "
+                    "pio address\n", pkt->getAddr());
+
+            // Save the port in the sender state object to be used later to
+            // route the response
+            pkt->pushSenderState(new SenderState(this));
+
+            // send next cycle
+            Tick req_ticks = ruby_port->memMasterPort.sendAtomic(pkt);
+            return ruby_port->ticksToCycles(req_ticks);
+        }
+
+        assert(getOffset(pkt->getAddr()) + pkt->getSize() <=
+               RubySystem::getBlockSizeBytes());
+    }
+
+    // Find appropriate directory for address
+    // This assumes that protocols have a Directory machine,
+    // which has its memPort hooked up to memory. This can
+    // fail for some custom protocols.
+    MachineID id = ruby_port->m_controller->mapAddressToMachine(
+                    pkt->getAddr(), MachineType_Directory);
+    RubySystem *rs = ruby_port->m_ruby_system;
+    AbstractController *directory =
+        rs->m_abstract_controls[id.getType()][id.getNum()];
+    return directory->recvAtomic(pkt);
+}
+
 void
 RubyPort::MemSlavePort::addToRetryList()
 {
index 6c991c162806b5c08123e7db4f551480556c2c03..146443282470e12deec8a09d361533ade29f7632 100644 (file)
@@ -46,6 +46,7 @@
 #include <string>
 
 #include "mem/protocol/RequestStatus.hh"
+#include "mem/ruby/common/MachineID.hh"
 #include "mem/ruby/network/MessageBuffer.hh"
 #include "mem/ruby/system/RubySystem.hh"
 #include "mem/mem_object.hh"
@@ -88,8 +89,7 @@ class RubyPort : public MemObject
       protected:
         bool recvTimingReq(PacketPtr pkt);
 
-        Tick recvAtomic(PacketPtr pkt)
-        { panic("RubyPort::MemSlavePort::recvAtomic() not implemented!\n"); }
+        Tick recvAtomic(PacketPtr pkt);
 
         void recvFunctional(PacketPtr pkt);
 
@@ -127,8 +127,7 @@ class RubyPort : public MemObject
       protected:
         bool recvTimingReq(PacketPtr pkt);
 
-        Tick recvAtomic(PacketPtr pkt)
-        { panic("recvAtomic not supported with ruby!"); }
+        Tick recvAtomic(PacketPtr pkt);
 
         void recvFunctional(PacketPtr pkt)
         { panic("recvFunctional should never be called on pio slave port!"); }