systemc-clang 2.0.0
Parsing SystemC constructs
Loading...
Searching...
No Matches
portbinding_recollect.py
Go to the documentation of this file.
1from lark import Tree, Token
2from parselib.transforms import TopDown
3from parselib.transforms.node import TypeDefType
4from ..utils import dprint, is_tree_type, get_ids_in_tree_types, ContextManager, get_tree_types
5from pprint import pprint
6from copy import deepcopy
7import logging
8
9
11 def portbindinglist(self, tree):
12 assert False, "portbindinglist should not be present in the tree"
13
14
16 """
17 This pass collects portbinding nodes and transform them into a portbindinglist node.
18 We have this pass because portbindings are scattered in hModinitblock
19 These blocks cannot be directly translated to verilog uniformly
20 """
21 def __init__(self, ports):
22 # pre checks
23 super().__init__()
25 self.ports = ports
26
27
28 def hmodule(self, tree):
29 with self.ctx.add_values(current_module=tree.children[0].value, module_type={}):
30 self.__push_up(tree)
31 return tree
32
33 def forinit(self, tree):
34 with self.ctx.add_values(is_in_for_init=True):
35 self.__push_up(tree)
36 return tree
37
38 def hvarref(self, tree):
39 if self.ctx.is_in_for_init and self.ctx.is_in_initblock:
40 self.ctx.for_var_catcher.add(tree.children[0])
41 return tree
42
43 def forstmt(self, tree):
44 if not self.ctx.is_in_initblock:
45 return tree
46
47 # assert: self.is_in_initblock
48 with self.ctx.add_values(
49 is_in_for=True,
50 for_has_portbinding=False,
51 has_non_portbinding_stmt=False,
52 ):
53 self.__push_up(tree)
54
55 # allow some level of nesting
56 assert not (self.ctx.for_has_portbinding and self.ctx.has_non_portbinding_stmt), \
57 "portbinding and non-portbinding stmts should not be mixed in a for block"
58
59 # if this is the outermost for block, collect it for portbinding
60 if self.ctx.is_in_initblock and self.ctx.for_has_portbinding and self.ctx.search_key_in_outer_context("is_in_for") is None:
61 self.ctx.for_port_bindings.append(tree)
62 return None
63 else:
64 return tree
65
66 def stmt(self, tree):
67 # self.__push_up(tree)
68 # if self.is_in_initblock and self.is_in_for:
69 # if tree.children[0].data != 'portbinding':
70 # self.has_non_portbinding_stmt = True
71 if self.ctx.is_in_initblock and self.ctx.is_in_for:
72 if tree.children[0].data not in ['portbinding', 'hcstmt', 'forstmt']:
73 self.ctx.has_non_portbinding_stmt = True
74
75 self.__push_up(tree)
76 if len(tree.children) == 1 and tree.children[0] is None:
77 return None
78 else:
79 return tree
80
81 def stmts(self, tree):
82 self.__push_up(tree)
83 if self.ctx.is_in_initblock:
84 tree.children = list(filter(lambda x: x is not None, tree.children))
85 return tree
86
87 def hmodinitblock(self, tree):
88 with self.ctx.add_values(
89 is_in_initblock=True,
90 simple_port_bindings=[],
91 for_port_bindings=[],
92 for_var_catcher=set()
93 ):
94 self.__push_up(tree)
95
96 portbindinglist_node = Tree('portbindinglist', [
97 None,
98 [*self.ctx.simple_port_bindings],
99 ])
100 forbindinglist_node = Tree('genbindinglist', [
101 Tree('genvardecl', list(self.ctx.for_var_catcher)),
102 Tree('genfor', self.ctx.for_port_bindings)
103 ])
104 # dprint(portbindinglist_node.pretty())
105
106 tree.children.append(portbindinglist_node)
107 if len(self.ctx.for_port_bindings) > 0:
108 tree.children.append(forbindinglist_node)
109 return tree
110
111 def moduleinst(self, tree):
112 self.__push_up(tree)
113 module_inst_name = str(tree.children[0])
114 module_type_name = tree.children[1].children[0].children[0].value
115 self.ctx.module_type[module_inst_name] = module_type_name
116 return tree
117
118 def modulearrayinst(self, tree):
119 self.__push_up(tree)
120 module_inst_name = str(tree.children[0])
121 module_type_name = tree.children[1].children[0].children[1].children[0].value
122 self.ctx.module_type[module_inst_name] = module_type_name
123 return tree
124
125
126
128 normal_name = tree.children[0].value
129 # TODO: change this to something that cannot be confused with a module name
130 if 'NONAME' in normal_name:
131 module_name = get_ids_in_tree_types(tree.children[1])[0].value
132 return module_name
133 return normal_name
134
136 normal_name = tree.children[0].value
137 if 'NONAME' in normal_name:
138 # This corrsponds to the case where the port name is behind a dot
139 # node = tree.children[1]
140 node = get_tree_types(tree, ['hfieldaccess'])[0]
141 if node.data == 'hfieldaccess':
142 return node.children[1].children[0].value
143 else:
144 dprint(tree.pretty())
145 assert False, "Unknown case"
146 else:
147 return get_ids_in_tree_types(tree.children[1])[0].value
148
149
150 def portbinding(self, tree):
151 # self.collected_portbinding.append(tree)
152 # self.for_has_portbinding = True
153 if self.ctx.is_in_for:
154 self.ctx.for_has_portbinding = True
155 module_orig = tree.children[0].value
156 module = self.get_module_name_in_portbinding(tree)
157 if module not in self.ctx.module_type:
158 logging.warn(f"TODO: Module {module} not found in moduleinst, future fix is required")
159 return tree
160 module_type = self.ctx.module_type[module]
161
162 # print(self.ports[module_type])
163 # children[1] is always the port name ref
164 # port_name = get_ids_in_tree_types(tree.children[1])[0].value
165 port_name = self.get_port_name_in_portbinding(tree)
166 port_dir = self.ports[module_type][port_name]
167 # default order is children[0] <- children[1] (in Verilog)
168 # if it is an output port, we need to reverse them.
169 if port_dir == PortDirectionCollector.OUTPUT:
170 tree.children[1:3] = tree.children[2:0:-1]
171 tree.swap_for_for_loop = True
172 # This is an indication so that at a later pass
173 # the dot syntax can be inserted properly
174 return tree
175 else:
176 self.ctx.simple_port_bindings.append(tree)
177 return None
178
179
181 INPUT = 0
182 OUTPUT = 1
183
184 def __init__(self):
185 self.ports= { }
187
188 def hmodule(self, tree):
189 with self.ctx.add_values(current_module=tree.children[0].value):
190 self.ports[self.ctx.current_module] = {}
191 self.__push_up(tree)
192 return tree
193
194 def inportdecl(self, tree):
195 self.ports[self.ctx.current_module][tree.children[0].value] = PortDirectionCollector.INPUT
196 return tree
197
198 def outportdecl(self, tree):
199 self.ports[self.ctx.current_module][tree.children[0].value] = PortDirectionCollector.OUTPUT
200 return tree
201
202 def sigdecltype(self, tree):
203
204 if hasattr(tree.meta, 'direction'):
205 d = tree.meta.direction
206 if d == 'input':
207 self.ports[self.ctx.current_module][tree.children[0].children[0].value] = PortDirectionCollector.INPUT
208 elif d == 'output':
209 self.ports[self.ctx.current_module][tree.children[0].children[0].value] = PortDirectionCollector.OUTPUT
210 else:
211 raise ValueError(f"Unknown direction {d}")
212 return tree
213
214
216 """
217 This pass simply lowers the the field access to a simple portbinding
218 """
219 def __init__(self, port_meta):
221 self.port_meta = port_meta
222 pass
223
224 def genbindinglist(self, tree):
225 with self.ctx.add_values(is_in_genbindinglist=True):
226 self.__push_up(tree)
227 return tree
228
229 def hvarref(self, tree):
230 if not self.ctx.is_in_genbindinglist:
231 return tree
232
233 assert len(tree.children) == 1, "Internal error, hvarref should only have one child"
234 cur_mod = self.ctx.current_module
235 if cur_mod not in self.port_meta:
236 return tree
237
238 # TODO: this checks whether a varref is a port of current module
239 # we could refactor this to be a function call such as _is_port_of_current_module()
240 interface = self.port_meta[cur_mod]
241 port_decls = interface.interfaces
242 for port_decl in port_decls:
243 # PortDecl
244 if port_decl.name == tree.children[0]:
245 # if this vardef is a local port
246 tree.children[0] = Token('ID',
247 value=f'{interface.generate_interface_decl_name()}.{port_decl.name}')
248 break
249 return tree.children[0]
250
251 def harrayref(self, tree):
252 if not self.ctx.is_in_genbindinglist:
253 return tree
254 self.ctx.cur_depth += 1
255 self.__push_up(tree)
256 self.ctx.cur_depth -= 1
257 if self.ctx.cur_depth == 0:
258 return '{}[{}]'.format(tree.children[0], tree.children[1])
259 else:
260 return '{}[{}].dim'.format(tree.children[0], tree.children[1])
261
262 def numlit(self, tree):
263 if not self.ctx.is_in_genbindinglist:
264 return tree
265 return tree.children[0]
266
267 def hfieldname(self, tree):
268 if not self.ctx.is_in_genbindinglist:
269 return tree
270 return tree.children[0]
271 def hfieldaccess(self, tree):
272 if self.ctx.is_in_genbindinglist:
273 with self.ctx.add_values(cur_depth=0):
274 self.__push_up(tree)
275 return tree.children[0] + ".itf." + tree.children[1]
276 return tree
277
278 def hmodule(self, tree):
279 with self.ctx.add_values(current_module=tree.children[0].value):
280 self.__push_up(tree)
281 return tree
__push_up(self, current_node)
Definition top_down.py:29