-- MIPS I system -- Copyright 2011-2012 Stefan Schuermans -- Copyleft GNU public license V2 or later -- http://www.gnu.org/copyleft/gpl.html LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.NUMERIC_STD.ALL; ENTITY e_io_eth_rxframe IS PORT ( rst: IN std_logic; clk: IN std_logic; i_data: IN std_logic_vector( 7 DOWNTO 0); i_data_en: IN std_logic; i_done: IN std_logic; i_err: IN std_logic; i_mac: IN std_logic_vector(47 DOWNTO 0); o_data: OUT std_logic_vector(31 DOWNTO 0); o_data_en: OUT std_logic; o_done: OUT std_logic; o_err: OUT std_logic ); END ENTITY e_io_eth_rxframe; ARCHITECTURE a_io_eth_rxframe OF e_io_eth_rxframe IS TYPE t_state IS (st_idle, st_sync, st_mac, st_mac_uni, st_mac_brd, st_data); SUBTYPE t_mac_cnt IS natural RANGE 0 TO 5; SUBTYPE t_data_cnt IS natural RANGE 0 TO 3; SIGNAL r_state: t_state := st_idle; SIGNAL n_state: t_state; SIGNAL r_mac_cnt: t_mac_cnt := 0; SIGNAL n_mac_cnt: t_mac_cnt; SIGNAL r_data_cnt: t_data_cnt := 0; SIGNAL n_data_cnt: t_data_cnt; SIGNAL r_out_data: std_logic_vector(31 DOWNTO 0) := (OTHERS => '0'); SIGNAL n_out_data: std_logic_vector(31 DOWNTO 0); SIGNAL r_out_data_en: std_logic := '0'; SIGNAL n_out_data_en: std_logic; SIGNAL r_out_done: std_logic := '0'; SIGNAL n_out_done: std_logic; SIGNAL r_out_err: std_logic := '0'; SIGNAL n_out_err: std_logic; SIGNAL s_crc_en: std_logic; SIGNAL s_crc_start: std_logic; SIGNAL s_crc_data: std_logic_vector( 7 DOWNTO 0); SIGNAL s_crc_crc: std_logic_vector(31 DOWNTO 0); COMPONENT e_block_crc32 IS PORT ( rst: IN std_logic; clk: IN std_logic; i_en: IN std_logic; i_start: IN std_logic; i_data: IN std_logic_vector( 7 DOWNTO 0); o_crc: OUT std_logic_vector(31 DOWNTO 0) ); END COMPONENT e_block_crc32; BEGIN crc32: e_block_crc32 PORT MAP ( rst => rst, clk => clk, i_en => s_crc_en, i_start => s_crc_start, i_data => s_crc_data, o_crc => s_crc_crc ); p_next: PROCESS(r_state, r_mac_cnt, r_data_cnt, r_out_data, i_data, i_data_en, i_done, i_err, i_mac, s_crc_crc) VARIABLE v_mac: std_logic_vector(7 DOWNTO 0); VARIABLE v_data: boolean; BEGIN n_state <= r_state; n_mac_cnt <= r_mac_cnt; n_data_cnt <= r_data_cnt; n_out_data <= r_out_data; n_out_data_en <= '0'; n_out_done <= '0'; n_out_err <= '0'; s_crc_en <= '0'; s_crc_start <= '0'; s_crc_data <= (OTHERS => '0'); -- next state v_data := false; CASE r_state IS WHEN st_idle => IF i_data_en = '1' AND i_data = X"55" THEN n_state <= st_sync; END IF; WHEN st_sync => IF i_data_en = '1' THEN IF i_data = X"D5" THEN n_state <= st_mac; n_mac_cnt <= 0; n_data_cnt <= 0; ELSIF i_data /= X"55" THEN n_state <= st_idle; END IF; ELSIF i_done = '1' OR i_err = '1' THEN n_state <= st_idle; END IF; WHEN st_mac => IF i_data_en = '1' THEN v_mac := i_mac(7 + 8 * r_mac_cnt DOWNTO 8 * r_mac_cnt); IF v_mac = X"FF" THEN IF i_data = v_mac THEN v_data := true; ELSE n_state <= st_idle; n_out_err <= '1'; END IF; ELSE IF i_data = v_mac THEN v_data := true; n_state <= st_mac_uni; ELSIF i_data = X"FF" THEN v_data := true; n_state <= st_mac_brd; ELSE n_state <= st_idle; n_out_err <= '1'; END IF; END IF; IF r_mac_cnt < 5 THEN n_mac_cnt <= r_mac_cnt + 1; ELSE n_state <= st_data; END IF; ELSIF i_done = '1' OR i_err = '1' THEN n_state <= st_idle; n_out_err <= '1'; END IF; WHEN st_mac_uni => IF i_data_en = '1' THEN v_mac := i_mac(7 + 8 * r_mac_cnt DOWNTO 8 * r_mac_cnt); IF i_data = v_mac THEN v_data := true; ELSE n_state <= st_idle; n_out_err <= '1'; END IF; IF r_mac_cnt < 5 THEN n_mac_cnt <= r_mac_cnt + 1; ELSE n_state <= st_data; END IF; ELSIF i_done = '1' OR i_err = '1' THEN n_state <= st_idle; n_out_err <= '1'; END IF; WHEN st_mac_brd => IF i_data_en = '1' THEN IF i_data = X"FF" THEN v_data := true; ELSE n_state <= st_idle; n_out_err <= '1'; END IF; IF r_mac_cnt < 5 THEN n_mac_cnt <= r_mac_cnt + 1; ELSE n_state <= st_data; END IF; ELSIF i_done = '1' OR i_err = '1' THEN n_state <= st_idle; n_out_err <= '1'; END IF; WHEN st_data => IF i_data_en = '1' THEN v_data := true; ELSIF i_done = '1' THEN n_state <= st_idle; -- check CRC: last 4 bytes = 4 byte delayed CRC value IF r_out_data = s_crc_crc THEN n_out_done <= '1'; ELSE n_out_err <= '1'; END IF; ELSIF i_err = '1' THEN n_state <= st_idle; n_out_err <= '1'; END IF; WHEN OTHERS => NULL; END CASE; -- data output / CRC IF v_data THEN n_out_data(31 DOWNTO 24) <= i_data; n_out_data(23 DOWNTO 0) <= r_out_data(31 DOWNTO 8); IF r_data_cnt < 3 THEN n_data_cnt <= r_data_cnt + 1; ELSE n_data_cnt <= 0; n_out_data_en <= '1'; END IF; -- calculate CRC with 4 bytes delay, -- so CRC value is available when i_done = 1 s_crc_en <= '1'; s_crc_data <= r_out_data(7 DOWNTO 0); IF r_mac_cnt = 4 THEN s_crc_start <= '1'; END IF; END IF; END PROCESS p_next; p_sync: PROCESS(rst, clk) BEGIN IF rst = '1' THEN r_state <= st_idle; r_mac_cnt <= 0; r_data_cnt <= 0; r_out_data <= (OTHERS => '0'); r_out_data_en <= '0'; r_out_done <= '0'; r_out_err <= '0'; ELSIF rising_edge(clk) THEN r_state <= n_state; r_mac_cnt <= n_mac_cnt; r_data_cnt <= n_data_cnt; r_out_data <= n_out_data; r_out_data_en <= n_out_data_en; r_out_done <= n_out_done; r_out_err <= n_out_err; END IF; END PROCESS p_sync; o_data <= r_out_data; o_data_en <= r_out_data_en; o_done <= r_out_done; o_err <= r_out_err; END ARCHITECTURE a_io_eth_rxframe;