-- -- Readout Deserialiser -- -- Log: -- 09/05/2012 - changed actions of almost full fifo to abort always in WaitBits -- - stopped reverting to header detect after trailer timeout, rather wait for trailer indefinitely -- - send truncated packet if fragments try for higher than 1 -- 02/10/2012 - added ff to header_seen_o, added "if en='0'" to WaitStart's library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; library utils; use utils.pkg_types.all; library hsio; use hsio.pkg_core_globals.all; entity ro_deser is port( STREAM_ID : in integer; --RAW_MULTI_EN : in std_logic; sr_data_word_i : in std_logic_vector (15 downto 0); header_seen_i : in std_logic; trailer_seen_i : in std_logic; tseen_lch_i : in std_logic; tseen_lch_clr_o : out std_logic; --gendata_sel_i : in std_logic; capture_mode_i : in std_logic; wide_cap_mode_i : in std_logic; capture_len_i : in std_logic_vector (8 downto 0); --strm_src_i : in std_logic_vector (2 downto 0); capture_start_i : in std_logic; --ocrawcom_start_i : in std_logic; mode40_strobe_i : in std_logic; -- output fifo interface fifo_we_o : out std_logic; fifo_eof_o : out std_logic; fifo_sof_o : out std_logic; fifo_data_o : out slv16; data_len_o : out std_logic_vector (10 downto 0); data_len_wr_o : out std_logic; data_truncd_o : out std_logic; -- fifo monitoring fifo_near_full_i : in std_logic; fifo_full_i : in std_logic; len_fifo_near_full_i : in std_logic; len_fifo_full_i : in std_logic; -- header details l1id_i : in std_logic_vector (23 downto 0); bcid_i : in std_logic_vector (11 downto 0); -- deser monitoring dropped_pkts_o : out slv8; -- infra en : in std_logic; clk : in std_logic; rst : in std_logic ); -- Declarations end ro_deser ; -- architecture rtl of ro_deser is -- need to keep tabs on data size to ensure we don't exceed ethernet frame size. -- also now want it a multiple of 16 constant OC_WORDS_MAX : integer := 736; -- 1488-16=1472/2 = 743/16 = 46 constant OC_BLOCKS_MAX : integer := OC_WORDS_MAX/16; -- signal dcom_seqid_inc : std_logic; signal data_len_store : std_logic; signal fifo_data : std_logic_vector(15 downto 0); signal fifo_we : std_logic; signal fifo_sof : std_logic; signal fifo_eof : std_logic; signal fifo_data_we : std_logic; signal fifo_dcomhdr_we : std_logic; signal fifo_zero_we : std_logic; signal dcom_fragid : std_logic; signal dcom_fragid_inc : std_logic; signal dcom_seqid : slv16; signal chan_fragid : slv16; signal bit_counter : integer range 0 to 16#3FFF#; signal bit_counter_clr : std_logic; signal bit_counter_slv : std_logic_vector(13 downto 0); signal block_count : std_logic_vector(5 downto 0); signal word_count : std_logic_vector(9 downto 0); signal word16_count : std_logic_vector(3 downto 0); signal word_bit : std_logic_vector(3 downto 0); signal word_bit_f : std_logic; signal mode_coded : std_logic_vector(7 downto 0); type states is ( WaitStart, WaitBitsMain, WaitBitsHeader, CaptureWaitStart, CaptureWaitBitsMain, CaptureWaitBitsHeader, InTrailer, PadTrailerEOP, FragmentEOP, PadFragmentEOP, NextFragment, CaptureEOP, CaptureFIFONearFullEOP, --CaptureEmptyEv, TruncWaitTrailer, EmptyEvWaitTrailer, FIFONearFullEOP, SendEmptyEvErrPkt, EmptyEvErrPktSOF, EmptyEvErrPktEOF, EEWaitTrailer, SendErrorPkt, ErrorPktSOF, ErrorPktEOF, Reset ); signal state : states := Reset; constant OC_HEADER_LEN : integer := 3; constant DATA_HEADER_LEN : integer := 1; constant TRAILER_PAD_LEN : integer := 1; constant HEADER_ALIGN_OFFSET : integer := -7; constant OC_START_BCNT : integer := 16 + -- added to increase len reported (TRAILER_PAD_LEN*16)+ (DATA_HEADER_LEN*16)+ HEADER_ALIGN_OFFSET; constant DATA_START_BCNT : integer := OC_START_BCNT + OC_HEADER_LEN + DATA_HEADER_LEN; constant DATA_START_BCNT_MINUS1 : integer := DATA_START_BCNT - 1; -- signal dcomhdr_data : slv16; --*** fixme:+1??? signal dcomhdr : slv16_array(DATA_START_BCNT+1 downto OC_START_BCNT); -- signal errhdr : slv16_array(OC_START_BCNT+4 downto OC_START_BCNT); signal fifo_errhdr_we : std_logic; signal dropped_pkts_inc : std_logic; signal dropped_pkts_count : slv8; signal error_code : slv16; constant EC_EMPTY_EVENT : slv16 := x"0001"; constant EC_TRUNCEV_TRAILER_TO : slv16 := x"0002"; constant EC_FRAGEV_TRAILER_TO : slv16 := x"0003"; constant EC_EMPTYEV_TRAILER_TO : slv16 := x"0004"; constant EC_LEN_FIFO_FULL : slv16 := x"0005"; signal strm_id_final : integer; begin mode_coded <= "00000" & capture_mode_i & --gendata_sel_i & "00"; -- gstmid0 : if (C_RAW_MULTI_EN = 1) and (STREAM_ID < 16) generate -- strm_id_final <= (STREAM_ID+16) when strm_src_i = "001" else -- (STREAM_ID+32) when strm_src_i = "010" else -- STREAM_ID; -- end generate; -- gstmid16 : if (C_RAW_MULTI_EN = 1) and (STREAM_ID >= 16) generate -- strm_id_final <= STREAM_ID; -- end generate; -- grawmulti0 : if (C_RAW_MULTI_EN = 0) generate -- strm_id_final <= STREAM_ID; -- end generate; -- *** Hopefully the optimiser will see this for what it is - generics for pre- -- synthed blocks --prc_strm_id : process (RAW_MULTI_EN, STREAM_ID, strm_src_i) --begin --if (RAW_MULTI_EN = '1') then --if (STREAM_ID < 16) then --if (strm_src_i = "001") then --strm_id_final <= (STREAM_ID+16); --elsif(strm_src_i = "010") then --strm_id_final <= (STREAM_ID+32); --else --strm_id_final <= STREAM_ID; --end if; --else -- (STREAM_ID >= 16) then --strm_id_final <= STREAM_ID; --end if; --else --(RAW_MULTI_EN = 0) then strm_id_final <= STREAM_ID; --end if; --end process; chan_fragid <= conv_std_logic_vector(strm_id_final, 8) & "0000000" & dcom_fragid; -- Note: headers also include first word/s of payload as needed -- *** fixme : should need the +1 below dcomhdr(OC_START_BCNT+1) <= x"D0" & mode_coded; dcomhdr(OC_START_BCNT+2) <= dcom_seqid; -- Sequence ID dcomhdr(OC_START_BCNT+3) <= x"0000"; -- Payload Size place holder dcomhdr(OC_START_BCNT+4) <= chan_fragid; -- Channel/Fragment ID errhdr(OC_START_BCNT+0) <= x"F0" & mode_coded; errhdr(OC_START_BCNT+1) <= dcom_seqid; -- Sequence ID errhdr(OC_START_BCNT+2) <= x"0000"; -- Payload Size place holder errhdr(OC_START_BCNT+3) <= chan_fragid; -- Channel/Fragment ID errhdr(OC_START_BCNT+4) <= error_code; --------------------------------------------------- -- FIFO Data Output --------------------------------------------------- fifo_data <= sr_data_word_i when (fifo_data_we = '1') else dcomhdr(bit_counter) when (fifo_dcomhdr_we = '1') else errhdr(bit_counter) when (fifo_errhdr_we = '1') else (others => '0'); -- fifo_zero_we fifo_we <= fifo_data_we or fifo_dcomhdr_we or fifo_zero_we or fifo_errhdr_we; fifo_data_o <= fifo_data; fifo_we_o <= fifo_we; fifo_eof_o <= fifo_eof; fifo_sof_o <= fifo_sof; --------------------------------------------------- -- Deserialiser Machine --------------------------------------------------- prc_bit_counter : process (clk) begin if rising_edge(clk) then if (rst = '1') then bit_counter <= OC_START_BCNT; else if (mode40_strobe_i = '1') then if (bit_counter_clr = '1') then bit_counter <= OC_START_BCNT; else bit_counter <= bit_counter + 1; end if; end if; end if; end if; end process; bit_counter_slv <= conv_std_logic_vector(bit_counter, 14); block_count <= bit_counter_slv(13 downto 8) when (wide_cap_mode_i = '0') else bit_counter_slv(9 downto 4); word_count <= bit_counter_slv(13 downto 4); word16_count <= bit_counter_slv(7 downto 4); word_bit <= bit_counter_slv(3 downto 0); word_bit_f <= '1' when (word_bit = x"f") else '0'; -- prc_pseudo_sync_state_part : process (clk, mode40_strobe_i) -- begin -- if (mode40_i = '0') then -- state <= nstate; -- else -- -- This is the cludge needed to make things go at 40MHz -- if rising_edge(clk) then -- if (rst = '1') then -- state <= Reset; -- else -- state <= nstate; -- end if; -- end if; -- end if; -- end process; prc_sm_inproc : process (clk) begin if rising_edge(clk) then if (rst = '1') then fifo_data_we <= '0'; fifo_dcomhdr_we <= '0'; fifo_zero_we <= '0'; fifo_sof <= '0'; fifo_eof <= '0'; bit_counter_clr <= '1'; -- dcom_seqid_inc <= '0'; data_len_store <= '0'; state <= Reset; fifo_errhdr_we <= '0'; dropped_pkts_inc <= '0'; dcom_fragid <= '0'; tseen_lch_clr_o <= '0'; error_code <= (others => '0'); else -- defaults fifo_data_we <= '0'; fifo_dcomhdr_we <= '0'; fifo_zero_we <= '0'; fifo_sof <= '0'; fifo_eof <= '0'; dropped_pkts_inc <= '0'; tseen_lch_clr_o <= '0'; fifo_errhdr_we <= '0'; data_len_store <= '0'; if (mode40_strobe_i = '1') then -- defaults -- need to hold value at 40 bit_counter_clr <= '0'; tseen_lch_clr_o <= '0'; case state is when Reset => state <= Reset; bit_counter_clr <= '1'; tseen_lch_clr_o <= '1'; dcom_fragid <= '0'; error_code <= (others => '0'); if (en = '1') then if (capture_mode_i = '1') then state <= CaptureWaitStart; else state <= WaitStart; end if; end if; when WaitStart => state <= WaitStart; bit_counter_clr <= '1'; tseen_lch_clr_o <= '1'; if (en = '0') then state <= Reset; elsif (capture_mode_i = '1') then -- splitting Norm/Cap mode states state <= CaptureWaitStart; elsif (header_seen_i = '1') then bit_counter_clr <= '0'; --dcom_seqid_inc <= '1'; if (len_fifo_near_full_i = '1') then error_code <= EC_LEN_FIFO_FULL; state <= SendErrorPkt; elsif (fifo_full_i = '1') or (fifo_near_full_i = '1') or (len_fifo_full_i = '1') then --drop dropped_pkts_inc <= '1'; state <= Reset; else state <= WaitBitsHeader; end if; end if; when CaptureWaitStart => state <= CaptureWaitStart; bit_counter_clr <= '1'; tseen_lch_clr_o <= '1'; if (en = '0') then state <= Reset; elsif (capture_mode_i = '0') then -- splitting Cap/Norm mode states state <= WaitStart; elsif (capture_start_i = '1') then bit_counter_clr <= '0'; --dcom_seqid_inc <= '1'; if (len_fifo_near_full_i = '1') then error_code <= EC_LEN_FIFO_FULL; state <= SendErrorPkt; elsif (fifo_full_i = '1') or (fifo_near_full_i = '1') or (len_fifo_full_i = '1') then --drop dropped_pkts_inc <= '1'; state <= Reset; else state <= CaptureWaitBitsHeader; end if; end if; when WaitBitsHeader => state <= WaitBitsHeader; if (word_bit_f = '1') then fifo_data_we <= '1'; end if; if (bit_counter = OC_START_BCNT) then fifo_sof <= '1'; end if; if (bit_counter < DATA_START_BCNT) then -- write header words fifo_dcomhdr_we <= '1'; end if; if (bit_counter = DATA_START_BCNT_MINUS1) then state <= WaitBitsMain; end if; when WaitBitsMain => state <= WaitBitsMain; if (word_bit_f = '1') then fifo_data_we <= '1'; end if; if (fifo_near_full_i = '1') then data_len_store <= '1'; -- data_truncd_o <= '1'; state <= FIFONearFullEOP; else if (tseen_lch_i = '1') then -- data_len_store <= '1'; -- Done later state <= InTrailer; elsif (block_count = OC_BLOCKS_MAX) then --data_len_store <= '1'; state <= FragmentEOP; end if; end if; ------------------------------------------------------------ when CaptureWaitBitsHeader => state <= CaptureWaitBitsHeader; if (word_bit_f = '1') then fifo_data_we <= '1'; end if; if (bit_counter = OC_START_BCNT) then fifo_sof <= '1'; end if; if (bit_counter < DATA_START_BCNT) then -- write header words fifo_dcomhdr_we <= '1'; end if; if (bit_counter = DATA_START_BCNT_MINUS1) then state <= CaptureWaitBitsMain; end if; when CaptureWaitBitsMain => state <= CaptureWaitBitsMain; if (word_bit_f = '1') or (wide_cap_mode_i = '1') then fifo_data_we <= '1'; end if; if (fifo_near_full_i = '1') then data_len_store <= '1'; -- data_truncd_o <= '1'; state <= CaptureFIFONearFullEOP; elsif (block_count(4 downto 0) >= (capture_len_i(8 downto 4))) then data_len_store <= '1'; state <= CaptureEOP; end if; -- Normal Packet handling incl. Capture --------------------------------------- when InTrailer => state <= InTrailer; if (word_bit_f = '1') then fifo_data_we <= '1'; data_len_store <= '1'; state <= PadTrailerEOP; end if; when PadTrailerEOP => -- add the zeros artificually so sm is ready for a directly following header fifo_zero_we <= '1'; fifo_eof <= '1'; state <= Reset; when CaptureEOP => state <= CaptureEOP; if (word_bit_f = '1') then fifo_data_we <= '1'; fifo_eof <= '1'; state <= Reset; end if; -- Fragment handling ---------------------------------------------- when FragmentEOP => state <= FragmentEOP; if (word_bit_f = '1') then data_len_store <= '1'; --if (dcom_fragid = '1') then -- data_truncd_o <= '1'; --end if; fifo_data_we <= '1'; state <= PadFragmentEOP; end if; when PadFragmentEOP => fifo_zero_we <= '1'; fifo_eof <= '1'; state <= NextFragment; when NextFragment => state <= NextFragment; if (dcom_fragid = '1') then --already on second fragment state <= TruncWaitTrailer; elsif (word_bit = x"7") then -- re-align dcom_fragid <= '1'; bit_counter_clr <= '1'; state <= WaitBitsHeader; end if; -- FIFO near full/truncated packet handling ---------------------------------------------- when FIFONearFullEOP => state <= FIFONearFullEOP; if (word_bit_f = '1') then fifo_data_we <= '1'; fifo_eof <= '1'; bit_counter_clr <= '1'; --data_truncd_o <= '1'; -- now must be done before data_len_store if (tseen_lch_i = '1') then state <= Reset; else state <= TruncWaitTrailer; end if; end if; when TruncWaitTrailer => state <= TruncWaitTrailer; if (tseen_lch_i = '1') then state <= Reset; elsif (block_count = "111111") then -- timeout waiting for trailer error_code <= EC_TRUNCEV_TRAILER_TO; state <= SendEmptyEvErrPkt; end if; when CaptureFIFONearFullEOP => state <= CaptureFIFONearFullEOP; if (word_bit_f = '1') then fifo_data_we <= '1'; fifo_eof <= '1'; bit_counter_clr <= '1'; --data_truncd_o <= '1'; state <= Reset; end if; -- Empty Event Handling -------------------------------------------------- when EmptyEvWaitTrailer => state <= EmptyEvWaitTrailer; if (tseen_lch_i = '1') then error_code <= EC_EMPTY_EVENT; state <= SendEmptyEvErrPkt; elsif (block_count = "111111") then -- timeout waiting for trailer error_code <= EC_EMPTYEV_TRAILER_TO; state <= SendEmptyEvErrPkt; end if; --when CaptureEmptyEv => -- error_code <= EC_EMPTY_EVENT; -- state <= SendEmptyEvErrPkt; -- Empty Event Error Packet Sending ------------------------------------------------------- when SendEmptyEvErrPkt => data_truncd_o <= '0'; bit_counter_clr <= '1'; state <= EmptyEvErrPktSOF; when EmptyEvErrPktSOF => fifo_errhdr_we <= '1'; fifo_sof <= '1'; state <= EmptyEvErrPktEOF; when EmptyEvErrPktEOF => state <= EmptyEvErrPktEOF; fifo_errhdr_we <= '1'; if (bit_counter = OC_START_BCNT+2) then data_len_store <= '1'; end if; if (bit_counter = OC_START_BCNT+3) then fifo_eof <= '1'; state <= EEWaitTrailer; end if; when EEWaitTrailer => if (tseen_lch_i = '1') then state <= Reset; else state <= EEWaitTrailer; end if; -- Error Packet Sending ------------------------------------------------------- when SendErrorPkt => --data_truncd_o <= '0'; bit_counter_clr <= '1'; state <= ErrorPktSOF; when ErrorPktSOF => fifo_errhdr_we <= '1'; fifo_sof <= '1'; state <= ErrorPktEOF; when ErrorPktEOF => state <= ErrorPktEOF; fifo_errhdr_we <= '1'; if (bit_counter = OC_START_BCNT+2) then data_len_store <= '1'; end if; if (bit_counter = OC_START_BCNT+3) then fifo_eof <= '1'; state <= Reset; end if; end case; end if; end if; end if; end process; -- Sequence ID ----------------------------------------------------------------------- prc_dcom_seqid_count : process (clk) begin if rising_edge(clk) then if (rst = '1') then dcom_seqid <= (others => '0'); --elsif (dcom_seqid_inc = '1') then elsif (fifo_sof = '1') and (fifo_we = '1') then dcom_seqid <= dcom_seqid + '1'; end if; end if; end process; -- Len FIFO Write -------------------------------------------------------------------------- data_len_wr_o <= data_len_store; --data_len_o <= block_count & x"0" & '0'; -- double for bytes data_len_o <= word_count & '0'; -- double for bytes -- Dropped Packets Counter -------------------------------------------------------------------------- prc_dropped_pks_count : process (clk) begin if rising_edge(clk) then if (rst = '1') then dropped_pkts_count <= (others => '0'); elsif (dropped_pkts_count < x"ff") and (dropped_pkts_inc = '1') then dropped_pkts_count <= dropped_pkts_count + '1'; end if; end if; end process; dropped_pkts_o <= dropped_pkts_count; end architecture rtl;