1、ARP幀存在的做用:網絡
在網絡通信時,源主機的應用程序知道目的的IP地址和端口號,殊不知道目的主機的硬件地址,而數據包首先是被網卡接收到再去處理上層協議的,若是接收到的數據包的硬件地址與本機不符,則直接丟棄。所以在通信前必須得到目的主機的硬件地址。ARP協議就起這個做用。ide
2、ARP幀的工做原理:測試
源主機發出ARP請求,詢問「IP地址是 192.168.0.1的主機的硬件地址是多少」,並將這個請求廣播到本地網段(以太網幀首部的硬件地址填 FF:FF:FF:FF:FF:FF表示廣播),目的主機接收到廣播的ARP請求,發現其中的IP地址與本機相符,則發送一個ARP應答數據包給源主機,將本身的硬件地址填寫在應答包中。spa
3、ARP數據報格式設計
*** 以太網目的地址:48'hff_ff_ff_ff_ff_ff,廣播到電腦;code
*** 以太網源地址:48'h00_0a_35_01_fe_c0,開發板的以太網芯片地址(貌似是能夠本身設定);blog
*** 幀類型:0x0806表示ARP幀;接口
*** 硬件類型:0x0001表示以太網類型值;ip
*** 協議類型:0x0800表示上層協議爲IP協議;開發
*** 硬件地址長度:0x6表示以太網的地址長度是6個字節;
*** 協議地址長度:0x4表示IP地址長度爲4個字節;
*** op:0x1表示ARP請求包,0x2表示ARP應答包;
*** 發送者硬件地址:源MAC地址(開發板的以太網芯片地址);
*** 發送者IP:發送方的IP地址;
*** 目的硬件地址:電腦的MAC地址;
*** 目標IP地址:電腦的IP地址;
4、MAC協議格式
*** 前導碼:55_55_55_55_55_55_55,是用來實現數據的同步;
*** SFD:幀起始界定符:8'h5d,表示一幀的開始;
*** FCS:爲確保數據的正確傳輸,在數據的尾部加入了4個字節的循環冗餘校驗碼(CRC校驗) ;
5、ARP協議是加載在MAC協議上來發送的,以下圖所示:
6、代碼設計(參考的小梅哥的設計思路,在小梅哥的設計的基礎上,作了小小的修改)
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
1 // Time : 2020.04.06 21:12 2 // Describe : eth_test 3 4 module eth_test( 5 rst_n, 6 7 //MII 接口信號 8 mii_tx_clk, 9 mii_tx_en, 10 mii_tx_er, 11 mii_tx_data, 12 13 mii_rx_clk, 14 mii_rx_dv, 15 mii_rx_er, 16 mii_rx_data, 17 18 phy_rst_n 19 ); 20 21 input rst_n; 22 23 input mii_tx_clk; //MII接口發送時鐘,由PHY芯片產生,25MHz 24 output mii_tx_en; //MII接口發送數據使能信號,高電平有效 25 output mii_tx_er; //發送錯誤,用以破壞數據包發送 26 output reg[3:0]mii_tx_data; //MII接口發送數據線,FPGA經過該數據線將須要發送的數據依次送給PHY芯片 27 output phy_rst_n; //PHY 復位信號 28 29 input mii_rx_clk; //MII接口接收時鐘,由PHY芯片產生,25MHz 30 input mii_rx_dv; //MII接口接收數據有效信號,高電平有效 31 input mii_rx_er; //接收錯誤,本實例中暫時忽略該信號 32 input [3:0]mii_rx_data; //MII接口數據總線,FPGA經過該數據線讀取PHY芯片接收到的以太網數據 33 34 assign phy_rst_n = 1'b1; 35 36 parameter des_mac = 48'hff_ff_ff_ff_ff_ff; //目標MAC地址 37 parameter src_mac = 48'h34_23_87_99_f4_61; //本機/源MAC地址 38 parameter type_length = 16'h08_06; //數據幀類型 39 parameter data_length = 12'd92; //數據長度(由於MII接口一個字節分兩個時鐘,每一個時鐘4位的方式發送,所以本值爲實際數據所佔字節數的2倍) 40 41 parameter CRC = 32'h5b0ea9fa; //整個數據包CRC校驗值,本例中使用CRC計算軟件計算得出。 42 43 wire[31:0] CRC_Result; 44 45 assign CRC_Result = {CRC[7:0],CRC[15:8],CRC[23:16],CRC[31:24]}; //調整 CRC校驗字字節順序以符合以太網數據包校驗格式 46 47 wire tx_go; // 使能發送 48 49 reg [7:0] lsm_cnt; //序列機計數器,本以太網幀發送系統使用線性序列機方式設計 50 reg en_tx; //內部的數據幀發送使能信號,高電平時將數據經過MII接口送出 51 52 reg [28:0]cnt; //發送間隔計數器 53 always@(posedge mii_tx_clk or negedge rst_n) 54 if(!rst_n) 55 cnt <= 28'd0; 56 else if(cnt == 28'd3500) // 35000000 57 cnt <= 28'd0; 58 else 59 cnt <= cnt + 1'b1; 60 61 //每671ms啓動一次發送數據 62 assign tx_go = (cnt == 28'd3500) ? 1'b1 : 1'b0; // 35000000 63 64 //根據發送啓動信號產生內部發送使能信號 65 always@(posedge mii_tx_clk or negedge rst_n) 66 if(!rst_n) 67 en_tx <= 1'd0; 68 else if(tx_go) 69 en_tx <= 1'd1; 70 else if(lsm_cnt >= 145) //一幀數據發送完成,清零發送使能信號 71 en_tx <= 1'd0; 72 73 always@(posedge mii_tx_clk or negedge rst_n) //主序列機計數器 74 if(!rst_n) 75 lsm_cnt <= 8'd0; 76 else if(en_tx) begin 77 if(lsm_cnt == 8'd145) 78 lsm_cnt <= 8'd0; 79 else 80 lsm_cnt <= lsm_cnt + 1'b1; 81 end 82 else 83 lsm_cnt <= 8'd0; 84 85 /* 86 always@(posedge mii_tx_clk or negedge rst_n) 87 if(!rst_n) begin 88 mii_tx_data <= 4'd0; 89 end 90 else begin 91 */ 92 always@(*) begin 93 case(lsm_cnt) 94 1: mii_tx_data <= 4'h5; // 前導碼 + 分隔符的一個5 95 2: mii_tx_data <= 4'h5; 96 3: mii_tx_data <= 4'h5; 97 4: mii_tx_data <= 4'h5; 98 5: mii_tx_data <= 4'h5; 99 6: mii_tx_data <= 4'h5; 100 7: mii_tx_data <= 4'h5; 101 8: mii_tx_data <= 4'h5; 102 9: mii_tx_data <= 4'h5; 103 10:mii_tx_data <= 4'h5; 104 11:mii_tx_data <= 4'h5; 105 12:mii_tx_data <= 4'h5; 106 13:mii_tx_data <= 4'h5; 107 14:mii_tx_data <= 4'h5; 108 15:mii_tx_data <= 4'h5; 109 110 16: mii_tx_data <= 4'hd; // 分隔符 111 112 17: mii_tx_data <= des_mac[43:40]; // 目的MAC地址,先發高八位中的低四位 48'hff_ff_ff_ff_ff_ff 113 18: mii_tx_data <= des_mac[47:44]; 114 19: mii_tx_data <= des_mac[35:32]; 115 20: mii_tx_data <= des_mac[39:36]; 116 21: mii_tx_data <= des_mac[27:24]; 117 22: mii_tx_data <= des_mac[31:28]; 118 23: mii_tx_data <= des_mac[19:16]; 119 24: mii_tx_data <= des_mac[23:20]; 120 25: mii_tx_data <= des_mac[11:8]; 121 26: mii_tx_data <= des_mac[15:12]; 122 27: mii_tx_data <= des_mac[3:0]; 123 28: mii_tx_data <= des_mac[7:4]; 124 125 126 29: mii_tx_data <= src_mac[43:40];// 0 //源MAC地址 48'h00_0a_35_01_fe_c0 127 30: mii_tx_data <= src_mac[47:44];// 0 128 31: mii_tx_data <= src_mac[35:32];// a 129 32: mii_tx_data <= src_mac[39:36];// 0 130 33: mii_tx_data <= src_mac[27:24];// 5 131 34: mii_tx_data <= src_mac[31:28];// 3 132 35: mii_tx_data <= src_mac[19:16];// 1 133 36: mii_tx_data <= src_mac[23:20];// 0 134 37: mii_tx_data <= src_mac[11:8]; // e 135 38: mii_tx_data <= src_mac[15:12];// f 136 39: mii_tx_data <= src_mac[3:0]; // 0 137 40: mii_tx_data <= src_mac[7:4]; // c 138 139 140 41: mii_tx_data <= type_length[11:8]; //以太網幀類型/長度 141 42: mii_tx_data <= type_length[15:12]; 142 43: mii_tx_data <= type_length[3:0]; 143 44: mii_tx_data <= type_length[7:4]; 144 145 45: mii_tx_data = 4'h0; 146 46: mii_tx_data = 4'h0; 147 47: mii_tx_data = 4'h1; 148 48: mii_tx_data = 4'h0; 149 150 //protocol type 151 49: mii_tx_data = 4'h8; 152 50: mii_tx_data = 4'h0; 153 51: mii_tx_data = 4'h0; 154 52: mii_tx_data = 4'h0; 155 156 //hdwr size 157 53: mii_tx_data = 4'h6; 158 54: mii_tx_data = 4'h0; 159 160 //protocol size 161 55: mii_tx_data = 4'h4; 162 56: mii_tx_data = 4'h0; 163 164 //opcode 165 57: mii_tx_data = 4'h0; 166 58: mii_tx_data = 4'h0; 167 59: mii_tx_data = 4'h1; 168 60: mii_tx_data = 4'h0; 169 170 //sender mac 171 61: mii_tx_data = 4'h0; 172 62: mii_tx_data = 4'h0; 173 63: mii_tx_data = 4'ha; 174 64: mii_tx_data = 4'h0; 175 65: mii_tx_data = 4'h5; 176 66: mii_tx_data = 4'h3; 177 67: mii_tx_data = 4'h1; 178 68: mii_tx_data = 4'h0; 179 69: mii_tx_data = 4'he; 180 70: mii_tx_data = 4'hf; 181 71: mii_tx_data = 4'h0; 182 72: mii_tx_data = 4'hc; 183 184 //sender ip : 192.168.0.2 185 73: mii_tx_data = 4'h0;//192 186 74: mii_tx_data = 4'hc; 187 188 75: mii_tx_data = 4'h8;//168 189 76: mii_tx_data = 4'ha; 190 191 77: mii_tx_data = 4'h0;//0 192 78: mii_tx_data = 4'h0; 193 194 79: mii_tx_data = 4'h2; 195 80: mii_tx_data = 4'h0;//2 196 197 //target mac 198 81: mii_tx_data = 4'h4; // 4 //48'b84 7b eb 48 94 13 199 82: mii_tx_data = 4'h3; // 8 //48'b34 23 87 99 f4 61 200 83: mii_tx_data = 4'h3; // b 201 84: mii_tx_data = 4'h2; // 7 202 85: mii_tx_data = 4'h7; // b 203 86: mii_tx_data = 4'h8; // e 204 87: mii_tx_data = 4'h9; // 8 205 88: mii_tx_data = 4'h9; // 4 206 89: mii_tx_data = 4'h4; // 4 207 90: mii_tx_data = 4'hf; // 9 208 91: mii_tx_data = 4'h1; // 3 209 92: mii_tx_data = 4'h6; // 1 210 211 //target ip : 192.168.0.3 212 93: mii_tx_data = 4'h0;//192 213 94: mii_tx_data = 4'hc; 214 215 95: mii_tx_data = 4'h8;//168 216 96: mii_tx_data = 4'ha; 217 218 97: mii_tx_data = 4'h0;//0 219 98: mii_tx_data = 4'h0; 220 221 99: mii_tx_data = 4'h3;//3 222 100: mii_tx_data = 4'h0; 223 224 //填充字段,以使整個數據幀長度達到64字節 225 101: mii_tx_data = 4'h0; 226 102: mii_tx_data = 4'h0; 227 103: mii_tx_data = 4'h0; 228 104: mii_tx_data = 4'h0; 229 105: mii_tx_data = 4'hf; 230 106: mii_tx_data = 4'hf; 231 107: mii_tx_data = 4'hf; 232 108: mii_tx_data = 4'hf; 233 109: mii_tx_data = 4'hf; 234 110: mii_tx_data = 4'hf; 235 111: mii_tx_data = 4'hf; 236 112: mii_tx_data = 4'hf; 237 113: mii_tx_data = 4'hf; 238 114: mii_tx_data = 4'hf; 239 115: mii_tx_data = 4'hf; 240 116: mii_tx_data = 4'hf; 241 117: mii_tx_data = 4'h0; 242 118: mii_tx_data = 4'h0; 243 119: mii_tx_data = 4'h3; 244 120: mii_tx_data = 4'h2; 245 121: mii_tx_data = 4'hd; 246 122: mii_tx_data = 4'hc; 247 123: mii_tx_data = 4'h6; 248 124: mii_tx_data = 4'h7; 249 125: mii_tx_data = 4'h3; 250 126: mii_tx_data = 4'h6; 251 127: mii_tx_data = 4'ha; 252 128: mii_tx_data = 4'h1; 253 129: mii_tx_data = 4'h8; 254 130: mii_tx_data = 4'h0; 255 131: mii_tx_data = 4'h6; 256 132: mii_tx_data = 4'h0; 257 133: mii_tx_data = 4'h0; 258 134: mii_tx_data = 4'h0; 259 135: mii_tx_data = 4'h1; 260 136: mii_tx_data = 4'h0; 261 262 137: mii_tx_data <= CRC_Result[27:24]; //發送CRC 校驗結果 263 138: mii_tx_data <= CRC_Result[31:28]; 264 139: mii_tx_data <= CRC_Result[19:16]; 265 140: mii_tx_data <= CRC_Result[23:20]; 266 141: mii_tx_data <= CRC_Result[11:8]; 267 142: mii_tx_data <= CRC_Result[15:12]; 268 143: mii_tx_data <= CRC_Result[3:0]; 269 144: mii_tx_data <= CRC_Result[7:4]; 270 271 145: mii_tx_data <= 4'd0; 272 default: mii_tx_data <= 4'd0; 273 endcase 274 end 275 276 /* 277 always@(posedge mii_tx_clk or negedge rst_n) //MII數據發送使能信號 278 if(!rst_n) 279 mii_tx_en <= 1'b0; 280 else if((lsm_cnt >= 1) && (lsm_cnt <= 144)) // lsm_cnt >= 1 281 mii_tx_en <= 1'b1; 282 else 283 mii_tx_en <= 1'b0; 284 */ 285 286 assign mii_tx_en = ((lsm_cnt >= 1) && (lsm_cnt <= 144)) ? 1'b1 : 1'b0; 287 288 endmodule 289
測試代碼:
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
1 `timescale 1ns/1ns 2 3 module eth_test_tb; 4 5 reg rst_n; 6 //MII 接口信號 7 reg mii_tx_clk; 8 wire mii_tx_en; 9 wire mii_tx_er; 10 wire [3:0]mii_tx_data; 11 wire phy_rst_n; 12 13 eth_test eth_test( 14 .rst_n(rst_n), 15 .mii_tx_clk(mii_tx_clk), 16 .mii_tx_en(mii_tx_en), 17 .mii_tx_er(mii_tx_er), 18 .mii_tx_data(mii_tx_data), 19 .phy_rst_n(phy_rst_n) 20 ); 21 22 initial mii_tx_clk = 1; 23 always #20 mii_tx_clk = ~mii_tx_clk; 24 25 initial begin 26 rst_n = 0; 27 #201; 28 rst_n = 1; 29 30 #1000000; 31 32 $stop; 33 end 34 35 endmodule
仿真效果:
圖1
圖2
上板效果圖:
圖3
注:代碼設計參考了小梅哥的設計,梅哥寫的比較簡單易懂,文字敘述方面也摘抄了梅哥的《基於ac620的fpga系統設計與驗證明戰指南20190516》;
若是沒法收到ARP提示,多是時序的問題,須要添加時序約束;
若是收到了ARP提示,可是沒有應答包,那就有多是電腦上沒有綁定在代碼中設定的目的IP地址(在本文中的 des_ip:192.168.0.3);
若有不當之處,還望各位道友指正~