FPGA 開発においてコンパイルを実行する前に、作成した論理回路 (デザイン) が期待通りの動作になっているかを確認することは
重要なことです。
ハードウェア言語 (HDL) による設計が主流である現在では、論理シミュレーションも言語でおこないます。
シミュレーションには入力パターン情報が欠かせませんが、その入力パターンも設計者が HDL で記述し、それを "テストベンチ" と呼んでいます。
ここでは、テストベンチの超基本的な記述について紹介します。
VHDL の書式
テストベンチを作成するときも FPGA のデザインを作成するときと同様に パッケージの呼び出し と エンティティ部 (entity~)、アーキテクチャー部 (architecture~) を記述します。しかし、一般的にテストベンチには入出力ポートが存在しないため、エンティティ部にはポート宣言を記述する必要はありません。したがって各種宣言と回路記述部には、検証対象となるデザインへ入力する信号の入力条件を HDL で記述します。

各種宣言 (コンポーネント宣言 & 信号の宣言)

「各種宣言」をもう少し細かくすると、「コンポーネント宣言」と「信号の宣言」に分けることができます。
「回路記述部」で下位階層のデザインを呼び出す記述を書くときは、上位階層のアーキテクチャー部に下位階層デザインのコンポーネント宣言をします。コンポーネント宣言のコンポーネント名は、下位階層のエンティティ名と同じにした方がわかりやすいです。
下位階層デザインの全ポート名を port の後の () 内に記述してください。ポートの記述には入出力の方向やデータ型を記述しますが、これらは下位階層デザインのエンティティ部と同じにしないと、正しくシミュレーションできません。
例)
component top_tb
port (
clock : in std_logic;
resetn : in std_logic;
test : in std_logic;
datain : in std_logic_vector (7 downto 0);
dataout : out std_logic_vector (7 downto 0)
);
end component;
「信号の宣言」は、エンティティ部で使用する信号を宣言します。
検証対象デザイン (主に最上位階層) への入力信号や検証対象デザインからの出力信号、テストベンチ内だけで使用する信号を signal 文 を使用して信号名とデータ型を記述します。
例)
signal CLOCK : std_logic;
signal RESETn : std_logic;
signal TEST : std_logic;
signal DATAIN : std_logic_vector (7 downto 0);
signal DATAOUT : std_logic_vector (7 downto 0);
回路記述部 (下位階層の呼び出し & 入力条件の記述)

「下位階層 (検証対象デザイン) の呼び出し」は、通常の下位階層の呼び出しの記述と同様です。
インスタンス名 : エンティティ名
port map (
下位階層のポート名 => 現階層の信号名,
下位階層のポート名 => 現階層の信号名,
下位階層のポート名 => 現階層の信号名
);
以下は、インスタンス名を "u1"、検証対象デザインのエンティティ名を "top" とした場合の記述例です。
例)
u1 : top
port map (
clock => CLOCK,
resetn => RESETn,
test => TEST,
datain => DATAIN,
dataout => DATAOUT
);
下位階層 (検証対象デザイン) への入力条件の記述

ここでは主に
- 常にレベルが固定している信号の記述
- 一定間隔で値がインクリメントする信号の記述
- 定期的または非定期的に '1' (High レベル)と '0' (Low レベル) を繰り返す信号の記述
について説明します。
これらをマスターすれば、テストベンチを自分で書けるようになります。
なお、ここで紹介した以外の記述方法もありますので、後々勉強して習得してください。
1. 常にレベルが固定している信号の記述
1行で記述できます。
なお 数値を記入する際、シングルビットの場合は ' ' (シングルクォーテーション) で囲み、複数ビットの場合は " " (ダブルクォーテーション) で囲みます。

2. 一定間隔で値がインクリメントする信号の記述
process begin の後に初期値を記述します。
その後 loop 文 を使って一定間隔でインクリメントする式を記述します。
なお 数値を記入する際、シングルビットの場合は ' ' で囲み、複数ビットの場合は " " で囲みます。

3. 定期的または非定期的に '1' (High レベル) と '0' (Low レベル) を繰り返す信号の記述
process begin の後に初期値を記述し、その後 wait for の後に次の値の変化までの時間を記述します。
なお 数値を記入する際、シングルビットの場合は ' ' で囲み、複数ビットの場合は " " で囲みます。
この記述では、一番下まで実行したら process 文 を抜け、最初に戻って実行し、繰り返します。

クロックの例では、この記述で 5ns ごとに '0' (Low レベル) と '1' (High レベル) を永遠に繰り返します。
つまり 1周期が 10ns (100MHz) のクロック信号となります。

サンプルデザイン
以下のページから演習データをダウンロードできます。
このサンプルはテストベンチの記述も使われているので、参考にしてください。
コーヒー・ブレイク:センシティビティー・リスト

センシティビティー・リストとは、VHDL の process 文の直後の ( ) 内に記述する信号で、この信号が変化した時にこのプロセスがアクティブになって、begin~end process 内の処理が実行されます。シミュレーションの場合は、記入しないケースがあります。センシティビティー・リストを記述しない時は ( ) も不要です。シミュレーション開始と共に実行を始め、一番下まで行くと再び一番上から実行を始め、永久に繰り返します。
コーヒー・ブレイク:シミュレーションの停止

VHDL には、シミュレーションを停止する専用の文がありません。したがって、先ほど紹介した process 文 を使用した記述だけでは、シミュレータでシミュレーションを停止させるか、もしくはシミュレーション時間を指定して実行しないと永遠に終わりません。そこで、テストベンチにシミュレーションを終わらせるための記述を書きたい時は、wait を使用します。
左下の例では、100ns + 200ns + 400ns + 2000ns = 2,700 ns 経過したら process 文 を抜け、最初に戻って実行し、繰り返します。
右下の例のように、end process の手前に wait を記述すれば、2,700ns 後にシミュレーションが停止します。
