cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Highlighted
Scholar
Scholar
367 Views
Registered: ‎06-20-2017

Feeback: Constraint wizard is *still* rewriting non-target XDC files! This is a huge bug and should be made a higher priority

The constraint wizard is still rewriting non-target constraint files, turning [expr $val1 + $val2] into magic numbers, removing end of line xdc comments "; # This will be removed by the constraint wizard".

 

This is a huge no-no, and it should be fixed.  I reported this previously here:  https://forums.xilinx.com/t5/Timing-Analysis/Constraints-wizard-rewrites-all-constraints/td-p/852556

 

That submission that could only benefit Xilinx had zero responses from the forum moderators.  You would think somebody would notice, since that other post was submitted in April of 2018, more than two years ago.

No warnings that the constraints wizard will turn well structured XDC into magic numbers while removing comments. 

Please fix this *BUG*.

0 Kudos
2 Replies
Highlighted
Guide
Guide
344 Views
Registered: ‎01-23-2009

I agree that this behavior is frustrating, and, in an ideal world, not what you would want the tools to do. However, it is the "expected" behavior and isn't technically a "bug" (and hence won't be "fixed").

You have to understand the fairly bizarre problem Xilinx has created with all this "constraint management" stuff. XDC which is derived from SDC is a set of constraining and object management commands that are written in Tcl syntax - they are a script. As each command is executed, it makes some annotations or changes to the design database that reflect the effect of the command; creating new objects (like clocks) or adding new timing relationships (like input and output delay characteristics) or changing the behavior of certain paths (timing exceptions). These are described with a pretty sophisticated syntax that allows you to do all this stuff flexibly; including traversing connectivity of the netlist, setting and modifying properties of the netlist as well as using all the syntax from Tcl which is underlying it all. Once a constraint command is executed in a "traditional" usage (like Synopsys Design Compiler and, to a certain extent, in non-project mode of Vivado) the command no longer needs to exist; the underlying netlist has been modified, the text command that made this modification is done and is no longer needed.

As a scripting language, it works exactly as intended.

However, in order to make Vivado more user friendly, Xilinx added the entire concept of the "project" and added all kinds of mechanisms for managing and creating these projects. As part of this, the concept of "constraint management" had to be added - this was required not only to enable the graphical helpers for creating and viewing constraints, but also for a lot of the underlying concepts of the "project". To do this, the constraint commands need to be more than just Tcl commands that are executed and affect the underlying netlist and are then discarded, they need to be things unto themselves that need to be tracked.

This leads to a dichotomy - are constraint commands "things in a constraint database" or "Tcl scripts to be executed". For all of this to work, they need to be both. And that is where the problems come in.

In order to enable the concept of the project and the graphical helpers, Xilinx introduced the concept of the "constraint database". This is something tracked by the tool - as each constraint related command is executed, and its effects are applied to the design, the constraint command is also "memorized" by the tool; it is put into the constraint database. This database can be viewed through the constraint window and manipulated through the various mechanisms (and this is important) - through the various graphical helpers or through commands entered on the Tcl command line or through scripts.

But the constraint commands themselves (things like create_clock, set_input_delay, set_false_paths) are only a small part of the Tcl syntax; the constraint database cannot store the entire script - it stores the individual constraint commands - not all the stuff around them. So when you create a variable and use that variable as part of the set_input_delay command only the constraint command itself is stored in the design database; the variable is (actually was) expanded by the Tcl parser before it was passed to the constraint subsystem (Actually this isn't always true, Xilinx does make some attempts to preserve some variable usage, but it can't do everything). This works fine for most parts of the flow.

The problem comes in when this constraint database needs to be fully or at least partially written back to some file or files, which is needed if the constraints are modified and the project closed. The only place these constraints can go are the XDC file. Since only the constraint commands themselves were stored, the original source of the command cannot be completely reproduced - Xilinx tries, but as you have seen, expressions get expanded, comments get moved or deleted, loops even get unrolled. This is not desirable, but is pretty much unavoidable.

