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
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
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] )], [] )
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
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