library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity ethmac_tx is 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(1 downto 0); rmii_txen : out std_logic ); end entity ethmac_tx; architecture RTL of ethmac_tx is 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 3 := 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 <= "00"; 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 <= "00" & data_reg(7 downto 2); -- Increment counters: if dibit_counter = 3 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 = 3) then -- Last dibit of preamble+SFD rmii_tx <= "11"; -- latch data_in and continue to data phase data_reg <= data_in; data_ack <= '1'; tx_state <= DATA; eof_reg <= end_of_frame; else rmii_tx <= "01"; end if; when DATA => rmii_txen <= '1'; crc_calc <= '1'; byte_counter_disable <= '1'; rmii_tx <= data_reg(1 downto 0); if dibit_counter = 0 then -- first dibit to transmit => shift register yet intact => Load crc; crc_data_in <= data_reg; crc_data_valid <= '1'; end if; -- Output Least significant dibit of data reg if dibit_counter = 3 and eof_reg = '0' then -- Ladt dibit sent => latch new data data_reg <= data_in; data_ack <= '1'; eof_reg <= end_of_frame; elsif dibit_counter = 3 and eof_reg = '1' then -- Last dibit sent, no further data => CRC tx_state <= CRC; data_reg <= crc_data_out; 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(1 downto 0); if dibit_counter = 1 and byte_counter /= 3 then -- Request new data byte crc_data_valid <= '1'; elsif dibit_counter = 3 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; end if; end if; when IPG => rmii_txen <= '0'; byte_counter_disable <= '0'; if byte_counter = 11 and dibit_counter = 3 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;