当前位置:   article > 正文

CRC-16/XMODEM串行计算的Verilog源码及仿真_crc16 verilog

crc16 verilog


未经授权,严禁转载。

前言

本文主要讲解使用Verilog实现CRC串行计算的方法。

一、CRC是什么?

CRC在线计算:http://www.ip33.com/crc.html
在这里插入图片描述

二、硬件串行计算原理分析

1. 串行计算原理分析

(1) 原理图

多项式公式: G n ( x ) = g n x n + g n − 1 x n − 1 + g n − 2 x n − 2 + ⋯ + g 2 x 2 + g 1 x 1 + 1 G_n(x)=g_nx^n+g_{n-1}x^{n-1}+g_{n-2}x^{n-2}+\cdots+g_2x^2+g_1x^1+1 Gn(x)=gnxn+gn1xn1+gn2xn2++g2x2+g1x1+1
在这里插入图片描述

图1 串行计算原理图

(2) 计算过程

多项式中 g 0 , g 1 , ⋯   , g n g_0,g_1,\cdots,g_n g0,g1,,gn为0或1,不管多项式是什么样的形式,图1中的 g 0 g_0 g0 g n g_n gn都为1,其中input_bit为输入的单bit数据(发送数据的某一个bit)。在每个时钟周期下进行一次计算,经过n个时钟周期后得到最终的计算结果。

(3) 以CRC-16/XMODEM为例

采用CRC-16/XMODEM计算发送数据的CRC码时,n=16,多项式公式为 G 16 ( x ) = x 16 + x 12 + x 5 + 1 G_{16}(x)=x^{16}+x^{12}+x^{5}+1 G16(x)=x16+x12+x5+1

CRC算法名称多项式公式宽度多项式初始值结果异或值输入反转输出反转
CRC-16/XMODEM x 16 + x 12 + x 5 + 1 x^{16}+x^{12}+x^5+1 x16+x12+x5+1160x102100000000falsefalse

以计算一个16bit位宽的发送数据的CRC-16/XMODEM码为例,在计算时,首先向串行计算电路中输入发送数据的最高位,再在下一个时钟输入次高位,依次类推,直到发送数据的最低位输入到串行计算电路后,得到最终的CRC码。

2. Verilog代码

    (1) 单次计算Verilog代码如下:
    模块接口定义:

namedirectionwidthdescription
datainput1串行输入的单bit数据,相当于原理图中的input bit
crc_preinput16前一个时钟周期运算的crc结果
crcoutput16当前时钟周期下crc运算结果
module crc16ccitt_d1(
	input           data,
	input  [15:0]   crc_pre,
	output [15:0]   crc
);
	assign crc[0] = crc_pre[15] ^ data;
	assign crc[1] = crc_pre[0];
	assign crc[2] = crc_pre[1];
	assign crc[3] = crc_pre[2];
	assign crc[4] = crc_pre[3];
	assign crc[5] = crc_pre[4] ^ crc_pre[15] ^ data;
	assign crc[6] = crc_pre[5];
	assign crc[7] = crc_pre[6];
	assign crc[8] = crc_pre[7];
	assign crc[9] = crc_pre[8];
	assign crc[10] = crc_pre[9];
	assign crc[11] = crc_pre[10];
	assign crc[12] = crc_pre[11] ^ crc_pre[15] ^ data;
	assign crc[13] = crc_pre[12];
	assign crc[14] = crc_pre[13];
	assign crc[15] = crc_pre[14];
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

    (2) 计算一个16bit数据的CRC码:
    模块接口定义:

namedirectionwidthdescription
clkinput1模块时钟信号
rst_ninput1模块复位信号
data_ininput16对发送数据data_in计算CRC校验码
eninput1计算使能信号,单周期高电平有效
crc_rstoutput16CRC计算结果
crc_rst_vldoutput1CRC计算结果有效标志,单周期高脉冲有效
module crc16ccitt_d16(
	input  			clk			, // 时钟
	input  			rst_n		, // 复位
	input  [15:0] 	data_in		, // 对data_in计算CRC码
	input 			en			, // 使能信号
	output [15:0] 	crc_rst		, // CRC码
	output  		crc_rst_vld   // CRC码有效标志信号
);
reg 	[15:0] 				crc_pre		;
reg		[15:0]				data_cal	;
reg		[ 3:0]				cnt			;
reg							state		;
parameter	IDLE 	=	1'b0,
			SHIFT	= 	1'b1;
always @(posedge clk or negedge rst_n)
	if (!rst_n) begin
		state 		<= 		IDLE	;
		data_cal 	<= 		16'd0	;	
		crc_pre		<= 		16'd0	;
		cnt			<= 		4'd0	;
	end	else if (en) begin
		state 		<= 		SHIFT	;
		data_cal 	<=		data_in	;
		crc_pre		<= 		16'd0	;
		cnt			<= 		4'd0	;
	end else begin
		case (state)
			IDLE	:
				begin
					state    <= IDLE  	;
					data_cal <= 16'd0	;
					crc_pre	 <= 16'd0	;
					cnt		 <= 4'd0	;
				end
			
			SHIFT	: 
				begin
					data_cal <= data_cal << 1;
					crc_pre	 <= crc_rst	;
					cnt		 <=	cnt	+ 1'b1;
					if (cnt == 4'd14)
						state <= IDLE;
					else
						state <= SHIFT;
				end
				
			default:
				begin
					data_cal <= 16'd0 ;
					cnt		 <= 4'd0  ;
				end
		endcase
	end

assign crc_rst_vld = (cnt == 4'd15);

crc16ccitt_d1 crc16ccitt_d1(
	.data     (data_cal[15]),
	.crc_pre  (crc_pre     ),
	.crc      (crc_rst     )
);
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62

测试文件:

`timescale 1ns / 1ps
module testbench;

reg				clk			;
reg 			rst_n		;
reg		[15:0]	data_in		;
reg				en			;
wire	[15:0]	crc_rst		;
wire			crc_rst_vld	;

initial clk = 0;
always #10 clk = ~clk;

initial begin
	rst_n = 1'b0;
	#100;
	rst_n = 1'b1;
end

initial begin
	data_in = 16'd0;
	en		= 1'b0;
	#200;
	@(posedge clk) #5;
	data_in = 16'h5afc;
	en		= 1'b1;
	@(posedge clk) #5;
	en		= 1'b0;
	
	#5000;
	$stop;
end

crc16ccitt_d16 dut(
	.clk		 (clk          ),
	.rst_n		 (rst_n        ),
	.data_in	 (data_in      ),
	.en			 (en           ),
	.crc_rst	 (crc_rst      ),
	.crc_rst_vld (crc_rst_vld  )
);
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

3. 仿真结果分析

(1)Modelsim仿真结果

在这里插入图片描述
在端口data_in输入16’h5afc,同时拉高en信号一个时钟周期,使能该模块对输入的数据计算CRC码,经过16个时钟周期后,crc_rst_vld信号变为高电平,标志计算结果crc_rst有效,得到计算结果为16’hcfe7。

(2) 在线计算结果

在这里插入图片描述
使用CRC在线计算工具,计算16’h5afc的CRC-16/XMODEM码,计算结果同样为CFE7。


三、总结

以上就是本文介绍的内容,本文简要介绍了CRC码的串行计算的原理以及过程,并且给出了Verilog代码和仿真结果。

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号