Learning clock domain transitions on FPGAs (Xilinx) - Page 1
Forum section: electronics / general

author: Korken
author_rank: Regular Contributor
timestamp: August 24, 2017, 08:18:53 am
content: Hi all!I have been testing how to transition a signal from one clock domain to another, and read a lot of different blogs on the matter.So I decided to test a simple 2 flip flop synchronization in an Xilinx (Artix-7) FPGA, but I am not getting the expected result.What I have done to test this is to have the input signal be in a 50 MHz domain (the system clock), and I have generated a 26 MHz domain (to not be a multiple of the input clock) in which I want the output signal.But I get a Setup timing constraint violation from the Vivado tool that I do not understand why I am getting. As I understood the synchronization is there to solve exactly this problem.I know that the input signal must be stable for more than 1 clock in the output clock domain, but for now I am only testing signals doing one transition (low -> high) - so there are no fast pulses.This is my synchronization entity:Code:entity sync_2ff isport (clk_in : in std_logic;clk_out : in std_logic;input : in std_logic;output : out std_logic);end sync_2ff;architecture Behavioral of sync_2ff issignal s_r1 : std_logic := '0';signal s_r2 : std_logic := '0';signal s_r3 : std_logic := '0';begin-- Input register, in the input clock domainprocess (clk_in) isbeginif rising_edge(clk_in) thens_r1 <= input;end if;end process;-- Output registers, synchronizing the signalprocess (clk_out) isbeginif rising_edge(clk_out) thens_r2 <= s_r1; -- metastables_r3 <= s_r2; -- stableend if;end process;-- Connect the outputoutput <= s_r3;end Behavioral;Attached is an conceptual image over the design.And I get a timing violation between s_r1 and s_r2, so when I am crossing the clock domains.Could someone help a beginner in FPGAs, and help me get better insight? Thanks!

author: jefflieu
author_rank: Contributor
timestamp: August 24, 2017, 01:39:41 pm
content: Hi,The timing tool doesn't solve your timing problem, it just reports a that you WILL have problem transferring that signal from s_r1 to s_r2, and it is right, because you WILL violate setup/hold time of s_r2.What you did there with the synchroniser is not to avoid that violation, but tolerate it. By having another stage, the output of s_r3 will be much less likely to get into metastable state, therefore, subsequent logic will not be affected by the VIOLATION at s_r2.So in practice, people use:- Double Flop Synchroniser- Assign an attribute of "ASYNC" to the flop s_r2, s_r3- And tell the timing tool that, this path is special (false path or use a different maximum delay rather than the timing relationship between the 2 clocks).

author: fourtytwo42
author_rank: Super Contributor
timestamp: August 24, 2017, 05:55:37 pm
content: Yes another interesting point with HDL's is that compilers have been known to optimise out double flop synchronisers so make sure you label the intermediate signal and apply a keep to it

author: marshallh
author_rank: Unknown
timestamp: August 24, 2017, 08:09:37 pm
content: You need to tell the timing analyzer that your 2 clock domains are separate and not mesosychnronous. You can set false paths or put them in separate clock groups (two ways to accomplish the same thing).

author: John_ITIC
author_rank: Frequent Contributor
timestamp: August 24, 2017, 09:02:08 pm
content: In other words; the first FF in the synchronizer chain will have its setup time violated / unspecified. Setting a false path from the signal being synchronized to the first FF's D input will make the timing analyzer ignore this path for timing closure purposes. The first FF can (and will most likely) still go meta-stable but the meta-stable signal will not make its way through the second FF in the synchronizer chain.

author: NorthGuy
author_rank: Super Contributor
timestamp: August 24, 2017, 09:03:10 pm
content: Obviously, it doesn't make any sense to do timing analysis between asynchronous clock domains, so you either use "set_false_path" in XDC to tell Vivado not to attempt this for your specific path, or you tell it that your clocks are asynchronous by using "set_clock_groups" (this is the same as using "set_false_path" many times at once). Otherwise Vivado assumes all the clocks are synchronus and analyzes all the paths.https://www.xilinx.com/support/answers/44651.html

author: KE5FX
author_rank: Super Contributor
timestamp: August 24, 2017, 09:44:25 pm
content: Quote from: Xilinx answer record above<rant>Jeez, constraints are such a dumpster fire. Somebody fix this, please.</rant>

author: Korken
author_rank: Regular Contributor
timestamp: August 28, 2017, 07:15:04 am
content: Thank you all for the clarification! I finally understand why the timing is failing.Though, it feels like a large design would really clutter the constraints file. Is this common?

author: hamster_nz
author_rank: Super Contributor
timestamp: August 28, 2017, 07:55:57 am
content: Quote from: fourtytwo42 on August 24, 2017, 05:55:37 pmFor Xilinx best practice, you want to define the "ASYNC_REG" attribute. This will not only preserve the register, but also attempt to minimize the routing delays between the registers.