Furthermore, this idea that "the tools can only write to the target constraint file" is not true. The target constraint file is where the tool will put any new constraints that have been created, but, unfortunately, it can't be "the only file the tools can modify". Remember, XDC/SDC files are not a database language, they are in a scripting language. Order matters; so if you change an existing constraint, the tools pretty much have to put it back in place of the original constraints. Furthermore, some constraints can't be "undone" - if you have a set_false_path in an XDC script, there is nothing you can do to "unset" the false path (through the XDC language). So if, through one of the helpers, you remove an existing set_false_path command, the tools must modify the XDC file where the set_false_path command was, regardless as to whether that set_false_path command was in the target XDC file or not - there simply is no other choice.

So, yes, this does result in some undesirable consequences - the ones that you have mentioned. But it is a necessary evil - it is not a "bug". The only solution is to never let Vivado save any constraints. Use the visualization and analysis tools all you want. You can even use the helpers to help you find appropriate XDC syntax for commands, but never let the tool save them. All commands (no matter how they are created) end up in the Tcl console; you can manually copy them from there to wherever you want, in whatever format you want (using an external text editor). But once you are done, close the design and don't save the constraints. Saving the constraints will change your XDC files (and not just the target one).

Avrum

Highlighted
Scholar
Scholar
305 Views
Registered: ‎06-20-2017

Thank you for the thoughtful response, @avrumw.  I know you like to share knowledge, and also know from this response and others that you put a lot of thought into these posts.  

But I am philosophically disagreeing with the Xilinx rationalizations of bad design.   So don't take my harsh response as directed toward you, just the ideas you're valiantly defending. 

1.  The timing constraint editor doesn't rewrite other unrelated constraints, just the constraint wizard has this bug feature.

2.  Regarding "Since only the constraint commands themselves were stored..." That is a design defect and bad engineering, or what I call a bug.  This feature is made worse by the fact that it may have been intentional.  Or it may have been justified after the fact, but the reality is somebody was not thinking empathetically about their victims customers, and nobody cares enough to fix this bad behavior even after two years.  Thanks to computer science, data structure, and database magic, Xilinx has already demonstrated it knows where each primitive comes from, and can trace it to which line of HDL it originates from, within Vivado.  So they know how to solve this type of problem (as do most computer science graduates who take pride in their work). 

3.  It is plain and simple *bad* engineering to modify unrelated constraints, sad that it is unaddressed after two years, and worse to do so without warning.

 

newtarget.png

 

The following is a non target constraint file sabotaged by the constraints wizard when using the constraints wizard to create a generated clock constraint for a forwarded clock:

Before sabotage:

# #########################################################
# INPUT delay timing
# #########################################################
# Oscillator to FPGA clock PCB time delays
set US_FD 0.180 ;                                                # in nS/inch
set OSC2FPGA_TraceLenMin 1.0 ;                                   # in inches
set OSC2FPGA_TraceLenMax 1.5 ;                                   # in inches
set OSC2FPGA_TraceDlyMin [expr $US_FD * $OSC2FPGA_TraceLenMin] ; # in nS
set OSC2FPGA_TraceDlyMax [expr $US_FD * $OSC2FPGA_TraceLenMax] ; # in nS
# Set the clock latency of the clock at the FPGA pad (port in SDC speak)
set_clock_latency -min -source $OSC2FPGA_TraceDlyMin [get_clocks -of_objects [get_ports iCLK]]
set_clock_latency -max -source $OSC2FPGA_TraceDlyMax [get_clocks -of_objects [get_ports iCLK]]

# Create a virtual clock for the upstream device
set US_PERIOD   [get_property period   [get_clocks -of_objects [get_ports iCLK]]]
set US_WAVEFORM [get_property waveform [get_clocks -of_objects [get_ports iCLK]]]
create_clock -period $US_PERIOD -name VIRT_US_CLK_obj -waveform $US_WAVEFORM
# Oscillator to upstream device PCB time delays
set US_FD 0.180 ;                                                  # in nS/inch
set OSC2USDEV_TraceLenMin 2.0 ;                                    # in inches
set OSC2USDEV_TraceLenMax 2.5 ;                                    # in inches
set OSC2USDEV_TraceDlyMin [expr $US_FD * $OSC2USDEV_TraceLenMin] ; # in nS
set OSC2USDEV_TraceDlyMax [expr $US_FD * $OSC2USDEV_TraceLenMax] ; # in nS
# Set clock latench of virtual clock at the upstream device
set_clock_latency -min -source $OSC2USDEV_TraceDlyMin [get_clocks VIRT_US_CLK_obj]
set_clock_latency -max -source $OSC2USDEV_TraceDlyMax [get_clocks VIRT_US_CLK_obj]

