并行CRC—Verilog代码实现

在线crc代码代码生成:http://outputlogic.com/
该网站提供的crc并行算法原理:http://outputlogic.com/?p=158

假设crc位宽为N,即生成多项式的最高次幂为N;假设并行数据D宽度为M。
crc并行计算可粗略的表述为(实际所有都是异或):
在这里插入图片描述
重点在与得到 crc系数矩阵AData系数矩阵B
特别说明:系数矩阵中元素为1表示该项参与异或,为0表示不参与异或(任何数据与自身异或都为零),为偶数同理(因此可取模2简化表述)。

1.构造系数方阵F

根据生成多项式G(x)构造系数N×N方阵F
在这里插入图片描述
其中E为N-1维单位阵。
以生成多项式为G=x5+x2+1的crc-5为例,G可表示为100101,省去最高项为00101,则F为:
在这里插入图片描述

2.计算CRC系数

求F的M次方FM(方阵乘法)再取模二,所得即为并行代码中的crc系数。
以N=5为例,矩阵与系数的对应关系如下:
也可以先对结果旋转,使C的序号和矩阵脚标序号对应,下图表示的是最初始的方阵乘法结果
在这里插入图片描述

3.计算DATA系数

求F的N次方FN(方阵乘法)再取模二,所得即为并行代码中的data系数。不过该系数中只有后面几列用得上,后续细说。

  1. 如果N=M,则Step2和Step3中的结果直接用:
    在这里插入图片描述
  2. 如果N>M,此为大多数应用场景,则D的系数为Step3结果的后M列:
    承上N=5,假设M=4,则D的系数如下:
    标灰色的部分不使用
    在这里插入图片描述
  3. 如果N<M,按实际M值计算:
    1. 如N<M<2N,则还需计算F2M
    2. 如2N<M<3N,则还需计算F2M和F3M
    3. 其他类推。
      承上N=5,假设M=8,并则将F5记为F1(黄色)、F10记为F2(蓝色和灰色),则D的系数与F1、F2的关系如下:
      在这里插入图片描述

3.1.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]的系数;
以此类推。

4.合并系数

将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

5.验证

http://outputlogic.com/ 网址中生成的代码为准进行验证。

  1. crc5 = x5+x2+1 data width =4:
    在这里插入图片描述结果:
    在这里插入图片描述
    matlab系数计算结果:
    因为该网站生成结果小序号在前,因此为对比方便对结果进行了旋转:
%% 旋转,小序号在前、在上
b1=rot90(rot90(b1));
b3=rot90(rot90(b3));

在这里插入图片描述2. crc5= x5+x2+1,data width = 13:

在这里插入图片描述3. 常用的crc31,篇幅过大不放了,也经过了验证。

6.其他选项

包括输入翻转、预设初值、输出翻转,这些都是可选项,可增强算法的检错能力。
参看crc caculator中的设置:
在这里插入图片描述

6.1输入翻转

是指将输入值在字节内进行bit反转(换序),同时字节间保持原序。
进行输入反转时,仅影响Data的系数,有两种方法完成此操作。

  1. 在对Data的系数计算完成后,对结果里面的Data系数翻转。

  2. 在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]};

6.2预设初值

即在进行第一次crc运算前,预先设定Cin项初值,默认情况下为全零,如802.3中使用的crc32的预设初值为32’hFFFFFFFF。

6.3输出翻转+取反

在输出至端口时,对计算得到的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]};

7.Matlab生成并行crc代码(不计算)

再改改,添加格式输出,将生成多项式输入方式改为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

8.常见crc

场景位数多项式多项式简写省略最高位简写
crc-5 usb2.05x5+x2+10x250x05
crc-88x8+x2+x+10x1070x07
crc-16 usb2.016x16+x15+x2+10x180050x8005
crc-32 802.332x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+10x104c11db70x04c11db7

9.附crc32源码

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
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值