CRCモジュール(Verilog-HDL)

弊社で作成したVerilog-HDLのCRCモジュールをご紹介いたします。
入力データビット幅、CRCデータ幅、多項式、シード値、CRC出力反転をパラメータ設定できます。
DATA_WIDTHは、入力データのビット幅を設定します。シリアル通信の場合などに、1ビット毎での入力を行うことも可能ですし、8ビットにして1バイト分の演算を1クロックサイクルで処理するなど自由に設定を行うことが出来ます。それによってデバイス、ロジック規模、クロックレートによって最適な使用方法を選択できます。
CRC_WIDTHは、CRCのビット幅を設定します。
POLYNOMIALは、多項式を設定します。例えばCRC-16-CCITT x16+x12+x5+1の場合、16’h1021となります。
SEED_VALは、初期値を設定します。通常は0を設定します。
OUTPUT_EXORは、出力の反転設定をします。通常は0を設定します。

【crc.v】


//% @file
//% @brief crc

//% CRC演算

module crc # (
		parameter DATA_WIDTH = 8,							//% データ幅
		parameter CRC_WIDTH = 16,							//% CRCデータ幅
		parameter [CRC_WIDTH-1:0] POLYNOMIAL = 16'h1021,	//% 生成多項式
		parameter [CRC_WIDTH-1:0] SEED_VAL = 16'h0,			//% シード値
		parameter OUTPUT_EXOR = 16'h0						//% 出力反転
	) (
		input CLK,        									//% クロック
		input RESET_N, 										//% リセット(負論理)
		input IN_CLR,										//% 入力CRC初期化
		input IN_ENA,										//% 入力イネーブル
		input [DATA_WIDTH-1:0] IN_DATA,						//% 入力データ
		output [CRC_WIDTH-1:0] OUT_CRC						//% CRC演算結果出力
	);

	reg [CRC_WIDTH-1:0] crc_reg;

	/*! CRC演算関数
	 */
	function [CRC_WIDTH-1:0] crc_calc;
		input [CRC_WIDTH-1:0] in_crc;
		input in_data;
		integer i;
		begin
			for (i = 0; i < CRC_WIDTH; i = i + 1) begin
				crc_calc[i] = 1'b0;
				if (i != 0)		
					crc_calc[i] = in_crc[i-1];
				if (POLYNOMIAL[i])
					crc_calc[i] = crc_calc[i] ^ in_crc[CRC_WIDTH-1] ^ in_data;
			end

		end
	endfunction

	/*! CRC演算ループ関数
	 */
	function [CRC_WIDTH-1:0] crc_calc_l;
		input [CRC_WIDTH-1:0] in_crc;
		input [DATA_WIDTH-1:0] in_data;
		integer i;
		begin
			crc_calc_l = in_crc;
			for (i = 0; i < DATA_WIDTH; i = i + 1) begin
				crc_calc_l = crc_calc(crc_calc_l, in_data[(DATA_WIDTH-1)-i]);
			end
		end
	endfunction

	/*! CRCレジスタ
	 */
	always @(posedge CLK) begin: crc_reg_l
		if (!RESET_N)
			crc_reg <= SEED_VAL;
		else begin
			if (IN_CLR)
				crc_reg <= SEED_VAL;
			else if (IN_ENA)
				crc_reg <= crc_calc_l(crc_reg, IN_DATA);
		end
	end

	assign OUT_CRC = crc_reg ^ OUTPUT_EXOR;

endmodule


SDカードで使用しているCRC-7、CRC-16-CCITT、およびCRC-64-ECMA-182でシミュレーションしてみました。

[CRC-7 8ビット入力]
parameter DATA_WIDTH = 8;
parameter CRC_WIDTH = 7;
parameter [CRC_WIDTH-1:0] POLYNOMIAL = 7’h09;
parameter [CRC_WIDTH-1:0] SEED_VAL = 7’h0;
parameter [CRC_WIDTH-1:0] OUTPUT_EXOR = 7’h0;

CRC7(8bit)

SDのSPIコマンド セットCMD8 {48,00,00,01,AA}を入力しています。CRC-7の結果は7’h43となります。
7’h43を先頭詰めの8bitにすると8’h86になるので、8’h86を入力すると、CRC-7の結果は0となります。

[CRC-7 1ビット入力]
parameter DATA_WIDTH = 1;
parameter CRC_WIDTH = 7;
parameter [CRC_WIDTH-1:0] POLYNOMIAL = 7’h09;
parameter [CRC_WIDTH-1:0] SEED_VAL = 7’h0;
parameter [CRC_WIDTH-1:0] OUTPUT_EXOR = 7’h0;

CRC7(1bit)

同じくSPIコマンド セットCMD8 {48,00,00,01,AA}を入力しています。
結果は、当然ですが8ビット入力時と同じです。

[CRC-16 8ビット入力]
parameter DATA_WIDTH = 8;
parameter CRC_WIDTH = 16;
parameter [CRC_WIDTH-1:0] POLYNOMIAL = 16’h1021;
parameter [CRC_WIDTH-1:0] SEED_VAL = 16’h0;
parameter [CRC_WIDTH-1:0] OUTPUT_EXOR = 16’h0;

CRC16_CCITT

適当な値で{21,39,71,4B}を入力しています。CRC-16の結果は16’hD809となります。
{D8,09}を入力すると、CRC-16の結果は0となります。

[CRC-16 8ビット入力 シード値FFFF CRC出力反転]
parameter DATA_WIDTH = 8;
parameter CRC_WIDTH = 16;
parameter [CRC_WIDTH-1:0] POLYNOMIAL = 16’h1021;
parameter [CRC_WIDTH-1:0] SEED_VAL = 16’h0;
parameter [CRC_WIDTH-1:0] OUTPUT_EXOR = 16’h0;

CRC16_CCITT(FFFF_INV)

適当な値で{21,39,71,4B}を入力しています。CRC-16の結果は16’hA336となります。
16’hA336をビット反転すると16’h5CC9となりますので5C,C9}を入力すると、CRC-16の結果は16’hFFFFとなります。

[CRC-64-ECMA-182 8ビット入力]
parameter DATA_WIDTH = 8;
parameter CRC_WIDTH = 64;
parameter [CRC_WIDTH-1:0] POLYNOMIAL = 64’h42F0E1EBA9EA3693;
parameter [CRC_WIDTH-1:0] SEED_VAL = 64’h0;
parameter [CRC_WIDTH-1:0] OUTPUT_EXOR = 64’h0;

CRC64_ECMA_182

適当な値で{DE,AD,BE,EF}を入力しています。CRC-64の結果は64’h3DF370C78407B980となります。
{3D,F3,70,C7,84,07,B9,80}を入力すると、CRC-64の結果は0となります。

タグ


2015年9月12日 | コメントは受け付けていません。|

カテゴリー:技術情報

このページの先頭へ

イメージ画像