--==============================================================================
-- © 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_chk.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-checker (prbs_chk)
--
--! @brief parallel unfolded PRBS-checker with clock enable signal
--! Frame PRBS checker
--! Convention: LSB first received
--!
--! @author Eduardo Brandao de Souza Mendes - eduardo.brandao.de.souza.mendes@cern.ch
--! @date 22\10\2019
--! @version 1.0
--! @details
--!
--! Dependencies:\n
--!
--!
--! References:\n
--! \n
--!
--!
--! Modified by:\n
--! Author: Eduardo Brandao de Souza Mendes
-------------------------------------------------------------------------------
--! \n\nLast changes:\n
--! 22\10\2019 - EBSM - Created\n
--! 14\07\2020 - EBSM - Reset error and locked flag, check if pattern is not constant before locking\n
--!
-------------------------------------------------------------------------------
--! @todo - \n
--! Add error counting \n
--
-------------------------------------------------------------------------------
--==============================================================================
--! Entity declaration for prbs_chk
--==============================================================================
entity prbs_chk is
generic (
g_GOOD_FRAME_TO_LOCK : integer := 15 ; --! Number of correct frames predicted for PRBS to go locked (g_GOOD_FRAME_TO_LOCK+2)
g_BAD_FRAME_TO_UNLOCK : integer := 5 ; --! Number of wrong received frames for PRBS to go unlocked (g_BAD_FRAME_TO_UNLOCK+2)
g_PARAL_FACTOR : integer := 254 ; --! Size of parallel bus: it is assumed in this implementation that the size of the parallel bus is bigger than the length of the polynomial
g_PRBS_POLYNOMIAL : std_logic_vector := "11000001" --! Notation: x^7 + x^6 + 1 (PRBS-7)
);
port (
clk_i : in std_logic; --! clock input
reset_i : in std_logic; --! active high sync. reset <--- N ---> ____ ____ ____ ____
en_i : in std_logic; --! enable input ______/ \_____/ \_____/ \_____/ \_____/ \_____/
data_i : in std_logic_vector(g_PARAL_FACTOR-1 downto 0); --! Input data X D1 X D2 X D3 X D4-error X D5 X
data_o : out std_logic_vector(g_PARAL_FACTOR-1 downto 0); --! PRBS output expected data X D0 X D1 X D2 X D3 X D4____X____ - Latency is 2N cycles
error_o : out std_logic; --! PRBS Frame error ______________________________________________________/ \ - Kept to one for the whole duration; Latency is 2N+1 cycles
locked_o : out std_logic --! PRBS locked <-------- 2N ---------> <-+1->
);
end prbs_chk;
--==============================================================================
-- architecture declaration
--==============================================================================
architecture rtl of prbs_chk is
--! Function declaration
function fcn_max(arg1 : integer; arg2 : integer) return integer is
begin
if(arg1 > arg2) then
return arg1;
else
return arg2;
end if;
end fcn_max;
--! Constant declaration
--! Signal declaration
signal seed : std_logic_vector(g_PRBS_POLYNOMIAL'length-2 downto 0); --! Seed for polynomial
signal load : std_logic; --! Load seed when not locked
signal error : std_logic; --! PRBS error
signal data_notzero : std_logic; --! Check if data is not always 0 before locking
signal data_chk : std_logic_vector(g_PARAL_FACTOR-1 downto 0); --! PRBS output data
--------------------------------------------------------------------------------------------------------------
-- FSM PRBS-locking
-- principle:
-- HUNT : received a correct frame -> GOING_LOCK
-- received a wrong frame -> HUNT
-- GOING_LOCK : received a consecutive number of correct frame -> LOCK
-- received a wrong frame -> HUNT
-- LOCK : received a wrong frame -> GOING_HUNT
-- GOING_HUNT : received a consecutive number of wrong frame -> HUNT
-- received a correct frame -> LOCK
type t_PRBS_LOCK_STATE is (HUNT, GOING_LOCK, LOCK, GOING_HUNT);
signal prbs_lock_state : t_PRBS_LOCK_STATE;
signal frame_cntr : integer range 0 to fcn_max(g_BAD_FRAME_TO_UNLOCK, g_GOOD_FRAME_TO_LOCK);
--------------------------------------------------------------------------------------------------------------
signal data_r : std_logic_vector(data_i'range);
signal data_r2 : std_logic_vector(data_i'range);
--! Component declaration
component 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 component prbs_gen;
begin
--! Seed is retrieved from the input data
seed <= data_i(seed'range);
--! Component declaration of prbs generator
cmp_prbs_gen : prbs_gen
generic map(
g_PARAL_FACTOR => g_PARAL_FACTOR,
g_PRBS_POLYNOMIAL => g_PRBS_POLYNOMIAL
)
port map(
clk_i => clk_i ,
en_i => en_i ,
reset_i => reset_i,
seed_i => seed ,
load_i => load ,
data_o => data_chk,
data_valid_o => open
);
--============================================================================
-- Process p_prbs_lock_fsm
--============================================================================
p_prbs_lock_fsm : process(clk_i)
begin
if(clk_i'event and clk_i = '1') then
if(reset_i = '1') then
prbs_lock_state <= HUNT;
else
if(en_i='1') then
case prbs_lock_state is
when HUNT =>
if(error='0') then
prbs_lock_state <= GOING_LOCK;
end if;
when GOING_LOCK =>
if(error='1') then
prbs_lock_state <= HUNT;
elsif(frame_cntr >= g_GOOD_FRAME_TO_LOCK) then
if(data_notzero='1') then
prbs_lock_state <= LOCK;
else
prbs_lock_state <= HUNT;
end if;
end if;
when LOCK =>
if(error='1') then
prbs_lock_state <= GOING_HUNT;
end if;
when GOING_HUNT =>
if(error='0') then
prbs_lock_state <= LOCK;
elsif(frame_cntr >= g_BAD_FRAME_TO_UNLOCK) then
prbs_lock_state <= HUNT;
end if;
when others => prbs_lock_state <= HUNT;
end case;
end if;
end if;
end if;
end process p_prbs_lock_fsm;
--============================================================================
-- Process p_frame_cntr
--============================================================================
p_frame_cntr : process(clk_i)
begin
if(clk_i'event and clk_i = '1') then
if(reset_i = '1') then
frame_cntr <= 0;
else
if(en_i='1') then
if(prbs_lock_state = GOING_LOCK or prbs_lock_state=GOING_HUNT) then
if(frame_cntr < fcn_max(g_BAD_FRAME_TO_UNLOCK, g_GOOD_FRAME_TO_LOCK)) then
frame_cntr <= frame_cntr + 1;
else
frame_cntr <= 0;
end if;
else
frame_cntr <= 0;
end if;
end if;
end if;
end if;
end process p_frame_cntr;
--============================================================================
-- Process p_data_r
--============================================================================
p_data_r : process(clk_i)
begin
if(clk_i'event and clk_i = '1') then
if(en_i='1') then
data_r <= data_i;
data_r2 <= data_r;
end if;
end if;
end process p_data_r;
--============================================================================
-- Process p_status_out
--============================================================================
load <= '1' when prbs_lock_state = HUNT or prbs_lock_state = GOING_LOCK else '0';
error <= '1' when data_chk /= data_r2 else '0';
p_status_out : process(clk_i)
begin
if(clk_i'event and clk_i = '1') then
if(reset_i='1') then
locked_o <= '0';
error_o <= '0';
else
locked_o <= (not load);
error_o <= error;
end if;
end if;
end process p_status_out;
data_o <= data_chk;
--============================================================================
-- Process p_data_notzero - used to check if data it not always zero before locking
--============================================================================
p_data_notzero : process(clk_i)
begin
if(clk_i'event and clk_i = '1') then
if(prbs_lock_state = HUNT) then
data_notzero <= '0';
elsif(prbs_lock_state = GOING_LOCK) then
if(to_integer(unsigned(data_r2)) /= 0 ) then
data_notzero <= '1';
end if;
end if;
end if;
end process p_data_notzero;
end architecture rtl;
--==============================================================================
-- architecture end
--==============================================================================