⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ethernet.vhd

📁 设计ip协议的vhdl实现
💻 VHD
字号:
-------------------------------------------------------------------------------
-- ethernet.vhd
--
-- Author(s):     Ashley Partis and Jorgen Peddersen
-- Created:       Jan 2001
-- Last Modified: Feb 2001
-- 
-- Receives frames from the PHY chip and passes them to the next layer(s)
-- using a bytestream.  Only allows valid IP frames and ARP frames.  Frames
-- with incorrect CRCs are declared invalid.  Frames with MACs that are not
-- broadcasts or the same as in the global_constants are ignored.  RX_ERR is
-- ignored.
--
-------------------------------------------------------------------------------

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use work.global_constants.all;

entity ethernet is
    port (
		clk: in STD_LOGIC;								-- clock
		rstn: in STD_LOGIC;								-- asynchornous active low reset
		RX_DATA: in STD_LOGIC_VECTOR (3 downto 0);		-- 4 bit receive data line from the ethernet PHY
		RX_DV: in STD_LOGIC;							-- PHY receive data valid signal
--		RX_ERR: in STD_LOGIC;							-- PHY receive error signal
		RX_CLK: in STD_LOGIC;							-- PHY receiver clock
		frameType: out STD_LOGIC;						-- Inform the ARP or IP processes when we have a byte
		frameByte: out STD_LOGIC;						-- signal to write data to IP layer
		frameData: out STD_LOGIC_VECTOR (7 downto 0);	-- data to write to the IP layer
		newFrame: out STD_LOGIC;						-- new frame signal to the next layer
		endFrame: out STD_LOGIC;						-- end of frame signal to the next layer
		frameValid: out STD_LOGIC						-- indicate if the frame is valid (assert with endFrame)
	);
end Ethernet;

architecture ethernet_arch of Ethernet is

component crcGenerator is
    port (
    	clk: in STD_LOGIC;								-- Input clock
        rstn: in STD_LOGIC;								-- Asynchronous active low reset
        newFrame: in STD_LOGIC;							-- Assert to restart calculations
        newByte: in STD_LOGIC;							-- Assert to indicate a crcValid input byte
        inByte: in STD_LOGIC_VECTOR (7 downto 0);		-- Input byte
        crcValid: out STD_LOGIC;						-- Indicates crcValid CRC.  Active HIGH
        crcValue: out STD_LOGIC_VECTOR (31 downto 0)	-- CRC output
    );
end component;

-- buffer to store target MAC as we receive it
signal targetMAC: STD_LOGIC_VECTOR (47 downto 0);
signal nextTargetMAC: STD_LOGIC_VECTOR (47 downto 0);

-- state declarations
type STATETYPE is (stIdle, stLowNybbleRXClkLowTime, stLowNybbleRXClkHighTime, stHiNybbleRXClkLowTime, 
			stHiNybbleRXClkHighTime, stInvalidFrame, CHKCRC);

signal presState: STATETYPE;
signal nextState: STATETYPE;

signal rstCnt: STD_LOGIC;								-- signal to reset the address counter
signal incCnt: STD_LOGIC;								-- signal to increment the address counter
signal cnt: STD_LOGIC_VECTOR (3 downto 0);				-- byte counter for the header

-- buffer to hold the nybbles of each byte as they are received from the PHY
signal nextFrameData: STD_LOGIC_VECTOR (7 downto 0);	
signal frameDataSig: STD_LOGIC_VECTOR (7 downto 0);		-- internal signal that gets mapped to the frameData output

-- buffers for the asynchronous inputs from the PHY to avoid lockups
signal RX_DATALatch: STD_LOGIC_VECTOR (3 downto 0);
signal RX_DVLatch: STD_LOGIC;
signal RX_CLKLatch: STD_LOGIC;

-- signals for the CRC generator
signal newByte: STD_LOGIC;								-- sends a byte to the CRC checker when asserted
signal CRCNewFrame: STD_LOGIC;							-- resets the CRC checker when asserted
signal CRC: STD_LOGIC_VECTOR (31 downto 0);				-- CRC value

