------------------------------------------------------------------------------- -- Title : Ethernet RX Core -- Project : EthMAC ------------------------------------------------------------------------------- -- File : design/ethmac_rx.vhd -- Author : Mario Hüttel -- Standard : VHDL'93/02 ------------------------------------------------------------------------------- -- Description: LED Demonstration for Ethernet RX + TX ------------------------------------------------------------------------------- -- Copyright (c) 2016 -- -- This file is part of EthMAC. -- -- EthMAC is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, version 2 of the License. -- -- This code is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this code. If not, see . -- ------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity ethmac_rx is generic( IFACE_WIDTH : natural := 2); port( clk_50 : in std_logic; rst : in std_logic; rmii_rx : in std_logic_vector(IFACE_WIDTH - 1 downto 0); rmii_dv : in std_logic; start_of_frame : out std_logic; end_of_frame : out std_logic; data_out : out std_logic_vector(7 downto 0); data_strb : out std_logic; crc_check_valid : out std_logic ); end entity ethmac_rx; architecture RTL of ethmac_rx is constant DIBIT_COUNT : natural := 8 / IFACE_WIDTH; type ethstate_t is (ETH_INIT, ETH_PREAMBLE, ETH_DATA); signal framestate : ethstate_t; signal crc_data_in : std_logic_vector(7 downto 0); signal crc_init : std_logic; signal crc_calc_en : std_logic; signal crc_data_valid : std_logic; signal crc_valid : std_logic; signal dibit_counter : integer range 0 to (DIBIT_COUNT - 1) := 0; signal data_delay_in : std_logic_vector(7 downto 0); signal data_delay_in_strb : std_logic; signal data_delay_truncate : std_logic; signal end_of_frame_s : std_logic; type data_fifo_t is array (0 to 3) of std_logic_vector(7 downto 0); signal data_delay_fifo : data_fifo_t; -- signal datatype_reg: ethfield_t; -- signal data : std_logic_vector( 7 downto 0); begin ethfcs_inst : entity work.ethfcs port map( CLOCK => clk_50, RESET => rst, DATA => crc_data_in, LOAD_INIT => crc_init, CALC => crc_calc_en, D_VALID => crc_data_valid, CRC => open, CRC_REG => open, CRC_VALID => crc_valid); rx_framefsm : process(clk_50, rst) is variable recv_byte : std_logic_vector(7 downto 0) := (others => '0'); begin if rst = '1' then framestate <= ETH_INIT; dibit_counter <= 0; recv_byte := (others => '0'); crc_calc_en <= '0'; data_delay_truncate <= '0'; data_delay_in_strb <= '0'; data_delay_in <= (others => '0'); crc_init <= '0'; crc_data_in <= (others => '0'); crc_data_valid <= '0'; crc_calc_en <= '0'; start_of_frame <= '0'; end_of_frame_s <= '0'; elsif rising_edge(clk_50) then end_of_frame_s <= '0'; crc_calc_en <= '0'; start_of_frame <= '0'; data_delay_truncate <= '0'; data_delay_in_strb <= '0'; crc_init <= '0'; crc_data_valid <= '0'; if dibit_counter = DIBIT_COUNT - 1 then dibit_counter <= 0; else dibit_counter <= dibit_counter + 1; end if; -- input data shift register (LSB first) recv_byte := rmii_rx & recv_byte(7 downto IFACE_WIDTH); case framestate is when ETH_INIT => if rmii_dv = '0' then -- Wait for inter frame gap for sync crc_init <= '1'; framestate <= ETH_PREAMBLE; end if; when ETH_PREAMBLE => if rmii_dv = '1' and rmii_rx(rmii_rx'left downto rmii_rx'left - 1) = "11" then -- Data valid and last dibit of preamble recieved -- reset dibit counter dibit_counter <= 0; start_of_frame <= '1'; framestate <= ETH_DATA; -- crc_init <= '1'; end if; when ETH_DATA => crc_calc_en <= '1'; if rmii_dv = '1' then if dibit_counter = DIBIT_COUNT -1 then -- Data word received data_delay_in <= recv_byte; data_delay_in_strb <= '1'; crc_data_in <= recv_byte; crc_data_valid <= '1'; end if; else framestate <= ETH_INIT; end_of_frame_s <= '1'; crc_calc_en <= '0'; data_delay_truncate <= '1'; end if; end case; end if; end process rx_framefsm; data_delay : process(rst, clk_50) is -- This implements a four byte big delay buffer/FIFO used for removing the crc variable data_count : integer range 0 to 4 := 0; begin if rst = '1' then data_out <= (others => '0'); data_strb <= '0'; data_count := 0; for i in 0 to 3 loop data_delay_fifo(i) <= (others => '0'); end loop; elsif rising_edge(clk_50) then data_strb <= '0'; if data_delay_truncate = '1' then data_count := 0; -- resetting counter is enough. FIFO itself has not to be cleared elsif data_delay_in_strb = '1' then data_delay_fifo(0) <= data_delay_in; for i in 3 downto 1 loop data_delay_fifo(i) <= data_delay_fifo(i - 1); end loop; if data_count < 4 then data_count := data_count + 1; else -- Enable output data_out <= data_delay_fifo(3); data_strb <= '1'; end if; end if; end if; end process data_delay; crc_valid_gen : process(crc_valid) is begin crc_check_valid <= crc_valid; end process crc_valid_gen; eof_sync : process(clk_50, rst) is begin if rst = '1' then end_of_frame <= '0'; elsif rising_edge(clk_50) then end_of_frame <= end_of_frame_s; end if; end process eof_sync; end architecture RTL;