## Define the ADI_USE_OOC_SYNTHESIS environment variable to enable out of context # synthesis if {[info exists ::env(ADI_USE_OOC_SYNTHESIS)]} { if {[string equal $::env(ADI_USE_OOC_SYNTHESIS) n]} { set ADI_USE_OOC_SYNTHESIS 0 } else { set ADI_USE_OOC_SYNTHESIS 1 } } elseif {![info exists ADI_USE_OOC_SYNTHESIS]} { set ADI_USE_OOC_SYNTHESIS 1 } ## Set number of parallel out of context jobs through environment variable if {![info exists ::env(ADI_MAX_OOC_JOBS)]} { set ADI_MAX_OOC_JOBS 4 } else { set ADI_MAX_OOC_JOBS $::env(ADI_MAX_OOC_JOBS) } ## Set to enable incremental compilation set ADI_USE_INCR_COMP 1 ## Set to enable power optimization set ADI_POWER_OPTIMIZATION 0 ## Initialize global variables set p_board "not-applicable" set p_device "none" set sys_zynq 1 set p_prcfg_init "" set p_prcfg_list "" set p_prcfg_status "" ## Creates a Xilinx project for a given board # # \param[project_name] - name of the project # \param[mode] - if set non-project mode will be used, otherwise project mode # flow, see UG892 for more information # \param[parameter_list] - a list of global parameters (parameters of the # system_top module) # # Supported carrier names are: ac701, kc705, vc707, vcu118, vcu128, kcu105, zed, # microzed, zc702, zc706, mitx405, zcu102. # proc adi_project {project_name {mode 0} {parameter_list {}} } { set device "" set board "" # Determine the device based on the board name if [regexp "_ac701" $project_name] { set device "xc7a200tfbg676-2" set board [lindex [lsearch -all -inline [get_board_parts] *ac701*] end] } if [regexp "_kc705" $project_name] { set device "xc7k325tffg900-2" set board [lindex [lsearch -all -inline [get_board_parts] *kc705*] end] } if [regexp "_vc707" $project_name] { set device "xc7vx485tffg1761-2" set board [lindex [lsearch -all -inline [get_board_parts] *vc707*] end] } if [regexp "_vcu118" $project_name] { set device "xcvu9p-flga2104-2L-e" set board [lindex [lsearch -all -inline [get_board_parts] *vcu118*] end] } if [regexp "_vcu128" $project_name] { set device "xcvu37p-fsvh2892-2L-e" set board [lindex [lsearch -all -inline [get_board_parts] *vcu128:part0*] end] } if [regexp "_kcu105" $project_name] { set device "xcku040-ffva1156-2-e" set board [lindex [lsearch -all -inline [get_board_parts] *kcu105*] end] } if [regexp "_zed" $project_name] { set device "xc7z020clg484-1" set board [lindex [lsearch -all -inline [get_board_parts] *zed*] end] } if [regexp "_coraz7s" $project_name] { set device "xc7z007sclg400-1" set board "not-applicable" } if [regexp "_microzed" $project_name] { set device "xc7z010clg400-1" set board "not-applicable" } if [regexp "_zc702" $project_name] { set device "xc7z020clg484-1" set board [lindex [lsearch -all -inline [get_board_parts] *zc702*] end] } if [regexp "_zc706" $project_name] { set device "xc7z045ffg900-2" set board [lindex [lsearch -all -inline [get_board_parts] *zc706*] end] } if [regexp "_mitx045" $project_name] { set device "xc7z045ffg900-2" set board "not-applicable" } if [regexp "_zcu102" $project_name] { set device "xczu9eg-ffvb1156-2-e" set board [lindex [lsearch -all -inline [get_board_parts] *zcu102*] end] } if [regexp "_vmk180_es1" $project_name] { enable_beta_device xcvm* xhub::refresh_catalog [xhub::get_xstores xilinx_board_store] xhub::install [xhub::get_xitems xilinx.com:xilinx_board_store:vmk180_es:*] -quiet set_param board.repoPaths [get_property LOCAL_ROOT_DIR [xhub::get_xstores xilinx_board_store]] set device "xcvm1802-vsva2197-2MP-e-S-es1" set board [lindex [lsearch -all -inline [get_board_parts] *vmk180_es*] end] } if [regexp "_vmk180" $project_name] { set device "xcvm1802-vsva2197-2MP-e-S" set board [lindex [lsearch -all -inline [get_board_parts] *vmk180*] end] } if [regexp "_vck190" $project_name] { set device "xcvc1902-vsva2197-2MP-e-S" set board [lindex [lsearch -all -inline [get_board_parts] *vck190*] end] } if [regexp "_vc709" $project_name] { set device "xc7vx690tffg1761-2" set board [lindex [lsearch -all -inline [get_board_parts] *vc709*] end] } adi_project_create $project_name $mode $parameter_list $device $board } ## Creates a Xilinx project. # # \param[project_name] - name of the project # \param[mode] - if set non-project mode will be used, otherwise project mode # flow, see UG892 for more information # \param[parameter_list] - a list of global parameters (parameters of the # system_top module) # \param[device] - Canonical Xilinx device string # \param[board] - board BSP name (optional) # proc adi_project_create {project_name mode parameter_list device {board "not-applicable"}} { global ad_hdl_dir global ad_ghdl_dir global ad_project_dir global p_board global p_device global sys_zynq global required_vivado_version global IGNORE_VERSION_CHECK global ADI_USE_OOC_SYNTHESIS global ADI_USE_INCR_COMP if {![info exists ::env(ADI_PROJECT_DIR)]} { set actual_project_name $project_name } else { set actual_project_name "$::env(ADI_PROJECT_DIR)${project_name}" } ## update the value of $p_device only if it was not already updated elsewhere if {$p_device eq "none"} { set p_device $device } set p_board $board if [regexp "^xc7z" $p_device] { set sys_zynq 1 } elseif [regexp "^xczu" $p_device] { set sys_zynq 2 } elseif [regexp "^xcv\[ecmph\]" $p_device] { set sys_zynq 3 } else { set sys_zynq 0 } set VIVADO_VERSION [version -short] if {$IGNORE_VERSION_CHECK} { if {[string compare $VIVADO_VERSION $required_vivado_version] != 0} { puts -nonewline "CRITICAL WARNING: vivado version mismatch; " puts -nonewline "expected $required_vivado_version, " puts -nonewline "got $VIVADO_VERSION.\n" } } else { if {[string compare $VIVADO_VERSION $required_vivado_version] != 0} { puts -nonewline "ERROR: vivado version mismatch; " puts -nonewline "expected $required_vivado_version, " puts -nonewline "got $VIVADO_VERSION.\n" puts -nonewline "This ERROR message can be down-graded to CRITICAL WARNING by setting ADI_IGNORE_VERSION_CHECK environment variable to 1. Be aware that ADI will not support you, if you are using a different tool version.\n" exit 2 } } if {$mode == 0} { set project_system_dir "${actual_project_name}.srcs/sources_1/bd/system" create_project ${actual_project_name} . -part $p_device -force } else { set project_system_dir "${actual_project_name}.srcs/sources_1/bd/system" create_project -in_memory -part $p_device } if {$mode == 1} { file mkdir ${actual_project_name}.data } if {$p_board ne "not-applicable"} { set_property board_part $p_board [current_project] } set lib_dirs $ad_hdl_dir/library if {[info exists ::env(ADI_GHDL_DIR)]} { if {$ad_hdl_dir ne $ad_ghdl_dir} { lappend lib_dirs $ad_ghdl_dir/library } } else { # puts -nonew-line "INFO: ADI_GHDL_DIR not defined.\n" } # Set a common IP cache for all projects if {$ADI_USE_OOC_SYNTHESIS == 1} { if {[file exists $ad_hdl_dir/ipcache] == 0} { file mkdir $ad_hdl_dir/ipcache } config_ip_cache -import_from_project -use_cache_location $ad_hdl_dir/ipcache } set_property ip_repo_paths $lib_dirs [current_fileset] update_ip_catalog ## Load custom message severity definitions if {![info exists ::env(ADI_DISABLE_MESSAGE_SUPPRESION)]} { source $ad_hdl_dir/projects/scripts/adi_xilinx_msg.tcl } ## In Vivado there is a limit for the number of warnings and errors which are ## displayed by the tool for a particular error or warning; the default value ## of this limit is 100. ## Overrides the default limit to 2000. set_param messaging.defaultLimit 2000 # Set parameters of the top level file # Make the same parameters available to system_bd.tcl set proj_params [get_property generic [current_fileset]] foreach {param value} $parameter_list { lappend proj_params $param=$value set ad_project_params($param) $value } set_property generic $proj_params [current_fileset] create_bd_design "system" source system_bd.tcl save_bd_design validate_bd_design if {$ADI_USE_OOC_SYNTHESIS == 1} { set_property synth_checkpoint_mode Hierarchical [get_files $project_system_dir/system.bd] } else { set_property synth_checkpoint_mode None [get_files $project_system_dir/system.bd] } generate_target {synthesis implementation} [get_files $project_system_dir/system.bd] if {$ADI_USE_OOC_SYNTHESIS == 1} { export_ip_user_files -of_objects [get_files $project_system_dir/system.bd] -no_script -sync -force -quiet create_ip_run [get_files $project_system_dir/system.bd] } make_wrapper -files [get_files $project_system_dir/system.bd] -top if {$mode == 0} { import_files -force -norecurse -fileset sources_1 $project_system_dir/hdl/system_wrapper.v } else { write_hwdef -file "${actual_project_name}.data/$project_name.hwdef" } if {$ADI_USE_INCR_COMP == 1} { if {[file exists ./reference.dcp]} { set_property incremental_checkpoint ./reference.dcp [get_runs impl_1] } } } ## Add source files to an exiting project. # # \param[project_name] - name of the project # \param[project_files] - list of project files # proc adi_project_files {project_name project_files} { foreach pfile $project_files { if {[string range $pfile [expr 1 + [string last . $pfile]] end] == "xdc"} { add_files -norecurse -fileset constrs_1 $pfile } elseif [regexp "_constr.tcl" $pfile] { add_files -norecurse -fileset sources_1 $pfile } else { add_files -norecurse -fileset sources_1 $pfile } } # NOTE: top file name is always system_top set_property top system_top [current_fileset] } ## Run an existing project (generate bit stream). # # \param[project_name] - name of the project # proc adi_project_run {project_name} { global ad_project_dir global ADI_POWER_OPTIMIZATION global ADI_USE_OOC_SYNTHESIS global ADI_MAX_OOC_JOBS if {![info exists ::env(ADI_PROJECT_DIR)]} { set actual_project_name $project_name set ad_project_dir "" } else { set actual_project_name "$::env(ADI_PROJECT_DIR)${project_name}" set ad_project_dir "$::env(ADI_PROJECT_DIR)" } if {$ADI_USE_OOC_SYNTHESIS == 1} { launch_runs -jobs $ADI_MAX_OOC_JOBS system_*_synth_1 synth_1 } else { launch_runs synth_1 } wait_on_run synth_1 open_run synth_1 report_timing_summary -file ${ad_project_dir}timing_synth.log if {![info exists ::env(ADI_NO_BITSTREAM_COMPRESSION)] && ![info exists ADI_NO_BITSTREAM_COMPRESSION]} { set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design] } if {$ADI_POWER_OPTIMIZATION == 1} { set_property STEPS.POWER_OPT_DESIGN.IS_ENABLED true [get_runs impl_1] set_property STEPS.POST_PLACE_POWER_OPT_DESIGN.IS_ENABLED true [get_runs impl_1] } set_param board.repoPaths [get_property LOCAL_ROOT_DIR [xhub::get_xstores xilinx_board_store]] launch_runs impl_1 -to_step write_bitstream wait_on_run impl_1 open_run impl_1 report_timing_summary -warn_on_violation -file ${ad_project_dir}timing_impl.log if {[info exists ::env(ADI_GENERATE_UTILIZATION)]} { set csv_file ${ad_project_dir}resource_utilization.csv if {[ catch { xilinx::designutils::report_failfast -csv -file $csv_file -transpose -no_header -ignore_pr -quiet set MMCM [llength [get_cells -hierarchical -filter { PRIMITIVE_TYPE =~ *MMCM* }]] set PLL [llength [get_cells -hierarchical -filter { PRIMITIVE_TYPE =~ *PLL* }]] set worst_slack_setup [get_property SLACK [get_timing_paths -setup]] set worst_slack_hold [get_property SLACK [get_timing_paths -hold]] set fileRead [open $csv_file r] set lines [split [read $fileRead] "\n"] set names_line [lindex $lines end-3] set values_line [lindex $lines end-2] close $fileRead set fileWrite [open $csv_file w] puts $fileWrite "$names_line,MMCM*,PLL*,Worst_Setup_Slack,Worst_Hold_Slack" puts $fileWrite "$values_line,$MMCM,$PLL,$worst_slack_setup,$worst_slack_hold" close $fileWrite } issue ] != 0 } { puts "GENERATE_REPORTS: tclapp::xilinx::designutils not installed" } # Define a list of IPs for which to generate report utilization set IP_list { ad_ip_jesd_204_tpl_adc ad_ip_jesd_204_tpl_dac axi_jesd204_rx axi_jesd204_tx jesd204_rx jesd204_tx axi_adxcvr util_adxcvr axi_dmac util_cpack2 util_upack2 } foreach IP_name $IP_list { set output_file ${ad_project_dir}${IP_name}_resource_utilization.log file delete $output_file foreach IP_instance [ get_cells -quiet -hierarchical -filter " ORIG_REF_NAME =~ $IP_name || REF_NAME =~ $IP_name " ] { report_utilization -hierarchical -hierarchical_depth 1 -cells $IP_instance -file $output_file -append -quiet report_property $IP_instance -file $output_file -append -quiet set report_file [ open $output_file a ] puts $report_file "\n\n\n" close $report_file } } } else { puts "GENERATE_REPORTS: Resource utilization files won't be generated because ADI_GENERATE_UTILIZATION env var is not set" } if {[info exists ::env(ADI_GENERATE_XPA)]} { set csv_file ${ad_project_dir}power_analysis.csv set Layers "8to11" set CapLoad "20" set ToggleRate "15.00000" set StatProb "0.500000" set_load $CapLoad [all_outputs] set_operating_conditions -board_layers $Layers set_switching_activity -default_toggle_rate $ToggleRate set_switching_activity -default_static_probability $StatProb set_switching_activity -type lut -toggle_rate $ToggleRate -static_probability $StatProb -all set_switching_activity -type register -toggle_rate $ToggleRate -static_probability $StatProb -all set_switching_activity -type shift_register -toggle_rate $ToggleRate -static_probability $StatProb -all set_switching_activity -type lut_ram -toggle_rate $ToggleRate -static_probability $StatProb -all set_switching_activity -type bram -toggle_rate $ToggleRate -static_probability $StatProb -all set_switching_activity -type dsp -toggle_rate $ToggleRate -static_probability $StatProb -all set_switching_activity -type gt_rxdata -toggle_rate $ToggleRate -static_probability $StatProb -all set_switching_activity -type gt_txdata -toggle_rate $ToggleRate -static_probability $StatProb -all set_switching_activity -type io_output -toggle_rate $ToggleRate -static_probability $StatProb -all set_switching_activity -type bram_enable -toggle_rate $ToggleRate -static_probability $StatProb -all set_switching_activity -type bram_wr_enable -toggle_rate $ToggleRate -static_probability $StatProb -all set_switching_activity -type io_bidir_enable -toggle_rate $ToggleRate -static_probability $StatProb -all report_power -file $csv_file set fileRead [open $csv_file r] set filecontent [read $fileRead] set input_list [split $filecontent "\n"] set TextList [lsearch -all -inline $input_list "*Total On-Chip Power (W)*"] set on_chip_pwr "[lindex [lindex $TextList 0] 6] W" set TextList [lsearch -all -inline $input_list "*Junction Temperature (C)*"] set junction_temp "[lindex [lindex $TextList 0] 5] *C" close $fileRead set fileWrite [open $csv_file w] puts $fileWrite "On-chip_power,Junction_temp" puts $fileWrite "$on_chip_pwr,$junction_temp" close $fileWrite } else { puts "GENERATE_REPORTS: Power analysis files won't be generated because ADI_GENERATE_XPA env var is not set" } # Look for undefined clocks which do not show up in the timing summary set timing_check [check_timing -override_defaults no_clock -no_header -return_string] if {[regexp { (\d+) register} $timing_check -> num_regs]} { if {[info exist num_regs]} { if {$num_regs > 0} { puts "CRITICAL WARNING: There are $num_regs registers with no clocks !!! See no_clock.log for details." check_timing -override_defaults no_clock -verbose -file ${ad_project_dir}no_clock.log } } } else { puts "CRITICAL WARNING: The search for undefined clocks failed !!!" } file mkdir ${actual_project_name}.sdk set timing_string $[report_timing_summary -return_string] if { [string match "*VIOLATED*" $timing_string] == 1 || [string match "*Timing constraints are not met*" $timing_string] == 1} { write_hw_platform -fixed -force -include_bit -file ${actual_project_name}.sdk/system_top_bad_timing.xsa return -code error [format "ERROR: Timing Constraints NOT met!"] } else { write_hw_platform -fixed -force -include_bit -file ${actual_project_name}.sdk/system_top.xsa } } ## Run synthesis on an partial design; use it in Partial Reconfiguration flow. # # \param[project_name] - project name # \param[prcfg_name] - name of the partial design # \param[hdl_files] - hdl source of the partial design # \param[xdc_files] - XDC constraint source of the partial design # proc adi_project_synth {project_name prcfg_name hdl_files {xdc_files ""}} { global p_device global ad_project_dir if {![info exists ::env(ADI_PROJECT_DIR)]} { set actual_project_name $project_name } else { set actual_project_name "$::env(ADI_PROJECT_DIR)${project_name}" } set p_prefix "${actual_project_name}.data/$project_name" if {$prcfg_name eq ""} { read_verilog .srcs/sources_1/bd/system/hdl/system_wrapper.v read_verilog $hdl_files read_xdc $xdc_files synth_design -mode default -top system_top -part $p_device > $p_prefix.synth.rds write_checkpoint -force $p_prefix.synth.dcp close_project } else { create_project -in_memory -part $p_device read_verilog $hdl_files synth_design -mode out_of_context -top "prcfg" -part $p_device > $p_prefix.${prcfg_name}_synth.rds write_checkpoint -force $p_prefix.${prcfg_name}_synth.dcp close_project } } ## Run implementation on an partial design; use it in Partial Reconfiguration # flow. # # \param[project_name] - project name # \param[prcfg_name] - name of the partial design # \param[xdc_files] - XDC constraint source of the partial design # proc adi_project_impl {project_name prcfg_name {xdc_files ""}} { global p_device global p_prcfg_init global p_prcfg_list global p_prcfg_status global ad_project_dir if {![info exists ::env(ADI_PROJECT_DIR)]} { set actual_project_name $project_name } else { set actual_project_name "$::env(ADI_PROJECT_DIR)${project_name}" } set p_prefix "${actual_project_name}.data/$project_name" if {$prcfg_name eq "default"} { set p_prcfg_status 0 set p_prcfg_list "" set p_prcfg_init "$p_prefix.${prcfg_name}_impl.dcp" file mkdir $project_name.sdk } if {$prcfg_name eq "default"} { open_checkpoint $p_prefix.synth.dcp -part $p_device read_xdc $xdc_files read_checkpoint -cell i_prcfg $p_prefix.${prcfg_name}_synth.dcp set_property HD.RECONFIGURABLE 1 [get_cells i_prcfg] opt_design > $p_prefix.${prcfg_name}_opt.rds write_debug_probes -force $p_prefix.${prcfg_name}_debug_nets.ltx place_design > $p_prefix.${prcfg_name}_place.rds route_design > $p_prefix.${prcfg_name}_route.rds } else { open_checkpoint $p_prefix.default_impl_bb.dcp -part $p_device lock_design -level routing read_checkpoint -cell i_prcfg $p_prefix.${prcfg_name}_synth.dcp read_xdc $xdc_files opt_design > $p_prefix.${prcfg_name}_opt.rds place_design > $p_prefix.${prcfg_name}_place.rds route_design > $p_prefix.${prcfg_name}_route.rds } write_checkpoint -force $p_prefix.${prcfg_name}_impl.dcp report_utilization -pblocks pb_prcfg -file $p_prefix.${prcfg_name}_utilization.rpt report_timing_summary -file $p_prefix.${prcfg_name}_timing_summary.rpt if [expr [get_property SLACK [get_timing_paths]] < 0] { set p_prcfg_status 1 puts "CRITICAL WARNING: Timing Constraints NOT met ($prcfg_name)!" } write_checkpoint -force -cell i_prcfg $p_prefix.${prcfg_name}_prcfg_impl.dcp update_design -cell i_prcfg -black_box write_checkpoint -force $p_prefix.${prcfg_name}_impl_bb.dcp open_checkpoint $p_prefix.${prcfg_name}_impl.dcp -part $p_device write_bitstream -force -bin_file -file $p_prefix.${prcfg_name}.bit write_sysdef -hwdef $p_prefix.hwdef -bitfile $p_prefix.${prcfg_name}.bit -file $p_prefix.${prcfg_name}.hdf file copy -force $p_prefix.${prcfg_name}.hdf $project_name.sdk/system_top.${prcfg_name}.hdf if {$prcfg_name ne "default"} { lappend p_prcfg_list "$p_prefix.${prcfg_name}_impl.dcp" } if {$prcfg_name eq "default"} { file copy -force $p_prefix.${prcfg_name}.hdf $project_name.sdk/system_top.hdf } } ## Verify an implemented partial reconfiguration design, checks if all the # partial design are compatible with the base design. # # \param[project_name] - project name # proc adi_project_verify {project_name} { # checkpoint for the default design global p_prcfg_init # list of checkpoints with all the PRs integrated into the default design global p_prcfg_list global p_prcfg_status set p_prefix "${actual_project_name}.data/$project_name" pr_verify -full_check -initial $p_prcfg_init \ -additional $p_prcfg_list \ -file $p_prefix.prcfg_verify.log if {$p_prcfg_status == 1} { return -code error [format "ERROR: Timing Constraints NOT met!"] } }