Mem: Make SimpleMemory single ported
authorAndreas Hansson <andreas.hansson@arm.com>
Thu, 12 Jul 2012 16:56:13 +0000 (12:56 -0400)
committerAndreas Hansson <andreas.hansson@arm.com>
Thu, 12 Jul 2012 16:56:13 +0000 (12:56 -0400)
This patch changes the simple memory to have a single slave port
rather than a vector port. The simple memory makes no attempts at
modelling the contention between multiple ports, and any such
multiplexing and demultiplexing could be done in a bus (or crossbar)
outside the memory controller. This scenario also matches with the
ongoing work on a SimpleDRAM model, which will be a single-ported
single-channel controller that can be used in conjunction with a bus
(or crossbar) to create a multi-port multi-channel controller.

There are only very few regressions that make use of the vector port,
and these are all for functional accesses only. To facilitate these
cases, memtest and memtest-ruby have been updated to also have a
"functional" bus to perform the (de)multiplexing of the functional
memory accesses.

configs/example/memtest.py
configs/example/ruby_mem_test.py
src/mem/SimpleMemory.py
src/mem/simple_mem.cc
src/mem/simple_mem.hh
tests/configs/memtest-ruby.py
tests/configs/memtest.py

index 5903789203092a7c8d6cf290ebbe007a26ab4a79..4f57ef06307e10fbee7c427518f311385dece1ba 100644 (file)
@@ -141,6 +141,7 @@ for scale in treespec[:-2]:
 
 # system simulated
 system = System(funcmem = SimpleMemory(in_addr_map = False),
+                funcbus = NoncoherentBus(),
                 physmem = SimpleMemory(latency = "100ns"))
 
 def make_level(spec, prototypes, attach_obj, attach_port):
@@ -169,10 +170,13 @@ def make_level(spec, prototypes, attach_obj, attach_port):
           parent.cpu = objs
           for t in objs:
                t.test = getattr(attach_obj, attach_port)
-               t.functional = system.funcmem.port
+               t.functional = system.funcbus.slave
 
 make_level(treespec, prototypes, system.physmem, "port")
 
+# connect reference memory to funcbus
+system.funcbus.master = system.funcmem.port
+
 # -----------------------
 # run simulation
 # -----------------------
