【【通信协议之ICMP协议的FPGA实现】】

通信协议之ICMP协议的FPGA实现

整体的实现框图如下所示
在这里插入图片描述

arp_rx.v

module arp_rx#(//开发板MAC地址 00-11-22-33-44-55parameter 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}      )(input                clk        , //时钟信号input                rst_n      , //复位信号,低电平有效input                gmii_rx_dv , //GMII输入数据有效信号input        [7:0]   gmii_rxd   , //GMII输入数据output  reg          arp_rx_done, //ARP接收完成信号output  reg          arp_rx_type, //ARP接收类型 0:请求  1:应答output  reg  [47:0]  src_mac    , //接收到的源MAC地址output  reg  [31:0]  src_ip       //接收到的源IP地址);//parameter define
localparam  st_idle     = 5'b0_0001; //初始状态,等待接收前导码
localparam  st_preamble = 5'b0_0010; //接收前导码状态 
localparam  st_eth_head = 5'b0_0100; //接收以太网帧头
localparam  st_arp_data = 5'b0_1000; //接收ARP数据
localparam  st_rx_end   = 5'b1_0000; //接收结束
localparam  ETH_TPYE    = 16'h0806;  //以太网帧类型 ARP//reg define
reg    [4:0]   cur_state ;
reg    [4:0]   next_state;                       
reg            skip_en   ; //控制状态跳转使能信号
reg            error_en  ; //解析错误使能信号
reg    [4:0]   cnt       ; //解析数据计数器
reg    [47:0]  des_mac_t ; //接收到的目的MAC地址
reg    [31:0]  des_ip_t  ; //接收到的目的IP地址
reg    [47:0]  src_mac_t ; //接收到的源MAC地址
reg    [31:0]  src_ip_t  ; //接收到的源IP地址
reg    [15:0]  eth_type  ; //以太网类型
reg    [15:0]  op_data   ; //操作码//*****************************************************
//**                    main code
//*****************************************************//(三段式状态机)同步时序描述状态转移
always @(posedge clk or negedge rst_n) beginif(!rst_n)cur_state <= st_idle;  elsecur_state <= next_state;
end//组合逻辑判断状态转移条件
always @(*) beginnext_state = st_idle;case(cur_state)st_idle : begin                     //等待接收前导码if(skip_en) next_state = st_preamble;elsenext_state = st_idle;    endst_preamble : begin                 //接收前导码if(skip_en) next_state = st_eth_head;else if(error_en) next_state = st_rx_end;    elsenext_state = st_preamble;   endst_eth_head : begin                 //接收以太网帧头if(skip_en) next_state = st_arp_data;else if(error_en) next_state = st_rx_end;elsenext_state = st_eth_head;   end  st_arp_data : begin                  //接收ARP数据if(skip_en)next_state = st_rx_end;else if(error_en)next_state = st_rx_end;elsenext_state = st_arp_data;   end                  st_rx_end : begin                   //接收结束if(skip_en)next_state = st_idle;elsenext_state = st_rx_end;          enddefault : next_state = st_idle;endcase                                          
end    //时序电路描述状态输出,解析以太网数据
always @(posedge clk or negedge rst_n) beginif(!rst_n) beginskip_en <= 1'b0;error_en <= 1'b0;cnt <= 5'd0;des_mac_t <= 48'd0;des_ip_t <= 32'd0;src_mac_t <= 48'd0;src_ip_t <= 32'd0;        eth_type <= 16'd0;op_data <= 16'd0;arp_rx_done <= 1'b0;arp_rx_type <= 1'b0;src_mac <= 48'd0;src_ip <= 32'd0;endelse beginskip_en <= 1'b0;error_en <= 1'b0;  arp_rx_done <= 1'b0;case(next_state)st_idle : begin                                  //检测到第一个8'h55if((gmii_rx_dv == 1'b1) && (gmii_rxd == 8'h55)) skip_en <= 1'b1;else;endst_preamble : beginif(gmii_rx_dv) begin                         //解析前导码cnt <= cnt + 5'd1;if((cnt < 5'd6) && (gmii_rxd != 8'h55))  //7个8'h55  error_en <= 1'b1;else if(cnt==5'd6) begincnt <= 5'd0;if(gmii_rxd==8'hd5)                  //1个8'hd5skip_en <= 1'b1;elseerror_en <= 1'b1;    endelse;end else;endst_eth_head : beginif(gmii_rx_dv) begincnt <= cnt + 5'b1;if(cnt < 5'd6) des_mac_t <= {des_mac_t[39:0],gmii_rxd};else if(cnt == 5'd6) begin//判断MAC地址是否为开发板MAC地址或者公共地址if((des_mac_t != BOARD_MAC)&& (des_mac_t != 48'hff_ff_ff_ff_ff_ff))           error_en <= 1'b1;endelse if(cnt == 5'd12) eth_type[15:8] <= gmii_rxd;          //以太网协议类型else if(cnt == 5'd13) begineth_type[7:0] <= gmii_rxd;cnt <= 5'd0;if(eth_type[15:8] == ETH_TPYE[15:8]  //判断是否为ARP协议&& gmii_rxd == ETH_TPYE[7:0])skip_en <= 1'b1; elseerror_en <= 1'b1;                       end else;end  else;endst_arp_data : beginif(gmii_rx_dv) begincnt <= cnt + 5'd1;if(cnt == 5'd6) op_data[15:8] <= gmii_rxd;           //操作码       else if(cnt == 5'd7)op_data[7:0] <= gmii_rxd;else if(cnt >= 5'd8 && cnt < 5'd14)      //源MAC地址src_mac_t <= {src_mac_t[39:0],gmii_rxd};else if(cnt >= 5'd14 && cnt < 5'd18)     //源IP地址src_ip_t<= {src_ip_t[23:0],gmii_rxd};else if(cnt >= 5'd24 && cnt < 5'd28)     //目标IP地址des_ip_t <= {des_ip_t[23:0],gmii_rxd};else if(cnt == 5'd28) begincnt <= 5'd0;if(des_ip_t == BOARD_IP) begin       //判断目的IP地址和操作码if((op_data == 16'd1) || (op_data == 16'd2)) beginskip_en <= 1'b1;arp_rx_done <= 1'b1;src_mac <= src_mac_t;src_ip <= src_ip_t;src_mac_t <= 48'd0;src_ip_t <= 32'd0;des_mac_t <= 48'd0;des_ip_t <= 32'd0;if(op_data == 16'd1)         arp_rx_type <= 1'b0;     //ARP请求elsearp_rx_type <= 1'b1;     //ARP应答endelseerror_en <= 1'b1;end elseerror_en <= 1'b1;endelse;endelse;endst_rx_end : begin     cnt <= 5'd0;//单包数据接收完成   if(gmii_rx_dv == 1'b0 && skip_en == 1'b0)skip_en <= 1'b1; else;end    default : ;endcase                                                        end
endendmodule

arp_tx.v

