基于Verilog的CRC-CCITT校验

Posted blueszone

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于Verilog的CRC-CCITT校验相关的知识,希望对你有一定的参考价值。

由于笔者在自己设计CRC模块时遇到很多问题,在网上并未找到一篇具有实际指导意义的文章,在经过多次仿真修改再仿真之后得到了正确的结果,故愿意在本文中为大家提供整个设计流程供大家快速完成设计。本文章主要针对具体的实际应用给出一套亲测可行的实现办法,给出设计代码并提供仿真结果,供各位参考。

一.CRC概述
CRC(Cyclic Redundancy Check),循环冗余校验,是一种数字通信中的常用查错校验码。其特征是信息段和校验字段的长度可以任意选定。
校验方法为发送方对信息数据执行约定好除数的二进制除法计算,并将得到的余数附在帧的后面,发送给接收方;接收方也执行类似的算法,两侧对比结果的余数,相同则说明接收信息完整且正确,以保证数据传输的正确性和完整性。
具体来讲,在K位信息码后再拼接R位的校验码,整个编码长度为N(=K+R)位,因此,这种编码也叫(N,K)码。对于一个给定的(N,K)码,可以证明存在一个最高次幂为N-K=R的多项式G(x)。根据G(x)可以生成K位信息的校验码,而G(x)叫做这个CRC码的生成多项式。
校验码的具体生成过程为:假设要发送的信息用多项式C(X)表示,将C(x)左移R位(可表示成C(x)2R),这样C(x)的右边就会空出R位,这就是校验码的位置。用 C(x)2R 除以生成多项式G(x)得到的余数就是校验码FCS(Frame Check Series)。
 任意一个由二进制位串组成的代码都可以和一个系数仅为‘0’和‘1’取值的多项式一一对应。例如:代码1010111对应的多项式为x6+x4+x2+x+1,而多项式为x5+x3+x2+x+1对应的代码101111。
CRC校验根据所采用的生成多项式不同分为很多不同的标准,常见的有:
名称 生成多项式 简记式 应用举例

CRC-4 x4+x+1 3 ITU G.704

CRC-8 x8+x5+x4+1 31 DS18B20
CRC-12 x12+x11+x3+x2+x+1 0x80F
CRC-16 x16+x15+x2+1 0x8005 IBM SDLC
CRC-ITU(CCITT) x16+x12+x5+1 0x1021 ISO HDLC, ITU
CRC-32 x32+x26+x23+...+x2+x+1 0x04C11DB7 ZIP, RAR
CRC-32c x32+x28+x27+...+x8+x6+1 0x1EDC6F41 SCTP
说明:简记式最高位应为1,此处都省略了;

二.实现方法
本文章所要讲的标准为CRC-ITU(CCITT-Xmodem),即生成多项式为0x1021
0x1021 = 0x11021 = 1,0001,0000,0010,0001

在此提供一个在线计算CRC校验网站,方便进行验证
https://www.lammertbies.nl/comm/info/crc-calculation.html

源代码根据需求在源码网站进行生成,后根据自己的需求进行修改,仿真验证;
现提供生成源码的步骤:
STEP1: http://outputlogic.com/?page_id=321
STEP2: 根据实际需求选择输入数据位宽和输出校验码位宽,CRC校验标准为自定义或者可选的几种;
技术分享图片
STEP3: 若选择User defined,则进入第二页选择自定义的多项式,本仿真采用CCITT标准,即生成多项式为x16+x12+x5+1,此处只需要选中1,x5,x12即可,因为x16为1是默认的;
技术分享图片
STEP4: 对生成的Verilog或者VHDL语言代码进行修改,应用到实际当中;

三.实际应用仿真
现基于笔者实际应用场景进行一个具体的CRC校验设计与仿真,其中,always 模块里的CRC校验计算过程不需要理解,若需要理解,可以下载该网站给出的文章(下载代码会附)
A Practical Parallel CRC Generation Method
常用的CRC校验方法有直接计算二进制除法,查表法,具体计算原理见下链接
https://blog.csdn.net/xing414736597/article/details/78693781
代码如下:

