From 4091af69fdc53c62b50d5387b4a2c69c7098c7c4 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 2 Apr 2015 14:28:19 -0600 Subject: [PATCH] fhdl/decorators: make the transform logic more idiomatic * 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 | 144 ++++++++++++++++++++++----------------- migen/fhdl/simplify.py | 6 +- 2 files changed, 85 insertions(+), 65 deletions(-) diff --git a/migen/fhdl/decorators.py b/migen/fhdl/decorators.py index f1314f945..815d7fcd1 100644 --- a/migen/fhdl/decorators.py +++ b/migen/fhdl/decorators.py @@ -1,94 +1,114 @@ +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_fragment(self, f): + def transform_instance(self, i): pass - def get_fragment(self): - f = self._md_decorated.get_fragment() - self.transform_fragment(f) - return f + # overload this in derived classes + def transform_fragment(self, i, f): + pass - def __dir__(self): - return dir(self._md_decorated) + def wrap_class(self, victim): + class Wrapped(victim): + def __init__(i, *args, **kwargs): + victim.__init__(i, *args, **kwargs) + self.transform_instance(i) -class DecorateModule: - def __init__(self, decorator, *dec_args, **dec_kwargs): - self.decorator = decorator - self.dec_args = dec_args - self.dec_kwargs = dec_kwargs + def get_fragment(i): + f = victim.get_fragment(i) + self.transform_fragment(i, f) + return f - 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)) + Wrapped.__name__ = victim.__name__ + # "{}_{}".format(self.__class__.__name__, victim.__name__) + return Wrapped -class InsertControl(ModuleDecorator): - def __init__(self, control_name, decorated, clock_domains=None): - ModuleDecorator.__init__(self, decorated) + def wrap_instance(self, victim): + self.transform_instance(victim) + orig_get_fragment = victim.get_fragment - object.__setattr__(self, "_ic_control_name", control_name) - object.__setattr__(self, "_ic_clock_domains", clock_domains) + def get_fragment(): + f = orig_get_fragment() + self.transform_fragment(victim, f) + return f - if clock_domains is None: - ctl = Signal(name=control_name) - assert(not hasattr(decorated, control_name)) - object.__setattr__(self, control_name, ctl) + 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 - def transform_fragment_insert(self, f, to_insert): +class ResetInserter(ControlInserter): + control_name = "reset" + + 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 diff --git a/migen/fhdl/simplify.py b/migen/fhdl/simplify.py index 531146553..1bc2eeca0 100644 --- a/migen/fhdl/simplify.py +++ b/migen/fhdl/simplify.py @@ -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: