階層構造_構文編(Verilog)

階層構造_構文編(Verilog)

本ブログは階層構造_構文編(VHDL)をVerilogに書き直したものです。内容は同一ですので、両方の言語を学ばれる方は並べて読んでください。 

HDLで設計するときに、1つのテキストファイルですべてを記述することはありません。多くの場合、仕様書に従ってブロック別に記載していきます。

 ブロック別にHDLファイルで設計する際には、1つのブロックを1つの階層で作っていきます。そして、いくつかの階層を構成して最上位にトップファイルという統括するファイルを作成します。簡単な階層構造の例を次に示します。

Verilog階層構造の例

 一番上位にworkという記載がありますが、これは使っている統合開発環境によって違います。その一つ下のpractice_topと記載された部分に着目してください。

 practice_top.vはこのプロジェクトの最上位ファイルです。先ほど、統括する。と記載しましたが、これがそのファイルです。統合開発環境を使うと、最上位ファイルはこのように上位に位置していることがツリー構造の構成図で表示されるので、わかりやすいと思います。

 困ったことに、VHDLもVerilogも言語の仕様としては自動で最上位のファイルを見つけることができません。統合開発環境だから階層構造が分かりやすいのです。これは、半年後にプロジェクトを読み解こうとすると、必ず統合開発環境を立ち上げなくてはならない。という事につながります。

 メーカーの統合開発環境は頻繁にバージョンアップを繰り返します。したがって、半年経つとバージョンが上がっていて、古いプロジェクトファイルもそれに合わせてコンバートしなくてはならない場合があります。

 このような面倒なことが起こらないように、統合開発環境以外の仕様書でツリー構造をドキュメント化しておく事をお勧めします。ファイルが多くなると大変なのですが、その時には最上位ファイルだけを判別できるようにしてください。

 最上位さえわかれば、あとはソースコードをテキストエディターで開いて追いかける事ができます。私の場合には、最上位ファイル名に必ず top を付けるようにしています。

 それでは、practice_top.vhdのファイルを見てみましょう。

//  TITLE:					"practice_top.v"
//  MODULE NAME:			practice_top
//  PROJECT CODE:			
//  AUTHOR:					 (****@nakaharagiken.com)
//  CREATION DATE:			2020.1.1
//  SOURCE:            		
//  LICENSE:           		Copyright (c) 2020 nakaharagiken All rights reserved. 
//  DESCRIPTION:            練習用FPGAトップファイル
//  NOTES TO USER:			
//  SOURCE CONTROL:			
//  REVISION HISTORY:  	    v0.1	2020.1.2	First edition
//
//
//
//
//
//
//

