--============================================================================== -- © Copyright CERN for the benefit of the HPTD interest group 2018. All rights not -- expressly granted are reserved. -- -- This file is part of tx_phase_aligner. -- -- tx_phase_aligner 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. -- -- tx_phase_aligner 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 tx_phase_aligner. If not, see . --============================================================================== --! @file tx_phase_aligner_fsm.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: Tx Phase Aligner FSM logic (tx_phase_aligner_fsm) -- --! @brief Tx Phase Aligner FSM logic --! - Implements control algorithm for transmitter phase alignment acting on tx_pi_ctrl and fifo_fill_level_acc --! - Many algorithm flavour and alignment strategies are possible and those are further explained in the reference note containing this design --! --! @author Eduardo Brandao de Souza Mendes - eduardo.brandao.de.souza.mendes@cern.ch --! @date 02\05\2018 --! @version 1.0 --! @details --! --! Dependencies:\n --! --! --! References:\n --! \n --! --! --! Modified by:\n --! Author: Eduardo Brandao de Souza Mendes ------------------------------------------------------------------------------- --! \n\nLast changes:\n --! 02\05\2018 - EBSM - Created\n --! 13\09\2018 - EBSM - register tx_aligned_o output\n --! ------------------------------------------------------------------------------- --! @todo - \n --! \n -- ------------------------------------------------------------------------------- --============================================================================== --! Entity declaration for tx_phase_aligner_fsm --============================================================================== entity tx_phase_aligner_fsm is generic( g_SPEED_PD_FACTOR : integer range 0 to 19 := 10; --! coarse alignment procedure takes tx_fifo_fill_pd_max_i/(2**g_SPEED_PD_FACTOR) g_PI_COARSE_STEP : integer range 0 to 15 := 8; --! coarse PI steps g_PI_FINE_STEP : integer range 0 to 15 := 1 --! fine PI steps ); port ( -- Clock / reset clk_sys_i : in std_logic; --! system clock input reset_i : in std_logic; --! active high sync. reset -- Top level interface tx_aligned_o : out std_logic; --! Use it as a reset for the user transmitter logic -- Config (for different flavours) tx_pi_phase_calib_i : in std_logic_vector(6 downto 0); --! previous calibrated tx pi phase tx_ui_align_calib_i : in std_logic; --! align with previous calibrated tx pi phase tx_enable_reset_i : in std_logic; --! enable tx reset for perfect phase alignment (only relevant if tx_ui_align_calib_i is '1') tx_fifo_fill_pd_max_i : in std_logic_vector(31 downto 0); --! phase detector accumulated max output, sets precision of phase detector --! this is supposedly a static signal, this block shall be reset whenever this signal changes --! the time for each phase detection after a clear is given by tx_fifo_fill_pd_max_i * PERIOD_clk_txusr_i tx_fine_realign_i : in std_logic; --! A rising edge will cause the Tx to perform a fine realignment to the half-response -- Tx pi controller interface - see user interface tx_pi_ctrl.vhd for more information tx_pi_strobe_o : out std_logic; --! see user interface tx_pi_ctrl.vhd for more information tx_pi_inc_ndec_o : out std_logic; --! see user interface tx_pi_ctrl.vhd for more information tx_pi_phase_step_o : out std_logic_vector(3 downto 0); --! see user interface tx_pi_ctrl.vhd for more information tx_pi_done_i : in std_logic; --! see user interface tx_pi_ctrl.vhd for more information tx_pi_phase_i : in std_logic_vector(6 downto 0); --! see user interface tx_pi_ctrl.vhd for more information -- Tx fifo fill level phase detector interface - see user interface fifo_fill_level_acc.vhd for more information tx_fifo_fill_pd_clear_o : out std_logic; --! see user interface fifo_fill_level_acc.vhd for more information tx_fifo_fill_pd_done_i : in std_logic; --! see user interface fifo_fill_level_acc.vhd for more information tx_fifo_fill_pd_i : in std_logic_vector(31 downto 0); --! see user interface fifo_fill_level_acc.vhd for more information tx_fifo_fill_pd_max_o : out std_logic_vector(31 downto 0); --! see user interface fifo_fill_level_acc.vhd for more information -- Tx MGT reset (only used when tx_enable_reset_i is activated) tx_reset_o : out std_logic ); end tx_phase_aligner_fsm; --============================================================================== -- architecture declaration --============================================================================== architecture rtl of tx_phase_aligner_fsm is --! Function declaration function fcn_reduce_or(arg : std_logic_vector) return std_logic is variable result : std_logic; begin result := '0'; for i in arg'range loop result := result or arg(i); end loop; return result; end; --! Constant declaration --! Signal declaration -- FSM to control the phase alignment -- The phase alignment is divided into four steps: -- COARSE : Initial coarse and fast alignment to optimize time of routine, aligns to 1.0 as phase detector response -- FINE : Fine alignment to find the ideal position where phase detector gives 0.5 as response -- UI_ALIGN : Fine UI alignment to ensure PI position is always the same -- ALIGNED : Keeps checking phase detector response type t_PHASE_ALIGNER_FSM is (IDLE, -- | -- | COARSE_SET_CONFIG , -- | -- v COARSE_SHIFT_PI , -- | <--. -- v | COARSE_WAIT_PD , -- | | -- |----. -- v FINE_SET_CONFIG , -- | <----------------------------------------------------------. -- v | FINE_CHECK_DIRECTION,-- | | -- v | FINE_SHIFT_PI , -- |<---. | -- v | | FINE_WAIT_PD , -- |----. | -- v | FINE_ALIGNED , -- | | -- | ----------. | -- v | | UI_SET_OFFSET , -- | | | -- v | | UI_CHECK_SHIFT_PI , -- |-----------. | -- v ^ | | | UI_SHIFT_PI , -- ---| | | | -- | | - IF NOT ENABLE UI ALIGNMENT | UI_RESET_TX , -- <-----. | | -- | | -- | | ALIGNED_CLEAR_PD , -- <------------. - ALIGNED | -- | ^ ------------------------------------ ALIGNED_WAIT_PD -- v------| - ALIGNED ); signal phase_aligner_state : t_PHASE_ALIGNER_FSM; -- Identify rising edge of 'tx_fine_realign_i' and realign (only capture if already aligned) signal tx_fine_realign_r : std_logic; -- Set configuration of PI and PD signal tx_pi_inc_ndec : std_logic; signal tx_pi_phase_step : std_logic_vector(tx_pi_phase_step_o'range); signal tx_fifo_fill_pd_max : std_logic_vector(tx_fifo_fill_pd_max_o'range); -- half_response is used to indicate whether the signal half_response : std_logic; signal half_response_mem : std_logic; -- UI algorithm math signal ref_dist_mod64 : unsigned(tx_pi_phase_i'left-1 downto 0); signal ui_align_cntr : unsigned(tx_pi_phase_i'left-1 downto 0); -- Reset Tx pipeline signal reset_tx_pipe : std_logic_vector(4 downto 0); -- Tx aligned combinatorial signal tx_aligned : std_logic; begin --============================================================================ -- Main FSM algorithm --============================================================================ --============================================================================ -- Process p_phase_aligner_fsm --! Main FSM for the algorithm flow control --! read: \n --! write: -\n --! r/w: drp_tx_pi_state\n --============================================================================ p_phase_aligner_fsm : process(clk_sys_i) begin if(rising_edge(clk_sys_i)) then if(reset_i = '1') then phase_aligner_state <= IDLE; else case phase_aligner_state is when IDLE => phase_aligner_state <= COARSE_SET_CONFIG; when COARSE_SET_CONFIG => phase_aligner_state <= COARSE_SHIFT_PI; when COARSE_SHIFT_PI => if(tx_pi_done_i = '1') then phase_aligner_state <= COARSE_WAIT_PD; end if; when COARSE_WAIT_PD => if(tx_fifo_fill_pd_done_i = '1') then if(tx_fifo_fill_pd_i(tx_fifo_fill_pd_i'left - g_SPEED_PD_FACTOR downto 0) = tx_fifo_fill_pd_max_i(tx_fifo_fill_pd_max_i'left downto g_SPEED_PD_FACTOR))then phase_aligner_state <= FINE_SET_CONFIG; --reached full PD response (1.0) else phase_aligner_state <= COARSE_SHIFT_PI; end if; end if; when FINE_SET_CONFIG => phase_aligner_state <= FINE_CHECK_DIRECTION; when FINE_CHECK_DIRECTION => if(tx_fifo_fill_pd_done_i = '1') then phase_aligner_state <= FINE_SHIFT_PI; end if; when FINE_SHIFT_PI => if(tx_pi_done_i = '1') then phase_aligner_state <= FINE_WAIT_PD; end if; when FINE_WAIT_PD => if(tx_fifo_fill_pd_done_i = '1') then if(half_response /= half_response_mem) then --reached half PD response 0.5 phase_aligner_state <= FINE_ALIGNED; else phase_aligner_state <= FINE_SHIFT_PI; end if; end if; when FINE_ALIGNED => if(tx_ui_align_calib_i = '1') then -- go to UI mod-shift if user wants this option phase_aligner_state <= UI_SET_OFFSET; else phase_aligner_state <= ALIGNED_CLEAR_PD; end if; when UI_SET_OFFSET => phase_aligner_state <= UI_CHECK_SHIFT_PI; when UI_CHECK_SHIFT_PI => if(to_integer(ui_align_cntr) /= 0) then phase_aligner_state <= UI_SHIFT_PI; else if(tx_enable_reset_i = '1') then if(tx_pi_phase_i(tx_pi_phase_i'left) = tx_pi_phase_calib_i(tx_pi_phase_calib_i'left)) then --perfect alignment (mod 128) phase_aligner_state <= ALIGNED_WAIT_PD; else -- reset the transmitter to try to achieve perfect alignment phase_aligner_state <= UI_RESET_TX; end if; else phase_aligner_state <= ALIGNED_CLEAR_PD; end if; end if; when UI_SHIFT_PI => if(tx_pi_done_i = '1') then phase_aligner_state <= UI_CHECK_SHIFT_PI; end if; when UI_RESET_TX => if (reset_tx_pipe(reset_tx_pipe'left) = '1') then phase_aligner_state <= IDLE; end if; when ALIGNED_CLEAR_PD => if(tx_fine_realign_i = '1' and tx_fine_realign_r = '0') then phase_aligner_state <= FINE_SET_CONFIG; else phase_aligner_state <= ALIGNED_WAIT_PD; end if; when ALIGNED_WAIT_PD => if(tx_fine_realign_i = '1' and tx_fine_realign_r = '0') then phase_aligner_state <= FINE_SET_CONFIG; elsif(tx_fifo_fill_pd_done_i = '1') then phase_aligner_state <= ALIGNED_CLEAR_PD; end if; when others => phase_aligner_state <= IDLE; end case; end if; end if; end process p_phase_aligner_fsm; -- register for rising edge identification tx_fine_realign_r <= tx_fine_realign_i when rising_edge(clk_sys_i); --============================================================================ -- PI and PD control --============================================================================ --============================================================================ -- Process p_set_config --! Sets config for Tx PI and phase detector depending on part of algorithm --! read: phase_aligner_state, tx_fifo_fill_pd_max_i, ref_dist_mod64\n --! write: \n --! r/w: tx_pi_inc_ndec, tx_pi_phase_step, tx_fifo_fill_pd_max\n --============================================================================ p_set_config : process(clk_sys_i) begin if(rising_edge(clk_sys_i)) then if(reset_i = '1') then tx_pi_inc_ndec <= '0'; tx_pi_phase_step <= (others => '0'); tx_fifo_fill_pd_max <= (others => '0'); else case phase_aligner_state is when COARSE_SET_CONFIG => tx_pi_inc_ndec <= '1'; tx_pi_phase_step <= std_logic_vector(to_unsigned(g_PI_COARSE_STEP, tx_pi_phase_step'length)); tx_fifo_fill_pd_max(tx_fifo_fill_pd_max_i'left-g_SPEED_PD_FACTOR downto 0) <= tx_fifo_fill_pd_max_i(tx_fifo_fill_pd_max_i'left downto g_SPEED_PD_FACTOR); tx_fifo_fill_pd_max(tx_fifo_fill_pd_max_i'left downto tx_fifo_fill_pd_max_i'left-g_SPEED_PD_FACTOR+1) <= (others => '0'); when FINE_SET_CONFIG => tx_pi_inc_ndec <= tx_pi_inc_ndec; tx_pi_phase_step <= std_logic_vector(to_unsigned(g_PI_FINE_STEP, tx_pi_phase_step'length)); tx_fifo_fill_pd_max <= tx_fifo_fill_pd_max_i; when FINE_CHECK_DIRECTION => tx_pi_inc_ndec <= half_response; tx_pi_phase_step <= tx_pi_phase_step; tx_fifo_fill_pd_max <= tx_fifo_fill_pd_max; when UI_SET_OFFSET => tx_pi_inc_ndec <= not ref_dist_mod64(ref_dist_mod64'left); --not bigger than half UI tx_pi_phase_step <= tx_pi_phase_step; tx_fifo_fill_pd_max <= tx_fifo_fill_pd_max; when others => tx_pi_inc_ndec <= tx_pi_inc_ndec; tx_pi_phase_step <= tx_pi_phase_step; tx_fifo_fill_pd_max <= tx_fifo_fill_pd_max; end case; end if; end if; end process p_set_config; tx_pi_strobe_o <= '1' when (phase_aligner_state = COARSE_SHIFT_PI or phase_aligner_state = FINE_SHIFT_PI or phase_aligner_state = UI_SHIFT_PI) else '0'; tx_pi_inc_ndec_o <= tx_pi_inc_ndec; tx_pi_phase_step_o <= tx_pi_phase_step; tx_fifo_fill_pd_clear_o <= '1' when (tx_pi_done_i = '1' or phase_aligner_state = ALIGNED_CLEAR_PD or phase_aligner_state = FINE_SET_CONFIG) else '0'; tx_fifo_fill_pd_max_o <= tx_fifo_fill_pd_max; --============================================================================ -- Math --============================================================================ ref_dist_mod64 <= unsigned(tx_pi_phase_calib_i(tx_pi_phase_i'left-1 downto 0)) - unsigned(tx_pi_phase_i(tx_pi_phase_i'left-1 downto 0)); --============================================================================ -- Process p_half_response_mem --! Saves half response from PD --! read: half_response\n --! write: half_response_mem\n --! r/w: \n --============================================================================ half_response <= '1' when (unsigned(tx_fifo_fill_pd_i) <= unsigned('0'&tx_fifo_fill_pd_max_i(tx_fifo_fill_pd_max_i'left downto 1))) else '0'; p_half_response_mem : process(clk_sys_i) begin if (rising_edge(clk_sys_i)) then if (tx_fifo_fill_pd_done_i = '1') then half_response_mem <= half_response; end if; end if; end process p_half_response_mem; --============================================================================ -- Process p_ui_align_cntr --! Sets config for Tx PI and phase detector depending on part of algorithm --! read: phase_aligner_state, ref_dist_mod64, tx_pi_done_i\n --! write: \n --! r/w: ui_align_cntr\n --============================================================================ p_ui_align_cntr : process(clk_sys_i) begin if(rising_edge(clk_sys_i)) then if(reset_i = '1') then ui_align_cntr <= (others => '0'); else case phase_aligner_state is when UI_SET_OFFSET => if(ref_dist_mod64(ref_dist_mod64'left) = '1') then -- bigger than half-UI ui_align_cntr <= (not ref_dist_mod64) + to_unsigned(1, ref_dist_mod64'length); else ui_align_cntr <= ref_dist_mod64; end if; when UI_SHIFT_PI => if(tx_pi_done_i = '1') then ui_align_cntr <= ui_align_cntr - 1; end if; when others => ui_align_cntr <= ui_align_cntr; end case; end if; end if; end process p_ui_align_cntr; --============================================================================ -- Process p_reset_tx_pipe --! Resets transmitter pipe --! read: phase_aligner_state\n --! write: tx_reset_o\n --! r/w: reset_tx_pipe\n --============================================================================ p_reset_tx_pipe : process(clk_sys_i) begin if(rising_edge(clk_sys_i)) then if(phase_aligner_state = UI_RESET_TX) then reset_tx_pipe(0) <= '1'; else reset_tx_pipe(0) <= '0'; end if; reset_tx_pipe(reset_tx_pipe'left downto 1) <= reset_tx_pipe(reset_tx_pipe'left-1 downto 0); tx_reset_o <= fcn_reduce_or(reset_tx_pipe); end if; end process p_reset_tx_pipe; --============================================================================ -- Alignment condition --============================================================================ tx_aligned <= '1' when (phase_aligner_state = ALIGNED_CLEAR_PD or phase_aligner_state = ALIGNED_WAIT_PD) else '0'; tx_aligned_o <= tx_aligned when rising_edge(clk_sys_i); end architecture rtl; --============================================================================== -- architecture end --==============================================================================