hdl.ir: resolve hierarchy conflicts before creating missing domains.

Otherwise, code such as:

    m.submodules.a = (something with cd_sync)
    m.submodules.b = (something with cd_sync)
    m.d.b_sync += x.eq(y)

causes an assertion failure.

Fixes #304 (again).
This commit is contained in:
whitequark 2020-01-18 10:30:36 +00:00
parent 7cb3095334
commit a7be3b480a
2 changed files with 29 additions and 2 deletions

View file

@ -203,6 +203,15 @@ class Fragment:
driver_subfrags = SignalDict()
memory_subfrags = OrderedDict()
def add_subfrag(registry, entity, entry):
# Because of missing domain insertion, at the point when this code runs, we have
# a mixture of bound and unbound {Clock,Reset}Signals. Map the bound ones to
# the actual signals (because the signal itself can be driven as well); but leave
# the unbound ones as it is, because there's no concrete signal for it yet anyway.
if isinstance(entity, ClockSignal) and entity.domain in self.domains:
entity = self.domains[entity.domain].clk
elif isinstance(entity, ResetSignal) and entity.domain in self.domains:
entity = self.domains[entity.domain].rst
if entity not in registry:
registry[entity] = set()
registry[entity].add(entry)
@ -387,12 +396,15 @@ class Fragment:
"requested domain '{}' (defines {})."
.format(domain_name, ", ".join("'{}'".format(n) for n in defined)))
self.add_subfragment(new_fragment, "cd_{}".format(domain_name))
self.add_domains(new_fragment.domains.values())
return new_domains
def _propagate_domains(self, missing_domain):
new_domains = self.create_missing_domains(missing_domain)
self._propagate_domains_up()
self._propagate_domains_down()
self._resolve_hierarchy_conflicts()
new_domains = self.create_missing_domains(missing_domain)
self._propagate_domains_down()
return new_domains
def _prepare_use_def_graph(self, parent, level, uses, defs, ios, top):
@ -543,7 +555,6 @@ class Fragment:
fragment = SampleLowerer()(self)
new_domains = fragment._propagate_domains(missing_domain)
fragment = DomainLowerer()(fragment)
fragment._resolve_hierarchy_conflicts()
if ports is None:
fragment._propagate_ports(ports=(), all_undef_as_ports=True)
else:

View file

@ -408,6 +408,22 @@ class FragmentDomainsTestCase(FHDLTestCase):
None: SignalSet((ResetSignal("b_sync"),))
}))
def test_domain_conflict_rename_drivers(self):
cda = ClockDomain("sync")
cdb = ClockDomain("sync")
s = Signal()
fa = Fragment()
fa.add_domains(cda)
fb = Fragment()
fb.add_domains(cdb)
f = Fragment()
f.add_subfragment(fa, "a")
f.add_subfragment(fb, "b")
f.add_driver(s, "b_sync")
f._propagate_domains(lambda name: ClockDomain(name))
def test_propagate_down(self):
cd = ClockDomain()