fhdl/decorators: make the transform logic more idiomatic
authorRobert Jordens <jordens@gmail.com>
Thu, 2 Apr 2015 20:28:19 +0000 (14:28 -0600)
committerSebastien Bourdeauducq <sb@m-labs.hk>
Sat, 4 Apr 2015 11:16:50 +0000 (19:16 +0800)
* the transformers work on classes and instances.
  you can now do just do:

    @ResetInserter()
    @ClockDomainRenamer({"sys": "new"})
    class Foo(Module):
        pass

  or:

    a = ResetInserter()(FooModule())

* the old usage semantics still work
* the old DecorateModule is deprecated,
  ModuleDecorator has been refactored into ModuleTransformer
  (because it not only decorates things)

migen/fhdl/decorators.py
migen/fhdl/simplify.py

index f1314f945fe6c7772b877b81f233b2f42ad91765..815d7fcd1c05be855da659173e35c24de03cdd6b 100644 (file)
+import warnings
+
 from migen.fhdl.structure import *
 from migen.fhdl.tools import insert_reset, rename_clock_domain
 
-class ModuleDecorator:
-       def __init__(self, decorated):
-               object.__setattr__(self, "_md_decorated", decorated)
-
-       def __getattr__(self, name):
-               return getattr(self._md_decorated, name)
-
-       def __setattr__(self, name, value):
-               return setattr(self._md_decorated, name, value)
+class ModuleTransformer:
+       # overload this in derived classes
+       def transform_instance(self, i):
+               pass
 
        # overload this in derived classes
-       def transform_fragment(self, f):
+       def transform_fragment(self, i, f):
                pass
 
-       def get_fragment(self):
-               f = self._md_decorated.get_fragment()
-               self.transform_fragment(f)
-               return f
-
-       def __dir__(self):
-               return dir(self._md_decorated)
-
-class DecorateModule:
-       def __init__(self, decorator, *dec_args, **dec_kwargs):
-               self.decorator = decorator
-               self.dec_args = dec_args
-               self.dec_kwargs = dec_kwargs
-
-       def __call__(self, decorated):
-               def dfinit(dfself, *args, **kwargs):
-                       self.decorator.__init__(dfself, decorated(*args, **kwargs),
-                               *self.dec_args, **self.dec_kwargs)
-               typename = self.decorator.__name__ + "(" + decorated.__name__ + ")"
-               return type(typename, (self.decorator,), dict(__init__=dfinit))
-
-class InsertControl(ModuleDecorator):
-       def __init__(self, control_name, decorated, clock_domains=None):
-               ModuleDecorator.__init__(self, decorated)
-
-               object.__setattr__(self, "_ic_control_name", control_name)
-               object.__setattr__(self, "_ic_clock_domains", clock_domains)
-
-               if clock_domains is None:
-                       ctl = Signal(name=control_name)
-                       assert(not hasattr(decorated, control_name))
-                       object.__setattr__(self, control_name, ctl)
+       def wrap_class(self, victim):
+               class Wrapped(victim):
+                       def __init__(i, *args, **kwargs):
+                               victim.__init__(i, *args, **kwargs)
+                               self.transform_instance(i)
+
+                       def get_fragment(i):
+                               f = victim.get_fragment(i)
+                               self.transform_fragment(i, f)
+                               return f
+
+               Wrapped.__name__ = victim.__name__
+               # "{}_{}".format(self.__class__.__name__, victim.__name__)
+               return Wrapped
+
+       def wrap_instance(self, victim):
+               self.transform_instance(victim)
+               orig_get_fragment = victim.get_fragment
+
+               def get_fragment():
+                       f = orig_get_fragment()
+                       self.transform_fragment(victim, f)
+                       return f
+
+               victim.get_fragment = get_fragment
+               return victim
+
+       def __call__(self, victim):
+               try:
+                       return self.wrap_class(victim)
+               except TypeError:
+                       return self.wrap_instance(victim)
+
+       @classmethod
+       def adhoc(cls, i, *args, **kwargs):
+               warnings.warn("deprecated, use the plain transformer", DeprecationWarning)
+               return cls(*args, **kwargs)(i)
+
+def DecorateModule(transformer, *args, **kwargs):
+       warnings.warn("deprecated, use the plain transformer", DeprecationWarning)
+       return transformer.__self__(*args, **kwargs)
+
+class ControlInserter(ModuleTransformer):
+       control_name = None  # override this
+
+       def __init__(self, clock_domains=None):
+               self.clock_domains = clock_domains
+
+       def transform_instance(self, i):
+               if self.clock_domains is None:
+                       ctl = Signal(name=self.control_name)
+                       assert not hasattr(i, self.control_name)
+                       setattr(i, self.control_name, ctl)
                else:
