Repository: amaranth-lang/amaranth (python)

Issue:
Tracking issue for RFC 45: Move `hdl.Memory` to `lib.Memory`
- RFC PR: https://github.com/amaranth-lang/rfcs/pull/45
- Implementation PR: https://github.com/amaranth-lang/amaranth/pull/1142
- Documentation PR: https://github.com/amaranth-lang/amaranth/pull/1228
- Removal PR: https://github.com/amaranth-lang/amaranth/pull/1395

Pull request description:
hdl: remove `Memory`.
Fixes #1083.

Patch:
diff --git a/amaranth/__init__.py b/amaranth/__init__.py
index b968958..f9c20d8 100644
--- a/amaranth/__init__.py
+++ b/amaranth/__init__.py
@@ -20,6 +20,5 @@ __all__ = [
     "Module",
     "ClockDomain",
     "Elaboratable", "Fragment", "Instance",
-    "Memory",
     "DomainRenamer", "ResetInserter", "EnableInserter",
 ]
diff --git a/amaranth/hdl/__init__.py b/amaranth/hdl/__init__.py
index 0eab602..0a1f753 100644
--- a/amaranth/hdl/__init__.py
+++ b/amaranth/hdl/__init__.py
@@ -8,7 +8,7 @@ from ._dsl import Module
 from ._cd import DomainError, ClockDomain
 from ._ir import AlreadyElaborated, UnusedElaboratable, Elaboratable, DriverConflict, Fragment
 from ._ir import Instance, IOBufferInstance
-from ._mem import MemoryData, MemoryInstance, Memory, ReadPort, WritePort, DummyPort
+from ._mem import MemoryData, MemoryInstance
 from ._nir import CombinationalCycle
 from ._xfrm import DomainRenamer, ResetInserter, EnableInserter
 
@@ -31,7 +31,7 @@ __all__ = [
     # _nir
     "CombinationalCycle",
     # _mem
-    "MemoryData", "MemoryInstance", "Memory", "ReadPort", "WritePort", "DummyPort",
+    "MemoryData", "MemoryInstance",
     # _xfrm
     "DomainRenamer", "ResetInserter", "EnableInserter",
 ]
diff --git a/amaranth/hdl/_ast.py b/amaranth/hdl/_ast.py
index c192384..58d57e9 100644
--- a/amaranth/hdl/_ast.py
+++ b/amaranth/hdl/_ast.py
@@ -253,9 +253,8 @@ class ShapeCastable:
             raise TypeError(f"Class '{cls.__name__}' deriving from 'ShapeCastable' must override "
                             f"the '__call__' method")
         if cls.from_bits is ShapeCastable.from_bits:
-            warnings.warn(f"Class '{cls.__name__}' deriving from 'ShapeCastable' does not override "
-                          f"the 'from_bits' method, which will be required in Amaranth 0.6",
-                          DeprecationWarning, stacklevel=2)
+            raise TypeError(f"Class '{cls.__name__}' deriving from 'ShapeCastable' must override "
+                            f"the 'from_bits' method")
 
     # The signatures and definitions of these methods are weird because they are present here for
     # documentation (and error checking above) purpose only and should not affect control flow.
@@ -321,8 +320,10 @@ class ShapeCastable:
         """
         return super().const(*args, **kwargs) # :nocov:
 
-    def from_bits(self, raw):
-        """Lift a bit pattern to a higher-level representation.
+    def from_bits(self, *args, **kwargs):
+        """from_bits(raw)
+
+        Lift a bit pattern to a higher-level representation.
 
         This method is called by the Amaranth language to lift :py:`raw`, which is an :class:`int`,
         to a higher-level representation, which may be any object accepted by :meth:`const`.
@@ -353,7 +354,7 @@ class ShapeCastable:
             either directly or as a cause of another exception. While not constrained here,
             usually the exception class will be :exc:`ValueError`.
         """
