基于FPGA的千兆以太网的实现

一、简介

  一般来说,我们要将 FPGA 板子上采集的数据传输到 PC 端有多种方式,如  UART、USB、千兆网、光纤、PCIe等手段,感觉还是千兆网传输的性价比最高,实现上不是很难,传输速率也比较快。以太网的分类有标准以太网(10Mbit/s),快速以太网(100Mbit/s)和千兆以太网(1000Mbit/s)。随着以太网技术的飞速发展,市场上也出现了万兆以太网(10Gbit/s),它扩展了IEEE802.3协议和MAC规范,使其技术支持 10Gbit/s的传输速率。然而在实际应用中,标准以太网和快速以太网已经能够满足我们的日常需求,对通信速率较高的场合才会用到千兆以太网。

二、对以太网数据包格式的协议一一讲解

  由上图可知,要发送的数据是加载在UDP协议中,UDP协议又是加载在IP协议中,IP协议加载在MAC协议中,是一种层层包含的关系,下面对MAC、IP、UDP协议一一详细讲解。

  1、MAC帧格式

     1)前导码(Preamble):实现底层数据的正确阐述,物理层使用 7 个字节同步码(0和1交替(55_55_55_55_55_55_55))实现数据的同步。

     2)帧起始界定符:一个字节,固定为(0xd5)来表示一帧的开始,即后面紧跟着传输的就是以太网的帧头。

     3)目的MAC地址:六个字节,表明帧的接受者(电脑的MAC地址)。

     4)源MAC地址:六个字节,表明帧的发送者(板子的MAC地址,一般为自己设置一个地址)。

     5)长度/类型:两个字节,长度/类型具有两个意义,当着连个字节的值小于1536(十六进制为0x0600)时,代表该以太网中数据段的长度;如果这两个字节的值大于1536,则表示该以太网中的数据属于哪个上层协议,例如0x0800代表IP协议、0x0806代表ARP协议等。

     6)数据:以太网中的数据段长度最小 46 字节,最大1500个字节。最大值1500称为以太网的最大传输单元,之所以闲置最大传输单元是因为在多个计算机的数据帧排队等待传输时,如果某个数据帧太大的话,那么其他数据帧等待的时间就会加长,导致体验变差。

     7)帧校验序列(FCS):四个字节,为了保证数据的正确传输,在数据的尾部加入了4个字节的循环冗余校验码(CRC校验)来检测数据是否传输错误。CRC数据校验从以太网帧头开始即不包含前导码和帧起始界定符。

    值得注意的地方:以太网相邻两帧之间的时间间隔,即帧间隙(IFG)。帧间隙的时间就是网络设备和组件在接收一帧之后,需要短暂的时间来恢复并未接收下一帧做准备的时间。不管是10M/100M/1000M的以太网,两帧之间最少要有96bit time,IFG的最小间隔时间计算方法如下:

    10Mbit/s 最小时间为 :96 * 100ns = 9600ns;

    100Mbit/s最小时间为 :96 *10ns = 960ns;

    1000Mbit/s最小时间为:96 * 1ns = 96ns;

  2、IP数据报格式

    IP数据报前 20 个字节是固定的,IP首部的每一行以32位(4个字节)为单位。

    1)版本:4位IP版本号,设置为0x4时,表示 IPv4,设置为0x6,表示IPv6,目前使用较多的IP协议版本号是IPv4。

    2)首部长度:4位首部长度,表示IP首部一共有多少个32位。在没有可选字段时,IP首部长度为20个字节,因此首部长度的值为0x5。

    3)服务类型:8位服务类型,一般设置为全零,8'h00。

    4)总长度:16位,IP首部长度 + UDP首部长度 + 数据部分的长度(如:IP首部长度固定为 20个字节 + UDP首部长度为 8个字节 + 数据部分的字节数)。

    5)标识:16位,用来标识主句发送的每一份数据报,通常每发一份报文它的值就会加1。(也可以设置为0)

    6)标志字段:3位,第一位为保留为;第二位表示禁止分片(1表示不分片,0表示分片);第三位表示更多分片。(也可以设置为0)

    7)片偏移:13位,在接收方进行数据报重组时用来标识分片的顺序。(也可以设置为0)

    8)生存时间:8位,防止丢失的数据包在无休止的传播,一般被设置为64或者128。

    9)协议:8位,表示此数据包所携带上层数据使用的协议类型,ICMP为1,TCP为6,UDP为17。

    10)首部校验和:16位,该字段只校验数据报的首部,不包含数据部分,校验IP数据报头部是否被破坏、篡改和丢失等。

    11)源IP地址:32位,即发送端的IP地址(板子的IP地址),一般为自己设置,如192.168.0.2。

    12)目的IP地址:32位,即接收端的IP地址(电脑的IP地址),也可以自己设置,如192.168.0.3。在上板实验时,需将电脑上的IP改为自己设置的那个IP地址。

    IP首部校验和的计算方法:

      (1)将16位检核和字段置为0,然后将IP首部按照16位分成多个单元;

      (2)将各个单元采用反码加法运算(即高位溢出会加到低位,通常的补码运算时直接丢掉溢出的高位);

      (3)此时仍然可能出现进位的情况,将得到的和再次分成高16位和低16位进行累加;

      (4)最后将得到的和的反码填入校验和字段;

      如:0 - 31:  45_00_00_32

        0 - 31:  00_00_00_00

        0 - 31:  40_11_00_00

        0 - 31 :  c0_a8_00_02

        0 - 31 :  c0_a8_00_03

        (a)0x4500 + 0x0032 +0x0000 +0x0000 +0x4011 +0x0000 + 0xc0a8 +0x 0002 + 0xc0a8 +0x0003 = 0x20698

        (b)0x0002 + 0x0698 = 0x0698

        (c)0x0000 + 0x0698 = 0x0698

        (d)ip_checksm = ~0x0698 = 0xf967

  3、UDP协议

     1)源端口号:16位发送端端口号,用于区分不同服务的端口。

     2)目的端口号:16位接收端端口号。

     3)UDP长度:16位UDP长度,包含UDP首部长度 + 数据长度,单位是字节;(如,UDP首部长度 8 个字节 + 传输的数据字段的字节数)

     4)UDP校验和:16位UDP校验和,在大多数情况下设置 0x0000

三、接口时序

    1、接口信号介绍

    (1)GTX_CLK:发送时钟信号,由FPGA中的PLL产生发送给以太网芯片,频率为 125MHz;

    (2)TX_EN:发送数据使能信号,高电平有效;

    (3)TX_ER:发送错误信号,高电平有效,用以破坏数据包的发送,这个信号有些博文中设置为零,但是有条件的话还是设置一下,这个信号挺有用的;

    (4)TXD:发送数据线,FPGA通过该数据线将需要发送的数据依次发送给PHY芯片;

    (5)RX_CLK:由PHY芯片产生,125MHz;

    (6)RX_EN:接收使能信号,高电平有效;

    (7)RX_ER:接收错误信号,高电平有效;

    (8)RXD:接收数据线,FPGA通过该数据线从PHY接收数据;

    2、接口时序(仅列出发送时序)

     这个GMII模式的千兆网的发送时序,在TX_EN为高电平时,在时钟的上升沿发送数据给以太网芯片,在千兆网中,发送数据是先发高位,再发低位;

   3、按照上述的协议,发送数据实现协议的顺序如下:

    (1)前导码 + 帧定界符:64'h55_55_55_55_55_55_55_d5;

    (2)MAC首部:des_mac:48'hff_ff_ff_ff_ff_ff;src_mac:48'h00_0a_35_01_fe_c0;type_len:16'h08_00;

    (3)IP首部:0~31:45_00_00_(ip_total_len)

           :0~31:00_00_00_00(注:这一列数据要慎重考虑,可以设为零,也可以按照正经要求来填写)

           :0~31:40_11_(ip_checksum)

           :0~31:c0_a8_00_02

           :0~31:c0_a8_00_03

    (4)UDP首部:0~31:13_88_17_70(这里源端口和目的端口分别为5000,6000)

           :0~31:(udp_len)_00_00

    (5)数据部分,自定义;

    (6)CRC校验,我用的是一个普遍适用的CRC校验,代码会在下文给出;

四、代码实现(仅做参考用)

  1、硬件平台:MP801

  2、软件环境:Quartus II 13.0

  3、RTL视图:

   注:以太网芯片为 RTL8211EG;以太网复位是高电平有效;gtx_clk这个时钟信号是由FPGA通过PLL倍频到 125MHz;

  4、实现源码:

  顶层模块:gmii_test.v

 1 // *********************************************************************************
 2 // Project Name : udpsend
 3 // Email             : 
 4 // Create Time    : 2020/07/06 15:21
 5 // Module Name  : udpsend
 6 // editor         : qing
 7 // Version         : Rev1.0.0
 8 // *********************************************************************************
 9 
10 module gmii_test(
11     input                    sclk            ,
12     
13     output                phy_rst_n,
14     output    [7:0]               tx_data            ,
15     output                tx_en        ,
16     output                tx_er        ,
17     output                gtx_clk    
18 );
19 
20 
21 
22 pll u0 (
23     .inclk0 (sclk    ),
24     .c0     (gtx_clk )
25     );
26     
27 
28 
29 udp_send u2(
30         .gtx_clk        (gtx_clk        ),                   //GMII发送的时钟信号
31         .tx_en        (tx_en        ),                  //GMII数据使能信号
32         .tx_er        (tx_er        ),                  //GMII发送错误信号
33         .tx_data        (tx_data        ),
34         .phy_rst_n        (phy_rst_n         )
35 );
36 
37 
38 
39 endmodule
40    
View Code

  子模块:udp_send.v

  1 // *********************************************************************************
  2 // Project Name : gmii_tx_test
  3 // Email        : 
  4 // Create Time  : 2020/07/06 19:15
  5 // Module Name  : udp_send
  6 // editor        : qing
  7 // Version        : Rev1.0.0
  8 // *********************************************************************************
  9 
 10 module udp_send(
 11         input                    gtx_clk        ,
 12 
 13         output    reg                tx_en        ,
 14         output    reg                tx_er        ,
 15         output    reg[7:0]        tx_data        ,
 16         output                    phy_rst_n
 17     );
 18 
 19 //========================================================================
 20 // =========== Define Parameter and Internal signals =========== 
 21 //========================================================================/
 22 
 23 wire            [15:0]        data_length        ;  // 数据字段的长度
 24 wire            [15:0]        ip_total_length ;  // ip首部 + udp首部 + 数据字段的长度
 25 
 26 reg                [3:0]        state             ;
 27 
 28 reg        [31:0]    ip_head        [6:0]            ;  // ip首部 + udp首部
 29 reg        [ 7:0]    premeble     [7:0]            ;
 30 reg        [ 7:0]  mac_addr    [13:0]            ;  // mac 首部
 31 
 32 reg        [ 4:0]  i,j                         ;
 33 
 34 reg        [31:0]  check_buff                    ;
 35 reg     [31:0]    delay_cnt                    ;
 36 reg     [15:0]    cnt_data                    ;
 37 
 38 reg                crcen                        ;
 39 reg                crcre                         ;
 40 wire     [31:0]    crc                         ;
 41 wire    [31:0]    CrcNext                     ;
 42 
 43 
 44 parameter         idle         =    4'b0000        ;
 45 parameter         start       =   4'b0001        ;
 46 parameter         make         =    4'b0010     ;
 47 parameter         send55      =   4'b0011        ;
 48 parameter         sendmac     =     4'b0100     ;
 49 parameter         sendhead    =   4'b0101     ;
 50 parameter         senddata    =    4'b0110     ;
 51 parameter         sendcrc     =   4'b0111     ;
 52 
 53 //=============================================================================
 54 //****************************     Main Code    *******************************
 55 //=============================================================================
 56 
 57 crc u0(
 58     .Clk         (gtx_clk    ), 
 59     .Reset        (crcre        ), 
 60     .Data_in    (tx_data    ), 
 61     .Enable        (crcen      ), 
 62     .Crc         (crc           ),
 63     .CrcNext    (CrcNext    )
 64     );
 65 
 66 assign data_length = 16'd33 ;
 67 assign ip_total_length = 16'd28 + data_length;
 68 assign phy_rst_n = 1'b1;
 69 
 70 always @(posedge gtx_clk ) begin
 71     premeble[0]    <= 8'h55;
 72     premeble[1]    <= 8'h55;
 73     premeble[2]    <= 8'h55;
 74     premeble[3]    <= 8'h55;
 75     premeble[4]    <= 8'h55;
 76     premeble[5]    <= 8'h55;
 77     premeble[6]    <= 8'h55;
 78     premeble[7]    <= 8'hd5;
 79 
 80     mac_addr[0] <= 8'hff;
 81     mac_addr[1] <= 8'hff;
 82     mac_addr[2] <= 8'hff;
 83     mac_addr[3] <= 8'hff;
 84     mac_addr[4] <= 8'hff;
 85     mac_addr[5] <= 8'hff;
 86 
 87     mac_addr[6] <= 8'h00;
 88     mac_addr[7] <= 8'h0a;
 89     mac_addr[8] <= 8'h35;
 90     mac_addr[9] <= 8'h01;
 91     mac_addr[10] <= 8'hfe;
 92     mac_addr[11] <= 8'hc0;
 93 
 94     mac_addr[12] <= 8'h08;
 95     mac_addr[13] <= 8'h00;
 96 end
 97 
 98 initial
 99     begin
