FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

LLHDの論文を読む (2. HDL(SystemVerilogやVHDL)からLLHDへのマッピング)

"3. HDL(SystemVerilogやVHDL)からLLHDへのマッピング"から。

SystemVerilogやVHDLなどのHDLから、LLHDへのマッピングを行う。ここでは、SystemVerilogをLLHDにどのようにマッピングするかについて見ていく。

3.1 階層構造

SystemVerilogのmoduleVHDLentityは、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)
f:id:msyksphinz:20210428001919p:plain

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
}