synthesijer hls 20150116

51
Synthesijer @高位合成友の会 わさらぼ 三好 健文 2015.01.16

Upload: takefumi-miyoshi

Post on 13-Jul-2015

2.005 views

Category:

Engineering


0 download

TRANSCRIPT

Page 1: Synthesijer hls 20150116

Synthesijer @高位合成友の会

わさらぼ 三好 健文

2015.01.16

Page 2: Synthesijer hls 20150116

2

Synthesijer とは✔ JavaプログラムをFPGA上のハードウェアに変換

✔ 複雑なアルゴリズムのハードウェア実装を楽に✔ オブクジェクト指向設計による再利用性の向上

✔ 特殊な記法,追加構文はない✔ ソフトウェアとして実行可能.動作の確認、検証が容易✔ 書けるプログラムに制限は加える

(動的なnew,再帰は不可など)

Javaコンパイラフロントエンド

Synthesijerエンジン

Javaコンパイラバックエンド

合成配置配線

while(){if(...){ … }else{ … … }….}

複雑な状態遷移も,Javaの制御構文を使って楽に設計できる同じJavaプログラムをソフトウェアとしてもFPGA上のハードウェアとしても実行可能

Open-source

Page 3: Synthesijer hls 20150116

3

サンプル1: グラフィクス表示✔ 90度位相ずれしたサインカーブをSWで描画

Page 4: Synthesijer hls 20150116

4

FPGAでの実行例✔ 90度位相ずれしたサインカーブを実機で確認

Page 5: Synthesijer hls 20150116

5

Synthesijer 開発の経緯✔ 2009年頃 Bluespecに感銘を受ける✔ 2010年12月頃 高位合成処理系を作ってみたい→Javaベースに✔ 2011年7月 JavaRockの開発を開始 JavaをVHDLに変換する.1文1ステート→簡単な並列化

✔ 2012(?)年〜2013年 農工大中條研小池さんによるJavaRock-Thrashの開発 種々の最適化の実装など

✔ 2014年

Synthesijerとして名称をあらため開発を再スタート

JavaRock/JavaRock-Thrashの実装を通じた知見の活用

なぜか

Page 6: Synthesijer hls 20150116

6

Synthesijer クイックスタート

Page 7: Synthesijer hls 20150116

7

クイックスタート 1/8(1) バイナリパッケージをダウンロードします

http://synthesijer.sourceforge.net

なるべく日付の新しいものをDLしてください

ダウンロードページに遷移します

✔ JDK7が必要です.✔ Eclipseを使って開発してみます.

Page 8: Synthesijer hls 20150116

8

クイックスタート 2/8

(2) Eclipseでプロジェクトを作ります

Page 9: Synthesijer hls 20150116

9

クイックスタート 3/8(3) libフォルダを作ってDLしたJARをコピー,ビルドパスに追加する

DLしたJARをD&Dでコピー

ビルドパスに追加

準備完了!!

Page 10: Synthesijer hls 20150116

10

クイックスタート 4/8(4) Javaのクラスを作る

クラス生成ダイアログ

Page 11: Synthesijer hls 20150116

11

クイックスタート 5/8(5) 間隔をおいて変数ledをtrue/falseするプログラムを書く

Lチカに相当する変数

適当なウェイト点滅

自動コンパイルが裏で動くので,Javaコードとしての正しさは即座にチェックされる

Page 12: Synthesijer hls 20150116

12

クイックスタート 6/8(6) Synthesijerを使ってJavaコードをHDLに変換

実行

中間生成物

VHDL/Verilog HDL

Page 13: Synthesijer hls 20150116

13

クイックスタート 7/8(7) ISEで合成,配置配線

生成したモジュールのインスタンスを生成

トップのHDLとUCFは別途用意

Page 14: Synthesijer hls 20150116

14

クイックスタート 8/8(8) FPGAをコンフィギュレーションして動作を確認

Page 15: Synthesijer hls 20150116

15

補足✔ 配列(= ブロックRAM)やVHDL/Verilogライブラリ:

synthesijer_lib_yyyymmdd.zip✔ サンプル:

