Synthesijer.Scala (PROSYM 2015)

50
ScalaFPGADSL2015.01.09

Transcript of Synthesijer.Scala (PROSYM 2015)

Page 1: Synthesijer.Scala (PROSYM 2015)

ScalaによるFPGAアプリケーション開発用DSLの設計

わさらぼ

三好 健文

2015.01.09

Page 2: Synthesijer.Scala (PROSYM 2015)

2

FPGAとは?

✔ 論理回路・データパスを自由に作り込めるLSI✔ I/Oを自由に使える

Field Programmable Gate Array

Page 3: Synthesijer.Scala (PROSYM 2015)

3

FPGAとは?

✔ 論理回路・データパスを自由に作り込めるLSI

✔ I/Oを自由に使える

✔ クロックレベルの同期と並列性を活用した処理を実現

Field Programmable Gate Array

Page 4: Synthesijer.Scala (PROSYM 2015)

4

FPGAとは?

✔ 論理回路・データパスを自由に作り込めるLSI

✔ I/Oを自由に使える✔ クロックレベルの同期と並列性を活用した処理を実現

✔ ASIC開発のプロトタイプとして✔ 特定用途向け(少数生産)の製品として

Field Programmable Gate Array

Page 5: Synthesijer.Scala (PROSYM 2015)

5

計算プラットフォームとしてのFPGAプロセッサの場合

FPGAの場合 高性能低消費電力コンパクト

Page 6: Synthesijer.Scala (PROSYM 2015)

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

Page 7: Synthesijer.Scala (PROSYM 2015)

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

Page 8: Synthesijer.Scala (PROSYM 2015)

8

FPGAの開発手法HDLによるRTL設計

Page 9: Synthesijer.Scala (PROSYM 2015)

9

開発フロー

HDLを使ったRTL設計で所望のモジュールを実装

RTLシミュレーションによる動作検証

使用するFPGAにあわせた制約を定義

ツールで合成,配置配線,FPGA構成情報生成

実機で動作確認

Page 10: Synthesijer.Scala (PROSYM 2015)

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;

カウンタの設計

Page 11: Synthesijer.Scala (PROSYM 2015)

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;

カウンタのシミュレーションコード

Page 12: Synthesijer.Scala (PROSYM 2015)

12

VHDLによるRTL設計の例シミュレーション結果

Page 13: Synthesijer.Scala (PROSYM 2015)

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

Page 14: Synthesijer.Scala (PROSYM 2015)

14

RTL設計の辛さ

✔ “信号の流れ”を記述する✔ “処理の流れ”を“信号の流れ”に変換 ↔ 書きたいのは“処理の流れ”

✔たくさんの似たような構造✔ たくさんの似たような名前

✔ 記述の再利用をしたいが難しい

本質としては

実務的には

Page 15: Synthesijer.Scala (PROSYM 2015)

15

手軽なFPGA開発のための取り組み✔ 高位合成言語処理系✔ DSL

Page 16: Synthesijer.Scala (PROSYM 2015)

16

高位合成処理系✔ CやJava,C#などを入力言語とした開発環境✔ 開発コストを小さくできる✔ 生成したHWの質は処理系依存✔ 良いHW生成にはコツが必要

✔ ディレクティブの活用✔ 書き方を考える必要がある

Page 17: Synthesijer.Scala (PROSYM 2015)

17

高位合成処理系✔ Vivado HLS

✔ OpenCL対象の処理系✔ CyberWorkBench

✔ Cynthesizer

✔ Symphony C Compiler

✔ ImpulseC

✔ Lime

✔ Synthesijer (旧JavaRock)

などなどなど

Page 18: Synthesijer.Scala (PROSYM 2015)

18

DSLベースの設計手法✔ RTL設計を楽にするためのDSL

✔ 実装したいアプリケーション別のDSL

✔ プログラミングモデルに特化したDSL

Page 19: Synthesijer.Scala (PROSYM 2015)

19

様々なDSLベースのシステム開発(1)

✔ MyHDL (Pythonベース)

✔ JHDL (Javaベース)

✔ Chisel (Scalaベース)

などなどなど

RTL設計(あるいは少し抽象的なHW設計)をより楽にするためのDSL

Page 20: Synthesijer.Scala (PROSYM 2015)

20

様々なDSLベースのシステム開発(2)

✔ Spiral ←Linear Digital Processing

✔ HDL Coder ← 信号処理(Matlab)

✔ Optimus ← ストリーム処理✔ LINQ ← クエリプロセッシングなどなどなど

✔ DSLを作るツールも.(たとえば,LMS/Scala)

実装したいアプリケーションに特化したDSL

Page 21: Synthesijer.Scala (PROSYM 2015)

21

様々なDSLベースのシステム開発(3)

✔ Bluespec (並行プログラミング)

✔ MaxCompiler (データフロープログラミング)

✔ FloPoCo (浮動小数点数パイプライン)

などなどなど

使用するプログラミングモデルに特化したDSL

Page 22: Synthesijer.Scala (PROSYM 2015)

22

DSLベースの設計手法✔ RTL設計を楽にするためのDSL

←依然RTLであることに代わりはない

✔ 実装したいアプリケーション別のDSL

←HWの設計探索をしたい場合には不向き

✔ プログラミングモデルに特化したDSL

→さて,どんなモデルがよいだろうか?

Page 23: Synthesijer.Scala (PROSYM 2015)

23

FPGAが有用なのはなぜか?

