Example #1
0
    def get_imported_object(s, m):
        config = s.get_config(m)
        rtype = get_component_ifc_rtlir(m)
        full_name = get_component_unique_name(rtype)
        p_map = config.get_port_map() if config.is_port_mapped(
        ) else lambda x: x
        no_clk, no_reset = not config.has_clk(), not config.has_reset()
        _packed_ports = s.gen_packed_ports(rtype)
        clk = next(filter(lambda x: x[0] == 'clk', _packed_ports))[1]
        reset = next(filter(lambda x: x[0] == 'reset', _packed_ports))[1]
        packed_ports = \
            ([('clk', '' if no_clk else p_map('clk'), clk)] if no_clk else []) + \
            ([('reset', '' if no_reset else p_map('reset'), reset)] if no_reset else []) + \
            [ (n, p_map(n), p) for n, p in _packed_ports \
              if not (n == 'clk' and no_clk or n == 'reset' and no_reset)]

        cached = s.is_cached(m, full_name)

        # Create a new Verilog source file if a new top-level wrapper is needed
        if config.is_top_wrapper():
            s.add_param_wrapper(m, config, rtype, packed_ports)

        s.create_verilator_model(m, config, cached)

        port_cdefs = \
            s.create_verilator_c_wrapper( m, config, packed_ports, cached )

        s.create_shared_lib(m, config, cached)

        symbols = \
            s.create_py_wrapper( m, config, rtype, packed_ports, port_cdefs, cached )

        imp = s.import_component(m, config, symbols)

        return imp
Example #2
0
  def get_imported_object( s, m ):
    ph_cfg = s.get_placeholder_config( m )
    ip_cfg = s.get_config( m )
    ip_cfg.setup_configs( m, s.get_translation_namespace(m) )

    rtype = get_component_ifc_rtlir( m )

    # Now we selectively unpack array of ports if they are referred to in
    # port_map
    ports = s.get_gen_mapped_port()( m, ph_cfg.port_map, ph_cfg.has_clk, ph_cfg.has_reset )

    cached, config_file, cfg_d = s.is_cached( m, ip_cfg )

    s.create_verilator_model( m, ph_cfg, ip_cfg, cached )

    port_cdefs = s.create_verilator_c_wrapper( m, ph_cfg, ip_cfg, ports, cached )

    s.create_shared_lib( m, ph_cfg, ip_cfg, cached )

    symbols = s.create_py_wrapper( m, ph_cfg, ip_cfg, rtype, ports, port_cdefs, cached )

    imp = s.import_component( m, ph_cfg, ip_cfg, symbols )

    imp._ip_cfg = ip_cfg
    imp._ph_cfg = ph_cfg
    imp._ports = ports

    # Dump configuration dict to config_file
    with open( config_file, 'w' ) as fd:
      json.dump( cfg_d, fd, indent = 4 )

    return imp
Example #3
0
    def fill_missing(s, m):
        rtype = get_component_ifc_rtlir(m)
        s.v_param = rtype.get_params()
        s.is_param_wrapper = isinstance(m, Placeholder) and s.v_param
        top_module = s.get_top_module()

        # Check if the keys of `port_map` are port names of `m`
        # Note that the keys can be expressions such as `ifc[0].foo` and
        # therefore we do not check if a port name of `m` is in the keys.
        if s.get_option("port_map"):
            s.check_p_map(rtype)

        # Fill in the top module if unspecified
        # If the top-level module is not a wrapper
        if not s.is_param_wrapper:
            full_name = get_component_unique_name(rtype)
            if not top_module:
                # Default top_module is the name of component concatenated
                # with parameters
                s.set_option("top_module", full_name)

        # If the top-level module is a wrapper
        else:
            # Check if all parameters are integers
            assert all(isinstance(v[1], int) for v in s.v_param), \
                "Only support integers as parameters of Verilog modules!"

            # wrapped_module is the name of the module to be parametrized
            # top_module is the name of the new top-level module
            if top_module:
                s.wrapped_module = top_module
                s.set_option("top_module", f"{top_module}_w_params")
            else:
                # Default top_module is the name of component
                s.wrapped_module = rtype.get_name()
                s.set_option("top_module", f"{s.wrapped_module}_w_params")

        top_module = s.get_top_module()

        # Only try to infer the name of Verilog source file if both
        # flist and the source file are not specified.
        if not s.get_option("vl_src") and not s.get_option("vl_flist"):
            s.set_option("vl_src", f"{top_module}.sv")

        if not s.get_option("vl_mk_dir"):
            s.set_option("vl_mk_dir", f"obj_dir_{top_module}")

        if s.is_param_wrapper:
            # If toplevel module is a param-wrapper, `vl_src` has to be specified
            # because the file containing the wrapper will include `vl_src` for
            # the module to be parametrized.
            if not s.get_option("vl_src"):
                raise InvalidPassOptionValue(
                    "vl_src", s.get_option("vl_src"), s.PassName,
                    "vl_src must be specified when Placeholder is to be imported!"
                )
            s.v_module2param = s.get_option("vl_src")
            s.set_option("vl_src", top_module + ".sv")
    def visit_placeholder(s, m):
        irepr = get_component_ifc_rtlir(m)

        s.setup_default_configs(m, irepr)

        # after the previous setup step, placeholder `m` is guaranteed to have
        # config_placeholder attribute.
        if m.config_placeholder.is_valid:
            s.check_valid(m, m.config_placeholder, irepr)
            s.pickle(m, m.config_placeholder, irepr)
    def gen_subcomp_array_decl( c_id, port_conns, ifc_conns, n_dim, c_n_dim ):
      nonlocal m, s
      tplt = dedent(
          """\
            {c_name} {c_id}
            (
          {port_conn_decls}
            );""")
      if not n_dim:
        # Get the object from the hierarchy
        _n_dim = list(int(num_str) for num_str in c_n_dim.split('__') if num_str)
        attr = c_id + ''.join(f'[{dim}]' for dim in _n_dim)
        obj = eval(f'm.{attr}')
        # Get the translated component name
        obj_c_rtype = get_component_ifc_rtlir(obj)
        _c_name = s.rtlir_tr_component_unique_name(obj_c_rtype)

        if isinstance(obj, Placeholder):
          c_name = obj.config_placeholder.pickled_top_module
        else:
          c_name = _c_name

        orig_c_id = c_id
        c_id = c_id + c_n_dim

        # Generate correct connections
        port_conn_decls = []
        unpacked_str = ''.join([f'[{i}]' for i in _n_dim])

        no_clk   = s.structural.component_no_synthesis_no_clk[obj]
        no_reset = s.structural.component_no_synthesis_no_reset[obj]

        for i, dscp in enumerate(port_conns + ifc_conns):
          comma = ',\n' if i != len(port_conns+ifc_conns)-1 else ''
          port_name = dscp['id']
          ph_port_name = dscp['ph_id']
          port_wire = f"{orig_c_id}__{dscp['id']}{unpacked_str}"
          if (port_name == 'clk' and no_clk) or (port_name == 'reset' and no_reset):
            comma = ',\n' if i != len(port_conns+ifc_conns)-1 else '\n'
            newline = '\n' if i != len(port_conns+ifc_conns)-1 else ''
            port_conn_decls.append("`ifndef SYNTHESIS\n")
            port_conn_decls.append(f".{ph_port_name}( {port_wire} ){comma}")
            port_conn_decls.append(f"`endif{newline}")
          else:
            port_conn_decls.append(f".{ph_port_name}( {port_wire} ){comma}")

        make_indent( port_conn_decls, 2 )
        port_conn_decls = ''.join(port_conn_decls)
        return [ tplt.format( **locals() ) ]

      else:
        return sum( [gen_subcomp_array_decl( c_id,
            port_conns, ifc_conns, n_dim[1:], c_n_dim+'__'+str(idx) ) \
                for idx in range( n_dim[0] )], [] )
Example #6
0
def gen_mapped_ports(m, port_map, has_clk=True, has_reset=True):
    """Return a list of (pname, vname, rt.Port/rt.Array ) that has all ports
  of `rtype`. This method performs SystemVerilog backend-specific name
  mangling and returns all ports that appear in the interface of component
  `rtype`. Each tuple contains a port or an array of port that has any data type
  allowed in RTLIRDataType.
  Shunning: Now we also take port_map into account. Two points to note:
  1. If a port's pname appears as a key in port_map, we need to use the
     corresponding value as vname
  2. For an n-D array of ports, we enforce the rule that assumes either no
     element is mapped in port_map, or _all_ of the elements are mapped.
  """
    def _mangle_vector(pname, vname, port, dtype, port_idx):
        return [([pname], port_map[pname] if pname in port_map else vname,
                 rt.Port(port.direction, dtype), port_idx)]

    def _mangle_struct(pname, vname, port, dtype, port_idx):
        ret = []
        for field_name, field_dtype in dtype.get_all_properties().items():
            ret += _mangle_dtype(f"{pname}.{field_name}",
                                 f"{vname}__{field_name}", port, field_dtype,
                                 port_idx)
        return ret

    def _mangle_packed(pname, vname, port, dtype, n_dim, port_idx):
        if not n_dim:
            return _mangle_dtype(pname, vname, port, dtype, port_idx)
        else:
            ret = []
            for i in range(n_dim[0]):
                ret += _mangle_packed(f"{pname}[{i}]", f"{vname}__{i}", port,
                                      dtype, n_dim[1:], port_idx)
            return ret

    def _mangle_dtype(pname, vname, port, dtype, port_idx):
        if isinstance(dtype, rdt.Vector):
            return _mangle_vector(pname, vname, port, dtype, port_idx)
        elif isinstance(dtype, rdt.Struct):
            return _mangle_struct(pname, vname, port, dtype, port_idx)
        elif isinstance(dtype, rdt.PackedArray):
            return _mangle_packed(pname, vname, port, dtype.get_sub_dtype(),
                                  dtype.get_dim_sizes(), port_idx)
        else:
            assert False, f'unrecognized data type {dtype}!'

    def _mangle_port(pname, vname, port, n_dim, port_idx):
        # Normal port
        if not n_dim:
            return _mangle_dtype(pname, vname, port, port.get_dtype(),
                                 port_idx)

        # Handle port array. We just assume if one element of the port array
        # is mapped, we need the user to map every element in the array.
        else:
            ret = []
            for i in range(n_dim[0]):
                ret += _mangle_port(f"{pname}[{i}]", f"{vname}__{i}", port,
                                    n_dim[1:], port_idx)
            return ret

    def _mangle_ifc(pname, vname, ifc, n_dim, port_idx):
        ret = []
        if not n_dim:
            for port_name, port_rtype in ifc.get_all_properties_packed():
                port_n_dim, port_rtype = get_rtype(port_rtype)
                if isinstance(port_rtype, rt.InterfaceView):
                    ret += _mangle_ifc(f"{pname}.{port_name}",
                                       f"{vname}__{port_name}", port_rtype,
                                       port_n_dim, port_idx)
                elif isinstance(port_rtype, rt.Port):
                    ret += _mangle_port(f"{pname}.{port_name}",
                                        f"{vname}__{port_name}", port_rtype,
                                        port_n_dim, port_idx)
                else:
                    assert False, "unrecognized interface/port {port_rtype}!"
        else:
            for i in range(n_dim[0]):
                ret += _mangle_ifc(f"{pname}[{i}]", f"{vname}__{i}", ifc,
                                   n_dim[1:], port_idx + 1)
        return ret

    # We start from all packed ports/interfaces, and unpack arrays if
    # it is found in a port.
    rtype = get_component_ifc_rtlir(m)
    ret = []

    for name, port in rtype.get_ports_packed():
        if not has_clk and name == 'clk': continue
        if not has_reset and name == 'reset': continue
        p_n_dim, p_rtype = get_rtype(port)
        ret += _mangle_port(name, name, p_rtype, p_n_dim, 0)

    for name, ifc in rtype.get_ifc_views_packed():
        i_n_dim, i_rtype = get_rtype(ifc)
        ret += _mangle_ifc(name, name, i_rtype, i_n_dim, 0)

    return ret