synthesijer_samples_yyyymmdd.zip

Page 16: Synthesijer hls 20150116

16

参考✔ http://synthesijer.sourceforge.net

✔ リソース一式,クイックスタートガイドなど✔ http://qiita.com/kazunori279/items/4951ca5f6164040878ce✔ Synthesijer関連資料まとめ✔ http://labs.beatcraft.com/ja/index.php?Synthesijer

✔ Altera DE0-nanoでのサンプルの動作手順など (ビートクラフト様)

✔ http://marsee101.blog19.fc2.com/blog-category-116.html✔ FPGAの部屋: Synthesijerでラプラシアンフィルタを作ってみた

✔ http://wasa-labo.com/wp/✔ わさらぼ ブログ – 開発状況,Tipsなど

Page 17: Synthesijer hls 20150116

17

Synthesijer とは? 

Page 18: Synthesijer hls 20150116

18

高位合成処理系に何を求めるか?✔ 記述コストの軽減

✔ 高抽象度の表現方法を利用したい✔ 言語習得にコストをかけたくない

✔ 動作検証/デバッグ効率の向上✔ 短時間で動作を確認したい✔ 見通しよく,手軽なデバッグをしたい

✔ FPGAのパフォーマンスの活用✔ 粗粒度,細粒度の並列性の活用✔ IPコアや内部機能ユニットを活用したい✔ 設計空間の探索

Page 19: Synthesijer hls 20150116

19

Synthesijer

✔ クラスによるオブジェクト指向設計言語

 ← HWのモジュール設計との親和性は高そう✔ 言語仕様で並列処理をサポート

✔ Thread,wait-notify✔ (Cと違い)明示的なポインタの扱いが不要

✔ 言語の想定するメモリ構造から解放され得るかも

✔ 動的な振る舞いは厄介そう

Javaベースの高位合成処理系

Page 20: Synthesijer hls 20150116

20

Synthesijer 設計基本方針✔ JavaプログラムをそのままHDL→HW化

✔ 追加構文,データ型は導入しない✔ 使える記述には制限を導入

HDLで書けることをすべてJavaで書けるようにするではない

Javaで書けることををすべてHDL(HW)にするではない

Javaとして実行可能なプログラムをHWにする≒ フェッチのないJavaプロセッサをHDLで直接生成する

Page 21: Synthesijer hls 20150116

21

3つの開発パタン

(1) Javaによるモジュールだけでシステムを構成

(2) HDLによるモジュールを部品として利用.全体管理はJavaで記述 = 既存IPコア,FPGAの性能を活用

(3) Javaによるモジュールを部品として利用.全体管理はHDLで記述 = 複雑なアルゴリズムをSWプログラマに書いてもらう.SW資産の活用

(1)Javaでシステムを構成 (2)Java + HDL記述の部品 (3)HDL + Java記述の部品

Page 22: Synthesijer hls 20150116

22

最近よく実装しているパタン

FIFO

実行ステージ

FIFO

実行ステージ

FIFO

スループット T [bps]

実行ステージ

FIFO

実行ステージ

FIFO

実行ステージ

FIFO

実行ステージ

FIFOここをJavaで書く

Page 23: Synthesijer hls 20150116

23

FPGAにキラーアプリはないの定理Florent de Dinechin, "Building Custom Arithmetic Operators with the FloPoCo Generator”,http://www.hipeac.net/conference/berlin/tutorial/flopoco

なんとかして開発スピードを速くしたい

Page 24: Synthesijer hls 20150116

24

SynthesijerのHDL生成方法

Page 25: Synthesijer hls 20150116

25

Synthesijer でのHDL生成

Javaコード グローバルテーブルの作成

スケジュール表の作成

最適化

出力 VHDL/Verilog HDLコード

Javaコード

VHDL/Verilog HDLコード

Page 26: Synthesijer hls 20150116

26

Synthesijer でのHDL生成: 例題

package blink_led;

public class BlinkLED { public boolean led; public void run(){ while(true){ led = true; for(int i = 0; i < 5000000; i++) ; led = false; for(int i = 0; i < 5000000; i++) ; } }}

