Skip to content

Commit 6a3da1f

Browse files
committed
hdl: remove Memory.
1 parent c9de103 commit 6a3da1f

File tree

6 files changed

+14
-430
lines changed

6 files changed

+14
-430
lines changed

amaranth/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,5 @@
2020
"Module",
2121
"ClockDomain",
2222
"Elaboratable", "Fragment", "Instance",
23-
"Memory",
2423
"DomainRenamer", "ResetInserter", "EnableInserter",
2524
]

amaranth/hdl/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from ._cd import DomainError, ClockDomain
99
from ._ir import AlreadyElaborated, UnusedElaboratable, Elaboratable, DriverConflict, Fragment
1010
from ._ir import Instance, IOBufferInstance
11-
from ._mem import MemoryData, MemoryInstance, Memory, ReadPort, WritePort, DummyPort
11+
from ._mem import MemoryData, MemoryInstance
1212
from ._nir import CombinationalCycle
1313
from ._xfrm import DomainRenamer, ResetInserter, EnableInserter
1414

@@ -31,7 +31,7 @@
3131
# _nir
3232
"CombinationalCycle",
3333
# _mem
34-
"MemoryData", "MemoryInstance", "Memory", "ReadPort", "WritePort", "DummyPort",
34+
"MemoryData", "MemoryInstance",
3535
# _xfrm
3636
"DomainRenamer", "ResetInserter", "EnableInserter",
3737
]

amaranth/hdl/_mem.py

Lines changed: 3 additions & 261 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
import operator
2-
from collections import OrderedDict
32
from collections.abc import MutableSequence
43

54
from .. import tracer
65
from ._ast import *
7-
from ._ir import Elaboratable, Fragment, AlreadyElaborated
6+
from ._ir import Fragment, AlreadyElaborated
87
from ..utils import ceil_log2
9-
from .._utils import deprecated, final
8+
from .._utils import final
109

1110

12-
__all__ = ["MemoryData", "Memory", "ReadPort", "WritePort", "DummyPort"]
11+
__all__ = ["MemoryData", "MemoryInstance"]
1312

1413

