UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 
Scholar ronnywebers
Scholar
11,699 Views
Registered: ‎10-10-2014

how to constrain a CDC

Jump to solution

I created a custom IP which contains a CDC, based on the paper of Cummings (fig 5.6.2).

 

I've attached my own block diagram version of this (pdf), and below is the code of the CDC (with the ASYNC_REG attribute on the sync FF's - hope this is done correctly), which is instantiated inside the custom IP. The custom IP itself is part of a larger block diagram with a Zynq and many more IP. 

 

In the block design I've added a clocking wizard IP, that generates my 2 clocks for each domain : a 100MHz (CPU domain) and a 13MHz clock (IO domain). Now the 13MHz will in a later phase of the project come from the external world, but for now it's internally generated. But I think I can / must consider them as asynchronous, hence I've added the CDC's in my design.

 

Now I know that I need to put the right constraints on the CDC, but I have no real clue which constraints. Referring to my block diagram, I think that I need to constrain :

 

1) the path from the first sync FF to the 2nd FF (the path that can go metastable)

2) the path between the 2 data register latches in each domain

 

or can I just tell Vivado that these 2 clocks are unrelated, so I don't need to specify the paths in detail?

 

Also, once I know which constraints I need to add, I have no clue how to start in Vivado searching for the signal names that go into these constraints ... . Is there some example available, or can someone shed some light on this? How do I dig down to the potentially metastable path between the 2 sync FF's,  and how do I find the the data register path name? Using some search wizard to find these? 

 

I've seen that there are tcl commands that can help, like report_clocks, report_cdc, ... should I start with these? Or the clock matrix?

 

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity sync_2ff is
Port 
(
    SRC_DIN         : in std_logic_vector(15 downto 0);     -- data input, i.e. CPU IO data
    SRC_SEND        : in std_logic;                         -- pulsed input, i.e. write pulse from CPU
    
    SRC_HOLD        : out std_logic;                        -- when '1', the source should not send any data (is ignored anyway)
    
    SRC_CLK         : in std_logic;                         -- source clock
    SRC_RESET       : in std_logic;                         -- reset synchronized to source clock domain
    
    DST_CLK         : in std_logic;                         -- destination clock
    DST_RESET       : in std_logic;                         -- reset synchronized to destination clock domain
    
    DST_OUT         : out std_logic_vector(15 downto 0);    -- data synchronized to destination clock
    DST_OUT_VALID   : out std_logic                         -- single cycle pulse indicating new data is valid
);
end sync_2ff;

architecture Behavioral of sync_2ff is

    attribute ASYNC_REG : string;

    -- we need to latch the incoming data as CPU only pulses IO_WR high for 1 SRC_CLK cycle
    signal src_din_reg              : std_logic_vector(15 downto 0);
    
    signal src_send_next_data       : std_logic;
    
    signal src_send_toggle_src_clk  : std_logic;
    
    signal event_toggle_meta        : std_logic;    -- attrib ASYNC_REG
    signal event_toggle_dst_clk     : std_logic;    -- attrib ASYNC_REG
    
    attribute ASYNC_REG of event_toggle_meta    : signal is "true";
    attribute ASYNC_REG of event_toggle_dst_clk : signal is "true";
    
    signal event_toggle_dst_clk_p1  : std_logic;

    signal event_out                : std_logic;

    signal data_dst_clk             : std_logic_vector(15 downto 0);
    signal dst_out_valid_dst_clk    : std_logic;

    -- ack data synchronizer & pusle generator
    signal ack_meta                 : std_logic;    -- attrib ASYNC_REG
    signal ack_src_clk              : std_logic;    -- attrib ASYNC_REG

    attribute ASYNC_REG of ack_meta    : signal is "true";
    attribute ASYNC_REG of ack_src_clk : signal is "true";
    
    signal ack_src_clk_p1           : std_logic;
    signal ack_pulse                : std_logic;
    
    signal busy                     : std_logic;
    
