-- -- HSIO RX packet decoder -- -- Chops off pre-opcode header and passes opcode out via FIFO -- Sends Ack -- -- -- changelog: -- 2011-01ish - birthday -- 2012-03ish - added ocfifo to fix long combintoral loop issue -- 2012-06-12 - added ocfifofull monitoring -- 2012-06-12 - removed watchdog - now handled by ocb_echo_watchdog -- 2012-07-30 - attempt to convert tdack to "tristate" bus -- 2013-07-09 - changed magic number to 0x876X to allow more than one process to send packets -- 2015-01-21 - Added oc_start output -- 2015-05-24 - Started rework for 2 clock domains 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 locallink; library hsio; use hsio.pkg_core_globals.all; entity rx_packet_decoder is port( -- rx ll fifo interface rx_lls_i : in t_llsrc; rx_lld_o : out std_logic; -- decoded out (for debug) rx_magicn_o : out slv16; rx_seq_o : out slv16; rx_len_o : out slv16; rx_cbcnt_o : out slv16; rx_opcode_o : out slv16; rx_ocseq_o : out slv16; rx_size_o : out slv16; -- locallink tx interface lls_o : out t_llsrc; lld_i : in std_logic; -- Core signals - oc bus, resets oc_data_o : out slv16; oc_valid_o : out std_logic; oc_dack_ni : in std_logic; dbg_oc_start_o : out std_logic; rst_ocb_o : out std_logic; clk80 : in std_logic; rst80 : in std_logic; -- infrastructure clk125 : in std_logic; rst125 : in std_logic ); -- Declarations end rx_packet_decoder; architecture rtl of rx_packet_decoder is component ll_ack_gen port ( -- input interface opcode_i : in slv16; ocseq_i : in slv16; ocsize_i : in slv16; payload_i : in slv16; send_i : in std_logic; busy_o : out std_logic; -- locallink tx interface lls_o : out t_llsrc; lld_i : in std_logic; -- infrastucture clk : in std_logic; rst : in std_logic ); end component; component cg_cxbrfifo_2kx18_ft port ( wr_clk : in std_logic; wr_rst : in std_logic; rd_clk : in std_logic; rd_rst : 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; --almost_full : out std_logic; empty : out std_logic; prog_full : out std_logic ); end component; signal rst_ocb_q : std_logic; signal rst_ocb : std_logic; signal dbg_oc_start_q : std_logic; signal dbg_oc_start0 : std_logic; signal rx_magicn : slv16; signal rx_seq : slv16; signal rx_len : slv16; signal rx_cbcnt : slv16; signal rx_opcode : slv16; signal rx_ocseq : slv16; signal rx_size : slv16; --signal rx_word0 : slv16; signal rx_hdr1 : slv16_array (1 to 4) := (others => x"0000"); signal rx_hdr2 : slv16_array (1 to 3) := (others => x"0000"); signal header1_we : std_logic; signal header2_we : std_logic; signal wcount : integer range 1 to 1023; signal wcount_inc : std_logic; signal wcount_set1 : std_logic; signal occount : slv8; signal occount_inc : std_logic; signal occount_set1 : std_logic; -- signal data_store : slv16 := x"0000"; signal data_store_en : std_logic; signal ack_send : std_logic; signal ack_busy : std_logic; signal oc_dtack_all : std_logic; signal oc_port : slv4; signal ocfifo_ocdata : std_logic_vector(15 downto 0); signal ocfifo_din : std_logic_vector(17 downto 0); signal ocfifo_wr : std_logic; signal ocfifo_valid : std_logic; signal ocfifo_dout : std_logic_vector(17 downto 0); signal ocfifo_prog_full : std_logic; --signal ocfifo_data_count : std_logic_vector(3 downto 0); signal ocfifo_wr_rst : std_logic; signal opcode_valid : std_logic; signal tx_opcode : slv16; signal tx_ocseq : slv16; type states is ( --***WaitHeader, WaitSOF, WaitCountSize, WaitEOF, WaitEOFNoAck, WaitHeader, WaitCountSize, WaitEOF, WaitEOFNoAck, OC_Check, OC_Start0, OC_Start1, OC_Next, SendAck, SendAck_Busy, FIFOFull_SendAck, FIFOFull_SendAck_Busy, WaitOCFIFO_NotFull, Idle, Reset ); signal state : states := Idle; signal nstate : states := Idle; begin rx_magicn <= rx_hdr1(1); rx_seq <= rx_hdr1(2); rx_len <= rx_hdr1(3); rx_cbcnt <= rx_hdr1(4); rx_magicn_o <= rx_magicn; rx_seq_o <= rx_seq; rx_len_o <= rx_len; rx_cbcnt_o <= rx_cbcnt; rx_opcode <= rx_hdr2(1); rx_ocseq <= rx_hdr2(2); rx_size <= rx_hdr2(3); -- rx_word0 <= rx_hdr(8); rx_opcode_o <= rx_opcode; rx_ocseq_o <= rx_ocseq; rx_size_o <= rx_size; -- rx_word0_o <= rx_word0; -- State Machine -------------------------------------------------------- prc_sync_part : process (clk125) begin if rising_edge(clk125) then if (rst125 = '1') then state <= Reset; else state <= nstate; end if; end if; end process; ------------------------------------------------------------------ prc_async_machine : process (ack_busy, oc_port, occount, ocfifo_prog_full, rx_cbcnt, rx_lls_i.data, rx_lls_i.eof, rx_lls_i.sof, rx_lls_i.src_rdy, rx_magicn(15 downto 4), rx_ocseq, rx_size, state, wcount) begin -- defaults nstate <= Idle; rx_lld_o <= '0'; wcount_inc <= '0'; wcount_set1 <= '0'; ocfifo_valid <= '0'; ack_send <= '0'; tx_opcode <= oc_insert_port(OC_ACK, oc_port); tx_ocseq <= rx_ocseq; ocfifo_wr <= '0'; header1_we <= '0'; header2_we <= '0'; --ocfifo_wr_rst <= '0'; occount_set1 <= '0'; occount_inc <= '0'; rst_ocb <= '0'; opcode_valid <= '0'; dbg_oc_start0 <= '0'; case state is ------------------------------------------------------------------- when Reset => nstate <= Reset; --ocfifo_wr_rst <= '1'; rst_ocb <= '1'; if (ack_busy = '0') then nstate <= Idle; end if; when Idle => nstate <= Idle; wcount_set1 <= '1'; occount_set1 <= '1'; rx_lld_o <= '1'; -- *** if (ocfifo_prog_full = '1') then nstate <= FIFOFull_SendAck; elsif (rx_lls_i.src_rdy = '1') and (rx_lls_i.sof = '1') then --***elsif (rx_lls_i.src_rdy = '1') then wcount_set1 <= '0'; --*** wcount_inc <= '1'; --*** header1_we <= '1'; --*** nstate <= WaitHeader; --*** --***nstate <= WaitSOF; end if; -- when WaitSOF => -- nstate <= WaitSOF; -- rx_lld_o <= '1'; -- if (rx_lls_i.sof = '1') then -- wcount_inc <= '1'; -- header1_we <= '1'; -- nstate <= WaitHeader; -- end if; when WaitHeader => -- magicn, seq, len, cbcnt nstate <= WaitHeader; rx_lld_o <= '1'; wcount_inc <= '1'; header1_we <= '1'; if (wcount = 4) then wcount_set1 <= '1'; if (rx_magicn(15 downto 4) = x"876") then -- leaving room for more sources nstate <= OC_Check; else nstate <= WaitEOFNoAck; end if; end if; when OC_Check => if (rx_lls_i.data = OC_RESET_OCB) then rst_ocb <= '1'; nstate <= WaitEOF; else nstate <= OC_Start0; end if; -------------------------------------------------------------- when OC_Start0 => ocfifo_valid <= '1'; -- rising oc_valid = sof ocfifo_wr <= '1'; rx_lld_o <= '1'; wcount_inc <= '1'; header2_we <= '1'; opcode_valid <= '1'; dbg_oc_start0 <= '1'; -- signal start of opcode processing on dbg pin nstate <= OC_Start1; when OC_Start1 => nstate <= OC_Start1; ocfifo_valid <= '1'; ocfifo_wr <= '1'; rx_lld_o <= '1'; wcount_inc <= '1'; header2_we <= '1'; if (wcount = 3) then wcount_set1 <= '1'; nstate <= WaitCountSize; end if; when WaitCountSize => nstate <= WaitCountSize; if (ocfifo_prog_full = '0') then ocfifo_valid <= '1'; rx_lld_o <= '1'; ocfifo_wr <= '1'; wcount_inc <= '1'; if (rx_size = x"0000") then -- *** this is cludgy - have another look one day rx_lld_o <= '0'; ocfifo_valid <= '0'; nstate <= OC_Next; elsif (wcount = conv_integer(rx_size(10 downto 1))) then ocfifo_valid <= '0'; nstate <= OC_Next; elsif (rx_lls_i.eof = '1') then nstate <= SendAck; end if; end if; when OC_Next => wcount_set1 <= '1'; if (occount = rx_cbcnt) then nstate <= WaitEOF; else occount_inc <= '1'; nstate <= OC_Start0; end if; when WaitEOF => nstate <= WaitEOF; rx_lld_o <= '1'; wcount_inc <= '1'; if (rx_lls_i.eof = '1') then nstate <= SendAck; end if; when WaitEOFNoAck => nstate <= WaitEOFNoAck; rx_lld_o <= '1'; if (rx_lls_i.eof = '1') then nstate <= Idle; end if; ----------------------------------------------------------------- when SendAck => ack_send <= '1'; nstate <= SendAck_Busy; when SendAck_Busy => nstate <= SendAck_Busy; if (ack_busy = '0') then nstate <= Idle; end if; ------------------- when FIFOFull_SendAck => ack_send <= '1'; nstate <= FIFOFull_SendAck_Busy; when FIFOFull_SendAck_Busy => nstate <= FIFOFull_SendAck_Busy; tx_opcode <= oc_insert_port(OC_RXPKTDEC_FIFOFULL, oc_port); tx_ocseq <= x"0000"; if (ack_busy = '0') then nstate <= WaitOCFIFO_NotFull; end if; when WaitOCFIFO_NotFull => nstate <= WaitOCFIFO_NotFull; if (ocfifo_prog_full = '0') then nstate <= Idle; end if; end case; end process; -------------------------------------------------------------------- prc_word_counter : process (clk125) begin if rising_edge(clk125) then if (rst125 = '1') or (wcount_set1 = '1') then wcount <= 1; elsif (wcount_inc = '1') then wcount <= wcount + 1; end if; end if; end process; prc_opcode_counter : process (clk125) begin if rising_edge(clk125) then if (rst125 = '1') or (occount_set1 = '1') then occount <= x"01"; else if (occount_inc = '1') then occount <= occount + '1'; end if; end if; end if; end process; prc_hdr_store : process (clk125) begin if rising_edge(clk125) then --if (rst125 = '1') then -- rx_hdr(5) <= x"ffec"; -- preset ocseq --else if (header1_we = '1') then rx_hdr1(wcount) <= rx_lls_i.data; end if; if (header2_we = '1') then rx_hdr2(wcount) <= rx_lls_i.data; end if; --end if; end if; end process; ------------------------------------------------------------------------- -- Ack ------------------------------------------------------------------------- pktdec_ack : entity locallink.ll_ack_gen port map ( opcode_i => tx_opcode, ocseq_i => tx_ocseq, ocsize_i => x"0002", payload_i => rx_seq, send_i => ack_send, busy_o => ack_busy, lls_o => lls_o, lld_i => lld_i, clk => clk125, rst => rst125 ); ------------------------------------------------------------------------- -- Core clock domain stuff ------------------------------------------------------------------------- prc_cx : process (clk80) begin -- *** These need to be tig'd if rising_edge(clk80) then dbg_oc_start_q <= dbg_oc_start0; dbg_oc_start_o <= dbg_oc_start_q ; rst_ocb_q <= rst_ocb; rst_ocb_o <= rst_ocb_q; end if; end process; -- OCB Interface and FIFO ------------------------------------------------------------------------------------- -- FIFO used to remove the combinatorial connection between rx_net_fifo and tx_net_ -- fifo flow controls oc_dtack_all <= not oc_dack_ni; -- Only do routing if eth.type lsn > 7) oc_port <= x"0" when (rx_magicn(3) = '0') else ('0' & rx_magicn(2 downto 0)); ocfifo_ocdata <= oc_insert_port(rx_lls_i.data, oc_port) when (opcode_valid = '1') else rx_lls_i.data; --ocfifo_din <= '0' & ocfifo_valid & rx_lls_i.data; ocfifo_din <= '0' & ocfifo_valid & ocfifo_ocdata; --inst_oc_fifo : cg_brfifo_1kx18_ft -- port map ( -- clk => clk, -- srst => ocfifo_rst, -- din => ocfifo_din, -- wr_en => ocfifo_wr, -- rd_en => oc_dtack_all, -- dout => ocfifo_dout, -- full => open, -- almost_full => ocfifo_almost_full, -- empty => open, -- data_count => ocfifo_data_count -- ); ocfifo0 : cg_cxbrfifo_2kx18_ft port map ( wr_clk => clk125, wr_rst => rst125, --ocfifo_wr_rst, rd_clk => clk80, rd_rst => rst80, din => ocfifo_din, wr_en => ocfifo_wr, rd_en => oc_dtack_all, dout => ocfifo_dout, full => open, --almost_full => ocfifo_almost_full, empty => open, prog_full => ocfifo_prog_full ); oc_valid_o <= ocfifo_dout(16); oc_data_o <= ocfifo_dout(15 downto 0); end architecture;