1514
@final
@@ -270,260 +269,3 @@ def write_port(self, *, domain, addr, data, en):
270269
assert len(port._addr) == ceil_log2(self._data.depth)
271270
self._write_ports.append(port)
272271
return len(self._write_ports) - 1
273-
274-
275-
class Memory(Elaboratable):
276-
"""A word addressable storage.
277-
278-
Parameters
279-
----------
280-
width : int
281-
Access granularity. Each storage element of this memory is ``width`` bits in size.
282-
depth : int
283-
Word count. This memory contains ``depth`` storage elements.
284-
init : list of int
285-
Initial values. At power on, each storage element in this memory is initialized to
286-
the corresponding element of ``init``, if any, or to zero otherwise.
287-
Uninitialized memories are not currently supported.
288-
name : str
289-
Name hint for this memory. If ``None`` (default) the name is inferred from the variable
290-
name this ``Signal`` is assigned to.
291-
attrs : dict
292-
Dictionary of synthesis attributes.
293-
294-
Attributes
295-
----------
296-
width : int
297-
depth : int
298-
init : list of int
299-
attrs : dict
300-
"""
301-
# TODO(amaranth-0.6): remove
302-
@deprecated("`amaranth.hdl.Memory` is deprecated, use `amaranth.lib.memory.Memory` instead")
303-
def __init__(self, *, width, depth, init=None, name=None, attrs=None, simulate=True):
304-
if not isinstance(width, int) or width < 0:
305-
raise TypeError("Memory width must be a non-negative integer, not {!r}"
306-
.format(width))
307-
if not isinstance(depth, int) or depth < 0:
308-
raise TypeError("Memory depth must be a non-negative integer, not {!r}"
309-
.format(depth))
310-
311-
self.name = name or tracer.get_var_name(depth=3, default="$memory")
312-
self.src_loc = tracer.get_src_loc(src_loc_at=1)
313-
314-
self.width = width
315-
self.depth = depth
316-
self.attrs = OrderedDict(() if attrs is None else attrs)
317-
318-
self._read_ports = []
319-
self._write_ports = []
320-
self._data = MemoryData(shape=width, depth=depth, init=init or [])
321-
322-
@property
323-
def init(self):
324-
return self._data.init
325-
326-
@init.setter
327-
def init(self, new_init):
328-
self._data.init = new_init
329-
330-
def read_port(self, *, src_loc_at=0, **kwargs):
331-
"""Get a read port.
332-
333-
See :class:`ReadPort` for details.
334-
335-
Arguments
336-
---------
337-
domain : str
338-
transparent : bool
339-
340-
Returns
341-
-------
342-
An instance of :class:`ReadPort` associated with this memory.
343-
"""
344-
return ReadPort(self, src_loc_at=1 + src_loc_at, **kwargs)
345-
346-
def write_port(self, *, src_loc_at=0, **kwargs):
347-
"""Get a write port.
348-
349-
See :class:`WritePort` for details.
350-
351-
Arguments
352-
---------
353-
domain : str
354-
granularity : int
355-
356-
Returns
357-
-------
358-
An instance of :class:`WritePort` associated with this memory.
359-
"""
360-
return WritePort(self, src_loc_at=1 + src_loc_at, **kwargs)
361-
362-
def __getitem__(self, index):
363-
return self._data[index]
364-
365-
def elaborate(self, platform):
366-
f = MemoryInstance(data=self._data, attrs=self.attrs, src_loc=self.src_loc)
367-
write_ports = {}
368-
for port in self._write_ports:
369-
port._MustUse__used = True
370-
iport = f.write_port(domain=port.domain, addr=port.addr, data=port.data, en=port.en)
371-
write_ports.setdefault(port.domain, []).append(iport)
372-
for port in self._read_ports:
373-
port._MustUse__used = True
374-
if port.domain == "comb":
375-
f.read_port(domain="comb", addr=port.addr, data=port.data, en=Const(1), transparent_for=())
376-
else:
377-
transparent_for = []
378-
if port.transparent:
379-
transparent_for = write_ports.get(port.domain, [])
380-
f.read_port(domain=port.domain, addr=port.addr, data=port.data, en=port.en, transparent_for=transparent_for)
381-
return f
382-
383-
384-
class ReadPort(Elaboratable):
385-
"""A memory read port.
386-
387-
Parameters
388-
----------
389-
memory : :class:`Memory`
390-
Memory associated with the port.
391-
domain : str
392-
Clock domain. Defaults to ``"sync"``. If set to ``"comb"``, the port is asynchronous.
393-
Otherwise, the read data becomes available on the next clock cycle.
394-
transparent : bool
395-
Port transparency. If set (default), a read at an address that is also being written to in
396-
the same clock cycle will output the new value. Otherwise, the old value will be output
397-
first. This behavior only applies to ports in the same domain.
398-
399-
Attributes
400-
----------
401-
memory : :class:`Memory`
402-
domain : str
403-
transparent : bool
404-
addr : Signal(range(memory.depth)), in
405-
Read address.
406-
data : Signal(memory.width), out
407-
Read data.
408-
en : Signal or Const, in
409-
Read enable. If asserted, ``data`` is updated with the word stored at ``addr``.
410-
411-
Exceptions
412-
----------
413-
Raises :exn:`ValueError` if the read port is simultaneously asynchronous and non-transparent.
414-
"""
415-
def __init__(self, memory, *, domain="sync", transparent=True, src_loc_at=0):
416-
if domain == "comb" and not transparent:
417-
raise ValueError("Read port cannot be simultaneously asynchronous and non-transparent")
418-
419-
self.memory = memory
420-
self.domain = domain
421-
self.transparent = transparent
422-
423-
self.addr = Signal(range(memory.depth),
424-
name=f"{memory.name}_r_addr", src_loc_at=1 + src_loc_at)
425-
self.data = Signal(memory.width,
426-
name=f"{memory.name}_r_data", src_loc_at=1 + src_loc_at)
427-
if self.domain != "comb":
428-
self.en = Signal(name=f"{memory.name}_r_en", init=1,
429-
src_loc_at=1 + src_loc_at)
430-
else:
431-
self.en = Const(1)
432-
433-
memory._read_ports.append(self)
434-
435-
def elaborate(self, platform):
436-
if self is self.memory._read_ports[0]:
437-
return self.memory
438-
else:
439-
return Fragment()
440-
441-
442-
class WritePort(Elaboratable):
443-
"""A memory write port.
444-
445-
Parameters
446-
----------
447-
memory : :class:`Memory`
448-
Memory associated with the port.
449-
domain : str
450-
Clock domain. Defaults to ``"sync"``. Writes have a latency of 1 clock cycle.
451-
granularity : int
452-
Port granularity. Defaults to ``memory.width``. Write data is split evenly in
453-
``memory.width // granularity`` chunks, which can be updated independently.
454-
455-
Attributes
456-
----------
457-
memory : :class:`Memory`
458-
domain : str
459-
granularity : int
460-
addr : Signal(range(memory.depth)), in
461-
Write address.
462-
data : Signal(memory.width), in
463-
Write data.
464-
en : Signal(memory.width // granularity), in
465-
Write enable. Each bit selects a non-overlapping chunk of ``granularity`` bits on the
466-
``data`` signal, which is written to memory at ``addr``. Unselected chunks are ignored.
467-
468-
Exceptions
469-
----------
470-
Raises :exn:`ValueError` if the write port granularity is greater than memory width, or does not
471-
divide memory width evenly.
472-
"""
473-
def __init__(self, memory, *, domain="sync", granularity=None, src_loc_at=0):
474-
if granularity is None:
475-
granularity = memory.width
476-
if not isinstance(granularity, int) or granularity < 0:
477-
raise TypeError("Write port granularity must be a non-negative integer, not {!r}"
478-
.format(granularity))
479-
if granularity > memory.width:
480-
raise ValueError("Write port granularity must not be greater than memory width "
481-
"({} > {})"
482-
.format(granularity, memory.width))
483-
if memory.width // granularity * granularity != memory.width:
484-
raise ValueError("Write port granularity must divide memory width evenly")
485-
486-
self.memory = memory
487-
self.domain = domain
488-
self.granularity = granularity
489-
490-
self.addr = Signal(range(memory.depth),
491-
name=f"{memory.name}_w_addr", src_loc_at=1 + src_loc_at)
492-
self.data = Signal(memory.width,
493-
name=f"{memory.name}_w_data", src_loc_at=1 + src_loc_at)
494-
self.en = Signal(memory.width // granularity,
495-
name=f"{memory.name}_w_en", src_loc_at=1 + src_loc_at)
496-
497-
memory._write_ports.append(self)
498-
499-
def elaborate(self, platform):
500-
if not self.memory._read_ports and self is self.memory._write_ports[0]:
501-
return self.memory
502-
else:
503-
return Fragment()
504-
505-
506-
class DummyPort:
507-
"""Dummy memory port.
508-
509-
This port can be used in place of either a read or a write port for testing and verification.
510-
It does not include any read/write port specific attributes, i.e. none besides ``"domain"``;
511-
any such attributes may be set manually.
512-
"""
513-
# TODO(amaranth-0.6): remove
514-
@deprecated("`DummyPort` is deprecated, use `amaranth.lib.memory.ReadPort` or "
515-
"`amaranth.lib.memory.WritePort` instead")
516-
def __init__(self, *, data_width, addr_width, domain="sync", name=None, granularity=None):
517-
self.domain = domain
518-
519-
if granularity is None:
520-
granularity = data_width
521-
if name is None:
522-
name = tracer.get_var_name(depth=3, default="dummy")
523-
524-
self.addr = Signal(addr_width,
525-
name=f"{name}_addr", src_loc_at=1)
526-
self.data = Signal(data_width,
527-
name=f"{name}_data", src_loc_at=1)
528-
self.en = Signal(data_width // granularity,
529-
name=f"{name}_en", src_loc_at=1)

docs/changes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Language changes
2929
.. currentmodule:: amaranth.hdl
3030

3131
* Removed: (deprecated in 0.4) :class:`Record`.
32+
* Removed: (deprecated in 0.5) :class:`Memory` (`RFC 45`_)
3233
* Removed: (deprecated in 0.5) public submodules of :mod:`amaranth.hdl`.
3334
* Removed: (deprecated in 0.5) :meth:`Value.implies`.
3435

0 commit comments

Comments
 (0)