--- /dev/null
+library ieee;\r
+use ieee.std_logic_1164.all;\r
+use ieee.numeric_std.all;\r
+\r
+library work;\r
+use work.trb_net_std.all;\r
+--use work.trb_net_components.all;\r
+\r
+entity trb_net16_rx_packets is\r
+port(\r
+ -- Resets\r
+ RESET_IN : in std_logic;\r
+ QUAD_RST_IN : in std_logic;\r
+ -- data stream from SerDes\r
+ CLK_IN : in std_logic; -- SerDes RX clock\r
+ RX_ALLOW_IN : in std_logic;\r
+ RX_DATA_IN : in std_logic_vector(7 downto 0);\r
+ RX_K_IN : in std_logic;\r
+ -- media interface\r
+ SYSCLK_IN : in std_logic; -- 100MHz master clock\r
+ MED_DATA_OUT : out std_logic_vector(15 downto 0);\r
+ MED_DATAREADY_OUT : out std_logic;\r
+ MED_READ_IN : in std_logic;\r
+ MED_PACKET_NUM_OUT : out std_logic_vector(2 downto 0);\r
+ -- reset handling\r
+ SEND_RESET_WORDS_OUT : out std_logic;\r
+ MAKE_TRBNET_RESET_OUT : out std_logic;\r
+ -- Status signals\r
+ LINK_BROKEN_OUT : out std_logic;\r
+ CLEAR_STATUS_IN : in std_logic;\r
+ -- Debug signals\r
+ BSM_OUT : out std_logic_vector(3 downto 0);\r
+ DBG_OUT : out std_logic_vector(15 downto 0)\r
+);\r
+end entity trb_net16_rx_packets;\r
+\r
+\r
+architecture behavioral of trb_net16_rx_packets is\r
+\r
+-- components\r
+component trb_net_fifo_8bit_16bit_bram_dualport is\r
+port(\r
+ READ_CLOCK_IN : in std_logic;\r
+ WRITE_CLOCK_IN : in std_logic;\r
+ READ_ENABLE_IN : in std_logic;\r
+ WRITE_ENABLE_IN : in std_logic;\r
+ FIFO_GSR_IN : in std_logic;\r
+ WRITE_DATA_IN : in std_logic_vector(7 downto 0);\r
+ READ_DATA_OUT : out std_logic_vector(15 downto 0);\r
+ FULL_OUT : out std_logic;\r
+ EMPTY_OUT : out std_logic;\r
+ WCNT_OUT : out std_logic_vector(9 downto 0);\r
+ RCNT_OUT : out std_logic_vector(8 downto 0)\r
+);\r
+end component trb_net_fifo_8bit_16bit_bram_dualport;\r
+\r
+-- State description:\r
+--\r
+-- IDLE: wait for any data to be written into the FIFO\r
+-- RD1 : first word prefetch\r
+-- RD2 : first word output reg, second word prefetch, wait state for full packet in FIFO\r
+-- RDI : generates initial dataready_out, wait state for handshake of first data word\r
+-- RD3 : second word output reg, third word prefetch, wait state for handshake of second data word\r
+-- RD4 : third word output reg, fourth word prefetch, wait state for handshake of third data word\r
+-- RD5 : fourth word output reg, fifth word prefetch, wait state for handshake of forth data word\r
+-- => decision: continous data stream or stalling as FIFO runs empty!\r
+-- RDO : fifth word output reg, wait state for handshake of fifth data word, can also resume transmission \r
+-- if new data is available in FIFO\r
+-- RDW : fifth word output reg, first word prefetch, wait state for handshake of fifth data word, \r
+-- continue data stream or stall if for complete packet\r
+\r
+-- state declarations\r
+type STATES is (IDLE, RD1, RD2, RDI, RD3, RD4, RD5, RDO, RDW, TOC, CLEAN);\r
+signal CURRENT_STATE, NEXT_STATE: STATES;\r
+\r
+-- normal signals\r
+signal bsm_x : std_logic_vector(3 downto 0);\r
+signal bsm : std_logic_vector(3 downto 0);\r
+signal update_x : std_logic;\r
+signal med_dataready_x : std_logic;\r
+signal med_dataready : std_logic;\r
+signal med_data : std_logic_vector(15 downto 0);\r
+\r
+signal buf_rx_data : std_logic_vector(7 downto 0);\r
+signal buf_rx_k : std_logic;\r
+\r
+signal fifo_wr_en : std_logic;\r
+signal fifo_rd_en_x : std_logic;\r
+signal fifo_wr_data : std_logic_vector(7 downto 0);\r
+signal fifo_rd_data : std_logic_vector(15 downto 0);\r
+signal fifo_reset : std_logic;\r
+signal fifo_rcnt_stdlv : std_logic_vector(8 downto 0);\r
+signal fifo_rcnt : unsigned(8 downto 0);\r
+signal fifo_rst_x : std_logic;\r
+signal fifo_rst : std_logic;\r
+\r
+signal rx_counter : unsigned(2 downto 0);\r
+\r
+signal is_idle_word : std_logic;\r
+signal rx_starting : std_logic;\r
+signal send_reset_words : std_logic;\r
+signal make_trbnet_reset : std_logic;\r
+signal reset_word_cnt : unsigned(4 downto 0);\r
+\r
+signal timeout_ctr : unsigned(9 downto 0);\r
+signal rst_toc_x : std_logic;\r
+signal rst_toc : std_logic;\r
+signal ce_toc_x : std_logic;\r
+signal ce_toc : std_logic;\r
+signal toc_done_x : std_logic;\r
+signal toc_done : std_logic;\r
+signal link_broken : std_logic;\r
+\r
+signal debug : std_logic_vector(15 downto 0);\r
+\r
+begin\r
+\r
+----------------------------------------------------------------------\r
+-- FIFO write process\r
+----------------------------------------------------------------------\r
+THE_WRITE_RX_FIFO_PROC: process( CLK_IN )\r
+begin\r
+ if( rising_edge(CLK_IN) ) then\r
+ buf_rx_data <= RX_DATA_IN;\r
+ buf_rx_k <= RX_K_IN;\r
+ if( (RESET_IN = '1') or (RX_ALLOW_IN = '0') ) then\r
+ fifo_wr_en <= '0';\r
+ is_idle_word <= '1';\r
+ rx_starting <= '1';\r
+ else\r
+ fifo_wr_data <= buf_rx_data;\r
+ if( (buf_rx_k = '0') and (is_idle_word = '0') and (rx_starting = '0') ) then\r
+ fifo_wr_en <= '1';\r
+ else\r
+ fifo_wr_en <= '0';\r
+ end if;\r
+ if ( buf_rx_k = '1' ) then\r
+ is_idle_word <= '1';\r
+ rx_starting <= '0';\r
+ elsif( (buf_rx_k = '0') and (is_idle_word = '1') ) then\r
+ is_idle_word <= '0';\r
+ end if;\r
+ end if;\r
+ end if;\r
+end process THE_WRITE_RX_FIFO_PROC;\r
+\r
+----------------------------------------------------------------------\r
+-- TRBnet reset handling\r
+----------------------------------------------------------------------\r
+THE_CNT_RESET_PROC: process( CLK_IN )\r
+begin\r
+ if( rising_edge(CLK_IN) ) then\r
+ if( RESET_IN = '1' ) then\r
+ send_reset_words <= '0';\r
+ make_trbnet_reset <= '0';\r
+ reset_word_cnt <= (others => '0');\r
+ else\r
+ send_reset_words <= '0';\r
+ make_trbnet_reset <= '0';\r
+ if( (buf_rx_data = x"FE") and (buf_rx_k = '1') ) then\r
+ if( reset_word_cnt(4) = '0' ) then\r
+ reset_word_cnt <= reset_word_cnt + 1;\r
+ else\r
+ send_reset_words <= '1';\r
+ end if;\r
+ else\r
+ reset_word_cnt <= (others => '0');\r
+ make_trbnet_reset <= reset_word_cnt(4);\r
+ end if;\r
+ end if;\r
+ end if;\r
+end process;\r
+\r
+----------------------------------------------------------------------\r
+-- the RX FIFO itself\r
+----------------------------------------------------------------------\r
+THE_RX_FIFO: trb_net_fifo_8bit_16bit_bram_dualport\r
+port map(\r
+ READ_CLOCK_IN => SYSCLK_IN,\r
+ WRITE_CLOCK_IN => CLK_IN,\r
+ READ_ENABLE_IN => fifo_rd_en_x,\r
+ WRITE_ENABLE_IN => fifo_wr_en,\r
+ FIFO_GSR_IN => fifo_reset,\r
+ WRITE_DATA_IN => fifo_wr_data,\r
+ READ_DATA_OUT => fifo_rd_data,\r
+ FULL_OUT => open,\r
+ EMPTY_OUT => open,\r
+ WCNT_OUT => open, -- not needed\r
+ RCNT_OUT => fifo_rcnt_stdlv\r
+);\r
+\r
+fifo_reset <= RESET_IN or QUAD_RST_IN or not RX_ALLOW_IN or fifo_rst;\r
+\r
+fifo_rcnt <= unsigned(fifo_rcnt_stdlv);\r
+\r
+----------------------------------------------------------------------\r
+-- RX packet state machine\r
+----------------------------------------------------------------------\r
+-- state registers\r
+STATE_MEM: process( SYSCLK_IN )\r
+begin\r
+ if( rising_edge(SYSCLK_IN) ) then\r
+ if( RESET_IN = '1' ) then\r
+ CURRENT_STATE <= IDLE;\r
+ med_dataready <= '0';\r
+ ce_toc <= '0';\r
+ rst_toc <= '0';\r
+ fifo_rst <= '0';\r
+ bsm <= (others => '0');\r
+ else\r
+ CURRENT_STATE <= NEXT_STATE;\r
+ med_dataready <= med_dataready_x;\r
+ ce_toc <= ce_toc_x;\r
+ rst_toc <= rst_toc_x;\r
+ fifo_rst <= fifo_rst_x;\r
+ bsm <= bsm_x;\r
+ end if;\r
+ end if;\r
+end process STATE_MEM;\r
+\r
+-- state transitions\r
+STATE_TRANSFORM: process( CURRENT_STATE, fifo_rcnt, MED_READ_IN, med_dataready, toc_done )\r
+begin\r
+ NEXT_STATE <= IDLE; -- avoid latches\r
+ fifo_rd_en_x <= '0';\r
+ med_dataready_x <= '0';\r
+ update_x <= '0';\r
+ ce_toc_x <= '0';\r
+ rst_toc_x <= '0';\r
+ fifo_rst_x <= '0';\r
+ case CURRENT_STATE is\r
+ when IDLE => if( fifo_rcnt > 0 ) then\r
+ -- we have at least one data word in FIFO, so we prefetch it\r
+ NEXT_STATE <= RD1; \r
+ fifo_rd_en_x <= '1';\r
+ ce_toc_x <= '1';\r
+ else\r
+ NEXT_STATE <= IDLE;\r
+ end if;\r
+ when RD1 => if ( fifo_rcnt > 1 ) then -- was 0\r
+ -- second data word is available in FIFO, so we prefetch it and \r
+ -- forward the first word to the output register\r
+ NEXT_STATE <= RD2;\r
+ fifo_rd_en_x <= '1';\r
+ update_x <= '1';\r
+ ce_toc_x <= '1';\r
+ elsif( toc_done = '1' ) then\r
+ NEXT_STATE <= TOC;\r
+ rst_toc_x <= '1';\r
+ fifo_rst_x <= '1';\r
+ else\r
+ NEXT_STATE <= RD1;\r
+ ce_toc_x <= '1';\r
+ end if;\r
+ when RD2 => if ( fifo_rcnt > 2 ) then\r
+ -- at least all three missing words in FIFO... so we go ahead and notify full packet availability\r
+ NEXT_STATE <= RDI;\r
+ med_dataready_x <= '1';\r
+ rst_toc_x <= '1';\r
+ elsif( toc_done = '1' ) then\r
+ NEXT_STATE <= TOC;\r
+ rst_toc_x <= '1';\r
+ fifo_rst_x <= '1';\r
+ else\r
+ NEXT_STATE <= RD2;\r
+ ce_toc_x <= '1';\r
+ end if;\r
+ when RDI => med_dataready_x <= '1';\r
+ if( MED_READ_IN = '1' ) then\r
+ -- first word of packet has been transfered, update output register and prefetch next data word\r
+ NEXT_STATE <= RD3;\r
+ fifo_rd_en_x <= '1';\r
+ update_x <= '1';\r
+ else\r
+ NEXT_STATE <= RDI;\r
+ end if;\r
+ when RD3 => med_dataready_x <= '1';\r
+ if( MED_READ_IN = '1' ) then\r
+ -- second word of packet has been transfered, update output register and prefetch next data word\r
+ NEXT_STATE <= RD4;\r
+ fifo_rd_en_x <= '1';\r
+ update_x <= '1';\r
+ else\r
+ NEXT_STATE <= RD3;\r
+ end if;\r
+ when RD4 => med_dataready_x <= '1';\r
+ -- third word of packet has been transfered, update output register and prefetch next data word\r
+ if( MED_READ_IN = '1' ) then\r
+ NEXT_STATE <= RD5;\r
+ fifo_rd_en_x <= '1';\r
+ update_x <= '1';\r
+ else\r
+ NEXT_STATE <= RD4;\r
+ end if;\r
+ when RD5 => med_dataready_x <= '1';\r
+ -- DANGER. This is the key state for decisions here. \r
+ -- There are many ways to do it the wrong way, depending on the FIFO fill level.\r
+ if ( (MED_READ_IN = '1') and (fifo_rcnt < 3) ) then -- was 2, changed due to RCNT latency\r
+ -- fourth word of packet has been transfered, and FIFO has not seen any new packet word.\r
+ -- so we update output register only, no prefetch\r
+ NEXT_STATE <= RDO;\r
+ update_x <= '1';\r
+ elsif( (MED_READ_IN = '1') and (fifo_rcnt > 2) ) then -- was 1, changed due to RCNT latency\r
+ -- fourth word of packet DONE, new packet data already in the FIFO\r
+ -- so we can prefetch on data word already and update the output register\r
+ NEXT_STATE <= RDW;\r
+ fifo_rd_en_x <= '1';\r
+ update_x <= '1';\r
+ else\r
+ NEXT_STATE <= RD5;\r
+ end if;\r
+ when RDO => if ( (MED_READ_IN = '1') and (fifo_rcnt = 0) ) then\r
+ -- last word of packet has been transfered, and no new data words to handle.\r
+ -- we keep the last transfered word in the output register and wait for new packets to arrive.\r
+ NEXT_STATE <= IDLE;\r
+ elsif( (MED_READ_IN = '1') and (fifo_rcnt > 0) ) then\r
+ -- last word of packet has been transfered, and a new packet data available.\r
+ -- so we enter the prefetch phase again.\r
+ NEXT_STATE <= RD1;\r
+ fifo_rd_en_x <= '1';\r
+ else\r
+ NEXT_STATE <= RDO;\r
+ med_dataready_x <= '1';\r
+ end if;\r
+ when RDW => if ( (MED_READ_IN = '1') and (fifo_rcnt > 3) ) then\r
+ -- last word of packet has been transfered, complete packet in FIFO, so we can go ahead.\r
+ NEXT_STATE <= RDI;\r
+ fifo_rd_en_x <= '1';\r
+ update_x <= '1';\r
+ med_dataready_x <= '1';\r
+ elsif( (MED_READ_IN = '1') and (fifo_rcnt < 4 ) ) then\r
+ -- last word of packet has been transfered, but new packet not complete yet.\r
+ NEXT_STATE <= RD2;\r
+ fifo_rd_en_x <= '1';\r
+ update_x <= '1';\r
+ else\r
+ NEXT_STATE <= RDW;\r
+ med_dataready_x <= '1'; \r
+ end if;\r
+ when TOC => NEXT_STATE <= CLEAN;\r
+ fifo_rst_x <= '1';\r
+ when CLEAN => NEXT_STATE <= IDLE;\r
+ \r
+ when others => NEXT_STATE <= IDLE;\r
+ end case;\r
+end process STATE_TRANSFORM;\r
+\r
+-- just for debugging\r
+THE_DECODE_PROC: process( NEXT_STATE )\r
+begin\r
+ case NEXT_STATE is\r
+ when IDLE => bsm_x <= x"0";\r
+ when RD1 => bsm_x <= x"1";\r
+ when RD2 => bsm_x <= x"2";\r
+ when RDI => bsm_x <= x"3";\r
+ when RD3 => bsm_x <= x"4";\r
+ when RD4 => bsm_x <= x"5";\r
+ when RD5 => bsm_x <= x"6";\r
+ when RDO => bsm_x <= x"7";\r
+ when RDW => bsm_x <= x"8";\r
+ when TOC => bsm_x <= x"9";\r
+ when CLEAN => bsm_x <= x"a";\r
+ when others => bsm_x <= x"f";\r
+ end case;\r
+end process THE_DECODE_PROC;\r
+\r
+THE_SYNC_PROC: process( SYSCLK_IN )\r
+begin\r
+ if( rising_edge(SYSCLK_IN) ) then\r
+ if( update_x = '1' ) then\r
+ med_data <= fifo_rd_data;\r
+ end if;\r
+ end if;\r
+end process THE_SYNC_PROC;\r
+\r
+----------------------------------------------------------------------\r
+-- Status bit\r
+----------------------------------------------------------------------\r
+THE_STATUS_BIT_PROC: process( SYSCLK_IN )\r
+begin\r
+ if( rising_edge(SYSCLK_IN) ) then\r
+ if ( CURRENT_STATE = CLEAN ) then\r
+ link_broken <= '1';\r
+ elsif( CLEAR_STATUS_IN = '1' ) then\r
+ link_broken <= '0';\r
+ end if;\r
+ end if;\r
+end process THE_STATUS_BIT_PROC;\r
+\r
+----------------------------------------------------------------------\r
+-- RX packet counter\r
+----------------------------------------------------------------------\r
+THE_RX_PACKETS_PROC: process( SYSCLK_IN )\r
+begin\r
+ if( rising_edge(SYSCLK_IN) ) then\r
+ if( (RESET_IN = '1') or (RX_ALLOW_IN = '0') ) then\r
+ rx_counter <= unsigned(c_H0);\r
+ else\r
+ if( (med_dataready = '1') and (MED_READ_IN = '1') ) then -- modified\r
+ if( rx_counter = unsigned(c_max_word_number) ) then\r
+ rx_counter <= (others => '0');\r
+ else\r
+ rx_counter <= rx_counter + 1;\r
+ end if;\r
+ end if;\r
+ end if;\r
+ end if;\r
+end process THE_RX_PACKETS_PROC;\r
+\r
+----------------------------------------------------------------------\r
+-- Timeout counter\r
+----------------------------------------------------------------------\r
+THE_TOC_PROC: process( SYSCLK_IN )\r
+begin\r
+ if( rising_edge(SYSCLK_IN) ) then\r
+ toc_done <= toc_done_x;\r
+ if ( (RESET_IN = '1') or (rst_toc = '1') ) then\r
+ timeout_ctr <= (others => '0');\r
+ elsif( (ce_toc = '1') and (toc_done = '0') ) then\r
+ timeout_ctr <= timeout_ctr + 1;\r
+ end if;\r
+ end if;\r
+end process THE_TOC_PROC;\r
+\r
+toc_done_x <= '1' when ( timeout_ctr(9 downto 2) = b"11_1111_11" ) else '0';\r
+\r
+----------------------------------------------------------------------\r
+-- Debug signals\r
+----------------------------------------------------------------------\r
+debug(15) <= toc_done;\r
+debug(14) <= ce_toc;\r
+debug(13) <= rst_toc;\r
+debug(12) <= fifo_rst;\r
+debug(11 downto 9) <= (others => '0');\r
+debug(8 downto 0) <= fifo_rcnt_stdlv;\r
+\r
+--debug(15 downto 8) <= fifo_rcnt_stdlv(7 downto 0);\r
+--debug(7 downto 2) <= (others => '0');\r
+--debug(1) <= update_x;\r
+--debug(0) <= fifo_rd_en_x;\r
+\r
+----------------------------------------------------------------------\r
+-- Output signals\r
+----------------------------------------------------------------------\r
+SEND_RESET_WORDS_OUT <= send_reset_words;\r
+MAKE_TRBNET_RESET_OUT <= make_trbnet_reset;\r
+LINK_BROKEN_OUT <= link_broken;\r
+\r
+MED_DATAREADY_OUT <= med_dataready;\r
+MED_DATA_OUT <= med_data;\r
+MED_PACKET_NUM_OUT <= std_logic_vector(rx_counter);\r
+\r
+BSM_OUT <= bsm;\r
+DBG_OUT <= debug;\r
+\r
+end behavioral;
\ No newline at end of file