✔ 論理回路・データパスを自由に作り込めるLSI

✔ I/Oを自由に使える

✔ クロックレベルの同期と並列性を活用した処理を実現

Field Programmable Gate Array

Page 24: Synthesijer.Scala (PROSYM 2015)

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 より

データはどうせ移動させる移動途中で副次的に処理できる

Page 25: Synthesijer.Scala (PROSYM 2015)

25

鍵はパイプライン並列化

FIFO

スループット T [bps]

w [byte]f [Hz]

実行ステージ

FIFO

実行ステージ

実行ステージ

Page 26: Synthesijer.Scala (PROSYM 2015)

26

データが来たら迎え撃つ

タワーディフェンス系のゲームの画像

Page 27: Synthesijer.Scala (PROSYM 2015)

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

実行ステージ

実行ステージ

とはいえ,各ステージで状態遷移のある処理が必要

Page 28: Synthesijer.Scala (PROSYM 2015)

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

実行ステージ

実行ステージ

とはいえ,各ステージで状態遷移のある処理が必要

限られた許容サイクルを効率よく使う必要

Page 29: Synthesijer.Scala (PROSYM 2015)

29

組み合わせ回路/データ並列性の活用✔ プロセッサと比べてFPGA回路のφは圧倒的に低速✔ 高速データ処理では1クロックでデータを捌く必要も✔ 時にはソフトウェア実装とは全く違う場合も

条件

・・・

条件

v.s

Page 30: Synthesijer.Scala (PROSYM 2015)

30

欲しいDSL

✔ Bluespec (並行プログラミング)

✔ MaxCompiler (データフロープログラミング)

✔ FloPoCo (浮動小数点数パイプライン)

などなどなど

使用するプログラミングモデルに特化したDSL

状態遷移および各状態での処理設計がやりやすく組み合わせ回路が書きやすい言語

Page 31: Synthesijer.Scala (PROSYM 2015)

31

設計: Synthesijer.scala✔ 組み合わせ回路の設計の容易は失わないまま✔ “処理の流れ”の記述を容易にする

✔ クロックベースの状態管理と状態遷移を言語機能に

✔ 内部DSLとして設計.回路設計にScalaの機能を活用.✔ 設計資産の再利用性を高める✔ 見通しの良い設計を可能にする

Page 32: Synthesijer.Scala (PROSYM 2015)

32

開発フロー

Scalaプログラムとして実装 → VHDLまたはVerilog HDLを生成

RTLシミュレーションによる動作検証

使用するFPGAにあわせた制約を定義

ツールで合成,配置配線,FPGA構成情報生成

実機で動作確認

Synthesijer.Scalaを使ってモジュールを実装

Page 33: Synthesijer.Scala (PROSYM 2015)

33

モデル

モジュールの設計単位

入出力.クロック単位で状態保持

組み合わせ回路.状態は持たない

クロック単位での状態保持状態遷移マシン

Page 34: Synthesijer.Scala (PROSYM 2015)

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;

Page 35: Synthesijer.Scala (PROSYM 2015)

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番目の引数が真の場合にのみ遷移.

Page 36: Synthesijer.Scala (PROSYM 2015)

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)

Page 37: Synthesijer.Scala (PROSYM 2015)

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)

Page 38: Synthesijer.Scala (PROSYM 2015)

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}

Page 39: Synthesijer.Scala (PROSYM 2015)

39

ベンディングマシンの例

ドリンク

自動販売機¢5

¢10

ドリンク一杯¢20お釣りは出ません

Page 40: Synthesijer.Scala (PROSYM 2015)

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;…

Page 41: Synthesijer.Scala (PROSYM 2015)

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()

Page 42: Synthesijer.Scala (PROSYM 2015)

42

ベンディングマシンのステートマシン

Page 43: Synthesijer.Scala (PROSYM 2015)

43

Scalaの機能を使った設計効率化の向上✔ 設計資産をメソッドやクラスとして保存,再利用✔ 類似オブジェクトや類似オブジェクトの生成✔ ループとパタンマッチによる直列化/復元コードの生成

Page 44: Synthesijer.Scala (PROSYM 2015)

44

設計資産の再利用

例: デコーダ (7セグメントLEDの点灯)

4

0

2

51

6

73

Page 45: Synthesijer.Scala (PROSYM 2015)

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設計の場合

Page 46: Synthesijer.Scala (PROSYM 2015)

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を使う場合

実データに合わせた回路の生成

Page 47: Synthesijer.Scala (PROSYM 2015)

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

Page 48: Synthesijer.Scala (PROSYM 2015)

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)

Page 49: Synthesijer.Scala (PROSYM 2015)

49

性能と回路のリソース使用量✔ クロック単位での処理を記述できる✔ 1クロック内での並列処理が記述可能

✔Scalaの機能を使ってHDLを生成している✔ 回路としてのオーバヘッドは発生しない

記述できる回路の処理性能は本質的にはHDLによるRTL設計と遜色ない

回路リソース使用量は本質的にはHDLによるRTL設計と遜色ない

Page 50: Synthesijer.Scala (PROSYM 2015)

50

まとめと今後の課題

✔ 状態遷移と組み合わせ回路設計に特化したDSLを設計✔ Scalaの言語機能を利用して再利用性の高い開発を実現

✔ 設計空間の自動探索✔ 抽象的な設計手法ならではの最適化手法の適用

まとめ

今後の課題

http://synthesijer.sourceforge.net/