循环冗余校验(Cyclic Redundancy Check, CRC)是一种根据网络数据包或电脑文件等数据产生简短固定位数校验码的一种散列函数,主要用来检测或校验数据传输或者保存后可能出现的错误。它是利用除法及余数的原理来作错误侦测的。
步骤:选一个多项式,转成n位二进制码gx_crc_n,在原始数据后加上n-1位0,模2整除gx_crc_n,将最后的五位余数补到原始码的末尾。
现假设选择的CRC生成多项式为G(X) = X4 + X3 + 1,要求出二进制序列10110011的CRC校验码。下面是具体的计算过程:
①将多项式转化为二进制序列,由G(X) = X4 + X3 + 1可知二进制一种有五位,第4位、第三位和第零位分别为1,则序列为11001
②多项式的位数位5,则在数据帧的后面加上5-1位0,数据帧变为101100110000,然后使用模2除法除以除数11001,得到余数。
Verilog源码:多项式为 X5+X4 + X2+ 1 ---110101
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 19:35:30 04/24/2018
// Design Name:
// Module Name: crc_test
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module crc_test(
input data_en,
input [9:0] data_in,
input clk,
input rst_n,
output reg [4:0] crc_out, //最后的余数,将其附加至data_out末尾
output reg [14:0] data_out
);
wire [14:0] data_in_reg;
//reg[3:0] cnt;
reg [5:0] crc_out_r;
reg crc_start;
parameter gx_crc_8=6'h35;
reg crc_end;
//crc 时钟
reg clk_crc;
reg [3:0] cnt;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n) begin
cnt<=0;
clk_crc<=0;
end
else if(cnt==4'd5) begin
cnt<=0;
clk_crc<=~clk_crc;
end
else
cnt<=cnt+1;
end
reg data_en1,data_en2;
wire data_en_pos;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n) begin
data_en1<=1'b0;
data_en2<=1'b0;
end
else begin
data_en1<=data_en;
data_en2<=data_en1;
end
end
assign data_en_pos=(data_en1&(~data_en2)); //检测使能上升沿
always @(posedge clk or negedge rst_n)
begin
if(!rst_n) begin
crc_start<=1'b0;
end
else if(data_en_pos) begin
crc_start<=1'b1;
end
else if(crc_end)
crc_start<=1'b0;
end
assign data_in_reg={data_in,5'b00_000};
/*always @(posedge clk_crc or negedge rst_n)
begin
if(!rst_n)
data_in_reg<=16'b0;
else
data_in_reg<={data_in,5'b00_000};
end
*/
reg [3:0] i;
//data width >crc width crc_8
always @(posedge clk or negedge rst_n)
begin
if(!rst_n) begin
crc_out_r<=data_in_reg[14:9];
i<=4'd8;
crc_end<=1'b0;
data_out<=0;
crc_out<=0;
end
else if(crc_start) begin
if (i==0) begin
if(crc_out_r[5]) begin //decide shift or conduct xor operate
crc_out_r<=crc_out_r^gx_crc_8;
end
else begin
i<=4'd10;
crc_out_r<={crc_out_r[4:0],1'b0};
crc_end<=1'b1;
end
end
else if(i>0 &&i<=8) begin
if(crc_out_r[5]) //decide shift or conduct xor operate
crc_out_r<=crc_out_r^gx_crc_8;
else begin
crc_out_r<={crc_out_r[4:0],data_in_reg[i]};
i<=i-1; //shift
end
end
else if (i==10) begin
crc_out<=crc_out_r[5]?(crc_out_r[4:0]^gx_crc_8[4:0]):crc_out_r[4:0];
data_out<={data_in,crc_out};
end
end
else begin
i<=4'd8;
crc_end<=1'b0;
crc_out_r<=data_in_reg[14:9];
end
end
Endmodule
Testbench
`timescale 1ns / 1ps
////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 21:05:36 04/24/2018
// Design Name: crc_test
// Module Name: D:/ise ex/crc/crc_test/crc_tsb.v
// Project Name: crc_test
// Target Device:
// Tool versions:
// Description:
//
// Verilog Test Fixture created by ISE for module: crc_test
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
////////////////////////////////////////////////////////////////////////////////
module crc_tsb;
// Inputs
reg data_en;
reg clk;
reg rst_n;
reg [9:0] data_in;
reg clk_crc;
// Outputs
wire [4:0] crc_out;
wire [14:0] data_out;
// Instantiate the Unit Under Test (UUT)
crc_test uut (
.data_en(data_en),
.data_in(data_in),
.clk(clk),
.rst_n(rst_n),
.crc_out(crc_out),
.data_out(data_out)
);
initial begin
// Initialize Inputs
data_en = 0;
clk = 0;
clk_crc=0;
rst_n = 0;
data_in=10'b1010001101;
// Wait 100 ns for global reset to finish
#100;
rst_n =1;
#100;
data_en=1;
#100;
data_en=0;
data_in=10'b1011001101;
#300;
data_en=1;
#100;
data_en=0;
data_in=10'b1011011101;
#300;
如果直接repeat,会执行一个顺序块,也就是data_en完成后再产生数据
//repeat (10) @(posedge clk_crc) data_en=~data_en;
//repeat (10) @(posedge clk_crc) data_in<=data_in+1;
解决办法:用fork join 生成并行块
fork
repeat (10) @(posedge clk_crc) data_en<=~data_en;
repeat (10) @(posedge clk_crc) data_in<=data_in+1;
join
// Add stimulus here
end
always #10 clk=~clk;
always #100 clk_crc=~clk_crc;