ruby: provide a backing store
[gem5.git] / configs / ruby / Ruby.py
index 3c43fa6c6ab7b2583830352c954a5cc2bd02d152..b99e251d37916a6ce9a72e08065830a8f2c84a78 100644 (file)
@@ -45,6 +45,7 @@ from m5.objects import *
 from m5.defines import buildEnv
 from m5.util import addToPath, fatal
 
+import MemConfig
 addToPath('../topologies')
 
 def define_options(parser):
@@ -55,6 +56,9 @@ def define_options(parser):
                       default='2GHz',
                       help="Clock for blocks running at Ruby system's speed")
 
+    parser.add_option("--access-backing-store", action="store_true", default=False,
+                      help="Should ruby maintain a second copy of memory")
+
     # Options related to cache structure
     parser.add_option("--ports", action="store", type="int", default=4,
                       help="used of transitions per cycle which is a proxy \
@@ -75,22 +79,67 @@ def define_options(parser):
                       help="high order address bit to use for numa mapping. " \
                            "0 = highest bit, not specified = lowest bit")
 
-    # ruby sparse memory options
-    parser.add_option("--use-map", action="store_true", default=False)
-    parser.add_option("--map-levels", type="int", default=4)
-
     parser.add_option("--recycle-latency", type="int", default=10,
                       help="Recycle latency for ruby controller input buffers")
 
     parser.add_option("--random_seed", type="int", default=1234,
                       help="Used for seeding the random number generator")
 
-    parser.add_option("--ruby_stats", type="string", default="ruby.stats")
-
     protocol = buildEnv['PROTOCOL']
     exec "import %s" % protocol
     eval("%s.define_options(parser)" % protocol)
 
+def setup_memory_controllers(system, ruby, dir_cntrls, options):
+    ruby.block_size_bytes = options.cacheline_size
+    ruby.memory_size_bits = 48
+    block_size_bits = int(math.log(options.cacheline_size, 2))
+
+    if options.numa_high_bit:
+        numa_bit = options.numa_high_bit
+    else:
+        # if the numa_bit is not specified, set the directory bits as the
+        # lowest bits above the block offset bits, and the numa_bit as the
+        # highest of those directory bits
+        dir_bits = int(math.log(options.num_dirs, 2))
+        numa_bit = block_size_bits + dir_bits - 1
+
+    index = 0
+    mem_ctrls = []
+    crossbars = []
+
+    # Sets bits to be used for interleaving.  Creates memory controllers
+    # attached to a directory controller.  A separate controller is created
+    # for each address range as the abstract memory can handle only one
+    # contiguous address range as of now.
+    for dir_cntrl in dir_cntrls:
+        dir_cntrl.directory.numa_high_bit = numa_bit
+
+        crossbar = None
+        if len(system.mem_ranges) > 1:
+            crossbar = NoncoherentXBar()
+            crossbars.append(crossbar)
+            dir_cntrl.memory = crossbar.slave
+
+        for r in system.mem_ranges:
+            mem_ctrl = MemConfig.create_mem_ctrl(
+                MemConfig.get(options.mem_type), r, index, options.num_dirs,
+                int(math.log(options.num_dirs, 2)), options.cacheline_size)
+
+            mem_ctrls.append(mem_ctrl)
+
+            if crossbar != None:
+                mem_ctrl.port = crossbar.master
+            else:
+                mem_ctrl.port = dir_cntrl.memory
+
+        index += 1
+
+    system.mem_ctrls = mem_ctrls
+
+    if len(crossbars) > 0:
+        ruby.crossbars = crossbars
+
+
 def create_topology(controllers, options):
     """ Called from create_system in configs/ruby/<protocol>.py
         Must return an object which is a subclass of BaseTopology
@@ -101,9 +150,9 @@ def create_topology(controllers, options):
     topology = eval("Topo.%s(controllers)" % options.topology)
     return topology
 
-def create_system(options, system, piobus = None, dma_ports = []):
+def create_system(options, full_system, system, piobus = None, dma_ports = []):
 
-    system.ruby = RubySystem(no_mem_vec = options.use_map)
+    system.ruby = RubySystem()
     ruby = system.ruby
 
     # Set the network classes based on the command line options
@@ -137,7 +186,8 @@ def create_system(options, system, piobus = None, dma_ports = []):
     exec "import %s" % protocol
     try:
         (cpu_sequencers, dir_cntrls, topology) = \
-             eval("%s.create_system(options, system, dma_ports, ruby)"
+             eval("%s.create_system(options, full_system, system, dma_ports,\
+                                    ruby)"
                   % protocol)
     except:
         print "Error: could not create sytem for ruby protocol %s" % protocol
@@ -168,33 +218,7 @@ def create_system(options, system, piobus = None, dma_ports = []):
         network.enable_fault_model = True
         network.fault_model = FaultModel()
 
-    # Loop through the directory controlers.
-    # Determine the total memory size of the ruby system and verify it is equal
-    # to physmem.  However, if Ruby memory is using sparse memory in SE
-    # mode, then the system should not back-up the memory state with
-    # the Memory Vector and thus the memory size bytes should stay at 0.
-    # Also set the numa bits to the appropriate values.
-    total_mem_size = MemorySize('0B')
-
-    ruby.block_size_bytes = options.cacheline_size
-    block_size_bits = int(math.log(options.cacheline_size, 2))
-
-    if options.numa_high_bit:
-        numa_bit = options.numa_high_bit
-    else:
-        # if the numa_bit is not specified, set the directory bits as the
-        # lowest bits above the block offset bits, and the numa_bit as the
-        # highest of those directory bits
-        dir_bits = int(math.log(options.num_dirs, 2))
-        numa_bit = block_size_bits + dir_bits - 1
-
-    for dir_cntrl in dir_cntrls:
-        total_mem_size.value += dir_cntrl.directory.size.value
-        dir_cntrl.directory.numa_high_bit = numa_bit
-
-    phys_mem_size = sum(map(lambda r: r.size(), system.mem_ranges))
-    assert(total_mem_size.value == phys_mem_size)
-    ruby.mem_size = total_mem_size
+    setup_memory_controllers(system, ruby, dir_cntrls, options)
 
     # Connect the cpu sequencers and the piobus
     if piobus != None:
@@ -208,3 +232,8 @@ def create_system(options, system, piobus = None, dma_ports = []):
     ruby._cpu_ports = cpu_sequencers
     ruby.num_of_sequencers = len(cpu_sequencers)
     ruby.random_seed    = options.random_seed
+
+    # Create a backing copy of physical memory in case required
+    if options.access_backing_store:
+        ruby.phys_mem = SimpleMemory(range=AddrRange(options.mem_size),
+                                     in_addr_map=False)