--- /dev/null
+------------------------------------------------------------------
+-- Mupix data 10b8b readout with internal FIFO
+--T. Weber, Ruhr Universität Bochum
+------------------------------------------------------------------
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+entity MupixDataLink is
+ port(
+ sysclk : in std_logic; --trb system clock (typically 100 MHz)
+ dataclk : in std_logic; --mupix link clock from FPGA PLL(50 - 150 MHz)
+ rst : in std_logic; --synchronous reset
+ clear : in std_logic; --asynchronous reset
+ rst_fifo : in std_logic; --synchronous fifo reset
+ --lattice serdes
+ mupix_data : in std_logic_vector(7 downto 0); --lvds pairs of 4 incoming data channels
+ refclk2core : out std_logic; --reference clk from serdes (not really needed since clock sync is done internally with FIFOs?)
+ clk_rx_half_out : out std_logic; --serdes receive clock half
+ clk_rx_full_out : out std_logic; --serdes receive clock
+ --fifo signals
+ fifo_rden : in std_logic_vector(3 downto 0); -- read enable to FIFOs
+ fifo_empty : out std_logic_vector(3 downto 0); -- input FIFO empty flags
+ fifo_full : out std_logic_vector(3 downto 0); -- input FIFO full flags
+ fifo_data : out std_logic_vector(127 downto 0); -- input data from FIFOs
+ --misc
+ channel_status_led : out std_logic_vector(3 downto 0);
+ --TRB slow control channel
+ SLV_READ_IN : in std_logic;
+ SLV_WRITE_IN : in std_logic;
+ SLV_DATA_OUT : out std_logic_vector(31 downto 0);
+ SLV_DATA_IN : in std_logic_vector(31 downto 0);
+ SLV_ADDR_IN : in std_logic_vector(15 downto 0);
+ SLV_ACK_OUT : out std_logic;
+ SLV_NO_MORE_DATA_OUT : out std_logic;
+ SLV_UNKNOWN_ADDR_OUT : out std_logic);
+end entity MupixDataLink;
+
+architecture rtl of MupixDataLink is
+
+ -----------------------------------
+ -- Mupix data channel to serdes map
+ -- Serdes0 = Data4
+ -- Serdes1 = Data1
+ -- Serdes2 = Data3
+ -- Serdes3 = Data2
+ ------------------------------------
+ constant c_used_serdes_channels : integer := 4;
+ constant c_serdes_data_width : integer := 8;
+ constant c_serdes_fifo_rdcnt_width : integer := 10;
+ constant c_serdes_fifo_large_rdcnt_width : integer := 11;
+
+ signal data_from_serdes_i : std_logic_vector(c_used_serdes_channels*c_serdes_data_width - 1 downto 0);
+ signal data_from_fifos_i : std_logic_vector(127 downto 0);
+ signal serdes_fifo_rdcnt_i : std_logic_vector((c_used_serdes_channels - 1)*c_serdes_fifo_rdcnt_width - 1 downto 0);
+ signal serdes_fifo_large_rdcnt_i : std_logic_vector(c_serdes_fifo_large_rdcnt_width - 1 downto 0);
+
+ signal rx_los_low_s, rx_los_low_s_sync : std_logic_vector(c_used_serdes_channels - 1 downto 0);
+ signal lsm_status_s, lsm_status_s_sync : std_logic_vector(c_used_serdes_channels - 1 downto 0);
+ signal rx_cdr_lol_s, rx_cdr_lol_s_sync : std_logic_vector(c_used_serdes_channels - 1 downto 0);
+
+ component InputSynchronizer
+ generic(depth : integer := 2;
+ width : integer := 1);
+ port(
+ clk : in std_logic;
+ rst : in std_logic;
+ input : in std_logic_vector(width - 1 downto 0);
+ sync_output : out std_logic_vector(width - 1 downto 0));
+ end component InputSynchronizer;
+
+ component serdes_fifo is
+ port(
+ Data : in std_logic_vector(c_serdes_data_width - 1 downto 0);
+ WrClock : in std_logic;
+ RdClock : in std_logic;
+ WrEn : in std_logic;
+ RdEn : in std_logic;
+ Reset : in std_logic;
+ RPReset : in std_logic;
+ Q : out std_logic_vector(31 downto 0);
+ RCNT : out std_logic_vector(c_serdes_fifo_rdcnt_width - 1 downto 0);
+ Empty : out std_logic;
+ Full : out std_logic);
+ end component serdes_fifo;
+
+ component serdes_fifo_large is
+ port(
+ Data : in std_logic_vector(c_serdes_data_width - 1 downto 0);
+ WrClock : in std_logic;
+ RdClock : in std_logic;
+ WrEn : in std_logic;
+ RdEn : in std_logic;
+ Reset : in std_logic;
+ RPReset : in std_logic;
+ Q : out std_logic_vector(31 downto 0);
+ RCNT : out std_logic_vector(c_serdes_fifo_large_rdcnt_width - 1 downto 0);
+ Empty : out std_logic;
+ Full : out std_logic);
+ end component serdes_fifo_large;
+
+ component mupix_serdes is
+ GENERIC(USER_CONFIG_FILE : String := "mupix_serdes.txt");
+ port(
+ ------------------
+ -- CH0 --
+ hdinp_ch0, hdinn_ch0 : in std_logic;
+ rxiclk_ch0 : in std_logic;
+ rx_full_clk_ch0 : out std_logic;
+ rx_half_clk_ch0 : out std_logic;
+ fpga_rxrefclk_ch0 : in std_logic;
+ rxdata_ch0 : out std_logic_vector(c_serdes_data_width - 1 downto 0);
+ rx_k_ch0 : out std_logic;
+ rx_disp_err_ch0 : out std_logic;
+ rx_cv_err_ch0 : out std_logic;
+ rx_pwrup_ch0_c : in std_logic;
+ rx_los_low_ch0_s : out std_logic;
+ lsm_status_ch0_s : out std_logic;
+ rx_cdr_lol_ch0_s : out std_logic;
+ rx_div2_mode_ch0_c : in std_logic;
+ -- CH1 --
+ hdinp_ch1, hdinn_ch1 : in std_logic;
+ rxiclk_ch1 : in std_logic;
+ rx_full_clk_ch1 : out std_logic;
+ rx_half_clk_ch1 : out std_logic;
+ fpga_rxrefclk_ch1 : in std_logic;
+ rxdata_ch1 : out std_logic_vector(c_serdes_data_width - 1 downto 0);
+ rx_k_ch1 : out std_logic;
+ rx_disp_err_ch1 : out std_logic;
+ rx_cv_err_ch1 : out std_logic;
+ rx_pwrup_ch1_c : in std_logic;
+ rx_los_low_ch1_s : out std_logic;
+ lsm_status_ch1_s : out std_logic;
+ rx_cdr_lol_ch1_s : out std_logic;
+ rx_div2_mode_ch1_c : in std_logic;
+ -- CH2 --
+ hdinp_ch2, hdinn_ch2 : in std_logic;
+ rxiclk_ch2 : in std_logic;
+ rx_full_clk_ch2 : out std_logic;
+ rx_half_clk_ch2 : out std_logic;
+ fpga_rxrefclk_ch2 : in std_logic;
+ rxdata_ch2 : out std_logic_vector(c_serdes_data_width - 1 downto 0);
+ rx_k_ch2 : out std_logic;
+ rx_disp_err_ch2 : out std_logic;
+ rx_cv_err_ch2 : out std_logic;
+ rx_pwrup_ch2_c : in std_logic;
+ rx_los_low_ch2_s : out std_logic;
+ lsm_status_ch2_s : out std_logic;
+ rx_cdr_lol_ch2_s : out std_logic;
+ rx_div2_mode_ch2_c : in std_logic;
+ -- CH3 --
+ hdinp_ch3, hdinn_ch3 : in std_logic;
+ rxiclk_ch3 : in std_logic;
+ rx_full_clk_ch3 : out std_logic;
+ rx_half_clk_ch3 : out std_logic;
+ fpga_rxrefclk_ch3 : in std_logic;
+ rxdata_ch3 : out std_logic_vector(c_serdes_data_width - 1 downto 0);
+ rx_k_ch3 : out std_logic;
+ rx_disp_err_ch3 : out std_logic;
+ rx_cv_err_ch3 : out std_logic;
+ rx_pwrup_ch3_c : in std_logic;
+ rx_los_low_ch3_s : out std_logic;
+ lsm_status_ch3_s : out std_logic;
+ rx_cdr_lol_ch3_s : out std_logic;
+ rx_div2_mode_ch3_c : in std_logic;
+ ---- Miscillaneous ports
+ fpga_txrefclk : in std_logic;
+ tx_sync_qd_c : in std_logic;
+ refclk2fpga : out std_logic;
+ rst_n : in std_logic;
+ serdes_rst_qd_c : in std_logic);
+ end component mupix_serdes;
+
+begin
+
+ SLV_BUS : process(sysclk) is
+ begin
+ if rising_edge(sysclk) then
+ if rst = '1' then
+ SLV_DATA_OUT <= (others => '0');
+ SLV_UNKNOWN_ADDR_OUT <= '0';
+ SLV_NO_MORE_DATA_OUT <= '0';
+ SLV_ACK_OUT <= '0';
+ else
+ if SLV_READ_IN = '1' then
+ case SLV_ADDR_IN is
+ when x"0001" => --read counters are already synchronous to trb system clock
+ SLV_DATA_OUT(c_serdes_fifo_rdcnt_width - 1 downto 0) <= serdes_fifo_rdcnt_i(c_serdes_fifo_rdcnt_width - 1 downto 0);
+ SLV_ACK_OUT <= '1';
+ when x"0002" =>
+ SLV_DATA_OUT(c_serdes_fifo_rdcnt_width - 1 downto 0) <= serdes_fifo_rdcnt_i(2*c_serdes_fifo_rdcnt_width - 1 downto c_serdes_fifo_rdcnt_width);
+ SLV_ACK_OUT <= '1';
+ when x"0003" =>
+ SLV_DATA_OUT(c_serdes_fifo_rdcnt_width - 1 downto 0) <= serdes_fifo_rdcnt_i(3*c_serdes_fifo_rdcnt_width - 1 downto 2*c_serdes_fifo_rdcnt_width);
+ SLV_ACK_OUT <= '1';
+ when x"0004" =>
+ SLV_DATA_OUT(c_serdes_fifo_rdcnt_width - 1 downto 0) <= serdes_fifo_large_rdcnt_i(c_serdes_fifo_large_rdcnt_width - 1 downto 0);
+ SLV_ACK_OUT <= '1';
+ when x"0005" =>
+ SLV_DATA_OUT(c_used_serdes_channels - 1 downto 0) <= lsm_status_s_sync;
+ SLV_ACK_OUT <= '1';
+ when x"0006" =>
+ SLV_DATA_OUT(c_used_serdes_channels - 1 downto 0) <= rx_los_low_s_sync;
+ SLV_ACK_OUT <= '1';
+ when x"0007" =>
+ SLV_DATA_OUT(c_used_serdes_channels - 1 downto 0) <= rx_cdr_lol_s_sync;
+ SLV_ACK_OUT <= '1';
+ when others =>
+ SLV_UNKNOWN_ADDR_OUT <= '1';
+ end case;
+ end if;
+ end if;
+ end if;
+ end process SLV_BUS;
+
+ --serdes status to led
+ led_status : process (rx_los_low_s, lsm_status_s, rx_cdr_lol_s) is
+ begin
+ for i in 0 to c_used_serdes_channels - 1 loop
+ channel_status_led(i) <= lsm_status_s(i) and not rx_cdr_lol_s(i) and not rx_los_low_s(i);
+ end loop;
+ end process led_status;
+
+ --synchronize status signals to trb clock domain
+ sync_lsm_status : component InputSynchronizer
+ generic map(depth => 2, width => c_used_serdes_channels)
+ port map(clk => sysclk, rst => rst, input => lsm_status_s, sync_output => lsm_status_s_sync);
+
+ sync_los_low : component InputSynchronizer
+ generic map(depth => 2, width => c_used_serdes_channels)
+ port map(clk => sysclk, rst => rst, input => rx_los_low_s, sync_output => rx_los_low_s_sync);
+
+ sync_cdr_lol : component InputSynchronizer
+ generic map(depth => 2, width => c_used_serdes_channels)
+ port map(clk => sysclk, rst => rst, input => rx_cdr_lol_s, sync_output => rx_cdr_lol_s_sync);
+
+
+end architecture;
\ No newline at end of file