From Hamsterworks Wiki!
This mini FPGA Project was completed in Jan 2016.
One of the key things you learn is that for FPGA designs to work correctly is that signal transitions should never occur very close to the active clock edge. This is because for a flipflop to work correctly it needs a signal to be stable for short time before and after the clock ticks (called setup and hold time). When you get a signal that can change anytime it likes it can cause your design to fail in unexpected ways.
One way for it to cause failures is that if an input is used in two or more places within your design the difference the uneven in routing delays can cause the same signal appear to have different values.
Another way is that if the input signal changes at just the wrong time then a flip-flop can go into a meta-stable state. This is where the two feedback paths within the flipflip are fighting each other to resolve into a stable '1' or '0' state, causing the output to bounce around for a short while. To ensure that these errors don't creep happen in your design any asynchronous signal needs to be synchronized with the logic's clock domain.
To do this the signal is 'sampled' using a flip=flop, then the output of that flipflop is then sampled the following clock cycle by a second flipflop, giving as much time as possible for the initial flip-flop to 'snap out' of any metastable state it should find itself in. When working at high speed and / or need high reliability additional stages of synchronization may also be required - each stage reduces the chance of an error exponentially.
This setup looks much like a shift register:
Vivado is pretty good at guessing when you are trying to synchronize a signal, but sometimes the tools decide to incorrectly implement the design using a shift register primative rather than a series of flip-flops. To avoid these problems you should ensure that the signals involved in synchronization have the ASYNC_REG attribute set to'true'. From http://www.xilinx.com/support/documentation/sw_manuals/xilinx2014_2/ug912-vivado-properties.pdf :
Specifying ASYNC_REG also affects optimization, placement, and routing to improve Mean Time Between Failure (MTBF) for registers that may go metastable. If ASYNC_REG is applied, the placer will ensure the flip-flops on a synchronization chain are placed closely to maximize MTBF. Registers with ASYNC_REG that are directly connected will be grouped and placed together into a single SLICE, assuming they have a compatible control set and the number of registers does not exceed the available resources of the SLICE.
When you instantiate this module you can set the 'stages' generic to control the number of flipflops in the synchronizer.
library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity synchronizer is generic ( stages : natural := 3 ); Port ( clk : in STD_LOGIC; i : in STD_LOGIC; o : out STD_LOGIC); end synchronizer; architecture Behavioral of synchronizer is signal flipflops : std_logic_vector(stages-1 downto 0):= (others => '0'); attribute ASYNC_REG : string; attribute ASYNC_REG of flipflops: signal is "true"; begin o <= flipflops(flipflops'high); clk_proc: process(clk) begin if rising_edge(clk) then flipflops <= flipflops(flipflops'high-1 downto 0) & i; end if; end process; end Behavioral;