基於FPGA的ARP協議實現

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、代碼設計(參考的小梅哥的設計思路,在小梅哥的設計的基礎上,作了小小的修改)

 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
View Code

測試代碼:

 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
View Code

仿真效果:

 

 圖1

 

 

 圖2

上板效果圖:

 圖3

  注:代碼設計參考了小梅哥的設計,梅哥寫的比較簡單易懂,文字敘述方面也摘抄了梅哥的《基於ac620的fpga系統設計與驗證明戰指南20190516》;

    若是沒法收到ARP提示,多是時序的問題,須要添加時序約束;

    若是收到了ARP提示,可是沒有應答包,那就有多是電腦上沒有綁定在代碼中設定的目的IP地址(在本文中的 des_ip:192.168.0.3);

 

   若有不當之處,還望各位道友指正~

相關文章
相關標籤/搜索