def __call__(self, top): if not hasattr(top._dag, "all_constraints"): raise PassOrderError("all_constraints") if hasattr(top, "_sched"): raise Exception("Some schedule pass has already been applied!") top._sched = PassMetadata() # Extract branchiness first # Initialize all generated net block to 0 branchiness self.meta_block_id = 0 self.branchiness = {x: 0 for x in top._dag.genblks} self.only_loop_at_top = {x: False for x in top._dag.genblks} v = CountBranchesLoops() # Shunning: since each loop turns into call_assembler_r, a pure-loop # update block is basically 0 branchiness and can be inserted anywhere. # At the beginning I tried not to put those blocks into any metablock # to avoid double call_assembler_r but it just turned out that there # is no difference of where you put the call_assembler_r.. Plus, # treating loop blocks as normal update block can activate subsequent # schedulable 0-branchiness block. for blk in top.get_all_update_blocks(): hostobj = top.get_update_block_host_component(blk) if blk in top._dag.blk_greenlet_mapping: gblk = top._dag.blk_greenlet_mapping[blk] self.branchiness[gblk], self.only_loop_at_top[gblk] = 0, 0 else: self.branchiness[blk], self.only_loop_at_top[blk] = v.enter( hostobj.get_update_block_info(blk)[-1]) self.schedule_ff(top) # Reuse simple's flip schedule simple = SimpleSchedulePass() simple.schedule_posedge_flip(top) self.schedule_intra_cycle(top) top._sim = PassMetadata() self.create_print_line_trace(top) self.create_sim_cycle_count(top) self.create_lock_unlock_simulation(top) top.lock_in_simulation() self.create_sim_eval_comb(top) self.create_sim_tick(top) self.create_sim_reset(top)
def _gen_metadata(s, m): # Create namespace if not hasattr(m, '_pass_structural_rtlir_gen'): m._pass_structural_rtlir_gen = PassMetadata() ns = m._pass_structural_rtlir_gen # Generate RTLIR types ns.rtlir_type = s.tr_top._rtlir_getter.get_rtlir(m) # Generate constants ns.consts = [] rtype = ns.rtlir_type const_types = rtype.get_consts_packed() for const_name, const_rtype in const_types: assert hasattr(m, const_name), \ f"Internal error: {const_name} is not a member of {m}" const_instance = getattr(m, const_name) ns.consts.append((const_name, const_rtype, const_instance)) # Sort connections m_conns_set = s.inst_conns[m] ordered_conns = [*m.get_connect_order()] assert len(ordered_conns) == len(m_conns_set) for i, x in enumerate(ordered_conns): if x not in m_conns_set: x = (x[1], x[0]) assert x in m_conns_set, "There is a connection missing from "\ "connect_order. Please contact PyMTL developers!" ordered_conns[i] = x ns.connections = [(gen_signal_expr(m, x[0]), gen_signal_expr(m, x[1])) for x in ordered_conns]
def __call__( self, top ): if not hasattr( top._dag, "all_constraints" ): raise PassOrderError( "all_constraints" ) top._sched = PassMetadata() top._sched.schedule = self.schedule( top )
def __call__(s, m): """ generate RTLIR for all upblks of m """ if not hasattr(m, '_pass_behavioral_rtlir_gen'): m._pass_behavioral_rtlir_gen = PassMetadata() m._pass_behavioral_rtlir_gen.rtlir_upblks = {} visitor = BehavioralRTLIRGeneratorL3(m) upblks = { 'CombUpblk': get_ordered_upblks(m), 'SeqUpblk': get_ordered_update_ff(m), } # Sort the upblks by their name upblks['CombUpblk'].sort(key=lambda x: x.__name__) upblks['SeqUpblk'].sort(key=lambda x: x.__name__) for upblk_type in ('CombUpblk', 'SeqUpblk'): for blk in upblks[upblk_type]: visitor._upblk_type = upblk_type upblk_info = m.get_update_block_info(blk) upblk = visitor.enter(blk, upblk_info[-1]) upblk.is_lambda = upblk_info[0] upblk.src = upblk_info[1] upblk.lino = upblk_info[2] upblk.filename = upblk_info[3] m._pass_behavioral_rtlir_gen.rtlir_upblks[blk] = upblk
def __call__( self, top ): if hasattr(top, "sim_reset"): raise AttributeError( "Please rename the attribute top.sim_reset") if hasattr(top, "print_line_trace"): raise AttributeError( "Please modify the attribute top.print_line_trace") if not hasattr( top, "_sched" ): raise PassOrderError( "_sched" ) if not hasattr( top._sched, "update_schedule" ): raise PassOrderError( "update_schedule" ) if not hasattr( top._sched, "schedule_ff" ): raise PassOrderError( "schedule_ff" ) if not hasattr( top._sched, "schedule_posedge_flip" ): raise PassOrderError( "schedule_posedge_flip" ) top._sim = PassMetadata() self.create_print_line_trace( top ) self.create_sim_cycle_count( top ) self.create_lock_unlock_simulation( top ) top.lock_in_simulation() self.create_sim_eval_comb( top ) self.create_sim_tick( top ) self.create_sim_reset( top )
def __call__( self, top ): if hasattr( top, "config_tracing" ): top.config_tracing.check() if top.config_tracing.tracing in [ 'text_ascii', 'text_fancy' ]: if not hasattr( top, "_tracing" ): top._tracing = PassMetadata() top._tracing.collect_text_sigs = self.collect_sig_func( top, top._tracing )
def __call__(self, top): if not hasattr(top._dag, "all_constraints"): raise PassOrderError("all_constraints") top._sched = PassMetadata() self.meta_schedule(top) self.trace_breaking_tick(top)
def __call__(self, top): if not hasattr(top._dag, "all_constraints"): raise PassOrderError("all_constraints") top._sched = PassMetadata() self.schedule_intra_cycle(top) self.schedule_ff(top) self.schedule_posedge_flip(top)
def __call__(self, top): if hasattr(top, "config_tracing"): top.config_tracing.check() if top.config_tracing.tracing != 'none': if not hasattr(top, "_tracing"): top._tracing = PassMetadata() top._tracing.vcd_func = self.make_vcd_func(top, top._tracing)
def traverse_hierarchy(s, m): if hasattr(m, "config_verilog_translate") and m.config_verilog_translate and \ m.config_verilog_translate.translate: if not hasattr(m, '_pass_verilog_translation'): m._pass_verilog_translation = PassMetadata() s.translator.translate(m, s.gen_tr_cfgs(m)) module_name = s.translator._top_module_full_name if m.config_verilog_translate.explicit_file_name: fname = m.config_verilog_translate.explicit_file_name if '.v' in fname: filename = fname.split('.v')[0] elif '.sv' in fname: filename = fname.split('.sv')[0] else: filename = fname else: filename = module_name output_file = filename + '.v' temporary_file = filename + '.v.tmp' # First write the file to a temporary file m._pass_verilog_translation.is_same = False with open(temporary_file, 'w') as output: output.write(s.translator.hierarchy.src) output.flush() os.fsync(output) output.close() # `is_same` is set if there exists a file that has the same filename as # `output_file`, and that file is the same as the temporary file if (os.path.exists(output_file)): m._pass_verilog_translation.is_same = \ filecmp.cmp( temporary_file, output_file ) # Rename the temporary file to the output file os.rename(temporary_file, output_file) # Expose some attributes about the translation process m.translated_top_module_name = module_name m._translator = s.translator m._pass_verilog_translation.translated = True m._pass_verilog_translation.translated_filename = output_file m._pass_verilog_translation.translated_top_module = module_name else: for child in m.get_child_components(): s.traverse_hierarchy(child)
def __call__(s, m): """Perform type checking on all RTLIR in rtlir_upblks.""" if not hasattr(m, '_pass_behavioral_rtlir_type_check'): m._pass_behavioral_rtlir_type_check = PassMetadata() m._pass_behavioral_rtlir_type_check.rtlir_freevars = OrderedDict() m._pass_behavioral_rtlir_type_check.rtlir_accessed = set() visitor = BehavioralRTLIRTypeCheckVisitorL1( m, m._pass_behavioral_rtlir_type_check.rtlir_freevars, m._pass_behavioral_rtlir_type_check.rtlir_accessed) for blk in m.get_update_blocks(): visitor.enter(blk, m._pass_behavioral_rtlir_gen.rtlir_upblks[blk])
def __call__(s, tr_top): """ generate structural RTLIR for component `tr_top` """ if not hasattr(tr_top, '_pass_structural_rtlir_gen'): tr_top._pass_structural_rtlir_gen = PassMetadata() s.tr_top = tr_top try: s.gen_rtlir_types(tr_top) s.gen_constants(tr_top) s.sort_connections(tr_top) except AssertionError as e: msg = '' if not e.args is None else e.args[0] raise RTLIRConversionError(tr_top, msg)
def __call__( self, top ): top.check() top._dag = PassMetadata() placeholders = [ x for x in top._dsl.all_named_objects if isinstance( x, Placeholder ) ] if placeholders: raise LeftoverPlaceholderError( placeholders ) self._generate_net_blocks( top ) self._process_value_constraints( top ) self._process_methods( top )
def __call__(s, m): """Perform type checking on all RTLIR in rtlir_upblks.""" if not hasattr(m, '_pass_behavioral_rtlir_type_check'): m._pass_behavioral_rtlir_type_check = PassMetadata() m._pass_behavioral_rtlir_type_check.rtlir_freevars = {} m._pass_behavioral_rtlir_type_check.rtlir_accessed = set() visitor = s.get_visitor_class()( m, m._pass_behavioral_rtlir_type_check.rtlir_freevars, m._pass_behavioral_rtlir_type_check.rtlir_accessed, s.tr_top._rtlir_getter, ) for blk in m.get_update_block_order(): visitor.enter(blk, m._pass_behavioral_rtlir_gen.rtlir_upblks[blk])
def __call__( self, top ): if not hasattr( top._dag, "all_constraints" ): raise PassOrderError( "all_constraints" ) if hasattr( top, "_sched" ): raise Exception("Some schedule pass has already been applied!") top._sched = PassMetadata() self.schedule_intra_cycle( top ) # Reuse simple's ff and flip schedule simple = SimpleSchedulePass() simple.schedule_ff( top ) simple.schedule_posedge_flip( top )
def __call__(self, top): if not hasattr(top._sched, "schedule"): raise PassOrderError("schedule") if hasattr(top, "_cl_trace"): schedule = top._cl_trace.schedule else: schedule = top._sched.schedule try: en = top.text_wave except AttributeError: return if en: top._textwave = PassMetadata() schedule.append(self.collect_sig_func(top, top._textwave))
def __call__(self, top): # Check for dum_vcd flag if not hasattr(top, "dump_vcd") or not top.dump_vcd: return if not hasattr(top._sched, "schedule"): raise PassOrderError("schedule") if hasattr(top, "_cl_trace"): schedule = top._cl_trace.schedule else: schedule = top._sched.schedule top._vcd = PassMetadata() schedule.append(self.make_vcd_func(top))
def wrap_line_trace(obj): if not hasattr(obj, '_ml_trace'): obj._ml_trace = PassMetadata() obj._ml_trace.line_trace = obj.line_trace def wrapped_line_trace(self, *args, **kwargs): if self._dsl.param_tree is not None: if self._dsl.param_tree.leaf is not None: if 'line_trace' in self._dsl.param_tree.leaf: # TODO: figure out whether it is necessary to enforce no # positional args. assert len(args) == 0 more_args = self._dsl.param_tree.leaf[ 'line_trace'].items() kwargs.update({x: y for x, y in more_args}) return self._ml_trace.line_trace(*args, **kwargs) obj.line_trace = lambda *args, **kwargs: wrapped_line_trace( obj, *args, **kwargs)
def __call__(s, m): """ generate RTLIR for all upblks of m """ if not hasattr(m, '_pass_behavioral_rtlir_gen'): m._pass_behavioral_rtlir_gen = PassMetadata() m._pass_behavioral_rtlir_gen.rtlir_upblks = {} visitor = BehavioralRTLIRGeneratorL4(m) upblks = { 'CombUpblk': list(m.get_update_blocks() - m.get_update_on_edge()), 'SeqUpblk': list(m.get_update_on_edge()) } # Sort the upblks by their name upblks['CombUpblk'].sort(key=lambda x: x.__name__) upblks['SeqUpblk'].sort(key=lambda x: x.__name__) for upblk_type in ('CombUpblk', 'SeqUpblk'): for blk in upblks[upblk_type]: visitor._upblk_type = upblk_type m._pass_behavioral_rtlir_gen.rtlir_upblks[ blk ] = \ visitor.enter( blk, m.get_update_block_ast( blk ) )
def traverse_hierarchy(s, m): if hasattr(m, "yosys_translate") and m.yosys_translate: if not hasattr(m, '_pass_yosys_translation'): m._pass_yosys_translation = PassMetadata() s.translator.translate(m) module_name = s.translator._top_module_full_name output_file = module_name + '.sv' temporary_file = module_name + '.sv.tmp' # First write the file to a temporary file m._pass_yosys_translation.is_same = False with open(temporary_file, 'w') as output: output.write(s.translator.hierarchy.src) output.flush() os.fsync(output) output.close() # `is_same` is set if there exists a file that has the same filename as # `output_file`, and that file is the same as the temporary file if (os.path.exists(output_file)): m._pass_yosys_translation.is_same = \ filecmp.cmp( temporary_file, output_file ) # Rename the temporary file to the output file os.rename(temporary_file, output_file) m._translator = s.translator m._pass_yosys_translation.translated = True else: for child in m.get_child_components(): s.traverse_hierarchy(child)
def gen_metadata(s, m): if not hasattr(m, '_pass_structural_rtlir_gen'): m._pass_structural_rtlir_gen = PassMetadata() for child in m.get_child_components(): s.gen_metadata(child)
def __call__(self, top): if not hasattr(top, "_tracing"): top._tracing = PassMetadata() top._tracing.clear_cl_trace = self.process_component(top)
def __call__(self, top): if not top._dsl.constructed: raise VerilogImportError( top, f"please elaborate design {top} before applying the TBGen pass!" ) top._tbgen = PassMetadata() top._tbgen.tbgen_hooks = [] tbgen_components = [] def traverse_hierarchy(m): if hasattr(m, 'verilog_tbgen') and hasattr(m, '_ports'): tbgen_components.append((m, m.verilog_tbgen)) else: for child in m.get_child_components(): traverse_hierarchy(child) traverse_hierarchy(top) for x, case_name in tbgen_components: signal_decls = [] task_assign_strs = [] task_signal_decls = [] task_check_strs = [] dut_signal_decls = [] py_signal_order = [] for pname, vname, port, is_ifc in x._ports: if vname == "reset" or vname == "clk": continue # Prepare for generating strings if isinstance(port, rt.Port): direction = port.get_direction() elif isinstance(port, rt.Array): direction = port.get_sub_type().get_direction() else: raise Exception(f"unrecognized direction {d}!") p_n_dim, p_rtype = get_rtype(port) dtype = p_rtype.get_dtype() if isinstance(dtype, rdt.Vector): nbits = dtype.get_length() elif isinstance(dtype, rdt.Struct): nbits = get_nbits(dtype.get_class()) else: raise Exception(f"unrecognized data type {d}!") # signal_decls signal_decl_indices = " ".join([f"[0:{d-1}]" for d in p_n_dim]) signal_decls.append( f"logic [{nbits-1}:0] {vname} {signal_decl_indices}") # dut_signal_decls if p_n_dim: # https://sutherland-hdl.com/papers/2013-SNUG-SV_Synthesizable-SystemVerilog_paper.pdf # chapter 5.2.3 dut_signal_decls.append( f".{vname}({{ >> {{ {vname} }} }})") else: dut_signal_decls.append(f".{vname}({vname})") Q = deque([(vname, vname, p_n_dim)]) tot = 0 # This is to keep the same order as pname list while Q: name, mangled_name, indices = Q.popleft() if not indices: pyname = pname[tot] if direction == "input": task_signal_decls.append( f"input logic [{nbits-1}:0] inp_{mangled_name}" ) task_assign_strs.append( f"{name} = inp_{mangled_name}") else: # output task_signal_decls.append( f"input logic [{nbits-1}:0] ref_{mangled_name}" ) task_check_strs.append( f"`CHECK(lineno, {name}, ref_{mangled_name}, \"{pyname} ({name} in Verilog)\")" ) tot += 1 py_signal_order.append(pyname) else: for i in range(indices[0]): Q.append((f"{name}[{i}]", f"{mangled_name}__{i}", indices[1:])) dut_name = x._ip_cfg.translated_top_module with open(f"{dut_name}_{case_name}_tb.v", 'w') as output: output.write( tb_template.format( args_strs=",".join( [f"a{i}" for i in range(len(task_signal_decls))]), harness_name=dut_name + "_tb", signal_decls=";\n ".join( signal_decls ), # logic [31:0] xxx [0:3]; -- unpacked array task_signal_decls=",\n ".join( task_signal_decls ), # input logic [31:0] in__x;input logic [31:0] ref_y; -- unpacked ports task_assign_strs=";\n ".join( task_assign_strs), # x = in__x; -- unpacked task_check_strs=";\n ".join( task_check_strs ), # ERR( lineno, 'x', x, ref_x ) -- unpacked dut_name=dut_name, dut_clk_decl='.clk(clk)' if x._ph_cfg.has_clk else '', dut_reset_decl='.reset(reset)' if x._ph_cfg.has_reset else '', dut_signal_decls=",\n ".join( dut_signal_decls ), # logic [31:0] xxx, -- packed array, # .x(x), -- packed array cases_file_name=f"{dut_name}_{case_name}_tb.v.cases", )) case_file = open(f"{dut_name}_{case_name}_tb.v.cases", "w") top._tbgen.tbgen_hooks.append( self.gen_hook_func(top, x, py_signal_order, case_file))
def visit_placeholder(s, m): if not hasattr(m, '_placeholder_meta'): m._placeholder_meta = PassMetadata()