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)|

カテゴリー:技術情報

XILINX(ISE) カスタム AXI-Master IPのシミュレーション

AXIマスターオリジナルIPを製作する為に、Xilinx社提供のサンプルコードでのシミュレーションをご紹介します。
本来は、Xilinx社より提供されるAXI Bus Functional Model (BFM)を使用すれば良いのですが、こちらは有償となっておりますので、MicroBlazeのIPを接続してシミュレーションする環境をご紹介いたします。

プロジェクトの方針

Avnet社製MicroBoardの環境準備

avnet社のホームページよりMicroBoardのXBDを入手します。
EDK 14.3 XBD/IP-XACT Files : avnet_edk14_3_xbd_files_9_11_2012_spartan.zip

http://www.em.avnet.com/en-us/design/drc/Pages/Xilinx-Spartan-6-FPGA-LX9-MicroBoard.aspxのSupport and Downloadsから入手できます。

avnet_edk14_3_xbd_files.zip/boards/Avnet_S6LX9_MicroBoard_RevBを/Xilinx/14.7/ISE_DS\EDK/board/Xilinx/boardsにコピーします。
MicroBoard1


avnet_edk14_3_xbd_files.zip/ipxact/S6_MicroBoard_v1_0を/Xilinx/14.7/ISE_DS\EDK/board/Xilinx/ipxactにコピーします。
MicroBoard2

MicroBoardプロジェクトの作成

ISEプロジェクトを作成します。
MicroBoardPrj1


Evaliation Development BoardにAvnet S6LX9 MicroBoard RevBを選択します。
MicroBoardPrj2


その他は変更せずにfinishまで進めます。

XPSプロジェクトの作成

New Source WizardでISEプロジェクトに新しくEmbedded Processorを追加します。
EmbeddedProcessor1


New Source Wizardをfinishまで進めると、XPSが起動しBSB Wizardの使用を確認されるので、Yesを選択します。
MicroBoardPrj3


AXI Systemがデフォルトで選択されていますので、そのまま次に進みます。
MicroBoardPrj4


BoardおよびSystemに関する設定はデフォルトのままで次に進みます。
MicroBoardPrj5


processorとperipheralに関する設定です。
MicroBoardPrj6


今回は、AXI-MASTERのシミュレーションに特化しますので不要なペリフェラルをすべて削除します。MCB3_LPDDR(Cached)以外はすべてRemoveして、Finishします。
MicroBoardPrj7

XPSプロジェクトへのAXI-Master IPの追加

BSB Wizardが終了するとXPSが起動します。
MicroBoardXps1


今回は、AXI-MASTERのシミュレーションに特化しますのでaxilite_0とmicroblaze関連のIP及びdebug_moduleを削除します。
MicroBoardXps2


AR37425.zipをxilinx社のホームページからダウンロード-解凍して、axi_master_v1_00_aフォルダをAXI_MASTER_TEST/AXI_MASTER_TEST/pcoresにコピーします。
MicroBoardXps3


Project->Rescan User Repositoriesをクリックすると、IP CatalogにAXI Masterが追加されます。
MicroBoardXps4


MCB_LPDDRのAddressを確認します。0xA4000000-0xA7FFFFFFになっています。
Project->Rescan User Repositoriesをクリックすると、IP CatalogにAXI Masterが追加されます。
MicroBoardXps5


AXI Master IPを追加します。
C_M_AXI_TARGETは、前項で確認したMCB_LPDDRの先頭アドレスである0xA4000000を設定します。
C_M_AXI_BURST_LENは、AXIのバースト長を指定します。今回はディフォルトのままにします。
C_OFFSET_WIDTHはサンプルの書き込み範囲のビット数を示しております。初期値は9になっていますので0xA4000000から0xA40001FFまでの512バイトのWrite/Readテストを行います。
C_M_AXI_PROTOCOLはAXI(ディフォルト値)とします。
その他は変更不要です。
MicroBoardXps6


axi_master_0が追加されますので、axi_master_0をaxi4_0にバス接続します。
MicroBoardXps7


MCB3_LPDDRをaxi4_0にバス接続します。
MicroBoardXps8


