VHDLっていうと、IF文やCASE文を使っていろいろな条件を書いて回路を作っていくイメージですが、あまり知られていない文法がたくさんあります。
genericとfunctionを組み合わせて強力なパラメタライズをしたりとか、シミュレーション中でPROCEDUREを使って関数呼び出しをしたりとか、実はいろいろなことができるのです。そんなVHDLの高度な使い方を解説していきたいと思います。
今日は、シミュレーションを劇的に高度化するTEXTIOについて説明したいと思います。
TEXTIOを使うとVHDLのシミュレーション中にファイルの入出力ができるようになります。検証結果をファイルに書き込んだり、波形データをファイルから読み込んだりすることができるようになります。
波形データやパラメータをファイルから読み込むようにするとシミュレーションを再スタート(relaunch)しなくても、時刻を0に戻してから再Runすればよくなるので、シミュレーション時間の短縮にもつながります。また、Vivadoの画面上で波形を確認するのではなく、結果がファイルに書き込まれるので見るのも楽になります。
Vivadoではシミュレーションを行うためのソースとテストベンチを合わせて見えないところでEXEファイルを作り、そのEXEファイルを実行することシミュレーションを行っているようなので、検証の条件をファイルから読み込むようにすればEXEの再生成をしなくて済むようになります。
なので、TEXTIOを使ってファイル読み書きができるようになりましょう!
まず、TEXTIOを使うには、VHDLの先頭で
use ieee.std_logic_textio.all;
use std.textio.all;
を宣言しておきます。
ファイルを使うには変数や信号を宣言するところで、
file WRITE_FILE : text open write_mode is "result.txt";
のように宣言と同時にOpenしてもいいですし、宣言では
file F_SETTING : text;
と変数だけ作っておいて、PROCESS文の中で
file_open(F_SETTING, "setting.txt", READ_MODE);
として動的に開いてもよいでしょう。閉じるときはfile_close(F_SETTING);
file_close(F_SETTINGS);
で閉じます。シミュレーションが異常終了してファイルが閉じていないとWindowsの他のプログラムから書き換えできなくなるので、後者のやり方がおすすめです。
さて、ファイルを書き込むほうを見ていきましょう。といっても、TEXTIOで使える関数は、
procedure writeline(file f : text; l : inout line);
procedure write(l : inout line; value : in bit; justified : in side := RIGHT; field : in width := 0);
procedure write(l : inout line; value : in bit_vector; justified : in side := RIGHT; field : in width := 0);
procedure write(l : inout line; value : in boolean; justified : in side := RIGHT; field : in width := 0);
procedure write(l : inout line; value : in character; justified : in side := RIGHT; field : in width := 0);
procedure write(l : inout line; value : in integer; justified : in side := RIGHT; field : in width := 0);
procedure write(l : inout line; value : in real; justified : in side := RIGHT; field : in width := 0; digits : in natural := 0);
procedure write(l : inout line; value : in string; justified : in side := RIGHT; field : in width := 0);
procedure write(l : inout line; value : in time; justified : in side := RIGHT; field : in width := 0; unit : in time := ns);
くらいです。
あと、hwriteとowriteというのがあります。これは16進数や8進数で出力してくれるというもので、hwrite(lo, target_signal)のようにして使います。
驚くほど貧弱ですが、規格に腹を立てずに使いこなしてください。
VHDLは処理系としては貧弱ですが一丁前に関数のオーバーライドやデフォルトパラメータが使えます。基本的にはwrite関数でlineを作って、そのlineをwritelineで出力するというしくみです。第三引数以下は省略してかまいません。
write関数は第二引数に取った変数や信号の型に応じていろいろなタイプのwriteが用意されています。
第一引数のlというのは「アクセス」という特殊な型でmallocやdeleteをした動的なメモリ領域なのですが、深入りはせずに、使い方だけ示します。
process (・・・)
variable lo : line;
variable test : integer := 123;
begin
write(lo , VAL1);
writeline(WRITE_FILE, test);
・・・
です。
writeでloに行を詰め込んでいって、writelineで吐き出す。それと同時にloはクリアされるというしくみです。
std_logic_vectorもstd_logicもintegerもいい感じに表示してくれますが、real型は +3.0000000e5みたいな形式となるので使いにくいですね。
時刻を出力する際には、
write(lo, integer(current_time / 1 ns));
というふうに、1ns単位に割り算してからinteger型にキャストするといいでしょう。
さて、シミュレーションの結果ファイルに文字列を書き込みたい場合もあるでしょう。文字列を扱うのはちょっと大変です。
シミュレータに文字列型として認識させてやらねばならいません。そのためには、文字列の即値を作るSTRING'()というのを使って、
write(lo, STRING'("SUCCESS"));
のようにしたり。もしくは、
write(lo, "SUCCESS" &LF);
のように、CHARACTER型やSTRING型のと&で結合させてSTRING型にします。
ここで出てきたLFというのは改行コードです。VHDLでは""の中に\nと書いても改行にはなりません。よく使う特殊記号はLFのほかに、TABを示すHT(コード08)や、NBSP(コード160)があります。
文字列と数値などの相互変換はとても大変ですが、一応用意されています。数値(integer)を文字列に変換するにはinteger'image(value)というのを使います。例えば、Iという変数を書き出したい場合には、
write(lo, "CH=(" & integer'image(I) & ") . ");
のようにします。
とにかく用意されている機能が貧弱なのですが、TEXTIOで頑張ることで
# DAQTEST SIMULATION RESULT
#TIME[us] ADC1[mV]
0 0*
10 1000
20 1200
・・・
RESULT(0) SUCCESS , PERIOD=310[ns]
のような人間に読みやすいレポートを作成することができるようになります。
(続く)
最近のコメント