compat.fhdl.{module,structure}: import/wrap Migen code (WIP).
authorwhitequark <cz@m-labs.hk>
Wed, 12 Dec 2018 15:44:54 +0000 (15:44 +0000)
committerwhitequark <cz@m-labs.hk>
Wed, 12 Dec 2018 15:47:34 +0000 (15:47 +0000)
nmigen/compat/__init__.py
nmigen/compat/fhdl/module.py [new file with mode: 0644]
nmigen/compat/fhdl/structure.py [new file with mode: 0644]
nmigen/fhdl/dsl.py
nmigen/tools.py

index 47014fa022bb38f51258f9eddf8f0d7ed36e8933..25bd84ac81ebc87a953c640412b2e490d32200a1 100644 (file)
@@ -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 (file)
index 0000000..c5432bd
--- /dev/null
@@ -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.<domain> +=`, use `m.d.<domain> +=`")
+    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 (file)
index 0000000..95b8b5c
--- /dev/null
@@ -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)
index 66759e84453377446dcc4be9042a62c2b06a91a2..d5b73b9e4c756962b29fbdd7d0170e40e60affb4 100644 (file)
@@ -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)
 
index 3a2b96871fe6c3f0adbca19e904c1cc4d499ae00..87b3377318aca6c6de4f3939b6fbb3ed07414ff5 100644 (file)
@@ -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