Implement RFC 43: Rename reset= to init=.

This commit is contained in:
Wanda 2024-02-14 07:13:12 +01:00 committed by Catherine
parent b30c87fa3e
commit 24a392887a
30 changed files with 476 additions and 276 deletions

View file

@ -173,7 +173,7 @@ class ShapeCastable:
.. code:: .. code::
value_like = Signal(shape_castable, reset=initializer) value_like = Signal(shape_castable, init=initializer)
The code above is equivalent to: The code above is equivalent to:
@ -181,7 +181,7 @@ class ShapeCastable:
value_like = shape_castable(Signal( value_like = shape_castable(Signal(
shape_castable.as_shape(), shape_castable.as_shape(),
reset=shape_castable.const(initializer) init=shape_castable.const(initializer)
)) ))
Note that the :py:`shape_castable(x)` syntax performs :py:`shape_castable.__call__(x)`. Note that the :py:`shape_castable(x)` syntax performs :py:`shape_castable.__call__(x)`.
@ -1731,15 +1731,15 @@ class Signal(Value, DUID, metaclass=_SignalMeta):
name : str name : str
Name hint for this signal. If ``None`` (default) the name is inferred from the variable Name hint for this signal. If ``None`` (default) the name is inferred from the variable
name this ``Signal`` is assigned to. name this ``Signal`` is assigned to.
reset : int or integral Enum init : int or integral Enum
Reset (synchronous) or default (combinatorial) value. Reset (synchronous) or default (combinatorial) value.
When this ``Signal`` is assigned to in synchronous context and the corresponding clock When this ``Signal`` is assigned to in synchronous context and the corresponding clock
domain is reset, the ``Signal`` assumes the given value. When this ``Signal`` is unassigned domain is reset, the ``Signal`` assumes the given value. When this ``Signal`` is unassigned
in combinatorial context (due to conditional assignments not being taken), the ``Signal`` in combinatorial context (due to conditional assignments not being taken), the ``Signal``
assumes its ``reset`` value. Defaults to 0. assumes its ``init`` value. Defaults to 0.
reset_less : bool reset_less : bool
If ``True``, do not generate reset logic for this ``Signal`` in synchronous statements. If ``True``, do not generate reset logic for this ``Signal`` in synchronous statements.
The ``reset`` value is only used as a combinatorial default or as the initial value. The ``init`` value is only used as a combinatorial default or as the initial value.
Defaults to ``False``. Defaults to ``False``.
attrs : dict attrs : dict
Dictionary of synthesis attributes. Dictionary of synthesis attributes.
@ -1754,13 +1754,13 @@ class Signal(Value, DUID, metaclass=_SignalMeta):
width : int width : int
signed : bool signed : bool
name : str name : str
reset : int init : int
reset_less : bool reset_less : bool
attrs : dict attrs : dict
decoder : function decoder : function
""" """
def __init__(self, shape=None, *, name=None, reset=None, reset_less=False, def __init__(self, shape=None, *, name=None, init=None, reset=None, reset_less=False,
attrs=None, decoder=None, src_loc_at=0): attrs=None, decoder=None, src_loc_at=0):
super().__init__(src_loc_at=src_loc_at) super().__init__(src_loc_at=src_loc_at)
@ -1776,53 +1776,61 @@ class Signal(Value, DUID, metaclass=_SignalMeta):
self.width = shape.width self.width = shape.width
self.signed = shape.signed self.signed = shape.signed
orig_reset = reset # TODO(amaranth-0.7): remove
if reset is not None:
if init is not None:
raise ValueError("Cannot specify both `reset` and `init`")
warnings.warn("`reset=` is deprecated, use `init=` instead",
DeprecationWarning, stacklevel=2)
init = reset
orig_init = init
if isinstance(orig_shape, ShapeCastable): if isinstance(orig_shape, ShapeCastable):
try: try:
reset = Const.cast(orig_shape.const(reset)) init = Const.cast(orig_shape.const(init))
except Exception: except Exception:
raise TypeError("Reset value must be a constant initializer of {!r}" raise TypeError("Initial value must be a constant initializer of {!r}"
.format(orig_shape)) .format(orig_shape))
if reset.shape() != Shape.cast(orig_shape): if init.shape() != Shape.cast(orig_shape):
raise ValueError("Constant returned by {!r}.const() must have the shape that " raise ValueError("Constant returned by {!r}.const() must have the shape that "
"it casts to, {!r}, and not {!r}" "it casts to, {!r}, and not {!r}"
.format(orig_shape, Shape.cast(orig_shape), .format(orig_shape, Shape.cast(orig_shape),
reset.shape())) init.shape()))
else: else:
if reset is None: if init is None:
reset = 0 init = 0
try: try:
reset = Const.cast(reset) init = Const.cast(init)
except TypeError: except TypeError:
raise TypeError("Reset value must be a constant-castable expression, not {!r}" raise TypeError("Initial value must be a constant-castable expression, not {!r}"
.format(orig_reset)) .format(orig_init))
# Avoid false positives for all-zeroes and all-ones # Avoid false positives for all-zeroes and all-ones
if orig_reset is not None and not (isinstance(orig_reset, int) and orig_reset in (0, -1)): if orig_init is not None and not (isinstance(orig_init, int) and orig_init in (0, -1)):
if reset.shape().signed and not self.signed: if init.shape().signed and not self.signed:
warnings.warn( warnings.warn(
message="Reset value {!r} is signed, but the signal shape is {!r}" message="Initial value {!r} is signed, but the signal shape is {!r}"
.format(orig_reset, shape), .format(orig_init, shape),
category=SyntaxWarning, category=SyntaxWarning,
stacklevel=2) stacklevel=2)
elif (reset.shape().width > self.width or elif (init.shape().width > self.width or
reset.shape().width == self.width and init.shape().width == self.width and
self.signed and not reset.shape().signed): self.signed and not init.shape().signed):
warnings.warn( warnings.warn(
message="Reset value {!r} will be truncated to the signal shape {!r}" message="Initial value {!r} will be truncated to the signal shape {!r}"
.format(orig_reset, shape), .format(orig_init, shape),
category=SyntaxWarning, category=SyntaxWarning,
stacklevel=2) stacklevel=2)
self.reset = reset.value self.init = init.value
self.reset_less = bool(reset_less) self.reset_less = bool(reset_less)
if isinstance(orig_shape, range) and orig_reset is not None and orig_reset not in orig_shape: if isinstance(orig_shape, range) and orig_init is not None and orig_init not in orig_shape:
if orig_reset == orig_shape.stop: if orig_init == orig_shape.stop:
raise SyntaxError( raise SyntaxError(
f"Reset value {orig_reset!r} equals the non-inclusive end of the signal " f"Initial value {orig_init!r} equals the non-inclusive end of the signal "
f"shape {orig_shape!r}; this is likely an off-by-one error") f"shape {orig_shape!r}; this is likely an off-by-one error")
else: else:
raise SyntaxError( raise SyntaxError(
f"Reset value {orig_reset!r} is not within the signal shape {orig_shape!r}") f"Initial value {orig_init!r} is not within the signal shape {orig_shape!r}")
self.attrs = OrderedDict(() if attrs is None else attrs) self.attrs = OrderedDict(() if attrs is None else attrs)
@ -1850,6 +1858,18 @@ class Signal(Value, DUID, metaclass=_SignalMeta):
# Any other case is formatted as a plain integer. # Any other case is formatted as a plain integer.
self._value_repr = (Repr(FormatInt(), self),) self._value_repr = (Repr(FormatInt(), self),)
@property
def reset(self):
warnings.warn("`Signal.reset` is deprecated, use `Signal.init` instead",
DeprecationWarning, stacklevel=2)
return self.init
@reset.setter
def reset(self, value):
warnings.warn("`Signal.reset` is deprecated, use `Signal.init` instead",
DeprecationWarning, stacklevel=2)
self.init = value
@property @property
def decoder(self): def decoder(self):
return self._decoder return self._decoder
@ -1873,7 +1893,7 @@ class Signal(Value, DUID, metaclass=_SignalMeta):
self._decoder = enum_decoder self._decoder = enum_decoder
@classmethod @classmethod
def like(cls, other, *, name=None, name_suffix=None, src_loc_at=0, **kwargs): def like(cls, other, *, name=None, name_suffix=None, init=None, reset=None, src_loc_at=0, **kwargs):
"""Create Signal based on another. """Create Signal based on another.
Parameters Parameters
@ -1887,15 +1907,24 @@ class Signal(Value, DUID, metaclass=_SignalMeta):
new_name = other.name + str(name_suffix) new_name = other.name + str(name_suffix)
else: else:
new_name = tracer.get_var_name(depth=2 + src_loc_at, default="$like") new_name = tracer.get_var_name(depth=2 + src_loc_at, default="$like")
# TODO(amaranth-0.7): remove
if reset is not None:
if init is not None:
raise ValueError("Cannot specify both `reset` and `init`")
warnings.warn("`reset=` is deprecated, use `init=` instead",
DeprecationWarning, stacklevel=2)
init = reset
if isinstance(other, ValueCastable): if isinstance(other, ValueCastable):
shape = other.shape() shape = other.shape()
else: else:
shape = Value.cast(other).shape() shape = Value.cast(other).shape()
kw = dict(shape=shape, name=new_name) kw = dict(shape=shape, name=new_name)
if isinstance(other, Signal): if isinstance(other, Signal):
kw.update(reset=other.reset, reset_less=other.reset_less, kw.update(init=other.init, reset_less=other.reset_less,
attrs=other.attrs, decoder=other.decoder) attrs=other.attrs, decoder=other.decoder)
kw.update(kwargs) kw.update(kwargs)
if init is not None:
kw["init"] = init
return cls(**kw, src_loc_at=1 + src_loc_at) return cls(**kw, src_loc_at=1 + src_loc_at)
def shape(self): def shape(self):

View file

@ -374,14 +374,21 @@ class Module(_ModuleBuilderRoot, Elaboratable):
self._statements = _outer_case self._statements = _outer_case
@contextmanager @contextmanager
def FSM(self, reset=None, domain="sync", name="fsm"): def FSM(self, init=None, domain="sync", name="fsm", *, reset=None):
self._check_context("FSM", context=None) self._check_context("FSM", context=None)
if domain == "comb": if domain == "comb":
raise ValueError(f"FSM may not be driven by the '{domain}' domain") raise ValueError(f"FSM may not be driven by the '{domain}' domain")
# TODO(amaranth-0.7): remove
if reset is not None:
if init is not None:
raise ValueError("Cannot specify both `reset` and `init`")
warnings.warn("`reset=` is deprecated, use `init=` instead",
DeprecationWarning, stacklevel=2)
init = reset
fsm_data = self._set_ctrl("FSM", { fsm_data = self._set_ctrl("FSM", {
"name": name, "name": name,
"signal": Signal(name=f"{name}_state", src_loc_at=2), "signal": Signal(name=f"{name}_state", src_loc_at=2),
"reset": reset, "init": init,
"domain": domain, "domain": domain,
"encoding": OrderedDict(), "encoding": OrderedDict(),
"decoding": OrderedDict(), "decoding": OrderedDict(),
@ -489,17 +496,17 @@ class Module(_ModuleBuilderRoot, Elaboratable):
src_loc=src_loc, case_src_locs=switch_case_src_locs)) src_loc=src_loc, case_src_locs=switch_case_src_locs))
if name == "FSM": if name == "FSM":
fsm_signal, fsm_reset, fsm_encoding, fsm_decoding, fsm_states = \ fsm_signal, fsm_init, fsm_encoding, fsm_decoding, fsm_states = \
data["signal"], data["reset"], data["encoding"], data["decoding"], data["states"] data["signal"], data["init"], data["encoding"], data["decoding"], data["states"]
fsm_state_src_locs = data["state_src_locs"] fsm_state_src_locs = data["state_src_locs"]
if not fsm_states: if not fsm_states:
return return
fsm_signal.width = bits_for(len(fsm_encoding) - 1) fsm_signal.width = bits_for(len(fsm_encoding) - 1)
if fsm_reset is None: if fsm_init is None:
fsm_signal.reset = fsm_encoding[next(iter(fsm_states))] fsm_signal.init = fsm_encoding[next(iter(fsm_states))]
else: else:
fsm_signal.reset = fsm_encoding[fsm_reset] fsm_signal.init = fsm_encoding[fsm_init]
# The FSM is encoded such that the state with encoding 0 is always the reset state. # The FSM is encoded such that the state with encoding 0 is always the init state.
fsm_decoding.update((n, s) for s, n in fsm_encoding.items()) fsm_decoding.update((n, s) for s, n in fsm_encoding.items())
fsm_signal.decoder = lambda n: f"{fsm_decoding[n]}/{n}" fsm_signal.decoder = lambda n: f"{fsm_decoding[n]}/{n}"

