【【通信协议ARP的verilog实现】】

news2024/11/17 3:25:29

【【通信协议ARP的verilog实现】】

eth_arp_test.v

module  eth_arp_test(
    input                  sys_clk       , //系统时钟
    input                  sys_rst_n     , //系统复位信号,低电平有效
    input                  touch_key     , //触摸按键,用于触发开发板发出ARP请求
    //PL以太网RGMII接口
    input                  eth_rxc       , //RGMII接收数据时钟
    input                  eth_rx_ctl    , //RGMII输入数据有效信号
    input       [3:0]      eth_rxd       , //RGMII输入数据
    output                 eth_txc       , //RGMII发送数据时钟
    output                 eth_tx_ctl    , //RGMII输出数据有效信号
    output      [3:0]      eth_txd       , //RGMII输出数据
    output                 eth_rst_n   //以太网芯片复位信号,低电平有效
  );

  //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};
  //输入数据IO延时(如果为n,表示延时n*78ps)
  parameter IDELAY_VALUE = 0;



//wire define
wire          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_rx_done; //ARP接收完成信号
wire          arp_rx_type; //ARP接收类型 0:请求  1:应答
wire  [47:0]  src_mac    ; //接收到目的MAC地址
wire  [31:0]  src_ip     ; //接收到目的IP地址    
wire          arp_tx_en  ; //ARP发送使能信号
wire          arp_tx_type; //ARP发送类型 0:请求  1:应答
wire          tx_done    ; //发送的目标MAC地址
wire  [47:0]  des_mac    ; //发送的目标IP地址
wire  [31:0]  des_ip     ; //以太网发送完成信号    

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

assign des_mac = src_mac;
assign des_ip = src_ip;
assign eth_rst_n = sys_rst_n;

//PLL
clk_wiz_0 clk_wiz_0_inst
(
 // Clock out ports
 .clk_out1(clk_200m),     // output clk_out1
 // Status and control signals
 .reset(~sys_rst_n), // input reset
 .locked(locked),       // output locked
// Clock in ports
 .clk_in1(sys_clk));      // input clk_in1


//GMII接口转RGMII接口
gmii_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    (gmii_tx_en ),
    .gmii_txd      (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       (tx_done    )
    );

//ARP控制
arp_ctrl u_arp_ctrl(
    .clk           (gmii_rx_clk),
    .rst_n         (sys_rst_n),
                   
    .touch_key     (touch_key),
    .arp_rx_done   (arp_rx_done),
    .arp_rx_type   (arp_rx_type),
    .arp_tx_en     (arp_tx_en),
    .arp_tx_type   (arp_tx_type)
    );

endmodule

arp_ctrl.v

module  arp_ctrl(
    input               clk          ,
    input               rst_n        ,


    input               touch_key    ,
    input               arp_rx_done  ,
    input               arp_rx_type  ,
    output   reg        arp_tx_en    ,
    output   reg        arp_tx_type
  );


  // reg define
  reg             touch_key_d0     ;
  reg             touch_key_d1     ;
  reg             touch_key_d2     ;


  wire            pos_touch_key    ;



  //--------------------------------------------//
  //-----------------main  code ----------------//
  //--------------------------------------------//

  assign pos_touch_key  =  ~touch_key_d2 & touch_key_d1 ;


  always@(posedge clk or negedge rst_n)
  begin
    if(rst_n == 0)
    begin
      touch_key_d0   <=   0  ;
      touch_key_d1   <=   0  ;
      touch_key_d2   <=   0  ;
    end
    else
    begin
      touch_key_d0  <=  touch_key     ;
      touch_key_d1  <=  touch_key_d0  ;
      touch_key_d2  <=  touch_key_d1  ;
    end
  end


  always@(posedge clk or negedge rst_n )
  begin
    if(rst_n == 0)
    begin
      arp_tx_en    <=    0 ;
      arp_tx_type  <=    0 ;
    end
    else
    begin
      if(pos_touch_key == 1)
      begin  // 发送请求
        arp_tx_en     <=  1  ;
        arp_tx_type   <=  0  ;
      end
      else if((arp_rx_done ==1) & (arp_rx_type == 0))
      begin
        arp_tx_en  <=  1  ;
        arp_tx_type   <=  1  ;
      end
      else
        arp_tx_en   <=  0  ;
    end
  end
endmodule

arp_rx.v

module  arp_rx #(
    parameter     BOARD_MAC  = 48'h00_11_22_33_44_55, //开发板mac地址
    parameter     BOARD_IP   =  {8'd192,8'd168,8'd1,8'd10}
  )(
    input                      clk         ,  // 时钟信号
    input                      rst_n       ,  //
    input                      gmii_rx_dv  ,  //
    input           [7 : 0]    gmii_rxd    ,

    output  reg                arp_rx_done ,
    output  reg                arp_rx_type ,
    output  reg     [47 : 0]   src_mac     ,
    output  reg     [31 : 0]   src_ip
  );

  //---------------------------------------------------//
  //        parameter and 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      [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     ;
  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       ; //操作码








  // ---------------------------------------------- //
  // -------next is main code --------------------- //
  // ---------------------------------------------- //
  always@(posedge clk or negedge rst_n )
  begin
    if(rst_n == 0)
    begin
      cur_state  <=  st_idle      ;
    end
    else
    begin
      cur_state  <=  next_state   ;
    end
  end

  always@(posedge clk or negedge rst_n )
  begin
    if(rst_n == 0 )
    begin
      next_state <= st_idle ;
    end
    else
    begin
      case(cur_state)
        st_idle :
        begin
          if(skip_en == 1)
          begin
            next_state <= st_preamble ;
          end
          else
          begin
            next_state <= st_idle ;
          end
        end

        st_preamble :
        begin
          if(skip_en == 1)
          begin
            next_state <= st_eth_head ;
          end
          else
          begin
            if(error_en == 1)
            begin
              next_state <= st_rx_end ;
            end
            else
            begin
              next_state <= st_preamble ;
            end
          end
        end

        st_eth_head :
        begin
          if(skip_en == 1)
          begin
            next_state <= st_arp_data ;
          end
          else
          begin
            if(error_en == 1)
            begin
              next_state <= st_rx_end ;
            end
            else
            begin
              next_state <= st_eth_head ;
            end
          end
        end

        st_arp_data :
        begin
          if(skip_en  == 1)
          begin
            next_state <= st_rx_end ;
          end
          else if(error_en == 1)
          begin
            next_state <= st_rx_end ;
          end
          else
          begin
            next_state <= st_arp_data ;
          end
        end

        st_rx_end :
        begin
          if(skip_en == 1)
          begin
            next_state <= st_idle ;
          end
          else
          begin
            next_state <= st_rx_end ;
          end
        end

        default :
        begin
          next_state <= st_idle ;
        end
      endcase
    end
  end


  // 三段状态机的第三段
  always@(posedge clk or  negedge rst_n)
  begin
    if(rst_n == 0)
    begin
      skip_en       <=   0    ;
      error_en      <=   0    ;
      cnt           <=   0    ;
      arp_rx_done   <=   0    ;
      des_mac_t     <=   0    ;
      des_ip_t      <=   0    ;
      src_mac_t     <=   0    ;
      src_ip_t      <=   0    ;
      eth_type      <=   0    ;
      op_data       <=   0    ;
      arp_rx_type   <=   0    ;
      src_mac       <=   0    ;
      src_ip        <=   0    ;
    end
    else
    begin
      skip_en      <=  0   ;
      error_en     <=  0   ;
      arp_rx_done  <=  0   ;
      case(next_state)

        st_idle :
        begin
          if((gmii_rx_dv == 1)&&(gmii_rxd ==8'h55 ) ==1 )
            skip_en <= 1 ;
          else
            ;
        end

        st_preamble :
        begin
          if(gmii_rx_dv == 1)
          begin
            // 再计数-6次判断是否满足条件
            cnt <=  cnt + 1 ;
            if((cnt < 6)&&(gmii_rxd != 8'h55) ==1)
            begin
              error_en  <= 1 ;
            end
            else
            begin
              if(cnt == 6)
              begin
                cnt <= 0 ;
                if(gmii_rxd == 8'hd5)
                begin
                  skip_en <= 1 ;
                end
                else
                begin
                  error_en <= 1 ;
                end
              end
              else
                ;
            end
          end
          else
            ;
        end

        // 因为是接收状态所以只需要判断目的是否满足条件就好
        st_eth_head :
        begin
          if(gmii_rx_dv == 1)
          begin
            cnt  <=  cnt + 1 ;
            if(cnt < 6)
            begin
              des_mac_t <= {des_mac_t[39 : 0],gmii_rxd} ;
            end
            else if(cnt == 6)
            begin
              // 其实去判断一下自己接收的地址是否是正确的即可
              if((des_mac_t != BOARD_MAC) &&(des_mac_t != 48'hff_ff_ff_ff_ff_ff))
                error_en <= 1 ;
            end
            else if(cnt == 12)
            begin
              eth_type[15 : 8] <= gmii_rxd ;
            end
            else if(cnt == 13)
            begin
              eth_type[7 : 0]  <=  gmii_rxd ;
              cnt  <=  0 ;
              if(eth_type[15:8] == ETH_TPYE[15:8]  //判断是否为ARP协议
                  && gmii_rxd == ETH_TPYE[7:0])
                skip_en <= 1'b1;
              else
                error_en <= 1'b1;
            end
            else
              ;
          end
          else
            ;
        end

        st_arp_data :
        begin
          if(gmii_rx_dv == 1 )
          begin
            cnt <= cnt + 1 ;
            if(cnt == 6)
            begin
              op_data[15 : 8] <= gmii_rxd ;
            end
            else if( cnt == 7)
            begin
              op_data[7 : 0]  <= gmii_rxd ;
            end
            else if(cnt>=8 && cnt < 14)
            begin
              src_mac_t <= {src_mac_t[39: 0],gmii_rxd} ;
            end
            else if(cnt>=14 && cnt <18 )
            begin
              src_ip_t <= {src_ip_t[23:0],gmii_rxd} ;
            end
            else if(cnt >=24 && cnt <28)
            begin
              des_ip_t <= {des_ip_t[23 : 0],gmii_rxd} ;
            end
            else if(cnt == 28)
            begin
              cnt  <= 0 ; 
              if(des_ip_t == BOARD_IP)
              begin
                if((op_data ==1 )|| (op_data ==2) )
                begin
                  skip_en <= 1 ;
                  arp_rx_done <= 1 ;
                  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请求
                  else
                    arp_rx_type <= 1'b1;     //ARP应答
                end
                else
                  error_en <= 1'b1;
              end
              else
                error_en <= 1'b1;
            end
            else
              ;
          end
          else
            ;
        end

        st_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
  end

endmodule

arp_tx.v

module arp_tx(
    input                       clk         ,
    input                       rst_n       ,

    input                       arp_tx_en   ,
    input                       arp_tx_type ,
    input         [31 : 0]      des_ip      ,
    input         [47 : 0]      des_mac     ,
    input         [31 : 0]      crc_data    ,
    input         [7  : 0]      crc_next    ,
    output  reg   [7  : 0]      gmii_txd    ,
    output  reg                 crc_clr     ,
    output  reg                 crc_en      ,
    output  reg                 gmii_tx_en  ,
    output  reg                 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};


  //localparam 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; //
  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;


  always@(posedge clk or negedge rst_n)
  begin
    if(rst_n == 0)
    begin
      tx_en_d0  <= 1'b0        ;
      tx_en_d1  <= 1'b0        ;
      tx_en_d2  <= 1'b0        ;
    end
    else
    begin
      tx_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)
  begin
    if(!rst_n)
      cur_state <= st_idle;
    else
      cur_state <= next_state;
  end

  //组合逻辑判断状态转移条件
  always @(*)
  begin
    next_state = st_idle;
    case(cur_state)
      st_idle :
      begin                     //空闲状态
        if(skip_en)
          next_state = st_preamble;
        else
          next_state = st_idle;
      end

      st_preamble :
      begin                 //发送前导码+帧起始界定符
        if(skip_en)
          next_state = st_eth_head;
        else
          next_state = st_preamble;
      end
      
      st_eth_head :
      begin                 //发送以太网首部
        if(skip_en)
          next_state = st_arp_data;
        else
          next_state = st_eth_head;
      end
      st_arp_data :
      begin                 //发送ARP数据
        if(skip_en)
          next_state = st_crc;
        else
          next_state = st_arp_data;
      end
      st_crc:
      begin                       //发送CRC校验值
        if(skip_en)
          next_state = st_idle;
        else
          next_state = st_crc;
      end
      default :
        next_state = st_idle;
    endcase
  end


  always@(posedge clk or negedge rst_n)
  begin
    if(rst_n == 0 )
    begin
      skip_en    <=    0      ;
      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;               //硬件地址长度,6
      arp_data[5]  <= 8'h04;               //协议地址长度,4
      arp_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];
    end
    else
    begin
      skip_en <= 1'b0;
      crc_en <= 1'b0;
      gmii_tx_en <= 1'b0;
      tx_done_t <= 1'b0;
      case(next_state)
        st_idle :
        begin
          if(pos_tx_en)
          begin
            skip_en <= 1'b1;
            //如果目标MAC地址和IP地址已经更新,则发送正确的地址
            if((des_mac != 48'b0) || (des_ip != 32'd0))
            begin
              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];
              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];
            end
            else
              ;
            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;
          end
          else
            cnt <= cnt + 1'b1;
        end

        st_eth_head :
        begin                          //发送以太网首部
          gmii_tx_en <= 1'b1;
          crc_en <= 1'b1;
          gmii_txd <= eth_head[cnt];
          if (cnt == 6'd13)
          begin
            skip_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)
          begin
            data_cnt <= data_cnt + 1'b1;
            gmii_txd <= arp_data[data_cnt];
          end
          else
            gmii_txd <= 8'd0;                    //Padding,填充0
        end
        st_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)
          begin
            gmii_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]};
          end
          else if(cnt == 6'd3)
          begin
            gmii_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)
  begin
    if(!rst_n)
    begin
      tx_done <= 1'b0;
      crc_clr <= 1'b0;
    end
    else
    begin
      tx_done <= tx_done_t;
      crc_clr <= tx_done_t;
    end
  end

