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)
This commit is contained in:
parent
aac953dd90
commit
4091af69fd
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue