------------------------------------------------------------------------------- -- Title : Ethernet TX Core -- Project : EthMAC ------------------------------------------------------------------------------- -- File : design/ethmac_tx.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_tx is generic( IFACE_WIDTH : natural := 2); port( clk_50 : in std_logic; rst : in std_logic; tx_ready : out std_logic; start_of_frame : in std_logic; end_of_frame : in std_logic; data_in : in std_logic_vector(7 downto 0); data_ack : out std_logic; abort : in std_logic; --- RMII Interface rmii_tx : out std_logic_vector(IFACE_WIDTH -1 downto 0); rmii_txen : out std_logic ); end entity ethmac_tx; architecture RTL of ethmac_tx is constant DIBIT_COUNT : natural := 8 / IFACE_WIDTH; constant PREAMBLE_BYTE : std_logic_vector(7 downto 0) := x"55"; constant PREAMBLE_SFD : std_logic_vector(7 downto 0) := x"D5"; type eth_tx_state_t is (INIT, PREAMBLE, DATA, CRC, IPG); signal crc_data_in : std_logic_vector(7 downto 0); signal crc_init : std_logic; signal crc_data_out : std_logic_vector(7 downto 0); signal crc_data_valid : std_logic; signal crc_calc : std_logic; signal dibit_counter : integer range 0 to DIBIT_COUNT - 1 := 0; signal byte_counter : integer range 0 to 15 := 0; signal tx_state : eth_tx_state_t; signal data_reg : std_logic_vector(7 downto 0); signal eof_reg : std_logic; signal byte_counter_disable : std_logic; begin ethfcs_inst : entity work.ethfcs port map( CLOCK => clk_50, RESET => rst, DATA => crc_data_in, LOAD_INIT => crc_init, CALC => crc_calc, D_VALID => crc_data_valid, CRC => crc_data_out, CRC_REG => open, CRC_VALID => open ); eth_tx_fsm : process(clk_50, rst) is begin if rst = '1' then crc_data_in <= (others => '0'); crc_data_valid <= '0'; crc_calc <= '0'; crc_init <= '0'; dibit_counter <= 0; byte_counter <= 0; rmii_txen <= '0'; rmii_tx <= (others => '0'); tx_state <= INIT; data_reg <= (others => '0'); data_ack <= '0'; elsif rising_edge(clk_50) then crc_init <= '0'; crc_calc <= '0'; rmii_txen <= '0'; data_ack <= '0'; crc_data_valid <= '0'; -- Shift data register data_reg <= std_logic_vector(to_unsigned(0, IFACE_WIDTH)) & data_reg(7 downto IFACE_WIDTH); -- Increment counters: if dibit_counter = DIBIT_COUNT - 1 then dibit_counter <= 0; if byte_counter_disable /= '1' then if byte_counter = 15 then report "Byte Counter overflow" severity error; end if; byte_counter <= byte_counter + 1; end if; else dibit_counter <= dibit_counter + 1; end if; if abort = '1' then report "Ethernet Transfer aborted in state " & eth_tx_state_t'image(tx_state) severity note; tx_state <= INIT; else case tx_state is when INIT => byte_counter_disable <= '1'; -- Wait for start of frame if start_of_frame = '1' then crc_init <= '1'; tx_state <= PREAMBLE; byte_counter_disable <= '0'; dibit_counter <= 0; byte_counter <= 0; eof_reg <= '0'; end if; when PREAMBLE => rmii_txen <= '1'; byte_counter_disable <= '0'; if (byte_counter = 7 and dibit_counter = DIBIT_COUNT -1) then -- Last dibit of preamble+SFD rmii_tx <= PREAMBLE_SFD(7 downto 8 - IFACE_WIDTH); -- latch data_in and continue to data phase data_reg <= data_in; data_ack <= '1'; tx_state <= DATA; eof_reg <= end_of_frame; crc_data_valid <= '1'; crc_calc <= '1'; crc_data_in <= data_in; else rmii_tx <= PREAMBLE_BYTE(IFACE_WIDTH -1 downto 0); end if; when DATA => rmii_txen <= '1'; crc_calc <= '1'; byte_counter_disable <= '1'; rmii_tx <= data_reg(IFACE_WIDTH - 1 downto 0); if dibit_counter = DIBIT_COUNT - 1 and eof_reg = '0' then -- Ladt dibit sent => latch new data data_reg <= data_in; data_ack <= '1'; eof_reg <= end_of_frame; crc_data_valid <= '1'; crc_data_in <= data_in; elsif dibit_counter = DIBIT_COUNT - 1 and eof_reg = '1' then -- Last dibit sent, no further data => CRC tx_state <= CRC; data_reg <= crc_data_out; crc_data_valid <= '1'; byte_counter <= 0; byte_counter_disable <= '0'; crc_calc <= '0'; end if; when CRC => byte_counter_disable <= '0'; rmii_txen <= '1'; rmii_tx <= data_reg(IFACE_WIDTH - 1 downto 0); if dibit_counter = DIBIT_COUNT - 1 then -- Either latch new CRC data or proceed to IPG when CRC is finished. if byte_counter = 3 then byte_counter <= 0; tx_state <= IPG; else data_reg <= crc_data_out; crc_data_valid <= '1'; end if; end if; when IPG => rmii_txen <= '0'; byte_counter_disable <= '0'; if byte_counter = 11 and dibit_counter = DIBIT_COUNT - 1 then tx_state <= INIT; end if; end case; end if; -- abort condition end if; -- rising edge end process eth_tx_fsm; end process eth_tx_fsm; tx_ready <= '1' when tx_state = INIT else '0'; end architecture RTL;