cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Highlighted
Observer
Observer
700 Views
Registered: ‎09-30-2019

apply set_false_path to registers between different clocks using name wildcard

Hello,

I'm developing several IP cores where signals are clocked by logic_clock and a local bus port is used to read/write registers, which is clocked by lb_clock.
Of course in some points register vectors will cross clock domains, so some synchronization / metastability safe logic is needed.
In some case however the design including the IP could use the same clock for both logic_clock and lb_clock.

On a general case, when data_SLV must cross clock domains, to avoid wrong values being improperly sampled,
data_SLV is stored to data_SLV_storage and a single bit signal is toggled with source clock, then toggle is resampled / edge detected with destination clock, so data_SLV_storage can be sampled when it is stable.

In this way data_SLV_storage is sampled when it's stable, there's no metastability risk, and a simple set_false_path can be enough.

I want an .xdc with a very generic set_false_path, adding the timing ignore constraint to every register named *_TIG in VHDL code,
crossing between logic_clock and lb_clock in both directions.

For instance, I'm trying with:

# timing ignore of registered signals between clocks logic_clock and lb_clock
set_false_path -from [filter [all_registers -clock [get_clocks -of_objects [get_ports logic_clock]]] {name =~ *_TIG}] -to [get_clocks -of_objects [get_ports lb_clock]] 
set_false_path -from [filter [all_registers -clock [get_clocks -of_objects [get_ports lb_clock]]] {name =~ *_TIG}] -to [get_clocks -of_objects [get_ports logic_clock]] 

and of course toggle and vector storage signals will be named xxx_TIG, e.g. toggle_TIG and data_SLV_storage_TIG.

Now comes the problem:

Suppose toggle_TIG is the output of a flipflop FF0 clocked by logic_clock, and propagated through two paths:

- to D input of FF0, through a not logic, to obtain the toggling

- to D input of cascade of FF1 and FF2, clocked by lb_clock to avoid metastability

When logic_clock != lb_clock, only path from from FF0 to FF1 is affected, which is correct.
However, when logic_clock == lb_clock, both paths are affected, so the toggle could not work properly.

I would actually need to apply the false path constraint only between different clocks, but I don't know how to describe this...
I thought about conditional constraint, using

Any advice?

Thanks

Andrea

 

 

 

 

 

 

 

 

 

0 Kudos
12 Replies
Highlighted
Xilinx Employee
Xilinx Employee
623 Views
Registered: ‎03-29-2013

Hi Andrea,

I can see 2 options:

1) Move from XDC to TCL file:

  => Vivado accepts *.tcl files as part of the constraints. They will be "unmanaged", meaning Vivado cannot update their content via the Timing Constraints Editor in the IDE. See https://www.xilinx.com/support/documentation/sw_manuals/xilinx2020_1/ug903-vivado-using-constraints.pdf page 6 for some info.

  => add a if condition to your constraints, like:

set clkA [get_clocks -of [get_ports A]]
set clkB [get_clocks -of [get_ports B]]
if {$clkA != $clkB} {
  set_false_path ...
}

2) Make the set_false_path constraint error out when clocks are the same, but remove the message & error thanks to the -quiet switch

  => Not the cleanest way of doing this as messages will always be silent for this constraint, which could be a problem for debugging other unforseen issues.

set clkA [get_clocks -of [get_ports A]]
set clkB [get_clocks -of [get_ports B]]
set_false_path -quiet -from [filter -quiet [all_registers -quiet -clock [filter $clkA "NAME!=$clkB"]] "NAME=~*_TIG"] -to $clkB

 

Highlighted
607 Views
Registered: ‎01-22-2015

@andpas.qas 

It sounds like you are properly placing a 2-flip-flop (2FF) synchronizer on every crossing between logic_clock and lb_clock.  If you give the first FF of the 2FF a unique name (eg. META_2FF) then you can target this FF with your generalized set_false_path.

set_false_path -to [get_cells -hier *META_2FF_reg]

Don’t forget to also set ASYNC_REG TRUE for both FFs in the 2FF.

Cheers,
Mark

Highlighted
Observer
Observer
463 Views
Registered: ‎09-30-2019

hello,

about .xdc files: is there a list of supported TCL commands (e.g. "if" is not supported)?

 

I tried the unmanaged way, renaming .xdc to .tcl and adding if on top of the set_false_path.

While adding .tcl file to the project seems to work, I'm encountering some problem adding it to the IP, as the packager reports as unknown file...

I added the file under the Synthesis sources, so at the same file group of VHDL files, where previously I added the .xdc file.

My impression is, when I add the IP to a project, this file is simply ignored...

Am I doing something wrong?

Thanks

Andrea

 

 

 

0 Kudos
Highlighted
Guide
Guide
454 Views
Registered: ‎01-23-2009

So, first...

The set_false_path isn't technically a safe constraint to use...

The mechanism you describe is a valid clock domain crossing circuit (CDCC); you are creating a stable version of the data to cross and sending an "event" (in the form of a toggle) between the domains using a metastability resolution circuit. I assume you are using the ASYNC_REG property on the two back to back synchronizing flip-flops...

