Skip to content

Implement RFC 45: Move hdl.Memory to lib.Memory. #1142

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

Merged
merged 1 commit into from
Feb 19, 2024
Merged
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
4 changes: 2 additions & 2 deletions amaranth/hdl/__init__.py
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@
from ._dsl import SyntaxError, SyntaxWarning, Module
from ._cd import DomainError, ClockDomain
from ._ir import UnusedElaboratable, Elaboratable, DriverConflict, Fragment, Instance
from ._mem import Memory, ReadPort, WritePort, DummyPort
from ._mem import MemoryIdentity, MemoryInstance, Memory, ReadPort, WritePort, DummyPort
from ._rec import Record
from ._xfrm import DomainRenamer, ResetInserter, EnableInserter

@@ -21,7 +21,7 @@
# _ir
"UnusedElaboratable", "Elaboratable", "DriverConflict", "Fragment", "Instance",
# _mem
"Memory", "ReadPort", "WritePort", "DummyPort",
"MemoryIdentity", "MemoryInstance", "Memory", "ReadPort", "WritePort", "DummyPort",
# _rec
"Record",
# _xfrm
2 changes: 1 addition & 1 deletion amaranth/hdl/_ir.py
Original file line number Diff line number Diff line change
@@ -1109,7 +1109,7 @@ def emit_read_port(self, module_idx: int, fragment: '_mem.MemoryInstance',
en=en,
clk=clk,
clk_edge=cd.clk_edge,
transparent_for=tuple(write_ports[idx] for idx in port._transparency),
transparent_for=tuple(write_ports[idx] for idx in port._transparent_for),
src_loc=port._data.src_loc,
)
data = self.netlist.add_value_cell(len(port._data), cell)
42 changes: 25 additions & 17 deletions amaranth/hdl/_mem.py
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@
from ._ast import *
from ._ir import Elaboratable, Fragment
from ..utils import ceil_log2
from .._utils import deprecated


__all__ = ["Memory", "ReadPort", "WritePort", "DummyPort"]
@@ -33,18 +34,19 @@ def __init__(self, identity, addr, data):

class MemoryInstance(Fragment):
class _ReadPort:
def __init__(self, *, domain, addr, data, en, transparency):
def __init__(self, *, domain, addr, data, en, transparent_for):
assert isinstance(domain, str)
self._domain = domain
self._addr = Value.cast(addr)
self._data = Value.cast(data)
self._en = Value.cast(en)
self._transparency = tuple(transparency)
self._transparent_for = tuple(transparent_for)
assert len(self._en) == 1
if domain == "comb":
assert isinstance(self._en, Const)
assert self._en.width == 1
assert self._en.value == 1
assert not self._transparent_for

