synthesijer fpgax 20150201
TRANSCRIPT
ソフトウェアエンジニアにもわかる高位合成
わさらぼみよし たけふみ
(miyox)
2015.02.01
2014 年 8 月 2015 年 1 月0
5
10
15
20
25
30
35
40
45
x20
2014 年 8 月 2015 年 1 月0
5
10
15
20
25
30
35
40
45
x20
高位合成を実装する人達の飲み会 # 2014.8.3
高位合成友の会# 2015.1.16
4
高位合成友の会(恋友)
✔ 豊島さん: 「両刀使いエンジニアは高位合成ツールの夢を見るか?」✔ たばたさん: Neon light compiler - http://goo.gl/JEhlyn
✔ みよし: Synthesijer – http://goo.gl/2w3J6Z
✔ 高前田さん: PyCoRAM – http://goo.gl/0b16rr
論理回路の高位合成について試作した実装とアイデアと妄想について語る会http://hls.connpass.com/event/11009/
5
高位合成処理系の前に
6
一般的なFPGAアプリ設計✔ 論理回路構成要素の内容を決める✔ 論理回路構成要素同士の接続関係を決める
7
一般的なFPGAアプリ設計
1) http://japan.xilinx.com/support/documentation/data_sheets/ds180_7Series_Overview.pdf2) http://hitechglobal.com/boards/virtex7_v2000t.htm
3) http://http://low-powerdesign.com/sleibson/2011/10/25/generation-jumping-2-5d-xilinx-virtex-7-2000t-fpga-delivers-1954560-logic-cells-consumes-only-20w/
8
一般的なFPGAアプリ設計HDL(VHDLやVerilog HDL)によるRTL(Register Transfer Level)設計
9
ちょっと脇道にそれますが
10
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 より
データはどうせ移動させる移動途中で副次的に処理できる
✔ Memcached部分はデータフローアーキテクチャ✔ レイテンシ = 481Cycles@156MHz
11
鍵はパイプライン並列化
FIFO
スループット T [bps]
w [byte]f [Hz]
実行ステージ
FIFO
実行ステージ
実行ステージ
12
データが来たら迎え撃つ
デスクトップタワーディフェンス的なゲーム
13
鍵はパイプライン並列化
パケットデータが 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
実行ステージ
実行ステージ
とはいえ,各ステージで状態遷移のある処理が必要
14
鍵はパイプライン並列化
パケットデータが 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
実行ステージ
実行ステージ
とはいえ,各ステージで状態遷移のある処理が必要
限られた許容サイクルを効率よく使う必要
15
組み合わせ回路/データ並列性の活用✔ プロセッサと比べてFPGA回路のφは圧倒的に低速✔ 高速データ処理では1クロックでデータを捌く必要も✔ 時にはソフトウェア実装とは全く違う場合も
条件
・・・
条件
v.s
16
話は戻りまして
17
一般的なFPGAアプリ設計HDL(VHDLやVerilog HDL)によるRTL(Register Transfer Level)設計
18
HDLによるRTL設計
✔ ロジックを抽象化した式/構文で設計できる✔ クロックレベルのデータ制御✔ 細粒度の並列性の活用
✔ 記述が煩雑✔ “状態”を自分で管理しなければいけない✔ デバッグ/動作検証が難しい
メリット
デメリット
19
HDLによるRTL設計
✔ ロジックを抽象化した式/構文で設計できる✔ クロックレベルのデータ制御✔ 細粒度の並列性の活用
✔ 記述が煩雑✔ “状態”を自分で管理しなければいけない✔ デバッグ/動作検証が難しい
メリット
デメリット
アプリケーション書くの大変開発に時間/コストがかかる
20
FPGAにキラーアプリはないの定理Florent de Dinechin, "Building Custom Arithmetic Operators with the FloPoCo Generator”,http://www.hipeac.net/conference/berlin/tutorial/flopoco
なんとかして開発スピードを速くしたい
21
デメリット克服のためには
✔ FPGAを使うのをやめる✔ より抽象度の高い設計手法/処理系を使う
22
デメリット克服のためには
✔ FPGAを使うのをやめる✔ 別にプロセッサを持ってくる✔ FPGAの上にプロセッサを作る
✔ より抽象度の高い設計手法/処理系を使う✔ 既存のプログラミング言語を借用する✔ 新しい記述言語を模索する✔ 新しい設計概念を模索する
23
デメリット克服のためには
✔ FPGAを使うのをやめる✔ 別にプロセッサを持ってくる✔ FPGAの上にプロセッサを作る
✔ より抽象度の高い設計手法/処理系を使う✔ 既存のプログラミング言語を借用する✔ 新しい記述言語を模索する✔ 新しい設計概念を模索する
24
高位合成処理系 Synthesijer
25
Synthesijer とは✔ JavaプログラムをFPGA上のハードウェアに変換
✔ 複雑なアルゴリズムのハードウェア実装を楽に✔ オブクジェクト指向設計による再利用性の向上
✔ 特殊な記法,追加構文はない✔ ソフトウェアとして実行可能.動作の確認、検証が容易✔ 書けるプログラムに制限は加える
(動的なnew,再帰は不可など)✔ HDLモジュールのJavaからのインスタンス生成
Javaコンパイラフロントエンド
Synthesijerエンジン
Javaコンパイラバックエンド
合成配置配線
while(){if(...){ … }else{ … … }….}
複雑な状態遷移も,Javaの制御構文を使って楽に設計できる同じJavaプログラムをソフトウェアとしてもFPGA上のハードウェアとしても実行可能
Open-source
26
Synthesijer 開発の経緯✔ 2009年頃 Bluespecに感銘を受ける✔ 2010年12月頃 高位合成処理系を作ってみたい→Javaベースに✔ 2011年7月 JavaRockの開発を開始 JavaをVHDLに変換する.1文1ステート→簡単な並列化
✔ 2012(?)年〜2013年 農工大中條研小池さんによるJavaRock-Thrashの開発 種々の最適化の実装など
✔ 2014年
Synthesijerとして名称をあらため開発を再スタート
JavaRock/JavaRock-Thrashの実装を通じた知見の活用
なぜか
27
参考✔ 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など
28
Synthesijerのコード生成
✔ (その前に)典型的な高位合成処理系✔ Synthesijerの場合✔ 最適化のために
29
高位合成処理系は何をするか?
http://www.ida.liu.se/~petel/SysSyn/lect3.frm.pdf
基本はこれに書いてありますHigh-Level Synthesis
30
高位合成処理系は何をするか
入力言語 データフロー スケジューリングデータパス生成
ステート生成物理マッピング
31
高位合成処理系は何をするか
入力言語 データフロー スケジューリングデータパス生成
ステート生成物理マッピング
(1) (2)
(3)
32
高位合成処理系のレイヤ
(1)言語デザイン
(2)アーキテクチャの生成
(3)テクノロジ・マッピング
✔ 設計コストが小さくなるように✔ パフォーマンスを出しやすいように
✔ 命令スケジューリング,並列化の抽出✔ 動作周波数,リソース使用量,レイテンシの考慮
✔ 適切な物理マッピング✔ 符号化
33
Synthesijerでは
✔ 設計コストが小さくなるように✔ パフォーマンスを出しやすいように
✔ 命令スケジューリング,並列化の抽出✔ 動作周波数,リソース使用量,レイテンシの考慮
✔ 適切な物理マッピング✔ 符号化
(1)言語デザイン
(2)アーキテクチャの生成
(3)テクノロジ・マッピング
Java - オブジェクト指向設計 - スレッドで並列化 - 既存資産の活用
ISE/Vivado,QuartusIIにお任せ
Javaから変換するエンジンを実装
34
Synthesijerオーバービュー
Javaコード 字句解析/構文解析
コントロール・データフロー作成
最適化
出力 VHDL/Verilog HDLコード
Javaコード
VHDL/Verilog HDLコード
35
Javaコンパイラ
Javaコード 字句解析/構文解析
コントロール・データフロー作成
最適化
出力 VHDL/Verilog HDLコード
Javaコード
class
JVM用のバイトコード
JVM命令セット内での最適化
36
(理想的な)高位合成処理系の場合
Javaコード 字句解析/構文解析
コントロール・データフロー作成
最適化
出力 VHDL/Verilog HDLコード
Javaコード
VHDL/Verilog HDLコード
自由なデータパスステートマシン
命令セットを強制されない/並列化し放題
37
(理想的な)高位合成処理系の場合
Javaコード 字句解析/構文解析
コントロール・データフロー作成
最適化
出力 VHDL/Verilog HDLコード
Javaコード
VHDL/Verilog HDLコード
自由なデータパスステートマシン
命令セットを強制されない/並列化し放題
完全にはムリ!!
38
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++) ; } }}
39
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モジュールを生成
40
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
41
スケジューラ表の疑似命令
✔ 四則演算,論理演算,シフト✔ 比較✔ 代入✔ 配列のアドレス指定,配列アクセス✔ Call/Return
✔ CallしたらReturnされるまで待つ(基本)✔ Thread.startの呼び出し時は待たずに次へ
✔ 無条件ジャンプ,条件分岐,SELECT✔ フィールドアクセス指示命令
42
Synthesijer でのHDL生成: 出力(状態遷移)
メソッド毎にスケジュール表を生成 → 状態遷移機械
whilefor
for
43
Synthesijer でのHDL生成: 状態遷移状態遷移機械に相当するステートマシンをベタに作る always @(posedge clk) begin if(reset == 1'b1) begin run_method <= run_method_IDLE; run_method_delay <= 32'h0; end else begin case (run_method) run_method_IDLE : begin run_method <= run_method_S_0000; end run_method_S_0000 : begin run_method <= run_method_S_0001; run_method <= run_method_S_0001; end run_method_S_0001 : begin if (run_req_flag == 1'b1) begin run_method <= run_method_S_0002; end end run_method_S_0002 : begin if (tmp_0003 == 1'b1) begin run_method <= run_method_S_0004; end else if (tmp_0004 == 1'b1) begin run_method <= run_method_S_0003; end end run_method_S_0003 : begin...
44
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
45
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...
46
最適化
✔ メモリ書き込みアクセスのパック✔ 基本ブロック内の細粒度並列化
✔ メモリ読み込みのアドレス指定のステート最適化✔ 演算のチェイニング
今実装しているもの
もうすぐ実装するもの
≒ スケジュール表ベースでサイズを小さくすること
47
たとえば public void test(){ boolean success = false; int a = 10; int b = 20; int c = 0; int d = 40; int e = 50; int f = 0; int g = 70; int h = 80; int i = 0; int j = 100; int k = 110; int l = 0; c = a + b; f = d + e; i = g + h; l = j + k; c = c + f; l = l + i; c = c + l; if(c == 10+20+40+50+70+80+100+110) success = true; boolean success2 = check(c); }
48
たとえばtest_0000: op=METHOD_EXIT, src=, dest=, next=0001test_0001: op=METHOD_ENTRY, src=, dest=, next=0002 (name=test)test_0002: op=ASSIGN, src=false:BOOLEAN, dest=test_success_0009:BOOLEAN, next=0003test_0003: op=ASSIGN, src=10:INT, dest=test_a_0010:INT, next=0004test_0004: op=ASSIGN, src=20:INT, dest=test_b_0011:INT, next=0005test_0005: op=ASSIGN, src=0:INT, dest=test_c_0012:INT, next=0006test_0006: op=ASSIGN, src=40:INT, dest=test_d_0013:INT, next=0007test_0007: op=ASSIGN, src=50:INT, dest=test_e_0014:INT, next=0008test_0008: op=ASSIGN, src=0:INT, dest=test_f_0015:INT, next=0009test_0009: op=ASSIGN, src=70:INT, dest=test_g_0016:INT, next=0010test_0010: op=ASSIGN, src=80:INT, dest=test_h_0017:INT, next=0011test_0011: op=ASSIGN, src=0:INT, dest=test_i_0018:INT, next=0012test_0012: op=ASSIGN, src=100:INT, dest=test_j_0019:INT, next=0013test_0013: op=ASSIGN, src=110:INT, dest=test_k_0020:INT, next=0014test_0014: op=ASSIGN, src=0:INT, dest=test_l_0021:INT, next=0015test_0015: op=ADD, src=test_a_0010:INT, test_b_0011:INT, dest=binary_expr_00022:INT, next=0016test_0016: op=ASSIGN, src=binary_expr_00022:INT, dest=test_c_0012:INT, next=0017test_0017: op=ADD, src=test_d_0013:INT, test_e_0014:INT, dest=binary_expr_00023:INT, next=0018test_0018: op=ASSIGN, src=binary_expr_00023:INT, dest=test_f_0015:INT, next=0019test_0019: op=ADD, src=test_g_0016:INT, test_h_0017:INT, dest=binary_expr_00024:INT, next=0020test_0020: op=ASSIGN, src=binary_expr_00024:INT, dest=test_i_0018:INT, next=0021test_0021: op=ADD, src=test_j_0019:INT, test_k_0020:INT, dest=binary_expr_00025:INT, next=0022test_0022: op=ASSIGN, src=binary_expr_00025:INT, dest=test_l_0021:INT, next=0023test_0023: op=ADD, src=test_c_0012:INT, test_f_0015:INT, dest=binary_expr_00026:INT, next=0024test_0024: op=ASSIGN, src=binary_expr_00026:INT, dest=test_c_0012:INT, next=0025test_0025: op=ADD, src=test_l_0021:INT, test_i_0018:INT, dest=binary_expr_00027:INT, next=0026test_0026: op=ASSIGN, src=binary_expr_00027:INT, dest=test_l_0021:INT, next=0027...
49
たとえばtest_0000: op=METHOD_EXIT, src=, dest=, next=0001test_0001: op=METHOD_ENTRY, src=, dest=, next=0002 (name=test)test_0002: op=ASSIGN, src=false:BOOLEAN, dest=test_success_0009:BOOLEAN, next=0015test_0002: op=ASSIGN, src=10:INT, dest=test_a_0010:INT, next=0015test_0002: op=ASSIGN, src=20:INT, dest=test_b_0011:INT, next=0015test_0002: op=ASSIGN, src=0:INT, dest=test_c_0012:INT, next=0015test_0002: op=ASSIGN, src=40:INT, dest=test_d_0013:INT, next=0015test_0002: op=ASSIGN, src=50:INT, dest=test_e_0014:INT, next=0015test_0002: op=ASSIGN, src=0:INT, dest=test_f_0015:INT, next=0015test_0002: op=ASSIGN, src=70:INT, dest=test_g_0016:INT, next=0015test_0002: op=ASSIGN, src=80:INT, dest=test_h_0017:INT, next=0015test_0002: op=ASSIGN, src=0:INT, dest=test_i_0018:INT, next=0015test_0002: op=ASSIGN, src=100:INT, dest=test_j_0019:INT, next=0015test_0002: op=ASSIGN, src=110:INT, dest=test_k_0020:INT, next=0015test_0002: op=ASSIGN, src=0:INT, dest=test_l_0021:INT, next=0015test_0002: op=ADD, src=10:INT, 20:INT, dest=binary_expr_00029:INT, next=0015test_0015: op=ADD, src=test_a_0010:INT, test_b_0011:INT, dest=binary_expr_00022:INT, next=0016test_0015: op=ADD, src=test_d_0013:INT, test_e_0014:INT, dest=binary_expr_00023:INT, next=0016test_0015: op=ADD, src=test_g_0016:INT, test_h_0017:INT, dest=binary_expr_00024:INT, next=0016test_0015: op=ADD, src=test_j_0019:INT, test_k_0020:INT, dest=binary_expr_00025:INT, next=0016test_0015: op=ADD, src=binary_expr_00029:INT, 40:INT, dest=binary_expr_00030:INT, next=0016test_0016: op=ASSIGN, src=binary_expr_00022:INT, dest=test_c_0012:INT, next=0023test_0016: op=ASSIGN, src=binary_expr_00023:INT, dest=test_f_0015:INT, next=0023test_0016: op=ASSIGN, src=binary_expr_00024:INT, dest=test_i_0018:INT, next=0023test_0016: op=ASSIGN, src=binary_expr_00025:INT, dest=test_l_0021:INT, next=0023test_0016: op=ADD, src=binary_expr_00030:INT, 50:INT, dest=binary_expr_00031:INT, next=0023...
50
結局プロセッサと何が違うの?CPU 高位合成でできたもの
処理方式 読む→解釈→実行 演算器としてならべられる適切なタイミングで確定
命令セット 決まっている 入力コードによって生成
I/O 決まっている 割と自由に追加できる
個数 決まっている 入力コードによって決まる
51
Synthesijerのこれから
52
ロードマップ
手続き型言語的基本演算,操作
整数プリミティブ型変数の利用
算術,論理,シフト演算(除算・剰余算以外)
制御構文(分岐,ループ)
メソッド呼び出し
除算・剰余算
浮動小数点数演算
オブジェクト指向的インスンタンス協調
finalでのインスタンスの生成
インスタンスメソッドの呼び出し
インスタンス変数へのリードアクセス
インスタンス変数へのライトアクセス
インスタンス間での配列読み書きのサポート
インスタンスの配列,配列の配列のサポート
コンストラクタのサポート
インスタンスのチェインアクセス
並列化パフォーマンス
基本ブロック内自動並列化
Threadによる明示的な処理の並列化をサポート
ループ内パイプライニング
ライブラリ 整数プリミティブ変数の配列
AXI接続用のコンポーネントライブラリの提供
Stringクラスのサポート
ユーザビリティ コマンドラインでのコンパイル
HDLモジュールとのバインディング機構
FPGA合成ツールとの連携,統一的な開発フローの提供
スケジューリング可視化ツール
HDL生成ライブラリを活用したDSLの提供
2014年7月 2014年12月 2015年3月 2015年6月
53
市販の高位合成処理系に憧れつつ...
✔ 設計空間の自動探索✔ パイプライン生成,ストリーム処理対応
54
今後挑戦したいこと
✔ メソッドのパイプライン化✔ I/Oストリームへの対応
✔ コンストラクタに対応✔ コンパイル時のJavaプログラム実行
✔ lambda式対応✔ Streamへの対応
✔ Erlangフロントエンド
55
ところで
56
高位合成処理系は何をするか
入力言語 データフロー スケジューリングデータパス生成
ステート生成物理マッピング
(1) (2)
(3)
57
共通基盤があると嬉しくない?
✔ 設計コストが小さくなるように✔ パフォーマンスを出しやすいように
✔ 命令スケジューリング,並列化の抽出✔ 動作周波数,リソース使用量,レイテンシの考慮
✔ 適切な物理マッピング✔ 符号化
(1)言語デザイン
(2)アーキテクチャの生成
(3)テクノロジ・マッピングベンダの合成ツール
最強の言語の設計に没頭!!
共通基盤
58
参考書
✔ 笠原博徳 “並列処理技術” コロナ社✔ 中田育男 “コンパイラの構成と最適化” 朝倉書店✔ 中田育男, 佐々政孝, 滝本宗宏, 渡邊坦 “コンパイラの基盤技術と実践―コンパイラ・インフラストラクチャCOINSを用いて” 朝倉書店
59
まとめ
✔ 高位合成処理系についてのオーバビュー
✔ Synthesijerのコード生成について
✔ 次回,高位合成友の会も是非ご参加ください