systemc-clang 2.0.0
Parsing SystemC constructs
Loading...
Searching...
No Matches
verilog_tranlation.py
Go to the documentation of this file.
1import warnings
2from .top_down import TopDown
3from ..primitives import *
4from ..utils import dprint, is_tree_type, get_ids_in_tree
5from lark import Tree, Token
6from functools import reduce
7import pprint
8import logging
9
10
12 """Translate low-level format of the _hdl.txt into Verilog
13 Note that type defs are already expanded at this point, so all htypeinfo/htype should only include primitive types
14 This pass does not perform any tree transformation that alters the semantics, but **only** generates Verilog
15 """
16 def __init__(self):
17 super().__init__()
20 self.indent_inc = 2
21 self.indent_stack = list()
22 self.bindings = dict()
23 self.local_variables = set()
24 self.in_for_init = False
25 self.module_var_type = None
28 self.is_in_thread = False
29 self.thread_comb = False
30
32 """denotes one of four types of scope: loop, switch, branch, None
33 currently, this is only useful for determine the handling of breaks
34 """
35 return self.__current_scope_type[-1]
36
37 def push_current_scope_type(self, scope):
38 assert scope in ['loop', 'switch', 'branch'], 'Incorrect scope type'
39 self.__current_scope_type.append(scope)
40
42 self.__current_scope_type.pop()
43
44
45 def start(self, tree):
46 self.__push_up(tree)
47 return tree.children[0]
48
49 def modulelist(self, tree):
50 self.__push_up(tree)
51 res = '\n'.join(tree.children)
52 return res
53
54 def nonrefexp(self, tree):
55 self.__push_up(tree)
56 assert len(tree.children) == 1
57 return tree.children[0]
58
59 def __get_var_name(self, tree):
60 if isinstance(tree, str):
61 return tree
62 elif isinstance(tree, Tree):
63 if tree.data in ['hvarref']:
64 return tree.children[0]
65 elif tree.data in ['harrayref', 'hslice']:
66 return self.__get_var_name(tree.children[0])
67 assert False, 'Cannot extract variable name from {}'.format(tree)
68
69 def __get_var_names(self, tree):
70 """return a list of variable names"""
71 if isinstance(tree, Tree) and tree.data in ['hconcat']:
72 return reduce(lambda x, y: x + y, [self.__get_var_names(sub) for sub in tree.children])
73 else:
74 return [self.__get_var_name(tree)]
75
76
77 def hmethodcall(self, tree):
78 self.__push_up(tree)
79 return '{}({})'.format(tree.children[0], ','.join(map(str, tree.children[1:])))
80
81 def hwait(self, tree):
82 warnings.warn('hwait encountered, not implemented')
83 return "// hwait"
84
85 def hvarinitlist(self, tree):
86 self.__push_up(tree)
87 return '{' + ','.join(tree.children) + '}'
88
89 def blkassign(self, tree):
90 # dprint("--------------START----------------")
91 current_proc = self.get_current_proc_name()
92 sense_list = self.get_sense_list()
93
94 # dprint(self.current_module, ':', current_proc)
95 # dprint('Sensitivity: ', pprint.pformat(self.get_sense_list()))
96 # dprint('Var w/ type: ', pprint.pformat(self.module_var_type))
97 var_names = self.__get_var_names(tree.children[0])
98 tpes = [self.get_current_module_var_type_or_default(vn) for vn in var_names]
99 all_none = all(t is None for t in tpes)
100 all_non_none = all(t is not None for t in tpes)
101 if not all_none and not all_non_none:
102 raise ValueError('LHS of assignment must be all local variables or all non-local variables. On line: {}.'.format(tree.line))
103 is_nb = [isinstance(tpe, sc_signal) or
104 isinstance(tpe, sc_out) or
105 isinstance(tpe, array) and isinstance(tpe.get_element_type(), sc_signal) for tpe in tpes]
106 # is_nb checks whether one of the type needs to be non-blocking assignment
107 # and special case for thread
108 all_nb = all(is_nb) or current_proc in ['#thread_sync#']
109 all_b = all(not p for p in is_nb) or (self.is_in_thread and current_proc in ['#function#'])
110 if not all_nb and not all_b:
111 raise ValueError('The assignment must not mix blocking assignment and non-blocking assignment. On line: {}.'.format(tree.line))
112
113 # var_name = self.__get_var_name(tree.children[0])
114 # tpe = self.get_current_module_var_type_or_default(var_name)
115 # if tpe is None, it is either a local variable within a process or block, in this case, it should be =
116 # if current_proc not in ['#initblock#', '#function#']: # TODO: use a more programmatic way
117 # dprint("--------------END-------------------")
118 blocking = True
119 # while using non-blocking assignments in function is not recommended, we will need to use
120 # non-blocking assignments in a function so that its value can get properly assigned
121 # An example of such is the m_bits_data_valid signal in encode_stream
122 # In SystemC, when a signal is used in RHS, it will be added to the sensitivity list
123 if current_proc in sense_list or (current_proc in ['#function#', '#thread_sync#'] and not (self.is_in_thread and current_proc == '#function#')):
124 # sense_list = sense_list[current_proc]
125 # tpe is only recorded if the declaration crosses process boundary
126 # if tpe is not None:
127 if all_non_none:
128 # dprint(tpe.get_element_type())
129 # if isinstance(tpe, sc_signal) or \
130 # isinstance(tpe, sc_out) or \
131 # isinstance(tpe, array) and isinstance(tpe.get_element_type(), sc_signal):
132 # dprint('Changed to non-blocking assignment: '.format(var_name))
133 if all_nb:
134 blocking = False
135 if self.thread_comb:
136 blocking = True
137 self.__push_up(tree)
138 assert len(tree.children) == 2
139 is_local_var = self.__all_local_variables(var_names)
140 op = '=' if self.in_for_init or blocking or is_local_var else '<='
141 l = tree.children[0]
142 r = tree.children[1]
143
144
145 if type(l) == Tree and l.data == 'harrayref':
146 # __A[__r:__s] = __X
147 __A = l.children[0]
148 __r = l.children[1]
149 __s = l.children[2]
150 l = __A
151 if type(r) == Tree and r.data == 'harrayref': # special case for irreducible RHS
152 __X = r.children[3]
153 __B = r.children[0]
154 else:
155 __X = r
156 __B = r
157 r = "(({} & ~(~($bits({})'('b0)) << (({})-({})+1))) << ({})) | (({}) & ((~($bits({})'('b0)) ) << (({}) + 1) | ~(( ~($bits({})'('b0)) ) << ({}))))".format(
158 __X, __B,
159 __r, __s,
160 __s, __A,
161 __A, __r, __A, __s
162 )
163 elif type(r) == Tree and r.data == 'harrayref':
164 r = r.children[3]
165
166 res = '{} {} {}'.format(l, op, r)
167 return res
168
169 def syscwrite(self, tree):
170 raise RuntimeError('Unsupported node: syscwrite')
171 self.__push_up(tree)
172 res = '{} {} {}'.format(tree.children[1], tree.children[0], tree.children[2])
173 return res
174
175
176 def numlitwidth(self, tree):
177 self.__push_up(tree)
178 lit, tpe = tree.children
179 assert hasattr(tpe, 'width'), 'Literal width type should have width member'
180 w = tpe.width # the primitive type must have width
181 return "{}{}'d{}".format('-' if lit < 0 else '', w, abs(lit))
182
183 def hcondop(self, tree):
184 self.__push_up(tree)
185 return '{} ? {} : {}'.format(tree.children[0], tree.children[1], tree.children[2])
186
187 def hliteral(self, tree):
188 """stops at literal, it is some kinds of terminal"""
189 self.__push_up(tree)
190 assert len(tree.children) == 1
191 return str(tree.children[0])
192
193 def hvarref(self, tree):
194 assert len(tree.children) == 1
195 if is_tree_type(tree.children[0], 'func_param_name_stub'):
196 return tree.children[0].children[0]
197 stripped = tree.children[0].replace("#", "")
198 return stripped
199
200 def syscread(self, tree):
201 """syscread: hsigassignr, token"""
202 self.__push_up(tree)
203 return tree.children[1]
204
205 def __check_const(self, tree):
206 """check whether the tree valuates to constant"""
207 if isinstance(tree, int):
208 return True
209 elif is_tree_type(tree, 'hliteral'):
210 return True
211 elif is_tree_type(tree, 'hbinop'):
212 return self.__check_const(tree.children[1]) and self.__check_const(tree.children[2])
213 return False
214
215 def _clean_harrayref(self, harrayref_node):
216 assert harrayref_node.data == 'harrayref'
217 if is_tree_type(harrayref_node.children[0], 'hsigassignr'):
218 # dprint(harrayref_node)
219 harrayref_node.children = harrayref_node.children[1:]
220 # dprint(harrayref_node)
221
222 def harrayref(self, tree):
223 # Check whether
224 l_const = None
225 r_const = None
226 self._clean_harrayref(tree)
227 if isinstance(tree.children[0], Tree) and tree.children[0].data == 'hslice':
228 if len(tree.children[0].children) == 3:
229 hslice = tree.children[0]
230 l, r = hslice.children[1:]
231 l_const = self.__check_const(l)
232 r_const = self.__check_const(r)
233
234 self.__push_up(tree)
235 if isinstance(tree.children[0], Tree) and tree.children[0].data == 'hslice':
236 hslice = tree.children[0]
237 var = hslice.children[0]
238 m = None
239 if len(hslice.children) == 3:
240 l, r = hslice.children[1:]
241 elif len(hslice.children) == 2:
242 m = hslice.children[1]
243 # l_const = isinstance(l, int)
244 # r_const = isinstance(r, int)
245 if l_const and r_const:
246 idx = '{}:{}'.format(l, r)
247 elif m is not None:
248 idx = '{}'.format(m)
249 else:
250 # for slicing that is not constant
251 tree.children = [var, l, r, "(({}) >> ({})) & ~(~($bits({})'('b0)) << (({}) - ({}) + 1))".format(var, r, var, l, r)]
252 return tree # irreducible hslice node
253 else:
254 var, idx = tree.children
255 res = '{}[{}]'.format(var, idx)
256 return res
257
258 def hsigassignl(self, tree):
259 warnings.warn('Implementing SigAssignL as non-blocking')
260 return '<='
261
262 def __is_local_variable(self, var_name):
263 return var_name in self.local_variables
264
265 def __all_local_variables(self, var_names):
266 return all(self.__is_local_variable(var_name) for var_name in var_names)
267
268 def hbinop(self, tree):
269 self.__push_up(tree)
270 if tree.children[0] == 'ARRAYSUBSCRIPT':
271 res = '{}[({})]'.format(tree.children[1], tree.children[2])
272 else:
273 op = tree.children[0]
274 if op == '=':
275 pass
276 # op = '<='
277 if op == ',': # concatenation
278 res = '{{({}), ({})}}'.format(tree.children[1], tree.children[2])
279 elif op == '>>': # Note: shift right
280 res = '({}) {} ({})'.format(tree.children[1], '>>>', tree.children[2])
281 elif op == 'concat':
282 res = '{{ ({}) {} ({}) }}'.format(tree.children[1], ',', tree.children[2])
283 elif op == '@=': # non-blocking assignment in thread context
284 res = '{} <= ({})'.format(tree.children[1], tree.children[2])
285 else:
286 res = '({}) {} ({})'.format(tree.children[1], op, tree.children[2])
287 return res
288
289 def hpostfix(self, tree):
290 self.__push_up(tree)
291 return "{}{}".format(tree.children[1], tree.children[0])
292
293 def hprefix(self, tree):
294 self.__push_up(tree)
295 return "{}{}".format(tree.children[0], tree.children[1])
296
297 def hunop(self, tree):
298 self.__push_up(tree)
299 if len(tree.children) == 1:
300 return tree.children[0]
301 elif len(tree.children) == 2:
302 res = '{}({})'.format(tree.children[0], tree.children[1])
303 return res
304 else:
305 assert False
306 # The ++ and -- only shows in loop
307 # The original method is deprecated, we can hand over the self-increment to the synthesizer
308 # since we assue that we generate system verilog
309 # if tree.children[0] == '++':
310 # res = '{} = {} + 1'.format(tree.children[1], tree.children[1])
311 # elif tree.children[0] == '--':
312 # res = '{} = {} - 1'.format(tree.children[1], tree.children[1])
313 # else:
314 # res = '{}({})'.format(tree.children[0], tree.children[1])
315 # return res
316
317 def hcstmt(self, tree):
318 self.__push_up(tree)
319 assert len(tree.children) <= 1, "hcstmt should contain 0 or 1 child"
320 if tree.children:
321 return tree.children[0]
322 else:
323 return ''
324
325 def continuestmt(self, tree):
326 return 'continue'
327
329 ind = self.current_indent * self.indent_character
330 return ind
331
332 def casevalue(self, tree):
333 self.__push_up(tree)
334 return tree.children[0]
335
336 def switchbody(self, tree):
337 self.push_current_scope_type('switch')
338 self.__push_up(tree)
340 return '\n'.join(tree.children)
341
342 def casestmt(self, tree):
343 self.inc_indent()
344 self.__push_up(tree)
345 self.dec_indent()
346 ind = self.get_current_ind_prefix()
347 res = '{}{}: begin\n{}\n{}end'.format(ind, tree.children[0], '\n'.join(tree.children[1:]), ind)
348 return res
349
350 def switchcond(self, tree):
351 self.__push_up(tree)
352 return tree.children[0]
353
354 def switchstmt(self, tree):
355 self.inc_indent()
356 self.__push_up(tree)
357 self.dec_indent()
358 ind = self.get_current_ind_prefix()
359 res = '{}case({})\n{}\n{}endcase'.format(ind, tree.children[0], tree.children[1], ind)
360 return res
361
362 def breakstmt(self, tree):
363 if self.get_current_scope_type() in ['switch']:
364 return ""
365 else:
366 ind = self.get_current_ind_prefix()
367 res = '{}break;'.format(ind)
368 return res
369
370 def stmt(self, tree):
371 indentation = []
372 sep = []
373 noindent = ['hcstmt', 'ifstmt', 'forstmt', 'switchstmt', 'casestmt', 'breakstmt', 'whilestmt', 'dostmt']
374 nosemico = ['hcstmt', 'ifstmt', 'forstmt', 'switchstmt', 'casestmt', 'breakstmt', 'whilestmt', 'dostmt']
375 for x in tree.children:
376 if x.data in noindent:
377 indentation.append('')
378 else:
379 indentation.append(self.get_current_ind_prefix())
380 if x.data in nosemico:
381 sep.append('')
382 else:
383 sep.append(';')
384
385 self.__push_up(tree)
386 def f_concat(x):
387 try:
388 if isinstance(x[1], Tree):
389 if x[1].data == 'expression_in_stmt':
390 # logging.warning('Expression as a statement may not have an effect. On line: {}'.format(x[1].line))
391 x = (x[0], x[1].children[0], x[2])
392 else:
393 assert False, 'Unrecognized construct: {}'.format(x[1])
394 res = str(x[0]) + str(x[1]) + str(x[2])
395 return res
396 except Exception as e:
397 print(x[0])
398 print(x[1])
399 print(x[2])
400 raise
401 res = '\n'.join(map(f_concat,
402 filter(lambda x: x[1] is not None, zip(indentation, tree.children, sep))
403 ))
404 return res
405
406 def hnoop(self, tree):
407 warnings.warn('Encountered noop at line: {}'.format(tree.meta.line))
408 return ""
409
410 def whilestmt(self, tree):
411 self.push_current_scope_type('loop')
412 self.inc_indent()
413 self.__push_up(tree)
414 self.dec_indent()
415 prefix = self.get_current_ind_prefix()
416 res = "{}while({}) begin\n".format(prefix, tree.children[0])
417 res += ''.join(tree.children[1:])
418 res += '\n{}end'.format(prefix)
420 return res
421
422 def dostmt(self, tree):
423 self.push_current_scope_type('loop')
424 self.inc_indent()
425 self.__push_up(tree)
426 self.dec_indent()
427 prefix = self.get_current_ind_prefix()
428
429 res = "{}do begin\n".format(prefix)
430 res += ''.join(tree.children[1:])
431 res += '\n{}end while({})'.format(prefix, tree.children[0])
432
434 return res
435
436 def stmts(self, tree):
437 self.__push_up(tree)
438 res = '\n'.join(tree.children)
439 return res
440
441 def inc_indent(self):
442 self.current_indent += self.indent_inc
443
444 def dec_indent(self):
445 self.current_indent -= self.indent_inc
446
447 def push_indent(self):
448 """used to service temporary indent removal, such as that in for condition"""
449 self.indent_stack.append(self.current_indent)
450 self.current_indent = 0
451 def pop_indent(self):
452 self.current_indent = self.indent_stack.pop()
453
454 def ifstmt(self, tree):
455 self.push_current_scope_type('branch')
456 self.inc_indent()
457 self.__push_up(tree)
458 self.dec_indent()
459 ind = self.get_current_ind_prefix()
460 res = ind + 'if ({}) begin\n'.format(tree.children[0])
461 if len(tree.children) > 1:
462 res += tree.children[1] + '\n'
463 res += ind + 'end'
464 # print('If Body: ', tree.children[1])
465 if len(tree.children) == 3:
466 res += ' else begin\n' + tree.children[2]
467 res += '\n'
468 res += ind + 'end\n'
469
471 return res
472
473 def forinit(self, tree):
474
475 self.in_for_init = True
476 self.__push_up(tree)
477 self.in_for_init = False
478
479 if tree.children:
480 return tree.children[0]
481 else:
482 return ''
483
484 def forcond(self, tree):
485 self.__push_up(tree)
486 return tree.children[0]
487
488 def forpostcond(self, tree):
489 self.__push_up(tree)
490 return tree.children[0]
491
492 def forbody(self, tree):
493 self.__push_up(tree)
494 return tree.children[0]
495
496 def forstmt(self, tree):
497
498 self.push_current_scope_type('loop')
499 new_children = []
500 self.push_indent()
501 new_children.extend(self.visit(t) for t in tree.children[:3])
502 self.pop_indent()
503
504 self.inc_indent()
505 new_children.extend(self.visit(t) for t in tree.children[3:])
506 self.dec_indent()
507
508 for_init, for_cond, for_post, for_body = new_children
509
510 ind = self.get_current_ind_prefix()
511 res = ind + 'for ({};{};{}) begin\n'.format(for_init, for_cond, for_post)
512 res += for_body + '\n'
513 res += ind + 'end'
515 return res
516
517 def hsensvars(self, tree):
518 self.__push_up(tree)
519 return tree
520
521 def npa(self, tree):
522 return tree.children[0]
523
524 def hsensedge(self, tree):
525 self.__push_up(tree)
526 return tree.children[0]
527
528 def get_sense_list(self):
529 return self.senselist
530
531 def hsenslist(self, tree):
532 self.__push_up(tree)
533 proc_name = tree.children[0]
534 assert proc_name not in self.senselist, 'Duplicated process: {}'.format(proc_name)
535 self.senselist[proc_name] = []
536 for sv in tree.children[1:]:
537 # special treatment
538 sens_var, sens_edge = sv.children
539 if is_tree_type(sv.children[0], "hsensvar"):
540 warnings.warn("Malformatted sensitivity list")
541 sens_edge, sens_var = sv.children[0].children
542 if sens_edge == 'posedge_event':
543 edge = 'posedge'
544 elif sens_edge == 'negedge_event':
545 edge = 'negedge'
546 else:
547 edge = ''
548 sen_str = '{} {}'.format(edge, sens_var)
549 else:
550 if isinstance(sens_var, Token):
551 sens_var = sens_var.value
552 if sens_edge == 'always':
553 sen_str = sens_var
554 elif sens_edge in ['pos', 'posedge_event']:
555 sen_str = 'posedge {}'.format(sens_var)
556 elif sens_edge in ['neg', 'negedge_event']:
557 sen_str = 'negedge {}'.format(sens_var)
558 else:
559 raise ValueError('Edge can only be one of pos/neg/always')
560 self.senselist[proc_name].append(sen_str)
561 return None
562
563 def hvalchange(self, tree):
564 warnings.warn('value change is deprecated, but is detected in hcode', DeprecationWarning)
565 self.__push_up(tree)
566 return tree.children[0]
567
568 def set_current_proc_name(self, name):
569 self.current_proc_name = name
570
572 self.current_proc_name = None
573
575 return self.current_proc_name
576
578 return any('posedge' in x or 'negedge' in x for x in sense_list)
579
580 def hprocess(self, tree):
581 proc_name, proc_name_2, prevardecl, *body = tree.children
582 self.set_current_proc_name(proc_name)
583 for n in prevardecl.children:
584 var_name = n.children[0].children[0] # get the variable name of local variables
585 self.__add_local_variables(var_name)
586 self.inc_indent()
587 self.__push_up(tree)
588 self.dec_indent()
589
590 proc_name, proc_name_2, prevardecl, *body = tree.children
591
592 prevardecl.children = list(filter(lambda x: not is_tree_type(x, 'vardeclrn'), prevardecl.children))
593
594 ind = self.get_current_ind_prefix()
595 decls = list(map(lambda x: x[0] + ';', prevardecl.children))
596 decls_init = list(map(lambda x: '{} = {};'.format(x[1], x[2]), filter(lambda x: len(x) == 3 and x[2] is not None, prevardecl.children)))
597 sense_list = self.get_sense_list()
598 assert proc_name in sense_list, "Process name {} is not in module {}".format(proc_name, self.current_module)
599 # res = ind + 'always @({}) begin: {}\n'.format(' or '.join(self.get_sense_list()[proc_name]), proc_name)
600 if self.__is_synchronous_sensitivity_list(sense_list[proc_name]):
601 res = ind + 'always_ff @({}) begin: {}\n'.format(' or '.join(self.get_sense_list()[proc_name]), proc_name)
602 else:
603 res = ind + 'always @({}) begin: {}\n'.format(' or '.join(self.get_sense_list()[proc_name]), proc_name)
604 # res = ind + 'always_comb begin: {}\n'.format(proc_name)
605 self.inc_indent()
606 ind = self.get_current_ind_prefix()
607 res += ind + ('\n' + ind).join(decls) + '\n'
608 res += ind + ('\n' + ind).join(decls_init) + '\n'
609 self.dec_indent()
610 ind = self.get_current_ind_prefix()
611 res += '\n'.join(body) + '\n'
612 res += ind + 'end'
615 return res
616
618 self.local_variables = set()
619
620 def __add_local_variables(self, var_name):
621 assert var_name not in self.local_variables, 'Local variable {} already existed'.format(var_name)
622 self.local_variables.add(var_name)
623
624 def htype(self, tree):
625 self.__push_up(tree)
626 name, *args = tree.children
627 tpe = Primitive.get_primitive(name)
628 assert tpe is not None, 'Type {} is not defined'.format(name)
629 return tpe(*args)
630
631 def hreturnstmt(self, tree):
632 self.__push_up(tree)
633 logging.warning(
634 """Return statement is detected and omitted.\n"""
635 """ A return statement may not produce expected result,\n"""
636 """ consider removing it in the C++ code.\n"""
637 )
638 if len(tree.children) == 1:
639 return 'return {}'.format(tree.children[0])
640 elif len(tree.children) == 0:
641 return 'return'
642 return ''
643 else:
644 assert len(tree.children) in [0, 1], 'return statement can only have 0 or 1 return value'
645
646 def __gen_funcparam(self, tree):
647 self.__push_up(tree)
648 var_name, tpe = tree.children
649 ctx = TypeContext(suffix='')
650 decl = tpe.to_str(var_name, context=ctx)
651 # if self.get_current_proc_name() is None:
652 # # we only check variables that are across processes, otherwise, there is no point in having non-blocking
653 # # assignment
654 # self.insert_current_module_var_type(var_name, tpe)
655 return decl, var_name, None
656
657 def funcparami(self, tree):
658 return self.__gen_funcparam(tree)
659
660 def funcparamio(self, tree):
661 return self.__gen_funcparam(tree)
662
663 def vardeclinit(self, tree):
664 self.__push_up(tree)
665 init_val = None
666 tpe = None
667 if len(tree.children) == 2:
668 var_name, tpe = tree.children
669 elif len(tree.children) == 3:
670 var_name, tpe, init_val = tree.children
671 else:
672 assert False, 'children size of vardeclinit is not 2 or 3, there might be a bug in the translator'
673 ctx = TypeContext(suffix='')
674 decl = tpe.to_str(var_name, context=ctx)
675 if self.get_current_proc_name() is None:
676 # we only check variables that are across processes, otherwise, there is no point in having non-blocking
677 # assignment
678 self.insert_current_module_var_type(var_name, tpe)
679 return (decl, var_name, init_val)
680
681 def hbindingarrayref(self, tree):
682 """
683 this expansion should only be invoked by expanding_binding_ref and should not be invoked elsewhere
684 the reason is that we need to collect binding information per arry-like port
685 """
686 self.__push_up(tree)
687 return '{}[{}]'.format(tree.children[0], tree.children[1])
688
689 def expand_binding_ref(self, tree):
690 if not is_tree_type(tree, 'hbindingarrayref'):
691 raise ValueError('expand_binding_ref only accepts hbindingarrayref')
692 self.__push_back(tree)
693 return '{}[{}]'.format(tree.children[0], tree.children[1])
694
695 def moduleinst(self, tree):
696 # dprint(tree)
697 mod_name, mod_type = tree.children
698 # expand if it is an element of module array
699 mod_name = '_'.join(mod_name.split('#'))
700 if len(mod_type.children[0].children) > 1:
701 warnings.warn('Type parameters for modules are not supported')
702 mod_type_name = mod_type.children[0].children[0]
703 if mod_name not in self.bindings:
704 warnings.warn('Port bindings for module instance name {} not found'.format(mod_name))
705 bindings = []
706 else:
707 bindings = self.bindings[mod_name]
708 def extract_binding_name(x):
709 # FIXME: when the port connection is 2D, the original approach may not work
710 return get_ids_in_tree(x[0])[0]
711 # if is_tree_type(x[0], 'hbindingarrayref'):
712 # res = x[0].children[0].children[0]
713 # else:
714 # res = x[0].children[0]
715 # return res
716 orig_bindings = bindings
717 bindings_normal = list(filter(lambda x: '.' not in extract_binding_name(x), orig_bindings))
718 bindings_hier = list(filter(lambda x: '.' in extract_binding_name(x), orig_bindings))
719 bindings = bindings_normal
720 ind = self.get_current_ind_prefix()
721 res = ind + '{} {}('.format(mod_type_name, mod_name) + '\n'
722 self.inc_indent()
723 ind = self.get_current_ind_prefix()
724 binding_str = []
725 array_bindings = {}
726 for binding in bindings:
727 # for backward compatibility, we keep the case where binding is a list
728 if type(binding) == list:
729 sub, par = binding
730 else:
731 warnings.warn('Using Tree as binding is deprecated', DeprecationWarning)
732 sub, par = binding.children
733 if is_tree_type(sub, 'hbindingarrayref'):
734 # The .xxx part is an array
735 sub_name = get_ids_in_tree(sub)[0].value # assuming varref
736 if sub_name not in array_bindings:
737 array_bindings[sub_name] = {}
738 # if sub.children[0].data == 'hbindingarrayref':
739 # raise ValueError('nested 2-D array port is not supported')
740 array_bindings[sub_name][sub.children[1].children[0]] = par
741 else:
742 # at this point, the par should be able to be fully expanded even if it is an array
743 if is_tree_type(par, 'hbindingarrayref'):
744 par = self.expand_binding_ref(par)
745 else:
746 par = par.children[0].value
747 binding_str.append(ind + '.{}({})'.format(sub.children[0].value, par))
748 for sub_name, bindings in array_bindings.items():
749 # for now, we keep a dict of array binding
750 array_seq = [None] * len(bindings)
751 for idx, b in bindings.items():
752 # dprint(self.expand_binding_ref(b))
753 # array_seq[idx] = '{}[{}]'.format(b.children[0].children[0].value, b.children[1].children[0])
754 array_seq[idx] = self.expand_binding_ref(b)
755 binding_str.append(ind + ".{}('{{ {} }})".format(
756 sub_name, ','.join(array_seq)
757 ))
758 res += ',\n'.join(binding_str)
759 res += '\n'
760 self.dec_indent()
761 ind = self.get_current_ind_prefix()
762 res += ind + ');'
763 res += '\n'
764 res += ind + "always @(*) begin\n"
765 # res += ind + "always_comb begin\n"
766 self.inc_indent()
767 ind = self.get_current_ind_prefix()
768 for bl, br in bindings_hier:
769 res += ind + '{} = {};\n'.format(bl.children[0], br.children[0])
770 self.dec_indent()
771 ind = self.get_current_ind_prefix()
772 res += ind + "end\n"
773 # add an always block for port binding when we encounter sub module case
774 tree.children = [res]
775 return tree
776
777 def hlrotate(self, tree):
778 self.__push_up(tree)
779 val, rot = tree.children
780 return '({} << {}) | ($unsigned({}) >> ($bits({}) - {}))'.format(val, rot, val, val, rot)
781 def horreduce(self, tree):
782 self.__push_up(tree)
783 val = tree.children[0]
784 return '(|{})'.format(val)
785
786 def hconcat(self, tree):
787 self.__push_up(tree)
788 l, r = tree.children[0], tree.children[1]
789 res = '{{ {}, {} }}'.format(l, r)
790 return res
791
792 def vardecl(self, tree):
793 self.__push_up(tree)
794 return tree.children
795
796 def prevardecl(self, tree):
797 self.__push_up(tree)
798 new_children = []
799 for t in tree.children:
800 new_children.extend(t)
801 tree.children = new_children
802 return tree
803
804 def htypeinfo(self, tree):
805 # Note: htypeinfo should return an object that can be used to apply to a variable
806 self.__push_up(tree)
807 return tree.children[0]
808
809 def func_param_name_stub(self, tree):
810 self.__push_up(tree)
811 tree.insert_name(self.module_var_type.keys())
812 var_name, tpe = tree.children
813 ctx = TypeContext(suffix='')
814 decl = tpe.to_str(var_name, context=ctx)
815 return decl, var_name, None
816
817 def hfunctionparams(self, tree):
818 self.__push_up(tree)
819 return tree
820
821 def hfunctionrettype(self, tree):
822 self.__push_up(tree)
823 if len(tree.children) != 0:
824 tpe = tree.children[0]
825 res = tpe.to_str(var_name='')
826 else:
827 res = "void"
828 return res
829
830 def htouint(self, tree):
831 self.__push_up(tree)
832 return '$unsigned({})'.format(tree.children[0])
833
834 def htoint(self, tree):
835 self.__push_up(tree)
836 return '$signed({})'.format(tree.children[0])
837
838 def htoulong(self, tree):
839 self.__push_up(tree)
840 return '$unsigned({})'.format(tree.children[0])
841
842 def htolong(self, tree):
843 self.__push_up(tree)
844 return '$signed({})'.format(tree.children[0])
845
846 def hfunctionlocalvars(self, tree):
847 self.__push_up(tree)
848 return tree
849
850 def hfunction(self, tree):
851 self.set_current_proc_name('#function#')
852 self.inc_indent()
853 self.__push_up(tree)
854 self.dec_indent()
855 ind = self.get_current_ind_prefix()
856
857 # function_name, return_type, params, localvar, body = tree.children
858 function_name, return_type = tree.children[:2]
859 params = ''
860 for ch in tree.children[2:]:
861 if is_tree_type(ch, 'hfunctionparams'):
862 params = ', '.join(map(lambda x: x[0], ch.children))
863 elif is_tree_type(ch, 'hfunctionlocalvars'):
864 localvar = ch
865 elif is_tree_type(ch, "hfunctionbody"):
866 body = ch
867
868
869 self.inc_indent()
870 ind = self.get_current_ind_prefix()
871 localvars = '\n'.join(map(lambda x: ind + x[0] + ';', localvar.children))
872 self.dec_indent()
873 body = '\n'.join(body.children)
874
875 ind = self.get_current_ind_prefix()
876 res = '{}function automatic {} {} ({});\n{}begin\n{}\n{}\n{}end\n{}endfunction'.format(ind, return_type, function_name,
877 params, ind,
878 localvars, body, ind, ind)
880 return res
881
882 def collect_type(self, port_or_sig):
883 assert isinstance(port_or_sig, Tree) and \
884 port_or_sig.data in ['sigdecltype', 'portdecltype'], \
885 'collect_type must be invoked with portdecltype or sigdecltype, but got: {}'.format(port_or_sig)
886 id = port_or_sig.children[0].children[0]
887 tpe = port_or_sig.children[1]
889
890 def sigdecltype(self, tree):
891 self.__push_up(tree)
892 self.collect_type(tree)
893 return tree
894
895 def portdecltype(self, tree):
896 self.__push_up(tree)
897 self.collect_type(tree)
898 return tree
899
900 def modportsiglist(self, tree):
901 self.__push_up(tree)
902 return tree
903
905 return self.module_var_type[id]
906
907 def get_current_module_var_type_or_default(self, id, default=None):
908 if id not in self.module_var_type:
909 return default
910 return self.module_var_type[id]
911
913 self.module_var_type = dict()
914
916 if id in self.module_var_type:
917 raise ValueError('Duplicate signal declaration: {}'.format(id))
918 self.module_var_type[id] = tpe
919
920 def hthread(self, tree):
921 # hthread concists of 4 parts as children
922 # 1. thread name
923 # 2. signals declaration across hmethods
924 # 3. synchronous hmethod for setting state to next_state and reset
925 # 4. combinational hmethod for driving next_state
926 # We need 2 to be at the module level and thus its processing will be handled in hmodule
927 self.is_in_thread = True
928 self.thread_name = tree.children[0]
929 self.__push_up(tree)
930 del self.thread_name
931 self.is_in_thread = False
932 return tree
933
934 def __generate_hthread_block(self, tree, is_sync):
935 # currently we assume that the hthread block is simply and there is no sensitivity list and
936 # var decls, this might change in the future when we add support for resets
937 proc_name, *body = tree.children
938 if is_sync:
939 self.set_current_proc_name('#thread_sync#')
940 else:
941 self.set_current_proc_name(proc_name)
942
943 ind = self.get_current_ind_prefix()
944
945 thread_name = self.thread_name
946 sense_list = self.get_sense_list()
947 assert thread_name in sense_list, "Process name {} is not in module {}".format(proc_name, self.current_module)
948 if is_sync:
949 res = ind + 'always @({}) begin: {}\n'.format(' or '.join(self.get_sense_list()[thread_name]), proc_name)
950 else:
951 res = ind + 'always @(*) begin: {}\n'.format(proc_name)
952 self.inc_indent()
953 self.__push_up(tree)
954 proc_name, *body = tree.children
955 ind = self.get_current_ind_prefix()
956 res += '\n'.join(body) + '\n'
957 self.dec_indent()
958 ind = self.get_current_ind_prefix()
959 res += ind + 'end'
962 return res
963
964 def hthreadsync(self, tree):
965 res = self.__generate_hthread_block(tree, is_sync=True)
966 return res
967
968 def hthreadswitch(self, tree):
969 self.thread_comb = True
970 res = self.__generate_hthread_block(tree, is_sync=False)
971 self.thread_comb = False
972 return res
973
974 def hmodule(self, tree):
975 # dprint("Processing Module: ", tree.children[0])
976 # print("Retrieving Portbindings")
977 self.current_module = tree.children[0]
978 self.senselist = {}
980 initialization_block = []
981 encountered_initblock = False
982 self.bindings = dict()
983 for t in tree.children:
984 if isinstance(t, Tree) and t.data == 'portbindinglist':
985 self.bindings[t.children[0]] = t.children[1]
986 elif is_tree_type(t, 'hmodinitblock'): # currently we only have one block
987 if encountered_initblock:
988 raise ValueError('Only one hmodinitblock should present')
989 encountered_initblock = True
990 name = t.children[0]
991 initblock, portbindings, senslist = None, None, []
992 for ch in t.children[1:]:
993 if ch.data == 'hcstmt': # TODO: have a dedicated node for initial block
994 initblock = ch
995 elif ch.data == 'portbindinglist':
996 portbindings = ch
997 elif ch.data == 'hsenslist':
998 senslist.append(ch)
999 else:
1000 raise ValueError(ch.pretty())
1001 if initblock:
1002 self.inc_indent()
1003 self.inc_indent()
1004 self.set_current_proc_name('#initblock#')
1005 self.__push_up(initblock)
1007 self.dec_indent()
1008 self.dec_indent()
1009 if portbindings:
1010 for bds in portbindings.children[1]:
1011 mod_name = bds.children[0]
1012 bindings = bds.children[1:]
1013 if mod_name not in self.bindings:
1014 self.bindings[mod_name] = []
1015 self.bindings[mod_name].append(bindings)
1016 # has something within the initialization block
1017 if initblock and initblock.children:
1018 initialization_block.append(initblock.children[0])
1019 tree.children = list(filter(lambda x: not isinstance(x, Tree) or x.data != 'portbindinglist', tree.children))
1020 self.inc_indent()
1021 self.__push_up(tree)
1022 self.dec_indent()
1023
1024 module_name = tree.children[0]
1025 modportsiglist = None
1026 processlist = None
1027 functionlist = []
1028 vars = None
1029 mods = []
1030 for t in tree.children:
1031 if isinstance(t, Tree):
1032 if t.data == 'modportsiglist':
1033 modportsiglist = t
1034 elif t.data == 'processlist':
1035 processlist = t
1036 elif t.data =='hfunction':
1037 functionlist.append(t)
1038
1039 # module_name, modportsiglist, processlist, portbindinglist = tree.children
1040 if modportsiglist:
1041 ports = list(filter(lambda x: isinstance(x, Tree) and x.data == 'portdecltype', modportsiglist.children))
1042 sigs = list(filter(lambda x: isinstance(x, Tree) and x.data == 'sigdecltype', modportsiglist.children))
1043 vars = list(filter(lambda x: isinstance(x, tuple), modportsiglist.children))
1044 mods = list(filter(lambda x: isinstance(x, Tree) and x.data == 'moduleinst', modportsiglist.children))
1045 else:
1046 ports, sigs = None, None
1047
1048
1049 res = 'module {} ('.format(module_name) + '\n'
1050 # Generate ports
1051 if ports:
1052 self.inc_indent()
1053 ind = self.get_current_ind_prefix()
1054 for idx, p in enumerate(ports):
1055 name, tpe = p.children
1056 name = name.children[0].value
1057 type_context = None
1058 if idx == len(ports) - 1:
1059 type_context = TypeContext(suffix='')
1060 res += ind + tpe.to_str(name, type_context) + '\n'
1061 self.dec_indent()
1062 res += ');\n'
1063 # Generate signals
1064 if sigs:
1065 self.inc_indent()
1066 ind = self.get_current_ind_prefix()
1067 for idx, p in enumerate(sigs):
1068 name, tpe = p.children
1069 name = name.children[0].value
1070 type_context = None
1071 res += ind + tpe.to_str(name, type_context) + '\n'
1072 self.dec_indent()
1073 # generate vars (including modules)
1074 if vars:
1075 self.inc_indent()
1076 ind = self.get_current_ind_prefix()
1077 res = self.__generate_vars_decl(ind, res, vars)
1078 self.dec_indent()
1079 # generate initialization block
1080 if initialization_block:
1081 self.inc_indent()
1082 ind = self.get_current_ind_prefix()
1083 res += '{}initial begin\n'.format(ind)
1084 res += '\n'.join(initialization_block)
1085 res += '\n{}end\n'.format(ind)
1086 self.dec_indent()
1087 # generate module instantiations
1088 if len(mods) > 0:
1089 for m in mods:
1090 res += m.children[0] + '\n'
1091 # Generate processes
1092 if processlist:
1093 for proc in processlist.children:
1094 if is_tree_type(proc, 'hthread'):
1095 # thread_name, thread_sig, thread_sync, thread_comb = proc.children
1096 thread_func = None
1097 if len(proc.children) == 3:
1098 thread_name, thread_sync, thread_comb = proc.children
1099 elif len(proc.children) == 4:
1100 thread_name, thread_func, thread_sync, thread_comb = proc.children
1101 else:
1102 assert False, "thread should have 3 or 4 children node"
1103 self.inc_indent()
1104 ind = self.get_current_ind_prefix()
1105 res += '{}// Thread: {}\n'.format(ind, thread_name)
1106 # res = self.__generate_vars_decl(ind, res, thread_sig.children)
1107 self.dec_indent()
1108 res += thread_sync + "\n"
1109 if thread_func:
1110 res += thread_func + "\n"
1111 res += thread_comb + "\n"
1112 else:
1113 res += proc + '\n'
1114
1115 if functionlist:
1116 # for f in functionlist:
1117 # res += f + '\n'
1118 assert False, "functionlist should be empty, there may be a bug in the code"
1119 res += "endmodule"
1120 return res
1121
1122 def hbuiltin(self, tree):
1123 self.__push_up(tree)
1124 return tree.children[0]
1125
1126 def hscmax(self, tree):
1127 assert len(tree.children) == 2, "sc_max node should only have 2 children"
1128 self.__push_up(tree)
1129 L = tree.children[0]
1130 R = tree.children[1]
1131 return "(({}) < ({}) ? ({}) : ({}))".format(L, R, R, L)
1132
1133 def hscmin(self, tree):
1134 assert len(tree.children) == 2, "sc_min node should only have 2 children"
1135 self.__push_up(tree)
1136 L = tree.children[0]
1137 R = tree.children[1]
1138 return "(({}) < ({}) ? ({}) : ({}))".format(L, R, L, R)
1139
1140 def __is_generated_signal(self, name):
1141 return name.endswith('#')
1142
1143 def __generate_vars_decl(self, ind, res, vars):
1144 for decl, name, init in vars:
1145 if self.__is_generated_signal(name):
1146 # decl = '(* mark_debug = "true" *) ' + decl.replace('#', "")
1147 decl = decl.replace('#', "")
1148 if init:
1149 decl = decl + ' = ' + str(init) + ';'
1150 else:
1151 decl += ';'
1152 res += ind + decl + '\n'
1153 return res
__push_up(self, current_node)
Definition top_down.py:29