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)实现数据的同步。
起始定界符(SFD, Start 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 个字节。
帧校验序列(FCS, Frame 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。
OP(Opcode):操作码,用于表示该数据包为 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测试实验完成。