From b4dab74b2e27f391faf65bb593f0ff045c120793 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 12 Dec 2018 15:44:54 +0000 Subject: [PATCH] compat.fhdl.{module,structure}: import/wrap Migen code (WIP). --- nmigen/compat/__init__.py | 4 +- nmigen/compat/fhdl/module.py | 132 ++++++++++++++++++++++++++++++++ nmigen/compat/fhdl/structure.py | 65 ++++++++++++++++ nmigen/fhdl/dsl.py | 12 +-- nmigen/tools.py | 4 +- 5 files changed, 208 insertions(+), 9 deletions(-) create mode 100644 nmigen/compat/fhdl/module.py create mode 100644 nmigen/compat/fhdl/structure.py diff --git a/nmigen/compat/__init__.py b/nmigen/compat/__init__.py index 47014fa..25bd84a 100644 --- a/nmigen/compat/__init__.py +++ b/nmigen/compat/__init__.py @@ -1,5 +1,5 @@ -# from .fhdl.structure import * -# from .fhdl.module import * +from .fhdl.structure import * +from .fhdl.module import * # from .fhdl.specials import * from .fhdl.bitcontainer import * # from .fhdl.decorators import * diff --git a/nmigen/compat/fhdl/module.py b/nmigen/compat/fhdl/module.py new file mode 100644 index 0000000..c5432bd --- /dev/null +++ b/nmigen/compat/fhdl/module.py @@ -0,0 +1,132 @@ +from collections import Iterable + +from ...tools import flatten, deprecated +from ...fhdl import dsl + + +__all__ = ["Module", "FinalizeError"] + + +def _flat_list(e): + if isinstance(e, Iterable): + return list(flatten(e)) + else: + return [e] + + +class CompatFinalizeError(Exception): + pass + + +FinalizeError = CompatFinalizeError + + +class _CompatModuleProxy: + def __init__(self, cm): + object.__setattr__(self, "_cm", cm) + + +class _CompatModuleComb(_CompatModuleProxy): + @deprecated("instead of `self.comb +=`, use `m.d.comb +=`") + def __iadd__(self, assigns): + self._cm._module._add_statement(assigns, cd_name=None, depth=0, compat_mode=True) + return self + + +class _CompatModuleSyncCD: + def __init__(self, cm, cd): + self._cm = cm + self._cd = cd + + @deprecated("instead of `self.sync. +=`, use `m.d. +=`") + def __iadd__(self, assigns): + self._cm._module._add_statement(assigns, cd_name=self._cd, depth=0, compat_mode=True) + return self + + +class _CompatModuleSync(_CompatModuleProxy): + @deprecated("instead of `self.sync +=`, use `m.d.sync +=`") + def __iadd__(self, assigns): + self._cm._module._add_statement(assigns, cd_name="sync", depth=0, compat_mode=True) + return self + + def __getattr__(self, name): + return _CompatModuleSyncCD(self._cm, name) + + def __setattr__(self, name, value): + if not isinstance(value, _ModuleSyncCD): + raise AttributeError("Attempted to assign sync property - use += instead") + + +class _CompatModuleForwardAttr: + @deprecated("TODO") + def __setattr__(self, name, value): + self.__iadd__(value) + setattr(self._cm, name, value) + + +class _CompatModuleSpecials(_CompatModuleProxy, _CompatModuleForwardAttr): + @deprecated("TODO") + def __iadd__(self, other): + self._cm._fragment.specials |= set(_flat_list(other)) + return self + + +class _CompatModuleSubmodules(_CompatModuleProxy): + @deprecated("TODO") + def __setattr__(self, name, value): + self._cm._submodules += [(name, e) for e in _flat_list(value)] + setattr(self._cm, name, value) + + @deprecated("TODO") + def __iadd__(self, other): + self._cm._submodules += [(None, e) for e in _flat_list(other)] + return self + + +class _CompatModuleClockDomains(_CompatModuleProxy, _CompatModuleForwardAttr): + @deprecated("TODO") + def __iadd__(self, other): + self._cm._fragment.clock_domains += _flat_list(other) + return self + + +class CompatModule: + def get_fragment(self): + assert not self.get_fragment_called + self.get_fragment_called = True + self.finalize() + return self._fragment + + def __getattr__(self, name): + if name == "comb": + return _CompatModuleComb(self) + elif name == "sync": + return _CompatModuleSync(self) + elif name == "specials": + return _CompatModuleSpecials(self) + elif name == "submodules": + return _CompatModuleSubmodules(self) + elif name == "clock_domains": + return _CompatModuleClockDomains(self) + elif name == "finalized": + self.finalized = False + return self.finalized + elif name == "_module": + self._module = dsl.Module() + return self._module + elif name == "_submodules": + self._submodules = [] + return self._submodules + elif name == "_clock_domains": + self._clock_domains = [] + return self._clock_domains + elif name == "get_fragment_called": + self.get_fragment_called = False + return self.get_fragment_called + else: + raise AttributeError("'{}' object has no attribute '{}'" + .format(type(self).__name__, name)) + + +Module = CompatModule diff --git a/nmigen/compat/fhdl/structure.py b/nmigen/compat/fhdl/structure.py new file mode 100644 index 0000000..95b8b5c --- /dev/null +++ b/nmigen/compat/fhdl/structure.py @@ -0,0 +1,65 @@ +from collections import OrderedDict + +from ...tools import deprecated +from ...fhdl import ast +from ...fhdl.ast import DUID, Value, Signal, Mux, Cat, Repl, Const, C, ClockSignal, ResetSignal +from ...fhdl.cd import ClockDomain + + +__all__ = ["DUID", "wrap", "Mux", "Cat", "Replicate", "Constant", "C", "Signal", "ClockSignal", + "ResetSignal", "If", "Case", "Array", "ClockDomain", + "SPECIAL_INPUT", "SPECIAL_OUTPUT", "SPECIAL_INOUT"] + + +@deprecated("instead of `wrap`, use `Value.wrap`") +def wrap(v): + return Value.wrap(v) + + +@deprecated("instead of `Replicate`, use `Repl`") +def Replicate(v, n): + return Repl(v, n) + + +@deprecated("instead of `Constant`, use `Const`") +def Constant(value, bits_sign=None): + return Const(value, bits_sign) + + +class If(ast.Switch): + @deprecated("instead of `If(cond, ...)`, use `with m.If(cond): ...`") + def __init__(self, cond, *stmts): + super().__init__(cond, {"1": ast.Statement.wrap(stmts)}) + + @deprecated("instead of `.Elif(cond, ...)`, use `with m.Elif(cond): ...`") + def Elif(self, cond, *stmts): + self.cases = OrderedDict(("-" + k, v) for k, v in self.cases.items()) + self.cases["1" + "-" * len(self.test)] = ast.Statement.wrap(stmts) + self.test = Cat(self.test, cond) + return self + + @deprecated("instead of `.Else(...)`, use `with m.Else(): ...`") + def Else(self, *stmts): + self.cases["-" * len(self.test)] = ast.Statement.wrap(stmts) + return self + + +class Case(ast.Switch): + @deprecated("instead of `Case(test, ...)`, use `with m.Case(test, ...):`") + def __init__(self, test, cases): + new_cases = [] + for k, v in cases.items(): + if k == "default": + k = "-" * len(ast.Value.wrap(test)) + new_cases.append((k, v)) + super().__init__(test, OrderedDict(new_cases)) + + def makedefault(self, key=None): + raise NotImplementedError + + +def Array(*args): + raise NotImplementedError + + +(SPECIAL_INPUT, SPECIAL_OUTPUT, SPECIAL_INOUT) = range(3) diff --git a/nmigen/fhdl/dsl.py b/nmigen/fhdl/dsl.py index 66759e8..d5b73b9 100644 --- a/nmigen/fhdl/dsl.py +++ b/nmigen/fhdl/dsl.py @@ -192,7 +192,7 @@ class Module(_ModuleBuilderRoot): self._stmt_switch_test = None self._stmt_switch_cases = OrderedDict() - def _add_statement(self, assigns, cd_name, depth): + def _add_statement(self, assigns, cd_name, depth, compat_mode=False): def cd_human_name(cd_name): if cd_name is None: return "comb" @@ -204,17 +204,19 @@ class Module(_ModuleBuilderRoot): self._stmt_depth = depth for assign in Statement.wrap(assigns): - if not isinstance(assign, Assign): - raise TypeError("Only assignments can be appended to {}".format(self.cd_name(cd))) + if not compat_mode and not isinstance(assign, Assign): + raise TypeError("Only assignments can be appended to {}" + .format(cd_human_name(cd_name))) - for signal in assign.lhs._lhs_signals(): + for signal in assign._lhs_signals(): if signal not in self._driving: self._driving[signal] = cd_name elif self._driving[signal] != cd_name: cd_curr = self._driving[signal] raise ValueError("Driver-driver conflict: trying to drive {!r} from d.{}, but " "it is already driven from d.{}" - .format(signal, cd_human_name(cd), cd_human_name(cd_curr))) + .format(signal, cd_human_name(cd_name), + cd_human_name(cd_curr))) self._statements.append(assign) diff --git a/nmigen/tools.py b/nmigen/tools.py index 3a2b968..87b3377 100644 --- a/nmigen/tools.py +++ b/nmigen/tools.py @@ -44,11 +44,11 @@ def bits_for(n, require_sign_bit=False): return r -def deprecated(message): +def deprecated(message, stacklevel=2): def decorator(f): @functools.wraps(f) def wrapper(*args, **kwargs): - warnings.warn(message, DeprecationWarning, stacklevel=2) + warnings.warn(message, DeprecationWarning, stacklevel=stacklevel) return f(*args, **kwargs) return wrapper return decorator -- 2.30.2