-        return raw
+        return super().from_bits(*args, **kwargs) # :nocov:
 
     def __call__(self, *args, **kwargs):
         """__call__(obj)
diff --git a/amaranth/hdl/_mem.py b/amaranth/hdl/_mem.py
index add1a89..0554f73 100644
--- a/amaranth/hdl/_mem.py
+++ b/amaranth/hdl/_mem.py
@@ -1,15 +1,14 @@
 import operator
-from collections import OrderedDict
 from collections.abc import MutableSequence
 
 from .. import tracer
 from ._ast import *
-from ._ir import Elaboratable, Fragment, AlreadyElaborated
+from ._ir import Fragment, AlreadyElaborated
 from ..utils import ceil_log2
-from .._utils import deprecated, final
+from .._utils import final
 
 
-__all__ = ["MemoryData", "Memory", "ReadPort", "WritePort", "DummyPort"]
+__all__ = ["MemoryData", "MemoryInstance"]
 
 
 @final
@@ -270,260 +269,3 @@ class MemoryInstance(Fragment):
         assert len(port._addr) == ceil_log2(self._data.depth)
         self._write_ports.append(port)
         return len(self._write_ports) - 1
-
-
-class Memory(Elaboratable):
-    """A word addressable storage.
-
-    Parameters
-    ----------
-    width : int
-        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
-        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.
-    name : str
-        Name hint for this memory. If ``None`` (default) the name is inferred from the variable
-        name this ``Signal`` is assigned to.
-    attrs : dict
-        Dictionary of synthesis attributes.
-
-    Attributes
-    ----------
-    width : int
-    depth : int
-    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}"
-                            .format(width))
-        if not isinstance(depth, int) or depth < 0:
-            raise TypeError("Memory depth must be a non-negative integer, not {!r}"
-                            .format(depth))
-
-        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
-        self.attrs = OrderedDict(() if attrs is None else attrs)
-
-        self._read_ports = []
-        self._write_ports = []
-        self._data = MemoryData(shape=width, depth=depth, init=init or [])
-
-    @property
-    def init(self):
-        return self._data.init
-
-    @init.setter
-    def init(self, new_init):
-        self._data.init = new_init
-
-    def read_port(self, *, src_loc_at=0, **kwargs):
-        """Get a read port.
-
-        See :class:`ReadPort` for details.
-
-        Arguments
-        ---------
-        domain : str
-        transparent : bool
-
-        Returns
-        -------
-        An instance of :class:`ReadPort` associated with this memory.
-        """
-        return ReadPort(self, src_loc_at=1 + src_loc_at, **kwargs)
-
-    def write_port(self, *, src_loc_at=0, **kwargs):
-        """Get a write port.
-
-        See :class:`WritePort` for details.
-
-        Arguments
-        ---------
-        domain : str
-        granularity : int
-
-        Returns
-        -------
-        An instance of :class:`WritePort` associated with this memory.
-        """
-        return WritePort(self, src_loc_at=1 + src_loc_at, **kwargs)
-
-    def __getitem__(self, index):
-        return self._data[index]
-
-    def elaborate(self, platform):
-        f = MemoryInstance(data=self._data, attrs=self.attrs, src_loc=self.src_loc)
-        write_ports = {}
-        for port in self._write_ports:
-            port._MustUse__used = True
-            iport = f.write_port(domain=port.domain, addr=port.addr, data=port.data, en=port.en)
-            write_ports.setdefault(port.domain, []).append(iport)
-        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), transparent_for=())
-            else:
-                transparent_for = []
-                if port.transparent:
-                    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
-
-
-class ReadPort(Elaboratable):
-    """A memory read port.
-
-    Parameters
-    ----------
-    memory : :class:`Memory`
-        Memory associated with the port.
-    domain : str
-        Clock domain. Defaults to ``"sync"``. If set to ``"comb"``, the port is asynchronous.
-        Otherwise, the read data becomes available on the next clock cycle.
-    transparent : bool
-        Port transparency. If set (default), a read at an address that is also being written to in
-        the same clock cycle will output the new value. Otherwise, the old value will be output
-        first. This behavior only applies to ports in the same domain.
-
-    Attributes
-    ----------
-    memory : :class:`Memory`
-    domain : str
-    transparent : bool
-    addr : Signal(range(memory.depth)), in
-        Read address.
-    data : Signal(memory.width), out
-        Read data.
-    en : Signal or Const, in
-        Read enable. If asserted, ``data`` is updated with the word stored at ``addr``.
-
-    Exceptions
-    ----------
-    Raises :exn:`ValueError` if the read port is simultaneously asynchronous and non-transparent.
-    """
-    def __init__(self, memory, *, domain="sync", transparent=True, src_loc_at=0):
-        if domain == "comb" and not transparent:
-            raise ValueError("Read port cannot be simultaneously asynchronous and non-transparent")
-
-        self.memory      = memory
-        self.domain      = domain
-        self.transparent = transparent
-
-        self.addr = Signal(range(memory.depth),
-                           name=f"{memory.name}_r_addr", src_loc_at=1 + src_loc_at)
-        self.data = Signal(memory.width,
-                           name=f"{memory.name}_r_data", src_loc_at=1 + src_loc_at)
-        if self.domain != "comb":
-            self.en = Signal(name=f"{memory.name}_r_en", init=1,
-                             src_loc_at=1 + src_loc_at)
-        else:
-            self.en = Const(1)
-
-        memory._read_ports.append(self)
-
-    def elaborate(self, platform):
-        if self is self.memory._read_ports[0]:
-            return self.memory
-        else:
-            return Fragment()
-
-
-class WritePort(Elaboratable):
-    """A memory write port.
-
-    Parameters
-    ----------
-    memory : :class:`Memory`
-        Memory associated with the port.
-    domain : str
-        Clock domain. Defaults to ``"sync"``. Writes have a latency of 1 clock cycle.
-    granularity : int
-        Port granularity. Defaults to ``memory.width``. Write data is split evenly in
-        ``memory.width // granularity`` chunks, which can be updated independently.
-
-    Attributes
-    ----------
-    memory : :class:`Memory`
-    domain : str
-    granularity : int
-    addr : Signal(range(memory.depth)), in
-        Write address.
-    data : Signal(memory.width), in
-        Write data.
-    en : Signal(memory.width // granularity), in
-        Write enable. Each bit selects a non-overlapping chunk of ``granularity`` bits on the
-        ``data`` signal, which is written to memory at ``addr``. Unselected chunks are ignored.
-
-    Exceptions
-    ----------
-    Raises :exn:`ValueError` if the write port granularity is greater than memory width, or does not
-    divide memory width evenly.
-    """
-    def __init__(self, memory, *, domain="sync", granularity=None, src_loc_at=0):
-        if granularity is None:
-            granularity = memory.width
-        if not isinstance(granularity, int) or granularity < 0:
-            raise TypeError("Write port granularity must be a non-negative integer, not {!r}"
-                            .format(granularity))
-        if granularity > memory.width:
-            raise ValueError("Write port granularity must not be greater than memory width "
-                             "({} > {})"
-                             .format(granularity, memory.width))
-        if memory.width // granularity * granularity != memory.width:
-            raise ValueError("Write port granularity must divide memory width evenly")
-
-        self.memory       = memory
-        self.domain       = domain
-        self.granularity  = granularity
-
-        self.addr = Signal(range(memory.depth),
-                           name=f"{memory.name}_w_addr", src_loc_at=1 + src_loc_at)
-        self.data = Signal(memory.width,
-                           name=f"{memory.name}_w_data", src_loc_at=1 + src_loc_at)
-        self.en   = Signal(memory.width // granularity,
-                           name=f"{memory.name}_w_en", src_loc_at=1 + src_loc_at)
-
-        memory._write_ports.append(self)
-
-    def elaborate(self, platform):
-        if not self.memory._read_ports and self is self.memory._write_ports[0]:
-            return self.memory
-        else:
-            return Fragment()
-
-
-class DummyPort:
-    """Dummy memory port.
-
-    This port can be used in place of either a read or a write port for testing and verification.
-    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=3, default="dummy")
-
-        self.addr = Signal(addr_width,
-                           name=f"{name}_addr", src_loc_at=1)
-        self.data = Signal(data_width,
-                           name=f"{name}_data", src_loc_at=1)
-        self.en   = Signal(data_width // granularity,
-                           name=f"{name}_en", src_loc_at=1)
diff --git a/amaranth/lib/data.py b/amaranth/lib/data.py
index 623d327..5ef38d9 100644
--- a/amaranth/lib/data.py
+++ b/amaranth/lib/data.py
@@ -922,8 +922,8 @@ class Const(ValueCastable):
     Slicing a constant or accessing its attributes returns a part of the underlying value
     corresponding to the field with that index or name. If the shape of the field is
     a :class:`Layout`, the returned value is a :class:`Const`; if it is a different
-    :ref:`shape-like <lang-shapelike>` object implementing :meth:`~.ShapeCastable.from_bits`,
-    it will be the result of calling that method; otherwise, it is an :class:`int`.
+    :ref:`shape-like <lang-shapelike>` object, it will be the result of calling
+    :meth:`~.ShapeCastable.from_bits`; otherwise, it is an :class:`int`.
 
     Slicing a constant whose layout is an :class:`ArrayLayout` can be done with an index that is
     an Amaranth value rather than a constant integer. The returned element is chosen dynamically
@@ -990,8 +990,8 @@ class Const(ValueCastable):
         """Slice the underlying value.
 
         A field corresponding to :py:`key` is looked up in the layout. If the field's shape is
