📄 ethernetsnd.vhd
字号:
-------------------------------------------------------------------------------
-- 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 + -