首页 > 其他分享 >基于FPGA的以太网设计(四)

基于FPGA的以太网设计(四)

时间:2024-10-17 17:22:48浏览次数:9  
标签:ARP 基于 FPGA 主机 地址 reg 发送 MAC 以太网

1.ARP协议简介

ARP(Address Resolution Protocol),即地址解析协议,是根据IP地址(逻辑地址)获取MAC地址的一种TCP/IP协议。在以太网通信中,数据是以“帧”的格式进行传输的,帧格式里面包含目的主机的MAC地址。

源主机的应用程序知道目的主机的IP地址,却不知道目的主机的MAC地址。而目的主机的MAC地址直接被网卡接收和解析,当解析到目的MAC地址非本地MAC地址时,则直接丢弃该包数据,因此在通信前需要先获得目的MAC地址,而ARP协议正是实现了此功能。

ARP协议的基本功能是通过目的主机IP地址,获取目的主机的MAC地址,以保证通信的顺利进行。MAC地址在网络中表示网卡的ID,每个网卡都需要并有且仅有一个MAC地址。在获取到目的MAC地址之后,将目的MAC地址更新至ARP缓存表中,称为ARP映射。下次通信时,可以直接从ARP缓存表中获取,而不用重新通过ARP获取MAC地址。但一般ARP缓存表会有过期时间,过期后需要重新通过ARP协议进行获取。

ARP映射是指将IP地址和MAC地址映射起来,分为静态映射和动态映射。

ARP工作流程如下:

假设主机A和B在同一个网段,主机A要向主机B发送信息,具体的地址解析过程如下:

(1) 主机A首先查看自己的ARP,确定其中是否包含有主机B对应的ARP表项。如果找到了对应的MAC地址,则主机A直接利用ARP表中的MAC地址,对IP数据包进行帧封装,并将数据包发送给主机B。

(2) 如果主机A在ARP表中找不到对应的MAC地址,则将缓存该数据报文,然后以广播方式发送一个ARP请求报文。

ARP请求报文中的发送端IP地址和发送端MAC地址主机A的IP地址和MAC地址目标IP地址和目标MAC地址主机B的IP地址和全0的MAC地址

由于ARP请求报文以广播方式发送,该网段上的所有主机都可以接收到该请求,但只有被请求的主机(即主机B)会对该请求进行处理。

(3) 主机B比较自己IP地址和ARP请求报文中的 目标IP 地址,当两者相同时进行如下处理:ARP请求报文中的发送端(即主机A)的IP地址和MAC地址存入自己的ARP表中

之后以单播方式发送ARP响应报文给主机A,其中包含了自己的MAC地址。

(4) 主机A收到ARP响应报文后,将主机B的MAC地址加入到自己的ARP表中以用于后续报文的转发,同时将IP数据包进行封装后发送出去。

  1. 2.ARP协议实现

2.1接收部分:

接收部分采用一个状态机来实现,其状态转换图如下所示:

开始状态机处于IDLE状态,当检测到第一个8’h55的时候进入PREAMBLE状态,即接收前导码和SFD,与此同时我们对接收数据进行计数,当计数器计数到6时检测此时接收的数据是不是8’hd5,如果是进入接收帧头状态;否则,进入接收终止状态。接收帧头状态的跳转也和PREAEBLE状态的跳转情况差不多,只不过此时需要检测接受到的以太网类型,而以太网类型是两字节,因此需要先接收高位,再进行对比。ARP_DATA状态的跳转则需要检测接受到的目的ip地址与开发板的ip地址是否相同并且还要检测操作码是否有效。当接收完单包数据后下一个时钟周期跳转到IDLE状态。

整体的实现还是比较简单的,利用一个状态机就能完成,但是需要对以太网帧格式比较熟悉。具体实现代码如下:

