From 00cdddd4f3e2e6c93150809b94e83086c4a704c7 Mon Sep 17 00:00:00 2001 From: Catherine Date: Sat, 25 Nov 2023 00:38:33 +0000 Subject: [PATCH] hdl: remove deprecated `Sample`, `Past`, `Stable`, `Rose`, `Fell`. --- amaranth/asserts.py | 6 ++- amaranth/back/rtlil.py | 16 +++++--- amaranth/build/plat.py | 3 +- amaranth/hdl/ast.py | 74 +---------------------------------- amaranth/hdl/dsl.py | 4 +- amaranth/hdl/ir.py | 7 ++-- amaranth/hdl/xfrm.py | 88 ------------------------------------------ amaranth/sim/_pyrtl.py | 3 -- docs/changes.rst | 1 + tests/test_hdl_ast.py | 35 +---------------- tests/test_hdl_dsl.py | 19 --------- tests/test_hdl_xfrm.py | 48 ----------------------- tests/test_sim.py | 47 ---------------------- 13 files changed, 23 insertions(+), 328 deletions(-) diff --git a/amaranth/asserts.py b/amaranth/asserts.py index b0e97b9cb..6ff2037a4 100644 --- a/amaranth/asserts.py +++ b/amaranth/asserts.py @@ -1,2 +1,4 @@ -from .hdl.ast import AnyConst, AnySeq, Assert, Assume, Cover -from .hdl.ast import Past, Stable, Rose, Fell, Initial +from .hdl.ast import AnyConst, AnySeq, Initial, Assert, Assume, Cover + + +__all__ = ["AnyConst", "AnySeq", "Initial", "Assert", "Assume", "Cover"] diff --git a/amaranth/back/rtlil.py b/amaranth/back/rtlil.py index bd6a3f8ac..3af2f0aec 100644 --- a/amaranth/back/rtlil.py +++ b/amaranth/back/rtlil.py @@ -398,12 +398,6 @@ def on_ClockSignal(self, value): def on_ResetSignal(self, value): raise NotImplementedError # :nocov: - def on_Sample(self, value): - raise NotImplementedError # :nocov: - - def on_Initial(self, value): - raise NotImplementedError # :nocov: - def on_Cat(self, value): return "{{ {} }}".format(" ".join(reversed([self(o) for o in value.parts]))) @@ -498,6 +492,13 @@ def on_AnySeq(self, value): self.s.anys[value] = res return res + def on_Initial(self, value): + res = self.s.rtlil.wire(width=1, src=_src(value.src_loc)) + self.s.rtlil.cell("$initstate", ports={ + "\\Y": res, + }, src=_src(value.src_loc)) + return res + def on_Signal(self, value): wire_curr, wire_next = self.s.resolve(value) return wire_curr @@ -646,6 +647,9 @@ def on_AnyConst(self, value): def on_AnySeq(self, value): raise TypeError # :nocov: + def on_Initial(self, value): + raise TypeError # :nocov: + def on_Operator(self, value): if value.operator in ("u", "s"): # These operators are transparent on the LHS. diff --git a/amaranth/build/plat.py b/amaranth/build/plat.py index 5a56b29f5..d13217876 100644 --- a/amaranth/build/plat.py +++ b/amaranth/build/plat.py @@ -9,7 +9,7 @@ from .. import __version__ from .._toolchain import * from ..hdl import * -from ..hdl.xfrm import SampleLowerer, DomainLowerer +from ..hdl.xfrm import DomainLowerer from ..lib.cdc import ResetSynchronizer from ..back import rtlil, verilog from .res import * @@ -143,7 +143,6 @@ def prepare(self, elaboratable, name="top", **kwargs): self._prepared = True fragment = Fragment.get(elaboratable, self) - fragment = SampleLowerer()(fragment) fragment._propagate_domains(self.create_missing_domain, platform=self) fragment = DomainLowerer()(fragment) diff --git a/amaranth/hdl/ast.py b/amaranth/hdl/ast.py index af5746522..33e1ef949 100644 --- a/amaranth/hdl/ast.py +++ b/amaranth/hdl/ast.py @@ -20,7 +20,7 @@ "Array", "ArrayProxy", "Signal", "ClockSignal", "ResetSignal", "ValueCastable", "ValueLike", - "Sample", "Past", "Stable", "Rose", "Fell", "Initial", + "Initial", "Statement", "Switch", "Property", "Assign", "Assert", "Assume", "Cover", "ValueKey", "ValueDict", "ValueSet", "SignalKey", "SignalDict", "SignalSet", @@ -1549,70 +1549,6 @@ def __new__(cls, *args, **kwargs): raise TypeError("ValueLike is an abstract class and cannot be constructed") -# TODO(amaranth-0.5): remove -@final -class Sample(Value): - """Value from the past. - - A ``Sample`` of an expression is equal to the value of the expression ``clocks`` clock edges - of the ``domain`` clock back. If that moment is before the beginning of time, it is equal - to the value of the expression calculated as if each signal had its reset value. - """ - @deprecated("instead of using `Sample`, create a register explicitly") - def __init__(self, expr, clocks, domain, *, src_loc_at=0): - super().__init__(src_loc_at=1 + src_loc_at) - self.value = Value.cast(expr) - self.clocks = int(clocks) - self.domain = domain - if not isinstance(self.value, (Const, Signal, ClockSignal, ResetSignal, Initial)): - raise TypeError("Sampled value must be a signal or a constant, not {!r}" - .format(self.value)) - if self.clocks < 0: - raise ValueError("Cannot sample a value {} cycles in the future" - .format(-self.clocks)) - if not (self.domain is None or isinstance(self.domain, str)): - raise TypeError("Domain name must be a string or None, not {!r}" - .format(self.domain)) - - def shape(self): - return self.value.shape() - - def _rhs_signals(self): - return SignalSet((self,)) - - def __repr__(self): - return "(sample {!r} @ {}[{}])".format( - self.value, "" if self.domain is None else self.domain, self.clocks) - - -# TODO(amaranth-0.5): remove -@deprecated("instead of using `Past`, create a register explicitly") -def Past(expr, clocks=1, domain=None): - with _ignore_deprecated(): - return Sample(expr, clocks, domain) - - -# TODO(amaranth-0.5): remove -@deprecated("instead of using `Stable`, create registers and comparisons explicitly") -def Stable(expr, clocks=0, domain=None): - with _ignore_deprecated(): - return Sample(expr, clocks + 1, domain) == Sample(expr, clocks, domain) - - -# TODO(amaranth-0.5): remove -@deprecated("instead of using `Rose`, create registers and comparisons explicitly") -def Rose(expr, clocks=0, domain=None): - with _ignore_deprecated(): - return ~Sample(expr, clocks + 1, domain) & Sample(expr, clocks, domain) - - -# TODO(amaranth-0.5): remove -@deprecated("instead of using `Fell`, create registers and comparisons explicitly") -def Fell(expr, clocks=0, domain=None): - with _ignore_deprecated(): - return Sample(expr, clocks + 1, domain) & ~Sample(expr, clocks, domain) - - @final class Initial(Value): """Start indicator, for model checking. @@ -1626,7 +1562,7 @@ def shape(self): return Shape(1) def _rhs_signals(self): - return SignalSet((self,)) + return SignalSet() def __repr__(self): return "(initial)" @@ -1895,8 +1831,6 @@ def __init__(self, value): elif isinstance(self.value, ArrayProxy): self._hash = hash((ValueKey(self.value.index), tuple(ValueKey(e) for e in self.value._iter_as_values()))) - elif isinstance(self.value, Sample): - self._hash = hash((ValueKey(self.value.value), self.value.clocks, self.value.domain)) elif isinstance(self.value, Initial): self._hash = 0 else: # :nocov: @@ -1942,10 +1876,6 @@ def __eq__(self, other): all(ValueKey(a) == ValueKey(b) for a, b in zip(self.value._iter_as_values(), other.value._iter_as_values()))) - elif isinstance(self.value, Sample): - return (ValueKey(self.value.value) == ValueKey(other.value.value) and - self.value.clocks == other.value.clocks and - self.value.domain == self.value.domain) elif isinstance(self.value, Initial): return True else: # :nocov: diff --git a/amaranth/hdl/dsl.py b/amaranth/hdl/dsl.py index e6412ca08..6acd2fe7a 100644 --- a/amaranth/hdl/dsl.py +++ b/amaranth/hdl/dsl.py @@ -491,7 +491,6 @@ def domain_name(domain): .format(domain_name(domain))) stmt._MustUse__used = True - stmt = SampleDomainInjector(domain)(stmt) for signal in stmt._lhs_signals(): if signal not in self._driving: @@ -539,8 +538,7 @@ def elaborate(self, platform): fragment.add_subfragment(Fragment.get(self._named_submodules[name], platform), name) for submodule in self._anon_submodules: fragment.add_subfragment(Fragment.get(submodule, platform), None) - statements = SampleDomainInjector("sync")(self._statements) - fragment.add_statements(statements) + fragment.add_statements(self._statements) for signal, domain in self._driving.items(): fragment.add_driver(signal, domain) fragment.add_domains(self._domains.values()) diff --git a/amaranth/hdl/ir.py b/amaranth/hdl/ir.py index 5b2811f26..16aab52dd 100644 --- a/amaranth/hdl/ir.py +++ b/amaranth/hdl/ir.py @@ -506,11 +506,10 @@ def lca_of(fragu, fragv): self.add_ports(sig, dir="i") def prepare(self, ports=None, missing_domain=lambda name: ClockDomain(name)): - from .xfrm import SampleLowerer, DomainLowerer + from .xfrm import DomainLowerer - fragment = SampleLowerer()(self) - new_domains = fragment._propagate_domains(missing_domain) - fragment = DomainLowerer()(fragment) + new_domains = self._propagate_domains(missing_domain) + fragment = DomainLowerer()(self) if ports is None: fragment._propagate_ports(ports=(), all_undef_as_ports=True) else: diff --git a/amaranth/hdl/xfrm.py b/amaranth/hdl/xfrm.py index 1ef8ab7da..acda1cc22 100644 --- a/amaranth/hdl/xfrm.py +++ b/amaranth/hdl/xfrm.py @@ -15,7 +15,6 @@ "FragmentTransformer", "TransformedElaboratable", "DomainCollector", "DomainRenamer", "DomainLowerer", - "SampleDomainInjector", "SampleLowerer", "SwitchCleaner", "LHSGroupAnalyzer", "LHSGroupFilter", "ResetInserter", "EnableInserter"] @@ -65,10 +64,6 @@ def on_Cat(self, value): def on_ArrayProxy(self, value): pass # :nocov: - @abstractmethod - def on_Sample(self, value): - pass # :nocov: - @abstractmethod def on_Initial(self, value): pass # :nocov: @@ -103,8 +98,6 @@ def on_value(self, value): new_value = self.on_Cat(value) elif type(value) is ArrayProxy: new_value = self.on_ArrayProxy(value) - elif type(value) is Sample: - new_value = self.on_Sample(value) elif type(value) is Initial: new_value = self.on_Initial(value) else: @@ -153,9 +146,6 @@ def on_ArrayProxy(self, value): return ArrayProxy([self.on_value(elem) for elem in value._iter_as_values()], self.on_value(value.index)) - def on_Sample(self, value): - return Sample(self.on_value(value.value), value.clocks, value.domain) - def on_Initial(self, value): return value @@ -369,9 +359,6 @@ def on_ArrayProxy(self, value): self.on_value(elem) self.on_value(value.index) - def on_Sample(self, value): - self.on_value(value.value) - def on_Initial(self, value): pass @@ -509,81 +496,6 @@ def on_fragment(self, fragment): return new_fragment -class SampleDomainInjector(ValueTransformer, StatementTransformer): - def __init__(self, domain): - self.domain = domain - - @_ignore_deprecated - def on_Sample(self, value): - if value.domain is not None: - return value - return Sample(value.value, value.clocks, self.domain) - - def __call__(self, stmts): - return self.on_statement(stmts) - - -class SampleLowerer(FragmentTransformer, ValueTransformer, StatementTransformer): - def __init__(self): - self.initial = None - self.sample_cache = None - self.sample_stmts = None - - def _name_reset(self, value): - if isinstance(value, Const): - return f"c${value.value}", value.value - elif isinstance(value, Signal): - return f"s${value.name}", value.reset - elif isinstance(value, ClockSignal): - return "clk", 0 - elif isinstance(value, ResetSignal): - return "rst", 1 - elif isinstance(value, Initial): - return "init", 0 # Past(Initial()) produces 0, 1, 0, 0, ... - else: - raise NotImplementedError # :nocov: - - @_ignore_deprecated - def on_Sample(self, value): - if value in self.sample_cache: - return self.sample_cache[value] - - sampled_value = self.on_value(value.value) - if value.clocks == 0: - sample = sampled_value - else: - assert value.domain is not None - sampled_name, sampled_reset = self._name_reset(value.value) - name = f"$sample${sampled_name}${value.domain}${value.clocks}" - sample = Signal.like(value.value, name=name, reset_less=True, reset=sampled_reset) - sample.attrs["amaranth.sample_reg"] = True - - prev_sample = self.on_Sample(Sample(sampled_value, value.clocks - 1, value.domain)) - if value.domain not in self.sample_stmts: - self.sample_stmts[value.domain] = [] - self.sample_stmts[value.domain].append(sample.eq(prev_sample)) - - self.sample_cache[value] = sample - return sample - - def on_Initial(self, value): - if self.initial is None: - self.initial = Signal(name="init") - return self.initial - - def map_statements(self, fragment, new_fragment): - self.initial = None - self.sample_cache = ValueDict() - self.sample_stmts = OrderedDict() - new_fragment.add_statements(map(self.on_statement, fragment.statements)) - for domain, stmts in self.sample_stmts.items(): - new_fragment.add_statements(stmts) - for stmt in stmts: - new_fragment.add_driver(stmt.lhs, domain) - if self.initial is not None: - new_fragment.add_subfragment(Instance("$initstate", o_Y=self.initial)) - - class SwitchCleaner(StatementVisitor): def on_ignore(self, stmt): return stmt diff --git a/amaranth/sim/_pyrtl.py b/amaranth/sim/_pyrtl.py index a74006027..bb31cdfba 100644 --- a/amaranth/sim/_pyrtl.py +++ b/amaranth/sim/_pyrtl.py @@ -103,9 +103,6 @@ def on_AnyConst(self, value): def on_AnySeq(self, value): raise NotImplementedError # :nocov: - def on_Sample(self, value): - raise NotImplementedError # :nocov: - def on_Initial(self, value): raise NotImplementedError # :nocov: diff --git a/docs/changes.rst b/docs/changes.rst index 93716d771..0f718f59c 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -13,6 +13,7 @@ Language changes .. currentmodule:: amaranth.hdl * Removed: (deprecated in 0.4) :meth:`Const.normalize`. (`RFC 5`_) +* Removed: (deprecated in 0.4) :class:`ast.Sample`, :class:`ast.Past`, :class:`ast.Stable`, :class:`ast.Rose`, :class:`ast.Fell`. Standard library changes diff --git a/tests/test_hdl_ast.py b/tests/test_hdl_ast.py index 56dfca3d1..625e0e884 100644 --- a/tests/test_hdl_ast.py +++ b/tests/test_hdl_ast.py @@ -894,7 +894,7 @@ def test_repr(self): def test_cast(self): c = Cat(1, 0) self.assertEqual(repr(c), "(cat (const 1'd1) (const 1'd0))") - + def test_str_wrong(self): with self.assertRaisesRegex(TypeError, r"^Object 'foo' cannot be converted to an Amaranth value$"): @@ -1382,39 +1382,6 @@ class EnumD(Enum): self.assertFalse(isinstance(EnumD.A, ValueLike)) -class SampleTestCase(FHDLTestCase): - @_ignore_deprecated - def test_const(self): - s = Sample(1, 1, "sync") - self.assertEqual(s.shape(), unsigned(1)) - - @_ignore_deprecated - def test_signal(self): - s1 = Sample(Signal(2), 1, "sync") - self.assertEqual(s1.shape(), unsigned(2)) - s2 = Sample(ClockSignal(), 1, "sync") - s3 = Sample(ResetSignal(), 1, "sync") - - @_ignore_deprecated - def test_wrong_value_operator(self): - with self.assertRaisesRegex(TypeError, - (r"^Sampled value must be a signal or a constant, not " - r"\(\+ \(sig \$signal\) \(const 1'd1\)\)$")): - Sample(Signal() + 1, 1, "sync") - - @_ignore_deprecated - def test_wrong_clocks_neg(self): - with self.assertRaisesRegex(ValueError, - r"^Cannot sample a value 1 cycles in the future$"): - Sample(Signal(), -1, "sync") - - @_ignore_deprecated - def test_wrong_domain(self): - with self.assertRaisesRegex(TypeError, - r"^Domain name must be a string or None, not 0$"): - Sample(Signal(), 1, 0) - - class InitialTestCase(FHDLTestCase): def test_initial(self): i = Initial() diff --git a/tests/test_hdl_dsl.py b/tests/test_hdl_dsl.py index 9fc210ff5..9558ef61c 100644 --- a/tests/test_hdl_dsl.py +++ b/tests/test_hdl_dsl.py @@ -133,25 +133,6 @@ def test_reset_signal(self): ) """) - @_ignore_deprecated - def test_sample_domain(self): - m = Module() - i = Signal() - o1 = Signal() - o2 = Signal() - o3 = Signal() - m.d.sync += o1.eq(Past(i)) - m.d.pix += o2.eq(Past(i)) - m.d.pix += o3.eq(Past(i, domain="sync")) - f = m.elaborate(platform=None) - self.assertRepr(f.statements, """ - ( - (eq (sig o1) (sample (sig i) @ sync[1])) - (eq (sig o2) (sample (sig i) @ pix[1])) - (eq (sig o3) (sample (sig i) @ sync[1])) - ) - """) - def test_If(self): m = Module() with m.If(self.s1): diff --git a/tests/test_hdl_xfrm.py b/tests/test_hdl_xfrm.py index f450d005d..e3ff03b51 100644 --- a/tests/test_hdl_xfrm.py +++ b/tests/test_hdl_xfrm.py @@ -210,54 +210,6 @@ def test_lower_wrong_reset_less_domain(self): DomainLowerer()(f) -class SampleLowererTestCase(FHDLTestCase): - def setUp(self): - self.i = Signal() - self.o1 = Signal() - self.o2 = Signal() - self.o3 = Signal() - - @_ignore_deprecated - def test_lower_signal(self): - f = Fragment() - f.add_statements( - self.o1.eq(Sample(self.i, 2, "sync")), - self.o2.eq(Sample(self.i, 1, "sync")), - self.o3.eq(Sample(self.i, 1, "pix")), - ) - - f = SampleLowerer()(f) - self.assertRepr(f.statements, """ - ( - (eq (sig o1) (sig $sample$s$i$sync$2)) - (eq (sig o2) (sig $sample$s$i$sync$1)) - (eq (sig o3) (sig $sample$s$i$pix$1)) - (eq (sig $sample$s$i$sync$1) (sig i)) - (eq (sig $sample$s$i$sync$2) (sig $sample$s$i$sync$1)) - (eq (sig $sample$s$i$pix$1) (sig i)) - ) - """) - self.assertEqual(len(f.drivers["sync"]), 2) - self.assertEqual(len(f.drivers["pix"]), 1) - - @_ignore_deprecated - def test_lower_const(self): - f = Fragment() - f.add_statements( - self.o1.eq(Sample(1, 2, "sync")), - ) - - f = SampleLowerer()(f) - self.assertRepr(f.statements, """ - ( - (eq (sig o1) (sig $sample$c$1$sync$2)) - (eq (sig $sample$c$1$sync$1) (const 1'd1)) - (eq (sig $sample$c$1$sync$2) (sig $sample$c$1$sync$1)) - ) - """) - self.assertEqual(len(f.drivers["sync"]), 2) - - class SwitchCleanerTestCase(FHDLTestCase): def test_clean(self): a = Signal() diff --git a/tests/test_sim.py b/tests/test_sim.py index 60fd58e3e..19e493b25 100644 --- a/tests/test_sim.py +++ b/tests/test_sim.py @@ -911,53 +911,6 @@ def process(): sim.add_clock(1e-6) sim.add_sync_process(process) - @_ignore_deprecated - def test_sample_helpers(self): - m = Module() - s = Signal(2) - def mk(x): - y = Signal.like(x) - m.d.comb += y.eq(x) - return y - p0, r0, f0, s0 = mk(Past(s, 0)), mk(Rose(s)), mk(Fell(s)), mk(Stable(s)) - p1, r1, f1, s1 = mk(Past(s)), mk(Rose(s, 1)), mk(Fell(s, 1)), mk(Stable(s, 1)) - p2, r2, f2, s2 = mk(Past(s, 2)), mk(Rose(s, 2)), mk(Fell(s, 2)), mk(Stable(s, 2)) - p3, r3, f3, s3 = mk(Past(s, 3)), mk(Rose(s, 3)), mk(Fell(s, 3)), mk(Stable(s, 3)) - with self.assertSimulation(m) as sim: - def process_gen(): - yield s.eq(0b10) - yield - yield - yield s.eq(0b01) - yield - def process_check(): - yield - yield - yield - - self.assertEqual((yield p0), 0b01) - self.assertEqual((yield p1), 0b10) - self.assertEqual((yield p2), 0b10) - self.assertEqual((yield p3), 0b00) - - self.assertEqual((yield s0), 0b0) - self.assertEqual((yield s1), 0b1) - self.assertEqual((yield s2), 0b0) - self.assertEqual((yield s3), 0b1) - - self.assertEqual((yield r0), 0b01) - self.assertEqual((yield r1), 0b00) - self.assertEqual((yield r2), 0b10) - self.assertEqual((yield r3), 0b00) - - self.assertEqual((yield f0), 0b10) - self.assertEqual((yield f1), 0b00) - self.assertEqual((yield f2), 0b00) - self.assertEqual((yield f3), 0b00) - sim.add_clock(1e-6) - sim.add_sync_process(process_gen) - sim.add_sync_process(process_check) - def test_vcd_wrong_nonzero_time(self): s = Signal() m = Module()