LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.NUMERIC_STD.ALL; ENTITY e_io_eth IS PORT ( rst: IN std_logic; clk: IN std_logic; i_addr: IN std_logic_vector( 2 DOWNTO 0); o_rd_data: OUT std_logic_vector(31 DOWNTO 0); i_rd_en: IN std_logic_vector( 3 DOWNTO 0); i_wr_data: IN std_logic_vector(31 DOWNTO 0); i_wr_en: IN std_logic_vector( 3 DOWNTO 0); o_bm_req: OUT std_logic; i_bm_grant: IN std_logic; o_bm_addr: OUT std_logic_vector(31 DOWNTO 0); i_bm_rd_data: IN std_logic_vector(31 DOWNTO 0); o_bm_rd_en: OUT std_logic_vector( 3 DOWNTO 0); o_bm_wr_data: OUT std_logic_vector(31 DOWNTO 0); o_bm_wr_en: OUT std_logic_vector( 3 DOWNTO 0); pin_o_nrst: OUT std_logic; pin_i_rx_clk: IN std_logic; pin_i_rxd: IN std_logic_vector(4 DOWNTO 0); pin_i_rx_dv: IN std_logic; pin_i_crs: IN std_logic; pin_i_col: IN std_logic; pin_i_tx_clk: IN std_logic; pin_o_txd: OUT std_logic_vector(3 DOWNTO 0); pin_o_tx_en: OUT std_logic ); END ENTITY e_io_eth; ARCHITECTURE a_io_eth OF e_io_eth IS SIGNAL s_rxif_data: std_logic_vector(7 DOWNTO 0); SIGNAL s_rxif_data_en: std_logic; SIGNAL s_rxif_done: std_logic; SIGNAL s_rxif_err: std_logic; SIGNAL s_rxframe_data: std_logic_vector(31 DOWNTO 0); SIGNAL s_rxframe_data_en: std_logic; SIGNAL s_rxframe_done: std_logic; SIGNAL s_rxframe_err: std_logic; -- RX buffer registers -- start: current buffer begin -- cur: address of next data write -- size: size of data received -- end: address just behind buffer -- data is written to buffer like this: ... -- size is written last -- next packet begins directly afterwards -- all addresses/sizes are word-aligned SIGNAL r_rx_start: std_logic_vector(31 DOWNTO 0) := X"00000000"; SIGNAL n_rx_start: std_logic_vector(31 DOWNTO 0); SIGNAL r_rx_cur: std_logic_vector(31 DOWNTO 0) := X"00000004"; SIGNAL n_rx_cur: std_logic_vector(31 DOWNTO 0); SIGNAL r_rx_size: std_logic_vector(31 DOWNTO 0) := X"00000000"; SIGNAL n_rx_size: std_logic_vector(31 DOWNTO 0); SIGNAL r_rx_end: std_logic_vector(31 DOWNTO 0) := X"00000000"; SIGNAL n_rx_end: std_logic_vector(31 DOWNTO 0); -- RX new buffer registers -- new_start: begin of new buffer -- new_end: address just behind new buffer -- new_en: if a new buffer is available -- all addresses are word-aligned SIGNAL r_rx_new_start: std_logic_vector(31 DOWNTO 0) := X"00000000"; SIGNAL n_rx_new_start: std_logic_vector(31 DOWNTO 0); SIGNAL r_rx_new_end: std_logic_vector(31 DOWNTO 0) := X"00000000"; SIGNAL n_rx_new_end: std_logic_vector(31 DOWNTO 0); SIGNAL r_rx_new_en: std_logic := '0'; SIGNAL n_rx_new_en: std_logic; SIGNAL s_rx_new: std_logic; SIGNAL s_wrbuf_wr_rdy: std_logic; SIGNAL s_wrbuf_wr_data: std_logic_vector(63 DOWNTO 0); SIGNAL s_wrbuf_wr_en: std_logic; SIGNAL s_wrbuf_rd_rdy: std_logic; SIGNAL s_wrbuf_rd_data: std_logic_vector(63 DOWNTO 0); SIGNAL s_wrbuf_rd_en: std_logic; COMPONENT e_io_eth_rst IS PORT ( rst: IN std_logic; clk: IN std_logic; pin_o_nrst: OUT std_logic ); END COMPONENT e_io_eth_rst; COMPONENT e_io_eth_rxif IS PORT ( rst: IN std_logic; clk: IN std_logic; o_data: OUT std_logic_vector(7 DOWNTO 0); o_data_en: OUT std_logic; o_done: OUT std_logic; o_err: OUT std_logic; pin_i_rx_clk: IN std_logic; pin_i_rxd: IN std_logic_vector(4 DOWNTO 0); pin_i_rx_dv: IN std_logic; pin_i_crs: IN std_logic; pin_i_col: IN std_logic ); END COMPONENT e_io_eth_rxif; COMPONENT 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 COMPONENT e_io_eth_rxframe; COMPONENT e_block_fifo IS GENERIC ( addr_width: natural; data_width: natural ); PORT ( rst: IN std_logic; clk: IN std_logic; o_wr_rdy: OUT std_logic; i_wr_data: IN std_logic_vector(data_width - 1 DOWNTO 0); i_wr_en: IN std_logic; o_rd_rdy: OUT std_logic; o_rd_data: OUT std_logic_vector(data_width - 1 DOWNTO 0); i_rd_en: IN std_logic ); END COMPONENT e_block_fifo; BEGIN reset: e_io_eth_rst PORT MAP ( rst => rst, clk => clk, pin_o_nrst => pin_o_nrst ); rxif: e_io_eth_rxif PORT MAP ( rst => rst, clk => clk, o_data => s_rxif_data, o_data_en => s_rxif_data_en, o_done => s_rxif_done, o_err => s_rxif_err, pin_i_rx_clk => pin_i_rx_clk, pin_i_rxd => pin_i_rxd, pin_i_rx_dv => pin_i_rx_dv, pin_i_crs => pin_i_crs, pin_i_col => pin_i_col ); rxframe: e_io_eth_rxframe PORT MAP ( rst => rst, clk => clk, i_data => s_rxif_data, i_data_en => s_rxif_data_en, i_done => s_rxif_done, i_err => s_rxif_err, i_mac => X"070605040302", o_data => s_rxframe_data, o_data_en => s_rxframe_data_en, o_done => s_rxframe_done, o_err => s_rxframe_err ); p_rx_next: PROCESS(r_rx_start, r_rx_cur, r_rx_size, r_rx_end, r_rx_new_start, r_rx_new_end, r_rx_new_en, s_rxframe_data, s_rxframe_data_en, s_rxframe_done, s_rxframe_err, s_wrbuf_wr_rdy) VARIABLE v_abort: boolean; -- abort current packet reception VARIABLE v_ignore: boolean; -- ignore rest of packet VARIABLE v_store: boolean; -- store packet data VARIABLE v_finish: boolean; -- finish reception of packet BEGIN n_rx_start <= r_rx_start; n_rx_cur <= r_rx_cur; n_rx_size <= r_rx_size; n_rx_end <= r_rx_end; s_wrbuf_wr_data <= (OTHERS => '0'); s_wrbuf_wr_en <= '0'; s_rx_new <= '0'; -- determine which action to perform v_abort := false; v_ignore := false; v_store := false; v_finish := false; -- incoming data IF s_rxframe_data_en = '1' THEN IF r_rx_start = r_rx_end THEN v_ignore := true; -- buffer not available -> ignore rest of packet ELSIF r_rx_cur = r_rx_end THEN v_ignore := true; -- buffer full -> ignore rest of packet ELSIF s_wrbuf_wr_rdy = '0' THEN v_ignore := true; -- bus master write buffer full -> ignore rest of packet ELSE v_store := true; -- store data END IF; -- packet complete ELSIF s_rxframe_done = '1' THEN IF r_rx_start = r_rx_end THEN v_abort := true; -- buffer not available -> abort ELSIF r_rx_cur = r_rx_end THEN v_abort := true; -- buffer full -> abort ELSIF s_wrbuf_wr_rdy = '0' THEN v_abort := true; -- bus master write buffer full -> abort ELSIF r_rx_size = X"00000000" THEN v_abort := true; -- empty packet -> abort ELSE v_finish := true; -- finish packet recpetion END IF; -- error ELSIF s_rxframe_err = '1' THEN v_abort := true; -- abort END IF; -- perform action selected above -- abort current packet IF v_abort THEN n_rx_cur <= std_logic_vector(unsigned(r_rx_start) + X"00000004"); n_rx_size <= X"00000000"; -- ignore rest of packet -- count size to ensure it is not zero ELSIF v_ignore THEN n_rx_cur <= r_rx_end; n_rx_size <= std_logic_vector(unsigned(r_rx_size) + X"00000004"); -- store data to current address and advance in buffer ELSIF v_store THEN s_wrbuf_wr_data <= r_rx_cur & s_rxframe_data; s_wrbuf_wr_en <= '1'; n_rx_cur <= std_logic_vector(unsigned(r_rx_cur) + X"00000004"); n_rx_size <= std_logic_vector(unsigned(r_rx_size) + X"00000004"); -- store size to start and restart after packet ELSIF v_finish THEN s_wrbuf_wr_data <= r_rx_start & r_rx_size; s_wrbuf_wr_en <= '1'; n_rx_start <= r_rx_cur; n_rx_cur <= std_logic_vector(unsigned(r_rx_cur) + X"00000004"); n_rx_size <= X"00000000"; END IF; -- use new buffer -- if no action, no data yet and new_en set IF NOT v_abort AND NOT v_ignore AND NOT v_store AND NOT v_finish AND r_rx_size = X"00000000" AND r_rx_new_en = '1' THEN -- terminate old buffer by writing size 0 (if old buffer was available) IF r_rx_start /= r_rx_end THEN s_wrbuf_wr_data <= r_rx_start & X"00000000"; s_wrbuf_wr_en <= '1'; END IF; -- take over new_start and new_end n_rx_start <= r_rx_new_start; n_rx_cur <= std_logic_vector(unsigned(r_rx_new_start) + X"00000004"); n_rx_size <= X"00000000"; n_rx_end <= r_rx_new_end; -- signal overtake of new buffer to process p_write s_rx_new <= '1'; END IF; END PROCESS p_rx_next; p_rx_sync: PROCESS(rst, clk) BEGIN IF rst = '1' THEN r_rx_start <= X"00000000"; r_rx_cur <= X"00000004"; r_rx_size <= X"00000000"; r_rx_end <= X"00000000"; r_rx_new_start <= X"00000000"; r_rx_new_end <= X"00000000"; r_rx_new_en <= '0'; ELSIF rising_edge(clk) THEN r_rx_start <= n_rx_start; r_rx_cur <= n_rx_cur; r_rx_size <= n_rx_size; r_rx_end <= n_rx_end; r_rx_new_start <= n_rx_new_start; r_rx_new_end <= n_rx_new_end; r_rx_new_en <= n_rx_new_en; END IF; END PROCESS p_rx_sync; -- register interface write p_write: PROCESS(r_rx_new_start, r_rx_new_end, r_rx_new_en, s_rx_new, i_addr, i_wr_data, i_wr_en) BEGIN n_rx_new_start <= r_rx_new_start; n_rx_new_end <= r_rx_new_end; n_rx_new_en <= r_rx_new_en; IF s_rx_new = '1' THEN n_rx_new_en <= '0'; -- new buffer has been overtaken, reset new_en END IF; IF i_wr_en = "1111" THEN CASE i_addr IS WHEN "100" => n_rx_new_start <= i_wr_data; WHEN "101" => n_rx_new_end <= i_wr_data; WHEN "110" => n_rx_new_en <= i_wr_data(0); WHEN OTHERS => NULL; END CASE; END IF; END PROCESS p_write; -- register interface read p_read: PROCESS(rst, clk) BEGIN IF rst = '1' THEN o_rd_data <= (OTHERS => '0'); ELSIF rising_edge(clk) THEN o_rd_data <= (OTHERS => '0'); CASE i_addr IS WHEN "000" => o_rd_data <= r_rx_start; WHEN "001" => o_rd_data <= r_rx_cur; WHEN "010" => o_rd_data <= r_rx_size; WHEN "011" => o_rd_data <= r_rx_end; WHEN "100" => o_rd_data <= r_rx_new_start; WHEN "101" => o_rd_data <= r_rx_new_end; WHEN "110" => o_rd_data(0) <= r_rx_new_en; WHEN OTHERS => NULL; END CASE; END IF; END PROCESS p_read; -- bus master write buffer -- as the core has lower bus priority than ethernet, -- the core will never access memory or ethernet registers -- when data is in this buffer wrbuf: e_block_fifo GENERIC MAP ( addr_width => 2, data_width => 64 ) PORT MAP ( rst => rst, clk => clk, o_wr_rdy => s_wrbuf_wr_rdy, i_wr_data => s_wrbuf_wr_data, i_wr_en => s_wrbuf_wr_en, o_rd_rdy => s_wrbuf_rd_rdy, o_rd_data => s_wrbuf_rd_data, i_rd_en => s_wrbuf_rd_en ); pin_o_txd <= "0000"; pin_o_tx_en <= '0'; -- bus master write p_bm_wr: PROCESS(s_wrbuf_rd_rdy, s_wrbuf_rd_data, i_bm_grant) BEGIN s_wrbuf_rd_en <= '0'; o_bm_req <= '0'; o_bm_addr <= (OTHERS => '0'); o_bm_rd_en <= (OTHERS => '0'); o_bm_wr_data <= (OTHERS => '0'); o_bm_wr_en <= (OTHERS => '0'); -- process write requests from write buffer IF s_wrbuf_rd_rdy = '1' THEN s_wrbuf_rd_en <= i_bm_grant; o_bm_req <= '1'; o_bm_addr <= s_wrbuf_rd_data(63 DOWNTO 32); o_bm_wr_data <= s_wrbuf_rd_data(31 DOWNTO 0); o_bm_wr_en <= "1111"; END IF; END PROCESS p_bm_wr; END ARCHITECTURE a_io_eth;