author: rstofer
author_rank: Super Contributor
timestamp: August 28, 2017, 03:32:09 pm
content: Quote from: hamster_nz on August 28, 2017, 07:55:57 amI guess "how" would be an obvious question. I'll concede to not having much of a clue about constraints...Same story with "keep" - I have no idea!It is staggering how little I know about this stuff. That anything works must have been a matter of luck!

author: NorthGuy
author_rank: Super Contributor
timestamp: August 28, 2017, 04:34:51 pm
content: Quote from: rstofer on August 28, 2017, 03:32:09 pmFor pure single-click RTL design you don't need much. If you just specify the clock, and it'll do all the timing analysis automatically.

author: nctnico
author_rank: Super Contributor
timestamp: August 28, 2017, 04:45:46 pm
content: Quote from: NorthGuy on August 28, 2017, 04:34:51 pmNot entirely true. You will need to constrain the delay between the inputs to flipflops and the flipflops to outputs as well otherwise you can get funny behaviour as well.

author: rstofer
author_rank: Super Contributor
timestamp: August 28, 2017, 06:26:11 pm
content: Quote from: NorthGuy on August 28, 2017, 04:34:51 pmIt was pretty easy to tell ISE to ignore timing checks on signals coming in on pads from external, asynchronous sources. Haven't tumbled to that with Vivado but, apparently, I haven't needed to. My total experience with Vivado is really just the last few days implementing that LC3 project. So far, it works well as does the project. It's been interesting...I am just about ready to concede that I like Vivado better than ISE. Just about...

author: legacy
author_rank: Super Contributor
timestamp: August 28, 2017, 06:38:39 pm
content: Quote from: rstofer on August 28, 2017, 06:26:11 pmWhy do you need the special constraint for it?it shouldn't been required since there is only one clock: the main clock, attached to external crystal.You might want to use the DCM.PLL in order to triplicate it to handle external SRAM, but again ... there is just one source of synchronization.p.s.anyway, how do you handle it on ISE?

author: rstofer
author_rank: Super Contributor
timestamp: August 28, 2017, 06:58:32 pm
content: Quote from: legacy on August 28, 2017, 06:38:39 pmI was thinking more generally about the constraints file rather than specific timing issues. All I have in the .xdc file is the pinout, clock definition and perhaps some ILA signals.With ISE, I just added 'TIG' to the Net line in the UCF file:NET "Switches<0>" LOC = "G18" | TIG;No need to analyze timing from an external toggle switch. It will get debounced and synchronized in a dual FF circuit.

author: legacy
author_rank: Super Contributor
timestamp: August 28, 2017, 07:34:22 pm
content: ( I said "triplicate the frequency" because I was thinking about the Papilio/Pro board: it comes with a crystal of 33Mhz, the SRAM need to be clocked at 99Mhz. The DCM.PLL should supply the 3X! )

author: rstofer
author_rank: Super Contributor
timestamp: August 28, 2017, 08:02:15 pm
content: Quote from: legacy on August 28, 2017, 07:34:22 pmRight, the timing generator IP takes care of this for Microblaze projects. It's a pretty nice feature considering it is free.My ISE interest was strictly in getting rid of the annoying warnings about timing analysis, thus the TIG.Yes, the entire purpose of the DCMs is to keep things synchronized. I used the DCM on a couple of projects but I don't recall the circumstances. In any event, everything worked out.

author: hamster_nz
author_rank: Super Contributor
timestamp: August 28, 2017, 09:11:33 pm
content: Quote from: rstofer on August 28, 2017, 03:32:09 pmHere's how I would do it (in VHDL):Code:library IEEE;use IEEE.STD_LOGIC_1164.ALL;entity synchronizer isgeneric ( stages : natural := 3 );Port ( clk : in STD_LOGIC;i : in STD_LOGIC;o : out STD_LOGIC);end synchronizer;architecture Behavioral of synchronizer issignal flipflops : std_logic_vector(stages-1 downto 0):= (others => '0');attribute ASYNC_REG : string;attribute ASYNC_REG of flipflops: signal is "true";begino <= flipflops(flipflops'high);clk_proc: process(clk)beginif rising_edge(clk) thenflipflops <= flipflops(flipflops'high-1 downto 0) & i;end if;end process;end Behavioral;Here's what the documentation says about ASYNC_REG:Quote

author: rstofer
author_rank: Super Contributor
timestamp: August 28, 2017, 10:31:37 pm
content: Quote from: hamster_nz on August 28, 2017, 09:11:33 pmVery nice, thanks!Elsewhere, I believe you posted code to read a hex file and initialize RAM - thanks for that as well!