From 015998eba9ca3d43aee3921e804a22aa7a5454cc Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 16 Dec 2018 23:51:24 +0000 Subject: [PATCH] hdl.dsl: add clock domain support. --- nmigen/compat/fhdl/module.py | 2 +- nmigen/hdl/dsl.py | 43 +++++++++++++++++++++++++----------- nmigen/hdl/ir.py | 2 +- nmigen/test/test_hdl_dsl.py | 12 ++++++++++ 4 files changed, 44 insertions(+), 15 deletions(-) diff --git a/nmigen/compat/fhdl/module.py b/nmigen/compat/fhdl/module.py index a9730ae..84b51a1 100644 --- a/nmigen/compat/fhdl/module.py +++ b/nmigen/compat/fhdl/module.py @@ -90,7 +90,7 @@ class _CompatModuleClockDomains(_CompatModuleProxy): @deprecated("TODO") def __iadd__(self, other): - self._cm._fragment.clock_domains += _flat_list(other) + self._cm._module.domains += _flat_list(other) return self diff --git a/nmigen/hdl/dsl.py b/nmigen/hdl/dsl.py index e240513..7a386db 100644 --- a/nmigen/hdl/dsl.py +++ b/nmigen/hdl/dsl.py @@ -2,6 +2,7 @@ from collections import OrderedDict from collections.abc import Iterable from contextlib import contextmanager +from ..tools import flatten from .ast import * from .ir import * from .xfrm import * @@ -20,7 +21,7 @@ class _ModuleBuilderProxy: object.__setattr__(self, "_depth", depth) -class _ModuleBuilderDomain(_ModuleBuilderProxy): +class _ModuleBuilderDomainExplicit(_ModuleBuilderProxy): def __init__(self, builder, depth, domain): super().__init__(builder, depth) self._domain = domain @@ -30,13 +31,13 @@ class _ModuleBuilderDomain(_ModuleBuilderProxy): return self -class _ModuleBuilderDomains(_ModuleBuilderProxy): +class _ModuleBuilderDomainImplicit(_ModuleBuilderProxy): def __getattr__(self, name): if name == "comb": domain = None else: domain = name - return _ModuleBuilderDomain(self._builder, self._depth, domain) + return _ModuleBuilderDomainExplicit(self._builder, self._depth, domain) def __getitem__(self, name): return self.__getattr__(name) @@ -44,7 +45,7 @@ class _ModuleBuilderDomains(_ModuleBuilderProxy): def __setattr__(self, name, value): if name == "_depth": object.__setattr__(self, name, value) - elif not isinstance(value, _ModuleBuilderDomain): + elif not isinstance(value, _ModuleBuilderDomainExplicit): raise AttributeError("Cannot assign 'd.{}' attribute; did you mean 'd.{} +='?" .format(name, name)) @@ -55,7 +56,7 @@ class _ModuleBuilderDomains(_ModuleBuilderProxy): class _ModuleBuilderRoot: def __init__(self, builder, depth): self._builder = builder - self.domain = self.d = _ModuleBuilderDomains(builder, depth) + self.domain = self.d = _ModuleBuilderDomainImplicit(builder, depth) def __getattr__(self, name): if name in ("comb", "sync"): @@ -70,11 +71,7 @@ class _ModuleBuilderSubmodules: object.__setattr__(self, "_builder", builder) def __iadd__(self, modules): - if isinstance(modules, Iterable): - for module in modules: - self._builder._add_submodule(module) - else: - module = modules + for module in flatten([modules]): self._builder._add_submodule(module) return self @@ -82,17 +79,33 @@ class _ModuleBuilderSubmodules: self._builder._add_submodule(submodule, name) +class _ModuleBuilderDomainSet: + def __init__(self, builder): + object.__setattr__(self, "_builder", builder) + + def __iadd__(self, domains): + for domain in flatten([domains]): + self._builder._add_domain(domain) + return self + + def __setattr__(self, name, domain): + self._builder._add_domain(domain) + + class Module(_ModuleBuilderRoot): def __init__(self): _ModuleBuilderRoot.__init__(self, self, depth=0) - self.submodules = _ModuleBuilderSubmodules(self) + self.submodules = _ModuleBuilderSubmodules(self) + self.domains = _ModuleBuilderDomainSet(self) - self._submodules = [] - self._driving = ValueDict() self._statements = Statement.wrap([]) self._ctrl_context = None self._ctrl_stack = [] + self._driving = ValueDict() + self._submodules = [] + self._domains = [] + def _check_context(self, construct, context): if self._ctrl_context != context: if self._ctrl_context is None: @@ -259,6 +272,9 @@ class Module(_ModuleBuilderRoot): "a submodule".format(submodule)) self._submodules.append((submodule, name)) + def _add_domain(self, cd): + self._domains.append(cd) + def _flush(self): while self._ctrl_stack: self._pop_ctrl() @@ -272,6 +288,7 @@ class Module(_ModuleBuilderRoot): fragment.add_statements(self._statements) for signal, domain in self._driving.items(): fragment.add_driver(signal, domain) + fragment.add_domains(self._domains) return fragment get_fragment = lower diff --git a/nmigen/hdl/ir.py b/nmigen/hdl/ir.py index 844cc7b..1ff1961 100644 --- a/nmigen/hdl/ir.py +++ b/nmigen/hdl/ir.py @@ -63,7 +63,7 @@ class Fragment: return signals def add_domains(self, *domains): - for domain in domains: + for domain in flatten(domains): assert isinstance(domain, ClockDomain) assert domain.name not in self.domains self.domains[domain.name] = domain diff --git a/nmigen/test/test_hdl_dsl.py b/nmigen/test/test_hdl_dsl.py index f156880..f5fec90 100644 --- a/nmigen/test/test_hdl_dsl.py +++ b/nmigen/test/test_hdl_dsl.py @@ -1,4 +1,5 @@ from ..hdl.ast import * +from ..hdl.cd import * from ..hdl.dsl import * from .tools import * @@ -342,6 +343,17 @@ class DSLTestCase(FHDLTestCase): msg="Trying to add '1', which does not implement .get_fragment(), as a submodule"): m.submodules += 1 + def test_domain_named_implicit(self): + m = Module() + m.domains += ClockDomain("sync") + self.assertEqual(len(m._domains), 1) + + def test_domain_named_explicit(self): + m = Module() + m.domains.foo = ClockDomain() + self.assertEqual(len(m._domains), 1) + self.assertEqual(m._domains[0].name, "foo") + def test_lower(self): m1 = Module() m1.d.comb += self.c1.eq(self.s1) -- 2.30.2