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
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
4 changes: 2 additions & 2 deletions amaranth/hdl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -21,7 +21,7 @@
# _ir
"UnusedElaboratable", "Elaboratable", "DriverConflict", "Fragment", "Instance",
# _mem
"Memory", "ReadPort", "WritePort", "DummyPort",
"MemoryIdentity", "MemoryInstance", "Memory", "ReadPort", "WritePort", "DummyPort",
# _rec
"Record",
# _xfrm
Expand Down
2 changes: 1 addition & 1 deletion amaranth/hdl/_ir.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
42 changes: 25 additions & 17 deletions amaranth/hdl/_mem.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand Down Expand Up @@ -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):
Expand All @@ -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)
Expand Down Expand Up @@ -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}"
Expand All @@ -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
Expand Down Expand Up @@ -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


Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion amaranth/hdl/_xfrm.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
]
Expand Down
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"]
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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))

Expand Down Expand Up @@ -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),
Expand Down
Loading