10G UDP协议栈 IP层设计-(6)IP TX模块

一、模块功能

1、上层数据封装IP报文头部

2、计算首部校验和

二、首部校验和计算方法

在发送方,先把IP数据报首部划分为许多16位字的序列,并把检验和字段置零。用反码算术运算把所有16位字相加后,将得到的和的反码写入检验和字段。接收方收到数据报后,将首部的所有16位字再使用反码算术运算相加一次。将得到的和取反码,即得出接收方检验和的计算结果。若首部未发生任何变化,则此结果必为0,于是就保留这个数据报。否则即认为出差错。

原文链接:https://blog.csdn.net/weixin_44870077/article/details/118106364

例如一包数据的首部:64'h4500001400012000、64'h8017d0b9c0a86464、64'hc0a8646300000000

版本号到片偏移:64'h4500001400012000

生存时间:8'h80

协议号:8'h17

计算出来的首部校验和:16'hd0b9

源IP地址:c0a86464

目的IP地址:c0a86463

划分为长度为16bit的字段:4500 0014 0001 2000 8017 首部校验和初始计算值0000 c0a8 6464 c0a8 6463

相加:4500 + 0014 + 0001 + 2000 + 8017 + 0000 + c0a8 + 6464 + c0a8 + 6463 = 3 2F43

进位的高位再次加到低16位:2F43 + 0003 = 2F46

按位取法之后得到:d0b9

三、程序设计

参考:奇哥FPGA

复制代码
//将数据缓存到FIFO
FIFO_UDP_DATA_64X16 u_FIFO_UDP_DATA_64X16 (
  .clk          (i_clk              ), 
  .srst         (i_rst              ), 
  .din          (rs_axis_out_data   ), 
  .wr_en        (rs_axis_out_valid  ), 
  .rd_en        (r_fifo_rden        ), 
  .dout         (w_fifo_data_out    ), 
  .full         (), 
  .empty        (w_fifo_empty       )  
);


always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)begin
        rs_axis_out_data    <= 'd0; 
        rs_axis_out_user    <= 'd0;
        rs_axis_out_keep    <= 'd0;
        rs_axis_out_last    <= 'd0;
        rs_axis_out_valid   <= 'd0;
    end
    else begin
        rs_axis_out_data    <= s_axis_out_data  ;
        rs_axis_out_user    <= s_axis_out_user  ;
        rs_axis_out_keep    <= s_axis_out_keep  ;
        rs_axis_out_last    <= s_axis_out_last  ;
        rs_axis_out_valid   <= s_axis_out_valid ;
    end
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)begin
        r_fifo_rden_ff1 <= 'd0;
        r_fifo_rden_ff2 <= 'd0;
    end
    else begin
        r_fifo_rden_ff1 <= r_fifo_rden;
        r_fifo_rden_ff2 <= r_fifo_rden_ff1;
    end
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_fifo_data_out <= 'd0;
    else
        r_fifo_data_out <= w_fifo_data_out;
end


always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_last_user <= 'd0;
    else
        if(s_axis_out_last)
            r_last_user <= s_axis_out_user;
        else
            r_last_user <= r_last_user;
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_last_keep <= 'd0;
    else
        if(s_axis_out_last)
            r_last_keep <= s_axis_out_keep;
        else
            r_last_keep <= r_last_keep;
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        ri_set_source_ip <= P_SOURCE_IP;
    else
        if(i_set_source_valid)
            ri_set_source_ip <= i_set_source_ip;
        else
            ri_set_source_ip <= ri_set_source_ip;
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        ri_set_target_ip <= P_TARGET_IP;
    else
        if(i_set_target_valid)
            ri_set_target_ip <= i_set_target_ip;
        else
            ri_set_target_ip <= ri_set_target_ip;
