--==============================================================================
-- © 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 mgt_fixed_phase.vhd
--==============================================================================
--! Standard library
library ieee;
--! Standard packages
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
--! Specific packages
library UNISIM;
use UNISIM.vcomponents.all;
-------------------------------------------------------------------------------
-- --
-- CERN, EP-ESE-BE, HPTD
-- --
-------------------------------------------------------------------------------
--
-- unit name: Example design for fixed-phase MGT infrastructure with debugging options (mgt_fixed_phase)
--
--! @brief Example design for fixed-phase MGT infrastructure with debugging options
--!
--! @author Eduardo Brandao de Souza Mendes - eduardo.brandao.de.souza.mendes@cern.ch
--! @date 18\10\2019
--! @version 1.0
--! @details
--!
--! Dependencies:\n
--!
--!
--! References:\n
--! \n
--!
--!
--! Modified by:\n
--! Author: Eduardo Brandao de Souza Mendes
-------------------------------------------------------------------------------
--! \n\nLast changes:\n
--! 18\10\2019 - EBSM - Created\n
--!
-------------------------------------------------------------------------------
--! @todo - \n
--! \n
--
-------------------------------------------------------------------------------
--==============================================================================
--! Entity declaration for mgt_fixed_phase
--==============================================================================
entity mgt_fixed_phase is
port (
--***************************************************************
--************************ USER PORTS ***************************
--***************************************************************
-----------------------------------------------------------------
--------------------- System clock / resets ---------------------
-----------------------------------------------------------------
-- System clock (must come from a free-running source)
clk_sys_i : in std_logic; --! system clock input
reset_i : in std_logic; --! system clock reset / sync to clk_sys_i
clk_txusr_i : in std_logic; --! txusrclk from transceiver
clk_rxusr_i : in std_logic; --! rxusrclk from transceiver
tx_ready_o : out std_logic; --! Tx is ready for data transmission (use as reset for tx logic) / sync to clk_sys_i
rx_ready_o : out std_logic; --! Rx is ready for data transmission (use as reset for rx logic) / sync to clk_sys_i
-----------------------------------------------------------------
--------------- Low-level transceiver control/debug -------------
-----------------------------------------------------------------
-- Polarity control
txpolarity_i : in std_logic; --! Tx serial data polarity inversion / sync to clk_sys_i
rxpolarity_i : in std_logic; --! Rx serial data polarity inversion / sync to clk_sys_i
-- Built-in PRBS testing structures
txprbsforceerr_i : in std_logic; --! Tx prbs force errors / sync to clk_sys_i
txprbssel_i : in std_logic_vector(3 downto 0); --! Tx built-in data generator pattern selection / sync to clk_sys_i
--! 0000 = Normal operation
--! 0001 = PRBS-7
--! 0010 = PRBS-9
--! 0011 = PRBS-15
--! 0100 = PRBS-23
--! 0101 = PRBS-31
--! 1001 = Square wave with 2 UI (alternating 0s/1s)
--! 1010 = Square wave with 32 UI
--! others = Reserved
rxprbscntreset_i : in std_logic; --! Rx prbs error counter reset / sync to clk_sys_i
rxprbssel_i : in std_logic_vector(3 downto 0); --! Rx built-in data checker pattern selection (same convention as txprbssel_i) / sync to clk_sys_i
rxprbserr_o : out std_logic; --! Rx built-in error detection flag / sync to clk_sys_i
rxprbslocked_o : out std_logic; --! Rx built-in prbs locked flag / sync to clk_sys_i
-----------------------------------------------------------------
----------------------------- DRP -------------------------------
-----------------------------------------------------------------
-- Dynamic reconfiguration port
drpwe_i : in std_logic; --! DRP write enable / sync to clk_sys_i
drpen_i : in std_logic; --! DRP enable (a rising edge detector is included in mgt_fixed_phase to allow slow control) / sync to clk_sys_i
drpaddr_i : in std_logic_vector(9 downto 0); --! DRP address / sync to clk_sys_i
drpdi_i : in std_logic_vector(15 downto 0); --! DRP Data In / sync to clk_sys_i
drprdy_latched_o : out std_logic; --! DRP ready (goes to 0 when drpen_i rising edge is detected, goes to 1 when transceiver drprdy issues a pulse) / sync to clk_sys_i
drpdo_o : out std_logic_vector(15 downto 0); --! DRP Data Out
-----------------------------------------------------------------
------------------- HPTD IP - Tx Phase Aligner ------------------
-----------------------------------------------------------------
-- Configuration
tx_fifo_fill_pd_max_i : in std_logic_vector(31 downto 0); --! Minimum 0x00400000 / sync to clk_sys_i
tx_pi_phase_calib_i : in std_logic_vector(6 downto 0); --! Connect to tx_pi_phase_o value after first reset / sync to clk_sys_i
tx_ui_align_calib_i : in std_logic; --! Connect to 1 to freeze tx_pi_phase after first reset / sync to clk_sys_i
-- Tx PI phase value
tx_pi_phase_o : out std_logic_vector(6 downto 0); --! Tx PI phase / sync to clk_sys_i
-- Tx fifo fill level phase detector
tx_fifo_fill_pd_o : out std_logic_vector(31 downto 0); --! Tx PD value / sync to clk_sys_i
-- Fine Phase Shift Interface (only valid once transceiver is ready tx_ready_o=1)
ps_strobe_i : in std_logic; --! Shall be used only once tx_ready_o='1', moves tx phase / sync to clk_sys_i
ps_inc_ndec_i : in std_logic; --! Increment or decrement phase / sync to clk_sys_i
ps_phase_step_i : in std_logic_vector(3 downto 0); --! Step number in Tx PI units / sync to clk_sys_i
ps_done_latched_o : out std_logic; --! Goes to 0 when ps_strobe_i rising edge is detected, goes to 1 when requested phase shift is performed (rising edge is detected in ps_strobe_i) / sync to clk_sys_i
-----------------------------------------------------------------
--------------------- Digital Monitor ---------------------------
-----------------------------------------------------------------
dmonitor_o : out std_logic_vector (15 downto 0); --! Rx Digital Monitor / sync to clk_sys_i
--***************************************************************
--************************* MGT PORTS ***************************
--***************************************************************
-- Status
mgt_reset_tx_done_i : in std_logic; --! MGT Tx reset is finished / sync to clk_txusr_i
mgt_reset_rx_done_i : in std_logic; --! MGT Rx reset is finished / sync to clk_rxusr_i
-- DRP bus / sync to clk_sys_i
mgt_drpaddr_o : out std_logic_vector(9 downto 0);
mgt_drpclk_o : out std_logic;
mgt_drpdi_o : out std_logic_vector(15 downto 0);
mgt_drpen_o : out std_logic;
mgt_drpwe_o : out std_logic;
mgt_drpdo_i : in std_logic_vector(15 downto 0);
mgt_drprdy_i : in std_logic;
-- Digital Monitor / sync to clk_sys_i
mgt_dmonitorclk_o : out std_logic;
mgt_dmonitorout_i : in std_logic_vector(15 downto 0);
-- Polarity
mgt_txpolarity_o : out std_logic; --! sync to clk_txusr_i
mgt_rxpolarity_o : out std_logic; --! sync to clk_rxusr_i
-- Tx PRBS / sync to clk_txusr_i
mgt_txprbsforceerr_o : out std_logic;
mgt_txprbssel_o : out std_logic_vector(3 downto 0);
-- Rx PRBS / sync to clk_rxusr_i
mgt_rxprbserr_i : in std_logic;
mgt_rxprbslocked_i : in std_logic;
mgt_rxprbscntreset_o : out std_logic;
mgt_rxprbssel_o : out std_logic_vector(3 downto 0);
-- Tx PI + FIFO Fill level flag / sync to clk_txusr_i
mgt_txbufstatus_i : in std_logic_vector(1 downto 0);
mgt_txpippmen_o : out std_logic;
mgt_txpippmovrden_o : out std_logic;
mgt_txpippmpd_o : out std_logic;
mgt_txpippmsel_o : out std_logic;
mgt_txpippmstepsize_o : out std_logic_vector(4 downto 0)
);
end entity mgt_fixed_phase;
--==============================================================================
-- architecture declaration
--==============================================================================
architecture rtl of mgt_fixed_phase is
--! Function declaration
--! Constant declaration
--! Signal declaration
------------------------- Auxiliar MGT interface ------------------------------
signal tx_ready_async : std_logic; -- user ready status
signal rx_ready_async : std_logic; -- user ready status
signal mgt_rxprbserr_i_latched : std_logic; -- latch mgt_rxprbserr_i flag
signal rxprbscntreset_s : std_logic; -- rx PRBS counter reset
-------------------------------- DRP arbiter ----------------------------------
constant c_NUM_DRP_MASTER : integer := 2;
signal master_drpwe : std_logic_vector(c_NUM_DRP_MASTER-1 downto 0);
signal master_drpen : std_logic_vector(c_NUM_DRP_MASTER-1 downto 0);
signal master_drpaddr : std_logic_vector(10*c_NUM_DRP_MASTER-1 downto 0);
signal master_drpdi : std_logic_vector(16*c_NUM_DRP_MASTER-1 downto 0);
signal master_drprdy : std_logic_vector(c_NUM_DRP_MASTER-1 downto 0);
signal master_drpdo : std_logic_vector(16*c_NUM_DRP_MASTER-1 downto 0);
signal drpen_r : std_logic;
------------------------- HPTD IP Core - Tx Phase Aligner ---------------------
signal tx_phase_aligner_reset_async : std_logic;
signal tx_phase_aligner_reset_syssync : std_logic;
signal tx_aligned : std_logic;
signal ps_strobe_r : std_logic;
signal ps_done_hptd : std_logic;
------------------------------- Digital Monitor ---------------------------
signal dmonitorout_r : std_logic_vector (15 downto 0);
signal dmonitorout_r2 : std_logic_vector (15 downto 0);
signal dmonitorout_latch : std_logic_vector (15 downto 0);
--! Component declaration
component reset_synchronizer
port (
clk_in : in std_logic;
rst_in : in std_logic;
rst_out : out std_logic
);
end component;
component bit_synchronizer is
generic (
INITIALIZE : std_logic_vector(4 downto 0) := "00000"
);
port (
clk_in : in std_logic;
i_in : in std_logic;
o_out : out std_logic
);
end component;
component drp_arbiter is
generic(
g_NUM_MASTER : integer := 2
);
port (
-- global input signals --
clk_i : in std_logic;
reset_i : in std_logic;
--------------------------
-- Interface to user --
master_drpwe_i : in std_logic_vector(g_NUM_MASTER-1 downto 0);
master_drpen_i : in std_logic_vector(g_NUM_MASTER-1 downto 0);
master_drpaddr_i : in std_logic_vector(10*g_NUM_MASTER-1 downto 0);
master_drpdi_i : in std_logic_vector(16*g_NUM_MASTER-1 downto 0);
master_drprdy_o : out std_logic_vector(g_NUM_MASTER-1 downto 0);
master_drpdo_o : out std_logic_vector(16*g_NUM_MASTER-1 downto 0);
-------------------------------
-- DRP connection to GTH/GTX --
mgt_drpwe_o : out std_logic;
mgt_drpen_o : out std_logic;
mgt_drpaddr_o : out std_logic_vector(9 downto 0);
mgt_drpdi_o : out std_logic_vector(15 downto 0);
mgt_drprdy_i : in std_logic;
mgt_drpdo_i : in std_logic_vector(15 downto 0)
-------------------------------
);
end component drp_arbiter;
component tx_phase_aligner is
generic(
-- User choice of DRP control or port control
g_DRP_NPORT_CTRL : boolean := true;
g_DRP_ADDR_TXPI_PPM_CFG : std_logic_vector(8 downto 0) := ("010011010")
);
port (
--==============================================================================
--! User control/monitor ports
--==============================================================================
-- Clock / reset
clk_sys_i : in std_logic;
reset_i : in std_logic;
-- Top level interface
tx_aligned_o : out std_logic;
-- Config (for different flavours)
tx_pi_phase_calib_i : in std_logic_vector(6 downto 0);
tx_ui_align_calib_i : in std_logic;
tx_fifo_fill_pd_max_i : in std_logic_vector(31 downto 0);
tx_fine_realign_i : in std_logic;
ps_strobe_i : in std_logic;
ps_inc_ndec_i : in std_logic;
ps_phase_step_i : in std_logic_vector(3 downto 0);
ps_done_o : out std_logic;
-- Tx PI phase value
tx_pi_phase_o : out std_logic_vector(6 downto 0);
-- Tx fifo fill level phase detector
tx_fifo_fill_pd_o : out std_logic_vector(31 downto 0);
--==============================================================================
--! MGT ports
--==============================================================================
clk_txusr_i : in std_logic;
-- Tx fifo fill level
tx_fifo_fill_level_i : in std_logic;
-- Transmitter PI ports
txpippmen_o : out std_logic;
txpippmovrden_o : out std_logic;
txpippmsel_o : out std_logic;
txpippmpd_o : out std_logic;
txpippmstepsize_o : out std_logic_vector(4 downto 0);
-- DRP interface
drpaddr_o : out std_logic_vector(8 downto 0);
drpen_o : out std_logic;
drpdi_o : out std_logic_vector(15 downto 0);
drprdy_i : in std_logic;
drpdo_i : in std_logic_vector(15 downto 0);
drpwe_o : out std_logic
);
end component tx_phase_aligner;
begin
--============================================================================
--! User Tx/Rx Ready
--============================================================================
tx_ready_async <= tx_aligned and mgt_reset_tx_done_i;
cmp_tx_ready_bit_synchronizer : bit_synchronizer
port map (
clk_in => clk_sys_i,
i_in => tx_ready_async,
o_out => tx_ready_o
);
rx_ready_async <= mgt_reset_rx_done_i;
cmp_rx_ready_bit_synchronizer : bit_synchronizer
port map (
clk_in => clk_sys_i,
i_in => rx_ready_async,
o_out => rx_ready_o
);
--============================================================================
--! Transceiver low-level control/testing features
--============================================================================
-- Polarity control
txpolarity_bit_synchronizer : bit_synchronizer
port map(
clk_in => clk_txusr_i,
i_in => txpolarity_i,
o_out => mgt_txpolarity_o
);
rxpolarity_bit_synchronizer : bit_synchronizer
port map(
clk_in => clk_rxusr_i,
i_in => rxpolarity_i,
o_out => mgt_rxpolarity_o
);
-- Built-in PRBS testing structures
txprbsforceerr_bit_synchronizer : bit_synchronizer
port map(
clk_in => clk_txusr_i,
i_in => txprbsforceerr_i,
o_out => mgt_txprbsforceerr_o
);
txprbssel0_bit_synchronizer : bit_synchronizer
port map(
clk_in => clk_txusr_i,
i_in => txprbssel_i(0),
o_out => mgt_txprbssel_o(0)
);
txprbssel1_bit_synchronizer : bit_synchronizer
port map(
clk_in => clk_txusr_i,
i_in => txprbssel_i(1),
o_out => mgt_txprbssel_o(1)
);
txprbssel2_bit_synchronizer : bit_synchronizer
port map(
clk_in => clk_txusr_i,
i_in => txprbssel_i(2),
o_out => mgt_txprbssel_o(2)
);
txprbssel3_bit_synchronizer : bit_synchronizer
port map(
clk_in => clk_txusr_i,
i_in => txprbssel_i(3),
o_out => mgt_txprbssel_o(3)
);
rxprbscntreset_bit_synchronizer : bit_synchronizer
port map(
clk_in => clk_rxusr_i,
i_in => rxprbscntreset_i,
o_out => rxprbscntreset_s
);
mgt_rxprbscntreset_o <= rxprbscntreset_s;
rxprbssel0_bit_synchronizer : bit_synchronizer
port map(
clk_in => clk_rxusr_i,
i_in => rxprbssel_i(0),
o_out => mgt_rxprbssel_o(0)
);
rxprbssel1_bit_synchronizer : bit_synchronizer
port map(
clk_in => clk_rxusr_i,
i_in => rxprbssel_i(1),
o_out => mgt_rxprbssel_o(1)
);
rxprbssel2_bit_synchronizer : bit_synchronizer
port map(
clk_in => clk_rxusr_i,
i_in => rxprbssel_i(2),
o_out => mgt_rxprbssel_o(2)
);
rxprbssel3_bit_synchronizer : bit_synchronizer
port map(
clk_in => clk_rxusr_i,
i_in => rxprbssel_i(3),
o_out => mgt_rxprbssel_o(3)
);
-- Latch error flag for software control
p_rxprbserrlatched : process (clk_rxusr_i) is
begin
if clk_rxusr_i'event and clk_rxusr_i = '1' then
if rxprbscntreset_s = '1' then
mgt_rxprbserr_i_latched <= '0';
else
if(mgt_rxprbserr_i = '1') then
mgt_rxprbserr_i_latched <= '1';
end if;
end if;
end if;
end process p_rxprbserrlatched;
rxprbserr_bit_synchronizer : bit_synchronizer
port map(
clk_in => clk_sys_i,
i_in => mgt_rxprbserr_i_latched,
o_out => rxprbserr_o
);
rxprbslocked_bit_synchronizer : bit_synchronizer
port map(
clk_in => clk_sys_i,
i_in => mgt_rxprbslocked_i,
o_out => rxprbslocked_o
);
--============================================================================
--! DRP arbiter
--============================================================================
cmp_drp_arbiter : drp_arbiter
generic map(
g_NUM_MASTER => c_NUM_DRP_MASTER
)
port map(
-- global input signals --
clk_i => clk_sys_i,
reset_i => reset_i,
--------------------------
-- Interface to user --
master_drpwe_i => master_drpwe,
master_drpen_i => master_drpen,
master_drpaddr_i => master_drpaddr,
master_drpdi_i => master_drpdi,
master_drprdy_o => master_drprdy,
master_drpdo_o => master_drpdo,
-------------------------------
-- DRP connection to GTH/GTX --
mgt_drpwe_o => mgt_drpwe_o,
mgt_drpen_o => mgt_drpen_o,
mgt_drpaddr_o => mgt_drpaddr_o,
mgt_drpdi_o => mgt_drpdi_o,
mgt_drprdy_i => mgt_drprdy_i,
mgt_drpdo_i => mgt_drpdo_i
-------------------------------
);
mgt_drpclk_o <= clk_sys_i;
--============================================================================
--! DRP user control
--============================================================================
p_drp_user_access : process (clk_sys_i) is
begin
if clk_sys_i'event and clk_sys_i = '1' then
if(reset_i='1') then
drpen_r <= '0';
master_drpen(1) <= '0';
drprdy_latched_o <= '0';
drpdo_o <= (others => '0');
else
drpen_r <= drpen_i;
if(drpen_i = '1' and drpen_r = '0') then -- detects rising edge of drpen_i signal
master_drpen(1) <= '1';
drprdy_latched_o <= '0';
else
master_drpen(1) <= '0';
if(master_drprdy(1) = '1') then
drpdo_o <= master_drpdo(16*2-1 downto 16*1) ;
drprdy_latched_o <= '1';
end if;
end if;
end if;
end if;
end process p_drp_user_access;
master_drpwe(1) <= drpwe_i ;
master_drpaddr(10*2-1 downto 10*1) <= drpaddr_i ;
master_drpdi(16*2-1 downto 16*1) <= drpdi_i ;
--============================================================================
--! HPTD IP Core - Tx Phase Aligner
--============================================================================
-- Reset HPTD IP Core until transceiver is not ready
tx_phase_aligner_reset_async <= not mgt_reset_tx_done_i;
reset_synchronizer_tx_phase_aligner_inst : reset_synchronizer
port map (
clk_in => clk_sys_i,
rst_in => tx_phase_aligner_reset_async,
rst_out => tx_phase_aligner_reset_syssync
);
cmp_tx_phase_aligner : tx_phase_aligner
generic map(
-- User choice of DRP control or port control
-- Recommended nowadays to use in DRP control as a strange behaviour was observed using the port in PI code stepping mode
g_DRP_NPORT_CTRL => true,
g_DRP_ADDR_TXPI_PPM_CFG => "010011010"
)
port map(
--==============================================================================
--! User control/monitor ports
--==============================================================================
-- Clock / reset
clk_sys_i => clk_sys_i ,
reset_i => tx_phase_aligner_reset_syssync,
-- Top level interface
tx_aligned_o => tx_aligned ,
-- Config (for different flavours)
tx_pi_phase_calib_i => tx_pi_phase_calib_i ,
tx_ui_align_calib_i => tx_ui_align_calib_i ,
tx_fifo_fill_pd_max_i => tx_fifo_fill_pd_max_i ,
tx_fine_realign_i => '0' ,
-- It is only valid to re-shift clock once aligned (tx_aligned_o = '1')
ps_strobe_i => ps_strobe_i ,
ps_inc_ndec_i => ps_inc_ndec_i ,
ps_phase_step_i => ps_phase_step_i ,
ps_done_o => ps_done_hptd ,
-- Tx PI phase value
tx_pi_phase_o => tx_pi_phase_o ,
-- Tx fifo fill level phase detector
tx_fifo_fill_pd_o => tx_fifo_fill_pd_o ,
--==============================================================================
--! MGT ports
--==============================================================================
clk_txusr_i => clk_txusr_i ,
-- Tx fifo fill level
tx_fifo_fill_level_i => mgt_txbufstatus_i(0) ,
-- Transmitter PI ports
txpippmen_o => mgt_txpippmen_o ,
txpippmovrden_o => mgt_txpippmovrden_o ,
txpippmsel_o => mgt_txpippmsel_o ,
txpippmpd_o => mgt_txpippmpd_o ,
txpippmstepsize_o => mgt_txpippmstepsize_o ,
-- DRP interface
drpaddr_o => master_drpaddr(10*1-2 downto 10*0) ,
drpen_o => master_drpen(0) ,
drpdi_o => master_drpdi(16*1-1 downto 16*0) ,
drprdy_i => master_drprdy(0) ,
drpdo_i => master_drpdo(16*1-1 downto 16*0) ,
drpwe_o => master_drpwe(0)
);
master_drpaddr(10*1-1) <= '0' ;
--! Latch ps_done for slow control
p_hptd_ps_done_latched : process (clk_sys_i) is
begin
if clk_sys_i'event and clk_sys_i = '1' then
if(tx_phase_aligner_reset_syssync='1' or tx_aligned='0') then
ps_strobe_r <= '0';
ps_done_latched_o <= '0';
else
ps_strobe_r <= ps_strobe_i;
if(ps_strobe_i = '1' and ps_strobe_r = '0') then -- detects rising edge of ps_strobe_i signal
ps_done_latched_o <= '0';
else
if(ps_done_hptd = '1') then
ps_done_latched_o <= '1';
end if;
end if;
end if;
end if;
end process p_hptd_ps_done_latched;
--============================================================================
--! Receiver Equalizer Control
--============================================================================
-- digital monitor
mgt_dmonitorclk_o <= clk_sys_i;
-- Changes in dmonitorout port are slow compared to clk_sys_i
-- Following process avoids metastability in dmonitorout_latch port
p_dmonitor : process (clk_sys_i) is
begin
if clk_sys_i'event and clk_sys_i = '1' then
dmonitorout_r <= mgt_dmonitorout_i;
dmonitorout_r2 <= dmonitorout_r;
if(dmonitorout_r = dmonitorout_r2) then
dmonitorout_latch <= dmonitorout_r2;
else
dmonitorout_latch <= dmonitorout_latch;
end if;
end if;
end process p_dmonitor;
dmonitor_o <= dmonitorout_latch;
end architecture rtl;
--==============================================================================
-- architecture end
--==============================================================================