begin

    -- only allow next data if FSM indicates we're not busy
    -- CPU should check SRC_HOLD (connected to IO_WR_FULL), and not write any data
    -- if so, the write is ignored and data is dropped
    src_send_next_data <= '1' when (SRC_SEND = '1' and busy = '0') else '0';

    -- we need to latch the incoming data (in the SRC clock domain) because CPU only pulses
    -- IO_WR high for 1 SRC_CLK cycle
    process(SRC_CLK)
    begin
        if rising_edge(SRC_CLK) then
            if SRC_RESET = '1' then 
                src_din_reg <= (others => '0');
            else
                if src_send_next_data = '1' then
                    src_din_reg <= SRC_DIN;
                end if;
            end if;
        end if;
    end process;
    
    -- create a toggle from the SRC_SEND
    process(SRC_CLK)
    begin
        if rising_edge(SRC_CLK) then
            if SRC_RESET = '1' then
                src_send_toggle_src_clk <= '0';
            else 
                src_send_toggle_src_clk <= src_send_toggle_src_clk xor src_send_next_data;
            end if;
        end if;
    end process;

    process(DST_CLK)
    begin
        if rising_edge(DST_CLK) then
            if DST_RESET = '1' then
                event_toggle_meta <= '0';  -- attrib ASYNC_REG
                event_toggle_dst_clk <= '0';  -- attrib ASYNC_REG
                event_toggle_dst_clk_p1 <= '0';            
            else
                event_toggle_meta <= src_send_toggle_src_clk;  -- attrib ASYNC_REG
                event_toggle_dst_clk <= event_toggle_meta;  -- attrib ASYNC_REG
                event_toggle_dst_clk_p1 <= event_toggle_dst_clk;
            end if;
        end if;
    end process;

    event_out <= event_toggle_dst_clk_p1 xor event_toggle_dst_clk;

    -- latch the data in the output clock domain
    -- 'event_out' is only valid for a single DST_CLK cycle
    process(DST_CLK)
    begin
        if rising_edge(DST_CLK) then
            if DST_RESET = '1' then
                data_dst_clk <= (others => '0');
            else
                if event_out = '1' then
                    data_dst_clk <= src_din_reg;     -- needs constraints
                end if;
            end if;
        end if;
    end process;

    -- create a data valid pulse in the DST_CLK domain
    -- the valid pulse is a single DST_CLK cycle
    
    process(DST_CLK)
    begin
        if rising_edge(DST_CLK) then
            if DST_RESET = '1' then
                dst_out_valid_dst_clk <= '0';
            else
                dst_out_valid_dst_clk <= event_out;
            end if;
        end if;
    end process;

    -- connect outputs
    DST_OUT <= data_dst_clk;
    DST_OUT_VALID <= dst_out_valid_dst_clk;
    
    -- ack feedback (pusle generator)
    process(SRC_CLK)
    begin
        if rising_edge(SRC_CLK) then
            if SRC_RESET = '1' then
                ack_meta <= '0';
                ack_src_clk <= '0';
                ack_src_clk_p1 <= '0';
            else
                ack_meta <= event_toggle_dst_clk_p1;    -- q output (3-FF delay)
                ack_src_clk <= ack_meta;
                ack_src_clk_p1 <= ack_src_clk;
            end if;
        end if;
    end process;
    
    ack_pulse <= ack_src_clk_p1 xor ack_src_clk;
    
    -- busy FSM
    process(SRC_CLK)
    begin
        if rising_edge(SRC_CLK) then
            if SRC_RESET = '1' then
                busy <= '0';
            else
                if busy = '0' and SRC_SEND = '1' then
                    busy <= '1';
                elsif busy = '1' and ack_pulse = '1' then
                    busy <= '0';
                end if;
            end if;
        end if;
    end process;
    
    SRC_HOLD <= busy;
    
end Behavioral;

 

** kudo if the answer was helpful. Accept as solution if your question is answered **
1 Solution

Accepted Solutions
Historian
Historian
18,031 Views
Registered: ‎01-23-2009

Re: how to constrain a CDC

Jump to solution

or can I just tell Vivado that these 2 clocks are unrelated, so I don't need to specify the paths in detail?

 

Absolutely not.

 

First lets look at 1) the path from the first sync FF to the 2nd FF (the path that can go metastable). According to Xilinx the only thing that is necessary is the ASYNC_REG property.

 

In the past I would have constrained this path to be "small". The whole point of the 2 back to back flip-flops is to ensure that there is "time" for the metastability of the first flip-flop to resolve before the second flip-flop samples it. With no constraint, the tools can take just shy of one full destination clock period for the routing - if it does this, then it leaves no time for metastability resolution.

 

The ASYNC_REG property is supposed to solve this by ensuring that the FFs stay "near" eachother - in the same slice if possible. If they are really in the same slice, then I can't see any way for the route between them to be anything but really short. If they are in neighboring slices (which should only happen if they can't be packed into the same slice, which shouldn't happen here), in theory there still could be significant routing delays between them (very unlikely, but possible).

 

So, in the past, and maybe even now, I would constrain them with

 

set_max_delay 1.5 -from <meta_flop> -to <dst_flop>

 

I know that 1.5ns (including clock skew) is enough for two reasonably closely placed flip-flops, which leaves the remainder of the clock period for metastability, Note that there is no -datapath_only on this constraint.

 

For 2) the path between the 2 data register latches in each domain - you must constrain this.

 

The synchronizer of the toggle event takes 1-2 dst clocks, which means that the sampling of the data_dst_clk register takes place 2-3 dst clock periods after the toggle of src_send_toggle_src_clk plus the routing delay between src_send_toggle_src_clk and event_toggle_meta.

 

Without constraints (i.e. declaring the clocks unrelated) the routing between src_din_reg and data_dst_clk is unconstrained (as is the path from src_send_toggle_src_clk to event_toggle_meta). This means that it can (for example) take 2ns for the path between src_send_toggle_src_clk to event_toggle_meta, and 3000ns for the path between src_din_reg and data_dst_clk. So data_dst_clk is updated 2-3 dst_clk periods plus 2ns after the edge of src_clk that causes src_send_toggle_src_clk to toggle, but the data only arrives at data_dst_clk 3000ns after that edge of src_clk - clearly your synchronizer will fail under these conditions.

 

So you absolutely need constraints to limit the skew between these paths - the best way to do that is with a set_max_delay -datapath_only with a "reasonable" time (say one dst_clk period, or even one period of the smaller clock) on each path that crosses the clock domain boundary.

 

Avrum

26 Replies
Teacher muzaffer
Teacher
11,688 Views
Registered: ‎03-31-2012

Re: how to constrain a CDC

Jump to solution

@ronnywebers within xilinx flow, in addition to async_reg constraint on the first N registers on the target clock, the main constraint you need is max_delay -data_path_only between the last register on the source clock and the first register on the target clock.

- Please mark the Answer as "Accept as solution" if information provided is helpful.
Give Kudos to a post which you think is helpful and reply oriented.
Historian
Historian
18,032 Views
Registered: ‎01-23-2009

Re: how to constrain a CDC

Jump to solution

