Implement RFC 43: Rename reset=
to init=
.
This commit is contained in:
parent
b30c87fa3e
commit
24a392887a
|
@ -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):
|
||||
|
|
|
@ -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}"
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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":
|
||||
|
|
|
@ -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)``
|
||||
* 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 ``reset=`` keyword argument to ``init=``
|
||||
* 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``
|
||||
|
||||
|
@ -39,11 +40,13 @@ Implemented RFCs
|
|||
.. _RFC 17: https://amaranth-lang.org/rfcs/0017-remove-log2-int.html
|
||||
.. _RFC 27: https://amaranth-lang.org/rfcs/0027-simulator-testbenches.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 17`_: Remove ``log2_int``
|
||||
* `RFC 27`_: Testbench processes for the simulator
|
||||
* `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)``
|
||||
|
||||
|
||||
|
@ -56,9 +59,10 @@ Language changes
|
|||
* 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: ``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: ``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`_)
|
||||
* Removed: (deprecated in 0.4) :meth:`Const.normalize`. (`RFC 5`_)
|
||||
* Removed: (deprecated in 0.4) :class:`Repl`. (`RFC 10`_)
|
||||
|
|
|
@ -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
|
||||
---------------------
|
||||
|
||||
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.
|
||||
|
||||
.. TODO: using "reset" for "initial value" is awful, let's rename it to "init"
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> Signal(4).reset
|
||||
>>> Signal(4).init
|
||||
0
|
||||
>>> Signal(4, reset=5).reset
|
||||
>>> Signal(4, init=5).init
|
||||
5
|
||||
>>> Signal(Direction, reset=Direction.LEFT).reset
|
||||
>>> Signal(Direction, init=Direction.LEFT).init
|
||||
1
|
||||
|
||||
|
||||
|
@ -467,7 +465,7 @@ In contrast, code written in the Amaranth language *describes* computations on a
|
|||
|
||||
.. doctest::
|
||||
|
||||
>>> a = Signal(8, reset=5)
|
||||
>>> a = Signal(8, init=5)
|
||||
>>> a + 1
|
||||
(+ (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
|
||||
|
||||
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::
|
||||
|
||||
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:
|
||||
|
@ -1255,7 +1253,7 @@ Consider the following code:
|
|||
|
||||
.. testcode::
|
||||
|
||||
a = Signal(8, reset=1)
|
||||
a = Signal(8, init=1)
|
||||
with m.If(en):
|
||||
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):
|
||||
m.d.sync += n.eq(n + 1)
|
||||
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)
|
||||
|
||||
.. tip::
|
||||
|
|
|
@ -555,7 +555,7 @@ Signatures
|
|||
.. autodata:: Out
|
||||
.. autodata:: In
|
||||
|
||||
.. autoclass:: Member(flow, description, *, reset=None)
|
||||
.. autoclass:: Member(flow, description, *, init=None)
|
||||
|
||||
.. autoexception:: SignatureError
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ from amaranth.cli import main
|
|||
|
||||
class Counter(Elaboratable):
|
||||
def __init__(self, width):
|
||||
self.v = Signal(width, reset=2**width-1)
|
||||
self.v = Signal(width, init=2**width-1)
|
||||
self.o = Signal()
|
||||
|
||||
def elaborate(self, platform):
|
||||
|
|
|
@ -5,7 +5,7 @@ from amaranth.back import verilog
|
|||
|
||||
class Counter(Elaboratable):
|
||||
def __init__(self, width):
|
||||
self.v = Signal(width, reset=2**width-1)
|
||||
self.v = Signal(width, init=2**width-1)
|
||||
self.o = Signal()
|
||||
self.en = Signal()
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ cd_por = ClockDomain(reset_less=True)
|
|||
cd_sync = ClockDomain()
|
||||
m.domains += cd_por, cd_sync
|
||||
|
||||
delay = Signal(range(256), reset=255)
|
||||
delay = Signal(range(256), init=255)
|
||||
with m.If(delay != 0):
|
||||
m.d.por += delay.eq(delay - 1)
|
||||
m.d.comb += [
|
||||
|
|
|
@ -32,7 +32,7 @@ class UART(Elaboratable):
|
|||
m = Module()
|
||||
|
||||
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))
|
||||
|
||||
m.d.comb += self.tx_o.eq(tx_shreg[0])
|
||||
|
@ -55,7 +55,7 @@ class UART(Elaboratable):
|
|||
]
|
||||
|
||||
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))
|
||||
|
||||
m.d.comb += self.rx_data.eq(rx_shreg[1:-1])
|
||||
|
|
|
@ -1140,24 +1140,26 @@ class SignalTestCase(FHDLTestCase):
|
|||
s2 = Signal(name="sig")
|
||||
self.assertEqual(s2.name, "sig")
|
||||
|
||||
def test_reset(self):
|
||||
s1 = Signal(4, reset=0b111, reset_less=True)
|
||||
self.assertEqual(s1.reset, 0b111)
|
||||
def test_init(self):
|
||||
s1 = Signal(4, init=0b111, reset_less=True)
|
||||
self.assertEqual(s1.init, 0b111)
|
||||
self.assertEqual(s1.reset_less, True)
|
||||
s2 = Signal.like(s1, init=0b011)
|
||||
self.assertEqual(s2.init, 0b011)
|
||||
|
||||
def test_reset_enum(self):
|
||||
s1 = Signal(2, reset=UnsignedEnum.BAR)
|
||||
self.assertEqual(s1.reset, 2)
|
||||
def test_init_enum(self):
|
||||
s1 = Signal(2, init=UnsignedEnum.BAR)
|
||||
self.assertEqual(s1.init, 2)
|
||||
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'>$"):
|
||||
Signal(1, reset=StringEnum.FOO)
|
||||
Signal(1, init=StringEnum.FOO)
|
||||
|
||||
def test_reset_const_castable(self):
|
||||
s1 = Signal(4, reset=Cat(Const(0, 1), Const(1, 1), Const(0, 2)))
|
||||
self.assertEqual(s1.reset, 2)
|
||||
def test_init_const_castable(self):
|
||||
s1 = Signal(4, init=Cat(Const(0, 1), Const(1, 1), Const(0, 2)))
|
||||
self.assertEqual(s1.init, 2)
|
||||
|
||||
def test_reset_shape_castable_const(self):
|
||||
def test_init_shape_castable_const(self):
|
||||
class CastableFromHex(ShapeCastable):
|
||||
def as_shape(self):
|
||||
return unsigned(8)
|
||||
|
@ -1168,54 +1170,80 @@ class SignalTestCase(FHDLTestCase):
|
|||
def const(self, init):
|
||||
return int(init, 16)
|
||||
|
||||
s1 = Signal(CastableFromHex(), reset="aa")
|
||||
self.assertEqual(s1.reset, 0xaa)
|
||||
s1 = Signal(CastableFromHex(), init="aa")
|
||||
self.assertEqual(s1.init, 0xaa)
|
||||
|
||||
with self.assertRaisesRegex(ValueError,
|
||||
r"^Constant returned by <.+?CastableFromHex.+?>\.const\(\) must have the shape "
|
||||
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):
|
||||
X = 1
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
r"^Reset value must be a constant initializer of <enum 'EnumA'>$"):
|
||||
Signal(EnumA) # implied reset=0
|
||||
r"^Initial value must be a constant initializer of <enum 'EnumA'>$"):
|
||||
Signal(EnumA) # implied init=0
|
||||
|
||||
def test_reset_signed_mismatch(self):
|
||||
def test_init_signed_mismatch(self):
|
||||
with self.assertWarnsRegex(SyntaxWarning,
|
||||
r"^Reset value -2 is signed, but the signal shape is unsigned\(2\)$"):
|
||||
Signal(unsigned(2), reset=-2)
|
||||
r"^Initial value -2 is signed, but the signal shape is unsigned\(2\)$"):
|
||||
Signal(unsigned(2), init=-2)
|
||||
|
||||
def test_reset_wrong_too_wide(self):
|
||||
def test_init_wrong_too_wide(self):
|
||||
with self.assertWarnsRegex(SyntaxWarning,
|
||||
r"^Reset value 2 will be truncated to the signal shape unsigned\(1\)$"):
|
||||
Signal(unsigned(1), reset=2)
|
||||
r"^Initial value 2 will be truncated to the signal shape unsigned\(1\)$"):
|
||||
Signal(unsigned(1), init=2)
|
||||
with self.assertWarnsRegex(SyntaxWarning,
|
||||
r"^Reset value 1 will be truncated to the signal shape signed\(1\)$"):
|
||||
Signal(signed(1), reset=1)
|
||||
r"^Initial value 1 will be truncated to the signal shape signed\(1\)$"):
|
||||
Signal(signed(1), init=1)
|
||||
with self.assertWarnsRegex(SyntaxWarning,
|
||||
r"^Reset value -2 will be truncated to the signal shape signed\(1\)$"):
|
||||
Signal(signed(1), reset=-2)
|
||||
r"^Initial value -2 will be truncated to the signal shape signed\(1\)$"):
|
||||
Signal(signed(1), init=-2)
|
||||
|
||||
def test_reset_wrong_fencepost(self):
|
||||
def test_init_wrong_fencepost(self):
|
||||
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$"):
|
||||
Signal(range(0, 10), reset=10)
|
||||
Signal(range(0, 10), init=10)
|
||||
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$"):
|
||||
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,
|
||||
r"^Reset value 11 is not within the signal shape range\(0, 10\)$"):
|
||||
Signal(range(0, 10), reset=11)
|
||||
r"^Initial value 11 is not within the signal shape range\(0, 10\)$"):
|
||||
Signal(range(0, 10), init=11)
|
||||
with self.assertRaisesRegex(SyntaxError,
|
||||
r"^Reset value 0 is not within the signal shape range\(1, 10\)$"):
|
||||
Signal(range(1, 10), reset=0)
|
||||
r"^Initial value 0 is not within the signal shape range\(1, 10\)$"):
|
||||
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):
|
||||
s1 = Signal()
|
||||
|
@ -1232,8 +1260,8 @@ class SignalTestCase(FHDLTestCase):
|
|||
self.assertEqual(s1.shape(), unsigned(4))
|
||||
s2 = Signal.like(Signal(range(-15, 1)))
|
||||
self.assertEqual(s2.shape(), signed(5))
|
||||
s3 = Signal.like(Signal(4, reset=0b111, reset_less=True))
|
||||
self.assertEqual(s3.reset, 0b111)
|
||||
s3 = Signal.like(Signal(4, init=0b111, reset_less=True))
|
||||
self.assertEqual(s3.init, 0b111)
|
||||
self.assertEqual(s3.reset_less, True)
|
||||
s4 = Signal.like(Signal(attrs={"no_retiming": True}))
|
||||
self.assertEqual(s4.attrs, {"no_retiming": True})
|
||||
|
|
|
@ -451,7 +451,7 @@ class DSLTestCase(FHDLTestCase):
|
|||
RED = 1
|
||||
BLUE = 2
|
||||
m = Module()
|
||||
se = Signal(Color, reset=Color.RED)
|
||||
se = Signal(Color, init=Color.RED)
|
||||
with m.Switch(se):
|
||||
with m.Case(Color.RED):
|
||||
m.d.comb += self.c1.eq(1)
|
||||
|
@ -638,10 +638,10 @@ class DSLTestCase(FHDLTestCase):
|
|||
1: "SECOND"
|
||||
}))
|
||||
|
||||
def test_FSM_reset(self):
|
||||
def test_FSM_init(self):
|
||||
a = Signal()
|
||||
m = Module()
|
||||
with m.FSM(reset="SECOND"):
|
||||
with m.FSM(init="SECOND"):
|
||||
with m.State("FIRST"):
|
||||
m.d.comb += a.eq(0)
|
||||
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):
|
||||
a = Signal()
|
||||
|
@ -683,7 +732,7 @@ class DSLTestCase(FHDLTestCase):
|
|||
with m.State("SECOND"):
|
||||
pass
|
||||
m._flush()
|
||||
self.assertEqual(m._generated["fsm"].state.reset, 1)
|
||||
self.assertEqual(m._generated["fsm"].state.init, 1)
|
||||
self.maxDiff = 10000
|
||||
self.assertRepr(m._statements["comb"], """
|
||||
(
|
||||
|
|
|
@ -59,7 +59,7 @@ class MemoryTestCase(FHDLTestCase):
|
|||
self.assertEqual(len(rdport.data), 8)
|
||||
self.assertEqual(len(rdport.en), 1)
|
||||
self.assertIsInstance(rdport.en, Signal)
|
||||
self.assertEqual(rdport.en.reset, 1)
|
||||
self.assertEqual(rdport.en.init, 1)
|
||||
|
||||
def test_read_port_non_transparent(self):
|
||||
mem = Memory(width=8, depth=4)
|
||||
|
@ -69,7 +69,7 @@ class MemoryTestCase(FHDLTestCase):
|
|||
self.assertEqual(rdport.transparent, False)
|
||||
self.assertEqual(len(rdport.en), 1)
|
||||
self.assertIsInstance(rdport.en, Signal)
|
||||
self.assertEqual(rdport.en.reset, 1)
|
||||
self.assertEqual(rdport.en.init, 1)
|
||||
|
||||
def test_read_port_asynchronous(self):
|
||||
mem = Memory(width=8, depth=4)
|
||||
|
|
|
@ -199,11 +199,11 @@ class RecordTestCase(FHDLTestCase):
|
|||
self.assertEqual(r1.a.name, "r1__a")
|
||||
self.assertEqual(r1.b.name, "r1__b")
|
||||
self.assertEqual(r1.b.s.name, "r1__b__s")
|
||||
r1.a.reset = 1
|
||||
r1.b.s.reset = 1
|
||||
r1.a.init = 1
|
||||
r1.b.s.init = 1
|
||||
r2 = Record.like(r1)
|
||||
self.assertEqual(r2.a.reset, 1)
|
||||
self.assertEqual(r2.b.s.reset, 1)
|
||||
self.assertEqual(r2.a.init, 1)
|
||||
self.assertEqual(r2.b.s.init, 1)
|
||||
self.assertEqual(r2.a.name, "r2__a")
|
||||
self.assertEqual(r2.b.name, "r2__b")
|
||||
self.assertEqual(r2.b.s.name, "r2__b__s")
|
||||
|
|
|
@ -247,8 +247,8 @@ class DomainLowererTestCase(FHDLTestCase):
|
|||
class ResetInserterTestCase(FHDLTestCase):
|
||||
def setUp(self):
|
||||
self.s1 = Signal()
|
||||
self.s2 = Signal(reset=1)
|
||||
self.s3 = Signal(reset=1, reset_less=True)
|
||||
self.s2 = Signal(init=1)
|
||||
self.s3 = Signal(init=1, reset_less=True)
|
||||
self.c1 = Signal()
|
||||
|
||||
def test_reset_default(self):
|
||||
|
|
|
@ -35,10 +35,10 @@ class FFSynchronizerTestCase(FHDLTestCase):
|
|||
sim.add_process(process)
|
||||
sim.run()
|
||||
|
||||
def test_reset_value(self):
|
||||
i = Signal(reset=1)
|
||||
def test_init_value(self):
|
||||
i = Signal(init=1)
|
||||
o = Signal()
|
||||
frag = FFSynchronizer(i, o, reset=1)
|
||||
frag = FFSynchronizer(i, o, init=1)
|
||||
|
||||
sim = Simulator(frag)
|
||||
sim.add_clock(1e-6)
|
||||
|
@ -54,6 +54,34 @@ class FFSynchronizerTestCase(FHDLTestCase):
|
|||
sim.add_process(process)
|
||||
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):
|
||||
def test_stages_wrong(self):
|
||||
|
@ -115,7 +143,7 @@ class AsyncFFSynchronizerTestCase(FHDLTestCase):
|
|||
sim.run()
|
||||
|
||||
def test_neg_edge(self):
|
||||
i = Signal(reset=1)
|
||||
i = Signal(init=1)
|
||||
o = Signal()
|
||||
m = Module()
|
||||
m.domains += ClockDomain("sync")
|
||||
|
@ -166,7 +194,7 @@ class ResetSynchronizerTestCase(FHDLTestCase):
|
|||
m = Module()
|
||||
m.domains += ClockDomain("sync")
|
||||
m.submodules += ResetSynchronizer(arst)
|
||||
s = Signal(reset=1)
|
||||
s = Signal(init=1)
|
||||
m.d.sync += s.eq(0)
|
||||
|
||||
sim = Simulator(m)
|
||||
|
|
|
@ -430,13 +430,13 @@ class LayoutTestCase(FHDLTestCase):
|
|||
sl = StructLayout({"f": unsigned(1)})
|
||||
self.assertRepr(sl.const({"f": Const(1)}).as_value(), "(const 1'd1)")
|
||||
|
||||
def test_signal_reset(self):
|
||||
def test_signal_init(self):
|
||||
sl = StructLayout({
|
||||
"a": unsigned(1),
|
||||
"b": unsigned(2)
|
||||
})
|
||||
self.assertEqual(Signal(sl).as_value().reset, 0)
|
||||
self.assertEqual(Signal(sl, reset={"a": 0b1, "b": 0b10}).as_value().reset, 5)
|
||||
self.assertEqual(Signal(sl).as_value().init, 0)
|
||||
self.assertEqual(Signal(sl, init={"a": 0b1, "b": 0b10}).as_value().init, 5)
|
||||
|
||||
|
||||
class ViewTestCase(FHDLTestCase):
|
||||
|
@ -454,17 +454,17 @@ class ViewTestCase(FHDLTestCase):
|
|||
self.assertEqual(cv.shape(), unsigned(3))
|
||||
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)}),
|
||||
reset={"a": 0b1, "b": 0b10})
|
||||
self.assertEqual(Value.cast(v1).reset, 0b101)
|
||||
init={"a": 0b1, "b": 0b10})
|
||||
self.assertEqual(Value.cast(v1).init, 0b101)
|
||||
v2 = Signal(StructLayout({"a": unsigned(1),
|
||||
"b": StructLayout({"x": unsigned(1), "y": unsigned(1)})}),
|
||||
reset={"a": 0b1, "b": {"x": 0b0, "y": 0b1}})
|
||||
self.assertEqual(Value.cast(v2).reset, 0b101)
|
||||
init={"a": 0b1, "b": {"x": 0b0, "y": 0b1}})
|
||||
self.assertEqual(Value.cast(v2).init, 0b101)
|
||||
v3 = Signal(ArrayLayout(unsigned(2), 2),
|
||||
reset=[0b01, 0b10])
|
||||
self.assertEqual(Value.cast(v3).reset, 0b1001)
|
||||
init=[0b01, 0b10])
|
||||
self.assertEqual(Value.cast(v3).init, 0b1001)
|
||||
|
||||
def test_layout_wrong(self):
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
|
@ -625,13 +625,13 @@ class ViewTestCase(FHDLTestCase):
|
|||
def test_bug_837_array_layout_getitem_str(self):
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
r"^Views with array layout may only be indexed with an integer or a value, "
|
||||
r"not 'reset'$"):
|
||||
Signal(ArrayLayout(unsigned(1), 1), reset=[0])["reset"]
|
||||
r"not 'init'$"):
|
||||
Signal(ArrayLayout(unsigned(1), 1), init=[0])["init"]
|
||||
|
||||
def test_bug_837_array_layout_getattr(self):
|
||||
with self.assertRaisesRegex(AttributeError,
|
||||
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):
|
||||
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.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):
|
||||
p: 4
|
||||
q: 2 = 1
|
||||
|
@ -744,11 +744,11 @@ class StructTestCase(FHDLTestCase):
|
|||
S.q
|
||||
|
||||
v1 = Signal(S)
|
||||
self.assertEqual(v1.as_value().reset, 0b010000)
|
||||
v2 = Signal(S, reset=dict(p=0b0011))
|
||||
self.assertEqual(v2.as_value().reset, 0b010011)
|
||||
v3 = Signal(S, reset=dict(p=0b0011, q=0b00))
|
||||
self.assertEqual(v3.as_value().reset, 0b000011)
|
||||
self.assertEqual(v1.as_value().init, 0b010000)
|
||||
v2 = Signal(S, init=dict(p=0b0011))
|
||||
self.assertEqual(v2.as_value().init, 0b010011)
|
||||
v3 = Signal(S, init=dict(p=0b0011, q=0b00))
|
||||
self.assertEqual(v3.as_value().init, 0b000011)
|
||||
|
||||
def test_shape_undefined_wrong(self):
|
||||
class S(Struct):
|
||||
|
@ -835,33 +835,33 @@ class UnionTestCase(FHDLTestCase):
|
|||
self.assertRepr(v.a, "(slice (sig v) 0:1)")
|
||||
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,
|
||||
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\)$"):
|
||||
class U(Union):
|
||||
a: unsigned(1) = 1
|
||||
b: unsigned(2) = 1
|
||||
|
||||
def test_construct_reset_two_wrong(self):
|
||||
def test_construct_init_two_wrong(self):
|
||||
class U(Union):
|
||||
a: unsigned(1)
|
||||
b: unsigned(2)
|
||||
|
||||
with self.assertRaisesRegex(TypeError,
|
||||
r"^Reset value must be a constant initializer of <class '.+?\.U'>$") as cm:
|
||||
Signal(U, reset=dict(a=1, b=2))
|
||||
r"^Initial value must be a constant initializer of <class '.+?\.U'>$") as cm:
|
||||
Signal(U, init=dict(a=1, b=2))
|
||||
self.assertRegex(cm.exception.__cause__.message,
|
||||
r"^Initializer for at most one field can be provided for a union "
|
||||
r"class \(specified: a, b\)$")
|
||||
|
||||
def test_construct_reset_override(self):
|
||||
def test_construct_init_override(self):
|
||||
class U(Union):
|
||||
a: unsigned(1) = 1
|
||||
b: unsigned(2)
|
||||
|
||||
self.assertEqual(Signal(U).as_value().reset, 0b01)
|
||||
self.assertEqual(Signal(U, reset=dict(b=0b10)).as_value().reset, 0b10)
|
||||
self.assertEqual(Signal(U).as_value().init, 0b01)
|
||||
self.assertEqual(Signal(U, init=dict(b=0b10)).as_value().init, 0b10)
|
||||
|
||||
|
||||
# Examples from https://github.com/amaranth-lang/amaranth/issues/693
|
||||
|
|
|
@ -36,7 +36,7 @@ class MemberTestCase(unittest.TestCase):
|
|||
self.assertEqual(member.flow, In)
|
||||
self.assertEqual(member.is_port, True)
|
||||
self.assertEqual(member.shape, unsigned(1))
|
||||
self.assertEqual(member.reset, None)
|
||||
self.assertEqual(member.init, None)
|
||||
self.assertEqual(member.is_signature, False)
|
||||
with self.assertRaisesRegex(AttributeError,
|
||||
r"^A port member does not have a signature$"):
|
||||
|
@ -50,33 +50,58 @@ class MemberTestCase(unittest.TestCase):
|
|||
r"not 'whatever'$"):
|
||||
Member(In, "whatever")
|
||||
|
||||
def test_port_member_reset(self):
|
||||
member = Member(Out, unsigned(1), reset=1)
|
||||
def test_port_member_init(self):
|
||||
member = Member(Out, unsigned(1), init=1)
|
||||
self.assertEqual(member.flow, Out)
|
||||
self.assertEqual(member.shape, unsigned(1))
|
||||
self.assertEqual(member.reset, 1)
|
||||
self.assertEqual(repr(member._reset_as_const), repr(Const(1, 1)))
|
||||
self.assertEqual(repr(member), "Out(unsigned(1), reset=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)")
|
||||
|
||||
def test_port_member_reset_wrong(self):
|
||||
def test_port_member_init_wrong(self):
|
||||
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\)$"):
|
||||
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})
|
||||
member = Member(In, layout, reset={"a": 1})
|
||||
member = Member(In, layout, init={"a": 1})
|
||||
self.assertEqual(member.flow, In)
|
||||
self.assertEqual(member.shape, layout)
|
||||
self.assertEqual(member.reset, {"a": 1})
|
||||
self.assertEqual(repr(member), "In(StructLayout({'a': 32}), reset={'a': 1})")
|
||||
self.assertEqual(member.init, {"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,
|
||||
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}\)$"):
|
||||
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):
|
||||
sig = Signature({"data": Out(unsigned(32))})
|
||||
|
@ -87,8 +112,8 @@ class MemberTestCase(unittest.TestCase):
|
|||
r"^A signature member does not have a shape$"):
|
||||
member.shape
|
||||
with self.assertRaisesRegex(AttributeError,
|
||||
r"^A signature member does not have a reset value$"):
|
||||
member.reset
|
||||
r"^A signature member does not have an initial value$"):
|
||||
member.init
|
||||
self.assertEqual(member.is_signature, True)
|
||||
self.assertEqual(member.signature, sig)
|
||||
self.assertEqual(member.dimensions, ())
|
||||
|
@ -103,8 +128,8 @@ class MemberTestCase(unittest.TestCase):
|
|||
r"^A signature member does not have a shape$"):
|
||||
member.shape
|
||||
with self.assertRaisesRegex(AttributeError,
|
||||
r"^A signature member does not have a reset value$"):
|
||||
member.reset
|
||||
r"^A signature member does not have an initial value$"):
|
||||
member.init
|
||||
self.assertEqual(member.is_signature, True)
|
||||
self.assertEqual(member.signature, sig.flip())
|
||||
self.assertEqual(member.dimensions, ())
|
||||
|
@ -112,8 +137,8 @@ class MemberTestCase(unittest.TestCase):
|
|||
|
||||
def test_signature_member_wrong(self):
|
||||
with self.assertRaisesRegex(ValueError,
|
||||
r"^A signature member cannot have a reset value$"):
|
||||
Member(In, Signature({}), reset=1)
|
||||
r"^A signature member cannot have an initial value$"):
|
||||
Member(In, Signature({}), init=1)
|
||||
|
||||
def test_array(self):
|
||||
array_2 = Member(In, unsigned(1)).array(2)
|
||||
|
@ -143,8 +168,8 @@ class MemberTestCase(unittest.TestCase):
|
|||
def test_equality(self):
|
||||
self.assertEqual(In(1), In(1))
|
||||
self.assertNotEqual(In(1), Out(1))
|
||||
self.assertNotEqual(In(1), In(1, reset=1))
|
||||
self.assertNotEqual(In(1), In(1, reset=0))
|
||||
self.assertNotEqual(In(1), In(1, init=1))
|
||||
self.assertNotEqual(In(1), In(1, init=0))
|
||||
self.assertEqual(In(1), In(1).array())
|
||||
self.assertNotEqual(In(1), In(1).array(1))
|
||||
sig = Signature({})
|
||||
|
@ -237,12 +262,12 @@ class SignatureMembersTestCase(unittest.TestCase):
|
|||
self.assertEqual(attrs["s"].b.shape(), unsigned(2))
|
||||
self.assertEqual(attrs["s"].b.name, "attrs__s__b")
|
||||
|
||||
def test_create_reset(self):
|
||||
def test_create_init(self):
|
||||
members = SignatureMembers({
|
||||
"a": In(1, reset=1),
|
||||
"a": In(1, init=1),
|
||||
})
|
||||
attrs = members.create()
|
||||
self.assertEqual(attrs["a"].reset, 1)
|
||||
self.assertEqual(attrs["a"].init, 1)
|
||||
|
||||
def test_create_tuple(self):
|
||||
sig = SignatureMembers({
|
||||
|
@ -421,12 +446,12 @@ class SignatureTestCase(unittest.TestCase):
|
|||
sig=Signature({"a": In(unsigned(1))}),
|
||||
obj=NS(a=Signal(signed(1))))
|
||||
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)}),
|
||||
obj=NS(a=Signal(reset=1)))
|
||||
obj=NS(a=Signal(init=1)))
|
||||
self.assertNotCompliant(
|
||||
r"^'obj\.a' is expected to have the reset value 1, but it has the reset value 0$",
|
||||
sig=Signature({"a": In(1, reset=1)}),
|
||||
r"^'obj\.a' is expected to have the initial value 1, but it has the initial value 0$",
|
||||
sig=Signature({"a": In(1, init=1)}),
|
||||
obj=NS(a=Signal(1)))
|
||||
self.assertNotCompliant(
|
||||
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)}),
|
||||
a=Signal(Cycle)))
|
||||
|
||||
def test_reset_mismatch(self):
|
||||
def test_init_mismatch(self):
|
||||
m = Module()
|
||||
with self.assertRaisesRegex(ConnectionError,
|
||||
r"^Cannot connect together the member 'q\.a' with reset value 1 and the member "
|
||||
r"'p\.a' with reset value 0 because the reset values do not match$"):
|
||||
r"^Cannot connect together the member 'q\.a' with initial value 1 and the member "
|
||||
r"'p\.a' with initial value 0 because the initial values do not match$"):
|
||||
connect(m,
|
||||
p=NS(signature=Signature({"a": Out(1, reset=0)}),
|
||||
p=NS(signature=Signature({"a": Out(1, init=0)}),
|
||||
a=Signal()),
|
||||
q=NS(signature=Signature({"a": In(1, reset=1)}),
|
||||
a=Signal(reset=1)))
|
||||
q=NS(signature=Signature({"a": In(1, init=1)}),
|
||||
a=Signal(init=1)))
|
||||
|
||||
def test_reset_none_match(self):
|
||||
def test_init_none_match(self):
|
||||
m = Module()
|
||||
connect(m,
|
||||
p=NS(signature=Signature({"a": Out(1, reset=0)}),
|
||||
p=NS(signature=Signature({"a": Out(1, init=0)}),
|
||||
a=Signal()),
|
||||
q=NS(signature=Signature({"a": In(1)}),
|
||||
a=Signal()))
|
||||
|
|
|
@ -18,12 +18,12 @@ from amaranth._utils import _ignore_deprecated
|
|||
|
||||
|
||||
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]
|
||||
output = Value.cast(output)
|
||||
|
||||
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)
|
||||
frag = Fragment()
|
||||
|
@ -243,9 +243,9 @@ class SimulatorUnitTestCase(FHDLTestCase):
|
|||
|
||||
def test_slice_lhs(self):
|
||||
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)
|
||||
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):
|
||||
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):
|
||||
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(2), C(0b101, 3)], C(0b11110111, 8), reset=0b11111111)
|
||||
self.assertStatement(stmt, [C(3), C(0b110, 3)], C(0b11110111, 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), init=0b11111111)
|
||||
self.assertStatement(stmt, [C(3), C(0b110, 3)], C(0b11110111, 8), init=0b11111111)
|
||||
|
||||
def test_word_select(self):
|
||||
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):
|
||||
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(1), C(0b101, 3)], C(0b11101111, 8), reset=0b11111111)
|
||||
self.assertStatement(stmt, [C(2), C(0b110, 3)], C(0b10111111, 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), init=0b11111111)
|
||||
self.assertStatement(stmt, [C(2), C(0b110, 3)], C(0b10111111, 8), init=0b11111111)
|
||||
|
||||
def test_cat(self):
|
||||
stmt = lambda y, *xs: y.eq(Cat(*xs))
|
||||
|
@ -315,9 +315,9 @@ class SimulatorUnitTestCase(FHDLTestCase):
|
|||
self.assertStatement(stmt, [C(4)], C(10))
|
||||
|
||||
def test_array_lhs(self):
|
||||
l = Signal(3, reset=1)
|
||||
m = Signal(3, reset=4)
|
||||
n = Signal(3, reset=7)
|
||||
l = Signal(3, init=1)
|
||||
m = Signal(3, init=4)
|
||||
n = Signal(3, init=7)
|
||||
array = Array([l, m, n])
|
||||
stmt = lambda y, a, b: [array[a].eq(b), y.eq(Cat(*array))]
|
||||
self.assertStatement(stmt, [C(0), C(0b000)], C(0b111100000))
|
||||
|
@ -426,7 +426,7 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
|
|||
sim.run_until(deadline)
|
||||
|
||||
def setUp_counter(self):
|
||||
self.count = Signal(3, reset=4)
|
||||
self.count = Signal(3, init=4)
|
||||
self.sync = ClockDomain()
|
||||
|
||||
self.m = Module()
|
||||
|
@ -876,7 +876,7 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
|
|||
|
||||
def test_comb_bench_process(self):
|
||||
m = Module()
|
||||
a = Signal(reset=1)
|
||||
a = Signal(init=1)
|
||||
b = Signal()
|
||||
m.d.comb += b.eq(a)
|
||||
with self.assertSimulation(m) as sim:
|
||||
|
@ -890,7 +890,7 @@ class SimulatorIntegrationTestCase(FHDLTestCase):
|
|||
|
||||
def test_sync_bench_process(self):
|
||||
m = Module()
|
||||
a = Signal(reset=1)
|
||||
a = Signal(init=1)
|
||||
b = Signal()
|
||||
m.d.sync += b.eq(a)
|
||||
t = Signal()
|
||||
|
|
Loading…
Reference in a new issue