module CRC(
input clk,//输入时钟
input reset,//总体复位信号
input crc_en,//选择是否进行下一步CRC运算
input [63:0] data_in,//输入数据为64位
output [15:0] crc_out//输出数据即CRC校验结果为16位
);
reg [15:0] lfsr_q,lfsr_c;
wire reset;
assign crc_out = lfsr_c;

always @(*) begin
lfsr_c[0] = lfsr_q[0] ^ lfsr_q[1] ^ lfsr_q[3] ^ lfsr_q[4] ^ lfsr_q[7] ^ lfsr_q[8] ^ lfsr_q[10] ^ lfsr_q[15] ^ data_in[0] ^ data_in[4] ^ data_in[8] ^ data_in[11] ^ data_in[12] ^ data_in[19] ^ data_in[20] ^ data_in[22] ^ data_in[26] ^ data_in[27] ^ data_in[28] ^ data_in[32] ^ data_in[33] ^ data_in[35] ^ data_in[42] ^ data_in[48] ^ data_in[49] ^ data_in[51] ^ data_in[52] ^ data_in[55] ^ data_in[56] ^ data_in[58] ^ data_in[63];
lfsr_c[1] = lfsr_q[1] ^ lfsr_q[2] ^ lfsr_q[4] ^ lfsr_q[5] ^ lfsr_q[8] ^ lfsr_q[9] ^ lfsr_q[11] ^ data_in[1] ^ data_in[5] ^ data_in[9] ^ data_in[12] ^ data_in[13] ^ data_in[20] ^ data_in[21] ^ data_in[23] ^ data_in[27] ^ data_in[28] ^ data_in[29] ^ data_in[33] ^ data_in[34] ^ data_in[36] ^ data_in[43] ^ data_in[49] ^ data_in[50] ^ data_in[52] ^ data_in[53] ^ data_in[56] ^ data_in[57] ^ data_in[59];
lfsr_c[2] = lfsr_q[2] ^ lfsr_q[3] ^ lfsr_q[5] ^ lfsr_q[6] ^ lfsr_q[9] ^ lfsr_q[10] ^ lfsr_q[12] ^ data_in[2] ^ data_in[6] ^ data_in[10] ^ data_in[13] ^ data_in[14] ^ data_in[21] ^ data_in[22] ^ data_in[24] ^ data_in[28] ^ data_in[29] ^ data_in[30] ^ data_in[34] ^ data_in[35] ^ data_in[37] ^ data_in[44] ^ data_in[50] ^ data_in[51] ^ data_in[53] ^ data_in[54] ^ data_in[57] ^ data_in[58] ^ data_in[60];
lfsr_c[3] = lfsr_q[3] ^ lfsr_q[4] ^ lfsr_q[6] ^ lfsr_q[7] ^ lfsr_q[10] ^ lfsr_q[11] ^ lfsr_q[13] ^ data_in[3] ^ data_in[7] ^ data_in[11] ^ data_in[14] ^ data_in[15] ^ data_in[22] ^ data_in[23] ^ data_in[25] ^ data_in[29] ^ data_in[30] ^ data_in[31] ^ data_in[35] ^ data_in[36] ^ data_in[38] ^ data_in[45] ^ data_in[51] ^ data_in[52] ^ data_in[54] ^ data_in[55] ^ data_in[58] ^ data_in[59] ^ data_in[61];
lfsr_c[4] = lfsr_q[4] ^ lfsr_q[5] ^ lfsr_q[7] ^ lfsr_q[8] ^ lfsr_q[11] ^ lfsr_q[12] ^ lfsr_q[14] ^ data_in[4] ^ data_in[8] ^ data_in[12] ^ data_in[15] ^ data_in[16] ^ data_in[23] ^ data_in[24] ^ data_in[26] ^ data_in[30] ^ data_in[31] ^ data_in[32] ^ data_in[36] ^ data_in[37] ^ data_in[39] ^ data_in[46] ^ data_in[52] ^ data_in[53] ^ data_in[55] ^ data_in[56] ^ data_in[59] ^ data_in[60] ^ data_in[62];
lfsr_c[5] = lfsr_q[0] ^ lfsr_q[1] ^ lfsr_q[3] ^ lfsr_q[4] ^ lfsr_q[5] ^ lfsr_q[6] ^ lfsr_q[7] ^ lfsr_q[9] ^ lfsr_q[10] ^ lfsr_q[12] ^ lfsr_q[13] ^ data_in[0] ^ data_in[4] ^ data_in[5] ^ data_in[8] ^ data_in[9] ^ data_in[11] ^ data_in[12] ^ data_in[13] ^ data_in[16] ^ data_in[17] ^ data_in[19] ^ data_in[20] ^ data_in[22] ^ data_in[24] ^ data_in[25] ^ data_in[26] ^ data_in[28] ^ data_in[31] ^ data_in[35] ^ data_in[37] ^ data_in[38] ^ data_in[40] ^ data_in[42] ^ data_in[47] ^ data_in[48] ^ data_in[49] ^ data_in[51] ^ data_in[52] ^ data_in[53] ^ data_in[54] ^ data_in[55] ^ data_in[57] ^ data_in[58] ^ data_in[60] ^ data_in[61];
lfsr_c[6] = lfsr_q[0] ^ lfsr_q[1] ^ lfsr_q[2] ^ lfsr_q[4] ^ lfsr_q[5] ^ lfsr_q[6] ^ lfsr_q[7] ^ lfsr_q[8] ^ lfsr_q[10] ^ lfsr_q[11] ^ lfsr_q[13] ^ lfsr_q[14] ^ data_in[1] ^ data_in[5] ^ data_in[6] ^ data_in[9] ^ data_in[10] ^ data_in[12] ^ data_in[13] ^ data_in[14] ^ data_in[17] ^ data_in[18] ^ data_in[20] ^ data_in[21] ^ data_in[23] ^ data_in[25] ^ data_in[26] ^ data_in[27] ^ data_in[29] ^ data_in[32] ^ data_in[36] ^ data_in[38] ^ data_in[39] ^ data_in[41] ^ data_in[43] ^ data_in[48] ^ data_in[49] ^ data_in[50] ^ data_in[52] ^ data_in[53] ^ data_in[54] ^ data_in[55] ^ data_in[56] ^ data_in[58] ^ data_in[59] ^ data_in[61] ^ data_in[62];
lfsr_c[7] = lfsr_q[1] ^ lfsr_q[2] ^ lfsr_q[3] ^ lfsr_q[5] ^ lfsr_q[6] ^ lfsr_q[7] ^ lfsr_q[8] ^ lfsr_q[9] ^ lfsr_q[11] ^ lfsr_q[12] ^ lfsr_q[14] ^ lfsr_q[15] ^ data_in[2] ^ data_in[6] ^ data_in[7] ^ data_in[10] ^ data_in[11] ^ data_in[13] ^ data_in[14] ^ data_in[15] ^ data_in[18] ^ data_in[19] ^ data_in[21] ^ data_in[22] ^ data_in[24] ^ data_in[26] ^ data_in[27] ^ data_in[28] ^ data_in[30] ^ data_in[33] ^ data_in[37] ^ data_in[39] ^ data_in[40] ^ data_in[42] ^ data_in[44] ^ data_in[49] ^ data_in[50] ^ data_in[51] ^ data_in[53] ^ data_in[54] ^ data_in[55] ^ data_in[56] ^ data_in[57] ^ data_in[59] ^ data_in[60] ^ data_in[62] ^ data_in[63];
lfsr_c[8] = lfsr_q[2] ^ lfsr_q[3] ^ lfsr_q[4] ^ lfsr_q[6] ^ lfsr_q[7] ^ lfsr_q[8] ^ lfsr_q[9] ^ lfsr_q[10] ^ lfsr_q[12] ^ lfsr_q[13] ^ lfsr_q[15] ^ data_in[3] ^ data_in[7] ^ data_in[8] ^ data_in[11] ^ data_in[12] ^ data_in[14] ^ data_in[15] ^ data_in[16] ^ data_in[19] ^ data_in[20] ^ data_in[22] ^ data_in[23] ^ data_in[25] ^ data_in[27] ^ data_in[28] ^ data_in[29] ^ data_in[31] ^ data_in[34] ^ data_in[38] ^ data_in[40] ^ data_in[41] ^ data_in[43] ^ data_in[45] ^ data_in[50] ^ data_in[51] ^ data_in[52] ^ data_in[54] ^ data_in[55] ^ data_in[56] ^ data_in[57] ^ data_in[58] ^ data_in[60] ^ data_in[61] ^ data_in[63];
lfsr_c[9] = lfsr_q[3] ^ lfsr_q[4] ^ lfsr_q[5] ^ lfsr_q[7] ^ lfsr_q[8] ^ lfsr_q[9] ^ lfsr_q[10] ^ lfsr_q[11] ^ lfsr_q[13] ^ lfsr_q[14] ^ data_in[4] ^ data_in[8] ^ data_in[9] ^ data_in[12] ^ data_in[13] ^ data_in[15] ^ data_in[16] ^ data_in[17] ^ data_in[20] ^ data_in[21] ^ data_in[23] ^ data_in[24] ^ data_in[26] ^ data_in[28] ^ data_in[29] ^ data_in[30] ^ data_in[32] ^ data_in[35] ^ data_in[39] ^ data_in[41] ^ data_in[42] ^ data_in[44] ^ data_in[46] ^ data_in[51] ^ data_in[52] ^ data_in[53] ^ data_in[55] ^ data_in[56] ^ data_in[57] ^ data_in[58] ^ data_in[59] ^ data_in[61] ^ data_in[62];
lfsr_c[10] = lfsr_q[4] ^ lfsr_q[5] ^ lfsr_q[6] ^ lfsr_q[8] ^ lfsr_q[9] ^ lfsr_q[10] ^ lfsr_q[11] ^ lfsr_q[12] ^ lfsr_q[14] ^ lfsr_q[15] ^ data_in[5] ^ data_in[9] ^ data_in[10] ^ data_in[13] ^ data_in[14] ^ data_in[16] ^ data_in[17] ^ data_in[18] ^ data_in[21] ^ data_in[22] ^ data_in[24] ^ data_in[25] ^ data_in[27] ^ data_in[29] ^ data_in[30] ^ data_in[31] ^ data_in[33] ^ data_in[36] ^ data_in[40] ^ data_in[42] ^ data_in[43] ^ data_in[45] ^ data_in[47] ^ data_in[52] ^ data_in[53] ^ data_in[54] ^ data_in[56] ^ data_in[57] ^ data_in[58] ^ data_in[59] ^ data_in[60] ^ data_in[62] ^ data_in[63];
lfsr_c[11] = lfsr_q[0] ^ lfsr_q[5] ^ lfsr_q[6] ^ lfsr_q[7] ^ lfsr_q[9] ^ lfsr_q[10] ^ lfsr_q[11] ^ lfsr_q[12] ^ lfsr_q[13] ^ lfsr_q[15] ^ data_in[6] ^ data_in[10] ^ data_in[11] ^ data_in[14] ^ data_in[15] ^ data_in[17] ^ data_in[18] ^ data_in[19] ^ data_in[22] ^ data_in[23] ^ data_in[25] ^ data_in[26] ^ data_in[28] ^ data_in[30] ^ data_in[31] ^ data_in[32] ^ data_in[34] ^ data_in[37] ^ data_in[41] ^ data_in[43] ^ data_in[44] ^ data_in[46] ^ data_in[48] ^ data_in[53] ^ data_in[54] ^ data_in[55] ^ data_in[57] ^ data_in[58] ^ data_in[59] ^ data_in[60] ^ data_in[61] ^ data_in[63];
lfsr_c[12] = lfsr_q[0] ^ lfsr_q[3] ^ lfsr_q[4] ^ lfsr_q[6] ^ lfsr_q[11] ^ lfsr_q[12] ^ lfsr_q[13] ^ lfsr_q[14] ^ lfsr_q[15] ^ data_in[0] ^ data_in[4] ^ data_in[7] ^ data_in[8] ^ data_in[15] ^ data_in[16] ^ data_in[18] ^ data_in[22] ^ data_in[23] ^ data_in[24] ^ data_in[28] ^ data_in[29] ^ data_in[31] ^ data_in[38] ^ data_in[44] ^ data_in[45] ^ data_in[47] ^ data_in[48] ^ data_in[51] ^ data_in[52] ^ data_in[54] ^ data_in[59] ^ data_in[60] ^ data_in[61] ^ data_in[62] ^ data_in[63];
lfsr_c[13] = lfsr_q[0] ^ lfsr_q[1] ^ lfsr_q[4] ^ lfsr_q[5] ^ lfsr_q[7] ^ lfsr_q[12] ^ lfsr_q[13] ^ lfsr_q[14] ^ lfsr_q[15] ^ data_in[1] ^ data_in[5] ^ data_in[8] ^ data_in[9] ^ data_in[16] ^ data_in[17] ^ data_in[19] ^ data_in[23] ^ data_in[24] ^ data_in[25] ^ data_in[29] ^ data_in[30] ^ data_in[32] ^ data_in[39] ^ data_in[45] ^ data_in[46] ^ data_in[48] ^ data_in[49] ^ data_in[52] ^ data_in[53] ^ data_in[55] ^ data_in[60] ^ data_in[61] ^ data_in[62] ^ data_in[63];
lfsr_c[14] = lfsr_q[1] ^ lfsr_q[2] ^ lfsr_q[5] ^ lfsr_q[6] ^ lfsr_q[8] ^ lfsr_q[13] ^ lfsr_q[14] ^ lfsr_q[15] ^ data_in[2] ^ data_in[6] ^ data_in[9] ^ data_in[10] ^ data_in[17] ^ data_in[18] ^ data_in[20] ^ data_in[24] ^ data_in[25] ^ data_in[26] ^ data_in[30] ^ data_in[31] ^ data_in[33] ^ data_in[40] ^ data_in[46] ^ data_in[47] ^ data_in[49] ^ data_in[50] ^ data_in[53] ^ data_in[54] ^ data_in[56] ^ data_in[61] ^ data_in[62] ^ data_in[63];
lfsr_c[15] = lfsr_q[0] ^ lfsr_q[2] ^ lfsr_q[3] ^ lfsr_q[6] ^ lfsr_q[7] ^ lfsr_q[9] ^ lfsr_q[14] ^ lfsr_q[15] ^ data_in[3] ^ data_in[7] ^ data_in[10] ^ data_in[11] ^ data_in[18] ^ data_in[19] ^ data_in[21] ^ data_in[25] ^ data_in[26] ^ data_in[27] ^ data_in[31] ^ data_in[32] ^ data_in[34] ^ data_in[41] ^ data_in[47] ^ data_in[48] ^ data_in[50] ^ data_in[51] ^ data_in[54] ^ data_in[55] ^ data_in[57] ^ data_in[62] ^ data_in[63];
end
//此段代码为CRC具体的计算过程,基于LFSR(线性反馈移位寄存器);