or can I just tell Vivado that these 2 clocks are unrelated, so I don't need to specify the paths in detail?

 

Absolutely not.

 

First lets look at 1) the path from the first sync FF to the 2nd FF (the path that can go metastable). According to Xilinx the only thing that is necessary is the ASYNC_REG property.

 

In the past I would have constrained this path to be "small". The whole point of the 2 back to back flip-flops is to ensure that there is "time" for the metastability of the first flip-flop to resolve before the second flip-flop samples it. With no constraint, the tools can take just shy of one full destination clock period for the routing - if it does this, then it leaves no time for metastability resolution.

 

The ASYNC_REG property is supposed to solve this by ensuring that the FFs stay "near" eachother - in the same slice if possible. If they are really in the same slice, then I can't see any way for the route between them to be anything but really short. If they are in neighboring slices (which should only happen if they can't be packed into the same slice, which shouldn't happen here), in theory there still could be significant routing delays between them (very unlikely, but possible).

 

So, in the past, and maybe even now, I would constrain them with

 

set_max_delay 1.5 -from <meta_flop> -to <dst_flop>

 

I know that 1.5ns (including clock skew) is enough for two reasonably closely placed flip-flops, which leaves the remainder of the clock period for metastability, Note that there is no -datapath_only on this constraint.

 

For 2) the path between the 2 data register latches in each domain - you must constrain this.

 

The synchronizer of the toggle event takes 1-2 dst clocks, which means that the sampling of the data_dst_clk register takes place 2-3 dst clock periods after the toggle of src_send_toggle_src_clk plus the routing delay between src_send_toggle_src_clk and event_toggle_meta.

 

Without constraints (i.e. declaring the clocks unrelated) the routing between src_din_reg and data_dst_clk is unconstrained (as is the path from src_send_toggle_src_clk to event_toggle_meta). This means that it can (for example) take 2ns for the path between src_send_toggle_src_clk to event_toggle_meta, and 3000ns for the path between src_din_reg and data_dst_clk. So data_dst_clk is updated 2-3 dst_clk periods plus 2ns after the edge of src_clk that causes src_send_toggle_src_clk to toggle, but the data only arrives at data_dst_clk 3000ns after that edge of src_clk - clearly your synchronizer will fail under these conditions.

 

So you absolutely need constraints to limit the skew between these paths - the best way to do that is with a set_max_delay -datapath_only with a "reasonable" time (say one dst_clk period, or even one period of the smaller clock) on each path that crosses the clock domain boundary.

 

Avrum

Scholar ronnywebers
Scholar
11,571 Views
Registered: ‎10-10-2014

Re: how to constrain a CDC

Jump to solution

thanks both!

 

@avrumw, the first one is clear to me (set_max_delay 1.5 ...), thanks for that!

 

however I'm a bit puzzled on your explanation of the 2nd, the path between the 2 data registers. I understand this part :

 

The synchronizer of the toggle event takes 1-2 dst clocks, which means that the sampling of the data_dst_clk register takes place 2-3 dst clock periods after the toggle of src_send_toggle_src_clk plus the routing delay between src_send_toggle_src_clk and event_toggle_meta.

 

Without constraints (i.e. declaring the clocks unrelated) the routing between src_din_reg and data_dst_clk is unconstrained (as is the path from src_send_toggle_src_clk to event_toggle_meta).

 

but then you write :

 

This means that it can (for example) take 2ns for the path between src_send_toggle_src_clk to event_toggle_meta, and 3000ns for the path between src_din_reg and data_dst_clk. So data_dst_clk is updated 2-3 dst_clk periods plus 2ns after the edge of src_clk that causes src_send_toggle_src_clk to toggle, but the data only arrives at data_dst_clk 3000ns after that edge of src_clk - clearly your synchronizer will fail under these conditions.

 

I'm not getting this '3000ns' especially the bold parts ...

1) you say 'for example' -> do you assume a dst_clock of 1MHz, hence 1000ns for 1 cycle -> 3 cycles = 3000ns? 

2) data only arrives at data_dst_clk 3000ns after that edge of src_clk ... -> why would this be? Isn't the data already stable long before the data_dst_clk clock enable arrives through the synchronisers, as the data is latched in the src_din_reg, and even kept stable by the FSM until ack comes from the destination domain?

 

 

** kudo if the answer was helpful. Accept as solution if your question is answered **
0 Kudos
Scholar ronnywebers
Scholar
11,559 Views
Registered: ‎10-10-2014

Re: how to constrain a CDC

Jump to solution

I have a further question regarding the actual 'syntax' of this constraint I need to add :

 

set_max_delay 1.5 -from <meta_flop> -to <dst_flop>

 

-> how do I find/get the syntax for 'meta_flop' and 'dst_flop'?

 

I tried this (but not sure if this is the way to do it) : open synthesised design -> tab setlist -> dig down to the meta_flop

 

netlist.png

 

then I checked the tab properties :

 

net property.png

 

so I thought it would be like this :

 

set_max_delay 1.5

-from design_1_i/snap_sin_rx_0/U0/sync_2ff_i/event_toggle_meta.Q 

-to design_1_i/snap_sin_rx_0/U0/sync_2ff_i/event_toggle_dst_clk.D

 

but it's clearly missing something (or even completely incorrect?) :

 

WARNING: [Vivado 12-1580] clock, cell, port or pin 'design_1_i/snap_sin_rx_0/U0/sync_2ff_i/event_toggle_meta.Q' not found.
WARNING: [Vivado 12-1580] clock, cell, port or pin 'design_1_i/snap_sin_rx_0/U0/sync_2ff_i/event_toggle_dst_clk.D' not found.
ERROR: [Vivado 12-1387] No valid object(s) found for set_max_delay constraint with option '-from design_1_i/snap_sin_rx_0/U0/sync_2ff_i/event_toggle_meta.Q'.

 

** kudo if the answer was helpful. Accept as solution if your question is answered **
0 Kudos
Xilinx Employee
Xilinx Employee
11,548 Views
Registered: ‎05-07-2015

Re: how to constrain a CDC

Jump to solution

HI @ronnywebers

As Avrum mentioned ASYNC_REG will indeed take care of placing these two registers in the same slice. hence please do not spend your time trying to constrain this path.

What is more important and necessary to constrain is the path between source clk register and first meta register of target clock as muzaffer and avrum (point 2) mentioned.

It is important to ensure the the data path between the source and destination regs  is not more than the  one clock period of dest clock..

Thanks
Bharath
--------------------------------------------------​--------------------------------------------
Please mark the Answer as "Accept as solution" if information provided addresses your query/concern.
Give Kudos to a post which you think is helpful.
--------------------------------------------------​-------------------------------------------
Scholar ronnywebers
Scholar
11,544 Views
Registered: ‎10-10-2014

Re: how to constrain a CDC

Jump to solution

thanks @nagabhar, can you clarify in this phrase:

 

It is important to ensure the the data path between the source and destination regs  is not more than the  one clock period of dest clock..

 

why is this? so why not more than one clock period of the dest clock? Isn't data asumed to be stable until sampled at the destination register? And as the 2 sync FF + 1 pulse FF takes 2 to 3 dest clock cycles, why can' t the path be longer than 1 dest clock cycle? Like 1.9, as at earliest the data is sampled after 2 dest clock cycles? I'm probably thinking wrong ...? I understand it makes no sense to have a data path longer than the dest clock period, but in theory why couldn't this be longer?

** kudo if the answer was helpful. Accept as solution if your question is answered **
0 Kudos
Historian
Historian
11,540 Views
Registered: ‎01-23-2009

Re: how to constrain a CDC

Jump to solution

I'm not getting this '3000ns' especially the bold parts ...

 

The number 3000ns was chosen to illustrate my point. If you have no constraint, then the placer/router is not constrained. This literally means that any delay is allowed. The tools may choose an implementation that has 2ns of delay or 20ns of delay or 300ns of delay (unlikely), or even 3000ns of delay (really really unlikely, but still theoretically possible) - because it has no constraints, then it can do any of these.

 

Clearly if it chooses an implementation that has 3000ns or even 200ns of even, for some frequencies 30ns of delay on the path, the synchronizer will fail  - the data_dst_clk flip-flops will capture data that has not yet had time to propagate to it. So you need a constraint to tell it that only implementations that have a delay of less than a certain amount are acceptable. That is what the set_max_delay -datapath_only does.

 

Avrum

 

 

Historian
Historian
11,538 Views
Registered: ‎01-23-2009

Re: how to constrain a CDC

Jump to solution

so I thought it would be like this :

 

set_max_delay 1.5

-from design_1_i/snap_sin_rx_0/U0/sync_2ff_i/event_toggle_meta.Q 

-to design_1_i/snap_sin_rx_0/U0/sync_2ff_i/event_toggle_dst_clk.D

 

If you are going to figure this out, you are going to have to learn the formal syntax of both the netlist and the Vivado Design Suite database. This is going to be fundamental to getting anything "advanced" done. You can try learning this through the user guides (like UG903 for one), but you may want to consider some classes from Xilinx. There used to be one class on timing constraints that you could take, but it is now only being offered by some of the Authorized Training Providers (like this one from Hardent). Other providers give classes with the timing constraints scattered throughout a more holistic set of classes (See the four Designing FPGAs using the Vivado Design Suite classes) - check with the Authorized Training Provider in your area.

 

The problem with your constraints is that you got the names from the "Nets" list, not the "Leaf Cells" list, and then you tried to tack the pin name to the net (a net has no pins).

 

You should find the corresponding cells in the "Leaf Cells" list, and use the cell itself for the constraints, rather than the pins (technically a path does start at the C pin of a cell and end at the D pin, but it is "better" to go cell to cell).

 

Second, you should get the object with the "get" commands to tell the tool what you are looking for.

 

Almost certainly the constraint would be

 

set_max_delay 1.5 -from [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/event_toggle_meta_reg]   -to [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/event_toggle_dst_clk_reg]

 

Avrum

Scholar ronnywebers
Scholar
11,525 Views
Registered: ‎10-10-2014

Re: how to constrain a CDC

Jump to solution

thanks @avrumw, your version of the constraint works! Got if for the 3000ns :-)

 

got it for the leaf cells, I found it just a bit below the net in the netlist view!

 

I asume I could use wild-cards too if later on I add multiple instances of these CDC's too? 

 

 

 

ps.: regarding the training, thanks for the tips, I'll consider these in the near future! I hoped I would be able to learn enough from the free online sources, but looks like training for this kind of technology would be worth the investment (though it is a serious investment for me  ... :-)

 

 

 

 

 

 

 

 

** kudo if the answer was helpful. Accept as solution if your question is answered **
0 Kudos
Scholar ronnywebers
Scholar
10,393 Views
Registered: ‎10-10-2014

Re: how to constrain a CDC

Jump to solution

to finish this thread, I focussed on the 2nd constraint, the -datapath_only

 

I tested this one, looks ok - I assume I can use a wild-card for the 16-bit databus like this: (?)

 

set_max_delay -from [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/src_din_reg_reg[*]] -to [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/data_dst_clk_reg[*]] -datapath_only 75.0

I used 75.0ns, as the current clock is 13MHz (so 76.9...ns period)

 

last question: still puzzled why this maximum delay should be less than 1 cycle of the dest clock domain? 

** kudo if the answer was helpful. Accept as solution if your question is answered **
0 Kudos
Historian
Historian
10,387 Views
Registered: ‎01-23-2009

Re: how to constrain a CDC

Jump to solution

I asume I could use wild-cards too if later on I add multiple instances of these CDC's too? 

 

Yes. You could also use a scoped XDC file - that can be a cleaner solution, but requires more understanding of how the constraint system works.

 

Avrum

Tags (2)
Historian
Historian
10,386 Views
Registered: ‎01-23-2009

Re: how to constrain a CDC

Jump to solution

last question: still puzzled why this maximum delay should be less than 1 cycle of the dest clock domain? 

 

You are right - it could be more. The sampling won't happen for a minimum of 2 destination clock periods after the change in the event, so you could constrain it for 2 minus the possible setup time of the flop. But why push it? If the tools can meet a one clock timing requirement on all other paths on the destination domain, why would it need more on this path (which is just flop to flop)?

 

Avrum

Scholar ronnywebers
Scholar
10,378 Views
Registered: ‎10-10-2014

Re: how to constrain a CDC

Jump to solution

ok thanks for clearing that up, you're right - I shouldn't push it further than 1 dest clock cycle. If the tools can't handle that anymore, I probably have another problem :-)

 

thanks all for your answers in this thread. Closing the case.

** kudo if the answer was helpful. Accept as solution if your question is answered **
0 Kudos
Scholar ronnywebers
Scholar
10,362 Views
Registered: ‎10-10-2014

Re: how to constrain a CDC

Jump to solution

for completeness, I forgot the constraint from the dest domain to the src domain (on the 'ack' signal), so here are all constraints for completeness - @avrumw would you mind doing a final check on this?

 

# constrain between the 2 synchronizer FF's from src to dst clock (the 'send' signal)
# note : here are 2 opinions : 
# 1) some say this is not needed if you put the ASYNC_REG attribute on the sync regs, the tools should detect this
#    and put the FF's in the same slice
# 2) some say it's safer to (on top of the ASYNC_REG attribute) constrain the path between the 2 sync FF's to a
#    small value, so you have a check on the tools that they put the 2 FF's close to each other
set_max_delay 1.5 -from [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/event_toggle_meta_reg]   -to [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/event_toggle_dst_clk_reg]

# constrain the datapath between the src data register and dst data register
set_max_delay -from [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/src_din_reg_reg[*]] -to [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/data_dst_clk_reg[*]] -datapath_only 75.0

# constrain the 2 synchronizer FF's from dst to src clock (the 'ack' signal)
set_max_delay 1.5 -from [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/ack_meta_reg]   -to [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/ack_src_clk_reg]

 

** kudo if the answer was helpful. Accept as solution if your question is answered **
0 Kudos
Scholar ronnywebers
Scholar
10,346 Views
Registered: ‎10-10-2014

Re: how to constrain a CDC

Jump to solution

With the above constraints, I'm getting a timing error as follows :

 

setup failure.png

 

I don't get this one ... I have the ASYNC_REG property set on the event_toggle_meta_reg and event_toggle_dst_clk_reg in my HDL source.

 

Additionally I have the constraint set (of which some people say it's even not necessary, but I understand why you set it as a 'safety' measure) :

 

set_max_delay 1.5 -from [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/event_toggle_meta_reg]   -to [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/event_toggle_dst_clk_reg]

so why does the timing report complain about the path src_send_toggle_src_clk_reg.Q to event_toggle_meta_reg.D ? Shouldn't that path be ignored by the timing analyser because of the ASYNC_REG set on the following FF (event_toggle_meta_reg) ? I believe that is called a 'false path' ?

 

 

 

 

** kudo if the answer was helpful. Accept as solution if your question is answered **
0 Kudos
Historian
Historian
10,332 Views
Registered: ‎01-23-2009

Re: how to constrain a CDC

Jump to solution

I don't get this one ... I have the ASYNC_REG property set on the event_toggle_meta_reg and event_toggle_dst_clk_reg in my HDL source.

 

First, the constraint is wrong. The set_max_delay 1.5 (without the -datapath_only) is the "paranoid" constraint to set between the first and second flip-flop on the destination domain. This limits the routing on the net between them to allow for maximum time for metastability settling. This is fulfilling the same role as the ASYNC_REG, which tells the tools to keep the two flip-flops together (most people rely only on the ASYNC_REG).

 

The ASYNC_REG is a placement constraint - it does not affect timing analysis. Furthermore all clocks in Vivado are considered to be synchronous by default (this is the mantra for XDC/SDC). So even though there may be no real relationship between these clocks, and even though they share no common generation point, they are considered synchronous until told otherwise. There are NO false paths in XDC/SDC unless you declare the path false.

 

In addition, we specifically don't want this path to be false, we want it to be overridden by an exception - specifically the set_max_delay -datapath_only with the value of the destination clock. This exception removes the "default" relationship (which isn't correct since these clocks are, in fact, unrelated), and replaces it with a constraint. It is through this mechanism (among others) that we inform the tool that these clocks are unrelated...

 

You should carefully read through the thread again to be sure you are clear between the (probably unecessary) set_max_delay 1.5, and the set_max_delay -datapath_only <dst_period> - these are two different constraints on two different paths in the clock crosser that are accomplishing different goals.

 

Avrum

Tags (3)
Scholar ronnywebers
Scholar
10,319 Views
Registered: ‎10-10-2014

Re: how to constrain a CDC

Jump to solution

thanks @avrumw, I must be missing something, sorry for that ... I've read through the entire post again after a large coffee this morning :-)

 

I've numbered my 3 constraints that I have so far:

 

# constraint 1 : (paranoid) between the 2 synchronizer FF's from src to dst clock (the 'send' signal)
close to each other
set_max_delay 1.5 -from [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/event_toggle_meta_reg]   -to [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/event_toggle_dst_clk_reg]

# constraint 2 : the datapath between the src data register and dst data register
set_max_delay -from [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/src_din_reg_reg[*]] -to [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/data_dst_clk_reg[*]] -datapath_only 75.0

# constraint 3: (paranoid) between the 2 synchronizer FF's from dst to src clock (the 'ack' signal)
set_max_delay 1.5 -from [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/ack_meta_reg]   -to [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/ack_src_clk_reg]

 

just focussing on constraint 1 for a moment, the one that applies to the CDC of the 'send pulse' (src_send_next_data signal), I'll try to recap what I think to understand so far:

 

this constraint 1 is a 'paranoid / safeguard' constraint specifying that the 2 synchronizer FF's 'event_toggle_meta_reg' and 'event_toggle_dst_clk_reg' must have at max 1.5ns delay between them (just an extra check in case ASYNC_REG wouldn't do it's job perfectly). I copied this constraint from your older reply, so I think this one was correct.

 

Screen Shot 2017-02-14 at 21.44.12.png

 

My understanding so far is that this 'paranoid' constraint 1 is needed because :

 

the Q output of 'event_toggle_meta_reg' might go metastable when the FF samples it's .D input right at the moment that the signal toggles'. By placing a second FF (event_toggle_dst_clk_reg)  right after it (with no other fanout on the connection between them, and minimum path length), the MTBF can be reduced to acceptable levels. Depending on freq etc, even more 'synchronizer flip-flops' must be added to further improve MTBF (enough papers on that on the web :-), but 2 is in most cases acceptable, and 3 is really safe.

 

Normally ASYNC_REG attribute on both FF's would take care of this short path between the synchronizer FF's (as you explained : these are just 'placement constraints, not timing constraints'). But to have a double check / safeguard on Vivado's placement, you prefer this 'paranoid' constraint (which I like, I'm often paranoid on such things too :-) 

 

timing analysis path1:

 

if I see it right, the timing analysis complains about the path (path 1) between src_send_toggle_src_clk_reg.Q and event_toggle_meta_reg.Q, which is the datapath between 2 different clock domains.  

 