View file

@ -691,8 +691,8 @@ class NetlistDriver:
def emit_value(self, builder): def emit_value(self, builder):
if self.domain is None: if self.domain is None:
reset = _ast.Const(self.signal.reset, self.signal.width) init = _ast.Const(self.signal.init, self.signal.width)
default, _signed = builder.emit_rhs(self.module_idx, reset) default, _signed = builder.emit_rhs(self.module_idx, init)
else: else:
default = builder.emit_signal(self.signal) default = builder.emit_signal(self.signal)
if len(self.assignments) == 1: if len(self.assignments) == 1:
@ -1184,7 +1184,7 @@ class NetlistEmitter:
arst = _nir.Net.from_const(0) arst = _nir.Net.from_const(0)
cell = _nir.FlipFlop(driver.module_idx, cell = _nir.FlipFlop(driver.module_idx,
data=value, data=value,
init=driver.signal.reset, init=driver.signal.init,
clk=clk, clk=clk,
clk_edge=driver.domain.clk_edge, clk_edge=driver.domain.clk_edge,
arst=arst, arst=arst,
@ -1198,12 +1198,12 @@ class NetlistEmitter:
src_loc = driver.signal.src_loc src_loc = driver.signal.src_loc
self.connect(self.emit_signal(driver.signal), value, src_loc=src_loc) self.connect(self.emit_signal(driver.signal), value, src_loc=src_loc)
# Connect all undriven signal bits to their reset values. This can only happen for entirely # Connect all undriven signal bits to their initial values. This can only happen for entirely
# undriven signals, or signals that are partially driven by instances. # undriven signals, or signals that are partially driven by instances.
for signal, value in self.netlist.signals.items(): for signal, value in self.netlist.signals.items():
for bit, net in enumerate(value): for bit, net in enumerate(value):
if net.is_late and net not in self.netlist.connections: if net.is_late and net not in self.netlist.connections:
self.netlist.connections[net] = _nir.Net.from_const((signal.reset >> bit) & 1) self.netlist.connections[net] = _nir.Net.from_const((signal.init >> bit) & 1)
def emit_fragment(self, fragment: _ir.Fragment, parent_module_idx: 'int | None'): def emit_fragment(self, fragment: _ir.Fragment, parent_module_idx: 'int | None'):
from . import _mem from . import _mem

View file

@ -262,7 +262,7 @@ class ReadPort(Elaboratable):
self.data = Signal(memory.width, self.data = Signal(memory.width,
name=f"{memory.name}_r_data", src_loc_at=1 + src_loc_at) name=f"{memory.name}_r_data", src_loc_at=1 + src_loc_at)
if self.domain != "comb": if self.domain != "comb":
self.en = Signal(name=f"{memory.name}_r_en", reset=1, self.en = Signal(name=f"{memory.name}_r_en", init=1,
src_loc_at=1 + src_loc_at) src_loc_at=1 + src_loc_at)
else: else:
self.en = Const(1) self.en = Const(1)

View file

@ -521,7 +521,7 @@ class DomainLowerer(FragmentTransformer, ValueTransformer, StatementTransformer)
domain = fragment.domains[domain_name] domain = fragment.domains[domain_name]
if domain.rst is None: if domain.rst is None:
continue continue
stmts = [signal.eq(Const(signal.reset, signal.width)) stmts = [signal.eq(Const(signal.init, signal.width))
for signal in signals if not signal.reset_less] for signal in signals if not signal.reset_less]
fragment.add_statements(domain_name, Switch(domain.rst, {1: stmts})) fragment.add_statements(domain_name, Switch(domain.rst, {1: stmts}))
@ -559,7 +559,7 @@ class _ControlInserter(FragmentTransformer):
class ResetInserter(_ControlInserter): class ResetInserter(_ControlInserter):
def _insert_control(self, fragment, domain, signals): def _insert_control(self, fragment, domain, signals):
stmts = [s.eq(Const(s.reset, s.width)) for s in signals if not s.reset_less] stmts = [s.eq(Const(s.init, s.width)) for s in signals if not s.reset_less]
fragment.add_statements(domain, Switch(self.controls[domain], {1: stmts}, src_loc=self.src_loc)) fragment.add_statements(domain, Switch(self.controls[domain], {1: stmts}, src_loc=self.src_loc))

View file

@ -1,3 +1,5 @@
import warnings
from .. import * from .. import *
@ -26,8 +28,8 @@ class FFSynchronizer(Elaboratable):
Signal connected to synchroniser output. Signal connected to synchroniser output.
o_domain : str o_domain : str
Name of output clock domain. Name of output clock domain.
reset : int init : int
Reset value of the flip-flops. On FPGAs, even if ``reset_less`` is ``True``, Initial and reset value of the flip-flops. On FPGAs, even if ``reset_less`` is ``True``,
the :class:`FFSynchronizer` is still set to this value during initialization. the :class:`FFSynchronizer` is still set to this value during initialization.
reset_less : bool reset_less : bool
If ``True`` (the default), this :class:`FFSynchronizer` is unaffected by ``o_domain`` If ``True`` (the default), this :class:`FFSynchronizer` is unaffected by ``o_domain``
@ -62,14 +64,24 @@ class FFSynchronizer(Elaboratable):
Define the ``get_ff_sync`` platform method to override the implementation of Define the ``get_ff_sync`` platform method to override the implementation of
:class:`FFSynchronizer`, e.g. to instantiate library cells directly. :class:`FFSynchronizer`, e.g. to instantiate library cells directly.
""" """
def __init__(self, i, o, *, o_domain="sync", reset=0, reset_less=True, stages=2, def __init__(self, i, o, *, o_domain="sync", init=None, reset=None, reset_less=True, stages=2,
max_input_delay=None): max_input_delay=None):
_check_stages(stages) _check_stages(stages)
self.i = i self.i = i
self.o = o self.o = o
self._reset = reset # TODO(amaranth-0.7): remove
if reset is not None:
if init is not None:
raise ValueError("Cannot specify both `reset` and `init`")
warnings.warn("`reset=` is deprecated, use `init=` instead",
DeprecationWarning, stacklevel=2)
init = reset
if init is None:
init = 0
self._init = init
self._reset_less = reset_less self._reset_less = reset_less
self._o_domain = o_domain self._o_domain = o_domain
self._stages = stages self._stages = stages
@ -87,7 +99,7 @@ class FFSynchronizer(Elaboratable):
m = Module() m = Module()
flops = [Signal(self.i.shape(), name=f"stage{index}", flops = [Signal(self.i.shape(), name=f"stage{index}",
reset=self._reset, reset_less=self._reset_less) init=self._init, reset_less=self._reset_less)
for index in range(self._stages)] for index in range(self._stages)]
for i, o in zip((self.i, *flops), flops): for i, o in zip((self.i, *flops), flops):
m.d[self._o_domain] += o.eq(i) m.d[self._o_domain] += o.eq(i)
@ -161,7 +173,7 @@ class AsyncFFSynchronizer(Elaboratable):
m = Module() m = Module()
m.domains += ClockDomain("async_ff", async_reset=True, local=True) m.domains += ClockDomain("async_ff", async_reset=True, local=True)
flops = [Signal(1, name=f"stage{index}", reset=1) flops = [Signal(1, name=f"stage{index}", init=1)
for index in range(self._stages)] for index in range(self._stages)]
for i, o in zip((0, *flops), flops): for i, o in zip((0, *flops), flops):
m.d.async_ff += o.eq(i) m.d.async_ff += o.eq(i)

View file

@ -383,7 +383,7 @@ class Processor(Elaboratable):
def elaborate(self, platform): def elaborate(self, platform):
m = Module() m = Module()
crc_reg = Signal(self._crc_width, reset=self._initial_crc.value) crc_reg = Signal(self._crc_width, init=self._initial_crc.value)
data_in = Signal(self._data_width) data_in = Signal(self._data_width)
# Optionally bit-reflect input words. # Optionally bit-reflect input words.

View file

@ -812,7 +812,7 @@ class _AggregateMeta(ShapeCastable, type):
cls = type.__new__(metacls, name, bases, namespace) cls = type.__new__(metacls, name, bases, namespace)
if cls.__layout_cls is UnionLayout: if cls.__layout_cls is UnionLayout:
if len(default) > 1: if len(default) > 1:
raise ValueError("Reset value for at most one field can be provided for " raise ValueError("Initial value for at most one field can be provided for "
"a union class (specified: {})" "a union class (specified: {})"
.format(", ".join(default.keys()))) .format(", ".join(default.keys())))
cls.__layout = cls.__layout_cls(layout) cls.__layout = cls.__layout_cls(layout)
@ -855,12 +855,12 @@ class Struct(View, metaclass=_AggregateMeta):
"""Structures defined with annotations. """Structures defined with annotations.
The :class:`Struct` base class is a subclass of :class:`View` that provides a concise way The :class:`Struct` base class is a subclass of :class:`View` that provides a concise way
to describe the structure layout and reset values for the fields using Python to describe the structure layout and initial values for the fields using Python
:term:`variable annotations <python:variable annotation>`. :term:`variable annotations <python:variable annotation>`.
Any annotations containing :ref:`shape-like <lang-shapelike>` objects are used, Any annotations containing :ref:`shape-like <lang-shapelike>` objects are used,
in the order in which they appear in the source code, to construct a :class:`StructLayout`. in the order in which they appear in the source code, to construct a :class:`StructLayout`.
The values assigned to such annotations are used to populate the reset value of the signal The values assigned to such annotations are used to populate the initial value of the signal
created by the view. Any other annotations are kept as-is. created by the view. Any other annotations are kept as-is.
.. testsetup:: .. testsetup::
@ -907,15 +907,15 @@ class Struct(View, metaclass=_AggregateMeta):
>>> flt.is_subnormal() >>> flt.is_subnormal()
(== (slice (sig flt) 23:31) (const 1'd0)) (== (slice (sig flt) 23:31) (const 1'd0))
The reset values for individual fields can be overridden during instantiation: The initial values for individual fields can be overridden during instantiation:
.. doctest:: .. doctest::
>>> hex(Signal(IEEE754Single).as_value().reset) >>> hex(Signal(IEEE754Single).as_value().init)
'0x3f800000' '0x3f800000'
>>> hex(Signal(IEEE754Single, reset={'sign': 1}).as_value().reset) >>> hex(Signal(IEEE754Single, init={'sign': 1}).as_value().init)
'0xbf800000' '0xbf800000'
>>> hex(Signal(IEEE754Single, reset={'exponent': 0}).as_value().reset) >>> hex(Signal(IEEE754Single, init={'exponent': 0}).as_value().init)
'0x0' '0x0'
Classes inheriting from :class:`Struct` can be used as base classes. The only restrictions Classes inheriting from :class:`Struct` can be used as base classes. The only restrictions
@ -964,8 +964,8 @@ class Union(View, metaclass=_AggregateMeta):
annotation>`. It is very similar to the :class:`Struct` class, except that its layout annotation>`. It is very similar to the :class:`Struct` class, except that its layout
is a :class:`UnionLayout`. is a :class:`UnionLayout`.
A :class:`Union` can have only one field with a specified reset value. If a reset value is A :class:`Union` can have only one field with a specified initial value. If an initial value is
explicitly provided during instantiation, it overrides the reset value specified with explicitly provided during instantiation, it overrides the initial value specified with
an annotation: an annotation:
.. testcode:: .. testcode::
@ -976,9 +976,9 @@ class Union(View, metaclass=_AggregateMeta):
.. doctest:: .. doctest::
>>> Signal(VarInt).as_value().reset >>> Signal(VarInt).as_value().init
256 256
>>> Signal(VarInt, reset={'int8': 10}).as_value().reset >>> Signal(VarInt, init={'int8': 10}).as_value().init
10 10
""" """
_AggregateMeta__layout_cls = UnionLayout _AggregateMeta__layout_cls = UnionLayout

View file

@ -165,8 +165,8 @@ class EnumMeta(ShapeCastable, py_enum.EnumMeta):
def const(cls, init): def const(cls, init):
# Same considerations apply as above. # Same considerations apply as above.
if init is None: if init is None:
# Signal with unspecified reset value passes ``None`` to :meth:`const`. # Signal with unspecified initial value passes ``None`` to :meth:`const`.
# Before RFC 9 was implemented, the unspecified reset value was 0, so this keeps # Before RFC 9 was implemented, the unspecified initial value was 0, so this keeps
# the old behavior intact. # the old behavior intact.
member = cls(0) member = cls(0)
else: else:

View file

@ -59,16 +59,23 @@ class Flow(enum.Enum):
return Out return Out
assert False # :nocov: assert False # :nocov:
def __call__(self, description, *, reset=None, src_loc_at=0): def __call__(self, description, *, init=None, reset=None, src_loc_at=0):
"""Create a :class:`Member` with this data flow and the provided description and """Create a :class:`Member` with this data flow and the provided description and
reset value. initial value.
Returns Returns
------- -------
:class:`Member` :class:`Member`
:py:`Member(self, description, reset=reset)` :py:`Member(self, description, init=init)`
""" """
return Member(self, description, reset=reset, src_loc_at=src_loc_at + 1) # TODO(amaranth-0.7): remove
if reset is not None:
if init is not None:
raise ValueError("Cannot specify both `reset` and `init`")
warnings.warn("`reset=` is deprecated, use `init=` instead",
DeprecationWarning, stacklevel=2)
init = reset
return Member(self, description, init=init, src_loc_at=src_loc_at + 1)
def __repr__(self): def __repr__(self):
return self.name return self.name
@ -98,17 +105,24 @@ class Member:
object (in which case it is created as a port member). After creation the :class:`Member` object (in which case it is created as a port member). After creation the :class:`Member`
instance cannot be modified. instance cannot be modified.
When a :class:`Signal` is created from a description of a port member, the signal's reset value When a :class:`Signal` is created from a description of a port member, the signal's initial value
is taken from the member description. If this signal is never explicitly assigned a value, it is taken from the member description. If this signal is never explicitly assigned a value, it
will equal ``reset``. will equal ``init``.
Although instances can be created directly, most often they will be created through Although instances can be created directly, most often they will be created through
:data:`In` and :data:`Out`, e.g. :py:`In(unsigned(1))` or :py:`Out(stream.Signature(RGBPixel))`. :data:`In` and :data:`Out`, e.g. :py:`In(unsigned(1))` or :py:`Out(stream.Signature(RGBPixel))`.
""" """
def __init__(self, flow, description, *, reset=None, _dimensions=(), src_loc_at=0): def __init__(self, flow, description, *, init=None, reset=None, _dimensions=(), src_loc_at=0):
# TODO(amaranth-0.7): remove
if reset is not None:
if init is not None:
raise ValueError("Cannot specify both `reset` and `init`")
warnings.warn("`reset=` is deprecated, use `init=` instead",
DeprecationWarning, stacklevel=2)
init = reset
self._flow = flow self._flow = flow
self._description = description self._description = description
self._reset = reset self._init = init
self._dimensions = _dimensions self._dimensions = _dimensions
self.src_loc = tracer.get_src_loc(src_loc_at=src_loc_at) self.src_loc = tracer.get_src_loc(src_loc_at=src_loc_at)
@ -121,23 +135,23 @@ class Member:
except TypeError as e: except TypeError as e:
raise TypeError(f"Port member description must be a shape-castable object or " raise TypeError(f"Port member description must be a shape-castable object or "
f"a signature, not {description!r}") from e f"a signature, not {description!r}") from e
# This mirrors the logic that handles Signal(reset=). # This mirrors the logic that handles Signal(init=).
# TODO: We need a simpler way to check for "is this a valid constant initializer" # TODO: We need a simpler way to check for "is this a valid constant initializer"
if issubclass(type(self._description), ShapeCastable): if issubclass(type(self._description), ShapeCastable):
try: try:
self._reset_as_const = Const.cast(self._description.const(self._reset)) self._init_as_const = Const.cast(self._description.const(self._init))
except Exception as e: except Exception as e:
raise TypeError(f"Port member reset value {self._reset!r} is not a valid " raise TypeError(f"Port member initial value {self._init!r} is not a valid "
f"constant initializer for {self._description}") from e f"constant initializer for {self._description}") from e
else: else:
try: try:
self._reset_as_const = Const.cast(reset or 0) self._init_as_const = Const.cast(init or 0)
except TypeError: except TypeError:
raise TypeError(f"Port member reset value {self._reset!r} is not a valid " raise TypeError(f"Port member initial value {self._init!r} is not a valid "
f"constant initializer for {shape}") f"constant initializer for {shape}")
if self.is_signature: if self.is_signature:
if self._reset is not None: if self._init is not None:
raise ValueError(f"A signature member cannot have a reset value") raise ValueError(f"A signature member cannot have an initial value")
def flip(self): def flip(self):
"""Flip the data flow of this member. """Flip the data flow of this member.
@ -148,7 +162,7 @@ class Member:
A new :py:`member` with :py:`member.flow` equal to :py:`self.flow.flip()`, and identical A new :py:`member` with :py:`member.flow` equal to :py:`self.flow.flip()`, and identical
to :py:`self` other than that. to :py:`self` other than that.
""" """
return Member(self._flow.flip(), self._description, reset=self._reset, return Member(self._flow.flip(), self._description, init=self._init,
_dimensions=self._dimensions) _dimensions=self._dimensions)
def array(self, *dimensions): def array(self, *dimensions):
@ -175,7 +189,7 @@ class Member:
if not (isinstance(dimension, int) and dimension >= 0): if not (isinstance(dimension, int) and dimension >= 0):
raise TypeError(f"Member array dimensions must be non-negative integers, " raise TypeError(f"Member array dimensions must be non-negative integers, "
f"not {dimension!r}") f"not {dimension!r}")
return Member(self._flow, self._description, reset=self._reset, return Member(self._flow, self._description, init=self._init,
_dimensions=(*dimensions, *self._dimensions)) _dimensions=(*dimensions, *self._dimensions))
@property @property
@ -231,13 +245,13 @@ class Member:
return self._description return self._description
@property @property
def reset(self): def init(self):
"""Reset value of a port member. """Initial value of a port member.
Returns Returns
------- -------
:ref:`const-castable object <lang-constcasting>` :ref:`const-castable object <lang-constcasting>`
The reset value that was provided when constructing this :class:`Member`. The initial value that was provided when constructing this :class:`Member`.
Raises Raises
------ ------
@ -245,8 +259,14 @@ class Member:
If :py:`self` describes a signature member. If :py:`self` describes a signature member.
""" """
if self.is_signature: if self.is_signature:
raise AttributeError(f"A signature member does not have a reset value") raise AttributeError(f"A signature member does not have an initial value")
return self._reset return self._init
@property
def reset(self):
warnings.warn("`Member.reset` is deprecated, use `Member.init` instead",
DeprecationWarning, stacklevel=2)
return self.init
@property @property
def signature(self): def signature(self):
@ -288,16 +308,16 @@ class Member:
return (type(other) is Member and return (type(other) is Member and
self._flow == other._flow and self._flow == other._flow and
self._description == other._description and self._description == other._description and
self._reset == other._reset and self._init == other._init and
self._dimensions == other._dimensions) self._dimensions == other._dimensions)
def __repr__(self): def __repr__(self):
reset_repr = dimensions_repr = "" init_repr = dimensions_repr = ""
if self._reset: if self._init:
reset_repr = f", reset={self._reset!r}" init_repr = f", init={self._init!r}"
if self._dimensions: if self._dimensions:
dimensions_repr = f".array({', '.join(map(str, self._dimensions))})" dimensions_repr = f".array({', '.join(map(str, self._dimensions))})"
return f"{self._flow!r}({self._description!r}{reset_repr}){dimensions_repr}" return f"{self._flow!r}({self._description!r}{init_repr}){dimensions_repr}"
@final @final
@ -470,7 +490,7 @@ class SignatureMembers(Mapping):
def create(self, *, path=None, src_loc_at=0): def create(self, *, path=None, src_loc_at=0):
"""Create members from their descriptions. """Create members from their descriptions.
For each port member, this function creates a :class:`Signal` with the shape and reset For each port member, this function creates a :class:`Signal` with the shape and initial
value taken from the member description, and the name constructed from value taken from the member description, and the name constructed from
the :ref:`paths <wiring-path>` to the member (by concatenating path items with a double the :ref:`paths <wiring-path>` to the member (by concatenating path items with a double
underscore, ``__``). underscore, ``__``).
@ -497,7 +517,7 @@ class SignatureMembers(Mapping):
# Ideally we would keep both source locations here, but the .src_loc attribute # Ideally we would keep both source locations here, but the .src_loc attribute
# data structure doesn't currently support that, so keep the more important one: # data structure doesn't currently support that, so keep the more important one:
# the one with the name of the signal (the `In()`/`Out()` call site.) # the one with the name of the signal (the `In()`/`Out()` call site.)
signal = Signal(member.shape, reset=member.reset, src_loc_at=1 + src_loc_at, signal = Signal(member.shape, init=member.init, src_loc_at=1 + src_loc_at,
name="__".join(str(item) for item in path)) name="__".join(str(item) for item in path))
signal.src_loc = member.src_loc signal.src_loc = member.src_loc
return signal return signal
@ -775,7 +795,7 @@ class Signature(metaclass=SignatureMeta):
def iter_member(value, *, path): def iter_member(value, *, path):
if member.is_port: if member.is_port:
yield path, Member(member.flow, member.shape, reset=member.reset), value yield path, Member(member.flow, member.shape, init=member.init), value
elif member.is_signature: elif member.is_signature:
for sub_path, sub_member, sub_value in member.signature.flatten(value): for sub_path, sub_member, sub_value in member.signature.flatten(value):
if member.flow == In: if member.flow == In:
@ -816,7 +836,7 @@ class Signature(metaclass=SignatureMeta):
* for port members, is a :ref:`value-like <lang-valuelike>` object casting to * for port members, is a :ref:`value-like <lang-valuelike>` object casting to
a :class:`Signal` or a :class:`Const` whose width and signedness is the same as that a :class:`Signal` or a :class:`Const` whose width and signedness is the same as that
of the member, and (in case of a :class:`Signal`) which is not reset-less and whose of the member, and (in case of a :class:`Signal`) which is not reset-less and whose
reset value is that of the member; initial value is that of the member;
* for signature members, matches the description in the signature as verified by * for signature members, matches the description in the signature as verified by
:meth:`Signature.is_compliant`. :meth:`Signature.is_compliant`.
@ -878,11 +898,11 @@ class Signature(metaclass=SignatureMeta):
f"the shape {_format_shape(attr_shape)}") f"the shape {_format_shape(attr_shape)}")
return False return False
if isinstance(attr_value_cast, Signal): if isinstance(attr_value_cast, Signal):
if attr_value_cast.reset != member._reset_as_const.value: if attr_value_cast.init != member._init_as_const.value:
if reasons is not None: if reasons is not None:
reasons.append(f"{_format_path(path)} is expected to have " reasons.append(f"{_format_path(path)} is expected to have "
f"the reset value {member.reset!r}, but it has " f"the initial value {member.init!r}, but it has "
f"the reset value {attr_value_cast.reset!r}") f"the initial value {attr_value_cast.init!r}")
return False return False
if attr_value_cast.reset_less: if attr_value_cast.reset_less:
if reasons is not None: if reasons is not None:
@ -1343,7 +1363,7 @@ def connect(m, *args, **kwargs):
* Every interface object must have the same set of port members, and they must have the same * Every interface object must have the same set of port members, and they must have the same
:meth:`dimensions <Member.dimensions>`. :meth:`dimensions <Member.dimensions>`.
* For each path, the port members of every interface object must have the same width and reset * For each path, the port members of every interface object must have the same width and initial
value (for port members corresponding to signals) or constant value (for port members value (for port members corresponding to signals) or constant value (for port members
corresponding to constants). Signedness may differ. corresponding to constants). Signedness may differ.
* For each path, at most one interface object must have the corresponding port member be * For each path, at most one interface object must have the corresponding port member be
@ -1486,8 +1506,8 @@ def connect(m, *args, **kwargs):
is_first = False is_first = False
first_path = path first_path = path
first_member_shape = member.shape first_member_shape = member.shape
first_member_reset = member.reset first_member_init = member.init
first_member_reset_as_const = member._reset_as_const first_member_init_as_const = member._init_as_const
continue continue
if Shape.cast(first_member_shape).width != Shape.cast(member_shape).width: if Shape.cast(first_member_shape).width != Shape.cast(member_shape).width:
raise ConnectionError( raise ConnectionError(
@ -1496,13 +1516,13 @@ def connect(m, *args, **kwargs):
f"shape {_format_shape(member_shape)} because the shape widths " f"shape {_format_shape(member_shape)} because the shape widths "
f"({Shape.cast(first_member_shape).width} and " f"({Shape.cast(first_member_shape).width} and "
f"{Shape.cast(member_shape).width}) do not match") f"{Shape.cast(member_shape).width}) do not match")
if first_member_reset_as_const.value != member._reset_as_const.value: if first_member_init_as_const.value != member._init_as_const.value:
raise ConnectionError( raise ConnectionError(
f"Cannot connect together the member {_format_path(first_path)} with reset " f"Cannot connect together the member {_format_path(first_path)} with initial "
f"value {first_member_reset!r} and the member {_format_path(path)} with reset " f"value {first_member_init!r} and the member {_format_path(path)} with initial "
f"value {member.reset} because the reset values do not match") f"value {member.init} because the initial values do not match")
# If there are no Out members, there is nothing to connect. The In members, while not # If there are no Out members, there is nothing to connect. The In members, while not
# explicitly connected, will stay at the same value since we ensured their reset values # explicitly connected, will stay at the same value since we ensured their initial values
# are all identical. # are all identical.
if len(out_kind) == 0: if len(out_kind) == 0:
continue continue

