起動するには、左の図のように、テストベンチファイルにカーソルを合わせ、「Simulate Behavioral VHDL Model」をダブルクリックします。
ソースVHDLとテストベンチにエラーがなければ、ModelSIMが起動し、いろいろなウィンドウが表示されたあと、waveというウインドウが表示されます。結果のグラフィカルな表示はwaveウィンドウに表示されます。
ところがたとえテストベンチに1msくらいのシミュレーションを書いたとしても、実際には1usまでのシミュレーションしか行ってくれません。それはデフォルトの設定がそうなっているからです。
先ほど「Simulate Behavioral VHDL Model」でダブルクリックしましたが、代わりに右クリックをして「Property」を選びます。
すると、下のようなプロパティーが表れますので、「Simulation Run Time」を好きな値に設定します。
あまり長すぎると、シミュレーションが計算にかかりすぎて、なかなか制御が戻ってきませんのでご注意ください。
一度ModelSIMを起動した後で、再度シミュレーションを行うには2つの方法があります。(あるいはもっとある)
1.ModelSIMのメインのウィンドウで、コマンドから「> run 10000000」などと入力する。
この方法では、時間を指定してシミュレーションを実行できます。結果は画像で表示されます。デフォルトの単位はピコ秒のようです。
2.ModelSIMのメインのウィンドウで、コマンドから「> do テストベンチファイル名.fdo」などと入力する。ファイル名は拡張子vhdを抜き、fdoを付けてください。csync13m_test.vhdなら「do csync13m_test.fdo」になります。この方法ではModelSIMを再起動しなくても最新のVHDLとテストベンチが反映されるようです。
3.シミュレーションボタンを押す。
いくつかのボタンがありますが、すべてのボタンはコマンドでも同じ動作をさせることができます。
ただし、ソースVHDLやテストベンチを書き換えた場合は、手順2の「do ***.fdo」を行う必要があります。
std_logic_vector型などの信号はデフォルトでは11010などの2進数です。これを10進や16進で表示させたい場合、表示させたい信号名にカーソルを持っていき、右クリックします。そして、「Radix」を選びますと、中には8進数や10進数、16進だけでなく符号付10進数、ASCII文字などから選ぶことができます。
下の図は、NTSCインターレース同期信号発生回路で、VPOS(現在の走査線の値)を10進数で表示したものです。走査線が266の時のCSYNC(コンポジット同期信号)の値が見えます。10進で表示すると、このようにとても見やすくなります。
カウンタや、アナログ信号を扱う回路では波形をアナログで表示させたいときもあります。そんなときは、10進や16進で表示させるときと同じように、信号名を選択して右クリックします。
そして「Format」を選びます。Formatの中には
があります。アナログを選ぶと何やら数式が出てきます。
これは、信号の値にあるオフセット値を足して、それに係数を掛けるというものです。単位は恐らくピクセルではないかと思います。例えば信号の値が800で、オフセットが0、係数が0.01なら、8ピクセルで画面には表示されると思います。なお、画面表示はクリップされませんので、上と下の波形が重なってしまうこともあります。
下のシミュレーションでは、各アナログ信号の値が-32768から32767であると期待されているので、オフセットとして32768を足し、係数として0.001を掛けています。
メインメニューの「Edit->Display Properties...」を選択し、「RowMargin」の値を増やすと信号表示の縦幅を増やすことができます。下の図はRowMarginを30にしているため、デフォルトの状態よりも縦が広くなっています。
参考までに、上記のアナログ波形シミュレーションに使ったソースVHDLを載せます。
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity main is Port ( CLK : in std_logic; RESET : in std_logic; OUTX : out Integer; OUTY : out Integer; OUTX2 : out Integer; OUTY2 : out Integer; OUTP : out Integer ); end main; architecture Behavioral of main is signal X: Integer; signal Y: Integer; signal X2: Integer; signal Y2: Integer; begin process(clk) begin if(clk'event and clk='1') then if(reset = '1') then X <= 16383; Y <= 0; X2 <= 16383; Y2 <= 0; else X <= X - Y / 2560; Y <= Y + X / 2560; X2 <= X2 - Y2 / 256; Y2 <= Y2 + X2 / 256; end if; OUTX <= X; OUTY <= Y; OUTX2 <= X2; OUTY2 <= Y2; OUTP <= (X / 256) * (X2 / 256); end if; end process; end Behavioral; |
擬似的な三角関数発生の仕組みは簡単です。まず、2次元ベクトル平面上の点の回転を考えます。座標(x,y)にあった点が、角度θ回転した後の座標(x',y')は
x'=x*cosθ-y*sinθ
y'=y*cosθ+x*sinθ
になります。延々と回転を繰り返せば、点の軌跡は原点を中心とした円の上を回転します。Xだけ、もしくはYだけを取り出せばそれは擬似的に三角関数になっているわけです。
さて、ここで、θが極めて小さいときにはsinθ≒θで、cosθ≒1と近似できますから、
x'=x-y*θ
y'=y+x*θ
となります。三角関数を必要とせずに、掛け算だけで円上の点の振る舞いを算出できます。CPUパワーの弱い8ビット機で立体表示を行う場合には重宝しました。
ところが、三角関数を近似しているため、長い間計算していると誤差が蓄積されてきます。そのため、徐々に波形の振幅が拡大あるいは縮小してしまうという欠点があります。
なお、こんな簡単なVHDLでも実際のデバイスにフィットさせるには、SpartanIIの200kゲートでもだめで、VirtexEの300kゲートが必要でした。やはり頭を使って洗練されたVHDLファイルを書かなければ、実際のデバイスにフィットさせるのは簡単ではありません。
-- VHDL Test Bench Created from source file main.vhd -- 01:24:26 08/03/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 main PORT( CLK : IN std_logic; RESET : IN std_logic; OUTX : OUT Integer; OUTY : OUT Integer; OUTX2: OUT Integer; OUTY2: OUT Integer; OUTP : OUT Integer ); END COMPONENT; SIGNAL CLK : std_logic; SIGNAL RESET : std_logic; SIGNAL OUTX : Integer; SIGNAL OUTY : Integer; SIGNAL OUTX2: Integer; SIGNAL OUTY2: Integer; SIGNAL OUTP : Integer; BEGIN uut: main PORT MAP( CLK => CLK, RESET => RESET, OUTX => OUTX, OUTY => OUTY, OUTX2 => OUTX2, OUTY2 => OUTY2, OUTP => OUTP ); -- *** Test Bench - User Defined Section *** tb : PROCESS VARIABLE step: INTEGER RANGE 0 to 999999; CONSTANT period: time := 50 ns; BEGIN step := 1; RESET <= '1'; while (step < 10000000) loop if(step = 3) then RESET <= transport '0'; elsif(step * period > 4 ms) then RESET <= transport '0'; elsif(step * period > 3 ms) then RESET <= transport '1'; end if; if(step * period > 5 ms) then wait; 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; -- *** End Test Bench - User Defined Section *** END; |