"3. HDL(SystemVerilogやVHDL)からLLHDへのマッピング"から。
SystemVerilogやVHDLなどのHDLから、LLHDへのマッピングを行う。ここでは、SystemVerilogをLLHDにどのようにマッピングするかについて見ていく。
3.1 階層構造
SystemVerilogのmodule
やVHDLのentity
は、LLHDのエンティティとしてそのままマッピングされる。
- SystemVerilog
module acc_tb; bit clk, en; bit [31:0] x, q; acc i_dut (.*);
- LLHD
entity @acc_tb () -> () { %zero0 = const i1 0 %zero1 = const i32 0 %clk = sig i1 %zero0 %en = sig i1 %zero0 %x = sig i32 %zero1 %q = sig i32 %zero1 inst @acc (i1$ %clk, i32$ %x, i1$ %en) -> (i32$ %q) inst @acc_tb_initial (i32$ %q) -> (i1$ %clk, i32$ %x, i1$ %en) }
- SystemVerilog
module acc (input clk, input [31:0] x, input en, output [31:0] q); bit [31:0] d, q; always_ff @(posedge clk) q <= #1ns d; always_comb begin d <= #2ns q; if (en) d <= #2ns q+x; end endmodule
- LLHD
entity @acc (i1$ %clk, i32$ %x, i1$ %en) -> (i32$ %q) { %zero = const i32 0 %d = sig i32 %zero %q = sig i32 %zero inst @acc_ff (i1$ %clk, i32$ %d) -> (i32$ %q) inst @acc_comb (i32$ %q, i32$ %x, i1$ %en) -> (i32$ %d) }
3.2 プロセス
SystemVerilogのalways_ff
, always_comb
, initial
などをどのようにLLHDに変換するか。
3.2.1 組み合わせ回路
単純なシーケンシャル命令列に置き換えられる。
always_comb begin d <= #2ns q; if (en) d <= #2ns q+x; end
- LLHD
proc @acc_comb (i32$ %q, i32$ %x, i1$ %en) -> (i32$ %d) { entry: %qp = prb i32$ %q %enp = prb i1$ %en %delay = const time 2ns drv i32$ %d, %qp after %delay br %enp, %final, %enabled enabled: %xp = prb i32$ %x %sum = add i32 %qp, %xp drv i32$ %d, %sum after %delay br %final final: wait %entry for %q, %x, %en }
3.2.2 シーケンシャル回路
always_ff @(posedge clk) q <= #1ns d;
- LLHD:よくよく読むとクロックのトリガがここで記述されている。
proc @acc_ff (i1$ %clk, i32$ %d) -> (i32$ %q) { init: %clk0 = prb i1$ %clk wait %check for %clk check: %clk1 = prb i1$ %clk %chg = neq i1 %clk0, %clk1 %posedge = and i1 %chg, %clk1 br %posedge, %init, %event event: %dp = prb i32$ %d %delay = const time 1ns drv i32$ %q, %dp after %delay br %init }
3.3 genericステートメントとパラメータ
SystemVerilogなどのgenericなパラメータ記述をサポートしているが、これらはLLHDに変換されず、別々のエンティティに分割された。
4. LLHDの変換プロセス
LLHDは、入力したSystemVerilogをさらなる低レベルな構造記述に変換することができる。
- 演算の複雑さを減らす (§ 4.1)
- 演算を基本ブロックから外す (ECM, § 4.2)
- ドライブを基本ブロックの外に出す (TCM, § 4.3)
- ファイとコントロール・フローを mux に置き換える (TCFE, § 4.4)
- 些細なプロセスをエンティティに置き換える (PL, § 4.5)
- フリップフロップとラッチの識別 (Deseq., § 4.6)
4.1 基本的な変換
- CF (Constant Folding) : 定数畳み込み
- DCE (Dead Code Elimination) : デッドコード除去
- CSE (Common Statement Elimination) : 共通部分除去
- ECM (Early Code Motion) : 命令を制御フローグラフの上側に移動させる。
などの基本的な変換を行う。上記のシーケンシャル回路の記述が以下のように変換される。
proc @acc_ff (i1$ %clk, i32$ %d) -> (i32$ %q) { init: %delay = const time 1ns %clk0 = prb i1$ %clk wait %check for %clk check: %clk1 = prb i1$ %clk %dp = prb i32$ %d %chg = neq i1 %clk0, %clk1 %posedge = and i1 %chg, %clk1 br %posedge, %init, %event event: drv i32$ %q, %dp after %delay br %init
4.3 TCM (Temporal Code Motion)
物理的な時間の一定の期間に実行されるコードセクションにコードを分割する。
proc @acc_ff (i1$ %clk, i32$ %d) -> (i32$ %q) { init: %delay = const time 1ns %clk0 = prb i1$ %clk wait %check for %clk check: %clk1 = prb i1$ %clk %dp = prb i32$ %d %chg = neq i1 %clk0, %clk1 %posedge = and i1 %chg, %clk1 br %posedge, %aux, %event event: br %aux aux:drv i32$ %q, %dp after %delay if %posedge br %init
4.4 全体制御フローの削除
制御フローをデータフローに、分岐をマルチプレクサに置き換える。
entity @acc_ff (…) -> (…) { %delay = const time 1ns %clkp = prb i1$ %clk %dp = prb i32$ %d reg i32$ %q, %dp rise %clkp after %delay }