--============================================================================== -- © 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 tb_cdc_tx.vhd --============================================================================== --! Standard library library ieee; --! Standard packages use ieee.std_logic_1164.all; use std.textio.all; use ieee.std_logic_textio.all; use ieee.numeric_std.all; use ieee.math_real.uniform; use ieee.math_real.floor; --! Specific packages ------------------------------------------------------------------------------- -- -- -- CERN, EP-ESE-BE, HPTD -- -- ------------------------------------------------------------------------------- -- -- unit name: mesochronous CDC test-bench (tb_cdc_tx) -- --! @brief Mesochronous CDC test-bench --! Very simple test bench only to check briefly the operation of circuitry --! --! @author Eduardo Brandao de Souza Mendes - eduardo.brandao.de.souza.mendes@cern.ch --! @date 30\06\2020 --! @version 1.0 --! @details --! --! Dependencies:\n --! --! --! References:\n --! \n --! --! --! Modified by:\n --! Author: Eduardo Brandao de Souza Mendes ------------------------------------------------------------------------------- --! \n\nLast changes:\n --! 30\06\2020 - EBSM - Created\n --! ------------------------------------------------------------------------------- --! @todo - \n --! Extensive verification \n -- ------------------------------------------------------------------------------- --============================================================================== --! Entity declaration for tb_cdc_tx --============================================================================== entity tb_cdc_tx is generic( g_CLOCK_A_RATIO : integer := 1; g_CLOCK_B_RATIO : integer := 8 ); end tb_cdc_tx; --============================================================================== -- architecture declaration --============================================================================== architecture tb of tb_cdc_tx is --! Function declaration --! Constant declaration constant c_STROBE_PERIOD : time := 25.2 ns; constant c_CLOCK_FREERUN_PERIOD : time := 8.0 ns; constant c_PRBS_POLYNOMIAL : std_logic_vector(23 downto 0) := (23 => '1', 18=> '1', 0 => '1', others => '0'); -- PRBS-23 testing (x^7 + x^6 + 1) --! Signal declaration signal clk_freerun : std_logic; signal clk_a : std_logic; signal clk_b : std_logic; -- CLK_A signal prbsgen_en : std_logic; signal prbsgen_reset : std_logic; signal prbsgen_seed : std_logic_vector(c_PRBS_POLYNOMIAL'length-2 downto 0) := (others => '1'); signal prbsgen_load : std_logic; signal prbsgen_data : std_logic_vector(254-1 downto 0); signal prbsgen_data_valid : std_logic; signal reset_a : std_logic; signal data_a : std_logic_vector(254-1 downto 0); signal strobe_a : std_logic; signal data_b : std_logic_vector(254-1 downto 0); signal strobe_b : std_logic; signal ready_b : std_logic; -- CLK_B signal prbschk_reset : std_logic; signal prbschk_error : std_logic; signal prbschk_locked : std_logic; signal prbschk_data_chk : std_logic_vector(254-1 downto 0); -- Phase signal phase : std_logic_vector(9 downto 0); signal phase_calib : std_logic_vector(9 downto 0); --! Phase measured in first reset signal phase_force : std_logic; --! Force the phase to be the calibrated one -- Aux test-bench signal save_file : std_logic := '0'; --! Component declaration component cdc_tx is generic ( g_CLOCK_A_RATIO : integer := 1 ; --! Ratio between strobe period and clock A period g_CLOCK_B_RATIO : integer := 8 ; --! Ratio between strobe period and clock B period (>=4) g_ACC_PHASE : integer := 125*8; --! Phase accumulator number - only relevant for fixed phase operation g_PHASE_SIZE : integer := 10 --! ceil(log2(g_ACC_PHASE)) ); port ( -- Interface A (latch - from where data comes) reset_a_i : in std_logic; --! reset (only de-assert when all clocks and strobe A are stable) clk_a_i : in std_logic; --! clock A data_a_i : in std_logic_vector; --! data A strobe_a_i : in std_logic; --! strobe A -- Interface B (capture - to where data goes) clk_b_i : in std_logic; --! clock B data_b_o : out std_logic_vector; --! data B (connected to vector of same size as data_a_i) strobe_b_o : out std_logic; --! strobe B ready_b_o : out std_logic; --! ready B (CDC is operating) -- Only relevant for fixed-phase operation clk_freerun_i : in std_logic; --! Free-running clock (125MHz) phase_o : out std_logic_vector(g_PHASE_SIZE-1 downto 0); --! Phase to check fixed-phase phase_calib_i : in std_logic_vector(g_PHASE_SIZE-1 downto 0); --! Phase measured in first reset phase_force_i : in std_logic --! Force the phase to be the calibrated one ); end component cdc_tx; 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; component 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 component prbs_chk; begin --! ----------------------------------- Clock process ----------------------------------- p_clk_freerun : process begin clk_freerun <= '0'; wait for c_CLOCK_FREERUN_PERIOD/2; clk_freerun <= '1'; wait for c_CLOCK_FREERUN_PERIOD/2; end process; p_clk_a : process begin clk_a <= '0'; wait for (c_STROBE_PERIOD/g_CLOCK_A_RATIO)/2; clk_a <= '1'; wait for (c_STROBE_PERIOD/g_CLOCK_A_RATIO)/2; end process; p_clk_b : process begin clk_b <= '0'; wait for (c_STROBE_PERIOD/g_CLOCK_B_RATIO)/2; clk_b <= '1'; wait for (c_STROBE_PERIOD/g_CLOCK_B_RATIO)/2; end process; ----------------------------------------------------------------------------------------- --! ------------------------------------ Components ------------------------------------ p_strobe_a : process begin prbsgen_en <= '1'; wait until rising_edge(clk_a); for i in 0 to g_CLOCK_A_RATIO-2 loop prbsgen_en <= '0'; wait until rising_edge(clk_a); end loop; end process p_strobe_a; cmp_prbs_gen : prbs_gen generic map( g_PARAL_FACTOR => 254 , g_PRBS_POLYNOMIAL =>c_PRBS_POLYNOMIAL ) port map( clk_i => clk_a , en_i => prbsgen_en , reset_i => prbsgen_reset, seed_i => prbsgen_seed , load_i => prbsgen_load , data_o => prbsgen_data , data_valid_o => prbsgen_data_valid ); -- DUT data_a <= prbsgen_data; strobe_a <= prbsgen_data_valid; cmp_cdc_tx : cdc_tx generic map( g_CLOCK_A_RATIO => g_CLOCK_A_RATIO , g_CLOCK_B_RATIO => g_CLOCK_B_RATIO , g_ACC_PHASE => 4*5*6*8 , g_PHASE_SIZE => phase'length ) port map( -- Interface A (latch - from where data comes) reset_a_i => reset_a , clk_a_i => clk_a , data_a_i => data_a , strobe_a_i => strobe_a , -- Interface B (capture - to where data goes) clk_b_i => clk_b , data_b_o => data_b , strobe_b_o => strobe_b , ready_b_o => ready_b , -- Only relevant for fixed-phase operation clk_freerun_i => clk_freerun , phase_o => phase , phase_calib_i => phase_calib , phase_force_i => phase_force ); cmp_prbs_chk : prbs_chk generic map( g_GOOD_FRAME_TO_LOCK => 15 , g_BAD_FRAME_TO_UNLOCK => 5 , g_PARAL_FACTOR => 254, g_PRBS_POLYNOMIAL => c_PRBS_POLYNOMIAL ) port map( clk_i => clk_b , reset_i => prbschk_reset , en_i => strobe_b , data_i => data_b , data_o => prbschk_data_chk , error_o => prbschk_error , locked_o => prbschk_locked ); ----------------------------------------------------------------------------------------- --! -------------------------------------- Stimulis ------------------------------------- p_stimulis : process is variable v_PHASE_MEM : std_logic_vector(phase'range) := (others => '0'); begin --! Basic test bench to observe waveforms -- No Force prbsgen_reset <= '1'; prbsgen_load <= '1'; prbschk_reset <= '1'; reset_a <= '1'; phase_calib <= (others=>'0'); phase_force <= '0'; wait for 10*c_STROBE_PERIOD; wait until rising_edge(clk_a); prbsgen_reset <= '0'; wait until rising_edge(clk_a); prbsgen_load <= '0'; wait for 10*c_STROBE_PERIOD; wait until rising_edge(clk_a); reset_a <= '0'; wait for 10*c_STROBE_PERIOD; wait until rising_edge(clk_b); prbschk_reset <= '0'; wait for 12*125*8*c_CLOCK_FREERUN_PERIOD; v_PHASE_MEM := phase; wait for 12*125*8*c_CLOCK_FREERUN_PERIOD; save_file <= '1'; wait until rising_edge(clk_freerun); save_file <= '0'; wait until rising_edge(clk_freerun); -- Force for i in -1*(4*5*6*8/g_CLOCK_B_RATIO)/8 to (4*5*6*8/g_CLOCK_B_RATIO)/8 loop prbsgen_reset <= '1'; reset_a <= '1'; prbsgen_load <= '1'; prbschk_reset <= '1'; phase_calib <= std_logic_vector(to_unsigned(to_integer(unsigned(v_PHASE_MEM))+i*8, phase'length)); phase_force <= '1'; wait for 10*c_STROBE_PERIOD; wait until rising_edge(clk_a); prbsgen_reset <= '0'; wait until rising_edge(clk_a); prbsgen_load <= '0'; wait for 10*c_STROBE_PERIOD; wait until rising_edge(clk_a); reset_a <= '0'; wait for 10*c_STROBE_PERIOD; wait until rising_edge(clk_b); prbschk_reset <= '0'; wait for 12*125*8*c_CLOCK_FREERUN_PERIOD; save_file <= '1'; wait until rising_edge(clk_freerun); save_file <= '0'; wait until rising_edge(clk_freerun); end loop; wait; end process p_stimulis; ------------------------------------------------------------------------------ --! ------------------------------ Save output ------------------------------- p_save : process file f_handler : text open write_mode is "out_tb_cdc_tx_clock_A_"&integer'image(g_CLOCK_A_RATIO)&"_clock_B_"&integer'image(g_CLOCK_B_RATIO)&".txt"; variable row : line; begin wait until rising_edge(save_file); WRITE(row,phase_calib, right, 15); WRITE(row,phase, right, 15); WRITE(row,prbschk_locked, right, 15); WRITE(row,prbschk_error, right, 15); WRITE(row,ready_b, right, 15); WRITELINE(f_handler,row); wait until rising_edge(clk_freerun); end process p_save; ------------------------------------------------------------------------------ end architecture tb; --============================================================================== -- architecture end --==============================================================================