synthesijer hls 20150116

Post on 13-Jul-2015

2.005 Views

Category:

Engineering

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Synthesijer @高位合成友の会

わさらぼ 三好 健文

2015.01.16

2

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

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

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

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

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

Synthesijerエンジン

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

合成配置配線

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

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

Open-source

3

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

4

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

5

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

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

✔ 2014年

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

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

なぜか

6

Synthesijer クイックスタート

7

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

http://synthesijer.sourceforge.net

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

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

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

8

クイックスタート 2/8

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

9

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

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

ビルドパスに追加

準備完了!!

10

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

クラス生成ダイアログ

11

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

Lチカに相当する変数

適当なウェイト点滅

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

12

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

実行

中間生成物

VHDL/Verilog HDL

13

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

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

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

14

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

15

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

synthesijer_lib_yyyymmdd.zip✔ サンプル:

synthesijer_samples_yyyymmdd.zip

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など

17

Synthesijer とは? 

18

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

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

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

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

19

Synthesijer

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

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

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

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

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

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

20

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

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

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

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

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

21

3つの開発パタン

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

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

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

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

22

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

FIFO

実行ステージ

FIFO

実行ステージ

FIFO

スループット T [bps]

実行ステージ

FIFO

実行ステージ

FIFO

実行ステージ

FIFO

実行ステージ

FIFOここをJavaで書く

23

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

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

24

SynthesijerのHDL生成方法

25

Synthesijer でのHDL生成

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

スケジュール表の作成

最適化

出力 VHDL/Verilog HDLコード

Javaコード

VHDL/Verilog HDLコード

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++) ; } }}

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モジュールを生成

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

29

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

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

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

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...

32

最適化

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

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

今実装しているもの

もうすぐ実装するもの

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

33

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

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

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

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

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では使わない

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では使わない

39

+α Synthesijer.scala

40

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

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

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

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

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

41

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

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

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

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

43

設計資産の再利用

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

4

0

2

51

6

73

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

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

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

46

Synthesijer.Scalaについて詳細

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

47

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

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

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

例えば...

などなど

48

今後のSynthesijer

49

ロードマップ

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

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

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

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

メソッド呼び出し

除算・剰余算

浮動小数点数演算

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

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

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

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

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

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

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

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

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

並列化パフォーマンス

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

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

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

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

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

Stringクラスのサポート

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

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

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

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

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

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

50

今後挑戦したいこと

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

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

✔ lambda式対応✔ Streamへの対応

51

Synthesijerhttp://synthesijer.sourceforge.net/

top related