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'