-                       for cd in clock_domains:
-                               name = control_name + "_" + cd
+                       for cd in self.clock_domains:
+                               name = self.control_name + "_" + cd
                                ctl = Signal(name=name)
-                               assert(not hasattr(decorated, name))
-                               object.__setattr__(self, name, ctl)
+                               assert not hasattr(i, name)
+                               setattr(i, name, ctl)
 
-       def transform_fragment(self, f):
-               control_name = self._ic_control_name
-               clock_domains = self._ic_clock_domains
-               if clock_domains is None:
+       def transform_fragment(self, i, f):
+               if self.clock_domains is None:
                        if len(f.sync) != 1:
                                raise ValueError("Control signal clock domains must be specified when module has more than one domain")
                        cdn = list(f.sync.keys())[0]
-                       to_insert = [(getattr(self, control_name), cdn)]
+                       to_insert = [(getattr(i, self.control_name), cdn)]
                else:
-                       to_insert = [(getattr(self, control_name+"_"+cdn), cdn) for cdn in clock_domains]
-               self.transform_fragment_insert(f, to_insert)
+                       to_insert = [(getattr(i, self.control_name + "_" + cdn), cdn)
+                               for cdn in clock_domains]
+               self.transform_fragment_insert(i, f, to_insert)
 
-class InsertCE(InsertControl):
-       def __init__(self, *args, **kwargs):
-               InsertControl.__init__(self, "ce", *args, **kwargs)
+class CEInserter(ControlInserter):
+       control_name = "ce"
 
-       def transform_fragment_insert(self, f, to_insert):
+       def transform_fragment_insert(self, i, f, to_insert):
                for ce, cdn in to_insert:
                        f.sync[cdn] = [If(ce, *f.sync[cdn])]
 
-class InsertReset(InsertControl):
-       def __init__(self, *args, **kwargs):
-               InsertControl.__init__(self, "reset", *args, **kwargs)
+InsertCE = CEInserter.adhoc
+
+class ResetInserter(ControlInserter):
+       control_name = "reset"
 
-       def transform_fragment_insert(self, f, to_insert):
+       def transform_fragment_insert(self, i, f, to_insert):
                for reset, cdn in to_insert:
                        f.sync[cdn] = insert_reset(reset, f.sync[cdn])
 
-class RenameClockDomains(ModuleDecorator):
-       def __init__(self, decorated, cd_remapping):
-               ModuleDecorator.__init__(self, decorated)
+InsertReset = ResetInserter.adhoc
+
+class ClockDomainsRenamer(ModuleTransformer):
+       def __init__(self, cd_remapping):
                if isinstance(cd_remapping, str):
                        cd_remapping = {"sys": cd_remapping}
-               object.__setattr__(self, "_rc_cd_remapping", cd_remapping)
+               self.cd_remapping = cd_remapping
 
-       def transform_fragment(self, f):
-               for old, new in self._rc_cd_remapping.items():
+       def transform_fragment(self, i, f):
+               for old, new in self.cd_remapping.items():
                        rename_clock_domain(f, old, new)
+
+RenameClockDomains = ClockDomainsRenamer.adhoc
index 531146553e0e75346c4810a42725fb9bcce80ada..1bc2eeca0ebf8754e4d65c9bfc05d0a96560cc01 100644 (file)
@@ -1,10 +1,10 @@
 from migen.fhdl.std import *
 from migen.fhdl.specials import _MemoryPort
-from migen.fhdl.decorators import ModuleDecorator
+from migen.fhdl.decorators import ModuleTransformer
 from migen.util.misc import gcd_multiple
 
-class FullMemoryWE(ModuleDecorator):
-       def transform_fragment(self, f):
+class FullMemoryWE(ModuleTransformer):
+       def transform_fragment(self, i, f):
                newspecials = set()
 
                for orig in f.specials: