以前の記事(Yosysを使ってみる(その1) - よーる)でYosysというオープンソースの論理合成ツールを紹介しました。 今回は、乗算器を複数の作り方で作ってみて、その回路面積を比較してみようと思います。 全加算器セルのような複数出力のセルを使いたいので、その説明もします。
実験に使うソースコード
32bit×32bitの乗算器を、以下の二通りの方法で書いてみました。
↓合成系におまかせバージョン↓
module multiplier (a, b, out); input [31:0] a; input [31:0] b; output[63:0] out; assign out = a * b; endmodule
↓四進乗算器指定バージョン↓
module multiplier (a, b, out); input [31:0] a; input [31:0] b; output[63:0] out; wire[33:0] a1 = { 2'b0, a }; wire[33:0] a2 = { 1'b0, a, 1'b0 }; wire[33:0] a3 = a1 + a2; function[33:0] f(input [1:0] k); f = a1 & {34{ k[0]&~k[1]}} | a2 & {34{~k[0]& k[1]}} | a3 & {34{ k[0]& k[1]}}; endfunction wire[63:0] f0 = { 30'b0, f(b[ 1: 0]) }; wire[63:0] f1 = { 28'b0, f(b[ 3: 2]), 2'b0 }; wire[63:0] f2 = { 26'b0, f(b[ 5: 4]), 4'b0 }; wire[63:0] f3 = { 24'b0, f(b[ 7: 6]), 6'b0 }; wire[63:0] f4 = { 22'b0, f(b[ 9: 8]), 8'b0 }; wire[63:0] f5 = { 20'b0, f(b[11:10]), 10'b0 }; wire[63:0] f6 = { 18'b0, f(b[13:12]), 12'b0 }; wire[63:0] f7 = { 16'b0, f(b[15:14]), 14'b0 }; wire[63:0] f8 = { 14'b0, f(b[17:16]), 16'b0 }; wire[63:0] f9 = { 12'b0, f(b[19:18]), 18'b0 }; wire[63:0] f10 = { 10'b0, f(b[21:20]), 20'b0 }; wire[63:0] f11 = { 8'b0, f(b[23:22]), 22'b0 }; wire[63:0] f12 = { 6'b0, f(b[25:24]), 24'b0 }; wire[63:0] f13 = { 4'b0, f(b[27:26]), 26'b0 }; wire[63:0] f14 = { 2'b0, f(b[29:28]), 28'b0 }; wire[63:0] f15 = { f(b[31:30]), 30'b0 }; assign out = f0 + f1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 + f9 + f10 + f11 + f12 + f13 + f14 + f15; endmodule
復習:回路面積の算出方法
前回の記事で紹介したように、以下のようなコマンドで回路面積を算出することができます。
yosys> read_verilog multiplier.v; proc; opt; techmap; opt; abc -liberty osu018_stdcells.lib; stat -liberty osu018_stdcells.lib
しかし、osu018_stdcells.libには全加算器セルが含まれているのに、それを使ってくれません。
全加算器セルの使い方
全加算器セルを使うには、次の内容のtechmap.vを作業ディレクトリに配置した上で、以下のようにコマンドを実行します。
module \$fa (A, B, C, X, Y); parameter WIDTH = 0; input A, B, C; output X, Y; wire X, Y; FAX1 _TECHMAP_REPLACE_ ( .A(A), .B(B), .C(C), .YC(X), .YS(Y) ); endmodule
yosys> read_verilog multiplier.v; proc; opt; techmap; opt; alumacc; opt; extract_fa -fa; opt; techmap -map techmap.v; opt; abc -liberty osu018_stdcells.lib; stat -liberty osu018_stdcells.lib
なお、この方法は、yosys full adderでググって出てきたExtract_fa not extracting all full adders · Issue #3724 · YosysHQ/yosys · GitHubと、https://www.reddit.com/r/yosys/comments/clk9z9/how_to_techmap_a_full_adder/を参考にしました。
乗算器の回路面積
乗算器の回路面積は以下のようになりました。
| 全加算器セルなし | 全加算器セルあり | |
|---|---|---|
| 合成系にお任せ | 206331 | 165267 |
| 四進乗算器 | 134053 | 141722 |
おまかせよりも四進を指定した時の方が小さくなるのはよさそうです。 しかし、四進乗算器の時に全加算器セルありの方が回路面積が大きくなっているのはいまいちです。 最初から全加算器セルが使えることを見据えて合成しているのではなく、合成してから全加算器セルが使えそうなところだけ置き換え、みたいな戦略になっているのがよくなさそうです。
以下の手順で合成するほうが良いようです(よく見たらExtract_fa not extracting all full adders · Issue #3724 · YosysHQ/yosys · GitHubもこの手順を示していました)。
yosys> read_verilog multiplier.v; proc; opt; alumacc; opt; techmap; opt; extract_fa -fa; opt; techmap -map techmap.v; opt; abc -liberty osu018_stdcells.lib; stat -liberty osu018_stdcells.lib
先ほどの手順との違いは、techmap(抽象度を下げてゲートレベルに近づける変換?)の前にalumacc(ALUっぽい部分をくくりだす変換?)をやるようにした点です。
| 全加算器セルなし | 全加算器セルあり | 全加算器セルあり(改良手順) | |
|---|---|---|---|
| 合成系にお任せ | 206331 | 165267 | 165267 |
| 四進乗算器 | 134053 | 141722 | 115556 |
無事、全加算器セルなしの場合よりも小さい面積に合成されました。
まとめ
Yosysというオープンソースの論理合成ツールを使い、複数の乗算器の構成の回路面積を比較してみました。 前回の記事で紹介した方法では全加算器セルのような複数出力のセルを使うことができませんでしたが、追加の手順を行うことで使うことができました。