--============================================================================== -- © Copyright CERN for the benefit of the HPTD interest group 2019. All rights not -- expressly granted are reserved. -- -- This file is part of TClink. -- -- TClink is free VHDL code: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- TClink is distributed in the hope that it will be useful, -- but WITHout ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with TClink. If not, see . --============================================================================== --! @file prbs_gen.vhd --============================================================================== --! Standard library library ieee; --! Standard packages use ieee.std_logic_1164.all; use ieee.numeric_std.all; --! Specific packages ------------------------------------------------------------------------------- -- -- -- CERN, EP-ESE-BE, HPTD -- -- ------------------------------------------------------------------------------- -- -- unit name: PRBS-generator (prbs_gen) -- --! @brief parallel unfolded PRBS-generator with clock enable signal --! Convention: LSB first transmitted --! A multicycle path timing constraint might be applied from node_ff to node_ff register and from node_ff to data_o register --! The number of cycles allowed for this operation is equal to the PERIOD of en_i --! --! @author Eduardo Brandao de Souza Mendes - eduardo.brandao.de.souza.mendes@cern.ch --! @date 21\10\2019 --! @version 1.0 --! @details --! --! Dependencies:\n --! --! --! References:\n --! \n --! --! --! Modified by:\n --! Author: Eduardo Brandao de Souza Mendes ------------------------------------------------------------------------------- --! \n\nLast changes:\n --! 21\10\2019 - EBSM - Created\n --! 11\06\2020 - EBSM - Data valid output\n ------------------------------------------------------------------------------- --! @todo - \n --! \n -- ------------------------------------------------------------------------------- --============================================================================== --! Entity declaration for prbs_gen --============================================================================== entity prbs_gen is generic ( g_PARAL_FACTOR : integer := 254 ; --! Size of parallel bus g_PRBS_POLYNOMIAL : std_logic_vector := "11000001" --! Notation: x^7 + x^6 + 1 (PRBS-7) ); port ( clk_i : in std_logic; --! clock input en_i : in std_logic; --! enable input reset_i : in std_logic; --! active high sync. reset seed_i : in std_logic_vector(g_PRBS_POLYNOMIAL'length-2 downto 0); --! Seed for polynomial load_i : in std_logic; --! Load seed data_o : out std_logic_vector(g_PARAL_FACTOR-1 downto 0); --! PRBS output data data_valid_o : out std_logic --! PRBS data valid output ); end prbs_gen; --============================================================================== -- architecture declaration --============================================================================== architecture rtl of prbs_gen is --! Function declaration function fcn_xor_reduce(arg1 : std_logic_vector; arg_mask : std_logic_vector) return std_logic is variable result : std_logic := '0'; begin for i in arg1'range loop result := result xor (arg1(i) and arg_mask(i)); end loop; return result; end fcn_xor_reduce; --! Constant declaration --! Signal declaration type t_node_array is array (g_PARAL_FACTOR-1 downto 0) of std_logic_vector(g_PRBS_POLYNOMIAL'length-2 downto 0); signal node_array : t_node_array; signal parallel_data : std_logic_vector(g_PARAL_FACTOR-1 downto 0); signal node_ff : std_logic_vector(g_PRBS_POLYNOMIAL'length-2 downto 0); begin ----------------------------------------------------------------------------------------------------------- --! Generates all LFSR states in an unfolded fashion -- --! Ex. for PRBS-7 (x^7 + x^6 + 1) unfolded n times -- --! ------------------------------------------------------------------------------------------------------- --! lin-j) -- --! col-k) Ekj represent the node_array points -- --! En0_r xor En6_r -> E06 E05 E04 E03 E02 E01 E00 -> Parallel data(MSB) -- --! \ \ \ \ \ \ -- --! E00 xor E06 -> E16 E15 E14 E13 E12 E11 E10 -> Parallel data -- --! \ \ \ \ \ \ -- --! ... -- --! \ \ \ \ \ \ -- --! En-10 xor En-16 -> En6 En5 En4 En3 En2 En1 En0 -> Parallel data (LSB) -- --! ------------------------------------------------------------------------------------------------------- --! Last column is then registered to node_ff N and it is used to feed column 0 -- ----------------------------------------------------------------------------------------------------------- gen_shift_lsfr : for k in 0 to (g_PARAL_FACTOR-1) generate gen_first_state : if k = 0 generate node_array(k) <= node_ff; end generate gen_first_state; gen_other_states : if (k > 0) generate node_array(k)(node_array(k)'left-1 downto 0) <= node_array(k-1)(node_array(k-1)'left downto 1); node_array(k)(node_array(k)'left) <= fcn_xor_reduce(node_array(k-1), g_PRBS_POLYNOMIAL(g_PRBS_POLYNOMIAL'left-1 downto 0)); end generate gen_other_states; parallel_data(k) <= node_array(k)(0); end generate gen_shift_lsfr; --! p_node_ff generates the FF memory feedback for the prbs generator p_node_ff : process(clk_i) begin if(clk_i'event and clk_i = '1') then if(reset_i = '1') then node_ff <= seed_i; else if(en_i = '1') then if(load_i='0') then node_ff(node_ff'left-1 downto 0) <= node_array(g_PARAL_FACTOR-1)(node_array(g_PARAL_FACTOR-1)'left downto 1); node_ff(node_ff'left) <= fcn_xor_reduce(node_array(g_PARAL_FACTOR-1), g_PRBS_POLYNOMIAL(g_PRBS_POLYNOMIAL'left-1 downto 0)); else node_ff <= seed_i; end if; end if; end if; end if; end process p_node_ff; --! p_data_o generates the output data p_data_o : process(clk_i) begin if(clk_i'event and clk_i = '1') then if(reset_i = '1') then data_o <= (others => '0'); data_valid_o <= '0'; else if(en_i = '1') then data_o <= parallel_data; end if; if(en_i = '1') then data_valid_o <= '1'; else data_valid_o <= '0'; end if; end if; end if; end process p_data_o; end architecture rtl; --============================================================================== -- architecture end --==============================================================================