新しいプロジェクトでVHDLファイルを作るだけでは、シミュレーションはできません。
シミュレーションを行うためには、テストベンチというファイルを作る必要があります。作り方は新規のVHDLソースを作るのと同様の手順です。WebPACKの新規ソースの作成画面へ行き、「VHDL Test Bench」を選択します。
次の例ではファイル名はcsync13m_testにしました。
「次へ」を押すと、どのVHDLソースに関連付けるかを聞かれます。ソースが1つしかなければ、先ほどのcsyncmainが表示されているはずなので、そのまま「次へ」を押します。
すると、先ほどのVHDLファイルを元にしたテストベンチというVHDLを作ってくれます。この中にVHDL形式で、テストしたい条件を記述します。
この一連の作業にどう言う意味があるのかは後ほど解説します。
-- VHDL Test Bench Created from source file csyncmain.vhd -- 10:03:51 08/01/2002 -- -- Notes: -- This testbench has been automatically generated using types std_logic and -- std_logic_vector for the ports of the unit under test. Xilinx recommends -- that these types always be used for the top-level I/O of a design in order -- to guarantee that the testbench will bind correctly to the post-implementation -- simulation model. -- LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE ieee.numeric_std.ALL; ENTITY testbench IS END testbench; ARCHITECTURE behavior OF testbench IS COMPONENT csyncmain PORT( CLK : IN std_logic; ENA : IN std_logic; RESET : IN std_logic; HPOS : INOUT std_logic_vector(9 downto 0); VPOS : INOUT std_logic_vector(9 downto 0); VBLNK : INOUT std_logic; BLANK : INOUT std_logic; VSYNC : OUT std_logic; HSYNC : OUT std_logic; CSYNC : OUT std_logic; FIELD : OUT std_logic; HD : OUT std_logic; VD : OUT std_logic ); END COMPONENT; SIGNAL CLK : std_logic; SIGNAL ENA : std_logic; SIGNAL RESET : std_logic; SIGNAL HPOS : std_logic_vector(9 downto 0); SIGNAL VPOS : std_logic_vector(9 downto 0); SIGNAL VSYNC : std_logic; SIGNAL HSYNC : std_logic; SIGNAL CSYNC : std_logic; SIGNAL FIELD : std_logic; SIGNAL HD : std_logic; SIGNAL VD : std_logic; SIGNAL VBLNK : std_logic; SIGNAL BLANK : std_logic; BEGIN uut: csyncmain PORT MAP( CLK => CLK, ENA => ENA, RESET => RESET, HPOS => HPOS, VPOS => VPOS, VSYNC => VSYNC, HSYNC => HSYNC, CSYNC => CSYNC, FIELD => FIELD, HD => HD, VD => VD, VBLNK => VBLNK, BLANK => BLANK ); -- *** Test Bench - User Defined Section *** tb : PROCESS BEGIN wait; -- will wait forever END PROCESS; -- *** End Test Bench - User Defined Section *** END; |
最後の部分に「*** Test Bench - User Defined Section ***」と書かれていますが、この中にシミュレーションしたい条件を自分で記述します。
ModelSIMはテストベンチを先頭から順に実行していきます。その中にプログラムを書くように各種の条件を指定することで、シミュレーションができます。
とりあえず、以下の2つの命令を知っていれば、シミュレーションができます。
この命令は、入力ピンをある状態にセットします。
例:RESET <= transport '1';
transport文にはafter文を付けることができるようです。たとえば、
RESET <= transport '0' after 5 ns;
とすると、RESETという信号をシミュレーション時に5ns後に遷移させます。なお、transport文は省略してしまっても機能してくれるようです。
この命令は、指定された時間を待ちます。
例:WAIT FOR 37.037 ns;
このように記述すると、シミュレーションは25ns待つという動作を行います。
また、waitの引数を書かなければ、永遠に待ちます。これはシミュレーションの最後の行に記述します。そうしないと、最後のコマンドを実行した後、また最初に戻ってやり直してしまいます。
例: WAIT;
クロックピンをCLKとして、20MHzのクロックを与えたいとします。20MHzのクロックは周期が50nsなので、'1'の期間が25ns、'0'の期間が25nsです。これをtransport文とwait文で書くと下のような表記になります。
CLK <= transport '1'; WAIT FOR 25 ns; CLK <= transport '0'; WAIT FOR 25 ns; CLK <= transport '1'; WAIT FOR 25 ns; CLK <= transport '0'; WAIT FOR 25 ns; CLK <= transport '1'; WAIT FOR 25 ns; CLK <= transport '0'; WAIT FOR 25 ns; CLK <= transport '1'; WAIT FOR 25 ns; CLK <= transport '0'; WAIT FOR 25 ns; CLK <= transport '1'; WAIT FOR 25 ns; CLK <= transport '0'; WAIT FOR 25 ns; CLK <= transport '1'; WAIT FOR 25 ns; CLK <= transport '0'; WAIT FOR 25 ns; CLK <= transport '1'; WAIT FOR 25 ns; CLK <= transport '0'; WAIT FOR 25 ns; CLK <= transport '1'; WAIT FOR 25 ns; CLK <= transport '0'; WAIT FOR 25 ns; CLK <= transport '1'; WAIT FOR 25 ns; CLK <= transport '0'; WAIT FOR 25 ns; ・ ・ ・ ・ ・ |
あらゆる意味で面倒くさいですね。
変数を使って楽に綺麗に書きましょう。
FOR文を使うと、クロックを延々と与えた場合の長時間の動作を観察するテストベンチを楽に作成できます。先ほどの「初級編応用例」で示したクロックを与える方法を、FOR文を使って書くと下のようになります。
for I in 0 to 1000000 loop CLK <= transport '1'; WAIT FOR 25 ns; CLK <= transport '0'; WAIT FOR 25 ns; end loop; |
この方法の欠点を挙げるとすれば、現在の時刻が簡単にわからないということではないでしょうか?上の例では25nsのwaitですが、これは周期をナノ秒であらわしたときに整数になったからです。例えばクロックが13.5MHzなどの半端な数の場合には、周期が74.074074・・・となってしまい、正確な現在時刻を知ることは難しくなります。
そのうえ、3回クロック経過した後にRESETを'0'に遷移させて、その後再びクロックを与える場合などは、FOR文を2回記述しなければなりません。
WHILE文もFOR文と同様に繰り返しを実行します。FOR文ではインクリメントする変数はFOR文の中で使う変数でしたが、WHILE文ではWHILE文の外でVARIABLE文を使って宣言しなければなりません。VALIABLE文の位置はPROCESS文とBEGINの間です。
IF文
IF文は何らかの値などを比較してアクションを起こす文です。VHDLのロジック記述での使い方と同じです。
以上の応用として、クロックを与えるすっきりとした記述方法を考えましたので参考までに載せます。
VARIABLE step: INTEGER RANGE 0 to 999999; VARIABLE sig_a: std_logic; CONSTANT period: time := 74.074 ns; BEGIN step := 1; RESET <= '1'; ENA <= '0'; while (step < 1000) loop if(step*period > 600 ns) then sig_a := '1'; else sig_a := '0'; end if; if(sig_a = '1') then RESET <= transport '0';end if; if(step = 10) then ENA <= transport '1' after 5 ns;end if; step := step + 1; CLK <= transport '1'; WAIT FOR period/2; CLK <= transport '0'; WAIT FOR period/2; end loop; wait; -- will wait forever END PROCESS; |
まず、2つの変数stepとsig_aを宣言しています。stepはクロックのステップ数を数えるための変数です。sig_aは600ns経過したら1に遷移する信号です。periodはクロックの周期です。
while文ではクロックを1000ステップまで数えるというループ条件にしています。
次のif文ではstep*periodつまり現在の時刻が600nsを超えていたらsig_aを'1'にします。その次のif文では先ほどのsig_aが'1'ならばRESET信号を'0'に遷移させます。つまり、シミュレーションが開始してから600ns経過した後の最初のクロックの立ち上がりでsig_aも遷移します。
一方、ENA信号はクロックのステップ数が10、つまり10個目のクロックで'1'に遷移します。しかしながら、after文があるので、実際の遷移はさらに5ns遅れ、シミュレーションが経過してから約740ns経過した後に遷移します。シミュレーション開始から745.74ns後になります。
いろいろと複雑な条件を書いてきましたが、これだけ使えばかなりのテスト条件を効率良く記述できるのではないでしょうか?
最後に、テストベンチとソースVHDLファイルの意味を簡単に説明します。
ModelSIMが実行するのは、ソースファイルではなくテストベンチファイルです。
テストベンチファイルもVHDLファイルですが、このVHDLファイルにはロジックは記述されません。テストベンチファイルの目的は、シミュレーションを実行するための手順を記述することです。このファイルには、例えば「Aという信号を1にする」や「何ns待つ」といった操作が書かれていて、ModelSIMはこの命令を忠実に実行してその結果を画面に表示します。
シミュレーション時にテストベンチから元のソースファイルを参照できるようにするために、ソースファイルのentity名を使って、元のソースファイルをコンポーネントとして宣言しています。そのため、ピンの指定などが必要になってきます。
ModelSIMはテストベンチに記述されたとおりに元のソースファイルのピンを'1'や'0'にします。その結果生じた出力ピンの状態をModelSIMは表示します。シミュレーションで操作と表示ができるのは、ピンとして宣言した信号で、内部ノード信号はシミュレーションできません。
なお、HDL Bencherはコンポーネントの宣言や、ピンの宣言の雛型を自動で作ってくれるツールです。