------------------------------------------------------ -- encapsulate the data/ack/init for Opt Link -- -- Ver 2.00 -- -- Dominique Gigi May 2015 ------------------------------------------------------ -- Move the logic to 10Gb interface (XGMII) & -- -- -- ------------------------------------------------------ LIBRARY ieee; USE ieee.std_logic_1164.all; use ieee.numeric_std.all; use ieee.std_logic_unsigned.all; use work.mydefs.all; entity build_pckt_s_XGMII is port ( reset_CLK : in std_logic; Greset_CLK : in std_logic; clock : in std_logic; start_pckt : in std_logic; -- trigger the packet send init_pckt : in std_logic; -- indicates that the packet is a Init packet ack_pckt : in std_logic; -- indicates that the packet is a acknoldge packet data_pckt : in std_logic; -- indicates that the packet is a data packet data_evt : in std_logic_vector(63 downto 0); --data for data packet read_bck : in std_logic_vector(63 downto 0); --data back for acknowledge packet card_ID : in std_logic_vector(15 downto 0); -- CARD_ID Seq_nb : in std_logic_vector(30 downto 0); -- sequence number len_pckt : in std_logic_vector(15 downto 0); -- length of the packet (for data packet only) other 0 cmd : in std_logic_vector(63 downto 0); -- command bit for data packet only error_gen : in std_logic_vector(3 downto 0); rd_dt : out std_logic; -- request data for data packet only end_pckt : out std_logic; datao : out std_logic_vector(63 downto 0); --- data and K bit send to SERDES k_byte : out std_logic_vector( 7 downto 0); idle_state : out std_logic; status_state : out std_logic_vector(31 downto 0); cnt_pckt_snd : out std_logic_vector(31 downto 0) ); end build_pckt_s_XGMII; architecture behavioral of build_pckt_s_XGMII is type packet_type is ( idle, preamble, start_of_frame, status_s, command, data, CRC_end_frame, wait_crc, gap0, gap1, gap2, gap3 ); signal packet,packetNext:packet_type; component crc_gen_32b IS PORT( clock : IN STD_LOGIC; reset : IN STD_LOGIC; data : IN STD_LOGIC_VECTOR(63 DOWNTO 0); data_valid : IN STD_LOGIC; eoc : IN STD_LOGIC; crc : OUT STD_LOGIC_VECTOR(31 DOWNTO 0); crc_valid : OUT STD_LOGIC ); end component; signal cmp_crc : std_logic; signal val_crc : std_logic_vector(31 downto 0); signal crc_valid : std_logic; signal end_crc : std_logic; signal pckt_type : std_logic_vector(2 downto 0); signal seqnb_mem : std_logic_vector(31 downto 0); signal len_mem : std_logic_vector(15 downto 0); signal cmd_mem : std_logic_vector(63 downto 0); signal del_crc : std_logic_vector(2 downto 0); signal tmp_dt_crc : std_logic_vector(63 downto 0); signal pipe_dta : std_logic_vector(63 downto 0); signal pipe_dtb : std_logic_vector(63 downto 0); signal pipe_dtc : std_logic_vector(63 downto 0); signal pipe_ka : std_logic_vector( 7 downto 0); signal pipe_kb : std_logic_vector( 7 downto 0); signal pipe_kc : std_logic_vector( 7 downto 0); signal nxt_dt : std_logic; signal wc_val : std_logic_vector(15 downto 0); signal mem_error :std_logic_vector(3 downto 0); signal mem_error_gen :std_logic_vector(3 downto 0); signal cnt_pck : std_logic_vector(31 downto 0); --******************************************************* --************** BEGIN ******************************** --******************************************************* begin --***************** error gen **************** -- 0 error on wc -- 1 error on crc -- 2 error on seq number -- 3 error on frame process(Greset_CLK,clock) begin if Greset_CLK = '0' then mem_error <= (others => '0'); mem_error_gen <= (others => '0'); elsif rising_edge(clock) then if error_gen /= "0000" then mem_error <= error_gen; elsif start_pckt = '1' and data_pckt = '1' then mem_error <= (others => '0'); end if; if start_pckt = '1' and data_pckt = '1' then mem_error_gen <= mem_error ; elsif del_crc(1) = '1' and data_pckt = '1' then mem_error_gen <= (others => '0'); end if; end if; end process; --******************************************** --Initiatlize some values -- Sequence number insert in the packet --length of the packet --bit ACK on (1) or OFF (0) --Packet type (001) INIT packet -- (010) data packet -- (100) ack packet process(reset_CLK,clock) begin if reset_CLK = '0' then pckt_type <= (others => '0'); elsif rising_edge(clock) then if start_pckt = '1' then pckt_type <= "000"; seqnb_mem(30 downto 0) <= Seq_nb; seqnb_mem(31) <= '0'; len_mem <= len_pckt; cmd_mem <= cmd; if init_pckt = '1' then pckt_type(0) <= '1'; seqnb_mem <= (others => '0'); len_mem <= (others => '0'); elsif ack_pckt = '1' then pckt_type(2) <= '1'; seqnb_mem(31) <= '1'; len_mem <= (others => '0'); elsif data_pckt = '1' then pckt_type(1) <= '1'; end if; end if; end if; end process; -- compute the CRC on fly (64 bit data => result in 32 bit) CRC_engine:crc_gen_32b PORT MAP( clock => clock, reset => start_pckt, data => tmp_dt_crc, data_valid => cmp_crc, eoc => end_crc, crc => val_crc, crc_valid => crc_valid ); --Clock for state machine state_clk:process(clock,reset_CLK) begin if reset_CLK = '0' then packet <= idle; elsif rising_edge(clock) then packet <= packetNext; end if; end process; state_step:process(packet,start_pckt,pckt_type,wc_val,crc_valid) begin packetNext <= packet; end_crc <= '0'; Case packet is -- wait for a packet to send when idle => status_state(0) <= '1'; if start_pckt = '1' then packetNext <= preamble; end if; when preamble => packetNext <= start_of_frame; -- start the frame with a "START FRAME" + the SEQUENCE number +LSC/LDC_ID + LENGTH when start_of_frame => -- and seq_number status_state(1) <= '1'; if pckt_type(0) = '1' then -- init packetNext <= CRC_end_frame; elsif pckt_type(1) = '1' then -- data packetNext <= command; elsif pckt_type(2) = '1' then -- ack packetNext <= status_s; end if; -- In case of a ACK include the STATUS when status_s => status_state(2) <= '1'; packetNext <= CRC_end_frame; -- In case of a DATA include the COMMAND when command => status_state(3) <= '1'; packetNext <= data; -- In case of a DATA include the DATA0 when data => status_state(4) <= '1'; if wc_val = x"0000" then packetNext <= CRC_end_frame; end if; -- conclude by the CRC when CRC_end_frame => status_state(5) <= '1'; end_crc <= '1'; packetNext <= wait_crc; -- the CRC will arrive in a deterministic number of clock -- wait is not the real case, but avoid to put multiple state between CEC_END_FRAME and WAIT_CRC when wait_crc => status_state(6) <= '1'; if crc_valid = '1' then packetNext <= gap0; end if; -- include some gap between packet like in ETHERNET when gap0 => status_state(7) <= '1'; packetNext <= gap1; when gap1 => status_state(8) <= '1'; packetNext <= idle;--gap2; when gap2 => status_state(9) <= '1'; packetNext <= gap3; when gap3 => status_state(10) <= '1'; packetNext <= idle; when others => packetNext <= idle; end case; end process; --generate the pulse to read data to include in the packet process(reset_CLK,clock) begin if reset_CLK = '0' then nxt_dt <= '0'; elsif rising_edge(clock) then nxt_dt <= '0'; if packet = data or packet = command or (packet = start_of_frame and pckt_type(1) = '1')then nxt_dt <= '1'; end if; end if; end process; rd_dt <= nxt_dt; -- count down starting from len_pckt (latch at the request "start_pckt") process(reset_CLK,clock) begin if reset_CLK = '0' then wc_val <= (others => '0'); elsif rising_edge(clock) then if start_pckt = '1' then wc_val <= len_pckt; elsif nxt_dt = '1' then wc_val <= std_logic_vector( TO_SIGNED ( TO_INTEGER ( UNSIGNED (wc_val) - 1),16) ); end if; end if; end process; -- MULTIPLEXER of values (SATRT_FRAME,Seq#,ID, DATA, Command,...) to create the packet process(reset_CLK,clock) variable status_wrd : std_logic_vector(63 downto 0); variable local_v : std_logic_vector(63 downto 0); begin if reset_CLK = '0' then pipe_ka <= "11111111"; pipe_dta <= x"0707070707070707"; --IDLE STATE cmp_crc <= '0'; elsif rising_edge(clock) then pipe_ka <= "11111111"; pipe_dta <= x"0707070707070707"; --IDLE STATE if packet = preamble then pipe_ka <= "00000001"; pipe_dta <= x"D5555555555555FB"; -- preamble and start of frame elsif packet = start_of_frame then --ACK PACKET cmp_crc <= '1'; local_v(63 downto 32) := Seqnb_mem; local_v(45) := Seqnb_mem(13) xor mem_error_gen(2); -- error gen local_v(31 downto 16) := card_ID; local_v(15 downto 0) := len_mem; local_v(5) := len_mem(5) xor mem_error_gen(0); -- error gen -- used to compute the CRC tmp_dt_crc <= local_v; pipe_ka <= "00000000"; pipe_dta(63 downto 00) <= local_v(63 downto 00); pipe_dta(63) <= local_v(63) xor mem_error_gen(3); -- error gen elsif packet = status_s then --ACK PACKET status_wrd := read_bck; --status word; this value may change in futur tmp_dt_crc <= status_wrd; pipe_ka <= "00000000"; pipe_dta(63 downto 00) <= status_wrd; elsif packet = command then -- CMD DATA read returned tmp_dt_crc <= cmd_mem; pipe_ka <= "00000000"; pipe_dta(63 downto 00) <= cmd_mem; elsif packet = data then tmp_dt_crc <= data_evt; pipe_ka <= "00000000"; pipe_dta(63 downto 00) <= data_evt; elsif packet = CRC_end_frame then cmp_crc <= '0'; pipe_ka <= "11110000"; pipe_dta(63 downto 32) <= x"070707FD"; -- place END of FRAME + idle pipe_dta(31 downto 00) <= x"00000000"; --CRC place -- place for CRC32 end if; end if; end process; -- create a delay to iintroduce the CRC result process(clock) begin if rising_edge(clock) then del_crc(2 downto 1) <= del_crc(1 downto 0); del_crc(0) <= '0'; if packet = CRC_end_frame then del_crc(0) <= '1'; end if; end if; end process; --pipe packet value until the CRC is ready process(clock) begin if rising_edge(clock) then pipe_kc <= pipe_kb; pipe_kb <= pipe_ka; pipe_dtc<= pipe_dtb; pipe_dtb<= pipe_dta; if del_crc(1) = '1' then pipe_dtc(31 downto 00) <= val_crc; pipe_dtc(9) <= val_crc(9) xor mem_error_gen(1); -- error gen end if; end if; end process; -- generate the end of packet create process(reset_CLK,clock) begin if reset_CLK = '0' then end_pckt <= '0'; elsif rising_edge(clock) then end_pckt <= '0'; if end_crc = '1' and pckt_type(1) = '1' then end_pckt <= '1'; end if; end if; end process; process(Greset_CLK,clock) begin if Greset_CLK = '0' then cnt_pck <= (others => '0'); elsif rising_edge(clock) then if end_crc = '1' and pckt_type(1) = '1' then cnt_pck <= cnt_pck + '1'; end if; end if; end process; idle_state <= '1' when packet = idle else '0'; process(pipe_dtc,pipe_kc) begin if FPGA_Brand = "ALTERA" then -- swapp bytes to be compliante to 10Gb (For Altera Only) datao(63 downto 56) <= pipe_dtc(63 downto 56); k_byte(7) <= pipe_kc(7); datao(55 downto 48) <= pipe_dtc(31 downto 24); k_byte(6) <= pipe_kc(3); datao(47 downto 40) <= pipe_dtc(55 downto 48); k_byte(5) <= pipe_kc(6); datao(39 downto 32) <= pipe_dtc(23 downto 16); k_byte(4) <= pipe_kc(2); datao(31 downto 24) <= pipe_dtc(47 downto 40); k_byte(3) <= pipe_kc(5); datao(23 downto 16) <= pipe_dtc(15 downto 08); k_byte(2) <= pipe_kc(1); datao(15 downto 08) <= pipe_dtc(39 downto 32); k_byte(1) <= pipe_kc(4); datao(07 downto 00) <= pipe_dtc(07 downto 00); k_byte(0) <= pipe_kc(0); elsif FPGA_Brand = "XILINX" then datao <= pipe_dtc; k_byte <= pipe_kc; end if; end process; cnt_pckt_snd <= cnt_pck; status_state(31 downto 11) <= (others => '0'); end behavioral;