library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; entity EthernetTX is port ( tx_clk : in std_logic; rst : in std_logic; ethTXStart : in std_logic; ethTXStrobe : out std_logic; ethTXData : in std_logic_vector(7 downto 0); ethTXDone : out std_logic; tx_en : out std_logic; txd : out std_logic_vector(3 downto 0) ); end EthernetTX; architecture EthernetTransmitter of EthernetTX is component crc32 is port ( clk: in std_logic; rst: in std_logic; crc_en: in std_logic; data_in: in std_logic_vector(7 downto 0); crc_out: out std_logic_vector(31 downto 0) ); end component; type TState is (stIdle, stSendPreamble, stSendFrameLowNybble, stSendFrameHighNybble, stSendCRC, stBeforeClearLine, stClearLine); signal state : TState := stIdle; signal counter: std_logic_vector(15 downto 0); signal frameLength: std_logic_vector(15 downto 0); signal txBuffer1, txBuffer2, txBuffer3, txBuffer4, txBuffer5 : std_logic_vector(7 downto 0); signal crcNewFrame : std_logic; signal crcByte : std_logic; signal crc : std_logic_vector(31 downto 0); begin crcInstance : crc32 port map ( clk => tx_clk, rst => crcNewFrame, crc_en => crcByte, data_in => txBuffer4, crc_out => crc ); process (tx_clk, rst) begin if rst = '1' then state <= stIdle; tx_en <= '0'; ethTXStrobe <= '0'; counter <= x"0000"; ethTXDone <= '0'; frameLength <= x"0000"; elsif falling_edge(tx_clk) then tx_en <= '1'; state <= state; counter <= counter; ethTXStrobe <= '0'; frameLength <= frameLength; crcByte <= '0'; crcNewFrame <= '0'; ethTXDone <= '0'; case state is when stIdle => tx_en <= '0'; if ethTXStart = '1' then state <= stSendPreamble; tx_en <= '1'; counter <= x"0000"; crcNewFrame <= '1'; end if; when stSendPreamble => counter <= counter + 1; txd <= x"5"; case counter(3 downto 0) is when x"0" => -- read frame length ethTXStrobe <= '1'; when x"1" => frameLength(15 downto 8) <= ethTXData; ethTXStrobe <= '1'; when x"2" => frameLength(7 downto 0) <= ethTXData; when x"3" | x"4" | x"5" | x"6" | x"7" | x"8" | x"9" => txd <= x"5"; when x"A" => ethTXStrobe <= '1'; when x"B" => ethTXStrobe <= '1'; txBuffer5 <= ethTXData; when x"C" | x"D" | x"E" => ethTXStrobe <= '1'; txBuffer1 <= txBuffer2; txBuffer2 <= txBuffer3; txBuffer3 <= txBuffer4; txBuffer4 <= txBuffer5; txBuffer5 <= ethTXData; crcByte <= '1'; when x"F" => txd <= x"D"; state <= stSendFrameLowNybble; txBuffer1 <= txBuffer2; txBuffer2 <= txBuffer3; txBuffer3 <= txBuffer4; txBuffer4 <= txBuffer5; txBuffer5 <= ethTXData; crcByte <= '1'; counter <= frameLength; when others => end case; when stSendFrameLowNybble => state <= stSendFrameHighNybble; txd <= txBuffer1(3 downto 0); crcByte <= '1'; if counter >= x"0006" then ethTXStrobe <= '1'; end if; when stSendFrameHighNybble => state <= stSendFrameLowNybble; txd <= txBuffer1(7 downto 4); txBuffer1 <= txBuffer2; txBuffer2 <= txBuffer3; txBuffer3 <= txBuffer4; txBuffer4 <= txBuffer5; if counter = x"0001" then state <= stSendCRC; elsif counter < x"0006" then txBuffer5 <= x"00"; else txBuffer5 <= ethTXData; end if; counter <= counter - 1; when stSendCRC => state <= stSendCRC; counter <= counter + 1; case counter(2 downto 0) is when "000" => txd <= crc(31 downto 28); when "001" => txd <= crc(27 downto 24); when "010" => txd <= crc(23 downto 20); when "011" => txd <= crc(19 downto 16); when "100" => txd <= crc(15 downto 12); when "101" => txd <= crc(11 downto 8); when "110" => txd <= crc(7 downto 4); when "111" => txd <= crc(3 downto 0); state <= stBeforeClearLine; when others => end case; when stBeforeClearLine => state <= stClearLine; counter(7 downto 0) <= x"FF"; when stClearLine => counter <= counter - 1; if counter(7 downto 0) = x"00" then state <= stIdle; ethTXDone <= '1'; else state <= stClearLine; end if; end case; end if; end process; end EthernetTransmitter;