def prepare_rtlsim(self): """Creates a Verilator emulation library for the RTL code generated for this node, sets the rtlsim_so attribute to its path and returns a PyVerilator wrapper around it.""" if PyVerilator is None: raise ImportError("Installation of PyVerilator is required.") # ensure that code is generated code_gen_dir = self.get_nodeattr("code_gen_dir_ipgen") assert (code_gen_dir != ""), """Node attribute "code_gen_dir_ipgen" is not set. Please run HLSSynthIP first.""" verilog_file = self.get_verilog_top_filename() assert os.path.isfile( verilog_file), "Cannot find top-level Verilog file." # build the Verilator emu library sim = PyVerilator.build( verilog_file, build_dir=make_build_dir("pyverilator_" + self.onnx_node.name + "_"), verilog_path=[ "{}/project_{}/sol1/impl/verilog/".format( code_gen_dir, self.onnx_node.name) ], trace_depth=get_rtlsim_trace_depth(), ) # save generated lib filename in attribute self.set_nodeattr("rtlsim_so", sim.lib._name) return sim
def pyverilate_stitched_ip(model): "Given a model with stitched IP, return a PyVerilator sim object." if PyVerilator is None: raise ImportError("Installation of PyVerilator is required.") vivado_stitch_proj_dir = model.get_metadata_prop("vivado_stitch_proj") with open(vivado_stitch_proj_dir + "/all_verilog_srcs.txt", "r") as f: all_verilog_srcs = f.read().split() def file_to_dir(x): return os.path.dirname(os.path.realpath(x)) def file_to_basename(x): return os.path.basename(os.path.realpath(x)) all_verilog_dirs = list(map(file_to_dir, all_verilog_srcs)) all_verilog_files = list( set( filter( lambda x: x.endswith(".v"), list(map(file_to_basename, all_verilog_srcs)), ))) top_module_name = model.get_metadata_prop("wrapper_filename") top_module_name = file_to_basename(top_module_name).strip(".v") build_dir = make_build_dir("pyverilator_ipstitched_") sim = PyVerilator.build( all_verilog_files, verilog_path=all_verilog_dirs, build_dir=build_dir, trace_depth=get_rtlsim_trace_depth(), top_module_name=top_module_name, auto_eval=False, ) return sim
def step_measure_rtlsim_performance(model: ModelWrapper, cfg: DataflowBuildConfig): """Measure performance + latency of stitched-IP model in rtlsim (pyverilator). Depends on the DataflowOutputType.STITCHED_IP output product. """ if DataflowOutputType.RTLSIM_PERFORMANCE in cfg.generate_outputs: assert ( DataflowOutputType.STITCHED_IP in cfg.generate_outputs ), "rtlsim_perf needs stitched IP" report_dir = cfg.output_dir + "/report" os.makedirs(report_dir, exist_ok=True) # prepare ip-stitched rtlsim rtlsim_model = deepcopy(model) rtlsim_model = prepare_for_stitched_ip_rtlsim(rtlsim_model, cfg) # run with single input to get latency orig_rtlsim_trace_depth = get_rtlsim_trace_depth() rtlsim_bs = int(cfg.rtlsim_batch_size) assert rtlsim_bs > 0, "rtlsim batch size must be >0" if cfg.verify_save_rtlsim_waveforms: # set depth to 3 for layer-by-layer visibility os.environ["RTLSIM_TRACE_DEPTH"] = "3" rtlsim_model.set_metadata_prop( "rtlsim_trace", "%s/rtlsim_perf_batch_%d.vcd" % (report_dir, rtlsim_bs) ) rtlsim_model.set_metadata_prop("extra_verilator_args", str(["-CFLAGS", "-O3"])) rtlsim_perf_dict = throughput_test_rtlsim(rtlsim_model, rtlsim_bs) rtlsim_latency = rtlsim_perf_dict["cycles"] rtlsim_perf_dict["latency_cycles"] = rtlsim_latency with open(report_dir + "/rtlsim_performance.json", "w") as f: json.dump(rtlsim_perf_dict, f, indent=2) if cfg.verify_save_rtlsim_waveforms: # restore original trace depth os.environ["RTLSIM_TRACE_DEPTH"] = str(orig_rtlsim_trace_depth) return model
def prepare_rtlsim(self): """Creates a Verilator emulation library for the RTL code generated for this node, sets the rtlsim_so attribute to its path and returns a PyVerilator wrapper around it.""" if PyVerilator is None: raise ImportError("Installation of PyVerilator is required.") verilog_paths = self.get_all_verilog_paths() verilog_files = self.get_all_verilog_filenames() # build the Verilator emu library sim = PyVerilator.build( verilog_files, build_dir=make_build_dir("pyverilator_" + self.onnx_node.name + "_"), verilog_path=verilog_paths, trace_depth=get_rtlsim_trace_depth(), top_module_name=self.get_verilog_top_module_name(), ) # save generated lib filename in attribute self.set_nodeattr("rtlsim_so", sim.lib._name) return sim
def pyverilate_stitched_ip(model): "Given a model with stitched IP, return a PyVerilator sim object." if PyVerilator is None: raise ImportError("Installation of PyVerilator is required.") vivado_stitch_proj_dir = model.get_metadata_prop("vivado_stitch_proj") with open(vivado_stitch_proj_dir + "/all_verilog_srcs.txt", "r") as f: all_verilog_srcs = f.read().split() def file_to_dir(x): return os.path.dirname(os.path.realpath(x)) all_verilog_dirs = list(map(file_to_dir, all_verilog_srcs)) top_verilog = model.get_metadata_prop("wrapper_filename") build_dir = make_build_dir("pyverilator_ipstitched_") sim = PyVerilator.build( top_verilog, verilog_path=all_verilog_dirs, build_dir=build_dir, trace_depth=get_rtlsim_trace_depth(), ) return sim
def pyverilate_stitched_ip(model, read_internal_signals=True): """Given a model with stitched IP, return a PyVerilator sim object. If read_internal_signals is True, it will be possible to examine the internal (not only port) signals of the Verilog module, but this may slow down compilation and emulation. Trace depth is also controllable, see get_rtlsim_trace_depth() """ if PyVerilator is None: raise ImportError("Installation of PyVerilator is required.") vivado_stitch_proj_dir = model.get_metadata_prop("vivado_stitch_proj") with open(vivado_stitch_proj_dir + "/all_verilog_srcs.txt", "r") as f: all_verilog_srcs = f.read().split() def file_to_dir(x): return os.path.dirname(os.path.realpath(x)) def file_to_basename(x): return os.path.basename(os.path.realpath(x)) top_module_file_name = file_to_basename( model.get_metadata_prop("wrapper_filename")) top_module_name = top_module_file_name.strip(".v") build_dir = make_build_dir("pyverilator_ipstitched_") # dump all Verilog code to a single file # this is because large models with many files require # a verilator command line too long for bash on most systems # NOTE: there are duplicates in this list, and some files # are identical but in multiple directories (regslice_core.v) # remove duplicates from list by doing list -> set -> list all_verilog_files = list( set(filter(lambda x: x.endswith(".v"), all_verilog_srcs))) # remove all but one instances of regslice_core.v filtered_verilog_files = [] remove_entry = False for vfile in all_verilog_files: if "regslice_core" in vfile: if not remove_entry: filtered_verilog_files.append(vfile) remove_entry = True else: filtered_verilog_files.append(vfile) # concatenate all verilog code into a single file with open(vivado_stitch_proj_dir + "/" + top_module_file_name, "w") as wf: for vfile in filtered_verilog_files: with open(vfile) as rf: wf.write("//Added from " + vfile + "\n\n") wf.write(rf.read()) sim = PyVerilator.build( top_module_file_name, verilog_path=[vivado_stitch_proj_dir], build_dir=build_dir, trace_depth=get_rtlsim_trace_depth(), top_module_name=top_module_name, auto_eval=False, read_internal_signals=read_internal_signals, ) return sim
def pyverilate_stitched_ip( model, read_internal_signals=True, disable_common_warnings=True, extra_verilator_args=[], ): """Given a model with stitched IP, return a PyVerilator sim object. Trace depth is also controllable, see get_rtlsim_trace_depth() :param read_internal_signals If set, it will be possible to examine the internal (not only port) signals of the Verilog module, but this may slow down compilation and emulation. :param disable_common_warnings If set, disable the set of warnings that Vivado-HLS-generated Verilog typically triggers in Verilator (which can be very verbose otherwise) """ if PyVerilator is None: raise ImportError("Installation of PyVerilator is required.") vivado_stitch_proj_dir = model.get_metadata_prop("vivado_stitch_proj") with open(vivado_stitch_proj_dir + "/all_verilog_srcs.txt", "r") as f: all_verilog_srcs = f.read().split() def file_to_dir(x): return os.path.dirname(os.path.realpath(x)) def file_to_basename(x): return os.path.basename(os.path.realpath(x)) top_module_file_name = file_to_basename( model.get_metadata_prop("wrapper_filename")) top_module_name = top_module_file_name.strip(".v") build_dir = make_build_dir("pyverilator_ipstitched_") # dump all Verilog code to a single file # this is because large models with many files require # a verilator command line too long for bash on most systems # NOTE: there are duplicates in this list, and some files # are identical but in multiple directories (regslice_core.v) # remove duplicates from list by doing list -> set -> list all_verilog_files = list( set(filter(lambda x: x.endswith(".v"), all_verilog_srcs))) # remove all but one instances of regslice_core.v filtered_verilog_files = [] remove_entry = False for vfile in all_verilog_files: if "regslice_core" in vfile: if not remove_entry: filtered_verilog_files.append(vfile) remove_entry = True else: filtered_verilog_files.append(vfile) # concatenate all verilog code into a single file with open(vivado_stitch_proj_dir + "/" + top_module_file_name, "w") as wf: for vfile in filtered_verilog_files: with open(vfile) as rf: wf.write("//Added from " + vfile + "\n\n") wf.write(rf.read()) verilator_args = [] # disable common verilator warnings that should be harmless but commonly occur # in large quantities for Vivado HLS-generated verilog code if disable_common_warnings: verilator_args += ["-Wno-STMTDLY"] verilator_args += ["-Wno-PINMISSING"] verilator_args += ["-Wno-IMPLICIT"] verilator_args += ["-Wno-WIDTH"] verilator_args += ["-Wno-COMBDLY"] # force inlining of all submodules to ensure we can read internal signals properly if read_internal_signals: verilator_args += ["--inline-mult", "0"] sim = PyVerilator.build( top_module_file_name, verilog_path=[vivado_stitch_proj_dir], build_dir=build_dir, trace_depth=get_rtlsim_trace_depth(), top_module_name=top_module_name, auto_eval=False, read_internal_signals=read_internal_signals, extra_args=verilator_args + extra_verilator_args, ) return sim