FPGA以太网入门(四)——ICMP测试实验(基于紫光同创)

标题

0 致读者

此篇为专栏《紫光同创FPGA开发笔记》的第八篇,同时也是 FPGA 以太网入门第四篇,记录我的学习 FPGA 的一些开发过程和心得感悟,刚接触 FPGA 的朋友们可以先去此博客 《FPGA零基础入门学习路线》来做最基础的扫盲。

本篇内容基于笔者实际开发过程和正点原子资料撰写,将会详细讲解此 FPGA 实验的全流程,诚挚地欢迎各位读者在评论区或者私信我交流!

ICMP(Internet Control Message Protocol)Internet 控制报文协议。它是 TCP/IP 协议簇的一个子协议,用于在 IP 主机、路由器之间传递控制消息。控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息。这些控制消息虽然并不传输用户数据,但是对于用户数据的传递起着重要的作用。

ICMP 使用 IP 的基本支持,就像它是一个更高级别的协议,但是,ICMP 实际上是 IP 的一个组成部分,必须由每个 IP 模块实现。

本文我们来学习如何使用 FPGA 开发板来实现 ICMP 测试的功能。

本文的工程文件开源地址如下(基于ATK-DFPGL22G,大家 clone 到本地就可以直接跑仿真,如果要上板请根据自己的开发板更改约束即可):

https://github.com/ChinaRyan666/PDS_ICMP_TEST



1 实验任务

本文的实验任务是电脑通过命令行窗口发送 ping 命令给 FPGAFPGA 通过以太网接口接收数据并将接收到的数据发送给电脑,完成以电脑 ping 开发板的实验测试。



2 简介

2.1 ICMP 概述

ICMP 协议是一种面向无连接的协议,用于传输出错报告控制信息。它是一个非常重要的协议,它对于网络安全具有极其重要的意义。它属于网络层协议,主要用于在主机与路由器之间传递控制信息包括报告错误交换受限控制状态信息等。当遇到 IP 数据无法访问目标、IP 路由器无法按当前的传输速率转发数据包等情况时,会自动发送 ICMP 消息。

ICMPTCP/IP 模型中网络层的重要成员,与 IP 协议、ARP 协议、RARP 协议及 IGMP 协议共同构成 TCP/IP 模型中的网络层。pingtracert 是两个常用网络管理命令,ping 用来测试网络可达性,tracert 用来显示到达目的主机的路径。pingtracert 都利用 ICMP 协议来实现网络功能,它们是把网络协议应用到日常网络管理的典型实例。

从技术角度来说,ICMP 就是一个 “错误侦测与回报机制”,其目的就是让我们能够检测网路的连线状况,也能确保连线的准确性。当路由器在处理一个数据包的过程中发生了意外,可以通过 ICMP 向数据包的源端报告有关事件。

其功能主要有:侦测远端主机是否存在,建立及维护路由资料,重导资料传送路径(ICMP 重定向),资料流量控制。ICMP 在沟通之中,主要是透过不同的类别(Type)与代码(Code)让机器来识别不同的连线状况。

ICMP 是个非常有用的协议,尤其是当我们要对网路连接状况进行判断的时候。

以太网 ICMP 传输单包数据的格式如下图所示。从图中可以看出,以太网的数据包就是对各层协议的逐层封装来实现数据的传输。用户数据打包在 ICMP 协议中,ICMP 协议又是基于 IP 协议之上的,IP 协议又是走 MAC 层发送的,即从包含关系来说:MAC 帧中的数据段为 IP 数据报,IP 报文中的数据段为 ICMP 报文,ICMP 报文中的数据段为用户希望传输的数据内容。

接下来我们逐个来向大家介绍不同层的数据格式。

在这里插入图片描述

图 2.1 以太网 ICMP 传输数据包格式


其中以太网的帧格式在本专栏《以太网ARP 测试实验》 中已经向大家作了详细的介绍,如果对以太网帧格式不熟悉的话,可以参考《以太网ARP 测试实验》

IP 协议(互联网分组交换协议)是 TCP/IP 协议簇中非常重要的一个协议,在本专栏《以太网UDP 测试实验》 中已经向大家作了详细的介绍,如果对 IP 协议不熟悉的话,可以参考《以太网UDP 测试实验》 中关于 IP 协议的介绍。


