電気回路/HDL/ModelSim の radix define のバックアップ差分(No.8)

更新


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

#contents

* ステートマシンのステートを記号で表示したい [#sd720719]

ModelSim の wave ウィンドウでは信号線の状態を
2進数や16進数、アナロググラフなど、
さまざまな形式で表示することができます。

しかし、Verilog で書いたステートマシンのステートを、
分かりやすく記号で表示するのは一筋縄では行きません。

こんなのを例として考えます。

 LANG:verilog
 module trimac_tx (
  ...
 );
    ...
 
    localparam stIdle           = 0;
    localparam stMem            = 1;
    localparam stTx             = 2;
    localparam stUdpChecksum0     = 3;
    localparam stUdpChecksum1     = 4;
    localparam stUdpChecksum2     = 5;
    localparam stUdpChecksum3     = 6;
    localparam stUdpChecksum4     = 7;
    localparam stDone           = 8;
    localparam stRewound        = 9;
 
    reg [3:0] state;
    always @(posedge tx_clk)
        if ( rst ) begin
            state <= stIdle;
        end else
        case (state)
 
        stIdle: 
            if (tx_start)
                state <= stMem;
    ...

この state という信号は、stIdle, stMem などの値を取り得るのですが、
ModelSim 上では 0 や 1 などの数値として表示されてしまいます。

テスト時には頭の中で数値をステート名に翻訳しなければなりません。

これを数値ではなく記号で表示する方法として、以下の2つを見つけました。

色分けできること、処理が軽いこと、を考えると後者がお勧めです。

* 表示用の信号を別に用意する [#kb177b67]

http://cafeandverify.blogspot.com/2007/09/verilog-modeenum.html

にもあるように、テストベンチ側に表示用の信号を別に用意して、
それを wave ウィンドウに追加すれば、どんな表示も可能になります。

例えば、いくつかの状態を1つにまとめて表示するなどの応用も可能です。

 LANG:verilog
 string trimac_tx_state;
 always @(uut.trimac.tx.state)
     case (uut.trimac.tx.state)
     0:         trimac_tx_state = "Idle";
     1:         trimac_tx_state = "Mem";
     2:         trimac_tx_state = "Tx";
     3,4,5,6,7: trimac_tx_state = "UdpChecksumX";
     8:         trimac_tx_state = "Done";
     9:         trimac_tx_state = "Rewound";
     endcase;

string を使うとシミュレーション速度が気になる場合には、
SystemVerilog の enum 型に代入するだけでも良いのかもしれません。

これの応用で、[[ModelSim 用 PicoBlaze ディスアセンブラ>電気回路/HDL/ModelSim 用 PicoBlaze ディスアセンブラ]]を作ってみました。
PicoBlaze のテスト時に、インストラクションをアセンブラで表示できます。

* radix define を使う [#k00e70a5]

こちらは ModelSim のマニュアルから発見しました。

ModelSim の radix define コマンドを使います。

ModelSim の Transcript ウィンドウに以下を打ち込むか、
あるいは *.udo ファイルに以下を記述して読み込むと、
wave の Radix 指定で TrimacTxStates を選択できるようになります。

     radix define TrimacTxStates {
         4'd0 "Idle",
         4'd1 "Mem",
         4'd2 "Tx",
         4'd3 "UdpChecksum0",
         4'd4 "UdpChecksum1",
         4'd5 "UdpChecksum2",
         4'd6 "UdpChecksum3",
         4'd7 "UdpChecksum4",
         4'd8 "Done",
         4'd9 "Rewound"
         -default decimal
     }

この方法の良いところは、記号で表示するだけでなく以下のように色も指定できるため、
文字が読めないくらいまで表示を縮小した場合にも、大まかな流れが分かります。

     radix define TrimacTxStates {
         0 "Idle" -color white,
         1 "Mem" -color yellow,
         2 "Tx" -color yellow,
         3 "UdpChecksum0" -color yellow,
         4 "UdpChecksum1" -color yellow,
         5 "UdpChecksum2" -color yellow,
         6 "UdpChecksum3" -color yellow,
         7 "UdpChecksum4" -color yellow,
         8 "Done" -color yellow,
         9 "Rewound" -color red
         -default decimal
         -defaultcolor purple
     }

~-default と -defaultcolor は、
本来あり得ない 10 以上の数が現れたときに適用されます。

表示のために余計な信号値を記憶する必要の無い分、
上の方法に比べるとテストが重くならずに済みます。

** radix define コマンドを Verilog コードに埋め込んでおく [#s8392c7b]

表示方法の指定がコードと離れたところにあると、
コードが変更されたときに更新し忘れそうなので、
radix define コマンドをコードに埋め込んでおいて
自動的に抜き出して使うことを考えました。

trimac_tx.v
 LANG:verilog
    ...
    
    localparam stIdle           = 0;
    localparam stMem            = 1;
    localparam stTx             = 2;
    localparam stUdpChecksum0   = 3;
    localparam stUdpChecksum1   = 4;
    localparam stUdpChecksum2   = 5;
    localparam stUdpChecksum3   = 6;
    localparam stUdpChecksum4   = 7;
    localparam stDone           = 8;
    localparam stRewound        = 9;
 
    /* include in udo
    radix define TrimacTxStates {
        0 "Idle" -color white,
        1 "Mem" -color yellow,
        2 "Tx" -color yellow,
        3 "UdpChecksum0" -color yellow,
        4 "UdpChecksum1" -color yellow,
        5 "UdpChecksum2" -color yellow,
        6 "UdpChecksum3" -color yellow,
        7 "UdpChecksum4" -color yellow,
        8 "Done" -color yellow,
        9 "Rewound" -color red
        -default decimal
        -defaultcolor purple
    }
    */
 ...

のように radix define コマンドを Verilog コードにコメントとして埋め込んでおいて、

extract.rb
 LANG:ruby
 #!/usr/bin/ruby -Ks
 require "jcode"
 
 # 第1パラメータが検索するタグ名
 search = ARGV.shift
 regex_open  = /\/\*\s*#{search}/
 regex_close = /^[ \t]*\*\//
 
 # 残りがファイル名
 ARGV.each do |filename|
     print "# #{filename}\n\n"
     extract = 0;
     line_number = 1;
     File.readlines(filename).each do |line|
         if (extract == 0)
             extract = line_number if line =~ regex_open
         else
             if line =~ regex_close
                 extract = 0 
             else
                 print line
             end
         end
         line_number += 1;
     end
     if extract != 0
         $stderr.print "Error: section starting at line #{extract} was not closed in #{filename}."
         exit(false)
     end
 end
 exit(true)

なんてスクリプトを作ります。

もともとの .udo ファイルを別名で取っておくことにして、

 LANG:console
 $ cp trimac_test.udo trimac_test.udo.orig

以下のようにすれば、

 LANG:console
 $ mv trimac_test.udo.orig trimac_test.udo
 $ ruby extract.rb "include in udo" *.v >> trimac_test.udo

~/* include in udo と */ で囲まれたコメント部分を
全ての .v ファイルから検索して .udo ファイルに抜き出せます。

trimac_test.udo
 ...
 # trimac_tx.v
    radix define TrimacTxStates {
        0 "Idle" -color white,
        1 "Mem" -color yellow,
        2 "Tx" -color yellow,
        3 "UdpChecksum0" -color yellow,
        4 "UdpChecksum1" -color yellow,
        5 "UdpChecksum2" -color yellow,
        6 "UdpChecksum3" -color yellow,
        7 "UdpChecksum4" -color yellow,
        8 "Done" -color yellow,
        9 "Rewound" -color red
        -default decimal
        -defaultcolor purple
    }

* コメント [#zc826d8f]
- 私はステートのストリングをソースに埋め込んでいます。http://marsee101.blog19.fc2.com/blog-entry-400.html -- [marsee] &new{2010-05-19 (水) 08:11:35};

#comment_kcaptcha


Counter: 15034 (from 2010/06/03), today: 4, yesterday: 0