`timescale 1ns/1ps


module practice_top(
	pClock,									//	in	system clock
	pnreset,								//	in	asynchronous reset 				____reset___|~~~normal~~~
	penable,								//	in	enable							________|~enable~|_______
	pSwitchIn_A,							//	in	入力ピンからの信号A 				
	pSwitchIn_B,							//	in	入力ピンからの信号B				
	pSwitchIn_C,							//	in	入力ピンからの信号C 				
	pSwitchIn_D,							//	in	入力ピンからの信号D				
	pinput_sel_AB,							//	in	入力ピンからのセレクト信号		___input_A__|~~input_B~~~
	pinput_sel_CD,							//	in	入力ピンからのセレクト信号		___input_C__|~~input_D~~~
	poutput_ans_AB,							//	out	A/B選択結果信号,レジスタ付き
	poutput_ans_CD							//	out	C/D選択結果信号,レジスタ付き
);

input	pClock;								//	in	system clock
input	pnreset;							//	in	asynchronous reset 				____reset___|~~~normal~~~
input	penable;							//	in	enable							________|~enable~|_______
input	pSwitchIn_A;						//	in	入力ピンからの信号A 				
input	pSwitchIn_B;						//	in	入力ピンからの信号B				
input	pSwitchIn_C;						//	in	入力ピンからの信号C 				
input	pSwitchIn_D;						//	in	入力ピンからの信号D				
input	pinput_sel_AB;						//	in	入力ピンからのセレクト信号		___input_A__|~~input_B~~~
input	pinput_sel_CD;						//	in	入力ピンからのセレクト信号		___input_C__|~~input_D~~~
output	poutput_ans_AB;						//	out	A/B選択結果信号,レジスタ付き
output	poutput_ans_CD;						//	out	C/D選択結果信号,レジスタ付き


///////////////////////////////////////////////////////////////
// SIGNALS
///////////////////////////////////////////////////////////////
wire	wSwitchIn_A_DFF;					// pSwitchIn_Aのメタステーブル対策後 2clock遅れ
wire	wSwitchIn_B_DFF;					// pSwitchIn_Bのメタステーブル対策後 2clock遅れ
wire	wSwitchIn_C_DFF;					// pSwitchIn_Cのメタステーブル対策後 2clock遅れ
wire	wSwitchIn_D_DFF;					// pSwitchIn_Dのメタステーブル対策後 2clock遅れ

wire	winput_sel_AB_DFF;					// pinput_sel_ABのメタステーブル対策後 2clock遅れ
wire	winput_sel_CD_DFF;					// pinput_sel_CDのメタステーブル対策後 2clock遅れ

wire	wseldata_AB;						// pSwitchIn_A/Bのセレクト結果
wire	wseldata_CD;						// pSwitchIn_C/Dのセレクト結果





///////////////////////////////////////////////////////////////
// pSwitchIn_Aのメタステーブル対策
///////////////////////////////////////////////////////////////
Synchronizing inst_SwitchIn_A_Synchronizing (
	.clock			(pClock),				//	in	std_logic	system clock
	.nreset			(pnreset),				//	in	std_logic	asynchronous reset 				____reset___|~~~normal~~~
	.enable			(1'b1),					//	in	std_logic	enable							________|~enable~|_______
	.indata			(pSwitchIn_A),			//	in	std_logic	入力信号
	.outdata		(wSwitchIn_A_DFF)		//	out	std_logic	出力信号
);

///////////////////////////////////////////////////////////////
// pSwitchIn_Bのメタステーブル対策
///////////////////////////////////////////////////////////////
Synchronizing inst_SwitchIn_B_Synchronizing (
	.clock			(pClock),				//	in	std_logic	system clock
	.nreset			(pnreset),				//	in	std_logic	asynchronous reset 				____reset___|~~~normal~~~
	.enable			(1'b1),					//	in	std_logic	enable							________|~enable~|_______
	.indata			(pSwitchIn_B),			//	in	std_logic	入力信号
	.outdata		(wSwitchIn_B_DFF)		//	out	std_logic	出力信号
);

///////////////////////////////////////////////////////////////
// pSwitchIn_Cのメタステーブル対策
///////////////////////////////////////////////////////////////
Synchronizing inst_SwitchIn_C_Synchronizing (
	.clock			(pClock),				//	in	std_logic	system clock
	.nreset			(pnreset),				//	in	std_logic	asynchronous reset 				____reset___|~~~normal~~~
	.enable			(1'b1),					//	in	std_logic	enable							________|~enable~|_______
	.indata			(pSwitchIn_C),			//	in	std_logic	入力信号
	.outdata		(wSwitchIn_C_DFF)		//	out	std_logic	出力信号
);

///////////////////////////////////////////////////////////////
// pSwitchIn_Dのメタステーブル対策
///////////////////////////////////////////////////////////////
Synchronizing inst_SwitchIn_D_Synchronizing (
	.clock			(pClock),				//	in	std_logic	system clock
	.nreset			(pnreset),				//	in	std_logic	asynchronous reset 				____reset___|~~~normal~~~
	.enable			(1'b1),					//	in	std_logic	enable							________|~enable~|_______
	.indata			(pSwitchIn_D),			//	in	std_logic	入力信号
	.outdata		(wSwitchIn_D_DFF)		//	out	std_logic	出力信号
);

///////////////////////////////////////////////////////////////
// pinput_sel_ABのメタステーブル対策
///////////////////////////////////////////////////////////////
Synchronizing inst_pinput_sel_AB_Synchronizing (
	.clock			(pClock),				//	in	std_logic	system clock
	.nreset			(pnreset),				//	in	std_logic	asynchronous reset 				____reset___|~~~normal~~~
	.enable			(1'b1),					//	in	std_logic	enable							________|~enable~|_______
	.indata			(pinput_sel_AB),		//	in	std_logic	入力信号
	.outdata		(winput_sel_AB_DFF)		//	out	std_logic	出力信号
);

///////////////////////////////////////////////////////////////
// pinput_sel_CDのメタステーブル対策
///////////////////////////////////////////////////////////////
Synchronizing inst_pinput_sel_CD_Synchronizing (
	.clock			(pClock),				//	in	std_logic	system clock
	.nreset			(pnreset),				//	in	std_logic	asynchronous reset 				____reset___|~~~normal~~~
	.enable			(1'b1),					//	in	std_logic	enable							________|~enable~|_______
	.indata			(pinput_sel_CD),		//	in	std_logic	入力信号
	.outdata		(winput_sel_CD_DFF)		//	out	std_logic	出力信号
);

///////////////////////////////////////////////////////////////
// SwitchIn_A,SwitchIn_Bの切り替え
///////////////////////////////////////////////////////////////
datasel inst_AB_datasel (
	.clock			(pClock),				//	in	std_logic	system clock
	.nreset			(pnreset),				//	in	std_logic	asynchronous reset 			____reset___|~~~normal~~~
	.enable			(1'b1),					//	in	std_logic	enable						________|~enable~|_______
	.SwitchIn_A		(wSwitchIn_A_DFF),		//	in	std_logic	入力信号A 				
	.SwitchIn_B		(wSwitchIn_B_DFF),		//	in	std_logic	入力信号B				
	.input_sel		(winput_sel_AB_DFF),	//	in	std_logic	入力のセレクト信号			___input_A__|~~input_B~~~
	.output_ans		(wseldata_AB)			//	out	std_logic	A/B選択結果信号,レジスタ付き
);

///////////////////////////////////////////////////////////////
// SwitchIn_C,SwitchIn_Dの切り替え
///////////////////////////////////////////////////////////////
datasel inst_CD_datasel (
	.clock			(pClock),				//	in	std_logic	system clock
	.nreset			(pnreset),				//	in	std_logic	asynchronous reset 				____reset___|~~~normal~~~
	.enable			(1'b1),					//	in	std_logic	enable							________|~enable~|_______
	.SwitchIn_A		(wSwitchIn_C_DFF),		//	in	std_logic	入力信号A 				
	.SwitchIn_B		(wSwitchIn_D_DFF),		//	in	std_logic	入力信号B				
	.input_sel		(winput_sel_CD_DFF),	//	in	std_logic	入力のセレクト信号				___input_A__|~~input_B~~~
	.output_ans		(wseldata_CD)			//	out	std_logic	C/D選択結果信号,レジスタ付き
);


assign poutput_ans_AB = wseldata_AB;
assign poutput_ans_CD = wseldata_CD;

endmodule

 統合開発環境の場合、HDLのトップファイルを図形エディターでブロック図化して描く事ができます。クライアントから、最上位はブロック図で描く事。という仕様の場合もあります。

 私個人は指示の無い限りトップファイルもHDLで記述します。それは、先に述べたように統合開発環境はバージョンアップが激しくて、トップファイルを開くのに苦労することがあるからです。

 また、トップファイルはFPGAの出力ピンに直結するファイルになります。したがって、入出力ピンの仕様や意味をコメントで記述したくなります。これも図形エディターでは残しにくい情報です。

 Verilogの場合、下位層と接続するには71行目のように、下位モジュールを直接記述します。ふつうは階層のモジュール宣言部からコピーして編集します。

 このように下位層の接続はVHDLよりもVerilogの方が簡単です。71行目の場合には Synchronizing モジュールを inst_SwitchIn_A_Synchronizing という名前で接続しています。この行をインスタンスといいますが、名前は自由です。私は頭にinst_を付けるようにしています。

 インスタンス部分で、各入出力に信号を 接続しています。76行目の最後に「,」が無いことに注意してください。本来、このインスタンス部分は1行で書く事も多いのですが、私は各接続にコメントを記述するようにしているのでこのような書き方にしています。

 82行目にも同じSynchronizingというコンポーネントを使用しています。このように、コンポーネントを使いまわすことができます。

 同じようにdataselのコンポーネントも137行目と150行目で使いまわしています。

 階層構造の書き方はそのままシミュレーションの書き方になります。