これで、axi_master_0とMCB3_LPDDRがAXI4で接続されました。
MicroBoardXps9


LPDDR SDRAMのシミュレーションモデルを生成する為に、MCB3_LPDDRのMIGを起動します。
MIG1


設定の変更は必要ありませんので、そのまま進んでいき、finishします。
MIG2


AXI_MASTER_TEST\AXI_MASTER_TEST\__xps\MCB3_LPDDRにLPDDR SDRAMのシミュレーションモデルが生成されます。
MIG3


axi_master_0のポートを接続します。
  • axi_master_0::ERROR – External Ports axi_master_0_error(新規)
  • axi_master_0::M_AXI::ACLK – clock_generator_0::CLKOUT2
MicroBoardXpsConnect1


Graphic Design Viewを確認します。
MicroBoardXpsConnect2


Design Rule Checkを行いErrorおよびWarningがないことを確認してXPSを終了します。

ISEプロジェクトの完成

ISEに戻って、Generate Top HDL Sourceを実行します。
IseProj1


AXI_MASTER_TEST_top.vが生成されます。
IseProj2


New Source WizardでISEプロジェクトに新しくテストベンチファイルを追加します。
IseProj3


AXI_MASTER_TEST_topを選択します。
IseProj4


先ほど生成したLPDDR SDRAMのシミュレーションモデル「AXI_MASTER_TEST/AXI_MASTER_TEST/__xps\MCB3_LPDDRのlpddr_model.v」をプロジェクトに追加します。
IseProj5


lpddr_modelがプロジェクトに追加されました。

IseProj6a


lpddr_modelとの接続等をテストベンチファイルAXI_MASTER_TEST_tf.vに記述します。
IseProj7


【AXI_MASTER_TEST_tf.v】

`timescale 1ps / 1ps

module AXI_MASTER_TEST_tf;

	// Inputs
	reg RESET;
	reg CLK_66MHZ;

	// Outputs
	wire mcbx_dram_we_n;
	wire mcbx_dram_udm;
	wire mcbx_dram_ras_n;
	wire mcbx_dram_ldm;
	wire mcbx_dram_clk_n;
	wire mcbx_dram_clk;
	wire mcbx_dram_cke;
	wire mcbx_dram_cas_n;
	wire [1:0] mcbx_dram_ba;
	wire [12:0] mcbx_dram_addr;
	wire axi_master_0_error;

	// Bidirs
	wire rzq;
	wire mcbx_dram_udqs;
	wire mcbx_dram_dqs;
	wire [15:0] mcbx_dram_dq;

	// Instantiate the Unit Under Test (UUT)
	AXI_MASTER_TEST_top uut (
		.rzq(rzq),
		.mcbx_dram_we_n(mcbx_dram_we_n),
		.mcbx_dram_udqs(mcbx_dram_udqs),
		.mcbx_dram_udm(mcbx_dram_udm),
		.mcbx_dram_ras_n(mcbx_dram_ras_n),
		.mcbx_dram_ldm(mcbx_dram_ldm),
		.mcbx_dram_dqs(mcbx_dram_dqs),
		.mcbx_dram_dq(mcbx_dram_dq),
		.mcbx_dram_clk_n(mcbx_dram_clk_n),
		.mcbx_dram_clk(mcbx_dram_clk),
		.mcbx_dram_cke(mcbx_dram_cke),
		.mcbx_dram_cas_n(mcbx_dram_cas_n),
		.mcbx_dram_ba(mcbx_dram_ba),
		.mcbx_dram_addr(mcbx_dram_addr),
		.RESET(RESET),
		.CLK_66MHZ(CLK_66MHZ),
		.axi_master_0_error(axi_master_0_error)
	);

	lpddr_model mem (
		.Dq(mcbx_dram_dq),
		.Dqs({mcbx_dram_udqs, mcbx_dram_dqs}),
		.Addr(mcbx_dram_addr),
		.Ba(mcbx_dram_ba),
		.Clk(mcbx_dram_clk),
		.Clk_n(mcbx_dram_clk_n),
		.Cke(mcbx_dram_cke),
		.Cs_n(1'b0),
		.Ras_n(mcbx_dram_ras_n),
		.Cas_n(mcbx_dram_cas_n),
		.We_n(mcbx_dram_we_n),
		.Dm({mcbx_dram_udm, mcbx_dram_ldm})
	);

	initial begin
		// Initialize Inputs
		RESET = 1;
		CLK_66MHZ = 0;

		// Wait 100 ns for global reset to finish
		#100;
  		RESET = 0;

		// Add stimulus here
		forever begin
			CLK_66MHZ = ~CLK_66MHZ;
			#(7576);
		end

	end

endmodule

シミュレーションの実効

Isim simulatorを実行すると、ワーニングが発生します。
ISim1


Isimの方を確認しても、確かに、Dq 32ビット, Addr 14ビット, DM 4ビットとなっています。
ISim2


プロジェクトのAutomatic `includesにあるlpddr_model_parameters.vhを見てみると、メモリ種別に対するifdefがあります。
XPSを再度立ち上げて、MCB3_LPDDRのMIGを起動しすると、MCB3_LPDDRのメモリパートは、MCBMT46H32M16XXXX-5が選択されています。
ISim3