View file

@ -436,7 +436,7 @@ class _FragmentCompiler:
if domain_name == "comb": if domain_name == "comb":
for signal in domain_signals: for signal in domain_signals:
signal_index = self.state.get_signal(signal) signal_index = self.state.get_signal(signal)
emitter.append(f"next_{signal_index} = {signal.reset}") emitter.append(f"next_{signal_index} = {signal.init}")
inputs = SignalSet() inputs = SignalSet()
_StatementCompiler(self.state, emitter, inputs=inputs)(domain_stmts) _StatementCompiler(self.state, emitter, inputs=inputs)(domain_stmts)

View file

@ -83,7 +83,7 @@ class Simulator:
def add_process(self, process): def add_process(self, process):
process = self._check_process(process) process = self._check_process(process)
def wrapper(): def wrapper():
# Only start a bench process after comb settling, so that the reset values are correct. # Only start a bench process after comb settling, so that the initial values are correct.
yield object.__new__(Settle) yield object.__new__(Settle)
yield from process() yield from process()
self._engine.add_coroutine_process(wrapper, default_cmd=None) self._engine.add_coroutine_process(wrapper, default_cmd=None)
@ -188,7 +188,7 @@ class Simulator:
if phase is None: if phase is None:
# By default, delay the first edge by half period. This causes any synchronous activity # By default, delay the first edge by half period. This causes any synchronous activity
# to happen at a non-zero time, distinguishing it from the reset values in the waveform # to happen at a non-zero time, distinguishing it from the initial values in the waveform
# viewer. # viewer.
phase = period // 2 phase = period // 2
else: else:
@ -199,7 +199,7 @@ class Simulator:
def reset(self): def reset(self):
"""Reset the simulation. """Reset the simulation.
Assign the reset value to every signal in the simulation, and restart every user process. Assign the initial value to every signal and memory in the simulation, and restart every user process.
""" """
self._engine.reset() self._engine.reset()

