FPGA以太网篇之ARP协议

  地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取MAC地址(物理地址)的一个TCP/IP协议。主机发送信息时将包含目标IP地址的ARP请求广播到局域网络上的所有主机,并接收返回消息,以此确定目标的物理地址;收到返回消息后将该IP地址和物理地址存入本机ARP缓存中并保留一定时间,下次请求时直接查询ARP缓存以节约资源。

  以太网通信中,数据都是以帧的形式进行传输,当网卡接收到来自外部的MAC地址不是本地的MAC地址时,直接丢弃数据包。要保证通信成功,则需要提前知道目标的MAC地址,ARP协议就起到了获取MAC地址的作用。ARP 协议分为 ARP 请求和 ARP 应答,源主机发起查询目的 MAC 地址的报文称为 ARP 请求,目的主
机响应源主机并发送包含本地 MAC 地址的报文称为 ARP 应答。

  当主机A需要与主机B通信时,首先需要知道主机B的MAC地址。此时主机A就可以发送ARP请求报文,由于只知道对方的IP地址,不知道对方的MAC地址,所以使用48‘hff_ff_ff_ff_ff_ff(协议规定的广播物理地址)代替主机B的MAC。主机B在接收到来自主机A的ARP请求报文时,IP地址与本地一致,主机B返回ARP应答报文。这个报文既包含了主机A的IP地址,MAC地址,也包含了主机B的IP地址及MAC地址。

  MAC层ARP协议的帧格式如下:

  

  前导码(Preamble) 7Byte : 使接收器建立比特同步,物理层使用 7 个字节同步码(0x55-55-55-55-55-55-55)实现数据的同步。

  起始定界符(SFDStart Frame Delimiter ) 1Byte:指示一帧的开始,固定为0xd5。

  目的MAC地址 6Byte:指接收端物理 MAC 地址,广播地址为:0xff_ff_ff_ff_ff_ff。

  源MAC地址 6Byte:指发送端物理 MAC 地址

  数据字段长度/类型 2Byte:当这两个字节的值小于 1536(十六进制为 0x0600)时,代表该以太网中数据段的长度;如果这两个字节的值大于 1536,则表示该以太网中的数据属于哪个上层协议,例如 0x0800 代表 IP 协议(网际协议) 、 0x0806 代表 ARP 协议(地址解析协议)等。

  数据 46~1500Byte:以太网中的数据段长度最小 46 个字节, 最大 1500 个字节。

  帧校验序列(FCSFrame Check Sequence) 4Byte:采用循环冗余校验码(CRC)用于检验帧在传输过程中有无差错。

 

  ARP数据报文格式为:

  硬件类型(Hardware type):硬件地址的类型, 1 表示以太网地址。
  协议类型(Protocol type):要映射的协议地址类型, ARP 协议的上层协议为 IP 协议,因此该协议类型为 IP 协议,其值为 0x0800
  硬件地址长度(Hardware size):硬件地址(MAC 地址)的长度,以字节为单位。对于以太网上 IP
  地址的 ARP 请求或者应答来说,该值为 6
  协议地址长度(Protocol size): IP 地址的长度,以字节为单位。对于以太网上 IP 地址的 ARP 请求或者应答来说,该值为 4
  OPOpcode):操作码,用于表示该数据包为 ARP 请求或者 ARP 应答。 1 表示 ARP 请求, 2 表示ARP 应答。
  源 MAC 地址:发送端的硬件地址,DEMO设为:48'h55_55_55_66_66_66。
  源 IP 地址:发送端的协议(IP)地址,这里DEMO为:192.168.1.6
  目的 MAC 地址:接收端的硬件地址,在 ARP 请求时由于不知道接收端 MAC 地址,因此该字段为广播地址,即 48’hff_ff_ff_ff_ff_ff
  目的地址IP:接收端的协议(IP)地址,这里DEMO设为:192.168.1.66。

  以上占了28Byte的长度,MAC协议帧要求ARP数据至少46Byte,故后面缺失部分补0处理。

  根据协议可完成Verilog代码块,如下。

  工程顶层文件Eth_arp.v

  1 //**************************************************************************
  2 // *** file name      : Eth_arp.v
  3 // *** version        : 1.0
  4 // *** Description    : Eth_arp
  5 // *** Blogs          : https://www.cnblogs.com/WenGalois123/
  6 // *** Author         : Galois_V
  7 // *** Date           : 2022.5.12
  8 // *** Changes        : Initial
  9 //**************************************************************************
 10 `timescale  1ns/1ps 
 11 module Eth_arp
 12 (
 13     input                        i_clk_200m_p    ,
 14     input                        i_clk_200m_n    ,
 15     input                        i_sys_rstn      ,
 16     input                        i_key_signal    ,
 17     output                       o_key_led       ,
 18     
 19     input                        eth_rxc         ,    //RGMII接收数据时钟
 20     input                        eth_rx_ctl      ,    //RGMII输入数据有效信号
 21     input        [3:0]           eth_rxd         ,    //RGMII输入数据
 22     output                       eth_txc         ,    //RGMII发送数据时钟    
 23     output                       eth_tx_ctl      ,    //RGMII输出数据有效信号
 24     output        [3:0]          eth_txd         ,    //RGMII输出数据          
 25     output                       eth_rst_n           //以太网芯片复位信号,低电平有效   
 26 );
 27     parameter SYS_FRE     = 100_000_000; 
 28     parameter BOARD_MAC = 48'h55_55_55_66_66_66; 
 29     parameter BOARD_IP  = {8'd192,8'd168,8'd1,8'd6};
 30     parameter DES_MAC   = 48'hff_ff_ff_ff_ff_ff;
 31     parameter DES_IP    = {8'd192,8'd168,8'd1,8'd66};
 32     
 33     wire                        w_sys_rstn        ;
 34     wire                        w_clk_100m        ;
 35     wire                        w_clk_200m        ;
 36     wire                        w_pll_locked      ;
 37     wire                        w_gmii_rx_clk     ;
 38     wire                        w_gmii_rx_dv      ;
 39     wire        [7:0]           w_gmii_rxd        ;
 40     wire                        w_gmii_tx_clk     ;
 41     wire                        w_gmii_tx_en      ;
 42     wire        [7:0]           w_gmii_txd        ;
 43     reg         [24:0]          r_rstn_cnt        ;
 44 /******************************************************************************\
 45 system clock pll
 46 \******************************************************************************/
 47     assign w_sys_rstn = i_sys_rstn & w_pll_locked;
 48     
 49     sys_pll u_sys_pll
 50     (
 51     // Clock out ports
 52         .clk_out1             (w_clk_200m        ),
 53         .clk_out2             (w_clk_100m        ),
 54     // Status and control signals
 55         .resetn               (i_sys_rstn        ),
 56         .locked               (w_pll_locked      ),
 57     // Clock in ports
 58         .clk_in1_p            (i_clk_200m_p      ),
 59         .clk_in1_n            (i_clk_200m_n      )
 60     );
 61     
 62     always@(posedge w_clk_200m)
 63     begin
 64         if(~w_sys_rstn)
 65             r_rstn_cnt <= 'd0;
 66         else if(r_rstn_cnt[24])
 67             r_rstn_cnt <= r_rstn_cnt;
 68         else
 69             r_rstn_cnt <= r_rstn_cnt + 1'b1;
 70     end
 71     
 72     assign eth_rst_n = r_rstn_cnt[24];
 73 /******************************************************************************\
 74 Gmii turn Rgmii
 75 \******************************************************************************/    
 76      Gmii_to_Rgmii u_gmii_to_rgmii
 77     (
 78         .rstn                 (w_sys_rstn       ),
 79         .gmii_rx_clk          (w_gmii_rx_clk    ),
 80         .gmii_rx_dv           (w_gmii_rx_dv     ),
 81         .gmii_rxd             (w_gmii_rxd       ),
 82         .gmii_tx_clk          (w_gmii_tx_clk    ),
 83         .gmii_tx_en           (w_gmii_tx_en     ),
 84         .gmii_txd             (w_gmii_txd       ),
 85         .gmii_tx_er           (1'b0             ),
 86         .rgmii_rxc            (eth_rxc          ),
 87         .rgmii_rx_ctl         (eth_rx_ctl       ),
 88         .rgmii_rxd            (eth_rxd          ),
 89         .rgmii_txc            (eth_txc          ),
 90         .rgmii_tx_ctl         (eth_tx_ctl       ),
 91         .rgmii_txd            (eth_txd          )
 92     );  
 93 /******************************************************************************\
 94 ARP protocol
 95 \******************************************************************************/
 96     Arp_top
 97     #(
 98         .SYS_FRE              (SYS_FRE          ), 
 99         .BOARD_MAC            (BOARD_MAC        ),
100         .BOARD_IP             (BOARD_IP         ),
101         .DES_MAC              (DES_MAC          ),
102         .DES_IP               (DES_IP           )
103     )
104     u_Arp_top
105     (
106         .i_sys_clk            (w_gmii_rx_clk    ),
107         .i_sys_rstn           (w_sys_rstn       ),
108         .i_gmii_rx_clk        (w_gmii_rx_clk    ),
109         .i_gmii_rx_vld        (w_gmii_rx_dv     ),
110         .i_gmii_rx_rxd        (w_gmii_rxd       ),
111         .i_gmii_tx_clk        (w_gmii_tx_clk    ),
112         .o_gmii_tx_vld        (w_gmii_tx_en     ),
113         .o_gmii_tx_txd        (w_gmii_txd       ),
114         .i_key_signal         (i_key_signal     ),
115         .o_key_led            (o_key_led        )
116     );
117 
118 endmodule

  sys_pll模块例化了官方的Clocking Wizard IP核。

  Gmii_to_Rgmii.v模块前面提过。

  Arp_top.v

 1 //**************************************************************************
 2 // *** file name      : Arp_top.v
 3 // *** version        : 1.0
 4 // *** Description    : Arp_top
 5 // *** Blogs          : https://www.cnblogs.com/WenGalois123/
 6 // *** Author         : Galois_V
 7 // *** Date           : 2022.5.12
 8 // *** Changes        : Initial
 9 //**************************************************************************
10 `timescale  1ns/1ps
11 module Arp_top
12 #(
13     parameter SYS_FRE   = 100_000_000,
14     parameter BOARD_MAC = 48'h55_55_55_66_66_66,
15     parameter BOARD_IP  = {8'd192,8'd168,8'd1,8'd6},
16     parameter DES_MAC   = 48'hff_ff_ff_ff_ff_ff,
17     parameter DES_IP    = {8'd192,8'd168,8'd1,8'd66}
18 )
19 (
20     input                        i_sys_clk         ,
21     input                        i_sys_rstn        ,
22 
23     input                        i_gmii_rx_clk     ,
24     input                        i_gmii_rx_vld     ,
25     input        [7:0]           i_gmii_rx_rxd     ,
26     input                        i_gmii_tx_clk     ,
27     output                       o_gmii_tx_vld     ,
28     output       [7:0]           o_gmii_tx_txd     ,
29     input                        i_key_signal      ,
30     output                       o_key_led
31 );
32     wire                        w_arp_tx_en    ;
33     wire                        w_arp_tx_mode  ;
34     wire                        w_arp_rx_mode  ;
35     wire                        w_arp_rx_done  ;
36     wire        [47:0]          w_des_mac      ;
37     wire        [31:0]          w_des_ip       ;
38 /******************************************************************************\
39 Arp tx
40 \******************************************************************************/
41     Arp_tx
42    #(
43         .BOARD_MAC           (BOARD_MAC        ),
44         .BOARD_IP            (BOARD_IP         ),
45         .DES_MAC             (DES_MAC          ),
46         .DES_IP              (DES_IP           )
47     )
48    u_Arp_tx
49    (
50         .i_sys_clk           (i_gmii_tx_clk    ),
51         .i_sys_rstn          (i_sys_rstn       ),
52         .i_arp_tx_en         (w_arp_tx_en      ),
53         .i_arp_tx_mode       (w_arp_tx_mode    ),
54         .i_des_mac           (w_des_mac        ),
55         .i_des_ip            (w_des_ip         ),
56         .o_tx_done           (tx_done          ),
57         .o_gmii_tx_vld       (o_gmii_tx_vld    ),
58         .o_gmii_txd          (o_gmii_tx_txd    )
59     );
60 /******************************************************************************\
61 Arp rx
62 \******************************************************************************/
63      arp_rx
64    #(
65         .BOARD_MAC           (BOARD_MAC        ),
66         .BOARD_IP            (BOARD_IP         )
67     )
68    u_arp_rx
69    (
70         .clk                 (i_gmii_rx_clk    ),
71         .rst_n               (i_sys_rstn       ),
72         .gmii_rx_dv          (i_gmii_rx_vld    ),
73         .gmii_rxd            (i_gmii_rx_rxd    ),
74         .arp_rx_done         (w_arp_rx_done    ),
75         .arp_rx_type         (w_arp_rx_mode    ),
76         .src_mac             (w_des_mac        ),
77         .src_ip              (w_des_ip         )
78     );
79 /******************************************************************************\
80 Arp control module
81 \******************************************************************************/
82     Arp_ctrl
83     #(
84         .SYS_FRE             (SYS_FRE          )
85     )
86     u_Arp_ctrl
87     (
88         .i_sys_clk           (i_gmii_rx_clk    ),
89         .i_sys_rstn          (i_sys_rstn       ),
90         .i_key_signal        (i_key_signal     ),
91         .o_key_led           (o_key_led        ),
92         .i_arp_rx_done       (w_arp_rx_done    ),
93         .i_arp_rx_mode       (w_arp_rx_mode    ),
94         .o_arp_tx_en         (w_arp_tx_en      ),
95         .o_arp_tx_mode       (w_arp_tx_mode    )
96     );
97 
98 endmodule

  Arp_tx.v

  1 //**************************************************************************
  2 // *** file name      : Arp_tx.v
  3 // *** version        : 1.0
  4 // *** Description    : Arp_tx
  5 // *** Blogs          : https://www.cnblogs.com/WenGalois123/
  6 // *** Author         : Galois_V
  7 // *** Date           : 2022.5.12
  8 // *** Changes        : Initial
  9 //**************************************************************************
 10 `timescale  1ns/1ps
 11 module Arp_tx
 12 (
 13     input                        i_sys_clk        ,
 14     input                        i_sys_rstn       ,
 15 
 16     input                        i_arp_tx_en      ,
 17     input                        i_arp_tx_mode    ,
 18     input        [47:0]          i_des_mac        ,
 19     input        [31:0]          i_des_ip         ,
 20     output    reg                o_tx_done        ,
 21     output    reg                o_gmii_tx_vld    ,
 22     output    reg[7:0]           o_gmii_txd
 23 );
 24     parameter        BOARD_MAC        = 48'h55_55_55_66_66_66;
 25     parameter        BOARD_IP         = {8'd192,8'd168,8'd1,8'd6 };
 26     parameter        DES_MAC          = 48'hff_ff_ff_ff_ff_ff;
 27     parameter        DES_IP           = {8'd192,8'd168,8'd1,8'd66};
 28     localparam       ARP_PRE          = 64'h55_55_55_55_55_55_55_d5;
 29     localparam       ETH_TYPE         = 16'h0806 ;
 30     localparam       HD_TYPE          = 16'h0001 ;
 31     localparam       PROTOCOL_TYPE    = 16'h0800 ;
 32 
 33     wire                        w_tx_en_pos        ;
 34     wire                        w_byte_cnt_end     ;
 35     wire                        w_crc_clr          ;
 36     wire        [7:0]           w_crc_d8           ;
 37     wire        [31:0]          w_crc_data         ;
 38     reg         [1:0]           r_arp_tx_en        ;
 39     reg                         r_arp_en           ;
 40     reg         [63:0]          r_arp_pre          ;
 41     reg         [47:0]          r_des_mac          ;
 42     reg         [31:0]          r_des_ip           ;
 43     reg         [31:0]          r_board_ip         ;
 44     reg         [47:0]          r_board_mac        ;
 45     reg         [15:0]          r_eth_type         ;
 46     reg         [15:0]          r_hd_type          ;
 47     reg         [15:0]          r_protocol_type    ;
 48     reg         [7:0]           r_hd_size          ;
 49     reg         [7:0]           r_protocol_size    ;
 50     reg         [15:0]          r_opcode           ;
 51     reg         [6:0]           r_byte_cnt         ;
 52     reg         [7:0]           r_arp_txd          ;
 53     reg                         r_crc_en           ;
 54     reg                         r_crc_en_dly       ;
 55 
 56     always@(posedge i_sys_clk)
 57     begin
 58         if(~i_sys_rstn)
 59         begin
 60             r_arp_tx_en <= 'd0;
 61         end
 62         else
 63         begin
 64             r_arp_tx_en <= {r_arp_tx_en[0],i_arp_tx_en};
 65         end
 66     end
 67 
 68     assign w_tx_en_pos = ~r_arp_tx_en[1] & r_arp_tx_en[0];
 69 
 70     always@(posedge i_sys_clk)
 71     begin
 72         if(~i_sys_rstn | w_byte_cnt_end)
 73         begin
 74             r_arp_en <= 'd0;
 75         end
 76         else if(w_tx_en_pos)
 77         begin
 78             r_arp_en <= 1'b1;
 79         end
 80     end
 81 /******************************************************************************\
 82 Gmii tx data encode
 83 \******************************************************************************/
 84     always@(posedge i_sys_clk)
 85     begin
 86         if(~i_sys_rstn)
 87         begin
 88             r_arp_pre        <= ARP_PRE;
 89             r_des_mac        <= DES_MAC;
 90             r_des_ip         <= DES_IP;
 91             r_board_ip       <= BOARD_IP;
 92             r_board_mac      <= BOARD_MAC;
 93             r_eth_type       <= ETH_TYPE;
 94             r_hd_type        <= HD_TYPE;
 95             r_protocol_type  <= PROTOCOL_TYPE;
 96             r_hd_size        <= 8'h06;
 97             r_protocol_size  <= 8'h04;
 98             r_opcode         <= 16'h0001;
 99         end
100         else
101         begin
102             if(i_arp_tx_mode)
103             begin
104                 r_opcode    <= 16'h0002;
105                 r_des_mac   <= i_des_mac;
106                 r_des_ip    <= i_des_ip;
107             end
108             else
109             begin
110                 r_opcode    <= 16'h0001;
111             end
112         end
113     end
114 
115     always@(posedge i_sys_clk)
116     begin
117         if(~i_sys_rstn | w_byte_cnt_end)
118         begin
119             r_byte_cnt <= 'd0;
120         end
121         else if(r_arp_en)
122         begin
123             r_byte_cnt <= r_byte_cnt + 1'b1;
124         end
125     end
126 
127     always@(posedge i_sys_clk)
128     begin
129         if(~i_sys_rstn)
130         begin
131             o_tx_done <= 'd0;
132         end
133         else
134         begin
135             o_tx_done <= w_byte_cnt_end;
136         end
137     end
138     assign w_byte_cnt_end = (r_byte_cnt == 7'd71);
139     assign w_crc_clr = o_tx_done;
140 
141     always@(*)
142     begin
143         case(r_byte_cnt)
144             0:r_arp_txd  = r_arp_pre[63:56];
145             1:r_arp_txd  = r_arp_pre[55:48];
146             2:r_arp_txd  = r_arp_pre[47:40];
147             3:r_arp_txd  = r_arp_pre[39:32];
148             4:r_arp_txd  = r_arp_pre[31:24];
149             5:r_arp_txd  = r_arp_pre[23:16];
150             6:r_arp_txd  = r_arp_pre[15:8];
151             7:r_arp_txd  = r_arp_pre[7:0];
152             8:r_arp_txd  = r_des_mac[47:40];
153             9:r_arp_txd  = r_des_mac[39:32];
154             10:r_arp_txd = r_des_mac[31:24];
155             11:r_arp_txd = r_des_mac[23:16];
156             12:r_arp_txd = r_des_mac[15:8];
157             13:r_arp_txd = r_des_mac[7:0];
158             14:r_arp_txd = r_board_mac[47:40];
159             15:r_arp_txd = r_board_mac[39:32];
160             16:r_arp_txd = r_board_mac[31:24];
161             17:r_arp_txd = r_board_mac[23:16];
162             18:r_arp_txd = r_board_mac[15:8];
163             19:r_arp_txd = r_board_mac[7:0];
164             20:r_arp_txd = r_eth_type[15:8];
165             21:r_arp_txd = r_eth_type[7:0];
166             22:r_arp_txd = r_hd_type[15:8];
167             23:r_arp_txd = r_hd_type[7:0];
168             24:r_arp_txd = r_protocol_type[15:8];
169             25:r_arp_txd = r_protocol_type[7:0];
170             26:r_arp_txd = r_hd_size;
171             27:r_arp_txd = r_protocol_size;
172             28:r_arp_txd = r_opcode[15:8];
173             29:r_arp_txd = r_opcode[7:0];
174             30:r_arp_txd = r_board_mac[47:40];
175             31:r_arp_txd = r_board_mac[39:32];
176             32:r_arp_txd = r_board_mac[31:24];
177             33:r_arp_txd = r_board_mac[23:16];
178             34:r_arp_txd = r_board_mac[15:8];
179             35:r_arp_txd = r_board_mac[7:0];
180             36:r_arp_txd = r_board_ip[31:24];
181             37:r_arp_txd = r_board_ip[23:16];
182             38:r_arp_txd = r_board_ip[15:8];
183             39:r_arp_txd = r_board_ip[7:0];
184             40:r_arp_txd = r_des_mac[47:40];
185             41:r_arp_txd = r_des_mac[39:32];
186             42:r_arp_txd = r_des_mac[31:24];
187             43:r_arp_txd = r_des_mac[23:16];
188             44:r_arp_txd = r_des_mac[15:8];
189             45:r_arp_txd = r_des_mac[7:0];
190             46:r_arp_txd = r_des_ip[31:24];
191             47:r_arp_txd = r_des_ip[23:16];
192             48:r_arp_txd = r_des_ip[15:8];
193             49:r_arp_txd = r_des_ip[7:0];
194             68:r_arp_txd = w_crc_data[31:24];
195             69:r_arp_txd = w_crc_data[23:16];
196             70:r_arp_txd = w_crc_data[15:8];
197             71:r_arp_txd = w_crc_data[7:0];
198             default:r_arp_txd = 'd0;
199         endcase
200     end
201 /******************************************************************************\
202 Tx CRC
203 \******************************************************************************/
204     crc32_d8   u_crc32_d8
205     (
206         .clk                (i_sys_clk        ),
207         .rst_n              (i_sys_rstn       ),
208         .data               (w_crc_d8         ),
209         .crc_en             (r_crc_en_dly     ),
210         .crc_clr            (w_crc_clr        ),
211         .crc_dout           (w_crc_data       ),
212         .crc_next           (                 )
213     );
214     assign w_crc_d8 = o_gmii_txd;
215 
216     always@(*)
217     begin
218         case(r_byte_cnt)
219             0,1,2,3,4,5,6,7:    r_crc_en = 'd0;
220             68,69,70,71:        r_crc_en = 'd0;
221             default:            r_crc_en = 1'b1;
222         endcase
223     end
224     always@(posedge i_sys_clk)
225     begin
226         r_crc_en_dly <= r_crc_en;
227     end
228 /******************************************************************************\
229 Gmii tx data
230 \******************************************************************************/
231     always@(posedge i_sys_clk)
232     begin
233         if(~i_sys_rstn | w_crc_clr)
234         begin
235             o_gmii_txd        <= 'd0;
236             o_gmii_tx_vld     <= 'd0;
237         end
238         else if(r_arp_en)
239         begin
240             o_gmii_txd        <= r_arp_txd;
241             o_gmii_tx_vld     <= 1'b1;
242         end
243         else
244         begin
245             o_gmii_tx_vld     <= 'd0;
246         end
247     end
248 
249 endmodule

  crc32_d8.v根据正点原子源码做了些修改。

  1 //****************************************Copyright (c)***********************************//
  2 //技术支持:www.openedv.com
  3 //淘宝店铺:http://openedv.taobao.com 
  4 //关注微信公众平台微信号:"正点原子",免费获取FPGA & STM32资料。
  5 //版权所有,盗版必究。
  6 //Copyright(C) 正点原子 2018-2028
  7 //All rights reserved                                  
  8 //----------------------------------------------------------------------------------------
  9 // File name:           crc32_d8
 10 // Last modified Date:  2019/8/21 8:37:49
 11 // Last Version:        V1.0
 12 // Descriptions:        CRC32校验模块
 13 //----------------------------------------------------------------------------------------
 14 // Created by:          正点原子
 15 // Created date:        2018/3/12 8:37:49
 16 // Version:             V1.0
 17 // Descriptions:        The original version
 18 //
 19 //----------------------------------------------------------------------------------------
 20 //****************************************************************************************//
 21 
 22 module crc32_d8(
 23     input                 clk     ,  //时钟信号
 24     input                 rst_n   ,  //复位信号,低电平有效
 25     input         [7:0]   data    ,  //输入待校验8位数据
 26     input                 crc_en  ,  //crc使能,开始校验标志
 27     input                 crc_clr ,  //crc数据复位信号            
 28     output         [31:0]  crc_dout,  //CRC校验数据
 29     output        [31:0]  crc_next   //CRC下次校验完成数据
 30     );
 31 
 32 //*****************************************************
 33 //**                    main code
 34 //*****************************************************
 35 
 36 //输入待校验8位数据,需要先将高低位互换
 37 wire    [7:0]    data_t;
 38 reg        [31:0]    crc_data;
 39 
 40 assign data_t = {data[0],data[1],data[2],data[3],data[4],data[5],data[6],data[7]};
 41 
 42 //CRC32的生成多项式为:G(x)= x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 
 43 //+ x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
 44 
 45 assign crc_next[0] = crc_data[24] ^ crc_data[30] ^ data_t[0] ^ data_t[6];
 46 assign crc_next[1] = crc_data[24] ^ crc_data[25] ^ crc_data[30] ^ crc_data[31] 
 47                      ^ data_t[0] ^ data_t[1] ^ data_t[6] ^ data_t[7];
 48 assign crc_next[2] = crc_data[24] ^ crc_data[25] ^ crc_data[26] ^ crc_data[30] 
 49                      ^ crc_data[31] ^ data_t[0] ^ data_t[1] ^ data_t[2] ^ data_t[6] 
 50                      ^ data_t[7];
 51 assign crc_next[3] = crc_data[25] ^ crc_data[26] ^ crc_data[27] ^ crc_data[31] 
 52                      ^ data_t[1] ^ data_t[2] ^ data_t[3] ^ data_t[7];
 53 assign crc_next[4] = crc_data[24] ^ crc_data[26] ^ crc_data[27] ^ crc_data[28] 
 54                      ^ crc_data[30] ^ data_t[0] ^ data_t[2] ^ data_t[3] ^ data_t[4] 
 55                      ^ data_t[6];
 56 assign crc_next[5] = crc_data[24] ^ crc_data[25] ^ crc_data[27] ^ crc_data[28] 
 57                      ^ crc_data[29] ^ crc_data[30] ^ crc_data[31] ^ data_t[0] 
 58                      ^ data_t[1] ^ data_t[3] ^ data_t[4] ^ data_t[5] ^ data_t[6] 
 59                      ^ data_t[7];
 60 assign crc_next[6] = crc_data[25] ^ crc_data[26] ^ crc_data[28] ^ crc_data[29] 
 61                      ^ crc_data[30] ^ crc_data[31] ^ data_t[1] ^ data_t[2] ^ data_t[4] 
 62                      ^ data_t[5] ^ data_t[6] ^ data_t[7];
 63 assign crc_next[7] = crc_data[24] ^ crc_data[26] ^ crc_data[27] ^ crc_data[29] 
 64                      ^ crc_data[31] ^ data_t[0] ^ data_t[2] ^ data_t[3] ^ data_t[5] 
 65                      ^ data_t[7];
 66 assign crc_next[8] = crc_data[0] ^ crc_data[24] ^ crc_data[25] ^ crc_data[27] 
 67                      ^ crc_data[28] ^ data_t[0] ^ data_t[1] ^ data_t[3] ^ data_t[4];
 68 assign crc_next[9] = crc_data[1] ^ crc_data[25] ^ crc_data[26] ^ crc_data[28] 
 69                      ^ crc_data[29] ^ data_t[1] ^ data_t[2] ^ data_t[4] ^ data_t[5];
 70 assign crc_next[10] = crc_data[2] ^ crc_data[24] ^ crc_data[26] ^ crc_data[27] 
 71                      ^ crc_data[29] ^ data_t[0] ^ data_t[2] ^ data_t[3] ^ data_t[5];
 72 assign crc_next[11] = crc_data[3] ^ crc_data[24] ^ crc_data[25] ^ crc_data[27] 
 73                      ^ crc_data[28] ^ data_t[0] ^ data_t[1] ^ data_t[3] ^ data_t[4];
 74 assign crc_next[12] = crc_data[4] ^ crc_data[24] ^ crc_data[25] ^ crc_data[26] 
 75                      ^ crc_data[28] ^ crc_data[29] ^ crc_data[30] ^ data_t[0] 
 76                      ^ data_t[1] ^ data_t[2] ^ data_t[4] ^ data_t[5] ^ data_t[6];
 77 assign crc_next[13] = crc_data[5] ^ crc_data[25] ^ crc_data[26] ^ crc_data[27] 
 78                      ^ crc_data[29] ^ crc_data[30] ^ crc_data[31] ^ data_t[1] 
 79                      ^ data_t[2] ^ data_t[3] ^ data_t[5] ^ data_t[6] ^ data_t[7];
 80 assign crc_next[14] = crc_data[6] ^ crc_data[26] ^ crc_data[27] ^ crc_data[28] 
 81                      ^ crc_data[30] ^ crc_data[31] ^ data_t[2] ^ data_t[3] ^ data_t[4]
 82                      ^ data_t[6] ^ data_t[7];
 83 assign crc_next[15] =  crc_data[7] ^ crc_data[27] ^ crc_data[28] ^ crc_data[29]
 84                      ^ crc_data[31] ^ data_t[3] ^ data_t[4] ^ data_t[5] ^ data_t[7];
 85 assign crc_next[16] = crc_data[8] ^ crc_data[24] ^ crc_data[28] ^ crc_data[29] 
 86                      ^ data_t[0] ^ data_t[4] ^ data_t[5];
 87 assign crc_next[17] = crc_data[9] ^ crc_data[25] ^ crc_data[29] ^ crc_data[30] 
 88                      ^ data_t[1] ^ data_t[5] ^ data_t[6];
 89 assign crc_next[18] = crc_data[10] ^ crc_data[26] ^ crc_data[30] ^ crc_data[31] 
 90                      ^ data_t[2] ^ data_t[6] ^ data_t[7];
 91 assign crc_next[19] = crc_data[11] ^ crc_data[27] ^ crc_data[31] ^ data_t[3] ^ data_t[7];
 92 assign crc_next[20] = crc_data[12] ^ crc_data[28] ^ data_t[4];
 93 assign crc_next[21] = crc_data[13] ^ crc_data[29] ^ data_t[5];
 94 assign crc_next[22] = crc_data[14] ^ crc_data[24] ^ data_t[0];
 95 assign crc_next[23] = crc_data[15] ^ crc_data[24] ^ crc_data[25] ^ crc_data[30] 
 96                       ^ data_t[0] ^ data_t[1] ^ data_t[6];
 97 assign crc_next[24] = crc_data[16] ^ crc_data[25] ^ crc_data[26] ^ crc_data[31] 
 98                       ^ data_t[1] ^ data_t[2] ^ data_t[7];
 99 assign crc_next[25] = crc_data[17] ^ crc_data[26] ^ crc_data[27] ^ data_t[2] ^ data_t[3];
100 assign crc_next[26] = crc_data[18] ^ crc_data[24] ^ crc_data[27] ^ crc_data[28] 
101                       ^ crc_data[30] ^ data_t[0] ^ data_t[3] ^ data_t[4] ^ data_t[6];
102 assign crc_next[27] = crc_data[19] ^ crc_data[25] ^ crc_data[28] ^ crc_data[29] 
103                       ^ crc_data[31] ^ data_t[1] ^ data_t[4] ^ data_t[5] ^ data_t[7];
104 assign crc_next[28] = crc_data[20] ^ crc_data[26] ^ crc_data[29] ^ crc_data[30] 
105                       ^ data_t[2] ^ data_t[5] ^ data_t[6];
106 assign crc_next[29] = crc_data[21] ^ crc_data[27] ^ crc_data[30] ^ crc_data[31] 
107                       ^ data_t[3] ^ data_t[6] ^ data_t[7];
108 assign crc_next[30] = crc_data[22] ^ crc_data[28] ^ crc_data[31] ^ data_t[4] ^ data_t[7];
109 assign crc_next[31] = crc_data[23] ^ crc_data[29] ^ data_t[5];
110 
111 always @(posedge clk or negedge rst_n) begin
112     if(!rst_n)
113         crc_data <= 32'hff_ff_ff_ff;
114     else if(crc_clr)                             //CRC校验值复位
115         crc_data <= 32'hff_ff_ff_ff;
116     else if(crc_en)
117         crc_data <= crc_next;
118 end
119 
120 assign crc_dout = {    ~crc_next[24], ~crc_next[25], ~crc_next[26],~crc_next[27],~crc_next[28], ~crc_next[29], ~crc_next[30], ~crc_next[31],
121                     ~crc_data[16], ~crc_data[17], ~crc_data[18],~crc_data[19],~crc_data[20], ~crc_data[21], ~crc_data[22], ~crc_data[23],
122                     ~crc_data[8] , ~crc_data[9] , ~crc_data[10],~crc_data[11],~crc_data[12], ~crc_data[13], ~crc_data[14], ~crc_data[15],
123                     ~crc_data[0] , ~crc_data[1] , ~crc_data[2] ,~crc_data[3] ,~crc_data[4] , ~crc_data[5] , ~crc_data[6] , ~crc_data[7]
124                     };
125 
126 endmodule

  arp_rx.v文件笔者是觉得比较简单,而且笔者比较懒,有了就直接拿来用,以下是直接调用了正点原子的模块。

  1 //****************************************Copyright (c)***********************************//
  2 //原子哥在线教学平台:www.yuanzige.com
  3 //技术支持:www.openedv.com
  4 //淘宝店铺:http://openedv.taobao.com 
  5 //关注微信公众平台微信号:"正点原子",免费获取ZYNQ & FPGA & STM32 & LINUX资料。
  6 //版权所有,盗版必究。
  7 //Copyright(C) 正点原子 2018-2028
  8 //All rights reserved                                  
  9 //----------------------------------------------------------------------------------------
 10 // File name:           arp_rx
 11 // Last modified Date:  2020/2/13 9:20:14
 12 // Last Version:        V1.0
 13 // Descriptions:        arp接收模块
 14 //----------------------------------------------------------------------------------------
 15 // Created by:          正点原子
 16 // Created date:        2020/2/13 9:20:14
 17 // Version:             V1.0
 18 // Descriptions:        The original version
 19 //
 20 //----------------------------------------------------------------------------------------
 21 //****************************************************************************************//
 22 
 23 module arp_rx
 24   #(
 25     //开发板MAC地址 00-11-22-33-44-55
 26     parameter BOARD_MAC = 48'h00_11_22_33_44_55,  
 27     //开发板IP地址 192.168.1.11   
 28     parameter BOARD_IP = {8'd192,8'd168,8'd1,8'd11}      
 29     )
 30    (
 31     input                clk        , //时钟信号
 32     input                rst_n      , //复位信号,低电平有效
 33                                     
 34     input                gmii_rx_dv , //GMII输入数据有效信号
 35     input        [7:0]   gmii_rxd   , //GMII输入数据
 36     output  reg          arp_rx_done, //ARP接收完成信号
 37     output  reg          arp_rx_type, //ARP接收类型 0:请求  1:应答
 38     output  reg  [47:0]  src_mac    , //接收到的源MAC地址
 39     output  reg  [31:0]  src_ip       //接收到的源IP地址
 40     );
 41 
 42 //parameter define
 43 localparam  st_idle     = 5'b0_0001; //初始状态,等待接收前导码
 44 localparam  st_preamble = 5'b0_0010; //接收前导码状态 
 45 localparam  st_eth_head = 5'b0_0100; //接收以太网帧头
 46 localparam  st_arp_data = 5'b0_1000; //接收ARP数据
 47 localparam  st_rx_end   = 5'b1_0000; //接收结束
 48 
 49 localparam  ETH_TPYE = 16'h0806;     //以太网帧类型 ARP
 50 
 51 //reg define
 52 (* dont_touch = "yes" *)reg    [4:0]   cur_state ;
 53 reg    [4:0]   next_state;
 54                          
 55 (* dont_touch = "yes" *)reg            skip_en   ; //控制状态跳转使能信号
 56 (* dont_touch = "yes" *)reg            error_en  ; //解析错误使能信号
 57 (* dont_touch = "yes" *)reg    [4:0]   cnt       ; //解析数据计数器
 58 (* dont_touch = "yes" *)reg    [47:0]  des_mac_t ; //接收到的目的MAC地址
 59 (* dont_touch = "yes" *)reg    [31:0]  des_ip_t  ; //接收到的目的IP地址
 60 (* dont_touch = "yes" *)reg    [47:0]  src_mac_t ; //接收到的源MAC地址
 61 (* dont_touch = "yes" *)reg    [31:0]  src_ip_t  ; //接收到的源IP地址
 62 (* dont_touch = "yes" *)reg    [15:0]  eth_type  ; //以太网类型
 63 reg    [15:0]  op_data   ; //操作码
 64 
 65 //*****************************************************
 66 //**                    main code
 67 //*****************************************************
 68 
 69 //(三段式状态机)同步时序描述状态转移
 70 always @(posedge clk or negedge rst_n) begin
 71     if(!rst_n)
 72         cur_state <= st_idle;  
 73     else
 74         cur_state <= next_state;
 75 end
 76 
 77 //组合逻辑判断状态转移条件
 78 always @(*) begin
 79     next_state = st_idle;
 80     case(cur_state)
 81         st_idle : begin                     //等待接收前导码
 82             if(skip_en) 
 83                 next_state = st_preamble;
 84             else
 85                 next_state = st_idle;    
 86         end
 87         st_preamble : begin                 //接收前导码
 88             if(skip_en) 
 89                 next_state = st_eth_head;
 90             else if(error_en) 
 91                 next_state = st_rx_end;    
 92             else
 93                 next_state = st_preamble;   
 94         end
 95         st_eth_head : begin                 //接收以太网帧头
 96             if(skip_en) 
 97                 next_state = st_arp_data;
 98             else if(error_en) 
 99                 next_state = st_rx_end;
100             else
101                 next_state = st_eth_head;   
102         end  
103         st_arp_data : begin                  //接收ARP数据
104             if(skip_en)
105                 next_state = st_rx_end;
106             else if(error_en)
107                 next_state = st_rx_end;
108             else
109                 next_state = st_arp_data;   
110         end                  
111         st_rx_end : begin                   //接收结束
112             if(skip_en)
113                 next_state = st_idle;
114             else
115                 next_state = st_rx_end;          
116         end
117         default : next_state = st_idle;
118     endcase                                          
119 end    
120 
121 //时序电路描述状态输出,解析以太网数据
122 always @(posedge clk or negedge rst_n) begin
123     if(!rst_n) begin
124         skip_en <= 1'b0;
125         error_en <= 1'b0;
126         cnt <= 5'd0;
127         des_mac_t <= 48'd0;
128         des_ip_t <= 32'd0;
129         src_mac_t <= 48'd0;
130         src_ip_t <= 32'd0;        
131         eth_type <= 16'd0;
132         op_data <= 16'd0;
133         arp_rx_done <= 1'b0;
134         arp_rx_type <= 1'b0;
135         src_mac <= 48'd0;
136         src_ip <= 32'd0;
137     end
138     else begin
139         skip_en <= 1'b0;
140         error_en <= 1'b0;  
141         arp_rx_done <= 1'b0;
142         case(next_state)
143             st_idle : begin                                  //检测到第一个8'h55
144                 if((gmii_rx_dv == 1'b1) && (gmii_rxd == 8'h55)) 
145                     skip_en <= 1'b1;
146             end
147             st_preamble : begin
148                 if(gmii_rx_dv) begin                         //解析前导码
149                     cnt <= cnt + 5'd1;
150                     if((cnt < 5'd6) && (gmii_rxd != 8'h55))  //7个8'h55  
151                         error_en <= 1'b1;
152                     else if(cnt==5'd6) begin
153                         cnt <= 5'd0;
154                         if(gmii_rxd==8'hd5)                  //1个8'hd5
155                             skip_en <= 1'b1;
156                         else
157                             error_en <= 1'b1;    
158                     end  
159                 end  
160             end
161             st_eth_head : begin
162                 if(gmii_rx_dv) begin
163                     cnt <= cnt + 5'b1;
164                     if(cnt < 5'd6) 
165                         des_mac_t <= {des_mac_t[39:0],gmii_rxd};
166                     else if(cnt == 5'd6) begin
167                         //判断MAC地址是否为开发板MAC地址或者公共地址
168                         if((des_mac_t != BOARD_MAC)
169                             && (des_mac_t != 48'hff_ff_ff_ff_ff_ff))           
170                             error_en <= 1'b1;
171                     end
172                     else if(cnt == 5'd12) 
173                         eth_type[15:8] <= gmii_rxd;          //以太网协议类型
174                     else if(cnt == 5'd13) begin
175                         eth_type[7:0] <= gmii_rxd;
176                         cnt <= 5'd0;
177                         if(eth_type[15:8] == ETH_TPYE[15:8]  //判断是否为ARP协议
178                             && gmii_rxd == ETH_TPYE[7:0])
179                             skip_en <= 1'b1; 
180                         else
181                             error_en <= 1'b1;                       
182                     end        
183                 end  
184             end
185             st_arp_data : begin
186                 if(gmii_rx_dv) begin
187                     cnt <= cnt + 5'd1;
188                     if(cnt == 5'd6) 
189                         op_data[15:8] <= gmii_rxd;           //操作码       
190                     else if(cnt == 5'd7)
191                         op_data[7:0] <= gmii_rxd;
192                     else if(cnt >= 5'd8 && cnt < 5'd14)      //源MAC地址
193                         src_mac_t <= {src_mac_t[39:0],gmii_rxd};
194                     else if(cnt >= 5'd14 && cnt < 5'd18)     //源IP地址
195                         src_ip_t<= {src_ip_t[23:0],gmii_rxd};
196                     else if(cnt >= 5'd24 && cnt < 5'd28)     //目标IP地址
197                         des_ip_t <= {des_ip_t[23:0],gmii_rxd};
198                     else if(cnt == 5'd28) begin
199                         cnt <= 5'd0;
200                         if(des_ip_t == BOARD_IP) begin       //判断目的IP地址和操作码
201                             if((op_data == 16'd1) || (op_data == 16'd2)) begin
202                                 skip_en <= 1'b1;
203                                 arp_rx_done <= 1'b1;
204                                 src_mac <= src_mac_t;
205                                 src_ip <= src_ip_t;
206                                 src_mac_t <= 48'd0;
207                                 src_ip_t <= 32'd0;
208                                 des_mac_t <= 48'd0;
209                                 des_ip_t <= 32'd0;
210                                 if(op_data == 16'd1)         
211                                     arp_rx_type <= 1'b0;     //ARP请求
212                                 else
213                                     arp_rx_type <= 1'b1;     //ARP应答
214                             end
215                             else
216                                 error_en <= 1'b1;
217                         end 
218                         else
219                             error_en <= 1'b1;
220                     end
221                 end                                
222             end
223             st_rx_end : begin     
224                 cnt <= 5'd0;
225                 //单包数据接收完成   
226                 if(gmii_rx_dv == 1'b0 && skip_en == 1'b0)
227                     skip_en <= 1'b1; 
228             end    
229             default : ;
230         endcase                                                        
231     end
232 end
233 
234 endmodule

  Arp_ctrl.v

 1 //**************************************************************************
 2 // *** file name      : Arp_ctrl.v
 3 // *** version        : 1.0
 4 // *** Description    : Arp_ctrl
 5 // *** Blogs          : https://www.cnblogs.com/WenGalois123/
 6 // *** Author         : Galois_V
 7 // *** Date           : 2022.5.12
 8 // *** Changes        : Initial
 9 //**************************************************************************
10 `timescale  1ns/1ps 
11 module Arp_ctrl
12 #(
13     parameter                    SYS_FRE        = 100_000_000
14 )
15 (
16     input                        i_sys_clk        ,
17     input                        i_sys_rstn       ,
18     
19     input                        i_key_signal     ,
20     output                       o_key_led        ,
21     input                        i_arp_rx_done    ,
22     input                        i_arp_rx_mode    ,
23     output        reg            o_arp_tx_en      ,
24     output        reg            o_arp_tx_mode    
25 );
26     
27     wire                        w_key_dejitter    ;
28     wire                        w_key_pos         ;
29     reg            [1:0]        r_key_signal      ;
30     
31 /******************************************************************************\
32 Key dejitter
33 \******************************************************************************/
34     Key_dejitter
35     #(
36         .SYS_FRE            (SYS_FRE           )
37     )
38     u_Key_dejitter
39     (
40         .i_sys_clk          (i_sys_clk         ),
41         .i_key_jitter       (i_key_signal      ),
42         .o_key_dejitter     (w_key_dejitter    )        
43     );
44 
45     assign o_key_led = w_key_dejitter;
46 /******************************************************************************\
47 Arp control signal generate
48 \******************************************************************************/
49     always@(posedge i_sys_clk)
50     begin
51         if(~i_sys_rstn)
52         begin
53             r_key_signal <= 'd0;
54         end
55         else
56         begin
57             r_key_signal <= {r_key_signal[0],w_key_dejitter};
58         end
59     end
60     
61     assign w_key_pos = ~r_key_signal[1] & r_key_signal[0];
62     
63     always@(posedge i_sys_clk)
64     begin
65         if(~i_sys_rstn)
66         begin
67             o_arp_tx_mode    <= 'd0;
68             o_arp_tx_en      <= 'd0;
69         end
70         else if(w_key_pos)
71         begin
72             o_arp_tx_en      <= 1'b1;
73             o_arp_tx_mode    <= 1'b0;
74         end
75         else if(i_arp_rx_done&&(i_arp_rx_mode==1'b0))
76         begin
77             o_arp_tx_en      <= 1'b1;
78             o_arp_tx_mode    <= 1'b1;
79         end
80         else
81         begin
82             o_arp_tx_en      <= 'd0;
83         end
84     end
85     
86 endmodule

  按键去抖模块Key_dejitter.v前面已经提过。

实验测试,连接好开发板与电脑的网线,把固件烧进黑金的开发板AXU3EG 。以管理员身份打开命令提示符,先输入arp - d删除所有的缓存地址,再输入arp -a显示如下:

按下测试按键,再输入arp -a,结果如下:

该结果说明由开发板发送的ARP请求,PC正常接收。

接着输入arp -d 再输入arp -a,确保把之前的开发板的IP及MAC地址删除。然后输入ping 192.168.1.6结果如下:

显示请求超时,这时输入arp -a,显示了开发板的相关信息:

说明由电脑发送arp请求,开发板接收正常。

ARP测试实验完成。

 

posted on 2022-06-14 15:41  Galois_V  阅读(1134)  评论(1编辑  收藏  举报