一、简介
一般来说,我们要将 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
子模块: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
子模块: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
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
子模块: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 */
子模块: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
五、参考
【1】代码实现上参考了小梅哥和黑金的千兆网程序;
【2】文字叙述上参考了《基于ac620的fpga系统设计与验证实战指南20190516》,《开拓者FPGA开发指南_V1.2》,草山FPGA等;
上面的文字中若有不当或者疏漏之处,还望各位道友能告知一二,我会立即订正~