【米联客-安路飞龙DR1-FPSOC】 UDP通信篇连载-03 IP_ARP层程序设计

软件版本:Anlogic -TD5.9.1-DR1_ES1.1

操作系统:WIN10 64bit

硬件平台:适用安路(Anlogic)FPGA

实验平台:米联客-MLK-L1-CZ06-DR1M90G开发板

板卡获取平台:https://milianke.tmall.com/

登录"米联客"FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!

3.2 IP_ARP层
由于IP和ARP数据包送至MAC层要经过同一个通道,需要对发送的数据包类型进行判断和仲裁,这就需要额外增加一个IP_ARP层。

/*******************************uiip_arp_rx模块*********************
--以下是米联客设计的uiip_arp_rx模块
1.该模块1用于区分接收数据是IP包还是ARP包
*********************************************************************/
`timescale 1ns/1ps
module  uiip_arp_rx
(
    input   wire                I_ip_arp_reset,     //复位
    input   wire                I_ip_arp_rclk,      //RX 接收时钟
    output  wire                O_ip_rvalid,        //接收的有效IP信号
    output  wire    [7:0]       O_ip_rdata,         //接收的IP数据
    output  wire                O_arp_rvalid,       //接收的有效ARP信号
    output  wire    [7:0]       O_arp_rdata,        //接收的有效ARP数据

    input   wire                I_mac_rvalid,       //MAC接收到的数据有效信号
    input   wire    [7:0]       I_mac_rdata,        //MAC接收的有效数据
    input   wire    [15:0]      I_mac_rdata_type    //MAC接收到的帧类型

);
reg                 ip_rx_data_valid;   //接收的有效IP信号
reg     [7:0]       ip_rx_data;         //接收的IP数据
reg                 arp_rx_data_valid;  //接收的有效ARP信号
reg     [7:0]       arp_rx_data;        //接收的有效ARP数据

assign  O_ip_rvalid     =   ip_rx_data_valid;
assign  O_ip_rdata      =   ip_rx_data;
assign  O_arp_rvalid    =   arp_rx_data_valid;
assign  O_arp_rdata     =   arp_rx_data;

localparam  ARP_TYPE    =   16'h0806;   //ARP包类型
localparam  IP_TYPE     =   16'h0800;   //IP 包类型
always@(posedge I_ip_arp_rclk or posedge I_ip_arp_reset) begin
    if(I_ip_arp_reset) begin
        ip_rx_data_valid    <=  1'b0;
        ip_rx_data          <=  8'd0;
        arp_rx_data_valid   <=  1'b0;
        arp_rx_data         <=  8'd0;
    end
    else if(I_mac_rvalid) begin
        if(I_mac_rdata_type == IP_TYPE) begin//IP包
            ip_rx_data_valid    <=  1'b1;
            ip_rx_data          <=  I_mac_rdata;
        end
        else if(I_mac_rdata_type == ARP_TYPE) begin//ARP包
            arp_rx_data_valid   <=  1'b1;
            arp_rx_data         <=  I_mac_rdata;
        end
        else begin
            ip_rx_data_valid    <=  1'b0;
            ip_rx_data          <=  8'd0;
            arp_rx_data_valid   <=  1'b0;
            arp_rx_data         <=  8'd0;
        end
    end
    else begin
        ip_rx_data_valid    <=  1'b0;
        ip_rx_data          <=  8'd0;
        arp_rx_data_valid   <=  1'b0;
        arp_rx_data         <=  8'd0;
    end
end

endmodul

3.2.1 IP_ARP接收模块
该模块接收到MAC帧经过MAC层解包得到的数据包,通过类型字段判断该包是IP包还是ARP包,将其送入对应的模块中处理。

3.2.2 IP_ARP发送模块
该模块接收IP层和ARP层传来的发送请求,通过busy信号与上层协议模块进行握手,来发送对应的数据。该模块的状态机转换图如图所示。


IDLE:如果是IP层发送的请求,且arp_req_pend信号没有挂起时,进入CHECK_MAC_CACHEE状态,进入ARP层查询mac_cache中缓存的MAC地址。如果是ARP层发送的请求,在MAC层非忙时,将arp_tbusy拉高,表示可以发送ARP包,进入WAIT_ARP_PACKET状态。

CHECK_MAC_CACHE:若没有查询到IP地址对应的MAC地址,则使能O_arp_treq_en信号,请求ARP层发送ARP广播包,并且将arp_req_pend挂起(该信号挂起时不能发送IP包),回到IDLE状态,等待ARP层发送请求信号。若查询到MAC地址,进入WAIT_IP_PACKET状态,等待IP层将有效数据发送过来。

WAIT_IP_PACKET:若I_ip_valid拉高,说明IP包有效数据开始传入,接收传来的数据并将其发送至MAC层,进入SEND_IP_PACKET状态。

SEND_IP_PACKET:等待一帧IP包数据全部发送完成时,回到IDLE状态。

WAIT_ARP_PACKET:I_arp_valid拉高,说明ARP包有效数据开始传入,接收传来的数据并将其发送至MAC层,进入SEND_ARP_PACKET状态。

SEND_ARP_PACKET:如果发送的数据包是ARP应答包,数据全部发送完成时,回到IDLE状态。如果发送的数据包是ARP请求包,则要进入SEND_ARP_REPLY状态,等待接收到对方发送ARP应答包。

SEND_ARP_REPLY:接收到ARP应答包后,将arp_req_pend信号拉低,回到IDLE状态。若超时未收到应答,则回到IDLE状态,此时由于arp_req_pend信号一直为高,该模块会持续发送ARP请求直至收到应答。

always@(posedge I_ip_arp_clk or posedge I_ip_arp_reset)begin
    if(I_ip_arp_reset) begin
        O_mac_cache_ren         <=  1'b0;   //查询MAC cache
        O_mac_cache_rip_addr    <=  32'd0;  //查询MAC cache地址
        O_arp_tbusy             <=  1'b0;   //ip_arp_tx arp 发送准备好
        O_arp_treq_en           <=  1'b0;   //ip_arp_tx arp请求发送ARP包(当发送IP包,没有找打cache中的MAC的时候发送)
        O_arp_treq_ip_addr      <=  32'd0;  //ARP可以发送模块通过发送带有目的IP地址的ARP请求,获取目的远程主机的MAC地址

        O_ip_tbusy              <=  1'b0;   //ip_arp_tx可以发送IP包

        O_mac_tdata_type        <=  2'd0;   //MAC发送数据类型
        O_mac_tvalid            <=  1'b0;   //MAC发送数据有效
        O_mac_tdata             <=  8'd0;   //MAC发送数据
        O_mac_tdest_addr        <=  48'd0;  //MAC发送地址

        tmac_addr_temp          <=  48'd0;
        arp_req_pend            <=  1'b0;
        dst_ip_unreachable      <=  1'b0;
        arp_wait_time           <=  30'd0;
        STATE                   <=  IDLE;
    end
    else begin
        case(STATE)
            IDLE:begin
                O_arp_treq_en   <=  1'b0;
                if(!I_mac_tbusy) begin//MAC层不忙
                    if(I_arp_treq) begin//是否有ARP请求
                        O_arp_tbusy             <=  1'b1;           //可以发送ARP包
                        O_ip_tbusy              <=  1'b0;
                        STATE                   <=  WAIT_ARP_PACKET;//等待ARP响应
                    end
                    else if(I_ip_treq && ~arp_req_pend) begin   //如果是IP请求,并且之前的ARP请求没有pend
                        O_arp_tbusy             <=  1'b0;
                        O_ip_tbusy              <=  1'b0;
                        O_mac_cache_ren         <=  1'b1;               //如果是IP请求,先从mac cache通过IP地址获取MAC地址
                        O_mac_cache_rip_addr    <=  I_ip_tdest_addr;    //通过IP地址查询MAC cache
                        STATE                   <=  CHECK_MAC_CACHE;
                    end
                    else begin
                        O_arp_tbusy             <= 1'b0;
                        O_ip_tbusy              <= 1'b0;
                        STATE                   <= IDLE;
                    end
                end
                else begin
                    O_arp_tbusy             <= 1'b0;
                    O_ip_tbusy              <= 1'b0;
                    O_mac_cache_ren         <= 1'b0;
                    O_mac_cache_rip_addr    <= 48'd0;
                    STATE                   <= IDLE;
                end
            end
            CHECK_MAC_CACHE:begin//查询MAC cache,如果没有查到MAC会请求ARP层发送ARP请求
                O_mac_cache_ren         <=  1'b0;
                if(I_mac_cache_rdone) begin                     //MAC cache查询完成
                    if(I_mac_cache_rdest_addr == 48'd0) begin   //如果没有查询到对应的MAC,请求ARP层发送ARP请求
                        O_arp_treq_en           <=  1'b1;       //请求ARP层发送ARP
                        O_ip_tbusy              <=  1'b0;
                        O_arp_treq_ip_addr      <=  O_mac_cache_rip_addr;   //如果没有查询到MAC需要根据提供的IP地址请求ARP层发送ARP包获取MAC
                        arp_req_pend            <=  1'b1;                   //arp请求Pend结束前不处理其他的arp请求
                        STATE                   <=  IDLE;                   //回到IDLE状态,等待ARP层发送ARP包
                    end
                    else begin
                        tmac_addr_temp          <=  I_mac_cache_rdest_addr; //从MAC cache查询到MAC地址
                        O_ip_tbusy              <=  1'b1;                   //返回IP层的ACK
                        O_arp_treq_en           <=  1'b0;
                        arp_req_pend            <=  1'b0;
                        STATE                   <=  WAIT_IP_PACKET;
                    end
                end
                    else
                        STATE                   <=  CHECK_MAC_CACHE;
            end
            WAIT_ARP_REPLY:begin//等待远程主机的ARP响应(ARP层的recieve模块会接收到ARP响应)
                if(I_arp_treply_done) begin//响应
                    arp_req_pend            <=  1'b0;
                    arp_wait_time           <=  30'd0;
                    dst_ip_unreachable      <=  1'b0;
                    STATE                   <=  IDLE;
                end
                else begin
                    if(arp_wait_time == ARP_TIMEOUT_VALUE) begin//超时,未收到响应
                        arp_req_pend            <=  1'b1;
                        O_arp_tbusy             <=  1'b0;
                        O_arp_treq_en           <=  1'b1;
                        O_arp_treq_ip_addr      <=  I_ip_tdest_addr;
                        dst_ip_unreachable      <=  1'b1;
                        arp_wait_time           <=  30'd0;
                        STATE                   <=  IDLE;
                    end
                    else begin
                        arp_req_pend            <=  1'b1;
                        O_arp_tbusy             <=  1'b1;
                        dst_ip_unreachable      <=  1'b0;
                        arp_wait_time           <=  arp_wait_time + 1'b1;
                        STATE                   <=  WAIT_ARP_REPLY;
                    end
                end
            end
            WAIT_ARP_PACKET:begin//ARP包有效,打拍后直接输出给MAC层
                if(I_arp_tvalid) begin
                    O_mac_tdata_type        <=  {1'b1,I_arp_tdata_type};//2'b10:arp reply; 2'b11:arp request ;2'b01 ip
                    O_mac_tvalid            <=  1'b1;
                    O_mac_tdata             <=  I_arp_tdata;
                    O_mac_tdest_addr        <=  I_arp_tdest_mac_addr;
                    STATE                   <=  SEND_ARP_PACKET;
                end
                else begin
                    O_mac_tdata_type        <=  2'd0;
                    O_mac_tvalid            <=  1'b0;
                    O_mac_tdata             <=  8'd0;
                    O_mac_tdest_addr        <=  48'd0;
                    STATE                   <=  WAIT_ARP_PACKET;
                end
            end
            SEND_ARP_PACKET:begin       //继续打拍后输出给MAC层
                if(I_arp_tvalid) begin  //如果ARP包有效
                    O_mac_tvalid            <=  1'b1;
                    O_mac_tdata             <=  I_arp_tdata;
                    STATE                   <=  SEND_ARP_PACKET;
                end
                else begin
                    O_arp_tbusy             <=  1'b0;
                    O_mac_tdata_type        <=  2'd0;
                    O_mac_tvalid            <=  1'b0;
                    O_mac_tdata             <=  8'd0;
                    O_mac_tdest_addr        <=  48'd0;
                    if(arp_req_pend)    //如果该信号有效,代表IP层发送IP包的时候没有从本地cache查询到MAC地址,而发送的ARP请求包,因此下一步等待远程主机发送ARP响应
                        STATE               <=  WAIT_ARP_REPLY;
                    else
                        STATE               <=  IDLE;   //如果是单纯的ARP层发送的包,到此结束
                end
            end
            WAIT_IP_PACKET:begin    //IP包的传输
                if(I_ip_tvalid) begin
                    O_mac_tdata_type        <=  2'b01;
                    O_mac_tvalid            <=  1'b1;
                    O_mac_tdata             <=  I_ip_tdata;
                    O_mac_tdest_addr        <=  tmac_addr_temp;
                    STATE                   <=  SEND_IP_PACKET;
                end
                else begin
                    O_mac_tdata_type        <=  2'd0;
                    O_mac_tvalid            <=  1'b0;
                    O_mac_tdata             <=  8'd0;
                    O_mac_tdest_addr        <=  48'd0;
                    STATE                   <=  WAIT_IP_PACKET;
                end
            end
            SEND_IP_PACKET:begin    //IP包的传输
                if(I_ip_tvalid) begin
                    O_mac_tvalid            <=  1'b1;
                    O_mac_tdata             <=  I_ip_tdata;
                    STATE                   <=  SEND_IP_PACKET;
                end
                else begin
                    O_ip_tbusy              <= 1'b0;
                    O_mac_tdata_type        <= 2'd0;
                    O_mac_tvalid            <= 1'b0;
                    O_mac_tdata             <= 8'd0;
                    O_mac_tdest_addr        <= 48'd0;
                    STATE                   <= IDLE;
                end
            end
        endcase
    end
end

本文来米联客(milianke),作者:米联客(milianke),转载请注明原文链接:https://www.cnblogs.com/milianke/p/18351341

最新文章

最新文章