hdl.ir: allow adding more than one domain in missing domain callback.

This is useful for injecting complex power-on reset logic.
This commit is contained in:
whitequark 2019-08-03 18:19:40 +00:00
parent 9c28b61d9f
commit e0b54b417e
2 changed files with 31 additions and 14 deletions

View file

@ -363,23 +363,21 @@ class Fragment:
if value is None: if value is None:
raise DomainError("Domain '{}' is used but not defined".format(domain_name)) raise DomainError("Domain '{}' is used but not defined".format(domain_name))
if type(value) is ClockDomain: if type(value) is ClockDomain:
domain = value self.add_domains(value)
# Only expose ports on clock domains returned directly, i.e. not as a part of # And expose ports on the newly added clock domain, since it is added directly
# a fragment driving that domain. # and there was no chance to add any logic driving it.
new_domains.append(domain) new_domains.append(value)
else: else:
new_fragment = Fragment.get(value, platform=None) new_fragment = Fragment.get(value, platform=None)
if new_fragment.domains.keys() != {domain_name}: if domain_name not in new_fragment.domains:
defined = new_fragment.domains.keys()
raise DomainError( raise DomainError(
"Fragment returned by missing domain callback should define exactly " "Fragment returned by missing domain callback does not define "
"one domain '{}', but defines domain(s) {}." "requested domain '{}' (defines {})."
.format(domain_name, .format(domain_name, ", ".join("'{}'".format(n) for n in defined)))
", ".join("'{}'".format(n)
for n in new_fragment.domains.keys())))
new_fragment.flatten = True new_fragment.flatten = True
self.add_subfragment(new_fragment) self.add_subfragment(new_fragment)
domain = new_fragment.domains[domain_name] self.add_domains(new_fragment.domains.values())
self.add_domains(domain)
return new_domains return new_domains
def _propagate_domains(self, missing_domain): def _propagate_domains(self, missing_domain):

View file

@ -421,6 +421,25 @@ class FragmentDomainsTestCase(FHDLTestCase):
]) ])
self.assertTrue(f2.flatten) self.assertTrue(f2.flatten)
def test_propagate_create_missing_fragment_many_domains(self):
s1 = Signal()
f1 = Fragment()
f1.add_driver(s1, "sync")
cd_por = ClockDomain("por")
cd_sync = ClockDomain("sync")
f2 = Fragment()
f2.add_domains(cd_por, cd_sync)
new_domains = f1._propagate_domains(missing_domain=lambda name: f2)
self.assertEqual(f1.domains.keys(), {"sync", "por"})
self.assertEqual(f2.domains.keys(), {"sync", "por"})
self.assertEqual(f1.domains["sync"], f2.domains["sync"])
self.assertEqual(new_domains, [])
self.assertEqual(f1.subfragments, [
(f2, None)
])
def test_propagate_create_missing_fragment_wrong(self): def test_propagate_create_missing_fragment_wrong(self):
s1 = Signal() s1 = Signal()
f1 = Fragment() f1 = Fragment()
@ -430,8 +449,8 @@ class FragmentDomainsTestCase(FHDLTestCase):
f2.add_domains(ClockDomain("foo")) f2.add_domains(ClockDomain("foo"))
with self.assertRaises(DomainError, with self.assertRaises(DomainError,
msg="Fragment returned by missing domain callback should define exactly " msg="Fragment returned by missing domain callback does not define requested "
"one domain 'sync', but defines domain(s) 'foo'."): "domain 'sync' (defines 'foo')."):
f1._propagate_domains(missing_domain=lambda name: f2) f1._propagate_domains(missing_domain=lambda name: f2)