hdl.xfrm: consider fragment's own domains in DomainLowerer.

Changed in preparation for introducing local clock domains.
This commit is contained in:
whitequark 2019-08-19 21:06:54 +00:00
parent 32bfbb11cb
commit 404f99f022
3 changed files with 37 additions and 14 deletions

View file

@ -395,7 +395,7 @@ class Fragment:
def _lower_domain_signals(self): def _lower_domain_signals(self):
from .xfrm import DomainLowerer 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 _prepare_use_def_graph(self, parent, level, uses, defs, ios, top):
def add_uses(*sigs, self=self): def add_uses(*sigs, self=self):

View file

@ -337,6 +337,11 @@ class TransformedElaboratable(Elaboratable):
class DomainCollector(ValueVisitor, StatementVisitor): class DomainCollector(ValueVisitor, StatementVisitor):
def __init__(self): def __init__(self):
self.domains = set() 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): def on_ignore(self, value):
pass pass
@ -347,10 +352,10 @@ class DomainCollector(ValueVisitor, StatementVisitor):
on_Signal = on_ignore on_Signal = on_ignore
def on_ClockSignal(self, value): def on_ClockSignal(self, value):
self.domains.add(value.domain) self._add_domain(value.domain)
def on_ResetSignal(self, value): def on_ResetSignal(self, value):
self.domains.add(value.domain) self._add_domain(value.domain)
on_Record = on_ignore on_Record = on_ignore
@ -406,11 +411,20 @@ class DomainCollector(ValueVisitor, StatementVisitor):
if isinstance(fragment, Instance): if isinstance(fragment, Instance):
for name, (value, dir) in fragment.named_ports.items(): for name, (value, dir) in fragment.named_ports.items():
self.on_value(value) 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.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: for subfragment, name in fragment.subfragments:
self.on_fragment(subfragment) self.on_fragment(subfragment)
self._local_domains = old_local_domains
def __call__(self, fragment): def __call__(self, fragment):
self.on_fragment(fragment) self.on_fragment(fragment)
return self.domains return self.domains
@ -457,8 +471,8 @@ class DomainRenamer(FragmentTransformer, ValueTransformer, StatementTransformer)
class DomainLowerer(FragmentTransformer, ValueTransformer, StatementTransformer): class DomainLowerer(FragmentTransformer, ValueTransformer, StatementTransformer):
def __init__(self, domains): def __init__(self):
self.domains = domains self.domains = None
def _resolve(self, domain, context): def _resolve(self, domain, context):
if domain not in self.domains: if domain not in self.domains:
@ -487,6 +501,11 @@ class DomainLowerer(FragmentTransformer, ValueTransformer, StatementTransformer)
.format(value, value.domain)) .format(value, value.domain))
return cd.rst 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): class SampleDomainInjector(ValueTransformer, StatementTransformer):
def __init__(self, domain): def __init__(self, domain):

View file