always @(posedge clk, negedge reset) begin
if(!reset) begin
lfsr_q <= {16{1‘b0}}; //CCITT_XModem初始值为16‘h0;其他协议根据具体情况修改;
end
else begin
lfsr_q <= crc_en ? lfsr_c : lfsr_q;//此处crc_en设为0,只计算一次即输出CRC校验结果,否则会持续不断进行运算
end
end
endmodule

编写testbench文件对该模块进行仿真:

module crc_simul;
reg [63:0] data_in;
reg crc_en;
reg reset;
reg clk;
wire [15:0] crc_out;
crc uut(
.data_in(data_in),
.crc_en(crc_en),
.crc_out(crc_out),
.reset(reset),
.clk(clk)
);
initial begin
data_in = 64‘d0;
crc_en = 1‘b0;
reset=1‘b0;
clk = 1‘b0;
#9;
reset=1‘b1;
#200;
data_in = {8‘hFF,8‘hFF,8‘hAA,8‘h55,8‘h00,8‘h01,16‘h13EC};//结果应为3DC3;
#500;
data_in = {8‘hFF,8‘hFF,8‘hAA,8‘h55,8‘h00,8‘h01,16‘h01F4};//结果应为CBEB;
end

always #1 clk = ~clk;
endmodule

仿真结果如下
技术分享图片

可以验证,仿真结果正确,在实际应用中也可以正确运行;


























































































以上是关于基于Verilog的CRC-CCITT校验的主要内容,如果未能解决你的问题,请参考以下文章

[从零开始学习FPGA编程-28]:进阶篇 - 基本组合电路-奇偶校验生成器(Verilog语言版本)

数字IC入门之一(Verilog)

CRC-CCITT 16 位 Python 手动计算

你知道Verilog HDL程序是如何构成的吗

求VHDL的查表法计算16位CRC-CCITT 。

基于verilog的四位全加器设计