--- /dev/null
+------------------------------------------------------------------------
+-- Link Synchronizer for TRBv3 Serdes Links
+-- From Mupix 8 documentation it is not possible to use the synchronizer
+-- present in the Serdes blocks (??).
+-- T. Weber, Ruhr University Bochum
+------------------------------------------------------------------------
+library IEEE;
+use IEEE.std_logic_1164.all;
+use IEEE.numeric_std.all;
+
+entity LinkSynchronizer is
+ generic (
+ clk_speed : integer := 8); -- clk speed in ns
+ port (
+ clk_in : in std_logic; -- clk in synchronous to serdes rx clock
+ reset_in : in std_logic; -- reset
+ comma_in : in std_logic; -- comma word detected by serdes
+ cverr_in : in std_logic; -- serdes data error in
+ link_sync_out : out std_logic; -- realign to link out pulse low to high to start word alignminment
+ link_sync_flag : out std_logic; -- link is synchronous
+ comma_counter_out : out std_logic_vector(15 downto 0)); -- comma word counter
+end entity LinkSynchronizer;
+
+architecture rtl of LinkSynchronizer is
+
+ constant look_for_comma_period : integer := 1000000; -- period to look for valid commas in ns
+ constant look_counter_max : integer := look_for_comma_period/clk_speed;
+
+ type sync_state_type is (idle, sync, notsync);
+ signal sync_fsm : sync_state_type := idle;
+
+ signal look_counter : integer range 0 to look_counter_max - 1 := 0;
+ signal comma_counter : integer range 0 to 2**16 - 1 := 0;
+ signal look_enable : std_logic := '0';
+ signal comma_seen : std_logic := '0';
+ signal link_sync_i : std_logic := '0';
+
+begin -- architecture rtl
+
+ counter_proc : process (clk_in) is
+ begin -- process counter_proc
+ if rising_edge(clk_in) then
+ if reset_in = '1' then
+ look_counter <= 0;
+ look_enable <= '0';
+ else
+ look_counter <= look_counter + 1;
+ look_enable <= '0';
+ if look_counter = look_counter_max - 1 then
+ look_enable <= '1';
+ look_counter <= 0;
+ end if;
+ end if;
+ end if;
+ end process counter_proc;
+
+ sync_proc : process (clk_in) is
+ begin -- process sync_proc
+ if rising_edge(clk_in) then
+ if reset_in = '1' then
+ comma_seen <= '0';
+ link_sync_i <= '0';
+ comma_counter <= 0;
+ sync_fsm <= idle;
+ else
+ link_sync_i <= '1';
+ -- look for incoming comma characters
+ if comma_in = '1' and cverr_in = '0' then
+ comma_seen <= '1';
+ comma_counter <= comma_counter + 1;
+ end if;
+ link_sync_i <= '1';
+ case sync_fsm is
+ when idle =>
+ sync_fsm <= idle;
+ link_sync_flag <= '0';
+ if look_enable = '1' then
+ if comma_seen = '1' then
+ sync_fsm <= sync;
+ else
+ sync_fsm <= notsync;
+ link_sync_i <= '0';
+ end if;
+ comma_seen <= '0';
+ end if;
+ when sync =>
+ link_sync_flag <= '1';
+ sync_fsm <= sync;
+ if look_enable = '1' then
+ if comma_seen = '0' then
+ sync_fsm <= notsync;
+ link_sync_i <= '0';
+ end if;
+ comma_seen <= '0';
+ end if;
+ when notsync =>
+ link_sync_flag <= '0';
+ sync_fsm <= notsync;
+ if look_enable = '1' then
+ if comma_seen = '1' then
+ sync_fsm <= sync;
+ else
+ link_sync_i <= '0';
+ end if;
+ comma_seen <= '0';
+ end if;
+ end case;
+ end if;
+ end if;
+ end process sync_proc;
+
+ comma_counter_out <= std_logic_vector(to_unsigned(comma_counter, 16));
+ link_sync_out <= link_sync_i;
+
+end architecture rtl;
--- /dev/null
+----------------------------------
+--Test bench for link synchronizer
+--T. Weber, Ruhr University Bochum
+----------------------------------
+library IEEE;
+use IEEE.std_logic_1164.all;
+use IEEE.numeric_std.all;
+
+entity LinkSynchronizerTest is
+end entity LinkSynchronizerTest;
+
+architecture sim of LinkSynchronizerTest is
+
+ component LinkSynchronizer is
+ generic (
+ clk_speed : integer);
+ port (
+ clk_in : in std_logic;
+ reset_in : in std_logic;
+ comma_in : in std_logic;
+ cverr_in : in std_logic;
+ link_sync_out : out std_logic;
+ link_sync_flag : out std_logic;
+ comma_counter_out : out std_logic_vector(15 downto 0));
+ end component LinkSynchronizer;
+
+ constant clk_speed : integer := 10;
+ constant clk_period : time := 10 ns;
+
+ signal clk_in : std_logic;
+ signal reset_in : std_logic := '0';
+ signal comma_in : std_logic := '0';
+ signal cverr_in : std_logic := '0';
+ signal link_sync_out : std_logic;
+ signal link_sync_flag : std_logic;
+ signal comma_counter_out : std_logic_vector(15 downto 0);
+
+ signal generate_commas_i : std_logic := '0';
+ signal generate_counter : integer := 0;
+
+begin
+
+ LinkSynchronizer_1 : entity work.LinkSynchronizer
+ generic map (
+ clk_speed => clk_speed)
+ port map (
+ clk_in => clk_in,
+ reset_in => reset_in,
+ comma_in => comma_in,
+ cverr_in => cverr_in,
+ link_sync_out => link_sync_out,
+ link_sync_flag => link_sync_flag,
+ comma_counter_out => comma_counter_out);
+
+ clk_gen : process is
+ begin
+ clk_in <= '0';
+ wait for clk_period/2;
+ clk_in <= '1';
+ wait for clk_period/2;
+ end process clk_gen;
+
+ comma_gen : process(clk_in) is
+ begin -- process comma_gen
+ if rising_edge(clk_in) then
+ comma_in <= '0';
+ if generate_commas_i = '1' then
+ generate_counter <= generate_counter + 1;
+ if generate_counter = 200 then
+ generate_counter <= 0;
+ comma_in <= '1';
+ end if;
+ end if;
+ end if;
+ end process comma_gen;
+
+ stimulus : process is
+ begin
+ generate_commas_i <= '0';
+ wait for 3 ms;
+ generate_commas_i <= '1';
+ wait for 3 ms;
+ generate_commas_i <= '0';
+ wait for 3 ms;
+ generate_commas_i <= '1';
+ wait;
+ end process stimulus;
+
+end architecture;