
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.
309 lines
12 KiB
VHDL
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;
|