def step_resnet50_set_fifo_depths(model: ModelWrapper, cfg: DataflowBuildConfig): """ Depending on the auto_fifo_depths setting, do one of the following: * if auto_fifo_depths=True: Run the `InsertAndSetFIFODepths` transformation to attempt to determine the FIFO sizes that provide full throughput. Involves running stitched-IP rtlsim and may take a long time. * if auto_fifo_depths=False: Assume the folding config file contains FIFO sizes as well. Runs the `InsertFIFO` transformation, then `ApplyConfig(cfg.folding_config_file)`, and finally `RemoveShallowFIFOs`. Coherency with config file node naming is ensured by calling `GiveUniqueNodeNames`. """ if cfg.auto_fifo_depths: model = model.transform( InsertAndSetFIFODepths( cfg._resolve_fpga_part(), cfg._resolve_hls_clk_period(), vivado_ram_style=cfg.large_fifo_mem_style.value, )) else: # assume folding cfg json contains FIFO sizes too # insert DWCs, FIFOs and run ApplyConfig once more model = model.transform(InsertDWC()) # need to make sure all FIFOs are created so that their depth can be # set by ApplyConfig, so create_shallow_fifos=True model = model.transform(InsertFIFO(create_shallow_fifos=True)) model = model.transform(GiveUniqueNodeNames()) model = model.transform(GiveReadableTensorNames()) if cfg.folding_config_file is not None: model = model.transform(ApplyConfig(cfg.folding_config_file)) # remove any shallow FIFOs model = model.transform(RemoveShallowFIFOs()) # extract the final configuration and save it as json hw_attrs = [ "PE", "SIMD", "ram_style", "depth", "impl_style", "resType", "mem_mode", "runtime_writeable_weights", ] extract_model_config_to_json(model, cfg.output_dir + "/final_hw_config.json", hw_attrs) # after FIFOs are ready to go, call PrepareIP and HLSSynthIP again # this will only run for the new nodes (e.g. FIFOs and DWCs) model = model.transform( PrepareIP(cfg._resolve_fpga_part(), cfg._resolve_hls_clk_period())) model = model.transform(HLSSynthIP()) model = model.transform(ReplaceVerilogRelPaths()) return model
def step_create_stitched_ip(model: ModelWrapper, cfg: DataflowBuildConfig): """Create stitched IP for a graph after all HLS IP blocks have been generated. Depends on the DataflowOutputType.STITCHED_IP output product.""" if DataflowOutputType.STITCHED_IP in cfg.generate_outputs: stitched_ip_dir = cfg.output_dir + "/stitched_ip" model = model.transform( CreateStitchedIP(cfg._resolve_fpga_part(), cfg.synth_clk_period_ns)) # TODO copy all ip sources into output dir? as zip? copytree(model.get_metadata_prop("vivado_stitch_proj"), stitched_ip_dir) print("Vivado stitched IP written into " + stitched_ip_dir) if VerificationStepType.STITCHED_IP_RTLSIM in cfg._resolve_verification_steps( ): # prepare ip-stitched rtlsim verify_model = deepcopy(model) # rtlsim only supports impl_style=rtl for StreamingFIFO, ensure that for fifo_layer in verify_model.get_nodes_by_op_type("StreamingFIFO"): getCustomOp(fifo_layer).set_nodeattr("impl_style", "rtl") # similarly for StreamingDataWidthConverter with impl_style=hls for dwc_layer in verify_model.get_nodes_by_op_type( "StreamingDataWidthConverter_Batch"): getCustomOp(dwc_layer).set_nodeattr("impl_style", "hls") verify_model = verify_model.transform(PrepareRTLSim()) verify_model.set_metadata_prop("exec_mode", "rtlsim") verify_step(verify_model, cfg, "stitched_ip_rtlsim", need_parent=True) return model
def step_out_of_context_synthesis(model: ModelWrapper, cfg: DataflowBuildConfig): """Run out-of-context synthesis and generate reports. Depends on the DataflowOutputType.STITCHED_IP output product.""" if DataflowOutputType.OOC_SYNTH in cfg.generate_outputs: assert ( DataflowOutputType.STITCHED_IP in cfg.generate_outputs ), "OOC needs stitched IP" model = model.transform( SynthOutOfContext( part=cfg._resolve_fpga_part(), clk_period_ns=cfg.synth_clk_period_ns ) ) report_dir = cfg.output_dir + "/report" os.makedirs(report_dir, exist_ok=True) ooc_res_dict = model.get_metadata_prop("res_total_ooc_synth") ooc_res_dict = eval(ooc_res_dict) estimate_network_performance = model.analysis(dataflow_performance) # add some more metrics to estimated performance n_clock_cycles_per_sec = float(ooc_res_dict["fmax_mhz"]) * (10 ** 6) est_fps = n_clock_cycles_per_sec / estimate_network_performance["max_cycles"] ooc_res_dict["estimated_throughput_fps"] = est_fps with open(report_dir + "/ooc_synth_and_timing.json", "w") as f: json.dump(ooc_res_dict, f, indent=2) return model
def step_hls_codegen(model: ModelWrapper, cfg: DataflowBuildConfig): "Generate Vivado HLS code to prepare HLSCustomOp nodes for IP generation." model = model.transform( PrepareIP(cfg._resolve_fpga_part(), cfg._resolve_hls_clk_period()) ) return model
def step_synthesize_bitfile(model: ModelWrapper, cfg: DataflowBuildConfig): """Synthesize a bitfile for the using the specified shell flow, using either Vivado or Vitis, to target the specified board.""" if DataflowOutputType.BITFILE in cfg.generate_outputs: bitfile_dir = cfg.output_dir + "/bitfile" os.makedirs(bitfile_dir, exist_ok=True) report_dir = cfg.output_dir + "/report" os.makedirs(report_dir, exist_ok=True) partition_model_dir = cfg.output_dir + "/intermediate_models/kernel_partitions" if cfg.shell_flow_type == ShellFlowType.VIVADO_ZYNQ: model = model.transform( ZynqBuild( cfg.board, cfg.synth_clk_period_ns, cfg.enable_hw_debug, partition_model_dir=partition_model_dir, ) ) copy(model.get_metadata_prop("bitfile"), bitfile_dir + "/finn-accel.bit") copy(model.get_metadata_prop("hw_handoff"), bitfile_dir + "/finn-accel.hwh") copy( model.get_metadata_prop("vivado_synth_rpt"), report_dir + "/post_synth_resources.xml", ) vivado_pynq_proj_dir = model.get_metadata_prop("vivado_pynq_proj") timing_rpt = ( "%s/finn_zynq_link.runs/impl_1/top_wrapper_timing_summary_routed.rpt" % vivado_pynq_proj_dir ) copy(timing_rpt, report_dir + "/post_route_timing.rpt") elif cfg.shell_flow_type == ShellFlowType.VITIS_ALVEO: model = model.transform( VitisBuild( cfg._resolve_fpga_part(), cfg.synth_clk_period_ns, cfg.vitis_platform, strategy=cfg._resolve_vitis_opt_strategy(), enable_debug=cfg.enable_hw_debug, floorplan_file=cfg.vitis_floorplan_file, partition_model_dir=partition_model_dir, ) ) copy(model.get_metadata_prop("bitfile"), bitfile_dir + "/finn-accel.xclbin") copy( model.get_metadata_prop("vivado_synth_rpt"), report_dir + "/post_synth_resources.xml", ) else: raise Exception("Unrecognized shell_flow_type: " + str(cfg.shell_flow_type)) print("Bitfile written into " + bitfile_dir) return model
def step_hls_ipgen(model: ModelWrapper, cfg: DataflowBuildConfig): "Run Vivado HLS synthesis on any HLSCustomOp nodes to generate IP blocks." model = model.transform( PrepareIP(cfg._resolve_fpga_part(), cfg._resolve_hls_clk_period())) model = model.transform(HLSSynthIP()) model = model.transform(ReplaceVerilogRelPaths()) report_dir = cfg.output_dir + "/report" os.makedirs(report_dir, exist_ok=True) estimate_layer_resources_hls = model.analysis(hls_synth_res_estimation) with open(report_dir + "/estimate_layer_resources_hls.json", "w") as f: json.dump(estimate_layer_resources_hls, f, indent=2) return model
def step_create_stitched_ip(model: ModelWrapper, cfg: DataflowBuildConfig): """Create stitched IP for a graph after all HLS IP blocks have been generated. Depends on the DataflowOutputType.STITCHED_IP output product.""" if DataflowOutputType.STITCHED_IP in cfg.generate_outputs: stitched_ip_dir = cfg.output_dir + "/stitched_ip" model = model.transform( CreateStitchedIP( cfg._resolve_fpga_part(), cfg.synth_clk_period_ns, vitis=cfg.stitched_ip_gen_dcp, ) ) # TODO copy all ip sources into output dir? as zip? copy_tree(model.get_metadata_prop("vivado_stitch_proj"), stitched_ip_dir) print("Vivado stitched IP written into " + stitched_ip_dir) if VerificationStepType.STITCHED_IP_RTLSIM in cfg._resolve_verification_steps(): # prepare ip-stitched rtlsim verify_model = deepcopy(model) verify_model = prepare_for_stitched_ip_rtlsim(verify_model, cfg) # use critical path estimate to set rtlsim liveness threshold # (very conservative) verify_model = verify_model.transform(AnnotateCycles()) estimate_network_performance = verify_model.analysis(dataflow_performance) prev_liveness = pyverilate_get_liveness_threshold_cycles() os.environ["LIVENESS_THRESHOLD"] = str( int(estimate_network_performance["critical_path_cycles"]) ) if cfg.verify_save_rtlsim_waveforms: report_dir = cfg.output_dir + "/report" os.makedirs(report_dir, exist_ok=True) verify_model.set_metadata_prop( "rtlsim_trace", "%s/verify_rtlsim.vcd" % (report_dir) ) verify_step(verify_model, cfg, "stitched_ip_rtlsim", need_parent=True) os.environ["LIVENESS_THRESHOLD"] = str(prev_liveness) return model