class _WritePort:
def __init__(self, *, domain, addr, data, en):
@@ -70,22 +72,24 @@ def __init__(self, *, identity, width, depth, init=None, attrs=None, src_loc=Non
self._identity = identity
self._width = operator.index(width)
self._depth = operator.index(depth)
self._init = tuple(init) if init is not None else ()
mask = (1 << self._width) - 1
self._init = tuple(item & mask for item in init) if init is not None else ()
assert len(self._init) <= self._depth
self._init += (0,) * (self._depth - len(self._init))
for x in self._init:
assert isinstance(x, int)
self._attrs = attrs or {}
self._read_ports = []
self._write_ports = []
self._read_ports: "list[MemoryInstance._ReadPort]" = []
self._write_ports: "list[MemoryInstance._WritePort]" = []

def read_port(self, *, domain, addr, data, en, transparency):
port = self._ReadPort(domain=domain, addr=addr, data=data, en=en, transparency=transparency)
def read_port(self, *, domain, addr, data, en, transparent_for):
port = self._ReadPort(domain=domain, addr=addr, data=data, en=en, transparent_for=transparent_for)
assert len(port._data) == self._width
assert len(port._addr) == ceil_log2(self._depth)
for x in port._transparency:
assert isinstance(x, int)
assert x in range(len(self._write_ports))
for idx in port._transparent_for:
assert isinstance(idx, int)
assert idx in range(len(self._write_ports))
assert self._write_ports[idx]._domain == port._domain
for signal in port._data._rhs_signals():
self.add_driver(signal, port._domain)
self._read_ports.append(port)
@@ -124,6 +128,8 @@ class Memory(Elaboratable):
init : list of int
attrs : dict
"""
# TODO(amaranth-0.6): remove
@deprecated("`amaranth.hdl.Memory` is deprecated, use `amaranth.lib.memory.Memory` instead")
def __init__(self, *, width, depth, init=None, name=None, attrs=None, simulate=True):
if not isinstance(width, int) or width < 0:
raise TypeError("Memory width must be a non-negative integer, not {!r}"
@@ -132,8 +138,8 @@ def __init__(self, *, width, depth, init=None, name=None, attrs=None, simulate=T
raise TypeError("Memory depth must be a non-negative integer, not {!r}"
.format(depth))

self.name = name or tracer.get_var_name(depth=2, default="$memory")
self.src_loc = tracer.get_src_loc()
self.name = name or tracer.get_var_name(depth=3, default="$memory")
self.src_loc = tracer.get_src_loc(src_loc_at=1)

self.width = width
self.depth = depth
@@ -208,12 +214,12 @@ def elaborate(self, platform):
for port in self._read_ports:
port._MustUse__used = True
if port.domain == "comb":
f.read_port(domain="comb", addr=port.addr, data=port.data, en=Const(1), transparency=())
f.read_port(domain="comb", addr=port.addr, data=port.data, en=Const(1), transparent_for=())
else:
transparency = []
transparent_for = []
if port.transparent:
transparency = write_ports.get(port.domain, [])
f.read_port(domain=port.domain, addr=port.addr, data=port.data, en=port.en, transparency=transparency)
transparent_for = write_ports.get(port.domain, [])
f.read_port(domain=port.domain, addr=port.addr, data=port.data, en=port.en, transparent_for=transparent_for)
return f


@@ -346,13 +352,15 @@ class DummyPort:
It does not include any read/write port specific attributes, i.e. none besides ``"domain"``;
any such attributes may be set manually.
"""
# TODO(amaranth-0.6): remove
@deprecated("`DummyPort` is deprecated, use `amaranth.lib.memory.ReadPort` or `amaranth.lib.memory.WritePort` instead")
def __init__(self, *, data_width, addr_width, domain="sync", name=None, granularity=None):
self.domain = domain

if granularity is None:
granularity = data_width
if name is None:
name = tracer.get_var_name(depth=2, default="dummy")
name = tracer.get_var_name(depth=3, default="dummy")

self.addr = Signal(addr_width,
name=f"{name}_addr", src_loc_at=1)
2 changes: 1 addition & 1 deletion amaranth/hdl/_xfrm.py
Original file line number Diff line number Diff line change
@@ -263,7 +263,7 @@ def on_fragment(self, fragment):
addr=port._addr,
data=port._data,
en=port._en,
transparency=port._transparency,
transparent_for=port._transparent_for,
)
for port in fragment._read_ports
]
13 changes: 6 additions & 7 deletions amaranth/lib/fifo.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
"""First-in first-out queues."""

import warnings

from .. import *
from ..asserts import *
from ..utils import ceil_log2
from .coding import GrayEncoder, GrayDecoder
from .cdc import FFSynchronizer, AsyncFFSynchronizer
from .memory import Memory


__all__ = ["FIFOInterface", "SyncFIFO", "SyncFIFOBuffered", "AsyncFIFO", "AsyncFIFOBuffered"]
@@ -130,7 +129,7 @@ def elaborate(self, platform):
do_read = self.r_rdy & self.r_en
do_write = self.w_rdy & self.w_en

storage = m.submodules.storage = Memory(width=self.width, depth=self.depth)
storage = m.submodules.storage = Memory(shape=self.width, depth=self.depth, init=[])
w_port = storage.write_port()
r_port = storage.read_port(domain="comb")
produce = Signal(range(self.depth))
@@ -257,9 +256,9 @@ def elaborate(self, platform):

