首先了解什么是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]};
这个题其实是看着电路写代码,还有很多种实现方法,以后有时间我再补充进来。如果有不对的地方,欢迎大家指正。