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

📄 ethernetsnd.vhd

📁 设计ip协议的vhdl实现
💻 VHD
📖 第 1 页 / 共 2 页
字号:
-------------------------------------------------------------------------------
-- ethernetsnd.vhd
--
-- Author(s):     Ashley Partis and Jorgen Peddersen
-- Created:       Jan 2001
-- Last Modified: Feb 2001
-- 
-- Sends frames to the PHY a nybble at a time to be sent over the network.
-- Any frame shorter that 46 bytes is forced to a length of 46 bytes and is
-- padded with whatever is currently in RAM at the time.  Sends both ARP and
-- IP frames.  The CRC is calculated as the bytes are sent and is sent at
-- the end.  Informs the layers above when it has transmitted their frame.
-- Pauses for over 12 bytes worth of data after each frame.
-- 
-------------------------------------------------------------------------------

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

entity ethernetSnd is
    port (
        clk: in STD_LOGIC;										-- clock
        rstn: in STD_LOGIC;										-- asynchronous active low reset
        complete: in STD_LOGIC;									-- RAM operation complete signal
        rdData: in STD_LOGIC_VECTOR (7 downto 0);				-- read data bus from the RAM
        newFrame: in STD_LOGIC;									-- send a new frame signal
        frameSize: in STD_LOGIC_VECTOR (10 downto 0);			-- size of the frame to send
        destinationMAC: in STD_LOGIC_VECTOR (47 downto 0);		-- target MAC of the frame
        frameType: in STD_LOGIC;								-- type of the frame to send (ARP or IP)
        TX_CLK: in STD_LOGIC;									-- transmit clock from the PHY
        TX_EN: out STD_LOGIC;									-- transmit enable line to the PHY
        TX_DATA: buffer STD_LOGIC_VECTOR (3 downto 0);			-- transmit data line to the PHY
        rdRAM: out STD_LOGIC;									-- read RAM signal
        rdAddr: out STD_LOGIC_VECTOR (18 downto 0);				-- read address bus to the RAM
        frameSent: out STD_LOGIC      							-- frame sent signal to ARP
    );
end ethernetSnd;

architecture ethernetSnd_arch of ethernetSnd is

-- declaration of the CRC generator component
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;

-- state definitions
type STATETYPE is (stIdle, stWaitForTransCLKHI, stWaitForTransCLKLO, stSendPreambleCLKHI, stSendPreambleCLKLO, 
			stSendFrameHeaderCLKHI, stSendFrameHeaderCLKLO, stReadData,	stSendFrameHiNybbleCLKHI,
			stSendFrameHiNybbleCLKLO, stSendFrameLoNybbleCLKHI, stSendFrameLoNybbleCLKLO, stSetCRCHI, 
			stSetCRCLO, stLineWait);
signal presState: STATETYPE;
signal nextState: STATETYPE;

-- frame length buffer
signal frameLen: STD_LOGIC_VECTOR (10 downto 0);
signal nextFrameLen: STD_LOGIC_VECTOR (10 downto 0);

-- type of frame to send buffer (ARP or IP)
signal frameTypeLatch: STD_LOGIC;
signal nextFrameTypeLatch: STD_LOGIC;

-- destination MAC address latch signal and buffer
signal latchDestinationMAC: STD_LOGIC;
signal destinationMAClatch: STD_LOGIC_VECTOR (47 downto 0);

-- counter to send the data and headers
-- and signals to increment and reset the counter
signal cnt: STD_LOGIC_VECTOR (10 downto 0);
signal incCnt: STD_LOGIC;
signal rstCnt: STD_LOGIC;

-- signal to make TX_DATA a buffer
signal next_TX_DATA: STD_LOGIC_VECTOR (3 downto 0);

-- signal and buffer to latch and hold the data read from RAM
signal latchRdData: STD_LOGIC;
signal rdLatch: STD_LOGIC_VECTOR (7 downto 0);

