文章部分转自https://blog.csdn.net/yongan1006/article/details/8716456
LFSR主要用于通信加扰解扰;CRC主要用于通信传输数据校验。
一 、LFSR
线性反馈移位寄存器(LFSR)是内测试电路中最基本的标准模块结构,既用作伪随机测试码产生器,也作为压缩测试结果数据的特征分析器。
一个n阶的LFSR由n个触发器和若干个异或门组成。在实际应用当中,主要用到两种类型的LFSR,即异或门外接线性反馈移位寄存器(IE型LFSR,图1)和异或门内接线性反馈移位寄存器(EE型LFSR,图2)。其中g0 g1g2 gn为’0’或’1’,Q1 Q2Q3 Qn为LFSR的输出,M(x)是输入的码字多项式,如M(x)=x4+ x1+1,表示输入端的输入顺序为11001,同样,LFSR的结构也可以表示为多项式G(x),称为生成多项式:
G(x)=gn*xn+ …+g1*x1+g0;
图1 IE型LFSR
图2 EE型LFSR
需要注意的是一位寄存器的初始值不能为全0;
二 、CRC
循环冗余校验码(CRC)的基本原理是:在K位信息码后再拼接R位的校验码,整个编码长度为N位,因此,这种编码又叫(N,K)码。对于一个给定的(N,K)码,可以证明存在一个最高次幂为N-K=R的多项式G(x)可以使整个编码被除余数为0。根据G(x)可以生成K位信息的校验码,而G(x)叫做这个CRC码的生成多项式。校验码的具体生成过程为:假设发送信息用信息多项式C(X)表示,将C(x)左移R位,则可表示成C(x)*2的R次方,这样C(x)的右边就会空出R位,这就是校验码的位置。通过C(x)*2的R次方除以生成多项式G(x)得到的余数就是校验码。
通过CRC的生成原理知道CRC的检验码生成是通过除法得到,由此联想到可以通过LFSR来产生校验码。
假设原信息码子多项式为
生成多项式为
那么CRC的码字为 ,使用用LFSR电路来进行实现,将M(x)向左移r位在电路中的意义即为输入完信息码后再输入r个0,所以在电路上的表现就如图5所示。
图5 使用LFSR来产生CRE校验码
需要注意的是移位寄存器的初始值不同结果是不一致的。
三、并行实现CRC校验
上面介绍的CRC校验主要是用于单比特流的校验,但是很多实际应用中位宽很大的一组数据需要做CRC校验的情况时以上一位寄存器是不能实现的。例如M位宽的并行数据,我们可以根据移位前的N位寄存器值和M位并行数据的位宽数据做逻辑运算计算出(N+1)阶的CRC值。
代码生成工具网站:https://www.easics.be/webtools/crctool
此网站可以生成Verilog和VHDL的逻辑代码,如果是时序电路把逻辑电路可以修改成时序电路。
生成代码的“Data”是每次输入位宽的数据;“CRC”是初始CRC值和上次生成的CRC。
例如:生成多项式是x^16+x^15+x^2+1,初始值为全1;
生成代码为
////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 1999-2008 Easics NV.
// This source file may be used and distributed without restriction
// provided that this copyright statement is not removed from the file
// and that any derivative work contains the original copyright notice
// and the associated disclaimer.
//
// THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS
// OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
// WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// Purpose : synthesizable CRC function
// * polynomial: x^16 + x^15 + x^2 + 1
// * data width: 16
//
// Info : [email protected]
// http://www.easics.com
////////////////////////////////////////////////////////////////////////////////
module CRC16_D16;
// polynomial: x^16 + x^15 + x^2 + 1
// data width: 16
// convention: the first serial bit is D[15]
function [15:0] nextCRC16_D16;
input [15:0] Data;
input [15:0] crc;
reg [15:0] d;
reg [15:0] c;
reg [15:0] newcrc;
begin
d = Data;
c = crc;
newcrc[0] = d[15] ^ d[13] ^ d[12] ^ d[11] ^ d[10] ^ d[9] ^ d[8] ^ d[7] ^ d[6] ^ d[5] ^ d[4] ^ d[3] ^ d[2] ^ d[1] ^ d[0] ^ c[0] ^ c[1] ^ c[2] ^ c[3] ^ c[4] ^ c[5] ^ c[6] ^ c[7] ^ c[8] ^ c[9] ^ c[10] ^ c[11] ^ c[12] ^ c[13] ^ c[15];
newcrc[1] = d[14] ^ d[13] ^ d[12] ^ d[11] ^ d[10] ^ d[9] ^ d[8] ^ d[7] ^ d[6] ^ d[5] ^ d[4] ^ d[3] ^ d[2] ^ d[1] ^ c[1] ^ c[2] ^ c[3] ^ c[4] ^ c[5] ^ c[6] ^ c[7] ^ c[8] ^ c[9] ^ c[10] ^ c[11] ^ c[12] ^ c[13] ^ c[14];
newcrc[2] = d[14] ^ d[1] ^ d[0] ^ c[0] ^ c[1] ^ c[14];
newcrc[3] = d[15] ^ d[2] ^ d[1] ^ c[1] ^ c[2] ^ c[15];
newcrc[4] = d[3] ^ d[2] ^ c[2] ^ c[3];
newcrc[5] = d[4] ^ d[3] ^ c[3] ^ c[4];
newcrc[6] = d[5] ^ d[4] ^ c[4] ^ c[5];
newcrc[7] = d[6] ^ d[5] ^ c[5] ^ c[6];
newcrc[8] = d[7] ^ d[6] ^ c[6] ^ c[7];
newcrc[9] = d[8] ^ d[7] ^ c[7] ^ c[8];
newcrc[10] = d[9] ^ d[8] ^ c[8] ^ c[9];
newcrc[11] = d[10] ^ d[9] ^ c[9] ^ c[10];
newcrc[12] = d[11] ^ d[10] ^ c[10] ^ c[11];
newcrc[13] = d[12] ^ d[11] ^ c[11] ^ c[12];
newcrc[14] = d[13] ^ d[12] ^ c[12] ^ c[13];
newcrc[15] = d[15] ^ d[14] ^ d[12] ^ d[11] ^ d[10] ^ d[9] ^ d[8] ^ d[7] ^ d[6] ^ d[5] ^ d[4] ^ d[3] ^ d[2] ^ d[1] ^ d[0] ^ c[0] ^ c[1] ^ c[2] ^ c[3] ^ c[4] ^ c[5] ^ c[6] ^ c[7] ^ c[8] ^ c[9] ^ c[10] ^ c[11] ^ c[12] ^ c[14] ^ c[15];
nextCRC16_D16 = newcrc;
end
endfunction
endmodule
仅供参考的时序电路为:
module CRC_16(
input clk,
input reset,
input sync,
input [15:0] Data,
output [15:0] newcrc
);
reg [15:0] d;
// wire [15:0] newcrc;
reg [15:0] c;
reg r_sync;
always@(posedge clk)
r_sync<=sync;
always@(posedge clk or posedge reset) begin
if(reset) begin
d<=16'd0;
c<=16'd0;
end
else if(sync) begin
d<=16'd0;
c<=16'd0;
end
else if(r_sync) begin
d <= Data;
c <= 16'hFFFF;
end
else begin
d <= Data;
c <= newcrc;
end
end
assign newcrc[0] = d[15] ^ d[13] ^ d[12] ^ d[11] ^ d[10] ^ d[9] ^ d[8] ^ d[7] ^ d[6] ^ d[5] ^ d[4] ^ d[3] ^ d[2] ^ d[1] ^ d[0] ^ c[0] ^ c[1] ^ c[2] ^ c[3] ^ c[4] ^ c[5] ^ c[6] ^ c[7] ^ c[8] ^ c[9] ^ c[10] ^ c[11] ^ c[12] ^ c[13] ^ c[15];
assign newcrc[1] = d[14] ^ d[13] ^ d[12] ^ d[11] ^ d[10] ^ d[9] ^ d[8] ^ d[7] ^ d[6] ^ d[5] ^ d[4] ^ d[3] ^ d[2] ^ d[1] ^ c[1] ^ c[2] ^ c[3] ^ c[4] ^ c[5] ^ c[6] ^ c[7] ^ c[8] ^ c[9] ^ c[10] ^ c[11] ^ c[12] ^ c[13] ^ c[14];
assign newcrc[2] = d[14] ^ d[1] ^ d[0] ^ c[0] ^ c[1] ^ c[14];
assign newcrc[3] = d[15] ^ d[2] ^ d[1] ^ c[1] ^ c[2] ^ c[15];
assign newcrc[4] = d[3] ^ d[2] ^ c[2] ^ c[3];
assign newcrc[5] = d[4] ^ d[3] ^ c[3] ^ c[4];
assign newcrc[6] = d[5] ^ d[4] ^ c[4] ^ c[5];
assign newcrc[7] = d[6] ^ d[5] ^ c[5] ^ c[6];
assign newcrc[8] = d[7] ^ d[6] ^ c[6] ^ c[7];
assign newcrc[9] = d[8] ^ d[7] ^ c[7] ^ c[8];
assign newcrc[10] = d[9] ^ d[8] ^ c[8] ^ c[9];
assign newcrc[11] = d[10] ^ d[9] ^ c[9] ^ c[10];
assign newcrc[12] = d[11] ^ d[10] ^ c[10] ^ c[11];
assign newcrc[13] = d[12] ^ d[11] ^ c[11] ^ c[12];
assign newcrc[14] = d[13] ^ d[12] ^ c[12] ^ c[13];
assign newcrc[15] = d[15] ^ d[14] ^ d[12] ^ d[11] ^ d[10] ^ d[9] ^ d[8] ^ d[7] ^ d[6] ^ d[5] ^ d[4] ^ d[3] ^ d[2] ^ d[1] ^ d[0] ^ c[0] ^ c[1] ^ c[2] ^ c[3] ^ c[4] ^ c[5] ^ c[6] ^ c[7] ^ c[8] ^ c[9] ^ c[10] ^ c[11] ^ c[12] ^ c[14] ^ c[15];
endmodule
testbench
module tb_crc_16;
// Inputs
reg clk;
reg reset;
reg sync;
reg [15:0] Data;
// Outputs
wire [15:0] c;
// Instantiate the Unit Under Test (UUT)
CRC_16 uut (
.clk(clk),
.reset(reset),
.sync(sync),
.Data(Data),
.newcrc(c)
);
initial begin
clk=0;
forever #5 clk=~clk;
end
initial begin
reset=1;
#30 reset=0;
end
initial begin
sync=1;
#50 sync=0;
end
initial begin
#50 Data<=16'h3132;
#10 Data<=16'h3334;
end
endmodule
在CRC在线计算器网站http://www.ip33.com/crc.html 设置如下,验证结果: