ModelSim で $messagelog を使う のバックアップ差分(No.1)

更新


  • 追加された行はこの色です。
  • 削除された行はこの色です。
[[公開メモ]]

#contents

* $messagelog [#qc78c59d]

verilog でテストベンチを書く際に画面にテキストを表示するには通常 
$display を使うのですが、ModelSim では $messagelog を使うと便利です。

テストベンチに

 LANG:verilog
 always @(posedge iclk_int)
     if (full & we)
         $messagelog("Write strobe was asserted while fifo is full.", "Error")

などと書いておけば、$display のように出力ウィンドウにメッセージを表示すると共に、
下図のように wave ウィンドウの message 欄にメッセージが表示された時刻を示す ▼ 
が表示されます(&COLOR(blue){青丸};)。

&attach_ref;

▼ の上にカーソルを持って行けば表示されたメッセージを見ることができますので、
$display に表示された時刻を目で追うような苦労から解放されます。

また、message 欄のタイトル部分(&COLOR(red){赤丸};)をクリックすることで、
アクティブなカーソルを次の ▼ まで飛ばすことができます。

そのようにすれば、▼ を目で探す必要もありません。

さらに、メニューの [View] - [Messsage Viewer] にチェックが入っていれば、
wave ウィンドウの隣に Message Viewer タブが出ます(&COLOR(purple){紫丸})。
ここでは、表示されたメッセージを条件別に並べ替えて表示するようなことも可能です。

&attach_ref;

(ちょっとメッセージ内容が違っているのは下記のルーチンを使っているためです)

* $messagelog を便利に利用するためのマクロ [#u3affc0e]

上記の通り $messagelog はとても便利なのですが、
そのままソースコードに書き込んでしまうと、
ModelSim 以外でテストするのが難しくなってしまいます。

そこで、直接 $messagelog を呼ぶのではなくマクロを使って記述することにしました。

simulation.inc
 LANG:verilog
 `ifndef VERBOSE
     `define VERBOSE 0
 `endif
 
 `define INFO(msg) \
     if(`VERBOSE) \
         $messagelog(`"%:S msg.`", "Note")
 
 `define ERROR(msg) \
     $messagelog(`"%:S msg.`", "Error")
 
 `define DONE \
     $messagelog(`"%:S Done.`", "Note")
 
 `define ASSERT(variable,value) \
     if((variable)!=(value)) \
         $messagelog(`"%:S Assertion [ variable == value ] was not met.`", "Error")
 
 `define ASSERT_ALWAYS(variable,value) \
     always @(variable) \
         if((variable)!=(value)) \
             $messagelog(`"%:S Assertion [ variable == value ] was not met.`", "Error")
 
 `define ASSERT_ON_CLK(clk,variable,value) \
     always @(clk) \
         if((variable)!=(value)) \
            $messagelog(`"%:S Assertion [ variable == value @ clk ] was not met.`", "Error")
 
上記を `include して使うようにしていれば、
ModelSim 以外でシミュレーションする必要が生じたときにも
このマクロ定義だけを書き換えれば済みますので、便利だと思います。

* ASSERT マクロ群 [#uc3ec9a3]

本来ならこういったことをするのには OVM とか、
標準の検証ライブラリを使うべきなのでしょうけれど、
使い方を覚えるのが面倒なのに加えて、
記述量を減らしたいという欲求もあって、
上記のようなマクロを書いて使ってしまっています。

ASSERT や ASSERT_ALWAYS などを書くのに SystemVerilog の構文を使っているのですが、
与えた条件からエラーメッセージを自動生成してくれるため、
アサーションを記述するのがとても楽です。

上記 FIFO の例であれば、

 LANG:verilog
 always @(posedge iclk_int)
     if (full & we)
         $messagelog("Write strobe was asserted while fifo is full.", "Error")

の代わりに

 LANG:verilog
 `ASSERT_ON_CLK(posedge iclk_int, full && we, 0);

とするだけで、

 # ** Error: Assertion [ full  && we == 0 @ posedge iclk_int ] was not met.

というメッセージが得られます。

これだけだとエラーの発生箇所が分かりませんが、上記の通り
Message Viewer を使えば調べられますので、
エラーメッセージはあまり長くしない方が見やすいようです。

* 検証コードをソースに埋め込む [#g854ecdb]

上記のような検証コードはテストベンチに記述しても良いのですが、
ロジックを記述したソースコードに直接埋め込んでおくのが良いようです。

FIFO のソースコード中に

 LANG:verilog
 `include "simulation.inc"
 ...
 
 module fifo (
   ...
 
 );
 
    ...
 
    // synthesis translate_off
    `ASSERT_ON_CLK(posedge iclk_int, full  && we, 0);
    `ASSERT_ON_CLK(posedge oclk_int, empty && re, 0);
    // synthesis translate_on
 
 endmodule

のように、synthesis translate_off / synthesis translate_on 
で挟んで検証コードを埋め込んでおくと、
インプリメント時にはこの部分が無視されるので、
ソースコードを変更することなく検証と合成のどちらも行えます。

*** 注意 [#ybf136d7]

恐らく、この検証コードは Behavior レベルのテストでしか効果がありませんので、
合成結果に対するテストでは別途テストベンチに検証コードを記述する必要があるのだと思います。


Counter: 12076 (from 2010/06/03), today: 3, yesterday: 0