`timescale 1ns / 1ps

module ARP_RX#(
    parameter   BOARD_MAC   =   48'h00_11_22_33_44_55       ,   //开发板MAC地址
    parameter   BOARD_IP    =   {8'd192,8'd168,8'd1,8'd10}      //开发板IP地址
)(
    //system
    input                       clk                         ,   //系统时钟
    input                       rst_n                       ,   //系统复位
    //input
    input                       gmii_rx_dv                  ,   //接收数据有效信号
    input           [7:0]       gmii_rxd                    ,   //接收数据
    //output
    output      reg             arp_rx_done                 ,   //ARP接收完成信号
    output      reg             arp_rx_type                 ,   //ARP接收类型0:请求 1:应答
    output      reg [47:0]      src_mac                     ,   //输出接收到的源MAC地址
    output      reg [31:0]      src_ip                          //输出接收到的源IP地址            
);
    parameter   IDLE      =     5'b0_0001                   ;   //空闲状态
    parameter   PREAMBLE  =     5'b0_0010                   ;   //接收前导码和SFD
    parameter   ETH_HEAD  =     5'b0_0100                   ;   //帧头
    parameter   ARP_DATA  =     5'b0_1000                   ;   //接收ARP数据
    parameter   RX_DONE   =     5'b1_0000                   ;   //接收CRC校验数据
    parameter   ETH_TPYE  =     16'h0806                    ;   //以太网帧类型

    reg                         state_en                    ;   //状态跳转使能信号
    reg             [4:0]       cur_state                   ;   //现态
    reg             [4:0]       next_state                  ;   //次态
    reg                         error_flag                  ;   //错误指示信号
    reg             [47:0]      des_mac_t                   ;   //目的MAC地址
    reg             [31:0]      des_ip_t                    ;   //目的ip地址
    reg             [47:0]      src_mac_t                   ;   //源MAC地址
    reg             [31:0]      src_ip_t                    ;   //源ip地址
    reg             [4:0]       cnt                         ;   //解析数据计数器
    reg             [15:0]      eth_type                    ;   //以太网类型
    reg             [15:0]      op_data                     ;   //操作码

    //三段式状态机第一段
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)
            cur_state <= IDLE;
        else 
            cur_state <= next_state;
    end

    //三段式状态机第二段
    always @(*) begin
        next_state = IDLE;
        casex (cur_state)
            IDLE:begin
                if(state_en)
                    next_state = PREAMBLE;
                else if(error_flag)
                    next_state = RX_DONE;
                else
                    next_state = IDLE;
            end 
            PREAMBLE:begin
                if(state_en)
                    next_state = ETH_HEAD;
                else if(error_flag)
                    next_state = RX_DONE;
                else
                    next_state = PREAMBLE;
            end
            ETH_HEAD:begin
                if(state_en)
                    next_state = ARP_DATA;
                else if(error_flag)
                    next_state = RX_DONE;
                else
                    next_state = ETH_HEAD; 
            end
            ARP_DATA:begin
                if(state_en)
                    next_state = RX_DONE;
                else if(error_flag)
                    next_state = RX_DONE;
                else
                    next_state = ARP_DATA;
            end
            RX_DONE:begin
                if(state_en)
                    next_state = IDLE;
                else
                    next_state = RX_DONE;
            end
            default: next_state = IDLE;
        endcase
    end

    //三段式状态机第三段
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            state_en <= 1'b0;
            cnt <= 6'd0;
            error_flag <= 1'b0;
            des_mac_t <= 48'd0;
            des_ip_t <= 32'd0;
            src_mac_t <= 48'd0;
            src_ip_t <= 32'd0;        
            eth_type <= 16'd0;
            op_data <= 16'd0;
            arp_rx_done <= 1'b0;
            arp_rx_type <= 1'b0;
            src_mac <= 48'd0;
            src_ip <= 32'd0;
        end
        else begin
            state_en <= 1'b0;
            arp_rx_done <= 1'b0;
            error_flag <= 1'b0;
            case (next_state)
                IDLE:begin//接收到第一个8'h55
                    if((gmii_rx_dv == 1'b1) && (gmii_rxd == 8'h55))
                        state_en <= 1'b1;
                    else;
                end 
                PREAMBLE:begin
                    if(gmii_rx_dv)begin
                        cnt <= cnt + 1'b1;
                        if((cnt < 5'd6) && (gmii_rxd !=8'h55))
                            error_flag <= 1'b1;
                        else if(cnt == 5'd6)begin
                            cnt <= 5'd0;
                            if(gmii_rxd == 8'hd5)
                                state_en <= 1'b1;
                            else
                                error_flag <= 1'b1; 
                        end
                    end
                    else;
                end
                ETH_HEAD:begin
                    if(gmii_rx_dv)begin
                        cnt <= cnt + 1'b1;
                        if(cnt < 5'd6)
                            des_mac_t <= {des_mac_t[39:0],gmii_rxd};//接收源MAC地址
                        else if(cnt == 5'd6)begin
                            if((des_mac_t != BOARD_MAC) && (des_mac_t != 48'hff_ff_ff_ff_ff_ff))
                                error_flag <= 1'b1;
                            else;
                        end
                        else if(cnt == 5'd12)
                            eth_type[15:8] <= gmii_rxd;
                        else if(cnt == 5'd13)begin
                            cnt <= 5'd0;
                            eth_type[7:0] <= gmii_rxd;
                            if(eth_type[15:8] == ETH_TPYE[15:8] && gmii_rxd == ETH_TPYE[7:0])
                                state_en <= 1'b1;
                            else
                                error_flag <= 1'b1;
                        end                            
                        else;
                    end
                    else;
                end
                ARP_DATA:begin
                    if(gmii_rx_dv)begin
                        cnt <= cnt + 1'b1;
                        if(cnt == 5'd6)
                            op_data[15:8] <= gmii_rxd;
                        else if(cnt == 5'd7)
                            op_data[7:0] <= gmii_rxd;//操作码
                        else if(cnt >= 5'd8 && cnt < 5'd14)
                            src_mac_t <= {src_mac_t[39:0],gmii_rxd};//源MAC地址
                        else if(cnt >= 5'd14 && cnt < 5'd18)
                            src_ip_t <= {src_ip_t[23:0],gmii_rxd};//源ip地址
                        else if(cnt >= 5'd24 && cnt < 5'd28)
                            des_ip_t <= {des_ip_t[23:0],gmii_rxd};//目的ip地址
                        else if(cnt == 5'd28)begin
                            cnt <= 5'd0; 
                            if(des_ip_t == BOARD_IP)begin//判断目的ip地址和操作码
                                if((op_data == 16'd1) || (op_data == 16'd2))begin
                                    state_en <= 1'b1;
                                    arp_rx_done <= 1'b1;
                                    src_ip <= src_ip_t;
                                    src_mac <= src_mac_t;
                                    src_mac_t <= 48'd0;
                                    src_ip_t <= 32'd0;
                                    des_ip_t <= 32'd0;
                                    des_mac_t <= 48'd0;
                                    if(op_data == 16'd1)
                                        arp_rx_type <= 1'b0;//ARP请求
                                    else 
                                        arp_rx_type <= 1'b1;//ARP应答
                                end
                                else 
                                    error_flag <= 1'b1; 
                            end                       
                            else 
                                error_flag <= 1'b1;
                        end
                    end
                end
                RX_DONE:begin
                    cnt <= 5'd0;
                    //单包数据接收完成
                    if(gmii_rx_dv && state_en)
                        state_en <= 1'b1;
                    else;
                end
                default: ;
            endcase
        end
    end
endmodule

2.2发送部分:

发送部分也可以采用一个状态机来完成,状态转换图如下所示:

发送部分的状态转换比接收部分的状态转换还简单一些,我们需要定义一个计数器,每个时钟的上升沿发送一字节数据并且计数器加1,即可很容易的控制状态机的状态转换,需要注意的是,进入ARP_DATA状态之后,我们将cnt计数器的值清零,并引入一个新的计数器用来计数前28字节数据。之所以这样是因为ARP_DATA状态我们总共需要发送46字节数据,而这里面的前28字节数据为ARP数据段,后18字节为填充段,为了将二者分开因此再定义一个计数器对ARP数据段进行计数。

发送部分的具体实现代码如下所示:

`timescale 1ns / 1ps

