DesignWare,算術演算,DesignCompiler,VCS


加算や乗算のような算術演算がverilogで一行で書けるというのは、常識だと思います。
#というか、情報系上がりの人にとっては、ちゃんと演算器組まないとだめだったという事の方が奇妙なわけで。
たとえば、assign result = opr0 * opr1;と書けば、
ちゃんと、DCさんが制約条件に”そこそこ”合わせて乗算回路を用意してくれるはずです。
このような、便利なことが可能なのは、DCさんがDesignWareっつーのを呼び出してるからです。

ただ、この便利なDesignWareにも、問題があります。(と、伊藤は最初思った。)
問題1.defaultのDCさんはDesignWare-Basicというのを呼んでくるが、これで生成した回路がかなり遅い。
問題2.DesignWareの使い方というか、いろいろ指定する方法がよくわかんない。

さて、ここで、上記2つの問題をどのように克服したかをメモっとこうと思います。
まず、問題1について。
この問題は簡単に解消できます。
DesignWare-Foundationを用いて下さい。
モノによりますが、経験上、大体2倍弱の高速化が期待できます。
#逆に言うと、Basicが遅すぎるわけで。。。テクノロジライブラリもフリーの奴は理不尽に遅いでしょ。。。

ただ、DesignWare-Basicは、デフォルトでDCに付いてきますが、
DesignWare-Foundationは、そのライセンス取得をしてないと(入ってるけど)使えません。
現在のところ、VDECだと、SYNOPSYSのライセンスを持ってれば使えるようです。
以下を.synopsys_dc.setupに書き加えれば使えるようになるはずです。(ライセンスがあれば)


get_license DesignWare-Foundation
link_library = {"使ってるテクノロジライブラリ","dw_foundation.sldb", "dw01.sldb","dw02.sldb", "dw03.sldb", "dw04.sldb", "dw05.sldb", "dw06.sldb", "dw07.sldb"}
synthetic_library = {"dw_foundation.sldb", "dw01.sldb", "dw02.sldb","dw03.sldb", "dw04.sldb", "dw05.sldb", "dw06.sldb", "dw07.sldb"}
synlib_wait_for_design_license={"DesignWare-Foundation"}
#上で既にライセンス取得してるからこれはなくてもよい。
dw_prefer_mc_inside = "true"
#説明は省くが、mc_insideなやつを指定したいとき用。
次に、問題2の解消方法である。
といっても、今改めて読んでみると、いまいち何が問題か分かりにくいので、
もう少し詳しく書く。

具体例として、符号付きの乗算器(32bit×16bit)を取り上げる。
(出力は32bitとし、また、簡単のためoverflowを扱わないものとする。)


module multiplier32s(opr0, opr1, signed_flag, result 
                    //,overflow
                    );
  
  input [31:0] opr0;
  input [15:0] opr1;
  input        signed_flag;
  
  output [31:0] result;
  //output 	overflow;
  
  wire 		signed  [31:0]  product_sig;
  wire [31:0] 	product_usig;

  assign 	product_sig = $signed(opr0) * $signed(opr1);
  assign 	product_usig = opr0 * opr1;
  assign 	result = signed_flag? $unsigned(product_sig) :product_usig;

endmodule // multiplier32s
上記は、SYNOPSYSのDWのマニュアルにoperand infering(だっけ?)の例として書いてあるものを参考にしたものである。
これをDesignAnalyzerで論理合成してスケマティックを見てみると、
「Oh My God!!」と思うはずである。
なんでかっていうと、乗算器が2個作られているからである。(正の結果出力用と負の結果出力用!!)
#今回は直接関係ないが、往々にして、VerilogはVHDLと比較して”資源共有”ということをしてくれないらしい。

このように、DCに推論させると訳分からない事をされることもあるし、
符号とかキャリーとかの細々としたことまで推論させるのはメンドイので、
伊藤はできるだけ、DWを自分で指定してます。
以下が、上記と同様の乗算器をDWを指定して書いたモノです。


module multiplier32s(opr0, opr1, signed_flag, result 
                    //,overflow
                    );
  
  input [31:0] opr0;
  input [15:0] opr1;
  input        signed_flag;
  
  output [31:0] result;
  //output 	overflow;
  
  wire [32+16-1:0] temp;
  
  // Instance of DW02_mult
  DW02_mult #(32, 16)
  U1( .A(opr0), .B(opr1), .TC(signed_flag), .PRODUCT(temp));

  assign 	result = temp[31:0];
  
endmodule // multiplier32
ここでは、DW02_mult という乗算器を直接指定しています。
そして、入力ビット数の指定、入力信号の指定を行っています。
#ついでに、ここではimplementationを指定していませんので、それは制約次第となります。(普通はその方がcost-effective)
TCというのが、signed,unsignedを指定する制御信号として、DW02_multでは用意されているので、
そこに、signed_flagを接続しています。
ただ、DesignWareでは、32bit×16bitなら出力が48bitとなるので、
Productに直接resultを接続すると、モジュール間のWidth Mismatchとなりますので、
ここでは、48bitのtempというwireを用意しています。

この為、16bit分余計な回路がくっついて合成されます。

一般に、DesignWareを使用すると、冗長回路ができることが多いので、
合成スクリプトにset_ungroup {*DW*}とか付けて消してやります。
というか、伊藤の場合、演算器の類は全部(どうせ小さいので)DWを呼んでるモジュールごとUngroupします。
プロセッサの実行段は(INTなら)全体でUngroupで行くべきだと思います。

最後に、上記の乗算器(が含まれる回路)をVCSで検証するときには、
DW02_mult.vというシミュ用ファイルを読んでやらないとVCSに怒られるので、忘れずに読んでやりましょう。
当然環境依存だが、伊藤の環境におけるこのDW用のシミュファイルの場所を参考の為に書いておく。
/usr/local/CADmedia/SYNOPSYS/synthesis/dw/sim_ver/の下にある。
#パスが遠いんで、伊藤はこいつは、コピってもっと近くにも置いてます。
ということで、こんな感じでVCSを立ち上げたらいいと思う。↓


vcs +v2k test_multiplier32s.v ../../rtl/multiplier32s.v ../../../sim_lib/DW02_mult.v
以上、おわり、ありがとう。


メール出すなら、
ito@ddna.is.tsukuba.ac.jp
まで(ってまじで出す人居ないよな。)