Mem: Make SimpleMemory single ported
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.
This commit is contained in:
parent
55bfe13705
commit
f00cba34eb
7 changed files with 34 additions and 32 deletions
|
@ -141,6 +141,7 @@ for scale in treespec[:-2]:
|
||||||
|
|
||||||
# system simulated
|
# system simulated
|
||||||
system = System(funcmem = SimpleMemory(in_addr_map = False),
|
system = System(funcmem = SimpleMemory(in_addr_map = False),
|
||||||
|
funcbus = NoncoherentBus(),
|
||||||
physmem = SimpleMemory(latency = "100ns"))
|
physmem = SimpleMemory(latency = "100ns"))
|
||||||
|
|
||||||
def make_level(spec, prototypes, attach_obj, attach_port):
|
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
|
parent.cpu = objs
|
||||||
for t in objs:
|
for t in objs:
|
||||||
t.test = getattr(attach_obj, attach_port)
|
t.test = getattr(attach_obj, attach_port)
|
||||||
t.functional = system.funcmem.port
|
t.functional = system.funcbus.slave
|
||||||
|
|
||||||
make_level(treespec, prototypes, system.physmem, "port")
|
make_level(treespec, prototypes, system.physmem, "port")
|
||||||
|
|
||||||
|
# connect reference memory to funcbus
|
||||||
|
system.funcbus.master = system.funcmem.port
|
||||||
|
|
||||||
# -----------------------
|
# -----------------------
|
||||||
# run simulation
|
# run simulation
|
||||||
# -----------------------
|
# -----------------------
|
||||||
|
|
|
@ -107,6 +107,7 @@ cpus = [ MemTest(atomic = False,
|
||||||
|
|
||||||
system = System(cpu = cpus,
|
system = System(cpu = cpus,
|
||||||
funcmem = SimpleMemory(in_addr_map = False),
|
funcmem = SimpleMemory(in_addr_map = False),
|
||||||
|
funcbus = NoncoherentBus(),
|
||||||
physmem = SimpleMemory())
|
physmem = SimpleMemory())
|
||||||
|
|
||||||
if options.num_dmas > 0:
|
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
|
# Tie the cpu memtester ports to the correct system ports
|
||||||
#
|
#
|
||||||
cpu.test = system.ruby._cpu_ruby_ports[i].slave
|
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
|
# 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
|
# Tie the dma memtester ports to the correct functional port
|
||||||
# Note that the test port has already been connected to the dma_sequencer
|
# 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
|
# run simulation
|
||||||
|
|
|
@ -44,6 +44,6 @@ from AbstractMemory import *
|
||||||
|
|
||||||
class SimpleMemory(AbstractMemory):
|
class SimpleMemory(AbstractMemory):
|
||||||
type = 'SimpleMemory'
|
type = 'SimpleMemory'
|
||||||
port = VectorSlavePort("Slave ports")
|
port = SlavePort("Slave ports")
|
||||||
latency = Param.Latency('30ns', "Request to response latency")
|
latency = Param.Latency('30ns', "Request to response latency")
|
||||||
latency_var = Param.Latency('0ns', "Request to response latency variance")
|
latency_var = Param.Latency('0ns', "Request to response latency variance")
|
||||||
|
|
|
@ -49,24 +49,17 @@ using namespace std;
|
||||||
|
|
||||||
SimpleMemory::SimpleMemory(const Params* p) :
|
SimpleMemory::SimpleMemory(const Params* p) :
|
||||||
AbstractMemory(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
|
void
|
||||||
SimpleMemory::init()
|
SimpleMemory::init()
|
||||||
{
|
{
|
||||||
for (vector<MemoryPort*>::iterator p = ports.begin(); p != ports.end();
|
// allow unconnected memories as this is used in several ruby
|
||||||
++p) {
|
// systems at the moment
|
||||||
if (!(*p)->isConnected()) {
|
if (port.isConnected()) {
|
||||||
fatal("SimpleMemory port %s is unconnected!\n", (*p)->name());
|
port.sendRangeChange();
|
||||||
} else {
|
|
||||||
(*p)->sendRangeChange();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,22 +95,14 @@ SimpleMemory::getSlavePort(const std::string &if_name, int idx)
|
||||||
if (if_name != "port") {
|
if (if_name != "port") {
|
||||||
return MemObject::getSlavePort(if_name, idx);
|
return MemObject::getSlavePort(if_name, idx);
|
||||||
} else {
|
} else {
|
||||||
if (idx >= static_cast<int>(ports.size())) {
|
return port;
|
||||||
fatal("SimpleMemory::getSlavePort: unknown index %d\n", idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
return *ports[idx];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
SimpleMemory::drain(Event *de)
|
SimpleMemory::drain(Event *de)
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = port.drain(de);
|
||||||
for (vector<MemoryPort*>::iterator p = ports.begin(); p != ports.end();
|
|
||||||
++p) {
|
|
||||||
count += (*p)->drain(de);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count)
|
if (count)
|
||||||
changeState(Draining);
|
changeState(Draining);
|
||||||
|
|
|
@ -54,9 +54,10 @@
|
||||||
#include "params/SimpleMemory.hh"
|
#include "params/SimpleMemory.hh"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The simple memory is a basic multi-ported memory with an infinite
|
* The simple memory is a basic single-ported memory controller with
|
||||||
* throughput and a fixed latency, potentially with a variance added
|
* an infinite throughput and a fixed latency, potentially with a
|
||||||
* to it. It uses a SimpleTimingPort to implement the timing accesses.
|
* variance added to it. It uses a SimpleTimingPort to implement the
|
||||||
|
* timing accesses.
|
||||||
*/
|
*/
|
||||||
class SimpleMemory : public AbstractMemory
|
class SimpleMemory : public AbstractMemory
|
||||||
{
|
{
|
||||||
|
@ -81,7 +82,7 @@ class SimpleMemory : public AbstractMemory
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<MemoryPort*> ports;
|
MemoryPort port;
|
||||||
|
|
||||||
Tick lat;
|
Tick lat;
|
||||||
Tick lat_var;
|
Tick lat_var;
|
||||||
|
|
|
@ -79,6 +79,7 @@ options.num_cpus = nb_cores
|
||||||
# system simulated
|
# system simulated
|
||||||
system = System(cpu = cpus,
|
system = System(cpu = cpus,
|
||||||
funcmem = SimpleMemory(in_addr_map = False),
|
funcmem = SimpleMemory(in_addr_map = False),
|
||||||
|
funcbus = NoncoherentBus(),
|
||||||
physmem = SimpleMemory())
|
physmem = SimpleMemory())
|
||||||
|
|
||||||
Ruby.create_system(options, system)
|
Ruby.create_system(options, system)
|
||||||
|
@ -91,7 +92,7 @@ for (i, ruby_port) in enumerate(system.ruby._cpu_ruby_ports):
|
||||||
# physmem, respectively
|
# physmem, respectively
|
||||||
#
|
#
|
||||||
cpus[i].test = ruby_port.slave
|
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
|
# 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
|
ruby_port.access_phys_mem = False
|
||||||
|
|
||||||
|
# connect reference memory to funcbus
|
||||||
|
system.funcmem.port = system.funcbus.master
|
||||||
|
|
||||||
# -----------------------
|
# -----------------------
|
||||||
# run simulation
|
# run simulation
|
||||||
# -----------------------
|
# -----------------------
|
||||||
|
|
|
@ -57,6 +57,7 @@ cpus = [ MemTest() for i in xrange(nb_cores) ]
|
||||||
|
|
||||||
# system simulated
|
# system simulated
|
||||||
system = System(cpu = cpus, funcmem = SimpleMemory(in_addr_map = False),
|
system = System(cpu = cpus, funcmem = SimpleMemory(in_addr_map = False),
|
||||||
|
funcbus = NoncoherentBus(),
|
||||||
physmem = SimpleMemory(),
|
physmem = SimpleMemory(),
|
||||||
membus = CoherentBus(clock="500GHz", width=16))
|
membus = CoherentBus(clock="500GHz", width=16))
|
||||||
|
|
||||||
|
@ -73,10 +74,13 @@ for cpu in cpus:
|
||||||
cpu.l1c = L1(size = '32kB', assoc = 4)
|
cpu.l1c = L1(size = '32kB', assoc = 4)
|
||||||
cpu.l1c.cpu_side = cpu.test
|
cpu.l1c.cpu_side = cpu.test
|
||||||
cpu.l1c.mem_side = system.toL2Bus.slave
|
cpu.l1c.mem_side = system.toL2Bus.slave
|
||||||
system.funcmem.port = cpu.functional
|
system.funcbus.slave = cpu.functional
|
||||||
|
|
||||||
system.system_port = system.membus.slave
|
system.system_port = system.membus.slave
|
||||||
|
|
||||||
|
# connect reference memory to funcbus
|
||||||
|
system.funcmem.port = system.funcbus.master
|
||||||
|
|
||||||
# connect memory to membus
|
# connect memory to membus
|
||||||
system.physmem.port = system.membus.master
|
system.physmem.port = system.membus.master
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue