hdl.ir: allow returning elaboratables from missing domain callback.
This allows e.g. injecting a clock/reset generator in platform build code on demand (i.e. if the domain is not instantiated manually). See #57.
This commit is contained in:
parent
fc846532c7
commit
cea92e9531
|
@ -359,9 +359,23 @@ class Fragment:
|
|||
if domain_name is None:
|
||||
continue
|
||||
if domain_name not in self.domains:
|
||||
domain = missing_domain(domain_name)
|
||||
if domain is None:
|
||||
value = missing_domain(domain_name)
|
||||
if value is None:
|
||||
raise DomainError("Domain '{}' is used but not defined".format(domain_name))
|
||||
if type(value) is ClockDomain:
|
||||
domain = value
|
||||
else:
|
||||
new_fragment = Fragment.get(value, platform=None)
|
||||
if new_fragment.domains.keys() != {domain_name}:
|
||||
raise DomainError(
|
||||
"Fragment returned by missing domain callback should define exactly "
|
||||
"one domain '{}', but defines domain(s) {}."
|
||||
.format(domain_name,
|
||||
", ".join("'{}'".format(n)
|
||||
for n in new_fragment.domains.keys())))
|
||||
new_fragment.flatten = True
|
||||
self.add_subfragment(new_fragment)
|
||||
domain = new_fragment.domains[domain_name]
|
||||
self.add_domains(domain)
|
||||
new_domains.append(domain)
|
||||
return new_domains
|
||||
|
|
|
@ -376,9 +376,10 @@ class FragmentDomainsTestCase(FHDLTestCase):
|
|||
f1.add_domains(cd)
|
||||
f1.add_subfragment(f2)
|
||||
|
||||
f1._propagate_domains(missing_domain=lambda name: None)
|
||||
new_domains = f1._propagate_domains(missing_domain=lambda name: None)
|
||||
self.assertEqual(f1.domains, {"cd": cd})
|
||||
self.assertEqual(f2.domains, {"cd": cd})
|
||||
self.assertEqual(new_domains, [])
|
||||
|
||||
def test_propagate_missing(self):
|
||||
s1 = Signal()
|
||||
|
@ -396,10 +397,42 @@ class FragmentDomainsTestCase(FHDLTestCase):
|
|||
f2 = Fragment()
|
||||
f1.add_subfragment(f2)
|
||||
|
||||
f1._propagate_domains(missing_domain=lambda name: ClockDomain(name))
|
||||
new_domains = f1._propagate_domains(missing_domain=lambda name: ClockDomain(name))
|
||||
self.assertEqual(f1.domains.keys(), {"sync"})
|
||||
self.assertEqual(f2.domains.keys(), {"sync"})
|
||||
self.assertEqual(f1.domains["sync"], f2.domains["sync"])
|
||||
self.assertEqual(new_domains, [f1.domains["sync"]])
|
||||
|
||||
def test_propagate_create_missing_fragment(self):
|
||||
s1 = Signal()
|
||||
f1 = Fragment()
|
||||
f1.add_driver(s1, "sync")
|
||||
|
||||
cd = ClockDomain("sync")
|
||||
f2 = Fragment()
|
||||
f2.add_domains(cd)
|
||||
|
||||
new_domains = f1._propagate_domains(missing_domain=lambda name: f2)
|
||||
self.assertEqual(f1.domains.keys(), {"sync"})
|
||||
self.assertEqual(f1.domains["sync"], f2.domains["sync"])
|
||||
self.assertEqual(new_domains, [f1.domains["sync"]])
|
||||
self.assertEqual(f1.subfragments, [
|
||||
(f2, None)
|
||||
])
|
||||
self.assertTrue(f2.flatten)
|
||||
|
||||
def test_propagate_create_missing_fragment_wrong(self):
|
||||
s1 = Signal()
|
||||
f1 = Fragment()
|
||||
f1.add_driver(s1, "sync")
|
||||
|
||||
f2 = Fragment()
|
||||
f2.add_domains(ClockDomain("foo"))
|
||||
|
||||
with self.assertRaises(DomainError,
|
||||
msg="Fragment returned by missing domain callback should define exactly "
|
||||
"one domain 'sync', but defines domain(s) 'foo'."):
|
||||
f1._propagate_domains(missing_domain=lambda name: f2)
|
||||
|
||||
|
||||
class FragmentHierarchyConflictTestCase(FHDLTestCase):
|
||||
|
|
Loading…
Reference in a new issue