------------------------------------------------------ -- data IN from FED -- -- Ver 1.00 -- -- Dominique Gigi Feb 2012 ------------------------------------------------------ -- This is the TOP level of the core for the sender part -- 17/09/2014 add some status counter -- 17/09/2014 add a logic to trash data between Trailer and next Header -- 21/01/2015 A detection of FED system clock ------------------------------------------------------ LIBRARY ieee; library work; USE ieee.std_logic_1164.all; use ieee.numeric_std.all; use ieee.std_logic_unsigned.all; use work.mydefs.all; entity fed_itf is generic (generator : boolean := false); port ( reset_sysCLK : in std_logic; Greset_sysCLK : in std_logic; sys_clk : in std_logic; -- link data write enable ACTIVE LOW LinkWe : in STD_LOGIC; -- link data header/trailer marker when '0' LinkCtrl : in STD_LOGIC; -- link data LinkData : in STD_LOGIC_VECTOR (63 downto 0); -- link data buffer almost full ACTIVE LOW LinkAlmostFull : out STD_LOGIC; -- link down ACTIVE LOW LinkDown : out STD_LOGIC; -- src_ID : in STD_LOGIC_VECTOR (15 downto 0); -- enables error injection to test error recovery inject_err : in STD_LOGIC_VECTOR (17 downto 0); -- Link status data read out read_ce : in STD_LOGIC; addr : in STD_LOGIC_VECTOR (15 downto 0); status_data : out STD_LOGIC_VECTOR (63 downto 0); -- Interface for internal logic reset_CLK : in std_logic; Greset_CLK : in std_logic; clock : in std_logic; -- clock from internal logic block_free : in std_logic; -- almost one block is free data_fed : out std_logic_vector(63 downto 0); block_sz_fed : out std_logic_vector(15 downto 0); wr_ena : out std_logic; start_evt : out std_logic; -- this block is the first for the current event stop_evt : out std_logic; -- this block is the last for the current event -- both can be set end_blk_fed : out std_logic; -- indicate end of the packet (max 4KBytes) -- interface slave to read and write wr_cmd : in std_logic; func : in std_logic_vector(31 downto 0); data_wr : in std_logic_vector(31 downto 0); data_rd : out std_logic_vector(63 downto 0); cnt_evt : out std_logic; -- pulse for each event (on sys_clk); cnt_pckt_rcv : in std_logic_vector(31 downto 0); cnt_pckt_snd : in std_logic_vector(31 downto 0); -- status retransmit_ena : in std_logic; status_state_build_p : in std_logic_vector(31 downto 0); status_state_core : in std_logic_vector(31 downto 0); Serdes_status : in std_logic_vector(31 downto 0) ); end fed_itf; architecture behavioral of fed_itf is type fill_blk_type is ( idle, read_fifo, update_para, dummy_a, dummy_b, dummy_c -- dummy state implement du to the CRC check , which take 2 clock cylces more ); signal fill_blk,fill_blkNext:fill_blk_type; component FIFO_sync port ( aclr : in std_logic; -- active low clk_w : in std_logic; wen : in std_logic; dataw : in std_logic_vector(65 downto 0); almost_f : out std_logic; -- active low clk_r : in std_logic; datar : out std_logic_vector(65 downto 0); ren : in std_logic; empty : out std_logic -- active low ); end component; component event_generator port ( reset : IN std_logic; low_clk : IN std_logic; -- frequency of 50 Mhz PCIe_clk : IN std_logic; PCIe_func : IN std_logic_vector(15 downto 0); PCIe_wen : IN std_logic; PCIe_dti : IN std_logic_vector(31 downto 0); PCIe_dto : out std_logic_vector(31 downto 0); PCIe_cs : IN std_logic; evt_clk : IN std_logic; wen : OUT std_logic; data : OUT std_logic_vector(63 downto 0); uctrl : OUT std_logic; Back_p : IN std_logic -- Back_p when '0' ); end component; component CRC_SLINKx Port ( D : in std_logic_vector(63 downto 0); CRC_out : out std_logic_vector(15 downto 0); clk : in std_logic; clear : in std_logic; enable : in std_logic); end component; component freq_measure port ( reset : in std_logic; sysclk : in std_logic;-- clock used by the FED to send data and to measure the backpressure base_clk : in std_logic;-- clock base used to measure the sysclk frequency : out std_logic_vector(31 downto 0)-- measure of the frequency) ); end component; signal G_rst_rd : std_logic; signal datar_rreg : std_logic_vector(63 downto 0); signal data_out : std_logic_vector(63 downto 0); signal datar : std_logic_vector(65 downto 0); signal datar_reg : std_logic_vector(63 downto 0); signal start_evt_mem : std_logic; signal stop_evt_mem : std_logic; signal end_frag : std_logic; signal finish_blk : std_logic; signal empt_ff : std_logic; signal rd_ff_reg : std_logic; signal del_rd_ff : std_logic_vector(1 downto 0); signal blk_size : std_logic_vector(15 downto 0); signal blk_full : std_logic; signal blk_full_anti : std_logic; signal End_pckt_lgc : std_logic; signal last_word : std_logic; signal sel_test_mode : std_logic; signal wen_tm : std_logic; signal data_tm : std_logic_vector(63 downto 0); signal uctrl_tm : std_logic; signal backpressure_mux : std_logic; signal wen_mux : std_logic; signal data_mux : std_logic_vector(63 downto 0); signal uctrl_mux : std_logic; signal PCIe_dto : std_logic_vector(31 downto 0); signal local_reg : std_logic_vector(31 downto 0); signal LINKDOWN_cell : std_logic; -- use to pipe frgament during the CRC check signal data_r_crc : std_logic_vector(63 downto 0); signal wen_ra : std_logic; signal CRC_Rst : std_logic; signal CRC_Check : std_logic; signal ena_CRC : std_logic; signal ena_CRC_reg : std_logic; signal CRC_frag : std_logic_vector(15 downto 0); signal CRC_cmp : std_logic_vector(15 downto 0); signal data_rb_mux : std_logic_vector(63 downto 0); signal backpressure : std_logic; -- statistic values signal block_counter : std_logic_vector(31 downto 0); signal event_counter : std_logic_vector(31 downto 0); signal data_counter : std_logic_vector(63 downto 0); signal Retransmit_counter : std_logic_vector(31 downto 0); signal cnt_back_p : std_logic_vector(31 downto 0); signal FED_CRC_error_cnt : std_logic_vector(31 downto 0); signal state_machine_status: std_logic_vector(2 downto 0); signal blk_size_reg : std_logic_vector(15 downto 0); signal start_evt_mem_reg : std_logic; signal stop_evt_mem_reg : std_logic; signal End_pckt_lgc_reg : std_logic; signal freq_measure_reg : std_logic_vector(31 downto 0); signal rsyc_test_mode : std_logic_vector(1 downto 0); signal rsyc_DAQON : std_logic_vector(1 downto 0); signal evt_ongoing : std_logic; signal HD_dup : std_logic; signal TR_dup : std_logic; signal track_evt_num : std_logic_vector(23 downto 0); signal found_dup : std_logic; --*********************************************************** --********************** BEGIN **************************** --*********************************************************** begin -- Set the TEST mode and DAQ_ON with function (6) -- this function will come from optical link send by DAQ side process(Greset_CLK,clock) begin if Greset_CLK = '0' then sel_test_mode <= '0'; LINKDOWN_cell <= '0'; elsif rising_edge(clock) then if func(6) = '1' and wr_cmd = '1' then sel_test_mode <= data_wr(31); LINKDOWN_cell <= data_wr(30); end if; end if; end process; process(sys_clk) begin if rising_edge(sys_clk) then rsyc_test_mode(1) <= rsyc_test_mode(0); rsyc_test_mode(0) <= sel_test_mode; END IF; end process; local_reg(31) <= sel_test_mode; local_reg(30) <= LINKDOWN_cell; local_reg(29) <= Backpressure; local_reg(28) <= '1' when block_free = '1' else '0'; local_reg(27 downto 7) <= (others => '0'); local_reg(6) <= found_dup; local_reg(5) <= TR_dup; local_reg(4) <= HD_dup; local_reg(3) <= evt_ongoing; local_reg(2 downto 0) <= state_machine_status(2 downto 0); process(Greset_sysCLK,sys_clk) begin if rising_edge(sys_clk) then rsyc_DAQON(1) <= rsyc_DAQON(0); rsyc_DAQON(0) <= LINKDOWN_cell; end if; end process; LinkDown <= rsyc_DAQON(1); -- measure the frequency used by the fed to send data req_i1:freq_measure port map( reset => Greset_sysCLK, sysclk => sys_clk, -- clock used by the FED to send data and to measure the backpressure base_clk => clock, frequency => freq_measure_reg-- measure of the frequency) ); process(Greset_sysCLK,sys_clk) begin if Greset_sysCLK = '0' then cnt_back_p <= (others => '0'); elsif rising_edge(sys_clk) then if backpressure_mux = '0' then cnt_back_p <= cnt_back_p + '1'; end if; end if; end process; --multiplex data local and Event_gen status/data for read command coming from optical link send by DAQ side process(clock) begin if rising_edge(clock) then data_rd(63 downto 32) <= (others => '0'); if func(6) = '1' then data_rd(31 downto 0) <= local_reg; elsif func(7) = '1' then data_rd <= data_counter; elsif func(8) = '1' then data_rd(31 downto 0) <= event_counter; elsif func(9) = '1' then data_rd(31 downto 0) <= block_counter; elsif func(10) = '1' then data_rd(31 downto 0) <= cnt_pckt_rcv; elsif func(11) = '1' then data_rd(31 downto 0) <= status_state_core; elsif func(12) = '1' then data_rd(31 downto 0) <= cnt_pckt_snd; elsif func(13) = '1' then data_rd(31 downto 0) <= status_state_build_p; elsif func(14) = '1' then data_rd(31 downto 0) <= cnt_back_p; elsif func(15) = '1' then data_rd(31 downto 0) <= version; elsif func(16) = '1' then data_rd(31 downto 0) <= Serdes_status; elsif func(17) = '1' then data_rd(31 downto 0) <= Retransmit_counter; elsif func(18) = '1' then data_rd(31 downto 0) <= freq_measure_reg; else data_rd(31 downto 0) <= PCIe_dto; end if; end if; end process; -- status going back to FED side process(sys_clk) begin if rising_edge(sys_clk) then status_data(63 downto 00) <= (others => '0'); if addr = x"0001" then status_data(31 downto 0) <= local_reg; elsif addr = x"0002" then status_data <= data_counter; elsif addr = x"0003" then status_data(31 downto 0) <= event_counter; elsif addr = x"0004" then status_data(31 downto 0) <= block_counter; elsif addr = x"0005" then status_data(31 downto 0) <= cnt_pckt_rcv; elsif addr = x"0006" then status_data(31 downto 0) <= status_state_core; elsif addr = x"0007" then status_data(31 downto 0) <= cnt_pckt_snd; elsif addr = x"0008" then status_data(31 downto 0) <= status_state_build_p; elsif addr = x"0009" then status_data(31 downto 0) <= cnt_back_p; elsif addr = x"000A" then status_data(31 downto 0) <= version; elsif addr = x"000B" then status_data(31 downto 0) <= Serdes_status; elsif addr = x"000C" then status_data(31 downto 0) <= Retransmit_counter; elsif addr = x"000D" then status_data(31 downto 0) <= FED_CRC_error_cnt; elsif addr = x"000E" then status_data(31 downto 0) <= freq_measure_reg; end if; end if; end process; -- retransmit counter process(Greset_CLK,clock) begin if Greset_CLK = '0' then Retransmit_counter <= (others => '0'); elsif rising_edge(clock) then if retransmit_ena = '1' then Retransmit_counter <= Retransmit_counter + '1'; end if; end if; end process; -- local Event generator used to test the link generator_inst:if generator generate i1:event_generator port map( reset => Greset_CLK, low_clk => clock, -- frequency of ??? Mhz PCIe_clk => clock, PCIe_func => func(15 downto 0), PCIe_wen => wr_cmd, PCIe_dti => data_wr, PCIe_dto => PCIe_dto, PCIe_cs => sel_test_mode, evt_clk => sys_clk, wen => wen_tm, data => data_tm, uctrl => uctrl_tm, Back_p => backpressure_mux ); end generate; --****************************************************************************** -- multiplexer for event DATA -- mux external (FED) and local data path (Event generator) ******************** wen_mux <= wen_tm when rsyc_test_mode(1) = '1' and generator else not(LinkWe); data_mux <= data_tm when rsyc_test_mode(1) = '1' and generator else LinkData; uctrl_mux <= uctrl_tm when rsyc_test_mode(1) = '1' and generator else LinkCtrl; --****************************************************************************** process(Greset_sysCLK,sys_clk) begin if Greset_sysCLK = '0' then data_counter <= (others => '0'); elsif rising_edge(sys_clk) then if wen_mux = '1' then data_counter <= data_counter + '1'; end if; end if; end process; --indicate the last word of the EVENT end_frag <= '1' when data_mux(63 downto 60) = x"A" and uctrl_mux = '0' else '0'; -- pulse to count the number of event dicover process(Greset_sysCLK,sys_clk) begin if Greset_sysCLK = '0' then cnt_evt <= '0'; elsif rising_edge(sys_clk) then cnt_evt <= '0'; if end_frag = '1' then cnt_evt <= '1'; end if; end if; end process; -- internal FIFO used to chnage the DATA clock domaine internal_FIFO:FIFO_sync --Show A Head ON port map ( aclr => Greset_sysCLK, clk_w => sys_clk, wen => wen_mux, dataw(63 downto 0) => data_mux, dataw(64) => uctrl_mux, dataw(65) => end_frag, almost_f => backpressure_mux, clk_r => clock, datar => datar, ren => rd_ff_reg, empty => empt_ff ); -- LinkAlmostFull LFF is valid only in no TEST mode otherwise ALLTIME active (low) Backpressure <= '0' when rsyc_test_mode(1) = '1' else backpressure_mux; LinkAlmostFull <= Backpressure; --****************************************************************************** -- -******* This state machine is used to read the FIFO and fill the blocks in the CORE_LOGIC.VHD file --state machine clock FED_itf_state_clk:process(Greset_CLK,clock) begin if Greset_CLK = '0' then fill_blk <= idle; elsif rising_edge(clock) then fill_blk <= fill_blkNext; end if; end process; FED_itf_state_machine:process(fill_blk,empt_ff,block_free,blk_full,last_word) begin fill_blkNext <= fill_blk; state_machine_status <= (others => '0'); Case fill_blk is -- wait data and free block in CORE_LOGIC.VHD when idle => state_machine_status(0) <='1'; if empt_ff = '0' and block_free = '1' then fill_blkNext <= read_fifo; end if; -- continue until the last word of the EVENT or until no free BLOCK when read_fifo => state_machine_status(1) <='1'; if blk_full = '1' or last_word = '1' then --stop_evt_mem = '1' then fill_blkNext <= update_para; end if; -- unpdate flags and indicate end of block (block full or end_of_event) when update_para => state_machine_status(2) <='1'; fill_blkNext <= dummy_a; when dummy_a => fill_blkNext <= dummy_b; when dummy_b => fill_blkNext <= dummy_c; -- take 3 clock to finish to clsoe the buffer, if no the block_free value can be wrong when dummy_c => fill_blkNext <= idle; when others => fill_blkNext <= idle; end case; end process; --****************************************************************************** last_word <= '1' when rd_ff_reg = '1' and datar(65) = '1' else '0'; G_rst_rd <= '0' when Greset_CLK = '0' or empt_ff = '1' or blk_full = '1' else '1'; -- automatic read FIFO until the the last word of the EVENT or end of block (change state FILL_BLK) process(G_rst_rd,clock) begin if G_rst_rd = '0' then rd_ff_reg <= '0'; elsif rising_edge(clock) then rd_ff_reg <= '0'; if fill_blk = read_fifo and last_word = '0' then rd_ff_reg <= '1'; end if; end if; end process; --****************************************************************************** -- CRC check process(Greset_CLK,clock) begin if Greset_CLK = '0' then CRC_Rst <= '1'; ena_crc <= '0'; event_counter <= (others => '0'); evt_ongoing <= '0'; TR_dup <= '0'; HD_dup <= '0'; found_dup <= '0'; track_evt_num <= (others => '0'); elsif rising_edge(clock) then if datar(64) = '0' and datar(63 downto 60) = x"A" and rd_ff_reg = '1' then -- UCTRL= 0 + trailer + DATA_valid -- remove the CRC in the trailer to compute the CRC data_r_crc(63 downto 32) <= datar(63 downto 32); data_r_crc(31 downto 16) <= (others => '0'); data_r_crc(15 downto 0) <= datar(15 downto 0); else data_r_crc <= datar(63 downto 00); end if; wen_ra <= rd_ff_reg; datar_reg <= datar(63 downto 00); -- create the envelop of the event + counter status if datar(64) = '0' and datar(63 downto 60) = x"5" and rd_ff_reg = '1' then event_counter <= event_counter + '1'; evt_ongoing <= '1'; if evt_ongoing = '1' then HD_dup <= '1'; end if; if track_evt_num = datar(55 downto 32) then found_dup <= '1'; end if; track_evt_num <= datar(55 downto 32); end if; -- specify the place of the Trailer ena_CRC_reg <= ena_CRC; ena_crc <= '0'; if datar(64) = '0' and datar(63 downto 60) = x"A" and rd_ff_reg = '1' then ena_crc <= '1'; crc_frag <= datar(31 downto 16); evt_ongoing <= '0'; if evt_ongoing = '0' then TR_dup <= '1'; end if; end if; -- reset the CRC machine between 2 fragments if ena_crc = '1' then CRC_Rst <= '1'; elsif datar(64) = '0' and datar(63 downto 60) = x"5" and rd_ff_reg = '1' then CRC_Rst <= '0'; end if; end if; end process; -- compute the CRC i_crc_check:CRC_SLINKx Port map( clear => CRC_Rst, clk => clock, D => data_r_crc, enable => wen_ra, CRC_out => crc_cmp ); -- compare the CRC received and the CRC computed crc_check <= '0' when crc_cmp = crc_frag else '1'; -- count number of FED crc error process(Greset_CLK,clock) begin if Greset_CLK = '0' then FED_CRC_error_cnt <= (others => '0'); elsif rising_edge(clock) then if ena_CRC_reg = '1' and crc_check = '1' then FED_CRC_error_cnt <= FED_CRC_error_cnt + '1'; end if; end if; end process; -- generate FLAG to indicate the beginning and the end of the event for each BLOCK process(Greset_CLK,clock) begin if Greset_CLK = '0' then start_evt_mem <= '0'; stop_evt_mem <= '0'; elsif rising_edge(clock) then if datar(64) = '0' and datar(63 downto 60) = x"5" and rd_ff_reg = '1' then start_evt_mem <= '1'; elsif last_word = '1' then stop_evt_mem <= '1'; elsif fill_blk = update_para then --finish_blk = '1' then start_evt_mem <= '0'; stop_evt_mem <= '0'; end if; end if; end process; -- compute the size of valid data in the BLOCK process(Greset_CLK,clock) begin if Greset_CLK = '0' then blk_size <= (others => '0'); elsif rising_edge(clock) then if fill_blk = idle then blk_size <= (others => '0'); elsif rd_ff_reg = '1' and blk_full = '0' then blk_size <= blk_size + '1'; end if; end if; end process; -- count the number of block used process(Greset_CLK,clock) begin if Greset_CLK = '0' then block_counter <= (others => '0'); elsif rising_edge(clock) then if blk_full = '1' or last_word = '1' then block_counter <= block_counter + '1'; end if; end if; end process; --flag when the BLOCK is full process(Greset_CLK,clock) begin if Greset_CLK = '0' then blk_full <= '0'; elsif rising_edge(clock) then if blk_size = x"01FF" and rd_ff_reg = '1' then --blk_size = 0x200 blk_full <= '1'; elsif End_pckt_lgc = '1' then blk_full <= '0'; end if; end if; end process; End_pckt_lgc <= '1' when fill_blk = update_para else '0'; --Pipe data for the CRC check process(clock) begin if rising_edge(clock) then datar_rreg(63 downto 0) <= datar_reg(63 downto 0); blk_size_reg <= blk_size; start_evt_mem_reg <= start_evt_mem; stop_evt_mem_reg <= stop_evt_mem; End_pckt_lgc_reg <= End_pckt_lgc; end if; end process; data_out(63 downto 32) <= datar_rreg(63 downto 32); data_out(31 downto 16) <= crc_cmp when ena_CRC_reg = '1' else datar_rreg(31 downto 16); data_out(15 downto 3) <= datar_rreg(15 downto 3); data_out(2) <= crc_check when ena_CRC_reg = '1' else datar_rreg(2); data_out(1 downto 0) <= datar_rreg(1 downto 0) ; process(clock) begin if rising_edge(clock) then del_rd_ff(1) <= del_rd_ff(0); del_rd_ff(0) <= rd_ff_reg; end if; end process; --Output value to Optical interface block_sz_fed <= blk_size_reg; -- number of data in the block ready to send data_fed <= data_out; wr_ena <= del_rd_ff(1); start_evt <= start_evt_mem_reg; -- flag is set if this block is the first of the event stop_evt <= stop_evt_mem_reg; -- flag is set if this block is the last of the event end_blk_fed <= End_pckt_lgc_reg; -- flag is set at the end of the event end behavioral;