最近在开发万兆网mac,由于发送和接收要在数据的尾端添加或者校验CRC32_64,决定写一篇关于CRC的文章,此博客的意义在于帮助自己和大家理解FPGA并行CRC的实现方式,为了简单说明,以CRC32_8为例讲解。
1、CRC32_8生成多项式:CRC32=X32+X26+X23+X22+X16+X12+X11+X10+X8+X7+X5+X4+X2+X1+1
2、CRC校验原理
(1)将发送数据左移K位,右侧补零(其中K为生成多项式最高次幂);
(2)用移位补零后的数据对G(x)进行模2除法(其实就是异或运算);
(3)用得到的余数即为该数据的CRC校验码;
3、首先采用串行方式实现CRC32_8的校验功能
4、数据由高位依次输入,当输入最后1bit数据时,CRC寄存器中即为校验值,同时如果将D0时刻的表达式表示出来,则为并行CRC的计算公式。
CRC[0] = D[6] ^ D[0] ^ C[24] ^ C[30];
CRC[1] = D[7] ^ D[6] ^ D[1] ^ D[0] ^ C[24] ^ C[25] ^ C[30] ^ C[31];
CRC[2] = D[7] ^ D[6] ^ D[2] ^ D[1] ^ D[0] ^ C[24] ^ C[25] ^ C[26] ^ C[30] ^ C[31];
CRC[3] = D[7] ^ D[3] ^ D[2] ^ D[1] ^ C[25] ^ C[26] ^ C[27] ^ C[31];
CRC[4] = D[6] ^ D[4] ^ D[3] ^ D[2] ^ D[0] ^ C[24] ^ C[26] ^ C[27] ^ C[28] ^ C[30];
CRC[5] = D[7] ^ D[6] ^ D[5] ^ D[4] ^ D[3] ^ D[1] ^ D[0] ^ C[24] ^ C[25] ^ C[27] ^ C[28] ^ C[29] ^ C[30] ^ C[31];
CRC[6] = D[7] ^ D[6] ^ D[5] ^ D[4] ^ D[2] ^ D[1] ^ C[25] ^ C[26] ^ C[28] ^ C[29] ^ C[30] ^ C[31];
CRC[7] = D[7] ^ D[5] ^ D[3] ^ D[2] ^ D[0] ^ C[24] ^ C[26] ^ C[27] ^ C[29] ^ C[31];
CRC[8] = D[4] ^ D[3] ^ D[1] ^ D[0] ^ C[0] ^ C[24] ^ C[25] ^ C[27] ^ C[28];
CRC[9] = D[5] ^ D[4] ^ D[2] ^ D[1] ^ C[1] ^ C[25] ^ C[26] ^ C[28] ^ C[29];
…
CRC[30] = D[7] ^ D[4] ^ C[22] ^ C[28] ^ C[31];
CRC[31] = D[5] ^ C[23] ^ C[29];
由于表中数据较长,在此不做全部列出。
5、FPGA中v代码
`timescale 1ns / 1ps
module CRC32_8_TEST(
input clk,
input rst_n,
input clr,//同步清零
input din_vld,
input [7:0] din,
output reg dout_vld,
output reg [31:0] dout//crc校验结果
);
// polynomial: x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
// data width: 8
wire [7:0] D;
wire [31:0] C;
assign D = din;
assign C = dout;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
dout <= 32'hffff_ffff;
else if(clr)
dout <= 32'hffff_ffff;
else if(din_vld)begin
dout[0] <= D[6] ^ D[0] ^ C[24] ^ C[30];
dout[1] <= D[7] ^ D[6] ^ D[1] ^ D[0] ^ C[24] ^ C[25] ^ C[30] ^ C[31];
dout[2] <= D[7] ^ D[6] ^ D[2] ^ D[1] ^ D[0] ^ C[24] ^ C[25] ^ C[26] ^ C[30] ^ C[31];
dout[3] <= D[7] ^ D[3] ^ D[2] ^ D[1] ^ C[25] ^ C[26] ^ C[27] ^ C[31];
dout[4] <= D[6] ^ D[4] ^ D[3] ^ D[2] ^ D[0] ^ C[24] ^ C[26] ^ C[27] ^ C[28] ^ C[30];
dout[5] <= D[7] ^ D[6] ^ D[5] ^ D[4] ^ D[3] ^ D[1] ^ D[0] ^ C[24] ^ C[25] ^ C[27] ^ C[28] ^ C[29] ^ C[30] ^ C[31];
dout[6] <= D[7] ^ D[6] ^ D[5] ^ D[4] ^ D[2] ^ D[1] ^ C[25] ^ C[26] ^ C[28] ^ C[29] ^ C[30] ^ C[31];
dout[7] <= D[7] ^ D[5] ^ D[3] ^ D[2] ^ D[0] ^ C[24] ^ C[26] ^ C[27] ^ C[29] ^ C[31];
dout[8] <= D[4] ^ D[3] ^ D[1] ^ D[0] ^ C[0] ^ C[24] ^ C[25] ^ C[27] ^ C[28];
dout[9] <= D[5] ^ D[4] ^ D[2] ^ D[1] ^ C[1] ^ C[25] ^ C[26] ^ C[28] ^ C[29];
dout[10] <= D[5] ^ D[3] ^ D[2] ^ D[0] ^ C[2] ^ C[24] ^ C[26] ^ C[27] ^ C[29];
dout[11] <= D[4] ^ D[3] ^ D[1] ^ D[0] ^ C[3] ^ C[24] ^ C[25] ^ C[27] ^ C[28];
dout[12] <= D[6] ^ D[5] ^ D[4] ^ D[2] ^ D[1] ^ D[0] ^ C[4] ^ C[24] ^ C[25] ^ C[26] ^ C[28] ^ C[29] ^ C[30];
dout[13] <= D[7] ^ D[6] ^ D[5] ^ D[3] ^ D[2] ^ D[1] ^ C[5] ^ C[25] ^ C[26] ^ C[27] ^ C[29] ^ C[30] ^ C[31];
dout[14] <= D[7] ^ D[6] ^ D[4] ^ D[3] ^ D[2] ^ C[6] ^ C[26] ^ C[27] ^ C[28] ^ C[30] ^ C[31];
dout[15] <= D[7] ^ D[5] ^ D[4] ^ D[3] ^ C[7] ^ C[27] ^ C[28] ^ C[29] ^ C[31];
dout[16] <= D[5] ^ D[4] ^ D[0] ^ C[8] ^ C[24] ^ C[28] ^ C[29];
dout[17] <= D[6] ^ D[5] ^ D[1] ^ C[9] ^ C[25] ^ C[29] ^ C[30];
dout[18] <= D[7] ^ D[6] ^ D[2] ^ C[10] ^ C[26] ^ C[30] ^ C[31];
dout[19] <= D[7] ^ D[3] ^ C[11] ^ C[27] ^ C[31];
dout[20] <= D[4] ^ C[12] ^ C[28];
dout[21] <= D[5] ^ C[13] ^ C[29];
dout[22] <= D[0] ^ C[14] ^ C[24];
dout[23] <= D[6] ^ D[1] ^ D[0] ^ C[15] ^ C[24] ^ C[25] ^ C[30];
dout[24] <= D[7] ^ D[2] ^ D[1] ^ C[16] ^ C[25] ^ C[26] ^ C[31];
dout[25] <= D[3] ^ D[2] ^ C[17] ^ C[26] ^ C[27];
dout[26] <= D[6] ^ D[4] ^ D[3] ^ D[0] ^ C[18] ^ C[24] ^ C[27] ^ C[28] ^ C[30];
dout[27] <= D[7] ^ D[5] ^ D[4] ^ D[1] ^ C[19] ^ C[25] ^ C[28] ^ C[29] ^ C[31];
dout[28] <= D[6] ^ D[5] ^ D[2] ^ C[20] ^ C[26] ^ C[29] ^ C[30];
dout[29] <= D[7] ^ D[6] ^ D[3] ^ C[21] ^ C[27] ^ C[30] ^ C[31];
dout[30] <= D[7] ^ D[4] ^ C[22] ^ C[28] ^ C[31];
dout[31] <= D[5] ^ C[23] ^ C[29];
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
dout_vld <= 0;
else
dout_vld <= din_vld;
end
endmodule
6、当8位数据输入为0xAB时,软件工具输出
ISE仿真输出
可知,当初始条件相同时,逻辑代码与工具生成的CRC校验是相同的,可以验证,编写的逻辑代码正确。
7、由CRC32_8可知CRC32_64的相关代码过程,由于原理基本相同,不在赘述。
来源:oschina
链接:https://my.oschina.net/u/4324616/blog/4454802