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

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

eth_arp_test.v

c 复制代码
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

c 复制代码
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

c 复制代码
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

c 复制代码
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

c 复制代码
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

c 复制代码
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

c 复制代码
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

c 复制代码
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

c 复制代码
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

c 复制代码
此模块用于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如下

c 复制代码
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图

相关推荐
fei_sun11 小时前
【Verilog】第一章作业
fpga开发·verilog
深圳市雷龙发展有限公司longsto12 小时前
基于FPGA(现场可编程门阵列)的SD NAND图片显示系统是一个复杂的项目,它涉及硬件设计、FPGA编程、SD卡接口、NAND闪存控制以及图像显示等多个方面
fpga开发
9527华安17 小时前
FPGA实现PCIE3.0视频采集转10G万兆UDP网络输出,基于XDMA+GTH架构,提供工程源码和技术支持
网络·fpga开发·udp·音视频·xdma·pcie3.0·万兆网
able陈17 小时前
为什么verilog中递归函数需要定义为automatic?
fpga开发
fei_sun17 小时前
【Verilog】第二章作业
fpga开发·verilog
碎碎思18 小时前
如何使用 Vivado 从源码构建 Infinite-ISP FPGA 项目
fpga开发·接口隔离原则
江山如画,佳人北望20 小时前
fpga-状态机的设计及应用
fpga开发
晓晓暮雨潇潇1 天前
Xilinx IP核(3)XADC IP核
fpga开发·vivado·xadc·ip核
CWNULT1 天前
AMD(Xilinx) FPGA配置Flash大小选择
fpga开发
碎碎思1 天前
很能体现FPGA硬件思维的一道面试题
fpga开发