-        a shape-castable object that has a :meth:`~.ShapeCastable.from_bits` method, returns
-        the result of calling that method. Otherwise, returns an :class:`int`.
+        a shape-castable object, returns the result of calling :meth:`~.ShapeCastable.from_bits`.
+        Otherwise, returns an :class:`int`.
 
         Arguments
         ---------
diff --git a/docs/changes.rst b/docs/changes.rst
index 4087686..be9539f 100644
--- a/docs/changes.rst
+++ b/docs/changes.rst
@@ -28,7 +28,9 @@ Language changes
 
 .. currentmodule:: amaranth.hdl
 
+* Changed: overriding :meth:`ValueCastable.from_bits` is now mandatory. (`RFC 51`_)
 * Removed: (deprecated in 0.4) :class:`Record`.
+* Removed: (deprecated in 0.5) :class:`Memory` (`RFC 45`_)
 * Removed: (deprecated in 0.5) public submodules of :mod:`amaranth.hdl`.
 * Removed: (deprecated in 0.5) :meth:`Value.implies`.
 


Test patch:
diff --git a/tests/test_hdl_ast.py b/tests/test_hdl_ast.py
index 4ec8618..cdb0367 100644
--- a/tests/test_hdl_ast.py
+++ b/tests/test_hdl_ast.py
@@ -211,25 +211,6 @@ class ShapeCastableTestCase(FHDLTestCase):
                 r"^Can't instantiate abstract class ShapeCastable$"):
             ShapeCastable()
 
-    def test_no_from_bits(self):
-        with self.assertWarnsRegex(DeprecationWarning,
-                r"^Class 'MockShapeCastableNoFromBits' deriving from 'ShapeCastable' does "
-                r"not override the 'from_bits' method, which will be required in Amaranth 0.6$"):
-            class MockShapeCastableNoFromBits(ShapeCastable):
-                def __init__(self, dest):
-                    self.dest = dest
-
-                def as_shape(self):
-                    return self.dest
-
-                def __call__(self, value):
-                    return value
-
-                def const(self, init):
-                    return Const(init, self.dest)
-
-        self.assertEqual(MockShapeCastableNoFromBits(unsigned(2)).from_bits(123), 123)
-
 
 class ShapeLikeTestCase(FHDLTestCase):
     def test_construct(self):
diff --git a/tests/test_hdl_mem.py b/tests/test_hdl_mem.py
index f165622..504e598 100644
--- a/tests/test_hdl_mem.py
+++ b/tests/test_hdl_mem.py
@@ -2,7 +2,6 @@
 
 from amaranth.hdl import *
 from amaranth.hdl._mem import *
-from amaranth._utils import _ignore_deprecated
 
 from .utils import *
 
@@ -32,160 +31,3 @@ class MemoryDataTestCase(FHDLTestCase):
         with self.assertRaisesRegex(ValueError,
                 r"^Value \(memory-row \(memory-data data\) 0\) can only be used in simulator processes$"):
             m.d.comb += data[0].eq(1)
