.. _program_listing_file_lib_Target_EmitHLSToVivadoTcl_EmitHLSToVivadoTcl.cpp: Program Listing for File EmitHLSToVivadoTcl.cpp =============================================== |exhale_lsh| :ref:`Return to documentation for file ` (``lib/Target/EmitHLSToVivadoTcl/EmitHLSToVivadoTcl.cpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp // Implementation of translation EmitHLSToVivadoTcl // // @file // @author Jiahong Bi (jiahong.bi@tu-dresden.de) #include "laksa-mlir/Dialect/EmitHLS/IR/EmitHLS.h" #include "laksa-mlir/Target/EmitHLSToVivadoTcl/VivadoTclEmitter.h" #include "llvm/Support/CommandLine.h" using namespace mlir; using namespace mlir::emithls; namespace { llvm::cl::opt clVivadoTargetDevice( "vivado-target-device", llvm::cl::desc( "Target part passed to Vivado's create_project in the generated " "run_vivado.tcl"), llvm::cl::init("xck26-sfvc784-2LV-c")); } // namespace // Finds the function marked as the design's top function, i.e. the one whose // body contains a PragmaTopInterfaceOp. Its symbol name doubles as the // Vivado project name and the HLS IP's VLNV/cell name. static FailureOr findTopFunc(ModuleOp moduleOp) { FuncOp topFunc = nullptr; auto result = moduleOp.walk([&](PragmaTopInterfaceOp topInterfaceOp) { FuncOp funcOp = topInterfaceOp->getParentOfType(); if (!funcOp || topFunc) return WalkResult::interrupt(); topFunc = funcOp; return WalkResult::advance(); }); if (result.wasInterrupted() || !topFunc) return moduleOp->emitError( "expected exactly one function containing a top_interface " "pragma"); return topFunc; } //===----------------------------------------------------------------------===// // Translation entry point //===----------------------------------------------------------------------===// LogicalResult emithls::translateEmitHLSToVivadoTcl(ModuleOp op, raw_ostream &os) { FailureOr topFunc = findTopFunc(op); if (failed(topFunc)) return failure(); StringRef projectName = topFunc->getSymName(); unsigned numArgs = topFunc->getNumArguments(); os << "set project_name \"" << projectName << "\"\n" << "set project_dir \"./vivado_project/\"\n" << "set project_path \"$project_dir/$project_name.xpr\"\n" << "set target_device \"" << clVivadoTargetDevice << "\"\n" << "set ip_repo_dir \"./hls_project\"\n" << "if {[file exists $project_dir]} {\n" << " puts \"INFO: Project directory exists.\"\n" << " exit 1\n" << "}\n" << "puts \"INFO: Creating a new project...\"\n" << "create_project $project_name $project_dir -part $target_device\n" << "set_property part $target_device [current_project]\n" << "set_property default_lib xil_defaultlib [current_project]\n" << "set_property target_language Verilog [current_project]\n" << "if {[file exists $ip_repo_dir]} {\n" << " puts \"INFO: Adding IP repository: $ip_repo_dir\"\n" << " set_property ip_repo_paths $ip_repo_dir [current_project]\n" << "} else {\n" << " puts \"WARNING: IP repository directory $ip_repo_dir does not " "exist!\"\n" << " exit 1\n" << "}\n" << "set bd_name \"${project_name}_bd\"\n" << "puts \"INFO: Creating block design: $bd_name\"\n" << "create_bd_design $bd_name\n" << "puts \"INFO: Adding Zynq MPSoC to the block design\"\n" << "set zynq_mpsoc [create_bd_cell -type ip -vlnv " "xilinx.com:ip:zynq_ultra_ps_e:3.5 zynq_mpsoc]\n" << "puts \"INFO: Applying board preset to Zynq MPSoC\"\n" << "apply_bd_automation -rule xilinx.com:bd_rule:zynq_ultra_ps_e " "-config {apply_board_preset \"1\"} $zynq_mpsoc\n" << "set_property CONFIG.PSU__FPGA_PL0_ENABLE {1} $zynq_mpsoc\n" << "set_property CONFIG.PSU__USE__M_AXI_GP0 {1} $zynq_mpsoc\n" << "set_property CONFIG.PSU__USE__M_AXI_GP1 {0} $zynq_mpsoc\n" << "set_property CONFIG.PSU__USE__M_AXI_GP2 {0} $zynq_mpsoc\n" << "set_property CONFIG.PSU__USE__S_AXI_GP0 {1} $zynq_mpsoc\n" << "set_property CONFIG.PSU__CRL_APB__PL0_REF_CTRL__FREQMHZ {100} " "$zynq_mpsoc\n" << "puts \"INFO: Adding HLS IP kernel to the block design\"\n" << "create_bd_cell -type ip -vlnv xilinx.com:hls:" << projectName << ":1.0 " << projectName << "\n" << "apply_bd_automation -rule xilinx.com:bd_rule:axi4 -config { " "Clk_master {Auto} Clk_slave {Auto} Clk_xbar {Auto} Master " "{/zynq_mpsoc/M_AXI_HPM0_FPD} Slave {/" << projectName << "/s_axi_control} ddr_seg {Auto} intc_ip {New AXI SmartConnect} " "master_apm {0}} [get_bd_intf_pins " << projectName << "/s_axi_control]\n"; // Each top-function argument becomes an m_axi_gmem_argN master port on the // HLS IP, which needs to be wired to the Zynq's HPC0 slave port. Automating // the first one enables Zynq's S_AXI_HPC0_FPD slave port and creates a new // AXI SmartConnect. Every subsequent one reuses that same SmartConnect, // automating the HLS IP's own port instead since the Zynq side is already // wired up. for (unsigned i = 0; i < numArgs; ++i) { os << "apply_bd_automation -rule xilinx.com:bd_rule:axi4 -config { " "Clk_master {Auto} Clk_slave {Auto} Clk_xbar {Auto} Master {/" << projectName << "/m_axi_gmem_arg" << i << "} Slave {/zynq_mpsoc/S_AXI_HPC0_FPD} ddr_seg {Auto} intc_ip {"; if (i == 0) os << "New AXI SmartConnect"; else os << "/axi_smc_1"; os << "} master_apm {0}} [get_bd_intf_pins "; if (i == 0) os << "zynq_mpsoc/S_AXI_HPC0_FPD"; else os << projectName << "/m_axi_gmem_arg" << i; os << "]\n"; } os << "puts \"INFO: Validating block design: $bd_name\"\n" << "if {[catch {validate_bd_design} result]} {\n" << " puts \"Block design validation failed: $result\"\n" << " exit 1\n" << "}\n" << "puts \"INFO: Validating succeeded\"\n" << "regenerate_bd_layout\n" << "save_bd_design\n" << "puts \"INFO: Closing block design: $bd_name\"\n" << "make_wrapper -files [get_files " "\"$project_dir/$project_name.srcs/sources_1/bd/$bd_name/" "$bd_name.bd\"] -top\n" << "set wrapper_path " "\"$project_dir/$project_name.srcs/sources_1/bd/$bd_name/hdl/" "${bd_name}_wrapper.v\"\n" << "add_files $wrapper_path\n" << "set_property top \"${bd_name}_wrapper\" [get_filesets sources_1]\n" << "set max_cores [get_param general.maxThreads]\n" << "puts \"INFO: Using up to $max_cores threads for synthesis and " "implementation.\"\n" << "puts \"INFO: Running Synthesis...\"\n" << "launch_runs synth_1 -jobs $max_cores\n" << "wait_on_run synth_1\n" << "set synth_status [get_property STATUS [get_runs synth_1]]\n" << "if {![string match \"*Complete!*\" $synth_status]} {\n" << " puts \"ERROR: Synthesis failed with status: $synth_status\"\n" << " exit 1\n" << "}\n" << "puts \"INFO: Synthesis completed successfully\"\n" << "puts \"INFO: Running Implementation...\"\n" << "reset_run impl_1\n" << "launch_runs impl_1 -to_step write_bitstream -jobs $max_cores\n" << "wait_on_run impl_1\n" << "set impl_status [get_property STATUS [get_runs impl_1]]\n" << "if {![string match \"*Complete!*\" $impl_status]} {\n" << " puts \"ERROR: Implementation failed with status: " "$impl_status\"\n" << " exit 1\n" << "}\n" << "puts \"INFO: Implementation completed successfully\"\n" << "puts \"INFO: Exporting hardware with bitstream\"\n" << "write_hw_platform -fixed -include_bit -force -file " "$project_dir/${project_name}_bd.xsa\n" << "exit\n"; return success(); }