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 ..utils import terminate_with_no_trace
6from ..utils import ContextManager
7from lark import Tree, Token
8from functools import reduce
9import pprint
10import logging
11from .interface_generation import Interface, PortDecl
12
13module_arg = ''
14module_inst_arg = ''
15interface_arg = ''
16interface_inst_arg = ''
17port_decl_inst_arg = ''
18
19# module_arg = '(* keep = "true" *) '
20# module_inst_arg = '(* keep = "true" *) '
21# interface_arg = '(* keep = "true" *) '
22# interface_inst_arg = '(* keep = "true" *) '
23# port_decl_inst_arg = '(* mark_debug = "true" *) (* keep = "true" *) '
24
26 """Translate low-level format of the _hdl.txt into Verilog
27 Note that type defs are already expanded at this point, so all htypeinfo/htype should only include primitive types
28 This pass does not perform any tree transformation that alters the semantics, but **only** generates Verilog
29 """
30 def __init__(self, itf_meta):
31 super().__init__()
34 self.indent_inc = 2
35 self.indent_stack = list()
36 self.bindingsbindings = dict()
37 self.local_variables = set()
38 self.in_for_init = False
39 self.module_var_type = None
42 self.is_in_thread = False
43 self.thread_comb = False
46 self.itf_meta = itf_meta
48
50 """denotes one of four types of scope: loop, switch, branch, None
51 currently, this is only useful for determine the handling of breaks
52 """
53 return self.__current_scope_type[-1]
54
55 def push_current_scope_type(self, scope):
56 assert scope in ['loop', 'switch', 'branch'], 'Incorrect scope type'
57 self.__current_scope_type.append(scope)
58
60 self.__current_scope_type.pop()
61
62 def interfaces(self, tree):
63 self.__push_up(tree)
64 return '\n'.join(tree.children)
65
66 def interface(self, tree):
67 itf_name = tree.children[0]
68 port_decls = tree.children[1:]
69 res = f'{self.get_current_ind_prefix()}{interface_arg}interface {itf_name};\n'
70 self.inc_indent()
71
72 for port_decl in port_decls:
73 self.__push_up(port_decl.type)
74 name, *args = port_decl.type.children
75 tpe = Primitive.get_primitive(name)
76 assert tpe is not None, 'Type {} is not defined'.format(name)
77 tx = tpe(*args)
78 if isinstance(tx, array):
79 tx.T = tx.T.T
80 type_signature = tx.to_str(port_decl.name)
81 else:
82 type_signature = tx.T.to_str(port_decl.name)
83 res += f'{self.get_current_ind_prefix()}{type_signature}\n'
84
85 in_names = []
86 out_names = []
87 for port_decl in port_decls:
88 p: PortDecl = port_decl
89 if p.direction == 'input':
90 in_names.append(p.name)
91 elif p.direction == 'output':
92 out_names.append(p.name)
93 modport = f'{self.get_current_ind_prefix()}modport port0(\n'
94 self.inc_indent()
95 modport += f'{self.get_current_ind_prefix()}input {",".join(in_names)},\n'
96 modport += f'{self.get_current_ind_prefix()}output {",".join(out_names)}\n'
97 self.dec_indent()
98 modport += f'{self.get_current_ind_prefix()});\n'
99
100 self.dec_indent()
101 res += modport
102 res += f'{self.get_current_ind_prefix()}endinterface\n'
103 return res
104
105 def start(self, tree):
106 dprint(tree.pretty())
107 self.__push_up(tree)
108 return tree.children[0]
109
110 def modulelist(self, tree):
111 self.__push_up(tree)
112 res = '\n'.join(tree.children)
113 return res
114
115 def nonrefexp(self, tree):
116 self.__push_up(tree)
117 assert len(tree.children) == 1
118 return tree.children[0]
119
120 def __get_var_name(self, tree):
121 if isinstance(tree, str):
122 return tree
123 elif isinstance(tree, Tree):
124 if tree.data in ['hvarref']:
125 return tree.children[0]
126 elif tree.data in ['harrayref', 'hslice']:
127 return self.__get_var_name(tree.children[0])
128 assert False, 'Cannot extract variable name from {}'.format(tree)
129
130 def __get_var_names(self, tree):
131 """return a list of variable names"""
132 if isinstance(tree, Tree) and tree.data in ['hconcat']:
133 return reduce(lambda x, y: x + y, [self.__get_var_names(sub) for sub in tree.children])
134 else:
135 return [self.__get_var_name(tree)]
136
137
138 def hmethodcall(self, tree):
139 with self.ctx.add_values(is_in_hmethodcall=True):
140 self.__push_up(tree)
141 # temporary hack
142 if tree.children[0] == 'zhw__plane_reg2__plane_reg_func_0':
143 return f'// TODO: fix this function call {tree.children}';
144 return '{}({})'.format(tree.children[0], ','.join(map(str, tree.children[1:])))
145
146 def hwait(self, tree):
147 warnings.warn('hwait encountered, not implemented')
148 return "// hwait"
149
150 def hvarinitlist(self, tree):
151 self.__push_up(tree)
152 return '{' + ','.join(tree.children) + '}'
153
154 def blkassign(self, tree):
155 # dprint("--------------START----------------")
156 current_proc = self.get_current_proc_name()
157 sense_list = self.get_sense_list()
158
159 # dprint(self.current_module, ':', current_proc)
160 # dprint('Sensitivity: ', pprint.pformat(self.get_sense_list()))
161 # dprint('Var w/ type: ', pprint.pformat(self.module_var_type))
162 var_names = self.__get_var_names(tree.children[0])
163 is_intf = [
164 isinstance(vn, Token) and vn.type == 'INTF_ID'
165 for vn in var_names
166 ]
167 tpes = [self.get_current_module_var_type_or_default(vn) for vn in var_names]
168 all_none = all(t is None for t in tpes)
169 all_non_none = all(
170 t is not None or is_intf[i] for i, t in enumerate(tpes)
171 )
172 assert len(is_intf) == len(tpes)
173 if not all_none and not all_non_none:
174 raise ValueError('LHS of assignment must be all local variables or all non-local variables. On line: {}.'.format(tree.line))
175 is_nb = [isinstance(tpe, sc_signal) or
176 isinstance(tpe, sc_out) or
177 isinstance(tpe, array) and isinstance(tpe.get_element_type(), sc_signal) for tpe in tpes]
178
179 is_nb = [
180 is_nb[i] or is_intf[i] for i in range(len(is_nb))
181 ]
182 # is_nb checks whether one of the type needs to be non-blocking assignment
183 # and special case for thread
184 all_nb = all(is_nb) or current_proc in ['#thread_sync#']
185 all_b = all(not p for p in is_nb) or (self.is_in_thread and current_proc in ['#function#'])
186 if not all_nb and not all_b:
187 raise ValueError('The assignment must not mix blocking assignment and non-blocking assignment. On line: {}.'.format(tree.line))
188
189 # var_name = self.__get_var_name(tree.children[0])
190 # tpe = self.get_current_module_var_type_or_default(var_name)
191 # if tpe is None, it is either a local variable within a process or block, in this case, it should be =
192 # if current_proc not in ['#initblock#', '#function#']: # TODO: use a more programmatic way
193 # dprint("--------------END-------------------")
194 blocking = True
195 # while using non-blocking assignments in function is not recommended, we will need to use
196 # non-blocking assignments in a function so that its value can get properly assigned
197 # An example of such is the m_bits_data_valid signal in encode_stream
198 # In SystemC, when a signal is used in RHS, it will be added to the sensitivity list
199 if current_proc in sense_list or (current_proc in ['#function#', '#thread_sync#'] and not (self.is_in_thread and current_proc == '#function#')):
200 # sense_list = sense_list[current_proc]
201 # tpe is only recorded if the declaration crosses process boundary
202 # if tpe is not None:
203 if all_non_none:
204 # dprint(tpe.get_element_type())
205 # if isinstance(tpe, sc_signal) or \
206 # isinstance(tpe, sc_out) or \
207 # isinstance(tpe, array) and isinstance(tpe.get_element_type(), sc_signal):
208 # dprint('Changed to non-blocking assignment: '.format(var_name))
209 if all_nb:
210 blocking = False
211 if self.thread_comb:
212 blocking = True
213 self.__push_up(tree)
214 assert len(tree.children) == 2
215 is_local_var = self.__all_local_variables(var_names)
216 op = '=' if self.in_for_init or blocking or is_local_var else '<='
217 l = tree.children[0]
218 r = tree.children[1]
219
220
221 if type(l) == Tree and l.data == 'harrayref':
222 # __A[__r:__s] = __X
223 __A = l.children[0]
224 __r = l.children[1]
225 __s = l.children[2]
226 l = __A
227 if type(r) == Tree and r.data == 'harrayref': # special case for irreducible RHS
228 __X = r.children[3]
229 __B = r.children[0]
230 else:
231 __X = r
232 __B = r
233 r = "(({} & ~(~($bits({})'('b0)) << (({})-({})+1))) << ({})) | (({}) & ((~($bits({})'('b0)) ) << (({}) + 1) | ~(( ~($bits({})'('b0)) ) << ({}))))".format(
234 __X, __B,
235 __r, __s,
236 __s, __A,
237 __A, __r, __A, __s
238 )
239 elif type(r) == Tree and r.data == 'harrayref':
240 r = r.children[3]
241
242 # FIXME: this handling of shared signal across thread/comb block should be fixed
243 if (current_proc is None) or ('thread' not in current_proc and '#function#' not in current_proc):
245
246 res = '{} {} {}'.format(l, op, r)
247
248 if (current_proc is not None) and 'thread' in current_proc and l in self.non_thread_comb_signalsnon_thread_comb_signals:
249 res = ''
250 return res
251
252 def syscwrite(self, tree):
253 raise RuntimeError('Unsupported node: syscwrite')
254 self.__push_up(tree)
255 res = '{} {} {}'.format(tree.children[1], tree.children[0], tree.children[2])
256 return res
257
258
259 def numlitwidth(self, tree):
260 self.__push_up(tree)
261 lit, tpe = tree.children
262 assert hasattr(tpe, 'width'), 'Literal width type should have width member'
263 w = tpe.width # the primitive type must have width
264 return "{}{}'d{}".format('-' if lit < 0 else '', w, abs(lit))
265
266 def hcondop(self, tree):
267 self.__push_up(tree)
268 return '{} ? {} : {}'.format(tree.children[0], tree.children[1], tree.children[2])
269
270 def hliteral(self, tree):
271 """stops at literal, it is some kinds of terminal"""
272 self.__push_up(tree)
273 assert len(tree.children) == 1
274 return str(tree.children[0])
275
276 def hvarref(self, tree):
277 assert len(tree.children) == 1
278 if is_tree_type(tree.children[0], 'func_param_name_stub'):
279 return tree.children[0].children[0]
280 stripped = tree.children[0].replace("#", "")
281 return stripped
282
283 def syscread(self, tree):
284 """syscread: hsigassignr, token"""
285 self.__push_up(tree)
286 return tree.children[1]
287
288 def __check_const(self, tree):
289 """check whether the tree valuates to constant"""
290 if isinstance(tree, int):
291 return True
292 elif is_tree_type(tree, 'hliteral'):
293 return True
294 elif is_tree_type(tree, 'hbinop'):
295 return self.__check_const(tree.children[1]) and self.__check_const(tree.children[2])
296 return False
297
298 def _clean_harrayref(self, harrayref_node):
299 assert harrayref_node.data == 'harrayref'
300 if is_tree_type(harrayref_node.children[0], 'hsigassignr'):
301 # dprint(harrayref_node)
302 harrayref_node.children = harrayref_node.children[1:]
303 # dprint(harrayref_node)
304
305 def harrayref(self, tree):
306 # Check whether
307 l_const = None
308 r_const = None
309 self._clean_harrayref(tree)
310 if isinstance(tree.children[0], Tree) and tree.children[0].data == 'hslice':
311 if len(tree.children[0].children) == 3:
312 hslice = tree.children[0]
313 l, r = hslice.children[1:]
314 l_const = self.__check_const(l)
315 r_const = self.__check_const(r)
316
317 self.__push_up(tree)
318 if isinstance(tree.children[0], Tree) and tree.children[0].data == 'hslice':
319 hslice = tree.children[0]
320 var = hslice.children[0]
321 m = None
322 if len(hslice.children) == 3:
323 l, r = hslice.children[1:]
324 elif len(hslice.children) == 2:
325 m = hslice.children[1]
326 # l_const = isinstance(l, int)
327 # r_const = isinstance(r, int)
328 if l_const and r_const:
329 idx = '{}:{}'.format(l, r)
330 elif m is not None:
331 idx = '{}'.format(m)
332 else:
333 # for slicing that is not constant
334 tree.children = [var, l, r, "(({}) >> ({})) & ~(~($bits({})'('b0)) << (({}) - ({}) + 1))".format(var, r, var, l, r)]
335 return tree # irreducible hslice node
336 else:
337 var, idx = tree.children
338 res = '{}[{}]'.format(var, idx)
339 return res
340
341 def hsigassignl(self, tree):
342 warnings.warn('Implementing SigAssignL as non-blocking')
343 return '<='
344
345 def __is_local_variable(self, var_name):
346 return var_name in self.local_variables
347
348 def __all_local_variables(self, var_names):
349 return all(self.__is_local_variable(var_name) for var_name in var_names)
350
351 def hbinop(self, tree):
352 method_call_lhs = is_tree_type(tree.children[1], 'hmethodcall')
353 self.__push_up(tree)
354 if tree.children[0] == 'ARRAYSUBSCRIPT':
355 res = '{}[({})]'.format(tree.children[1], tree.children[2])
356 # special case handling for hemthodcall nodes:
357 #
358 if self.ctx.is_in_hmethodcall:
359 if method_call_lhs:
360 res = '{} & (1 << {})'.format(tree.children[1], tree.children[2])
361 else:
362 op = tree.children[0]
363 if op == '=':
364 pass
365 # op = '<='
366 if op == ',': # concatenation
367 res = '{{({}), ({})}}'.format(tree.children[1], tree.children[2])
368 elif op == '>>': # Note: shift right
369 res = '({}) {} ({})'.format(tree.children[1], '>>>', tree.children[2])
370 elif op == 'concat':
371 res = '{{ ({}) {} ({}) }}'.format(tree.children[1], ',', tree.children[2])
372 elif op == '@=': # non-blocking assignment in thread context
373 res = '{} <= ({})'.format(tree.children[1], tree.children[2])
374 else:
375 res = '({}) {} ({})'.format(tree.children[1], op, tree.children[2])
376 return res
377
378 def hpostfix(self, tree):
379 self.__push_up(tree)
380 return "{}{}".format(tree.children[1], tree.children[0])
381
382 def hprefix(self, tree):
383 self.__push_up(tree)
384 return "{}{}".format(tree.children[0], tree.children[1])
385
386 def hunop(self, tree):
387 self.__push_up(tree)
388 if len(tree.children) == 1:
389 return tree.children[0]
390 elif len(tree.children) == 2:
391 res = '{}({})'.format(tree.children[0], tree.children[1])
392 return res
393 else:
394 assert False
395 # The ++ and -- only shows in loop
396 # The original method is deprecated, we can hand over the self-increment to the synthesizer
397 # since we assue that we generate system verilog
398 # if tree.children[0] == '++':
399 # res = '{} = {} + 1'.format(tree.children[1], tree.children[1])
400 # elif tree.children[0] == '--':
401 # res = '{} = {} - 1'.format(tree.children[1], tree.children[1])
402 # else:
403 # res = '{}({})'.format(tree.children[0], tree.children[1])
404 # return res
405
406 def hcstmt(self, tree):
407 self.__push_up(tree)
408 assert len(tree.children) <= 1, "hcstmt should contain 0 or 1 child"
409 if tree.children:
410 return tree.children[0]
411 else:
412 return ''
413
414 def continuestmt(self, tree):
415 return 'continue'
416
418 ind = self.current_indent * self.indent_character
419 return ind
420
421 def casevalue(self, tree):
422 self.__push_up(tree)
423 return tree.children[0]
424
425 def switchbody(self, tree):
426 self.push_current_scope_type('switch')
427 self.__push_up(tree)
429 return '\n'.join(tree.children)
430
431 def casestmt(self, tree):
432 self.inc_indent()
433 self.__push_up(tree)
434 self.dec_indent()
435 ind = self.get_current_ind_prefix()
436 res = '{}{}: begin\n{}\n{}end'.format(ind, tree.children[0], '\n'.join(tree.children[1:]), ind)
437 return res
438
439 def switchcond(self, tree):
440 self.__push_up(tree)
441 return tree.children[0]
442
443 def switchstmt(self, tree):
444 self.inc_indent()
445 self.__push_up(tree)
446 self.dec_indent()
447 ind = self.get_current_ind_prefix()
448 res = '{}case({})\n{}\n{}endcase'.format(ind, tree.children[0], tree.children[1], ind)
449 return res
450
451 def breakstmt(self, tree):
452 if self.get_current_scope_type() in ['switch']:
453 return ""
454 else:
455 ind = self.get_current_ind_prefix()
456 res = '{}break;'.format(ind)
457 return res
458
459 def stmt(self, tree):
460 indentation = []
461 sep = []
462 noindent = ['hcstmt', 'ifstmt', 'forstmt', 'switchstmt', 'casestmt', 'breakstmt', 'whilestmt', 'dostmt']
463 nosemico = ['hcstmt', 'ifstmt', 'forstmt', 'switchstmt', 'casestmt', 'breakstmt', 'whilestmt', 'dostmt']
464 for x in tree.children:
465 if x is None:
466 continue
467 if x.data in noindent:
468 indentation.append('')
469 else:
470 indentation.append(self.get_current_ind_prefix())
471 if x.data in nosemico:
472 sep.append('')
473 else:
474 sep.append(';')
475
476 self.__push_up(tree)
477 def f_concat(x):
478 try:
479 if isinstance(x[1], Tree):
480 if x[1].data == 'expression_in_stmt':
481 # logging.warning('Expression as a statement may not have an effect. On line: {}'.format(x[1].line))
482 x = (x[0], x[1].children[0], x[2])
483 res = str(x[0]) + str(x[1]) + str(x[2])
484 elif x[1].data == 'portbinding':
485 ch = x[1].children
486 if hasattr(x[1], 'swap_for_for_loop'):
487 # TODO: this assign here is just to please the synthesizer
488 # otherwise synthesis won't go through
489 if 'NONAME' in ch[0]:
490 dot_access = '' if 'NONAME' in ch[0] else (ch[0] + '.')
491 else:
492 module_name = ch[0]
493 interface_name = Interface.generate_instance_name(module_name, False)
494 dot_access = '{}.'.format(interface_name)
495 assignment = f"assign {ch[1]} = {dot_access}{ch[2]}"
496 else:
497 ind = self.get_current_ind_prefix()
498 self.inc_indent()
499 self.inc_indent()
500 ind_always = self.get_current_ind_prefix()
501 self.dec_indent()
502 self.dec_indent()
503 ind_end = self.get_current_ind_prefix()
504 if 'NONAME' in ch[0]:
505 dot_access = '' if 'NONAME' in ch[0] else (ch[0] + '.')
506 else:
507 module_name = ch[0]
508 interface_name = Interface.generate_instance_name(module_name, False)
509 dot_access = '{}.'.format(interface_name)
510 # assignment = f"always @(*) begin\n{ind_always}{dot_access}{ch[1]} = {ch[2]};\n{ind_end}end"
511 assignment = f"{ind}assign {dot_access}{ch[1]} = {ch[2]}"
512 res = ''.join([x[0], assignment, x[2]])
513 elif x[1].data == 'hnamedsensvar':
514 res = f'{x[0]} /* always {x[1].children[1]} */ {x[2]}'
515 else:
516 assert False, 'Unrecognized construct: {}'.format(x[1])
517 else:
518 res = ''.join(x)
519 return res
520 except Exception as e:
521 print(x[0])
522 print(x[1])
523 print(x[2])
524 raise
525 res = '\n'.join(map(f_concat,
526 filter(lambda x: x[1] is not None, zip(indentation, tree.children, sep))
527 ))
528 return res
529
530 def hnoop(self, tree):
531 warnings.warn('Encountered noop at line: {}'.format(tree.meta.line))
532 return ""
533
534 def whilestmt(self, tree):
535 self.push_current_scope_type('loop')
536 self.inc_indent()
537 self.__push_up(tree)
538 self.dec_indent()
539 prefix = self.get_current_ind_prefix()
540 res = "{}while({}) begin\n".format(prefix, tree.children[0])
541 res += ''.join(tree.children[1:])
542 res += '\n{}end'.format(prefix)
544 return res
545
546 def dostmt(self, tree):
547 self.push_current_scope_type('loop')
548 self.inc_indent()
549 self.__push_up(tree)
550 self.dec_indent()
551 prefix = self.get_current_ind_prefix()
552
553 res = "{}do begin\n".format(prefix)
554 res += ''.join(tree.children[1:])
555 res += '\n{}end while({})'.format(prefix, tree.children[0])
556
558 return res
559
560 def stmts(self, tree):
561 self.__push_up(tree)
562 res = '\n'.join(tree.children)
563 return res
564
565 def inc_indent(self):
566 self.current_indent += self.indent_inc
567
568 def dec_indent(self):
569 self.current_indent -= self.indent_inc
570
571 def push_indent(self):
572 """used to service temporary indent removal, such as that in for condition"""
573 self.indent_stack.append(self.current_indent)
574 self.current_indent = 0
575 def pop_indent(self):
576 self.current_indent = self.indent_stack.pop()
577
578 def ifstmt(self, tree):
579 self.push_current_scope_type('branch')
580 self.inc_indent()
581 self.__push_up(tree)
582 self.dec_indent()
583 ind = self.get_current_ind_prefix()
584 res = ind + 'if ({}) begin\n'.format(tree.children[0])
585 if len(tree.children) > 1:
586 res += tree.children[1] + '\n'
587 res += ind + 'end'
588 # print('If Body: ', tree.children[1])
589 if len(tree.children) == 3:
590 res += ' else begin\n' + tree.children[2]
591 res += '\n'
592 res += ind + 'end\n'
593
595 return res
596
597 def forinit(self, tree):
598
599 self.in_for_init = True
600 self.__push_up(tree)
601 self.in_for_init = False
602
603 if tree.children:
604 return tree.children[0]
605 else:
606 return ''
607
608 def forcond(self, tree):
609 self.__push_up(tree)
610 return tree.children[0]
611
612 def forpostcond(self, tree):
613 self.__push_up(tree)
614 return tree.children[0]
615
616 def forbody(self, tree):
617 self.__push_up(tree)
618 return tree.children[0]
619
620 def forstmt(self, tree):
622 return self.__forstmt_gen_block(tree)
623
624 self.push_current_scope_type('loop')
625 new_children = []
626 self.push_indent()
627 new_children.extend(self.visit(t) for t in tree.children[:3])
628 self.pop_indent()
629
630 self.inc_indent()
631 new_children.extend(self.visit(t) for t in tree.children[3:])
632 self.dec_indent()
633
634 if len(new_children) == 3:
635 warnings.warn("empty for loop")
636 for_init, for_cond, for_post = new_children
637 for_body = ''
638 else:
639 for_init, for_cond, for_post, for_body = new_children
640
641 ind = self.get_current_ind_prefix()
642 res = ind + 'for ({};{};{}) begin\n'.format(for_init, for_cond, for_post)
643 res += for_body + '\n'
644 res += ind + 'end'
646 return res
647
648 def hsensvars(self, tree):
649 self.__push_up(tree)
650 return tree
651
652 def npa(self, tree):
653 return tree.children[0]
654
655 def hsensedge(self, tree):
656 self.__push_up(tree)
657 return tree.children[0]
658
659 def get_sense_list(self):
660 return self.senselistsenselist
661
662 def hsenslist(self, tree):
663 self.__push_up(tree)
664 proc_name = tree.children[0]
665 assert proc_name not in self.senselistsenselist, 'Duplicated process: {}'.format(proc_name)
666 self.senselistsenselist[proc_name] = []
667 for sv in tree.children[1:]:
668 # special treatment
669 sens_var, sens_edge = sv.children
670 if is_tree_type(sv.children[0], "hsensvar"):
671 warnings.warn("Malformatted sensitivity list")
672 sens_edge, sens_var = sv.children[0].children
673 if sens_edge == 'posedge_event':
674 edge = 'posedge'
675 elif sens_edge == 'negedge_event':
676 edge = 'negedge'
677 else:
678 edge = ''
679 sen_str = '{} {}'.format(edge, sens_var)
680 else:
681 if isinstance(sens_var, Token):
682 sens_var = sens_var.value
683 if sens_edge == 'always':
684 sen_str = sens_var
685 elif sens_edge in ['pos', 'posedge_event']:
686 sen_str = 'posedge {}'.format(sens_var)
687 elif sens_edge in ['neg', 'negedge_event']:
688 sen_str = 'negedge {}'.format(sens_var)
689 else:
690 raise ValueError('Edge can only be one of pos/neg/always')
691 self.senselistsenselist[proc_name].append(sen_str)
692 return None
693
694 def hvalchange(self, tree):
695 warnings.warn('value change is deprecated, but is detected in hcode', DeprecationWarning)
696 self.__push_up(tree)
697 return tree.children[0]
698
699 def set_current_proc_name(self, name):
700 self.current_proc_name = name
701
703 self.current_proc_name = None
704
706 return self.current_proc_name
707
709 return any('posedge' in x or 'negedge' in x for x in sense_list)
710
711 def hprocess(self, tree):
712 proc_name, proc_name_2, prevardecl, *body = tree.children
713
714 self.set_current_proc_name(proc_name)
715 for n in prevardecl.children:
716 var_name = n.children[0].children[0] # get the variable name of local variables
717 self.__add_local_variables(var_name)
718 self.inc_indent()
719
720 if hasattr(tree, 'force_sensevar'):
721 tree.children = [tree.force_sensevar] + tree.children
722 self.__push_up(tree)
723 if hasattr(tree, 'force_sensevar'):
724 tree.force_sensevar = tree.children[0]
725 tree.children = tree.children[1:]
726 self.dec_indent()
727
728 proc_name, proc_name_2, prevardecl, *body = tree.children
729
730 prevardecl.children = list(filter(lambda x: not is_tree_type(x, 'vardeclrn'), prevardecl.children))
731
732 ind = self.get_current_ind_prefix()
733 decls = list(map(lambda x: x[0] + ';', prevardecl.children))
734 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)))
735 sense_list = self.get_sense_list()
736 assert proc_name in sense_list, "Process name {} is not in module {}".format(proc_name, self.current_module)
737 # res = ind + 'always @({}) begin: {}\n'.format(' or '.join(self.get_sense_list()[proc_name]), proc_name)
738 if hasattr(tree, 'force_sensevar'):
739 res = ind + 'always @({}) begin: {}\n'.format(tree.force_sensevar, proc_name)
740 elif self.__is_synchronous_sensitivity_list(sense_list[proc_name]):
741 res = ind + 'always_ff @({}) begin: {}\n'.format(' or '.join(self.get_sense_list()[proc_name]), proc_name)
742 else:
743 res = ind + 'always @({}) begin: {}\n'.format(' or '.join(self.get_sense_list()[proc_name]), proc_name)
744 # res = ind + 'always_comb begin: {}\n'.format(proc_name)
745 self.inc_indent()
746 ind = self.get_current_ind_prefix()
747 res += ind + ('\n' + ind).join(decls) + '\n'
748 res += ind + ('\n' + ind).join(decls_init) + '\n'
749 self.dec_indent()
750 ind = self.get_current_ind_prefix()
751 res += '\n'.join(body) + '\n'
752 res += ind + 'end'
755 return res
756
758 self.local_variables = set()
759
760 def __add_local_variables(self, var_name):
761 assert var_name not in self.local_variables, 'Local variable {} already existed'.format(var_name)
762 self.local_variables.add(var_name)
763
764 def htype(self, tree):
765 self.__push_up(tree)
766 name, *args = tree.children
767 tpe = Primitive.get_primitive(name)
768 assert tpe is not None, 'Type {} is not defined'.format(name)
769 return tpe(*args)
770
771 def hreturnstmt(self, tree):
772 self.__push_up(tree)
773 logging.warning(
774 """Return statement is detected and omitted.\n"""
775 """ A return statement may not produce expected result,\n"""
776 """ consider removing it in the C++ code.\n"""
777 )
778 if len(tree.children) == 1:
779 return 'return {}'.format(tree.children[0])
780 elif len(tree.children) == 0:
781 return 'return'
782 return ''
783 else:
784 assert len(tree.children) in [0, 1], 'return statement can only have 0 or 1 return value'
785
786 def __gen_funcparam(self, tree):
787 self.__push_up(tree)
788 var_name, tpe = tree.children
789 ctx = TypeContext(suffix='')
790 decl = tpe.to_str(var_name, context=ctx)
791 # if self.get_current_proc_name() is None:
792 # # we only check variables that are across processes, otherwise, there is no point in having non-blocking
793 # # assignment
794 # self.insert_current_module_var_type(var_name, tpe)
795 return decl, var_name, None
796
797 def funcparami(self, tree):
798 return self.__gen_funcparam(tree)
799
800 def funcparamio(self, tree):
801 return self.__gen_funcparam(tree)
802
803 def vardeclinit(self, tree):
804 self.__push_up(tree)
805 init_val = None
806 tpe = None
807 if len(tree.children) == 2:
808 var_name, tpe = tree.children
809 elif len(tree.children) == 3:
810 var_name, tpe, init_val = tree.children
811 else:
812 assert False, 'children size of vardeclinit is not 2 or 3, there might be a bug in the translator'
813 ctx = TypeContext(suffix='')
814 decl = tpe.to_str(var_name, context=ctx)
815 if self.get_current_proc_name() is None:
816 # we only check variables that are across processes, otherwise, there is no point in having non-blocking
817 # assignment
818 self.insert_current_module_var_type(var_name, tpe)
819 return (decl, var_name, init_val)
820
821 def hbindingarrayref(self, tree):
822 """
823 this expansion should only be invoked by expanding_binding_ref and should not be invoked elsewhere
824 the reason is that we need to collect binding information per arry-like port
825 """
826 self.__push_up(tree)
827 return '{}[{}]'.format(tree.children[0], tree.children[1])
828
829 def expand_binding_ref(self, tree):
830 if not is_tree_type(tree, 'hbindingarrayref'):
831 raise ValueError('expand_binding_ref only accepts hbindingarrayref')
832 self.__push_back(tree)
833 return '{}[{}]'.format(tree.children[0], tree.children[1])
834
835 def _get_interface_instance_decl(self, mod_name, mod_type_name, ind, is_array):
836 interface: Interface = self.itf_meta.get(mod_type_name, None)
837 res = ''
838 if interface:
839 res += ind + '{} {}();\n'.format(
840 interface.interface_name,
841 Interface.generate_instance_name(mod_name, is_array)
842 )
843 return res
844
845 def _get_interface_instance(self, mod_name, mod_type_name, is_array):
846 interface: Interface = self.itf_meta.get(mod_type_name, None)
847 if interface:
848 return Interface.generate_instance_name(mod_name, is_array)
849 return None
850
851 def modulearrayinst(self, tree):
852 res: str = ''
853 ind = self.get_current_ind_prefix()
854
855 mod_name, mod_type = tree.children
856 mod_type_name = mod_type.children[0].children[1].children[0]
857 mod_array_dimension = mod_type.children[0].children[2]
858
859 genvar_names = list(
860 map(lambda x: '_'.join([self.current_module, mod_name, str(x)]), range(len(mod_array_dimension)))
861 )
862 # genvar decl
863 for genvar in genvar_names:
864 res += ind + 'genvar {};\n'.format(genvar)
865
866 for idx, (genvar, dim) in enumerate(zip(genvar_names, mod_array_dimension)):
867 res += ind + "/*generate*/ for ({} = 0; {} < {}; {} = {} + 1) begin {}\n".format(
868 genvar, genvar, dim, genvar, genvar, ': ' + mod_name if idx == 0 else ''
869 )
870
871 self.inc_indent()
872 ind = self.get_current_ind_prefix()
873 # intf meta
874 res += self._get_interface_instance_decl(mod_name, mod_type_name, ind, True)
875 # the actual module def
876 res += ind + "{} mod(\n".format(mod_type_name)
877
878 # now collect the normal port binding
879 if mod_name not in self.bindingsbindings:
880 warnings.warn('Port bindings for module instance name {} not found'.format(mod_name))
881 bindings = []
882 else:
883 bindings = self.bindingsbindings[mod_name]
884
885
886
887 def extract_binding_name(x):
888 # FIXME: when the port connection is 2D, the original approach may not work
889 return get_ids_in_tree(x[0])[0]
890 # if is_tree_type(x[0], 'hbindingarrayref'):
891 # res = x[0].children[0].children[0]
892 # else:
893 # res = x[0].children[0]
894 # return res
895 # these are us trying to pull non-indexed bindings to the declaration point
896 orig_bindings = bindings
897 bindings_normal = list(filter(lambda x: '.' not in extract_binding_name(x), orig_bindings))
898 bindings_hier = list(filter(lambda x: '.' in extract_binding_name(x), orig_bindings))
899 bindings = bindings_normal
900 # ind = self.get_current_ind_prefix()
901 # res = ind + '{} {}('.format(mod_type_name, mod_name) + '\n'
902 # self.inc_indent()
903 # ind = self.get_current_ind_prefix()
904 binding_str = []
905 array_bindings = {}
906 for binding in bindings:
907 # for backward compatibility, we keep the case where binding is a list
908 if type(binding) == list:
909 sub, par = binding
910 else:
911 warnings.warn('Using Tree as binding is deprecated', DeprecationWarning)
912 sub, par = binding.children
913 if is_tree_type(sub, 'hbindingarrayref'):
914 # The .xxx part is an array
915 sub_name = get_ids_in_tree(sub)[0].value # assuming varref
916 if sub_name not in array_bindings:
917 array_bindings[sub_name] = {}
918 # if sub.children[0].data == 'hbindingarrayref':
919 # raise ValueError('nested 2-D array port is not supported')
920 array_bindings[sub_name][sub.children[1].children[0]] = par
921 else:
922 # at this point, the par should be able to be fully expanded even if it is an array
923 if is_tree_type(par, 'hbindingarrayref'):
924 par = self.expand_binding_ref(par)
925 else:
926 par = par.children[0].value
927 binding_str.append(ind + '.{}({})'.format(sub.children[0].value, par))
928 for sub_name, bindings in array_bindings.items():
929 # for now, we keep a dict of array binding
930 array_seq = [None] * len(bindings)
931 for idx, b in bindings.items():
932 # dprint(self.expand_binding_ref(b))
933 # array_seq[idx] = '{}[{}]'.format(b.children[0].children[0].value, b.children[1].children[0])
934 array_seq[idx] = self.expand_binding_ref(b)
935 binding_str.append(ind + ".{}('{{ {} }})".format(
936 sub_name, ','.join(array_seq)
937 ))
938 # res += ',\n'.join(binding_str)
939 # # switch to use interface
940 interface: Interface = self.itf_meta.get(mod_type_name, None)
941 self.inc_indent()
942 ind = self.get_current_ind_prefix()
943 res += ind + interface.generate_instance_name(mod_name, True)
944 self.dec_indent()
945 ind = self.get_current_ind_prefix()
946 res += "\n"
947
948 res += ind + ");\n"
949 self.dec_indent()
950 ind = self.get_current_ind_prefix()
951
952 for _ in mod_array_dimension:
953 res += ind + "end\n"
954
955
956 tree.children = [res]
957 return tree
958
959 def moduleinst(self, tree):
960 # -- these are actually for handling module array instance
961 # we should be ablt to forgo these
962 mod_name, mod_type = tree.children
963 # expand if it is an element of module array
964 mod_name = '_'.join(mod_name.split('#'))
965 if len(mod_type.children[0].children) > 1:
966 warnings.warn('Type parameters for modules are not supported')
967 mod_type_name = mod_type.children[0].children[0]
968 if mod_name not in self.bindingsbindings:
969 warnings.warn('Port bindings for module instance name {} not found'.format(mod_name))
970 bindings = []
971 else:
972 bindings = self.bindingsbindings[mod_name]
973 def extract_binding_name(x):
974 # FIXME: when the port connection is 2D, the original approach may not work
975 return get_ids_in_tree(x[0])[0]
976 # if is_tree_type(x[0], 'hbindingarrayref'):
977 # res = x[0].children[0].children[0]
978 # else:
979 # res = x[0].children[0]
980 # return res
981 # these are us trying to pull non-indexed bindings to the declaration point
982 interface_decl = self._get_interface_instance_decl(mod_name,
983 mod_type_name, '', False)
984 interface: Interface = self.itf_meta.get(mod_type_name, None)
985
986 # Now we need slightly different logic for port bindings since we are using interfaces
987
988 orig_bindings = bindings
989 bindings_normal = list(filter(lambda x: '.' not in extract_binding_name(x), orig_bindings))
990 bindings_hier = list(filter(lambda x: '.' in extract_binding_name(x), orig_bindings))
991 bindings = bindings_normal
992 ind = self.get_current_ind_prefix()
993 res = ind + interface_inst_arg + interface_decl + '\n'
994 res += ind + '{}{} {}('.format(module_inst_arg, mod_type_name, mod_name) + '\n'
995 self.inc_indent()
996 ind = self.get_current_ind_prefix()
997 interface_instance_name: str = self._get_interface_instance(mod_name, mod_type_name, False)
998 binding_str = []
999 array_bindings = {}
1000 for binding in bindings:
1001 # for backward compatibility, we keep the case where binding is a list
1002 if type(binding) == list:
1003 sub, par = binding
1004 else:
1005 warnings.warn('Using Tree as binding is deprecated', DeprecationWarning)
1006 sub, par = binding.children
1007 if is_tree_type(sub, 'hbindingarrayref'):
1008 # The .xxx part is an array
1009 sub_name = get_ids_in_tree(sub)[0].value # assuming varref
1010 if sub_name not in array_bindings:
1011 array_bindings[sub_name] = {}
1012 # if sub.children[0].data == 'hbindingarrayref':
1013 # raise ValueError('nested 2-D array port is not supported')
1014 array_bindings[sub_name][sub.children[1].children[0]] = par
1015 else:
1016 # at this point, the par should be able to be fully expanded even if it is an array
1017 if is_tree_type(par, 'hbindingarrayref'):
1018 par = self.expand_binding_ref(par)
1019 else:
1020 par = par.children[0].value
1021 if interface:
1022 for port_decl in interface.interfaces: # type: PortDecl
1023 if port_decl.name == sub.children[0].value:
1024 assert port_decl.direction in ['input', 'output'], "Interface port direction not recognized"
1025 if port_decl.direction == 'input':
1026 binding_str.append(ind + 'assign {}.{} = {};'.format(interface_instance_name, sub.children[0].value, par))
1027 elif port_decl.direction == 'output':
1028 binding_str.append(ind + 'assign {} = {}.{};'.format(par, interface_instance_name, sub.children[0].value))
1029 break
1030 for sub_name, bindings in array_bindings.items():
1031 assert False
1032 # for now, we keep a dict of array binding
1033 array_seq = [None] * len(bindings)
1034 for idx, b in bindings.items():
1035 # dprint(self.expand_binding_ref(b))
1036 # array_seq[idx] = '{}[{}]'.format(b.children[0].children[0].value, b.children[1].children[0])
1037 array_seq[idx] = self.expand_binding_ref(b)
1038 binding_str.append(ind + ".{}('{{ {} }})".format(
1039 sub_name, ','.join(array_seq)
1040 ))
1041 # Insert binding for hierarchical ports
1042 for binding in bindings:
1043 pass
1044 # dprint(binding)
1045
1046 if interface_instance_name:
1047 res += ind + interface_instance_name
1048
1049 res += '\n'
1050 self.dec_indent()
1051 ind = self.get_current_ind_prefix()
1052 res += ind + ');\n'
1053
1054 res += '\n'.join(binding_str)
1055
1056 res += '\n'
1057 res += ind + "always @(*) begin\n"
1058 # res += ind + "always_comb begin\n"
1059 self.inc_indent()
1060 ind = self.get_current_ind_prefix()
1061 for bl, br in bindings_hier:
1062 res += ind + '{} = {};\n'.format(bl.children[0], br.children[0])
1063 self.dec_indent()
1064 ind = self.get_current_ind_prefix()
1065 res += ind + "end\n"
1066 # add an always block for port binding when we encounter sub module case
1067 tree.children = [res]
1068 return tree
1069
1070 def hlrotate(self, tree):
1071 self.__push_up(tree)
1072 val, rot = tree.children
1073 return '({} << {}) | ($unsigned({}) >> ($bits({}) - {}))'.format(val, rot, val, val, rot)
1074 def horreduce(self, tree):
1075 self.__push_up(tree)
1076 val = tree.children[0]
1077 return '(|{})'.format(val)
1078
1079 def hconcat(self, tree):
1080 self.__push_up(tree)
1081 l, r = tree.children[0], tree.children[1]
1082 res = '{{ {}, {} }}'.format(l, r)
1083 return res
1084
1085 def vardecl(self, tree):
1086 self.__push_up(tree)
1087 return tree.children
1088
1089 def prevardecl(self, tree):
1090 self.__push_up(tree)
1091 new_children = []
1092 for t in tree.children:
1093 new_children.extend(t)
1094 tree.children = new_children
1095 return tree
1096
1097 def htypeinfo(self, tree):
1098 # Note: htypeinfo should return an object that can be used to apply to a variable
1099 self.__push_up(tree)
1100 return tree.children[0]
1101
1102 def func_param_name_stub(self, tree):
1103 self.__push_up(tree)
1104 tree.insert_name(self.module_var_type.keys())
1105 var_name, tpe = tree.children
1106 ctx = TypeContext(suffix='')
1107 decl = tpe.to_str(var_name, context=ctx)
1108 return decl, var_name, None
1109
1110 def hfunctionparams(self, tree):
1111 self.__push_up(tree)
1112 return tree
1113
1114 def hfunctionrettype(self, tree):
1115 self.__push_up(tree)
1116 if len(tree.children) != 0:
1117 tpe = tree.children[0]
1118 res = tpe.to_str(var_name='')
1119 else:
1120 res = "void"
1121 return res
1122
1123 def htouint(self, tree):
1124 self.__push_up(tree)
1125 return '$unsigned({})'.format(tree.children[0])
1126
1127 def htoint(self, tree):
1128 self.__push_up(tree)
1129 return '$signed({})'.format(tree.children[0])
1130
1131 def htoulong(self, tree):
1132 self.__push_up(tree)
1133 return '$unsigned({})'.format(tree.children[0])
1134
1135 def htolong(self, tree):
1136 self.__push_up(tree)
1137 return '$signed({})'.format(tree.children[0])
1138
1139 def hfunctionlocalvars(self, tree):
1140 self.__push_up(tree)
1141 return tree
1142
1143 def hfunction(self, tree):
1144 self.set_current_proc_name('#function#')
1145 self.inc_indent()
1146 self.__push_up(tree)
1147 self.dec_indent()
1148 ind = self.get_current_ind_prefix()
1149
1150 # function_name, return_type, params, localvar, body = tree.children
1151 function_name, return_type = tree.children[:2]
1152 params = ''
1153 for ch in tree.children[2:]:
1154 if is_tree_type(ch, 'hfunctionparams'):
1155 params = ', '.join(map(lambda x: x[0], ch.children))
1156 elif is_tree_type(ch, 'hfunctionlocalvars'):
1157 localvar = ch
1158 elif is_tree_type(ch, "hfunctionbody"):
1159 body = ch
1160
1161
1162 self.inc_indent()
1163 ind = self.get_current_ind_prefix()
1164 localvars = '\n'.join(map(lambda x: ind + x[0] + ';', localvar.children))
1165 self.dec_indent()
1166 body = '\n'.join(body.children)
1167
1168 ind = self.get_current_ind_prefix()
1169 res = '{}function automatic {} {} ({});\n{}begin\n{}\n{}\n{}end\n{}endfunction'.format(ind, return_type, function_name,
1170 params, ind,
1171 localvars, body, ind, ind)
1173 return res
1174
1175 def collect_type(self, port_or_sig):
1176 assert isinstance(port_or_sig, Tree) and \
1177 port_or_sig.data in ['sigdecltype', 'portdecltype'], \
1178 'collect_type must be invoked with portdecltype or sigdecltype, but got: {}'.format(port_or_sig)
1179 id = port_or_sig.children[0].children[0]
1180 tpe = port_or_sig.children[1]
1181 self.insert_current_module_var_type(id, tpe)
1182
1183 def sigdecltype(self, tree):
1184 self.__push_up(tree)
1185 self.collect_type(tree)
1186 return tree
1187
1188 def portdecltype(self, tree):
1189 self.__push_up(tree)
1190 self.collect_type(tree)
1191 return tree
1192
1193 def modportsiglist(self, tree):
1194 self.__push_up(tree)
1195 return tree
1196
1198 return self.module_var_type[id]
1199
1200 def get_current_module_var_type_or_default(self, id, default=None):
1201 if id not in self.module_var_type:
1202 return default
1203 return self.module_var_type[id]
1204
1206 self.module_var_type = dict()
1207
1209 if id in self.module_var_type:
1210 raise ValueError('Duplicate signal declaration: {}'.format(id))
1211 self.module_var_type[id] = tpe
1212
1213 def hthread(self, tree):
1214 # hthread concists of 4 parts as children
1215 # 1. thread name
1216 # 2. signals declaration across hmethods
1217 # 3. synchronous hmethod for setting state to next_state and reset
1218 # 4. combinational hmethod for driving next_state
1219 # We need 2 to be at the module level and thus its processing will be handled in hmodule
1220 self.is_in_thread = True
1221 self.thread_name = tree.children[0]
1222 self.__push_up(tree)
1223 del self.thread_name
1224 self.is_in_thread = False
1225 return tree
1226
1227 def __generate_hthread_block(self, tree, is_sync):
1228 # currently we assume that the hthread block is simply and there is no sensitivity list and
1229 # var decls, this might change in the future when we add support for resets
1230 proc_name, *body = tree.children
1231 if is_sync:
1232 self.set_current_proc_name('#thread_sync#')
1233 else:
1234 self.set_current_proc_name(proc_name)
1235
1236 ind = self.get_current_ind_prefix()
1237
1238 thread_name = self.thread_name
1239 sense_list = self.get_sense_list()
1240 assert thread_name in sense_list, "Process name {} is not in module {}".format(proc_name, self.current_module)
1241 if is_sync:
1242 sense_list = self.get_sense_list()[thread_name]
1243 if 'posedge clk' not in sense_list:
1244 warnings.warn("Clock not detected in senstivity list, adding one by default")
1245 sense_list = ['posedge clk'] + sense_list
1246 res = ind + 'always @({}) begin: {}\n'.format(' or '.join(sense_list), proc_name)
1247 else:
1248 res = ind + 'always @(*) begin: {}\n'.format(proc_name)
1249 self.inc_indent()
1250 self.__push_up(tree)
1251 proc_name, *body = tree.children
1252 ind = self.get_current_ind_prefix()
1253 res += '\n'.join(body) + '\n'
1254 self.dec_indent()
1255 ind = self.get_current_ind_prefix()
1256 res += ind + 'end'
1259 return res
1260
1261 def hthreadsync(self, tree):
1262 res = self.__generate_hthread_block(tree, is_sync=True)
1263 return res
1264
1265 def hthreadswitch(self, tree):
1266 self.thread_comb = True
1267 res = self.__generate_hthread_block(tree, is_sync=False)
1268 self.thread_comb = False
1269 return res
1270
1271 def genbindinglist(self, tree):
1272 # this node is created in portbinding_recollect.py passes
1273 # dprint(f"raw dynamically generated genbindinglist node:\n{tree.pretty()}")
1274 self.__push_up(tree)
1275 return tree
1276
1277 def genvardecl(self, tree):
1278 genvars = list(map(lambda x: "{}genvar {};".format(self.get_current_ind_prefix(), x), tree.children))
1279 res = '\n'.join(genvars)
1280 return res
1281
1282 def genfor(self, tree):
1283 self.__push_up(tree)
1284 return "\n".join(tree.children)
1285
1286 def hmodule(self, tree):
1287 # dprint("Processing Module: ", tree.children[0])
1288 # print("Retrieving Portbindings")
1289 self.current_module = tree.children[0]
1292 initialization_block = []
1293 encountered_initblock = False
1294 self.bindingsbindings = dict()
1295 genbindinglist = None
1296 for t in tree.children:
1297 if isinstance(t, Tree) and t.data == 'portbindinglist':
1298 self.bindingsbindings[t.children[0]] = t.children[1]
1299 assert False, "Deadcode"
1300 elif is_tree_type(t, 'hmodinitblock'): # currently we only have one block
1301 if encountered_initblock:
1302 raise ValueError('Only one hmodinitblock should present')
1303 encountered_initblock = True
1304 name = t.children[0]
1305 initblock, portbindings, senslist, genbindinglist = None, None, [], None
1306 for ch in t.children[1:]:
1307 if ch.data == 'hcstmt': # TODO: have a dedicated node for initial block
1308 initblock = ch
1309 elif ch.data == 'portbindinglist':
1310 portbindings = ch
1311 elif ch.data == 'hsenslist':
1312 senslist.append(ch)
1313 elif ch.data == 'vardecl':
1314 initblock = ch
1315 elif ch.data == 'hnamedsensevar':
1316 senslist.append(ch)
1317 elif ch.data == 'genbindinglist':
1318 genbindinglist = ch
1319 else:
1320 raise ValueError(ch.pretty())
1321 if initblock:
1322 self.inc_indent()
1323 self.inc_indent()
1324 self.set_current_proc_name('#initblock#')
1325 self.__push_up(initblock)
1327 self.dec_indent()
1328 self.dec_indent()
1329 if portbindings:
1330 for bds in portbindings.children[1]:
1331 mod_name = bds.children[0]
1332 bindings = bds.children[1:]
1333 if mod_name not in self.bindingsbindings:
1334 self.bindingsbindings[mod_name] = []
1335 self.bindingsbindings[mod_name].append(bindings)
1336 # has something within the initialization block
1337 if initblock and initblock.children:
1338 initialization_block.append(initblock.children[0])
1339 tree.children = list(filter(lambda x: not isinstance(x, Tree) or x.data != 'portbindinglist', tree.children))
1340 self.inc_indent()
1341 self.__push_up(tree)
1342 self.dec_indent()
1343
1344 module_name = tree.children[0]
1345 modportsiglist = None
1346 processlist = None
1347 generatelist = []
1348 functionlist = []
1349 vars = None
1350 mods = []
1351 for t in tree.children:
1352 if isinstance(t, Tree):
1353 if t.data == 'modportsiglist':
1354 modportsiglist = t
1355 elif t.data == 'processlist':
1356 processlist = t
1357 elif t.data == 'hgenerateblock':
1358 generatelist.append(t.children[0])
1359 elif t.data =='hfunction':
1360 functionlist.append(t)
1361
1362 # module_name, modportsiglist, processlist, portbindinglist = tree.children
1363 if modportsiglist:
1364 ports = list(filter(lambda x: isinstance(x, Tree) and x.data == 'portdecltype', modportsiglist.children))
1365 sigs = list(filter(lambda x: isinstance(x, Tree) and x.data == 'sigdecltype', modportsiglist.children))
1366 vars = list(filter(lambda x: isinstance(x, tuple), modportsiglist.children))
1367 mods = list(filter(lambda x: isinstance(x, Tree) and
1368 (x.data == 'moduleinst' or x.data == 'modulearrayinst'),
1369 modportsiglist.children))
1370 else:
1371 ports, sigs = None, None
1372
1373
1374 res = module_arg + 'module {} ('.format(module_name) + '\n'
1375 # Generate ports
1376 port_str = ''
1377 if ports:
1378 self.inc_indent()
1379 ind = self.get_current_ind_prefix()
1380 for idx, p in enumerate(ports):
1381 name, tpe = p.children
1382 name = name.children[0].value
1383 type_context = None
1384 if idx == len(ports) - 1:
1385 type_context = TypeContext(suffix='')
1386 port_str += ind + tpe.to_str(name, type_context) + '\n'
1387 self.dec_indent()
1388 interface = self.itf_meta.get(module_name, None)
1389 if interface:
1390 port_str = port_decl_inst_arg + ' ' + interface.interface_name + '.port0 ' + interface.generate_interface_decl_name() + '\n'
1391 res += port_str
1392 res += ');\n'
1393 # Generate signals
1394 if sigs:
1395 self.inc_indent()
1396 ind = self.get_current_ind_prefix()
1397 for idx, p in enumerate(sigs):
1398 name, tpe = p.children
1399 name = name.children[0].value
1400 type_context = None
1401 res += ind + tpe.to_str(name, type_context) + '\n'
1402 self.dec_indent()
1403 # generate vars (including modules)
1404 if vars:
1405 self.inc_indent()
1406 ind = self.get_current_ind_prefix()
1407 res = self.__generate_vars_decl(ind, res, vars)
1408 self.dec_indent()
1409 # generate initialization block
1410 if initialization_block:
1411 self.inc_indent()
1412 ind = self.get_current_ind_prefix()
1413 res += '{}initial begin\n'.format(ind)
1414 res += '\n'.join(initialization_block)
1415 res += '\n{}end\n'.format(ind)
1416 self.dec_indent()
1417 # generate module instantiations
1418 if len(mods) > 0:
1419 for m in mods:
1420 res += m.children[0] + '\n'
1421
1422 # Generate processes
1423 if processlist:
1424 for proc in processlist.children:
1425 if is_tree_type(proc, 'hthread'):
1426 # thread_name, thread_sig, thread_sync, thread_comb = proc.children
1427 thread_func = None
1428 if len(proc.children) == 3:
1429 thread_name, thread_sync, thread_comb = proc.children
1430 elif len(proc.children) == 4:
1431 thread_name, thread_func, thread_sync, thread_comb = proc.children
1432 else:
1433 assert False, "thread should have 3 or 4 children node"
1434 self.inc_indent()
1435 ind = self.get_current_ind_prefix()
1436 res += '{}// Thread: {}\n'.format(ind, thread_name)
1437 # res = self.__generate_vars_decl(ind, res, thread_sig.children)
1438 self.dec_indent()
1439 res += thread_sync + "\n"
1440 if thread_func:
1441 res += thread_func + "\n"
1442 res += thread_comb + "\n"
1443 else:
1444 res += proc + '\n'
1445
1446 if functionlist:
1447 # for f in functionlist:
1448 # res += f + '\n'
1449 assert False, "functionlist should be empty, there may be a bug in the code"
1450 if generatelist:
1451 for f in generatelist:
1452 res += f + '\n'
1453 if genbindinglist:
1454 res += "\n".join(genbindinglist.children) + "\n"
1455 res += "endmodule"
1456 return res
1457
1458 def hbuiltin(self, tree):
1459 self.__push_up(tree)
1460 return tree.children[0]
1461
1462 def hscmax(self, tree):
1463 assert len(tree.children) == 2, "sc_max node should only have 2 children"
1464 self.__push_up(tree)
1465 L = tree.children[0]
1466 R = tree.children[1]
1467 return "(({}) < ({}) ? ({}) : ({}))".format(L, R, R, L)
1468
1469 def hscmin(self, tree):
1470 assert len(tree.children) == 2, "sc_min node should only have 2 children"
1471 self.__push_up(tree)
1472 L = tree.children[0]
1473 R = tree.children[1]
1474 return "(({}) < ({}) ? ({}) : ({}))".format(L, R, L, R)
1475
1476 def __is_generated_signal(self, name):
1477 return name.endswith('#')
1478
1479 def __generate_vars_decl(self, ind, res, vars):
1480 for decl, name, init in vars:
1481 if self.__is_generated_signal(name):
1482 # decl = '(* mark_debug = "true" *) ' + decl.replace('#', "")
1483 decl = decl.replace('#', "")
1484 if init:
1485 decl = decl + ' = ' + str(init) + ';'
1486 else:
1487 decl += ';'
1488 res += ind + decl + '\n'
1489 return res
1490
1491 def hgenvardecl(self, tree):
1492 new_children = []
1493 for t in tree.children:
1494 for v in self.vardecl(t):
1495 new_children.append(v.children)
1496 ctx = TypeContext(prefix='genvar', suffix='')
1497 tree.children = [
1498 (t[1].to_str(t[0], context=ctx), t[0], None) for t in new_children
1499 ]
1500 return tree.children
1501
1502 """called for the special genblock"""
1503 def __forstmt_gen_block(self, tree):
1504
1505 self.push_current_scope_type('loop')
1506 new_children = []
1507 self.push_indent()
1508 new_children.extend(self.visit(t) for t in tree.children[:3])
1509 self.pop_indent()
1510
1511 self.inc_indent()
1512 new_children.extend(self.visit(t) for t in tree.children[3:])
1513 self.dec_indent()
1514
1515 if len(new_children) == 3:
1516 warnings.warn("empty for loop")
1517 for_init, for_cond, for_post = new_children
1518 for_body = ''
1519 else:
1520 for_init, for_cond, for_post, for_body = new_children
1521
1522 ind = self.get_current_ind_prefix()
1523 res = ind + '/*generate*/ for ({};{};{}) begin\n'.format(for_init, for_cond, for_post)
1524 res += for_body + '\n'
1525 res += ind + 'end'
1527 return res
1528
1529
1530 def hgenerateblock(self, tree):
1532 self.__push_up(tree)
1533
1534 hgenvarecl, *body = tree.children
1535 tree.children = [';\n'.join([
1536 t[0] for t in hgenvarecl
1537 ]) + ';\n' + "\n".join(body)]
1538
1540 return tree
__push_up(self, current_node)
Definition top_down.py:29
_get_interface_instance_decl(self, mod_name, mod_type_name, ind, is_array)
_get_interface_instance(self, mod_name, mod_type_name, is_array)