# from 0 to 19.
self.specials.mem = Memory(16, 2**12, init=list(range(20)))
- def do_simulation(self, selfp):
- # Read the memory. Use the cycle counter as address.
- value = selfp.mem[selfp.simulator.cycle_counter]
- # Print the result. Output is:
- # 0
- # 1
- # 2
- # ...
+
+def memory_test(dut):
+ # write (only first 5 values)
+ for i in range(5):
+ yield dut.mem[i], 42 + i
+ # remember: values are written after the tick, and read before the tick.
+ # wait one tick for the memory to update.
+ yield
+ # read what we have written, plus some initialization data
+ for i in range(10):
+ value = yield dut.mem[i]
print(value)
- # Raising StopSimulation disables the current (and here, only one)
- # simulation function. Simulator stops when all functions are disabled.
- if value == 10:
- raise StopSimulation
+
if __name__ == "__main__":
- run_simulation(Mem())
+ dut = Mem()
+ Simulator(dut, memory_test(dut)).run()
class FullMemoryWE(ModuleTransformer):
+ def __init__(self):
+ self.replacments = dict()
+
def transform_fragment(self, i, f):
newspecials = set()
if global_granularity == orig.width:
newspecials.add(orig) # nothing to do
else:
+ newmems = []
for i in range(orig.width//global_granularity):
if orig.init is None:
newinit = None
newinit = [(v >> i*global_granularity) & (2**global_granularity - 1) for v in orig.init]
newmem = Memory(global_granularity, orig.depth, newinit, orig.name_override + "_grain" + str(i))
newspecials.add(newmem)
+ newmems.append(newmem)
for port in orig.ports:
port_granularity = port.we_granularity if port.we_granularity else orig.width
newport = _MemoryPort(
clock_domain=port.clock)
newmem.ports.append(newport)
newspecials.add(newport)
+ self.replacments[orig] = newmems
f.specials = newspecials
class MemoryToArray(ModuleTransformer):
+ def __init__(self):
+ self.replacements = dict()
+
def transform_fragment(self, i, f):
newspecials = set()
continue
storage = Array()
+ self.replacements[mem] = storage
init = []
if mem.init is not None:
init = mem.init
# write
if port.we is not None:
- sync.append(If(port.we, storage[port.adr].eq(port.dat_w)))
+ if port.we_granularity:
+ n = mem.width//port.we_granularity
+ for i in range(n):
+ m = i*port.we_granularity
+ M = (i+1)*port.we_granularity
+ sync.append(If(port.we[i],
+ storage[port.adr][m:M].eq(port.dat_w)))
+ else:
+ sync.append(If(port.we,
+ storage[port.adr].eq(port.dat_w)))
f.specials = newspecials
from operator import itemgetter
from migen.fhdl.structure import *
-from migen.fhdl.structure import _DUID
+from migen.fhdl.structure import _DUID, _Value
from migen.fhdl.bitcontainer import bits_for, value_bits_sign
from migen.fhdl.tools import *
from migen.fhdl.tracer import get_obj_var_name
return "" # done by parent Memory object
+class _MemoryLocation(_Value):
+ def __init__(self, memory, index):
+ _Value.__init__(self)
+ if isinstance(index, (bool, int)):
+ index = Constant(index)
+ if not isinstance(index, _Value):
+ raise TypeError("Memory index is not a Migen value: {}"
+ .format(index))
+ self.memory = memory
+ self.index = index
+
+
class Memory(Special):
def __init__(self, width, depth, init=None, name=None):
Special.__init__(self)
self.init = init
self.name_override = get_obj_var_name(name, "mem")
+ def __getitem__(self, index):
+ # simulation only
+ return _MemoryLocation(self, index)
+
def get_port(self, write_capable=False, async_read=False,
has_re=False, we_granularity=0, mode=WRITE_FIRST,
clock_domain="sys"):
r += "\t$readmemh(\"" + memory_filename + "\", " + gn(memory) + ");\n"
r += "end\n\n"
-
return r
import operator
from migen.fhdl.structure import *
-from migen.fhdl.structure import (_Operator, _Slice, _ArrayProxy,
+from migen.fhdl.structure import (_Value, _Operator, _Slice, _ArrayProxy,
_Assign, _Fragment)
from migen.fhdl.bitcontainer import flen
from migen.fhdl.tools import list_targets
-from migen.fhdl.simplify import FullMemoryWE, MemoryToArray
+from migen.fhdl.simplify import MemoryToArray
+from migen.fhdl.specials import _MemoryLocation
__all__ = ["Simulator"]
class Evaluator:
- def __init__(self):
+ def __init__(self, replaced_memories):
+ self.replaced_memories = replaced_memories
self.signal_values = dict()
self.modifications = dict()
elif isinstance(node, _ArrayProxy):
return self.eval(node.choices[self.eval(node.key, postcommit)],
postcommit)
+ elif isinstance(node, _MemoryLocation):
+ array = self.replaced_memories[node.memory]
+ return self.eval(array[self.eval(node.index, postcommit)], postcommit)
else:
# TODO: ClockSignal, ResetSignal
raise NotImplementedError
self.assign(node, full_value)
elif isinstance(node, _ArrayProxy):
self.assign(node.choices[self.eval(node.key)], value)
+ elif isinstance(node, _MemoryLocation):
+ array = self.replaced_memories[node.memory]
+ self.assign(array[self.eval(node.index)], value)
else:
# TODO: ClockSignal, ResetSignal
raise NotImplementedError
else:
self.generators[k] = [v]
- FullMemoryWE().transform_fragment(None, self.fragment)
- MemoryToArray().transform_fragment(None, self.fragment)
+ mta = MemoryToArray()
+ mta.transform_fragment(None, self.fragment)
# TODO: insert_resets on sync
# comb signals return to their reset value if nothing assigns them
self.fragment.comb[0:0] = [s.eq(s.reset)
for s in list_targets(self.fragment.comb)]
self.time = TimeManager(clocks)
- self.evaluator = Evaluator()
+ self.evaluator = Evaluator(mta.replacements)
def _commit_and_comb_propagate(self):
# TODO: optimize
def _eval_nested_lists(self, x):
if isinstance(x, list):
return [self._eval_nested_lists(e) for e in x]
- elif isinstance(x, Signal):
+ elif isinstance(x, _Value):
return self.evaluator.eval(x)
else:
raise ValueError