View file

@ -99,7 +99,7 @@ class _VCDWriter:
self.vcd_signal_vars[signal] = [] self.vcd_signal_vars[signal] = []
self.gtkw_signal_names[signal] = [] self.gtkw_signal_names[signal] = []
for repr in signal._value_repr: for repr in signal._value_repr:
var_init = self.eval_field(repr.value, signal, signal.reset) var_init = self.eval_field(repr.value, signal, signal.init)
if isinstance(repr.format, FormatInt): if isinstance(repr.format, FormatInt):
var_type = "wire" var_type = "wire"
var_size = repr.value.shape().width var_size = repr.value.shape().width
@ -250,7 +250,7 @@ class _PySignalState(BaseSignalState):
self.signal = signal self.signal = signal
self.pending = pending self.pending = pending
self.waiters = {} self.waiters = {}
self.curr = self.next = signal.reset self.curr = self.next = signal.init
def set(self, value): def set(self, value):
if self.next == value: if self.next == value:
@ -342,7 +342,7 @@ class _PySimulation(BaseSimulation):
for signal, index in self.signals.items(): for signal, index in self.signals.items():
state = self.slots[index] state = self.slots[index]
assert isinstance(state, _PySignalState) assert isinstance(state, _PySignalState)
state.curr = state.next = signal.reset state.curr = state.next = signal.init
for index in self.memories.values(): for index in self.memories.values():
state = self.slots[index] state = self.slots[index]
assert isinstance(state, _PyMemoryState) assert isinstance(state, _PyMemoryState)

View file

@ -1174,7 +1174,7 @@ class XilinxPlatform(TemplatedPlatform):
def get_ff_sync(self, ff_sync): def get_ff_sync(self, ff_sync):
m = Module() m = Module()
flops = [Signal(ff_sync.i.shape(), name=f"stage{index}", flops = [Signal(ff_sync.i.shape(), name=f"stage{index}",
reset=ff_sync._reset, reset_less=ff_sync._reset_less, init=ff_sync._reset, reset_less=ff_sync._reset_less,
attrs={"ASYNC_REG": "TRUE"}) attrs={"ASYNC_REG": "TRUE"})
for index in range(ff_sync._stages)] for index in range(ff_sync._stages)]
if self.toolchain == "Vivado": if self.toolchain == "Vivado":

View file

@ -29,6 +29,7 @@ Apply the following changes to code written against Amaranth 0.4 to migrate it t
* Replace uses of ``Value.matches()`` with no patterns with ``Const(1)`` * Replace uses of ``Value.matches()`` with no patterns with ``Const(1)``
* Update uses of ``amaranth.utils.log2_int(need_pow2=False)`` to :func:`amaranth.utils.ceil_log2` * Update uses of ``amaranth.utils.log2_int(need_pow2=False)`` to :func:`amaranth.utils.ceil_log2`
* Update uses of ``amaranth.utils.log2_int(need_pow2=True)`` to :func:`amaranth.utils.exact_log2` * Update uses of ``amaranth.utils.log2_int(need_pow2=True)`` to :func:`amaranth.utils.exact_log2`
* Update uses of ``reset=`` keyword argument to ``init=``
* Convert uses of ``Simulator.add_sync_process`` used as testbenches to ``Simulator.add_testbench`` * 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`` * Convert other uses of ``Simulator.add_sync_process`` to ``Simulator.add_process``
@ -39,11 +40,13 @@ Implemented RFCs
.. _RFC 17: https://amaranth-lang.org/rfcs/0017-remove-log2-int.html .. _RFC 17: https://amaranth-lang.org/rfcs/0017-remove-log2-int.html
.. _RFC 27: https://amaranth-lang.org/rfcs/0027-simulator-testbenches.html .. _RFC 27: https://amaranth-lang.org/rfcs/0027-simulator-testbenches.html
.. _RFC 39: https://amaranth-lang.org/rfcs/0039-empty-case.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 46: https://amaranth-lang.org/rfcs/0046-shape-range-1.html .. _RFC 46: https://amaranth-lang.org/rfcs/0046-shape-range-1.html
* `RFC 17`_: Remove ``log2_int`` * `RFC 17`_: Remove ``log2_int``
* `RFC 27`_: Testbench processes for the simulator * `RFC 27`_: Testbench processes for the simulator
* `RFC 39`_: Change semantics of no-argument ``m.Case()`` * `RFC 39`_: Change semantics of no-argument ``m.Case()``
* `RFC 43`_: Rename ``reset=`` to ``init=``
* `RFC 46`_: Change ``Shape.cast(range(1))`` to ``unsigned(0)`` * `RFC 46`_: Change ``Shape.cast(range(1))`` to ``unsigned(0)``
@ -56,9 +59,10 @@ Language changes
* Added: :func:`amaranth.utils.ceil_log2`, :func:`amaranth.utils.exact_log2`. (`RFC 17`_) * Added: :func:`amaranth.utils.ceil_log2`, :func:`amaranth.utils.exact_log2`. (`RFC 17`_)
* Changed: ``m.Case()`` with no patterns is never active instead of always active. (`RFC 39`_) * Changed: ``m.Case()`` with no patterns is never active instead of always active. (`RFC 39`_)
* Changed: ``Value.matches()`` with no patterns is ``Const(0)`` instead of ``Const(1)``. (`RFC 39`_) * Changed: ``Value.matches()`` with no patterns is ``Const(0)`` instead of ``Const(1)``. (`RFC 39`_)
* Changed: ``Signal(range(stop), reset=stop)`` warning has been changed into a hard error and made to trigger on any out-of range value. * Changed: ``Signal(range(stop), init=stop)`` warning has been changed into a hard error and made to trigger on any out-of range value.
* Changed: ``Signal(range(0))`` is now valid without a warning. * Changed: ``Signal(range(0))`` is now valid without a warning.
* Changed: ``Shape.cast(range(1))`` is now ``unsigned(0)``. (`RFC 46`_) * Changed: ``Shape.cast(range(1))`` is now ``unsigned(0)``. (`RFC 46`_)
* 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`_)
* Deprecated: :func:`amaranth.utils.log2_int`. (`RFC 17`_) * Deprecated: :func:`amaranth.utils.log2_int`. (`RFC 17`_)
* Removed: (deprecated in 0.4) :meth:`Const.normalize`. (`RFC 5`_) * 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:`Repl`. (`RFC 10`_)

View file

@ -407,19 +407,17 @@ The names do not need to be unique; if two signals with the same name end up in
Initial signal values Initial signal values
--------------------- ---------------------
Each signal has an *initial value*, specified with the ``reset=`` parameter. If the initial value is not specified explicitly, zero is used by default. An initial value can be specified with an integer or an enumeration member. Each signal has an *initial value*, specified with the ``init=`` parameter. If the initial value is not specified explicitly, zero is used by default. An initial value can be specified with an integer or an enumeration member.
Signals :ref:`assigned <lang-assigns>` in a :ref:`combinatorial <lang-comb>` domain assume their initial value when none of the assignments are :ref:`active <lang-active>`. Signals assigned in a :ref:`synchronous <lang-sync>` domain assume their initial value after *power-on reset* and, unless the signal is :ref:`reset-less <lang-resetless>`, *explicit reset*. Signals that are used but never assigned are equivalent to constants of their initial value. Signals :ref:`assigned <lang-assigns>` in a :ref:`combinatorial <lang-comb>` domain assume their initial value when none of the assignments are :ref:`active <lang-active>`. Signals assigned in a :ref:`synchronous <lang-sync>` domain assume their initial value after *power-on reset* and, unless the signal is :ref:`reset-less <lang-resetless>`, *explicit reset*. Signals that are used but never assigned are equivalent to constants of their initial value.
.. TODO: using "reset" for "initial value" is awful, let's rename it to "init"
.. doctest:: .. doctest::
>>> Signal(4).reset >>> Signal(4).init
0 0
>>> Signal(4, reset=5).reset >>> Signal(4, init=5).init
5 5
>>> Signal(Direction, reset=Direction.LEFT).reset >>> Signal(Direction, init=Direction.LEFT).init
1 1
@ -467,7 +465,7 @@ In contrast, code written in the Amaranth language *describes* computations on a
.. doctest:: .. doctest::
>>> a = Signal(8, reset=5) >>> a = Signal(8, init=5)
>>> a + 1 >>> a + 1
(+ (sig a) (const 1'd1)) (+ (sig a) (const 1'd1))
@ -1190,11 +1188,11 @@ Simple `finite state machines <https://en.wikipedia.org/wiki/Finite-state_machin
.. TODO: FSM() should require keyword arguments, for good measure .. TODO: FSM() should require keyword arguments, for good measure
The reset state of the FSM can be provided when defining it using the :py:`with m.FSM(reset="Name"):` argument. If not provided, it is the first state in the order of definition. For example, this definition is equivalent to the one at the beginning of this section: The initial (and reset) state of the FSM can be provided when defining it using the :py:`with m.FSM(init="Name"):` argument. If not provided, it is the first state in the order of definition. For example, this definition is equivalent to the one at the beginning of this section:
.. testcode:: .. testcode::
with m.FSM(reset="Set Address"): with m.FSM(init="Set Address"):
... ...
The FSM belongs to a :ref:`clock domain <lang-domains>`, which is specified using the :py:`with m.FSM(domain="dom")` argument. If not specified, it is the ``sync`` domain. For example, this definition is equivalent to the one at the beginning of this section: The FSM belongs to a :ref:`clock domain <lang-domains>`, which is specified using the :py:`with m.FSM(domain="dom")` argument. If not specified, it is the ``sync`` domain. For example, this definition is equivalent to the one at the beginning of this section:
@ -1255,7 +1253,7 @@ Consider the following code:
.. testcode:: .. testcode::
a = Signal(8, reset=1) a = Signal(8, init=1)
with m.If(en): with m.If(en):
m.d.comb += a.eq(b + 1) m.d.comb += a.eq(b + 1)
@ -1534,7 +1532,7 @@ The application of control flow modifiers in it causes the behavior of the final
with m.If(en): with m.If(en):
m.d.sync += n.eq(n + 1) m.d.sync += n.eq(n + 1)
with m.If(rst): with m.If(rst):
m.d.sync += n.eq(n.reset) m.d.sync += n.eq(n.init)
m.d.comb += z.eq(n == 0) m.d.comb += z.eq(n == 0)
.. tip:: .. tip::

