本原创教程由芯驿电子科技(上海)有限公司(ALINX)创作,版权归本公司所有,如需转载,需授权并注明出处(http://www.alinx.com)。 适用于板卡型号: PGL22G 1. 简介本实验将实现FPGA芯片和PC之间进行千兆以太网数据通信, 通信协议采用Ethernet UDP通信协议。 FPGA通过RGMII总线和开发板上的Gigabit PHY芯片通信, Gigabit PHY芯片把数据通过网线发给PC,程序中实现了ARP,UDP,PING功能,此外还实现了100/1000M自适应。 2. 硬件介绍在开发板上通过1片RTL8211EG以太网PHY芯片为用户提供网络通信服务。以太网PHY芯片是连接到Pango FPGA的IO接口上。芯片支持10/100/1000 Mbps网络传输速率,通过RGMII接口跟FPGA进行数据通信。RTL8211EG支持MDI/MDX自适应,各种速度自适应,Master/Slave自适应,支持MDIO总线进行PHY的寄存器管理。当网口Link到千兆以太网时, FPGA通过RGMII总线和PHY芯片进行数据通信,当网口Link到百兆以太网时, FPGA通过MII总线和PHY芯片进行数据通信。另外FPGA可以通过MDI/MDIO管理接口来配置或读取PHY芯片内部的寄存器。在千兆的RGMII通信模式下(以U8为例), 发送数据时,发送时钟为125Mhz的E_GTXC信号, 数据为E_TXD[3:0], 数据有效信号为E_TXEN, E_TXC信号连接但没有使用; 接收数据时,接收时钟为125Mhz的E_RXC信号, 数据为E_RXC[3:0], 数据有效信号为E_RXDV。关于详细的管脚说明和RGMII/MII的通信时序,请大家参考RTL8211EG的芯片手册。 硬件电路设计如下:
开发板网络部分电路关于详细的管脚说明和RGMII的通信时序,请大家参考相关芯片手册。 3. 以太网帧3.1 以太网帧格式 下图为以太网的帧格式: 前导码(Preamble):8字节,连续7个8’h55加1个8’hd5,表示一个帧的开始,用于双方设备数据的同步。 目的MAC地址:6字节,存放目的设备的物理地址,即MAC地址 源MAC地址:6字节,存放发送端设备的物理地址 类型:2字节,用于指定协议类型,常用的有0800表示IP协议,0806表示ARP协议,8035 表示RARP协议 数据:46到1500字节,最少46字节,不足需要补全46字节,例如IP协议层就包含在数据 部分,包括其IP头及数据。 FCS:帧尾,4字节,称为帧校验序列,采用32位CRC校验,对目的MAC地址字段到数据字 段进行校验。 进一步扩展,以UDP协议为例,可以看到其结构如下,除了以太网首部的14字节,数据部分包含IP首部,UDP首部,应用数据共46~1500字节。 3.2 ARP数据报格式 ARP地址解析协议,即ARP(Address Resolution Protocol),根据IP地址获取物理地址。主机发送包含目的IP地址的ARP请求广播(MAC地址为48’hff_ff_ff_ff_ff_ff)到网络上的主机,并接收返回消息,以此确定目标的物理地址,收到返回消息后将IP地址和物理地址保存到缓存中,并保留一段时间,下次请求时直接查询ARP缓存以节约资源。下图为ARP数据报格式 。 帧类型:ARP帧类型为两字节0806 硬件类型:指链路层网络类型,1为以太网 协议类型:指要转换的地址类型,采用0x0800 IP类型,之后的硬件地址长度和协议地址长度分别对应6和4 OP字段中1表示ARP请求,2表示ARP应答 例如:|ff ff ff ff ff ff|00 0a 35 01 fe c0|08 06|00 01|08 00|06|04|00 01|00 0a 35 01 fe c0 |c0 a8 00 02| ff ff ff ff ff ff|c0 a8 00 03| 表示向192.168.0.3地址发送ARP请求。 |00 0a 35 01 fe c0 | 60 ab c1 a2 d5 15 |08 06|00 01|08 00|06|04|00 02| 60 ab c1 a2 d5 15 |c0 a8 00 03|00 0a 35 01 fe c0|c0 a8 00 02|表示向192.168.0.2地址发送ARP应答。 3.3 IP 数据报格式 因为UDP协议包只是IP包中的一种, 所以我们来介绍一下IP包的数据格式。下图为IP分组的报文头格式,报文头的前20个字节是固定的,后面的可变 版本:占 4 位,指 IP 协议的版本目前的 IP 协议版本号为 4 (即 IPv4) 首部长度:占4位,可表示的最大数值是15个单位(一个单位为 4 字节)因此IP 的首部长度的最大值是 60 字节 区分服务:占8位,用来获得更好的服务,在旧标准中叫做服务类型,但实际上一直未被使用过.1998 年这个字段改名为区分服务.只有在使用区分服务(DiffServ)时,这个字段才起作用.一般的情况下都不使用这个字段 总长度:占16位,指首部和数据之和的长度,单位为字节,因此数据报的最大长度为 65535 字节.总长度必须不超过最大传送单元 MTU 标识:占16位,它是一个计数器,用来产生数据报的标识 标志(flag): 占3位,目前只有前两位有意义 MF 标志字段的最低位是 MF (More Fragment) MF=1 表示后面“还有分片”。MF=0 表示最后一个分片 DF 标志字段中间的一位是 DF (Don't Fragment) 只有当 DF=0 时才允许分片 片偏移:占12位,指较长的分组在分片后某片在原分组中的相对位置.片偏移以 8 个字节为偏移单位 生存时间:占8位,记为TTL (Time To Live) 数据报在网络中可通过的路由器数的最大值,TTL 字段是由发送端初始设置一个 8 bit字段.推荐的初始值由分配数字 RFC 指定,当前值为 64.发送 ICMP 回显应答时经常把 TTL 设为最大值 255 协议:占8位,指出此数据报携带的数据使用何种协议以便目的主机的IP层将数据部分上交给哪个处理过程, 1表示为 ICMP 协议, 2表示为 IGMP 协议, 6表示为 TCP 协议, 17表示为 UDP 协议 首部检验和:占16位,只检验数据报的首部不检验数据部分,采用二进制反码求和,即将16位数据相加后,再将进位与低16位相加,直到进位为0,最后将16位取反。 源地址和目的地址:都各占4 字节,分别记录源地址和目的地址 3.4 UDP协议 UDP是User Datagram Protocol(用户数据报协议)的英文缩写。UDP只提供一种基本的、低延迟的被称为数据报的通讯。所谓数据报,就是一种自带寻址信息,从发送端走到接收端的数据包。UDP协议经常用于图像传输、网络监控数据交换等数据传输速度要求比较高的场合。 UDP协议的报头格式: UDP报头由4个域组成,其中每个域各占用2个字节,具体如下: ① UDP源端口号 ② 目标端口号 ③ 数据报长度 ④ 校验和 UDP协议使用端口号为不同的应用保留其各自的数据传输通道。数据发送一方将UDP数据报通过源端口发送出去,而数据接收一方则通过目标端口接收数据。 数据报的长度是指包括报头和数据部分在内的总字节数。因为报头的长度是固定的,所以该域主要被用来计算可变长度的数据部分(又称为数据负载)。数据报的最大长度根据操作环境的不同而各异。从理论上说,包含报头在内的数据报的最大长度为65535字节。不过,一些实际应用往往会限制数据报的大小,有时会降低到8192字节。 UDP协议使用报头中的校验值来保证数据的安全。校验值首先在数据发送方通过特殊的算法计算得出,在传递到接收方之后,还需要再重新计算。如果某个数据报在传输过程中被第三方篡改或者由于线路噪音等原因受到损坏,发送和接收方的校验计算值将不会相符,由此UDP协议可以检测是否出错。虽然UDP提供有错误检测,但检测到错误时,错误校正,只是简单地把损坏的消息段扔掉,或者给应用程序提供警告信息。 3.5 Ping功能 ICMP是TCP/IP协议族的一个IP层子协议,包含在IP数据报里,用于IP主机、路由器之间传递控制消息。控制消息是指网络是否连通,主机是否可达等功能。其中ping功能采用回送请求和回答报文,回送请求报文类型为8’h08,回答报文类型为8’h00。 4. SMI(MDC/MDIO)总线接口串行管理接口(Serial Management Interface),也被称作MII管理接口(MII Management Interface),包括MDC和MDIO两条信号线。MDIO是一个PHY的管理接口,用来读/写PHY的寄存器,以控制PHY的行为或获取PHY的状态,MDC为MDIO提供时钟,由MAC端提供,在本实验中也就是FPGA端。在RTL8211EG文档里可以看到MDC的周期最小为400ns,也就是最大时钟为2.5MHz。 4.1 SMI帧格式如下图,为SMI的读写帧格式: 名称 | 说明 | Preamble | 由MAC发送32个连续的逻辑“1”,同步于MDC信号,用于MAC与PHY之间的同步 | ST | 帧开始位,固定为01 | OP | 操作码,10表示读,01表示写 | PHYAD | PHY的地址,5 bits | REGAD | 寄存器地址,5 bits | TA | Turn Around,MDIO方向转换,在写状态下,不需要转换方向,值为10,在读状态下,MAC输出端为高阻态,在第二个周期,PHY将MDIO拉低 | DATA | 共16bits数据 | IDLE | 空闲状态,此状态下MDIO为高阻态,由外部上拉电阻拉高 |
4.2 读写时序 1)读时序
可以看到在Turn Around状态下,第一个周期MDIO为高阻态,第二个周期由PHY端拉低。 2)写时序
为了保证能够正确采集到数据,在MDC上升沿之前就把数据准备好,在本实验中为下降沿发送数据,上升沿接收数据。 5. 程序设计本实验以千兆以太网RGMII通信为例来设计verilog程序,会先发送预设的UDP数据到网络,每秒钟发送一次,如果FPGA检测网口发来的UDP的数据包,会把接收到的数据包存储在FPGA内部的RAM中,再不断的把RAM中的数据包通过网口发回到ethernet网络。程序分为两部分,分别为发送和接收,实现了ARP,UDP,Ping功能。以下为原理实现框图: 5.1 发送部分 1)MAC层发送发送部分中, mac_tx.v为MAC层发送模块,首先在SEND_START状态,等待mac_tx_ready信号,如果有效,表明IP或ARP的数据已经准备好,可以开始发送。再进入发送前导码状态,结束时发送mac_data_req,请求IP或ARP的数据,之后进入发送数据状态,最后进入发送CRC状态。在发送数据过程中,需要同时进行CRC校验。 信号名称 | 方向 | 宽度(bit) | 说明 | clk | in | 1 | 系统时钟 | rst_n | in | 1 | 异步复位,低电平复位 | crc_result | in | 32 | CRC32结果 | crcen | out | 1 | CRC使能信号 | crcre | out | 1 | CRC复位信号 | crc_din | out | 8 | CRC模块输入信号 | mac_frame_data | in | 8 | 从IP或ARP来的数据 | mac_tx_req | in | 1 | MAC的发送请求 | mac_tx_ready | in | 1 | IP或ARP数据已准备好 | mac_tx_end | in | 1 | IP或ARP数据已经传输完毕 | mac_tx_data | out | 8 | 向PHY发送数据 | mac_send_end | out | 1 | MAC数据发送结束 | mac_data_valid | out | 1 | MAC数据有效信号,即gmii_tx_en | mac_data_req | out | 1 | MAC层向IP或ARP请求数据 | 2)MAC发送模式工程中的mac_tx_mode.v为发送模式选择,根据发送模式是IP或ARP选择相应的信号与数据。 信号名称 | 方向 | 宽度(bit) | 说明 | clk | in | 1 | 系统时钟 | rst_n | in | 1 | 异步复位,低电平复位 | mac_send_end | in | 1 | MAC发送结束 | arp_tx_req | in | 1 | ARP发送请求 | arp_tx_ready | in | 1 | ARP数据已准备好 | arp_tx_data | in | 8 | ARP数据 | arp_tx_end | in | 1 | ARP数据发送到MAC层结束 | arp_tx_ack | in | 1 | ARP发送响应信号 | ip_tx_req | in | 1 | IP发送请求 | ip_tx_ready | in | 1 | IP数据已准备好 | ip_tx_data | in | 8 | IP数据 | ip_tx_end | in | 1 | IP数据发送到MAC层结束 | mac_tx_ready | out | 1 | MAC数据已准备好信号 | ip_tx_ack | out | 1 | IP发送响应信号 | mac_tx_ack | in | 1 | MAC发送响应信号 | mac_tx_req | out | 1 | MAC发送请求 | mac_tx_data | out | 8 | MAC发送数据 | mac_tx_end | out | 1 | MAC数据发送结束 | 3)ARP发送发送部分中,arp_tx.v为ARP发送模块, 在IDLE状态下,等待ARP发送请求或ARP应答请求信号,之后进入请求或应答等待状态,并通知MAC层,数据已经准备好,等待mac_data_req信号,之后进入请求或应答数据发送状态。由于数据不足46字节,需要补全46字节发送。 信号名称 | 方向 | 宽度(bit) | 说明 | clk | in | 1 | 系统时钟 | rst_n | in | 1 | 异步复位,低电平复位 | destination_mac_addr | in | 48 | 发送的目的MAC地址 | source_mac_addr | in | 48 | 发送的源MAC地址 | source_ip_addr | in | 32 | 发送的源IP地址 | destination_ip_addr | in | 32 | 发送的目的IP地址 | mac_data_req | in | 1 | MAC层请求数据信号 | arp_request_req | in | 1 | ARP请求的请求信号 | arp_reply_ack | out | 1 | ARP回复的应答信号 | arp_reply_req | in | 1 | ARP回复的请求信号 | arp_rec_source_ip_addr | in | 32 | ARP接收的源IP地址,回复时放到目的IP地址 | arp_rec_source_mac_addr | in | 48 | ARP接收的源MAC地址,回复时放到目的MAC地址 | mac_send_end | in | 1 | MAC发送结束 | mac_tx_ack | in | 1 | MAC发送应答 | arp_tx_ready | out | 1 | ARP数据准备好 | arp_tx_data | out | 8 | ARP发送数据 | arp_tx_end | out | 1 | ARP数据发送结束 | 4)IP层发送在发送部分,ip_tx.v为IP层发送模块,在IDLE状态下,如果ip_tx_req有效,也就是UDP或ICMP发送请求信号,进入等待发送数据长度状态,之后进入产生校验和状态,校验和是将IP首部所有数据以16位相加,最后将进位再与低16位相加,直到进入为0,再将低16位取反,得出校验和结果。此程序中校验和以树型加法结构,并插入流水线,能有效降低加法部分的延迟,但缺点是会消耗较多逻辑资源。如下图ABCD四个输入,A与B相加,结果为E,C与D相加,结果为F,再将E与F相加,结果为G,在每个相加结果之后都有寄存器。 在生成校验和之后,等待MAC层数据请求,开始发送数据,并在即将结束发送IP首部后请求UDP或ICMP数据。等发送完,进入IDLE状态。 信号名称 | 方向 | 宽度(bit) | 说明 | clk | in | 1 | 系统时钟 | rst_n | in | 1 | 异步复位,低电平复位 | destination_mac_addr | in | 48 | 发送的目的MAC地址 | source_mac_addr | in | 48 | 发送的源MAC地址 | source_ip_addr | in | 32 | 发送的源IP地址 | destination_ip_addr | in | 32 | 发送的目的IP地址 | TTL | in | 8 | 生存时间 | ip_send_type | in | 8 | 上层协议号,如UDP,ICMP | upper_layer_data | in | 8 | 从UDP或ICMP过来的数据 | upper_data_req | out | 1 | 向上层请求数据 | mac_tx_ack | in | 1 | MAC发送应答 | mac_send_end | in | 1 | MAC发送结束信号 | mac_data_req | in | 1 | MAC层请求数据信号 | upper_tx_ready | in | 1 | 上层UDP或ICMP数据准备好 | ip_tx_req | in | 1 | 发送请求,从上层过来 | ip_send_data_length | in | 16 | 发送数据总长度 | ip_tx_ack | out | | 产生IP发送应答 | ip_tx_busy | out | | P发送忙信号 | ip_tx_ready | out | 1 | IP数据已准备好 | ip_tx_data | out | 8 | IP数据 | ip_tx_end | out | 1 | IP数据发送到MAC层结束 | 5)IP发送模式工程中的ip_tx_mode.v为发送模式选择,根据发送模式是UDP或ICMP选择相应的信号与数据。 信号名称 | 方向 | 宽度(bit) | 说明 | clk | in | 1 | 系统时钟 | rst_n | in | 1 | 异步复位,低电平复位 | mac_send_end | in | 1 | MAC数据发送结束 | udp_tx_req | in | | UDP发送请求 | udp_tx_ready | in | 1 | UDP数据准备好 | udp_tx_data | in | 8 | UDP发送数据 | udp_send_data_length | in | 16 | UDP发送数据长度 | udp_tx_ack | out | 1 | 输出UDP发送应答 | icmp_tx_req | in | 1 | ICMP发送请求 | icmp_tx_ready | in | 1 | ICMP数据准备好 | icmp_tx_data | in | 8 | ICMP发送数据 | icmp_send_data_length | in | 16 | ICMP发送数据长度 | icmp_tx_ack | out | 1 | ICMP发送应答 | ip_tx_ack | in | 1 | IP发送应答 | ip_tx_req | in | 1 | IP发送请求 | ip_tx_ready | out | 1 | IP数据已准备好 | ip_tx_data | out | 8 | IP数据 | ip_send_type | out | 8 | 上层协议号,如UDP,ICMP | ip_send_data_length | out | 16 | 发送数据总长度 | 6)UDP发送发送部分中,udp_tx.v为UDP发送模块,第一步将数据写入UDP发送RAM,同时计算校验和,第二步将RAM中数据发送出去。UDP校验和与IP校验和计算方法一致。在计算时需要将伪首部加上,伪首部包括目的IP地址,源IP地址,网络类型,UDP数据长度。 信号名称 | 方向 | 宽度(bit) | 说明 | clk | in | 1 | 系统时钟 | rst_n | in | 1 | 异步复位,低电平复位 | source_ip_addr | in | 32 | 发送的源IP地址 | destination_ip_addr | in | 32 | 发送的目的IP地址 | udp_send_source_port | in | 16 | 源端口号 | udp_send_destination_port | in | 16 | 目的端口号 | udp_send_data_length | in | 16 | UDP发送数据长度,用户需给出其值 | ram_wr_data | in | 8 | 写UDP的RAM数据 | ram_wr_en | in | 1 | 写RAM使能 | udp_ram_data_req | out | 1 | 请求写RAM数据 | mac_send_end | in | 1 | MAC发送结束信号 | udp_tx_req | in | 1 | UDP发送请求 | ip_tx_req | out | 1 | IP发送请求 | ip_tx_ack | in | 1 | Ip应答 | udp_data_req | in | 1 | IP层请求数据 | udp_tx_ready | out | 1 | UDP数据准备好 | udp_tx_data | out | 8 | UDP数据 | udp_tx_end | out | 1 | UDP发送结束(未使用) | almost_full | out | 1 | Fifo接近满标志 |
5.2 接收部分 1) MAC层接收 在接收部分,其中mac_rx.v为mac层接收文件,首先在IDLE状态下需要判断rx_dv信号是否为高,在REC_PREAMBLE前导码状态下,接收前导码。之后进入接收MAC头部状态,即目的MAC地址,源MAC地址,类型,将它们缓存起来,并在此状态判断前导码是否正确,错误则进入REC_ERROR错误状态,在REC_IDENTIFY状态判断类型是IP(8’h0800)或ARP(8’h0806)。然后进入接收数据状态,将数据传送到IP或ARP模块,等待IP或ARP数据接收完毕,再接收CRC数据。并在接收数据的过程中对接收的数据进行CRC处理,将结果与接收到的CRC数据进行对比,判断数据是否接收正确,正确则结束,错误则进入ERROR状态。 信号名称 | 方向 | 宽度(bit) | 说明 | clk | in | 1 | 系统时钟 | rst_n | in | 1 | 异步复位,低电平复位 | crc_result | in | 32 | CRC32结果 | crcen | out | 1 | CRC使能信号 | crcre | out | 1 | CRC复位信号 | crc_din | out | 8 | CRC模块输入信号 | rx_dv | in | 1 | 从PHY层过来的rx_dv信号 | mac_rx_datain | in | 8 | 从PHY层接收的数据 | checksum_err | in | 1 | IP层校验和错误 | ip_rx_end | in | 1 | IP层接收结束 | arp_rx_end | in | 1 | ARP层接收结束 | ip_rx_req | out | 1 | 请求IP层接收 | arp_rx_req | out | 1 | 请求ARP接收 | mac_rx_dataout | out | 8 | MAC层接收数据输出给IP或ARP | mac_rec_error | out | 1 | MAC层接收错误 | mac_rx_destination_mac_addr | out | 48 | MAC接收的目的IP地址 | mac_rx_source_mac_addr | out | 48 | MAC接收的源IP地址 |
2) ARP接收 工程中的arp_rx.v为ARP接收模块,实现ARP数据接收,在IDLE状态下,接收到从MAC层发来的arp_rx_req信号,进入ARP接收状态,在此状态下,提取出目的MAC地址,源MAC地址,目的IP地址,源IP地址,并判断操作码OP是请求还是应答。如果是请求,则判断接收到的目的IP地址是否为本机地址,如果是,发送应答请求信号arp_reply_req,如果不是,则忽略。如果OP是应答,则判断接收到的目的IP地址及目的MAC地址是否与本机一致,如果是,则拉高arp_found信号,表明接收到了对方的地址。并将对方的MAC地址及IP地址存入ARP缓存中。 信号名称 | 方向 | 宽度(bit) | 说明 | clk | in | 1 | 系统时钟 | rst_n | in | 1 | 异步复位,低电平复位 | local_ip_addr | in | 32 | 本地IP地址 | local_mac_addr | in | 48 | 本地MAC地址 | arp_rx_data | in | 8 | ARP接收数据 | arp_rx_req | in | 1 | ARP接收请求 | arp_rx_end | out | 1 | ARP接收完成 | arp_reply_ack | in | 1 | ARP回复应答 | arp_reply_req | out | 1 | ARP回复请求 | arp_rec_source_ip_addr | in | 32 | ARP接收的源IP地址 | arp_rec_source_mac_addr | in | 48 | ARP接收的源MAC地址 | arp_found | out | 1 | ARP接收到请求应答正确 |
3) IP层接收模块 在工程中,ip_rx为IP层接收模块,实现IP层的数据接收,信息提取,并进行校验和检查。首先在IDLE状态下,判断从MAC层发过来的ip_rx_req信号,进入接收IP首部状态,先在REC_HEADER0提取出首部长度及IP总长度,进入REC_HEADER1状态,在此状态提取出目的IP地址,源IP地址,协议类型,根据协议类型发送udp_rx_req或icmp_rx_req。在接收首部的同时进行校验和的检查,将首部接收的所有数据相加,存入32位寄存器,再将高16位与低16位相加,直到高16位为0 ,再将低16位取反,判断其是否为0,如果是0,则检验正确,否则错误,进入IDLE状态,丢弃此帧数据,等待下次接收。 信号名称 | 方向 | 宽度(bit) | 说明 | clk | in | 1 | 系统时钟 | rst_n | in | 1 | 异步复位,低电平复位 | local_ip_addr | in | 32 | 本地IP地址 | local_mac_addr | in | 48 | 本地MAC地址 | ip_rx_data | in | 8 | 从MAC层接收的数据 | ip_rx_req | in | 1 | MAC层发送的IP接收请求信号 | mac_rx_destination_mac_addr | in | 48 | MAC层接收的目的MAC地址 | udp_rx_req | out | 1 | UDP接收请求信号 | icmp_rx_req | out | 1 | ICMP接收请求信号 | ip_addr_check_error | out | 1 | 地址检查错误信号 | upper_layer_data_length | out | 16 | 上层协议的数据长度 | ip_total_data_length | out | 16 | 数据总长度 | net_protocol | out | 8 | 网络协议号 | ip_rec_source_addr | out | 32 | IP层接收的源IP地址 | ip_rec_destination_addr | out | 32 | IP层接收的目的IP地址 | ip_rx_end | out | 1 | IP层接收结束 | ip_checksum_error | out | 1 | IP层校验和检查错误信号 |
4) UDP接收 在工程中,udp_rx.v为UDP接收模块,在此模块首先接收UDP首部,再接收数据部分,并将数据部分存入RAM中,在接收的同时进行UDP校验和检查,如果UDP数据是奇数个字节,在计算校验和时,在最后一个字节后加上8’h00,并进行校验和计算。校验方法与IP校验和一样,如果校验正确,将拉高udp_rec_data_valid信号,表明接收的UDP数据有效,否则无效,等待下次接收。 信号名称 | 方向 | 宽度(bit) | 说明 | clk | in | 1 | 系统时钟 | rst_n | in | 1 | 异步复位,低电平复位 | udp_rx_data | in | 8 | UDP接收数据 | udp_rx_req | in | 1 | UDP接收请求 | mac_rec_error | in | 1 | MAC层接收错误 | net_protocol | in | 8 | 网络协议号 | ip_rec_source_addr | in | 32 | IP层接收的源IP地址 | ip_rec_destination_addr | in | 32 | IP层接收的目的IP地址 | ip_checksum_error | in | 1 | IP层校验和检查错误信号 | ip_addr_check_error | in | 1 | 地址检查错误信号 | upper_layer_data_length | in | 16 | 上层协议的数据长度 | udp_rec_ram_rdata | out | 8 | UDP接收RAM读数据 | udp_rec_ram_read_addr | in | 11 | UDP接收RAM读地址 | udp_rec_data_length | out | 16 | UDP接收数据长度 | udp_rec_data_valid | out | 1 | UDP接收数据有效 |
5.3 SMI接口 1)SMI读写控制模块 smi_read_write.v文件用于SMI接口的读写控制,在IDLE状态下根据写请求或读请求到相应的状态,再根据SMI时序实现MDC和MDIO的控制。 信号名称 | 方向 | 宽度(bit) | 说明 | clk | in | 1 | 系统时钟 | rst_n | in | 1 | 异步复位,低电平复位 | mdc | out | 1 | MDC时钟 | mdio | inout | 1 | MDIO数据 | phy_addr | in | 5 | PHY地址 | reg_addr | in | 5 | 寄存器地址 | write_req | in | 1 | 写请求 | write_data | in | 16 | 写数据 | read_req | in | 1 | 读请求 | read_data | out | 16 | 读数据 | data_valid | out | 1 | 数据有效 | done | out | 1 | 读或写结束 |
2)SMI配置模块 smi_config.v文件读取寄存器0x11的bit10和bit[15:14]来判断以太网是否已经连接和当前的以太网速度,默认状态下,PHY芯片是自动协商速度,根据对方的速度做匹配。bit 10为1则link成功,否则失败,bit[15:14]为00则是10M,01为100M,10或11为1000M,根据不同的速度点亮LED灯,没有link都不亮,10M亮一个灯,100M亮两个灯,1000M亮三个灯。 信号名称 | 方向 | 宽度(bit) | 说明 | clk | in | 1 | 系统时钟 | rst_n | in | 1 | 异步复位,低电平复位 | mdc | out | 1 | MDC时钟 | mdio | inout | 1 | MDIO数据 | speed | out | 2 | 速度 00:10M; 01:100M; 10:1000M | link | out | 1 | 寄存器地址 | led | out | 4 | 写请求 |
5.4 10/100/1000M仲裁 由于10/100M传输数据时是单边沿采集数据,因此一个周期传输4bit数据,而RGMII为双边沿采集数据,所以要进行数据的转换,如发送时,要将一周其8bit数据转成一周期4bit数据,因此要设置数据缓存,读数据速率为写数据的一半。 1)TX buffer gmii_tx_buffer.v将要发送的8bit缓存到eth_data_fifo中,同时将数据长度缓存到len_fifo中,在状态机中判断长度FIFO中的数据是否大于0,是则表明已经缓存了数据,之后进入读FIFO数据状态,每两个周期读一次数据,此功能不好理解,最好用signaltap抓取信号帮助理解。 信号名称 | 方向 | 宽度(bit) | 说明 | clk | in | 1 | 系统时钟 | rst_n | in | 1 | 异步复位,低电平复位 | eth_10_100m_en | in | 1 | 10/100M使能信号 | link | in | 1 | Link信号 | gmii_tx_en | in | 1 | 内部的gmii发送使能 | gmii_txd | in | 8 | 内部的gmii发送数据 | e10_100_tx_en | out | 1 | 10/100M发送使能 | e10_100_txd | out | 8 | 10/100M发送数据 |
2)RX buffer gmii_rx_buffer.v将接收的10/100M数据缓存到eth_data_fifo中,同时将数据长度缓存到len_fifo中,在状态机中判断长度FIFO中的数据是否大于0,是则表明已经缓存了数据,之后进入读FIFO数据状态,每两个周期读一次数据,最好用signaltap抓取信号帮助理解。 信号名称 | 方向 | 宽度(bit) | 说明 | clk | in | 1 | 系统时钟 | rst_n | in | 1 | 异步复位,低电平复位 | eth_10_100m_en | in | 1 | 100M使能信号 | eth_10m_en | in | 1 | 10M使能信号 | link | in | 1 | Link信号 | gmii_rx_dv | in | 1 | 外部的gmii接收有效 | gmii_rxd | in | 8 | 外部的gmii接收数据 | e10_100_rx_dv | out | 1 | 10/100M接收有效信号 | e10_100_rxd | out | 8 | 10/100M接收数据 |
3)仲裁 gmii_arbi.v用于三种速度的仲裁,同时设定了发送的间隔都为1S。 信号名称 | 方向 | 宽度(bit) | 说明 | clk | in | 1 | 系统时钟 | rst_n | in | 1 | 异步复位,低电平复位 | speed | in | 2 | 以太网速度 | link | in | 1 | Link信号 | gmii_rx_dv | in | 1 | 外部的gmii接收有效 | gmii_rxd | in | 8 | 外部的gmii接收数据 | gmii_tx_en | in | 1 | 内部的gmii发送使能 | gmii_txd | out | 8 | 内部的gmii发送数据 | pack_total_len | out | 32 | 延迟数值,每种速度都设置为1S | e_rst_n | out | 1 | 复位MAC信号 | e_rx_dv | out | 1 | 仲裁后接收有效信号 | e_rxd | out | 8 | 仲裁后接收有效数据 | e_tx_en | out | 1 | 仲裁后发送使能信号 | e_txd | out | 8 | 仲裁后发送数据信号 |
5.5 其他部分 1)ICMP应答 在工程中,icmp_reply.v实现ping功能,首先接收其他设备发过来的icmp数据,判断类型是否是回送请求(ECHO REQUEST),如果是,将数据存入RAM,并计算校验和,判断校验和是否正确,如果正确则进入发送状态,将数据发送出去。 信号名称 | 方向 | 宽度(bit) | 说明 | clk | in | 1 | 系统时钟 | rst_n | in | 1 | 异步复位,低电平复位 | mac_send_end | in | 1 | Mac发送结束信号 | ip_tx_ack | in | 1 | IP发送应答 | icmp_rx_data | in | 8 | ICMP接收数据 | icmp_rx_req | in | 1 | ICMP接收请求 | icmp_rev_error | in | 1 | 接收错误信号 | upper_layer_data_length | in | 16 | 上层协议长度 | icmp_data_req | in | 1 | 发送请求ICMP数据 | icmp_tx_ready | out | 1 | ICMP发送准备好 | icmp_tx_data | out | 8 | ICMP发送数据 | icmp_tx_end | out | 1 | ICMP发送结束 | icmp_tx_req | out | 1 | ICMP发送请求 |
2)ARP缓存 在工程中,arp_cache.v为arp缓存模块,将接收到的其他设备IP地址和MAC地址缓存,在发送数据之前,查询目的地址是否存在,如果不存在,则向目的地址发送ARP请求,等待应答。在设计文件中,只做了一个缓存空间,如果有需要,可扩展。 信号名称 | 方向 | 宽度(bit) | 说明 | clk | in | 1 | 系统时钟 | rst_n | in | 1 | 异步复位,低电平复位 | arp_found | in | 1 | ARP接收到回复正确 | arp_rec_source_ip_addr | in | 32 | ARP接收的源IP地址 | arp_rec_source_mac_addr | in | 48 | ARP接收的源MAC地址 | destination_ip_addr | in | 32 | 目的IP地址 | destination_mac_addr | out | 48 | 目的MAC地址 | mac_not_exist | out | 1 | 目的地址对应的MAC地址不存在 |
3)CRC校验模块(crc.v) 一个IP数据包的CRC32校验是在目标MAC 地址开始计算的,一直计算到一个包的最后一个数据为止。以太网的CRC32的verilog的算法和多项式可以在以下网站中直接生成: http://www.easics.com/webtools/crctool 4)以太网测试模块(mac_test.v)测试模块实现数据流的控制,首先在按下按键后发送ARP请求信号,直到对方回应,进入发送UDP数据状态,如果在WAIT状态时发现UDP接收数据有效,则将接收的数据发送出去。循环1秒发送,在每次发送前需要检查目的IP地址是否能在ARP缓存里找到,如果没有,则发送ARP请求。 信号名称 | 方向 | 宽度(bit) | 说明 | clk_50m | in | 1 | 系统时钟 | rst_n | in | 1 | 异步复位,低电平复位 | pack_total_len | in | 32 | 包长度 | push_button | in | 1 | 按键信号 | gmii_tx_clk | in | 1 | GMII发送时钟 | gmii_rx_clk | in | 1 | GMII接收时钟 | gmii_rx_dv | in | 1 | 接收数据有效信号 | gmii_rxd | in | 8 | 接收数据 | gmii_tx_en | out | 1 | 发送数据有效信号 | gmii_txd | out | 8 | 发送数据 | 5)RGMII转GMII模块util_gmii_to_rgmii.v文件是将RGMII与GMII转换,提取出控制信号与数据信号。与PHY连接是RGMII接口。 GMII接口RGMII接口RGMII接口是GMII接口的简化版,在时钟的上升沿及下降沿都采样数据,上升沿发送TXD[3:0]/RXD[3:0],下降沿发送TXD[7:4]/RXD[7:4],TX_EN传送TX_EN(上升沿)和TX_ER(下降沿)两种信息,RX_DV传送RX_DV(上升沿)和RX_ER(下降沿)两种信息。 6. 下载和试验6.1 准备工作 第一步:首先确认一下自己PC的网卡是否是千兆网卡,用户可以点击本地连接查看,再用五类+或者六类网线连接开发板的网口和PC的网口。 第二步:修改PC的IP地址为192.168.0.3。PC的IP Address需要和mac_test.v中设置一致,不然网络调试助手会接收不到开发板发送的UDP数据包。 第三步:安装Wireshark是为了方便用户网络通信的调试,安装”\07_软件工具及驱动\网络调试工具\wireshark_cn”目录下的网络抓包工具Wireshark, 我们在实验的时候可以用这工具来查看PC网口发送的数据和接收到的数据的详细信息。 6.2 以太网通信测试 第一步:烧写ethernet_test.bit文件到FPGA,(如果需固化到FLASH中烧写ethernet_test.bin文件),等待两三秒,看到三个LED灯亮,为千兆网卡,两个灯亮为百兆网卡,如果都没亮,需要检查网口连接情况。 第二步:以管理员权限打开CMD窗口,输入arp –a查看ARP绑定结果,可以看到开发板的IP地址和MAC地址已经缓存。 第三步:在CMD窗口中,输入ping 192.168.0.2查看PC与开发板是否ping通。 第四步:打开“\07_软件工具及驱动\网络调试工具\NetAssist “目录下的网络调试助手并设置参数如下,再按连接按钮(这里的本地的IP地址为PC的IP Address, 本地端口需要跟FPGA程序中的一致,为8080)。 这时网络数据接收窗口会显示FPGA发给PC的以太网数据包"HELLO ALINX HEIJIN"目标主机的IP地址需要和FPGA程序中的IP地址一致,目标端口号也需要和FPGA程序的一致(8080)。如下图网络显示: 第五步:再在网络调试助手的发送窗口发送一大串字符,在网络的数据接收窗口我们可以看到从FPGA返回的数据也变成刚发送的字符串。 也可以发送较少字符,低于46字节,FPGA程序会自动补充至46字节,如下图: 第六步:这一步对用户来讲是可选的,用户如果想查看更多数据包传输的信息,可以使用网络抓包工具Wireshark来查看PC的网卡接收和发送的网络数据,打开安装好的wireshark抓包工具,点击菜单抓包->网络接口。 在弹出的抓包接口窗口选择PC的千兆网卡,按开始按钮开始抓包。 在wireshark抓包窗口我们可以看到开发板(192.168.0.2)向PC网口(192.168.0.2)发来的数据包,这里会显示数据包的目标MAC, 源MAC,IP包头和UDP包等信息, 如下图开发板抓包窗口显示: 6.3 以太网速度测试我们可以通过抓包工具wireshark测量以太网部分的数据发送的速度,因为千兆以太网理想模式网络的速度可以达到1Gbps,但实际因为每个数据包中有包头,CRC等非数据字符,而且每包之间有空隙,一般千兆以太网的数据传输速度最高在950Mbps左右。传输是上下对称传输,就是说上行和下行都能达到950Mbps左右。在这里,因为抓包wireshark只能统计接收的数据包,而不会发送数据,所以这里只是测试FPGA发给电脑的输送数据的速度。 第一步:修改程序,修改工程中mac_test.v中的代码,如下图所示 把上图中的红色标的”//”去掉,如下: 第二步:编译综合完成后下载测试程序,下载完成后这时FPGA网络会进行动态绑定,PC机的IP设置请参照5.2章节(如已设置忽略)。 打开wireshark,点击菜单“抓包”->"抓包参数选择”。在抓包选项中设置缓冲大小为1000megabyte,在10000个数据包之后停止抓包。(这里需要注意:如果不设置的话wireshark因为抓的包太多,处理不了导致软件崩溃) 按开始后抓包,等待接收到10000个包后停止抓包,用时0.087932秒。 我们可以看到每个数据包的内容都是00->FF的数据,总共是3个00->FF,1个00->e7的数据。总共是1000个有效数据。 这里我们看到软件用了0.087932秒收到了10000个数据包,每个数据包里含有的有效数据是1000个字节(8bit)。所以我们可以算出以太网的传输速度为: 传输速度 = 1000* 10000 * 8 / 0.087932 = 910Mbps。 这里提示一下,网络传输的速度跟包长也有关系,数据包长越长,效率就越高,传输数据的速度会变高;数据包越短,效率就越低,传输数据的速度就慢。这个道理我想大家应该明白的吧! 下面是1000000包的时间是8.799832秒,自己可以按照上面的方面算下速度,速度是非常稳定的。 6.4 以太网100M/1000M测试 改变电脑的网卡速度,首先打开网络连接,找到本地网卡,右键点击属性弹出如下窗口,再点击配置。 在弹出的窗口中找到链接速度,选择100Mbps全双工,点击确定,等待几秒钟,会发现LED灯会发生改变,之后再按前面的操作步骤进行测试。 到这里为止,我们的以太网数据通信就全部结束了,要实现以太网的数据通信首先需要理解以太网数据包的格式和通信协议,还需要了解MAC和PHY之间的GMII,RGMII,MII,RMII接口的时序。千兆以太网的数据传输速度非常快,而且是全双工传输,而且UDP通信的数据速度可以达到900Mbps以上,非常适合高速数据传输的场合,比如视频图像传输,高速数据采集等等。
|