100         //state <= idle;
101         
102         delay_cnt <= 0;
103         check_buff <= 32'h00000000;
104     end
105 
106 always @(posedge gtx_clk) begin
107     //state <= idle;
108     case(state)
109         idle:begin
110             tx_er <= 1'b0;
111             tx_en <= 1'b0;
112 
113             crcen <= 1'b0;
114             crcre <= 1'b1;
115             i <= 0;
116             j <= 0;
117             tx_data <= 8'd0;
118             cnt_data <= 0;
119 
120             if(delay_cnt == 32'h1000) begin  // 04000000
121                 state <= start;
122                 delay_cnt <= 0;
123             end
124             else
125                 delay_cnt <= delay_cnt + 1'b1;
126         end
127 
128         start:begin
129             ip_head[0] <= {16'h4500,ip_total_length};
130             ip_head[1][31:16] <= ip_head[1][31:16] + 1'b1;  //ip_head[1][31:16] + 1'b1
131             ip_head[1][15:0] <= 16'h0000;  // 4000
132             ip_head[2] <= 32'h80110000;
133             ip_head[3] <= 32'hc0a80002;
134             ip_head[4] <= 32'hc0a80003;
135             ip_head[5] <= 32'h13881770;
136             ip_head[6] <= {data_length,16'h0000};
137             state <= make; 
138         end
139 
140         make:begin
141             if(i==0) begin
142                 check_buff <= (ip_head[0][15:0] + ip_head[0][31:16] + ip_head[1][15:0] + ip_head[1][31:16]
143                              +ip_head[2][15:0] + ip_head[2][31:16] + ip_head[3][15:0] + ip_head[3][31:16]
144                              +ip_head[4][15:0] + ip_head[4][31:16] );
145                 i <= i + 1'b1;
146             end
147             else if(i == 1) begin
148                 check_buff[15:0] <= check_buff[31:16] + check_buff[15:0];
149                 i <= i + 1'b1;
150             end
151             else begin
152                 ip_head[2][15:0] <= ~check_buff[15:0];
153                 i <= 0;
154                 state <= send55;
155             end
156         end
157 
158         send55:begin
159             tx_en <= 1'b1;
160             crcre <= 1'b1;
161             if(i == 7) begin
162                 tx_data[7:0] <= premeble[i][7:0];
163                 i <= 0;
164                 state <= sendmac;
165             end
166             else begin
167                 tx_data[7:0] <= premeble[i][7:0];
168                 i <= i + 1'b1;
169             end
170         end
171 
172         sendmac:begin
173             crcen <= 1'b1;
174             crcre <= 1'b0;
175             if(i == 13) begin
176                 tx_data[7:0] <= mac_addr[i][7:0];
177                 i <= 0;
178                 state <= sendhead;
179             end
180             else begin
181                 tx_data[7:0] <= mac_addr[i][7:0];
182                 i <= i + 1'b1;
183             end
184         end
185 
186         sendhead:begin
187             if(j == 6) begin
188                 if(i == 0) begin
189                     tx_data[7:0] <= ip_head[j][31:24];
190                     i <= i + 1'b1;
191                 end
192                 else if(i == 1)begin
193                     tx_data[7:0] <= ip_head[j][23:16];
194                     i <= i + 1'b1;
195                 end
196                 else if(i == 2)begin
197                     tx_data[7:0] <= ip_head[j][15:8];
198                     i <= i + 1'b1;
199                 end
200                 else if(i == 3) begin
201                     tx_data <= ip_head[j][7:0];
202                     i <= 0;
203                     j <= 0;
204                     state <= senddata;
205                 end
206                 else
207                     tx_er <= 1'b1;
208             end
209             else begin
210                 if(i == 0) begin
211                     tx_data[7:0] <= ip_head[j][31:24];
212                     i <= i + 1'b1;
213                 end
214                 else if(i == 1) begin
215                     tx_data <= ip_head[j][23:16];
216                     i <= i + 1'b1;
217                 end
218                 else if(i == 2) begin
219                     tx_data <= ip_head[j][15:8];
220                     i <= i + 1'b1;
221                 end
222                 else if(i == 3) begin
223                     tx_data <= ip_head[j][7:0];
224                     i <= 0;
225                     j <= j + 1'b1;
226                 end
227                 else
228                     tx_er <= 1'b1;
229             end
230         end
231 
232         senddata:begin
233             if(cnt_data == data_length - 1) begin
234                 cnt_data <= 0;
235                 state <= sendcrc;
236                 tx_data <= 8'haa;
237             end
238             else begin
239                 cnt_data <= cnt_data + 1'b1;
240                 state <= senddata;
241             end
242             case(cnt_data)
243                 0:tx_data <= 8'hff;
244                 1:tx_data <= 8'h01;
245                 2:tx_data <= 8'h02;
246                 3:tx_data <= 8'h03;
247                 4:tx_data <= 8'h04;
248                 5:tx_data <= 8'h05;
249                 6:tx_data <= 8'h06;
250                 7:tx_data <= 8'h07;
251                 8:tx_data <= 8'h08;
252                 9:tx_data <= 8'h09;
253                 10:tx_data <= 8'h0a;
254                 11:tx_data <= 8'h0b;
255                 12:tx_data <= 8'h0c;
256                 13:tx_data <= 8'h0d;
257                 14:tx_data <= 8'h0e;
258                 15:tx_data <= 8'h0f;
259                 16:tx_data <= 8'hf0;
260                 17:tx_data <= 8'hf1;
261                 18:tx_data <= 8'hf2;
262                 19:tx_data <= 8'hf3;
263                 20:tx_data <= 8'hf4;
264                 21:tx_data <= 8'hf5;
265                 22:tx_data <= 8'hf6;
266                 23:tx_data <= 8'hf7;
267                 24:tx_data <= 8'hf8;
268                 25:tx_data <= 8'hf9;
269                 26:tx_data <= 8'hfa;
270                 27:tx_data <= 8'hfb;
271                 28:tx_data <= 8'hfc;
272                 29:tx_data <= 8'hfd;
273                 30:tx_data <= 8'hfe;
274                 31:tx_data <= 8'h11;
275                 32:tx_data <= 8'h22;
276                 default:tx_data <= 8'hff;
277             endcase
278         end
279 
280         sendcrc:begin
281             crcen <= 1'b0;
282             if(i == 0) begin
283                 tx_data[7:0] <= {~crc[24], ~crc[25], ~crc[26], ~crc[27], ~crc[28], ~crc[29], ~crc[30], ~crc[31]};
284                 i <= i + 1'b1; 
285             end
286             else begin
287                 if(i == 1) begin
288                     tx_data[7:0] <= {~crc[16], ~crc[17], ~crc[18], ~crc[19], ~crc[20], ~crc[21], ~crc[22], ~crc[23]};
289                     i <= i + 1'b1;
290                 end
291                 else if(i == 2) begin
292                     tx_data[7:0] <= {~crc[8], ~crc[9], ~crc[10], ~crc[11], ~crc[12], ~crc[13], ~crc[14], ~crc[15]};
293                     i <= i + 1'b1;
294                 end
295                 else if(i == 3) begin
296                     tx_data[7:0] <= {~crc[0], ~crc[1], ~crc[2], ~crc[3], ~crc[4], ~crc[5], ~crc[6], ~crc[7]};
297                     i <= 0;
298                     state <= idle;
299                 end
300                 else begin
301                     tx_er <= 1'b1;
302                 end
303             end
304         end
305         default:state <= idle;
306     endcase
307 end
308 
309 endmodule
View Code

  子模块:crc.v

 1 `timescale 1ns / 1ps
 2 /****************************************/
 3 //       CRC32数据校验模块          //
 4 /****************************************/
 5 module crc (Clk, Reset, Data_in, Enable, Crc,CrcNext);
 6 
 7 
 8 parameter Tp = 1;
 9 
10 input Clk;
11 input Reset;
12 input [7:0] Data_in;
13 
14 input Enable;
15 
16 output [31:0] Crc;
17 reg  [31:0] Crc;
18 
19 output [31:0] CrcNext;
20 
21 wire [7:0] Data;
22 
23 assign Data={Data_in[0],Data_in[1],Data_in[2],Data_in[3],Data_in[4],Data_in[5],Data_in[6],Data_in[7]};
24 
25 
26 assign CrcNext[0] = Crc[24] ^ Crc[30] ^ Data[0] ^ Data[6];
27 assign CrcNext[1] = Crc[24] ^ Crc[25] ^ Crc[30] ^ Crc[31] ^ Data[0] ^ Data[1] ^ Data[6] ^ Data[7];
28 assign CrcNext[2] = Crc[24] ^ Crc[25] ^ Crc[26] ^ Crc[30] ^ Crc[31] ^ Data[0] ^ Data[1] ^ Data[2] ^ Data[6] ^ Data[7];
29 assign CrcNext[3] = Crc[25] ^ Crc[26] ^ Crc[27] ^ Crc[31] ^ Data[1] ^ Data[2] ^ Data[3] ^ Data[7];
30 assign CrcNext[4] = Crc[24] ^ Crc[26] ^ Crc[27] ^ Crc[28] ^ Crc[30] ^ Data[0] ^ Data[2] ^ Data[3] ^ Data[4] ^ Data[6];
31 assign CrcNext[5] = Crc[24] ^ Crc[25] ^ Crc[27] ^ Crc[28] ^ Crc[29] ^ Crc[30] ^ Crc[31] ^ Data[0] ^ Data[1] ^ Data[3] ^ Data[4] ^ Data[5] ^ Data[6] ^ Data[7];
32 assign CrcNext[6] = Crc[25] ^ Crc[26] ^ Crc[28] ^ Crc[29] ^ Crc[30] ^ Crc[31] ^ Data[1] ^ Data[2] ^ Data[4] ^ Data[5] ^ Data[6] ^ Data[7];
33 assign CrcNext[7] = Crc[24] ^ Crc[26] ^ Crc[27] ^ Crc[29] ^ Crc[31] ^ Data[0] ^ Data[2] ^ Data[3] ^ Data[5] ^ Data[7];
34 assign CrcNext[8] = Crc[0] ^ Crc[24] ^ Crc[25] ^ Crc[27] ^ Crc[28] ^ Data[0] ^ Data[1] ^ Data[3] ^ Data[4];
35 assign CrcNext[9] = Crc[1] ^ Crc[25] ^ Crc[26] ^ Crc[28] ^ Crc[29] ^ Data[1] ^ Data[2] ^ Data[4] ^ Data[5];
36 assign CrcNext[10] = Crc[2] ^ Crc[24] ^ Crc[26] ^ Crc[27] ^ Crc[29] ^ Data[0] ^ Data[2] ^ Data[3] ^ Data[5];
37 assign CrcNext[11] = Crc[3] ^ Crc[24] ^ Crc[25] ^ Crc[27] ^ Crc[28] ^ Data[0] ^ Data[1] ^ Data[3] ^ Data[4];
38 assign CrcNext[12] = Crc[4] ^ Crc[24] ^ Crc[25] ^ Crc[26] ^ Crc[28] ^ Crc[29] ^ Crc[30] ^ Data[0] ^ Data[1] ^ Data[2] ^ Data[4] ^ Data[5] ^ Data[6];
39 assign CrcNext[13] = Crc[5] ^ Crc[25] ^ Crc[26] ^ Crc[27] ^ Crc[29] ^ Crc[30] ^ Crc[31] ^ Data[1] ^ Data[2] ^ Data[3] ^ Data[5] ^ Data[6] ^ Data[7];
40 assign CrcNext[14] = Crc[6] ^ Crc[26] ^ Crc[27] ^ Crc[28] ^ Crc[30] ^ Crc[31] ^ Data[2] ^ Data[3] ^ Data[4] ^ Data[6] ^ Data[7];
41 assign CrcNext[15] =  Crc[7] ^ Crc[27] ^ Crc[28] ^ Crc[29] ^ Crc[31] ^ Data[3] ^ Data[4] ^ Data[5] ^ Data[7];
42 assign CrcNext[16] = Crc[8] ^ Crc[24] ^ Crc[28] ^ Crc[29] ^ Data[0] ^ Data[4] ^ Data[5];
43 assign CrcNext[17] = Crc[9] ^ Crc[25] ^ Crc[29] ^ Crc[30] ^ Data[1] ^ Data[5] ^ Data[6];
44 assign CrcNext[18] = Crc[10] ^ Crc[26] ^ Crc[30] ^ Crc[31] ^ Data[2] ^ Data[6] ^ Data[7];
45 assign CrcNext[19] = Crc[11] ^ Crc[27] ^ Crc[31] ^ Data[3] ^ Data[7];
46 assign CrcNext[20] = Crc[12] ^ Crc[28] ^ Data[4];
47 assign CrcNext[21] = Crc[13] ^ Crc[29] ^ Data[5];
48 assign CrcNext[22] = Crc[14] ^ Crc[24] ^ Data[0];
49 assign CrcNext[23] = Crc[15] ^ Crc[24] ^ Crc[25] ^ Crc[30] ^ Data[0] ^ Data[1] ^ Data[6];
50 assign CrcNext[24] = Crc[16] ^ Crc[25] ^ Crc[26] ^ Crc[31] ^ Data[1] ^ Data[2] ^ Data[7];
51 assign CrcNext[25] = Crc[17] ^ Crc[26] ^ Crc[27] ^ Data[2] ^ Data[3];
52 assign CrcNext[26] = Crc[18] ^ Crc[24] ^ Crc[27] ^ Crc[28] ^ Crc[30] ^ Data[0] ^ Data[3] ^ Data[4] ^ Data[6];
53 assign CrcNext[27] = Crc[19] ^ Crc[25] ^ Crc[28] ^ Crc[29] ^ Crc[31] ^ Data[1] ^ Data[4] ^ Data[5] ^ Data[7];
54 assign CrcNext[28] = Crc[20] ^ Crc[26] ^ Crc[29] ^ Crc[30] ^ Data[2] ^ Data[5] ^ Data[6];
55 assign CrcNext[29] = Crc[21] ^ Crc[27] ^ Crc[30] ^ Crc[31] ^ Data[3] ^ Data[6] ^ Data[7];
56 assign CrcNext[30] = Crc[22] ^ Crc[28] ^ Crc[31] ^ Data[4] ^ Data[7];
57 assign CrcNext[31] = Crc[23] ^ Crc[29] ^ Data[5];
58 
59 always @ (posedge Clk, posedge Reset)
60  begin
61   if (Reset) begin
62     Crc <={32{1'b1}};
63   end
64    else if (Enable)
65     Crc <=CrcNext;
66  end
67 endmodule
View Code

  5、用Wireshark捕捉的数据包

   这个代码还是有些瑕疵的如:

    (1)在代码中,我发送的数据长度是 33 个字节,用Wireshark捕捉到的数据长度也有 33 个字节,但是像这个图中显示的数据长度 Len = 25,这个我还没搞明白;

    (2)在RTL仿真时,有些信号会出现未知的状态,但是上板却又能正常的工作;

  6、在学习千兆网的过程中,看了好几个人的百兆网,千兆网代码,下面列出一个自己写的代码,上板实验没有成功,但是RTL仿真和Signal Tap II仿真都是正常的,思路较为简单,容易上手,仅供参考。

  顶层模块:gmii_tx_test.v

 1 `timescale 1ns/1ps
 2 module gmii_tx_test(
 3     input                    clk            ,
 4     input                    rst_n            ,
 5     output                gtx_clk        ,
 6     output                tx_en            ,
 7     output                tx_er            ,
 8     output    [7:0]        tx_data        ,
 9     output                tx_done        ,
10     output                phy_rst_n
11 );
12 
13 
14 pll_125m    u0 (
15     .inclk0 ( clk                     ),
16     .c0     ( gtx_clk              )
17     );
18 
19 
20 gmii_tx u1(
21       .rst_n            (rst_n        ),
22       .tx_done        (tx_done        ),
23       .gtx_clk        (gtx_clk      ),
24       .tx_en            (tx_en        ),
25       .tx_er            (tx_er        ),
26       .tx_data        (tx_data        ),
27       .phy_rst_n    (phy_rst_n    )
28 );
29 
30 endmodule
View Code

  子模块:gmii_tx.v

  1  // *********************************************************************************
  2 // Project Name : gmii_tx
  3 // Email        : 
  4 // Create Time  : 2020/06/22  10:41
  5 // Module Name  : 
  6 // editor         : 
  7 // Version         : Rev1.0.0
  8 // *********************************************************************************
  9 
 10 // Notice : 较为主流的CRC复位是发生在 前导码 的时候,而我的复位是在 IDLE 状态
 11 //            主流的 CRC_EN 是发生在发送 MAC帧和CRC帧前面,我的都是组合逻辑来实现的,而其他的都是时序逻辑
 12 
 13 module gmii_tx(
 14       rst_n        ,
 15       tx_done    ,
 16 
 17       gtx_clk    ,
 18       tx_en        ,
 19       tx_er        ,
 20       tx_data    ,
 21 
 22       phy_rst_n    
 23 );
 24 input                    gtx_clk            ;
 25 input                    rst_n            ;
 26 output    reg                   tx_en            ;
 27 output    reg             tx_er            ;
 28 output    reg[7:0]        tx_data            ; 
 29 output    reg                 tx_done            ;
 30 output    wire            phy_rst_n        ;
 31 
 32 //========================================================================
 33 // =========== Define Parameter and Internal signals =========== 
 34 //========================================================================/
 35 
 36 parameter   Tx_Idle            =    4'd0                    ;
 37 parameter     Tx_premeble        =    4'd1                    ;
 38 parameter   Tx_Mac            =    4'd2                    ;
 39 parameter   Tx_ip            =    4'd3                    ;
 40 parameter   Tx_udp            =    4'd4                    ;
 41 parameter    Tx_data            =   4'd5                    ;
 42 parameter   Tx_crc            =    4'd6                    ;
 43 
 44 reg            [47:0]            des_mac                        ;
 45 reg            [47:0]            src_mac                        ;
 46 reg            [15:0]            type_length                    ;
 47 
 48 reg            [7:0]            ver_hdr_len                    ;
 49 reg            [7:0]            tos                            ;
 50 reg            [15:0]            ip_length                    ;
 51 reg            [15:0]            id                             ;
 52 reg         [15:0]            offset                        ;
 53 reg         [7:0]            ttl                         ;
 54 reg         [7:0]            protocol                    ;
 55 reg         [31:0]            des_ip                        ;
 56 reg         [31:0]            src_ip                        ;
 57 
 58 reg            [15:0]            des_port                    ;
 59 reg         [15:0]            src_port                    ;
 60 reg            [15:0]            udp_length                    ;
 61 reg         [15:0]            udp_checksum                ;
 62 
 63 /*
 64 parameter    data_length        =    16'h22                    ;  // 
 65 
 66 // -------------------- MAC ----------------------------
 67 parameter    des_mac            =    48'hff_ff_ff_ff_ff_ff    ;  // 18_31_bf_b8_b9_d9
 68 parameter    src_mac            =    48'h00_0a_35_01_fe_c0    ;
 69 parameter    type_length        =    16'h08_00                ;
 70 
 71 // -------------------- IP -----------------------------
 72 parameter    ver_hdr_len        =    8'h45                        ;
 73 parameter    tos             =    8'h00                         ;
 74 parameter    ip_length        =    16'h001c + data_length        ;  // 之前是 ip首部 + 数据部分,现在是 ip首部 + udp首部 + 数据长度
 75 parameter    id                =    16'h0000                     ;
 76 parameter    offset            =    16'h0000                     ;
 77 parameter    ttl             =    8'h40                         ;
 78 parameter    protocol        =    8'h11                         ;
 79 parameter    des_ip            =    32'hc0_a8_00_03                ;
 80 parameter    src_ip            =    32'hc0_a8_00_02                ;
 81 
 82 // -------------------- UDP ----------------------------
 83 
 84 parameter    des_port        =    16'h17_70                    ; // 6000
 85 parameter    src_port        =    16'h13_88                    ; // 5000
 86 parameter    udp_length        =    16'h0008 + data_length        ;
 87 parameter    udp_checksum    =    16'h0000                     ;
 88 */
 89 
 90 wire            [7:0]            tx_delay                ;
 91 reg                [19:0]            cnt                     ;
 92 
 93 reg                [3:0]            current_state            ;
 94 reg                [3:0]            next_state                ;
 95 
 96 wire            [15:0]            ip_checksum                ;
 97 wire            [31:0]            crc_result                ;
 98 wire            [31:0]            sum                        ;
 99 reg                                CRC_EN                    ;
100 reg                                CRC_reset                ;
101 
102 wire            [31:0]            crc                     ;
103 wire            [31:0]            crcNext                    ;
104 
105 reg                [4:0]            cnt_premeble            ;
106 reg                [4:0]            cnt_mac                    ;
107 reg                [4:0]            cnt_ip                    ;
108 reg                [4:0]            cnt_udp                    ;
109 reg                [5:0]            cnt_data                ;
110 reg                [4:0]            cnt_crc                    ;
111 
112 //=============================================================================
113 //****************************     Main Code    *******************************
114 //=============================================================================
115 
116 parameter    data_length        =    16'h22                    ;
117 
118 always @(posedge gtx_clk) begin  // MAC
119     des_mac    <=    48'hffffffffffff;
120     src_mac    <=    48'h000a3501fec0;
121     type_length    <= 16'h0800;
122 end
123 
124 always @(posedge gtx_clk) begin  // IP
125     ver_hdr_len    <=    8'h45;                    
126     tos         <=    8'h00 ;                    
127     ip_length    <=    16'h001c + data_length;    
128     id            <=    16'h0021;                 
129     offset        <=    16'h4000;                 
130     ttl         <=    8'h80;          //             
131     protocol    <=    8'h11;                     
132     des_ip        <=    32'hc0_a8_00_03;            
133     src_ip        <=    32'hc0_a8_00_02;            
134 end
135 
136 always @(posedge gtx_clk) begin  // UDP
137     des_port        <=    16'h17_70;                
138     src_port        <=    16'h13_88;                
139     udp_length        <=    16'h0008 + data_length;    
140     udp_checksum    <=    16'h0000 ;                
141 end
142 
143 assign sum = {ver_hdr_len,tos} + ip_length + id 
144             + offset + {ttl,protocol} + src_ip[31:16]
145             + src_ip[15:0] + des_ip[31:16] + des_ip[15:0];
146 
147 /*
148 CRC32_D8 u0 (
149     .Clk        (gtx_clk     ),
150     .Reset         (CRC_reset     ),
151     .Data_in    ( tx_data    ), 
152     .Enable     ( CRC_EN     ),
153     .Crc        (   Crc       ),
154     .CrcNext    (   CrcNext  ),
155     .Crc_eth    ( crc_result )
156 );
157 */
158 
159 crc u0(
160     .Clk        (gtx_clk   ), 
161     .Reset    (CRC_reset ),   // CRC_reset
162     .Data_in (tx_data   ), 
163     .Enable    (CRC_EN      ), 
164     .Crc        (    crc      ),
165     .CrcNext (crcNext   )
166 );
167     
168 //assign CRC_reset = (current_state == Tx_Idle) ? 1'b1 : 1'b0;
169 
170 //assign CRC_EN    = (current_state >= Tx_Mac && current_state <= Tx_data) ? 1'b1 : 1'b0;
171 
172 assign ip_checksum = ~(sum[31:16] + sum[15:0]);
173 
174 assign phy_rst_n   =  1'b1;
175 
176 always @(posedge gtx_clk or negedge rst_n) begin  // cnt
177     if(!rst_n)
178         cnt <= 20'd0;
179     else if(cnt == 80000)
180         cnt <= 20'd0;
181     else
182         cnt <= cnt + 1'b1;
183 end
184 
185 assign  tx_delay = (cnt == 80000)? 1'b1 : 1'b0;
186 
187 //=============================================================================\
188 //****************************    State Machine    *******************************\
189 //=============================================================================\
190 
191 always @(posedge gtx_clk or negedge rst_n) begin
192     if(!rst_n)
193         current_state <= Tx_Idle;
194     else
195         current_state <= next_state;
196 
197 end
198 
199 always @(*) begin
200     next_state = Tx_Idle;
201     case(current_state)
202         Tx_Idle:begin
203             if(tx_delay == 1'b1)
204                 next_state = Tx_premeble;
205             else
206                 next_state = current_state;
207         end
208 
209         Tx_premeble:begin
210             if(cnt_premeble >= 8 -1 )
211                 next_state = Tx_Mac;
212             else
213                 next_state = current_state;
214         end
215 
216         Tx_Mac:begin
217             if(cnt_mac >= 14-1)
218                 next_state = Tx_ip;
219             else
220                 next_state = current_state;
221         end
222 
223         Tx_ip:begin
224             if(cnt_ip >= 20-1)
225                 next_state = Tx_udp;
226             else
227                 next_state = current_state;
228         end
229 
230         Tx_udp:begin
231             if(cnt_udp >= 8-1)
232                 next_state = Tx_data;
233             else
234                 next_state = current_state;
235         end
236 
237         Tx_data:begin
238             if(cnt_data >= data_length- 1 )
239                 next_state = Tx_crc;
240             else
241                 next_state = current_state;
242         end
243 
244         Tx_crc:begin
245             if(cnt_crc >= 4-1 ) 
246                 next_state = Tx_Idle;
247             else
248                 next_state = current_state;
249         end
250 
251         default:begin
252             next_state = Tx_Idle;
253         end
254     endcase
255 end
256 
257 always @(posedge gtx_clk or negedge rst_n) begin
258     if(!rst_n) begin
259         tx_data <= 8'h00;
260         tx_en <= 1'b0;
261         tx_er <= 1'b0;
262         tx_done <= 1'b0;
263         cnt_premeble <= 0;
264         cnt_mac <= 0;
265         cnt_ip <= 0;
266         cnt_udp <= 0;
267         cnt_data <= 0;
268         cnt_crc <= 0;
269         CRC_EN <= 1'b0;
270         CRC_reset <= 1'b0;
271     end
272     else begin
273         case(current_state)  // next_satae
274             Tx_Idle: begin
275                 tx_done <= 1'b0;
276                 tx_en <= 1'b0;
277                 tx_er <= 1'b0;
278                 tx_data <= 8'h00;
279                 CRC_reset <= 1'b1;
280             end
281 
282             Tx_premeble:begin
283                 CRC_reset <= 1'b1;
284                 tx_en <= 1'b1;
285                 if(cnt_premeble >= 8 -1 )
286                     cnt_premeble <= 0;
287                 else
288                     cnt_premeble <= cnt_premeble + 1'b1;
289                 case(cnt_premeble)
290                     0,1,2,3,4,5,6:
291                         tx_data <= 8'h55;
292                     7:tx_data <= 8'hd5;
293                     default:tx_data <= 8'h55;
294                 endcase
295             end
296 
297             Tx_Mac:begin
298                 CRC_reset <= 1'b0;
299                 CRC_EN <= 1'b1;
300                 if(cnt_mac >= 14 -1)
301                     cnt_mac <= 0;
302                 else
303                     cnt_mac <= cnt_mac + 1'b1;
304                 case(cnt_mac)
305                     0 :tx_data <= des_mac[47:40];
306                     1 :tx_data <= des_mac[39:32];
307                     2 :tx_data <= des_mac[31:24];
308                     3 :tx_data <= des_mac[23:16];
309                     4 :tx_data <= des_mac[15: 8];
310                     5 :tx_data <= des_mac[ 7: 0];
311                     
312                     6 :tx_data <= src_mac[47:40];
313                     7 :tx_data <= src_mac[39:32];
314                     8 :tx_data <= src_mac[31:24];
315                     9 :tx_data <= src_mac[23:16];
316                     10:tx_data <= src_mac[15: 8];
317                     11:tx_data <= src_mac[ 7: 0];
318                     
319                     12:tx_data <= type_length[15:8];
320                     13:tx_data <= type_length[ 7:0];
321                     default:tx_data <= 8'hff;
322                 endcase
323             end
324 
325             Tx_ip:begin
326                 if(cnt_ip >= 20-1 )
327                     cnt_ip <= 0;
328                 else
329                     cnt_ip <= cnt_ip + 1'b1;
330                 case(cnt_ip)
331                     0 : tx_data <= ver_hdr_len;
332                     1 :    tx_data <= tos;
333                     2 :    tx_data <= ip_length[15:8];
334                     3 :    tx_data <= ip_length[7:0];
335                     4 :    tx_data <= id[15:8];
336                     5 :    tx_data <= id[7:0];
337                     6 :    tx_data <= offset[15:8];
338                     7 :    tx_data <= offset[7:0];
339                     8 :    tx_data <= ttl;
340                     9 :    tx_data <= protocol;
341                     10:    tx_data <= ip_checksum[15:8];
342                     11:    tx_data <= ip_checksum[7:0];
343                     12:    tx_data <= src_ip[31:24];
344                     13:    tx_data <= src_ip[23:16];
345                     14:    tx_data <= src_ip[15:8];
346                     15:    tx_data <= src_ip[7:0];
347                     16:    tx_data <= des_ip[31:24];
348                     17:    tx_data <= des_ip[23:16];
349                     18:    tx_data <= des_ip[15:8];
350                     19:    tx_data <= des_ip[7:0];
351                     default:tx_data <= 8'hff;
352                 endcase
353             end
354 
355             Tx_udp:begin
356                 if(cnt_udp >= 8 -1)
357                     cnt_udp <= 0;
358                 else
359                     cnt_udp <= cnt_udp + 1'b1;
360                 case(cnt_udp)
361                     0: tx_data <= src_port[15:8];
362                     1: tx_data <= src_port[7:0];
363                     2: tx_data <= des_port[15:8];
364                     3: tx_data <= des_port[7:0];
365                     4: tx_data <= udp_length[15:8];
366                     5: tx_data <= udp_length[7:0];
367                     6: tx_data <= udp_checksum[15:8];
368                     7: tx_data <= udp_checksum[7:0];
369                     default:tx_data <= 8'hff;
370                 endcase
371             end
372 
373             Tx_data:begin
374                 if(cnt_data >= data_length -1)
375                     cnt_data <= 0;
376                 else
377                     cnt_data <= cnt_data + 1'b1;
378                 case(cnt_data)
379                     0:  tx_data <= 8'hf;
380                     1:  tx_data <= 8'h0;
381                     2:  tx_data <= 8'h1;
382                     3:  tx_data <= 8'h2;
383                     4:  tx_data <= 8'h3;
384                     5:  tx_data <= 8'h4;
385                     6:  tx_data <= 8'h5;
386                     7:  tx_data <= 8'h6;
387                     8:  tx_data <= 8'h7;
388                     9:  tx_data <= 8'h8;
389                     10: tx_data <= 8'h9;
390                     11: tx_data <= 8'ha;
391                     12: tx_data <= 8'hb;
392                     13: tx_data <= 8'hc;
393                     14: tx_data <= 8'hd;
394                     15: tx_data <= 8'he;
395                     16: tx_data <= 8'hf;
396                     17: tx_data <= 8'h1;
397                     18: tx_data <= 8'h2;
398                     19: tx_data <= 8'h3;
399                     20: tx_data <= 8'h4;
400                     21: tx_data <= 8'h5;
401                     22: tx_data <= 8'h6;
402                     23: tx_data <= 8'h7;
403                     24: tx_data <= 8'h8;
404                     25: tx_data <= 8'h9;
405                     26: tx_data <= 8'ha;
406                     27: tx_data <= 8'hb;
407                     28: tx_data <= 8'hc;
408                     29: tx_data <= 8'hd;
409                     30: tx_data <= 8'he;
410                     
411                     31: tx_data <= 8'haa;
412                     32: tx_data <= 8'hab;
413                     33: tx_data <= 8'hac;
414                     default:tx_data <= 8'hff;
415                 endcase
416             end
417 
418             Tx_crc:begin
419                 CRC_EN <= 1'b0;
420                 if(cnt_crc >= 4 -1) begin
421                     tx_done <= 1'b1;
422                     cnt_crc <= 0;
423                     //tx_en <= 1'b0;
424                 end
425                 else
426                     cnt_crc <= cnt_crc + 1'b1;
427                 case(cnt_crc)
428                     0: tx_data <= {~crc[24], ~crc[25], ~crc[26], ~crc[27], ~crc[28], ~crc[29], ~crc[30], ~crc[31]};                        // 8'h1b;
429                     1: tx_data <= {~crc[16], ~crc[17], ~crc[18], ~crc[19], ~crc[20], ~crc[21], ~crc[22], ~crc[23]};                        // 8'h75;
430                     2: tx_data <= {~crc[8], ~crc[9], ~crc[10], ~crc[11], ~crc[12], ~crc[13], ~crc[14], ~crc[15]};                        // 8'h49;
431                     3: tx_data <= {~crc[0], ~crc[1], ~crc[2], ~crc[3], ~crc[4], ~crc[5], ~crc[6], ~crc[7]};                        // 8'h0c;
432                     default:tx_data <= 8'hff;
433                 endcase
434             end
435             default:tx_data <= 8'h00;
436         endcase
437     end
438 end
439 
440 
441 endmodule
442 
443 /*
444 crc_result[31:24];
445 crc_result[23:16];
446 crc_result[15:8];
447 crc_result[7:0];
448 */
View Code

  子模块:CRc32_D8.v

 1 `timescale 1ns/1ns
 2 module CRC32_D8(
 3     Clk,
 4     Reset,
 5     Data_in, 
 6     Enable,
 7     Crc,
 8     CrcNext,
 9     Crc_eth
10 );
11 
12     parameter Tp = 1;
13 
14     input Clk;
15     input Reset;
16     input [7:0] Data_in;
17     input Enable;
18 
19     output reg [31:0] Crc;
20     
21     output [31:0]Crc_eth;
22 
23     output [31:0] CrcNext;
24 
25     wire [7:0] Data;
26 
27     assign Data={Data_in[0],Data_in[1],Data_in[2],Data_in[3],Data_in[4],Data_in[5],Data_in[6],Data_in[7]};
28 
29     assign CrcNext[0] = Crc[24] ^ Crc[30] ^ Data[0] ^ Data[6];
30     assign CrcNext[1] = Crc[24] ^ Crc[25] ^ Crc[30] ^ Crc[31] ^ Data[0] ^ Data[1] ^ Data[6] ^ Data[7];
31     assign CrcNext[2] = Crc[24] ^ Crc[25] ^ Crc[26] ^ Crc[30] ^ Crc[31] ^ Data[0] ^ Data[1] ^ Data[2] ^ Data[6] ^ Data[7];
32     assign CrcNext[3] = Crc[25] ^ Crc[26] ^ Crc[27] ^ Crc[31] ^ Data[1] ^ Data[2] ^ Data[3] ^ Data[7];
33     assign CrcNext[4] = Crc[24] ^ Crc[26] ^ Crc[27] ^ Crc[28] ^ Crc[30] ^ Data[0] ^ Data[2] ^ Data[3] ^ Data[4] ^ Data[6];
34     assign CrcNext[5] = Crc[24] ^ Crc[25] ^ Crc[27] ^ Crc[28] ^ Crc[29] ^ Crc[30] ^ Crc[31] ^ Data[0] ^ Data[1] ^ Data[3] ^ Data[4] ^ Data[5] ^ Data[6] ^ Data[7];
35     assign CrcNext[6] = Crc[25] ^ Crc[26] ^ Crc[28] ^ Crc[29] ^ Crc[30] ^ Crc[31] ^ Data[1] ^ Data[2] ^ Data[4] ^ Data[5] ^ Data[6] ^ Data[7];
36     assign CrcNext[7] = Crc[24] ^ Crc[26] ^ Crc[27] ^ Crc[29] ^ Crc[31] ^ Data[0] ^ Data[2] ^ Data[3] ^ Data[5] ^ Data[7];
37     assign CrcNext[8] = Crc[0] ^ Crc[24] ^ Crc[25] ^ Crc[27] ^ Crc[28] ^ Data[0] ^ Data[1] ^ Data[3] ^ Data[4];
38     assign CrcNext[9] = Crc[1] ^ Crc[25] ^ Crc[26] ^ Crc[28] ^ Crc[29] ^ Data[1] ^ Data[2] ^ Data[4] ^ Data[5];
39     assign CrcNext[10] = Crc[2] ^ Crc[24] ^ Crc[26] ^ Crc[27] ^ Crc[29] ^ Data[0] ^ Data[2] ^ Data[3] ^ Data[5];
40     assign CrcNext[11] = Crc[3] ^ Crc[24] ^ Crc[25] ^ Crc[27] ^ Crc[28] ^ Data[0] ^ Data[1] ^ Data[3] ^ Data[4];
41     assign CrcNext[12] = Crc[4] ^ Crc[24] ^ Crc[25] ^ Crc[26] ^ Crc[28] ^ Crc[29] ^ Crc[30] ^ Data[0] ^ Data[1] ^ Data[2] ^ Data[4] ^ Data[5] ^ Data[6];
42     assign CrcNext[13] = Crc[5] ^ Crc[25] ^ Crc[26] ^ Crc[27] ^ Crc[29] ^ Crc[30] ^ Crc[31] ^ Data[1] ^ Data[2] ^ Data[3] ^ Data[5] ^ Data[6] ^ Data[7];
43     assign CrcNext[14] = Crc[6] ^ Crc[26] ^ Crc[27] ^ Crc[28] ^ Crc[30] ^ Crc[31] ^ Data[2] ^ Data[3] ^ Data[4] ^ Data[6] ^ Data[7];
44     assign CrcNext[15] =  Crc[7] ^ Crc[27] ^ Crc[28] ^ Crc[29] ^ Crc[31] ^ Data[3] ^ Data[4] ^ Data[5] ^ Data[7];
45     assign CrcNext[16] = Crc[8] ^ Crc[24] ^ Crc[28] ^ Crc[29] ^ Data[0] ^ Data[4] ^ Data[5];
46     assign CrcNext[17] = Crc[9] ^ Crc[25] ^ Crc[29] ^ Crc[30] ^ Data[1] ^ Data[5] ^ Data[6];
47     assign CrcNext[18] = Crc[10] ^ Crc[26] ^ Crc[30] ^ Crc[31] ^ Data[2] ^ Data[6] ^ Data[7];
48     assign CrcNext[19] = Crc[11] ^ Crc[27] ^ Crc[31] ^ Data[3] ^ Data[7];
49     assign CrcNext[20] = Crc[12] ^ Crc[28] ^ Data[4];
50     assign CrcNext[21] = Crc[13] ^ Crc[29] ^ Data[5];
51     assign CrcNext[22] = Crc[14] ^ Crc[24] ^ Data[0];
52     assign CrcNext[23] = Crc[15] ^ Crc[24] ^ Crc[25] ^ Crc[30] ^ Data[0] ^ Data[1] ^ Data[6];
53     assign CrcNext[24] = Crc[16] ^ Crc[25] ^ Crc[26] ^ Crc[31] ^ Data[1] ^ Data[2] ^ Data[7];
54     assign CrcNext[25] = Crc[17] ^ Crc[26] ^ Crc[27] ^ Data[2] ^ Data[3];
55     assign CrcNext[26] = Crc[18] ^ Crc[24] ^ Crc[27] ^ Crc[28] ^ Crc[30] ^ Data[0] ^ Data[3] ^ Data[4] ^ Data[6];
56     assign CrcNext[27] = Crc[19] ^ Crc[25] ^ Crc[28] ^ Crc[29] ^ Crc[31] ^ Data[1] ^ Data[4] ^ Data[5] ^ Data[7];
57     assign CrcNext[28] = Crc[20] ^ Crc[26] ^ Crc[29] ^ Crc[30] ^ Data[2] ^ Data[5] ^ Data[6];
58     assign CrcNext[29] = Crc[21] ^ Crc[27] ^ Crc[30] ^ Crc[31] ^ Data[3] ^ Data[6] ^ Data[7];
59     assign CrcNext[30] = Crc[22] ^ Crc[28] ^ Crc[31] ^ Data[4] ^ Data[7];
60     assign CrcNext[31] = Crc[23] ^ Crc[29] ^ Data[5];
61 
62     always @ (posedge Clk,posedge Reset)
63     if (Reset)
64         Crc <={32{1'b1}};
65    else if (Enable)
66         Crc <= #1 CrcNext;
67 
68 assign Crc_eth = ~{
69                         CrcNext[24], CrcNext[25], CrcNext[26], CrcNext[27],CrcNext[28], CrcNext[29], CrcNext[30], CrcNext[31],
70                         Crc[16], Crc[17], Crc[18], Crc[19],Crc[20], Crc[21], Crc[22], Crc[23],
71                         Crc[ 8], Crc[ 9], Crc[10], Crc[11],Crc[12], Crc[13], Crc[14], Crc[15],
72                         Crc[ 0], Crc[ 1], Crc[ 2], Crc[ 3],Crc[ 4], Crc[ 5], Crc[ 6], Crc[ 7]};        
73 
74 endmodule
View Code

五、参考

  【1】代码实现上参考了小梅哥和黑金的千兆网程序;

  【2】文字叙述上参考了《基于ac620的fpga系统设计与验证实战指南20190516》,《开拓者FPGA开发指南_V1.2》,草山FPGA等;

  

  上面的文字中若有不当或者疏漏之处,还望各位道友能告知一二,我会立即订正~

  

原文地址:https://www.cnblogs.com/571328401-/p/13268689.html