CRCモジュール(Verilog-HDL) テストベンチ

以前、弊社で作成したVerilog-HDLのCRCモジュールのテストベンチを公開致します。
簡単に数種類のテストを行っているだけで、網羅的なテストを目的としておりません。インタフェースや使い方の確認などにご利用いただければと思います。

【crc_tf.v】


//% @file
//% @brief crc_tf

//% CRC演算テストベンチ

module crc_tf;

	parameter CLK_CYCLE = 10000;	// 100MHz

//	parameter CRC_WIDTH = 7;	// CRCデータ幅
	parameter CRC_WIDTH = 16;	// CRCデータ幅
//	parameter CRC_WIDTH = 64;	// CRCデータ幅

	// CRC初期値 ALL 0
	parameter [CRC_WIDTH-1:0] SEED_VAL = {CRC_WIDTH{1'b0}};	
	// CRC初期値 ALL 1
//	parameter [CRC_WIDTH-1:0] SEED_VAL = {CRC_WIDTH{1'b1}};

	parameter DATA_WIDTH = 8;	// データ幅
//	parameter DATA_WIDTH = 2;	// データ幅
//	parameter DATA_WIDTH = 1;	// データ幅

	// 出力反転無し
	parameter OUTPUT_EXOR = {CRC_WIDTH{1'b0}};
	// 出力反転有り	
//	parameter OUTPUT_EXOR = {CRC_WIDTH{1'b1}};

	parameter [CRC_WIDTH-1:0] POLYNOMIAL =	
		(CRC_WIDTH == 7)?  7'h09 :   	// CRC7 X^7+X^3+1
		(CRC_WIDTH == 16)? 16'h1021 :	// CCITT CRC16 X^16+X^12+X^5+1
//		(CRC_WIDTH == 16)? 16'h8005 :	// CRC16 X^16+X^15+X^2+1
		(CRC_WIDTH == 64)? 64'h42F0E1EBA9EA3693 : // CRC64(ECMA-182)
		'h0;

	// Inputs
	reg CLK;
	reg RESET_N;
	reg IN_CLR;
	reg IN_ENA;
	reg [DATA_WIDTH-1:0] IN_DATA;

	// Outputs
	wire [CRC_WIDTH-1:0] OUT_CRC;

	// Instantiate the Unit Under Test (UUT)
	crc # (
		.DATA_WIDTH(DATA_WIDTH),
		.CRC_WIDTH(CRC_WIDTH),
		.POLYNOMIAL(POLYNOMIAL),
		.SEED_VAL(SEED_VAL),
		.OUTPUT_EXOR(OUTPUT_EXOR)
	) uut (
		.CLK(CLK), 
		.RESET_N(RESET_N), 
		.IN_CLR(IN_CLR), 
		.IN_ENA(IN_ENA), 
		.IN_DATA(IN_DATA), 
		.OUT_CRC(OUT_CRC)
	);

	initial begin
		CLK = 1'b1;		#(CLK_CYCLE / 2);
		forever begin
			CLK = ~CLK;	#(CLK_CYCLE / 2);
		end
	end

	task task_wait;
		input integer wait_time;
		begin
			repeat(wait_time)	@(posedge CLK);
		end
	endtask

	task task_crc7_1byte_test;
		input [7:0] data0;
		input [7:0] data1;
		input [7:0] data2;
		input [7:0] data3;
		input [7:0] data4;
		input integer wait_time;
		input [6:0] crc;
		begin
			@(posedge CLK);
			IN_CLR = 1;
     			task_wait(1);
			IN_CLR = 0;
   			task_wait(wait_time);
			IN_ENA = 1'b1;
			IN_DATA = data0;
			task_wait(1);
			IN_DATA = data1;
			task_wait(1);
			IN_DATA = data2;
			task_wait(1);
			IN_DATA = data3;
			task_wait(1);
			IN_DATA = data4;
			task_wait(1);
			IN_ENA = 1'b0;
			task_wait(wait_time);
			IN_ENA = 1'b1;
			IN_DATA = {crc, 1'b0};
 			task_wait(1);
			IN_DATA = 8'h00;
			IN_ENA = 1'b0;
		end
	endtask

	task task_8bit_serial;
		input [7:0] data;
		integer i;
		begin
			for (i = 0; i < 8; i = i + 1) begin
				IN_DATA = data[7-i];
				task_wait(1);
			end
		end
	endtask

	task task_4x2bit_serial;
		input [7:0] data;
		integer i;
		begin
			for (i = 0; i < 4; i = i + 1) begin
				IN_DATA[0] = data[7-i*2-1];
				IN_DATA[1] = data[7-i*2];
				task_wait(1);
			end
		end
	endtask

	task task_7bit_serial;
		input [6:0] data;
		integer i;
		begin
			for (i = 0; i < 7; i = i + 1) begin
				IN_DATA = data[6-i];
				task_wait(1);
			end
		end
	endtask

	task task_crc7_1bit_test;
		input [7:0] data0;
		input [7:0] data1;
		input [7:0] data2;
		input [7:0] data3;
		input [7:0] data4;
		input integer wait_time;
		input [6:0] crc;
		begin
			IN_CLR = 1;
			task_wait(1);
			IN_CLR = 0;
			task_wait(wait_time);
			IN_ENA = 1'b1;
			task_8bit_serial(data0);
			task_8bit_serial(data1);
			task_8bit_serial(data2);
			task_8bit_serial(data3);
			task_8bit_serial(data4);
			IN_ENA = 1'b0;
			task_wait(wait_time);
			IN_ENA = 1'b1;
			task_7bit_serial(crc);
			IN_DATA = 1'b0;
			IN_ENA = 1'b0;
		end
	endtask

	task task_crc16_test;
		input [7:0] data0;
		input [7:0] data1;
		input [7:0] data2;
		input [7:0] data3;
		input integer wait_time;
		input [15:0] crc;
		begin
			IN_CLR = 1;
			task_wait(1);
			IN_CLR = 0;
			task_wait(wait_time);
			IN_ENA = 1'b1;
			IN_DATA = data0;
			task_wait(1);
			IN_DATA = data1;
			task_wait(1);
			IN_DATA = data2;
			task_wait(1);
			IN_DATA = data3;
			task_wait(1);
			IN_ENA = 1'b0;
			task_wait(wait_time);
			IN_ENA = 1'b1;
			IN_DATA = crc[15:8];
			task_wait(1);
			IN_DATA = crc[7:0];
			task_wait(1);
			IN_DATA = 8'h00;
			IN_ENA = 1'b0;
		end
	endtask

	task task_crc16_2bit_test;
		input [7:0] data0;
		input [7:0] data1;
		input [7:0] data2;
		input [7:0] data3;
		input integer wait_time;
		input [15:0] crc;
		begin
			IN_CLR = 1;
			task_wait(1);
			IN_CLR = 0;
			task_wait(wait_time);
			IN_ENA = 1'b1;
			task_4x2bit_serial(data0);
			task_4x2bit_serial(data1);
			task_4x2bit_serial(data2);
			task_4x2bit_serial(data3);
			IN_ENA = 1'b0;
			task_wait(wait_time);
			IN_ENA = 1'b1;
			task_4x2bit_serial(crc[15:8]);
			task_4x2bit_serial(crc[7:0]);
			IN_DATA = 1'b0;
			IN_ENA = 1'b0;
		end
	endtask

	task task_crc64_test;
		input [7:0] data0;
		input [7:0] data1;
		input [7:0] data2;
		input [7:0] data3;
		input integer wait_time;
		input [63:0] crc;
		begin
			IN_CLR = 1;
			task_wait(1);
			IN_CLR = 0;
			task_wait(wait_time);
			IN_ENA = 1'b1;
			IN_DATA = data0;
		task_wait(1);
			IN_DATA = data1;
		task_wait(1);
			IN_DATA = data2;
		task_wait(1);
			IN_DATA = data3;
		task_wait(1);
			IN_ENA = 1'b0;
			task_wait(wait_time);
			IN_ENA = 1'b1;
			IN_DATA = crc[63:56];
			task_wait(1);
			IN_DATA = crc[55:48];
			task_wait(1);
			IN_DATA = crc[47:40];
			task_wait(1);
			IN_DATA = crc[39:32];
			task_wait(1);
			IN_DATA = crc[31:24];
			task_wait(1);
			IN_DATA = crc[23:16];
			task_wait(1);
			IN_DATA = crc[15:8];	
			task_wait(1);
			IN_DATA = crc[7:0];	
			task_wait(1);
			IN_DATA = 8'h00;
			IN_ENA = 1'b0;
		end
	endtask

	initial begin
		RESET_N = 0;
		IN_CLR = 0;
		IN_ENA = 0;
		IN_DATA = 0;

		task_wait(100);
		RESET_N = 1;

		task_wait(100);

		if (CRC_WIDTH == 7) begin
			if (DATA_WIDTH == 8) begin
				// SD CMD 0
				task_crc7_1byte_test(
						8'h40, 8'h00, 8'h00, 8'h00, 8'h00, 10, 7'h4A);
				task_wait(100);
				// SD CMD 8
				task_crc7_1byte_test(
						8'h48, 8'h00, 8'h00, 8'h01, 8'hAA, 10, 7'h43);
				task_wait(100);
				// SD CMD 16
				task_crc7_1byte_test(
						8'h50, 8'h00, 8'h00, 8'h02, 8'h00, 10, 7'h0A);
				task_wait(100);
			end
			else if (DATA_WIDTH == 1) begin
				// SD CMD 0
				task_crc7_1bit_test(
						8'h40, 8'h00, 8'h00, 8'h00, 8'h00, 10, 7'h4A);
				task_wait(100);
				// SD CMD 8
				task_crc7_1bit_test(
						8'h48, 8'h00, 8'h00, 8'h01, 8'hAA, 10, 7'h43);
				task_wait(100);
				// SD CMD 16
				task_crc7_1bit_test(
						8'h50, 8'h00, 8'h00, 8'h02, 8'h00, 10, 7'h0A);
				task_wait(100);
			end
		end
		else if (CRC_WIDTH == 16) begin
			if (DATA_WIDTH == 8) begin
				if ((SEED_VAL == 16'h0) && (OUTPUT_EXOR == 16'h0)) begin
					// "1234"
					task_crc16_test(
						8'h31, 8'h32, 8'h33, 8'h34, 2, 16'hD789);
					task_wait(100);
					// "!9qK"
					task_crc16_test(
						8'h21, 8'h39, 8'h71, 8'h4B, 2, 16'hD809);
					task_wait(100);
				end
				else if ((SEED_VAL == 16'hFFFF) && (OUTPUT_EXOR == 16'hFFFF)) begin
					// "1234" CRC = ACB6
					task_crc16_test(
						8'h31, 8'h32, 8'h33, 8'h34, 2, 16'h5349);
					task_wait(100);
					// "!9qK" CRC = A336
					task_crc16_test(
						8'h21, 8'h39, 8'h71, 8'h4B, 2, 16'h5CC9);
					task_wait(100);
				end
			end
			else if (DATA_WIDTH == 2) begin
				if ((SEED_VAL == 16'h0) && (OUTPUT_EXOR == 16'h0)) begin
					// "1234"
					task_crc16_2bit_test(
						8'h31, 8'h32, 8'h33, 8'h34, 2, 16'hD789);
					task_wait(100);
					// "!9qK"
					task_crc16_2bit_test(
						8'h21, 8'h39, 8'h71, 8'h4B, 2, 16'hD809);
					task_wait(100);
				end
			end
		end
		else if (CRC_WIDTH == 64) begin
			task_crc64_test('hDE, 'hAD, 'hBE, 'hEF, 4, 64'h3DF370C78407B980);
			task_wait(100);
		end

		$stop;
	end

endmodule

タグ


2017年6月2日 | コメント/トラックバック(0)|

カテゴリー:技術情報

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日 | コメントは受け付けていません。|

カテゴリー:技術情報

遅延モジュール(Verilog-HDL / Xilinx)

弊社のXilinx社製FPGAのRTL開発で使用しております遅延モジュールをご紹介いたします。

パイプラインにおける遅延調整の場合、ロジックの変更によって遅延量の変更が都度発生します。
その度にFFを1段追加あるいは削除するというのは、かなりの面倒な作業と思います。
また、外部入力信号や非同期クロック間転送(CDC)の為のダブルFFシンクロナイザも都度記述するのは、煩わしい作業では無いかと思います。

そこで、ビット幅および遅延量をパラメータ化した遅延モジュールを用意しております。
また、入力ピンおよび出力ピンに直結した場合にIOB内蔵のFFを使用するパラメータも用意しております。
リセットについては、弊社では殆どの場合、同期リセットを使用しておりますが、非同期リセットにも対応できるようにパラメータ化しております。

【delay_ff.v】

//% @file
//% @brief delay_ff (for Xilinx FPGA)

//% ディレーフリップフロップ

module delay_ff # (
		parameter DATA_WIDTH = 2,				//% データ幅
		parameter DELAY_TIME = 3,				//% 遅延時間
		parameter IFF_USE = 0,					//% 初段FF = IOB
		parameter OFF_USE = 0,					//% 最終FF = IOB
		parameter ARESET_USE = 0				//% 非同期リセット使用
	) (
		input CLK,        						//% クロック
		input RESET_N, 							//% リセット(負論理)
		input [DATA_WIDTH-1:0] IN_DATA,			//% 入力データ
		output [DATA_WIDTH-1:0] OUT_DATA		//% 出力データ
	);

	wire [DATA_WIDTH-1:0] data[DELAY_TIME:0];

	assign data[0] = IN_DATA;
	assign OUT_DATA = data[DELAY_TIME];

	/*! D-FF
	 */
	generate
		genvar i;
		for (i = 0; i < DELAY_TIME; i = i + 1) begin : gen_d_ff
			d_ff #(
				.DATA_WIDTH(DATA_WIDTH),
				.IOB_USE((i == 0)? IFF_USE : (i == (DELAY_TIME-1))? OFF_USE : 0),
				.ARESET_USE(ARESET_USE)
			) u_d_ff (
				.CLK(CLK),
				.RESET_N(RESET_N),
				.IN_DATA(data[i]),
				.OUT_DATA(data[i+1])
			);
		end
	endgenerate
endmodule

【d_ff.v】
//% @file
//% @brief d-ff (for Xilinx FPGA)

//% Dタイプフリップフロップ

module d_ff # (
		parameter DATA_WIDTH = 1,				//% データ幅
		parameter IOB_USE = 0,					//% IOB使用
		parameter ARESET_USE = 0				//% 非同期リセット使用
	) (
		input CLK,        						//% クロック
		input RESET_N, 							//% リセット(負論理)
		input [DATA_WIDTH-1:0] IN_DATA,			//% 入力データ
		output [DATA_WIDTH-1:0] OUT_DATA		//% 出力データ
	);

	(* IOB = (IOB_USE)? "TRUE" : "FALSE" *) reg [DATA_WIDTH-1:0] data_reg;

	assign OUT_DATA = data_reg;
	
	/*! データレジスタ
	 */
	generate
		if (ARESET_USE) begin
			always @(posedge CLK or negedge RESET_N) begin: data_reg_l
				if (!RESET_N)
					data_reg <= {DATA_WIDTH{1'b0}};
				else
					data_reg <= IN_DATA;
			end
		end
		else begin
			always @(posedge CLK) begin: data_reg_l
				if (!RESET_N)
					data_reg <= {DATA_WIDTH{1'b0}};
				else
					data_reg <= IN_DATA;
			end
		end
	endgenerate
endmodule
上記コードをSpartan-6にインプリメントしてみます。


View RTL Schematic
SCH
 

IFF_USE = 0, OFF_USE = 0 の場合
IOB00
 

IFF_USE = 1, OFF_USE = 0 の場合
IOB10
 

IFF_USE = 0, OFF_USE = 1 の場合
IOB01
IOB propertiesのReg(s)欄を確認すると、IFFあるいはOFFが使用されています。

ARESET_USE = 0 (同期リセットの場合)
fdr
FDR : D Flip-Flop with Synchronous Reset

ARESET_USE = 1 (非同期リセットの場合)
fdc
FDC : D Flip-Flop with Asynchronous Clear


タグ


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

カテゴリー:技術情報

FPGA評価ボード開発(受託開発)

ザイリンクス社製FPGA Spartan-6とADコンバータ・DAコンバータ・PWM出力回路・シリアル通信ポートなどの回路を搭載した評価ボードの回路設計およびRTLの受託開発いたしました。
RTLに関しましては、周辺回路を制御する為の雛型とハードウエア動作確認用のテストロジックまでを作成し実機テストを行い納品いたしました。
fpga-ev-board

タグ


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

カテゴリー:開発実績

タッチパネル用マイコンボード開発(受託開発)

投影型静電容量(PCAP)タッチパネル用のPICマイコンボードのハードウエア開発を行いました。
タッチセンサーコントローラとタッチパネル表示用のLEDドライバを搭載しています。
また、ホストインタフェースとして、USB2.0を備えております。

開発のベース回路として、自社開発のPrimrose DSCボードを採用することで短納期でかつ、低開発コストでのご提供をさせて頂きました。

タッチパネルマイコンボード

タグ


2014年4月27日 | コメントは受け付けていません。|

カテゴリー:開発実績

このページの先頭へ

イメージ画像