Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Synthesijer.Scala (PROSYM 2015)

5,317 views

Published on

Introduction of Synthesijer.Scala, which is a DSL to write HDL with Scala

Published in: Engineering

Synthesijer.Scala (PROSYM 2015)

  1. 1. Scalaによる FPGAアプリケーション開発用DSLの設計 わさらぼ 三好 健文 2015.01.09
  2. 2. 2 FPGAとは? ✔ 論理回路・データパスを自由に作り込めるLSI ✔ I/Oを自由に使える Field Programmable Gate Array
  3. 3. 3 FPGAとは? ✔ 論理回路・データパスを自由に作り込めるLSI ✔ I/Oを自由に使える ✔ クロックレベルの同期と並列性を活用した処理を実現 Field Programmable Gate Array
  4. 4. 4 FPGAとは? ✔ 論理回路・データパスを自由に作り込めるLSI ✔ I/Oを自由に使える ✔ クロックレベルの同期と並列性を活用した処理を実現 ✔ ASIC開発のプロトタイプとして ✔ 特定用途向け(少数生産)の製品として Field Programmable Gate Array
  5. 5. 5 計算プラットフォームとしてのFPGA プロセッサの場合 FPGAの場合 高性能 低消費電力 コンパクト
  6. 6. 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. 7. 7 Memcached@Xilinx, ETH Zurich 10G if DRAM Network adapter 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. 8. 8 FPGAの開発手法 HDLによるRTL設計
  9. 9. 9 開発フロー HDLを使ったRTL設計で所望のモジュールを実装 RTLシミュレーションによる動作検証 使用するFPGAにあわせた制約を定義 ツールで合成,配置配線,FPGA構成情報生成 実機で動作確認
  10. 10. 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. 11. 11 VHDLによるRTL設計の例 library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; entity sim is end 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. 12. 12 VHDLによるRTL設計の例 シミュレーション結果
  13. 13. 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. 14. 14 RTL設計の辛さ ✔ “信号の流れ”を記述する ✔ “処理の流れ”を“信号の流れ”に変換 ↔ 書きたいのは“処理の流れ” ✔たくさんの似たような構造 ✔ たくさんの似たような名前 ✔ 記述の再利用をしたいが難しい 本質としては 実務的には
  15. 15. 15 手軽なFPGA開発のための取り組み ✔ 高位合成言語処理系 ✔ DSL
  16. 16. 16 高位合成処理系 ✔ CやJava,C#などを入力言語とした開発環境 ✔ 開発コストを小さくできる ✔ 生成したHWの質は処理系依存 ✔ 良いHW生成にはコツが必要 ✔ ディレクティブの活用 ✔ 書き方を考える必要がある
  17. 17. 17 高位合成処理系 ✔ Vivado HLS ✔ OpenCL対象の処理系 ✔ CyberWorkBench ✔ Cynthesizer ✔ Symphony C Compiler ✔ ImpulseC ✔ Lime ✔ Synthesijer (旧JavaRock) などなどなど
  18. 18. 18 DSLベースの設計手法 ✔ RTL設計を楽にするためのDSL ✔ 実装したいアプリケーション別のDSL ✔ プログラミングモデルに特化したDSL
  19. 19. 19 様々なDSLベースのシステム開発(1) ✔ MyHDL (Pythonベース) ✔ JHDL (Javaベース) ✔ Chisel (Scalaベース) などなどなど RTL設計(あるいは少し抽象的なHW設計)を より楽にするためのDSL
  20. 20. 20 様々なDSLベースのシステム開発(2) ✔ Spiral ←Linear Digital Processing ✔ HDL Coder ← 信号処理(Matlab) ✔ Optimus ← ストリーム処理 ✔ LINQ ← クエリプロセッシング などなどなど ✔ DSLを作るツールも.(たとえば,LMS/Scala) 実装したいアプリケーションに特化したDSL
  21. 21. 21 様々なDSLベースのシステム開発(3) ✔ Bluespec (並行プログラミング) ✔ MaxCompiler (データフロープログラミング) ✔ FloPoCo (浮動小数点数パイプライン) などなどなど 使用するプログラミングモデルに特化したDSL
  22. 22. 22 DSLベースの設計手法 ✔ RTL設計を楽にするためのDSL ←依然RTLであることに代わりはない ✔ 実装したいアプリケーション別のDSL ←HWの設計探索をしたい場合には不向き ✔ プログラミングモデルに特化したDSL →さて,どんなモデルがよいだろうか?
  23. 23. 23 FPGAが有用なのはなぜか? ✔ 論理回路・データパスを自由に作り込めるLSI ✔ I/Oを自由に使える ✔ クロックレベルの同期と並列性を活用した処理を実現 Field Programmable Gate Array
  24. 24. 24 FPGAが有用なのはなぜか? 10G if DRAM Network adapter 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. 25. 25 鍵はパイプライン並列化 FIFO スループット T [bps] w [byte] f [Hz] 実行 ステージ FIFO 実行 ステージ 実行 ステージ
  26. 26. 26 データが来たら迎え撃つ タワーディフェンス系のゲームの画像
  27. 27. 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. 28. 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. 29. 29 組み合わせ回路/データ並列性の活用 ✔ プロセッサと比べてFPGA回路のφは圧倒的に低速 ✔ 高速データ処理では1クロックでデータを捌く必要も ✔ 時にはソフトウェア実装とは全く違う場合も 条件 ・・・ 条件 v.s
  30. 30. 30 欲しいDSL ✔ Bluespec (並行プログラミング) ✔ MaxCompiler (データフロープログラミング) ✔ FloPoCo (浮動小数点数パイプライン) などなどなど 使用するプログラミングモデルに特化したDSL 状態遷移および各状態での処理設計がやりやすく 組み合わせ回路が書きやすい言語
  31. 31. 31 設計: Synthesijer.scala ✔ 組み合わせ回路の設計の容易は失わないまま ✔ “処理の流れ”の記述を容易にする ✔ クロックベースの状態管理と状態遷移を言語機能に ✔ 内部DSLとして設計.回路設計にScalaの機能を活用. ✔ 設計資産の再利用性を高める ✔ 見通しの良い設計を可能にする
  32. 32. 32 開発フロー Scalaプログラムとして実装 → VHDLまたはVerilog HDLを生成 RTLシミュレーションによる動作検証 使用するFPGAにあわせた制約を定義 ツールで合成,配置配線,FPGA構成情報生成 実機で動作確認 Synthesijer.Scalaを使ってモジュールを実装
  33. 33. 33 モデル モジュールの設計単位 入出力. クロック単位で状態保持 組み合わせ回路. 状態は持たない クロック単位での状態保持 状態遷移マシン
  34. 34. 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 -- sequencers end RTL;
  35. 35. 35 Sequencer: 状態遷移機械 S0:State S1:State S2:State Sequencer val 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. 36. 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 := p t <= (s0, u)
  37. 37. 37 ExprItem: 組み合わせ回路 ✔ 演算構成要素 ✔ Signal/Port ✔ Value (即値) ✔ ExprItem同士の演算結果 val m = new Module("hoge") val s = m.signal(32) val t = m.signal(32) val e0 = s + s t := e0 s <= (s0, s + 1)
  38. 38. 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. 39. 39 ベンディングマシンの例 ドリンク 自動販売機 ¢5 ¢10 ドリンク一杯¢20 お釣りは出ません
  40. 40. 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. 41. 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. 42. 42 ベンディングマシンのステートマシン
  43. 43. 43 Scalaの機能を使った設計効率化の向上 ✔ 設計資産をメソッドやクラスとして保存,再利用 ✔ 類似オブジェクトや類似オブジェクトの生成 ✔ ループとパタンマッチによる直列化/復元コードの生成
  44. 44. 44 設計資産の再利用 例: デコーダ (7セグメントLEDの点灯) 4 0 2 51 6 7 3
  45. 45. 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 7 3 毎回このパターンを書かないといけない. 従来のHDLによるRTL設計の場合
  46. 46. 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. 47. 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. 48. 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. 49. 49 性能と回路のリソース使用量 ✔ クロック単位での処理を記述できる ✔ 1クロック内での並列処理が記述可能 ✔Scalaの機能を使ってHDLを生成している ✔ 回路としてのオーバヘッドは発生しない 記述できる回路の処理性能は本質的には HDLによるRTL設計と遜色ない 回路リソース使用量は本質的にはHDLによる RTL設計と遜色ない
  50. 50. 50 まとめと今後の課題 ✔ 状態遷移と組み合わせ回路設計に特化したDSLを設計 ✔ Scalaの言語機能を利用して再利用性の高い開発を実現 ✔ 設計空間の自動探索 ✔ 抽象的な設計手法ならではの最適化手法の適用 まとめ 今後の課題 http://synthesijer.sourceforge.net/

×