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_streamline(model: ModelWrapper, cfg: DataflowBuildConfig): """Run streamlining on given model. Streamlining involves moving floating point scale/shift parameters around, collapsing adjacent ones into a single parameter, then absorbing the scale/shift into the following `MultiThreshold` node. Streamlining requires careful topology design and cannot be applied to all topologies. """ model = model.transform(absorb.AbsorbSignBiasIntoMultiThreshold()) model = model.transform(Streamline()) need_lowering = len(model.get_nodes_by_op_type("Conv")) > 0 if need_lowering: model = model.transform(LowerConvsToMatMul()) model = model.transform(MakeMaxPoolNHWC()) model = model.transform(absorb.AbsorbTransposeIntoMultiThreshold()) model = model.transform(MakeMaxPoolNHWC()) model = model.transform(ConvertBipolarMatMulToXnorPopcount()) model = model.transform(Streamline()) # absorb final add-mul nodes into TopK model = model.transform(absorb.AbsorbScalarMulAddIntoTopK()) model = model.transform(InferDataLayouts()) model = model.transform(RemoveUnusedTensors()) if VerificationStepType.STREAMLINED_PYTHON in cfg._resolve_verification_steps( ): verify_step(model, cfg, "streamlined_python", need_parent=False) return model
def step_qonnx_to_finn(model: ModelWrapper, cfg: DataflowBuildConfig): """ This step will only execute if QONNX nodes are found. These include the following op_types: "Quant" , "Trunc" and "BinaryQuant". If such nodes are found the step will run the tidy-up step from QONNX and then convert the QONNX model to the FINN-ONNX dialect. """ # Check if any QONNX nodes exist, i.e. BinaryQuant, Quant or Trunc q_count = 0 for op_type in ["BinaryQuant", "Quant", "Trunc"]: q_count += len(model.get_nodes_by_op_type(op_type)) if q_count == 0: return model # QONNX cleanup model = cleanup_model(model) # QONNX to FINN-ONNX model = model.transform( ConvertQONNXtoFINN( filter_function=default_filter_function_generator( max_multithreshold_bit_width=cfg.max_multithreshold_bit_width ) ) ) if VerificationStepType.QONNX_TO_FINN_PYTHON in cfg._resolve_verification_steps(): verify_step(model, cfg, "qonnx_to_finn_python", need_parent=False) return model
def step_apply_folding_config(model: ModelWrapper, cfg: DataflowBuildConfig): """Apply the folding configuration file onto the model to set folding (parallelization) and other attributes, if config file is specified.""" if cfg.folding_config_file is not None: model = model.transform(GiveUniqueNodeNames()) model = model.transform(ApplyConfig(cfg.folding_config_file)) if VerificationStepType.FOLDED_HLS_CPPSIM in cfg._resolve_verification_steps(): # prepare cppsim model = model.transform(PrepareCppSim()) model = model.transform(CompileCppSim()) model = model.transform(SetExecMode("cppsim")) verify_step(model, cfg, "folded_hls_cppsim", need_parent=True) return model
def step_tidy_up(model: ModelWrapper, cfg: DataflowBuildConfig): """Run the tidy-up step on given model. This includes shape and datatype inference, constant folding, and giving nodes and tensors better names. """ model = model.transform(InferShapes()) model = model.transform(FoldConstants()) model = model.transform(GiveUniqueNodeNames()) model = model.transform(GiveReadableTensorNames()) model = model.transform(InferDataTypes()) model = model.transform(RemoveStaticGraphInputs()) if VerificationStepType.TIDY_UP_PYTHON in cfg._resolve_verification_steps(): verify_step(model, cfg, "initial_python", need_parent=False) 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