@ -107,11 +107,12 @@ class DomainLowererTestCase(FHDLTestCase):
def test_lower_clk(self): def test_lower_clk(self):
sync = ClockDomain() sync = ClockDomain()
f = Fragment() f = Fragment()
f.add_domains(sync)
f.add_statements( f.add_statements(
self.s.eq(ClockSignal("sync")) self.s.eq(ClockSignal("sync"))
) )
f = DomainLowerer({"sync": sync})(f) f = DomainLowerer()(f)
self.assertRepr(f.statements, """ self.assertRepr(f.statements, """
( (
(eq (sig s) (sig clk)) (eq (sig s) (sig clk))
@ -121,11 +122,12 @@ class DomainLowererTestCase(FHDLTestCase):
def test_lower_rst(self): def test_lower_rst(self):
sync = ClockDomain() sync = ClockDomain()
f = Fragment() f = Fragment()
f.add_domains(sync)
f.add_statements( f.add_statements(
self.s.eq(ResetSignal("sync")) self.s.eq(ResetSignal("sync"))
) )
f = DomainLowerer({"sync": sync})(f) f = DomainLowerer()(f)
self.assertRepr(f.statements, """ self.assertRepr(f.statements, """
( (
(eq (sig s) (sig rst)) (eq (sig s) (sig rst))
@ -135,11 +137,12 @@ class DomainLowererTestCase(FHDLTestCase):
def test_lower_rst_reset_less(self): def test_lower_rst_reset_less(self):
sync = ClockDomain(reset_less=True) sync = ClockDomain(reset_less=True)
f = Fragment() f = Fragment()
f.add_domains(sync)
f.add_statements( f.add_statements(
self.s.eq(ResetSignal("sync", allow_reset_less=True)) self.s.eq(ResetSignal("sync", allow_reset_less=True))
) )
f = DomainLowerer({"sync": sync})(f) f = DomainLowerer()(f)
self.assertRepr(f.statements, """ self.assertRepr(f.statements, """
( (
(eq (sig s) (const 1'd0)) (eq (sig s) (const 1'd0))
@ -149,17 +152,17 @@ class DomainLowererTestCase(FHDLTestCase):
def test_lower_drivers(self): def test_lower_drivers(self):
pix = ClockDomain() pix = ClockDomain()
f = Fragment() f = Fragment()
f.add_domains(pix)
f.add_driver(ClockSignal("pix"), None) f.add_driver(ClockSignal("pix"), None)
f.add_driver(ResetSignal("pix"), "sync") f.add_driver(ResetSignal("pix"), "sync")
f = DomainLowerer({"pix": pix})(f) f = DomainLowerer()(f)
self.assertEqual(f.drivers, { self.assertEqual(f.drivers, {
None: SignalSet((pix.clk,)), None: SignalSet((pix.clk,)),
"sync": SignalSet((pix.rst,)) "sync": SignalSet((pix.rst,))
}) })
def test_lower_wrong_domain(self): def test_lower_wrong_domain(self):
sync = ClockDomain()
f = Fragment() f = Fragment()
f.add_statements( f.add_statements(
self.s.eq(ClockSignal("xxx")) self.s.eq(ClockSignal("xxx"))
@ -167,18 +170,19 @@ class DomainLowererTestCase(FHDLTestCase):
with self.assertRaises(DomainError, with self.assertRaises(DomainError,
msg="Signal (clk xxx) refers to nonexistent domain 'xxx'"): msg="Signal (clk xxx) refers to nonexistent domain 'xxx'"):
DomainLowerer({"sync": sync})(f) DomainLowerer()(f)
def test_lower_wrong_reset_less_domain(self): def test_lower_wrong_reset_less_domain(self):
sync = ClockDomain(reset_less=True) sync = ClockDomain(reset_less=True)
f = Fragment() f = Fragment()
f.add_domains(sync)
f.add_statements( f.add_statements(
self.s.eq(ResetSignal("sync")) self.s.eq(ResetSignal("sync"))
) )
with self.assertRaises(DomainError, with self.assertRaises(DomainError,
msg="Signal (rst sync) refers to reset of reset-less domain 'sync'"): msg="Signal (rst sync) refers to reset of reset-less domain 'sync'"):
DomainLowerer({"sync": sync})(f) DomainLowerer()(f)
class SampleLowererTestCase(FHDLTestCase): class SampleLowererTestCase(FHDLTestCase):
@ -600,7 +604,7 @@ class UserValueTestCase(FHDLTestCase):
f.add_driver(signal, "sync") f.add_driver(signal, "sync")
f = ResetInserter(self.c)(f) f = ResetInserter(self.c)(f)
f = DomainLowerer({"sync": sync})(f) f = DomainLowerer()(f)
self.assertRepr(f.statements, """ self.assertRepr(f.statements, """
( (
(eq (sig s) (const 1'd1)) (eq (sig s) (const 1'd1))