手撕代码:crc串行校验(乐鑫)
首先了解什么是crc校验
该图片内容来源于《无线通信FPGA设计》
在CRC运算过程中会使用到模2除法运算。模2运算是一种二进制运算法则,与四则运算相同,模2运算也包括模2加、模2减、模2乘、模2除四种运算。模2运算用“+”表示加法运算,用“-”、“×”或“.”、“/”分别表示减法、乘法和除法运算。与普通四则运算法则不同的是,模2加法是不带进位的二进制加法运算,模2减法是不带借位的二进制减法运算。同时,模2乘法在累加中间结果时采用的是模2加法运算;模2除法求商过程中余数减除数采用的是模2减法运算。因此,两个二进制数进行模2加减法运算时,相当于两个二进制数进行按位异或运算,每一位的结果只与两个数的当前位有关。
1、题目要求:
Verilog实现串行CRC-8,G(D)=D8+D2+D+1。
2、代码
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2021/06/07 23:02:16
// Design Name:
// Module Name: CRC_8_serial
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module CRC_8_serial(
input clk,
input rst_n,
input [0:0]data,
input data_valid,
input crc_start,
output reg [0:0]crc_out,
output reg crc_valid
);
reg [1:0]state;
//reg [7:0]crc;
reg [7:0]initial_crc;
reg [7:0]crc_out_r;
reg crc_start_r;
reg data_valid_r;
reg [3:0]cnt;
always@(posedge clk or negedge rst_n)
if(!rst_n)
begin
crc_start_r<=0;
data_valid_r<=0;
cnt<=4'd8;
end
else begin
crc_start_r<=crc_start;
data_valid_r<=data_valid;
end
always@(posedge clk or negedge rst_n)
if(!rst_n)
begin
initial_crc<=8'b11111111;
state<=2'b00;
crc_out_r<=8'd0;
crc_valid<=1'b0;
crc_out<=0;
end
else
begin
case(state)
2'b00:
begin
if(crc_start_r==0&&crc_start==1)
state<=2'b01;
else
begin
initial_crc<=8'b11111111;//初始化种子值
state<=2'b00;
crc_out_r<=8'd0;
crc_valid<=1'b0;
end
end
2'b01:
begin//计算
if(crc_start_r==1&&crc_start==0)
begin
crc_out_r<=initial_crc;
//crc_valid<=1'b1;
state<=2'b10;
end
else if(data_valid==1)
initial_crc<=nextCRC8_D1(data,initial_crc);
else begin
initial_crc<=initial_crc;
crc_out_r<=crc_out_r;
crc_valid<=crc_valid;
state<=2'b01;
end
end
2'b10:
begin//串行输出,先输出最低位
if(cnt==0)
begin
state<=2'b00;
crc_valid<=0;
end
else
begin
crc_valid<=1;
crc_out_r<={1'b0,crc_out_r[7:1]};//并转串
crc_out<=crc_out_r[0];
cnt<=cnt-1;
state<=2'b10;
end
end
default:begin
state<=2'b00;
crc_valid<=1'b0;
crc_out<=0;
end
endcase
end
function [7:0]nextCRC8_D1;
input data;
input [7:0]crc;
reg [0:0]d;
reg [7:0]c;
reg [7:0]newcrc;
begin
d[0]=data;//这里不能写成d,要写成的d[0],否则会报错
c=crc;
newcrc[0]=d[0]^c[7];
newcrc[1]=d[0]^c[7]^c[0];
newcrc[2]=d[0]^c[7]^c[1];
newcrc[3]=c[2];
newcrc[4]=c[3];
newcrc[5]=c[4];
newcrc[6]=c[5];
newcrc[7]=c[6];
nextCRC8_D1=newcrc;
end
endfunction
endmodule
3、testebench
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2021/06/07 23:05:54
// Design Name:
// Module Name: CRC_8_serial_tst
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module CRC_8_serial_tst();
reg clk;
reg rst_n;
reg data;
reg data_valid;
reg crc_start;
wire crc_out;
wire crc_valid;
CRC_8_serial U_CRC_8_serial(
.clk (clk ),
.rst_n (rst_n ),
.data (data ),
.data_valid (data_valid ),
.crc_start (crc_start ),
.crc_out (crc_out ),
.crc_valid (crc_valid )
);
initial
begin
clk=0;
rst_n=0;
crc_start=0;
data_valid=0;
data=0;
#20 rst_n=1;
#20 crc_start=1;
//1
#20 data_valid=1;
data=1;
#20 data_valid=0;
//1
#20 data_valid=1;
data=1;
#20 data_valid=0;
//1
#20 data_valid=1;
data=1;
#20 data_valid=0;
//1 1111 f
#20 data_valid=1;
data=1;
#20 data_valid=0;
//0
#20 data_valid=1;
data=0;
#20 data_valid=0;
//1
#20 data_valid=1;
data=1;
#20 data_valid=0;
//1
#20 data_valid=1;
data=1;
#20 data_valid=0;
//0 0110 6
#20 data_valid=1;
data=0;
#20 data_valid=0;
//0
#20 data_valid=1;
data=0;
#20 data_valid=0;
//1
#20 data_valid=1;
data=1;
#20 data_valid=0;
//1
#20 data_valid=1;
data=1;
#20 data_valid=0;
//1 0111 7
#20 data_valid=1;
data=1;
#20 data_valid=0;
//1
#20 data_valid=1;
data=1;
#20 data_valid=0;
//1
#20 data_valid=1;
data=1;
#20 data_valid=0;
//0
#20 data_valid=1;
data=0;
#20 data_valid=0;
//1 1101 d
#20 data_valid=1;
data=1;
#20 data_valid=0;
crc_start=0;
//crc_result:c9
end
always #10 clk=~clk;
endmodule
3、现象
4、分析
考点1:crc的串行实现
分析的时候,最高位不管,比如,这里多项式是100000111,但是最高位不用管的,只需要管00000111。
考点2:并串转换
reg[7:0]crc_out_r;
reg [0:0]crc_out;
crc_out_r<={1’b0,crc_out_r[7:1]};//并转串
crc_out<=crc_out_r[0];
拓展:串并转换
crc_out_r<={data,crc_out_r[7:1]};
这个题其实是看着电路写代码,还有很多种实现方法,以后有时间我再补充进来。如果有不对的地方,欢迎大家指正。