Page 27: Synthesijer hls 20150116

27

Synthesijer でのHDL生成: 大枠

class

entity blink_led_BlinkLED is port ( clk : in std_logic; reset : in std_logic; field_led_output : out std_logic; field_led_input : in std_logic; field_led_input_we : in std_logic; run_req : in std_logic; run_busy : out std_logic );end blink_led_BlinkLED;

class BlinkLED {

public boolean led;

public void run(){ while(true){ … } }}

module

クラス毎にHWモジュールを生成

Page 28: Synthesijer hls 20150116

28

Synthesijer でのHDL生成: スケジュール表メソッド毎にスケジュール表を生成

run_0000: op=METHOD_EXIT, src=, dest=, next=0001run_0001: op=METHOD_ENTRY, src=, dest=, next=0002 (name=run)run_0002: op=JT, src=true:BOOLEAN, dest=, next=0004, 0003run_0003: op=JP, src=, dest=, next=0023run_0004: op=ASSIGN, src=true:BOOLEAN, dest=class_led_0000:BOOLEAN, next=0005run_0005: op=ASSIGN, src=0:INT, dest=run_i_0001:INT, next=0006run_0006: op=LT, src=run_i_0001:INT, 5000000:INT, dest=binary_expr_00002:BOOLEAN, next=0007run_0007: op=JT, src=binary_expr_00002:BOOLEAN, dest=, next=0012, 0008run_0008: op=JP, src=, dest=, next=0013run_0009: op=ADD, src=run_i_0001:INT, 1:INT, dest=unary_expr_00003:INT, next=0010run_0010: op=ASSIGN, src=unary_expr_00003:INT, dest=run_i_0001:INT, next=0011run_0011: op=JP, src=, dest=, next=0006run_0012: op=JP, src=, dest=, next=0009run_0013: op=ASSIGN, src=false:BOOLEAN, dest=class_led_0000:BOOLEAN, next=0014run_0014: op=ASSIGN, src=0:INT, dest=run_i_0004:INT, next=0015run_0015: op=LT, src=run_i_0004:INT, 5000000:INT, dest=binary_expr_00005:BOOLEAN, next=0016run_0016: op=JT, src=binary_expr_00005:BOOLEAN, dest=, next=0021, 0017run_0017: op=JP, src=, dest=, next=0022run_0018: op=ADD, src=run_i_0004:INT, 1:INT, dest=unary_expr_00006:INT, next=0019run_0019: op=ASSIGN, src=unary_expr_00006:INT, dest=run_i_0004:INT, next=0020run_0020: op=JP, src=, dest=, next=0015run_0021: op=JP, src=, dest=, next=0018run_0022: op=JP, src=, dest=, next=0002run_0023: op=JP, src=, dest=, next=0000

Page 29: Synthesijer hls 20150116

29

Synthesijer でのHDL生成: 出力(状態遷移)

メソッド毎にスケジュール表を生成 → 状態遷移機械

Page 30: Synthesijer hls 20150116

30

Synthesijer でのHDL生成: 出力(データ操作)

メソッド毎にスケジュール表を生成 → 文/式相当のデータ操作