View file

@ -555,7 +555,7 @@ Signatures
.. autodata:: Out .. autodata:: Out
.. autodata:: In .. autodata:: In
.. autoclass:: Member(flow, description, *, reset=None) .. autoclass:: Member(flow, description, *, init=None)
.. autoexception:: SignatureError .. autoexception:: SignatureError

View file

@ -4,7 +4,7 @@ from amaranth.cli import main
class Counter(Elaboratable): class Counter(Elaboratable):
def __init__(self, width): def __init__(self, width):
self.v = Signal(width, reset=2**width-1) self.v = Signal(width, init=2**width-1)
self.o = Signal() self.o = Signal()
def elaborate(self, platform): def elaborate(self, platform):

View file

@ -5,7 +5,7 @@ from amaranth.back import verilog
class Counter(Elaboratable): class Counter(Elaboratable):
def __init__(self, width): def __init__(self, width):
self.v = Signal(width, reset=2**width-1) self.v = Signal(width, init=2**width-1)
self.o = Signal() self.o = Signal()
self.en = Signal() self.en = Signal()

View file

@ -7,7 +7,7 @@ cd_por = ClockDomain(reset_less=True)
cd_sync = ClockDomain() cd_sync = ClockDomain()
m.domains += cd_por, cd_sync m.domains += cd_por, cd_sync
delay = Signal(range(256), reset=255) delay = Signal(range(256), init=255)
with m.If(delay != 0): with m.If(delay != 0):
m.d.por += delay.eq(delay - 1) m.d.por += delay.eq(delay - 1)
m.d.comb += [ m.d.comb += [

View file

@ -32,7 +32,7 @@ class UART(Elaboratable):
m = Module() m = Module()
tx_phase = Signal(range(self.divisor)) tx_phase = Signal(range(self.divisor))
tx_shreg = Signal(1 + self.data_bits + 1, reset=-1) tx_shreg = Signal(1 + self.data_bits + 1, init=-1)
tx_count = Signal(range(len(tx_shreg) + 1)) tx_count = Signal(range(len(tx_shreg) + 1))
m.d.comb += self.tx_o.eq(tx_shreg[0]) m.d.comb += self.tx_o.eq(tx_shreg[0])
@ -55,7 +55,7 @@ class UART(Elaboratable):
] ]
rx_phase = Signal(range(self.divisor)) rx_phase = Signal(range(self.divisor))
rx_shreg = Signal(1 + self.data_bits + 1, reset=-1) rx_shreg = Signal(1 + self.data_bits + 1, init=-1)
rx_count = Signal(range(len(rx_shreg) + 1)) rx_count = Signal(range(len(rx_shreg) + 1))
m.d.comb += self.rx_data.eq(rx_shreg[1:-1]) m.d.comb += self.rx_data.eq(rx_shreg[1:-1])

View file

@ -1140,24 +1140,26 @@ class SignalTestCase(FHDLTestCase):
s2 = Signal(name="sig") s2 = Signal(name="sig")
self.assertEqual(s2.name, "sig") self.assertEqual(s2.name, "sig")
def test_reset(self): def test_init(self):
s1 = Signal(4, reset=0b111, reset_less=True) s1 = Signal(4, init=0b111, reset_less=True)
self.assertEqual(s1.reset, 0b111) self.assertEqual(s1.init, 0b111)
self.assertEqual(s1.reset_less, True) self.assertEqual(s1.reset_less, True)
s2 = Signal.like(s1, init=0b011)
self.assertEqual(s2.init, 0b011)
def test_reset_enum(self): def test_init_enum(self):
s1 = Signal(2, reset=UnsignedEnum.BAR) s1 = Signal(2, init=UnsignedEnum.BAR)
self.assertEqual(s1.reset, 2) self.assertEqual(s1.init, 2)
with self.assertRaisesRegex(TypeError, with self.assertRaisesRegex(TypeError,
r"^Reset value must be a constant-castable expression, " r"^Initial value must be a constant-castable expression, "
r"not <StringEnum\.FOO: 'a'>$"): r"not <StringEnum\.FOO: 'a'>$"):
Signal(1, reset=StringEnum.FOO) Signal(1, init=StringEnum.FOO)
def test_reset_const_castable(self): def test_init_const_castable(self):
s1 = Signal(4, reset=Cat(Const(0, 1), Const(1, 1), Const(0, 2))) s1 = Signal(4, init=Cat(Const(0, 1), Const(1, 1), Const(0, 2)))
self.assertEqual(s1.reset, 2) self.assertEqual(s1.init, 2)
def test_reset_shape_castable_const(self): def test_init_shape_castable_const(self):
class CastableFromHex(ShapeCastable): class CastableFromHex(ShapeCastable):
def as_shape(self): def as_shape(self):
return unsigned(8) return unsigned(8)
@ -1168,54 +1170,80 @@ class SignalTestCase(FHDLTestCase):
def const(self, init): def const(self, init):
return int(init, 16) return int(init, 16)
s1 = Signal(CastableFromHex(), reset="aa") s1 = Signal(CastableFromHex(), init="aa")
self.assertEqual(s1.reset, 0xaa) self.assertEqual(s1.init, 0xaa)
with self.assertRaisesRegex(ValueError, with self.assertRaisesRegex(ValueError,
r"^Constant returned by <.+?CastableFromHex.+?>\.const\(\) must have the shape " r"^Constant returned by <.+?CastableFromHex.+?>\.const\(\) must have the shape "
r"that it casts to, unsigned\(8\), and not unsigned\(1\)$"): r"that it casts to, unsigned\(8\), and not unsigned\(1\)$"):
Signal(CastableFromHex(), reset="01") Signal(CastableFromHex(), init="01")
def test_reset_shape_castable_enum_wrong(self): def test_init_shape_castable_enum_wrong(self):
class EnumA(AmaranthEnum, shape=1): class EnumA(AmaranthEnum, shape=1):
X = 1 X = 1
with self.assertRaisesRegex(TypeError, with self.assertRaisesRegex(TypeError,
r"^Reset value must be a constant initializer of <enum 'EnumA'>$"): r"^Initial value must be a constant initializer of <enum 'EnumA'>$"):
Signal(EnumA) # implied reset=0 Signal(EnumA) # implied init=0
def test_reset_signed_mismatch(self): def test_init_signed_mismatch(self):
with self.assertWarnsRegex(SyntaxWarning, with self.assertWarnsRegex(SyntaxWarning,
r"^Reset value -2 is signed, but the signal shape is unsigned\(2\)$"): r"^Initial value -2 is signed, but the signal shape is unsigned\(2\)$"):
Signal(unsigned(2), reset=-2) Signal(unsigned(2), init=-2)
def test_reset_wrong_too_wide(self): def test_init_wrong_too_wide(self):
with self.assertWarnsRegex(SyntaxWarning, with self.assertWarnsRegex(SyntaxWarning,
r"^Reset value 2 will be truncated to the signal shape unsigned\(1\)$"): r"^Initial value 2 will be truncated to the signal shape unsigned\(1\)$"):
Signal(unsigned(1), reset=2) Signal(unsigned(1), init=2)
with self.assertWarnsRegex(SyntaxWarning, with self.assertWarnsRegex(SyntaxWarning,
r"^Reset value 1 will be truncated to the signal shape signed\(1\)$"): r"^Initial value 1 will be truncated to the signal shape signed\(1\)$"):
Signal(signed(1), reset=1) Signal(signed(1), init=1)
with self.assertWarnsRegex(SyntaxWarning, with self.assertWarnsRegex(SyntaxWarning,
r"^Reset value -2 will be truncated to the signal shape signed\(1\)$"): r"^Initial value -2 will be truncated to the signal shape signed\(1\)$"):
Signal(signed(1), reset=-2) Signal(signed(1), init=-2)
def test_reset_wrong_fencepost(self): def test_init_wrong_fencepost(self):
with self.assertRaisesRegex(SyntaxError, with self.assertRaisesRegex(SyntaxError,
r"^Reset value 10 equals the non-inclusive end of the signal shape " r"^Initial value 10 equals the non-inclusive end of the signal shape "
r"range\(0, 10\); this is likely an off-by-one error$"): r"range\(0, 10\); this is likely an off-by-one error$"):
Signal(range(0, 10), reset=10) Signal(range(0, 10), init=10)
with self.assertRaisesRegex(SyntaxError, with self.assertRaisesRegex(SyntaxError,
r"^Reset value 0 equals the non-inclusive end of the signal shape " r"^Initial value 0 equals the non-inclusive end of the signal shape "
r"range\(0, 0\); this is likely an off-by-one error$"): r"range\(0, 0\); this is likely an off-by-one error$"):
Signal(range(0), reset=0) Signal(range(0), init=0)
def test_reset_wrong_range(self): def test_init_wrong_range(self):
with self.assertRaisesRegex(SyntaxError, with self.assertRaisesRegex(SyntaxError,
r"^Reset value 11 is not within the signal shape range\(0, 10\)$"): r"^Initial value 11 is not within the signal shape range\(0, 10\)$"):
Signal(range(0, 10), reset=11) Signal(range(0, 10), init=11)
with self.assertRaisesRegex(SyntaxError, with self.assertRaisesRegex(SyntaxError,
r"^Reset value 0 is not within the signal shape range\(1, 10\)$"): r"^Initial value 0 is not within the signal shape range\(1, 10\)$"):
Signal(range(1, 10), reset=0) Signal(range(1, 10), init=0)
def test_reset(self):
with self.assertWarnsRegex(DeprecationWarning,
r"^`reset=` is deprecated, use `init=` instead$"):
s1 = Signal(4, reset=0b111)
self.assertEqual(s1.init, 0b111)
with self.assertWarnsRegex(DeprecationWarning,
r"^`Signal.reset` is deprecated, use `Signal.init` instead$"):
self.assertEqual(s1.reset, 0b111)
with self.assertWarnsRegex(DeprecationWarning,
r"^`Signal.reset` is deprecated, use `Signal.init` instead$"):
s1.reset = 0b010
self.assertEqual(s1.init, 0b010)
with self.assertWarnsRegex(DeprecationWarning,
r"^`reset=` is deprecated, use `init=` instead$"):
s2 = Signal.like(s1, reset=3)
self.assertEqual(s2.init, 3)
def test_reset_wrong(self):
with self.assertRaisesRegex(ValueError,
r"^Cannot specify both `reset` and `init`$"):
Signal(4, reset=1, init=1)
s1 = Signal(4)
with self.assertRaisesRegex(ValueError,
r"^Cannot specify both `reset` and `init`$"):
Signal.like(s1, reset=1, init=1)
def test_attrs(self): def test_attrs(self):
s1 = Signal() s1 = Signal()
@ -1232,8 +1260,8 @@ class SignalTestCase(FHDLTestCase):
self.assertEqual(s1.shape(), unsigned(4)) self.assertEqual(s1.shape(), unsigned(4))
s2 = Signal.like(Signal(range(-15, 1))) s2 = Signal.like(Signal(range(-15, 1)))
self.assertEqual(s2.shape(), signed(5)) self.assertEqual(s2.shape(), signed(5))
s3 = Signal.like(Signal(4, reset=0b111, reset_less=True)) s3 = Signal.like(Signal(4, init=0b111, reset_less=True))
self.assertEqual(s3.reset, 0b111) self.assertEqual(s3.init, 0b111)
self.assertEqual(s3.reset_less, True) self.assertEqual(s3.reset_less, True)
s4 = Signal.like(Signal(attrs={"no_retiming": True})) s4 = Signal.like(Signal(attrs={"no_retiming": True}))
self.assertEqual(s4.attrs, {"no_retiming": True}) self.assertEqual(s4.attrs, {"no_retiming": True})

