- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Summary:
If the bit that is missing a synchronizer is part of a vector, the DRC check CDC-50001 FAILS.
VHDL code:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
entity cdc is
port (
clk1 : in std_logic;
clk2 : in std_logic;
Input : in std_logic;
Output_A : out std_logic;
Output_B : out std_logic
);
end entity;
architecture rtl of cdc is
signal datai : std_logic;
signal datao : std_logic_vector(0 to 1);
begin
process (clk1) is
begin
if rising_edge(clk1) then
datai <= Input;
end if;
end process;
process (clk2) is
begin
if rising_edge(clk2) then
datao <= datai & '1';
Output_A <= datao(0);
Output_B <= datai;
end if;
end process;
end architecture;
SDC constraints:
#**************************************************************
# Create Clock
#**************************************************************
create_clock -name {clk2} -period 10.000 -waveform { 0.000 5.000 } [get_ports {clk2}]
create_clock -name {clk1} -period 10.000 -waveform { 0.000 5.000 } [get_ports {clk1}]
#**************************************************************
# Set Clock Groups
#**************************************************************
set_clock_groups -asynchronous \
-group [get_clocks {clk1}] \
-group [get_clocks {clk2}]
Problem observed:
A 1-bit synchronizer is needed in each of the paths driving outputs A and B. However, only the missing 1-bit synchronizer in output B is detected.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
May I know the Quartus version and edition you are using?
I would like to test it on my side.
By reviewing you code "signal datao : std_logic_vector(0 to 1)", this is declaring the vector signal hold two bit while in your code "datao <= datai & '1'" and "Output_A <= datao(0)" show is only hold one bit.
Thanks
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Mylee,
Yes, sure. I am using Quartus Prime Pro 19.3 Linux :)
In fact, in the previous code, you are right, the CDC was not detected because it had already two registers.
The reason I created this post was to reproduce the effect I see in a larger project, which would be difficult to share here.
I believe I have now managed to isolate the issue better. It seems that CDC-50001 DOES not work if the clock domain crossing is starting from an IP component pin. (nothing related to the vector, sorry)
For instance, the crossing from the IP pin "locked" to "Output_A" is not detected in the CDC-50001 DRC check, while the crossing from "locked_reg" to "Output_B" is.
Note that "clk1" and "outclk_0" belong to the same group, which is unrelated to clk2.
Therefore, the crossing from "locked" to "Output_A" should have been detected with the missing 1-bit synchronizer flag (DRC check CDC-50001)
This post is part of a larger effort in view of detecting mis-implemented clock domain crossings in larger projects we have here at CERN.
We like very much the Intel DRC check report, but we have leaned thorugh the experience in one of our projects that CDC-50001 does not work in this case, i.e. when the clock domain crossing involves an IP-component pin.
Can you help us out solving this issue?
Best Regards.
Marcos
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
For your reference:
VHDL file:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
entity cdc is
port (
clk1 : in std_logic;
clk2 : in std_logic;
rst : in std_logic;
Output_A : out std_logic;
Output_B : out std_logic
);
end entity;
architecture rtl of cdc is
signal locked : std_logic;
signal locked_reg : std_logic;
signal clk1_pll : std_logic;
component pll is
port (
rst : in std_logic := 'X'; -- reset
refclk : in std_logic := 'X'; -- clk
locked : out std_logic; -- export
outclk_0 : out std_logic -- clk
);
end component pll;
begin
u0 : component pll
port map (
rst => rst, -- reset.reset
refclk => clk1, -- refclk.clk
locked => locked, -- locked.export
outclk_0 => clk1_pll -- outclk0.clk
);
process (clk1_pll) is
begin
if rising_edge(clk1_pll) then
locked_reg <= locked;
end if;
end process;
process (clk2) is
begin
if rising_edge(clk2) then
Output_A <= locked;
Output_B <= locked_reg;
end if;
end process;
end architecture;
SDC file:
#**************************************************************
# Create Clock
#**************************************************************
create_clock -name {clk2} -period 10.000 -waveform { 0.000 5.000 } [get_ports {clk2}]
create_clock -name {clk1} -period 10.000 -waveform { 0.000 5.000 } [get_ports {clk1}]
#**************************************************************
# Create Generated Clock
#**************************************************************
create_generated_clock -name {u0|iopll_0|outclk0} -source [get_pins {u0|iopll_0|altera_iopll_i|twentynm_pll|iopll_inst|refclk[0]}] -duty_cycle 50/1 -multiply_by 6 -divide_by 6 -master_clock {clk1} [get_pins {u0|iopll_0|altera_iopll_i|twentynm_pll|iopll_inst|outclk[0]}]
#**************************************************************
# Set Clock Latency
#**************************************************************
#**************************************************************
# Set Clock Uncertainty
#**************************************************************
set_clock_uncertainty -rise_from [get_clocks {clk1}] -rise_to [get_clocks {clk1}] 0.030
set_clock_uncertainty -rise_from [get_clocks {clk1}] -fall_to [get_clocks {clk1}] 0.030
set_clock_uncertainty -fall_from [get_clocks {clk1}] -rise_to [get_clocks {clk1}] 0.030
set_clock_uncertainty -fall_from [get_clocks {clk1}] -fall_to [get_clocks {clk1}] 0.030
set_clock_uncertainty -rise_from [get_clocks {clk2}] -rise_to [get_clocks {clk2}] 0.030
set_clock_uncertainty -rise_from [get_clocks {clk2}] -fall_to [get_clocks {clk2}] 0.030
set_clock_uncertainty -fall_from [get_clocks {clk2}] -rise_to [get_clocks {clk2}] 0.030
set_clock_uncertainty -fall_from [get_clocks {clk2}] -fall_to [get_clocks {clk2}] 0.030
#**************************************************************
# Set Input Delay
#**************************************************************
#**************************************************************
# Set Output Delay
#**************************************************************
#**************************************************************
# Set Clock Groups
#**************************************************************
set_clock_groups -asynchronous -group [get_clocks {clk1 u0|iopll_0|outclk0}] -group [get_clocks {clk2}]
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
May I have the .qar design file (include the test bench file) for further investigate?
Thanks
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
Yes, sure. Here it is :)
There is no testbench though.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
It seems like the output for pll_locked to output_a is not a timing path.
CDC rules only show violation for timing paths.
Thanks
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
Indeed. There is an internal request at intel to discuss if this port should be timed or not.
I believe it should. In one way or the other the DRC check has to be able to detect a missing synchronizer from an IP port, right?
Cheers.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
It depends on whether we have the DRC check rule that was able to do it. My suggestion is in your internal request, if this feature does not exist, request them to have a enhancement on it.

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page