--- /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;
+
+use work.StdTypes.all;
+use work.Constants.all;
+
+entity MupixDataLinkWithUnpacker is
+ generic (
+ useRecoveredClock : integer range 0 to 1 := c_Yes);
+ 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
+ --lattice serdes
+ mupix_data : in std_logic_vector(7 downto 0); --lvds pairs of 4 incoming data channels
+ --fifo signals
+ fifo_rden : in std_logic_vector(c_links - 1 downto 0); -- read enable to FIFOs
+ fifo_empty : out std_logic_vector(c_links - 1 downto 0); -- input FIFO empty flags
+ fifo_full : out std_logic_vector(c_links - 1 downto 0); -- input FIFO full flags
+ fifo_data : out std_logic_vector(c_links*c_mupixhitsize - 1 downto 0); -- input data from FIFOs
+ --misc
+ channel_status_led : out std_logic_vector(c_links - 1 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 MupixDataLinkWithUnpacker;
+
+architecture rtl of MupixDataLinkWithUnpacker is
+
+ signal clkrx : std_logic_vector(3 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
+ port (
+ Data : in std_logic_vector(39 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(39 downto 0);
+ RCNT : out std_logic_vector(10 downto 0);
+ Empty : out std_logic;
+ Full : out std_logic);
+ end component serdes_fifo;
+
+ component mupix_serdes_new
+ generic (USER_CONFIG_FILE : string := "mupix_serdes_new.txt");
+ port (
+------------------
+-- CH0 --
+ hdinp_ch0, hdinn_ch0 : in std_logic; -- input serial link from mupix
+ rxiclk_ch0 : in std_logic; -- rx clock for fifo bridge (should be sysclock or recovered clock?)
+ rx_full_clk_ch0 : out std_logic; -- full receive clock from serdes
+ rx_half_clk_ch0 : out std_logic; -- half receive clock from serdes
+ fpga_rxrefclk_ch0 : in std_logic; -- reference clock from fpga fabric
+ rxdata_ch0 : out std_logic_vector (7 downto 0); -- received data
+ rx_k_ch0 : out std_logic; -- control charactor indicator
+ rx_disp_err_ch0 : out std_logic; -- indicate disparity error
+ rx_cv_err_ch0 : out std_logic; -- error in data
+ word_align_en_ch0_c : in std_logic; -- enable word alignment (pulse high)
+ rx_pwrup_ch0_c : in std_logic; -- power up receive channel
+ rx_los_low_ch0_s : out std_logic; -- signal lost
+ rx_cdr_lol_ch0_s : out std_logic; -- clock recovery failure
+ rx_div2_mode_ch0_c : in std_logic; -- enable clock div mode
+-- 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 (7 downto 0);
+ rx_k_ch1 : out std_logic;
+ rx_disp_err_ch1 : out std_logic;
+ rx_cv_err_ch1 : out std_logic;
+ word_align_en_ch1_c : in std_logic;
+ rx_pwrup_ch1_c : in std_logic;
+ rx_los_low_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 (7 downto 0);
+ rx_k_ch2 : out std_logic;
+ rx_disp_err_ch2 : out std_logic;
+ rx_cv_err_ch2 : out std_logic;
+ word_align_en_ch2_c : in std_logic;
+ rx_pwrup_ch2_c : in std_logic;
+ rx_los_low_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 (7 downto 0);
+ rx_k_ch3 : out std_logic;
+ rx_disp_err_ch3 : out std_logic;
+ rx_cv_err_ch3 : out std_logic;
+ word_align_en_ch3_c : in std_logic;
+ rx_pwrup_ch3_c : in std_logic;
+ rx_los_low_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 reference clock
+ tx_sync_qd_c : in std_logic; -- serializer reset
+ refclk2fpga : out std_logic; -- reference clock to fpga core
+ rst_n : in std_logic; -- reset all
+ serdes_rst_qd_c : in std_logic); -- reset serdes, but nor pcs
+ end component mupix_serdes_new;
+
+ component MupixUnpacker
+ generic(
+ g_hitsize : integer := 40;
+ g_countersize : integer := 32
+ );
+ port(
+ clk : in std_logic;
+ reset : in std_logic;
+ data_in : in std_logic_vector(7 downto 0);
+ komma : in std_logic;
+ valid : in std_logic;
+ hit_out : out std_logic_vector(g_hitsize - 1 downto 0);
+ hit_enable : out std_logic;
+ coarsecounter : out std_logic_vector(g_countersize - 1 downto 0);
+ counter_enable : out std_logic;
+ link_flag : out std_logic;
+ errorcounter : out std_logic_vector(31 downto 0));
+ end component MupixUnpacker;
+
+ component LinkSynchronizer
+ generic (
+ clk_speed : integer := 8);
+ port (
+ clk_in : in std_logic;
+ reset_in : in std_logic;
+ comma_in : in std_logic;
+ cverr_in : in std_logic;
+ link_sync_out : out std_logic;
+ link_sync_flag : out std_logic;
+ comma_counter_out : out std_logic_vector(15 downto 0));
+ end component LinkSynchronizer;
+
+ constant ch_powerup_i : std_logic_vector(3 downto 0) := "1111"; -- change to powerdown unused channels
+ constant ch_divmode_i : std_logic_vector(3 downto 0) := "0000"; -- use half rx clock speed
+
+ -- serdes signals (declare for all channels possibly used)
+ signal rx_full_clock_i : std_logic_vector(3 downto 0); -- recovered receive clock
+ signal rx_data_i : std_logic_vector(4*8 - 1 downto 0); -- receive data
+ signal rx_komma_i : std_logic_vector(3 downto 0); -- komma words
+ signal rx_disp_err_i : std_logic_vector(3 downto 0); -- disparity error indicator
+ signal rx_dataerror_i : std_logic_vector(3 downto 0); -- error in rx data
+ signal align_en_i : std_logic_vector(3 downto 0); -- regain word alignment to rx data
+ signal rx_sig_lost_i : std_logic_vector(3 downto 0); -- rx signal lost
+ signal rx_cdr_i : std_logic_vector(3 downto 0); -- clock recovery failure
+
+ -- synced signals
+ signal rx_cdr_sync : std_logic_vector(3 downto 0);
+ signal rx_sig_lost_sync : std_logic_vector(3 downto 0);
+
+ -- fifo signals
+ signal fifo_data_oi : std_logic_vector(c_links*c_mupixhitsize - 1 downto 0);
+ signal fifo_data_ii : std_logic_vector(c_links*c_mupixhitsize - 1 downto 0);
+ signal fifo_empty_i : std_logic_vector(c_links - 1 downto 0) := (others => '0');
+ signal fifo_full_i : std_logic_vector(c_links - 1 downto 0) := (others => '0');
+ signal fifo_wren_i : std_logic_vector(c_links - 1 downto 0) := (others => '0');
+ signal fifo_rden_i : std_logic_vector(c_links - 1 downto 0) := (others => '0');
+ constant fifo_depth : integer := 10; -- fifo depth (change when regenerating FIFO IP core)
+ signal fifo_readcnt_i : std_logic_vector((c_links - 1)*fifo_depth - 1 downto 0);
+
+ -- status and error counters
+ signal serdes_channel_select : integer range 0 to 3 := 0;
+ signal disp_error_counter : t_counter_array(0 to 3) := (others => (others => '0'));
+ signal data_error_counter : t_counter_array(0 to 3) := (others => (others => '0'));
+ signal unpacker_error_counter : t_counter_array(0 to 3) := (others => (others => '0'));
+
+ -- link synchronizer signals
+ signal link_sync_out_i : std_logic_vector(c_links - 1 downto 0) := (others => '0');
+ signal link_sync_flag_i : std_logic_vector(c_links - 1 downto 0) := (others => '0');
+ signal komma_counter : t_counter_array(0 to 3) := (others => (others => '0'));
+
+ -- unpacker signals
+ signal unpacker_valid_i : std_logic_vector(c_links - 1 downto 0) := (others => '0');
+
+begin
+
+ gen_receive_clock_rec : if useRecoveredClock = c_Yes generate
+ clkrx <= rx_full_clock_i;
+ end generate;
+
+ gen_receive_clock_norec : if useRecoveredClock = c_No generate
+ clkrx <= sysclk & sysclk & sysclk & sysclk;
+ end generate;
+
+ -- not sure about correct clock distribution
+ mupix_serdes_new : entity work.mupix_serdes_new
+ generic map (
+ USER_CONFIG_FILE => "mupix_serdes_new.txt")
+ port map (
+ hdinp_ch0 => mupix_data(0),
+ hdinn_ch0 => mupix_data(1),
+ rxiclk_ch0 => clkrx(0),
+ rx_full_clk_ch0 => rx_full_clock_i(0),
+ rx_half_clk_ch0 => open,
+ fpga_rxrefclk_ch0 => dataclk,
+ rxdata_ch0 => rx_data_i(1*8 - 1 downto 0*8),
+ rx_k_ch0 => rx_komma_i(0),
+ rx_disp_err_ch0 => rx_disp_err_i(0),
+ rx_cv_err_ch0 => rx_dataerror_i(0),
+ word_align_en_ch0_c => align_en_i(0),
+ rx_pwrup_ch0_c => ch_powerup_i(0),
+ rx_los_low_ch0_s => rx_sig_lost_i(0),
+ rx_cdr_lol_ch0_s => rx_cdr_i(0),
+ rx_div2_mode_ch0_c => ch_divmode_i(0),
+ hdinp_ch1 => mupix_data(2),
+ hdinn_ch1 => mupix_data(3),
+ rxiclk_ch1 => clkrx(1),
+ rx_full_clk_ch1 => rx_full_clock_i(1),
+ rx_half_clk_ch1 => open,
+ fpga_rxrefclk_ch1 => dataclk,
+ rxdata_ch1 => rx_data_i(2*8 - 1 downto 1*8),
+ rx_k_ch1 => rx_komma_i(1),
+ rx_disp_err_ch1 => rx_disp_err_i(1),
+ rx_cv_err_ch1 => rx_dataerror_i(1),
+ word_align_en_ch1_c => align_en_i(1),
+ rx_pwrup_ch1_c => ch_powerup_i(1),
+ rx_los_low_ch1_s => rx_sig_lost_i(1),
+ rx_cdr_lol_ch1_s => rx_cdr_i(1),
+ rx_div2_mode_ch1_c => ch_divmode_i(1),
+ hdinp_ch2 => mupix_data(4),
+ hdinn_ch2 => mupix_data(5),
+ rxiclk_ch2 => clkrx(2),
+ rx_full_clk_ch2 => rx_full_clock_i(2),
+ rx_half_clk_ch2 => open,
+ fpga_rxrefclk_ch2 => dataclk,
+ rxdata_ch2 => rx_data_i(3*8 - 1 downto 2*8),
+ rx_k_ch2 => rx_komma_i(2),
+ rx_disp_err_ch2 => rx_disp_err_i(2),
+ rx_cv_err_ch2 => rx_dataerror_i(2),
+ word_align_en_ch2_c => align_en_i(2),
+ rx_pwrup_ch2_c => ch_powerup_i(2),
+ rx_los_low_ch2_s => rx_sig_lost_i(2),
+ rx_cdr_lol_ch2_s => rx_cdr_i(2),
+ rx_div2_mode_ch2_c => ch_divmode_i(2),
+ hdinp_ch3 => mupix_data(6),
+ hdinn_ch3 => mupix_data(7),
+ rxiclk_ch3 => clkrx(3),
+ rx_full_clk_ch3 => rx_full_clock_i(3),
+ rx_half_clk_ch3 => open,
+ fpga_rxrefclk_ch3 => dataclk,
+ rxdata_ch3 => rx_data_i(4*8 - 1 downto 3*8),
+ rx_k_ch3 => rx_komma_i(3),
+ rx_disp_err_ch3 => rx_disp_err_i(3),
+ rx_cv_err_ch3 => rx_dataerror_i(3),
+ word_align_en_ch3_c => align_en_i(3),
+ rx_pwrup_ch3_c => ch_powerup_i(3),
+ rx_los_low_ch3_s => rx_sig_lost_i(3),
+ rx_cdr_lol_ch3_s => rx_cdr_i(3),
+ rx_div2_mode_ch3_c => ch_divmode_i(2),
+ fpga_txrefclk => dataclk,
+ tx_sync_qd_c => '0',
+ refclk2fpga => open,
+ rst_n => '1',
+ serdes_rst_qd_c => clear);
+
+ generate_synchronizer : for j in 0 to c_links - 1 generate
+ entity work.LinkSynchronizer
+ generic map (
+ clk_speed => 8)
+ port map (
+ clk_in => clkrx,
+ reset_in => rst,
+ comma_in => rx_komma_i(j),
+ cverr_in => rx_dataerror_i(j),
+ link_sync_out => link_sync_out_i(j),
+ link_sync_flag => link_sync_flag_i(j),
+ comma_counter_out => komma_counter(j));
+ end generate generate_synchronizer;
+
+ unpacker_valid_i <= not rx_dataerror_i;
+
+ generate_unpacker : for j in 0 to c_links - 1 generate
+ entity work.MupixUnpacker
+ generic map (
+ g_hitsize => c_mupixhitsize,
+ g_countersize => 31)
+ port map (
+ clk => clkrx,
+ reset => rst,
+ data_in => rx_data_i((j + 1)*8 - 1 downto j*8),
+ komma => rx_komma_i(j),
+ valid => unpacker_valid_i(j),
+ hit_out => fifo_data_ii((j + 1)*c_mupixhitsize downto j*c_mupixhitsize),
+ hit_enable => fifo_wren_i(j),
+ coarsecounter => open,
+ counter_enable => open,
+ link_flag => open,
+ errorcounter => unpacker_error_counter(j));
+ end generate generate_fifo;
+
+ generate_fifo : for j in 0 to c_links - 1 generate
+ entity work.serdes_fifo
+ port map (
+ Data => fifo_data_ii((j + 1)*c_mupixhitsize downto j*c_mupixhitsize),
+ WrClock => clkrx(j),
+ RdClock => sysclk,
+ WrEn => fifo_wren_i(j),
+ RdEn => fifo_rden_i(j),
+ Reset => rst,
+ RPReset => rst,
+ Q => fifo_data_oi((j + 1)*c_mupixhitsize downto j*c_mupixhitsize),
+ RCNT => fifo_readcnt_i((j + 1)*fifo_depth - 1 downto j*fifo_depth),
+ Empty => fifo_empty_i(j),
+ Full => fifo_full_i(j));
+ end generate generate_fifo;
+
+ sync_los_low : InputSynchronizer
+ generic map(depth => 2, width => 4)
+ port map(clk => sysclk, rst => rst, input => rx_sig_lost_i, sync_output => rx_sig_lost_sync);
+
+ sync_cdr_lol : InputSynchronizer
+ generic map(depth => 2, width => 4)
+ port map(clk => sysclk, rst => rst, input => rx_cdr_i, sync_output => rx_cdr_sync);
+
+end architecture;