From: whitequark Date: Mon, 19 Aug 2019 20:46:46 +0000 (+0000) Subject: hdl.cd: implement local clock domains. X-Git-Tag: locally_working~20 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=003ba3b45f4e9f293da61a775cac9bdc6ae9ff6a;p=nmigen.git hdl.cd: implement local clock domains. Closes #175. --- diff --git a/nmigen/hdl/cd.py b/nmigen/hdl/cd.py index 06f8d79..6813a9d 100644 --- a/nmigen/hdl/cd.py +++ b/nmigen/hdl/cd.py @@ -25,6 +25,9 @@ class ClockDomain: If ``True``, the domain uses an asynchronous reset, and registers within this domain are initialized to their reset state when reset level changes. Otherwise, registers are initialized to reset state at the next clock cycle when reset is asserted. + local : bool + If ``True``, the domain will propagate only downwards in the design hierarchy. Otherwise, + the domain will propagate everywhere. Attributes ---------- @@ -42,7 +45,7 @@ class ClockDomain: else: return "{}_{}".format(domain_name, signal_name) - def __init__(self, name=None, reset_less=False, async_reset=False): + def __init__(self, name=None, reset_less=False, async_reset=False, local=False): if name is None: try: name = tracer.get_var_name() @@ -62,6 +65,8 @@ class ClockDomain: self.async_reset = async_reset + self.local = local + def rename(self, new_name): self.name = new_name self.clk.name = self._name_for(new_name, "clk") diff --git a/nmigen/hdl/ir.py b/nmigen/hdl/ir.py index c21bc82..bd52226 100644 --- a/nmigen/hdl/ir.py +++ b/nmigen/hdl/ir.py @@ -305,12 +305,14 @@ class Fragment: subfrag._propagate_domains_up(hierarchy + (hier_name,)) # Second, classify subfragments by domains they define. - for domain in subfrag.iter_domains(): - domain_subfrags[domain].add((subfrag, name, i)) + for domain_name, domain in subfrag.domains.items(): + if domain.local: + continue + domain_subfrags[domain_name].add((subfrag, name, i)) # For each domain defined by more than one subfragment, rename the domain in each # of the subfragments such that they no longer conflict. - for domain, subfrags in domain_subfrags.items(): + for domain_name, subfrags in domain_subfrags.items(): if len(subfrags) == 1: continue @@ -321,7 +323,7 @@ class Fragment: raise DomainError("Domain '{}' is defined by subfragments {} of fragment '{}'; " "it is necessary to either rename subfragment domains " "explicitly, or give names to subfragments" - .format(domain, ", ".join(names), ".".join(hierarchy))) + .format(domain_name, ", ".join(names), ".".join(hierarchy))) if len(names) != len(set(names)): names = sorted("#{}".format(i) for f, n, i in subfrags) @@ -329,16 +331,18 @@ class Fragment: "some of which have identical names; it is necessary to either " "rename subfragment domains explicitly, or give distinct names " "to subfragments" - .format(domain, ", ".join(names), ".".join(hierarchy))) + .format(domain_name, ", ".join(names), ".".join(hierarchy))) for subfrag, name, i in subfrags: - self.subfragments[i] = \ - (DomainRenamer({domain: "{}_{}".format(name, domain)})(subfrag), name) + domain_name_map = {domain_name: "{}_{}".format(name, domain_name)} + self.subfragments[i] = (DomainRenamer(domain_name_map)(subfrag), name) # Finally, collect the (now unique) subfragment domains, and merge them into our domains. for subfrag, name in self.subfragments: - for domain in subfrag.iter_domains(): - self.add_domains(subfrag.domains[domain]) + for domain_name, domain in subfrag.domains.items(): + if domain.local: + continue + self.add_domains(domain) def _propagate_domains_down(self): # For each domain defined in this fragment, ensure it also exists in all subfragments. diff --git a/nmigen/test/test_hdl_cd.py b/nmigen/test/test_hdl_cd.py index 23c4637..da04e2c 100644 --- a/nmigen/test/test_hdl_cd.py +++ b/nmigen/test/test_hdl_cd.py @@ -8,6 +8,7 @@ class ClockDomainTestCase(FHDLTestCase): self.assertEqual(sync.name, "sync") self.assertEqual(sync.clk.name, "clk") self.assertEqual(sync.rst.name, "rst") + self.assertEqual(sync.local, False) pix = ClockDomain() self.assertEqual(pix.name, "pix") self.assertEqual(pix.clk.name, "pix_clk") @@ -19,6 +20,8 @@ class ClockDomainTestCase(FHDLTestCase): with self.assertRaises(ValueError, msg="Clock domain name must be specified explicitly"): ClockDomain() + cd_reset = ClockDomain(local=True) + self.assertEqual(cd_reset.local, True) def test_with_reset(self): pix = ClockDomain() diff --git a/nmigen/test/test_hdl_ir.py b/nmigen/test/test_hdl_ir.py index c89e8d7..84bc2e2 100644 --- a/nmigen/test/test_hdl_ir.py +++ b/nmigen/test/test_hdl_ir.py @@ -290,6 +290,17 @@ class FragmentDomainsTestCase(FHDLTestCase): f1._propagate_domains_up() self.assertEqual(f1.domains, {"cd": cd}) + def test_propagate_up_local(self): + cd = ClockDomain(local=True) + + f1 = Fragment() + f2 = Fragment() + f1.add_subfragment(f2) + f2.add_domains(cd) + + f1._propagate_domains_up() + self.assertEqual(f1.domains, {}) + def test_domain_conflict(self): cda = ClockDomain("sync") cdb = ClockDomain("sync")