zoukankan      html  css  js  c++  java
  • 基于FPGA的ARP协议实现

    一、ARP帧存在的作用:

           在网络通讯时,源主机的应用程序知道目的的IP地址和端口号,却不知道目的主机的硬件地址,而数据包首先是被网卡接收到再去处理上层协议的,如果接收到的数据包的硬件地址与本机不符,则直接丢弃。因此在通讯前必须获得目的主机的硬件地址。ARP协议就起这个作用。

    二、ARP帧的工作原理:

           源主机发出ARP请求,询问“IP地址是 192.168.0.1的主机的硬件地址是多少”,并将这个请求广播到本地网段(以太网帧首部的硬件地址填 FF:FF:FF:FF:FF:FF表示广播),目的主机接收到广播的ARP请求,发现其中的IP地址与本机相符,则发送一个ARP应答数据包给源主机,将自己的硬件地址填写在应答包中。

    三、ARP数据报格式

     ***  以太网目的地址:48'hff_ff_ff_ff_ff_ff,广播到电脑;

     ***  以太网源地址:48'h00_0a_35_01_fe_c0,开发板的以太网芯片地址(貌似是可以自己设定);

     ***  帧类型:0x0806表示ARP帧;

     *** 硬件类型:0x0001表示以太网类型值;

     *** 协议类型:0x0800表示上层协议为IP协议;

     *** 硬件地址长度:0x6表示以太网的地址长度是6个字节;

     *** 协议地址长度:0x4表示IP地址长度为4个字节;

     *** op:0x1表示ARP请求包,0x2表示ARP应答包;

     *** 发送者硬件地址:源MAC地址(开发板的以太网芯片地址);

     *** 发送者IP:发送方的IP地址;

     *** 目的硬件地址:电脑的MAC地址;

     *** 目标IP地址:电脑的IP地址;

    四、MAC协议格式

      *** 前导码:55_55_55_55_55_55_55,是用来实现数据的同步;

      *** SFD:帧起始界定符:8'h5d,表示一帧的开始;

      *** FCS:为确保数据的正确传输,在数据的尾部加入了4个字节的循环冗余校验码(CRC校验) ;

    五、ARP协议是加载在MAC协议上来发送的,如下图所示:

    六、代码设计(参考的小梅哥的设计思路,在小梅哥的设计的基础上,做了小小的修改)

      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 crc32_d4 u0(
     35   .Clk(mii_tx_clk),
     36   .Rst_n(rst_n), 
     37   .Data(mii_tx_data), 
     38   .Enable(CRC_EN),
     39   .Initialize(~mii_tx_en),
     40   .Crc(), 
     41   .CrcError(),
     42   .Crc_eth(CRC_Result)
     43  );
     44 
     45 assign phy_rst_n = 1'b1;
     46 
     47 parameter des_mac     = 48'hff_ff_ff_ff_ff_ff;  //目标MAC地址
     48 parameter src_mac     = 48'h00_0a_35_01_fe_c0;  //源MAC地址
     49 parameter type_length = 16'h08_06;                //数据帧类型
     50 parameter data_length = 12'd92;                   //数据长度(因为MII接口一个字节分两个时钟,每个时钟4位的方式发送,因此本值为实际数据所占字节数的2倍)
     51 
     52 wire[31:0] CRC_Result;
     53 
     54 wire CRC_EN;
     55 
     56 assign CRC_EN = (lsm_cnt > 17 && lsm_cnt <= 137);
     57 
     58 wire tx_go;                // 使能发送
     59 
     60 reg [7:0] lsm_cnt;           //序列机计数器,本以太网帧发送系统使用线性序列机方式设计
     61 reg en_tx;                   //内部的数据帧发送使能信号,高电平时将数据通过MII接口送出
     62 
     63 reg [28:0]cnt;  //发送间隔计数器
     64 always@(posedge mii_tx_clk or negedge rst_n)
     65   if(!rst_n)
     66      cnt <= 28'd0;
     67   else if(cnt == 28'd3500)  // 35000000
     68      cnt <= 28'd0;
     69   else
     70     cnt <= cnt + 1'b1;
     71     
     72 //每671ms启动一次发送数据    
     73 assign tx_go = (cnt == 28'd3500) ? 1'b1 : 1'b0;  // 35000000
     74 
     75 //根据发送启动信号产生内部发送使能信号
     76 always@(posedge mii_tx_clk or negedge rst_n) 
     77   if(!rst_n)
     78      en_tx <= 1'd0;
     79   else if(tx_go)
     80      en_tx <= 1'd1;
     81   else if(lsm_cnt >= 145)      //一帧数据发送完成,清零发送使能信号
     82      en_tx <= 1'd0;
     83 
     84 always@(posedge mii_tx_clk or negedge rst_n) //主序列机计数器
     85   if(!rst_n)
     86      lsm_cnt <= 8'd0;
     87   else if(en_tx) begin
     88     if(lsm_cnt == 8'd145)
     89        lsm_cnt <= 8'd0;
     90      else
     91        lsm_cnt <= lsm_cnt + 1'b1;
     92   end
     93   else
     94      lsm_cnt <= 8'd0;    
     95      
     96 /*
     97 always@(posedge mii_tx_clk or negedge rst_n) 
     98   if(!rst_n) begin
     99     mii_tx_data <= 4'd0;
    100   end
    101   else begin
    102 */
    103 always@(*) begin
    104     case(lsm_cnt)
    105        1: mii_tx_data <= 4'h5;  // 前导码 + 分隔符的一个5
    106         2: mii_tx_data <= 4'h5;
    107         3: mii_tx_data <= 4'h5;
    108         4: mii_tx_data <= 4'h5;
    109         5: mii_tx_data <= 4'h5;
    110         6: mii_tx_data <= 4'h5;
    111         7: mii_tx_data <= 4'h5;
    112         8: mii_tx_data <= 4'h5;
    113         9: mii_tx_data <= 4'h5;
    114         10:mii_tx_data <= 4'h5;
    115         11:mii_tx_data <= 4'h5;
    116         12:mii_tx_data <= 4'h5;
    117         13:mii_tx_data <= 4'h5;
    118         14:mii_tx_data <= 4'h5;
    119         15:mii_tx_data <= 4'h5;
    120             
    121         16: mii_tx_data <= 4'hd;  // 分隔符
    122         
    123         17: mii_tx_data <= des_mac[43:40];  // 目的MAC地址,先发高八位中的低四位 48'hff_ff_ff_ff_ff_ff
    124         18: mii_tx_data <= des_mac[47:44];
    125         19: mii_tx_data <= des_mac[35:32];
    126         20: mii_tx_data <= des_mac[39:36];
    127         21: mii_tx_data <= des_mac[27:24];
    128         22: mii_tx_data <= des_mac[31:28];
    129         23: mii_tx_data <= des_mac[19:16];
    130         24: mii_tx_data <= des_mac[23:20];
    131         25: mii_tx_data <= des_mac[11:8];
    132         26: mii_tx_data <= des_mac[15:12];
    133         27: mii_tx_data <= des_mac[3:0];
    134         28: mii_tx_data <= des_mac[7:4];    
    135     
    136                   
    137         29: mii_tx_data <= src_mac[43:40];// 0  //源MAC地址 48'h00_0a_35_01_fe_c0
    138         30: mii_tx_data <= src_mac[47:44];// 0
    139         31: mii_tx_data <= src_mac[35:32];// a
    140         32: mii_tx_data <= src_mac[39:36];// 0
    141         33: mii_tx_data <= src_mac[27:24];// 5
    142         34: mii_tx_data <= src_mac[31:28];// 3
    143         35: mii_tx_data <= src_mac[19:16];// 1
    144         36: mii_tx_data <= src_mac[23:20];// 0
    145         37: mii_tx_data <= src_mac[11:8]; // e
    146         38: mii_tx_data <= src_mac[15:12];// f
    147         39: mii_tx_data <= src_mac[3:0]; // 0
    148         40: mii_tx_data <= src_mac[7:4];    // c
    149         
    150                     
    151         41: mii_tx_data <= type_length[11:8];  //以太网帧类型/长度
    152         42: mii_tx_data <= type_length[15:12];
    153         43: mii_tx_data <= type_length[3:0];
    154         44: mii_tx_data <= type_length[7:4];
    155         
    156         45: mii_tx_data =    4'h0;
    157         46: mii_tx_data =    4'h0;
    158         47: mii_tx_data =    4'h1;
    159         48: mii_tx_data =    4'h0;
    160         
    161         //protocol type
    162         49: mii_tx_data =    4'h8;
    163         50: mii_tx_data =    4'h0;
    164         51: mii_tx_data =    4'h0;
    165         52: mii_tx_data =    4'h0;
    166         
    167         //hdwr size
    168         53: mii_tx_data =    4'h6;
    169         54: mii_tx_data =    4'h0;
    170         
    171         //protocol size
    172         55: mii_tx_data =    4'h4;
    173         56: mii_tx_data =    4'h0;
    174         
    175         //opcode
    176         57: mii_tx_data =    4'h0;
    177         58: mii_tx_data =    4'h0;
    178         59: mii_tx_data =    4'h1;
    179         60: mii_tx_data =    4'h0;
    180         
    181         //sender mac
    182         61: mii_tx_data =    4'h0;
    183         62: mii_tx_data =    4'h0;
    184         63: mii_tx_data =    4'ha;
    185         64: mii_tx_data =    4'h0;
    186         65: mii_tx_data =    4'h5;
    187         66: mii_tx_data =    4'h3;
    188         67: mii_tx_data =    4'h1;
    189         68: mii_tx_data =    4'h0;
    190         69: mii_tx_data =    4'he;
    191         70: mii_tx_data =    4'hf;
    192         71: mii_tx_data =    4'h0;
    193         72: mii_tx_data =    4'hc;
    194         
    195         //sender ip : 192.168.0.2
    196         73: mii_tx_data =    4'h0;//192
    197         74: mii_tx_data =    4'hc;
    198         
    199         75: mii_tx_data =    4'h8;//168
    200         76: mii_tx_data =    4'ha;
    201         
    202         77: mii_tx_data =    4'h0;//0
    203         78: mii_tx_data =    4'h0;
    204         
    205         79: mii_tx_data =    4'h2;
    206         80: mii_tx_data =    4'h0;//2
    207         
    208         //target mac
    209         81: mii_tx_data =    4'h4;  // 4  //48'b84 7b eb 48 94 13
    210         82: mii_tx_data =    4'hc;  // 8  //48'b34 23 87 99 f4 61
    211         83: mii_tx_data =    4'h4;  // b
    212         84: mii_tx_data =    4'h5;  // 7
    213         85: mii_tx_data =    4'h4;  // b
    214         86: mii_tx_data =    4'h4;  // e
    215         87: mii_tx_data =    4'h7;  // 8
    216         88: mii_tx_data =    4'h9;  // 4
    217         89: mii_tx_data =    4'h5;  // 4
    218         90: mii_tx_data =    4'hc;  // 9
    219         91: mii_tx_data =    4'h7;  // 3
    220         92: mii_tx_data =    4'hd;  // 1
    221         
    222         //target ip : 192.168.0.3
    223         93: mii_tx_data =    4'h0;//192
    224         94: mii_tx_data =    4'hc;
    225         
    226         95: mii_tx_data =    4'h8;//168
    227         96: mii_tx_data =    4'ha;
    228         
    229         97: mii_tx_data =    4'h0;//0
    230         98: mii_tx_data =    4'h0;
    231         
    232         99: mii_tx_data =    4'h3;//3
    233         100: mii_tx_data = 4'h0;
    234         
    235         //填充字段,以使整个数据帧长度达到64字节
    236         101: mii_tx_data = 4'h0;
    237         102: mii_tx_data = 4'h0;
    238         103: mii_tx_data = 4'h0;
    239         104: mii_tx_data = 4'h0;
    240         105: mii_tx_data = 4'hf;
    241         106: mii_tx_data = 4'hf;
    242         107: mii_tx_data = 4'hf;
    243         108: mii_tx_data = 4'hf;
    244         109: mii_tx_data = 4'hf;
    245         110: mii_tx_data = 4'hf;
    246         111: mii_tx_data = 4'hf;
    247         112: mii_tx_data = 4'hf;
    248         113: mii_tx_data = 4'hf;
    249         114: mii_tx_data = 4'hf;
    250         115: mii_tx_data = 4'hf;
    251         116: mii_tx_data = 4'hf;
    252         117: mii_tx_data = 4'h0;
    253         118: mii_tx_data = 4'h0;
    254         119: mii_tx_data = 4'h3;
    255         120: mii_tx_data = 4'h2;
    256         121: mii_tx_data = 4'hd;
    257         122: mii_tx_data = 4'hc;
    258         123: mii_tx_data = 4'h6;
    259         124: mii_tx_data = 4'h7;
    260         125: mii_tx_data = 4'h3;
    261         126: mii_tx_data = 4'h6;
    262         127: mii_tx_data = 4'ha;
    263         128: mii_tx_data = 4'h1;
    264         129: mii_tx_data = 4'h8;
    265         130: mii_tx_data = 4'h0;
    266         131: mii_tx_data = 4'h6;
    267         132: mii_tx_data = 4'h0;
    268         133: mii_tx_data = 4'h0;
    269         134: mii_tx_data = 4'h0;
    270         135: mii_tx_data = 4'h1;
    271         136: mii_tx_data = 4'h0;
    272         
    273         137: mii_tx_data <= CRC_Result[27:24];  //发送CRC 校验结果
    274         138: mii_tx_data <= CRC_Result[31:28];
    275         139: mii_tx_data <= CRC_Result[19:16];
    276         140: mii_tx_data <= CRC_Result[23:20];
    277         141: mii_tx_data <= CRC_Result[11:8];
    278         142: mii_tx_data <= CRC_Result[15:12];
    279         143: mii_tx_data <= CRC_Result[3:0];
    280         144: mii_tx_data <= CRC_Result[7:4];
    281 
    282         145: mii_tx_data <= 4'd0;
    283         default: mii_tx_data <= 4'd0;
    284      endcase
    285   end
    286   
    287 /*
    288 always@(posedge mii_tx_clk or negedge rst_n)  //MII数据发送使能信号
    289   if(!rst_n)
    290      mii_tx_en <= 1'b0;
    291   else if((lsm_cnt >= 1) && (lsm_cnt <= 144))  // lsm_cnt >= 1
    292      mii_tx_en <= 1'b1;
    293   else
    294      mii_tx_en <= 1'b0;
    295 */
    296 
    297 assign mii_tx_en = ((lsm_cnt >= 1) && (lsm_cnt <= 144)) ? 1'b1 : 1'b0;
    298 
    299 endmodule
    300     
    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);

       如有不当之处,还望各位道友指正~

     

  • 相关阅读:
    团队项目
    四则运算
    关于软件工程的问题
    自我介绍
    各种排序
    2017年03月14日 新模块投产日记
    第一发和技术无关的博客
    分享一款好用的PHP下ID混淆插件
    批量抓取cisco设备配置脚本编写(expect/sed/awk/shell)
    ntp/heartbeat/postfix/dns故障处理记录
  • 原文地址:https://www.cnblogs.com/571328401-/p/12655923.html
Copyright © 2011-2022 走看看