EthMac/design/ethmac_rx.vhd

202 lines
6.0 KiB
VHDL

-------------------------------------------------------------------------------
-- Title : Ethernet RX Core
-- Project : EthMAC
-------------------------------------------------------------------------------
-- File : design/ethmac_rx.vhd
-- Author : Mario Hüttel <mario.huettel@gmx.net>
-- 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 <http://www.gnu.org/licenses/>.
--
-------------------------------------------------------------------------------
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;