run_0000: op=METHOD_EXIT, src=, dest=, next=0001run_0001: op=METHOD_ENTRY, src=, dest=, next=0002 (name=run)run_0002: op=JT, src=true:BOOLEAN, dest=, next=0004, 0003run_0003: op=JP, src=, dest=, next=0023run_0004: op=ASSIGN, src=true:BOOLEAN, dest=class_led_0000:BOOLEAN, next=0005run_0005: op=ASSIGN, src=0:INT, dest=run_i_0001:INT, next=0006run_0006: op=LT, src=run_i_0001:INT, 5000000:INT, dest=binary_expr_00002:BOOLEAN, next=0007run_0007: op=JT, src=binary_expr_00002:BOOLEAN, dest=, next=0012, 0008run_0008: op=JP, src=, dest=, next=0013run_0009: op=ADD, src=run_i_0001:INT, 1:INT, dest=unary_expr_00003:INT, next=0010run_0010: op=ASSIGN, src=unary_expr_00003:INT, dest=run_i_0001:INT, next=0011run_0011: op=JP, src=, dest=, next=0006run_0012: op=JP, src=, dest=, next=0009run_0013: op=ASSIGN, src=false:BOOLEAN, dest=class_led_0000:BOOLEAN, next=0014run_0014: op=ASSIGN, src=0:INT, dest=run_i_0004:INT, next=0015run_0015: op=LT, src=run_i_0004:INT, 5000000:INT, dest=binary_expr_00005:BOOLEAN, next=0016run_0016: op=JT, src=binary_expr_00005:BOOLEAN, dest=, next=0021, 0017run_0017: op=JP, src=, dest=, next=0022run_0018: op=ADD, src=run_i_0004:INT, 1:INT, dest=unary_expr_00006:INT, next=0019run_0019: op=ASSIGN, src=unary_expr_00006:INT, dest=run_i_0004:INT, next=0020run_0020: op=JP, src=, dest=, next=0015run_0021: op=JP, src=, dest=, next=0018run_0022: op=JP, src=, dest=, next=0002run_0023: op=JP, src=, dest=, next=0000

Page 31: Synthesijer hls 20150116

31

Synthesijer でのHDL生成: 出力(データ操作)

メソッド毎にスケジュール表を生成 → 文/式相当のデータ操作

run_0000: op=METHOD_EXIT, src=, dest=, next=0001run_0001: op=METHOD_ENTRY, src=, dest=, next=0002 (name=run)run_0002: op=JT, src=true:BOOLEAN, dest=, next=0004, 0003run_0003: op=JP, src=, dest=, next=0023run_0004: op=ASSIGN, src=true:BOOLEAN, dest=class_led_0000:BOOLEAN, next=0005run_0005: op=ASSIGN, src=0:INT, dest=run_i_0001:INT, next=0006run_0006: op=LT, src=run_i_0001:INT, 5000000:INT, dest=binary_expr_00002:BOOLEAN, next=0007run_0007: op=JT, src=binary_expr_00002:BOOLEAN, dest=, next=0012, 0008run_0008: op=JP, src=, dest=, next=0013run_0009: op=ADD, src=run_i_0001:INT, 1:INT, dest=unary_expr_00003:INT, next=0010run_0010: op=ASSIGN, src=unary_expr_00003:INT, dest=run_i_0001:INT, next=0011run_0011: op=JP, src=, dest=, next=0006run_0012: op=JP, src=, dest=, next=0009run_0013: op=ASSIGN, src=false:BOOLEAN, dest=class_led_0000:BOOLEAN, next=0014run_0014: op=ASSIGN, src=0:INT, dest=run_i_0004:INT, next=0015run_0015: op=LT, src=run_i_0004:INT, 5000000:INT, dest=binary_expr_00005:BOOLEAN, next=0016run_0016: op=JT, src=binary_expr_00005:BOOLEAN, dest=, next=0021, 0017run_0017: op=JP, src=, dest=, next=0022run_0018: op=ADD, src=run_i_0004:INT, 1:INT, dest=unary_expr_00006:INT, next=0019run_0019: op=ASSIGN, src=unary_expr_00006:INT, dest=run_i_0004:INT, next=0020run_0020: op=JP, src=, dest=, next=0015run_0021: op=JP, src=, dest=, next=0018run_0022: op=JP, src=, dest=, next=0002run_0023: op=JP, src=, dest=, next=0000

