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

四、仿真

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/626150.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Docker安装Redis,并在 Visual Studio Code 中使用它

Docker安装Redis 查找Redis docker search Redis完整结果 PS C:\Users\cheng> docker search Redis NAME DESCRIPTION STARS OFFICIAL redis Redis is an open …

【强化学习-Mode-Free DRL】深度强化学习如何选择合适的算法?DQN、DDPG、A3C等经典算法Mode-Free DRL算法的四个核心改进方向

【强化学习-DRL】深度强化学习如何选择合适的算法&#xff1f; 引言&#xff1a;本文第一节先对DRL的脉络进行简要介绍&#xff0c;引出Mode-Free DRL。第二节对Mode-Free DRL的两种分类进行简要介绍&#xff0c;并对三种经典的DQL算法给出其交叉分类情况&#xff1b;第三节对…

Excel如何设置密码保护【图文详情】

文章目录 前言一、Excel如何设置密码保护&#xff1f;二、Excel如何取消密码保护&#xff1f;总结 前言 在软件项目开发过程中&#xff0c;会输出很多技术文档&#xff0c;其中也包括保密级别很高的服务器账号Excel文档。为了确保服务器账号相关的Excel文档的安全性&#xff0…

超级简单的地图操作工具开发可疑应急,地图画点,画线,画区域,获取地图经纬度等

使用echars的地图画点,画线,画区域,获取地图经纬度等 解压密码:10086007 地图也是用临时的bmap.js和china.js纯离线二选一 一共就这么多文件 画点,画线,画区域 点击地图获取经纬度-打印到控制台,这样就能渲染航迹,多变形,结合其他算法算圆等等操作 下载资源:https://download…

C# OpenCvSharp DNN 黑白老照片上色

C# OpenCvSharp DNN 黑白老照片上色 目录 效果 项目 代码 下载 参考 效果 项目 代码 using OpenCvSharp; using OpenCvSharp.Extensions; using System; using System.Diagnostics; using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropS…

CVPR2022人脸识别Partial FC论文及代码学习笔记

论文链接&#xff1a;https://openaccess.thecvf.com/content/CVPR2022/papers/An_Killing_Two_Birds_With_One_Stone_Efficient_and_Robust_Training_CVPR_2022_paper.pdf 代码链接&#xff1a;insightface/recognition/arcface_torch at master deepinsight/insightface G…

leetcode——链表的中间节点

876. 链表的中间结点 - 力扣&#xff08;LeetCode&#xff09; 链表的中间节点是一个简单的链表OJ。我们要返回中间节点有两种情况&#xff1a;节点数为奇数和节点数是偶数。如果是奇数则直接返回中间节点&#xff0c;如果是偶数则返回第二个中间节点。 这道题的解题思路是&a…

【JS面试题】this

this取什么值&#xff0c;是在函数执行的时候确定的&#xff0c;不是在函数定义的时候确定的&#xff01; this的6种使用场景&#xff1a; ① 在普通函数中使用&#xff1a;返回window对象 ② 使用call apply bind 调用&#xff1a;绑定的是哪个对象就返回哪个对象 ③ 在对象…

LeetCode2390从字符串中移除星号

题目描述 给你一个包含若干星号 * 的字符串 s 。在一步操作中&#xff0c;你可以&#xff1a;选中 s 中的一个星号。移除星号 左侧 最近的那个 非星号 字符&#xff0c;并移除该星号自身。返回移除 所有 星号之后的字符串。注意&#xff1a;生成的输入保证总是可以执行题面中描…

电子邮箱是什么?怎么申请一个电子邮箱?

电子邮箱是我们沟通的工具&#xff0c;细分为免费版电子邮箱和付费版电子邮箱。怎么申请一个属于自己的电子邮箱&#xff1f;今天小编就分享一下电子邮箱注册教程&#xff0c;手把手教您注册一个电子邮箱。 一、电子邮箱的定义 电子邮箱&#xff0c;简称邮箱&#xff0c;是一…

