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
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
32 """denotes one of four types of scope: loop, switch, branch, None
33 currently, this is only useful for determine the handling of breaks
38 assert scope
in [
'loop',
'switch',
'branch'],
'Incorrect scope type'
47 return tree.children[0]
51 res =
'\n'.join(tree.children)
56 assert len(tree.children) == 1
57 return tree.children[0]
60 if isinstance(tree, str):
62 elif isinstance(tree, Tree):
63 if tree.data
in [
'hvarref']:
64 return tree.children[0]
65 elif tree.data
in [
'harrayref',
'hslice']:
67 assert False,
'Cannot extract variable name from {}'.format(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])
79 return '{}({})'.format(tree.children[0],
','.join(map(str, tree.children[1:])))
82 warnings.warn(
'hwait encountered, not implemented')
87 return '{' +
','.join(tree.children) +
'}'
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]
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))
123 if current_proc
in sense_list
or (current_proc
in [
'#function#',
'#thread_sync#']
and not (self.
is_in_thread and current_proc ==
'#function#')):
138 assert len(tree.children) == 2
140 op =
'=' if self.
in_for_init or blocking
or is_local_var
else '<='
145 if type(l) == Tree
and l.data ==
'harrayref':
151 if type(r) == Tree
and r.data ==
'harrayref':
157 r =
"(({} & ~(~($bits({})'('b0)) << (({})-({})+1))) << ({})) | (({}) & ((~($bits({})'('b0)) ) << (({}) + 1) | ~(( ~($bits({})'('b0)) ) << ({}))))".format(
163 elif type(r) == Tree
and r.data ==
'harrayref':
166 res =
'{} {} {}'.format(l, op, r)
170 raise RuntimeError(
'Unsupported node: syscwrite')
172 res =
'{} {} {}'.format(tree.children[1], tree.children[0], tree.children[2])
178 lit, tpe = tree.children
179 assert hasattr(tpe,
'width'),
'Literal width type should have width member'
181 return "{}{}'d{}".format(
'-' if lit < 0
else '', w, abs(lit))
185 return '{} ? {} : {}'.format(tree.children[0], tree.children[1], tree.children[2])
188 """stops at literal, it is some kinds of terminal"""
190 assert len(tree.children) == 1
191 return str(tree.children[0])
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(
"#",
"")
201 """syscread: hsigassignr, token"""
203 return tree.children[1]
206 """check whether the tree valuates to constant"""
207 if isinstance(tree, int):
209 elif is_tree_type(tree,
'hliteral'):
211 elif is_tree_type(tree,
'hbinop'):
216 assert harrayref_node.data ==
'harrayref'
217 if is_tree_type(harrayref_node.children[0],
'hsigassignr'):
219 harrayref_node.children = harrayref_node.children[1:]
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:]
235 if isinstance(tree.children[0], Tree)
and tree.children[0].data ==
'hslice':
236 hslice = tree.children[0]
237 var = hslice.children[0]
239 if len(hslice.children) == 3:
240 l, r = hslice.children[1:]
241 elif len(hslice.children) == 2:
242 m = hslice.children[1]
245 if l_const
and r_const:
246 idx =
'{}:{}'.format(l, r)
251 tree.children = [var, l, r,
"(({}) >> ({})) & ~(~($bits({})'('b0)) << (({}) - ({}) + 1))".format(var, r, var, l, r)]
254 var, idx = tree.children
255 res =
'{}[{}]'.format(var, idx)
259 warnings.warn(
'Implementing SigAssignL as non-blocking')
270 if tree.children[0] ==
'ARRAYSUBSCRIPT':
271 res =
'{}[({})]'.format(tree.children[1], tree.children[2])
273 op = tree.children[0]
278 res =
'{{({}), ({})}}'.format(tree.children[1], tree.children[2])
280 res =
'({}) {} ({})'.format(tree.children[1],
'>>>', tree.children[2])
282 res =
'{{ ({}) {} ({}) }}'.format(tree.children[1],
',', tree.children[2])
284 res =
'{} <= ({})'.format(tree.children[1], tree.children[2])
286 res =
'({}) {} ({})'.format(tree.children[1], op, tree.children[2])
291 return "{}{}".format(tree.children[1], tree.children[0])
295 return "{}{}".format(tree.children[0], tree.children[1])
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])
319 assert len(tree.children) <= 1,
"hcstmt should contain 0 or 1 child"
321 return tree.children[0]
334 return tree.children[0]
340 return '\n'.join(tree.children)
347 res =
'{}{}: begin\n{}\n{}end'.format(ind, tree.children[0],
'\n'.join(tree.children[1:]), ind)
352 return tree.children[0]
359 res =
'{}case({})\n{}\n{}endcase'.format(ind, tree.children[0], tree.children[1], ind)
367 res =
'{}break;'.format(ind)
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(
'')
380 if x.data
in nosemico:
388 if isinstance(x[1], Tree):
389 if x[1].data ==
'expression_in_stmt':
391 x = (x[0], x[1].children[0], x[2])
393 assert False,
'Unrecognized construct: {}'.format(x[1])
394 res = str(x[0]) + str(x[1]) + str(x[2])
396 except Exception
as e:
401 res =
'\n'.join(map(f_concat,
402 filter(
lambda x: x[1]
is not None, zip(indentation, tree.children, sep))
407 warnings.warn(
'Encountered noop at line: {}'.format(tree.meta.line))
416 res =
"{}while({}) begin\n".format(prefix, tree.children[0])
417 res +=
''.join(tree.children[1:])
418 res +=
'\n{}end'.format(prefix)
429 res =
"{}do begin\n".format(prefix)
430 res +=
''.join(tree.children[1:])
431 res +=
'\n{}end while({})'.format(prefix, tree.children[0])
438 res =
'\n'.join(tree.children)
448 """used to service temporary indent removal, such as that in for condition"""
460 res = ind +
'if ({}) begin\n'.format(tree.children[0])
461 if len(tree.children) > 1:
462 res += tree.children[1] +
'\n'
465 if len(tree.children) == 3:
466 res +=
' else begin\n' + tree.children[2]
480 return tree.children[0]
486 return tree.children[0]
490 return tree.children[0]
494 return tree.children[0]
501 new_children.extend(self.visit(t)
for t
in tree.children[:3])
505 new_children.extend(self.visit(t)
for t
in tree.children[3:])
508 for_init, for_cond, for_post, for_body = new_children
511 res = ind +
'for ({};{};{}) begin\n'.format(for_init, for_cond, for_post)
512 res += for_body +
'\n'
522 return tree.children[0]
526 return tree.children[0]
533 proc_name = tree.children[0]
536 for sv
in tree.children[1:]:
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':
544 elif sens_edge ==
'negedge_event':
548 sen_str =
'{} {}'.format(edge, sens_var)
550 if isinstance(sens_var, Token):
551 sens_var = sens_var.value
552 if sens_edge ==
'always':
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)
559 raise ValueError(
'Edge can only be one of pos/neg/always')
564 warnings.warn(
'value change is deprecated, but is detected in hcode', DeprecationWarning)
566 return tree.children[0]
578 return any(
'posedge' in x
or 'negedge' in x
for x
in sense_list)
581 proc_name, proc_name_2, prevardecl, *body = tree.children
583 for n
in prevardecl.children:
584 var_name = n.children[0].children[0]
590 proc_name, proc_name_2, prevardecl, *body = tree.children
592 prevardecl.children = list(filter(
lambda x:
not is_tree_type(x,
'vardeclrn'), prevardecl.children))
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)))
598 assert proc_name
in sense_list,
"Process name {} is not in module {}".format(proc_name, self.
current_module)
601 res = ind +
'always_ff @({}) begin: {}\n'.format(
' or '.join(self.
get_sense_list()[proc_name]), proc_name)
603 res = ind +
'always @({}) begin: {}\n'.format(
' or '.join(self.
get_sense_list()[proc_name]), proc_name)
607 res += ind + (
'\n' + ind).join(decls) +
'\n'
608 res += ind + (
'\n' + ind).join(decls_init) +
'\n'
611 res +=
'\n'.join(body) +
'\n'
621 assert var_name
not in self.
local_variables,
'Local variable {} already existed'.format(var_name)
626 name, *args = tree.children
627 tpe = Primitive.get_primitive(name)
628 assert tpe
is not None,
'Type {} is not defined'.format(name)
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"""
638 if len(tree.children) == 1:
639 return 'return {}'.format(tree.children[0])
640 elif len(tree.children) == 0:
644 assert len(tree.children)
in [0, 1],
'return statement can only have 0 or 1 return value'
648 var_name, tpe = tree.children
650 decl = tpe.to_str(var_name, context=ctx)
655 return decl, var_name,
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
672 assert False,
'children size of vardeclinit is not 2 or 3, there might be a bug in the translator'
674 decl = tpe.to_str(var_name, context=ctx)
679 return (decl, var_name, init_val)
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
687 return '{}[{}]'.format(tree.children[0], tree.children[1])
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])
697 mod_name, mod_type = tree.children
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]
704 warnings.warn(
'Port bindings for module instance name {} not found'.format(mod_name))
708 def extract_binding_name(x):
710 return get_ids_in_tree(x[0])[0]
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
721 res = ind +
'{} {}('.format(mod_type_name, mod_name) +
'\n'
726 for binding
in bindings:
728 if type(binding) == list:
731 warnings.warn(
'Using Tree as binding is deprecated', DeprecationWarning)
732 sub, par = binding.children
733 if is_tree_type(sub,
'hbindingarrayref'):
735 sub_name = get_ids_in_tree(sub)[0].value
736 if sub_name
not in array_bindings:
737 array_bindings[sub_name] = {}
740 array_bindings[sub_name][sub.children[1].children[0]] = par
743 if is_tree_type(par,
'hbindingarrayref'):
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():
750 array_seq = [
None] * len(bindings)
751 for idx, b
in bindings.items():
755 binding_str.append(ind +
".{}('{{ {} }})".format(
756 sub_name,
','.join(array_seq)
758 res +=
',\n'.join(binding_str)
764 res += ind +
"always @(*) begin\n"
768 for bl, br
in bindings_hier:
769 res += ind +
'{} = {};\n'.format(bl.children[0], br.children[0])
774 tree.children = [res]
779 val, rot = tree.children
780 return '({} << {}) | ($unsigned({}) >> ($bits({}) - {}))'.format(val, rot, val, val, rot)
783 val = tree.children[0]
784 return '(|{})'.format(val)
788 l, r = tree.children[0], tree.children[1]
789 res =
'{{ {}, {} }}'.format(l, r)
799 for t
in tree.children:
800 new_children.extend(t)
801 tree.children = new_children
807 return tree.children[0]
812 var_name, tpe = tree.children
814 decl = tpe.to_str(var_name, context=ctx)
815 return decl, var_name,
None
823 if len(tree.children) != 0:
824 tpe = tree.children[0]
825 res = tpe.to_str(var_name=
'')
832 return '$unsigned({})'.format(tree.children[0])
836 return '$signed({})'.format(tree.children[0])
840 return '$unsigned({})'.format(tree.children[0])
844 return '$signed({})'.format(tree.children[0])
858 function_name, return_type = tree.children[:2]
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'):
865 elif is_tree_type(ch,
"hfunctionbody"):
871 localvars =
'\n'.join(map(
lambda x: ind + x[0] +
';', localvar.children))
873 body =
'\n'.join(body.children)
876 res =
'{}function automatic {} {} ({});\n{}begin\n{}\n{}\n{}end\n{}endfunction'.format(ind, return_type, function_name,
878 localvars, body, ind, ind)
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]
917 raise ValueError(
'Duplicate signal declaration: {}'.format(id))
937 proc_name, *body = tree.children
947 assert thread_name
in sense_list,
"Process name {} is not in module {}".format(proc_name, self.
current_module)
949 res = ind +
'always @({}) begin: {}\n'.format(
' or '.join(self.
get_sense_list()[thread_name]), proc_name)
951 res = ind +
'always @(*) begin: {}\n'.format(proc_name)
954 proc_name, *body = tree.children
956 res +=
'\n'.join(body) +
'\n'
980 initialization_block = []
981 encountered_initblock =
False
983 for t
in tree.children:
984 if isinstance(t, Tree)
and t.data ==
'portbindinglist':
986 elif is_tree_type(t,
'hmodinitblock'):
987 if encountered_initblock:
988 raise ValueError(
'Only one hmodinitblock should present')
989 encountered_initblock =
True
991 initblock, portbindings, senslist =
None,
None, []
992 for ch
in t.children[1:]:
993 if ch.data ==
'hcstmt':
995 elif ch.data ==
'portbindinglist':
997 elif ch.data ==
'hsenslist':
1000 raise ValueError(ch.pretty())
1010 for bds
in portbindings.children[1]:
1011 mod_name = bds.children[0]
1012 bindings = bds.children[1:]
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))
1024 module_name = tree.children[0]
1025 modportsiglist =
None
1030 for t
in tree.children:
1031 if isinstance(t, Tree):
1032 if t.data ==
'modportsiglist':
1034 elif t.data ==
'processlist':
1036 elif t.data ==
'hfunction':
1037 functionlist.append(t)
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))
1046 ports, sigs =
None,
None
1049 res =
'module {} ('.format(module_name) +
'\n'
1054 for idx, p
in enumerate(ports):
1055 name, tpe = p.children
1056 name = name.children[0].value
1058 if idx == len(ports) - 1:
1060 res += ind + tpe.to_str(name, type_context) +
'\n'
1067 for idx, p
in enumerate(sigs):
1068 name, tpe = p.children
1069 name = name.children[0].value
1071 res += ind + tpe.to_str(name, type_context) +
'\n'
1080 if initialization_block:
1083 res +=
'{}initial begin\n'.format(ind)
1084 res +=
'\n'.join(initialization_block)
1085 res +=
'\n{}end\n'.format(ind)
1090 res += m.children[0] +
'\n'
1093 for proc
in processlist.children:
1094 if is_tree_type(proc,
'hthread'):
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
1102 assert False,
"thread should have 3 or 4 children node"
1105 res +=
'{}// Thread: {}\n'.format(ind, thread_name)
1108 res += thread_sync +
"\n"
1110 res += thread_func +
"\n"
1111 res += thread_comb +
"\n"
1118 assert False,
"functionlist should be empty, there may be a bug in the code"
1124 return tree.children[0]
1127 assert len(tree.children) == 2,
"sc_max node should only have 2 children"
1129 L = tree.children[0]
1130 R = tree.children[1]
1131 return "(({}) < ({}) ? ({}) : ({}))".format(L, R, R, L)
1134 assert len(tree.children) == 2,
"sc_min node should only have 2 children"
1136 L = tree.children[0]
1137 R = tree.children[1]
1138 return "(({}) < ({}) ? ({}) : ({}))".format(L, R, L, R)
1141 return name.endswith(
'#')
1144 for decl, name, init
in vars:
1147 decl = decl.replace(
'#',
"")
1149 decl = decl +
' = ' + str(init) +
';'
1152 res += ind + decl +
'\n'