Assuming this is done correctly, you are making sure your data is stable on the source domain N clocks before you generate the pulse event and M clocks after the pulse event (all on the source clock). The pulse event needs to go through a synchronizer, so will take 1-2 destination clock periods to get through the synchronizer and your sampler will work on the clock period after that. Thus, your data must remain stable for at least 3 destination clock periods after your toggle event. Lets put some number on this as an example - say your destination clock is 200MHz, this means that your stable data must be valid for at least 15ns after the toggle event (there are also requirements before the pulse, but those are easier).

But, you need to take into account propagation delay. Both the stable data and the pulse event are being routed on the FPGA; they both start at synchronous elements on your source domain, and end at different elements at your destination domain. With a set_false_path, these routes are completely unconstrained. There is nothing that (say) allows for the sampled data to be routed with short routes (less than 1ns), but the toggle signal to take a very very long route (say to avoid congestion) - this is technically unbounded - it could take 100ns for this signal to propagate (not likely - maybe verging on impossible, but since there is no constraint, it is unbounded). If this signal really does take 100ns, and your data is only stable for (say) 20ns (5ns more than the minimum required), then this clock domain crossing circuit has failed.

To make sure this doesn't happen, you need to bound the route delays. This was traditionally done with the "set_false_path -datapath_only" constraint on the paths between the two domains - for example, if you set this to 5ns, then the maximum skew between the two sets of paths (the stable data and the strobe) can be +/-5ns. So if, at your source, you design your sample circuit to guarantee that the the data stays valid 2-3 destination clock cycles plus 5ns, and you use a "set_max_delay -datapath_only 5" on your paths - now your CDCC is properly constrained and guaranteed to work.

Starting in around 2016 a second way of bounding this was introduced, using the "set_bus_skew" command. I have less experience with this, but you should be able to constrain the skew between the bus and the toggle (which is really what you care about). However, with this mechanism alone, the latency of your CDCC is unbounded - so if you constrain the skew to 5ns and make sure your data is valid for 20ns after the event, the CDCC will work, but you don't know how long it will take. Again, technically, the data could have a 100ns routing delay and the pulse 105ns - the CDCC will work, but the data arrives at the destination domain long after it was generated in the source. For this reason, I still mostly prefer to use the set_max_delay -datapath_only (which constrains the latency directly, and the skew indirectly) rather than the set_bus_skew (which constrains the skew directly and the latency not at all).

Avrum

0 Kudos
Highlighted
Guide
Guide
449 Views
Registered: ‎01-23-2009

However, when logic_clock == lb_clock, both paths are affected, so the toggle could not work properly.

Constraining between clocks (or, as you are doing between a register and a clock) is always somewhat dangerous. The situation you describe is going to be hard to protect against using the methodology you have described. While using unmanaged constraints (a .tcl script instead of a .xdc) allows more Tcl syntax in your constraint files, it breaks a whole bunch of downstream flow related things - I am not surprised that the IP packager doesn't work with it (at least cleanly).

The best way to work around this is to constrain these CDCCs differently. The "best" way is often putting these CDCCs in their own module and then using a scoped XDC file for constraining them. In your case, if the whole thing (the generation of the stable data on the source domain, the generation of the toggle, the synchronizing flops for the toggle on the destination domain, the capture of the stable data on the destination) are all in one module, then you can write a very simple scoped XDC file that constrains all the paths involved in this CDCC from the hierarchical viewpoint of the CDCC (which is what the scoped constraints do). Done this way, whenever you use this CDCC module, it automatically comes with the constraints required. You can even use commands in the scoped XDC file that determine the periods of your source and destination clocks used for this instance of the CDCC to come up with the right values for the set_max_delay -datapath_only command - these are well supported (and used by all the Xilinx CDC IPs).

Avrum

Tags (1)
Highlighted
Observer
Observer
397 Views
Registered: ‎09-30-2019

Hello Avrumw,

I indeed wrote some VHDL modules for resync tasks, both of simple pulses (through toggle, resync and edge detection) and busses (the bus is sampled when output is ready, a strobe toggled, resynchronized, edge detected, then bus sampled value is sampled again with output clock).

Specific signals inside these generic modules are easy to identify, however fact that false paths can be only specified on separated files is a little bit confusing to me, I would prefer a signal attribute directly inside VHDL, applied to these signals...

Now suppose I have a generic module for pulse resynchronization, from a practical point of view, how should I handle .vhd module and the separate .xdc file (scoped to it) inside Vivado in a generic project?
How inside a project for IP packaging?
I mean: there's a way to scope automatically .xdc file to .vhd, so they are associated somehow, e.g. by name?
If the entity in .vhd file is instantiated multiple times?
Please note that I would use the constraints also where .vhd file is included in a project without being packaged.

Thanks

Andrea

0 Kudos
Highlighted
Guide
Guide
364 Views
Registered: ‎01-23-2009

I mean: there's a way to scope automatically .xdc file to .vhd, so they are associated somehow, e.g. by name?

You don't associate the .xdc with a .vhd, but with an entity (or module in Verilog/SystemVerilog). The mechanism differs depending on whether you are in a project or non-project flow...

