hdl.ast: deprecate Repl
and remove from AST; add Value.replicate
.
This commit is contained in:
parent
b1cce87630
commit
d218273b9b
|
@ -632,9 +632,6 @@ class _RHSValueCompiler(_ValueCompiler):
|
||||||
}, src=_src(value.src_loc))
|
}, src=_src(value.src_loc))
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def on_Repl(self, value):
|
|
||||||
return "{{ {} }}".format(" ".join(self(value.value) for _ in range(value.count)))
|
|
||||||
|
|
||||||
|
|
||||||
class _LHSValueCompiler(_ValueCompiler):
|
class _LHSValueCompiler(_ValueCompiler):
|
||||||
def on_Const(self, value):
|
def on_Const(self, value):
|
||||||
|
@ -695,9 +692,6 @@ class _LHSValueCompiler(_ValueCompiler):
|
||||||
range(1 << len(value.offset))[:max_branches],
|
range(1 << len(value.offset))[:max_branches],
|
||||||
value.src_loc)
|
value.src_loc)
|
||||||
|
|
||||||
def on_Repl(self, value):
|
|
||||||
raise TypeError # :nocov:
|
|
||||||
|
|
||||||
|
|
||||||
class _StatementCompiler(xfrm.StatementVisitor):
|
class _StatementCompiler(xfrm.StatementVisitor):
|
||||||
def __init__(self, state, rhs_compiler, lhs_compiler):
|
def __init__(self, state, rhs_compiler, lhs_compiler):
|
||||||
|
|
|
@ -69,9 +69,9 @@ def Constant(value, bits_sign=None):
|
||||||
return Const(value, bits_sign)
|
return Const(value, bits_sign)
|
||||||
|
|
||||||
|
|
||||||
@deprecated("instead of `Replicate`, use `Repl`")
|
@deprecated("instead of `Replicate(v, n)`, use `v.replicate(n)`")
|
||||||
def Replicate(v, n):
|
def Replicate(v, n):
|
||||||
return Repl(v, n)
|
return v.replicate(n)
|
||||||
|
|
||||||
|
|
||||||
@extend(Const)
|
@extend(Const)
|
||||||
|
|
|
@ -539,6 +539,29 @@ class Value(metaclass=ABCMeta):
|
||||||
amount %= len(self)
|
amount %= len(self)
|
||||||
return Cat(self[amount:], self[:amount])
|
return Cat(self[amount:], self[:amount])
|
||||||
|
|
||||||
|
def replicate(self, count):
|
||||||
|
"""Replication.
|
||||||
|
|
||||||
|
A ``Value`` is replicated (repeated) several times to be used
|
||||||
|
on the RHS of assignments::
|
||||||
|
|
||||||
|
len(v.replicate(n)) == len(v) * n
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
count : int
|
||||||
|
Number of replications.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
Value, out
|
||||||
|
Replicated value.
|
||||||
|
"""
|
||||||
|
if not isinstance(count, int) or count < 0:
|
||||||
|
raise TypeError("Replication count must be a non-negative integer, not {!r}"
|
||||||
|
.format(count))
|
||||||
|
return Cat(self for _ in range(count))
|
||||||
|
|
||||||
def eq(self, value):
|
def eq(self, value):
|
||||||
"""Assignment.
|
"""Assignment.
|
||||||
|
|
||||||
|
@ -914,8 +937,9 @@ class Cat(Value):
|
||||||
return "(cat {})".format(" ".join(map(repr, self.parts)))
|
return "(cat {})".format(" ".join(map(repr, self.parts)))
|
||||||
|
|
||||||
|
|
||||||
@final
|
# TODO(amaranth-0.5): remove
|
||||||
class Repl(Value):
|
@deprecated("instead of `Repl(value, count)`, use `value.replicate(count)`")
|
||||||
|
def Repl(value, count):
|
||||||
"""Replicate a value
|
"""Replicate a value
|
||||||
|
|
||||||
An input value is replicated (repeated) several times
|
An input value is replicated (repeated) several times
|
||||||
|
@ -932,31 +956,16 @@ class Repl(Value):
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
Repl, out
|
Value, out
|
||||||
Replicated value.
|
Replicated value.
|
||||||
"""
|
"""
|
||||||
def __init__(self, value, count, *, src_loc_at=0):
|
if isinstance(value, int) and value not in [0, 1]:
|
||||||
if not isinstance(count, int) or count < 0:
|
warnings.warn("Value argument of Repl() is a bare integer {} used in bit vector "
|
||||||
raise TypeError("Replication count must be a non-negative integer, not {!r}"
|
"context; consider specifying explicit width using C({}, {}) instead"
|
||||||
.format(count))
|
.format(value, value, bits_for(value)),
|
||||||
|
SyntaxWarning, stacklevel=3)
|
||||||
|
|
||||||
super().__init__(src_loc_at=src_loc_at)
|
return Value.cast(value).replicate(count)
|
||||||
if isinstance(value, int) and value not in [0, 1]:
|
|
||||||
warnings.warn("Value argument of Repl() is a bare integer {} used in bit vector "
|
|
||||||
"context; consider specifying explicit width using C({}, {}) instead"
|
|
||||||
.format(value, value, bits_for(value)),
|
|
||||||
SyntaxWarning, stacklevel=2 + src_loc_at)
|
|
||||||
self.value = Value.cast(value)
|
|
||||||
self.count = count
|
|
||||||
|
|
||||||
def shape(self):
|
|
||||||
return Shape(len(self.value) * self.count)
|
|
||||||
|
|
||||||
def _rhs_signals(self):
|
|
||||||
return self.value._rhs_signals()
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "(repl {!r} {})".format(self.value, self.count)
|
|
||||||
|
|
||||||
|
|
||||||
class _SignalMeta(ABCMeta):
|
class _SignalMeta(ABCMeta):
|
||||||
|
@ -1728,8 +1737,6 @@ class ValueKey:
|
||||||
tuple(ValueKey(e) for e in self.value._iter_as_values())))
|
tuple(ValueKey(e) for e in self.value._iter_as_values())))
|
||||||
elif isinstance(self.value, Sample):
|
elif isinstance(self.value, Sample):
|
||||||
self._hash = hash((ValueKey(self.value.value), self.value.clocks, self.value.domain))
|
self._hash = hash((ValueKey(self.value.value), self.value.clocks, self.value.domain))
|
||||||
elif isinstance(self.value, Repl):
|
|
||||||
self._hash = hash((ValueKey(self.value.value), self.value.count))
|
|
||||||
elif isinstance(self.value, Initial):
|
elif isinstance(self.value, Initial):
|
||||||
self._hash = 0
|
self._hash = 0
|
||||||
else: # :nocov:
|
else: # :nocov:
|
||||||
|
@ -1769,9 +1776,6 @@ class ValueKey:
|
||||||
return (len(self.value.parts) == len(other.value.parts) and
|
return (len(self.value.parts) == len(other.value.parts) and
|
||||||
all(ValueKey(a) == ValueKey(b)
|
all(ValueKey(a) == ValueKey(b)
|
||||||
for a, b in zip(self.value.parts, other.value.parts)))
|
for a, b in zip(self.value.parts, other.value.parts)))
|
||||||
elif isinstance(self.value, Repl):
|
|
||||||
return (ValueKey(self.value.value) == ValueKey(other.value.value) and
|
|
||||||
self.value.count == other.value.count)
|
|
||||||
elif isinstance(self.value, ArrayProxy):
|
elif isinstance(self.value, ArrayProxy):
|
||||||
return (ValueKey(self.value.index) == ValueKey(other.value.index) and
|
return (ValueKey(self.value.index) == ValueKey(other.value.index) and
|
||||||
len(self.value.elems) == len(other.value.elems) and
|
len(self.value.elems) == len(other.value.elems) and
|
||||||
|
|
|
@ -281,7 +281,7 @@ class WritePort(Elaboratable):
|
||||||
p_CLK_POLARITY=1,
|
p_CLK_POLARITY=1,
|
||||||
p_PRIORITY=0,
|
p_PRIORITY=0,
|
||||||
i_CLK=ClockSignal(self.domain),
|
i_CLK=ClockSignal(self.domain),
|
||||||
i_EN=Cat(Repl(en_bit, self.granularity) for en_bit in self.en),
|
i_EN=Cat(en_bit.replicate(self.granularity) for en_bit in self.en),
|
||||||
i_ADDR=self.addr,
|
i_ADDR=self.addr,
|
||||||
i_DATA=self.data,
|
i_DATA=self.data,
|
||||||
)
|
)
|
||||||
|
|
|
@ -62,10 +62,6 @@ class ValueVisitor(metaclass=ABCMeta):
|
||||||
def on_Cat(self, value):
|
def on_Cat(self, value):
|
||||||
pass # :nocov:
|
pass # :nocov:
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def on_Repl(self, value):
|
|
||||||
pass # :nocov:
|
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def on_ArrayProxy(self, value):
|
def on_ArrayProxy(self, value):
|
||||||
pass # :nocov:
|
pass # :nocov:
|
||||||
|
@ -106,8 +102,6 @@ class ValueVisitor(metaclass=ABCMeta):
|
||||||
new_value = self.on_Part(value)
|
new_value = self.on_Part(value)
|
||||||
elif type(value) is Cat:
|
elif type(value) is Cat:
|
||||||
new_value = self.on_Cat(value)
|
new_value = self.on_Cat(value)
|
||||||
elif type(value) is Repl:
|
|
||||||
new_value = self.on_Repl(value)
|
|
||||||
elif type(value) is ArrayProxy:
|
elif type(value) is ArrayProxy:
|
||||||
new_value = self.on_ArrayProxy(value)
|
new_value = self.on_ArrayProxy(value)
|
||||||
elif type(value) is Sample:
|
elif type(value) is Sample:
|
||||||
|
@ -156,9 +150,6 @@ class ValueTransformer(ValueVisitor):
|
||||||
def on_Cat(self, value):
|
def on_Cat(self, value):
|
||||||
return Cat(self.on_value(o) for o in value.parts)
|
return Cat(self.on_value(o) for o in value.parts)
|
||||||
|
|
||||||
def on_Repl(self, value):
|
|
||||||
return Repl(self.on_value(value.value), value.count)
|
|
||||||
|
|
||||||
def on_ArrayProxy(self, value):
|
def on_ArrayProxy(self, value):
|
||||||
return ArrayProxy([self.on_value(elem) for elem in value._iter_as_values()],
|
return ArrayProxy([self.on_value(elem) for elem in value._iter_as_values()],
|
||||||
self.on_value(value.index))
|
self.on_value(value.index))
|
||||||
|
@ -374,9 +365,6 @@ class DomainCollector(ValueVisitor, StatementVisitor):
|
||||||
for o in value.parts:
|
for o in value.parts:
|
||||||
self.on_value(o)
|
self.on_value(o)
|
||||||
|
|
||||||
def on_Repl(self, value):
|
|
||||||
self.on_value(value.value)
|
|
||||||
|
|
||||||
def on_ArrayProxy(self, value):
|
def on_ArrayProxy(self, value):
|
||||||
for elem in value._iter_as_values():
|
for elem in value._iter_as_values():
|
||||||
self.on_value(elem)
|
self.on_value(elem)
|
||||||
|
|
|
@ -213,18 +213,6 @@ class _RHSValueCompiler(_ValueCompiler):
|
||||||
return f"({' | '.join(gen_parts)})"
|
return f"({' | '.join(gen_parts)})"
|
||||||
return f"0"
|
return f"0"
|
||||||
|
|
||||||
def on_Repl(self, value):
|
|
||||||
part_mask = (1 << len(value.value)) - 1
|
|
||||||
gen_part = self.emitter.def_var("repl", f"{part_mask:#x} & {self(value.value)}")
|
|
||||||
gen_parts = []
|
|
||||||
offset = 0
|
|
||||||
for _ in range(value.count):
|
|
||||||
gen_parts.append(f"({gen_part} << {offset})")
|
|
||||||
offset += len(value.value)
|
|
||||||
if gen_parts:
|
|
||||||
return f"({' | '.join(gen_parts)})"
|
|
||||||
return f"0"
|
|
||||||
|
|
||||||
def on_ArrayProxy(self, value):
|
def on_ArrayProxy(self, value):
|
||||||
index_mask = (1 << len(value.index)) - 1
|
index_mask = (1 << len(value.index)) - 1
|
||||||
gen_index = self.emitter.def_var("rhs_index", f"{index_mask:#x} & {self(value.index)}")
|
gen_index = self.emitter.def_var("rhs_index", f"{index_mask:#x} & {self(value.index)}")
|
||||||
|
@ -325,9 +313,6 @@ class _LHSValueCompiler(_ValueCompiler):
|
||||||
offset += len(part)
|
offset += len(part)
|
||||||
return gen
|
return gen
|
||||||
|
|
||||||
def on_Repl(self, value):
|
|
||||||
raise TypeError # :nocov:
|
|
||||||
|
|
||||||
def on_ArrayProxy(self, value):
|
def on_ArrayProxy(self, value):
|
||||||
def gen(arg):
|
def gen(arg):
|
||||||
index_mask = (1 << len(value.index)) - 1
|
index_mask = (1 << len(value.index)) - 1
|
||||||
|
|
|
@ -375,7 +375,7 @@ class IntelPlatform(TemplatedPlatform):
|
||||||
def _get_oereg(m, pin):
|
def _get_oereg(m, pin):
|
||||||
# altiobuf_ requires an output enable signal for each pin, but pin.oe is 1 bit wide.
|
# altiobuf_ requires an output enable signal for each pin, but pin.oe is 1 bit wide.
|
||||||
if pin.xdr == 0:
|
if pin.xdr == 0:
|
||||||
return Repl(pin.oe, pin.width)
|
return pin.oe.replicate(pin.width)
|
||||||
elif pin.xdr in (1, 2):
|
elif pin.xdr in (1, 2):
|
||||||
oe_reg = Signal(pin.width, name="{}_oe_reg".format(pin.name))
|
oe_reg = Signal(pin.width, name="{}_oe_reg".format(pin.name))
|
||||||
oe_reg.attrs["useioff"] = "1"
|
oe_reg.attrs["useioff"] = "1"
|
||||||
|
|
|
@ -528,7 +528,7 @@ class LatticeECP5Platform(TemplatedPlatform):
|
||||||
if "o" in pin.dir:
|
if "o" in pin.dir:
|
||||||
o = pin_o
|
o = pin_o
|
||||||
if pin.dir in ("oe", "io"):
|
if pin.dir in ("oe", "io"):
|
||||||
t = Repl(~pin.oe, pin.width)
|
t = (~pin.oe).replicate(pin.width)
|
||||||
elif pin.xdr == 1:
|
elif pin.xdr == 1:
|
||||||
if "i" in pin.dir:
|
if "i" in pin.dir:
|
||||||
get_ireg(pin.i_clk, i, pin_i)
|
get_ireg(pin.i_clk, i, pin_i)
|
||||||
|
|
|
@ -37,6 +37,7 @@ Implemented RFCs
|
||||||
.. _RFC 5: https://amaranth-lang.org/rfcs/0005-remove-const-normalize.html
|
.. _RFC 5: https://amaranth-lang.org/rfcs/0005-remove-const-normalize.html
|
||||||
.. _RFC 8: https://amaranth-lang.org/rfcs/0008-aggregate-extensibility.html
|
.. _RFC 8: https://amaranth-lang.org/rfcs/0008-aggregate-extensibility.html
|
||||||
.. _RFC 9: https://amaranth-lang.org/rfcs/0009-const-init-shape-castable.html
|
.. _RFC 9: https://amaranth-lang.org/rfcs/0009-const-init-shape-castable.html
|
||||||
|
.. _RFC 10: https://amaranth-lang.org/rfcs/0010-move-repl-to-value.html
|
||||||
.. _RFC 15: https://amaranth-lang.org/rfcs/0015-lifting-shape-castables.html
|
.. _RFC 15: https://amaranth-lang.org/rfcs/0015-lifting-shape-castables.html
|
||||||
|
|
||||||
* `RFC 1`_: Aggregate data structure library
|
* `RFC 1`_: Aggregate data structure library
|
||||||
|
@ -45,6 +46,7 @@ Implemented RFCs
|
||||||
* `RFC 5`_: Remove Const.normalize
|
* `RFC 5`_: Remove Const.normalize
|
||||||
* `RFC 8`_: Aggregate extensibility
|
* `RFC 8`_: Aggregate extensibility
|
||||||
* `RFC 9`_: Constant initialization for shape-castable objects
|
* `RFC 9`_: Constant initialization for shape-castable objects
|
||||||
|
* `RFC 10`_: Move Repl to Value.replicate
|
||||||
* `RFC 15`_: Lifting shape-castable objects
|
* `RFC 15`_: Lifting shape-castable objects
|
||||||
|
|
||||||
|
|
||||||
|
@ -57,12 +59,14 @@ Language changes
|
||||||
* Added: :meth:`Value.as_signed` and :meth:`Value.as_unsigned` can be used on left-hand side of assignment (with no difference in behavior).
|
* Added: :meth:`Value.as_signed` and :meth:`Value.as_unsigned` can be used on left-hand side of assignment (with no difference in behavior).
|
||||||
* Added: :meth:`Const.cast`. (`RFC 4`_)
|
* Added: :meth:`Const.cast`. (`RFC 4`_)
|
||||||
* Added: :meth:`Value.matches` and ``with m.Case():`` accept any constant-castable objects. (`RFC 4`_)
|
* Added: :meth:`Value.matches` and ``with m.Case():`` accept any constant-castable objects. (`RFC 4`_)
|
||||||
|
* Added: :meth:`Value.replicate`, superseding :class:`Repl`. (`RFC 10`_)
|
||||||
* Changed: creating a :class:`Signal` with a shape that is a :class:`ShapeCastable` implementing :meth:`ShapeCastable.__call__` wraps the returned object using that method. (`RFC 15`_)
|
* Changed: creating a :class:`Signal` with a shape that is a :class:`ShapeCastable` implementing :meth:`ShapeCastable.__call__` wraps the returned object using that method. (`RFC 15`_)
|
||||||
* Changed: :meth:`Value.cast` casts :class:`ValueCastable` objects recursively.
|
* Changed: :meth:`Value.cast` casts :class:`ValueCastable` objects recursively.
|
||||||
* Changed: :meth:`Value.cast` treats instances of classes derived from both :class:`enum.Enum` and :class:`int` (including :class:`enum.IntEnum`) as enumerations rather than integers.
|
* Changed: :meth:`Value.cast` treats instances of classes derived from both :class:`enum.Enum` and :class:`int` (including :class:`enum.IntEnum`) as enumerations rather than integers.
|
||||||
* Changed: :meth:`Value.matches` with an empty list of patterns returns ``Const(1)`` rather than ``Const(0)``, to match the behavior of ``with m.Case():``.
|
* Changed: :meth:`Value.matches` with an empty list of patterns returns ``Const(1)`` rather than ``Const(0)``, to match the behavior of ``with m.Case():``.
|
||||||
* Changed: :class:`Cat` warns if an enumeration without an explicitly specified shape is used. (`RFC 3`_)
|
* Changed: :class:`Cat` warns if an enumeration without an explicitly specified shape is used. (`RFC 3`_)
|
||||||
* Deprecated: :meth:`Const.normalize`. (`RFC 5`_)
|
* Deprecated: :meth:`Const.normalize`. (`RFC 5`_)
|
||||||
|
* Deprecated: :class:`Repl`; use :meth:`Value.replicate` instead. (`RFC 10`_)
|
||||||
* Removed: (deprecated in 0.1) casting of :class:`Shape` to and from a ``(width, signed)`` tuple.
|
* Removed: (deprecated in 0.1) casting of :class:`Shape` to and from a ``(width, signed)`` tuple.
|
||||||
* Removed: (deprecated in 0.3) :class:`ast.UserValue`.
|
* Removed: (deprecated in 0.3) :class:`ast.UserValue`.
|
||||||
* Removed: (deprecated in 0.3) support for ``# nmigen:`` linter instructions at the beginning of file.
|
* Removed: (deprecated in 0.3) support for ``# nmigen:`` linter instructions at the beginning of file.
|
||||||
|
|
|
@ -705,7 +705,7 @@ Operation Description Notes
|
||||||
``a.bit_select(b, w)`` overlapping part select with variable offset
|
``a.bit_select(b, w)`` overlapping part select with variable offset
|
||||||
``a.word_select(b, w)`` non-overlapping part select with variable offset
|
``a.word_select(b, w)`` non-overlapping part select with variable offset
|
||||||
``Cat(a, b)`` concatenation [#opS3]_
|
``Cat(a, b)`` concatenation [#opS3]_
|
||||||
``Repl(a, n)`` replication
|
``a.replicate(n)`` replication
|
||||||
======================= ================================================ ======
|
======================= ================================================ ======
|
||||||
|
|
||||||
.. [#opS1] Words "length" and "width" have the same meaning when talking about Amaranth values. Conventionally, "width" is used.
|
.. [#opS1] Words "length" and "width" have the same meaning when talking about Amaranth values. Conventionally, "width" is used.
|
||||||
|
@ -718,7 +718,7 @@ For the operators introduced by Amaranth, the following table explains them in t
|
||||||
Amaranth operation Equivalent Python code
|
Amaranth operation Equivalent Python code
|
||||||
======================= ======================
|
======================= ======================
|
||||||
``Cat(a, b)`` ``a + b``
|
``Cat(a, b)`` ``a + b``
|
||||||
``Repl(a, n)`` ``a * n``
|
``a.replicate(n)`` ``a * n``
|
||||||
``a.bit_select(b, w)`` ``a[b:b+w]``
|
``a.bit_select(b, w)`` ``a[b:b+w]``
|
||||||
``a.word_select(b, w)`` ``a[b*w:b*w+w]``
|
``a.word_select(b, w)`` ``a[b*w:b*w+w]``
|
||||||
======================= ======================
|
======================= ======================
|
||||||
|
|
|
@ -353,6 +353,23 @@ class ValueTestCase(FHDLTestCase):
|
||||||
r"^Rotate amount must be an integer, not 'str'$"):
|
r"^Rotate amount must be an integer, not 'str'$"):
|
||||||
Const(31).rotate_right("str")
|
Const(31).rotate_right("str")
|
||||||
|
|
||||||
|
def test_replicate_shape(self):
|
||||||
|
s1 = Const(10).replicate(3)
|
||||||
|
self.assertEqual(s1.shape(), unsigned(12))
|
||||||
|
self.assertIsInstance(s1.shape(), Shape)
|
||||||
|
s2 = Const(10).replicate(0)
|
||||||
|
self.assertEqual(s2.shape(), unsigned(0))
|
||||||
|
|
||||||
|
def test_replicate_count_wrong(self):
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
Const(10).replicate(-1)
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
Const(10).replicate("str")
|
||||||
|
|
||||||
|
def test_replicate_repr(self):
|
||||||
|
s = Const(10).replicate(3)
|
||||||
|
self.assertEqual(repr(s), "(cat (const 4'd10) (const 4'd10) (const 4'd10))")
|
||||||
|
|
||||||
|
|
||||||
class ConstTestCase(FHDLTestCase):
|
class ConstTestCase(FHDLTestCase):
|
||||||
def test_shape(self):
|
def test_shape(self):
|
||||||
|
@ -863,33 +880,19 @@ class CatTestCase(FHDLTestCase):
|
||||||
|
|
||||||
|
|
||||||
class ReplTestCase(FHDLTestCase):
|
class ReplTestCase(FHDLTestCase):
|
||||||
def test_shape(self):
|
@_ignore_deprecated
|
||||||
s1 = Repl(Const(10), 3)
|
|
||||||
self.assertEqual(s1.shape(), unsigned(12))
|
|
||||||
self.assertIsInstance(s1.shape(), Shape)
|
|
||||||
s2 = Repl(Const(10), 0)
|
|
||||||
self.assertEqual(s2.shape(), unsigned(0))
|
|
||||||
|
|
||||||
def test_count_wrong(self):
|
|
||||||
with self.assertRaises(TypeError):
|
|
||||||
Repl(Const(10), -1)
|
|
||||||
with self.assertRaises(TypeError):
|
|
||||||
Repl(Const(10), "str")
|
|
||||||
|
|
||||||
def test_repr(self):
|
|
||||||
s = Repl(Const(10), 3)
|
|
||||||
self.assertEqual(repr(s), "(repl (const 4'd10) 3)")
|
|
||||||
|
|
||||||
def test_cast(self):
|
def test_cast(self):
|
||||||
r = Repl(0, 3)
|
r = Repl(0, 3)
|
||||||
self.assertEqual(repr(r), "(repl (const 1'd0) 3)")
|
self.assertEqual(repr(r), "(cat (const 1'd0) (const 1'd0) (const 1'd0))")
|
||||||
|
|
||||||
|
@_ignore_deprecated
|
||||||
def test_int_01(self):
|
def test_int_01(self):
|
||||||
with warnings.catch_warnings():
|
with warnings.catch_warnings():
|
||||||
warnings.filterwarnings(action="error", category=SyntaxWarning)
|
warnings.filterwarnings(action="error", category=SyntaxWarning)
|
||||||
Repl(0, 3)
|
Repl(0, 3)
|
||||||
Repl(1, 3)
|
Repl(1, 3)
|
||||||
|
|
||||||
|
@_ignore_deprecated
|
||||||
def test_int_wrong(self):
|
def test_int_wrong(self):
|
||||||
with self.assertWarnsRegex(SyntaxWarning,
|
with self.assertWarnsRegex(SyntaxWarning,
|
||||||
r"^Value argument of Repl\(\) is a bare integer 2 used in bit vector context; "
|
r"^Value argument of Repl\(\) is a bare integer 2 used in bit vector context; "
|
||||||
|
|
|
@ -556,7 +556,22 @@ class EnableInserterTestCase(FHDLTestCase):
|
||||||
mem = Memory(width=8, depth=4)
|
mem = Memory(width=8, depth=4)
|
||||||
f = EnableInserter(self.c1)(mem.write_port()).elaborate(platform=None)
|
f = EnableInserter(self.c1)(mem.write_port()).elaborate(platform=None)
|
||||||
self.assertRepr(f.named_ports["EN"][0], """
|
self.assertRepr(f.named_ports["EN"][0], """
|
||||||
(m (sig c1) (cat (repl (slice (sig mem_w_en) 0:1) 8)) (const 8'd0))
|
(m
|
||||||
|
(sig c1)
|
||||||
|
(cat
|
||||||
|
(cat
|
||||||
|
(slice (sig mem_w_en) 0:1)
|
||||||
|
(slice (sig mem_w_en) 0:1)
|
||||||
|
(slice (sig mem_w_en) 0:1)
|
||||||
|
(slice (sig mem_w_en) 0:1)
|
||||||
|
(slice (sig mem_w_en) 0:1)
|
||||||
|
(slice (sig mem_w_en) 0:1)
|
||||||
|
(slice (sig mem_w_en) 0:1)
|
||||||
|
(slice (sig mem_w_en) 0:1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(const 8'd0)
|
||||||
|
)
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -289,8 +289,8 @@ class SimulatorUnitTestCase(FHDLTestCase):
|
||||||
stmt = lambda y, a: [rec.eq(a), y.eq(rec)]
|
stmt = lambda y, a: [rec.eq(a), y.eq(rec)]
|
||||||
self.assertStatement(stmt, [C(0b101, 3)], C(0b101, 3))
|
self.assertStatement(stmt, [C(0b101, 3)], C(0b101, 3))
|
||||||
|
|
||||||
def test_repl(self):
|
def test_replicate(self):
|
||||||
stmt = lambda y, a: y.eq(Repl(a, 3))
|
stmt = lambda y, a: y.eq(a.replicate(3))
|
||||||
self.assertStatement(stmt, [C(0b10, 2)], C(0b101010, 6))
|
self.assertStatement(stmt, [C(0b10, 2)], C(0b101010, 6))
|
||||||
|
|
||||||
def test_array(self):
|
def test_array(self):
|
||||||
|
@ -879,11 +879,6 @@ class SimulatorRegressionTestCase(FHDLTestCase):
|
||||||
dut.d.comb += Signal().eq(Cat())
|
dut.d.comb += Signal().eq(Cat())
|
||||||
Simulator(dut).run()
|
Simulator(dut).run()
|
||||||
|
|
||||||
def test_bug_325_bis(self):
|
|
||||||
dut = Module()
|
|
||||||
dut.d.comb += Signal().eq(Repl(Const(1), 0))
|
|
||||||
Simulator(dut).run()
|
|
||||||
|
|
||||||
def test_bug_473(self):
|
def test_bug_473(self):
|
||||||
sim = Simulator(Module())
|
sim = Simulator(Module())
|
||||||
def process():
|
def process():
|
||||||
|
|
Loading…
Reference in a new issue