From 404f99f022c79cd758adc3647165953205b409ca Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 19 Aug 2019 21:06:54 +0000 Subject: [PATCH] hdl.xfrm: consider fragment's own domains in DomainLowerer. Changed in preparation for introducing local clock domains. --- nmigen/hdl/ir.py | 2 +- nmigen/hdl/xfrm.py | 29 ++++++++++++++++++++++++----- nmigen/test/test_hdl_xfrm.py | 20 ++++++++++++-------- 3 files changed, 37 insertions(+), 14 deletions(-) diff --git a/nmigen/hdl/ir.py b/nmigen/hdl/ir.py index 6dd5d08..79e308a 100644 --- a/nmigen/hdl/ir.py +++ b/nmigen/hdl/ir.py @@ -395,7 +395,7 @@ class Fragment: def _lower_domain_signals(self): from .xfrm import DomainLowerer - return DomainLowerer(self.domains)(self) + return DomainLowerer()(self) def _prepare_use_def_graph(self, parent, level, uses, defs, ios, top): def add_uses(*sigs, self=self): diff --git a/nmigen/hdl/xfrm.py b/nmigen/hdl/xfrm.py index 4c96b7c..2fdf707 100644 --- a/nmigen/hdl/xfrm.py +++ b/nmigen/hdl/xfrm.py @@ -337,6 +337,11 @@ class TransformedElaboratable(Elaboratable): class DomainCollector(ValueVisitor, StatementVisitor): def __init__(self): self.domains = set() + self._local_domains = set() + + def _add_domain(self, domain_name): + if domain_name not in self._local_domains: + self.domains.add(domain_name) def on_ignore(self, value): pass @@ -347,10 +352,10 @@ class DomainCollector(ValueVisitor, StatementVisitor): on_Signal = on_ignore def on_ClockSignal(self, value): - self.domains.add(value.domain) + self._add_domain(value.domain) def on_ResetSignal(self, value): - self.domains.add(value.domain) + self._add_domain(value.domain) on_Record = on_ignore @@ -406,11 +411,20 @@ class DomainCollector(ValueVisitor, StatementVisitor): if isinstance(fragment, Instance): for name, (value, dir) in fragment.named_ports.items(): self.on_value(value) + + old_local_domains, self._local_domains = self._local_domains, set(self._local_domains) + for domain_name, domain in fragment.domains.items(): + if domain.local: + self._local_domains.add(domain_name) + self.on_statements(fragment.statements) - self.domains.update(fragment.drivers.keys()) + for domain_name in fragment.drivers: + self._add_domain(domain_name) for subfragment, name in fragment.subfragments: self.on_fragment(subfragment) + self._local_domains = old_local_domains + def __call__(self, fragment): self.on_fragment(fragment) return self.domains @@ -457,8 +471,8 @@ class DomainRenamer(FragmentTransformer, ValueTransformer, StatementTransformer) class DomainLowerer(FragmentTransformer, ValueTransformer, StatementTransformer): - def __init__(self, domains): - self.domains = domains + def __init__(self): + self.domains = None def _resolve(self, domain, context): if domain not in self.domains: @@ -487,6 +501,11 @@ class DomainLowerer(FragmentTransformer, ValueTransformer, StatementTransformer) .format(value, value.domain)) return cd.rst + def on_fragment(self, fragment): + self.domains = fragment.domains + new_fragment = super().on_fragment(fragment) + return new_fragment + class SampleDomainInjector(ValueTransformer, StatementTransformer): def __init__(self, domain): diff --git a/nmigen/test/test_hdl_xfrm.py b/nmigen/test/test_hdl_xfrm.py index 4081dd4..1a2a6c8 100644 --- a/nmigen/test/test_hdl_xfrm.py +++ b/nmigen/test/test_hdl_xfrm.py @@ -107,11 +107,12 @@ class DomainLowererTestCase(FHDLTestCase): def test_lower_clk(self): sync = ClockDomain() f = Fragment() + f.add_domains(sync) f.add_statements( self.s.eq(ClockSignal("sync")) ) - f = DomainLowerer({"sync": sync})(f) + f = DomainLowerer()(f) self.assertRepr(f.statements, """ ( (eq (sig s) (sig clk)) @@ -121,11 +122,12 @@ class DomainLowererTestCase(FHDLTestCase): def test_lower_rst(self): sync = ClockDomain() f = Fragment() + f.add_domains(sync) f.add_statements( self.s.eq(ResetSignal("sync")) ) - f = DomainLowerer({"sync": sync})(f) + f = DomainLowerer()(f) self.assertRepr(f.statements, """ ( (eq (sig s) (sig rst)) @@ -135,11 +137,12 @@ class DomainLowererTestCase(FHDLTestCase): def test_lower_rst_reset_less(self): sync = ClockDomain(reset_less=True) f = Fragment() + f.add_domains(sync) f.add_statements( self.s.eq(ResetSignal("sync", allow_reset_less=True)) ) - f = DomainLowerer({"sync": sync})(f) + f = DomainLowerer()(f) self.assertRepr(f.statements, """ ( (eq (sig s) (const 1'd0)) @@ -149,17 +152,17 @@ class DomainLowererTestCase(FHDLTestCase): def test_lower_drivers(self): pix = ClockDomain() f = Fragment() + f.add_domains(pix) f.add_driver(ClockSignal("pix"), None) f.add_driver(ResetSignal("pix"), "sync") - f = DomainLowerer({"pix": pix})(f) + f = DomainLowerer()(f) self.assertEqual(f.drivers, { None: SignalSet((pix.clk,)), "sync": SignalSet((pix.rst,)) }) def test_lower_wrong_domain(self): - sync = ClockDomain() f = Fragment() f.add_statements( self.s.eq(ClockSignal("xxx")) @@ -167,18 +170,19 @@ class DomainLowererTestCase(FHDLTestCase): with self.assertRaises(DomainError, msg="Signal (clk xxx) refers to nonexistent domain 'xxx'"): - DomainLowerer({"sync": sync})(f) + DomainLowerer()(f) def test_lower_wrong_reset_less_domain(self): sync = ClockDomain(reset_less=True) f = Fragment() + f.add_domains(sync) f.add_statements( self.s.eq(ResetSignal("sync")) ) with self.assertRaises(DomainError, msg="Signal (rst sync) refers to reset of reset-less domain 'sync'"): - DomainLowerer({"sync": sync})(f) + DomainLowerer()(f) class SampleLowererTestCase(FHDLTestCase): @@ -600,7 +604,7 @@ class UserValueTestCase(FHDLTestCase): f.add_driver(signal, "sync") f = ResetInserter(self.c)(f) - f = DomainLowerer({"sync": sync})(f) + f = DomainLowerer()(f) self.assertRepr(f.statements, """ ( (eq (sig s) (const 1'd1)) -- 2.30.2