Synthesijer.Scala (PROSYM 2015)
-
Upload
takefumi-miyoshi -
Category
Engineering
-
view
2.325 -
download
1
Transcript of Synthesijer.Scala (PROSYM 2015)
ScalaによるFPGAアプリケーション開発用DSLの設計
わさらぼ
三好 健文
2015.01.09
2
FPGAとは?
✔ 論理回路・データパスを自由に作り込めるLSI✔ I/Oを自由に使える
Field Programmable Gate Array
3
FPGAとは?
✔ 論理回路・データパスを自由に作り込めるLSI
✔ I/Oを自由に使える
✔ クロックレベルの同期と並列性を活用した処理を実現
Field Programmable Gate Array
4
FPGAとは?
✔ 論理回路・データパスを自由に作り込めるLSI
✔ I/Oを自由に使える✔ クロックレベルの同期と並列性を活用した処理を実現
✔ ASIC開発のプロトタイプとして✔ 特定用途向け(少数生産)の製品として
Field Programmable Gate Array
5
計算プラットフォームとしてのFPGAプロセッサの場合
FPGAの場合 高性能低消費電力コンパクト
6
とても有名な例
1) http://www.theregister.co.uk/Print/2011/12/12/ibm_vs_oracle_data_centre_optimisation/
2) http://www.redbooks.ibm.com/redpapers/pdfs/redp4725.pdf
1)
2)
例: IBM Netteza
7
Memcached@Xilinx, ETH Zurich
10G if
DRAM
Networkadapter
FPGA
Network stack Memcached
x86 DRAM
motherboard
✔ Memcached部分はデータフローアーキテクチャ✔ レイテンシ = 481Cycles@156MHz
Hash table Value store
https://www.usenix.org/sites/default/files/conference/protected-files/blott_hotcloud13_slides.pdf
8
FPGAの開発手法HDLによるRTL設計
9
開発フロー
HDLを使ったRTL設計で所望のモジュールを実装
RTLシミュレーションによる動作検証
使用するFPGAにあわせた制約を定義
ツールで合成,配置配線,FPGA構成情報生成
実機で動作確認
10
VHDLによるRTL設計の例library IEEE;use IEEE.std_logic_1164.all;use IEEE.numeric_std.all;entity led is port ( clk, reset : in std_logic; q : out std_logic );end led;architecture RTL of led is signal c : unsigned(31 downto 0);begin q <= c(5); process(clk) begin if clk'event and clk = '1' then if reset = '1' then c <= (others => '0'); else c <= c + 1; end if; end if; end process;end RTL;
カウンタの設計
11
VHDLによるRTL設計の例
library IEEE;use IEEE.std_logic_1164.all;use IEEE.numeric_std.all;
entity sim isend sim;
architecture BEHAV of sim is
component led port ( clk, reset : in std_logic; q : out std_logic ); end component led;
signal clk : std_logic := '0'; signal reset : std_logic := '0'; signal counter : unsigned(31 downto 0) := (others => '0'); signal q : std_logic;
begin process begin clk <= '1'; wait for 10 ns; clk <= '0'; wait for 10 ns; end process; process(clk) begin if clk'event and clk = '1' then counter <= counter + 1; end if; end process; reset <= '1' when counter < 10 else '0';
U : led port map( clk => clk, reset => reset, q => q ); end BEHAV;
カウンタのシミュレーションコード
12
VHDLによるRTL設計の例シミュレーション結果
13
Verilog HDLによるRTL設計の例module led ( input wire clk, input wire reset, output wire q );
reg [31:0] c = 32'h0;
assign q = c[5]; always @(posedge clk) begin c <= c + 1; end endmodule // led
module led_sim();
reg clk = 1'b0; reg reset; wire q; always #5 clk <= !clk;
initial begin $dumpfile("led_sim.vcd"); $dumpvars(0, led_sim); reset = 1; repeat(10) @(posedge clk); reset <= 0; end
led U(.clk(clk), .reset(reset), .q(q));
endmodule // led_sim
14
RTL設計の辛さ
✔ “信号の流れ”を記述する✔ “処理の流れ”を“信号の流れ”に変換 ↔ 書きたいのは“処理の流れ”
✔たくさんの似たような構造✔ たくさんの似たような名前
✔ 記述の再利用をしたいが難しい
本質としては
実務的には
15
手軽なFPGA開発のための取り組み✔ 高位合成言語処理系✔ DSL
16
高位合成処理系✔ CやJava,C#などを入力言語とした開発環境✔ 開発コストを小さくできる✔ 生成したHWの質は処理系依存✔ 良いHW生成にはコツが必要
✔ ディレクティブの活用✔ 書き方を考える必要がある
17
高位合成処理系✔ Vivado HLS
✔ OpenCL対象の処理系✔ CyberWorkBench
✔ Cynthesizer
✔ Symphony C Compiler
✔ ImpulseC
✔ Lime
✔ Synthesijer (旧JavaRock)
などなどなど
18
DSLベースの設計手法✔ RTL設計を楽にするためのDSL
✔ 実装したいアプリケーション別のDSL
✔ プログラミングモデルに特化したDSL
19
様々なDSLベースのシステム開発(1)
✔ MyHDL (Pythonベース)
✔ JHDL (Javaベース)
✔ Chisel (Scalaベース)
などなどなど
RTL設計(あるいは少し抽象的なHW設計)をより楽にするためのDSL
20
様々なDSLベースのシステム開発(2)
✔ Spiral ←Linear Digital Processing
✔ HDL Coder ← 信号処理(Matlab)
✔ Optimus ← ストリーム処理✔ LINQ ← クエリプロセッシングなどなどなど
✔ DSLを作るツールも.(たとえば,LMS/Scala)
実装したいアプリケーションに特化したDSL
21
様々なDSLベースのシステム開発(3)
✔ Bluespec (並行プログラミング)
✔ MaxCompiler (データフロープログラミング)
✔ FloPoCo (浮動小数点数パイプライン)
などなどなど
使用するプログラミングモデルに特化したDSL
22
DSLベースの設計手法✔ RTL設計を楽にするためのDSL
←依然RTLであることに代わりはない
✔ 実装したいアプリケーション別のDSL
←HWの設計探索をしたい場合には不向き
✔ プログラミングモデルに特化したDSL
→さて,どんなモデルがよいだろうか?
23
FPGAが有用なのはなぜか?
✔ 論理回路・データパスを自由に作り込めるLSI
✔ I/Oを自由に使える
✔ クロックレベルの同期と並列性を活用した処理を実現
Field Programmable Gate Array
24
FPGAが有用なのはなぜか?
10G if
DRAM
Networkadapter
FPGA
Network stack Memcached
x86 DRAM
motherboard
Hash table Value store
図は https://www.usenix.org/sites/default/files/conference/protected-files/blott_hotcloud13_slides.pdf より
データはどうせ移動させる移動途中で副次的に処理できる
25
鍵はパイプライン並列化
FIFO
スループット T [bps]
w [byte]f [Hz]
実行ステージ
FIFO
実行ステージ
実行ステージ
26
データが来たら迎え撃つ
タワーディフェンス系のゲームの画像
27
鍵はパイプライン並列化
パケットデータが d [byte] のとき全データ入力を受け取るのにかかる時間 = (d/w)*(1/f) [sec]同様に、全データの出力にかかる時間 = (d/w)*(1/f) [sec]
スループットT [bps]を実現するとき、パケットデータを(8*d)*(1/T) [sec]内で処理し続ける必要がある
→ 各モジュールで処理に使える時間 t は 8*d/T-2*d/(w*f) [sec] → (8*d/T-2*d/(w*f))/(1/f) [cycle]
たとえば、d=1500, T=1G, w=4, f=100Mのとき 1パケットあたりの処理にかけられるサイクル数は450サイクル.
f=200Mなら1650サイクル,w=16なら1012サイクル T=10Gの場合,w=16,f=200M でも 52サイクル
FIFO
スループット T [bps]
w [byte]f [Hz]
実行ステージ
FIFO
実行ステージ
実行ステージ
とはいえ,各ステージで状態遷移のある処理が必要
28
鍵はパイプライン並列化
パケットデータが d [byte] のとき全データ入力を受け取るのにかかる時間 = (d/w)*(1/f) [sec]同様に、全データの出力にかかる時間 = (d/w)*(1/f) [sec]
スループットT [bps]を実現するとき、パケットデータを(8*d)*(1/T) [sec]内で処理し続ける必要がある
→ 各モジュールで処理に使える時間 t は 8*d/T-2*d/(w*f) [sec] → (8*d/T-2*d/(w*f))/(1/f) [cycle]
たとえば、d=1500, T=1G, w=4, f=100Mのとき 1パケットあたりの処理にかけられるサイクル数は450サイクル.
f=200Mなら1650サイクル,w=16なら1012サイクル T=10Gの場合,w=16,f=200M でも 52サイクル
FIFO
スループット T [bps]
w [byte]f [Hz]
実行ステージ
FIFO
実行ステージ
実行ステージ
とはいえ,各ステージで状態遷移のある処理が必要
限られた許容サイクルを効率よく使う必要
29
組み合わせ回路/データ並列性の活用✔ プロセッサと比べてFPGA回路のφは圧倒的に低速✔ 高速データ処理では1クロックでデータを捌く必要も✔ 時にはソフトウェア実装とは全く違う場合も
条件
・・・
条件
v.s
30
欲しいDSL
✔ Bluespec (並行プログラミング)
✔ MaxCompiler (データフロープログラミング)
✔ FloPoCo (浮動小数点数パイプライン)
などなどなど
使用するプログラミングモデルに特化したDSL
状態遷移および各状態での処理設計がやりやすく組み合わせ回路が書きやすい言語
31
設計: Synthesijer.scala✔ 組み合わせ回路の設計の容易は失わないまま✔ “処理の流れ”の記述を容易にする
✔ クロックベースの状態管理と状態遷移を言語機能に
✔ 内部DSLとして設計.回路設計にScalaの機能を活用.✔ 設計資産の再利用性を高める✔ 見通しの良い設計を可能にする
32
開発フロー
Scalaプログラムとして実装 → VHDLまたはVerilog HDLを生成
RTLシミュレーションによる動作検証
使用するFPGAにあわせた制約を定義
ツールで合成,配置配線,FPGA構成情報生成
実機で動作確認
Synthesijer.Scalaを使ってモジュールを実装
33
モデル
モジュールの設計単位
入出力.クロック単位で状態保持
組み合わせ回路.状態は持たない
クロック単位での状態保持状態遷移マシン
34
Module: 設計単位✔ ハードウェアモジュールの設計単位✔ 構成要素の生成メソッドを提供✔ 自身に相当するVHDL/Verilogを生成するメソッドを提供
def main(args:Array[String]) = { val m = new Module("hoge") m.genVHDL() m.genVerilog()}
entity hoge is port ( clk : in std_logic; reset : in std_logic );end hoge;architecture RTL of hoge is signal clk_sig : std_logic; signal reset_sig : std_logic;begin clk_sig <= clk; reset_sig <= reset; -- expressions -- sequencersend RTL;
35
Sequencer: 状態遷移機械
S0:State
S1:State
S2:State
Sequencerval m = new Module("hoge")
val seq0 = m.sequencer("S")val s0, s1, s2 = seq0.add()s0 -> s1 -> s2 -> s0
val seq1 = m.sequencer("T")val t0, t1, t2 = seq1.add()t0 -> (flag, t1)t0 -> (flag!, t2)
✔ 状態遷移機械(Sequencer)と状態(State)
✔ ->演算子で状態遷移.状態毎に遷移する.✔ ->演算子の引数にタプルを渡した場合, タプルの1番目の引数が真の場合にのみ遷移.
36
Signal/Port: 状態に応じた値の保持✔ SignalはFPGA上のレジスタに対応✔ Portはモジュール外部とのデータ入出力ポート✔ :=演算子で値を代入できる✔ <=演算子で,特定の状態で値を代入できる
val m = new Module("hoge")
val p = m.inP("data", 32)val seq = m.sequencer("S")val s0, s1, s2 = seq.add()
val s = m.signal(32)val t = m.signal(32)
s := pt <= (s0, u)
37
ExprItem: 組み合わせ回路✔ 演算構成要素
✔ Signal/Port
✔ Value (即値)
✔ ExprItem同士の演算結果
val m = new Module("hoge")
val s = m.signal(32)val t = m.signal(32)
val e0 = s + st := e0s <= (s0, s + 1)
38
はじめてのSynthesijer.scala✔ Lチカの例
def generate_led() : Module = { val m = new Module("led") val q = m.outP("q") val counter = m.signal(32) q <= ref(counter, 5) val seq = m.sequencer("main") counter <= (seq.idle, VECTOR_ZERO) val s0 = seq.idle -> seq.add() counter <= (s0, counter + 1) return m}
def generate_sim(target:Module, name:String) : SimModule = { val sim = new SimModule(name) val inst = sim.instance(target, "U") val (clk, reset, counter) = sim.system(10) inst.sysClk <= clk inst.sysReset <= reset return sim}
39
ベンディングマシンの例
ドリンク
自動販売機¢5
¢10
ドリンク一杯¢20お釣りは出ません
40
RTLでの設計の場合
… type stateType is (NONE, CHARGE_5, CHARGE_10, CHARGE_15, OK) signal state, next_state: stateType := NONE;… case (state) is when NONE => if nickel then next_state <= CHARGE_5; elsif dime then next_state <= CHARGE_10; else next_state <= NONE; end if; when CHARGE_5 => if nickel then next_state <= CHARGE_10; elsif dime then next_state <= CHARGE_15; else next_state <= NONE; end if;…
41
ベンディングマシンの例class VendingMachine(n:String,c:String,r:String) extends Module(n,c,r){ val nickel = inP("nickel") val dime = inP("dime") val rdy = outP("rdy") val seq = sequencer("main") val s5,s10,s15,s_ok = seq.add() rdy <= (seq.idle, LOW) rdy <= (s_ok, HIGH) seq.idle -> (nickel, s5) seq.idle -> (dime, s10)
s5 -> (nickel,s10) s5 -> (dime, s15)
s10 -> (nickel, s15) s10 -> (dime, s_ok)
s15 -> (nickel, s_ok) s15 -> (dime, s_ok)
s_ok -> seq.idle}
val m = new VendingMachine("machine", "clk", "reset")m.genVHDL()m.visuallize_statemachine()
42
ベンディングマシンのステートマシン
43
Scalaの機能を使った設計効率化の向上✔ 設計資産をメソッドやクラスとして保存,再利用✔ 類似オブジェクトや類似オブジェクトの生成✔ ループとパタンマッチによる直列化/復元コードの生成
44
設計資産の再利用
例: デコーダ (7セグメントLEDの点灯)
4
0
2
51
6
73
45
設計資産の再利用
process (data)begin case (data) is when 0 => segment <= X"7e"; when 1 => segment <= X"30"; … when 9 => segment <= X"79"; when others => null; end case;end process;
4
0
2
51
6
73
毎回このパターンを書かないといけない.
従来のHDLによるRTL設計の場合
46
設計資産の再利用
def decoder(s:ExprItem, l:List[(Int,Int)], w:Int) = { l.foldRight(value(0,w)){ (a, z) => ?(s == a._1, value(a._2, w), z)}
val tbl = List((0, 0x7e), (1, 0x30), …, (9, 0x79)) segment := decoder(data, tbl, segment.width())
パターンを作るメソッド.回路のレシピ.
Synthesijer.scalaを使う場合
実データに合わせた回路の生成
47
類似オブジェクトの生成
class MemPort(m:Module, p:String, d:Int){ val we = inP(p + "_we") val oe = inP(p + "_oe") val addr = inP(p + "_addr") val din = inP(p + "_din") val dout = outP(p + "_dout")}
val m0 = new MemPort(module, "m0", 32) val m1 = new MemPort(module, "m1", 8)
ユニットをクラスとしてまとめる
生成
m0
m1
48
直列化/復元コードのテンプレート化val data = inP("data", 32)val seq = seq("main")
def for_first(s:State, d:Port) = {...}def for_second(s:State, d:Port) = {...}def for_rest(s:State, d:Port) = {...}
var s = seq.add()for(i <- 0 to 1){ i match { case 0 => for_first(s, data) case 1 => for_second(s, data) } s = s -> seq.add()}for_rest(s, data)s -> (done, done_state)
49
性能と回路のリソース使用量✔ クロック単位での処理を記述できる✔ 1クロック内での並列処理が記述可能
✔Scalaの機能を使ってHDLを生成している✔ 回路としてのオーバヘッドは発生しない
記述できる回路の処理性能は本質的にはHDLによるRTL設計と遜色ない
回路リソース使用量は本質的にはHDLによるRTL設計と遜色ない
50
まとめと今後の課題
✔ 状態遷移と組み合わせ回路設計に特化したDSLを設計✔ Scalaの言語機能を利用して再利用性の高い開発を実現
✔ 設計空間の自動探索✔ 抽象的な設計手法ならではの最適化手法の適用
まとめ
今後の課題
http://synthesijer.sourceforge.net/