First you write your .xdc assuming your synchronization module is the "top" of your design. The ports of the module/entity are referred to using "get_ports", the cells within them as "get_cells" assuming the cell is at the top of your module; i.e. if a flip-flop is generated with the signal/reg/logic "my_meta", then you would refer to the resulting flip-flop with "get_cells my_meta_reg" (with no hierarchy above it). Same with nets and pins within the module.

To get access to the clocks used in the instance of the module, you would ask for it as "the clock that is coming in through this port";

get_clocks -of_objects [get_ports <port_name>]

Next you associate the .xdc file with the module/entity. In a project flow, you add the .xdc file to your project and then set the "SCOPED_TO_REF" attribute of that .xdc file to the name of the module/entity. So if you .vhd defines an entity named "my_bus_sync", and you create the file my_bus_sync.xdc for the scoped constraints, you either go into the properties of my_bus_sync.xdc and change the "SCOPED_TO_REF" property to "my_bus_sync". Alternatively, you use the command

set_property SCOPED_TO_REF my_bus_sync [get_files my_bus_sync.xdc]

In non-project mode, you read in the .xdc using the command

read_xdc -ref my_bus_sync my_bus_sync.xdc

Once this is done, the .xdc file is associated with the reference (the name for a module/entity). For every instance of this entity anywhere in your design, the tools will automatically read in the my_bus_sync.xdc for that instance.

Avrum

0 Kudos
Highlighted
Observer
Observer
334 Views
Registered: ‎09-30-2019

Thanks,

that was clear!

What about the same .vhd / .xdc pair, when employed inside a project which will be packaged as an IP?
It's all the same or I need to do something more to have the included .xdc automatically imported on the host project (i.e. which will include the IP itself)?

Thanks

Andrea

 

 

0 Kudos
Highlighted
231 Views
Registered: ‎12-27-2016

Hi,

How do you target the source clock domain flip-flop (which is outside of the CDC module) in your set_max_delay when your CDC module is scoped_to_ref?

Here is what I tried to do but Vivado keep sending me warning that it can't find the FF:

 

 

set cdc_period_ratio 0.95

# [Vivado 12-1347] No FF(s) found
set dest_ff [get_pins -of [filter [all_ffs] {NAME =~ "*/data_sr_reg[0]"}] -filter {NAME =~ "*D"}]

# [Vivado 12-829] No fanin objects found for 'all_fanin -flat -only_cells -startpoints_only [get_pins -of [filter [all_ffs] {NAME =~ "*/data_sr_reg[0]"}] -filter {NAME =~ "*D"}]'.
set src_ff [all_fanin -flat -only_cells -startpoints_only $dest_ff]

set_max_delay -from [get_pins -of $src_ff -filter {NAME =~ "*C"}]\
              -to   $dest_ff\
              -datapath_only [expr [get_property -min PERIOD [get_clocks -of_objects $src_ff]] * $cdc_period_ratio]
0 Kudos
Highlighted
Observer
Observer
212 Views
Registered: ‎09-30-2019

Hello Nicolas,

as Avrumw stated, 

to get access to the clocks used in the instance of the module, you should employ a rule including a clock name obtained from 

get_clocks -of_objects [get_ports <port_name>]

 

Andrea

0 Kudos
Highlighted
203 Views
Registered: ‎12-27-2016

Hi Andrea,

I already have:

get_property -min PERIOD [get_clocks -of_objects $src_ff]

 in the last line of my "set_max_delay" example.

 

I don't understand how Avrumw get the FF (src_ff in my code) that is driving the signal to synchronize. This is what I tried:

set src_ff [all_fanin -flat -only_cells -startpoints_only $dest_ff]

Since the FF is outside of the CDC module, Vivado seems to be unable to find it when the XDC is scoped_to_ref.
Maybe there is another way to write it ?

0 Kudos
Highlighted
Guide
Guide
186 Views
Registered: ‎01-23-2009

Yes, the all_fanin doesn't appear to be able to find things that are outside the current module. However, I have tested this, and it does work (it is weird that some commands can and some commands can't - I have also seen posts that state that the "all_registers" command with some filters can be used...)

set src_ff [get_cells -of_objects [get_pins -filter {IS_LEAF && DIRECTION == OUT} -of_objects [get_nets -segments -of_objects [get_pins signal_meta_reg/D]]]]

(In this module, the first flip-flop in the metastability chain is called signal_meta_reg)

This only works if there is no combinatorial logic on the path between the flip-flop that generates the signal on the source domain, and the metastability flip-flop. However, for a "proper" synchronizer, this should always be the case...

So here is my complete scoped constraint for my metastability module

set dst_ff [get_cells signal_meta_reg]
set src_ff [get_cells -of_objects [get_pins -filter {IS_LEAF && DIRECTION == OUT} -of_objects [get_nets -segments -of_objects [get_pins signal_meta_reg/D]]]]
set min_period [get_property -min PERIOD [get_clocks -of_objects [list $src_ff $dst_ff]]]
set_max_delay -from $src_ff -to $dst_ff [expr {$min_period}]

Avrum

0 Kudos