View file

@ -451,7 +451,7 @@ class DSLTestCase(FHDLTestCase):
RED = 1 RED = 1
BLUE = 2 BLUE = 2
m = Module() m = Module()
se = Signal(Color, reset=Color.RED) se = Signal(Color, init=Color.RED)
with m.Switch(se): with m.Switch(se):
with m.Case(Color.RED): with m.Case(Color.RED):
m.d.comb += self.c1.eq(1) m.d.comb += self.c1.eq(1)
@ -638,10 +638,10 @@ class DSLTestCase(FHDLTestCase):
1: "SECOND" 1: "SECOND"
})) }))
def test_FSM_reset(self): def test_FSM_init(self):
a = Signal() a = Signal()
m = Module() m = Module()
with m.FSM(reset="SECOND"): with m.FSM(init="SECOND"):
with m.State("FIRST"): with m.State("FIRST"):
m.d.comb += a.eq(0) m.d.comb += a.eq(0)
m.next = "SECOND" m.next = "SECOND"
@ -670,6 +670,55 @@ class DSLTestCase(FHDLTestCase):
) )
) )
""") """)
self.assertEqual(m._generated["fsm"].state.init, 1)
def test_FSM_reset(self):
a = Signal()
m = Module()
with self.assertWarnsRegex(DeprecationWarning,
r"^`reset=` is deprecated, use `init=` instead$"):
with m.FSM(reset="SECOND"):
with m.State("FIRST"):
m.d.comb += a.eq(0)
m.next = "SECOND"
with m.State("SECOND"):
m.next = "FIRST"
m._flush()
self.assertRepr(m._statements["comb"], """
(
(switch (sig fsm_state)
(case 0
(eq (sig a) (const 1'd0))
)
(case 1 )
)
)
""")
self.assertRepr(m._statements["sync"], """
(
(switch (sig fsm_state)
(case 0
(eq (sig fsm_state) (const 1'd1))
)
(case 1
(eq (sig fsm_state) (const 1'd0))
)
)
)
""")
self.assertEqual(m._generated["fsm"].state.init, 1)
def test_FSM_reset_wrong(self):
a = Signal()
m = Module()
with self.assertRaisesRegex(ValueError,
r"^Cannot specify both `reset` and `init`$"):
with m.FSM(reset="SECOND", init="SECOND"):
with m.State("FIRST"):
m.d.comb += a.eq(0)
m.next = "SECOND"
with m.State("SECOND"):
m.next = "FIRST"
def test_FSM_ongoing(self): def test_FSM_ongoing(self):
a = Signal() a = Signal()
@ -683,7 +732,7 @@ class DSLTestCase(FHDLTestCase):
with m.State("SECOND"): with m.State("SECOND"):
pass pass
m._flush() m._flush()
self.assertEqual(m._generated["fsm"].state.reset, 1) self.assertEqual(m._generated["fsm"].state.init, 1)
self.maxDiff = 10000 self.maxDiff = 10000
self.assertRepr(m._statements["comb"], """ self.assertRepr(m._statements["comb"], """
( (

View file

@ -59,7 +59,7 @@ class MemoryTestCase(FHDLTestCase):
self.assertEqual(len(rdport.data), 8) self.assertEqual(len(rdport.data), 8)
self.assertEqual(len(rdport.en), 1) self.assertEqual(len(rdport.en), 1)
self.assertIsInstance(rdport.en, Signal) self.assertIsInstance(rdport.en, Signal)
self.assertEqual(rdport.en.reset, 1) self.assertEqual(rdport.en.init, 1)
def test_read_port_non_transparent(self): def test_read_port_non_transparent(self):
mem = Memory(width=8, depth=4) mem = Memory(width=8, depth=4)
@ -69,7 +69,7 @@ class MemoryTestCase(FHDLTestCase):
self.assertEqual(rdport.transparent, False) self.assertEqual(rdport.transparent, False)
self.assertEqual(len(rdport.en), 1) self.assertEqual(len(rdport.en), 1)
self.assertIsInstance(rdport.en, Signal) self.assertIsInstance(rdport.en, Signal)
self.assertEqual(rdport.en.reset, 1) self.assertEqual(rdport.en.init, 1)
def test_read_port_asynchronous(self): def test_read_port_asynchronous(self):
mem = Memory(width=8, depth=4) mem = Memory(width=8, depth=4)

View file

@ -199,11 +199,11 @@ class RecordTestCase(FHDLTestCase):
self.assertEqual(r1.a.name, "r1__a") self.assertEqual(r1.a.name, "r1__a")
self.assertEqual(r1.b.name, "r1__b") self.assertEqual(r1.b.name, "r1__b")
self.assertEqual(r1.b.s.name, "r1__b__s") self.assertEqual(r1.b.s.name, "r1__b__s")
r1.a.reset = 1 r1.a.init = 1
r1.b.s.reset = 1 r1.b.s.init = 1
r2 = Record.like(r1) r2 = Record.like(r1)
self.assertEqual(r2.a.reset, 1) self.assertEqual(r2.a.init, 1)
self.assertEqual(r2.b.s.reset, 1) self.assertEqual(r2.b.s.init, 1)
self.assertEqual(r2.a.name, "r2__a") self.assertEqual(r2.a.name, "r2__a")
self.assertEqual(r2.b.name, "r2__b") self.assertEqual(r2.b.name, "r2__b")
self.assertEqual(r2.b.s.name, "r2__b__s") self.assertEqual(r2.b.s.name, "r2__b__s")

View file

@ -247,8 +247,8 @@ class DomainLowererTestCase(FHDLTestCase):
class ResetInserterTestCase(FHDLTestCase): class ResetInserterTestCase(FHDLTestCase):
def setUp(self): def setUp(self):
self.s1 = Signal() self.s1 = Signal()
self.s2 = Signal(reset=1) self.s2 = Signal(init=1)
self.s3 = Signal(reset=1, reset_less=True) self.s3 = Signal(init=1, reset_less=True)
self.c1 = Signal() self.c1 = Signal()
def test_reset_default(self): def test_reset_default(self):

View file

@ -35,10 +35,10 @@ class FFSynchronizerTestCase(FHDLTestCase):
sim.add_process(process) sim.add_process(process)
sim.run() sim.run()
def test_reset_value(self): def test_init_value(self):
i = Signal(reset=1) i = Signal(init=1)
o = Signal() o = Signal()
frag = FFSynchronizer(i, o, reset=1) frag = FFSynchronizer(i, o, init=1)
sim = Simulator(frag) sim = Simulator(frag)
sim.add_clock(1e-6) sim.add_clock(1e-6)
@ -54,6 +54,34 @@ class FFSynchronizerTestCase(FHDLTestCase):
sim.add_process(process) sim.add_process(process)
sim.run() sim.run()
def test_reset_value(self):
i = Signal(init=1)
o = Signal()
with self.assertWarnsRegex(DeprecationWarning,
r"^`reset=` is deprecated, use `init=` instead$"):
frag = FFSynchronizer(i, o, reset=1)
sim = Simulator(frag)
sim.add_clock(1e-6)
def process():
self.assertEqual((yield o), 1)
yield i.eq(0)
yield Tick()
self.assertEqual((yield o), 1)
yield Tick()
self.assertEqual((yield o), 1)
yield Tick()
self.assertEqual((yield o), 0)
sim.add_process(process)
sim.run()
def test_reset_wrong(self):
i = Signal(init=1)
o = Signal()
with self.assertRaisesRegex(ValueError,
r"^Cannot specify both `reset` and `init`$"):
FFSynchronizer(i, o, reset=1, init=1)
class AsyncFFSynchronizerTestCase(FHDLTestCase): class AsyncFFSynchronizerTestCase(FHDLTestCase):
def test_stages_wrong(self): def test_stages_wrong(self):
@ -115,7 +143,7 @@ class AsyncFFSynchronizerTestCase(FHDLTestCase):
sim.run() sim.run()
def test_neg_edge(self): def test_neg_edge(self):
i = Signal(reset=1) i = Signal(init=1)
o = Signal() o = Signal()
m = Module() m = Module()
m.domains += ClockDomain("sync") m.domains += ClockDomain("sync")
@ -166,7 +194,7 @@ class ResetSynchronizerTestCase(FHDLTestCase):
m = Module() m = Module()
m.domains += ClockDomain("sync") m.domains += ClockDomain("sync")
m.submodules += ResetSynchronizer(arst) m.submodules += ResetSynchronizer(arst)
s = Signal(reset=1) s = Signal(init=1)
m.d.sync += s.eq(0) m.d.sync += s.eq(0)
sim = Simulator(m) sim = Simulator(m)

View file

@ -430,13 +430,13 @@ class LayoutTestCase(FHDLTestCase):
sl = StructLayout({"f": unsigned(1)}) sl = StructLayout({"f": unsigned(1)})
self.assertRepr(sl.const({"f": Const(1)}).as_value(), "(const 1'd1)") self.assertRepr(sl.const({"f": Const(1)}).as_value(), "(const 1'd1)")
def test_signal_reset(self): def test_signal_init(self):
sl = StructLayout({ sl = StructLayout({
"a": unsigned(1), "a": unsigned(1),
"b": unsigned(2) "b": unsigned(2)
}) })
self.assertEqual(Signal(sl).as_value().reset, 0) self.assertEqual(Signal(sl).as_value().init, 0)
self.assertEqual(Signal(sl, reset={"a": 0b1, "b": 0b10}).as_value().reset, 5) self.assertEqual(Signal(sl, init={"a": 0b1, "b": 0b10}).as_value().init, 5)
class ViewTestCase(FHDLTestCase): class ViewTestCase(FHDLTestCase):
@ -454,17 +454,17 @@ class ViewTestCase(FHDLTestCase):
self.assertEqual(cv.shape(), unsigned(3)) self.assertEqual(cv.shape(), unsigned(3))
self.assertEqual(cv.name, "v") self.assertEqual(cv.name, "v")
def test_construct_signal_reset(self): def test_construct_signal_init(self):
v1 = Signal(StructLayout({"a": unsigned(1), "b": unsigned(2)}), v1 = Signal(StructLayout({"a": unsigned(1), "b": unsigned(2)}),
reset={"a": 0b1, "b": 0b10}) init={"a": 0b1, "b": 0b10})
self.assertEqual(Value.cast(v1).reset, 0b101) self.assertEqual(Value.cast(v1).init, 0b101)
v2 = Signal(StructLayout({"a": unsigned(1), v2 = Signal(StructLayout({"a": unsigned(1),
"b": StructLayout({"x": unsigned(1), "y": unsigned(1)})}), "b": StructLayout({"x": unsigned(1), "y": unsigned(1)})}),
reset={"a": 0b1, "b": {"x": 0b0, "y": 0b1}}) init={"a": 0b1, "b": {"x": 0b0, "y": 0b1}})
self.assertEqual(Value.cast(v2).reset, 0b101) self.assertEqual(Value.cast(v2).init, 0b101)
v3 = Signal(ArrayLayout(unsigned(2), 2), v3 = Signal(ArrayLayout(unsigned(2), 2),
reset=[0b01, 0b10]) init=[0b01, 0b10])
self.assertEqual(Value.cast(v3).reset, 0b1001) self.assertEqual(Value.cast(v3).init, 0b1001)
def test_layout_wrong(self): def test_layout_wrong(self):
with self.assertRaisesRegex(TypeError, with self.assertRaisesRegex(TypeError,
@ -625,13 +625,13 @@ class ViewTestCase(FHDLTestCase):
def test_bug_837_array_layout_getitem_str(self): def test_bug_837_array_layout_getitem_str(self):
with self.assertRaisesRegex(TypeError, with self.assertRaisesRegex(TypeError,
r"^Views with array layout may only be indexed with an integer or a value, " r"^Views with array layout may only be indexed with an integer or a value, "
r"not 'reset'$"): r"not 'init'$"):
Signal(ArrayLayout(unsigned(1), 1), reset=[0])["reset"] Signal(ArrayLayout(unsigned(1), 1), init=[0])["init"]
def test_bug_837_array_layout_getattr(self): def test_bug_837_array_layout_getattr(self):
with self.assertRaisesRegex(AttributeError, with self.assertRaisesRegex(AttributeError,
r"^View of \(sig \$signal\) with an array layout does not have fields$"): r"^View of \(sig \$signal\) with an array layout does not have fields$"):
Signal(ArrayLayout(unsigned(1), 1), reset=[0]).reset Signal(ArrayLayout(unsigned(1), 1), init=[0]).init
def test_eq(self): def test_eq(self):
s1 = Signal(StructLayout({"a": unsigned(2)})) s1 = Signal(StructLayout({"a": unsigned(2)}))
@ -735,7 +735,7 @@ class StructTestCase(FHDLTestCase):
self.assertRepr(v.b.q.r, "(s (slice (slice (slice (sig v) 1:9) 4:8) 0:2))") self.assertRepr(v.b.q.r, "(s (slice (slice (slice (sig v) 1:9) 4:8) 0:2))")
self.assertRepr(v.b.q.s, "(s (slice (slice (slice (sig v) 1:9) 4:8) 2:4))") self.assertRepr(v.b.q.s, "(s (slice (slice (slice (sig v) 1:9) 4:8) 2:4))")
def test_construct_reset(self): def test_construct_init(self):
class S(Struct): class S(Struct):
p: 4 p: 4
q: 2 = 1 q: 2 = 1
@ -744,11 +744,11 @@ class StructTestCase(FHDLTestCase):
S.q S.q
v1 = Signal(S) v1 = Signal(S)
self.assertEqual(v1.as_value().reset, 0b010000) self.assertEqual(v1.as_value().init, 0b010000)
v2 = Signal(S, reset=dict(p=0b0011)) v2 = Signal(S, init=dict(p=0b0011))
self.assertEqual(v2.as_value().reset, 0b010011) self.assertEqual(v2.as_value().init, 0b010011)
v3 = Signal(S, reset=dict(p=0b0011, q=0b00)) v3 = Signal(S, init=dict(p=0b0011, q=0b00))
self.assertEqual(v3.as_value().reset, 0b000011) self.assertEqual(v3.as_value().init, 0b000011)
def test_shape_undefined_wrong(self): def test_shape_undefined_wrong(self):
class S(Struct): class S(Struct):
@ -835,33 +835,33 @@ class UnionTestCase(FHDLTestCase):
self.assertRepr(v.a, "(slice (sig v) 0:1)") self.assertRepr(v.a, "(slice (sig v) 0:1)")
self.assertRepr(v.b, "(s (slice (sig v) 0:3))") self.assertRepr(v.b, "(s (slice (sig v) 0:3))")
def test_define_reset_two_wrong(self): def test_define_init_two_wrong(self):
with self.assertRaisesRegex(ValueError, with self.assertRaisesRegex(ValueError,
r"^Reset value for at most one field can be provided for a union class " r"^Initial value for at most one field can be provided for a union class "
r"\(specified: a, b\)$"): r"\(specified: a, b\)$"):
class U(Union): class U(Union):
a: unsigned(1) = 1 a: unsigned(1) = 1
b: unsigned(2) = 1 b: unsigned(2) = 1
def test_construct_reset_two_wrong(self): def test_construct_init_two_wrong(self):
class U(Union): class U(Union):
a: unsigned(1) a: unsigned(1)
b: unsigned(2) b: unsigned(2)
with self.assertRaisesRegex(TypeError, with self.assertRaisesRegex(TypeError,
r"^Reset value must be a constant initializer of <class '.+?\.U'>$") as cm: r"^Initial value must be a constant initializer of <class '.+?\.U'>$") as cm:
Signal(U, reset=dict(a=1, b=2)) Signal(U, init=dict(a=1, b=2))
self.assertRegex(cm.exception.__cause__.message, self.assertRegex(cm.exception.__cause__.message,
r"^Initializer for at most one field can be provided for a union " r"^Initializer for at most one field can be provided for a union "
r"class \(specified: a, b\)$") r"class \(specified: a, b\)$")
def test_construct_reset_override(self): def test_construct_init_override(self):
class U(Union): class U(Union):
a: unsigned(1) = 1 a: unsigned(1) = 1
b: unsigned(2) b: unsigned(2)
self.assertEqual(Signal(U).as_value().reset, 0b01) self.assertEqual(Signal(U).as_value().init, 0b01)
self.assertEqual(Signal(U, reset=dict(b=0b10)).as_value().reset, 0b10) self.assertEqual(Signal(U, init=dict(b=0b10)).as_value().init, 0b10)
# Examples from https://github.com/amaranth-lang/amaranth/issues/693 # Examples from https://github.com/amaranth-lang/amaranth/issues/693

View file

@ -36,7 +36,7 @@ class MemberTestCase(unittest.TestCase):
self.assertEqual(member.flow, In) self.assertEqual(member.flow, In)
self.assertEqual(member.is_port, True) self.assertEqual(member.is_port, True)
self.assertEqual(member.shape, unsigned(1)) self.assertEqual(member.shape, unsigned(1))
self.assertEqual(member.reset, None) self.assertEqual(member.init, None)
self.assertEqual(member.is_signature, False) self.assertEqual(member.is_signature, False)
with self.assertRaisesRegex(AttributeError, with self.assertRaisesRegex(AttributeError,
r"^A port member does not have a signature$"): r"^A port member does not have a signature$"):
@ -50,33 +50,58 @@ class MemberTestCase(unittest.TestCase):
r"not 'whatever'$"): r"not 'whatever'$"):
Member(In, "whatever") Member(In, "whatever")
def test_port_member_reset(self): def test_port_member_init(self):
member = Member(Out, unsigned(1), reset=1) member = Member(Out, unsigned(1), init=1)
self.assertEqual(member.flow, Out) self.assertEqual(member.flow, Out)
self.assertEqual(member.shape, unsigned(1)) self.assertEqual(member.shape, unsigned(1))
self.assertEqual(member.reset, 1) self.assertEqual(member.init, 1)
self.assertEqual(repr(member._reset_as_const), repr(Const(1, 1))) self.assertEqual(repr(member._init_as_const), repr(Const(1, 1)))
self.assertEqual(repr(member), "Out(unsigned(1), reset=1)") self.assertEqual(repr(member), "Out(unsigned(1), init=1)")
def test_port_member_reset_wrong(self): def test_port_member_init_wrong(self):
with self.assertRaisesRegex(TypeError, with self.assertRaisesRegex(TypeError,
r"^Port member reset value 'no' is not a valid constant initializer " r"^Port member initial value 'no' is not a valid constant initializer "
r"for unsigned\(1\)$"): r"for unsigned\(1\)$"):
Member(In, 1, reset="no") Member(In, 1, init="no")
def test_port_member_reset_shape_castable(self): def test_port_member_init_shape_castable(self):
layout = data.StructLayout({"a": 32}) layout = data.StructLayout({"a": 32})
member = Member(In, layout, reset={"a": 1}) member = Member(In, layout, init={"a": 1})
self.assertEqual(member.flow, In) self.assertEqual(member.flow, In)
self.assertEqual(member.shape, layout) self.assertEqual(member.shape, layout)
self.assertEqual(member.reset, {"a": 1}) self.assertEqual(member.init, {"a": 1})
self.assertEqual(repr(member), "In(StructLayout({'a': 32}), reset={'a': 1})") self.assertEqual(repr(member), "In(StructLayout({'a': 32}), init={'a': 1})")
def test_port_member_reset_shape_castable_wrong(self): def test_port_member_init_shape_castable_wrong(self):
with self.assertRaisesRegex(TypeError, with self.assertRaisesRegex(TypeError,
r"^Port member reset value 'no' is not a valid constant initializer " r"^Port member initial value 'no' is not a valid constant initializer "
r"for StructLayout\({'a': 32}\)$"): r"for StructLayout\({'a': 32}\)$"):
Member(In, data.StructLayout({"a": 32}), reset="no") Member(In, data.StructLayout({"a": 32}), init="no")
def test_port_member_reset(self):
with self.assertWarnsRegex(DeprecationWarning,
r"^`reset=` is deprecated, use `init=` instead$"):
member = Member(Out, unsigned(1), reset=1)
self.assertEqual(member.flow, Out)
self.assertEqual(member.shape, unsigned(1))
self.assertEqual(member.init, 1)
self.assertEqual(repr(member._init_as_const), repr(Const(1, 1)))
self.assertEqual(repr(member), "Out(unsigned(1), init=1)")
with self.assertWarnsRegex(DeprecationWarning,
r"^`Member.reset` is deprecated, use `Member.init` instead$"):
self.assertEqual(member.reset, 1)
with self.assertWarnsRegex(DeprecationWarning,
r"^`reset=` is deprecated, use `init=` instead$"):
member = Out(unsigned(1), reset=1)
self.assertEqual(member.init,1)
def test_port_member_reset_wrong(self):
with self.assertRaisesRegex(ValueError,
r"^Cannot specify both `reset` and `init`$"):
Member(Out, unsigned(1), reset=1, init=1)
with self.assertRaisesRegex(ValueError,
r"^Cannot specify both `reset` and `init`$"):
Out(unsigned(1), reset=1, init=1)
def test_signature_member_out(self): def test_signature_member_out(self):
sig = Signature({"data": Out(unsigned(32))}) sig = Signature({"data": Out(unsigned(32))})
@ -87,8 +112,8 @@ class MemberTestCase(unittest.TestCase):
r"^A signature member does not have a shape$"): r"^A signature member does not have a shape$"):
member.shape member.shape
with self.assertRaisesRegex(AttributeError, with self.assertRaisesRegex(AttributeError,
r"^A signature member does not have a reset value$"): r"^A signature member does not have an initial value$"):
member.reset member.init
self.assertEqual(member.is_signature, True) self.assertEqual(member.is_signature, True)
self.assertEqual(member.signature, sig) self.assertEqual(member.signature, sig)
self.assertEqual(member.dimensions, ()) self.assertEqual(member.dimensions, ())
@ -103,8 +128,8 @@ class MemberTestCase(unittest.TestCase):
r"^A signature member does not have a shape$"): r"^A signature member does not have a shape$"):
member.shape member.shape
with self.assertRaisesRegex(AttributeError, with self.assertRaisesRegex(AttributeError,
r"^A signature member does not have a reset value$"): r"^A signature member does not have an initial value$"):
member.reset member.init
self.assertEqual(member.is_signature, True) self.assertEqual(member.is_signature, True)
self.assertEqual(member.signature, sig.flip()) self.assertEqual(member.signature, sig.flip())
self.assertEqual(member.dimensions, ()) self.assertEqual(member.dimensions, ())
@ -112,8 +137,8 @@ class MemberTestCase(unittest.TestCase):
def test_signature_member_wrong(self): def test_signature_member_wrong(self):
with self.assertRaisesRegex(ValueError, with self.assertRaisesRegex(ValueError,
r"^A signature member cannot have a reset value$"): r"^A signature member cannot have an initial value$"):
Member(In, Signature({}), reset=1) Member(In, Signature({}), init=1)
def test_array(self): def test_array(self):
array_2 = Member(In, unsigned(1)).array(2) array_2 = Member(In, unsigned(1)).array(2)
@ -143,8 +168,8 @@ class MemberTestCase(unittest.TestCase):
def test_equality(self): def test_equality(self):
self.assertEqual(In(1), In(1)) self.assertEqual(In(1), In(1))
self.assertNotEqual(In(1), Out(1)) self.assertNotEqual(In(1), Out(1))
self.assertNotEqual(In(1), In(1, reset=1)) self.assertNotEqual(In(1), In(1, init=1))
self.assertNotEqual(In(1), In(1, reset=0)) self.assertNotEqual(In(1), In(1, init=0))
self.assertEqual(In(1), In(1).array()) self.assertEqual(In(1), In(1).array())
self.assertNotEqual(In(1), In(1).array(1)) self.assertNotEqual(In(1), In(1).array(1))
sig = Signature({}) sig = Signature({})
@ -237,12 +262,12 @@ class SignatureMembersTestCase(unittest.TestCase):
self.assertEqual(attrs["s"].b.shape(), unsigned(2)) self.assertEqual(attrs["s"].b.shape(), unsigned(2))
self.assertEqual(attrs["s"].b.name, "attrs__s__b") self.assertEqual(attrs["s"].b.name, "attrs__s__b")
def test_create_reset(self): def test_create_init(self):
members = SignatureMembers({ members = SignatureMembers({
"a": In(1, reset=1), "a": In(1, init=1),
}) })
attrs = members.create() attrs = members.create()
self.assertEqual(attrs["a"].reset, 1) self.assertEqual(attrs["a"].init, 1)
def test_create_tuple(self): def test_create_tuple(self):
sig = SignatureMembers({ sig = SignatureMembers({
@ -421,12 +446,12 @@ class SignatureTestCase(unittest.TestCase):
sig=Signature({"a": In(unsigned(1))}), sig=Signature({"a": In(unsigned(1))}),
obj=NS(a=Signal(signed(1)))) obj=NS(a=Signal(signed(1))))
self.assertNotCompliant( self.assertNotCompliant(
r"^'obj\.a' is expected to have the reset value None, but it has the reset value 1$", r"^'obj\.a' is expected to have the initial value None, but it has the initial value 1$",
sig=Signature({"a": In(1)}), sig=Signature({"a": In(1)}),
obj=NS(a=Signal(reset=1))) obj=NS(a=Signal(init=1)))
self.assertNotCompliant( self.assertNotCompliant(
r"^'obj\.a' is expected to have the reset value 1, but it has the reset value 0$", r"^'obj\.a' is expected to have the initial value 1, but it has the initial value 0$",
sig=Signature({"a": In(1, reset=1)}), sig=Signature({"a": In(1, init=1)}),
obj=NS(a=Signal(1))) obj=NS(a=Signal(1)))
self.assertNotCompliant( self.assertNotCompliant(
r"^'obj\.a' is expected to not be reset-less$", r"^'obj\.a' is expected to not be reset-less$",
@ -820,21 +845,21 @@ class ConnectTestCase(unittest.TestCase):
q=NS(signature=Signature({"a": In(Cycle)}), q=NS(signature=Signature({"a": In(Cycle)}),
a=Signal(Cycle))) a=Signal(Cycle)))
def test_reset_mismatch(self): def test_init_mismatch(self):
m = Module() m = Module()
with self.assertRaisesRegex(ConnectionError, with self.assertRaisesRegex(ConnectionError,
r"^Cannot connect together the member 'q\.a' with reset value 1 and the member " r"^Cannot connect together the member 'q\.a' with initial value 1 and the member "
r"'p\.a' with reset value 0 because the reset values do not match$"): r"'p\.a' with initial value 0 because the initial values do not match$"):
connect(m, connect(m,
p=NS(signature=Signature({"a": Out(1, reset=0)}), p=NS(signature=Signature({"a": Out(1, init=0)}),
a=Signal()), a=Signal()),
q=NS(signature=Signature({"a": In(1, reset=1)}), q=NS(signature=Signature({"a": In(1, init=1)}),
a=Signal(reset=1))) a=Signal(init=1)))
def test_reset_none_match(self): def test_init_none_match(self):
m = Module() m = Module()
connect(m, connect(m,
p=NS(signature=Signature({"a": Out(1, reset=0)}), p=NS(signature=Signature({"a": Out(1, init=0)}),
a=Signal()), a=Signal()),
q=NS(signature=Signature({"a": In(1)}), q=NS(signature=Signature({"a": In(1)}),
a=Signal())) a=Signal()))

View file

@ -18,12 +18,12 @@ from amaranth._utils import _ignore_deprecated
class SimulatorUnitTestCase(FHDLTestCase): class SimulatorUnitTestCase(FHDLTestCase):
def assertStatement(self, stmt, inputs, output, reset=0): def assertStatement(self, stmt, inputs, output, init=0):
inputs = [Value.cast(i) for i in inputs] inputs = [Value.cast(i) for i in inputs]
output = Value.cast(output) output = Value.cast(output)
isigs = [Signal(i.shape(), name=n) for i, n in zip(inputs, "abcd")] isigs = [Signal(i.shape(), name=n) for i, n in zip(inputs, "abcd")]
osig = Signal(output.shape(), name="y", reset=reset) osig = Signal(output.shape(), name="y", init=init)
stmt = stmt(osig, *isigs) stmt = stmt(osig, *isigs)
frag = Fragment() frag = Fragment()
@ -243,9 +243,9 @@ class SimulatorUnitTestCase(FHDLTestCase):
def test_slice_lhs(self): def test_slice_lhs(self):
stmt1 = lambda y, a: y[2].eq(a) stmt1 = lambda y, a: y[2].eq(a)
self.assertStatement(stmt1, [C(0b0, 1)], C(0b11111011, 8), reset=0b11111111) self.assertStatement(stmt1, [C(0b0, 1)], C(0b11111011, 8), init=0b11111111)
stmt2 = lambda y, a: y[2:4].eq(a) stmt2 = lambda y, a: y[2:4].eq(a)
self.assertStatement(stmt2, [C(0b01, 2)], C(0b11110111, 8), reset=0b11111011) self.assertStatement(stmt2, [C(0b01, 2)], C(0b11110111, 8), init=0b11111011)
def test_bit_select(self): def test_bit_select(self):
stmt = lambda y, a, b: y.eq(a.bit_select(b, 3)) stmt = lambda y, a, b: y.eq(a.bit_select(b, 3))
@ -255,9 +255,9 @@ class SimulatorUnitTestCase(FHDLTestCase):
def test_bit_select_lhs(self): def test_bit_select_lhs(self):
stmt = lambda y, a, b: y.bit_select(a, 3).eq(b) stmt = lambda y, a, b: y.bit_select(a, 3).eq(b)
self.assertStatement(stmt, [C(0), C(0b100, 3)], C(0b11111100, 8), reset=0b11111111) self.assertStatement(stmt, [C(0), C(0b100, 3)], C(0b11111100, 8), init=0b11111111)
self.assertStatement(stmt, [C(2), C(0b101, 3)], C(0b11110111, 8), reset=0b11111111) self.assertStatement(stmt, [C(2), C(0b101, 3)], C(0b11110111, 8), init=0b11111111)
self.assertStatement(stmt, [C(3), C(0b110, 3)], C(0b11110111, 8), reset=0b11111111) self.assertStatement(stmt, [C(3), C(0b110, 3)], C(0b11110111, 8), init=0b11111111)
def test_word_select(self): def test_word_select(self):
stmt = lambda y, a, b: y.eq(a.word_select(b, 3)) stmt = lambda y, a, b: y.eq(a.word_select(b, 3))
@ -267,9 +267,9 @@ class SimulatorUnitTestCase(FHDLTestCase):
def test_word_select_lhs(self): def test_word_select_lhs(self):
stmt = lambda y, a, b: y.word_select(a, 3).eq(b) stmt = lambda y, a, b: y.word_select(a, 3).eq(b)
self.assertStatement(stmt, [C(0), C(0b100, 3)], C(0b11111100, 8), reset=0b11111111) self.assertStatement(stmt, [C(0), C(0b100, 3)], C(0b11111100, 8), init=0b11111111)
self.assertStatement(stmt, [C(1), C(0b101, 3)], C(0b11101111, 8), reset=0b11111111) self.assertStatement(stmt, [C(1), C(0b101, 3)], C(0b11101111, 8), init=0b11111111)
self.assertStatement(stmt, [C(2), C(0b110, 3)], C(0b10111111, 8), reset=0b11111111) self.assertStatement(stmt, [C(2), C(0b110, 3)], C(0b10111111, 8), init=0b11111111)
def test_cat(self): def test_cat(self):
stmt = lambda y, *xs: y.eq(Cat(*xs)) stmt = lambda y, *xs: y.eq(Cat(*xs))
@ -315,9 +315,9 @@ class SimulatorUnitTestCase(FHDLTestCase):
self.assertStatement(stmt, [C(4)], C(10)) self.assertStatement(stmt, [C(4)], C(10))
def test_array_lhs(self): def test_array_lhs(self):
l = Signal(3, reset=1) l = Signal(3, init=1)
m = Signal(3, reset=4) m = Signal(3, init=4)
n = Signal(3, reset=7) n = Signal(3, init=7)
array = Array([l, m, n]) array = Array([l, m, n])
stmt = lambda y, a, b: [array[a].eq(b), y.eq(Cat(*array))] stmt = lambda y, a, b: [array[a].eq(b), y.eq(Cat(*array))]
self.assertStatement(stmt, [C(0), C(0b000)], C(0b111100000)) self.assertStatement(stmt, [C(0), C(0b000)], C(0b111100000))
@ -426,7 +426,7 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
sim.run_until(deadline) sim.run_until(deadline)
def setUp_counter(self): def setUp_counter(self):
self.count = Signal(3, reset=4) self.count = Signal(3, init=4)
self.sync = ClockDomain() self.sync = ClockDomain()
self.m = Module() self.m = Module()
@ -876,7 +876,7 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
def test_comb_bench_process(self): def test_comb_bench_process(self):
m = Module() m = Module()
a = Signal(reset=1) a = Signal(init=1)
b = Signal() b = Signal()
m.d.comb += b.eq(a) m.d.comb += b.eq(a)
with self.assertSimulation(m) as sim: with self.assertSimulation(m) as sim:
@ -890,7 +890,7 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
def test_sync_bench_process(self): def test_sync_bench_process(self):
m = Module() m = Module()
a = Signal(reset=1) a = Signal(init=1)
b = Signal() b = Signal()
m.d.sync += b.eq(a) m.d.sync += b.eq(a)
t = Signal() t = Signal()