module ARP_TX(
    //system
    input                           clk                         ,   //系统时钟
    input                           rst_n                       ,   //系统复位
    //input             
    input                           arp_tx_en                   ,   //ARP发送使能信号
    input                           arp_tx_type                 ,   //ARP发送类型0:请求 1:应答
    input               [31:0]      des_ip                      ,   //目的ip地址
    input               [47:0]      des_mac                     ,   //目的MAC地址
    input               [31:0]      crc_data                    ,   //CRC校验数据
    input               [7:0]       crc_next                    ,   //CRC下次校验数据
    //output                
    output          reg             tx_done                     ,   //发送完成信号
    output          reg             gmii_tx_en                  ,   //GMII发送使能信号
    output          reg[7:0]        gmii_txd                    ,   //GMII发送数据
    output          reg             crc_en                      ,   //CRC校验使能信号
    output          reg             crc_clr                         //CRC清零系信号                                   
);
    parameter   DES_IP        =     {8'd192,8'd168,8'd1,8'd102} ;   //目的ip地址即PC端ip地址
    parameter   DES_MAC       =     48'hff_ff_ff_ff_ff_ff       ;   //目的MAC地址
    parameter   BOARD_IP      =     {8'd192,8'd168,8'd1,8'd10}  ;   //开发板ip地址
    parameter   BOARD_MAC     =     48'h00_11_22_33_44_55       ;   //开发板MAC地址,用户可自行设置
    parameter   ETH_TPYE      =     16'h0806                    ;   //以太网帧类型 ARP
    parameter   HD_TYPE       =     16'h0001                    ;   //硬件协议类型
    parameter   PROTOCOL_TYPE =     16'h0800                    ;   //上层协议类型为ip协议

    localparam  IDLE          =     5'b0_0001                   ;   //空闲状态
    localparam  PREAMBLE      =     5'b0_0010                   ;   //发送前导码+SFD
    localparam  ETH_HEAD      =     5'b0_0100                   ;   //发送帧头
    localparam  ARP_DATA      =     5'b0_1000                   ;   //发送ARP数据
    localparam  CRC           =     5'b1_0000                   ;   //发送CRC校验数据
    localparam  MIN_DATA_NUM  =     6'd46                       ;   //最小计数值,不满则填充数据

    //reg type
    reg                             arp_tx_en_r0                ;   //对ARP发送使能信号打拍以检测上升沿
    reg                             arp_tx_en_r1                ;   
    reg                             arp_tx_en_r2                ;   
    reg                 [4:0]       cur_state                   ;   //现态
    reg                 [4:0]       next_state                  ;   //次态
    reg                             state_en                    ;   //状态转移使能信号
    reg                 [5:0]       cnt                         ;
    reg                 [4:0]       data_cnt                    ;   //发送数据计数器
    reg                             tx_done_t                   ;   //发送完成信号暂存
    reg                 [7:0]       preamble    [7:0]           ;   //前导码+SFD
    reg                 [7:0]       eth_head    [13:0]          ;   //帧头
    reg                 [7:0]       arp_data    [27:0]          ;   //ARP数据

    //wire type
    wire                            posedge_arp_tx_en             ;   //ARP发送使能信号上升沿

    assign posedge_arp_tx_en =  ~arp_tx_en_r2 && arp_tx_en_r1   ;

    //对使能信号打拍以检测上升沿
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            arp_tx_en_r0 <= 1'b0;
            arp_tx_en_r1 <= 1'b0;
            arp_tx_en_r2 <= 1'b0;
        end
        else begin
            arp_tx_en_r0 <= arp_tx_en;
            arp_tx_en_r1 <= arp_tx_en_r0;
            arp_tx_en_r2 <= arp_tx_en_r1;
        end
    end

    //三段式状态机第一段,状态转移
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)
            cur_state <= IDLE;
        else
            cur_state <= next_state;
    end

    //三段式状态机第二段
    always @(*) begin
        next_state = IDLE;
        case (cur_state)
            IDLE:begin
                if(state_en)
                    next_state = PREAMBLE;
                else
                    next_state = IDLE;
            end 
            PREAMBLE:begin
                if(state_en)
                    next_state = ETH_HEAD;
                else
                    next_state = PREAMBLE; 
            end
            ETH_HEAD:begin
                if(state_en)
                    next_state = ARP_DATA;
                else
                    next_state = ETH_HEAD; 
            end
            ARP_DATA:begin
                if(state_en)
                    next_state = CRC;
                else
                    next_state = ARP_DATA; 
            end
            CRC:begin
                if(state_en)
                    next_state = IDLE;
                else
                    next_state = CRC; 
            end
            default:next_state = IDLE;
        endcase
    end

    //三段式状态机第三段,判读数据输出结果
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            tx_done_t <= 1'b0;
            state_en <= 1'b0;
            cnt <= 6'd0;
            gmii_tx_en <= 1'b0;
            gmii_txd <= 7'd0;
            data_cnt <= 5'd0;
            crc_en <= 1'b0;
            //前导码
            preamble[0] <= 8'h55;
            preamble[1] <= 8'h55;
            preamble[2] <= 8'h55;
            preamble[3] <= 8'h55;
            preamble[4] <= 8'h55;
            preamble[5] <= 8'h55;
            preamble[6] <= 8'h55;
            //SFD
            preamble[7] <= 8'hd5;
            //帧头
            eth_head[0] <= DES_MAC[47:40];//目的MAC地址
            eth_head[1] <= DES_MAC[39:32];
            eth_head[2] <= DES_MAC[31:24];
            eth_head[3] <= DES_MAC[23:16];
            eth_head[4] <= DES_MAC[15:8];
            eth_head[5] <= DES_MAC[7:0];
            eth_head[6] <= BOARD_MAC[47:40];//开发板MAC地址
            eth_head[7] <= BOARD_MAC[39:32];
            eth_head[8] <= BOARD_MAC[31:24];
            eth_head[9] <= BOARD_MAC[23:16];
            eth_head[10] <= BOARD_MAC[15:8];
            eth_head[11] <= BOARD_MAC[7:0];
            eth_head[12] <= ETH_TPYE[15:8];//以太网帧类型
            eth_head[13] <= ETH_TPYE[7:0];
            //ARP数据
            arp_data[0] <= HD_TYPE[15:8];//硬件类型
            arp_data[1] <= HD_TYPE[7:0];
            arp_data[2] <= PROTOCOL_TYPE[15:8];//上层协议类型
            arp_data[3] <= PROTOCOL_TYPE[7:0];
            arp_data[4] <= 8'h06;//硬件地址长度
            arp_data[5] <= 8'h04;//协议地址长度
            arp_data[6] <= 8'h00;//
            arp_data[7] <= 8'h01;//OP操作码 01:request 02:ack
            arp_data[8] <= BOARD_MAC[47:40];    //发送端(源)MAC地址
            arp_data[9] <= BOARD_MAC[39:32];
            arp_data[10] <= BOARD_MAC[31:24];
            arp_data[11] <= BOARD_MAC[23:16];
            arp_data[12] <= BOARD_MAC[15:8];
            arp_data[13] <= BOARD_MAC[7:0];
            arp_data[14] <= BOARD_IP[31:24];    //发送端(源)IP地址
            arp_data[15] <= BOARD_IP[23:16];
            arp_data[16] <= BOARD_IP[15:8];
            arp_data[17] <= BOARD_IP[7:0];
            arp_data[18] <= DES_MAC[47:40];     //接收端(目的)MAC地址
            arp_data[19] <= DES_MAC[39:32];
            arp_data[20] <= DES_MAC[31:24];
            arp_data[21] <= DES_MAC[23:16];
            arp_data[22] <= DES_MAC[15:8];
            arp_data[23] <= DES_MAC[7:0];  
            arp_data[24] <= DES_IP[31:24];      //接收端(目的)IP地址
            arp_data[25] <= DES_IP[23:16];
            arp_data[26] <= DES_IP[15:8];
            arp_data[27] <= DES_IP[7:0];
        end
        else begin
            state_en <= 1'b0;
            crc_en <= 1'b0;
            tx_done_t <= 1'b0;
            gmii_tx_en <= 1'b0;
            case (next_state)
                IDLE:begin
                    if(posedge_arp_tx_en)begin
                        state_en <= 1'b1;
                        if((des_ip != 32'd0) || (des_mac != 48'd0))begin
                        eth_head[0] <= des_mac[47:40];
                        eth_head[1] <= des_mac[39:32];
                        eth_head[2] <= des_mac[31:24];
                        eth_head[3] <= des_mac[23:16];
                        eth_head[4] <= des_mac[15:8];
                        eth_head[5] <= des_mac[7:0];                            
                        arp_data[18] <= des_mac[47:40];
                        arp_data[19] <= des_mac[39:32];
                        arp_data[20] <= des_mac[31:24];
                        arp_data[21] <= des_mac[23:16];
                        arp_data[22] <= des_mac[15:8];
                        arp_data[23] <= des_mac[7:0];  
                        arp_data[24] <= des_ip[31:24]; 
                        arp_data[25] <= des_ip[23:16];
                        arp_data[26] <= des_ip[15:8];
                        arp_data[27] <= des_ip[7:0];
                       end 
                       else;
                       if(arp_tx_type == 1'b0)
                            arp_data[7] <= 8'h01;
                        else
                            arp_data[7] <= 8'h02;
                    end
                else;
                end
                PREAMBLE:begin//进入PREAMBLE状态之后拉高gmii_tx_en信号表示开始发送数据,并且每次时钟周期发送8位数据总共发送7个8'h55和一个8'hd5
                    gmii_tx_en <= 1'b1;
                    gmii_txd <= preamble[cnt];
                    if(cnt == 6'd7)begin
                        state_en <= 1'b1;
                        cnt <= 6'd0;
                    end
                    else
                        cnt <= cnt + 1'b1;
                end
                ETH_HEAD:begin//发送帧头                    
                    gmii_tx_en <= 1'b1;
                    crc_en <= 1'b1;
                    gmii_txd <= eth_head[cnt];  
                    if(cnt == 6'd13)begin
                        state_en <= 1'b1;
                        cnt <= 6'd0;
                    end             
                    else
                        cnt <= cnt + 1'b1; 
                    end
                ARP_DATA:begin
                    gmii_tx_en <= 1'b1;
                    crc_en <= 1'b1;
                    if(cnt == MIN_DATA_NUM - 1'b1)begin
                        state_en <= 1'b1;
                        cnt <= 6'd0;
                        data_cnt <= 5'd0;
                    end
                    else
                        cnt <= cnt + 1'b1;
                    if(data_cnt <= 5'd27)begin
                        data_cnt <= data_cnt + 1'b1;
                        gmii_txd <= arp_data[data_cnt];
                    end
                    else
                        gmii_txd <= 8'd0;//填充
                end
                CRC:begin//发送CRC校验值
                    gmii_tx_en <= 1'b1;
                    cnt <= cnt + 1'b1;
                                    if(cnt == 6'd0)
                    gmii_txd <= {~crc_next[0], ~crc_next[1], ~crc_next[2],~crc_next[3],
                                 ~crc_next[4], ~crc_next[5], ~crc_next[6],~crc_next[7]};
                else if(cnt == 6'd1)
                    gmii_txd <= {~crc_data[16], ~crc_data[17], ~crc_data[18],
                                 ~crc_data[19], ~crc_data[20], ~crc_data[21], 
                                 ~crc_data[22],~crc_data[23]};
                else if(cnt == 6'd2) begin
                    gmii_txd <= {~crc_data[8], ~crc_data[9], ~crc_data[10],
                                 ~crc_data[11],~crc_data[12], ~crc_data[13], 
                                 ~crc_data[14],~crc_data[15]};                              
                end
                else if(cnt == 6'd3) begin
                    gmii_txd <= {~crc_data[0], ~crc_data[1], ~crc_data[2],~crc_data[3],
                                 ~crc_data[4], ~crc_data[5], ~crc_data[6],~crc_data[7]};  
                    tx_done_t <= 1'b1;
                    state_en <= 1'b1;
                    cnt <= 1'b0;
                end   
				else;
                end
                default:;
            endcase
        end
    end

    //发送ARP发送完成信号和CRC复位信号
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            tx_done <= 1'b0;
            crc_clr <= 1'b0;
        end
        else begin
            tx_done <= tx_done_t;
            crc_clr <= tx_done_t;
        end
    end

endmodule

仿真结果如下所示:

发送部分

发送使能信号拉高,并且在打拍之后检测到时钟上升沿,代表一次发送开始。

发送数据与发送数据计数。

单包数据发生完成。

接收部分

检测到第一个8’h55,状态机的状态进行跳转。

接收数据与接收数据计数。

接收到的MAC地址和ip地址。

上板测试:

按下按键后,利用wireshark抓取数据包结果如下图所示:

开发板发送请求信号,PC端进行应答。

开发板MAC地址与ip地址。

代码参考正点原子。

ARP协议详解 ------- 一看就懂-CSDN博客

标签:ARP,基于,FPGA,主机,地址,reg,发送,MAC,以太网
From: https://blog.csdn.net/qq_69315815/article/details/142993370

相关文章

  • 基于Springboot技术的高校实验室教学管理系统的设计与实现---附源码 53564
    目 录摘要1绪论1.1研究背景与意义1.2国内外研究现状1.3论文结构与章节安排2 计算机实验室管理平台系统分析2.1可行性分析2.1.1技术可行性分析2.1.2 经济可行性分析2.1.3社会可行性分析2.2系统功能分析2.2.1功能性分析2.2.2非功能性分......
  • 基于SpringBoot及Vue的银行卡业务系统的设计与实现---附源码53473
    目 录摘 要1绪论1.1研究背景1.2研究意义1.3论文结构与章节安排2 银行卡业务系统系统分析2.1可行性分析2.2系统流程分析2.2.1数据增加流程2.2.2数据修改流程2.2.3数据删除流程2.3 系统功能分析2.3.1功能性分析2.3.2非功能性分析......
  • [1426]基于JAVA的微信公众号运营智慧管理系统的设计与实现
    毕业设计(论文)开题报告表姓名学院专业班级题目基于JAVA的微信公众号运营智慧管理系统的设计与实现指导老师(一)选题的背景和意义选题背景与意义:在当前信息化、数字化的社会环境下,微信公众号已经成为企事业单位、商家和个体进行品牌推广、客户服务、产品营销以及用户管理......
  • [1437]基于JAVA的志愿者服务智慧管理系统的设计与实现
    毕业设计(论文)开题报告表姓名学院专业班级题目基于JAVA的志愿者服务智慧管理系统的设计与实现指导老师(一)选题的背景和意义选题背景与意义:随着我国社会文明程度的不断提升,志愿服务已成为社会进步、社区建设与发展的重要力量。志愿者服务智慧管理系统作为一种信息化工具,......
  • 基于ssm+vue.js的二手车交易网站附带文章源码部署视频讲解等
    文章目录前言详细视频演示具体实现截图核心技术介绍后端框架SSM前端框架Vue持久层框架MyBaits为什么选择我代码参考数据库参考测试用例参考源码获取前言......
  • 基于BP神经网络的CoSaMP信道估计算法matlab性能仿真,对比LS,OMP,MOMP,CoSaMP
    1.算法仿真效果matlab2022a仿真结果如下(完整代码运行后无水印):   仿真操作步骤可参考程序配套的操作视频。 2.算法涉及理论知识概要        LS估计法实现方式较为简单,其估计过程没有考虑实际信道的噪声因素。因此,特别当毫米波MIMO信道干扰较大时,其估计性能较......
  • 【开题报告】基于django+vue基于智能点击推荐的在线购物商城系统(论文+源码)计算机毕
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着互联网技术的飞速发展,电子商务已成为现代商业活动的重要组成部分。在线购物商城作为电子商务的核心平台,不仅为消费者提供了便捷、高效......
  • 【开题报告】基于django+vue社团管理系统(论文+源码)计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景在当今高校生活中,社团活动作为丰富学生课余生活、培养学生兴趣爱好的重要平台,其管理效率与透明度直接影响到学生的参与热情与社团的健康发......
  • 基于Kronig-Penney能带模型的MATLAB求解与仿真
    1.程序功能描述基于Kronig-Penney能带模型的MATLAB求解与仿真.综合利用MATLAB提供的求解常微分方程、矩阵行列式、代数表达式化简及绘图等函数,可使Kronig-Penney能带模型分析计算的工作量大为减少。2.测试软件版本以及运行结果展示MATLAB2013b版本运行  3......
  • 基于PID控制器的四旋翼无人机控制系统的simulink建模与仿真,并输出虚拟现实动画
    1.课题概述      基于PID控制器的四旋翼无人机控制系统的simulink建模与仿真,并输出vr虚拟现实动画,输出PID控制器的控制反馈曲线。整个仿真过程,无人机为升空,下降,再升空的飞行效果。 2.系统仿真结果 3.核心程序与模型版本:MATLAB2022a  4.系统原理简介4.1......