import migen in litex/gen
[litex.git] / litex / gen / migen / fhdl / decorators.py
1 from migen.fhdl.structure import *
2 from migen.fhdl.module import Module
3 from migen.fhdl.tools import insert_reset, rename_clock_domain
4
5
6 __all__ = ["CEInserter", "ResetInserter", "ClockDomainsRenamer",
7 "ModuleTransformer"]
8
9
10 class ModuleTransformer:
11 # overload this in derived classes
12 def transform_instance(self, i):
13 pass
14
15 # overload this in derived classes
16 def transform_fragment(self, i, f):
17 pass
18
19 def wrap_class(self, victim):
20 class Wrapped(victim):
21 def __init__(i, *args, **kwargs):
22 victim.__init__(i, *args, **kwargs)
23 self.transform_instance(i)
24
25 def get_fragment(i):
26 f = victim.get_fragment(i)
27 self.transform_fragment(i, f)
28 return f
29
30 Wrapped.__name__ = victim.__name__
31 # "{}_{}".format(self.__class__.__name__, victim.__name__)
32 return Wrapped
33
34 def wrap_instance(self, victim):
35 self.transform_instance(victim)
36 orig_get_fragment = victim.get_fragment
37
38 def get_fragment():
39 f = orig_get_fragment()
40 self.transform_fragment(victim, f)
41 return f
42
43 victim.get_fragment = get_fragment
44 return victim
45
46 def __call__(self, victim):
47 if isinstance(victim, Module):
48 return self.wrap_instance(victim)
49 else:
50 return self.wrap_class(victim)
51
52
53 class ControlInserter(ModuleTransformer):
54 control_name = None # override this
55
56 def __init__(self, clock_domains=None):
57 self.clock_domains = clock_domains
58
59 def transform_instance(self, i):
60 if self.clock_domains is None:
61 ctl = Signal(name=self.control_name)
62 assert not hasattr(i, self.control_name)
63 setattr(i, self.control_name, ctl)
64 else:
65 for cd in self.clock_domains:
66 name = self.control_name + "_" + cd
67 ctl = Signal(name=name)
68 assert not hasattr(i, name)
69 setattr(i, name, ctl)
70
71 def transform_fragment(self, i, f):
72 if self.clock_domains is None:
73 if len(f.sync) != 1:
74 raise ValueError("Control signal clock domains must be specified when module has more than one domain")
75 cdn = list(f.sync.keys())[0]
76 to_insert = [(getattr(i, self.control_name), cdn)]
77 else:
78 to_insert = [(getattr(i, self.control_name + "_" + cdn), cdn)
79 for cdn in self.clock_domains]
80 self.transform_fragment_insert(i, f, to_insert)
81
82
83 class CEInserter(ControlInserter):
84 control_name = "ce"
85
86 def transform_fragment_insert(self, i, f, to_insert):
87 for ce, cdn in to_insert:
88 f.sync[cdn] = [If(ce, *f.sync[cdn])]
89
90
91 class ResetInserter(ControlInserter):
92 control_name = "reset"
93
94 def transform_fragment_insert(self, i, f, to_insert):
95 for reset, cdn in to_insert:
96 f.sync[cdn] = insert_reset(reset, f.sync[cdn])
97
98
99 class ClockDomainsRenamer(ModuleTransformer):
100 def __init__(self, cd_remapping):
101 if isinstance(cd_remapping, str):
102 cd_remapping = {"sys": cd_remapping}
103 self.cd_remapping = cd_remapping
104
105 def transform_fragment(self, i, f):
106 for old, new in self.cd_remapping.items():
107 rename_clock_domain(f, old, new)