def _subcomp_port_gen(c_name, c_id, n_dim, port_decls): p_wire_tplt = "logic {packed_type: <8} {id_};" p_conn_tplt = ".{port_id: <15}( {port_wire_id} )" template = \ """\ {port_wires} {c_name} {c_id} ( {port_conn_decls} );\ """ if not n_dim: p_wires, p_conns = [], [] for port in port_decls: msb, _id = port["msb"], port["id_"] id_ = c_id + "__" + _id port_id = _id port_wire_id = (f"{c_id}__{_id}").center(25) packed_type = f"[{msb}:0]" p_wires.append(p_wire_tplt.format(**locals())) p_conns.append(p_conn_tplt.format(**locals())) make_indent(p_wires, 1) make_indent(p_conns, 2) port_wires = "\n".join(p_wires) port_conn_decls = ",\n".join(p_conns) return [template.format(**locals())] else: ret = [] for i in range(n_dim[0]): ret += _subcomp_port_gen(c_name, c_id + "__" + str(i), n_dim[1:], port_decls) return ret
def visit_For( s, node ): src = [] body = [] loop_var = s.visit( node.var ) start = s.visit( node.start ) end = s.visit( node.end ) begin = ' begin' if len( node.body ) > 1 else '' cmp_op = '<' if node.step.value > 0 else '<' inc_op = '+' if node.step.value > 0 else '-' step_abs = s.visit( node.step ) step_abs = step_abs if node.step.value > 0 else step_abs[ 1 : ] for stmt in node.body: body.extend( s.visit( stmt ) ) make_indent( body, 1 ) for_begin = \ 'for ( int {v} = {s}; {v} {comp} {t}; {v} {inc}= {stp} ){begin}'.format( v = loop_var, s = start, t = end, stp = step_abs, comp = cmp_op, inc = inc_op, begin = begin ) # Assemble for statement src.extend( [ for_begin ] ) src.extend( body ) if len( node.body ) > 1: src.extend( [ 'end' ] ) return src
def rtlir_tr_struct_dtype( s, dtype ): dtype_name = dtype.get_name() field_decls = [] for id_, _dtype in dtype.get_all_properties(): if isinstance( _dtype, rdt.Vector ): decl = s.rtlir_tr_vector_dtype( _dtype )['decl'].format(**locals()) elif isinstance( _dtype, rdt.PackedArray ): decl = s.rtlir_tr_packed_array_dtype( _dtype )['decl'].format(**locals()) elif isinstance( _dtype, rdt.Struct ): decl = s.rtlir_tr_struct_dtype( _dtype )['decl'].format(**locals()) else: assert False, \ 'unrecoganized field type {} of struct {}!'.format( _dtype, dtype_name ) field_decls.append( decl + ';' ) make_indent( field_decls, 1 ) field_decl = '\n'.join( field_decls ) file_info = dtype.get_file_info() return { 'def' : \ """\ typedef struct packed {{ {field_decl} }} {dtype_name}; """.format( **locals() ), 'const_decl' : '{dtype_name} {{id_}}'.format( **locals() ), 'decl' : '{dtype_name} {{id_}}'.format( **locals() ), 'raw_dtype' : dtype }
def rtlir_tr_upblk_decls(s, upblk_decls): ret = '' for idx, upblk_decl in enumerate(upblk_decls): make_indent(upblk_decl, 1) if idx != 0: ret += '\n' ret += '\n' + '\n'.join(upblk_decl) return ret
def gen_line_trace_py(s, packed_ports): """Return the line trace method body that shows all interface ports.""" ret = ['lt = ""'] template = 'lt += "{my_name} = {{}}, ".format({full_name})' for name, v_name, port in packed_ports: my_name = name full_name = 's.mangled__' + s._verilator_name(name) ret.append(template.format(**locals())) ret.append('return lt') make_indent(ret, 2) return '\n'.join(ret)
def gen_internal_line_trace_py(s, packed_ports): """Return the line trace method body that shows all CFFI ports.""" ret = ['_ffi_m = s._ffi_m', 'lt = ""'] template = \ "lt += '{v_name} = {{}}, '.format(full_vector(s.mangled__{my_name}, _ffi_m.{v_name}))" for my_name, v_name, port in packed_ports: if v_name: my_name = s._verilator_name(my_name) v_name = s._verilator_name(v_name) ret.append(template.format(**locals())) ret.append('return lt') make_indent(ret, 2) return '\n'.join(ret)
def rtlir_tr_subcomp_decls(s, subcomp_decls): port_decls, wire_decls, conns = [], [], [] for subcomp_decl in subcomp_decls: port_decls.extend(subcomp_decl["port_decls"]) wire_decls.extend(subcomp_decl["wire_decls"]) conns.extend(subcomp_decl["connections"]) make_indent(wire_decls, 1) make_indent(conns, 1) return { "port_decls": "\n\n".join(port_decls), "wire_decls": "\n".join(wire_decls), "connections": "\n".join(conns) }
def create_verilator_c_wrapper(s, m, config, packed_ports, cached): """Return the file name of generated C component wrapper. Create a C wrapper that calls verilator C API and provides interfaces that can be later called through CFFI. """ component_name = config.get_top_module() dump_vcd = int(config.is_vl_trace_enabled()) vcd_timescale = config.get_vl_trace_timescale() half_cycle_time = config.get_vl_trace_half_cycle_time() wrapper_name = config.get_c_wrapper_path() config.vprint("\n=====Generate C wrapper=====") # The wrapper template should be in the same directory as this file template_name = \ os.path.dirname( os.path.abspath( __file__ ) ) + \ os.path.sep + 'verilator_wrapper.c.template' # Generate port declarations for the verilated model in C port_defs = [] for name, v_name, port in packed_ports: if v_name: port_defs.append(s.gen_signal_decl_c(v_name, port)) port_cdefs = copy.copy(port_defs) make_indent(port_defs, 2) port_defs = '\n'.join(port_defs) # Generate initialization statements for in/out ports port_inits = [] for name, v_name, port in packed_ports: if v_name: port_inits.extend(s.gen_signal_init_c(v_name, port)) make_indent(port_inits, 1) port_inits = '\n'.join(port_inits) # Fill in the C wrapper template # Since we may run import with or without dump_vcd enabled, we need # to dump C wrapper regardless of whether the verilated model is # cached or not. # TODO: we can avoid dumping C wrapper if we attach some metadata to # tell if the wrapper was generated with or without `dump_vcd` enabled. with open(template_name, 'r') as template: with open(wrapper_name, 'w') as output: c_wrapper = template.read() c_wrapper = c_wrapper.format(**locals()) output.write(c_wrapper) config.vprint(f"Successfully generated C wrapper {wrapper_name}!", 2) return port_cdefs
def visit_If(s, node): src = [] body = [] orelse = [] # Grab condition, if-body, and orelse-body cond = s.visit(node.cond) for stmt in node.body: body.extend(s.visit(stmt)) make_indent(body, 1) for stmt in node.orelse: orelse.extend(s.visit(stmt)) # Assemble the statement, starting with if-body if_begin = f'if ( {cond} ) begin' src.extend([if_begin]) src.extend(body) # if len( node.body ) > 1: src.extend(['end']) # If orelse-body is not empty, add it to the list of strings if node.orelse != []: # If an if statement is the only statement in the orelse-body if len(node.orelse) == 1 and isinstance(node.orelse[0], bir.If): # No indent will be added, also append if-begin to else-begin else_begin = f'else {orelse[0]}' orelse = orelse[1:] # Else indent orelse-body else: else_begin = 'else' + (' begin' if len(node.orelse) > 1 else '') make_indent(orelse, 1) src.extend([else_begin]) src.extend(orelse) if len(node.orelse) > 1: src.extend(['end']) return src
def visit_For(s, node): node.start._top_expr = 1 node.end._top_expr = 1 node.step._top_expr = 1 # Yosys-comptabile Verilog for loop src = [] body = [] loop_var = s.visit(node.var) start = s.visit(node.start) end = s.visit(node.end) loop_var = "__loopvar__" + s.blk.__name__ + "_" + loop_var if loop_var not in s.loopvars: s.loopvars.add(loop_var) begin = ' begin' if len(node.body) > 1 else '' cmp_op = '<' if node.step.value > 0 else '<' inc_op = '+' if node.step.value > 0 else '-' step_abs = s.visit(node.step) step_abs = step_abs if node.step.value > 0 else step_abs[1:] for stmt in node.body: body.extend(s.visit(stmt)) make_indent(body, 1) for_begin = \ 'for ( {v} = {s}; {v} {comp} {t}; {v} = {v} {inc} {stp} ){begin}'.format( v = loop_var, s = start, t = end, stp = step_abs, comp = cmp_op, inc = inc_op, begin = begin ) # Assemble for statement src.extend([for_begin]) src.extend(body) if len(node.body) > 1: src.extend(['end']) return src
def visit_SeqUpblk(s, node): """Return the SV representation of statements inside it.""" blk_name = node.name src = [] body = [] s.upblk_type = s.SEQUENTIAL s.check_res(node, blk_name) # Add name of the upblk to this always block src.append(f'always_ff @(posedge clk) begin : {blk_name}') for stmt in node.body: body.extend(s.visit(stmt)) make_indent(body, 1) src.extend(body) src.append('end') s.upblk_type = s.NONE return src
def visit_CombUpblk(s, node): """Return the SV representation of statements inside it.""" blk_name = node.name src = [] body = [] s.upblk_type = s.COMBINATIONAL s.check_res(node, blk_name) # Add name of the upblk to this always block src.extend(['always_comb begin : {blk_name}'.format(**locals())]) for stmt in node.body: body.extend(s.visit(stmt)) make_indent(body, 1) src.extend(body) src.extend(['end']) s.upblk_type = s.NONE return src
def rtlir_tr_port_decls(s, port_decls): ret = {"port_decls": [], "wire_decls": [], "connections": []} for port_decl in port_decls: ret["port_decls"] += port_decl["port_decls"] ret["wire_decls"] += port_decl["wire_decls"] ret["connections"] += port_decl["connections"] make_indent(ret["port_decls"], 1) make_indent(ret["wire_decls"], 1) make_indent(ret["connections"], 1) ret["port_decls"] = ",\n".join(ret["port_decls"]) ret["wire_decls"] = "\n".join(ret["wire_decls"]) ret["connections"] = "\n".join(ret["connections"]) return ret
def rtlir_tr_interface_decls(s, ifc_decls): port_decls, wire_decls, connections = [], [], [] for ifc_decl in ifc_decls: port_decls += ifc_decl["port_decls"] wire_decls += ifc_decl["wire_decls"] connections += ifc_decl["connections"] make_indent(port_decls, 1) make_indent(wire_decls, 1) make_indent(connections, 1) return { "port_decls": ",\n".join(port_decls), "wire_decls": "\n".join(wire_decls), "connections": "\n".join(connections), }
def rtlir_tr_port_decls( s, port_decls ): make_indent( port_decls, 1 ) return ',\n'.join( port_decls )
def rtlir_tr_connections( s, connections ): make_indent( connections, 1 ) return '\n'.join( connections )
def rtlir_tr_behavioral_freevars(s, freevars): make_indent(freevars, 1) return '\n'.join(freevars)
def rtlir_tr_upblk_py_srcs(s, upblk_py_srcs): ret = '' for upblk_py_src in upblk_py_srcs: make_indent(upblk_py_src, 1) ret += '\n' + '\n'.join(upblk_py_src) return ret
def rtlir_tr_behavioral_tmpvars( s, tmpvars ): make_indent( tmpvars, 1 ) return '\n'.join( tmpvars )
def rtlir_tr_behavioral_tmpvars(s, tmpvars): _tmpvars = [] for tmpvar in tmpvars: _tmpvars += tmpvar make_indent(_tmpvars, 1) return '\n'.join(_tmpvars)
def create_py_wrapper(s, m, config, rtype, packed_ports, port_cdefs, cached): """Return the file name of the generated PyMTL component wrapper.""" config.vprint("\n=====Generate PyMTL wrapper=====") # Load the wrapper template template_name = \ os.path.dirname( os.path.abspath( __file__ ) ) + \ os.path.sep + 'verilator_wrapper.py.template' wrapper_name = config.get_py_wrapper_path() # Port definitions of verilated model make_indent(port_cdefs, 4) # Port definition in PyMTL style symbols, port_defs, connections = s.gen_signal_decl_py(rtype) make_indent(port_defs, 2) make_indent(connections, 2) # Wire definition in PyMTL style wire_defs = [] for name, v_name, port in packed_ports: wire_defs.append(s.gen_wire_decl_py(name, port)) make_indent(wire_defs, 2) # Set upblk inputs and outputs set_comb_input = s.gen_comb_input(packed_ports) set_comb_output = s.gen_comb_output(packed_ports) make_indent(set_comb_input, 3) make_indent(set_comb_output, 3) # Generate constraints for sequential block constraints = s.gen_constraints(packed_ports) make_indent(constraints, 4) constraint_str = '' if not constraints else \ """\ constraint_list = [ {} ] s.add_constraints( *constraint_list ) """.format( '\n'.join( constraints ) ) # Line trace line_trace = s.gen_line_trace_py(packed_ports) # Internal line trace in_line_trace = s.gen_internal_line_trace_py(packed_ports) # Fill in the python wrapper template if not cached: with open(template_name, 'r') as template: with open(wrapper_name, 'w') as output: py_wrapper = template.read() py_wrapper = py_wrapper.format( component_name = config.get_top_module(), has_clk = int(config.has_clk()), clk = 'inv_clk' if not config.has_clk() else \ next(filter(lambda x: x[0]=='clk', packed_ports))[1], lib_file = config.get_shared_lib_path(), port_cdefs = (' '*4+'\n').join( port_cdefs ), port_defs = '\n'.join( port_defs ), wire_defs = '\n'.join( wire_defs ), connections = '\n'.join( connections ), set_comb_input = '\n'.join( set_comb_input ), set_comb_output = '\n'.join( set_comb_output ), constraint_str = constraint_str, line_trace = line_trace, in_line_trace = in_line_trace, dump_vcd = int(config.is_vl_trace_enabled()) ) output.write(py_wrapper) config.vprint(f"Successfully generated PyMTL wrapper {wrapper_name}!", 2) return symbols
def rtlir_tr_wire_decls( s, wire_decls ): make_indent( wire_decls, 1 ) return '\n'.join( wire_decls )
def rtlir_tr_wire_decls(s, wire_decls): wires = [] for wire_decl in wire_decls: wires += wire_decl make_indent(wires, 1) return '\n'.join(wires)
def rtlir_tr_interface_decls(s, ifc_decls): all_decls = sum(ifc_decls, []) make_indent(all_decls, 1) return ',\n'.join(all_decls)
def rtlir_tr_const_decls( s, const_decls ): make_indent( const_decls, 1 ) return '\n'.join( const_decls )
def rtlir_tr_subcomp_ifc_port_decls(s, _ifc_port_decls): port_defs = [x['def'] for x in _ifc_port_decls] port_decls = [x['decl'] for x in _ifc_port_decls] make_indent(port_defs, 1) make_indent(port_decls, 2) return {'def': '\n'.join(port_defs), 'decl': ',\n'.join(port_decls)}