数据发送的整个过程由一个状态机控制完成。数据发送过程主要包括以下状态。
• StateIdle:系统复位后的状态。
• StatePreamble:添加报头。
• StateData0:通知主机接口提供下一个要传输的数据。
• StateData1:发送数据。
• StateFCS:根据要发送的数据产生校验序列。
• StateDefer:延迟。
• StateIPG:帧间隔。
• StatePAD:当发送数据比数据帧最小值(46 字节)小时,补充“0”直到满足帧数据格式的要求。发送数据的整个流程如图 10-10 所示。
(1)系统复位后首先进入 StateIdle 状态;上层协议通过主机接口设置 TxStartFrm 信号要求开始数据传输,并同时提供需要传输的第一个数据,系统进入 StatePreamble 状态。
(2)在 StatePreamble 状态,添加报头,同时通知外部 PHY 芯片传输即将开始;在报头和帧起始分隔符(SFD)传输完成后,系统进入 StateData0 状态,同时设置 TxUsedData 信号通知主机接口提供下一个数据;在数据的低 4 位数据发送完成后,系统进入 StateData1 状态;系统开始传输数据的高 4 位,系统开始在 StateData0 状态和 StateData1 状态之间切换,直到主机接口设置 TxEndFrm 信号通知数据传输结束。
(3)如果发送数据的大小大于帧数据格式要求的最小值,并且设置产生 CRC 校验序列,系统将进入 StateFCS 状态,并产生 CRC 校验序列;然后进入 StateDefer 状态,产生一定的延迟;接下来进入 StateIPG 状态,实现需要的帧间隔时间;最后回到 StateIdle 状态;如果发送数据的大小大于帧数据格式要求的最小值,并且设置不产生 CRC 校验序列,系统将进入StateDefer 状态,产生一定的延迟。
(4)接下来进入 StateIPG 状态,实现需要的帧间隔时间;最后回到 StateIdle 状态;如果发送数据的大小小于帧数据格式要求的最小值,并且设置数据长度满足帧数据格式的最小值要求并产生 CRC 校验序列,系统将进入 StatePAD 状态,补充数据长度直到满足帧数据格式的要求(46 个字节);然后进入 StateFCS 状态,并产生 CRC 校验序列;随后进入 StateDefer 状态,产生一定的延迟;接下来进入 StateIPG 状态,实现需要的帧间隔时间。最后回到 StateIdle状态。
(5)最后回到 StateIdle 状态;如果发送数据的大小小于帧数据格式要求的最小值,并且设置产生 CRC 校验序列但不要求数据长度满足最小值要求,系统将进入 StateFCS 状态,并产生 CRC 校验序列;随后进入 StateDefer 状态,产生一定的延迟;接下来进入 StateIPG 状态,实现需要的帧间隔时间;最后回到 StateIdle 状态;如果发送数据的大小小于帧数据格式要求的最小值,并且设置不产生 CRC 校验序列但不要求数据长度满足最小值要求,系统将进入StateDefer 状态,产生一定的延迟;接下来进入 StateIPG 状态,实现需要的帧间隔时间;最后回到 StateIdle 状态。
发送数据状态机的主要代码如下:
- `include "timescale.v"
- module eth_txstatem (MTxClk, Reset, ExcessiveDefer, CarrierSense, NibCnt, IPGT, IPGR1,
- IPGR2, FullD, TxStartFrm, TxEndFrm, TxUnderRun, Collision, UnderRun, StartTxDone, TooBig,
- NibCntEq7, NibCntEq15, MaxFrame, Pad, CrcEn, NibbleMinFl, RandomEq0, ColWindow,
- RetryMax, NoBckof, RandomEqByteCnt, StateIdle, StateIPG, StatePreamble, StateData, StatePAD,
- StateFCS, StateJam, StateJam_q, StateBackOff, StateDefer, StartFCS, StartJam, StartBackoff,
- StartDefer, DeferIndication, StartPreamble, StartData, StartIPG );
- parameter Tp = 1;
- //输入输出信号
- input MTxClk;
- input Reset;
- output StartIPG;
- //连线与寄存器
- wire StartIdle; //下一个时钟将进入 Idle 状态
- wire StartPAD; // 下一个时钟将进入 PAD 状态
- ……
- reg Rule1;
- //定义下一个状态
- assign StartIPG = StateDefer & ~ExcessiveDefer & ~CarrierSense;
- assign StartIdle = StateIPG & (Rule1 & NibCnt[6:0] >= IPGT | ~Rule1 & NibCnt[6:0] >= IPGR2);
- assign StartPreamble = StateIdle & TxStartFrm & ~CarrierSense;
- assign StartData[0] = ~Collision & (StatePreamble & NibCntEq15 | StateData[1] & ~TxEndFrm);
- assign StartData[1] = ~Collision & StateData[0] & ~TxUnderRun & ~MaxFrame;
- assign StartPAD = ~Collision & StateData[1] & TxEndFrm & Pad & ~NibbleMinFl;
- assign StartFCS = ~Collision & StateData[1] & TxEndFrm & (~Pad | Pad & NibbleMinFl) & CrcEn
- | ~Collision & StatePAD & NibbleMinFl & CrcEn;
- assign StartJam = (Collision | UnderRun) & ((StatePreamble & NibCntEq15) | (|StateData[1:0])
- | StatePAD | StateFCS);
- assign StartBackoff = StateJam & ~RandomEq0 & ColWindow & ~RetryMax & NibCntEq7 & ~NoBckof;
- assign StartDefer = StateIPG & ~Rule1 & CarrierSense & NibCnt[6:0] <= IPGR1 & NibCnt[6:0] !=
- IPGR2
- | StateIdle & CarrierSense
- | StateJam & NibCntEq7 & (NoBckof | RandomEq0 | ~ColWindow | RetryMax)
- | StateBackOff & (TxUnderRun | RandomEqByteCnt)
- | StartTxDone | TooBig;
- assign DeferIndication = StateIdle & CarrierSense;
- //发送数据状态机
- always @ (posedge MTxClk or posedge Reset)
- begin
- if(Reset)
- begin
- StateIPG <= #Tp 1'b0;
- StateIdle <= #Tp 1'b0;
- StatePreamble <= #Tp 1'b0;
- StateData[1:0] <= #Tp 2'b0;
- StatePAD <= #Tp 1'b0;
- StateFCS <= #Tp 1'b0;
- StateJam <= #Tp 1'b0;
- StateJam_q <= #Tp 1'b0;
- StateBackOff <= #Tp 1'b0;
- StateDefer <= #Tp 1'b1;
- end
- else
- begin
- StateData[1:0] <= #Tp StartData[1:0];
- StateJam_q <= #Tp StateJam;
- if(StartDefer | StartIdle)
- StateIPG <= #Tp 1'b0;
- else
- if(StartIPG)
- StateIPG <= #Tp 1'b1;
- if(StartDefer | StartPreamble)
- StateIdle <= #Tp 1'b0;
- else
- if(StartIdle)
- StateIdle <= #Tp 1'b1;
- if(StartData[0] | StartJam)
- StatePreamble <= #Tp 1'b0;
- else
- if(StartPreamble)
- StatePreamble <= #Tp 1'b1;
- if(StartFCS | StartJam)
- StatePAD <= #Tp 1'b0;
- else
- if(StartPAD)
- StatePAD <= #Tp 1'b1;
- if(StartJam | StartDefer)
- StateFCS <= #Tp 1'b0;
- else
- if(StartFCS)
- StateFCS <= #Tp 1'b1;
- if(StartBackoff | StartDefer)
- StateJam <= #Tp 1'b0;
- else
- if(StartJam)
- StateJam <= #Tp 1'b1;
- if(StartDefer)
- StateBackOff <= #Tp 1'b0;
- else
- if(StartBackoff)
- StateBackOff <= #Tp 1'b1;
- if(StartIPG)
- StateDefer <= #Tp 1'b0;
- else
- if(StartDefer)
- StateDefer <= #Tp 1'b1;
- end
- end
- //定义帧间隔
- always @ (posedge MTxClk or posedge Reset)
- begin
- if(Reset)
- Rule1 <= #Tp 1'b0;
- else
- begin
- if(StateIdle | StateBackOff)
- Rule1 <= #Tp 1'b0;
- else
- if(StatePreamble | FullD)
- Rule1 <= #Tp 1'b1;
- end
- end
- endmodule