end
//当FIFO有数据时就开始读FIFO
always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_fifo_rden <= 'd0;
    else
        if(!w_fifo_empty && r_cnt == 0)
            r_fifo_rden <= 1'b1;
        else if(w_fifo_empty)
            r_fifo_rden <= 1'b0;
        else
            r_fifo_rden <= r_fifo_rden;
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_cnt <= 'd0;
    else
        if(rm_axis_mac_last)
            r_cnt <= 'd0;
        else if((!w_fifo_empty && r_cnt == 0 && m_axis_mac_ready)|| r_cnt)
            r_cnt <= r_cnt + 1;
        else
            r_cnt <= r_cnt;
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        rs_axis_out_ready <= 'd1;
    else
        if(s_axis_out_last || !m_axis_mac_ready)
            rs_axis_out_ready <= 'd0;
        else if(rm_axis_mac_last || (!rm_axis_mac_valid && !m_axis_mac_ready))
            rs_axis_out_ready <= 'd1;
        else
            rs_axis_out_ready <= rs_axis_out_ready ;
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        rm_axis_mac_data <= 'd0;
    else
        if(!w_fifo_empty && r_cnt == 0)
            rm_axis_mac_data <= {4'b0100,4'b0101,8'd0,(rs_axis_out_user[70:55] + 16'd20),
                                 rs_axis_out_user[15:0],{1'b0,rs_axis_out_user[54],~rs_axis_out_user[37]},rs_axis_out_user[28:16]};
        else if(r_cnt == 1)
            rm_axis_mac_data <= {8'd128,rs_axis_out_user[36:29],~r_header_check[15:0],ri_set_source_ip[31:0]};
        else if(r_cnt == 2)
            rm_axis_mac_data <= {ri_set_target_ip[31:0],w_fifo_data_out[63:32]};
        else
            rm_axis_mac_data <= {r_fifo_data_out[31:0],w_fifo_data_out[63:32]};
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_hd_check_cnt <= 'd0;
    else
        if(s_axis_out_valid)
            r_hd_check_cnt <= r_hd_check_cnt + 1;
        else
            r_hd_check_cnt <= 'd0;
end

//做首部校验和
always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_header_check <= 'd0;
    else
        if(r_hd_check_cnt == 1)
            r_header_check <= 16'h4500 + (rs_axis_out_user[70:55] + 16'd20) + rs_axis_out_user[15:0] + 
                              ({{1'b0,rs_axis_out_user[54],~rs_axis_out_user[37]},rs_axis_out_user[28:16]})
                              + {8'd128,rs_axis_out_user[36:29]} ++ ri_set_source_ip[31:16] + ri_set_source_ip[15:0] 
                              + ri_set_target_ip[31:16] + ri_set_target_ip[15:0];
        else if(r_hd_check_cnt == 1)
            r_header_check <= r_header_check[31:16] + r_header_check[15:0]; //可能会产生进位
        else if(r_hd_check_cnt == 2)
            r_header_check <= r_header_check[31:16] + r_header_check[15:0]; //加进位之后,可能还会产生进位,所以要再加一次
        else
            r_header_check <= r_header_check;
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        rm_axis_mac_user <= 'd0;
    else
        rm_axis_mac_user <= {((rs_axis_out_user[70:55] + 16'd19) >> 3) + 1,48'hFFFFFFFF_FFFF,16'h0800};
end
//字节对齐
always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        rm_axis_mac_keep <= 'd0;
    else
        if(w_fifo_rden_neg && r_last_keep <= 8'b1111_0000)
            case(r_last_keep)
                // 8'b1111_1111: rm_axis_mac_keep <= 8'b1111_1111
                // 8'b1111_1110: rm_axis_mac_keep <= 
                // 8'b1111_1100: rm_axis_mac_keep <=
                // 8'b1111_1000: rm_axis_mac_keep <=
                8'b1111_0000: rm_axis_mac_keep <= 8'b1111_1111;
                8'b1110_0000: rm_axis_mac_keep <= 8'b1111_1110;
                8'b1100_0000: rm_axis_mac_keep <= 8'b1111_1100;
                8'b1000_0000: rm_axis_mac_keep <= 8'b1111_1000;
                default     : rm_axis_mac_keep <= 8'b1111_1111;
            endcase
        else if(w_fifo_rden_neg_ff1 && r_last_keep >= 8'b1111_1000)
            case(r_last_keep)
                8'b1111_1111: rm_axis_mac_keep <= 8'b1111_0000;
                8'b1111_1110: rm_axis_mac_keep <= 8'b1110_0000;
                8'b1111_1100: rm_axis_mac_keep <= 8'b1100_0000;
                8'b1111_1000: rm_axis_mac_keep <= 8'b1000_0000;
                // 8'b1111_0000: rm_axis_mac_keep <= 8'b1111_1111;
                // 8'b1110_0000: rm_axis_mac_keep <= 8'b1111_1110;
                // 8'b1100_0000: rm_axis_mac_keep <= 8'b1111_1100;
                // 8'b1000_0000: rm_axis_mac_keep <= 8'b1111_1000;
                default     : rm_axis_mac_keep <= 8'b0000_0000;
            endcase   
        else
               rm_axis_mac_keep <= 8'b1111_1111;      
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        rm_axis_mac_last <= 'd0;
    else
        if(w_fifo_rden_neg && r_last_keep <= 8'b1111_0000)
            rm_axis_mac_last <= 1'b1;
        else if(w_fifo_rden_neg_ff1 && r_last_keep >= 8'b1111_1000)
            rm_axis_mac_last <= 1'b1;
        else
            rm_axis_mac_last <= 'd0;
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        rm_axis_mac_valid <= 'd0;
    else
        if(!w_fifo_empty && r_cnt == 0)
            rm_axis_mac_valid <= 1'b1;
        else if(rm_axis_mac_last)
            rm_axis_mac_valid <= 'd0;
        else
            rm_axis_mac_valid <= rm_axis_mac_valid ;

end

四、仿真

相关推荐
青衫码上行1 天前
【从0开始学习Java | 第21篇】网络编程综合练习
java·网络·学习
Chicheng_MA1 天前
IPQ5322 Wi-Fi 7 SoC 路由器方案介绍
网络·路由器·ipq
EasyDSS1 天前
超越“接收端”:解析视频推拉流EasyDSS在RTMP推流生态中的核心价值与中流砥柱作用
网络·音视频
小糖学代码1 天前
网络:2.Socket编程UDP
网络·网络协议·udp
Empty_7771 天前
Python编程之常用模块
开发语言·网络·python
Ching·1 天前
linux系统编程(十②)RK3568 socket之 TCP 客户端的实现
linux·tcp/ip·rk3568
m0_611779961 天前
MQTT和WebSocket的差别
网络·websocket·网络协议
AORO20251 天前
防爆手机与普通手机有什么区别?防爆手机哪个牌子好?
运维·服务器·网络·5g·智能手机·信息与通信
望获linux1 天前
【实时Linux实战系列】使用 u-trace 或 a-trace 进行用户态应用剖析
java·linux·前端·网络·数据库·elasticsearch·操作系统
对岸住着星星1 天前
断电重启后自动重连WiFi并分配固定IP的Armbian脚本
服务器·网络·tcp/ip