转自:http://zhangxun0712.blog.163.com/blog/static/8007301200832304247543/
首先介绍一个不错的CRC校验的网站,http://www.easics.com/webtools/crctool 现在估计所有的工程应用均来自该网站生成的代码。使用方便。
但是该网站的代码不易于CRC的学习和研究,但是保证是对的,工程实践证明。现在将我的研究成果和大家分享一下:用于任意CRC的校验。
网站上的校验方式最大提供CRC32 和任意数据位(最大511)的校验。当然一般的情况下应该是够用了。我所做的设计可以扩展到任意数据的校验,当然是并行数据的校验,串行数据的校验应用可以参照网上的一些资料。很简单,不再赘述。以CRC32为例
首先建立函数,=====设计的的关键
//--------------------------------------------------------------------------
function [31:0] next_c32;
input [31:0] crc;
input B;
begin
next_c32 = {crc[30:0],1'b0} ^ ({32{(crc[31] ^ B)}} &32'h04c11db7);//下划线的部分为本征多项式
end
endfunction
/*这是校验和左移一位求校验和的计算公式*/
相同的如果CRC8
//--------------------------------------------------------------------------
function [7:0] next_c8;
input [7:0] crc;
input B;
begin
next_c8 = {crc[6:0],1'b0} ^ ({8{(crc[7] ^ B)}} & 8'h03);//下划线的部分为本征多项式
end
endfunction
其他的是一样的。
其次 如果我们要求CRC32_D(M)M >= 32
function [31:0] next_c32_ge; //M+1 is the data maximum with
input [M:0] data;
input [31:0] crc;
integer i;
begin
next_c32_ge = crc;
for(i=0; i<=M; i="i"+1) begin
next_c32_ge = next_c32(next_c32_ge,data[M-i]);
end
end
endfunction
假设我们求CRC32_D64 那么M=63
function [31:0] next_c32_D64; //M+1 is the data maximum with
input [63:0] data;
input [31:0] crc;
integer i;
begin
next_c32_D64 = crc;
for(i=0; i<=63; i="i"+1) begin
next_c32_D64 = next_c32(next_c32_D64,data[63-i]);
end
end
endfunction
假设我们求CRC32_D128 那么M=127
function [31:0] next_c32_D128;
input [127:0] data;
input [31:0] crc;
integer i;
begin
next_c32_D128 = crc;
for(i=0; i<=127; i="i"+1) begin
next_c32_D128= next_c32(next_c32_D128,data[127-i]);
end
end
endfunction
再次如果我们要求CRC32_D(M) M<=32
function [31:0] next_c32_le;
input [31:0] data;
input [31:0] inp;
input [4:0] be;
integer i;
begin
next_c32_le = data;
for(i=0; i<=31-be; i="i"+1) begin
next_c32_le = next_c32(next_c32_le,inp[31-be-i]);
end
end
endfunction
我们首先校验完毕所有的有效数据位下面的函数是对CRC的空闲位的修正。
function [K-1:0] next_cK_1_any_LEK_1;
input [N-1:0] data;
input [K-1:0] crc;
begin
next_cK_1_any_LEK_1 = next_c32_le({data,{(K-N){1'b0}}},{crc[K-1:N],{(K-N){1'b0}}},(K-N))^{crc<
end
endfunction
//以CRC32D16 K =32 N =16 这个函数就变成
function [31:0] next_C32_D16;
input [15:0] data;
input [31:0] crc;
begin
next_C32_D16 = next_c32_le({data,{16{1'b0}}},{crc[31:16],{16{1'b0}}},16)^{crc<<16};
end
endfunction
经过modelsim和Qii软件仿真无误。本来想做成动态数据长度校验的函数,本人也作了一些尝试,在CRC--N N = 2^m时都是没有问题的 比如CRC8 CRC16 CRC32 CRC64 等等,但是若是不是这些数值比如CRC12 CRC10的Qii会抱错(因为部分函数的输入部分必须为常数),但是Modelsim不会抱错而且仿真和实际的结果一致。可以用来做验证。 这边仅仅举了CRC32 的例子,其他的也都类似。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity CODE_74_NEW is
Port ( clk : in STD_LOGIC;
data_in: in STD_LOGIC_VECTOR (3 downto 0);
--cnt_out: out std_logic_vector (2 downto 0);
--dtemp_out: out std_logic_vector (3 downto 0);
data_crc : out STD_LOGIC);
end CODE_74_NEW;
architecture Behavioral of CODE_74_NEW is
constant multi_coef:std_logic_vector (3 downto 0):="1101";--生成多项式系数,MSB一定为1,g(x)=x^3+x^2+1
begin
process(clk)
variable crcvar,dtemp,sdata:std_logic_vector(3 downto 0);--除法运算被除数变量
variable cnt:std_logic_vector (2 downto 0):="000";--运算次数控制
begin
if clk'event and clk='1' then
cnt:=cnt+1;
--cnt_out<=cnt;
--dtemp_out<=dtemp;
if cnt<=4 then --前四个时钟,串行输出四位信息码
if cnt=1 then --初始化操作
dtemp:=data_in;--装载原数据,用于运算校验码
sdata:=data_in;--装载原数据,保存
end if;
data_crc<=sdata(3);--当计数器小于4时,每来一个时钟串行输出一位信息码
sdata:=sdata(2 downto 0) & '0'; --左移
--以下为校验码运算
if dtemp(3)='1' then --当前运算的四位码,如果最高位为1则可进行模二除法
crcvar:=dtemp(3 downto 0) xor multi_coef;--异或运算模二除法
dtemp:=crcvar(2 downto 0) & '0';--运算后补零
else dtemp:=dtemp(2 downto 0) & '0';--当前运算的四位码,如果最高位为0则只进行移位补零
end if;
elsif cnt>4 then --后三个时钟串行输?位校验码
data_crc<=dtemp(3);--输出,移位
dtemp:=dtemp(2 downto 0) & '0';
if cnt=7 then --第7个时钟清零
cnt:=(others=>'0');
end if;
end if;
end if;
end process;
end Behavioral;