diff --git a/projects/adrv9361z7035/ccbob_cmos/system_project.tcl b/projects/adrv9361z7035/ccbob_cmos/system_project.tcl index 99a8e2e7d1..6b38f48e34 100644 --- a/projects/adrv9361z7035/ccbob_cmos/system_project.tcl +++ b/projects/adrv9361z7035/ccbob_cmos/system_project.tcl @@ -6,7 +6,7 @@ source ../../../scripts/adi_env.tcl source $ad_hdl_dir/projects/scripts/adi_project_xilinx.tcl source $ad_hdl_dir/projects/scripts/adi_board.tcl -set ADI_POST_ROUTE_POD_PRE_SCRIPT [file normalize $ad_hdl_dir/projects/scripts/route_design.tcl] +set ADI_POST_ROUTE_SCRIPT [file normalize $ad_hdl_dir/projects/scripts/auto_timing_fix_xilinx.tcl] adi_project_create adrv9361z7035_ccbob_cmos 0 {} "xc7z035ifbg676-2L" adi_project_files adrv9361z7035_ccbob_cmos [list \ diff --git a/projects/adrv9361z7035/ccbob_lvds/system_project.tcl b/projects/adrv9361z7035/ccbob_lvds/system_project.tcl index 6bac5d4b92..5a610cdd64 100644 --- a/projects/adrv9361z7035/ccbob_lvds/system_project.tcl +++ b/projects/adrv9361z7035/ccbob_lvds/system_project.tcl @@ -6,7 +6,7 @@ source ../../../scripts/adi_env.tcl source $ad_hdl_dir/projects/scripts/adi_project_xilinx.tcl source $ad_hdl_dir/projects/scripts/adi_board.tcl -set ADI_POST_ROUTE_POD_PRE_SCRIPT [file normalize $ad_hdl_dir/projects/scripts/route_design.tcl] +set ADI_POST_ROUTE_SCRIPT [file normalize $ad_hdl_dir/projects/scripts/auto_timing_fix_xilinx.tcl] adi_project_create adrv9361z7035_ccbob_lvds 0 {} "xc7z035ifbg676-2L" adi_project_files adrv9361z7035_ccbob_lvds [list \ diff --git a/projects/adrv9361z7035/ccfmc_lvds/system_project.tcl b/projects/adrv9361z7035/ccfmc_lvds/system_project.tcl index de0daaa80c..15af032ff8 100644 --- a/projects/adrv9361z7035/ccfmc_lvds/system_project.tcl +++ b/projects/adrv9361z7035/ccfmc_lvds/system_project.tcl @@ -6,7 +6,7 @@ source ../../../scripts/adi_env.tcl source $ad_hdl_dir/projects/scripts/adi_project_xilinx.tcl source $ad_hdl_dir/projects/scripts/adi_board.tcl -set ADI_POST_ROUTE_POD_PRE_SCRIPT [file normalize $ad_hdl_dir/projects/scripts/route_design.tcl] +set ADI_POST_ROUTE_SCRIPT [file normalize $ad_hdl_dir/projects/scripts/auto_timing_fix_xilinx.tcl] adi_project_create adrv9361z7035_ccfmc_lvds 0 {} "xc7z035ifbg676-2L" adi_project_files adrv9361z7035_ccfmc_lvds [list \ diff --git a/projects/adrv9364z7020/ccbob_cmos/system_project.tcl b/projects/adrv9364z7020/ccbob_cmos/system_project.tcl index ffc7fab585..1be83d1904 100644 --- a/projects/adrv9364z7020/ccbob_cmos/system_project.tcl +++ b/projects/adrv9364z7020/ccbob_cmos/system_project.tcl @@ -6,7 +6,7 @@ source ../../../scripts/adi_env.tcl source $ad_hdl_dir/projects/scripts/adi_project_xilinx.tcl source $ad_hdl_dir/projects/scripts/adi_board.tcl -set ADI_POST_ROUTE_POD_PRE_SCRIPT [file normalize $ad_hdl_dir/projects/scripts/route_design.tcl] +set ADI_POST_ROUTE_SCRIPT [file normalize $ad_hdl_dir/projects/scripts/auto_timing_fix_xilinx.tcl] adi_project_create adrv9364z7020_ccbob_cmos 0 {} "xc7z020clg400-1" adi_project_files adrv9364z7020_ccbob_cmos [list \ diff --git a/projects/adrv9364z7020/ccbob_lvds/system_project.tcl b/projects/adrv9364z7020/ccbob_lvds/system_project.tcl index d42462a17e..cf7adf5f5f 100644 --- a/projects/adrv9364z7020/ccbob_lvds/system_project.tcl +++ b/projects/adrv9364z7020/ccbob_lvds/system_project.tcl @@ -6,7 +6,7 @@ source ../../../scripts/adi_env.tcl source $ad_hdl_dir/projects/scripts/adi_project_xilinx.tcl source $ad_hdl_dir/projects/scripts/adi_board.tcl -set ADI_POST_ROUTE_POD_PRE_SCRIPT [file normalize $ad_hdl_dir/projects/scripts/route_design.tcl] +set ADI_POST_ROUTE_SCRIPT [file normalize $ad_hdl_dir/projects/scripts/auto_timing_fix_xilinx.tcl] adi_project_create adrv9364z7020_ccbob_lvds 0 {} "xc7z020clg400-1" adi_project_files adrv9364z7020_ccbob_lvds [list \ diff --git a/projects/scripts/auto_timing_fix_xilinx.tcl b/projects/scripts/auto_timing_fix_xilinx.tcl index 63f6ba14c2..61ff86a3e1 100644 --- a/projects/scripts/auto_timing_fix_xilinx.tcl +++ b/projects/scripts/auto_timing_fix_xilinx.tcl @@ -1,6 +1,6 @@ ############################################################################### ## Copyright (C) 2025 Analog Devices, Inc. All rights reserved. -### SPDX short identifier: ADIBSD +## SPDX short identifier: ADIBSD ############################################################################### # This script attempts to automatically fix timing violations after routing # using phys_opt_design. It will make multiple attempts up to a maximum number @@ -13,8 +13,98 @@ # in nanoseconds. For example, a threshold of -1.0 means that only violations # where "0 > WNS > -1.0 ns" will be automatically fixed. # -puts "INFO: starting auto timing fix (ATF)..." -set attempt 0 +# If after all ATF attempts a HOLD violation persists, route_design is called +# and the ATF loop is re-run. +# + +# ATF loop function +# Arguments: +# prefix - string prefix for checkpoint and log file names +# max_attempts - maximum number of fix attempts +# wns_threshold - WNS threshold for automatic fix (should be negative) +# Returns a list: {status final_wns delay_type attempts_made} +# status: "success", "failure", "no_paths", "no_violations", "threshold_exceeded", "unknown_type" +proc run_atf_loop {prefix max_attempts wns_threshold} { + set attempt 0 + set status "unknown" + set final_wns 0.0 + + write_checkpoint -force "${prefix}_before_system_top_placed.dcp" + + while {$attempt < $max_attempts} { + # Get the single worst timing path object in the design + set worst_path [get_timing_paths -nworst 1 -max_paths 1 -delay_type min_max] + if {[llength $worst_path] == 0} { + set status "no_paths" + break + } + set wns [get_property SLACK $worst_path] + set delay_type [get_property DELAY_TYPE $worst_path] ;# Returns "max" for Setup, "min" for Hold + + if {$wns >= 0.0} { + set status "success" + set final_wns $wns + break + } + + # Check if autofix should be attempted based on WNS threshold + if {$wns > $wns_threshold} { + incr attempt + puts "INFO: ATF: \[$prefix\] WNS = ${wns} ns of type $delay_type. Attempting automatic fix (${attempt} of ${max_attempts})." + report_timing_summary -delay_type min_max -max_paths 5 -nworst 1 -file "${prefix}_${attempt}_before_timing_summary.txt" + } else { + set status "threshold_exceeded" + set final_wns $wns + break + } + + # Attempt fix via phys_opt_design + if {$delay_type eq "min"} { + phys_opt_design -hold_fix + } elseif {$delay_type eq "max"} { + phys_opt_design + } else { + puts "ERROR: ATF: \[$prefix\] Unknown path type '${delay_type}'. Aborting automatic fix." + set status "unknown_type" + set final_wns $wns + break + } + + # Update final values after each attempt + set final_wns $wns + } + + # Get final timing status after loop + set worst_path [get_timing_paths -nworst 1 -max_paths 1 -delay_type min_max] + if {[llength $worst_path] > 0} { + set final_wns [get_property SLACK $worst_path] + set delay_type [get_property DELAY_TYPE $worst_path] + if {$final_wns >= 0.0} { + set status "success" + } + } + + report_timing_summary -delay_type min_max -max_paths 5 -nworst 1 -file "${prefix}_${attempt}_final_timing_summary.txt" + + # Write appropriate checkpoint based on status + if {$status eq "success"} { + puts "INFO: ATF: \[$prefix\] Auto Timing Fix SUCCESS after ${attempt} attempts - final WNS is ${final_wns} ns." + write_checkpoint -force "${prefix}_success_system_top_placed.dcp" + } elseif {$status eq "no_paths"} { + puts "ERROR: ATF: \[$prefix\] No constrained timing paths found." + } elseif {$status eq "threshold_exceeded"} { + puts "WARNING: ATF: \[$prefix\] WNS (${final_wns} ns) exceeds threshold (${wns_threshold} ns). Automatic fix aborted." + write_checkpoint -force "${prefix}_aborted_system_top_placed.dcp" + } else { + puts "WARNING: ATF: \[$prefix\] Auto Timing Fix FAILURE after ${attempt} attempts - final WNS is ${final_wns} ns." + write_checkpoint -force "${prefix}_failure_system_top_placed.dcp" + } + + return [list $status $final_wns $delay_type $attempt] +} + +# Main script execution -------------------------------------------------------- +puts "INFO: starting Auto Timing Fix (ATF)..." # Set default values if not provided if {![info exists ADI_AUTOFIX_WNS_THRESHOLD]} { @@ -26,56 +116,47 @@ if {![info exists ADI_AUTOFIX_MAX_ATTEMPTS]} { puts "INFO: ATF: ADI_AUTOFIX_MAX_ATTEMPTS not set, using default of $ADI_AUTOFIX_MAX_ATTEMPTS" } -write_checkpoint -force "AutoTimingFix_before_system_top_placed.dcp" -while {$attempt < $ADI_AUTOFIX_MAX_ATTEMPTS} { - # Get the single worst timing path object in the design - set worst_path [get_timing_paths -nworst 1 -max_paths 1 -delay_type min_max] - if {[llength $worst_path] == 0} { break } ; # No paths found +# Run first stage of ATF +puts "INFO: ATF: Starting Stage 1..." +set result [run_atf_loop "ATF_Stage1" $ADI_AUTOFIX_MAX_ATTEMPTS $ADI_AUTOFIX_WNS_THRESHOLD] + +# Check if we need to call route_design and retry +# Only do this if: +# 1. Timing was not fixed +# 2. The remaining violation is HOLD type (delay_type == "min") +# +# NOTE: This route_design workaround addresses hold timing issues that appear in +# Vivado 2024.x/2025.x where phys_opt_design -hold_fix alone is insufficient. +# This remedy was suggested by an AMD employee through the Xilinx forums. +# References: +# https://adaptivesupport.amd.com/s/question/0D5Pd00000pVOyuKAG/unexpected-hold-errors-when-moving-to-vivado-20251?language=en_US +# https://adaptivesupport.amd.com/s/question/0D5Pd0000153gqkKAA/persistent-hold-timing-violations-after-upgrading-to-vivado-2025x-physoptdesign-holdfix-ineffective?language=en_US +# +# Get the single worst timing path object in the design +set worst_path [get_timing_paths -nworst 1 -max_paths 1 -delay_type min_max] +if {[llength $worst_path] > 0} { set wns [get_property SLACK $worst_path] - if {${wns} >= 0.0} { break } ; # No violations remain set delay_type [get_property DELAY_TYPE $worst_path] ;# Returns "max" for Setup, "min" for Hold - # Check if autofix should attempt based on WNS threshold - if {$wns > $ADI_AUTOFIX_WNS_THRESHOLD} { - incr attempt - puts "INFO: ATF: WNS = ${wns} ns of type $delay_type. Attempting automatic fix (${attempt} of ${ADI_AUTOFIX_MAX_ATTEMPTS})." - report_timing_summary -delay_type min_max -max_paths 5 -nworst 1 -file "AutoTimingFix_${attempt}_before_timing_summary.txt" - } else { - break ; # Abort automatic fix due to WNS threshold - } - # Attempt fix via phys_opt_design - if {$delay_type eq "min"} { - phys_opt_design -hold_fix - } elseif {$delay_type eq "max"} { - phys_opt_design - } else { - puts "ERROR: ATF: Unknown path type '${delay_type}'. Aborting automatic fix." - break + if {$wns < 0.0} { + if {$delay_type eq "min"} { + puts "INFO: ATF: HOLD violation persists after Stage 1. Calling route_design (Vivado 2024.x/2025.x workaround)..." + route_design + puts "INFO: ATF: route_design completed. Starting Stage 2..." + set result [run_atf_loop "ATF_Stage2" $ADI_AUTOFIX_MAX_ATTEMPTS $ADI_AUTOFIX_WNS_THRESHOLD] + } } } -report_timing_summary -delay_type min_max -max_paths 5 -nworst 1 -file "AutoTimingFix_${attempt}_final_timing_summary.txt" - -# Print a final report -if {[llength $worst_path] == 0} { - # Loop broke early due to no paths found - puts "ERROR: ATF: No constrained timing paths found. Exiting." -} elseif {${attempt} == 0 && ${wns} >= 0.0} { - # Loop broke early due to no violations on first check - puts "INFO: ATF: No timing violations detected on first check. No action required." -} else { - # Loop broke after at least one attempt - set worst_path [get_timing_paths -nworst 1 -max_paths 1 -delay_type min_max] - set final_wns [get_property SLACK $worst_path] - if {$final_wns >= 0} { - puts "INFO: ATF: auto timing fix SUCCESS after ${attempt} attempts - final WNS is ${final_wns} ns." - write_checkpoint -force "AutoTimingFix_success_system_top_placed.dcp" - } elseif {$final_wns <= $ADI_AUTOFIX_WNS_THRESHOLD} { - puts "WARNING: ATF: WNS (${wns} ns) exceeds threshold (${ADI_AUTOFIX_WNS_THRESHOLD} ns). Automatic fix aborted." - write_checkpoint -force "AutoTimingFix_aborted_system_top_placed.dcp" +# Print final summary for Jenkins pipeline +set worst_path [get_timing_paths -nworst 1 -max_paths 1 -delay_type min_max] +if {[llength $worst_path] > 0} { + set wns [get_property SLACK $worst_path] + set delay_type [get_property DELAY_TYPE $worst_path] ;# Returns "max" for Setup, "min" for Hold + puts "INFO: ATF: final WNS is ${wns} ns of type ${delay_type}." + if {$wns < 0.0} { + puts "WARNING: ATF: Auto Timing Fix FAILURE. Timing closure is NOT achieved." } else { - puts "WARNING: ATF: auto timing fix FAILURE after ${attempt} attempts - final WNS is ${final_wns} ns." - write_checkpoint -force "AutoTimingFix_failure_system_top_placed.dcp" + puts "INFO: ATF: Auto Timing Fix SUCCESS. Timing closure IS achieved." } } - -puts "INFO: auto timing fix (ATF) finished." +puts "INFO: ATF: Auto Timing Fix finished." diff --git a/projects/scripts/route_design.tcl b/projects/scripts/route_design.tcl deleted file mode 100644 index 2b078064a4..0000000000 --- a/projects/scripts/route_design.tcl +++ /dev/null @@ -1,7 +0,0 @@ -# This script is used to fix some hold timing issues presented in more recent -# versions of vivado. This remedy was given by AMD employee through the xilinx -# forums. -# References: -# https://adaptivesupport.amd.com/s/question/0D5Pd00000pVOyuKAG/unexpected-hold-errors-when-moving-to-vivado-20251?language=en_US -# https://adaptivesupport.amd.com/s/question/0D5Pd0000153gqkKAA/persistent-hold-timing-violations-after-upgrading-to-vivado-2025x-physoptdesign-holdfix-ineffective?language=en_US -route_design