【Java基础】权限修饰符

一个java文件中只能有一个被public修饰的类&#xff0c;且该类名与java文件的名字一样 同一个类同一个包不同包有继承不同包无继承private✔❌❌❌默认✔✔❌❌protected✔✔✔❌public✔✔✔✔

景源畅信数字:抖音热门赛道有哪些?

抖音&#xff0c;作为当下流行的短视频平台&#xff0c;吸引了无数用户和创作者。热门赛道&#xff0c;即平台上受关注度高、活跃用户多的内容领域&#xff0c;是许多内容创作者关注的焦点。这些赛道不仅反映了用户的兴趣偏好&#xff0c;也指引着创作的方向。 一、美食制作与分…

产品新说:应急定界 | 如何在运维/技术支持领域中应对突发故障?

一、简介 应急定界的方案旨在帮助运维人员以业务故障驱动为起点&#xff0c;第一时间的快速恢复业务。该场景的条件基础是通过构建一体化监控告警平台&#xff0c;纳管应用与基础组件&#xff0c;提供业务系统监测、及时告警、排查分析能。通过告警、指标、日志、链路等重要运…

C语言中数组与指针的区别

一. 简介 本文学习了 C语言中数组与指针的区别。这样的话&#xff0c;可以在编写C代码时规避掉出错的问题。 二. C语言中数组与指针的区别 1. 数组 定义字符串数组时&#xff0c;必须让编译器知道需要多少空间。 一种方法是用足够空间的数组存储字符串。例如如下&#xf…

多表查询练习题

1、创建好数据库 create database text use text --学生表 (students) CREATE TABLE students ( student_id INT PRIMARY KEY, name VARCHAR(50), age INT, major VARCHAR(50) );--课程表 (courses) CREATE TABLE courses ( course_id INT PRIMARY KEY, course_name V…

Linux基础之进程-进程状态

目录 一、进程状态 1.1 什么是进程状态 1.2 运行状态 1.2 阻塞状态 1.3 挂起状态 二、Linux操作系统上具体的进程状态 2.1 状态 2.2 R 和 S 状态的查看 2.3 后台进程和前台进程 2.4 休眠状态和深度休眠状态 一、进程状态 1.1 什么是进程状态 首先我们知道我们的操作系…

Java学习47-Java 流(Stream)、文件(File)和IO - 其他流的使用

1.标准输入流System.in/标准输出流System.out System.in : 标准的输入流&#xff0c;默认从键盘输入 System.out: 标准的输出流&#xff0c;默认从显示器输出(理解为控制台输出) System.setOut()方法和 System.setIn()方法&#xff08;结合下面介绍的打印流举例&#xff09; …

灵活的静态存储控制器 (FSMC)的介绍(STM32F4)

目录 概述 1 认识FSMC 1.1 应用介绍 1.2 FSMC的主要功能 1.2.1 FSMC用途 1.2.2 FSMC的功能 2 FSMC的框架结构 2.1 AHB 接口 2.1.1 AHB 接口的Fault 2.1.2 支持的存储器和事务 2.2 外部器件地址映射 3 地址映射 3.1 NOR/PSRAM地址映射 3.2 NAND/PC卡地址映射 概述…

ctfshow web入门 php反序列化 web267--web270

web267 查看源代码发现这三个页面 然后发现登录页面直接admin/admin登录成功 然后看到了 ///backdoor/shell unserialize(base64_decode($_GET[code]))EXP <?php namespace yii\rest{class IndexAction{public $checkAccess;public $id;public function __construct(){…

定时器的理论和使用

文章目录 一、定时器理论1.1定时器创建和使用 二、定时器实践2.1周期触发定时器2.2按键消抖 一、定时器理论 定时器是一种允许在特定时间间隔后或在将来的某个时间点调用回调函数的机制。对于需要周期性任务或延迟执行任务的嵌入式应用程序特别有用。 软件定时器&#xff1a; …