Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/nmigen
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: fdb0c5a6bc5f
Choose a base ref
...
head repository: m-labs/nmigen
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: cea92e95314e
Choose a head ref
  • 2 commits
  • 2 files changed
  • 1 contributor

Commits on Aug 3, 2019

  1. hdl.ir: raise DomainError if a domain is used but not defined.

    Before this commit, a KeyError would be raised elsewhere in guts of
    hdl.ir, which is not helpful.
    whitequark committed Aug 3, 2019
    Copy the full SHA
    fc84653 View commit details
  2. 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.
    whitequark committed Aug 3, 2019
    Copy the full SHA
    cea92e9 View commit details
Showing with 69 additions and 8 deletions.
  1. +25 −6 nmigen/hdl/ir.py
  2. +44 −2 nmigen/test/test_hdl_ir.py
31 changes: 25 additions & 6 deletions nmigen/hdl/ir.py
Original file line number Diff line number Diff line change
@@ -351,19 +351,38 @@ def _propagate_domains_down(self):

subfrag._propagate_domains_down()

def _propagate_domains(self, missing_domain):
def _create_missing_domains(self, missing_domain):
from .xfrm import DomainCollector

self._propagate_domains_up()
new_domains = []
for domain_name in DomainCollector()(self):
if domain_name is None:
continue
if domain_name not in self.domains:
domain = missing_domain(domain_name)
if domain is not None:
self.add_domains(domain)
new_domains.append(domain)
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

def _propagate_domains(self, missing_domain):
self._propagate_domains_up()
new_domains = self._create_missing_domains(missing_domain)
self._propagate_domains_down()
return new_domains

46 changes: 44 additions & 2 deletions nmigen/test/test_hdl_ir.py
Original file line number Diff line number Diff line change
@@ -376,9 +376,19 @@ def test_propagate(self):
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()
f1 = Fragment()
f1.add_driver(s1, "sync")

with self.assertRaises(DomainError,
msg="Domain 'sync' is used but not defined"):
f1._propagate_domains(missing_domain=lambda name: None)

def test_propagate_create_missing(self):
s1 = Signal()
@@ -387,10 +397,42 @@ def test_propagate_create_missing(self):
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):