Skip to content

Support non-initialisable memories #824

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 21 additions & 20 deletions amaranth/back/rtlil.py
Original file line number Diff line number Diff line change
Expand Up @@ -877,26 +877,27 @@ def _convert_fragment(builder, fragment, name_map, hierarchy):
if memory not in memories:
memories[memory] = module.memory(width=memory.width, size=memory.depth,
name=memory.name, attrs=memory.attrs)
addr_bits = bits_for(memory.depth)
data_parts = []
data_mask = (1 << memory.width) - 1
for addr in range(memory.depth):
if addr < len(memory.init):
data = memory.init[addr] & data_mask
else:
data = 0
data_parts.append("{:0{}b}".format(data, memory.width))
module.cell("$meminit", ports={
"\\ADDR": rhs_compiler(ast.Const(0, addr_bits)),
"\\DATA": "{}'".format(memory.width * memory.depth) +
"".join(reversed(data_parts)),
}, params={
"MEMID": memories[memory],
"ABITS": addr_bits,
"WIDTH": memory.width,
"WORDS": memory.depth,
"PRIORITY": 0,
})
if memory.init is not None:
addr_bits = bits_for(memory.depth)
data_parts = []
data_mask = (1 << memory.width) - 1
for addr in range(memory.depth):
if addr < len(memory.init):
data = memory.init[addr] & data_mask
else:
data = 0
data_parts.append("{:0{}b}".format(data, memory.width))
module.cell("$meminit", ports={
"\\ADDR": rhs_compiler(ast.Const(0, addr_bits)),
"\\DATA": "{}'".format(memory.width * memory.depth) +
"".join(reversed(data_parts)),
}, params={
"MEMID": memories[memory],
"ABITS": addr_bits,
"WIDTH": memory.width,
"WORDS": memory.depth,
"PRIORITY": 0,
})

param_value = memories[memory]

Expand Down
16 changes: 8 additions & 8 deletions amaranth/hdl/mem.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ class Memory:
Access granularity. Each storage element of this memory is ``width`` bits in size.
depth : int
Word count. This memory contains ``depth`` storage elements.
init : list of int
init : list of int or None
Initial values. At power on, each storage element in this memory is initialized to
the corresponding element of ``init``, if any, or to zero otherwise.
Uninitialized memories are not currently supported.
the corresponding element of ``init``, if any, or to zero otherwise. If ``None``
(default), no explicit initialization is performed.
name : str
Name hint for this memory. If ``None`` (default) the name is inferred from the variable
name this ``Signal`` is assigned to.
Expand All @@ -32,7 +32,7 @@ class Memory:
----------
width : int
depth : int
init : list of int
init : list of int or None
attrs : dict
"""
def __init__(self, *, width, depth, init=None, name=None, attrs=None, simulate=True):
Expand Down Expand Up @@ -65,14 +65,14 @@ def init(self):

@init.setter
def init(self, new_init):
self._init = [] if new_init is None else list(new_init)
if len(self.init) > self.depth:
self._init = None if new_init is None else list(new_init)
if self.init is not None and len(self.init) > self.depth:
raise ValueError("Memory initialization value count exceed memory depth ({} > {})"
.format(len(self.init), self.depth))

try:
for addr in range(len(self._array)):
if addr < len(self._init):
if self.init is not None and addr < len(self._init):
self._array[addr].reset = operator.index(self._init[addr])
else:
self._array[addr].reset = 0
Expand Down Expand Up @@ -202,7 +202,7 @@ def elaborate(self, platform):
# the address input to achieve the correct address-to-data latency. Also, the reset
# value of the data output is forcibly set to the 0th initial value, if any--note that
# many FPGAs do not guarantee this behavior!
if len(self.memory.init) > 0:
if self.memory.init is not None and len(self.memory.init) > 0:
self.data.reset = operator.index(self.memory.init[0])
latch_addr = Signal.like(self.addr)
f.add_statements(
Expand Down
8 changes: 8 additions & 0 deletions tests/test_hdl_mem.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ def test_init_wrong_type(self):
r"'str' object cannot be interpreted as an integer$")):
m = Memory(width=8, depth=4, init=[1, "0"])

def test_init_default(self):
m = Memory(width=8, depth=4)
self.assertIsNone(m.init)

def test_init_empty(self):
m = Memory(width=8, depth=4, init=[])
self.assertEqual(m.init, [])

def test_attrs(self):
m1 = Memory(width=8, depth=4)
self.assertEqual(m1.attrs, {})
Expand Down