--- /dev/null
+-------------------------------------------------------------------------------
+--! @file
+--! @brief TRB-data parser
+--!
+--! Receives TRB data from a hub data interface (DATA_* ports) and parses the
+--! content. Outputs only valid TRB data to a 4-byte AXI-Stream interface.
+--! Discards the complete input packet in case of any format error or buffer
+--! overflow.
+--!
+--! Prepends a 32-bit word to every output packet:
+--!
+--! [31:24]: reserved
+--! [23:0]: MBS trigger-number
+--!
+--! Assumptions about DATA_* ports:
+--! - DATA_ACTIVE goes high for a new input packet and remains high until the
+--! packet is finished.
+--! - DATA_ACTIVE goes low for at least one clock cycle between packets.
+--! - DATA_READY signifies that the word on DATA_OUT is valid.
+-------------------------------------------------------------------------------
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library xpm;
+use xpm.vcomponents.all;
+
+entity trb_parser is
+ port (
+ CLK : in std_logic;
+ RESET : in std_logic;
+
+ DATA_ACTIVE : in std_logic;
+ DATA_OUT : in std_logic_vector(31 downto 0);
+ DATA_READY : in std_logic;
+ DATA_ADDRESS_SENDER : in std_logic_vector(15 downto 0);
+ DATA_SEQNMBR : in std_logic_vector(7 downto 0);
+ DATA_LENGTH : in std_logic_vector(15 downto 0);
+
+ M_AXIS_TVALID : out std_logic;
+ M_AXIS_TREADY : in std_logic;
+ M_AXIS_TDATA : out std_logic_vector(31 downto 0);
+ M_AXIS_TKEEP : out std_logic_vector(3 downto 0);
+ M_AXIS_TLAST : out std_logic
+ );
+end entity trb_parser;
+
+architecture behavioral of trb_parser is
+ type in_state is (
+ in_reset,
+ discard_input_packet,
+ trg_type_inactive,
+ trg_type,
+ combiner_header,
+ subsub_header,
+ dirich_data,
+ cts_data,
+ trailer_0,
+ trailer_1,
+ aaaa_or_end_of_packet,
+ end_of_packet,
+ terminate_input
+ );
+
+ type out_state is (
+ out_reset,
+ check_meta_fifo,
+ output_mbs_trg_num,
+ output_forward,
+ output_discard
+ );
+
+ signal in_state_cur : in_state := in_reset;
+ signal in_state_next : in_state;
+
+ signal out_state_cur : out_state := out_reset;
+ signal out_state_next : out_state;
+
+ type ERR_CODE is (
+ ERR_INIT_DATA_LOST, -- 0
+ ERR_READY_NOT_ACTIVE, -- 1
+ ERR_META_FIFO_FULL, -- 2
+ ERR_DATA_FIFO_FULL, -- 3
+ ERR_UNEXPECTED_EOP, -- 4
+ ERR_DATA_FIFO_AFULL, -- 5
+ ERR_COMBINER_SIZE, -- 6
+ ERR_TRAILER, -- 7
+ ERR_META_FIFO_FATAL, -- 8
+ ERR_DATA_FIFO_FATAL, -- 9
+ ERR_PADDING, -- A
+ ERR_TRAILING_DATA -- B
+ );
+
+ signal err_mask : std_logic_vector(ERR_CODE'pos(ERR_CODE'high) downto 0);
+
+ signal data_fifo_almost_full : std_logic;
+ signal data_fifo_dout : std_logic_vector(32 downto 0);
+ signal data_fifo_empty : std_logic;
+ signal data_fifo_full : std_logic;
+ signal data_fifo_rd_rst_busy : std_logic;
+ signal data_fifo_wr_rst_busy : std_logic;
+ signal data_fifo_din : std_logic_vector(32 downto 0);
+ signal data_fifo_rd_en : std_logic;
+ signal data_fifo_wr_en : std_logic;
+
+ signal meta_fifo_dout : std_logic_vector(24 downto 0);
+ signal meta_fifo_empty : std_logic;
+ signal meta_fifo_full : std_logic;
+ signal meta_fifo_rd_rst_busy : std_logic;
+ signal meta_fifo_wr_rst_busy : std_logic;
+ signal meta_fifo_din : std_logic_vector(24 downto 0);
+ signal meta_fifo_rd_en : std_logic;
+ signal meta_fifo_wr_en : std_logic;
+
+ signal comb_rem_words : unsigned(15 downto 0) := x"0000";
+ signal comb_rem_words_next : unsigned(15 downto 0);
+ signal subsub_rem_words : unsigned(15 downto 0) := x"0000";
+ signal subsub_rem_words_next : unsigned(15 downto 0);
+ signal mbs_trg_num : std_logic_vector(23 downto 0) := x"000000";
+ signal mbs_trg_num_next : std_logic_vector(23 downto 0);
+ signal comb_addr : std_logic_vector(15 downto 0) := x"0000";
+ signal comb_addr_next : std_logic_vector(15 downto 0);
+
+ signal fifo_resets_busy : std_logic;
+begin
+ data_fifo : xpm_fifo_sync
+ generic map (
+ DOUT_RESET_VALUE => "0",
+ ECC_MODE => "no_ecc",
+ FIFO_MEMORY_TYPE => "auto",
+ FIFO_READ_LATENCY => 0,
+ FIFO_WRITE_DEPTH => 16384, -- 16 to 4194304 (power of 2)
+ FULL_RESET_VALUE => 0,
+ PROG_EMPTY_THRESH => 10,
+ PROG_FULL_THRESH => 10,
+ RD_DATA_COUNT_WIDTH => 1,
+ READ_DATA_WIDTH => 33,
+ READ_MODE => "fwft",
+ SIM_ASSERT_CHK => 0,
+ USE_ADV_FEATURES => "0008", -- almost_full
+ WAKEUP_TIME => 0,
+ WRITE_DATA_WIDTH => 33,
+ WR_DATA_COUNT_WIDTH => 1
+ )
+ port map (
+ almost_empty => open,
+ almost_full => data_fifo_almost_full,
+ data_valid => open,
+ dbiterr => open,
+ dout => data_fifo_dout,
+ empty => data_fifo_empty,
+ full => data_fifo_full,
+ overflow => open,
+ prog_empty => open,
+ prog_full => open,
+ rd_data_count => open,
+ rd_rst_busy => data_fifo_rd_rst_busy,
+ sbiterr => open,
+ underflow => open,
+ wr_ack => open,
+ wr_data_count => open,
+ wr_rst_busy => data_fifo_wr_rst_busy,
+ din => data_fifo_din,
+ injectdbiterr => '0',
+ injectsbiterr => '0',
+ rd_en => data_fifo_rd_en,
+ rst => RESET,
+ sleep => '0',
+ wr_clk => CLK,
+ wr_en => data_fifo_wr_en
+ );
+
+ meta_fifo : xpm_fifo_sync
+ generic map (
+ DOUT_RESET_VALUE => "0",
+ ECC_MODE => "no_ecc",
+ FIFO_MEMORY_TYPE => "auto",
+ FIFO_READ_LATENCY => 0,
+ FIFO_WRITE_DEPTH => 16, -- 16 to 4194304 (power of 2)
+ FULL_RESET_VALUE => 0,
+ PROG_EMPTY_THRESH => 10,
+ PROG_FULL_THRESH => 10,
+ RD_DATA_COUNT_WIDTH => 1,
+ READ_DATA_WIDTH => 25,
+ READ_MODE => "fwft",
+ SIM_ASSERT_CHK => 0,
+ USE_ADV_FEATURES => "0000",
+ WAKEUP_TIME => 0,
+ WRITE_DATA_WIDTH => 25,
+ WR_DATA_COUNT_WIDTH => 1
+ )
+ port map (
+ almost_empty => open,
+ almost_full => open,
+ data_valid => open,
+ dbiterr => open,
+ dout => meta_fifo_dout,
+ empty => meta_fifo_empty,
+ full => meta_fifo_full,
+ overflow => open,
+ prog_empty => open,
+ prog_full => open,
+ rd_data_count => open,
+ rd_rst_busy => meta_fifo_rd_rst_busy,
+ sbiterr => open,
+ underflow => open,
+ wr_ack => open,
+ wr_data_count => open,
+ wr_rst_busy => meta_fifo_wr_rst_busy,
+ din => meta_fifo_din,
+ injectdbiterr => '0',
+ injectsbiterr => '0',
+ rd_en => meta_fifo_rd_en,
+ rst => RESET,
+ sleep => '0',
+ wr_clk => CLK,
+ wr_en => meta_fifo_wr_en
+ );
+
+ fifo_resets_busy <= data_fifo_rd_rst_busy or data_fifo_wr_rst_busy
+ or meta_fifo_rd_rst_busy or meta_fifo_wr_rst_busy;
+
+ in_sm_sync:
+ process (CLK) is
+ begin
+ if rising_edge(CLK) then
+ if RESET = '1' then
+ in_state_cur <= in_reset;
+ comb_rem_words <= x"0000";
+ subsub_rem_words <= x"0000";
+ mbs_trg_num <= x"000000";
+ comb_addr <= x"0000";
+ else
+ in_state_cur <= in_state_next;
+ comb_rem_words <= comb_rem_words_next;
+ subsub_rem_words <= subsub_rem_words_next;
+ mbs_trg_num <= mbs_trg_num_next;
+ comb_addr <= comb_addr_next;
+ end if;
+ end if;
+ end process in_sm_sync;
+
+ in_sm_comb:
+ process (
+ in_state_cur,
+ comb_rem_words,
+ subsub_rem_words,
+ mbs_trg_num,
+ comb_addr,
+ DATA_ACTIVE,
+ DATA_OUT,
+ DATA_READY,
+ fifo_resets_busy,
+ meta_fifo_full,
+ data_fifo_full,
+ data_fifo_almost_full
+ ) is
+ begin
+ in_state_next <= in_state_cur;
+
+ comb_rem_words_next <= comb_rem_words;
+ subsub_rem_words_next <= subsub_rem_words;
+ mbs_trg_num_next <= mbs_trg_num;
+ comb_addr_next <= comb_addr;
+
+ err_mask <= (others => '0');
+ err_mask(ERR_CODE'pos(ERR_READY_NOT_ACTIVE)) <= DATA_READY
+ and not DATA_ACTIVE;
+ err_mask(ERR_CODE'pos(ERR_DATA_FIFO_FATAL)) <= data_fifo_full
+ and data_fifo_wr_en;
+ err_mask(ERR_CODE'pos(ERR_META_FIFO_FATAL)) <= meta_fifo_full
+ and meta_fifo_wr_en;
+
+ data_fifo_din(31 downto 0) <= DATA_OUT;
+ data_fifo_din(32) <= '0';
+ data_fifo_wr_en <= '0';
+
+ meta_fifo_din(23 downto 0) <= mbs_trg_num;
+ meta_fifo_din(24) <= '0';
+ meta_fifo_wr_en <= '0';
+
+ case in_state_cur is
+ when in_reset =>
+ if fifo_resets_busy = '0' then
+ in_state_next <= discard_input_packet;
+ if DATA_ACTIVE = '0' then
+ in_state_next <= trg_type_inactive;
+ else
+ err_mask(ERR_CODE'pos(ERR_INIT_DATA_LOST)) <= '1';
+ in_state_next <= discard_input_packet;
+ end if;
+ end if;
+ when discard_input_packet =>
+ if DATA_ACTIVE = '0' then
+ in_state_next <= trg_type_inactive;
+ end if;
+ when trg_type_inactive =>
+ if DATA_ACTIVE = '1' then
+ if meta_fifo_full = '1' then
+ err_mask(ERR_CODE'pos(ERR_META_FIFO_FULL)) <= '1';
+ end if;
+ if data_fifo_full = '1' then
+ err_mask(ERR_CODE'pos(ERR_DATA_FIFO_FULL)) <= '1';
+ end if;
+ if meta_fifo_full = '1' or data_fifo_full = '1' then
+ -- Before accepting a new packet, we ensure that at least
+ -- one word can be written to both FIFOs. This condition is
+ -- kept up until the packet ends and the last data word and
+ -- meta word are written.
+ in_state_next <= discard_input_packet;
+ elsif DATA_READY = '1' then
+ if data_fifo_almost_full = '1' then
+ err_mask(ERR_CODE'pos(ERR_DATA_FIFO_AFULL)) <= '1';
+ in_state_next <= terminate_input;
+ else
+ data_fifo_wr_en <= '1';
+ in_state_next <= combiner_header;
+ end if;
+ else
+ in_state_next <= trg_type;
+ end if;
+ end if;
+ when trg_type =>
+ if DATA_ACTIVE = '0' then
+ err_mask(ERR_CODE'pos(ERR_UNEXPECTED_EOP)) <= '1';
+ data_fifo_din(32) <= '1';
+ data_fifo_wr_en <= '1';
+ meta_fifo_wr_en <= '1';
+ in_state_next <= trg_type_inactive;
+ elsif DATA_READY = '1' then
+ if data_fifo_almost_full = '1' then
+ err_mask(ERR_CODE'pos(ERR_DATA_FIFO_AFULL)) <= '1';
+ in_state_next <= terminate_input;
+ else
+ data_fifo_wr_en <= '1';
+ in_state_next <= combiner_header;
+ end if;
+ end if;
+ when combiner_header =>
+ comb_rem_words_next <= unsigned(DATA_OUT(31 downto 16));
+ comb_addr_next <= DATA_OUT(15 downto 0);
+ if DATA_ACTIVE = '0' then
+ err_mask(ERR_CODE'pos(ERR_UNEXPECTED_EOP)) <= '1';
+ data_fifo_din(32) <= '1';
+ data_fifo_wr_en <= '1';
+ meta_fifo_wr_en <= '1';
+ in_state_next <= trg_type_inactive;
+ elsif DATA_READY = '1' then
+ if data_fifo_almost_full = '1' then
+ err_mask(ERR_CODE'pos(ERR_DATA_FIFO_AFULL)) <= '1';
+ in_state_next <= terminate_input;
+ else
+ data_fifo_wr_en <= '1';
+ in_state_next <= subsub_header;
+ end if;
+ end if;
+ when subsub_header =>
+ subsub_rem_words_next <= unsigned(DATA_OUT(31 downto 16));
+ if DATA_ACTIVE = '0' then
+ err_mask(ERR_CODE'pos(ERR_UNEXPECTED_EOP)) <= '1';
+ data_fifo_din(32) <= '1';
+ data_fifo_wr_en <= '1';
+ meta_fifo_wr_en <= '1';
+ in_state_next <= trg_type_inactive;
+ elsif DATA_READY = '1' then
+ comb_rem_words_next <= comb_rem_words - 1;
+ if data_fifo_almost_full = '1' then
+ err_mask(ERR_CODE'pos(ERR_DATA_FIFO_AFULL)) <= '1';
+ in_state_next <= terminate_input;
+ else
+ data_fifo_wr_en <= '1';
+ if DATA_OUT(15 downto 0) = comb_addr then
+ in_state_next <= cts_data;
+ else
+ in_state_next <= dirich_data;
+ end if;
+ end if;
+ end if;
+ when dirich_data =>
+ if DATA_ACTIVE = '0' then
+ err_mask(ERR_CODE'pos(ERR_UNEXPECTED_EOP)) <= '1';
+ data_fifo_din(32) <= '1';
+ data_fifo_wr_en <= '1';
+ meta_fifo_wr_en <= '1';
+ in_state_next <= trg_type_inactive;
+ elsif DATA_READY = '1' then
+ comb_rem_words_next <= comb_rem_words - 1;
+ subsub_rem_words_next <= subsub_rem_words - 1;
+ if data_fifo_almost_full = '1' then
+ err_mask(ERR_CODE'pos(ERR_DATA_FIFO_AFULL)) <= '1';
+ in_state_next <= terminate_input;
+ else
+ data_fifo_wr_en <= '1';
+ if subsub_rem_words = 1 then
+ in_state_next <= subsub_header;
+ end if;
+ end if;
+ end if;
+ when cts_data =>
+ mbs_trg_num_next <= DATA_OUT(23 downto 0);
+ if DATA_ACTIVE = '0' then
+ err_mask(ERR_CODE'pos(ERR_UNEXPECTED_EOP)) <= '1';
+ data_fifo_din(32) <= '1';
+ data_fifo_wr_en <= '1';
+ meta_fifo_wr_en <= '1';
+ in_state_next <= trg_type_inactive;
+ elsif DATA_READY = '1' then
+ comb_rem_words_next <= comb_rem_words - 1;
+ subsub_rem_words_next <= subsub_rem_words - 1;
+ if data_fifo_almost_full = '1' then
+ err_mask(ERR_CODE'pos(ERR_DATA_FIFO_AFULL)) <= '1';
+ in_state_next <= terminate_input;
+ else
+ data_fifo_wr_en <= '1';
+ if subsub_rem_words = 1 then
+ if comb_rem_words = 1 then
+ in_state_next <= trailer_0;
+ else
+ err_mask(ERR_CODE'pos(ERR_COMBINER_SIZE)) <= '1';
+ in_state_next <= terminate_input;
+ end if;
+ end if;
+ end if;
+ end if;
+ when trailer_0 =>
+ if DATA_ACTIVE = '0' then
+ err_mask(ERR_CODE'pos(ERR_UNEXPECTED_EOP)) <= '1';
+ data_fifo_din(32) <= '1';
+ data_fifo_wr_en <= '1';
+ meta_fifo_wr_en <= '1';
+ in_state_next <= trg_type_inactive;
+ elsif DATA_READY = '1' then
+ if data_fifo_almost_full = '1' then
+ err_mask(ERR_CODE'pos(ERR_DATA_FIFO_AFULL)) <= '1';
+ in_state_next <= terminate_input;
+ else
+ data_fifo_wr_en <= '1';
+ if DATA_OUT = x"00015555" then
+ in_state_next <= trailer_1;
+ else
+ err_mask(ERR_CODE'pos(ERR_TRAILER)) <= '1';
+ in_state_next <= terminate_input;
+ end if;
+ end if;
+ end if;
+ when trailer_1 =>
+ if DATA_ACTIVE = '0' then
+ err_mask(ERR_CODE'pos(ERR_UNEXPECTED_EOP)) <= '1';
+ data_fifo_din(32) <= '1';
+ data_fifo_wr_en <= '1';
+ meta_fifo_wr_en <= '1';
+ in_state_next <= trg_type_inactive;
+ elsif DATA_READY = '1' then
+ if data_fifo_almost_full = '1' then
+ err_mask(ERR_CODE'pos(ERR_DATA_FIFO_AFULL)) <= '1';
+ in_state_next <= terminate_input;
+ else
+ data_fifo_wr_en <= '1';
+ in_state_next <= aaaa_or_end_of_packet;
+ end if;
+ end if;
+ when aaaa_or_end_of_packet =>
+ if DATA_ACTIVE = '0' then
+ in_state_next <= trg_type_inactive;
+ data_fifo_din(31 downto 0) <= x"600D_DA7A";
+ data_fifo_din(32) <= '1';
+ data_fifo_wr_en <= '1';
+ meta_fifo_din(24) <= '1';
+ meta_fifo_wr_en <= '1';
+ elsif DATA_READY = '1' then
+ if data_fifo_almost_full = '1' then
+ err_mask(ERR_CODE'pos(ERR_DATA_FIFO_AFULL)) <= '1';
+ in_state_next <= terminate_input;
+ else
+ data_fifo_wr_en <= '1';
+ if DATA_OUT = x"AAAAAAAA" then
+ in_state_next <= end_of_packet;
+ else
+ err_mask(ERR_CODE'pos(ERR_PADDING)) <= '1';
+ in_state_next <= terminate_input;
+ end if;
+ end if;
+ end if;
+ when end_of_packet =>
+ if DATA_ACTIVE = '0' then
+ in_state_next <= trg_type_inactive;
+ data_fifo_din(31 downto 0) <= x"600D_DA7A";
+ data_fifo_din(32) <= '1';
+ data_fifo_wr_en <= '1';
+ meta_fifo_din(24) <= '1';
+ meta_fifo_wr_en <= '1';
+ elsif DATA_READY = '1' then
+ err_mask(ERR_CODE'pos(ERR_TRAILING_DATA)) <= '1';
+ in_state_next <= terminate_input;
+ end if;
+ when terminate_input =>
+ data_fifo_din(32) <= '1';
+ data_fifo_wr_en <= '1';
+ meta_fifo_wr_en <= '1';
+ if DATA_ACTIVE = '1' then
+ in_state_next <= discard_input_packet;
+ else
+ in_state_next <= trg_type_inactive;
+ end if;
+ end case;
+ end process in_sm_comb;
+
+
+ out_sm_sync:
+ process (CLK) is
+ begin
+ if rising_edge(CLK) then
+ if RESET = '1' then
+ out_state_cur <= out_reset;
+ else
+ out_state_cur <= out_state_next;
+ end if;
+ end if;
+ end process out_sm_sync;
+
+ out_sm_comb:
+ process (
+ out_state_cur,
+ fifo_resets_busy,
+ meta_fifo_empty,
+ meta_fifo_dout,
+ data_fifo_empty,
+ data_fifo_dout,
+ M_AXIS_TREADY
+ ) is
+ begin
+ out_state_next <= out_state_cur;
+
+ M_AXIS_TVALID <= '0';
+ M_AXIS_TLAST <= data_fifo_dout(32);
+ M_AXIS_TDATA <= data_fifo_dout(31 downto 0);
+ M_AXIS_TKEEP <= "1111";
+
+ meta_fifo_rd_en <= '0';
+ data_fifo_rd_en <= '0';
+
+ case out_state_cur is
+ when out_reset =>
+ if fifo_resets_busy = '0' then
+ out_state_next <= check_meta_fifo;
+ end if;
+ when check_meta_fifo =>
+ if meta_fifo_empty = '0' then
+ if meta_fifo_dout(24) = '1' then
+ out_state_next <= output_mbs_trg_num;
+ else
+ meta_fifo_rd_en <= '1';
+ out_state_next <= output_discard;
+ end if;
+ end if;
+ when output_mbs_trg_num =>
+ M_AXIS_TVALID <= '1';
+ M_AXIS_TLAST <= '0';
+ M_AXIS_TDATA(31 downto 24) <= x"00";
+ M_AXIS_TDATA(23 downto 0) <= meta_fifo_dout(23 downto 0);
+ if M_AXIS_TREADY = '1' then
+ meta_fifo_rd_en <= '1';
+ out_state_next <= output_forward;
+ end if;
+ when output_forward =>
+ M_AXIS_TVALID <= not data_fifo_empty;
+ data_fifo_rd_en <= M_AXIS_TREADY;
+ if M_AXIS_TREADY = '1' and data_fifo_empty = '0'
+ and data_fifo_dout(32) = '1'
+ then
+ out_state_next <= check_meta_fifo;
+ end if;
+ when output_discard =>
+ data_fifo_rd_en <= '1';
+ if data_fifo_empty = '0' and data_fifo_dout(32) = '1' then
+ out_state_next <= check_meta_fifo;
+ end if;
+ end case;
+ end process out_sm_comb;
+end architecture behavioral;