... assign tmp_0010 = run_i_0001 + 32'h00000001;... always @(posedge clk) begin if(reset == 1'b1) begin run_i_0001 <= 32'h00000000; end else begin if (run_method == run_method_S_0004) begin run_i_0001 <= 32'h00000000; end else if (run_method == run_method_S_0010) begin run_i_0001 <= unary_expr_00003; end end end... always @(posedge clk) begin if(reset == 1'b1) begin unary_expr_00003 <= 0; end else begin if (run_method == run_method_S_0009) begin unary_expr_00003 <= tmp_0010; end end end...

Page 32: Synthesijer hls 20150116

32

最適化

✔ メモリ書き込みアクセスのパック✔ 基本ブロック内の細粒度並列化

✔ メモリ読み込みのアドレス指定のステート最適化✔ 演算のチェイニング

今実装しているもの

もうすぐ実装するもの

≒ スケジュール表ベースでサイズを小さくすること

Page 33: Synthesijer hls 20150116

33

SynthesijerはJavaベースなので...オブジェクト指向的プログラミング!!… … …

Page 34: Synthesijer hls 20150116

34

インスタンス生成クラスのインスタンスを生成/利用できる

public class Test002 { public static final int DEFAULT_VALUE = 0x20; public int[] a = new int[128]; public int x, y; public void init(){ for(int i = 0; i < a.length; i++){ a[i] = 0; } }

public void set(int i, int v){ a[i] = v; }…}

ex. sample/test/Test002.javaとsample/test/Test003.java

public class Test003 { private final Test002 t = new Test002(); public void test(){ t.init(); t.set(0, 100); // 0 <- 100 … }…}

Page 35: Synthesijer hls 20150116

35

インスタンス生成クラスのインスタンスを生成/利用できるex. sample/test/Test002.javaとsample/test/Test003.java

Test002 class_t_0000 ( .clk(class_t_0000_clk), .reset(class_t_0000_reset), .a_address(class_t_0000_a_address), .a_we(class_t_0000_a_we), .a_oe(class_t_0000_a_oe), .a_din(class_t_0000_a_din), .a_dout(class_t_0000_a_dout), .a_length(class_t_0000_a_length), … .set_i(class_t_0000_set_i), .set_v(class_t_0000_set_v), … .init_req(class_t_0000_init_req), .init_busy(class_t_0000_init_busy), … .set_req(class_t_0000_set_req), .set_busy(class_t_0000_set_busy), … );

Page 36: Synthesijer hls 20150116

36

インスタンス生成・拡張モジュールVHDL/Verilog HDLで書いたモジュールのインスタンス化

module hoge( input wire clk, input wire reset,

input signed [31:0] a_address, input signed [31:0] a_din, input wire we, input wire oe, output signed [31:0] a_dout, output signed [31:0] a_length,

input wire func_req, output wire func_busy,

output wire [31:0] q);

endmodule

clkreset

a_addressa_dina_wea_oe

a_din

a_dout

func_reqfunc_busy

hoge q

ex. Verilog HDLで書いたhogeをJavaから呼び出す

a_length

Page 37: Synthesijer hls 20150116

37

インスタンス生成・拡張モジュールVHDL/Verilog HDLで書いたモジュールのインスタンス化

class HogeIface extends HDLModule{

int[] a; void func(){}

public HogeIface(String... args){ newPort("a_address", HDLPort.DIR.IN, genSignedType(32)); newPort("a_din", HDLPort.DIR.IN, genSignedType(32)); newPort("a_we", HDLPort.DIR.IN, genBitType()); newPort("a_oe", HDLPort.DIR.IN, genBitType()); newPort("a_dout", HDLPort.DIR.OUT, genSignedType(32)); newPort("a_length", HDLPort.DIR.OUT, genSignedType(32)); newPort("func_req", HDLPort.DIR.IN, genBitType()); newPort("func_busy", HDLPort.DIR.OUT, genBitType());

newPort("q", HDLPort.DIR.OUT, genVectorType(32), Enum.of(OPTION.EXPORT)); } … }

↓のようなJava用のダミーコードを書いて,使う… private final HogeIface obj = new HogeIface();… private void func(){ obj.a[10] = 100; obj.func();…

a[]

func()

これはJavaでは使わない

Page 38: Synthesijer hls 20150116

38

インスタンス生成・拡張モジュールVHDL/Verilog HDLで書いたモジュールのインスタンス化

@SynthesijerNativeInterface("hoge")class HogeIface extends HDLModule{

int[] a; void func(){}

public HogeIface(String... args){

newPort("q", HDLPort.DIR.OUT, genVectorType(32), Enum.of(OPTION.EXPORT)); }

}

将来的にはこんな感じにすっきりさせたい

これはJavaでは使わない

Page 39: Synthesijer hls 20150116

39

+α Synthesijer.scala

Page 40: Synthesijer hls 20150116

40

Synthesijer.scala✔ Javaで全部書けない...とはいえ ✔ もう普通のHDL(= VHDL/Verilog HDL)は書きたくない

✔ たくさんの似たような名前の変数の定義✔ リセット,パルス信号をもとに戻すの忘れる✔ などなど

✔ 制御構造とデータ処理が同じ,な設計モデルはいやだ✔ 記述の再利用をしたい

✔ データ処理とデータ代入をわけたい

もっと高級なRTL設計言語があればいい

Page 41: Synthesijer hls 20150116

41

Synthesijer.scala とは✔ Synthesijerのバックエンドを使ってScala“で”HDLを書く

✔ signal, port: 状態を変更可能なオブジェクト✔ expr: 副作用なしの式✔ sequencer: 状態遷移機械✔ module: モジュール全体

✔ 上記のオブジェクトをScalaでインスタンス化.つなぎ合わせる.

Page 42: Synthesijer hls 20150116

42

はじめての Synthesijer.scala✔ Lチカ

def generate_led() : Module = { val m = new Module("led") val q = m.outP("q") val counter = m.signal(32) q := counter.ref(5) val seq = m.sequencer("main") counter is (VECTOR_ZERO in seq.idle) val s0 = seq.idle -> seq.add() counter <= (counter + 1 in s0) return m}

def main() = { val m = generate_led() m.genVHDL()}

Page 43: Synthesijer hls 20150116

43

設計資産の再利用

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

4

0

2

51

6

73

Page 44: Synthesijer hls 20150116

44

設計資産の再利用

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 45: Synthesijer hls 20150116

45

設計資産の再利用

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 46: Synthesijer hls 20150116

46

Synthesijer.Scalaについて詳細

http://www.slideshare.net/miyox/synthesijerscala-prosym-2015

Page 47: Synthesijer hls 20150116

47

自分なりのパタン,最適化の埋め込みも

✔ 組み合わせ回路の段数に応じたFF(状態)の追加,除去

✔ 入出力データに対するパタンマッチ✔ よく使うモジュールのテンプレート化

例えば...

などなど

Page 48: Synthesijer hls 20150116

48

今後のSynthesijer

Page 49: Synthesijer hls 20150116

49

ロードマップ

手続き型言語的基本演算,操作

整数プリミティブ型変数の利用

算術,論理,シフト演算(除算・剰余算以外)

制御構文(分岐,ループ)

メソッド呼び出し

除算・剰余算

浮動小数点数演算

オブジェクト指向的インスンタンス協調

finalでのインスタンスの生成

インスタンスメソッドの呼び出し

インスタンス変数へのリードアクセス

インスタンス変数へのライトアクセス

インスタンス間での配列読み書きのサポート

インスタンスの配列,配列の配列のサポート

コンストラクタのサポート

インスタンスのチェインアクセス

並列化パフォーマンス

基本ブロック内自動並列化

Threadによる明示的な処理の並列化をサポート

ループ内パイプライニング

ライブラリ 整数プリミティブ変数の配列

AXI接続用のコンポーネントライブラリの提供

Stringクラスのサポート

ユーザビリティ コマンドラインでのコンパイル

HDLモジュールとのバインディング機構

FPGA合成ツールとの連携,統一的な開発フローの提供

スケジューリング可視化ツール

HDL生成ライブラリを活用したDSLの提供

2014年7月 2014年12月 2015年3月 2015年6月

Page 50: Synthesijer hls 20150116

50

今後挑戦したいこと

✔ メソッドのパイプライン化✔ I/Oストリームへの対応

✔ コンストラクタに対応✔ コンパイル時のJavaプログラム実行

✔ lambda式対応✔ Streamへの対応

Page 51: Synthesijer hls 20150116

51

Synthesijerhttp://synthesijer.sourceforge.net/