Verilogで犯しがちな記述ミス の履歴(No.5)
更新- 履歴一覧
- 差分 を表示
- 現在との差分 を表示
- ソース を表示
- 電気回路/HDL/Verilogで犯しがちな記述ミス へ行く。
意図†
インプリメント時のワーニングをうまく見る方法が分からず、 簡単な記述ミスのせいで2,3時間を無駄にすることがしばしばなので、 ありがちなミスやそれへの対処法をここに記述して、日頃から注意しようという算段です。
宣言されていない信号線が幅1の wire として解釈される†
Verilog ではこれは言語仕様なので、警告も出ないのですよね。
このせいで、クロックが正しく繋がれていなかったり、 幅の広いバス線のはずが1ビット目しか繋がれていなかったり、 常に泣かされています。
宣言されていない信号線が使われたらエラーにするか、 最低でも警告を出すオプションがあればかなり開発が 順調に進むと思うのですが・・・
見つけられていないだけかもしれません?
対処法†
(2010/06/03 追記)
marsee さんに対処法を教えていただきました。
ソースコードの最初に
LANG:verilog `default_nettype none
を記述すれば良いそうで、定義していない信号をエラーにできます。 Verilog 2001 以降で使えるそうです。
以下の注意も一緒にいただきました。
Xilinxのライブラリなどでは、1ビットのwireは定義していないこともあるので、
コンパイルの順番によっては、そこでエラーになることがあります。
そこで、最後に`default_nettype wireを書いておくと良いと思います。
つまり、
LANG:verilog
`default_nettype none
(Verilogの回路本体)
`default_nettype wire
です。
で、もう一つ自分で見つけた注意点ですが、こっちは簡単な回避策が無くて困ります。
http://japan.xilinx.com/support/answers/34811.htm
にあるとおり、`default_nettype none があると、次のコードがコンパイルエラーになります。
LANG:verilog `default_nettype none module my_module ( input clk, input reset, input data_in , output data_out ); ... endmodule
次のように書けばエラーになりませんでした。
LANG:verilog `default_nettype none module my_module ( input wire clk, input wire reset, input wire data_in , output wire data_out ); ... endmodule
現在の所、Implementation 時にこのコードがエラーになるのは Virtex-6 と Spartan-6 FPGA といった最新の FPGA に対してのみのようで、 Spartan 3A DSP ではエラーになりません。
しかし ISim では最新のパーサーが使われるようで、 ほぼすべてのモジュールでエラーが出まくって驚きました。
今後のことも考えると、input / output で wire を省略するのはやめた方が良いようです。
・・・うーん、どこかで wire を入れるとエラーになったような???
あるいは、`default_nettype wire を `ifdef 〜 `endif で括るとか?
演算子の優先順位†
参考:http://homepage3.nifty.com/hdl_design/verilog_hdl2.htm
ビット演算子と等号†
ビット論理演算子の & や | よりも等号・不等号の方が優先順位が 高いことをすぐに忘れてしまい、痛い目を見ます。
LANG:verilog assign a = b == c & d;
これは、
LANG:verilog assign a = ( b == c ) & d;
と解釈されますので、
LANG:verilog assign a = b == ( c & d );
としたければ、括弧は必須です。
Pascal や Ruby ではビット論理演算が等号よりも強かったので、 今でも勘違いして原因が分からず途方に暮れます。
C++ や C#, Java もビット論理演算が等号より弱いので、 そちらでも間違えまくりです(泣
等号と3項演算子†
LANG:verilog assign a = b == c ? d : e
は、
LANG:verilog assign a = ( b == c ) ? d : e
と解釈されるので、
LANG:verilog assign a = b == ( c ? d : e )
としたければ括弧は必須です。
これも結構やらかします。
3項演算子 ? : はすべての演算子の中で最も優先順位が低い、と覚えておけばいいのですね。
比較や代入における信号のビット数の取り違い†
ちょっとすぐに例が思い浮かばないのですが、
http://japan.xilinx.com/support/answers/33037.htm
にある話と似たような状況で、定数や、演算結果のビット数が、 思い浮かべたビット数と異なるために、回路が思ったように動作しないことがしばしばありました。
大抵は、{ 8'h00, some_signal } のように明示的に信号幅の拡張を行うことで解決するのですが、 一見正しそうで間違った式を書くことができてしまうようなので、注意が必要です。
失敗例を思い出したら追記します。
インプリメント時のワーニング欄を見やすくする工夫†
ソフトウェアのプログラミングでもそうなのですが、 最近のコンパイラはかなり賢いので、 バグを含むコードを与えると高確率で的確な警告を出してくれるため、 ちゃんと警告欄に目を光らせていればデバッグの手間を大幅に省くことができます。
そして、コンパイラからの警告を有効に活用するため、 コンパイル時に出る警告は、それが無害なものであることが明らかでも、 コーディングを工夫することで上手に消すことが推奨されています。 したがって通常のソフトウェア開発では、 コードをコンパイルしても1つもコンパイル警告が出ないのが普通です。
しかし Xilinx ISE で Verilog を用いてコーディングしている限り、 コーディングの工夫だけでは警告を減らすことができず、 結果として警告欄が無害な警告であふれてしまって 本当に危険な警告に気づけない状況で開発を進めなければならないようです。
例えば PicoBlaze や CoreGenerator など、Xilinx のライブラリを組み込むだけで数百もの警告が出ますので、 もううんざり、、、なのです。
警告欄を有効活用するための方法をメモしたいと思います。
Message Filter を使う†
- Verilog 2001 では、コーディングの工夫だけではどうやっても消せない種類の警告があること、
- Xilinx 公式のコードから尋常じゃない数の警告が出ること、
などから、 無害な警告はコーディングの工夫ではなく、コンパイラ出力を目で追う段階でフィルタする、 という方法が提供されているようです。
Google:Xilinx ISE Message Filter
Project Navigator でのメッセージ フィルタの設定
http://www.xilinx.com/itp/xilinx7j/help/iseguide/html/ise_filtering_messages_pn.htm
これ、フィルタの数が少ないうちはよいのですが、フィルタ管理の GUI が弱すぎるため、 何百ものフィルタを This Instance Only で追加していくと、 フィルタの削除や無効化をしたいときににっちもさっちもいかなくなります。
[Edit Message Filters] メニューを選ぶだけで数十秒の時間が掛かり、 なおかつフィルタの無効化・有効化や、削除には、 1つ1つのフィルタに対してマウスでの操作が必要になります。
まとめて削除できない GUI は、あまりに手を抜きすぎです。
ISE 11 まではこれらのフィルタはプロジェクトディレクトリの filter.filter (だったっけ?)というテキストファイルに格納されていたので、 最後の手段はこれを慎重にテキストエディタで編集することでした。
ISE 12 では格納場所が変わったようで iseconfig/filter.filter ですね。
いざとなったらこれを編集するソフトを自作しなければならないかも、 と思っているのですが、すでにどこかにあったりするのでしょうか?
未稿†
以下、自分で書いたコードからなるべく警告を出さない工夫をメモろうとしたのですが、、、 まだあまり見つけられていません。
WARNING:Xst:2677 - Node <????????> of sequential type is unconnected in block <????>. HDLCompilers:261 - "????????" line ???? Connection to output port '??????' does not match port size
あたりは、いくつかのピンを意図的に使っていないことを指定する構文が verilog の言語仕様にあれば良いのですが、たぶんできないのですよね。
コメント†
()は必須です†
[アプロ] (2010-06-03 (木) 07:57:45)
assign文による組み合わせ回路で、条件判定する場合は、() でくくる癖をつけた方がいいですよ
また、あとあと論理がわかるように
(c == 1'b1) ?
とか明示するとよいでしょう
- 書き込みありがとうございます。予防のために括弧を付ける癖を付けるというのが正しい姿勢なのでしょうね。 -- [武内(管理人)]
- 条件判定で c == 1'b1 と書くのは個人的にはまだ受け入れにくいです。C を始めとするプログラミング言語では c != 0 とか c != false は冗長であるというのが常識で、この書き方もそれに似ているように思えてしまいます。特にビット幅まで指定した場合に c == 1'b1 と c == 1'b0 を瞬時に判別できないため、c と !c で書き分けるのに比べてかえって視認性が悪くなってしまうのではと感じています。c == 1'b1 という書き方のメリットはどのあたりにあるのでしょう? -- [武内(管理人)]
宣言されていない信号線が幅1の wire として解釈されるの解決法†
[marsee] (2010-06-03 (木) 07:09:46)
宣言されていない信号線が幅1の wire として解釈されるの解決法としては、`default_nettype noneを最初に記述するという方法があります。こうすると定義していない信号があるとエラーになります。ただ、これはVerilog2001の構文です。Xilinxのライブラリなどでは、1ビットのwireは定義していないこともあるので、コンパイルの順番によっては、そこでエラーになることがあります。そこで、最後に`default_nettype wireを書いておくと良いと思います。つまり、
`default_nettype none
Verilogの回路本体
`default_nettype wire
です。
- 大変有用な情報をありがとうございます。昨日からどこが悪いか全く分からず苦労している回路にこれを付けたらバグが見つかりそうな予感です(汗 -- [武内(管理人)]
- メモリモジュールのテストで ModelSim のステップ数制限にかかってしまったので、久しぶりに ISim を起動したら http://japan.xilinx.com/support/answers/34811.htm の影響が出てエラー出まくりでした。この `default_nettype none の副作用について上に追記しました。 -- [武内(管理人)]