CRC算法并行运算Verilog实现

news2024/11/18 22:23:53

        因为CRC循环冗余校验码的算法和硬件电路结构比较简单,所以CRC是一种在工程中常用的数据校验方法。尽管CRC简单,但在工程应用中还是有些问题会对工程师产生困惑。这篇文章将介绍一下CRC,希望对大家有所帮助。

一、CRC算法介绍

        CRC校验原理看起来比较复杂,好难懂,因为大多数书上基本上是以二进制的多项式形式来说明的。其实很简单的问题,其根本思想就是先在要发送的帧后面附加一个数(这个就是用来校验的校验码,但要注意,这里的数也是二进制序列的,下同),生成一个新帧发送给接收端。当然,这个附加的数不是随意的,它要使所生成的新帧能与发送端和接收端共同选定的某个特定数整除(注意,这里不是直接采用二进制除法,而是采用一种称之为“模2除法”)。到达接收端后,再把接收到的新帧除以(同样采用“模2除法”)这个选定的除数。因为在发送端发送数据帧之前就已通过附加一个数,做了“去余”处理(也就已经能整除了),所以结果应该是没有余数。如果有余数,则表明该帧在传输过程中出现了差错。

     【说明】“模2除法”与“算术除法”类似,但它既不向上位借位,也不比较除数和被除数的相同位数值的大小,只要以相同位数进行相除即可。模2加法运算为:1+1=0,0+1=1,0+0=0,无进位,也无借位;模2减法运算为:1-1=0,0-1=1,1-0=1,0-0=0,也无进位,无借位。相当于二进制中的逻辑异或运算。也就是比较后,两者对应位相同则结果为“0”,不同则结果为“1”。如100101除以1110,结果得到商为11,余数为1,如左图所示。如11×11=101,如右图所示。

         具体来说,CRC校验原理就是以下几个步骤:

        (1)先选择(可以随机选择,也可按标准选择,具体在后面介绍)一个用于在接收端进行校验时,对接收的帧进行除法运算的除数(是二进制比较特串,通常是以多项方式表示,所以CRC又称多项式编码方法,这个多项式也称之为“生成多项式”)。

        (2)看所选定的除数二进制位数(假设为k位),然后在要发送的数据帧(假设为m位)后面加上k-1位“0”,然后以这个加了k-1个“0“的新帧(一共是m+k-1位)以“模2除法”方式除以上面这个除数,所得到的余数(也是二进制的比特串)就是该帧的CRC校验码,也称之为FCS(帧校验序列)。但要注意的是,余数的位数一定要是比除数位数只能少一位,哪怕前面位是0,甚至是全为0(附带好整除时)也都不能省略。

        (3)再把这个校验码附加在原数据帧(就是m位的帧,注意不是在后面形成的m+k-1位的帧)后面,构建一个新帧发送到接收端;最后在接收端再把这个新帧以“模2除法”方式除以前面选择的除数,如果没有余数,则表明该帧在传输过程中没出错,否则出现了差错。

        通过以上介绍,大家一定可以理解CRC校验的原理,并且不再认为很复杂吧。

        从上面可以看出,CRC校验中有两个关键点:一是要预先确定一个发送端和接收端都用来作为除数的二进制比特串(或多项式);二是把原始帧与上面选定的除进行二进制除法运算,计算出FCS。前者可以随机选择,也可按国际上通行的标准选择,但最高位和最低位必须均为“1”,如在IBM的SDLC(同步数据链路控制)规程中使用的CRC-16(也就是这个除数一共是17位)生成多项式g(x)= x16 + x15 + x2 +1(对应二进制比特串为:11000000000000101);而在ISO HDLC(高级数据链路控制)规程、ITU的SDLC、X.25、V.34、V.41、V.42等中使用CCITT-16生成多项式g(x)= x16 + x15 + x5 +1(对应二进制比特串为:11000000000100001)。

        由以上分析可知,既然除数是随机,或者按标准选定的,所以CRC校验的关键是如何求出余数,也就是校验码(CRC校验码)。

    下面以一个例子来具体说明整个过程。现假设选择的CRC生成多项式为G(X) = X4 + X3 + 1,要求出二进制序列10110011的CRC校验码。下面是具体的计算过程:

         (1)首先把生成多项式转换成二进制数,由G(X) = X4 + X3 + 1可以知道(,它一共是5位(总位数等于最高位的幂次加1,即4+1=5),然后根据多项式各项的含义(多项式只列出二进制值为1的位,也就是这个二进制的第4位、第3位、第0位的二进制均为1,其它位均为0)很快就可得到它的二进制比特串为11001。

        (2)因为生成多项式的位数为5,根据前面的介绍,得知CRC校验码的位数为4(校验码的位数比生成多项式的位数少1)。因为原数据帧10110011,在它后面再加4个0,得到101100110000,然后把这个数以“模2除法”方式除以生成多项式,得到的余数(即CRC码)为0100,如图5-10所示。注意参考前面介绍的“模2除法”运算法则。

       

         (3)把上步计算得到的CRC校验0100替换原始帧101100110000后面的四个“0”,得到新帧101100110100。再把这个新帧发送到接收端。

        (4)当以上新帧到达接收端后,接收端会把这个新帧再用上面选定的除数11001以“模2除法”方式去除,验证余数是否为0,如果为0,则证明该帧数据在传输过程中没有出现差错,否则出现了差错。

    通过以上CRC校验原理的剖析和CRC校验码的计算示例的介绍,大家应该对这种看似很复杂的CRC校验原理和计算方法应该比较清楚了。 

二、CRC算法并行实现

1、实现流程

        (1) 用N表示数据宽度,M表示CRC宽度。例如,如果我们想为4位数据路径生成并行USB CRC5,N=4,M=5。

        (2) 使用给定的多项式或十六进制表示法实现串行CRC生成器例程。

         (3) 并行CRC实现是N位数据输入和M位当前状态CRC的函数,如下图所示。我们将构建两个矩阵:当N=0时,作为Min(当前状态CRC)函数的Mout(下一状态CRC)和当M=0时,作为Nin的函数的Mout。

         (4) 当Min=0时,使用(2)中的例程计算N个值的CRC。每个值都是one-hot的,也就是说只有一个位为1。对于N=4,值为0x1、0x2、0x4、0x8。Mout=F(Nin,Min=0)

        (5) 构建NxM矩阵,每一行包含按递增顺序来自(3)的结果。例如,第1行包含输入=0x1的结果,第2行为输入=0x2等。输出为M位宽,即所需的CRC宽度。以下是N=4的USB CRC5的矩阵。

         (6) 这个矩阵中的每一列,表示输出位Mout[i]作为Nin的函数。

        (7) 当Nin=0时,使用(3)中的例程计算M个值的CRC。每个值都是一个one-hot的,也就是说只有一个位为1。对于M=5,值为0x1、0x2、0x4、0x8、0x10。Mout=F(Nin=0,最小值)

        (8) 构建MxM矩阵,每一行包含按递增顺序来自(7)的结果。以下是N=4的USB CRC5的矩阵:

         (9) 现在,为每个Mout[i]位建立一个等式:列[i]中的所有Nin[j]和Min[k]位都参与该等式。参与的输入被异或在一起。

        Mout[0] = Min[1]^Min[4]^Nin[0]^Nin[3]

        Mout[1] = Min[2]^Nin[1]

        Mout[2] = Min[1]^Min[3]^Min[4]^Nin[0]^Nin[2]^Nin[3]

        Mout[3] = Min[2]^Min[4]^Nin[1]^Nin[3]

        Mout[4] = Min[0]^Min[3]^Nin[2]

        这就是并行CRC的输出。

2、实例及代码

        我们以CRC8举例,多项式G(x)=X8 +X7 +X6 +X4 +X2 +1 ,则其串行CRC代码如下:

//G(x)=X^8 +X^7 +X^6 +X^4 +X^2 + X^0
//input bit number = 1
// 
module CRC8_1BIT(
DATA,
CRC_OUT,
RESET,
ENABLE,
CLK);
input DATA;
input RESET;
input ENABLE;
input CLK;
output [7:0] CRC_OUT;
wire DATA
wire RESET;
wire ENABLE
wire CLK
reg [7:0] CRC_OUT;

wire LFSR_N
reg [7:0] LFSR_S;

assign LFSR_N=CRC_OUT[7]^DATA;

always@(*) begin
    LFSR_S[0] = LFSR_S[7] ;
    LFSR_S[1] = LFSR_S[0] ;
    LFSR_S[2] = LFSR_S[1]^LFSR_N ;
    LFSR_S[3] = LFSR_S[2] ;
    LFSR_S[4] = LFSR_S[3]^LFSR_N ;
    LFSR_S[5] = LFSR_S[4] ;
    LFSR_S[6] = LFSR_S[5]^LFSR_N ;
    LFSR_S[7] = LFSR_S[6]^LFSR_N ;
end

always@ (posedge CLK or posedge RESET) begin
    if(RESET) begin
        CRC_OUT <= 8’ hff;
    else if (ENABLE) begin
        CRC_OUT <= LFSR_S;
    end
end

endnodule

        然后根据这个LFSR迭代得到矩阵:

module crc8_paralle( 
input [7:0] data_in, 
output reg[7:0] crc8, 
input rst,
input cik
);
// LFSR for crc8 
function [7:0] crc8_serial; 
input [7:0] crc;
input data; 
begin 
    crc8_serial[0] = data^crc[7] ;
    crc8_serial[1] = crc[0] ;
    crc8_serial[2] = data^crc[7]^crc[1] ;
    crc8_serial[3] = crc[2] ;
    crc8_serial[4] = data^crc[7]^crc[3] ;
    crc8_serial[5] = crc[4] ;
    crc8_serial[6] = data^crc[7]^crc[5] ;
    crc8_serial[7] = data^crc[7]^crc[6] ;
end
endfunction

// 8 iterations of crc8 LFSR 
function [7:0] crc_iteration 
input [7:0] crc;
input [7:0] data integer i;
begin
crc_iteration = crc; 
for( i=0 ; i<8 ; i=i+1)
    crc_iteration = crc8_serial(crc_iteration, data[7-i]); 
end
endfunction

always@( posedge clk or posedge rst) begin 
    if(rst) begin
        crc8 <= 8'hff; 
    end
    else begin
        crc8 <= crc_iteration(crc8,data_in) ;
    end
end

endmodule

        输入data_in 的是8‘b00000001,得到crc8的值,就是H1的第一行8’hd5;输入data_in 的是8‘b00000010,得到crc8的值,就是H1的第二行8’h7f;以此类推。计算出上面矩阵H1=[]NxM。计算H2=[]MxM的方法和H1是一样的。经过上面计算得到矩阵:

// G (x) = X^8 +X^7 +X^6 +X^4 +X^2 +X^0
//input bit number 8
Nin[O]  1  1  0  1  0  1  0  1  
Nin[1]  0  1  1  1  1  1  1  1
Nin[2]  1  1  1  1  1  1  1  0
Nin[3]  0  0  1  0  1  0  0  1   H1
Nin[4]  0  1  0  1  0  0  1  0
Nin[5]  1  0  1  0  0  1  0  0
Nin[6]  1  0  0  1  1  1  0  1
Nin[7]  1  1  1  0  1  1  1  1
----------------------------------
Min[O]  1  1  0  1  0  1  0  1  
Min[1]  0  1  1  1  1  1  1  1
Min[2]  1  1  1  1  1  1  1  0
Min[3]  0  0  1  0  1  0  0  1   H2
Min[4]  0  1  0  1  0  0  1  0
Min[5]  1  0  1  0  0  1  0  0
Min[6]  1  0  0  1  1  1  0  1
Min[7]  1  1  1  0  1  1  1  1
----------------------------------
nxt_crc 7  6  5  4  3  2  1  0

           此时,我们可以写出并行CRC的Verilog程序:

//G(x)=X^8 +X^7 +X^6 +X^4 +X^2 + X^0
//input bit number = 1 
module CRC8_8BIT(
DATA,
CRC_OUT,
RESET,
ENABLE,
CLK);
input [7:0]DATA;
input RESET;
input ENABLE;
input CLK;
output [7:0] CRC_OUT;
wire [7:0]DATA
wire RESET;
wire ENABLE
wire CLK
wire [7:0] CRC_OUT;

assign CRC_OUT = LFSR_N;

reg [7:0] LFSR_N
reg [7:0] LFSR_S;

always@(*) begin
    LFSR_S[0] = DATA[0]^DATA[1]^DATA[3]^DATA[6]^DATA[7]^LFSR_N[0]^ LFSR_N[1]^LFSR_N[3]^LFSR_N[6]^LFSR_N[7];
    LFSR_S[1] = DATA[1]^DATA[2]^DATA[4]^DATA[7]^LFSR_N[1]^ LFSR_N[2]^LFSR_N[4]^LFSR_N[7];
    LFSR_S[2] = DATA[0]^DATA[1]^DATA[2]^DATA[5]^DATA[6]^DATA[7]^LFSR_N[0]^ LFSR_N[1]^LFSR_N[2]^LFSR_N[5]^LFSR_N[6]^LFSR_N[7];
    LFSR_S[3] = =DATA[1]^DATA[2]^DATA[3]^DATA[6]^DATA[7]^ LFSR_N[1]^LFSR_N[2]^LFSR_N[3]^LFSR_N[6]^LFSR_N[7];
    LFSR_S[4] = DATA[0]^DATA[1]^DATA[2]^DATA[4]^DATA[6]^LFSR_N[0]^ LFSR_N[1]^LFSR_N[2]^LFSR_N[4]^LFSR_N[6];
    LFSR_S[5] = DATA[1]^DATA[2]^DATA[3]^DATA[5]^DATA[7]^ LFSR_N[1]^LFSR_N[2]^LFSR_N[3]^LFSR_N[5]^LFSR_N[7];
    LFSR_S[6] = DATA[0]^DATA[1]^DATA[2]^DATA[4]^DATA[7]^LFSR_N[0]^ LFSR_N[1]^LFSR_N[2]^LFSR_N[4]^LFSR_N[7];
    LFSR_S[7] = DATA[0]^DATA[2]^DATA[5]^DATA[6]^DATA[7]^LFSR_N[0]^ LFSR_N[2]^LFSR_N[5]^LFSR_N[6]^LFSR_N[7];
end

always@ (posedge CLK or posedge RESET) begin
    if(RESET) begin
        LFSR_N <= 8’ hff;
    else if (ENABLE) begin
        LFSR_N <= LFSR_S;
    end
end

endnodule

3、自动生成器

        上面推导其实较为麻烦,不过上面的方法其实可写成一个脚本,实现任意多项式任意位宽输入的并行CRC硬件电路。

        http://www.OutputLogic.com 有自动生成器,大家可以试试。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PPO(Proximal Policy Optimization Algorithms)论文解读及实现

论文标题&#xff1a;Proximal Policy Optimization Algorithms 核心思路&#xff1a;使用off policy 代替on policy,用一个策略网络来产生数据&#xff0c;用一个策略网络来更新参数&#xff0c;分别为policy_old和policy 0 摘要 Whereas standard policy gradient methods …

Python自动化办公:pptx篇

文章目录 简介能做什么PPT要素介绍官方demo高阶引申参考文献 202201笔记迁移 简介 python-pptx包是用来自动化处理ppt的。 使用的第一步是安装 pip install python-pptx相比python-docx&#xff0c;python-pptx的使用更为麻烦一些&#xff0c;原因有很多&#xff0c;比如说&…

波奇学Linux:make和Makefile

make和Makefile自动化构建并能决定源文件调用顺序&#xff0c;同时不必再写gcc命令 第一行依赖关系&#xff0c;第二行是tab键开头&#xff0c;是依赖方法 依赖关系&#xff1a;目标文件&#xff1a;依赖文件。 依赖方法&#xff1a;目标文件和依赖文件间的关系。 如果只有一条…

es下载历史的tar文件

第一步进入官网找到历史版本 第二步复制历史版本名称组合成下面的链接 直接get访问下载。如下链接所示只需要修改7.3.0这个版本号 https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.3.0-linux-x86_64.tar.gz

ChatGLM使用记录

ChatGLM ChatGLM-6B 是一个开源的、支持中英双语的对话语言模型&#xff0c;基于 General Language Model (GLM) 架构&#xff0c;具有 62 亿参数。结合模型量化技术&#xff0c;用户可以在消费级的显卡上进行本地部署&#xff08;INT4 量化级别下最低只需 6GB 显存&#xff0…

opencv实战--角度测量和二维码条形码识别

文章目录 前言一、鼠标点击的角度测量二、二维码条形码识别 前言 一、鼠标点击的角度测量 首先导入一个带有角度的照片 然后下面的代码注册了一个鼠标按下的回调函数&#xff0c; 还有一个点的数列&#xff0c;鼠标事件为按下的时候就记录点&#xff0c;并画出点&#xff0c;…

uniapp微信小程序上传体积压缩包过大分包操作和上传时遇到代码质量未通过问题

1&#xff1a;首先我们得从项目最初阶段就得考虑项目是否要进行分包操作&#xff0c;如果得分包&#xff0c;我们应该创建一个与pages同级的文件夹&#xff0c;命名可以随意 2:第二部我们将需要分包的文件和页面放到分包文件夹里面subpage&#xff0c;这里我们得注意&#xff…

Python基础语法第三章之顺序循环条件

目录 一、顺序语句 二、条件语句 2.1什么是条件语句 2.2语法格式 2.2.1 if 2.2.2if - else 2.2.3if - elif - else 2.3缩进和代码块 2.4闰年的判断练习 2.5空语句 pass 三、循环语句 3.1while 循环 3.1.1代码示例练习 3.2 for 循环 ​3.3 continue 3.4 break 一…

给LLM装上知识:从LLM+LangChain的本地知识库问答到LLM与知识图谱的结合

前言 过去半年&#xff0c;随着ChatGPT的火爆&#xff0c;直接带火了整个LLM这个方向&#xff0c;然LLM毕竟更多是基于过去的经验数据预训练而来&#xff0c;没法获取最新的知识&#xff0c;以及各企业私有的知识 为了获取最新的知识&#xff0c;ChatGPT plus版集成了bing搜…

linux常用工具介绍

文章目录 前言目录文件查看ls1、查看详细信息&#xff08;文件大小用K、M等显示&#xff09;2、按照文件创建时间排序&#xff08;常在查看日志时使用&#xff09; sort1、排序数字 df 、du1、查看目录的大小2、查看目录 从大到小排序 显示前n个3、查看磁盘使用情况 tailf一些目…

银河麒麟高级服务器操作系统V10安装mysql数据库

一、安装前 1.检查是否已经安装mysql rpm -qa | grep mysql2.将查询出的包卸载掉 rpm -e --nodeps 文件名3.将/usr/lib64/libLLVM-7.so删除 rm -rf /usr/lib64/libLLVM-7.so4.检查删除结果 rpm -qa | grep mysql5.搜索残余文件 whereis mysql6.删除残余文件 rm -rf /usr/b…

怎么用二维码做企业介绍?企业宣传二维码2种制作方法

怎么做一个企业推广二维码呢&#xff1f;现在制作二维码来做宣传推广是常用的一种方式&#xff0c;一般需要包含企业介绍、工作环境、产品简介、宣传视频、公司地址等等方面内容&#xff0c;那么企业介绍二维码该如何制作&#xff1f;下面给大家分享一下使用二维码编辑器&#…

EventBus详解

目录 1 EventBus 简介简介角色关系图四种线程模型 2.EventBus使用步骤添加依赖注册解注册创建消息类发送消息接收消息粘性事件发送消息 使用postStick()接受消息 3 EventBus做通信优点4 源码getDefault()register()findSubscriberMethods方法findUsingReflection方法findUsingR…

前端部署项目,经常会出现下载完 node 或者 npm 运行时候发现,提示找不到

1. 首先要在下载时候选择要下载的路径&#xff0c;不能下载完后&#xff0c;再拖拽到其他文件夹&#xff0c;那样就会因为下载路径和当前路径不一致&#xff0c;导致找不到相关变量。 2. 所以一开始就要在下载时候确定要存放的路径&#xff0c;然后如果运行报错&#xff0c;就…

【Java基础教程】(十三)面向对象篇 · 第七讲:继承性详解——继承概念及其限制,方法覆写和属性覆盖,关键字super的魔力~

Java基础教程之面向对象 第七讲 本节学习目标1️⃣ 继承性1.1 继承的限制 2️⃣ 覆写2.1 方法的覆写2.2 属性的覆盖2.3 关键字 this与 super的区别 3️⃣ 继承案例3.1 开发数组的父类3.2 开发排序类3.3 开发反转类 &#x1f33e; 总结 本节学习目标 掌握继承性的主要作用、实…

git指令记录

参考博客&#xff08;侵权删&#xff09;&#xff1a;关于Git这一篇就够了_17岁boy想当攻城狮的博客-CSDN博客 Git工作区介绍_git 工作区_xyzso1z的博客-CSDN博客 git commit 命令详解_gitcommit_辰风沐阳的博客-CSDN博客 本博客只作为自己的学习记录&#xff0c;无商业用途&…

计算机存储设备

缓存为啥比内存快 内存使用 DRAM 来存储数据的、也就是动态随机存储器。内部使用 MOS 和一个电容来存储。 需要不停地给它刷新、保持它的状态、要是不刷新、数据就丢掉了、所以叫动态 、DRAM 缓存使用 SRAM 来存储数据、使用多个晶体管(比如6个)就是为了存储1比特 内存编码…

【python】python全国数据人均消费数据分析(代码+报告+数据)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、51CTO技术博主 &#x…

bio、nio、aio、io多路复用

BIO-同步阻塞IO NIO-同步非阻塞IO 不断的重复发起IO系统调用&#xff0c;这种不断的轮询&#xff0c;将会不断地询问内核&#xff0c;这将占用大量的 CPU 时间&#xff0c;系统资源利用率较低 IO多路复用模型-异步阻塞IO IO多路复用模型&#xff0c;就是通过一种新的系统调用&a…

前端开发者都应知道的 网站

1、ransform.tools 地址&#xff1a;transform.tools/ transform.tools 是一个网站&#xff0c;它可以让你转换几乎所有的东西&#xff0c;比如将HTML转换为JSX&#xff0c;JavaScript转换为JSON&#xff0c;CSS转换为JS对象等等。当我需要转换任何东西时&#xff0c;它真的帮…