2.2 ICMP 协议详解

ICMP 报文包含在 IP 数据报中,属于 IP 的一个用户,IP 头部就在 ICMP 报文的前面,所以一个 ICMP 报文包括 IP 头部、ICMP 头部和 ICMP 报文,IP 头部的 Protocol 值为 1 就说明这是一个 ICMP 报文,如图 2.2 所示,ICMP 头部中的类型(Type)域用于说明 ICMP 报文的作用及格式,此外还有一个代码(Code)域用于详细说明某种 ICMP 报文的类型,所有数据都在 ICMP 头部后面。

ICMP 报文格式具体可以阅读 RFC 777RFC 792 规范。

在这里插入图片描述

图 2.2 一帧 ICMP 报文


ICMP 数据格式如图 2.3 所示。

在这里插入图片描述

图 2.3 ICMP 数据格式


ICMP 首部共 8 个字节,同 IP 首部一样,也是一行以 32 位(4 个字节)为单位。

名称解释
类型(type占用了 8 bit 位,前面我们说,是 ICMP 报文类型,用于标识错误类型的差错报文或者查询类型的报告报文。
代码(code占用了 8 bit 位,根据 ICMP 差错报文的类型,进一步分析错误的原因,代码值不同对应的错误也不同,例如:类型为 11 且代码为 0,表示数据传输过程中超时了,超时的具体原因是 TTL 值为 0,数据报被丢弃。
校验和(checksum占用了 16 bit 位,数据发送到目的地后需要对 ICMP 数据报文做一个校验,用于检查数据报文是否有错误。
标识符(Identifier占用了 16 bit 位,对于每一个发送的数据报进行标识。
序列号(Sequence number占用了 16 bit 位,对于发送的每一个数据报文进行编号,比如:发送的第一个数据报序列号为 1,第二个序列号为 2
数据(Data要发送的 ICMP 数据。

ICMP 请求报文为例,我们来看一下 ICMP 请求报文的封装格式。

在这里插入图片描述

图 2.4 icmp 请求报文的封装格式


这是我们刚才通过 ping 命令抓的 ICMP 协议包,其中 requestICMP 请求数据报,replyICMP 回答数据报,另外 requestreply 是一组 ICMP 请求回答数据报。

在这里插入图片描述

图 2.5 ICMP 请求回答数据报


我们再针对一组 ICMP 请求回答数据报分析两个 ICMP 数据报是否为一组。Type 的值为 8’h08 是请求类型报文如图 2.6 所示,Type 的值为 8’h00 是应答类型报文如图 2.7 所示,序列号(Sequence number)一致是同一组 ICMP 请求回答数据报。

在这里插入图片描述

图 2.6 icmp 的 request


在这里插入图片描述

图 2.7 icmp 的 reply


下面我们来看一下,我们在用 ping 命令发送的 ping 包携带的是什么数据。

在这里插入图片描述

图 2.8 icmp 数据部分


Data 就是刚才 ping 命令所发送的 ICMP 数据报文里的数据部分,这些数据是 ping 命令发送的测试内容,左侧部分是以十六进制表示,右侧部分就是我们所发送的数据部分,这些数据长度正好是 32 字节,一个字母代表一个字节。



3 程序设计

3.1 总体设计

图 3.1 是根据本章实验任务画出的系统框图。和本专栏《以太网UDP 测试实验》 相比,本实验只有替换 UDP 顶层模块。本次实验虽然实现的是 ICMP 通信,但保留了 ARP 顶层模块,这是由于上位机应用程序只知道接收端目的 IP 地址端口号,却不知道接收端MAC 地址,因此这里通过 ARP 协议来获取接收端的 MAC 地址,否则需要在发送端手动绑定接收端 MAC 地址,而手动绑定的方法较为繁琐,因此这里保留了 ARP 协议

本次实验同时实现了 ARP 协议ICMP 协议GMII 接收侧的引脚同时连接至 ARP 顶层模块和 ICMP 顶层模块,这个两个模块会分别根据 ARP 协议和 ICMP 协议解析数据。而 GMII 发送侧引脚只能和 ARP 顶层模块和 ICMP 顶层模块的其中一个连接,因此以太网控制模块会根据当前接收到的协议类型,选择切换 GMII 发送侧引脚和 ARP 顶层模块或者 ICMP 顶层模块连接。

除此之外,以太网控制模块根据输入的 ARP 接收的类型,控制 ARP 顶层模块返回 ARP 应答信号。

在这里插入图片描述

图 3.1 以太网 ICMP 测试系统框图


由上图可知,FPGA 顶层模块例化了以下五个模块,GMII TO RGMII 模块(gmii_to_rgmii)、ARP顶层模块(arp)、ICMP 顶层模块(icmp)、同步 FIFO 模块(sync_fifo_2048x32b)和以太网控制模块(eth_ctrl),实现了各模块之间的数据交互。

其中 GMII TO RGMIIgmii_to_rgmii)模块和 ARP 顶层模块(arp)在本专栏的 “以太网 ARP 测试实验” 中已经向大家作了详细的介绍,如果大家对这部分内容不熟悉的话,可以参考本专栏的 “以太网 ARP 测试实验” 。 本文我们重点介绍 ICMP 顶层模块(icmp),ICMP 顶层模块实现了整个以太网帧格式与 ICMP 协议的功能。

ICMP 顶层模块例化了 ICMP 接收模块(icmp_rx)ICMP 发送模块(icmp_tx)CRC 校验模块(crc32_d8)


ICMP 接收模块(icmp_rx): ICMP 接收模块较为简单,因为我们不需要对数据做 IP 首部校验也不需要做 CRC 循环冗余校验,只需要判断目的 MAC 地址与开发板 MAC 地址、目的 IP 地址与开发板 IP 地址是否一致即可。

接收模块的解析顺序是:前导码+帧起始界定符以太网帧头IP 首部ICMP 首部ICMP 数据(有效数据)接收结束

IP 数据报一般以 32bit 为单位,为了和 IP 数据报格式保持一致,所以要把 8 位数据转成 32 位数据,因此接收模块实际上是完成了 8 位数据转 32 位数据的功能。


ICMP 发送模块(icmp_tx): ICMP 发送模块和接收模块比较类似,但是多了 IP 首部校验和和 CRC 循环冗余校验的计算。CRC 的校验并不是在发送模块完成,而是在 CRC 校验模块(crc32_d8)里完成的。

发送模块的发送顺序是:前导码+帧起始界定符以太网帧头IP 首部ICMP 首部ICMP 数据(有效数据)CRC 校验

输入的有效数据为 32 位数据,GMII 接口为 8 位数据接口,因此发送模块实际上完成的是 32 位数据转 8 位数据的功能。


CRC 校验模块(crc32_d8): CRC 校验模块是对 ICMP 发送模块的数据(不包括前导码和帧起始界定符)做校验,把校验结果值拼在以太网帧格式的 FCS 字段,如果 CRC 校验值计算错误或者没有的话,那么电脑网卡会直接丢弃该帧导致收不到数据(有些网卡是可以设置不做校验的)。

CRC32 校验在 FPGA 实现的原理是 LFSRLinear Feedback Shift Register,线性反馈移位寄存器),其思想是各个寄存器储存着上一次 CRC32 运算的结果,寄存器的输出即为 CRC32 的值。


其中 CRC 校验模块ARP 模块例化的校验模块完全相同,这里我们重点介绍 ICMP 接收模块ICMP 发送模块


3.2 ICMP 接收模块设计

ICMP 接收模块按照 ICMP 的数据格式解析数据,并实现将 8 位用户数据转成 32 位数据的功能。由 ICMP 的数据格式可知,解析 ICMP 数据很适合使用状态机来实现,图 3.2ICMP 接收模块的状态跳转图。

在这里插入图片描述

图 3.2 ICMP 接收模块的状态跳转图


接收模块使用三段式状态机来解析以太网包,从上图可以比较直观的看到每个状态实现的功能以及跳转到下一个状态的条件。这里需要注意的一点是,在中间状态如前导码错误MAC 地址错误以及 IP 地址错误时跳转到 st_rx_end 状态而不是跳转到 st_idle 状态。

因为中间状态在解析到数据错误时,单包数据的接收还没有结束,如果此时跳转到 st_idle 状态会误把有效数据当成前导码来解析,所以状态跳转到 st_rx_end。而 eth_rxdv 信号为 0 时,单包数据才算接收结束,所以 st_rx_end 跳转到 st_idle 的条件是 eth_rxdv = 0,准备接收下一包数据。

因为代码较长,只粘贴了第三段状态机的接收数据状态和接收结束状态源代码,代码如图 3.3 所示 。

在这里插入图片描述

图 3.3 ICMP 接收模块部分源代码


st_rx_data 状态表示接收 ICMP 的有效数据,程序中的 6~15 行代码将接收的 8 位数据转换位 32 位数据,16~31 行代码是将接收的相邻两个 8 位数据拼接成一个 16 位数据,并将拼接的 16 位数据进行累加得都到一个 32 位的累加和 reply_checksum_add。在接收完有效数据后,拉高rec_pkt_done(单包有效数据接收完成)信号,如程序中第 36 行代码所示。

Icmp 的仿真代码如下所示。

module  tb_icmp;

//parameter  define
parameter  T = 8;                       //时钟周期为8ns
parameter  OP_CYCLE = 100;              //操作周期(发送周期间隔)

//开发板MAC地址 00-11-22-33-44-55
parameter  BOARD_MAC = 48'h00_11_22_33_44_55;     
//开发板IP地址 192.168.1.10     
parameter  BOARD_IP  = {8'd192,8'd168,8'd1,8'd10};
//目的MAC地址 ff_ff_ff_ff_ff_ff
parameter  DES_MAC   = 48'hff_ff_ff_ff_ff_ff;
//目的IP地址 192.168.1.10
parameter  DES_IP    = {8'd192,8'd168,8'd1,8'd10};

//reg define
reg           gmii_clk;    //时钟信号
reg           sys_rst_n;   //复位信号

reg           tx_start_en;
reg   [31:0]  tx_data    ;
reg   [15:0]  tx_byte_num;
reg   [47:0]  des_mac    ;
reg   [31:0]  des_ip     ;

reg   [3:0]   flow_cnt   ;
reg   [13:0]  delay_cnt  ;

wire          gmii_rx_clk; //GMII接收时钟
wire          gmii_rx_dv ; //GMII接收数据有效信号
wire  [7:0]   gmii_rxd   ; //GMII接收数据
wire          gmii_tx_clk; //GMII发送时钟
wire          gmii_tx_en ; //GMII发送数据使能信号
wire  [7:0]   gmii_txd   ; //GMII发送数据
             
wire          tx_done    ; 
wire          tx_req     ;

//*****************************************************
//**                    main code
//*****************************************************

assign gmii_rx_clk = gmii_clk   ;
assign gmii_tx_clk = gmii_clk   ;
assign gmii_rx_dv  = gmii_tx_en ;
assign gmii_rxd    = gmii_txd   ;

//给输入信号初始值
initial begin
    gmii_clk           = 1'b0;
    sys_rst_n          = 1'b0;     //复位
    #(T+1)  sys_rst_n  = 1'b1;     //在第(T+1)ns的时候复位信号信号拉高
end

//125Mhz的时钟,周期则为1/125Mhz=8ns,所以每4ns,电平取反一次
always #(T/2) gmii_clk = ~gmii_clk;

always @(posedge gmii_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        tx_start_en <= 1'b0;
        tx_data <= 32'h_00_00_00_00;
        tx_byte_num <= 1'b0;
        des_mac <= 1'b0;
        des_ip <= 1'b0;
        delay_cnt <= 1'b0;
        flow_cnt <= 1'b0;
    end
    else begin
        case(flow_cnt)
            'd0 : flow_cnt <= flow_cnt + 1'b1;
            'd1 : begin
                tx_start_en <= 1'b1;  //拉高开始发送使能信号
                tx_byte_num <= 16'd20;//设置发送的字节数
                flow_cnt <= flow_cnt + 1'b1;
            end
            'd2 : begin 
                tx_start_en <= 1'b0;
                flow_cnt <= flow_cnt + 1'b1;
            end    
            'd3 : begin
                if(tx_req)
                    tx_data <= tx_data ;
                if(tx_done) begin
                    flow_cnt <= flow_cnt + 1'b1;
                    tx_data <= 32'h_00_00_00_00;
                end    
            end
            'd4 : begin
                delay_cnt <= delay_cnt + 1'b1;
                if(delay_cnt == OP_CYCLE - 1'b1)
                    flow_cnt <= flow_cnt + 1'b1;
            end
            'd5 : begin
                tx_start_en <= 1'b1;  //拉高开始发送使能信号
                tx_byte_num <= 16'd28;//设置发送的字节数
                flow_cnt <= flow_cnt + 1'b1;               
            end
            'd6 : begin 
                tx_start_en <= 1'b0;
                flow_cnt <= flow_cnt + 1'b1;
            end 
            'd7 : begin
                if(tx_req)
                    tx_data <= tx_data;
                if(tx_done) begin
                    flow_cnt <= flow_cnt + 1'b1;
                    tx_data <= 32'h_00_00_00_00;
                end  
            end
            default:;
        endcase    
    end
end

//例化ICMP模块
icmp
   #(
    .BOARD_MAC     (BOARD_MAC),      //参数例化
    .BOARD_IP      (BOARD_IP ),
    .DES_MAC       (DES_MAC  ),
    .DES_IP        (DES_IP   )
    )
   u_icmp(
    .rst_n         (sys_rst_n   ),
    
    .gmii_rx_clk   (gmii_rx_clk ),
    .gmii_rx_dv    (gmii_rx_dv  ),
    .gmii_rxd      (gmii_rxd    ),
    .gmii_tx_clk   (gmii_tx_clk ),
    .gmii_tx_en    (gmii_tx_en),
    .gmii_txd      (gmii_txd  ),
   
    .rec_pkt_done  (),
    .rec_en        (),
    .rec_data      (),
    .rec_byte_num  (),
    .tx_start_en   (tx_start_en ),
    .tx_data       (tx_data     ),
    .tx_byte_num   (tx_byte_num ),
    .des_mac       (des_mac     ),
    .des_ip        (des_ip      ),
    .tx_done       (tx_done     ),
    .tx_req        (tx_req      )
    ); 

endmodule

在仿真 icmp 的接收过程中需要将 icmp_tx.v 模块修改为开发板发送请求模块,既将报文类型进行如下修改即可。

//ICMP 报文类型:回显应答
//localparam ECHO_REPLY = 8'h00;
  localparam ECHO_REPLY = 8'h08; //用于仿真

图 3.4 为接收过程中的仿真波形图。 图中 gmii_rx_dvgmii_rxdGMII 接口的接收有效信号和数据,rec_byte_num 为发送的有效数据的个数。每次单包数据接收完成都会产生 rec_pkt_done 信号,rec_enrec_data 为收到的数据有效信号和 32 位数据。

在这里插入图片描述

图 3.4 icmp 接收的波形图


3.3 ICMP 发送模块设计

ICMP 发送模块按照 ICMP 的数据格式发送数据,并将 32 位用户数据转成 8 位数据的功能,也就是接收模块的逆过程。同样也非常适合使用状态机来完成发送数据的功能,状态跳转图如图 3.5 所示。

在这里插入图片描述

图 3.5 ICMP 发送模块的状态跳转图


发送模块接收模块有很多相似之处, 同样使用三段式状态机来发送以太网包,从上图可以比较直观的看到每个状态实现的功能以及跳转到下一个状态的条件。

发送模块的代码中定义了数组来存储以太网的帧头IP 首部以及 ICMP 的首部,在复位时初始化数组的值, 部分源代码如图 3.6 ~ 图 3.11 所示。

在这里插入图片描述

图 3.6 ICMP 发送模块部分源代码


省略部分代码……

在这里插入图片描述

图 3.7 ICMP 发送模块部分源代码


以上代码在复位时对数组进行初始化。

在这里插入图片描述

图 3.8 ICMP 发送模块部分源代码


图 3.8 程序的第 5 行至 23 行代码,为 IP 首部数组进行赋值。

在这里插入图片描述

图 3.9 ICMP 发送模块部分源代码


图 3.9 的代码是将 ICMP 首部与数据进行加法运算,8~12 行代码是消除加法运算的进位,第 17 行代码给需要发送的 icmp 首部校验和赋值。

在这里插入图片描述

图 3.10 ICMP 发送模块部分源代码


图 3.10 代码为发送 ICMP 数据段的状态。我们前面讲过以太网帧格式的数据部分最少是 46 个字节,去掉 IP 首部字节ICMP 首部字节后,有效数据至少为 18 个字节,程序设计中已经考虑到这种情况,当发送的有效数据少于 18 个字节时,会在有效数据后面发送补充位,填充的数据为 0

在这里插入图片描述

图 3.11 ICMP 发送模块部分源代码


图 3.11 中的代码为发送 CRC 校验值状态,发送模块的 CRC 校验是由 crc32_d4 模块完成的,发送模块将输入的 crc 的计算结果每 4 位高低位互换,按位取反发送出去。

图 3.12 为发送过程中的仿真波形图,图中 tx_start_en 作为开始发送的启动信号,gmii_tx_engmii_txdGMII 接口的发送接口。

在开始发送以太网帧头时 crc_en 拉高,开始 CRC 校验的计算,在将要发送有效数据时拉高 tx_req(发送数据请求)信号, tx_data 即为待发送的有效数据,在所有数据发送完成后输出 tx_done(发送完成)信号和 crc_clrCRC 校验值复位)信号。

在这里插入图片描述

图 3.12 ICMP 发送仿真的波形图


3.3 以太网控制模块设计

以太网控制模块的代码如下:

module eth_ctrl(
    input              clk       ,      //系统时钟
    input              rst_n     ,      //系统复位信号,低电平有效 
    //ARP相关端口信号                                    
    input              arp_rx_done,     //ARP接收完成信号
    input              arp_rx_type,     //ARP接收类型 0:请求  1:应答
    output  reg        arp_tx_en,       //ARP发送使能信号
    output             arp_tx_type,     //ARP发送类型 0:请求  1:应答
    input              arp_tx_done,     //ARP发送完成信号
    input              arp_gmii_tx_en,  //ARP GMII输出数据有效信号 
    input     [7:0]    arp_gmii_txd,    //ARP GMII输出数据
    //UDP相关端口信号
    input              icmp_tx_start_en,//ICMP开始发送信号
    input              icmp_tx_done,    //ICMP发送完成信号
    input              icmp_gmii_tx_en, //ICMP GMII输出数据有效信号  
    input     [7:0]    icmp_gmii_txd,   //ICMP GMII输出数据   
    //GMII发送引脚                     
    output             gmii_tx_en,      //GMII输出数据有效信号 
    output    [7:0]    gmii_txd         //ICMP GMII输出数据 
    );

//reg define
reg        protocol_sw; //协议切换信号
reg        icmp_tx_busy; //ICMP正在发送数据标志信号
reg        arp_rx_flag; //接收到ARP请求信号的标志

//*****************************************************
//**                    main code
//*****************************************************

assign arp_tx_type = 1'b1;   //ARP发送类型固定为ARP应答                                   
assign gmii_tx_en = protocol_sw ? icmp_gmii_tx_en : arp_gmii_tx_en;
assign gmii_txd = protocol_sw ? icmp_gmii_txd : arp_gmii_txd;

//控制ICMP发送忙信号
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        icmp_tx_busy <= 1'b0;
    else if(icmp_tx_start_en)   
        icmp_tx_busy <= 1'b1;
    else if(icmp_tx_done)
        icmp_tx_busy <= 1'b0;
end

//控制接收到ARP请求信号的标志
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        arp_rx_flag <= 1'b0;
    else if(arp_rx_done && (arp_rx_type == 1'b0))   
        arp_rx_flag <= 1'b1;
    else if(protocol_sw == 1'b0)
        arp_rx_flag <= 1'b0;
end

//控制protocol_sw和arp_tx_en信号
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        protocol_sw <= 1'b0;
        arp_tx_en <= 1'b0;
    end
    else begin
        arp_tx_en <= 1'b0;
        if(icmp_tx_start_en)
            protocol_sw <= 1'b1;
        else if(arp_rx_flag && (icmp_tx_busy == 1'b0)) begin
            protocol_sw <= 1'b0;
            arp_tx_en <= 1'b1;
        end    
    end        
end

endmodule

以太网控制模块的代码较简单,如果输入的 arp_rx_doneARP 接收完成信号)为高电平,且 arp_rx_type 为低电平(ARP 接收类型为请求)时,表示接收到 ARP 请求数据包,此时拉高 arp_rx_flag 信号;

arp_rx_flag 为高电平,且 icmp_tx_busy(当前 ICMP 发送模块处于空闲状态)信号为低电平时,此时拉高 arp_tx_en 信号,开始控制 ARP 顶层模块发送 ARP 应答数据包,并拉低 protocol_sw 信号,此时 GMII 发送端口信号和 ARP 顶层模块的发送端口信号相连。

protocol_sw 等于 1 时,GMII 发送引脚和 ICMP GMII 发送引脚相连,否则和 ARP GMII 发送引脚相连,如程序中第 32 行第 33 行代码所示。



4 下载验证

编译工程并生成比特流 .sbit 文件后,此时将下载器一端连接电脑,另一端与开发板上的 JTAG 下载口连接,将网线一端连接开发板的网口,另一端连接电脑的网口或者路由器,接下来连接电源线,并打开开发板的电源开关。

点击 PDS 工具栏的下载按钮,在弹出的 Fabric Configuration 界面中双击 Boundary Scan, 我们将生成好的 .sbit 流文件下载到开发板中去。

在这里插入图片描述

图 4.1 点击网络图标


接下来就可以打开电脑命令提示符框就可以执行 ping 命令了,如图 4.2 所示。

在这里插入图片描述

图 4.2 电脑命令提示符框


输入 “ping 192.168.1.10” 命令如图 4.3 所示,打印如下信息表示电脑 ping 开发板成功。

在这里插入图片描述

图 4.3 ping 命令输出信息


从上图可以看到开发板正常回复,电脑 ping 开发板成功。接下来通过 Wireshark 软件抓取网口的数据包,界面如图 4.4 所示。

在这里插入图片描述

图 4.4 wireshark 打开界面


双击上图所示的以太网或者先选中以太网,再点击上方红框选中的蓝色按钮,即可开始抓取本地连接的数据包,抓取界面如图 4.5 所示。

在这里插入图片描述

图 4.5 wireshark 打开界面


从上图可以看到, 已经抓取到其它应用程序使用以太网发送的数据包, 但是这些数据包并不是开发板发送的数据包,我们这个时候重新在电脑命令提示符框中发送ping 192.168.1.10命令,可以看到 Wireshark 软件中抓取的数据,如图 4.6 所示。

在这里插入图片描述

图 4.6 wireshark 以太网抓取到的数据包


上图中第 47 行是上位机发送的 ICMP 请求数据包,第 48 行是开发板返回的 ICMP 应答数据包。点击开发板返回的数据包,可以看到开发板发送的详细数据,如图 4.7 所示。

在这里插入图片描述

图 4.7 Wireshark 抓取到的详细数据


由上图可知,通信协议是 ICMP 协议,源 IP 地址(开发板 IP 地址)为 192.168.1.10,目的 IP 地址(电脑 IP 地址)为 192.168.1.102。上图中下方红框为开发板发送的 16 进制数据(去掉前导码SFDCRC 值),可以看到,ICMP 的用户数据段对应的 ASIC 码为abcdefghijklmn opqrstuvwabcdefg hi



5 总结

至此,本专栏中关于 FPGA 以太网入门的第四篇 —— ICMP测试实验已经全部讲解完毕,全文篇幅较长,爆肝近 2 万字,建议收藏后精读,有不理解的地方可以关注作者的微信公众号(沂舟无限进步),和作者深度链接~~

希望以上的内容对您有所帮助,诚挚地欢迎各位读者在评论区或者私信我交流!

微博:沂舟Ryan (@沂舟Ryan 的个人主页 - 微博 )

GitHub:ChinaRyan666

微信公众号:沂舟无限进步(内含精品资料及详细教程)

如果对您有帮助的话请点赞支持下吧!

集中一点,登峰造极。

  • 11
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ChinaRyan666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值