module arp_tx( input                clk        , //时钟信号input                rst_n      , //复位信号,低电平有效input                arp_tx_en  , //ARP发送使能信号input                arp_tx_type, //ARP发送类型 0:请求  1:应答input        [47:0]  des_mac    , //发送的目标MAC地址input        [31:0]  des_ip     , //发送的目标IP地址input        [31:0]  crc_data   , //CRC校验数据input         [7:0]  crc_next   , //CRC下次校验完成数据output  reg          tx_done    , //以太网发送完成信号output  reg          gmii_tx_en , //GMII输出数据有效信号output  reg  [7:0]   gmii_txd   , //GMII输出数据output  reg          crc_en     , //CRC开始校验使能output  reg          crc_clr      //CRC数据复位信号 );//parameter define
//开发板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.102     
parameter  DES_IP    = {8'd192,8'd168,8'd1,8'd102};localparam  st_idle      = 5'b0_0001; //初始状态,等待开始发送信号
localparam  st_preamble  = 5'b0_0010; //发送前导码+帧起始界定符
localparam  st_eth_head  = 5'b0_0100; //发送以太网帧头
localparam  st_arp_data  = 5'b0_1000; //
localparam  st_crc       = 5'b1_0000; //发送CRC校验值localparam  ETH_TYPE     = 16'h0806 ; //以太网帧类型 ARP协议
localparam  HD_TYPE      = 16'h0001 ; //硬件类型 以太网
localparam  PROTOCOL_TYPE= 16'h0800 ; //上层协议为IP协议
//以太网数据最小为46个字节,不足部分填充数据
localparam  MIN_DATA_NUM = 16'd46   ;    //reg define
reg  [4:0]  cur_state     ;
reg  [4:0]  next_state    ;reg  [7:0]  preamble[7:0] ; //前导码+SFD
reg  [7:0]  eth_head[13:0]; //以太网首部
reg  [7:0]  arp_data[27:0]; //ARP数据reg         tx_en_d0      ; //arp_tx_en信号延时
reg         tx_en_d1      ; 
reg			tx_en_d2	  ;
reg         skip_en       ; //控制状态跳转使能信号
reg  [5:0]  cnt           ; 
reg  [4:0]  data_cnt      ; //发送数据个数计数器
reg         tx_done_t     ; //wire define                   
wire        pos_tx_en     ; //arp_tx_en信号上升沿//*****************************************************
//**                    main code
//*****************************************************assign  pos_tx_en = (~tx_en_d2) & tx_en_d1;//对arp_tx_en信号延时打拍两次,用于采arp_tx_en的上升沿
always @(posedge clk or negedge rst_n) beginif(!rst_n) begintx_en_d0 <= 1'b0;tx_en_d1 <= 1'b0;tx_en_d2 <= 1'b0;end    else begintx_en_d0 <= arp_tx_en;tx_en_d1 <= tx_en_d0;tx_en_d2 <= tx_en_d1;end
end //(三段式状态机)同步时序描述状态转移
always @(posedge clk or negedge rst_n) beginif(!rst_n)cur_state <= st_idle;  elsecur_state <= next_state;
end//组合逻辑判断状态转移条件
always @(*) beginnext_state = st_idle;case(cur_state)st_idle : begin                     //空闲状态if(skip_en)                next_state = st_preamble;elsenext_state = st_idle;end                          st_preamble : begin                 //发送前导码+帧起始界定符if(skip_en)next_state = st_eth_head;elsenext_state = st_preamble;      endst_eth_head : begin                 //发送以太网首部if(skip_en)next_state = st_arp_data;elsenext_state = st_eth_head;      end              st_arp_data : begin                 //发送ARP数据                      if(skip_en)next_state = st_crc;elsenext_state = st_arp_data;      endst_crc: begin                       //发送CRC校验值if(skip_en)next_state = st_idle;elsenext_state = st_crc;      enddefault : next_state = st_idle;   endcase
end                      //时序电路描述状态输出,发送以太网数据
always @(posedge clk or negedge rst_n) beginif(!rst_n) beginskip_en <= 1'b0; cnt <= 6'd0;data_cnt <= 5'd0;crc_en <= 1'b0;gmii_tx_en <= 1'b0;gmii_txd <= 8'd0;tx_done_t <= 1'b0; //初始化数组    //前导码 7个8'h55 + 1个8'hd5 preamble[0] <= 8'h55;                preamble[1] <= 8'h55;preamble[2] <= 8'h55;preamble[3] <= 8'h55;preamble[4] <= 8'h55;preamble[5] <= 8'h55;preamble[6] <= 8'h55;preamble[7] <= 8'hd5;//以太网帧头 eth_head[0] <= DES_MAC[47:40];      //目的MAC地址eth_head[1] <= DES_MAC[39:32];eth_head[2] <= DES_MAC[31:24];eth_head[3] <= DES_MAC[23:16];eth_head[4] <= DES_MAC[15:8];eth_head[5] <= DES_MAC[7:0];        eth_head[6] <= BOARD_MAC[47:40];    //源MAC地址eth_head[7] <= BOARD_MAC[39:32];    eth_head[8] <= BOARD_MAC[31:24];    eth_head[9] <= BOARD_MAC[23:16];    eth_head[10] <= BOARD_MAC[15:8];    eth_head[11] <= BOARD_MAC[7:0];     eth_head[12] <= ETH_TYPE[15:8];     //以太网帧类型eth_head[13] <= ETH_TYPE[7:0];      //ARP数据                           arp_data[0] <= HD_TYPE[15:8];       //硬件类型arp_data[1] <= HD_TYPE[7:0];arp_data[2] <= PROTOCOL_TYPE[15:8]; //上层协议类型arp_data[3] <= PROTOCOL_TYPE[7:0];arp_data[4] <= 8'h06;               //硬件地址长度,6arp_data[5] <= 8'h04;               //协议地址长度,4arp_data[6] <= 8'h00;               //OP,操作码 8'h01:ARP请求 8'h02:ARP应答arp_data[7] <= 8'h01;arp_data[8] <= BOARD_MAC[47:40];    //发送端(源)MAC地址arp_data[9] <= BOARD_MAC[39:32];arp_data[10] <= BOARD_MAC[31:24];arp_data[11] <= BOARD_MAC[23:16];arp_data[12] <= BOARD_MAC[15:8];arp_data[13] <= BOARD_MAC[7:0];arp_data[14] <= BOARD_IP[31:24];    //发送端(源)IP地址arp_data[15] <= BOARD_IP[23:16];arp_data[16] <= BOARD_IP[15:8];arp_data[17] <= BOARD_IP[7:0];arp_data[18] <= DES_MAC[47:40];     //接收端(目的)MAC地址arp_data[19] <= DES_MAC[39:32];arp_data[20] <= DES_MAC[31:24];arp_data[21] <= DES_MAC[23:16];arp_data[22] <= DES_MAC[15:8];arp_data[23] <= DES_MAC[7:0];  arp_data[24] <= DES_IP[31:24];      //接收端(目的)IP地址arp_data[25] <= DES_IP[23:16];arp_data[26] <= DES_IP[15:8];arp_data[27] <= DES_IP[7:0];endelse beginskip_en <= 1'b0;crc_en <= 1'b0;gmii_tx_en <= 1'b0;tx_done_t <= 1'b0;case(next_state)st_idle : beginif(pos_tx_en) beginskip_en <= 1'b1;  //如果目标MAC地址和IP地址已经更新,则发送正确的地址if((des_mac != 48'b0) || (des_ip != 32'd0)) begineth_head[0] <= des_mac[47:40];eth_head[1] <= des_mac[39:32];eth_head[2] <= des_mac[31:24];eth_head[3] <= des_mac[23:16];eth_head[4] <= des_mac[15:8];eth_head[5] <= des_mac[7:0];  arp_data[18] <= des_mac[47:40];arp_data[19] <= des_mac[39:32];arp_data[20] <= des_mac[31:24];arp_data[21] <= des_mac[23:16];arp_data[22] <= des_mac[15:8];arp_data[23] <= des_mac[7:0];  arp_data[24] <= des_ip[31:24];arp_data[25] <= des_ip[23:16];arp_data[26] <= des_ip[15:8];arp_data[27] <= des_ip[7:0];endelse;if(arp_tx_type == 1'b0)arp_data[7] <= 8'h01;            //ARP请求 else arp_data[7] <= 8'h02;            //ARP应答end else;end                                                                   st_preamble : begin                          //发送前导码+帧起始界定符gmii_tx_en <= 1'b1;gmii_txd <= preamble[cnt];if(cnt == 6'd7) begin                        skip_en <= 1'b1;cnt <= 1'b0;    endelse    cnt <= cnt + 1'b1;                     endst_eth_head : begin                          //发送以太网首部gmii_tx_en <= 1'b1;crc_en <= 1'b1;gmii_txd <= eth_head[cnt];if (cnt == 6'd13) beginskip_en <= 1'b1;cnt <= 1'b0;end    else    cnt <= cnt + 1'b1;    end                    st_arp_data : begin                          //发送ARP数据  crc_en <= 1'b1;gmii_tx_en <= 1'b1;//至少发送46个字节if (cnt == MIN_DATA_NUM - 1'b1) begin    skip_en <= 1'b1;cnt <= 1'b0;data_cnt <= 1'b0;end    else    cnt <= cnt + 1'b1;  if(data_cnt <= 6'd27) begindata_cnt <= data_cnt + 1'b1;gmii_txd <= arp_data[data_cnt];end    elsegmii_txd <= 8'd0;                    //Padding,填充0endst_crc      : begin                          //发送CRC校验值gmii_tx_en <= 1'b1;cnt <= cnt + 1'b1;if(cnt == 6'd0)gmii_txd <= {~crc_next[0], ~crc_next[1], ~crc_next[2],~crc_next[3],~crc_next[4], ~crc_next[5], ~crc_next[6],~crc_next[7]};else if(cnt == 6'd1)gmii_txd <= {~crc_data[16], ~crc_data[17], ~crc_data[18],~crc_data[19], ~crc_data[20], ~crc_data[21], ~crc_data[22],~crc_data[23]};else if(cnt == 6'd2) begingmii_txd <= {~crc_data[8], ~crc_data[9], ~crc_data[10],~crc_data[11],~crc_data[12], ~crc_data[13], ~crc_data[14],~crc_data[15]};                              endelse if(cnt == 6'd3) begingmii_txd <= {~crc_data[0], ~crc_data[1], ~crc_data[2],~crc_data[3],~crc_data[4], ~crc_data[5], ~crc_data[6],~crc_data[7]};  tx_done_t <= 1'b1;skip_en <= 1'b1;cnt <= 1'b0;end   else;end                          default :;  endcase                                             end
end            //发送完成信号及crc值复位信号
always @(posedge clk or negedge rst_n) beginif(!rst_n) begintx_done <= 1'b0;crc_clr <= 1'b0;endelse begintx_done <= tx_done_t;crc_clr <= tx_done_t;end
endendmodule

arp.v

module arp(input                rst_n      , //复位信号,低电平有效//GMII接口input                gmii_rx_clk, //GMII接收数据时钟input                gmii_rx_dv , //GMII输入数据有效信号input        [7:0]   gmii_rxd   , //GMII输入数据input                gmii_tx_clk, //GMII发送数据时钟output               gmii_tx_en , //GMII输出数据有效信号output       [7:0]   gmii_txd   , //GMII输出数据          //用户接口output               arp_rx_done, //ARP接收完成信号output               arp_rx_type, //ARP接收类型 0:请求  1:应答output       [47:0]  src_mac    , //接收到目的MAC地址output       [31:0]  src_ip     , //接收到目的IP地址    input                arp_tx_en  , //ARP发送使能信号input                arp_tx_type, //ARP发送类型 0:请求  1:应答input        [47:0]  des_mac    , //发送的目标MAC地址input        [31:0]  des_ip     , //发送的目标IP地址output               tx_done      //以太网发送完成信号    );//parameter define
//开发板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.102     
parameter  DES_IP    = {8'd192,8'd168,8'd1,8'd102};//wire define
wire           crc_en  ; //CRC开始校验使能
wire           crc_clr ; //CRC数据复位信号 
wire   [7:0]   crc_d8  ; //输入待校验8位数据
wire   [31:0]  crc_data; //CRC校验数据
wire   [31:0]  crc_next; //CRC下次校验完成数据//*****************************************************
//**                    main code
//*****************************************************assign  crc_d8 = gmii_txd;//ARP接收模块    
arp_rx #(.BOARD_MAC       (BOARD_MAC),         //参数例化.BOARD_IP        (BOARD_IP ))u_arp_rx(.clk             (gmii_rx_clk),.rst_n           (rst_n),.gmii_rx_dv      (gmii_rx_dv),.gmii_rxd        (gmii_rxd  ),.arp_rx_done     (arp_rx_done),.arp_rx_type     (arp_rx_type),.src_mac         (src_mac    ),.src_ip          (src_ip     ));                                           //ARP发送模块
arp_tx#(.BOARD_MAC       (BOARD_MAC),         //参数例化.BOARD_IP        (BOARD_IP ),.DES_MAC         (DES_MAC  ),.DES_IP          (DES_IP   ))u_arp_tx(.clk             (gmii_tx_clk),.rst_n           (rst_n),.arp_tx_en       (arp_tx_en ),.arp_tx_type     (arp_tx_type),.des_mac         (des_mac   ),.des_ip          (des_ip    ),.crc_data        (crc_data  ),.crc_next        (crc_next[31:24]),.tx_done         (tx_done   ),.gmii_tx_en      (gmii_tx_en),.gmii_txd        (gmii_txd  ),.crc_en          (crc_en    ),.crc_clr         (crc_clr   ));     //以太网发送CRC校验模块
crc32_d8   u_crc32_d8(.clk             (gmii_tx_clk),                      .rst_n           (rst_n      ),                          .data            (crc_d8     ),            .crc_en          (crc_en     ),                          .crc_clr         (crc_clr    ),                         .crc_data        (crc_data   ),                        .crc_next        (crc_next   )                         );endmodule

crc_32_d8.v

module crc32_d8(input                 clk     ,  //时钟信号input                 rst_n   ,  //复位信号,低电平有效input         [7:0]   data    ,  //输入待校验8位数据input                 crc_en  ,  //crc使能,开始校验标志input                 crc_clr ,  //crc数据复位信号output   reg  [31:0]  crc_data,  //CRC校验数据output        [31:0]  crc_next   //CRC下次校验完成数据);//*****************************************************//**                    main code//*****************************************************//输入待校验8位数据,需要先将高低位互换wire    [7:0]  data_t;assign data_t = {data[0],data[1],data[2],data[3],data[4],data[5],data[6],data[7]};//CRC32的生成多项式为:G(x)= x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11//+ x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1assign crc_next[0] = crc_data[24] ^ crc_data[30] ^ data_t[0] ^ data_t[6];assign crc_next[1] = crc_data[24] ^ crc_data[25] ^ crc_data[30] ^ crc_data[31]^ data_t[0] ^ data_t[1] ^ data_t[6] ^ data_t[7];assign crc_next[2] = crc_data[24] ^ crc_data[25] ^ crc_data[26] ^ crc_data[30]^ crc_data[31] ^ data_t[0] ^ data_t[1] ^ data_t[2] ^ data_t[6]^ data_t[7];assign crc_next[3] = crc_data[25] ^ crc_data[26] ^ crc_data[27] ^ crc_data[31]^ data_t[1] ^ data_t[2] ^ data_t[3] ^ data_t[7];assign crc_next[4] = crc_data[24] ^ crc_data[26] ^ crc_data[27] ^ crc_data[28]^ crc_data[30] ^ data_t[0] ^ data_t[2] ^ data_t[3] ^ data_t[4]^ data_t[6];assign crc_next[5] = crc_data[24] ^ crc_data[25] ^ crc_data[27] ^ crc_data[28]^ crc_data[29] ^ crc_data[30] ^ crc_data[31] ^ data_t[0]^ data_t[1] ^ data_t[3] ^ data_t[4] ^ data_t[5] ^ data_t[6]^ data_t[7];assign crc_next[6] = crc_data[25] ^ crc_data[26] ^ crc_data[28] ^ crc_data[29]^ crc_data[30] ^ crc_data[31] ^ data_t[1] ^ data_t[2] ^ data_t[4]^ data_t[5] ^ data_t[6] ^ data_t[7];assign crc_next[7] = crc_data[24] ^ crc_data[26] ^ crc_data[27] ^ crc_data[29]^ crc_data[31] ^ data_t[0] ^ data_t[2] ^ data_t[3] ^ data_t[5]^ data_t[7];assign crc_next[8] = crc_data[0] ^ crc_data[24] ^ crc_data[25] ^ crc_data[27]^ crc_data[28] ^ data_t[0] ^ data_t[1] ^ data_t[3] ^ data_t[4];assign crc_next[9] = crc_data[1] ^ crc_data[25] ^ crc_data[26] ^ crc_data[28]^ crc_data[29] ^ data_t[1] ^ data_t[2] ^ data_t[4] ^ data_t[5];assign crc_next[10] = crc_data[2] ^ crc_data[24] ^ crc_data[26] ^ crc_data[27]^ crc_data[29] ^ data_t[0] ^ data_t[2] ^ data_t[3] ^ data_t[5];assign crc_next[11] = crc_data[3] ^ crc_data[24] ^ crc_data[25] ^ crc_data[27]^ crc_data[28] ^ data_t[0] ^ data_t[1] ^ data_t[3] ^ data_t[4];assign crc_next[12] = crc_data[4] ^ crc_data[24] ^ crc_data[25] ^ crc_data[26]^ crc_data[28] ^ crc_data[29] ^ crc_data[30] ^ data_t[0]^ data_t[1] ^ data_t[2] ^ data_t[4] ^ data_t[5] ^ data_t[6];assign crc_next[13] = crc_data[5] ^ crc_data[25] ^ crc_data[26] ^ crc_data[27]^ crc_data[29] ^ crc_data[30] ^ crc_data[31] ^ data_t[1]^ data_t[2] ^ data_t[3] ^ data_t[5] ^ data_t[6] ^ data_t[7];assign crc_next[14] = crc_data[6] ^ crc_data[26] ^ crc_data[27] ^ crc_data[28]^ crc_data[30] ^ crc_data[31] ^ data_t[2] ^ data_t[3] ^ data_t[4]^ data_t[6] ^ data_t[7];assign crc_next[15] =  crc_data[7] ^ crc_data[27] ^ crc_data[28] ^ crc_data[29]^ crc_data[31] ^ data_t[3] ^ data_t[4] ^ data_t[5] ^ data_t[7];assign crc_next[16] = crc_data[8] ^ crc_data[24] ^ crc_data[28] ^ crc_data[29]^ data_t[0] ^ data_t[4] ^ data_t[5];assign crc_next[17] = crc_data[9] ^ crc_data[25] ^ crc_data[29] ^ crc_data[30]^ data_t[1] ^ data_t[5] ^ data_t[6];assign crc_next[18] = crc_data[10] ^ crc_data[26] ^ crc_data[30] ^ crc_data[31]^ data_t[2] ^ data_t[6] ^ data_t[7];assign crc_next[19] = crc_data[11] ^ crc_data[27] ^ crc_data[31] ^ data_t[3] ^ data_t[7];assign crc_next[20] = crc_data[12] ^ crc_data[28] ^ data_t[4];assign crc_next[21] = crc_data[13] ^ crc_data[29] ^ data_t[5];assign crc_next[22] = crc_data[14] ^ crc_data[24] ^ data_t[0];assign crc_next[23] = crc_data[15] ^ crc_data[24] ^ crc_data[25] ^ crc_data[30]^ data_t[0] ^ data_t[1] ^ data_t[6];assign crc_next[24] = crc_data[16] ^ crc_data[25] ^ crc_data[26] ^ crc_data[31]^ data_t[1] ^ data_t[2] ^ data_t[7];assign crc_next[25] = crc_data[17] ^ crc_data[26] ^ crc_data[27] ^ data_t[2] ^ data_t[3];assign crc_next[26] = crc_data[18] ^ crc_data[24] ^ crc_data[27] ^ crc_data[28]^ crc_data[30] ^ data_t[0] ^ data_t[3] ^ data_t[4] ^ data_t[6];assign crc_next[27] = crc_data[19] ^ crc_data[25] ^ crc_data[28] ^ crc_data[29]^ crc_data[31] ^ data_t[1] ^ data_t[4] ^ data_t[5] ^ data_t[7];assign crc_next[28] = crc_data[20] ^ crc_data[26] ^ crc_data[29] ^ crc_data[30]^ data_t[2] ^ data_t[5] ^ data_t[6];assign crc_next[29] = crc_data[21] ^ crc_data[27] ^ crc_data[30] ^ crc_data[31]^ data_t[3] ^ data_t[6] ^ data_t[7];assign crc_next[30] = crc_data[22] ^ crc_data[28] ^ crc_data[31] ^ data_t[4] ^ data_t[7];assign crc_next[31] = crc_data[23] ^ crc_data[29] ^ data_t[5];always @(posedge clk or negedge rst_n)beginif(!rst_n)crc_data <= 32'hff_ff_ff_ff;else if(crc_clr)                             //CRC校验值复位crc_data <= 32'hff_ff_ff_ff;else if(crc_en)crc_data <= crc_next;endendmodule

eth_ctrl.v

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输出数据//ICMP相关端口信号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                   //GMII输出数据);//reg definereg        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)beginif(!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)beginif(!rst_n)arp_rx_flag <= 1'b0;else if(arp_rx_done && (arp_rx_type == 1'b0))arp_rx_flag <= 1'b1;elsearp_rx_flag <= 1'b0;end//控制protocol_sw和arp_tx_en信号always @(posedge clk or negedge rst_n)beginif(!rst_n)beginprotocol_sw <= 1'b0;arp_tx_en <= 1'b0;endelsebeginarp_tx_en <= 1'b0;if(icmp_tx_start_en)protocol_sw <= 1'b1;else if(arp_rx_flag && (icmp_tx_busy == 1'b0))beginprotocol_sw <= 1'b0;arp_tx_en <= 1'b1;endendendendmodule

eth_icmp_test.v – 这是整个的top函数

module    eth_icmp_test(input                   sys_clk     ,input                   sys_rst_n   ,// PL 浠ュお缃?input                   eth_rxc     ,   // 鎺ユ敹鏃堕挓input                   eth_rx_ctl  ,   // 杈撳叆鏈夋晥鏃堕挓input     [3 : 0]       eth_rxd     ,output                  eth_txc     ,output                  eth_tx_ctl  ,output    [3 : 0]       eth_txd     ,output                  eth_rst_n);// -------------------------------------------- ////           parameter  and  define             //// -------------------------------------------- ////parameter define//寮?鍙戞澘MAC鍦板潃 00-11-22-33-44-55parameter  BOARD_MAC =        48'h00_11_22_33_44_55       ;//寮?鍙戞澘IP鍦板潃 192.168.1.10parameter  BOARD_IP  =        {8'd192,8'd168,8'd1,8'd10}  ;//鐩殑MAC鍦板潃 ff_ff_ff_ff_ff_ffparameter  DES_MAC   =        48'hff_ff_ff_ff_ff_ff       ;//鐩殑IP鍦板潃 192.168.1.102parameter  DES_IP    =        {8'd192,8'd168,8'd1,8'd102} ;//杈撳叆鏁版嵁IO寤舵椂,姝ゅ涓?0,鍗充笉寤舵椂(濡傛灉涓簄,琛ㄧず寤舵椂n*78ps)parameter IDELAY_VALUE    = 0;// define//wire definewire          clk_200m        ; //鐢ㄤ簬IO寤舵椂鐨勬椂閽?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          arp_gmii_tx_en  ; //ARP GMII杈撳嚭鏁版嵁鏈夋晥淇″彿wire  [7:0]   arp_gmii_txd    ; //ARP GMII杈撳嚭鏁版嵁wire          arp_rx_done     ; //ARP鎺ユ敹瀹屾垚淇″彿wire          arp_rx_type     ; //ARP鎺ユ敹绫诲瀷 0:璇锋眰  1:搴旂瓟wire  [47:0]  src_mac         ; //鎺ユ敹鍒扮洰鐨凪AC鍦板潃wire  [31:0]  src_ip          ; //鎺ユ敹鍒扮洰鐨処P鍦板潃wire          arp_tx_en       ; //ARP鍙戦?佷娇鑳戒俊鍙?wire          arp_tx_type     ; //ARP鍙戦?佺被鍨? 0:璇锋眰  1:搴旂瓟wire  [47:0]  des_mac         ; //鍙戦?佺殑鐩爣MAC鍦板潃wire  [31:0]  des_ip          ; //鍙戦?佺殑鐩爣IP鍦板潃wire          arp_tx_done     ; //ARP鍙戦?佸畬鎴愪俊鍙?wire          icmp_gmii_tx_en ; //ICMP GMII杈撳嚭鏁版嵁鏈夋晥淇″彿wire  [7:0]   icmp_gmii_txd   ; //ICMP GMII杈撳嚭鏁版嵁wire          rec_pkt_done    ; //ICMP鍗曞寘鏁版嵁鎺ユ敹瀹屾垚淇″彿wire          rec_en          ; //ICMP鎺ユ敹鐨勬暟鎹娇鑳戒俊鍙?wire  [ 7:0]  rec_data        ; //ICMP鎺ユ敹鐨勬暟鎹?wire  [15:0]  rec_byte_num    ; //ICMP鎺ユ敹鐨勬湁鏁堝瓧鑺傛暟 鍗曚綅:bytewire  [15:0]  tx_byte_num     ; //ICMP鍙戦?佺殑鏈夋晥瀛楄妭鏁? 鍗曚綅:bytewire          icmp_tx_done    ; //ICMP鍙戦?佸畬鎴愪俊鍙?wire          tx_req          ; //ICMP璇绘暟鎹姹備俊鍙?wire  [ 7:0]  tx_data         ; //ICMP寰呭彂閫佹暟鎹?wire          tx_start_en     ; //ICMP鍙戦?佸紑濮嬩娇鑳戒俊鍙?// ------------------------------------------ ////            next  is  main  code           //// ---------------------------------------- //assign   tx_start_en   =   rec_pkt_done  ;assign   tx_byte_num   =   rec_byte_num  ;assign   des_mac       =   src_mac       ;assign   des_ip        =   src_ip        ;assign   eth_rst_n     =   sys_rst_n     ;// 鏃堕挓clk_wiz_0  u_clk_wiz_0 (.clk_out1(clk_200m)      ,     // output clk_out1.reset(~sys_rst_n)       ,     // input reset.locked(locked)          ,     // output locked.clk_in1(sys_clk));//  gmii_to_rgmiigmii_to_rgmii u_gmii_to_rgmii(.idelay_clk   ( clk_200m   ),.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     ),.rgmii_rxc    ( eth_rxc    ),.rgmii_rx_ctl ( eth_rx_ctl ),.rgmii_rxd    ( eth_rxd    ),.rgmii_txc    ( eth_txc    ),.rgmii_tx_ctl ( eth_tx_ctl ),.rgmii_txd    ( eth_txd    ));// arp閫氫俊 
arp u_arp(.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  ( arp_gmii_tx_en  ),.gmii_txd    ( arp_gmii_txd    ),.arp_rx_done ( arp_rx_done ),.arp_rx_type ( arp_rx_type ),.src_mac     ( src_mac     ),.src_ip      ( src_ip      ),.arp_tx_en   ( arp_tx_en   ),.arp_tx_type ( arp_tx_type ),.des_mac     ( des_mac     ),.des_ip      ( des_ip      ),.tx_done     ( arp_tx_done     )
);// icmp閫氫俊 
icmp 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    ( icmp_gmii_tx_en    ),.gmii_txd      ( icmp_gmii_txd      ),.rec_pkt_done  ( rec_pkt_done  ),.rec_en        ( rec_en        ),.rec_data      ( rec_data      ),.rec_byte_num  ( 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       ( icmp_tx_done       ),.tx_req        ( tx_req        )
);鍚屾FIFO
//sync_fifo_2048x8b sync_fifo_2048x8b_inst (
fifo_generator_0 sync_fifo_2048x8b_inst (.clk(gmii_rx_clk),      	// input wire clk//.rst(~sys_rst_n),      	// input wire rst.srst(~sys_rst_n),      	// input wire rst.din(rec_data),     		// input wire [7 : 0] din.wr_en(rec_en),  			// input wire wr_en.rd_en(tx_req),  			// input wire rd_en.dout(tx_data),    		// output wire [7 : 0] dout.full(),    				// output wire full.empty()  				// output wire empty
);//eth鈥斺?攃trl 
eth_ctrl u_eth_ctrl(.clk               ( gmii_rx_clk               ),.rst_n             ( sys_rst_n             ),.arp_rx_done       ( arp_rx_done       ),.arp_rx_type       ( arp_rx_type       ),.arp_tx_en         ( arp_tx_en         ),.arp_tx_type       ( arp_tx_type       ),.arp_tx_done       ( arp_tx_done       ),.arp_gmii_tx_en    ( arp_gmii_tx_en    ),.arp_gmii_txd      ( arp_gmii_txd      ),.icmp_tx_start_en  ( tx_start_en  ),.icmp_tx_done      ( icmp_tx_done      ),.icmp_gmii_tx_en   ( icmp_gmii_tx_en   ),.icmp_gmii_txd     ( icmp_gmii_txd     ),.gmii_tx_en        ( gmii_tx_en        ),.gmii_txd          ( gmii_txd          )
);endmodule  

gmii_to_rgmii.v

module   gmii_to_rgmii(input              idelay_clk  , //IDELAY时钟//以太网GMII接口output             gmii_rx_clk , //GMII接收时钟output             gmii_rx_dv  , //GMII接收数据有效信号output      [7:0]  gmii_rxd    , //GMII接收数据output             gmii_tx_clk , //GMII发送时钟input              gmii_tx_en  , //GMII发送数据使能信号input       [7:0]  gmii_txd    , //GMII发送数据//以太网RGMII接口input              rgmii_rxc   , //RGMII接收时钟input              rgmii_rx_ctl, //RGMII接收数据控制信号input       [3:0]  rgmii_rxd   , //RGMII接收数据output             rgmii_txc   , //RGMII发送时钟output             rgmii_tx_ctl, //RGMII发送数据控制信号output      [3:0]  rgmii_txd     //RGMII发送数据);parameter  IDEAY_VALUE =  0 ; // ------------------------------------ //// -------------main  code ------------ //// ------------------------------------ //assign gmii_tx_clk  = gmii_rx_clk  ;  // rgmii 
rgmii_rx u_rgmii_rx(.idelay_clk    ( idelay_clk    ),.rgmii_rxc     ( rgmii_rxc     ),.rgmii_rx_ctl  ( rgmii_rx_ctl  ),.rgmii_rxd     ( rgmii_rxd     ),.gmii_rx_clk   ( gmii_rx_clk   ),.gmii_rx_dv    ( gmii_rx_dv    ),.gmii_rxd      ( gmii_rxd      )
);// gmii 
rgmii_tx u_rgmii_tx(.gmii_tx_clk   ( gmii_tx_clk   ),.gmii_tx_en    ( gmii_tx_en    ),.gmii_txd      ( gmii_txd      ),.rgmii_txc     ( rgmii_txc     ),.rgmii_tx_ctl  ( rgmii_tx_ctl  ),.rgmii_txd     ( rgmii_txd     )
);endmodule 

icmp_rx.v

module icmp_rx(input                clk         ,    //时钟信号input                rst_n       ,    //复位信号,低电平有效input                gmii_rx_dv  ,    //GMII输入数据有效信号input        [7:0]   gmii_rxd    ,    //GMII输入数据output  reg          rec_pkt_done,    //以太网单包数据接收完成信号output  reg          rec_en      ,    //以太网接收的数据使能信号output  reg  [ 7:0]  rec_data    ,    //以太网接收的数据output  reg  [15:0]  rec_byte_num,    //以太网接收的有效字数 单位:byte output  reg  [15:0]  icmp_id     ,    //ICMP标识符output  reg  [15:0]  icmp_seq    ,    //ICMP序列号output  reg  [31:0]  reply_checksum   //接收数据校验);//parameter define
//开发板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};//状态机状态定义
localparam  st_idle             = 7'b000_0001; //初始状态,等待接收前导码
localparam  st_preamble         = 7'b000_0010; //接收前导码状态 
localparam  st_eth_head         = 7'b000_0100; //接收以太网帧头
localparam  st_ip_head          = 7'b000_1000; //接收IP首部
localparam  st_icmp_head        = 7'b001_0000; //接收ICMP首部
localparam  st_rx_data          = 7'b010_0000; //接收有效数据
localparam  st_rx_end           = 7'b100_0000; //接收结束//以太网类型定义
localparam  ETH_TYPE    = 16'h0800   ; //以太网协议类型 IP协议
localparam  ICMP_TYPE   = 8'd1       ; //ICMP协议类型//ICMP报文类型:回显请求
localparam ECHO_REQUEST = 8'h08 ; //reg define
reg  [6:0]   cur_state       ;
reg  [6:0]   next_state      ;                             
reg          skip_en         ; //控制状态跳转使能信号
reg          error_en        ; //解析错误使能信号reg  [4:0]   cnt             ; //解析数据计数器
reg  [47:0]  des_mac         ; //目的MAC地址
reg  [15:0]  eth_type        ; //以太网类型
reg  [31:0]  des_ip          ; //目的IP地址
reg  [5:0]   ip_head_byte_num; //IP首部长度
reg  [15:0]  total_length    ; //IP长度 
reg  [1:0]   rec_en_cnt      ; //8bit转32bit计数器
reg  [7:0]   icmp_type        ; //ICMP报文类型:用于标识错误类型的差错报文或者查询类型的报告报文
reg  [7:0]   icmp_code        ; //ICMP报文代码:根据ICMP差错报文的类型,进一步分析错误的原因,代码值不同对应的错误也不同//例如:类型为11且代码为0,表示数据传输过程中超时了,超时的具体原因是TTL值为0,数据报被丢弃。
reg  [15:0]  icmp_checksum    ; //接收校验和:数据发送到目的地后需要对ICMP数据报文做一个校验,用于检查数据报文是否有错误
reg  [15:0]  icmp_data_length ; //data length register
reg  [15:0]  icmp_rx_cnt      ; //接收数据计数
reg  [7:0]   icmp_rx_data_d0  ;
reg  [31:0]  reply_checksum_add ;
//****************************************************
//**                    main code
//*****************************************************//(三段式状态机)同步时序描述状态转移
always @(posedge clk or negedge rst_n) beginif(!rst_n)cur_state <= st_idle;  elsecur_state <= next_state;
end//组合逻辑判断状态转移条件
always @(*) beginnext_state = st_idle;case(cur_state)st_idle : begin                       //等待接收前导码if(skip_en) next_state = st_preamble;elsenext_state = st_idle; endst_preamble : begin                   //接收前导码if(skip_en) next_state = st_eth_head;else if(error_en) next_state = st_rx_end; elsenext_state = st_preamble; endst_eth_head : begin                   //接收以太网帧头if(skip_en) next_state = st_ip_head;else if(error_en) next_state = st_rx_end;elsenext_state = st_eth_head; end  st_ip_head : begin                    //接收IP首部if(skip_en)next_state = st_icmp_head;else if(error_en)next_state = st_rx_end;elsenext_state = st_ip_head; end st_icmp_head : begin                   //接收ICMP首部if(skip_en)next_state = st_rx_data;else if(error_en)next_state = st_rx_end;elsenext_state = st_icmp_head;end st_rx_data : begin                    //接收有效数据if(skip_en)next_state = st_rx_end;elsenext_state = st_rx_data; end st_rx_end : begin                     //接收结束if(skip_en)next_state = st_idle;elsenext_state = st_rx_end;enddefault : next_state = st_idle;endcase 
end //时序电路描述状态输出,解析以太网数据
always @(posedge clk or negedge rst_n) beginif(!rst_n) beginskip_en <= 1'b0;error_en <= 1'b0;cnt <= 5'd0;des_mac <= 48'd0;eth_type <= 16'd0;des_ip <= 32'd0;ip_head_byte_num <= 6'd0;total_length <= 16'd0;icmp_type <= 8'd0;icmp_code <= 8'd0;icmp_checksum <= 16'd0;icmp_id <= 16'd0;icmp_seq <= 16'd0;icmp_rx_data_d0 <= 8'd0 ;reply_checksum <= 32'd0;  //累加reply_checksum_add <= 32'd0;icmp_rx_cnt <= 16'd0;icmp_data_length <= 16'd0;rec_en_cnt <= 2'd0;rec_en <= 1'b0;rec_data <= 32'd0;rec_pkt_done <= 1'b0;rec_byte_num <= 16'd0;endelse beginskip_en <= 1'b0;error_en <= 1'b0;  rec_pkt_done <= 1'b0;case(next_state)st_idle : beginif((gmii_rx_dv == 1'b1) && (gmii_rxd == 8'h55)) skip_en <= 1'b1;else;endst_preamble : beginif(gmii_rx_dv) begin                         //解析前导码cnt <= cnt + 5'd1;if((cnt < 5'd6) && (gmii_rxd != 8'h55))  //7个8'h55error_en <= 1'b1;else if(cnt==5'd6) begincnt <= 5'd0;if(gmii_rxd==8'hd5)                  //1个8'hd5skip_en <= 1'b1;elseerror_en <= 1'b1; end  else;end  endst_eth_head : beginif(gmii_rx_dv) begincnt <= cnt + 5'b1;if(cnt < 5'd6) des_mac <= {des_mac[39:0],gmii_rxd}; //目的MAC地址else if(cnt == 5'd12) eth_type[15:8] <= gmii_rxd;          //以太网协议类型else if(cnt == 5'd13) begineth_type[7:0] <= gmii_rxd;cnt <= 5'd0;//判断MAC地址是否为开发板MAC地址或者公共地址if(((des_mac == BOARD_MAC) ||(des_mac == 48'hff_ff_ff_ff_ff_ff))&& eth_type[15:8] == ETH_TYPE[15:8] && gmii_rxd == ETH_TYPE[7:0])skip_en <= 1'b1;elseerror_en <= 1'b1;end else;end else;endst_ip_head : beginif(gmii_rx_dv) begin  //cnt ip首20个byte计数cnt <= cnt + 5'd1;if(cnt == 5'd0)ip_head_byte_num <= {gmii_rxd[3:0],2'd0}; // ip首位长度表示有多少个(4字节 ) 这里就是多少位了else if (cnt == 5'd2) total_length[15:8] <= gmii_rxd;else if (cnt == 5'd3)total_length[7:0] <= gmii_rxd;else if (cnt == 5'd4)//有效数据字节长度,(IP首部20个字节,icmp首部8个字节,所以减去28)icmp_data_length <= total_length - 16'd28; else if(cnt == 5'd9) beginif(gmii_rxd != ICMP_TYPE) begin//如果当前接收的数据不是ICMP协议,停止解析数据                        error_en <= 1'b1;               cnt <= 5'd0;                        endendelse if((cnt >= 5'd16) && (cnt <= 5'd18))des_ip <= {des_ip[23:0],gmii_rxd};   //目的IP地址else if(cnt == 5'd19) begindes_ip <= {des_ip[23:0],gmii_rxd}; //判断IP地址是否为开发板IP地址if((des_ip[23:0] == BOARD_IP[31:8])&& (gmii_rxd == BOARD_IP[7:0])) begin  skip_en <=1'b1; cnt <= 5'd0;end else begin //IP错误,停止解析数据 error_en <= 1'b1; cnt <= 5'd0;end end else;end else;endst_icmp_head : beginif(gmii_rx_dv) begin  //cnt ICMP首8个byte计数cnt <= cnt + 5'd1;if(cnt == 5'd0)icmp_type <= gmii_rxd;else if(cnt == 5'd1)icmp_code <= gmii_rxd ;else if(cnt == 5'd2)icmp_checksum[15:8] <= gmii_rxd;else if(cnt == 5'd3)icmp_checksum[7:0] <= gmii_rxd;else if(cnt == 5'd4)icmp_id[15:8] <= gmii_rxd;else if(cnt == 5'd5)icmp_id[7:0] <= gmii_rxd;else if(cnt == 5'd6)icmp_seq[15:8] <= gmii_rxd;else if(cnt == 5'd7)beginicmp_seq[7:0] <= gmii_rxd;//判断ICMP报文类型是否是回显请求if(icmp_type == ECHO_REQUEST) beginskip_en <=1'b1;cnt <= 5'd0;end else begin //ICMP报文类型错误,停止解析数据error_en <= 1'b1; cnt <= 5'd0;end end else;end else;end st_rx_data : begin         //接收数据           if(gmii_rx_dv) beginrec_en_cnt <= rec_en_cnt + 2'd1;icmp_rx_cnt <= icmp_rx_cnt + 16'd1;rec_data <= gmii_rxd;rec_en <= 1'b1;//判断接收到数据的奇偶个数if (icmp_rx_cnt == icmp_data_length - 1) begin                      icmp_rx_data_d0 <= 8'h00;if(icmp_data_length[0])		//判断接收到数据是否为奇数个数reply_checksum_add <= {8'd0,gmii_rxd} + reply_checksum_add;                           elsereply_checksum_add <= {icmp_rx_data_d0,gmii_rxd} + reply_checksum_add;    endelse if(icmp_rx_cnt < icmp_data_length) beginicmp_rx_data_d0 <= gmii_rxd;icmp_rx_cnt <= icmp_rx_cnt + 16'd1;if (icmp_rx_cnt[0] == 1'b1)reply_checksum_add <= {icmp_rx_data_d0,gmii_rxd} + reply_checksum_add; elsereply_checksum_add <= reply_checksum_add; endelse;if(icmp_rx_cnt == icmp_data_length - 16'd1) beginskip_en <= 1'b1;                    //有效数据接收完成icmp_rx_cnt <= 16'd0;rec_en_cnt <= 2'd0;rec_pkt_done <= 1'b1;               rec_byte_num <= icmp_data_length;end else;endelse;endst_rx_end : begin                               //单包数据接收完成rec_en <= 1'b0;if(gmii_rx_dv == 1'b0 && skip_en == 1'b0)beginreply_checksum <= reply_checksum_add ;skip_en <= 1'b1;reply_checksum_add <= 32'd0;endelse;end    default : ;endcaseend
endendmodule

icmp_tx.v

module icmp_tx(    input                clk        , //时钟信号input                rst_n      , //复位信号,低电平有效input        [31:0]  reply_checksum, //ICMP数据部分校验和input        [15:0]  icmp_id       , //ICMP标识符input        [15:0]  icmp_seq      , //ICMP序列号input                tx_start_en   , //以太网开始发送信号input        [ 7:0]  tx_data       , //以太网待发送数据input        [15:0]  tx_byte_num   , //以太网发送的有效字节数input        [47:0]  des_mac       , //发送的目标MAC地址input        [31:0]  des_ip        , //发送的目标IP地址input        [31:0]  crc_data      , //CRC校验数据input         [7:0]  crc_next      , //CRC下次校验完成数据output  reg          tx_done       , //以太网发送完成信号output  reg          tx_req        , //读数据请求信号output  reg          gmii_tx_en    , //GMII输出数据有效信号output  reg  [7:0]   gmii_txd      , //GMII输出数据output  reg          crc_en        , //CRC开始校验使能output  reg          crc_clr         //CRC数据复位信号);//parameter define
//开发板MAC地址 00-11-22-33-44-55
parameter BOARD_MAC = 48'h00_11_22_33_44_55;
//开发板IP地址 192.168.1.123     
parameter BOARD_IP  = {8'd192,8'd168,8'd1,8'd123};
//目的MAC地址 ff_ff_ff_ff_ff_ff
parameter DES_MAC   = 48'hff_ff_ff_ff_ff_ff;
//目的IP地址 192.168.1.102     
parameter DES_IP    = {8'd192,8'd168,8'd1,8'd102};//状态机状态定义
localparam st_idle       = 8'b0000_0001; //初始状态,等待开始发送信号
localparam st_check_sum  = 8'b0000_0010; //IP首部校验和
localparam st_check_icmp = 8'b0000_0100; //ICMP首部+数据校验
localparam st_preamble   = 8'b0000_1000; //发送前导码+帧起始界定符
localparam st_eth_head   = 8'b0001_0000; //发送以太网帧头
localparam st_ip_head    = 8'b0010_0000; //发送IP首部+ICMP首部
localparam st_tx_data    = 8'b0100_0000; //发送数据
localparam st_crc        = 8'b1000_0000; //发送CRC校验值//以太网类型定义
localparam  ETH_TYPE     = 16'h0800    ;  //以太网协议类型 IP协议//以太网数据最小46个字节,IP首部20个字节+ICMP首部8个字节 
//所以数据至少46-20-8=18个字节
localparam  MIN_DATA_NUM = 16'd18;//parameter define
//ICMP报文类型:回显应答
parameter ECHO_REPLY   = 8'h00;//reg define
reg  [7:0]   cur_state           ;											//1 				
reg  [7:0]   next_state          ;                          				//1      
reg  [7:0]   preamble[7:0]       ; //前导码
reg  [7:0]   eth_head[13:0]      ; //以太网首部
reg  [31:0]  ip_head[6:0]        ; //IP首部 + ICMP首部                             
reg          start_en_d0         ;                                          //1
reg          start_en_d1         ;   										//1
reg          start_en_d2         ;											//1
reg  [15:0]  tx_data_num         ; //发送的有效数据字节个数					//1
reg  [15:0]  total_num           ; //总字节数								//1
reg          trig_tx_en          ;											//1
reg          skip_en             ; //控制状态跳转使能信号					//1
reg  [4:0]   cnt                 ;											//1
reg  [31:0]  check_buffer        ; //ip首部校验和							//1
reg  [31:0]  check_buffer_icmp   ; //ip首部校验和							//1
reg  [1:0]   tx_bit_sel          ;											//1
reg  [15:0]  data_cnt            ; //发送数据个数计数器						//1
reg          tx_done_t           ;											//1
reg  [4:0]   real_add_cnt        ; //以太网数据实际多发的字节数			//1//wire define                       
wire         pos_start_en    ;//开始发送数据上升沿 							//1
wire [15:0]  real_tx_data_num;//实际发送的字节数(以太网最少字节要求)		//1
//*****************************************************
//**                    main code
//*****************************************************assign  pos_start_en = (~start_en_d2) & start_en_d1;
assign  real_tx_data_num = (tx_data_num >= MIN_DATA_NUM)? tx_data_num : MIN_DATA_NUM;//采tx_start_en的上升沿
always @(posedge clk or negedge rst_n) beginif(!rst_n) beginstart_en_d0 <= 1'b0;start_en_d1 <= 1'b0;start_en_d2 <= 1'b0;end    else beginstart_en_d0 <= tx_start_en;start_en_d1 <= start_en_d0;start_en_d2 <= start_en_d1;end
end 寄存数据有效字节
always @(posedge clk or negedge rst_n) beginif(!rst_n) begintx_data_num <= 16'd0;total_num <= 16'd0;endelse beginif(pos_start_en && cur_state==st_idle) begin//数据长度tx_data_num <= tx_byte_num;//IP长度:有效数据+IP首部长度(20bytes)+ICMP首部长度(8bytes)total_num <= tx_byte_num + 16'd28;end  else;end
end//触发发送信号
always @(posedge clk or negedge rst_n) beginif(!rst_n) trig_tx_en <= 1'b0;elsetrig_tx_en <= pos_start_en;endalways @(posedge clk or negedge rst_n) beginif(!rst_n)cur_state <= st_idle;elsecur_state <= next_state;
endalways @(*) beginnext_state = st_idle;case(cur_state)st_idle     : begin                               //等待发送数据if(skip_en)next_state = st_check_sum;elsenext_state = st_idle;end  st_check_sum: begin                               //IP首部校验if(skip_en)next_state = st_check_icmp;elsenext_state = st_check_sum;end  st_check_icmp: begin                              //ICMP首部校验if(skip_en)next_state = st_preamble;elsenext_state = st_check_icmp;end  st_preamble : begin                               //发送前导码+帧起始界定符if(skip_en)next_state = st_eth_head;elsenext_state = st_preamble;endst_eth_head : begin                               //发送以太网首部if(skip_en)next_state = st_ip_head;elsenext_state = st_eth_head;end              st_ip_head : begin                                //发送IP首部+icmp首部if(skip_en)next_state = st_tx_data;elsenext_state = st_ip_head;endst_tx_data : begin                                //发送数据if(skip_en)next_state = st_crc;elsenext_state = st_tx_data;endst_crc: begin                                     //发送CRC校验值if(skip_en)next_state = st_idle;elsenext_state = st_crc;enddefault : next_state = st_idle;endcase
end//发送数据
always @(posedge clk or negedge rst_n) beginif(!rst_n) beginskip_en <= 1'b0; cnt <= 5'd0;check_buffer <= 32'd0;check_buffer_icmp <= 32'd0;ip_head[1][31:16] <= 16'd0;tx_bit_sel <= 2'b0;crc_en <= 1'b0;gmii_tx_en <= 1'b0;gmii_txd <= 8'd0;tx_req <= 1'b0;tx_done_t <= 1'b0; data_cnt <= 16'd0;real_add_cnt <= 5'd0;//初始化数组    //前导码 7个8'h55 + 1个8'hd5preamble[0] <= 8'h55;preamble[1] <= 8'h55;preamble[2] <= 8'h55;preamble[3] <= 8'h55;preamble[4] <= 8'h55;preamble[5] <= 8'h55;preamble[6] <= 8'h55;preamble[7] <= 8'hd5;//目的MAC地址eth_head[0] <= DES_MAC[47:40];eth_head[1] <= DES_MAC[39:32];eth_head[2] <= DES_MAC[31:24];eth_head[3] <= DES_MAC[23:16];eth_head[4] <= DES_MAC[15:8];eth_head[5] <= DES_MAC[7:0];//源MAC地址eth_head[6] <= BOARD_MAC[47:40];eth_head[7] <= BOARD_MAC[39:32];eth_head[8] <= BOARD_MAC[31:24];eth_head[9] <= BOARD_MAC[23:16];eth_head[10] <= BOARD_MAC[15:8];eth_head[11] <= BOARD_MAC[7:0];//以太网类型eth_head[12] <= ETH_TYPE[15:8];eth_head[13] <= ETH_TYPE[7:0];endelse beginskip_en <= 1'b0;crc_en <= 1'b0;gmii_tx_en <= 1'b0;tx_done_t <= 1'b0;case(next_state)st_idle     : beginif(trig_tx_en) beginskip_en <= 1'b1; //版本号:4 首部长度:5(单位:32bit,20byte/4=5)ip_head[0] <= {8'h45,8'h00,total_num};//16位标识,每次发送累加1      ip_head[1][31:16] <= ip_head[1][31:16] + 1'b1;//bit[15:13]: 010表示不分片ip_head[1][15:0] <= 16'h4000;//8'h80:表示生存时间//8'd01:1代表ICMP,2代表IGMP,6代表TCP,17代表UDPip_head[2] <= {8'h80,8'd01,16'h0000};//源IP地址               ip_head[3] <= BOARD_IP;//目的IP地址    if(des_ip != 32'd0)ip_head[4] <= des_ip;elseip_head[4] <= DES_IP;// 8位icmp TYPE ,8位 icmp CODE ip_head[5][31:16] <= {ECHO_REPLY,8'h00};//16位identifier 16位sequenceip_head[6] <= {icmp_id,icmp_seq};//更新MAC地址if(des_mac != 48'b0) begin//目的MAC地址eth_head[0] <= des_mac[47:40];eth_head[1] <= des_mac[39:32];eth_head[2] <= des_mac[31:24];eth_head[3] <= des_mac[23:16];eth_head[4] <= des_mac[15:8];eth_head[5] <= des_mac[7:0];endelse;endelse;endst_check_sum: begin                           //IP首部校验cnt <= cnt + 5'd1;if(cnt == 5'd0) begincheck_buffer <= ip_head[0][31:16] + ip_head[0][15:0]+ ip_head[1][31:16] + ip_head[1][15:0]+ ip_head[2][31:16] + ip_head[2][15:0]+ ip_head[3][31:16] + ip_head[3][15:0]+ ip_head[4][31:16] + ip_head[4][15:0];endelse if(cnt == 5'd1)                      //可能出现进位,累加一次check_buffer <= check_buffer[31:16] + check_buffer[15:0];else if(cnt == 5'd2) begin                //可能再次出现进位,累加一次check_buffer <= check_buffer[31:16] + check_buffer[15:0];end                             else if(cnt == 5'd3) begin                //按位取反 skip_en <= 1'b1;cnt <= 5'd0;            ip_head[2][15:0] <= ~check_buffer[15:0];end else;endst_check_icmp: begin                           //ICMP首部+数据校验cnt <= cnt + 5'd1;if(cnt == 5'd0) begincheck_buffer_icmp <= ip_head[5][31:16] + ip_head[6][31:16] + ip_head[6][15:0]+ reply_checksum;endelse if(cnt == 5'd1)                      //可能出现进位,累加一次check_buffer_icmp <= check_buffer_icmp[31:16] + check_buffer_icmp[15:0];else if(cnt == 5'd2) begin                //可能再次出现进位,累加一次check_buffer_icmp <= check_buffer_icmp[31:16] + check_buffer_icmp[15:0];end                             else if(cnt == 5'd3) begin                //按位取反skip_en <= 1'b1;cnt <= 5'd0;// ICMP:16位校验和ip_head[5][15:0] <= ~check_buffer_icmp[15:0];endelse;endst_preamble : begin                     //发送前导码+帧起始界定符gmii_tx_en <= 1'b1;gmii_txd <= preamble[cnt];if(cnt == 5'd7) beginskip_en <= 1'b1;cnt <= 5'd0;endelsecnt <= cnt + 5'd1;endst_eth_head : begin                      //发送以太网首部gmii_tx_en <= 1'b1;crc_en <= 1'b1;gmii_txd <= eth_head[cnt];if (cnt == 5'd13) beginskip_en <= 1'b1;cnt <= 5'd0;endelsecnt <= cnt + 5'd1;endst_ip_head  : begin                        //发送IP首部crc_en <= 1'b1;gmii_tx_en <= 1'b1;tx_bit_sel <= tx_bit_sel + 2'd1;if(tx_bit_sel == 3'd0)gmii_txd <= ip_head[cnt][31:24];else if(tx_bit_sel == 3'd1)gmii_txd <= ip_head[cnt][23:16];else if(tx_bit_sel == 3'd2) begingmii_txd <= ip_head[cnt][15:8];if(cnt == 5'd6) begin//提前读请求数据,等待数据有效时发送tx_req <= 1'b1;endend else if(tx_bit_sel == 3'd3) begingmii_txd <= ip_head[cnt][7:0];if(cnt == 5'd6) beginskip_en <= 1'b1;cnt <= 5'd0;end    elsecnt <= cnt + 5'd1;endelse;endst_tx_data  : begin                           //发送数据crc_en <= 1'b1;gmii_tx_en <= 1'b1;gmii_txd <= tx_data;tx_bit_sel <= 3'd0; if(data_cnt < tx_data_num - 16'd1)data_cnt <= data_cnt + 16'd1;else if(data_cnt == tx_data_num - 16'd1)begin//如果发送的有效数据少于18个字节,在后面填补充位//补充的值为最后一次发送的有效数据if(data_cnt + real_add_cnt < real_tx_data_num - 16'd1)real_add_cnt <= real_add_cnt + 5'd1;  else beginskip_en <= 1'b1;data_cnt <= 16'd0;real_add_cnt <= 5'd0;end    endelse;if(data_cnt == tx_data_num - 16'd2)tx_req <= 1'b0; else ;end st_crc      : begin                          //发送CRC校验值gmii_tx_en <= 1'b1;tx_bit_sel <= tx_bit_sel + 3'd1;tx_req <= 1'b0; if(tx_bit_sel == 3'd0)gmii_txd <= {~crc_next[0], ~crc_next[1], ~crc_next[2],~crc_next[3],~crc_next[4], ~crc_next[5], ~crc_next[6],~crc_next[7]};else if(tx_bit_sel == 3'd1)gmii_txd <= {~crc_data[16], ~crc_data[17], ~crc_data[18],~crc_data[19],~crc_data[20], ~crc_data[21], ~crc_data[22],~crc_data[23]};else if(tx_bit_sel == 3'd2) begingmii_txd <= {~crc_data[8], ~crc_data[9], ~crc_data[10],~crc_data[11],~crc_data[12], ~crc_data[13], ~crc_data[14],~crc_data[15]};endelse if(tx_bit_sel == 3'd3) begingmii_txd <= {~crc_data[0], ~crc_data[1], ~crc_data[2],~crc_data[3],~crc_data[4], ~crc_data[5], ~crc_data[6],~crc_data[7]};tx_done_t <= 1'b1;skip_en <= 1'b1;endelse;enddefault :;endcaseend
end//发送完成信号及crc值复位信号
always @(posedge clk or negedge rst_n) beginif(!rst_n) begintx_done <= 1'b0;crc_clr <= 1'b0;endelse begintx_done <= tx_done_t;crc_clr <= tx_done_t;end
endendmodule

rgmii_rx.v

module  rgmii_rx(input             idelay_clk   ,    // 200Mhz鏃堕挓锛孖DELAY鏃堕挓// 杩欎竴娈垫槸浠ュお缃慠GNII鎺ュ彛input             rgmii_rxc    ,   // RGMII鎺ユ敹鏃堕挓input             rgmii_rx_ctl ,   // RGMII鎺ユ敹鏃堕挓鎺у埗淇″彿input   [3 : 0]   rgmii_rxd    ,   // RGMII鎺ユ敹鏁版嵁// 浠ュお锟�? GMII鎺ュ彛output            gmii_rx_clk  ,output            gmii_rx_dv   ,output  [7 : 0]   gmii_rxd);// -------------------------------------------//// ------parameter  and define--------------- //// -------------------------------------------//parameter         IDELAY_VALUE  =  0 ;wire              rgmii_rxc_bufg     ;   //鍏ㄥ眬鏃堕挓缂撳啿wire              rgmii_rxc_bufio    ;   //鍏ㄥ眬鏃堕挓IO缂撳瓨 -- 鎺ュ湪浜咮UFIO鍚庨潰锟�?wire              rgmii_rx_ctl_delay ;wire     [3 : 0]  rgmii_rxd_delay    ;wire     [1 : 0]  gmii_rxdv_t        ;   // 涓や綅GMII鎺ユ敹淇″彿// ---------------------------------------------//// ------------ main  code ---------------------////----------------------------------------------//assign  gmii_rx_clk  =  rgmii_rxc_bufg ;assign  gmii_rx_dv   =  gmii_rxdv_t[0] & gmii_rxdv_t[1] ;// 鍏ㄥ眬鏃堕挓缂撳瓨BUFG BUFG_inst(.I       (rgmii_rxc) ,.O       (rgmii_rxc_bufg));// 鍏ㄥ眬鏃堕挓缂撳瓨BUFIO BUFIO_inst (.I         (rgmii_rxc),.O         (rgmii_rxc_bufio));//锟斤拷锟斤拷锟斤拷时锟斤拷锟斤拷
// Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL
(* IODELAY_GROUP = "rgmii_rx_delay" *) 
IDELAYCTRL  IDELAYCTRL_inst (.RDY(),                      // 1-bit output: Ready output.REFCLK(idelay_clk),         // 1-bit input: Reference clock input.RST(1'b0)                   // 1-bit input: Active high reset input
);//rgmii_rx_ctl锟斤拷锟斤拷锟斤拷时锟斤拷双锟截诧拷锟斤拷
(* IODELAY_GROUP = "rgmii_rx_delay" *) 
IDELAYE2 #(.IDELAY_TYPE     ("FIXED"),           // FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE.IDELAY_VALUE    (IDELAY_VALUE),      // Input delay tap setting (0-31).REFCLK_FREQUENCY(200.0)              // IDELAYCTRL clock input frequency in MHz 
)
u_delay_rx_ctrl (.CNTVALUEOUT     (),                  // 5-bit output: Counter value output.DATAOUT         (rgmii_rx_ctl_delay),// 1-bit output: Delayed data output.C               (1'b0),              // 1-bit input: Clock input.CE              (1'b0),              // 1-bit input: enable increment/decrement.CINVCTRL        (1'b0),              // 1-bit input: Dynamic clock inversion input.CNTVALUEIN      (5'b0),              // 5-bit input: Counter value input.DATAIN          (1'b0),              // 1-bit input: Internal delay data input.IDATAIN         (rgmii_rx_ctl),      // 1-bit input: Data input from the I/O.INC             (1'b0),              // 1-bit input: Increment / Decrement tap delay.LD              (1'b0),              // 1-bit input: Load IDELAY_VALUE input.LDPIPEEN        (1'b0),              // 1-bit input: Enable PIPELINE register.REGRST          (1'b0)               // 1-bit input: Active-high reset tap-delay input
);//锟斤拷锟斤拷双锟截诧拷锟斤拷锟侥达拷锟斤拷
IDDR #(.DDR_CLK_EDGE("SAME_EDGE_PIPELINED"),// "OPPOSITE_EDGE", "SAME_EDGE" //    or "SAME_EDGE_PIPELINED" .INIT_Q1  (1'b0),                   // Initial value of Q1: 1'b0 or 1'b1.INIT_Q2  (1'b0),                   // Initial value of Q2: 1'b0 or 1'b1.SRTYPE   ("SYNC")                  // Set/Reset type: "SYNC" or "ASYNC" 
) u_iddr_rx_ctl (.Q1       (gmii_rxdv_t[0]),         // 1-bit output for positive edge of clock.Q2       (gmii_rxdv_t[1]),         // 1-bit output for negative edge of clock.C        (rgmii_rxc_bufio),        // 1-bit clock input.CE       (1'b1),                   // 1-bit clock enable input.D        (rgmii_rx_ctl_delay),     // 1-bit DDR data input.R        (1'b0),                   // 1-bit reset.S        (1'b0)                    // 1-bit set
);//rgmii_rxd锟斤拷锟斤拷锟斤拷时锟斤拷双锟截诧拷锟斤拷
genvar i;
generate for (i=0; i<4; i=i+1)(* IODELAY_GROUP = "rgmii_rx_delay" *) begin : rxdata_bus//锟斤拷锟斤拷锟斤拷时           (* IODELAY_GROUP = "rgmii_rx_delay" *) IDELAYE2 #(.IDELAY_TYPE     ("FIXED"),           // FIXED,VARIABLE,VAR_LOAD,VAR_LOAD_PIPE.IDELAY_VALUE    (IDELAY_VALUE),      // Input delay tap setting (0-31)    .REFCLK_FREQUENCY(200.0)              // IDELAYCTRL clock input frequency in MHz)u_delay_rxd (.CNTVALUEOUT     (),                  // 5-bit output: Counter value output.DATAOUT         (rgmii_rxd_delay[i]),// 1-bit output: Delayed data output.C               (1'b0),              // 1-bit input: Clock input.CE              (1'b0),              // 1-bit input: enable increment/decrement.CINVCTRL        (1'b0),              // 1-bit input: Dynamic clock inversion.CNTVALUEIN      (5'b0),              // 5-bit input: Counter value input.DATAIN          (1'b0),              // 1-bit input: Internal delay data input.IDATAIN         (rgmii_rxd[i]),      // 1-bit input: Data input from the I/O.INC             (1'b0),              // 1-bit input: Inc/Decrement tap delay.LD              (1'b0),              // 1-bit input: Load IDELAY_VALUE input.LDPIPEEN        (1'b0),              // 1-bit input: Enable PIPELINE register .REGRST          (1'b0)               // 1-bit input: Active-high reset tap-delay);//锟斤拷锟斤拷双锟截诧拷锟斤拷锟侥达拷锟斤拷IDDR #(.DDR_CLK_EDGE("SAME_EDGE_PIPELINED"),// "OPPOSITE_EDGE", "SAME_EDGE" //    or "SAME_EDGE_PIPELINED" .INIT_Q1  (1'b0),                   // Initial value of Q1: 1'b0 or 1'b1.INIT_Q2  (1'b0),                   // Initial value of Q2: 1'b0 or 1'b1.SRTYPE   ("SYNC")                  // Set/Reset type: "SYNC" or "ASYNC" ) u_iddr_rxd (.Q1       (gmii_rxd[i]),            // 1-bit output for positive edge of clock.Q2       (gmii_rxd[4+i]),          // 1-bit output for negative edge of clock.C        (rgmii_rxc_bufio),        // 1-bit clock input rgmii_rxc_bufio.CE       (1'b1),                   // 1-bit clock enable input.D        (rgmii_rxd_delay[i]),     // 1-bit DDR data input.R        (1'b0),                   // 1-bit reset.S        (1'b0)                    // 1-bit set);end
endgenerateendmodule

rgmii_tx.v

module   rgmii_tx(// GMII 发送端口input                gmii_tx_clk  ,   // GMII 发送信号input                gmii_tx_en   ,   // GMII 输出数据有效信号input    [7 : 0]     gmii_txd     ,//RGMII 发送端口output               rgmii_txc    ,output               rgmii_tx_ctl ,output   [3 : 0]     rgmii_txd);// --------------------------------------------- //// -------------- main code -------------------- //// --------------------------------------------- //assign  rgmii_txc = gmii_tx_clk ; // 输出时钟// 输出双沿采样ODDR #(.DDR_CLK_EDGE ("SAME_EDGE")            ,.INIT (1'b0)                           ,.SRTYPE ("SYNC")) ODDR_inst (.Q (rgmii_tx_ctl)                      ,.C (gmii_tx_clk)                       ,.CE (1'b1)                             ,.D1 (gmii_tx_en)                       ,  //  positive egde.D2 (gmii_tx_en)                       ,  //  negative edge.R (1'b0)                              ,.S (1'b0));genvar i;generate for (i=0; i<4; i=i+1)begin : txdata_busODDR #(.DDR_CLK_EDGE ("SAME_EDGE")    ,.INIT (1'b0),.SRTYPE ("SYNC")) ODDR_inst (.Q (rgmii_txd[i])              ,.C (gmii_tx_clk)               ,.CE (1'b1)                     ,.D1 (gmii_txd[i])              ,.D2 (gmii_txd[4+i])            ,.R (1'b0)                      ,.S (1'b0));endendgenerateendmodule

其中icmp_tx.v icmp_rx.v 与icmp_top.v 有tb如下

`timescale  1ns/1nsmodule  tb_icmp  ;parameter   T           =  8   ;      // 鏃堕挓鍛ㄦ湡 8nsparameter   OP_CYCLE    =  100 ;      // 鎿嶄綔鍛ㄦ湡 鍙戦?佸懆鏈熼棿闅?//寮?鍙戞澘MAC鍦板潃 00-11-22-33-44-55parameter  BOARD_MAC = 48'h00_11_22_33_44_55          ;//寮?鍙戞澘IP鍦板潃 192.168.1.10parameter  BOARD_IP  = {8'd192,8'd168,8'd1,8'd10}     ;//鐩殑MAC鍦板潃 ff_ff_ff_ff_ff_ffparameter  DES_MAC   = 48'hff_ff_ff_ff_ff_ff          ;//鐩殑IP鍦板潃 192.168.1.10parameter  DES_IP    = {8'd192,8'd168,8'd1,8'd10}     ;// =============================================================////                define   and  parameter                       //// =============================================================////reg definereg           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 definewire          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    ;initialbegingmii_clk     =    0    ;sys_rst_n    =    0    ;#(T+1)sys_rst_n    =    1    ;end//always #(T/2)  gmii_clk  =  ~gmii_clk  ;always@(posedge  gmii_clk  or negedge  sys_rst_n)beginif(sys_rst_n == 0)begintx_start_en   <=    0   ;tx_data       <=    0   ;tx_byte_num   <=    0   ;des_mac       <=    0   ;des_ip        <=    0   ;delay_cnt     <=    0   ;flow_cnt      <=    0   ;endelsebegincase(flow_cnt)0 :beginflow_cnt   <=  flow_cnt  +  1  ;end1 :begintx_start_en  <=  1    ;tx_byte_num  <=  20   ;flow_cnt     <=  flow_cnt  +  1   ;end2:begintx_start_en  <=  0    ;    // 鑴夊啿淇″彿flow_cnt     <=  flow_cnt  + 1   ;end3 :beginif(tx_req == 1)begintx_data   <=   tx_data  +  1  ;endif(tx_done == 1)beginflow_cnt  <=   flow_cnt  +  1  ;tx_data   <=   0  ;endend4 :  // 鎷夐珮绛夊緟begindelay_cnt  <=   delay_cnt  +  1  ;if(delay_cnt == OP_CYCLE - 1)flow_cnt   <=   flow_cnt  + 1  ;end5:begintx_start_en  <=  1   ;tx_byte_num  <=  28  ;flow_cnt     <=  flow_cnt  +  1  ;end6:begintx_start_en  <=  0   ;flow_cnt     <=  flow_cnt  + 1  ;end7:beginif(tx_req == 1)tx_data  <=  tx_data  +  1  ;if(tx_done == 1)beginflow_cnt  <=  flow_cnt  +  1  ;tx_data   <=  0    ;endenddefault:;endcaseendendicmp 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

其中的eth_icmp_test.v模块中的clk_wiz_0 与 fifo_generator_0都是xilinx官方IP

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1547577.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

RFID手持机——物联网时代的核心工具

一、行业背景 在当今物联网技术高速发展的时代&#xff0c;RFID技术作为核心的数据采集与识别手段&#xff0c;在物流、仓储、资产管理等众多领域发挥着至关重要的作用。以物流行业为例&#xff0c;利用RFID技术能够对货物进行全程精准跟踪&#xff0c;从入库、存储、搬运到出…

Keepalived+Nginx 高可用集群(双主模式)

1.基础环境配置 [rootlb1 ~]# systemctl stop firewalld # 关闭防火墙 [rootlb1 ~]# sed -i s/^SELINUX.*/SELINUXdisabled/ /etc/sysconfig/selinux # 关闭selinux&#xff0c;重启生效 [rootlb1 ~]# setenforce 0          …

从Elasticsearch到RedisSearch:探索更快的搜索引擎解决方案

文章目录 RedisSearch 的关键功能与 ElasticSearch 对比性能对比产品对比 如何使用 Docker 安装 RedisSearch1. 获取 RedisSearch Docker 镜像2. 启动 RedisSearch 容器3. 验证安装 RedisSearch 使用示例1. 连接到 RedisSearch2. 创建索引3. 添加文档4. 执行搜索搜索所有包含 &…

C++ | Leetcode C++题解之第440题字典序的第K小数字

题目&#xff1a; 题解&#xff1a; class Solution { public:int getSteps(int curr, long n) {int steps 0;long first curr;long last curr;while (first < n) {steps min(last, n) - first 1;first first * 10;last last * 10 9;}return steps;}int findKthNum…

Ubuntu20.04 安装汉语拼音后重启登入黑屏

在虚拟机上装了一个Ubuntu用来学C&#xff0c;默认没有安装中文输入。于是按照网上教程装了几个汉语包。切换输入法的时候突然死机&#xff0c;重启登入直接黑屏。百度后发现有不少老哥和我这个问题一模一样&#xff0c;按照他们的方法也终于整好了&#xff0c;虚惊一场。 解决…

Windows 10 系统安装 FFmpeg 查看、转换、编辑音频文件

1、FFmpeg官网&#xff1a;FFmpeg 点击下载 可以选择下载full版本 下载之后解压到指定目录&#xff0c;在系统环境变量 Path 里面新增环境变量 打开CMD终端运行 ffmpeg -version 查看是否安装成功。 2、基本命令 查看音频基本信息 ffprobe 1.mp3 ##输出 [mp3 000002ab334405…

DataLight(V1.4.5) 版本更新,新增 Ranger、Solr

DataLight&#xff08;V1.4.5&#xff09; 版本更新&#xff0c;新增 Ranger、Solr DataLight 迎来了重大的版本更新&#xff0c;现已发布 V1.4.5 版本。本次更新对平台进行了较多的功能拓展和优化&#xff0c;新增了对 Ranger 和 Solr 服务组件的支持&#xff0c;同时对多项已…

傅里叶级数在机器人中的应用(动力学参数辨识)

B站首发&#xff01;草履虫都能看懂的【傅里叶变换】讲解&#xff0c;清华大学李永乐老师教你如何理解傅里叶变换&#xff0c;辨清美颜和变声原理&#xff0c;&#xff01;&#xff01;_哔哩哔哩_bilibiliB站首发&#xff01;草履虫都能看懂的【傅里叶变换】讲解&#xff0c;清…

macOS安装MySQL以后如何配置环境变量

当安装了MySQL,解决了远程链接的问题以后, 还没有完事大捷, 还需要配置环境变量. 因为我需要使用mysql命令, 以及备份相关的命令. 下面是mysql的默认配置截图: 接着我查看了/usr/local/mysql/bin这个目录. 果然很多命令都在这个里面. 所以我将这个目录加载到了path中. e…

XSS | 反射型 XSS 攻击

关注这个漏洞的其他相关笔记&#xff1a;XSS 漏洞 - 学习手册-CSDN博客 0x01&#xff1a;反射型 XSS — 理论篇 反射型 XSS 又称非持久型 XSS&#xff0c;这种攻击方式往往具有一次性。 常见的攻击方式&#xff1a; 攻击者通过电子邮件等方式将包含 XSS 代码的恶意链接发送给…

Linux标准IO(五)-I/O缓冲详解

1.简介 出于速度和效率的考虑&#xff0c;系统 I/O 调用&#xff08;即文件 I/O&#xff0c;open、read、write 等&#xff09;和标准 C 语言库 I/O 函数&#xff08;即标准 I/O 函数&#xff09;在操作磁盘文件时会对数据进行缓冲&#xff0c;本小节将讨论文件 I/O 和标准 I/…

蓝桥杯--STM32G431RBT6(TIM定时器的输出频率和占空比,含详细原理介绍和使用方法)

目录 一、前言 二、代码 实现功能&#xff1a;​编辑 按如图配置 定义变量 编写执行代码 显示在LCD上 加入按键效果 三、效果展示 四、代码开源 一、前言 ARR 即自动重装载值&#xff08;Auto Reload Register&#xff09;。相当于一个水杯&#xff0c;水杯容量&am…

【EXCEL数据处理】000002 案列 条件格式之重复值。使用的软件是微软的Excel操作的。处理数据的目的是让数据更直观的显示出来,方便查看。

【EXCEL数据处理】000002 案列 条件格式之重复值。使用的软件是微软的Excel操作的。处理数据的目的是让数据更直观的显示出来&#xff0c;方便查看。 在日常的数据处理和分析工作中&#xff0c;Excel 是一款强大而广泛使用的工具。其中&#xff0c;条件格式中的重复值功能对于快…

Golang | Leetcode Golang题解之第438题找到字符串中所有字母异位词

题目&#xff1a; 题解&#xff1a; func findAnagrams(s, p string) (ans []int) {sLen, pLen : len(s), len(p)if sLen < pLen {return}count : [26]int{}for i, ch : range p {count[s[i]-a]count[ch-a]--}differ : 0for _, c : range count {if c ! 0 {differ}}if diff…

Java | Leetcode Java题解之第438题找到字符串中所有字母异位词

题目&#xff1a; 题解&#xff1a; class Solution {public List<Integer> findAnagrams(String s, String p) {int sLen s.length(), pLen p.length();if (sLen < pLen) {return new ArrayList<Integer>();}List<Integer> ans new ArrayList<Int…

滚珠丝杠在人形机器人及线控制动和转向中大放异彩

直线驱动器用于对旋转角度不大、高负载的场景,在人形机器人中多用于四肢。直线驱动器多采取“电机+丝杠”,将旋转运动转为关节末端的直线运动,能够起到较好的支撑和承重效果,能够较好的适配应用场景的负载需求。 特斯拉人形机器人Optimus 双足、双臂采用连杆结构,连杆末端…

25:stm32的低功耗模式

低功耗模式 1、PWR电源控制2、低功耗模式 1、PWR电源控制 PWR&#xff08;Power Control&#xff09;电源控制。PWR负责管理STM32内部的电源供电部分&#xff0c;可以实现可编程电压监测器和低功耗模式的功能&#xff0c;这里我们只学习低功耗模式的功能&#xff0c;低功耗模式…

MySQL --用户管理

文章目录 1.用户1.1用户信息1.2创建用户1.3删除用户1.4修改用户密码 2.数据库的权限2.1给用户授权2.2回收权限 如果我们只能使用root用户&#xff0c;这样存在安全隐患。这时&#xff0c;就需要使用MySQL的用户管理。 1.用户 1.1用户信息 MySQL中的用户&#xff0c;都存储在系…

性能调优知识点(mysql)一

Mysql 索引 索引介绍 1.索引是排好序的数据结构。他的目的是为了提升查询效率。 2.mysql存储引擎分为innodb和myisam。它是用来形容表的。 innodb支持事务、外键、行锁 myisam不支持事务、外键 3.myisam使用3个文件来存储每张表数据&#xff0c;每个文件名以表名开头&#x…

Python | Leetcode Python题解之第440题字典序的第K小数字

题目&#xff1a; 题解&#xff1a; class Solution:def getSteps(self, cur: int, n: int) -> int:steps, first, last 0, cur, curwhile first < n:steps min(last, n) - first 1first * 10last last * 10 9return stepsdef findKthNumber(self, n: int, k: int)…