diff --git a/migen/fhdl/decorators.py b/migen/fhdl/decorators.py new file mode 100644 index 000000000..0a9d1cf1c --- /dev/null +++ b/migen/fhdl/decorators.py @@ -0,0 +1,80 @@ +from migen.fhdl.structure import * +from migen.fhdl.tools import insert_reset + +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) + + # overload this in derived classes + def transform_fragment(self, f): + pass + + def get_fragment(self): + f = self._md_decorated.get_fragment() + self.transform_fragment(f) + return f + +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) + else: + for cd in clock_domains: + name = control_name + "_" + cd + ctl = Signal(name=name) + assert(not hasattr(decorated, name)) + object.__setattr__(self, name, ctl) + + def transform_fragment(self, f): + control_name = self._ic_control_name + clock_domains = self._ic_clock_domains + if 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)] + else: + to_insert = [(getattr(self, control_name+"_"+cdn), cdn) for cdn in clock_domains] + self.transform_fragment_insert(f, to_insert) + +class InsertCE(InsertControl): + def __init__(self, *args, **kwargs): + InsertControl.__init__(self, "ce", *args, **kwargs) + + def transform_fragment_insert(self, 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) + + def transform_fragment_insert(self, f, to_insert): + for reset, cdn in to_insert: + f.sync[cdn] = insert_reset(reset, f.sync[cdn]) diff --git a/migen/fhdl/std.py b/migen/fhdl/std.py index ccdc82c05..8a6f6845c 100644 --- a/migen/fhdl/std.py +++ b/migen/fhdl/std.py @@ -2,3 +2,4 @@ from migen.fhdl.structure import * from migen.fhdl.module import Module from migen.fhdl.specials import TSTriple, Instance, Memory from migen.fhdl.size import log2_int, bits_for, flen +from migen.fhdl.decorators import DecorateModule, InsertCE, InsertReset