Files
firmware_vhdl_evr320/hdl/v6vlx_gtxe1_wrapper.vhd
till straumann d135fbddca Add robustness to comma-detection and reset generation.
This patch addresses issues I occasionally observed:

a) I have seen occurrences when the GTX deasserts RXBYTEISALIGNED
   while the RXLOSSOFSYNC is *not* asserted.

   The comma-alignment state machine can be stuck in 'idle' believing
   all is well when in fact RXBYTEISALIGNED is deasserted.

   The proposed patch monitors RXBYTEISALIGNED in addition to
   RXLOSSOFSYNC in 'idle' state.

b) The synchronizer (inst_cdc_fast_stat) which takes the pulse
   width/delay to the EVR clock domain relies on a proper
   reset sequence for correct operation.

   It is possible, however, that the 'evr_clk' (which is generated
   from the recovered RX clock) is not ticking at all when 'xuser_RESET'
   resets said synchronizer. If e.g., there is no GTX reference clock
   present (because it requires i2c initialization which is performed
   later) then the EVR clock may not be ticking and prevent the
   destination side of the synchronizer from being reset. This
   has the consequence of 'width' and 'delay' *never* being
   updated.

   The proposed patch asserts the synchronizer reset while the RX PLL
   and/or MMCM are not locked.
2021-02-24 14:03:16 +01:00

309 lines
12 KiB
VHDL

