在线crc代码代码生成:http://outputlogic.com/
该网站提供的crc并行算法原理:http://outputlogic.com/?p=158
假设crc位宽为N,即生成多项式的最高次幂为N;假设并行数据D宽度为M。
crc并行计算可粗略的表述为(实际所有都是异或):
重点在与得到 crc系数矩阵A 和 Data系数矩阵B。
特别说明:系数矩阵中元素为1表示该项参与异或,为0表示不参与异或(任何数据与自身异或都为零),为偶数同理(因此可取模2简化表述)。
根据生成多项式G(x)构造系数N×N方阵F
其中E为N-1维单位阵。
以生成多项式为G=x5+x2+1的crc-5为例,G可表示为100101,省去最高项为00101,则F为:
求F的M次方FM(方阵乘法)再取模二,所得即为并行代码中的crc系数。
以N=5为例,矩阵与系数的对应关系如下:
也可以先对结果旋转,使C的序号和矩阵脚标序号对应,下图表示的是最初始的方阵乘法结果
求F的N次方FN(方阵乘法)再取模二,所得即为并行代码中的data系数。不过该系数中只有后面几列用得上,后续细说。
如果仔细观察F的结构会发现每多乘一次,上一次获得的列就往后移一次。因此事实上:
F(:,0)就是D[0]列的系数;
F2(:,0)是D[1]列的系数,F2(:,1)是D[0]的系数;
F3(:,0)是D[2]列的系数,F3(:,1)是D[1]的系数,F3(:,2)是D[0]的系数;
以此类推。
将Step2和Step3的C系数和D系数整合,所有的数值都相异或。
写个matlab函数用于获取两个系数矩阵,如下:
function [b1,b3] = CrcCoefByCC(N,G)
% N; %数据位宽
% G; %生成多项式
M=size(G,2); %生成多项式位宽(最高次)
%% 构造F
F=zeros(M,M);
for i=1:M-1
F(i,i+1)=1;
end
F(:,1)=G;
%% Cin系数
b1=mod(F^N,2);
%% D系数
x=ceil(N/M); %向上取整
b2=zeros(M,M*x); %D系数初值[ F^(xM) , ... , F^(2M) , F^M ]
for i=1:x
b2(:,(x-i)*M+1:(x-i+1)*M)=mod(F^(i*M),2);
end
b3=b2(:,M*x-N+1:M*x); %D系数:取后N列,与D位宽N对应
%% D系数另一种算法:每次取第一列
for i=1:N
bb=mod(F^i,2);
b4(:,N-i+1)=tcc(:,1);
end
end
以 http://outputlogic.com/ 网址中生成的代码为准进行验证。
%% 旋转,小序号在前、在上
b1=rot90(rot90(b1));
b3=rot90(rot90(b3));
2. crc5= x5+x2+1,data width = 13:
包括输入翻转、预设初值、输出翻转,这些都是可选项,可增强算法的检错能力。
参看crc caculator中的设置:
是指将输入值在字节内进行bit反转(换序),同时字节间保持原序。
进行输入反转时,仅影响Data的系数,有两种方法完成此操作。
在对Data的系数计算完成后,对结果里面的Data系数翻转。
在Data被使用前,进行字节内的bit位置反转操作。
以输入为16bit为例:
assign data1={din[8],din[9],din[10],din[11],din[12],din[13],din[14],din[15],din[0],din[1],din[2],din[3],din[4],din[5],din[6],din[7]};
即在进行第一次crc运算前,预先设定Cin项初值,默认情况下为全零,如802.3中使用的crc32的预设初值为32’hFFFFFFFF。
在输出至端口时,对计算得到的crc进行全bit位的换序和取反。
以crc-16为例:
assign crc_out = ~ { crc_new[0], crc_new[1], crc_new[2], crc_new[3], crc_new[4], crc_new[5], crc_new[6], crc_new[7],
crc_new[8], crc_new[9], crc_new[10], crc_new[11], crc_new[12], crc_new[13], crc_new[14], crc_new[15]};
再改改,添加格式输出,将生成多项式输入方式改为Hex。
需要注意的是生成多项式的最高位因为必然为1,因此常常被省略,如crc5=1+x2+x5,最高次为5,也就是共6位(即100101),但通常都省略掉最高位,记为00101。
function [crc_str_mid,crc_str_rlt] = CrcCoefByCC(N,FI,datain,G,M,crcin,FO,XOR)
% N;数据位宽
% M:生成多项式位宽(不包含最高项)
% G:生成多项式(省略最高项)
% FI:1,输入翻转(字节内)
% FO:1,输出取反且翻转
% crc_str_mid:中间输出,与输出选项FO无关,用于下轮计算
% crc_str_out:结果输出,与输出选项FO有关
% N=8;M=32;G='04c11db7';FI=0;FO=0;XOR=0;
% datain='b';
% crcin='5C86227B';%12的中间结果
cc = str2num(reshape(dec2bin(hex2dec(G),M),M,1)); %高位在前
crcin = str2num(reshape(dec2bin(hex2dec(crcin),M),M,1)); %高位在前
datain = str2num(reshape(dec2bin(hex2dec(datain),N),N,1)); %高位在前 十六进制
% datain = str2num(reshape(dec2bin(datain,N),N,1)); %高位在前 十进制
%% 构造F
F=zeros(M,M);
for i=1:M-1
F(i,i+1)=1;
end
F(:,1)=cc;
%% Cin系数
ct=mod(F^N,2);
%% D系数
% % D系数计算方法一:一次性计算M列
% x=ceil(N/M); %向上取整
% b2=zeros(M,M*x); %D系数初值[ F^(xM) , ... , F^(2M) , F^M ]
% for i=1:x
% b2(:,(x-i)*M+1:(x-i+1)*M)=mod(F^(i*M),2);
% end
% tc1=zeros(M,N);
% tc1=b2(:,M*x-N+1:M*x); %D系数:取后N列,对应D位宽N
% D系数另一种算法:每次取一列
tc2=zeros(M,N);
for i=1:N
tcc=mod(F^i,2);
tc2(:,N-i+1)=tcc(:,1);
end
%% crc计算
% datain必须为字节单位,不够则高位自动补零
x=ct*crcin;
if FI==1
datain=flipud(datain); % 输入上下翻转
end
y=tc2*datain;
crc_mid = mod(x+y,2); % 中间值,用于下一次计算
crc_rlt = crc_mid; % 输出结果,根据输出选项
if XOR==1
crc_rlt=~crc_rlt;
end
if FO==1
crc_rlt=flipud(crc_rlt);% 输出上下翻转
end
crc_str_mid ='';
crc_str_rlt ='';
for i=1:M
crc_str_mid = strcat(crc_str_mid, sprintf('%d',crc_mid(i))); %转为2进制字符串
crc_str_rlt = strcat(crc_str_rlt, sprintf('%d',crc_rlt(i))); %转为2进制字符串
end
crc_str_mid=dec2hex(bin2dec(crc_str_mid),M/4);%转为16进制字符串
crc_str_rlt=dec2hex(bin2dec(crc_str_rlt),M/4);%转为16进制字符串
%% 输出verilog代码,仅计算则注释掉
t1='';
[gc,~]=find(flipud(cc)==1);
for i=2:size(gc)
t1=strcat(t1,sprintf('+x^%d',gc(i)-1));
end
cct=strcat(sprintf('// CRC module for data[%d:0] \tcrc[%d:0]=1',N-1,M-1),t1);
dlmwrite('crc.txt',cct,'delimiter','');
for i=1:M
t2='';
t3='';
for j=1:M
if ct(M+1-i,M+1-j)==1
t2=strcat(t2,sprintf('Cin[%d]^',j-1));
end
end
for j=1:N
if tc2(M+1-i,N+1-j)==1
if FI==1
t3=strcat(t3,sprintf('D[%d]^',N+1-j-1));
else
t3=strcat(t3,sprintf('D[%d]^',j-1));
end
end
end
cct=strcat(sprintf('assign Cout[%d]=',i-1),t2,t3);
cct=strcat(cct(1:size(cct,2)-1),';');
dlmwrite('crc.txt',cct,'-append','delimiter','');
end
end
场景 | 位数 | 多项式 | 多项式简写 | 省略最高位简写 |
---|---|---|---|---|
crc-5 usb2.0 | 5 | x5+x2+1 | 0x25 | 0x05 |
crc-8 | 8 | x8+x2+x+1 | 0x107 | 0x07 |
crc-16 usb2.0 | 16 | x16+x15+x2+1 | 0x18005 | 0x8005 |
crc-32 802.3 | 32 | x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1 | 0x104c11db7 | 0x04c11db7 |
crc32常用于网络报文的校验
// CRC module for
// data(7:0)
// crc(31:0)=1+x^1+x^2+x^4+x^5+x^7+x^8+x^10+x^11+x^12+x^16+x^22+x^23+x^26+x^32;
// 输出翻转+取反
// 输入翻转
// 预设初值
module crc_byte(
input clock,
input reset,
input crc_en,
input [7:0] data_in,
output [31:0] data_out
);
//////////////////////////////////////////////////////////////////////
// Internal Declaration
//////////////////////////////////////////////////////////////////////
reg [31:0] r_q;
wire [31:0] r_c;
//////////////////////////////////////////////////////////////////////
// Main Block
//////////////////////////////////////////////////////////////////////
// 输出翻转
assign data_out = ~{r_q[0], r_q[1], r_q[2], r_q[3], r_q[4], r_q[5], r_q[6], r_q[7],
r_q[8], r_q[9], r_q[10], r_q[11], r_q[12], r_q[13], r_q[14], r_q[15],
r_q[16], r_q[17], r_q[18], r_q[19], r_q[20], r_q[21], r_q[22], r_q[23],
r_q[24], r_q[25], r_q[26], r_q[27], r_q[28], r_q[29], r_q[30], r_q[31]};
// 根据输入反转要求,已改变以下Data序号
// assign r_c[0] = r_q[24] ^ r_q[30] ^ data_in[0] ^ data_in[6]; // 无输入翻转
assign r_c[0] = r_q[24] ^ r_q[30] ^ data_in[7] ^ data_in[1]; // 输入翻转:0 7互换 1 6互换
assign r_c[1] = r_q[24] ^ r_q[25] ^ r_q[30] ^ r_q[31] ^ data_in[7] ^ data_in[6] ^ data_in[1] ^ data_in[0];
assign r_c[2] = r_q[24] ^ r_q[25] ^ r_q[26] ^ r_q[30] ^ r_q[31] ^ data_in[7] ^ data_in[6] ^ data_in[5] ^ data_in[1] ^ data_in[0];
assign r_c[3] = r_q[25] ^ r_q[26] ^ r_q[27] ^ r_q[31] ^ data_in[6] ^ data_in[5] ^ data_in[4] ^ data_in[0];
assign r_c[4] = r_q[24] ^ r_q[26] ^ r_q[27] ^ r_q[28] ^ r_q[30] ^ data_in[7] ^ data_in[5] ^ data_in[4] ^ data_in[3] ^ data_in[1];
assign r_c[5] = r_q[24] ^ r_q[25] ^ r_q[27] ^ r_q[28] ^ r_q[29] ^ r_q[30] ^ r_q[31] ^ data_in[7] ^ data_in[6] ^ data_in[4] ^ data_in[3] ^ data_in[2] ^ data_in[1] ^ data_in[0];
assign r_c[6] = r_q[25] ^ r_q[26] ^ r_q[28] ^ r_q[29] ^ r_q[30] ^ r_q[31] ^ data_in[6] ^ data_in[5] ^ data_in[3] ^ data_in[2] ^ data_in[1] ^ data_in[0];
assign r_c[7] = r_q[24] ^ r_q[26] ^ r_q[27] ^ r_q[29] ^ r_q[31] ^ data_in[7] ^ data_in[5] ^ data_in[4] ^ data_in[2] ^ data_in[0];
assign r_c[8] = r_q[0] ^ r_q[24] ^ r_q[25] ^ r_q[27] ^ r_q[28] ^ data_in[7] ^ data_in[6] ^ data_in[4] ^ data_in[3];
assign r_c[9] = r_q[1] ^ r_q[25] ^ r_q[26] ^ r_q[28] ^ r_q[29] ^ data_in[6] ^ data_in[5] ^ data_in[3] ^ data_in[2];
assign r_c[10] = r_q[2] ^ r_q[24] ^ r_q[26] ^ r_q[27] ^ r_q[29] ^ data_in[7] ^ data_in[5] ^ data_in[4] ^ data_in[2];
assign r_c[11] = r_q[3] ^ r_q[24] ^ r_q[25] ^ r_q[27] ^ r_q[28] ^ data_in[7] ^ data_in[6] ^ data_in[4] ^ data_in[3];
assign r_c[12] = r_q[4] ^ r_q[24] ^ r_q[25] ^ r_q[26] ^ r_q[28] ^ r_q[29] ^ r_q[30] ^ data_in[7] ^ data_in[6] ^ data_in[5] ^ data_in[3] ^ data_in[2] ^ data_in[1];
assign r_c[13] = r_q[5] ^ r_q[25] ^ r_q[26] ^ r_q[27] ^ r_q[29] ^ r_q[30] ^ r_q[31] ^ data_in[6] ^ data_in[5] ^ data_in[4] ^ data_in[2] ^ data_in[1] ^ data_in[0];
assign r_c[14] = r_q[6] ^ r_q[26] ^ r_q[27] ^ r_q[28] ^ r_q[30] ^ r_q[31] ^ data_in[5] ^ data_in[4] ^ data_in[3] ^ data_in[1] ^ data_in[0];
assign r_c[15] = r_q[7] ^ r_q[27] ^ r_q[28] ^ r_q[29] ^ r_q[31] ^ data_in[4] ^ data_in[3] ^ data_in[2] ^ data_in[0];
assign r_c[16] = r_q[8] ^ r_q[24] ^ r_q[28] ^ r_q[29] ^ data_in[7] ^ data_in[3] ^ data_in[2];
assign r_c[17] = r_q[9] ^ r_q[25] ^ r_q[29] ^ r_q[30] ^ data_in[6] ^ data_in[2] ^ data_in[1];
assign r_c[18] = r_q[10] ^ r_q[26] ^ r_q[30] ^ r_q[31] ^ data_in[5] ^ data_in[1] ^ data_in[0];
assign r_c[19] = r_q[11] ^ r_q[27] ^ r_q[31] ^ data_in[4] ^ data_in[0];
assign r_c[20] = r_q[12] ^ r_q[28] ^ data_in[3];
assign r_c[21] = r_q[13] ^ r_q[29] ^ data_in[2];
assign r_c[22] = r_q[14] ^ r_q[24] ^ data_in[7];
assign r_c[23] = r_q[15] ^ r_q[24] ^ r_q[25] ^ r_q[30] ^ data_in[7] ^ data_in[6] ^ data_in[1];
assign r_c[24] = r_q[16] ^ r_q[25] ^ r_q[26] ^ r_q[31] ^ data_in[6] ^ data_in[5] ^ data_in[0];
assign r_c[25] = r_q[17] ^ r_q[26] ^ r_q[27] ^ data_in[5] ^ data_in[4];
assign r_c[26] = r_q[18] ^ r_q[24] ^ r_q[27] ^ r_q[28] ^ r_q[30] ^ data_in[7] ^ data_in[4] ^ data_in[3] ^ data_in[1];
assign r_c[27] = r_q[19] ^ r_q[25] ^ r_q[28] ^ r_q[29] ^ r_q[31] ^ data_in[6] ^ data_in[3] ^ data_in[2] ^ data_in[0];
assign r_c[28] = r_q[20] ^ r_q[26] ^ r_q[29] ^ r_q[30] ^ data_in[5] ^ data_in[2] ^ data_in[1];
assign r_c[29] = r_q[21] ^ r_q[27] ^ r_q[30] ^ r_q[31] ^ data_in[4] ^ data_in[1] ^ data_in[0];
assign r_c[30] = r_q[22] ^ r_q[28] ^ r_q[31] ^ data_in[3] ^ data_in[0];
assign r_c[31] = r_q[23] ^ r_q[29] ^ data_in[2];
always @(posedge clock) begin
if (reset)
r_q <= 32'hFFFFFFFF; // 预设初值
else if (crc_en == 1'b1)
r_q <= r_c;
end
endmodule