endmodule

arp.v

module  arp(
    input                     rst_n        ,
    // GMII
    input                     gmii_rx_clk  ,
    input                     gmii_rx_dv   ,
    input    [7 : 0]          gmii_rxd     ,
    input                     gmii_tx_clk  ,
    output                    gmii_tx_en   ,
    output   [7 : 0]          gmii_txd     ,


    //用户接口
    input                     arp_tx_en    ,
    input                     arp_tx_type  ,
    input    [31 : 0]         des_ip       ,
    input    [47 : 0]         des_mac      ,
    output                    arp_rx_done  ,
    output                    arp_rx_type  ,
    output   [31 : 0]         src_ip       ,
    output   [47 : 0]         src_mac      ,
    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 + 1

  assign 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)
  begin
    if(!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;
  end

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 

rgmii_rx.v

module  rgmii_rx(
    input             idelay_clk   ,    // 200Mhz时钟,IDELAY时钟


    // 这一段是以太网RGNII接口
    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缓存 -- 接在了BUFIO后面�?
  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
endgenerate

endmodule

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_bus

      ODDR #(
             .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)
           );
    end
  endgenerate

endmodule

tb_arp.v

此模块用于arp的仿真 包括arp.v arp_tx.v  arp_rx.v 
`timescale  1ns/1ns                     //定义仿真时间单位1ns和仿真时间精度为1ns

module  tb_arp;

//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
//为了返回应答,仿真代码将开发板地址设置与目的IP地址相同     
parameter  BOARD_IP  = {8'd192,8'd168,8'd1,8'd102};
//目的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};

//reg define
reg           gmii_clk;    //时钟信号
reg           sys_rst_n;   //复位信号
reg           arp_tx_en  ; //ARP发送使能信号
reg           arp_tx_type; //ARP发送类型 0:请求  1:应答
reg   [3:0]   flow_cnt   ;
reg   [13:0]  delay_cnt  ;

//wire define
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_rx_done; //ARP接收完成信号
wire          arp_rx_type; //ARP接收类型 0:请求  1:应答
wire  [47:0]  src_mac    ; //接收到目的MAC地址
wire  [31:0]  src_ip     ; //接收到目的IP地址    
wire  [47:0]  des_mac    ; //发送的目标MAC地址
wire  [31:0]  des_ip     ; //发送的目标IP地址
wire          tx_done    ; //以太网发送完成信号 

//*****************************************************
//**                    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   ;
assign des_mac = src_mac;
assign des_ip = src_ip;

//给输入信号初始值
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
        arp_tx_en <= 1'b0;
        arp_tx_type <= 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
                arp_tx_en <= 1'b1;
                arp_tx_type <= 1'b0;  //发送ARP请求
                flow_cnt <= flow_cnt + 1'b1;
            end
            'd2 : begin 
                arp_tx_en <= 1'b0;
                flow_cnt <= flow_cnt + 1'b1;
            end    
            'd3 : begin
                if(tx_done)
                    flow_cnt <= flow_cnt + 1'b1;
            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
                arp_tx_en <= 1'b1;
                arp_tx_type <= 1'b1;  //发送ARP应答   
                flow_cnt <= flow_cnt + 1'b1;                
            end
            'd6 : begin 
                arp_tx_en <= 1'b0;
                flow_cnt <= flow_cnt + 1'b1;
            end 
            'd7 : begin
                if(tx_done)
                    flow_cnt <= flow_cnt + 1'b1;
            end
            default:;
        endcase    
    end
end

//ARP通信
arp                                             
   #(
    .BOARD_MAC     (BOARD_MAC),      //参数例化
    .BOARD_IP      (BOARD_IP ),
    .DES_MAC       (DES_MAC  ),
    .DES_IP        (DES_IP   )
    )
   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    (gmii_tx_en ),
    .gmii_txd      (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       (tx_done    )
    );

endmodule

注意点

本实验使用了Xillix的原语 在rgmii_rx.v模块中使用了 BUFG BUFIO IDELAYCTRL IDELAYE2 这几个原语
并且PLL 设置的clocking wizard 为输入50MHz 输出200MHz

基于ZYNQ 7020的xdc如下

create_clock -period 20.000 -name sys_clk [get_ports sys_clk]
create_clock -period 8.000 -name eth_rxc [get_ports eth_rxc]
set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports sys_clk]
set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]
set_property -dict {PACKAGE_PIN F16 IOSTANDARD LVCMOS33} [get_ports touch_key]
set_property -dict {PACKAGE_PIN K17 IOSTANDARD LVCMOS33} [get_ports eth_rxc]
set_property -dict {PACKAGE_PIN E17 IOSTANDARD LVCMOS33} [get_ports eth_rx_ctl]
set_property -dict {PACKAGE_PIN B19 IOSTANDARD LVCMOS33} [get_ports {eth_rxd[0]}]
set_property -dict {PACKAGE_PIN A20 IOSTANDARD LVCMOS33} [get_ports {eth_rxd[1]}]
set_property -dict {PACKAGE_PIN H17 IOSTANDARD LVCMOS33} [get_ports {eth_rxd[2]}]
set_property -dict {PACKAGE_PIN H16 IOSTANDARD LVCMOS33} [get_ports {eth_rxd[3]}]
set_property -dict {PACKAGE_PIN B20 IOSTANDARD LVCMOS33} [get_ports eth_txc]
set_property -dict {PACKAGE_PIN K18 IOSTANDARD LVCMOS33} [get_ports eth_tx_ctl]
set_property -dict {PACKAGE_PIN D18 IOSTANDARD LVCMOS33} [get_ports {eth_txd[0]}]
set_property -dict {PACKAGE_PIN C20 IOSTANDARD LVCMOS33} [get_ports {eth_txd[1]}]
set_property -dict {PACKAGE_PIN D19 IOSTANDARD LVCMOS33} [get_ports {eth_txd[2]}]
set_property -dict {PACKAGE_PIN D20 IOSTANDARD LVCMOS33} [get_ports {eth_txd[3]}]
set_property -dict {PACKAGE_PIN G15 IOSTANDARD LVCMOS33} [get_ports eth_rst_n]

module 图

在这里插入图片描述

top图

在这里插入图片描述

gmii2rgmii图

在这里插入图片描述

arp图

在这里插入图片描述

arp_rx图

在这里插入图片描述

arp_tx图

在这里插入图片描述

arp_ctrl图

在这里插入图片描述

crc_d8图

在这里插入图片描述

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

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

相关文章

【JVM】判断对象能否回收的两种方法:引用计数算法,可达性分析算法

1、引用计数算法&#xff1a; 给对象添加一个引用计数器&#xff0c;当该对象被其它对象引用时计数加一&#xff0c;引用失效时计数减一&#xff0c;计数为0时&#xff0c;可以回收。 特点&#xff1a;占用了一些额外的内存空间来进行计数&#xff0c;原理简单&#xff0c;判…

wincc利用拓展屏实现多台显示器显示单个项目配置方法详解

以下视频为完整操作教程 wincc利用拓展屏实现多台显示器显示单个项目配置方法详解 一、硬件接线 首先要保证wincc项目主机电脑要具备两个显示器接口&#xff0c;不管是VGA还是HDMI的都可以&#xff0c;让后将两台显示器接到同一台电脑上。如下图&#xff1a; 二、windows设置 …

基于python+django+vue的社区爱心养老管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于pythondjangovueMySQL的社…

设计模式重新整理

系统整理 河北王校长的 贯穿设计模式 和 王争的设计模式之美&#xff0c;希望能形成肌肉记忆 文章目录 为什么需要掌握设计模式1. 六大原则介绍1. 单一职责原则2. 开闭原则3. 里式替换原则4. 依赖倒置原则5. 接口隔离原则6. 迪米特法则 分类 单例模式适配器模式封装有缺陷的接口…

FFmpeg与OpenCV联合开发

本文讲述如何利用FFmpeg SDK与OpenCV 从RTSP流中获取图像&#xff08;OpenCV MAT 对象格式&#xff09;。 一&#xff0c;构造RTSP视频流 因为是在本机实验&#xff0c;所以我自己构造了一个RTSP流。如果你有现成的RTSP流也可以的。 实验用的源视频是黑神话悟空的《云宫讯音》…

苹果CMS vs. 海洋CMS:哪个系统更易于百度收录?

在选择网站内容管理系统&#xff08;影视网站选择那个CMS&#xff1f;&#xff09;时&#xff0c;收录效率和优化能力是关键考量因素。苹果CMS和海洋CMS都是受欢迎的选项&#xff0c;但在百度收录效果上&#xff0c;苹果CMS表现得更为出色。以下将详细探讨苹果CMS为何在百度收录…

房产销售系统|基于java和vue的房产销售系统(源码+数据库+文档)

房产销售|房地产|卖房系统 目录 基于java和vue的房产销售系统 一、前言 二、系统设计 三、系统功能设计 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设布道师&#xff0c;…

【网络安全】-ssrf服务器请求伪造攻击-burp

SSRF攻击服务器请求伪造攻击 CSRF攻击跨站请求伪造攻击也称客户端请求伪造攻击 两种攻击最主要的区别是一个在服务器&#xff0c;一个在客户端。 文章目录 前言 什么是SSRF攻击? 1.分类&#xff1a; 针对服务器的 SSRF 攻击&#xff1a; 针对后端系统的SSRF攻击&#xff1a; …

Kafka高吞吐量的原因

文章目录 生产者&#xff08;写入数据&#xff09;顺序写入Memory Mapped Files 消费者&#xff08;读取数据&#xff09;Kafka是如何巧妙设计的? 总结 众所周知kafka的吞吐量比一般的消息队列要高&#xff0c;号称the fastest&#xff0c;那他是如何做到的&#xff0c;让我们…

Java多线程-(线程的创建,线程安全,线程状态)

第一章.创建线程的方式 1.第一种方式_extends Thread 1.定义一个自定义线程类继承Thread 2.重写run方法(run方法是用于设置线程任务的) 3.创建自定义线程类对象 4.调用Thread类中的start方法(start方法:开启线程,jvm自动执行run方法) public class MyThread extends Thread{…

【SSRF漏洞】——gopherus工具伪造

改变的确很难&#xff0c;但结果值得冒险 本文如有错误之处&#xff0c;还请各位师傅指正 目录 一.gopherus概述 二.gopherus安装使用 三.gopherus覆盖的服务 四.使用案例 web359&#xff1a; web360&#xff1a; 一.gopherus概述 Gopherus是一个专为生成Gopher协议Payloa…

Leetcode 每日一题:Count Complete Tree Nodes

写在前面&#xff1a; 今天带来一道 Leetcde Easy 的题&#xff0c;但别觉得我在水帖&#xff0c;这道题目在 Google 的面试题中甚至可以升级到 Leetcode medium to hard 的级别&#xff0c;而今天我要带来的正是他的高阶要求&#xff0c;怎么样利用 Complete Binary Tree 的特…

经典负载调制平衡放大器(LMBA)设计-从理论到ADS仿真

经典负载调制平衡放大器&#xff08;LMBA&#xff09;设计-从理论到ADS仿真 ADS工程下载&#xff1a;经典负载调制平衡放大器&#xff08;LMBA&#xff09;设计-从理论到ADS仿真-ADS工程 参考论文: An Efficient Broadband Reconfigurable Power Amplifier Using Active Load…

华为 HCIP 认证费用和报名资格

在当今竞争激烈的信息技术领域&#xff0c;华为 HCIP认证备受关注。它不仅能提升个人的技术实力与职业竞争力&#xff0c;也为企业选拔优秀人才提供了重要依据。以下将详细介绍华为 HCIP 认证的费用和报名资格。 一、HCIP 认证费用 华为HCIP认证的费用主要由考试费和培训费构成…

似然函数与先验概率、后验概率的关系

似然函数、先验概率、后验概率这三个概念是贝叶斯统计中的核心概念&#xff0c;它们共同描述了如何根据已有数据更新我们对某个事件或参数的认识。下面用简单的语言解释这三个概念&#xff0c;并描述它们之间的关系。 1. 先验概率&#xff08;Prior Probability&#xff09; …

Debian11.9镜像基于jre1.8的Dockerfile

Debian11.9基于jre1.8的Dockerfile编写 # 使用Debian 11.9作为基础镜像 FROM debian:11.9 # 维护者信息&#xff08;建议使用LABEL而不是MAINTAINER&#xff0c;因为MAINTAINER已被弃用&#xff09; LABEL maintainer"caibingsen" # 创建一个目录来存放jre …

vue中v-bind和v-model的区别和应用

1.区别 v-bind&#xff1a; vue2中&#xff0c;v-bind是单向数据绑定&#xff0c;用于动态绑定HTML属性和组件属性&#xff0c;只能将vue实例中的数据同步到HTML元素上&#xff0c;实现数据的动态更新和响应式渲染。v-bind的简写形式使用冒号前缀&#xff08;&#xff1a;&am…

VSCode好用的插件推荐

1. Chinese 将vscode翻译成简体中文 2. ESLint 自动检查规范 3. Prettier - Code formatter 可以自动调整代码的缩进、换行和空格&#xff0c;确保代码风格统一。通过配置&#xff0c;Prettier可以在保存文件时自动格式化代码 https://juejin.cn/post/74025724757198274…

【时间盒子】-【7.标题菜单栏】自定义任务页面顶部的标题菜单栏组件

Tips&#xff1a; media媒体资源的使用&#xff1b; float.json、color.json资源文件的使用&#xff1b; 组件属性的定义。 预览效果&#xff1a; 一、创建组件文件 右击component目录 >> 新建 >> ArkTS File&#xff0c;文件命名为TitleContainer.ets。 Prev…

JZ2440开发板——S3C2440的时钟体系

参考博客 &#xff08;1&#xff09;S3C2440-裸机篇-05 | S3C2440时钟体系详解&#xff08;FCLK、PCLK、HCLK&#xff09; 一、三种时钟&#xff08;FCLK、HCLK、PCLK&#xff09; 如下图所示&#xff0c;S3C2440的时钟控制逻辑&#xff0c;给整个芯片提供三种时钟&#xff1…