------------------------------------------------------------------------------
-- Paul Scherrer Institute (PSI)
------------------------------------------------------------------------------
-- Unit : v6vlx_gtxe1_wrapper.vhd
-- Author : Goran Marinkovic, Section Diagnostic
-- : Waldemar Koprek, Section Diagnostic
-- : Patric Bucher, Section DSV
-- Version : $Revision: 1.1 $
------------------------------------------------------------------------------
-- Copyright© PSI, Section Diagnostic
------------------------------------------------------------------------------
-- Comment : Wrapper vor Virtex-6 GTX ready to use in HIPA and SwissFEL (SFEL)
------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library unisim;
use unisim.vcomponents.all;
use work.v6vlx_gtxe1_pkg.all;
entity v6vlx_gtxe1_wrapper is
generic(
g_MGT_LOCATION : string; -- "GTXE1_X0Y0" to "GTXE1_X0Y11" | "GTXE1_X0Y16" to "GTXE1_X0Y19"
g_FACILITY : string -- "HIPA" | "SFEL"
);
port(
-- MGT serial interface
i_mgt_refclk : in std_logic;
o_mgt_refclk : out std_logic;
i_mgt_rx_p : in std_logic;
i_mgt_rx_n : in std_logic;
o_mgt_tx_p : out std_logic;
o_mgt_tx_n : out std_logic;
-- MGT parallel interface
o_mgt_status : out std_logic_vector(31 downto 0); -- see lines 134-139 for details
i_mgt_control : in std_logic_vector(31 downto 0); -- see lines 127-131 for details
o_mgt_recclk : out std_logic;
o_mgt_rx_data : out std_logic_vector(15 downto 0);
o_mgt_rx_charisk : out std_logic_vector( 1 downto 0)
);
end v6vlx_gtxe1_wrapper;
architecture RTL of v6vlx_gtxe1_wrapper is
type typ_align_fsm is (
align_idle,
align_slide ,
align_wait_for_sync
);
signal s_align_fsm : typ_align_fsm := align_idle;
-- GTXE
signal i_mgt : gtxe_in_type;
signal o_mgt : gtxe_out_type;
signal sl_txoutclk : std_logic;
--fifo
signal sl_cpu_rx_empty : std_logic;
signal sl_gtxe_fifo_rst : std_logic;
signal sl_gtxe_rx_sync_done : std_logic;
signal slv_rxresetdone : std_logic_vector(7 downto 0);
signal sl_rx_sync_rst : std_logic;
signal sl_rxrecclk : std_logic;
signal sl_rx0_slide : std_logic;
signal slv_cnt : unsigned(5 downto 0);
-- MMCM
signal mmcm_CLKFB : std_logic;
signal mmcm_CLKFBOUT : std_logic;
signal mmcm_LOCKED : std_logic;
signal mmcm_RESET : std_logic;
signal mmcm_CLOCK : std_logic;
begin
-- inst_mgt_refclk_bufg: BUFG
-- port map
-- (
-- I => o_mgt.ctrl.REFCLKOUT,
-- O => o_mgt_refclk
-- );
-- GTXE INSTANCE ------------------------------------------------------------------
gen_gtxe1_sfel: if g_FACILITY = "SFEL" generate
ins_v6vlx_gtxe1_sfel: entity work.v6vlx_gtxe1_142MHz8_2Gbps856
generic map (
g_MGT_LOCATION => g_MGT_LOCATION )
port map (
i_mgt => i_mgt,
o_mgt => o_mgt
);
end generate;
gen_gtxe1_hipa: if g_FACILITY = "HIPA" generate
ins_v6vlx_gtxe1_hipa: entity work.v6vlx_gtxe1_101MHz27_1Gbps0127
generic map (
g_MGT_LOCATION => g_MGT_LOCATION )
port map (
i_mgt => i_mgt,
o_mgt => o_mgt
);
end generate;
assert not(g_FACILITY /= "HIPA" and g_FACILITY /= "SFEL")
report "Invalid value for g_FACILITY, valid values are 'HIPA'|'SFEL'"
severity failure;
-- GTXE CONTROL IF ----------------------------------------------------------------
i_mgt.ctrl.GTXRESET <= i_mgt_control(0);
i_mgt.ctrl.PLLRXRESET <= '0';
i_mgt.ctrl.PLLTXRESET <= '0';
i_mgt.ctrl.LOOPBACK <= "100"; -- Far-End PMA Loopback --> UG366 page 125
i_mgt.ctrl.CLKIN <= i_mgt_refclk;
-- GTXE STATUS IF (adapted to PSI generic part) -----------------------------------
o_mgt_status( 0) <= o_mgt.ctrl.TXPLLLKDET;
o_mgt_status( 1) <= o_mgt.ctrl.RXPLLLKDET;
o_mgt_status( 2) <= mmcm_LOCKED;
o_mgt_status( 3) <= o_mgt.ctrl.TXRESETDONE;
o_mgt_status( 4) <= o_mgt.ctrl.RXRESETDONE;
o_mgt_status( 5) <= '0'; -- TX_polarity inverted
o_mgt_status( 6) <= '0'; -- RX_polarity inverted
o_mgt_status( 7) <= '0'; -- reserved
o_mgt_status(12 downto 8) <= "00000"; -- DFEEYEDACMON[4:0]
o_mgt_status(13) <= '0'; -- RXPRBSERR
o_mgt_status(14) <= o_mgt.rx.RXBYTEISALIGNED;
o_mgt_status(15) <= o_mgt.rx.RXLOSSOFSYNC(1);
---------- additional status -------------
o_mgt_status(16) <= sl_rx0_slide;
o_mgt_status(17) <= sl_gtxe_rx_sync_done;
o_mgt_status(19 downto 18) <= o_mgt.rx.RXNOTINTABLE(1 downto 0); -- Byte 1 + Byte 0
o_mgt_status(21 downto 20) <= o_mgt.rx.RXDISPERR(1 downto 0); -- Byte 1 + Byte 0
o_mgt_status(31 downto 22) <= B"00_0000_0000"; -- undefined
-- GTXE RX IF ---------------------------------------------------------------------
-- MMCM use model based on AR#39430
gen_MMCM: if g_FACILITY = "SFEL" generate
begin
-- Use Core Generator to define parameters -> actual frequency 142.8 MHz
mmcm_rxclk : MMCM_BASE
generic map (
CLKFBOUT_MULT_F => 33.000 , -- Counter multiply value, Now supports non-integer values
CLKIN1_PERIOD => 7.002 , -- The reference clock frequency is required for properly configuring the
-- LOCK detect circuit and checking to make sure the VCO is operating within
-- the allowed range. If no value is specified, a warning should be issued
-- stating it was not provided so no error checking will be done.
CLKOUT0_DIVIDE_F => 8.250 , -- Counter divide value, Now supports non-integer values but you lose CLKOUT5
DIVCLK_DIVIDE => 4 -- Counter divide value, always configured for 50% duty cycle
)
port map (
CLKFBOUT => mmcm_CLKFBOUT, -- 1-bit MMCM Feedback clock output
CLKFBOUTB => open, -- 1-bit Inverted MMCM feedback clock output
CLKOUT0 => mmcm_CLOCK, -- 1-bit MMCM clock output 0
CLKOUT0B => open, -- 1-bit Inverted MMCM clock output 0
CLKOUT1 => open, -- 1-bit MMCM clock output 1
CLKOUT1B => open, -- 1-bit Inverted MMCM clock output 1
CLKOUT2 => open, -- 1-bit MMCM clock output 2
CLKOUT2B => open, -- 1-bit Inverted MMCM clock output 2
CLKOUT3 => open, -- 1-bit MMCM clock output 3
CLKOUT3B => open, -- 1-bit Inverted MMCM clock output 3
CLKOUT4 => open, -- 1-bit MMCM clock output 4
CLKOUT5 => open, -- 1-bit MMCM clock output 5, not used if CLKOUT0 is not an integer
CLKOUT6 => open, -- 1-bit MMCM clock output 6, not used if CLKFBOUT_MULT is not an integer
LOCKED => mmcm_LOCKED, -- 1-bit MMC locked signal
CLKFBIN => mmcm_CLKFB, -- 1-bit Feedback clock pin to the MMCM
CLKIN1 => o_mgt.rx.RXRECCLK, -- 1-bit Reference clock pin 1 to the MMCM
PWRDWN => '0', -- 1-bit Power down
RST => mmcm_RESET -- 1-bit MMCM global reset pin
);
mmcm_RESET <= not o_mgt.ctrl.RXPLLLKDET;
rxoutCLKFB_bufg0_i : BUFG
port map (
O => mmcm_CLKFB,
I => mmcm_CLKFBOUT
);
rxoutclk_bufg1_i : BUFG
port map (
O => sl_rxrecclk,
I => mmcm_CLOCK
);
end generate;
gen_BUFG: if g_FACILITY = "HIPA" generate
begin
rxoutclk_bufg0_i : BUFG
port map (
O => sl_rxrecclk,
I => o_mgt.rx.RXRECCLK
);
-- forward lock state
mmcm_LOCKED <= o_mgt.ctrl.RXPLLLKDET;
-- unused without mmcm
mmcm_CLKFB <= '0';
mmcm_CLKFBOUT <= '0';
mmcm_RESET <= '0';
mmcm_CLOCK <= '0';
end generate;
o_mgt_recclk <= sl_rxrecclk;
ins_v6vlx_gtxe1_sync : entity work.v6vlx_gtxe1_sync
port map (
RXENPMAPHASEALIGN => i_mgt.rx.RXENPMAPHASEALIGN ,
RXPMASETPHASE => i_mgt.rx.RXPMASETPHASE ,
RXDLYALIGNDISABLE => i_mgt.rx.RXDLYALIGNDISABLE ,
RXDLYALIGNOVERRIDE => i_mgt.rx.RXDLYALIGNOVERRIDE,
RXDLYALIGNRESET => i_mgt.rx.RXDLYALIGNRESET ,
SYNC_DONE => sl_gtxe_rx_sync_done,
USER_CLK => sl_rxrecclk,
RESET => sl_rx_sync_rst
);
prc_rx_reset_done_delay : process ( sl_rxrecclk )
begin
if rising_edge( sl_rxrecclk ) then
slv_rxresetdone <= slv_rxresetdone(6 downto 0) & o_mgt.ctrl.RXRESETDONE;
end if;
end process ;
sl_rx_sync_rst <= not slv_rxresetdone(7);
i_mgt.rx.RXUSRCLK <= sl_rxrecclk;
i_mgt.rx.RXUSRCLK2 <= sl_rxrecclk;
i_mgt.rx.RXP <= i_mgt_rx_p;
i_mgt.rx.RXN <= i_mgt_rx_n;
i_mgt.rx.RXENMCOMMAALIGN <= '0';
i_mgt.rx.RXENPCOMMAALIGN <= '0';
i_mgt.rx.RXRESET <= not mmcm_LOCKED;
i_mgt.rx.RXCDRRESET <= i_mgt_control(5);
i_mgt.rx.RXDLYALIGNMONENB <= '0';
o_mgt_rx_data <= o_mgt.rx.RXDATA(15 downto 0);
o_mgt_rx_charisk <= o_mgt.rx.RXCHARISK( 1 downto 0);
------------------------------------------------------------------------------
--RX comma alignment
------------------------------------------------------------------------------
prc_comma_align : process ( sl_rxrecclk )
begin
if rising_edge( sl_rxrecclk ) then
if o_mgt.ctrl.RXRESETDONE = '0' then
s_align_fsm <= align_idle;
else
case s_align_fsm is
when align_idle =>
if o_mgt.rx.RXLOSSOFSYNC( 1) = '1' or o_mgt.rx.RXBYTEISALIGNED = '0' then
s_align_fsm <= align_slide;
end if;
when align_slide =>
slv_cnt <= (others => '0');
s_align_fsm <= align_wait_for_sync;
when align_wait_for_sync =>
if slv_cnt(slv_cnt'left) = '1' then
if o_mgt.rx.RXLOSSOFSYNC( 1) = '0' and o_mgt.rx.RXBYTEISALIGNED = '1' then
s_align_fsm <= align_idle;
else
s_align_fsm <= align_slide;
end if;
else
slv_cnt <= slv_cnt + X"1";
end if;
end case;
end if;
end if;
end process ;
sl_rx0_slide <= '1' when s_align_fsm = align_slide or i_mgt_control(2) = '1' else '0';
i_mgt.rx.RXSLIDE <= sl_rx0_slide;
-- GTXE TX IF ---------------------------------------------------------------------
o_mgt_tx_p <= o_mgt.tx.TXP;
o_mgt_tx_n <= o_mgt.tx.TXN;
-- txoutclk_bufg0_i : BUFG
-- port map (
-- I => o_mgt.tx.TXOUTCLK,
-- O => sl_txoutclk
-- );
i_mgt.tx.TXRESET <= not mmcm_LOCKED;
i_mgt.tx.TXBYPASS8B10B <= X"0";
i_mgt.tx.TXCHARDISPMODE <= X"0";
i_mgt.tx.TXCHARDISPVAL <= X"0";
i_mgt.tx.TXUSRCLK <= sl_rxrecclk;
i_mgt.tx.TXUSRCLK2 <= sl_rxrecclk;
i_mgt.tx.TXDIFFCTRL <= "0110";
i_mgt.tx.TXPOSTEMPHASIS <= "00000";
i_mgt.tx.TXPREEMPHASIS <= "0000";
end RTL;