【【通信协议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图

相关推荐
cycf42 分钟前
CRC校验
fpga开发
landyjzlai2 小时前
AMBA总线(15)关于AXI-stream(sg模式)
arm开发·fpga开发·amba
白狐_7982 小时前
Quartus Prime 新手完全使用指南
fpga开发
Aaron158813 小时前
三种主流接收机架构(超外差、零中频、射频直采)对比及发展趋势浅析
c语言·人工智能·算法·fpga开发·架构·硬件架构·信号处理
博览鸿蒙13 小时前
一颗数字系统是如何在 FPGA 上“跑起来”的?
fpga开发
雨洛lhw18 小时前
FPGA JTAG接口设计全解析
fpga开发·jtag
minglie11 天前
iverilog 配合 Makefile 搭建 Verilog 仿真工程
fpga开发
芒果树技术1 天前
MangoTree案例分享:基于AtomRIO FPGA平台,客户实现自适应主动减振
测试工具·fpga开发·模块测试
雨洛lhw1 天前
按键电路设计的细节
fpga开发
minglie11 天前
vio_uart的浏览器版上位机
fpga开发