this 'datapath_only' option was not clear to me before (Google search didn't help me on this either), but I read the help of set_max_delay a few times, an I think to understand it now like this :

 

- datapath_only needs to be set on any path between 2 flip-flops (i.e. FF1.Q to FF2.D) that  are clocked by different, (Q: asynchronous??) clocks. In my case this looks to be the 'path1' that the timing analyser complains about. 

 

- by specifying datapath_only, clock skew and jitter is not considered in the delay calculation, as it is irrelevant since there are 2 different clocks in the game. As the help says 'only the clock-to-Q delay of the first flop, the wire delay between the flops, and the setup time of the second flop should be considered'

 

so is this what I misunderstood? I do need to set an additional a datapath_only constraint between src_send_toggle_src_clk_reg.Q and event_toggle_meta_reg.D? Like this: 

 

set_max_delay -datapath_only -from [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/src_send_toggle_src_clk_reg] -to [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/event_toggle_meta_reg] 10.0

so the 10.0ns is 1 clock period of the src clock : I found this in UG949 (2016.4, p.160) : 'it is usually sufficient to use the source clock period for the max delay value, just to ensure that no more than one data is present on the CDC path at any given time. When the ratio between clock periods is high, choosing the miminum of the source and destinatoin periods is also a good option to reduce the transer latency'. (this is something you mentioned in an earlier post)

 

What I also think to understand : I've found (Xilinx) IP that contains CDC's, and that comes with it's own .xdc files, and just uses 'set_false_path' or 'set_clock_groups'. But I understand from your previous answers that this is a 'brute force method', and hence inherently unsafer than just specifying a 'finer grained' exception on a single connection through set_max_delay -datapath_only?

 

 

ps: I think you mentioned that this course could be interesting on this subject? I'm not in ISE user, but I guess that doesn't matter much.

** kudo if the answer was helpful. Accept as solution if your question is answered **
0 Kudos
Scholar ronnywebers
Scholar
10,248 Views
Registered: ‎10-10-2014

Re: how to constrain a CDC

Jump to solution

I've updated my constraints, and timing analysis now shows all paths are ok. I also updated my block schematic, which now indicates the location where constraints are applied, where ASYNC_REG is set, ...

 

@avrumw would you mind doing a final check? The block diagram now also indicates the correct FF names and ports (matching my VHDL code), so it's easier to check the constraints by looking at the block diagram.

 

# *** CDC constraints ***
# ref : # https://forums.xilinx.com/t5/Timing-Analysis/how-to-constrain-a-CDC/m-p/748192#M11071

# note : constraint between the 2 synchronizer FF's from src to dst clock (the 'send' signal)
# there are 2 opinions : 
# 1) some say this is not needed if you put the ASYNC_REG attribute on the sync regs, the tools should detect this
#    and put the FF's in the same slice
# 2) some say it's safer to (on top of the ASYNC_REG attribute) constrain the path between the 2 sync FF's to a
#    small value, so you have a check on the tools that they put the 2 FF's close to each other (cfr. 'paranoid constraint' below)
# -> let's go for the extra safety check and add the 'paranoid constraint' too
#
# note : ASYNC_REG is a placement constrait, not a timing constraint.

# *** constraints for the 'send' signal ***
# -datapath_only constraint on the Q-to-D path between the 2 clock domains
set_max_delay -datapath_only 10.0 -from [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/src_send_toggle_src_clk_reg] -to [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/event_toggle_meta_reg] 
# 'paranoid constraint' for the 2 synchronizer FF's from dst to src clock
set_max_delay 1.5 -from [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/event_toggle_meta_reg]   -to [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/event_toggle_dst_clk_reg]

# *** constraint for the 16-bit data bus ***
# constrain the datapath between the src data register and dst data register (100MHz -> 10.0ns)
set_max_delay  -datapath_only 10.0 -from [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/src_din_reg_reg[*]] -to [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/data_dst_clk_reg[*]]

# *** constraints for the 'ack' signal *** 
# -datapath_only constraint on the Q-to-D path between the 2 clock domains
set_max_delay -datapath_only 10.0 -from [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/event_toggle_dst_clk_p1_reg] -to [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/ack_meta_reg]
# constrain the 2 synchronizer FF's from dst to src clock (the 'ack' signal)
set_max_delay 1.5 -from [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/ack_meta_reg]   -to [get_cells design_1_i/snap_sin_rx_0/U0/sync_2ff_i/ack_src_clk_reg]

My next mission is to add a tcl file with scoped timing constraints to my custom IP that contains the CDC's, so I don't have to bother about setting constraints in my Zynq block design when adding my custom IP.

 

** kudo if the answer was helpful. Accept as solution if your question is answered **
Historian
Historian
10,188 Views
Registered: ‎01-23-2009

Re: how to constrain a CDC

Jump to solution

Yes, this all looks correct now.

 

Avrum

Scholar ronnywebers
Scholar
6,611 Views
Registered: ‎10-10-2014

Re: how to constrain a CDC

Jump to solution

@avrumw, I'm looking at some 3rd party FPGA code. I cannot share it completely here, as it's copyrighted.

 

They also use synchronizers in their design for incoming asynchronous signals. I see that (besides marking the registers with ASYNC_REG), they just put a set_false_path constraint, I think on the first FF of the synchroniser chain :

 

set_false_path -to [get_pins */instance_name/stages[0].value_reg[*]/D]

 

What does this constraint do, and is it necessary?

 

they don't seem to set a set_max_delay constraint, so I think they asume the ASYNC_REG attribute is sufficient for the tools to put these regs together?

** kudo if the answer was helpful. Accept as solution if your question is answered **
0 Kudos
Highlighted
Historian
Historian
6,600 Views
Registered: ‎01-23-2009

Re: how to constrain a CDC

Jump to solution

they don't seem to set a set_max_delay constraint, so I think they asume the ASYNC_REG attribute is sufficient for the tools to put these regs together?

 

Almost everyone does - I am even starting to. Before the ASYNC_REG, the set_max_delay between the flip-flops in the metastability chain were "required" to ensure the maximum amount of time was given for metastability reduction. That being said, very few people actually did this - the result in most cases is a poorer MTBF, but that would be hard to measure.

 

With the ASYNC_REG, the tools will place the flops as close together as possible. That is probably good enough. The only thing that bothers me slightly is wondering about the router - just because the cells are close together doesn't necessarily mean the route will be the shortest possible.

 

So I ask the following questions to Xilinx (which can only be answered by someone who knows the place and route algorithms deeply).

 

If the two FFs are in the same slice with the Q of one connected to the D of the other, is the router guaranteed to take the route directly to and from the slice's switch matrix for the connection? Or, is it theoretically possible for the router to take a more circuitous route? Since they are in the same slice, I presume there is 0 clock skew and hence there will never be hold times that need fixing...

 

If, due to control set restrictions, the two flip-flops cannot be placed in the same slice, will they be placed in the same CLB (adjacent slices in the same CLB)? Or, can they be placed in adjacent slices in adjacent CLBs. In either case, is the above still true? In the same CLB, they share a common switch matrix (so if the above is true then it is probably true here too), but in adjacent CLBs, that is no longer the case - is the path still guaranteed to be "minimal"?

 

What does this constraint do, and is it necessary?

 

So "necessary" is a funny word in this context...

 

From a timing point of view, if the input has no "set_input_delay" then the "stuff" before the first capture flop is not a static timing path. A static timing path needs a startpoint, and there isn't one here.

 

Normally we "create" a startpoint with the set_input_delay command - this defines the startpoint, what clock it uses and the propagation delay through that startpoint.

 

So, we have two options:

  - don't specify a set_input_delay

      - from a timing point of view, this is fine - the path is unconstrained

      - but it will also show up on the unconstrained path report and will fail the "no input delay" check from check_timing

  - specify a set_input_delay - since the input is asynchronous, the value is meaningless

      - now the input is part of a timing path. But since it is asynchronous an going into a synchronizer, it now needs an exception

          - if you don't care about latency, the set_false_path you described is fine

          - if you do care about latency, then a set_max_delay -datapath_only is needed

 

So, if you have both the set_input_delay and the exception (set_max_delay -datapath_only or set_false_path) then the path exists, it has a set_input_delay (so check_timing is happy), and the timing has a proper exception on it.

 

I recommend doing that (the set_input_delay with the exception)....

 

Avrum

6,565 Views
Registered: ‎01-22-2015

Re: how to constrain a CDC

Jump to solution

FYI - when using older versions of Vivado (before v2016.1), @drjohnsmith and I found that VHDL attribute statements like those shown below did not reliably set ASYNC_REG=TRUE for registers used in synchronizers.  That is, “Open Implemented Design” often showed the synchronizer registers were physically located many slices apart.

 

   attribute ASYNC_REG : string;

   attribute ASYNC_REG of my_signal: signal is "TRUE";

 

Before Vivado v2016.1, a solution was to set ASYNC_REG=TRUE using a Tcl/XDC constraint similar to the following.

 

      set_property ASYNC_REG TRUE [get_cells -hierarchical my_signal_reg]

 

For more information see < this post >.

Contributor
Contributor
6,504 Views
Registered: ‎04-18-2016

Re: how to constrain a CDC

Jump to solution

 

In a design, the configuration logic usually was the common part with the lower frequency clock. All the path connected to other clock domains need to be constrain by 'set_max_delay'. So, can I use 'get_clocks' instead of 'get_cells' to constrain the maxium delay from one clock domain to the other? 

For example, 

set_max_delay -from [get_clocks clk_out1_mmcm100] -to [get_clocks clk_out1_mmcm233] -datapath_only 10.0

 

0 Kudos
Historian
Historian
6,490 Views
Registered: ‎01-23-2009

Re: how to constrain a CDC

Jump to solution

Yes.

 

The enumeration mechanism for all exceptions (and timing reporting commands like report_timing, get_timing_paths) are the same; they all use the -from/-to/-through (and variations with rise and fall) and can use nets, pins, cells, ports and clocks in any combination (the only exception is the set_max_delay -datapath_only which must have a -from).

 

So the command you show is legal. I am not a huge fan of "clock to clock" set_max_delay -datapath_only commands, but they are OK in certain circumstances - far better than "clock to clock" set_false_path commands or the set_clock_groups command...

 

Again, you must ensure that you have some form of clock domain crossing in place. Often if there is a large bank of configuration registers, this can be accomplished by a simple 2 flip-flop synchronizer on an "enable" pin (that is properly constrained via the set_max_delay -datapath_only), where this enable keeps all destinations of the rest of the clock crossing paths in the equivalent of reset...

 

Avrum

0 Kudos
Scholar ronnywebers
Scholar
6,479 Views
Registered: ‎10-10-2014

Re: how to constrain a CDC

Jump to solution

@avrumw, you wrote 'Often if there is a large bank of configuration registers, this can be accomplished by a simple 2 flip-flop synchronizer on an "enable" pin'

 

I want to make sure I fully understand that phrase :

 

In my design I create a bank of 'configuration registers' that are written by a soft core CPU. It's IO interface has :

- address bus

- data bus

- write strobe (1 clock cycle)

- read strobe (1 clock cycle)

 

some of these 'configuration registers' (and also status registers that are read back) are sitting in another clock domain (sometimes faster, sometimes slower).

 

In that case I put a CDC before each of these registers. The CDC looks like the XPM_CDC_HANDSHAKE, and the code can be found in my original question on this thread. 

 

Now do I understand your phrase correctly that I could do this in a simpeler fashion, and just CDC the 'write strobe' (what you call 'enable signal' ? With my current CDC I do latch the data in the src domain and dst domain. So is there a simpeler solution than mine, requireing less FF's ? Currently with 16-bit IO registers, I have like 16 src domain FF's + 16 dest domain FF's  + Sync FF's. 

 

 

** kudo if the answer was helpful. Accept as solution if your question is answered **
0 Kudos
Historian
Historian
6,471 Views
Registered: ‎01-23-2009

Re: how to constrain a CDC

Jump to solution

Under specific conditions, you can do less expensive clock crossing.

 

Many datapath designs have a large number of configuration signals. In many cases, some (or a significant number) of these configuration signals are set before data starts passing through the datapath and are not allowed to change while the datapath is being used. These can be referred to as pseudo-static signals.

 

If you have a large number of these pseudo-static signals, then you can design the system without explicit clock domain crossing circuits on each and every one of these control signals by setting up your design to take advantage of their pseudo-static nature.

 

You have to set up the design so that they never change any time that they matter. In practical terms, this means that you need to keep the datapath in reset or a "reset-like" state when these pseudo-static configuration signals are changing. Generally you need an enable (or reset) signal that controls your datapath; the deassertion of enable must hold all registers in the datapath in a reset-like state.

 

Now to change any of the pseudo-static inputs you

  - deassert the enable

  - (wait a couple of clocks)

  - change any of the registers controlling the pseudo-static control signals

  - (wait a couple of clocks)

  - re-enable the enable

 

By doing this it is legal to skip the synchronizers on all the pseudo-static signals. In this cases, even without specific clock domain crossing circuits on these busses, it is legal to put an exception on the paths through these signals because

   - whenever the startpoints can change, the endpoints are in reset

   - whenever the endpoints are not in reset, the startpoints can't change

 

So you can put a set_max_delay -datapath_only on them where the delay is specified as the "couple of clocks" that you wait before and after changing the enable signal.

 

Clearly the enable signal itself needs a proper clock domain crossing circuit. But it is a slow changing single bit signal, and hence a simple back to back flip-flop chain (with ASYNC_REG) is sufficient for it.

 

Avrum