# Upstream device to FPGA time delays
set USDEV2FPGA_FD          0.180                                           ; # in nS/inch
set USDEV2FPGA_TraceLenMin 2.0                                             ; # in inches
set USDEV2FPGA_TraceLenMax 2.5                                             ; # in inches
set USDEV2FPGA_TraceDlyMin [expr $USDEV2FPGA_FD * $USDEV2FPGA_TraceLenMin] ; # in nS
set USDEV2FPGA_TraceDlyMax [expr $USDEV2FPGA_FD * $USDEV2FPGA_TraceLenMax] ; # in nS
# Clock to out of upstream device (from datasheet)
set tcko_usdev_min   0.0
set tcko_usdev_max   0.3
# Input delays
set_input_delay -clock [get_clocks VIRT_US_CLK_obj] -min [expr $tcko_usdev_min + $USDEV2FPGA_TraceDlyMin] [get_ports iA]
set_input_delay -clock [get_clocks VIRT_US_CLK_obj] -max [expr $tcko_usdev_max + $USDEV2FPGA_TraceDlyMax] [get_ports iA]
set_input_delay -clock [get_clocks VIRT_US_CLK_obj] -min [expr $tcko_usdev_min + $USDEV2FPGA_TraceDlyMin] [get_ports iB]
set_input_delay -clock [get_clocks VIRT_US_CLK_obj] -max [expr $tcko_usdev_max + $USDEV2FPGA_TraceDlyMax] [get_ports iB]
set_input_delay -clock [get_clocks VIRT_US_CLK_obj] -min [expr $tcko_usdev_min + $USDEV2FPGA_TraceDlyMin] [get_ports iSel]
set_input_delay -clock [get_clocks VIRT_US_CLK_obj] -max [expr $tcko_usdev_max + $USDEV2FPGA_TraceDlyMax] [get_ports iSel]

After sabotage:

# #########################################################
# INPUT delay timing
# #########################################################
# Oscillator to FPGA clock PCB time delays
# Set the clock latency of the clock at the FPGA pad (port in SDC speak)
set_clock_latency -min -source 0.180 [get_clocks -of_objects [get_ports iCLK]]
set_clock_latency -max -source 0.270 [get_clocks -of_objects [get_ports iCLK]]

# Create a virtual clock for the upstream device
create_clock -period 5.000 -name VIRT_US_CLK_obj -waveform {0.000 2.500}
# Oscillator to upstream device PCB time delays
# Set clock latench of virtual clock at the upstream device
set_clock_latency -min -source 0.360 [get_clocks VIRT_US_CLK_obj]
set_clock_latency -max -source 0.450 [get_clocks VIRT_US_CLK_obj]

# Upstream device to FPGA time delays
# Clock to out of upstream device (from datasheet)
# Input delays
set_input_delay -clock [get_clocks VIRT_US_CLK_obj] -min 0.360 [get_ports iA]
set_input_delay -clock [get_clocks VIRT_US_CLK_obj] -max 0.750 [get_ports iA]
set_input_delay -clock [get_clocks VIRT_US_CLK_obj] -min 0.360 [get_ports iB]
set_input_delay -clock [get_clocks VIRT_US_CLK_obj] -max 0.750 [get_ports iB]
set_input_delay -clock [get_clocks VIRT_US_CLK_obj] -min 0.360 [get_ports iSel]
set_input_delay -clock [get_clocks VIRT_US_CLK_obj] -max 0.750 [get_ports iSel]

 The target constraint file got this:

 

create_generated_clock -name oCLK -source [get_pins ODDR_U0/CLKDIV] -divide_by 1 [get_ports oCLK]

 

0 Kudos