isim Process Propertiesの-d(Specify `define Macro Name and Value)にx512Mb|sg5|x16と入力します。(sg5 = -5 (CL=3))
パラメータは必ず”|”で結合してください。スペースも不可です。
x512Mb sg5 x16
x512Mb | sg5 | x16
これらでは、認識しません。
ISim4


isimを再起動すると、mem::Addr[12:0] mem::Dq[15:0] mem::Dm[1:0]となり、シミュレーションが成功します。
ISim5

タグ


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

カテゴリー:技術情報

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

カテゴリー:技術情報

PICマイコン USB HOST(USB Framework)のベンダークラス対応

マイクロチップ・テクノロジー社より提供されているApplication librariesに含まれるUSB Framework(v2013-06-15)を使用して、USBホストを構築する場合に、USBの標準クラスを使用する場合は問題ありませんが、ベンダークラスを使用した場合には、一部不適合箇所があります。

【usb_host.c】

BYTE USBHostIssueDeviceRequest( BYTE deviceAddress, BYTE bmRequestType,
            BYTE bRequest, WORD wValue, WORD wIndex, WORD wLength,
            BYTE *data, BYTE dataDirection, BYTE clientDriverID )
{
		・
		・
		・
    // If the user is doing a SET INTERFACE, we must reset DATA0 for all endpoints.
    if (bRequest == USB_REQUEST_SET_INTERFACE)		// !問題箇所
    {
        USB_ENDPOINT_INFO           *pEndpoint;
        USB_INTERFACE_INFO          *pInterface;
        USB_INTERFACE_SETTING_INFO  *pSetting;

条件文が(bRequest == SET_INTERFACE)となっていますが、SET_INTERFACEというのは標準リクエストでの値は[11]である為、ベンダーリクエストで値が[11]の要求があった場合に、上記の処理が意図せず実行されてしまいます。
以下のように修正することで、bmRequestTypeを「ホストからデバイス」「標準リクエスト」「リクエスト対象がデバイス」に限定します。

【usb_host.c】
BYTE USBHostIssueDeviceRequest( BYTE deviceAddress, BYTE bmRequestType,
            BYTE bRequest, WORD wValue, WORD wIndex, WORD wLength,
            BYTE *data, BYTE dataDirection, BYTE clientDriverID )
{
		・
		・
		・
    // If the user is doing a SET INTERFACE, we must reset DATA0 for all endpoints.
//  if (bRequest == USB_REQUEST_SET_INTERFACE)		// !修正箇所
    if ((bRequest == USB_REQUEST_SET_INTERFACE)
      && (bmRequestType == USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_DEVICE))
    {
        USB_ENDPOINT_INFO           *pEndpoint;
        USB_INTERFACE_INFO          *pInterface;
        USB_INTERFACE_SETTING_INFO  *pSetting;

ベンダーリクエストに[11]が存在するデバイス用のドライバを開発する場合は、この対応が必須となります。

タグ


2013年10月17日 | コメントは受け付けていません。|

カテゴリー:技術情報

このページの先頭へ

イメージ画像