-- buffer to avoid problems with the asynchronous input clock (to us) from the PHY
signal TX_CLKBuf: STD_LOGIC;

-- counter to create the required pause on the line after we've transmitted a frame
-- as well as an overflow signal and a reset signal
signal linePause: STD_LOGIC_VECTOR (10 downto 0);
signal rstLinePause: STD_LOGIC;
signal linePauseOverflow: STD_LOGIC;

-- signals for the CRC generator
signal CRC: STD_LOGIC_VECTOR (31 downto 0);
signal newCRCByte: STD_LOGIC;
signal CRCByte: STD_LOGIC_VECTOR (7 downto 0);
signal CRCNewFrame: STD_LOGIC;

begin

	-- instantiate the CRC generator
	EthernetSendCRCGen : crcGenerator port map (
    	clk => clk,
        rstn => rstn,
        newFrame => CRCnewFrame,
        newByte => newCRCByte,
        inByte => CRCByte,
        crcValid => open,
        crcValue => CRC
    );
	
	-- main clocked process
	process (clk, rstn)
	begin
		-- set up the asynchronous active low reset by defaulting to the idle state
		if rstn = '0' then
			presState <= stIdle;
		elsif clk'event and clk = '1' then
			presState <= nextState;
			-- set up frameLen, frameTypeLatch and TX_DATA buffers with their next signals
			frameLen <= nextFrameLen;
			frameTypeLatch <= nextFrameTypeLatch;
			TX_DATA <= next_TX_DATA;
			-- latch data from RAM when reads are finished
			if latchRdData = '1' then
				rdLatch <= rdData;
			end if;
			-- latch the destinationMAC input to remembed where to send the frame
			if latchDestinationMAC = '1' then
				destinationMACLatch <= destinationMAC;
			end if;
			-- increment and reset the counter synchronously to avoid race conditions
			if incCnt = '1' then
				cnt <= cnt + 1;
			elsif rstCnt = '1' then
				cnt <= (others => '0');
			end if;
			-- reset the pause counter (which creates a pause of 12 octets on the line) to
			-- 1, which will then automatically increment till it reaches 0 again
			-- set the overflow signal when it is at 0
			if rstLinePause = '1' then
				linePause <= "000" & x"01";
				linePauseOverflow <= '0';
			elsif linePause = 0 then
				linePauseOverflow <= '1';
			else
				linePause <= linePause + 1;
				linePauseOverflow <= '0';
			end if;
			-- buffer the asynchronous clock input from the PHY to avoid timing violations,
			-- which would result in potential lockups
			if TX_CLK = '1' then
				TX_CLKBuf <= '1';
			else
				TX_CLKBuf <= '0';
			end if;
		end if;
	end process;

	-- main FSM process
	process (presState, newFrame, frameLen, CRC, TX_DATA, rdLatch, complete, frameSize, 
			TX_CLKBuf, cnt, destinationMACLatch, frameTypeLatch, frameType, linePauseOverflow)
	begin
		-- signal defaults
		rstcnt <= '0';
		incCnt <= '0';
		-- default transmit enable to high, as it only needs to be low in few states
		TX_EN <= '1';
		-- remember the previous value of frameLen, TX_DATA and frameTypeLatch by default
		nextFrameLen <= frameLen;
		next_TX_DATA <= TX_DATA;
		nextFrameTypeLatch <= frameTypeLatch;
		latchDestinationMAC <= '0';
		rdRam <= '0';
		rdAddr <= (others => '0');
		latchRdData <= '0';
		newCRCByte <= '0';
		CRCByte <= (others => '0');
		CRCNewFrame <= '0';
		rstLinePause <= '0';
		frameSent <= '0';
		
		case presState is
			when stIdle =>
				-- wait for a new frame to be ready to transmit
				if newFrame = '0' then
					nextState <= stIdle;
					rstCnt <= '1';
					TX_EN <= '0';		-- keep transmit enable low till we are ready to transmit
				else
					nextState <= stWaitForTransCLKLO;
					-- if the frame size is less than the minimum size of 46 bytes (for ethernet),
					-- then set the frame size to 46
					if frameSize > 46 then
						nextFrameLen <= frameSize;
					else
						nextFrameLen <= "000" & x"2E";
					end if;
					-- reset the CRC generator
					CRCNewFrame <= '1';
					TX_EN <= '0';
					-- latch the destination MAC and frame type inputs
					latchDestinationMAC <= '1';
					nextFrameTypeLatch <= frameType;
				end if;
				
			when stWaitForTransCLKLO =>
				-- wait for TX_CLKBuf to hit a falling edge before we start
				-- make sure it is high before we continue
				-- this is because the PHY latches the data on the rising edge, so 
				-- we set it on the falling edge
				-- still keep transmit enable low until we assert the first nybble to send
				if TX_CLKBuf = '0' then
					nextState <= stWaitForTransCLKLO;
					TX_EN <= '0';
				else
					nextState <= stWaitForTransCLKHI;
					TX_EN <= '0';
				end if;

			when stWaitForTransCLKHI =>
				-- wait for TX_CLKBuf to hit a falling edge before we start
				-- allow TX_EN to go high
				if TX_CLKBuf = '0' then
					nextState <= stSendPreambleCLKLO;
					-- set the lower nybble of the first byte of the preamble
					next_TX_DATA <= x"5";
					incCnt <= '1';
				-- wait while TX_CLKBuf is still high
				else
					nextState <= stWaitForTransCLKHI;
					TX_EN <= '0';
				end if;
				
			when stSendPreambleCLKLO =>
				-- wait for another falling edge
				-- do nothing in TX_CLKBuf low time and on the rising edge
				if TX_CLKBuf = '0' then
					nextState <= stSendPreambleCLKLO;
				else
					nextState <= stSendPreambleCLKHI;
				end if;
			
			when stSendPreambleCLKHI =>
				-- when there's a falling edge, set the data
				if TX_CLKBuf = '0' then
					-- send the last nybble of the preamble
					-- we've finished the preamble, so start sending the headers
					if cnt = 15 then
						next_TX_DATA <= x"D";
						nextState <= stSendFrameHeaderCLKLO;
						rstCnt <= '1';
					-- send a preamble of alternating 1s and 0s, low bit gets sent first
					-- so the preamble consists of a series of 7 "5"s followed by "5D" - 
					-- the last two ones in the D tell it that the frame is about to follow
					else
						next_TX_DATA <= x"5";
						nextState <= stSendPreambleCLKLO;
						incCnt <= '1';
					end if;
				-- wait for the falling edge of TX_CLKBuf
				else
					nextState <= stSendPreambleCLKHI;
				end if;
			
			when stSendFrameHeaderCLKLO =>
				-- wait for another falling edge
				-- do nothing in TX_CLKBuf low time
				if TX_CLKBuf = '0' then
					nextState <= stSendFrameHeaderCLKLO;
				else
					nextState <= stSendFrameHeaderCLKHI;
				end if;
			
			when stSendFrameHeaderCLKHI =>
				-- if we've seen a falling edge, then set the next nybble of the header to send
				if TX_CLKBuf = '0' then
					-- if we've sent all 28 nybbles of the header, then start sending the data
					-- otherwise, keep sending the header
					if cnt (4 downto 0) = '1' & x"B" then			
						nextState <= stReadData;
						rstCnt <= '1';
						incCnt <= '0';
					else
						nextState <= stSendFrameHeaderCLKLO;
						incCnt <= '1';
					end if;
					-- set the headers according to cnt, a nybble at a time
					case cnt (4 downto 0) is
						-- first byte of destination MAC address (low nybble first)

⌨️ 快捷键说明

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