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),
Loading