d33ee71260477f62594aa4376c36ceca2ad67f47
[litex.git] / litex / gen / fhdl / decorators.py
1 from litex.gen.fhdl.structure import *
2 from litex.gen.fhdl.module import Module
3 from litex.gen.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 Wrapped.__doc__ = victim.__doc__
32 Wrapped.__module__ = victim.__module__
33 return Wrapped
34
35 def wrap_instance(self, victim):
36 self.transform_instance(victim)
37 orig_get_fragment = victim.get_fragment
38
39 def get_fragment():
40 f = orig_get_fragment()
41 self.transform_fragment(victim, f)
42 return f
43
44 victim.get_fragment = get_fragment
45 return victim
46
47 def __call__(self, victim):
48 if isinstance(victim, Module):
49 return self.wrap_instance(victim)
50 else:
51 return self.wrap_class(victim)
52
53
54 class ControlInserter(ModuleTransformer):
55 control_name = None # override this
56
57 def __init__(self, clock_domains=None):
58 self.clock_domains = clock_domains
59
60 def transform_instance(self, i):
61 if self.clock_domains is None:
62 ctl = Signal(name=self.control_name)
63 assert not hasattr(i, self.control_name)
64 setattr(i, self.control_name, ctl)
65 else:
66 for cd in self.clock_domains:
67 name = self.control_name + "_" + cd
68 ctl = Signal(name=name)
69 assert not hasattr(i, name)
70 setattr(i, name, ctl)
71
72 def transform_fragment(self, i, f):
73 if self.clock_domains is None:
74 if not f.sync:
75 return
76 if len(f.sync) > 1:
77 raise ValueError("Control signal clock domains must be specified when module has more than one domain")
78 cdn = list(f.sync.keys())[0]
79 to_insert = [(getattr(i, self.control_name), cdn)]
80 else:
81 to_insert = [(getattr(i, self.control_name + "_" + cdn), cdn)
82 for cdn in self.clock_domains]
83 self.transform_fragment_insert(i, f, to_insert)
84
85
86 class CEInserter(ControlInserter):
87 control_name = "ce"
88
89 def transform_fragment_insert(self, i, f, to_insert):
90 for ce, cdn in to_insert:
91 f.sync[cdn] = [If(ce, *f.sync[cdn])]
92
93
94 class ResetInserter(ControlInserter):
95 control_name = "reset"
96
97 def transform_fragment_insert(self, i, f, to_insert):
98 for reset, cdn in to_insert:
99 f.sync[cdn] = insert_reset(reset, f.sync[cdn])
100
101
102 class ClockDomainsRenamer(ModuleTransformer):
103 def __init__(self, cd_remapping):
104 if isinstance(cd_remapping, str):
105 cd_remapping = {"sys": cd_remapping}
106 self.cd_remapping = cd_remapping
107
108 def transform_fragment(self, i, f):
109 for old, new in self.cd_remapping.items():
110 rename_clock_domain(f, old, new)