merge most of misoc 54e1ef82 and migen e93d0601 changes
[litex.git] / litex / gen / fhdl / visit.py
1 from copy import copy
2 from operator import itemgetter
3
4 from litex.gen.fhdl.structure import *
5 from litex.gen.fhdl.structure import (_Operator, _Slice, _Assign, _ArrayProxy,
6 _Fragment)
7
8
9 class NodeVisitor:
10 def visit(self, node):
11 if isinstance(node, Constant):
12 self.visit_Constant(node)
13 elif isinstance(node, Signal):
14 self.visit_Signal(node)
15 elif isinstance(node, ClockSignal):
16 self.visit_ClockSignal(node)
17 elif isinstance(node, ResetSignal):
18 self.visit_ResetSignal(node)
19 elif isinstance(node, _Operator):
20 self.visit_Operator(node)
21 elif isinstance(node, _Slice):
22 self.visit_Slice(node)
23 elif isinstance(node, Cat):
24 self.visit_Cat(node)
25 elif isinstance(node, Replicate):
26 self.visit_Replicate(node)
27 elif isinstance(node, _Assign):
28 self.visit_Assign(node)
29 elif isinstance(node, If):
30 self.visit_If(node)
31 elif isinstance(node, Case):
32 self.visit_Case(node)
33 elif isinstance(node, _Fragment):
34 self.visit_Fragment(node)
35 elif isinstance(node, (list, tuple)):
36 self.visit_statements(node)
37 elif isinstance(node, dict):
38 self.visit_clock_domains(node)
39 elif isinstance(node, _ArrayProxy):
40 self.visit_ArrayProxy(node)
41 else:
42 self.visit_unknown(node)
43
44 def visit_Constant(self, node):
45 pass
46
47 def visit_Signal(self, node):
48 pass
49
50 def visit_ClockSignal(self, node):
51 pass
52
53 def visit_ResetSignal(self, node):
54 pass
55
56 def visit_Operator(self, node):
57 for o in node.operands:
58 self.visit(o)
59
60 def visit_Slice(self, node):
61 self.visit(node.value)
62
63 def visit_Cat(self, node):
64 for e in node.l:
65 self.visit(e)
66
67 def visit_Replicate(self, node):
68 self.visit(node.v)
69
70 def visit_Assign(self, node):
71 self.visit(node.l)
72 self.visit(node.r)
73
74 def visit_If(self, node):
75 self.visit(node.cond)
76 self.visit(node.t)
77 self.visit(node.f)
78
79 def visit_Case(self, node):
80 self.visit(node.test)
81 for v, statements in sorted(node.cases.items(),
82 key=lambda x: str(x[0])):
83 self.visit(statements)
84
85 def visit_Fragment(self, node):
86 self.visit(node.comb)
87 self.visit(node.sync)
88
89 def visit_statements(self, node):
90 for statement in node:
91 self.visit(statement)
92
93 def visit_clock_domains(self, node):
94 for clockname, statements in sorted(node.items(), key=itemgetter(0)):
95 self.visit(statements)
96
97 def visit_ArrayProxy(self, node):
98 for choice in node.choices:
99 self.visit(choice)
100 self.visit(node.key)
101
102 def visit_unknown(self, node):
103 pass
104
105
106 # Default methods always copy the node, except for:
107 # - Signals, ClockSignals and ResetSignals
108 # - Unknown objects
109 # - All fragment fields except comb and sync
110 # In those cases, the original node is returned unchanged.
111 class NodeTransformer:
112 def visit(self, node):
113 if isinstance(node, Constant):
114 return self.visit_Constant(node)
115 elif isinstance(node, Signal):
116 return self.visit_Signal(node)
117 elif isinstance(node, ClockSignal):
118 return self.visit_ClockSignal(node)
119 elif isinstance(node, ResetSignal):
120 return self.visit_ResetSignal(node)
121 elif isinstance(node, _Operator):
122 return self.visit_Operator(node)
123 elif isinstance(node, _Slice):
124 return self.visit_Slice(node)
125 elif isinstance(node, Cat):
126 return self.visit_Cat(node)
127 elif isinstance(node, Replicate):
128 return self.visit_Replicate(node)
129 elif isinstance(node, _Assign):
130 return self.visit_Assign(node)
131 elif isinstance(node, If):
132 return self.visit_If(node)
133 elif isinstance(node, Case):
134 return self.visit_Case(node)
135 elif isinstance(node, _Fragment):
136 return self.visit_Fragment(node)
137 elif isinstance(node, (list, tuple)):
138 return self.visit_statements(node)
139 elif isinstance(node, dict):
140 return self.visit_clock_domains(node)
141 elif isinstance(node, _ArrayProxy):
142 return self.visit_ArrayProxy(node)
143 else:
144 return self.visit_unknown(node)
145
146 def visit_Constant(self, node):
147 return node
148
149 def visit_Signal(self, node):
150 return node
151
152 def visit_ClockSignal(self, node):
153 return node
154
155 def visit_ResetSignal(self, node):
156 return node
157
158 def visit_Operator(self, node):
159 return _Operator(node.op, [self.visit(o) for o in node.operands])
160
161 def visit_Slice(self, node):
162 return _Slice(self.visit(node.value), node.start, node.stop)
163
164 def visit_Cat(self, node):
165 return Cat(*[self.visit(e) for e in node.l])
166
167 def visit_Replicate(self, node):
168 return Replicate(self.visit(node.v), node.n)
169
170 def visit_Assign(self, node):
171 return _Assign(self.visit(node.l), self.visit(node.r))
172
173 def visit_If(self, node):
174 r = If(self.visit(node.cond))
175 r.t = self.visit(node.t)
176 r.f = self.visit(node.f)
177 return r
178
179 def visit_Case(self, node):
180 cases = {v: self.visit(statements)
181 for v, statements in sorted(node.cases.items(),
182 key=lambda x: str(x[0]))}
183 r = Case(self.visit(node.test), cases)
184 return r
185
186 def visit_Fragment(self, node):
187 r = copy(node)
188 r.comb = self.visit(node.comb)
189 r.sync = self.visit(node.sync)
190 return r
191
192 # NOTE: this will always return a list, even if node is a tuple
193 def visit_statements(self, node):
194 return [self.visit(statement) for statement in node]
195
196 def visit_clock_domains(self, node):
197 return {clockname: self.visit(statements)
198 for clockname, statements in sorted(node.items(),
199 key=itemgetter(0))}
200
201 def visit_ArrayProxy(self, node):
202 return _ArrayProxy([self.visit(choice) for choice in node.choices],
203 self.visit(node.key))
204
205 def visit_unknown(self, node):
206 return node