--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library unisim;
+use unisim.vcomponents.all;
+
+
+entity metastability_detector is
+ port (
+ clk_i: in std_logic;
+ sig_i: in std_logic;
+
+ count_sync: out std_logic_vector(7 downto 0);
+ count_async: out std_logic_vector(7 downto 0)
+ );
+end metastability_detector;
+
+
+architecture behavioral of metastability_detector is
+
+ signal sig_a: std_logic;
+ signal sig_b: std_logic;
+
+ signal is_metastable: std_logic;
+ signal sync_counter_reg: unsigned(7 downto 0);
+
+ -- 5, 4 - Asynchronously set to zero by is_metastable, synchronize the rising edge out of reset
+ -- 3, 2 - Synchronize the falling edge into reset
+ -- 1, 0 - Edge detection
+ signal async_shift_reg: std_logic_vector(5 downto 0) := (others => '1');
+ signal was_metastable: std_logic;
+ signal async_counter_reg: unsigned(7 downto 0);
+
+begin
+
+ ------------------------------------------------------------------------
+ -- Detector portion
+ --
+ -- Two buffers buffering the same signal - their outputs should always
+ -- match, but might not if the input is in a metastable state. This
+ -- won't detect all metastabilty, just the metastability that actually
+ -- causes problems.
+
+ e_buf_a: lut1
+ generic map (INIT => "10")
+ port map (
+ I0 => sig_i,
+ O => sig_a
+ );
+
+ e_buf_b: lut1
+ generic map (INIT => "10")
+ port map (
+ I0 => sig_i,
+ O => sig_b
+ );
+
+ is_metastable <= '1' when sig_a /= sig_b else '0';
+
+ ------------------------------------------------------------------------
+ -- Event counters
+ --
+ -- Two metastability event counters:
+ -- - Counter that counts events where metastability persists all the way
+ -- to the next clock edge
+ -- - Asyncrhonous trigger that detects all metastability events, even if
+ -- they settle out before the next clock edge
+
+ -- Event counters
+ process (clk_i, is_metastable, was_metastable)
+ begin
+ if rising_edge(clk_i) then
+ if is_metastable = '1' then
+ sync_counter_reg <= sync_counter_reg + 1;
+ end if;
+ if was_metastable = '1' then
+ async_counter_reg <= async_counter_reg + 1;
+ end if;
+ end if;
+ end process;
+
+ -- Asynchronous glitch detector
+ process (clk_i, is_metastable)
+ begin
+ -- First two stages, asynchronously reset to zero to detect short
+ -- metastability events, synchronously shift 1 back in through two
+ -- stages to prevent metastability on the rising edge when recovering
+ if is_metastable = '1' then
+ async_shift_reg(5 downto 4) <= "00";
+ elsif rising_edge(clk_i) then
+ async_shift_reg(5 downto 4) <= '1' & async_shift_reg(5);
+ end if;
+
+ -- Next two stages, deal with metastability on falling edges, since the
+ -- previous stages were asynchronously reset
+ if rising_edge(clk_i) then
+ async_shift_reg(3 downto 2) <= async_shift_reg(4 downto 3);
+ end if;
+
+ -- Next two stages, all metastability has been dealt with and signals
+ -- are stable - detect rising edges as events
+ if rising_edge(clk_i) then
+ async_shift_reg(1 downto 0) <= async_shift_reg(2 downto 1);
+ end if;
+ end process;
+ was_metastable <= '1' when async_shift_reg(1 downto 0) = "10" else '0';
+
+ count_sync <= std_logic_vector(sync_counter_reg);
+ count_async <= std_logic_vector(async_counter_reg);
+
+end behavioral;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+use ieee.std_logic_misc.all;
+
+library unisim;
+use unisim.vcomponents.all;
+
+library utility;
+
+library nexys2_lib;
+
+
+entity nexyx2_metastability is
+ port (
+ clk_50: in std_logic;
+ DstmIFCLK: in std_logic;
+ seg: out std_logic_vector(6 downto 0);
+ dp: out std_logic;
+ an: out std_logic_vector(3 downto 0)
+ );
+end nexyx2_metastability;
+
+
+architecture behavioral of nexyx2_metastability is
+
+ -- Number of metastability detectors
+ constant INSTANCES: positive := 4096;
+
+ -- Metastability creation and detection signals
+ signal metastable_reg: std_logic_vector(INSTANCES-1 downto 0);
+ signal a_buf: std_logic_vector(INSTANCES-1 downto 0);
+ signal b_buf: std_logic_vector(INSTANCES-1 downto 0);
+ signal glitch: std_logic_vector(INSTANCES-1 downto 0);
+ signal detect: std_logic_vector(INSTANCES-1 downto 0);
+
+ signal count_reg: std_logic_vector(15 downto 0);
+
+ -- Output-related signals
+ signal clk_div_reg: unsigned(15 downto 0);
+ signal seg_0: std_logic_vector(6 downto 0);
+ signal seg_1: std_logic_vector(6 downto 0);
+ signal seg_2: std_logic_vector(6 downto 0);
+ signal seg_3: std_logic_vector(6 downto 0);
+
+begin
+
+ ------------------------------------------------------------------------
+ -- Generate a potentially metastable test signal
+
+ g_meta: for i in 0 to INSTANCES-1 generate
+ e_test_reg: fdce
+ port map (
+ D => DstmIFCLK,
+ CE => '1',
+ C => clk_50,
+ CLR => '0',
+ Q => metastable_reg(i)
+ );
+
+ e_buf_a: lut1
+ generic map (INIT => "10")
+ port map (
+ I0 => metastable_reg(i),
+ O => a_buf(i)
+ );
+
+ e_buf_b: lut1
+ generic map (INIT => "10")
+ port map (
+ I0 => metastable_reg(i),
+ O => b_buf(i)
+ );
+
+ glitch(i) <= '1' when a_buf(i) /= b_buf(i) else '0';
+
+ e_detect: entity utility.glitch_detector
+ port map (
+ clk_i => clk_50,
+ glitch => glitch(i),
+ rise => detect(i),
+ fall => open
+ );
+ end generate g_meta;
+
+
+ ------------------------------------------------------------------------
+ -- Count metastability events
+
+ process (clk_50, detect, count_reg)
+ begin
+ if rising_edge(clk_50) then
+ if or_reduce(detect) = '1' then
+ count_reg <= std_logic_vector(unsigned(count_reg) + 1);
+ end if;
+ end if;
+ end process;
+
+
+ ------------------------------------------------------------------------
+ -- Display results
+
+ e_seg0: entity nexys2_lib.seven_seg_hex
+ port map (
+ data_in => count_reg(3 downto 0),
+ seg_out => seg_0
+ );
+
+ e_seg1: entity nexys2_lib.seven_seg_hex
+ port map (
+ data_in => count_reg(7 downto 4),
+ seg_out => seg_1
+ );
+
+ e_seg2: entity nexys2_lib.seven_seg_hex
+ port map (
+ data_in => count_reg(11 downto 8),
+ seg_out => seg_2
+ );
+
+ e_seg3: entity nexys2_lib.seven_seg_hex
+ port map (
+ data_in => count_reg(15 downto 12),
+ seg_out => seg_3
+ );
+
+ process (clk_50, clk_div_reg)
+ begin
+ if rising_edge(clk_50) then
+ clk_div_reg <= clk_div_reg + 1;
+ end if;
+ end process;
+
+ e_sseg: entity nexys2_lib.seven_seg_mux
+ port map (
+ clk_in => clk_div_reg(15),
+ clk_en => '1',
+
+ seg_0_in => seg_0,
+ seg_1_in => seg_1,
+ seg_2_in => seg_2,
+ seg_3_in => seg_3,
+ dps_in => "1111",
+
+ seg_out => seg,
+ dp_out => dp,
+ an_out => an
+ );
+
+end behavioral;