LoginSignup
4
1

More than 5 years have passed since last update.

VerilogのテストベンチをRubyで書けるようにした(Verilator + SWIG風味)

Last updated at Posted at 2017-09-10

 みなさん、Verilog やってますか? 私も最近DNNの計算をFPGAでやりたくなり、押入れの中でホコリをかぶっていた Altera DE0 (nanoじゃないやつ) を引っ張り出してきました。

動機・経緯

 Linux で Quartus II と ModelSim を動かし、Lチカと4bit×4bitの乗算器くらい作ったところで、テストベンチ(ソフト開発で言うユニットテストみたいなやつ)を Verilog で書くのがかったるくなってきました。回路の記述は Verilog でいいとしても、テストくらいは好きな言語で書きたいよね、でもそんな方法あるのか?などと思い始めたのが5日前(2017.9.5)。

 Google先生に尋ねたところ、「Verilator というやつを使うと VerilogをC++に翻訳して、激速でシミュレーションできるらしい」ということがわかりました。ただし、テストベンチは C++ で書く必要があります。

 じゃーその生成されたC++を wrap して Ruby に 組み込めばいいんじゃね?と思いついたのも5日前。しかしながら、当方 SWIG も C++ も経験ない。。。CのライブラリをRubyに組み込んだことはありますけど。まあ勉強と思ってやってみっか、と決心しました。

 でまあ、仕事しながら調べては書き、試し、などしているうちに、どうやら所望のことができるようになったのが昨日。Rakeにするかextconf.rbベースにするか悩みつつ、結局 extconf.rb 崩れのようなコードになったのが今日。

 コード公開するなら github だべ、ということで初めて公開リポジトリ作ってみました。

できたよー!

 つうわけで恥ずかしながらコード晒します。

 https://github.com/sin00b/VerilatorGen.rb

 コードってもRubyスクリプトがひとつだけです。中には SWIG のテンプレートがヒアドキュメントで入ってたりして、結構赤面モノですが、「美しいが動かないコードより、汚くても動くコード」ということで勘弁してください。

 サンプル的な使い方は README に書きましたので、それ見てもらえればわかると思いますが、Rubyで書いたテストベンチの例と実行結果を挙げておきます。fooはクロックの立ち上がりで1ずつインクリメントし、goo1は初期値を1として2倍していくカウンタです。内部レジスタは両方barという名前です。そこそこ直感的に書けていると思いますがどうでしょうか。

require "./verilator"

top = Verilator::Vtest.new
(0..10).each do |i|
  clk = i % 2
  top.clk = clk
  top.eval
  puts "clk: #{clk} / top.foo.bar: #{top.foo.bar} / top.foo.goo1.bar #{top.foo.goo1.bar}"
end
$ ruby test.rb
clk: 0 / top.foo.bar: 0 / top.foo.goo1.bar 1
clk: 1 / top.foo.bar: 1 / top.foo.goo1.bar 2
clk: 0 / top.foo.bar: 1 / top.foo.goo1.bar 2
clk: 1 / top.foo.bar: 2 / top.foo.goo1.bar 4
clk: 0 / top.foo.bar: 2 / top.foo.goo1.bar 4
clk: 1 / top.foo.bar: 3 / top.foo.goo1.bar 8
clk: 0 / top.foo.bar: 3 / top.foo.goo1.bar 8
clk: 1 / top.foo.bar: 4 / top.foo.goo1.bar 16
clk: 0 / top.foo.bar: 4 / top.foo.goo1.bar 16
clk: 1 / top.foo.bar: 5 / top.foo.goo1.bar 32
clk: 0 / top.foo.bar: 5 / top.foo.goo1.bar 32

言い訳

 自分で作ってて言うのもなんですが、よくわかってないところが多々あります。特に、これはVerilatorの仕様になるんでしょうが、ブロッキング代入(=)とノンブロッキング代入(<=)をどう書き分けるのかとか、全然わかってません。Verilogモジュールを解釈してクラスに変換するのはまるっきりVerilator任せですし、そのクラスをRubyから使うとこも、これまた SWIG 任せです。

 ちなみに32ビットのクロックポートが1つあり、内部レジスタでカウントする単純なカウンタのラッパーコードが1.5k行くらいになったりします。

作ってみた感想など

 先ほども書いたようにSWIG使ってラッパー書くのは初めてで、Verilatorの仕様もC++自体もよくわかってない中でラッパーコードの正解を探るのは結構な修行でした。
 Verilator が吐くコードはコンピュータが生成してるわけですけど、それを(多少の手直しは必要とはいえ)解釈できるSWIGは賢い。
 SWIGが生成できるのはRubyはもちろん、Python、Perl、PHP、Goなど多岐にわたります。XMLを吐くオプションもありますし、ソースコードを静的解析したい、みたいな向きにも使えるんじゃないでしょうか。
 Pythonな人で興味のある方は、ハードコーディングされてる swig ソースを参照していただくといいと思います。

4
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1