OpenLANEと半導体設計入門
質問、修正案、その他連絡は@Cra2yPierr0tマデ
Github : https://github.com/The-OpenROAD-Project/OpenLane
ドキュメント : https://openlane.readthedocs.io/en/latest/
OpenLANEについて
OpenLANEとはOSSなRTL-to-GDSIIコンパイラであり、20個くらいのOSSを組み合わせて作られている。PDKとRTLとコンフィグを揃えて実行するとGDSIIが生えてくる。本記事ではOpenLANEの使い方及び各フローの説明を行いながら、現代の半導体設計を学んでいく。
OpenLANEの全体的なフローは次のようになっている。1
- Synthesis
- Floorplan and PDN
- Placement
- CTS
TritonCTS
- クロック供給ネットワーク(クロックツリー)の合成
- Routing
FastRoute
- グローバル配線CU-GR
- グローバル配線(プランB)TritonRoute
- ローカル配線SPEF_Extractor
- 寄生フォーマット”SPEF”の摘出
- GDSII Generation
- Checks
出典:https://openlane.readthedocs.io/en/latest/#openlane-architecture
以上を見たところで半導体設計もOpenLANEも完全に理解出来る訳が無いので、これから各項目について説明していく。楽しみましょう。
本記事では以下の適当に作ったALU(learn_lsi.v
)を題材に解説をしていきます。
module learn_lsi(
input i_rstn,
input i_clk,
input [1:0] i_ctrl,
input [31:0] i_data_a,
input [31:0] i_data_b,
output [31:0] o_data
);
always @(posedge i_clk, negedge i_rstn) begin
if(!i_rstn) begin
o_data <= 32'h0000_0000;
end else begin
case(i_ctrl)
2'b00 : o_data <= i_data_a + i_data_b;
2'b01 : o_data <= i_data_a | i_data_b;
2'b10 : o_data <= i_data_a & i_data_b;
2'b11 : o_data <= i_data_a ^ i_data_b;
default : o_data <= 32'h0000_0000;
endcase
end
end
endmodule
1. Synthesis
Logic Synthesis
Logic Synthesis、またの名を論理合成とは、HDLで書かれた内容をより単純なANDやORのような論理ゲートやFF等のディジタル回路に変換する処理の事を指します。
Yosysはこの論理合成を行うツールの一つです。HDLを単純なディジタル回路に変換すると言いましたが、例えばVerilog HDLで書いた回路が実際どんな形式のファイルに変換されるのか気になりませんか?気になりますね、気になるという事にしましょう。 実はYosysの場合、Verilog HDLで書かれた回路は、より単純なVerilog HDLに変換されます。実際にYosysを動かして見てみましょう。
yosysの起動。yosysはexitコマンドで抜けられます。
$ yosys
-----------
なんやかんや
-----------
yosys>
SystemVerilogモードでVerilogファイルの読み込む。VerilogだけどSVモードなのは気にしなくていい(多分)。
yosys> read -sv learn_lsi.v
トップモジュールを指定して階層構造をチェック
yosys> hierarchy -top learn_lsi
Yosysが処理しやすいように整形してシンプルな最適化を掛ける
yosys> proc
yosys> opt
ちなみにここでshow
コマンドを使うと回路図が見られる。
ディジタル回路を論理回路に変換してシンプルな最適化を掛ける
yosys> techmap
yosys> opt
Verilogファイルsynth.v
に出力
yosys> write_verilog synth.v
さて、出力されたsynth.v
が論理合成後のVerilog HDLです。中身を見てみましょう。
module learn_lsi(i_rstn, i_clk, i_ctrl, i_data_a, i_data_b, o_data);
wire _000_;
wire _001_;
wire [1:0] _002_;
wire [1:0] _003_;
wire [1:0] _004_;
wire [1:0] _005_;
wire [1:0] _006_;
wire [1:0] _007_;
なるほどね
assign _008_[1] = _040_[89] |(* src = "learn_lsi.v:0.0-0.0|learn_lsi.v:14.7-20.14|/usr/bin/../share/yosys/techmap.v:593.20-593.31" *) _040_[121];
assign _043_[25] = _008_[0] |(* src = "learn_lsi.v:0.0-0.0|learn_lsi.v:14.7-20.14|/usr/bin/../share/yosys/techmap.v:593.20-593.31" *) _008_[1];
assign _009_[0] = _040_[24] |(* src = "learn_lsi.v:0.0-0.0|learn_lsi.v:14.7-20.14|/usr/bin/../share/yosys/techmap.v:593.20-593.31" *) _040_[56];
assign _009_[1] = _040_[88] |(* src = "learn_lsi.v:0.0-0.0|learn_lsi.v:14.7-20.14|/usr/bin/../share/yosys/techmap.v:593.20-593.31" *) _040_[120];
assign _043_[24] = _009_[0] |(* src = "learn_lsi.v:0.0-0.0|learn_lsi.v:14.7-20.14|/usr/bin/../share/yosys/techmap.v:593.20-593.31" *) _009_[1];
assign _010_[0] = _040_[23] |(* src = "learn_lsi.v:0.0-0.0|learn_lsi.v:14.7-20.14|/usr/bin/../share/yosys/techmap.v:593.20-593.31" *) _040_[55];
assign _010_[1] = _040_[87] |(* src = "learn_lsi.v:0.0-0.0|learn_lsi.v:14.7-20.14|/usr/bin/../share/yosys/techmap.v:593.20-593.31" *) _040_[119];
assign _043_[23] = _010_[0] |(* src = "learn_lsi.v:0.0-0.0|learn_lsi.v:14.7-20.14|/usr/bin/../share/yosys/techmap.v:593.20-593.31" *) _010_[1];
なるほど、ちょっと意味が分からないですね。読めるわけがない。
我々が読むにはlearn_lsi.v
は複雑すぎました。以下のsimple.v
で試してみましょう。
module simple(
input i_clk,
input i_data_a,
input i_data_b,
input i_ctrl,
output o_data
);
always @(posedge i_clk) begin
if(i_ctrl) begin
o_data <= i_data_a & i_data_b;
end else begin
o_data <= i_data_a | i_data_b;
end
end
endmodule
Yosysで論理合成
yosys> read -sv simple.v
yosys> hierarchy -top simple
yosys> proc; opt
yosys> techmap; opt
yosys> write_verilog synth.v
さてsynth.v
を覗いてみましょう。
module simple(i_clk, i_data_a, i_data_b, i_ctrl, o_data);
(* src = "simple.v:9.3-15.6" *)
wire _0_;
(* src = "simple.v:11.20-11.39" *)
wire _1_;
(* src = "simple.v:13.20-13.39" *)
wire _2_;
(* src = "simple.v:2.9-2.14" *)
input i_clk;
wire i_clk;
(* src = "simple.v:5.9-5.15" *)
input i_ctrl;
wire i_ctrl;
(* src = "simple.v:3.9-3.17" *)
input i_data_a;
wire i_data_a;
(* src = "simple.v:4.9-4.17" *)
input i_data_b;
wire i_data_b;
(* src = "simple.v:6.10-6.16" *)
output o_data;
reg o_data;
(* src = "simple.v:9.3-15.6" *)
always @(posedge i_clk)
o_data <= _0_;
assign _0_ = i_ctrl ? (* src = "simple.v:10.8-10.14|simple.v:10.5-14.8" *) _1_ : _2_;
assign _1_ = i_data_a &(* src = "simple.v:11.20-11.39" *) i_data_b;
assign _2_ = i_data_a |(* src = "simple.v:13.20-13.39" *) i_data_b;
endmodule
あーギリ読めますね、なんか(* *)
で囲われた何か(正式名称: Attribute)が付いてますがendmodule
から4行が本体ですね。if文が三項演算子に変換されているのが分かります。
勉強中
2. Floorplan and PDN
勉強中
3. Placement
勉強中
4. CTS
勉強中
5. Routing
勉強中
6. GDSII Generation
勉強中
7. Checks
勉強中
-
https://openlane.readthedocs.io/en/latest/#openlane-design-stages ↩