-
-class MemoryTestCase(FHDLTestCase):
-    def test_name(self):
-        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):
-        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 _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):
-        with _ignore_deprecated():
-            m = Memory(width=8, depth=4, init=range(4))
-            self.assertEqual(list(m.init), [0, 1, 2, 3])
-
-    def test_init_wrong_count(self):
-        with _ignore_deprecated():
-            with self.assertRaisesRegex(ValueError,
-                    r"^Memory initialization value count exceeds memory depth \(8 > 4\)$"):
-                m = Memory(width=8, depth=4, init=range(8))
-
-    def test_init_wrong_type(self):
-        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):
-        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):
-        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):
-        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):
-        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):
-        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):
-        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):
-        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):
-        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)
-        with self.assertRaisesRegex(ValueError,
-                r"^Write port granularity must not be greater than memory width \(10 > 8\)$"):
-            mem.write_port(granularity=10)
-        with self.assertRaisesRegex(ValueError,
-                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):
-        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):
-        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)
diff --git a/tests/test_hdl_xfrm.py b/tests/test_hdl_xfrm.py
index 0ab2eee..4c2ff63 100644
--- a/tests/test_hdl_xfrm.py
+++ b/tests/test_hdl_xfrm.py
@@ -6,7 +6,7 @@ from amaranth.hdl._dsl import *
 from amaranth.hdl._ir import *
 from amaranth.hdl._xfrm import *
 from amaranth.hdl._mem import *
-from amaranth.hdl._mem import MemoryInstance
+from amaranth.lib.memory import Memory
 
 from .utils import *
 from amaranth._utils import _ignore_deprecated
@@ -120,7 +120,7 @@ class DomainRenamerTestCase(FHDLTestCase):
     def test_rename_mem_ports(self):
         m = Module()
         with _ignore_deprecated():
-            mem = Memory(depth=4, width=16)
+            mem = Memory(depth=4, shape=16, init=[])
         m.submodules.mem = mem
         mem.read_port(domain="a")
         mem.read_port(domain="b")
@@ -362,23 +362,23 @@ class EnableInserterTestCase(FHDLTestCase):
 
     def test_enable_read_port(self):
         with _ignore_deprecated():
-            mem = Memory(width=8, depth=4)
-        mem.read_port(transparent=False)
+            mem = Memory(shape=8, depth=4, init=[])
+        mem_r = mem.read_port()
         f = EnableInserter(self.c1)(mem).elaborate(platform=None)
         self.assertRepr(f._read_ports[0]._en, """
-        (& (sig mem_r_en) (sig c1))
+        (& (sig mem_r__en) (sig c1))
         """)
 
     def test_enable_write_port(self):
         with _ignore_deprecated():
-            mem = Memory(width=8, depth=4)
-        mem.write_port(granularity=2)
+            mem = Memory(shape=8, depth=4, init=[])
+        mem_w = mem.write_port(granularity=2)
         f = EnableInserter(self.c1)(mem).elaborate(platform=None)
         self.assertRepr(f._write_ports[0]._en, """
         (switch-value
             (sig c1)
             (case 0 (const 4'd0))
-            (default (sig mem_w_en))
+            (default (sig mem_w__en))
         )
         """)