do_inner_read = inner_r_rdy & (~self.r_rdy | self.r_en)

storage = m.submodules.storage = Memory(width=self.width, depth=inner_depth)
storage = m.submodules.storage = Memory(shape=self.width, depth=inner_depth, init=[])
w_port = storage.write_port()
r_port = storage.read_port(domain="sync", transparent=False)
r_port = storage.read_port(domain="sync")
produce = Signal(range(inner_depth))
consume = Signal(range(inner_depth))

@@ -438,9 +437,9 @@ def elaborate(self, platform):
m.d[self._w_domain] += self.w_level.eq(produce_w_bin - consume_w_bin)
m.d.comb += self.r_level.eq(produce_r_bin - consume_r_bin)

storage = m.submodules.storage = Memory(width=self.width, depth=self.depth)
storage = m.submodules.storage = Memory(shape=self.width, depth=self.depth, init=[])
w_port = storage.write_port(domain=self._w_domain)
r_port = storage.read_port (domain=self._r_domain, transparent=False)
r_port = storage.read_port (domain=self._r_domain)
m.d.comb += [
w_port.addr.eq(produce_w_bin[:-1]),
w_port.data.eq(self.w_data),
430 changes: 430 additions & 0 deletions amaranth/lib/memory.py

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion amaranth/sim/_pyrtl.py
Original file line number Diff line number Diff line change
@@ -505,7 +505,7 @@ def __call__(self, fragment):
addr = emitter.def_var("read_addr", f"({(1 << len(port._addr)) - 1:#x} & {addr})")
data = emitter.def_var("read_data", f"slots[{memory_index}].read({addr})")

for idx in port._transparency:
for idx in port._transparent_for:
waddr, wdata, wen = write_vals[idx]
emitter.append(f"if {addr} == {waddr}:")
with emitter.indent():
2 changes: 1 addition & 1 deletion amaranth/sim/pysim.py
Original file line number Diff line number Diff line change
@@ -85,7 +85,7 @@ def __init__(self, fragment, *, vcd_file, gtkw_file=None, traces=()):
trace_names[trace_signal] = {("bench", name)}
assigned_names.add(name)
self.traces.append(trace_signal)
elif isinstance(trace, (MemoryInstance, Memory)):
elif hasattr(trace, "_identity") and isinstance(trace._identity, MemoryIdentity):
if not trace._identity in memories:
raise ValueError(f"{trace!r} is a memory not part of the elaborated design")
self.traces.append(trace._identity)
5 changes: 5 additions & 0 deletions docs/changes.rst
Original file line number Diff line number Diff line change
@@ -32,6 +32,7 @@ Apply the following changes to code written against Amaranth 0.4 to migrate it t
* Update uses of ``reset=`` keyword argument to ``init=``
* Convert uses of ``Simulator.add_sync_process`` used as testbenches to ``Simulator.add_testbench``
* Convert other uses of ``Simulator.add_sync_process`` to ``Simulator.add_process``
* Replace uses of ``amaranth.hdl.Memory`` with ``amaranth.lib.memory.Memory``


Implemented RFCs
@@ -41,12 +42,14 @@ Implemented RFCs
.. _RFC 27: https://amaranth-lang.org/rfcs/0027-simulator-testbenches.html
.. _RFC 39: https://amaranth-lang.org/rfcs/0039-empty-case.html
.. _RFC 43: https://amaranth-lang.org/rfcs/0043-rename-reset-to-init.html
.. _RFC 45: https://amaranth-lang.org/rfcs/0045-lib-memory.html
.. _RFC 46: https://amaranth-lang.org/rfcs/0046-shape-range-1.html

* `RFC 17`_: Remove ``log2_int``
* `RFC 27`_: Testbench processes for the simulator
* `RFC 39`_: Change semantics of no-argument ``m.Case()``
* `RFC 43`_: Rename ``reset=`` to ``init=``
* `RFC 45`_: Move ``hdl.Memory`` to ``lib.Memory``
* `RFC 46`_: Change ``Shape.cast(range(1))`` to ``unsigned(0)``


@@ -65,6 +68,7 @@ Language changes
* Changed: the ``reset=`` argument of :class:`Signal`, :meth:`Signal.like`, :class:`amaranth.lib.wiring.Member`, :class:`amaranth.lib.cdc.FFSynchronizer`, and ``m.FSM()`` has been renamed to ``init=``. (`RFC 43`_)
* Changed: :class:`Shape` has been made immutable and hashable.
* Deprecated: :func:`amaranth.utils.log2_int`. (`RFC 17`_)
* Deprecated: :class:`amaranth.hdl.Memory`. (`RFC 45`_)
* Removed: (deprecated in 0.4) :meth:`Const.normalize`. (`RFC 5`_)
* Removed: (deprecated in 0.4) :class:`Repl`. (`RFC 10`_)
* Removed: (deprecated in 0.4) :class:`ast.Sample`, :class:`ast.Past`, :class:`ast.Stable`, :class:`ast.Rose`, :class:`ast.Fell`.
@@ -75,6 +79,7 @@ Standard library changes

.. currentmodule:: amaranth.lib

* Added: :mod:`amaranth.lib.memory`. (`RFC 45`_)
* Removed: (deprecated in 0.4) :mod:`amaranth.lib.scheduler`. (`RFC 19`_)
* Removed: (deprecated in 0.4) :class:`amaranth.lib.fifo.FIFOInterface` with ``fwft=False``. (`RFC 20`_)
* Removed: (deprecated in 0.4) :class:`amaranth.lib.fifo.SyncFIFO` with ``fwft=False``. (`RFC 20`_)
2 changes: 1 addition & 1 deletion docs/stdlib.rst
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ Standard library
The :mod:`amaranth.lib` module, also known as the standard library, provides modules that falls into one of the three categories:

1. Modules that will used by essentially all idiomatic Amaranth code, and are necessary for interoperability. This includes :mod:`amaranth.lib.enum` (enumerations), :mod:`amaranth.lib.data` (data structures), and :mod:`amaranth.lib.wiring` (interfaces and components).
2. Modules that abstract common functionality whose implementation differs between hardware platforms. This includes :mod:`amaranth.lib.cdc`.
2. Modules that abstract common functionality whose implementation differs between hardware platforms. This includes :mod:`amaranth.lib.cdc`, :mod:`amaranth.lib.memory`.
3. Modules that have essentially one correct implementation and are of broad utility in digital designs. This includes :mod:`amaranth.lib.coding`, :mod:`amaranth.lib.fifo`, and :mod:`amaranth.lib.crc`.

As part of the Amaranth backwards compatibility guarantee, any behaviors described in these documents will not change from a version to another without at least one version including a warning about the impending change. Any nontrivial change to these behaviors must also go through the public review as a part of the `Amaranth Request for Comments process <https://amaranth-lang.org/rfcs/>`_.
8 changes: 5 additions & 3 deletions examples/basic/mem.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from amaranth import *
from amaranth.lib.memory import Memory
from amaranth.cli import main


@@ -8,12 +9,13 @@ def __init__(self):
self.dat_r = Signal(8)
self.dat_w = Signal(8)
self.we = Signal()
self.mem = Memory(width=8, depth=16, init=[0xaa, 0x55])
self.mem = Memory(shape=8, depth=16, init=[0xaa, 0x55])

def elaborate(self, platform):
m = Module()
m.submodules.rdport = rdport = self.mem.read_port()
m.submodules.wrport = wrport = self.mem.write_port()
m.submodules.mem = self.mem
rdport = self.mem.read_port()
wrport = self.mem.write_port()
m.d.comb += [
rdport.addr.eq(self.adr),
self.dat_r.eq(rdport.data),
201 changes: 114 additions & 87 deletions tests/test_hdl_mem.py
Original file line number Diff line number Diff line change
@@ -2,113 +2,128 @@

from amaranth.hdl._ast import *
from amaranth.hdl._mem import *
from amaranth._utils import _ignore_deprecated

from .utils import *


class MemoryTestCase(FHDLTestCase):
def test_name(self):
m1 = Memory(width=8, depth=4)
self.assertEqual(m1.name, "m1")
m2 = [Memory(width=8, depth=4)][0]
self.assertEqual(m2.name, "$memory")
m3 = Memory(width=8, depth=4, name="foo")
self.assertEqual(m3.name, "foo")
with _ignore_deprecated():
m1 = Memory(width=8, depth=4)
self.assertEqual(m1.name, "m1")
m2 = [Memory(width=8, depth=4)][0]
self.assertEqual(m2.name, "$memory")
m3 = Memory(width=8, depth=4, name="foo")
self.assertEqual(m3.name, "foo")

def test_geometry(self):
m = Memory(width=8, depth=4)
self.assertEqual(m.width, 8)
self.assertEqual(m.depth, 4)
with _ignore_deprecated():
m = Memory(width=8, depth=4)
self.assertEqual(m.width, 8)
self.assertEqual(m.depth, 4)

def test_geometry_wrong(self):
with self.assertRaisesRegex(TypeError,
r"^Memory width must be a non-negative integer, not -1$"):
m = Memory(width=-1, depth=4)
with self.assertRaisesRegex(TypeError,
r"^Memory depth must be a non-negative integer, not -1$"):
m = Memory(width=8, depth=-1)
with _ignore_deprecated():
with self.assertRaisesRegex(TypeError,
r"^Memory width must be a non-negative integer, not -1$"):
m = Memory(width=-1, depth=4)
with self.assertRaisesRegex(TypeError,
r"^Memory depth must be a non-negative integer, not -1$"):
m = Memory(width=8, depth=-1)

def test_init(self):
m = Memory(width=8, depth=4, init=range(4))
self.assertEqual(m.init, [0, 1, 2, 3])
with _ignore_deprecated():
m = Memory(width=8, depth=4, init=range(4))
self.assertEqual(m.init, [0, 1, 2, 3])

def test_init_wrong_count(self):
with self.assertRaisesRegex(ValueError,
r"^Memory initialization value count exceed memory depth \(8 > 4\)$"):
m = Memory(width=8, depth=4, init=range(8))
with _ignore_deprecated():
with self.assertRaisesRegex(ValueError,
r"^Memory initialization value count exceed memory depth \(8 > 4\)$"):
m = Memory(width=8, depth=4, init=range(8))

def test_init_wrong_type(self):
with self.assertRaisesRegex(TypeError,
(r"^Memory initialization value at address 1: "
r"'str' object cannot be interpreted as an integer$")):
m = Memory(width=8, depth=4, init=[1, "0"])
with _ignore_deprecated():
with self.assertRaisesRegex(TypeError,
(r"^Memory initialization value at address 1: "
r"'str' object cannot be interpreted as an integer$")):
m = Memory(width=8, depth=4, init=[1, "0"])

def test_attrs(self):
m1 = Memory(width=8, depth=4)
self.assertEqual(m1.attrs, {})
m2 = Memory(width=8, depth=4, attrs={"ram_block": True})
self.assertEqual(m2.attrs, {"ram_block": True})
with _ignore_deprecated():
m1 = Memory(width=8, depth=4)
self.assertEqual(m1.attrs, {})
m2 = Memory(width=8, depth=4, attrs={"ram_block": True})
self.assertEqual(m2.attrs, {"ram_block": True})

def test_read_port_transparent(self):
mem = Memory(width=8, depth=4)
rdport = mem.read_port()
self.assertEqual(rdport.memory, mem)
self.assertEqual(rdport.domain, "sync")
self.assertEqual(rdport.transparent, True)
self.assertEqual(len(rdport.addr), 2)
self.assertEqual(len(rdport.data), 8)
self.assertEqual(len(rdport.en), 1)
self.assertIsInstance(rdport.en, Signal)
self.assertEqual(rdport.en.init, 1)
with _ignore_deprecated():
mem = Memory(width=8, depth=4)
rdport = mem.read_port()
self.assertEqual(rdport.memory, mem)
self.assertEqual(rdport.domain, "sync")
self.assertEqual(rdport.transparent, True)
self.assertEqual(len(rdport.addr), 2)
self.assertEqual(len(rdport.data), 8)
self.assertEqual(len(rdport.en), 1)
self.assertIsInstance(rdport.en, Signal)
self.assertEqual(rdport.en.init, 1)

def test_read_port_non_transparent(self):
mem = Memory(width=8, depth=4)
rdport = mem.read_port(transparent=False)
self.assertEqual(rdport.memory, mem)
self.assertEqual(rdport.domain, "sync")
self.assertEqual(rdport.transparent, False)
self.assertEqual(len(rdport.en), 1)
self.assertIsInstance(rdport.en, Signal)
self.assertEqual(rdport.en.init, 1)
with _ignore_deprecated():
mem = Memory(width=8, depth=4)
rdport = mem.read_port(transparent=False)
self.assertEqual(rdport.memory, mem)
self.assertEqual(rdport.domain, "sync")
self.assertEqual(rdport.transparent, False)
self.assertEqual(len(rdport.en), 1)
self.assertIsInstance(rdport.en, Signal)
self.assertEqual(rdport.en.init, 1)

def test_read_port_asynchronous(self):
mem = Memory(width=8, depth=4)
rdport = mem.read_port(domain="comb")
self.assertEqual(rdport.memory, mem)
self.assertEqual(rdport.domain, "comb")
self.assertEqual(rdport.transparent, True)
self.assertEqual(len(rdport.en), 1)
self.assertIsInstance(rdport.en, Const)
self.assertEqual(rdport.en.value, 1)
with _ignore_deprecated():
mem = Memory(width=8, depth=4)
rdport = mem.read_port(domain="comb")
self.assertEqual(rdport.memory, mem)
self.assertEqual(rdport.domain, "comb")
self.assertEqual(rdport.transparent, True)
self.assertEqual(len(rdport.en), 1)
self.assertIsInstance(rdport.en, Const)
self.assertEqual(rdport.en.value, 1)

def test_read_port_wrong(self):
mem = Memory(width=8, depth=4)
with self.assertRaisesRegex(ValueError,
r"^Read port cannot be simultaneously asynchronous and non-transparent$"):
mem.read_port(domain="comb", transparent=False)
with _ignore_deprecated():
mem = Memory(width=8, depth=4)
with self.assertRaisesRegex(ValueError,
r"^Read port cannot be simultaneously asynchronous and non-transparent$"):
mem.read_port(domain="comb", transparent=False)

def test_write_port(self):
mem = Memory(width=8, depth=4)
wrport = mem.write_port()
self.assertEqual(wrport.memory, mem)
self.assertEqual(wrport.domain, "sync")
self.assertEqual(wrport.granularity, 8)
self.assertEqual(len(wrport.addr), 2)
self.assertEqual(len(wrport.data), 8)
self.assertEqual(len(wrport.en), 1)
with _ignore_deprecated():
mem = Memory(width=8, depth=4)
wrport = mem.write_port()
self.assertEqual(wrport.memory, mem)
self.assertEqual(wrport.domain, "sync")
self.assertEqual(wrport.granularity, 8)
self.assertEqual(len(wrport.addr), 2)
self.assertEqual(len(wrport.data), 8)
self.assertEqual(len(wrport.en), 1)

def test_write_port_granularity(self):
mem = Memory(width=8, depth=4)
wrport = mem.write_port(granularity=2)
self.assertEqual(wrport.memory, mem)
self.assertEqual(wrport.domain, "sync")
self.assertEqual(wrport.granularity, 2)
self.assertEqual(len(wrport.addr), 2)
self.assertEqual(len(wrport.data), 8)
self.assertEqual(len(wrport.en), 4)
with _ignore_deprecated():
mem = Memory(width=8, depth=4)
wrport = mem.write_port(granularity=2)
self.assertEqual(wrport.memory, mem)
self.assertEqual(wrport.domain, "sync")
self.assertEqual(wrport.granularity, 2)
self.assertEqual(len(wrport.addr), 2)
self.assertEqual(len(wrport.data), 8)
self.assertEqual(len(wrport.en), 4)

def test_write_port_granularity_wrong(self):
mem = Memory(width=8, depth=4)
with _ignore_deprecated():
mem = Memory(width=8, depth=4)
with self.assertRaisesRegex(TypeError,
r"^Write port granularity must be a non-negative integer, not -1$"):
mem.write_port(granularity=-1)
@@ -119,20 +134,32 @@ def test_write_port_granularity_wrong(self):
r"^Write port granularity must divide memory width evenly$"):
mem.write_port(granularity=3)

def test_deprecated(self):
with self.assertWarnsRegex(DeprecationWarning,
r"^`amaranth.hdl.Memory` is deprecated.*$"):
mem = Memory(width=8, depth=4)


class DummyPortTestCase(FHDLTestCase):
def test_name(self):
p1 = DummyPort(data_width=8, addr_width=2)
self.assertEqual(p1.addr.name, "p1_addr")
p2 = [DummyPort(data_width=8, addr_width=2)][0]
self.assertEqual(p2.addr.name, "dummy_addr")
p3 = DummyPort(data_width=8, addr_width=2, name="foo")
self.assertEqual(p3.addr.name, "foo_addr")
with _ignore_deprecated():
p1 = DummyPort(data_width=8, addr_width=2)
self.assertEqual(p1.addr.name, "p1_addr")
p2 = [DummyPort(data_width=8, addr_width=2)][0]
self.assertEqual(p2.addr.name, "dummy_addr")
p3 = DummyPort(data_width=8, addr_width=2, name="foo")
self.assertEqual(p3.addr.name, "foo_addr")

def test_sizes(self):
p1 = DummyPort(data_width=8, addr_width=2)
self.assertEqual(p1.addr.width, 2)
self.assertEqual(p1.data.width, 8)
self.assertEqual(p1.en.width, 1)
p2 = DummyPort(data_width=8, addr_width=2, granularity=2)
self.assertEqual(p2.en.width, 4)
with _ignore_deprecated():
p1 = DummyPort(data_width=8, addr_width=2)
self.assertEqual(p1.addr.width, 2)
self.assertEqual(p1.data.width, 8)
self.assertEqual(p1.en.width, 1)
p2 = DummyPort(data_width=8, addr_width=2, granularity=2)
self.assertEqual(p2.en.width, 4)

def test_deprecated(self):
with self.assertWarnsRegex(DeprecationWarning,
r"^`DummyPort` is deprecated.*$"):
DummyPort(data_width=8, addr_width=2)
9 changes: 6 additions & 3 deletions tests/test_hdl_xfrm.py
Original file line number Diff line number Diff line change
@@ -128,7 +128,8 @@ def test_rename_cd_subfragment(self):

def test_rename_mem_ports(self):
m = Module()
mem = Memory(depth=4, width=16)
with _ignore_deprecated():
mem = Memory(depth=4, width=16)
m.submodules.mem = mem
mem.read_port(domain="a")
mem.read_port(domain="b")
@@ -397,15 +398,17 @@ def test_enable_subfragment(self):
""")

def test_enable_read_port(self):
mem = Memory(width=8, depth=4)
with _ignore_deprecated():
mem = Memory(width=8, depth=4)
mem.read_port(transparent=False)
f = EnableInserter(self.c1)(mem).elaborate(platform=None)
self.assertRepr(f._read_ports[0]._en, """
(& (sig mem_r_en) (sig c1))
""")

def test_enable_write_port(self):
mem = Memory(width=8, depth=4)
with _ignore_deprecated():
mem = Memory(width=8, depth=4)
mem.write_port(granularity=2)
f = EnableInserter(self.c1)(mem).elaborate(platform=None)
self.assertRepr(f._write_ports[0]._en, """
7 changes: 4 additions & 3 deletions tests/test_lib_fifo.py
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@
from amaranth.asserts import *
from amaranth.sim import *
from amaranth.lib.fifo import *
from amaranth.lib.memory import *

from .utils import *
from amaranth._utils import _ignore_deprecated
@@ -81,9 +82,9 @@ def __init__(self, *, width, depth, r_domain, w_domain):
def elaborate(self, platform):
m = Module()

storage = Memory(width=self.width, depth=self.depth)
w_port = m.submodules.w_port = storage.write_port(domain=self.w_domain)
r_port = m.submodules.r_port = storage.read_port (domain="comb")
storage = m.submodules.storage = Memory(shape=self.width, depth=self.depth, init=[])
w_port = storage.write_port(domain=self.w_domain)
r_port = storage.read_port (domain="comb")

produce = Signal(range(self.depth))
consume = Signal(range(self.depth))
369 changes: 369 additions & 0 deletions tests/test_lib_memory.py

Large diffs are not rendered by default.

26 changes: 12 additions & 14 deletions tests/test_sim.py
Original file line number Diff line number Diff line change
@@ -5,13 +5,13 @@
from amaranth._utils import flatten
from amaranth.hdl._ast import *
from amaranth.hdl._cd import *
from amaranth.hdl._mem import *
with warnings.catch_warnings():
warnings.filterwarnings(action="ignore", category=DeprecationWarning)
from amaranth.hdl.rec import *
from amaranth.hdl._dsl import *
from amaranth.hdl._ir import *
from amaranth.sim import *
from amaranth.lib.memory import Memory

from .utils import *
from amaranth._utils import _ignore_deprecated
@@ -752,14 +752,12 @@ def process():
sim.add_testbench(process)
self.assertTrue(survived)

def setUp_memory(self, rd_synchronous=True, rd_transparent=True, wr_granularity=None):
def setUp_memory(self, rd_synchronous=True, rd_transparent=False, wr_granularity=None):
self.m = Module()
self.memory = Memory(width=8, depth=4, init=[0xaa, 0x55])
self.m.submodules.rdport = self.rdport = \
self.memory.read_port(domain="sync" if rd_synchronous else "comb",
transparent=rd_transparent)
self.m.submodules.wrport = self.wrport = \
self.memory.write_port(granularity=wr_granularity)
self.memory = self.m.submodules.memory = Memory(shape=8, depth=4, init=[0xaa, 0x55])
self.wrport = self.memory.write_port(granularity=wr_granularity)
self.rdport = self.memory.read_port(domain="sync" if rd_synchronous else "comb",
transparent_for=[self.wrport] if rd_transparent else [])

def test_memory_init(self):
self.setUp_memory()
@@ -862,8 +860,8 @@ def process():

def test_memory_read_only(self):
self.m = Module()
self.memory = Memory(width=8, depth=4, init=[0xaa, 0x55])
self.m.submodules.rdport = self.rdport = self.memory.read_port()
self.m.submodules.memory = self.memory = Memory(shape=8, depth=4, init=[0xaa, 0x55])
self.rdport = self.memory.read_port()
with self.assertSimulation(self.m) as sim:
def process():
yield Tick()
@@ -920,9 +918,9 @@ def process():
def test_memory_transparency_simple(self):
m = Module()
init = [0x11, 0x22, 0x33, 0x44]
m.submodules.memory = memory = Memory(width=8, depth=4, init=init)
rdport = memory.read_port()
m.submodules.memory = memory = Memory(shape=8, depth=4, init=init)
wrport = memory.write_port(granularity=8)
rdport = memory.read_port(transparent_for=[wrport])
with self.assertSimulation(m) as sim:
def process():
yield rdport.addr.eq(0)
@@ -959,9 +957,9 @@ def process():
def test_memory_transparency_multibit(self):
m = Module()
init = [0x11111111, 0x22222222, 0x33333333, 0x44444444]
m.submodules.memory = memory = Memory(width=32, depth=4, init=init)
rdport = memory.read_port()
m.submodules.memory = memory = Memory(shape=32, depth=4, init=init)
wrport = memory.write_port(granularity=8)
rdport = memory.read_port(transparent_for=[wrport])
with self.assertSimulation(m) as sim:
def process():
yield rdport.addr.eq(0)