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::
value_like = Signal(shape_castable, reset=initializer)
value_like = Signal(shape_castable, init=initializer)
The code above is equivalent to:
@ -181,7 +181,7 @@ class ShapeCastable:
value_like = shape_castable(Signal(
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)`.
@ -1731,15 +1731,15 @@ class Signal(Value, DUID, metaclass=_SignalMeta):
name : str
Name hint for this signal. If ``None`` (default) the name is inferred from the variable
name this ``Signal`` is assigned to.
reset : int or integral Enum
init : int or integral Enum
Reset (synchronous) or default (combinatorial) value.
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
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
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``.
attrs : dict
Dictionary of synthesis attributes.
@ -1754,13 +1754,13 @@ class Signal(Value, DUID, metaclass=_SignalMeta):
width : int
signed : bool
name : str
reset : int
init : int
reset_less : bool
attrs : dict
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):
super().__init__(src_loc_at=src_loc_at)
@ -1776,53 +1776,61 @@ class Signal(Value, DUID, metaclass=_SignalMeta):
self.width = shape.width
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):
try:
reset = Const.cast(orig_shape.const(reset))
init = Const.cast(orig_shape.const(init))
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))
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 "
"it casts to, {!r}, and not {!r}"
.format(orig_shape, Shape.cast(orig_shape),
reset.shape()))
init.shape()))
else:
if reset is None:
reset = 0
if init is None:
init = 0
try:
reset = Const.cast(reset)
init = Const.cast(init)
except TypeError:
raise TypeError("Reset value must be a constant-castable expression, not {!r}"
.format(orig_reset))
raise TypeError("Initial value must be a constant-castable expression, not {!r}"
.format(orig_init))
# 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 reset.shape().signed and not self.signed:
if orig_init is not None and not (isinstance(orig_init, int) and orig_init in (0, -1)):
if init.shape().signed and not self.signed:
warnings.warn(
message="Reset value {!r} is signed, but the signal shape is {!r}"
.format(orig_reset, shape),
message="Initial value {!r} is signed, but the signal shape is {!r}"
.format(orig_init, shape),
category=SyntaxWarning,
stacklevel=2)
elif (reset.shape().width > self.width or
reset.shape().width == self.width and
self.signed and not reset.shape().signed):
elif (init.shape().width > self.width or
init.shape().width == self.width and
self.signed and not init.shape().signed):
warnings.warn(
message="Reset value {!r} will be truncated to the signal shape {!r}"
.format(orig_reset, shape),
message="Initial value {!r} will be truncated to the signal shape {!r}"
.format(orig_init, shape),
category=SyntaxWarning,
stacklevel=2)
self.reset = reset.value
self.init = init.value
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 orig_reset == orig_shape.stop:
if isinstance(orig_shape, range) and orig_init is not None and orig_init not in orig_shape:
if orig_init == orig_shape.stop:
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")
else:
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)
@ -1850,6 +1858,18 @@ class Signal(Value, DUID, metaclass=_SignalMeta):
# Any other case is formatted as a plain integer.
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
def decoder(self):
return self._decoder
@ -1873,7 +1893,7 @@ class Signal(Value, DUID, metaclass=_SignalMeta):
self._decoder = enum_decoder
@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.
Parameters
@ -1887,15 +1907,24 @@ class Signal(Value, DUID, metaclass=_SignalMeta):
new_name = other.name + str(name_suffix)
else:
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):
shape = other.shape()
else:
shape = Value.cast(other).shape()
kw = dict(shape=shape, name=new_name)
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)
kw.update(kwargs)
if init is not None:
kw["init"] = init
return cls(**kw, src_loc_at=1 + src_loc_at)
def shape(self):

View file

@ -374,14 +374,21 @@ class Module(_ModuleBuilderRoot, Elaboratable):
self._statements = _outer_case
@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)
if domain == "comb":
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", {
"name": name,
"signal": Signal(name=f"{name}_state", src_loc_at=2),
"reset": reset,
"init": init,
"domain": domain,
"encoding": OrderedDict(),
"decoding": OrderedDict(),
@ -489,17 +496,17 @@ class Module(_ModuleBuilderRoot, Elaboratable):
src_loc=src_loc, case_src_locs=switch_case_src_locs))
if name == "FSM":
fsm_signal, fsm_reset, fsm_encoding, fsm_decoding, fsm_states = \
data["signal"], data["reset"], data["encoding"], data["decoding"], data["states"]
fsm_signal, fsm_init, fsm_encoding, fsm_decoding, fsm_states = \
data["signal"], data["init"], data["encoding"], data["decoding"], data["states"]
fsm_state_src_locs = data["state_src_locs"]
if not fsm_states:
return
fsm_signal.width = bits_for(len(fsm_encoding) - 1)
if fsm_reset is None:
fsm_signal.reset = fsm_encoding[next(iter(fsm_states))]
if fsm_init is None:
fsm_signal.init = fsm_encoding[next(iter(fsm_states))]
else:
fsm_signal.reset = fsm_encoding[fsm_reset]
# The FSM is encoded such that the state with encoding 0 is always the reset state.
fsm_signal.init = fsm_encoding[fsm_init]
# 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_signal.decoder = lambda n: f"{fsm_decoding[n]}/{n}"

View file

@ -691,8 +691,8 @@ class NetlistDriver:
def emit_value(self, builder):
if self.domain is None:
reset = _ast.Const(self.signal.reset, self.signal.width)
default, _signed = builder.emit_rhs(self.module_idx, reset)
init = _ast.Const(self.signal.init, self.signal.width)
default, _signed = builder.emit_rhs(self.module_idx, init)
else:
default = builder.emit_signal(self.signal)
if len(self.assignments) == 1:
@ -1184,7 +1184,7 @@ class NetlistEmitter:
arst = _nir.Net.from_const(0)
cell = _nir.FlipFlop(driver.module_idx,
data=value,
init=driver.signal.reset,
init=driver.signal.init,
clk=clk,
clk_edge=driver.domain.clk_edge,
arst=arst,
@ -1198,12 +1198,12 @@ class NetlistEmitter:
src_loc = driver.signal.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.
for signal, value in self.netlist.signals.items():
for bit, net in enumerate(value):
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'):
from . import _mem

View file

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

View file

@ -521,7 +521,7 @@ class DomainLowerer(FragmentTransformer, ValueTransformer, StatementTransformer)
domain = fragment.domains[domain_name]
if domain.rst is None:
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]
fragment.add_statements(domain_name, Switch(domain.rst, {1: stmts}))
@ -559,7 +559,7 @@ class _ControlInserter(FragmentTransformer):
class ResetInserter(_ControlInserter):
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))

View file

@ -1,3 +1,5 @@
import warnings
from .. import *
@ -26,8 +28,8 @@ class FFSynchronizer(Elaboratable):
Signal connected to synchroniser output.
o_domain : str
Name of output clock domain.
reset : int
Reset value of the flip-flops. On FPGAs, even if ``reset_less`` is ``True``,
init : int
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.
reset_less : bool
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
: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):
_check_stages(stages)
self.i = i
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._o_domain = o_domain
self._stages = stages
@ -87,7 +99,7 @@ class FFSynchronizer(Elaboratable):
m = Module()
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 i, o in zip((self.i, *flops), flops):
m.d[self._o_domain] += o.eq(i)
@ -161,7 +173,7 @@ class AsyncFFSynchronizer(Elaboratable):
m = Module()
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 i, o in zip((0, *flops), flops):
m.d.async_ff += o.eq(i)

View file

@ -383,7 +383,7 @@ class Processor(Elaboratable):
def elaborate(self, platform):
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)
# Optionally bit-reflect input words.

View file

@ -812,7 +812,7 @@ class _AggregateMeta(ShapeCastable, type):
cls = type.__new__(metacls, name, bases, namespace)
if cls.__layout_cls is UnionLayout:
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: {})"
.format(", ".join(default.keys())))
cls.__layout = cls.__layout_cls(layout)
@ -855,12 +855,12 @@ class Struct(View, metaclass=_AggregateMeta):
"""Structures defined with annotations.
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>`.
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`.
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.
.. testsetup::
@ -907,15 +907,15 @@ class Struct(View, metaclass=_AggregateMeta):
>>> flt.is_subnormal()
(== (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::
>>> hex(Signal(IEEE754Single).as_value().reset)
>>> hex(Signal(IEEE754Single).as_value().init)
'0x3f800000'
>>> hex(Signal(IEEE754Single, reset={'sign': 1}).as_value().reset)
>>> hex(Signal(IEEE754Single, init={'sign': 1}).as_value().init)
'0xbf800000'
>>> hex(Signal(IEEE754Single, reset={'exponent': 0}).as_value().reset)
>>> hex(Signal(IEEE754Single, init={'exponent': 0}).as_value().init)
'0x0'
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
is a :class:`UnionLayout`.
A :class:`Union` can have only one field with a specified reset value. If a reset value is
explicitly provided during instantiation, it overrides the reset value specified with
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 initial value specified with
an annotation:
.. testcode::
@ -976,9 +976,9 @@ class Union(View, metaclass=_AggregateMeta):
.. doctest::
>>> Signal(VarInt).as_value().reset
>>> Signal(VarInt).as_value().init
256
>>> Signal(VarInt, reset={'int8': 10}).as_value().reset
>>> Signal(VarInt, init={'int8': 10}).as_value().init
10
"""
_AggregateMeta__layout_cls = UnionLayout

View file

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

View file

@ -59,16 +59,23 @@ class Flow(enum.Enum):
return Out
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
reset value.
initial value.
Returns
-------
: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):
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`
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
will equal ``reset``.
will equal ``init``.
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))`.
"""
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._description = description
self._reset = reset
self._init = init
self._dimensions = _dimensions
self.src_loc = tracer.get_src_loc(src_loc_at=src_loc_at)
@ -121,23 +135,23 @@ class Member:
except TypeError as e:
raise TypeError(f"Port member description must be a shape-castable object or "
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"
if issubclass(type(self._description), ShapeCastable):
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:
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
else:
try:
self._reset_as_const = Const.cast(reset or 0)
self._init_as_const = Const.cast(init or 0)
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}")
if self.is_signature:
if self._reset is not None:
raise ValueError(f"A signature member cannot have a reset value")
if self._init is not None:
raise ValueError(f"A signature member cannot have an initial value")
def flip(self):
"""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
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)
def array(self, *dimensions):
@ -175,7 +189,7 @@ class Member:
if not (isinstance(dimension, int) and dimension >= 0):
raise TypeError(f"Member array dimensions must be non-negative integers, "
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))
@property
@ -231,13 +245,13 @@ class Member:
return self._description
@property
def reset(self):
"""Reset value of a port member.
def init(self):
"""Initial value of a port member.
Returns
-------
: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
------
@ -245,8 +259,14 @@ class Member:
If :py:`self` describes a signature member.
"""
if self.is_signature:
raise AttributeError(f"A signature member does not have a reset value")
return self._reset
raise AttributeError(f"A signature member does not have an initial value")
return self._init
@property
def reset(self):
warnings.warn("`Member.reset` is deprecated, use `Member.init` instead",
DeprecationWarning, stacklevel=2)
return self.init
@property
def signature(self):
@ -288,16 +308,16 @@ class Member:
return (type(other) is Member and
self._flow == other._flow and
self._description == other._description and
self._reset == other._reset and
self._init == other._init and
self._dimensions == other._dimensions)
def __repr__(self):
reset_repr = dimensions_repr = ""
if self._reset:
reset_repr = f", reset={self._reset!r}"
init_repr = dimensions_repr = ""
if self._init:
init_repr = f", init={self._init!r}"
if 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
@ -470,7 +490,7 @@ class SignatureMembers(Mapping):
def create(self, *, path=None, src_loc_at=0):
"""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
the :ref:`paths <wiring-path>` to the member (by concatenating path items with a double
underscore, ``__``).
@ -497,7 +517,7 @@ class SignatureMembers(Mapping):
# 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:
# 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))
signal.src_loc = member.src_loc
return signal
@ -775,7 +795,7 @@ class Signature(metaclass=SignatureMeta):
def iter_member(value, *, path):
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:
for sub_path, sub_member, sub_value in member.signature.flatten(value):
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
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
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
:meth:`Signature.is_compliant`.
@ -878,11 +898,11 @@ class Signature(metaclass=SignatureMeta):
f"the shape {_format_shape(attr_shape)}")
return False
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:
reasons.append(f"{_format_path(path)} is expected to have "
f"the reset value {member.reset!r}, but it has "
f"the reset value {attr_value_cast.reset!r}")
f"the initial value {member.init!r}, but it has "
f"the initial value {attr_value_cast.init!r}")
return False
if attr_value_cast.reset_less:
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
: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
corresponding to constants). Signedness may differ.
* 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
first_path = path
first_member_shape = member.shape
first_member_reset = member.reset
first_member_reset_as_const = member._reset_as_const
first_member_init = member.init
first_member_init_as_const = member._init_as_const
continue
if Shape.cast(first_member_shape).width != Shape.cast(member_shape).width:
raise ConnectionError(
@ -1496,13 +1516,13 @@ def connect(m, *args, **kwargs):
f"shape {_format_shape(member_shape)} because the shape widths "
f"({Shape.cast(first_member_shape).width} and "
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(
f"Cannot connect together the member {_format_path(first_path)} with reset "
f"value {first_member_reset!r} and the member {_format_path(path)} with reset "
f"value {member.reset} because the reset values do not match")
f"Cannot connect together the member {_format_path(first_path)} with initial "
f"value {first_member_init!r} and the member {_format_path(path)} with initial "
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
# 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.
if len(out_kind) == 0:
continue

View file

@ -436,7 +436,7 @@ class _FragmentCompiler:
if domain_name == "comb":
for signal in domain_signals:
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()
_StatementCompiler(self.state, emitter, inputs=inputs)(domain_stmts)

View file

@ -83,7 +83,7 @@ class Simulator:
def add_process(self, process):
process = self._check_process(process)
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 from process()
self._engine.add_coroutine_process(wrapper, default_cmd=None)
@ -188,7 +188,7 @@ class Simulator:
if phase is None:
# 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.
phase = period // 2
else:
@ -199,7 +199,7 @@ class Simulator:
def reset(self):
"""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()

View file

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

View file

@ -1174,7 +1174,7 @@ class XilinxPlatform(TemplatedPlatform):
def get_ff_sync(self, ff_sync):
m = Module()
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"})
for index in range(ff_sync._stages)]
if self.toolchain == "Vivado":