基于verilog的CRC校验(汇总)

本文深入探讨了CRC(循环冗余校验)的工作原理,包括其数学基础和检错能力。详细介绍了CRC的计算过程,以一个具体的CRC-8/MAXIN参数模型为例进行了手动计算。此外,还讨论了CRC的检错与纠错机制,并展示了当数据传输中出现错误时如何定位错误位。最后,文章提到了CRC的Verilog实现,包括不同类型的并行实现方式,并给出了相关资源链接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


本来想整理一下关于CRC校验的内容,但是发现前辈们写的都很好,本文对内容进行整理汇总。

原理

crc为什么能够检错和纠错,这背后有着深刻的数学原理,这里没有进行阐述,有兴趣可以阅读相关论文。这里直接拿来主义。

这篇文章似乎介绍了原理,但我没有认真看。
CRC算法原理及其Verilog实现

CRC(循环冗余校验)在线计算

CRC校验(循环冗余校验)小知识
CRC即循环冗余校验码(Cyclic Redundancy Check):是数据通信领域中最常用的一种查错校验码,其特征是信息字段和校验字段的长度可以任意选定。循环冗余检查(CRC)是一种数据传输检错功能,对数据进行多项式计算,并将得到的结果附在帧的后面,接收设备也执行类似的算法,以保证数据传输的正确性和完整性。
CRC算法参数模型解释:
NAME:参数模型名称。
WIDTH:宽度,即CRC比特数。
POLY:生成项的简写,以16进制表示。例如:CRC-32即是0x04C11DB7,忽略了最高位的"1",即完整的生成项是0x104C11DB7。
INIT:这是算法开始时寄存器(crc)的初始化预置值,十六进制表示。
REFIN:待测数据的每个字节是否按位反转,True或False。
REFOUT:在计算后之后,异或输出之前,整个数据是否按位反转,True或False。
XOROUT:计算结果与此参数异或后得到最终的CRC值。

常见CRC参数模型如下:
在这里插入图片描述

计算

下面介绍crc的计算过程,图表见原文
CRC校验原理及实现

通常如果只给了一个多项式,其他的没有说明则:INIT=0x00,REFIN=false,REFOUT=false,XOROUT=0x00。
下面手算一个CRC值,来了解CRC计算的原理。
问:原始数据:0x34,使用CRC-8/MAXIN参数模型,求CRC值?
答:根据CRC参数模型表,得到CRC-8/MAXIN的参数如下:
POLY = 0x31 = 0011 0001(最高位1已经省略)
INIT = 0x00
XOROUT = 0x00
REFIN = TRUE
REFOUT = TRUE
有了上面的参数,这样计算条件才算完整,下面来实际计算:
0.原始数据 = 0x34 = 0011 0100,多项式 = 0x31 = 1 0011 0001
1.INIT = 00,原始数据高8位和初始值进行异或运算保持不变。
2.REFIN为TRUE,需要先对原始数据进行翻转:0011 0100 > 0010 1100
3.原始数据左移8位,即后面补8个0:0010 1100 0000 0000
4.把处理之后的数据和多项式进行模2除法,求得余数:
原始数据:0010 1100 0000 0000 = 10 1100 0000 0000
多项式:1 0011 0001
模2除法取余数低8位:1111 1011
5.与XOROUT进行异或,1111 1011 xor 0000 0000 = 1111 1011
6.因为REFOUT为TRUE,对结果进行翻转得到最终的CRC-8值:1101 1111 = 0xDF
7.数据+CRC:0011 0100 1101 1111 = 34DF,相当于原始数据左移8位+余数。

上面通过笔算的方式,讲解了CRC计算的原理,下面来介绍一下如何进行校验。
按照上面CRC计算的结果,最终的数据帧:0011 0100 1101 1111 = 34DF,前8位0011 0100是原始数据,后8位1101 1111 是 CRC结果。
接收端的校验有两种方式,一种是和CRC计算一样,在本地把接收到的数据和CRC分离,然后在本地对数据进行CRC运算,得到的CRC值和接收到的CRC进行比较,如果一致,说明数据接收正确,如果不一致,说明数据有错误。
另一种方法是把整个数据帧进行CRC运算,因为是数据帧相当于把原始数据左移8位,然后加上余数,如果直接对整个数据帧进行CRC运算(除以多项式),那么余数应该为0,如果不为0说明数据出错。

注意计算的时候,异或和翻转都是以字节为单位

检错与纠错

下面介绍检错与纠错,图表见原文
循环冗余校验码原理(CRC码)

假设数据为 10101011,生成多项式为 10011,求 CRC 码?
多项式就是双方约定的除数 10011
余数 1010 就是 CRC 码的校验位,加上信息位组合成最终的 CRC 码: 101010111010
用 101010111010 与 10011 相除,最终的余数一定是 0000

一位出错(不能纠错)
若是在传输过程中,crc码被错传为101010110010
把 101010110010代入模2除,得到余数 0100,对应十进制 4,也就是说 C4 处出错了

一位出错(不能纠错)
上面的例子,校验位是 4 位,可以表示 16 种状态,实际的 CRC 码只有 12 位,所以有纠错能力。
如果校验位是 3 位,可以表示 8 种状态,实际的 CRC 码有 9 位,这种情况下就没办法实现纠错了。
假如说现在求得的余数是 010 转换为十进制是 2,能否说明第 2 位出错了呢?
看下面表,010 对应的出错位是 2 和 9,也就是说当第二位或者第九位出错了,余数是一样的,这就导致了我们根据 010 没判断出错位了。

在这里插入图片描述

所以要使 CRC 码有纠错能力,必须满足:2^k >= n + k + 1
n + k 表示错误的状态的数量
1 表示的正确的状态

若是多位错误,则通过上述的方法无法纠错

纠错实现

还有出错位和余数的关系是由生成多项式决定的,上述余数与出错位的关系纯属巧合,不具有普遍性。如下所示。

1100,生成多项式为1011

在这里插入图片描述

根据不同的余数的值就能知道哪一位出错了,同时理论上也能进行纠错
但是,在实际的运行中,计算机并没有对每一位都做了纠错电路,这就需要用到CRC的循环性质
假设出错位是第五位,1100010 -> 1100110,此时的余数是100,对100补个0,依然用生成多项式G去做模2运算,得到的余数是011,由表可知,恰好是第四位出错时的余数,说明余数存在循环性
利用这个性质,计算机只在第一位做纠错电路,也就是说在纠错时,计算机不知道100和011,计算机只知道第一位出错的余数是101
还是假设出错位是第五位,此时接收方拿到的是1100110,余数位100
对余数不断的进行模2运算,同时移动校验码。

在这里插入图片描述

如此,就完成了第五位的纠错

Verilog实现

并入并处,需要多个时钟实现
【Verilog】CRC校验码生成器原理及verilog实现

并入并出,单时钟
CRC校验原理和verilog实现方法(三)
电路逻辑的推导见(二)

并入并出,有完整代码,单时钟
Verilog语言实现并行(循环冗余码)CRC校验

并入并出,多时钟
CRC循环冗余校验码verilog实现

多时钟强转单时钟
基于FPGA的CRC校验码生成器

This tool will generate Verilog or VHDL code for a CRC with a given data width and polynomial.
CRC Generator

FPGA手撕代码——CRC校验码的多种Verilog实现方式

FPGA/IC面试准备三之CRC校验

### 使用Verilog实现CRC16查表法 为了在FPGA或ASIC设计中高效地计算CRC16校验码,可以采用查表法来加速处理过程。这种方法预先计算好所有可能的输入数据对应的CRC值,并存储在一个表格中。当实际数据到来时,只需查询该表即可快速获得结果。 #### 查表法的工作原理 查表法的核心在于构建一张预定义好的CRC查找表。对于每一个可能的数据字节(共256种可能性),提前计算其对应的CRC值并存入表中。这样,在运行过程中只需要根据当前处理的数据字节索引到这张表里找到相应的CRC值,再按照一定的规则更新累计的CRC寄存器中的值[^2]。 #### Verilog代码示例 下面是一个简单的基于查表法的CRC16 (CCITT_FALSE) 计算模块: ```verilog module crc16_lookup ( input wire clk, input wire rst_n, // Active low reset input wire start, // Start signal to initiate CRC calculation input wire [7:0] data_in,// Input byte stream output reg ready, // Indicates when the result is valid output reg [15:0] crc_out// Output CRC value ); parameter TABLE_SIZE = 256; reg [15:0] crc_table[TABLE_SIZE-1:0]; // Precomputed table of CRC values for all possible bytes initial begin : init_crc_table integer i; for(i=0; i<TABLE_SIZE; i=i+1) begin crc_table[i] = calc_crc_for_byte(16'hFFFF,i); // Initialize with CCITT FALSE polynomial and initial seed FFFF end end function automatic [15:0] calc_crc_for_byte(input [15:0] crc, input [7:0] b); integer j; bit [15:0] cur_crc = crc ^ ({8{b[7]}},b[6:0]); for(j=0;j<8;j=j+1)begin if(cur_crc[0])cur_crc=(cur_crc>>1)^16'h1021; else cur_crc=cur_crc>>1; b=b<<1; end return cur_crc; endfunction integer state; localparam IDLE = 0, PROCESSING = 1; always @(posedge clk or negedge rst_n) begin if(!rst_n) begin state <= IDLE; crc_out <= 16'b0; ready <= 1'b0; end else case(state) IDLE:if(start)begin state<=PROCESSING; crc_out<=crc_table[data_in]; ready<=1'b0; end PROCESSING:begin crc_out<=crc_table[crc_out^data_in]; if(/* condition indicating last byte */)begin state<=IDLE; ready<=1'b1; end end endcase end endmodule ``` 此代码片段展示了如何创建一个用于CRC16计算的状态机,它会在接收到`start`信号后开始工作,并依次读取每个传入的数据字节(`data_in`),通过查找已初始化好的CRC表来逐步累积最终的结果(`crc_out`)。一旦完成了所有的数据处理,则设置`ready`标志位通知外部系统结果已经准备好。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值