begin

	-- instantiate the CRC generator component
	crcGenEthRec : crcGenerator port map (
    	clk => clk,
        rstn => rstn,
        newFrame => CRCNewFrame,
        newByte => newByte,
        inByte => frameDataSig,
        crcValid => open,
        crcValue => CRC
    );

	-- set the frame data output to frameDataSig to avoid treating the frameData output as a buffer
	frameData <= frameDataSig;

A:	process (rstn, clk)
	begin
		-- create the asynchronous active low reset
		if rstn = '0' then
			presState <= stIdle;
		-- main clocked process
		elsif clk'EVENT and clk = '1' then
			presState <= nextState;
			-- set targetMAC and frameData to their next values (defaults to keeping the old)
			targetMAC <= nextTargetMAC;
			frameDataSig <= nextFrameData;
			-- increment or reset the count synchronously when required to avoid race conditions
			if incCnt = '1' then
				cnt <= cnt + 1;
			elsif rstCnt = '1' then
				cnt <= (others => '0');
			end if;
		end if;
	end process;		-- end process A
	
-- main FSM process
B:	process (presState, RX_DVLatch, RX_DATALatch, RX_CLKLatch, cnt, frameDataSig, targetMAC, 
			CRC)
	begin
		-- signal defaults
		incCnt <= '0';
		rstCnt <= '0';
		newFrame <= '0';
		endFrame <= '0';
		frameValid <= '0';
		newByte <= '0';
		frameByte <= '0';
		-- default nextFrameData and frameDataSig to their current values
		nextFrameData <= frameDataSig;
		nextTargetMAC <= targetMAC;
		frameType <= '0';
		CRCNewFrame <= '0';
		
		case presState is
			when stIdle =>
				-- if receive data valid signal is high, start receiving the nybbles of data
				if RX_DVLatch = '1' then
					nextState <= stLowNybbleRXClkLowTime;
					-- reset the CRC
					CRCNewFrame <= '1';
				-- else, wait for new data to arrive
				else
					nextState <= stIdle;
					rstCnt <= '1';
				end if;
			
			when stLowNybbleRXClkLowTime =>
				-- latch the lower nybble of a byte on the rising edge of RX_CLK, as the
				-- lower nybble is received first by the PHY and given to us
				if RX_CLKLatch = '1' then
					nextState <= stLowNybbleRXClkHighTime;
					nextFrameData (3 downto 0) <= RX_DATALatch;
				-- wait for the rising edge of RX_CLK
				else 
					nextState <= stLowNybbleRXClkLowTime;
				end if;
	
			when stLowNybbleRXClkHighTime =>
				if RX_CLKLatch = '0' then
					-- if data valid is low then the whole frame has been received, and return to idle
					-- do this here to make sure the CRC has had enough time to be calculated, as it takes
					-- 8 clock cycles (or just under one half of the RX_CLK's clock cycle)
					if RX_DVLatch = '0' then
						nextState <= CHKCRC;
					-- do nothing on the falling edge or the high time of RX_CLK
					else
						nextState <= stHiNybbleRXClkLowTime;
					end if;
				else
					nextState <= stLowNybbleRXClkHighTime;
				end if;

			when stHiNybbleRXClkLowTime =>
				-- latch the higher nybble on the rising edge of RX_CLK
				if RX_CLKLatch = '1' then
					nextState <= stHiNybbleRXClkHighTime;
					nextFrameData (7 downto 4) <= RX_DATALatch;
				-- wait for the rising edge of RX_CLK
				else
					nextState <= stHiNybbleRXClkLowTime;
				end if;
			
			when stHiNybbleRXClkHighTime =>
				-- on the falling edge edge of RX_CLK, handle the received full byte
				-- of data appopriately, according to the counter
				if RX_CLKLatch = '0' then
					nextState <= stLowNybbleRXClkLowTime;
					case cnt is
						-- ignore the SFD, as at 10megabit operation the PHY sends the SFD
						-- first, followed by the ethernet frame
						when x"0" =>
							incCnt <= '1';
						-- get the target MAC address, MSB first (byte 5)
						-- remember to send the received frame to the CRC to check it (newByte)
						when x"1" =>
							nextTargetMAC (47 downto 40) <= frameDataSig;
							newByte <= '1';					-- frame headers
							incCnt <= '1';
						-- get byte 4 of the target MAC address
						when x"2" =>
							nextTargetMAC (39 downto 32) <= frameDataSig;
							incCnt <= '1';
							newByte <= '1';
						-- get byte 3 of the target MAC address
						when x"3" =>
							nextTargetMAC (31 downto 24) <= frameDataSig;
							newByte <= '1';
							incCnt <= '1';
						-- get byte 2 of the target MAC address
						when x"4" =>
							nextTargetMAC (23 downto 16) <= frameDataSig;
							incCnt <= '1';
							newByte <= '1';
						-- get byte 1 of the target MAC address
						when x"5" =>
							nextTargetMAC (15 downto 8) <= frameDataSig;
							incCnt <= '1';
							newByte <= '1';
						-- get byte 0 of the target MAC address
						when x"6" =>						
							nextTargetMAC (7 downto 0) <= frameDataSig;
							incCnt <= '1';
							newByte <= '1';
						-- start receiving the sender's MAC (ignored)
						-- check to see if the frame was meant for us or a broadcast
						-- if not, ignore
						when x"7" =>
							incCnt <= '1';
							newByte <= '1';
							if targetMAC /= DEVICE_MAC and targetMAC /= x"FFFFFFFFFFFF" then
								nextState <= stInvalidFrame;
							end if;
						-- receive and ignore the rest of the sender's MAC address
						-- (still send all the bytes to the CRC)
						when x"8" | x"9" | x"A" | x"B" | x"C" =>
							incCnt <= '1';
							newByte <= '1';
						-- get the ethernet type code
						-- the first byte should be x"08"
						when x"D" =>
							incCnt <= '1';
							newByte <= '1';
							if frameDataSig /= 8 then
								nextState <= stInvalidFrame;
							end if;							
						-- get the second byte of the ethernet type field...
						-- should be 00 for and IP datargam or 06 for an ARP message
						-- ignore everything else, and set frameType accordingly 
						-- (1 for IP, 0 for ARP)
						when x"E" =>
							incCnt <= '1';
							newByte <= '1';
							if frameDataSig = 0 then
								frameType <= '1';
								newFrame <= '1';
							elsif frameDataSig = 6 then
								frameType <= '0';
								newFrame <= '1';
							else 
								nextState <= stInvalidFrame;
							end if;
						-- receive the rest of the data in the frame
						-- (the CRC will be sent to the next layers as well, but they
						-- should ignore the extra 4 bytes)
						when x"F" =>
							incCnt <= '0';
							frameByte <= '1';
							newByte <= '1';

						when others =>
					end case;
				-- else do nothing on the RX_CLK high time
				else
					nextState <= stHiNybbleRXClkHighTime;
				end if;
			
			when stInvalidFrame =>
				-- if for some reason the frame is invalid, go here and wait for
				-- the frame to finish transmitting (RX_DV going low)
				if RX_DVLatch = '0' then
					nextState <= stIdle;
				else
					nextState <= stInvalidFrame;
				end if;
				
			when CHKCRC =>
				nextState <= stIdle;
				-- reset the address counter for a new frame
				rstCnt <= '1';
				-- inform the next layers that we have finished receiving the frame
				endFrame <= '1';
				-- check too see if the irc is valid
				-- if not, the next layers will ignore the frame
				if CRC = 0 then
					frameValid <= '1';
				end if;

			when others =>
		end case;
	end process;		-- end process B
	
	-- process to latch the aysnchronous inputs from the PHY device to avoid lockups
	-- caused by violating timings
C:	process (clk, rstn)
	begin
		if rstn = '0' then
			RX_DATALatch <= "0000";
			RX_DVLatch <= '0';
			RX_CLKLatch <= '0';
		elsif clk'event and clk = '1' then
			RX_DATALatch <= RX_DATA;
			RX_DVLatch <= RX_DV;
			RX_CLKLatch <= RX_CLK;
		end if;
	end process;		-- end process C
end Ethernet_arch;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -