-- -- Readout Unit FIFO for ABC130 packets -- -- Cut down version of a locallink stylee fifo that, adds headers etc needed -- for the ABC130 schema. -- -- -- 5/12/2012 - Files birthday! --13/02/2015 - Fixed to ensure packet header is only written when there is real -- data 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 ro13_mod_fifo is generic( STREAM_ID : integer := 0; TS_HIRES : integer := 0 ); port( l0id16_i : in std_logic_vector(15 downto 0); ts_count_i : in std_logic_vector(39 downto 0); ts_source_i : in std_logic_vector(3 downto 0); ts_always_i : in std_logic; ts_disable_i : in std_logic; timeout_tick_i : in std_logic; strm_src_i : in std_logic_vector(2 downto 0); capture_mode_i : in std_logic; -- input interface packet_i : in slv64; --t_packet; pkt_valid_i : in sl; pkt_rdack_o : out sl; -- locallink tx interface lls_o : out t_llsrc; lld_i : in std_logic; -- fifo status full_o : out std_logic; --near_full_o : out std_logic; overflow_o : out std_logic; underflow_o : out std_logic; data_count_o : out std_logic_vector (1 downto 0); -- infrastructure en : in std_logic; s40 : in std_logic; clk : in std_logic; rst : in std_logic ); -- Declarations end ro13_mod_fifo; architecture rtl of ro13_mod_fifo is component cg_brfifo_1kx18 port ( clk : in std_logic; srst : in std_logic; din : in std_logic_vector(17 downto 0); wr_en : in std_logic; rd_en : in std_logic; dout : out std_logic_vector(17 downto 0); full : out std_logic; overflow : out std_logic; empty : out std_logic; underflow : out std_logic; data_count : out std_logic_vector(1 downto 0); prog_full : out std_logic ); end component; component cg_brfifo_2kx18 port ( clk : in std_logic; srst : in std_logic; din : in std_logic_vector(17 downto 0); wr_en : in std_logic; rd_en : in std_logic; dout : out std_logic_vector(17 downto 0); full : out std_logic; overflow : out std_logic; empty : out std_logic; underflow : out std_logic; data_count : out std_logic_vector(1 downto 0) --prog_full : out std_logic ); end component; signal fifo_data_ready : std_logic; signal fifo_empty : std_logic; signal fifo_din : slv18; signal fifo_wr : std_logic; signal fin_we : std_logic; signal fin_sof : std_logic; signal fin_eof : std_logic; signal fin_data : slv16; signal fifo_rd : std_logic; signal fifo_dout : slv18; signal fifo_sof : std_logic; signal fifo_eof : std_logic; signal fifo_data : slv16; signal tx_opcode : slv16; signal seq_id : slv16; signal seq_id_inc : std_logic; signal len_count : integer range 0 to 255; signal len_inc : std_logic; signal len_clr : std_logic; constant LEN_COUNT_MAX : integer := 1472/8; -- max payload is 1500. -16 for -- oc headers, -6 for align-pre-pad zero -- -3 for our CRC = 1500-6-2 = 1492 -- /8 for 64bit = 186.5 . so 186*8= -- 1488 -- 1472 is rounded down signal ts_block : slv64; signal ts_ready : std_logic; signal ts_store : std_logic; signal ts_count : std_logic_vector(39 downto 0); type states is ( --***StartNetPkt, Idle, OpcodeSOF, SeqID, Len, Word0, Word1, Word2, TSPayload0, TSPayload1, TSPayload2, TSPayload3, Payload0, Payload1, Payload2, Payload3, WaitNext, WaitNextTO, WaitNextTO2, --***StartIdle Start ); signal state, nstate : states; type llstates is (LLIdle, LLFluffSOF, LLSrcRdy, LLSOF, LLWaitEOF); signal llstate, nllstate : llstates; begin -- ensure that timestamps don't change while filling the FIFO (!) gen_ts_hires : if (TS_HIRES = 1) generate ts_ready <= '1'; prc_tsq : process (clk) begin if rising_edge(clk) then if (ts_store = '1') then ts_count <= ts_count_i; end if; end if; end process; end generate; gen_ts_lores : if (TS_HIRES = 0) generate ts_ready <= '1' when (s40 = '1') and (ts_count_i(0) = '1') else '0'; ts_count <= ts_count_i; end generate; ts_block <= x"f" & -- 4 x"0" & --trig_src & -- 4 l0id16_i & -- 16 ts_count; -- 40 tx_opcode <= OC_STRM_CAPTURE_DATA when (capture_mode_i = '1') else OC_STRM_A13_RAW_DATA; --OC_STRM_A13_HIST_DATA --OC_STRM_A13_CAPT_DATA -- using common OC with abcn fifo0 : cg_brfifo_2kx18 port map ( clk => clk, srst => rst, din => fifo_din, wr_en => fifo_wr, rd_en => fifo_rd, dout => fifo_dout, full => full_o, overflow => overflow_o, empty => fifo_empty, underflow => underflow_o, data_count => data_count_o --prog_full => near_full_o ); fifo_din(15 downto 0) <= fin_data; fifo_din(16) <= fin_eof; fifo_din(17) <= fin_sof; fifo_wr <= fin_we; --------------------------------------------------------------- -- FIFO Fill Machine --------------------------------------------------------------- prc_sm_fifowr_sync : process (clk) begin if rising_edge(clk) then if (rst = '1') then --***state <= StartNetPkt; state <= Idle; else state <= nstate; end if; end if; end process; prc_sm_fifowr_async : process (pkt_valid_i, len_count, timeout_tick_i, en, seq_id, packet_i, ts_ready, ts_always_i, ts_disable_i, state) begin -- defaults pkt_rdack_o <= '0'; fin_we <= '1'; fin_sof <= '0'; fin_eof <= '0'; --fin_data <= x"0000"; seq_id_inc <= '0'; len_inc <= '0'; len_clr <= '0'; ts_store <= '0'; case state is --***when StartNetPkt => when Idle => --***nstate <= StartNetPkt; nstate <= Idle; fin_we <= '0'; len_clr <= '1'; --if (en = '1') then if (en = '1') and (pkt_valid_i = '1') then nstate <= OpcodeSOF; end if; --------------------------------------------------------------- when OpcodeSOF => fin_sof <= '1'; fin_data <= tx_opcode; nstate <= SeqID; when SeqID => fin_data <= seq_id; seq_id_inc <= '1'; nstate <= Len; when Len => fin_data <= conv_std_logic_vector(LEN_COUNT_MAX*8+6, 16); -- convert pkts to bytes + ... nstate <= Word0; when Word0 => fin_data <= conv_std_logic_vector(STREAM_ID, 8) & x"00"; nstate <= Word1; when Word1 => -- data format version fin_data <= x"0001"; nstate <= Word2; when Word2 => -- stream source (and maybe more later) fin_data <= x"000" & '0' & strm_src_i; --***nstate <= StartIdle; nstate <= Start; ---------------------------------------------------------- --***when StartIdle => --***nstate <= StartIdle; when Start => --***nstate <= StartIdle; fin_we <= '0'; --***if (pkt_valid_i = '1') then ts_store <= '1'; if (ts_always_i = '1') or (ts_disable_i = '1') then nstate <= Payload0; -- ts will be added after data anyway else nstate <= TSPayload0; end if; --***end if; --------------------------------------------- when TSPayload0 => nstate <= TSPayload0; fin_we <= '0'; fin_data <= ts_block(63 downto 48); if (ts_ready = '1') then -- make sure timing is right fin_we <= '1'; nstate <= TSPayload1; end if; when TSPayload1 => fin_data <= ts_block(47 downto 32); len_inc <= '1'; -- done here as prev state iffy nstate <= TSPayload2; when TSPayload2 => fin_data <= ts_block(31 downto 16); nstate <= TSPayload3; when TSPayload3 => fin_data <= ts_block(15 downto 0); if (len_count = LEN_COUNT_MAX) then fin_eof <= '1'; --***nstate StartNetPkt; nstate <= Idle; else nstate <= WaitNext; end if; ---------------------------------------------------------- when Payload0 => len_inc <= '1'; fin_data <= packet_i(63 downto 48); nstate <= Payload1; when Payload1 => fin_data <= packet_i(47 downto 32); nstate <= Payload2; when Payload2 => fin_data <= packet_i(31 downto 16); nstate <= Payload3; when Payload3 => fin_data <= packet_i(15 downto 0); pkt_rdack_o <= '1'; if (len_count = LEN_COUNT_MAX) then fin_eof <= '1'; --***nstate StartNetPkt; nstate <= Idle; else if (ts_always_i = '1') then if (ts_disable_i = '0') then nstate <= TSPayload0; else nstate <= WaitNext; end if; else nstate <= WaitNext; end if; end if; ----------------------------------------------- when WaitNext => nstate <= WaitNext; fin_we <= '0'; if (pkt_valid_i = '1') then ts_store <= '1'; nstate <= Payload0; elsif (timeout_tick_i = '1') then nstate <= WaitNextTO; end if; when WaitNextTO => -- Filter lucky ticks nstate <= WaitNextTO; fin_we <= '0'; if (pkt_valid_i = '1') then ts_store <= '1'; nstate <= Payload0; elsif (timeout_tick_i = '1') then nstate <= WaitNextTO2; end if; when WaitNextTO2 => -- It's been a long wait, add TS before data nstate <= WaitNextTO2; fin_we <= '0'; if (pkt_valid_i = '1') then ts_store <= '1'; if (ts_always_i = '0') or (ts_disable_i = '1') then nstate <= Payload0; else nstate <= TSPayload0; -- start-TS end if; elsif (timeout_tick_i = '1') then ts_store <= '1'; if (ts_disable_i = '0') then nstate <= TSPayload0; end if; end if; ------------------------------------------------------ end case; end process; prc_len_count : process (clk) begin if rising_edge(clk) then if (rst = '1') then len_count <= 0; else if (len_clr = '1') then len_count <= 0; elsif (len_inc = '1') then if (len_count /= LEN_COUNT_MAX) then len_count <= len_count + 1; end if; end if; end if; end if; end process; prc_fifo_data_ready : process (clk) begin if rising_edge(clk) then if (rst = '1') then fifo_data_ready <= '0'; else if (fin_eof = '1') then fifo_data_ready <= '1'; elsif (fifo_eof = '1') then fifo_data_ready <= '0'; end if; end if; end if; end process; --------------------------------------------------------------- -- FIFO LL Read Machine --------------------------------------------------------------- fifo_eof <= fifo_dout(16); fifo_sof <= fifo_dout(17); fifo_data <= fifo_dout(15 downto 0); lls_o.data <= fifo_data; prc_sm_fiford_sync : process (clk) begin if rising_edge(clk) then if (rst = '1') then llstate <= LLIdle; else llstate <= nllstate; end if; end if; end process; prc_sm_fiford_async : process (llstate, fifo_data_ready, fifo_sof, lld_i, fifo_eof) begin -- defaults nllstate <= LLIdle; lls_o.src_rdy <= '1'; lls_o.sof <= '0'; lls_o.eof <= '0'; fifo_rd <= '0'; case llstate is when LLIdle => nllstate <= LLIdle; lls_o.src_rdy <= '0'; if (fifo_data_ready = '1') then nllstate <= LLFluffSOF; end if; when LLFluffSOF => nllstate <= LLFluffSOF; lls_o.src_rdy <= '0'; fifo_rd <= '1'; if (fifo_sof = '1') then fifo_rd <= '0'; nllstate <= LLSrcRdy; end if; when LLSrcRdy => nllstate <= LLSrcRdy; if (lld_i = '1') then nllstate <= LLSOF; end if; when LLSOF => nllstate <= LLSOF; lls_o.sof <= '1'; if (lld_i = '1') then fifo_rd <= '1'; nllstate <= LLWaitEOF; end if; when LLWaitEOF => nllstate <= LLWaitEOF; if (lld_i = '1') then fifo_rd <= '1'; if (fifo_eof = '1') then lls_o.eof <= '1'; fifo_rd <= '0'; nllstate <= LLIdle; end if; end if; end case; end process; prc_seqid_count : process (clk) begin if rising_edge(clk) then if (rst = '1') then seq_id <= (others => '0'); else if (seq_id_inc = '1') then seq_id <= seq_id + '1'; end if; end if; end if; end process; end architecture;