Example #7
0
def gen_mapped_ports(m, port_map, has_clk=True, has_reset=True):
    """Return a list of (pname, vname, rt.Port/rt.Array ) that has all ports
  of `rtype`. This method performs SystemVerilog backend-specific name
  mangling and returns all ports that appear in the interface of component
  `rtype`. Each tuple contains a port or an array of port that has any data type
  allowed in RTLIRDataType.
  Shunning: Now we also take port_map into account. Two points to note:
  1. If a port's pname appears as a key in port_map, we need to use the
     corresponding value as vname
  2. For an n-D array of ports, we enforce the rule that assumes either no
     element is mapped in port_map, or _all_ of the elements are mapped.
  """

    # [pnames], vname, rtype, port_idx

    def _mangle_port(pname, vname, port, n_dim):

        # Normal port
        if not n_dim:
            return [([pname], port_map[pname] if pname in port_map else vname,
                     port, 0)]

        # Handle port array. We just assume if one element of the port array
        # is mapped, we need the user to map every element in the array.
        found = tot = 0
        all_ports = []
        Q = deque([(pname, vname, port, n_dim)])
        while Q:
            _pname, _vname, _port, _n_dim = Q.popleft()
            if not _n_dim:
                if _pname in port_map:
                    found += 1
                    _vname = port_map[_pname]
                all_ports.append(([_pname], _vname, _port, 0))
            else:
                for i in range(_n_dim[0]):
                    Q.append((f"{_pname}[{i}]", f"{_vname}__{i}", _port,
                              _n_dim[1:]))

        assert found == len(all_ports) or found == 0, \
            f"{pname} is an {len(n_dim)}-D array of ports with {len(all_ports)} ports in total, " \
            f" but only {found} of them is mapped. Please either map all of them or none of them."

        if not found:
            return [([pname], vname, rt.Array(n_dim, port), 0)]
        else:
            return all_ports

    def _is_ifc_mapped(pname, vname, rtype, n_dim):
        found, tot, flatten_ports = 0, 0, []
        # pname, vname, rtype, n_dim
        Q = deque([(pname, vname, rtype, n_dim, 0)])

        while Q:
            _pname, _vname, _rtype, _n_dim, _prev_dims = Q.popleft()
            if _n_dim:
                for i in range(_n_dim[0]):
                    Q.append((f"{_pname}[{i}]", f"{_vname}__{i}", _rtype,
                              _n_dim[1:], _prev_dims + 1))
            else:
                if isinstance(_rtype, rt.Port):
                    # Port inside the interface
                    tot += 1
                    if _pname in port_map:
                        found += 1
                        flatten_ports.append(
                            ([_pname], port_map[_pname], _rtype, _prev_dims))
                    else:
                        flatten_ports.append(
                            ([_pname], _vname, _rtype, _prev_dims))
                elif isinstance(_rtype, rt.InterfaceView):
                    # Interface (nested)
                    for sub_name, sub_rtype in _rtype.get_all_properties_packed(
                    ):
                        sub_n_dim, sub_rtype = get_rtype(sub_rtype)
                        Q.append(
                            (f"{_pname}.{sub_name}", f"{_vname}__{sub_name}",
                             sub_rtype, sub_n_dim, _prev_dims))
                else:
                    assert False, f"{_pname} is not interface(s) or port(s)!"

        assert (found == 0) or (found == tot), \
            f"{name} is an interface that has {tot} ports in total, " \
            f" but only {found} of them is mapped. Please either map all of them or none of them."
        return (found == tot), flatten_ports

    def _gen_packed_ifc(pname, vname, ifc, n_dim):
        packed_ifc, ret = [], []
        Q = deque([(pname, vname, ifc, n_dim, [], 0)])
        while Q:
            _pname, _vname, _rtype, _n_dim, _prev_n_dim, _port_idx = Q.popleft(
            )

            if isinstance(_rtype, rt.Port):
                if not (_prev_n_dim + _n_dim):
                    new_rtype = _rtype
                else:
                    new_rtype = rt.Array(_prev_n_dim + _n_dim, _rtype)
                packed_ifc.append((_pname, _vname, new_rtype, _port_idx))

            elif isinstance(_rtype, rt.InterfaceView):
                if _n_dim:
                    new_prev_n_dim = _prev_n_dim + [_n_dim[0]]
                    for i in range(_n_dim[0]):
                        Q.append((f"{_pname}[{i}]", _vname, _rtype, _n_dim[1:],
                                  new_prev_n_dim, _port_idx + 1))
                else:
                    new_prev_n_dim = _prev_n_dim
                    for sub_name, sub_rtype in _rtype.get_all_properties_packed(
                    ):
                        sub_n_dim, sub_rtype = get_rtype(sub_rtype)
                        Q.append(
                            (f"{_pname}.{sub_name}", f"{_vname}__{sub_name}",
                             sub_rtype, sub_n_dim, new_prev_n_dim, _port_idx))
            else:
                assert False, f"{_pname} is not interface(s) or port(s)!"

        # Merge entries whose vnames are the same. The result will have a list for
        # the pnames.
        names = set()
        for _, vname, rtype, port_idx in packed_ifc:
            if vname not in names:
                names.add(vname)
                ret.append(([], vname, rtype, port_idx))
                for _pname, _vname, _, _port_idx in packed_ifc:
                    if vname == _vname:
                        assert _port_idx == port_idx
                        ret[-1][0].append(_pname)

        return ret

    def _mangle_ifc(pname, vname, ifc, n_dim):
        is_mapped, flatten_ifc = _is_ifc_mapped(pname, vname, ifc, n_dim)
        if is_mapped:
            return flatten_ifc
        else:
            return _gen_packed_ifc(pname, vname, ifc, n_dim)

    # We start from all packed ports/interfaces, and unpack arrays if
    # it is found in a port.
    rtype = get_component_ifc_rtlir(m)
    ret = []

    for name, port in rtype.get_ports_packed():
        if not has_clk and name == 'clk': continue
        if not has_reset and name == 'reset': continue
        p_n_dim, p_rtype = get_rtype(port)
        ret += _mangle_port(name, name, p_rtype, p_n_dim)

    for name, ifc in rtype.get_ifc_views_packed():
        i_n_dim, i_rtype = get_rtype(ifc)
        ret += _mangle_ifc(name, name, i_rtype, i_n_dim)

    return ret