index e3dab955c6791a432cfb8f692d7f89fad741537d..858d13ee84a3f6274fe8ca2fd061e32f90e62999 100644 (file)
@@ -107,6 +107,7 @@ cpus = [ MemTest(atomic = False,
 
 system = System(cpu = cpus,
                 funcmem = SimpleMemory(in_addr_map = False),
+                funcbus = NoncoherentBus(),
                 physmem = SimpleMemory())
 
 if options.num_dmas > 0:
@@ -141,7 +142,7 @@ for (i, cpu) in enumerate(cpus):
     # Tie the cpu memtester ports to the correct system ports
     #
     cpu.test = system.ruby._cpu_ruby_ports[i].slave
-    cpu.functional = system.funcmem.port
+    cpu.functional = system.funcbus.slave
 
     #
     # Since the memtester is incredibly bursty, increase the deadlock
@@ -160,7 +161,10 @@ for (i, dma) in enumerate(dmas):
     # Tie the dma memtester ports to the correct functional port
     # Note that the test port has already been connected to the dma_sequencer
     #
-    dma.functional = system.funcmem.port
+    dma.functional = system.funcbus.slave
+
+# connect reference memory to funcbus
+system.funcbus.master = system.funcmem.port
 
 # -----------------------
 # run simulation
index 51de3374d7206b99cf1cdd5bffe8c7f4b3d91c1d..c47d04222a42a5585aaa15304cce87f0eab9b5af 100644 (file)
@@ -44,6 +44,6 @@ from AbstractMemory import *
 
 class SimpleMemory(AbstractMemory):
     type = 'SimpleMemory'
-    port = VectorSlavePort("Slave ports")
+    port = SlavePort("Slave ports")
     latency = Param.Latency('30ns', "Request to response latency")
     latency_var = Param.Latency('0ns', "Request to response latency variance")
index aa9168bf711313be514ff32e916c0b3700b7452d..b9db642769ffad1cde0db7fda5a17df06f59836f 100644 (file)
@@ -49,24 +49,17 @@ using namespace std;
 
 SimpleMemory::SimpleMemory(const Params* p) :
     AbstractMemory(p),
-    lat(p->latency), lat_var(p->latency_var)
+    port(name() + ".port", *this), lat(p->latency), lat_var(p->latency_var)
 {
-    for (size_t i = 0; i < p->port_port_connection_count; ++i) {
-        ports.push_back(new MemoryPort(csprintf("%s-port-%d", name(), i),
-                                       *this));
-    }
 }
 
 void
 SimpleMemory::init()
 {
-    for (vector<MemoryPort*>::iterator p = ports.begin(); p != ports.end();
-         ++p) {
-        if (!(*p)->isConnected()) {
-            fatal("SimpleMemory port %s is unconnected!\n", (*p)->name());
-        } else {
-            (*p)->sendRangeChange();
-        }
+    // allow unconnected memories as this is used in several ruby
+    // systems at the moment
+    if (port.isConnected()) {
+        port.sendRangeChange();
     }
 }
 
@@ -102,22 +95,14 @@ SimpleMemory::getSlavePort(const std::string &if_name, int idx)
     if (if_name != "port") {
         return MemObject::getSlavePort(if_name, idx);
     } else {
-        if (idx >= static_cast<int>(ports.size())) {
-            fatal("SimpleMemory::getSlavePort: unknown index %d\n", idx);
-        }
-
-        return *ports[idx];
+        return port;
     }
 }
 
 unsigned int
 SimpleMemory::drain(Event *de)
 {
-    int count = 0;
-    for (vector<MemoryPort*>::iterator p = ports.begin(); p != ports.end();
-         ++p) {
-        count += (*p)->drain(de);
-    }
+    int count = port.drain(de);
 
     if (count)
         changeState(Draining);
index 5f136ed51b9d1d5f640053fd9677a8697f02ecfc..95bfa57ad5f7d0401d513457dc4b84223549c8cf 100644 (file)
 #include "params/SimpleMemory.hh"
 
 /**
- * The simple memory is a basic multi-ported memory with an infinite
- * throughput and a fixed latency, potentially with a variance added
- * to it. It uses a SimpleTimingPort to implement the timing accesses.
+ * The simple memory is a basic single-ported memory controller with
+ * an infinite throughput and a fixed latency, potentially with a
+ * variance added to it. It uses a SimpleTimingPort to implement the
+ * timing accesses.
  */
 class SimpleMemory : public AbstractMemory
 {
@@ -81,7 +82,7 @@ class SimpleMemory : public AbstractMemory
 
     };
 
-    std::vector<MemoryPort*> ports;
+    MemoryPort port;
 
     Tick lat;
     Tick lat_var;
index 008daa1ad08e76503a08e2c3a85b809008f35f0a..560a8fd659cb98efd2dd9559fe1646c9c23e26b3 100644 (file)
@@ -79,6 +79,7 @@ options.num_cpus = nb_cores
 # system simulated
 system = System(cpu = cpus,
                 funcmem = SimpleMemory(in_addr_map = False),
+                funcbus = NoncoherentBus(),
                 physmem = SimpleMemory())
 
 Ruby.create_system(options, system)
@@ -91,7 +92,7 @@ for (i, ruby_port) in enumerate(system.ruby._cpu_ruby_ports):
      # physmem, respectively
      #
      cpus[i].test = ruby_port.slave
-     cpus[i].functional = system.funcmem.port
+     cpus[i].functional = system.funcbus.slave
      
      #
      # Since the memtester is incredibly bursty, increase the deadlock
@@ -105,6 +106,9 @@ for (i, ruby_port) in enumerate(system.ruby._cpu_ruby_ports):
      #
      ruby_port.access_phys_mem = False
 
+# connect reference memory to funcbus
+system.funcmem.port = system.funcbus.master
+
 # -----------------------
 # run simulation
 # -----------------------
index 0add2158fcb43c77cc2676d38d944916e7f0ec01..57f45b1d4c50cc9e35b40ed880f836da3a23eea3 100644 (file)
@@ -57,6 +57,7 @@ cpus = [ MemTest() for i in xrange(nb_cores) ]
 
 # system simulated
 system = System(cpu = cpus, funcmem = SimpleMemory(in_addr_map = False),
+                funcbus = NoncoherentBus(),
                 physmem = SimpleMemory(),
                 membus = CoherentBus(clock="500GHz", width=16))
 
@@ -73,10 +74,13 @@ for cpu in cpus:
     cpu.l1c = L1(size = '32kB', assoc = 4)
     cpu.l1c.cpu_side = cpu.test
     cpu.l1c.mem_side = system.toL2Bus.slave
-    system.funcmem.port = cpu.functional
+    system.funcbus.slave = cpu.functional
 
 system.system_port = system.membus.slave
 
+# connect reference memory to funcbus
+system.funcmem.port = system.funcbus.master
+
 # connect memory to membus
 system.physmem.port = system.membus.master