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.
JavaベースのFPGA向け高位合成処理系の
実装と活用事例
イーツリーズ・ジャパン/わさらぼ
三好 健文
2015.08.27
JavaベースのFPGA向け高位合成処理系の
実装と活用事例
イーツリーズ・ジャパン/わさらぼ
三好 健文
2015.08.27
Synthesijer
2
Synthesijer とは
✔ JavaプログラムをFPGA上のハードウェアに変換
✔ 複雑なアルゴリズムのハードウェア実装を楽に
✔ オブクジェクト指向設計による再利用性の向上
✔ 特殊な記法,追加構文はない
✔ ソフトウェアとして実行...
3
Synthesijer クイックスタート
4
クイックスタート 1/8
(1) バイナリパッケージをダウンロードします
http://synthesijer.github.io/web/
なるべく日付の新しいものをDLしてください
ダウンロードページに遷移します
✔ JDK8が必要です...
5
クイックスタート 2/8
(2) Eclipseでプロジェクトを作ります
6
クイックスタート 3/8
(3) libフォルダを作ってDLしたJARをコピー,ビルドパスに追加する
DLしたJARをD&Dでコピー
ビルドパスに追加
準備完了!!
7
クイックスタート 4/8
(4) Javaのクラスを作る
クラス生成ダイアログ
8
クイックスタート 5/8
(5) 間隔をおいて変数ledをtrue/falseするプログラムを書く
Lチカに相当する変数
適当なウェイト
点滅
自動コンパイルが裏で動くので,Javaコードとしての正しさは
即座にチェックされる
9
クイックスタート 6/8
(6) Synthesijerを使ってJavaコードをHDLに変換
10
クイックスタート 6/8
(6) Synthesijerを使ってJavaコードをHDLに変換
11
クイックスタート 7/8
(7) ISEで合成,配置配線
生成したモジュールのインスタンスを生成
制約ファイルは別途用意
12
クイックスタート 8/8
(8) FPGAをコンフィギュレーションして動作を確認
1
コンテンツ
✔ 高位合成処理系のあれこれ
✔ Synthesijerの設計と実装
✔ Synthesijerのサンプル/使用事例
✔ Synthesijer.Scala
✔ これからについて
2
“FPGAにキラーアプリはないの定理”への挑戦
Florent de Dinechin, "Building Custom Arithmetic Operators with the FloPoCo Generator”,
http://w...
3
デメリット克服のためには
✔ FPGAを使うのをやめる
✔ より抽象度の高い設計手法/処理系を使う
4
デメリット克服のためには
✔ FPGAを使うのをやめる
✔ 別にプロセッサを持ってくる
✔ FPGAの上にプロセッサを作る
✔ より抽象度の高い設計手法/処理系を使う
✔ 既存のプログラミング言語を借用する
✔ 新しい記述言語を模索する
✔...
5
デメリット克服のためには
✔ FPGAを使うのをやめる
✔ 別にプロセッサを持ってくる
✔ FPGAの上にプロセッサを作る
✔ より抽象度の高い設計手法/処理系を使う
✔ 既存のプログラミング言語を借用する
✔ 新しい記述言語を模索する
✔...
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
1
高位合成処理系あれこれ
2
ESLSynthesisの市場規模
3
Source
Abstraction
Level
Ease of
Impl.
Learning
curve
Document-
ation
Floating/
Fixed Pt.
Design
Exploration
Testbench
g...
4
高位合成処理系,躍進のわけ
✔ Embedded processors are in almost every SoC
✔ Huge silicon capacity
✔ Behavioral IP reuse
✔ Verification...
5
すみません,これはここまで
6
実際のところ高位合成は身近
1
Synthesijer 設計と実装 
2
高位合成処理系に何を求めるか?
✔ 記述コストの軽減
✔ 高抽象度の表現方法を利用したい
✔ 言語習得にコストをかけたくない
✔ 動作検証/デバッグ効率の向上
✔ 短時間で動作を確認したい
✔ 見通しよく,手軽なデバッグをしたい
✔ FPG...
3
Synthesijer
✔ クラスによるオブジェクト指向設計言語
 ← HWのモジュール設計との親和性は高そう
✔ 言語仕様で並列処理をサポート
✔ Thread,wait-notify
✔ (Cと違い)明示的なポインタの扱いが不要
✔ 言...
4
Synthesijer 設計基本方針
✔ JavaプログラムをそのままHDL→HW化
✔ 追加構文,データ型は導入しない
✔ 使える記述には制限を導入
HDLで書けることをすべてJavaで書けるようにするではない
Javaで書けることををす...
なぜJavaなのか?
Write Once, Run Anywhere!!
Write Once, Run Anywhere!!
たとえCPUがなくても!!
8
[朗報] OpenJDKが素敵!!
✔ オープンソースで開発されているJavaコンパイラ/実行環境
✔ 字句解析,構文解析はお任せ
✔ 最適化後の内部構造へのアクセスが簡単
✔ 実行時に型情報に触りやすい
✔ printfデバッグのノリで動...
9
Javaプログラムへのアクセス
/** Generate code and emit a class file for a given class
* @param env The attribution environment of th...
10
Javaコードの内部表現
この構造をたどるOpenJDKの仕組みを利用
JCMethodDecl
JCVariableDecl
JCMethodDecl
JCMethodDecl
・
・
・
・
・
・
JCVariableDecl
JC...
11
たとえばclass
public class JCTopVisitor extends Visitor{
private final Module module;
...
public void visitClassDef(JCClass...
12
たとえばmethod
public void visitMethodDef(JCMethodDecl decl){
String name = decl.getName().toString();
Type type;
if(JCFron...
13
たとえば制御構文
public void visitIf(JCIf that){
IfStatement tmp = new IfStatement(scope);
tmp.setCondition(stepIn(that.cond, s...
14
高位合成処理系は何をするか?
http://www.ida.liu.se/~petel/SysSyn/lect3.frm.pdf
基本はこれに書いてあります
High-Level Synthesis
15
高位合成処理系は何をするか
入力言語 データフロー スケジューリング
データパス生成
ステート生成
物理マッピング
16
高位合成処理系は何をするか
入力言語 データフロー スケジューリング
データパス生成
ステート生成
物理マッピング
(1) (2)
(3)
17
高位合成処理系の3つのレイヤ
(1)言語デザイン
(2)アーキテクチャの生成
(3)テクノロジ・マッピング
✔ 設計コストが小さくなるように
✔ パフォーマンスを出しやすいように
✔ 命令スケジューリング,並列性の抽出
✔ 動作周波数,リ...
18
Synthesijerでは
✔ 設計コストが小さくなるように
✔ パフォーマンスを出しやすいように
✔ 命令スケジューリング,並列化の抽出
✔ 動作周波数,リソース使用量,レイテンシの考慮
✔ 適切な物理マッピング
✔ 符号化
(1)言語...
19
Synthesijerオーバービュー
Javaコード
Javaプログラムの解析
スケジューリング表を作成
最適化
HDL構文の組み立て
VHDL/
Verilog HDL
コード
Javaコード
VHDL/
Verilog HDL
コード...
20
Synthesijer でのHDL生成: 例題
package blink_led;
public class BlinkLED {
public boolean led;
public void run(){
while(true){
...
21
Synthesijer でのHDL生成: 大枠
class
entity blink_led_BlinkLED is
port (
clk : in std_logic;
reset : in std_logic;
field_led_o...
22
Synthesijer でのHDL生成: スケジュール表
メソッド毎にスケジュール表を生成
run_0000: op=METHOD_EXIT, src=, dest=, next=0001
run_0001: op=METHOD_ENTR...
23
スケジューラ表の疑似命令
✔ 四則演算,論理演算,シフト
✔ 比較
✔ 代入
✔ 配列のアドレス指定,配列アクセス
✔ Call/Return
✔ CallしたらReturnされるまで待つ(基本)
✔ Thread.startの呼び出し時...
24
Synthesijer でのHDL生成: 出力(状態遷移)
メソッド毎にスケジュール表を生成 → 状態遷移機械
while
for
for
25
Synthesijer でのHDL生成: 状態遷移
状態遷移機械に相当するステートマシンをベタに作る
always @(posedge clk) begin
if(reset == 1'b1) begin
run_method <= ru...
26
Synthesijer でのHDL生成: 出力(データ操作)
メソッド毎にスケジュール表を生成 → 文/式相当のデータ操作
run_0000: op=METHOD_EXIT, src=, dest=, next=0001
run_0001...
27
Synthesijer でのHDL生成: 出力(データ操作)
メソッド毎にスケジュール表を生成 → 文/式相当のデータ操作
run_0000: op=METHOD_EXIT, src=, dest=, next=0001
run_0001...
28
最適化の例
べたなプログラムを用意
public class SimpleProgram{
public int sum(int a, int b, int c,
int d, int e, int f,
int g, int h, in...
29
最適化の例
べたなプログラムを用意
sum_0000: op=METHOD_EXIT, src=, dest=, next=0001
sum_0001: op=METHOD_ENTRY, src=, dest=, next=0002 (n...
30
最適化の例
べたなプログラムを用意
sum_0000: op=METHOD_EXIT, src=, dest=, next=0001
sum_0001: op=METHOD_ENTRY, src=, dest=, next=0002 (n...
31
最適化の例
べたなプログラムを用意
sum_0000: op=METHOD_EXIT, src=, dest=, next=0001
sum_0001: op=METHOD_ENTRY, src=, dest=, next=0002 (n...
32
最適化の例
内部はS式.S式を外でいじって処理系に戻すことも可
(SEQUENCER sum
(SLOT 0
(METHOD_EXIT :next (1))
)
(SLOT 1
(METHOD_ENTRY :next (2))
)
(SL...
33
SynthesijerはJavaベースなので...
オブジェクト指向的プログラミング!!
… … …
34
インスタンス生成
クラスのインスタンスを生成/利用できる
public class Test002 {
public static final int DEFAULT_VALUE = 0x20;
public int[] a = new ...
35
インスタンス生成
クラスのインスタンスを生成/利用できる
ex. sample/test/Test002.javaとsample/test/Test003.java
Test002 class_t_0000 (
.clk(class_t_...
36
インスタンス生成・拡張モジュール
VHDL/Verilog HDLで書いたモジュールのインスタンス化
module hoge(
input wire clk,
input wire reset,
input signed [31:0] a...
37
インスタンス生成・拡張モジュール
VHDL/Verilog HDLで書いたモジュールのインスタンス化
class HogeIface extends HDLModule{
int[] a;
void func(){}
public Hog...
38
インスタンス生成の例
乱数生成のハードウェアをJavaから使う
// xorshift RNG, period 2^128-1
// cf. http://www.jstatsoft.org/v08/i14/paper
module xo...
39
インスタンス生成の例
乱数生成のハードウェアをJavaから使う
/**
* リスト15: XOR128.java
* xor128をJavaから利用するためのダミークラス
*/
import synthesijer.hdl.HDLModu...
40
インスタンス生成の例
乱数生成のハードウェアをJavaから使う
/**
* リスト16: XOR128Test.java
* xor128をJavaから利用する例
*/
public class XOR128Test{
// XOR128...
41
インスタンス生成の例
乱数生成のハードウェアをJavaから使う
42
クラスの継承も可
継承したクラスのメソッドも利用可能
public class Test012 extends Test010{
public void run(){
test();
}
}
public class Test010{
p...
43
SynthesijerはJavaベースなので...
Threadを使って並列化できる
… … …
44
スレッドの利用例
JavaではThreadクラスを継承して並列動作を記述
/*
* リスト11: ThreadCounter.java
* Threadの活用例
*/
// JavaではThreadクラスを継承したクラスを作る
publi...
45
スレッドの利用例
JavaではThreadクラスを継承して並列動作を記述
import synthesijer.rt.unsynthesizable;
public class ThreadTest{
private final Thre...
46
スレッドの利用例
PCで実行したところ
47
スレッドの利用例
シミュレーションで確認したところ
48
ここまでのまとめ
✔ Synthesijer=JavaをVHDL/Verilog HDLに変換する処理系
✔ Javaなりのオブジェクト指向設計をサポート
✔ Threadによる並列処理の記述とHW化
49
Synthesijerオーバービュー
Javaコード
Javaプログラムの解析
スケジューリング表を作成
最適化
HDL構文の組み立て
VHDL/
Verilog HDL
コード
Javaコード
VHDL/
Verilog HDL
コード...
50
Synthesijer as a Compiler-Infrastructure
Javaコード
スケジューリング表を作成
最適化
Y構文の組み立て
VHDL/
Verilog HDL
コード
X言語
VHDL/
Verilog HDL
...
1
Synthesijer サンプル・事例 
2
2
✔ Javaといえば,スクリプト言語のホストとしても魅力的
✔ JRuby,Scala,Clojure,and etc.
✔ BrainF**k: とても小さなスクリプト言語処理系
→ hoge
サンプル1: プログラムインタプリタ
+...
3
サンプル1: BFのコード抜粋
private IO io = new IO();
private byte[] prog = new byte[CODESIZE];
private byte[] data = new byte[ARRAY...
4
サンプル1: ソフトウェアとして実行
✔ 標準入出力越しでBrainF**kインタプリタを実行
✔ +, -, >, <, [, ], ., ,の記号からなるインタプリタ
5
サンプル1: FPGAで実行
✔ 標準入出力の代わりにシリアル通信越しで実行
6
SWとHWで同じコードを利用
ソフトウェアで実行する時
BF
IO
Console
合成して実機で動かす時
IO
+ putchar()
+ getchar()
+ putchar()
+ getchar()
RS232Wrapper
7
サンプル1: 文字の入出力ルーチン
public void read() {
prompt();
for (int i = 0; i < CODESIZE; i++) {
byte b;
b = io.getchar();
//io.put...
8
サンプル1: SW版とHW版の入出力
public class IO {
private rs232c obj = new rs232c();
public void putchar(byte c) {
obj.write(c);
}
pu...
9
サンプル2: ディスプレイに絵を書く
public class BitMapTest extends Thread{
...
public void run(){
// 座標(100, 100)の位置にサイズ20の正方形を描画
canvas...
10
✔ ソフトウェアとして実行して動作を確認
サンプル2: ディスプレイに絵を書く
11
✔ 実FPGAとディスプレイで同じ動作を確認
サンプル2: ディスプレイに絵を書く
12
サンプル3: AHCI
✔ Advanced Host Controller Interface
✔ SATAなHDDやSSDを接続するためのインターフェース
✔ 最近のOSのほとんどでサポートされている
= 標準のデバドラでブロックデバ...
13
サンプル3: AHCI
PC
FPGA
ディスク?
何かの
処理
ディスク
インターネット
✔ なんでもディスクに見せてしまうのは楽しそう
✔ たとえば
BRAM
14
一般的なAHCIによるディスク接続
ディスクに送るコマンドを預かる
ディスクからのリプライを返す
作業用メモリのポインタの確認
複数コマンドをOoOで発行(NCQ)
ディスクへのFISの発行
ディスクからのFISの受信
ステータス管理
15
AHCIのメモリチェイン
どのコマンドが
有効かはPxCI
レジスタをみる
ディスクに
送るべきコマンド
PCIeのBAR5に
レジスタ空間への
ポインタがある
ディスクとの
やり取りに使う
メモリ領域への
ポインタ
近代的なOSでは大量...
16
AHCI越しのデータ授受のフロー
PCIe越しの通信
17
HBAの動作フロー/FIS取得まで
private int wait_for_command(){
while(reg.values[P0CI] == 0) ;
reg.values[P0CMD] = 0x10110007; // 処理開...
18
動作例
PCIデバイス→AHCIデバイス→ディスクに見えている
うまくOSを
だませている
/dev/sdbらしい
ddとかできる
19
Synthesijer 活用方法 - 3つのパタン
20
3つの開発パタン
(1) Javaによるモジュールだけでシステムを構成
(2) HDLによるモジュールを部品として利用.全体管理はJavaで記述
= 既存IPコア,FPGAの性能を活用
(3) Javaによるモジュールを部品として利用.全...
21
(1) Javaでシステムを構成
✔ すべてをJavaで記述
✔ トップモジュール,UCF/XDCなんかは必要
✔ I/Oなどは用意されたライブラリを利用
✔ シリアルI/O,SC1602,純粋なInput/Output, ...
✔ A...
22
(2) Java+HDL記述の部品
✔ JavaプログラムにHDL記述の部品を埋め込む
✔ Javaで記述したオブジェクトのようにHDL記述部品をインスタンス化して使う
✔ HDLモジュールを簡単に使い回せる
✔ Synthesijer内...
23
インスタンス生成・拡張モジュール
VHDL/Verilog HDLで書いたモジュールのインスタンス化
module hoge(
input wire clk,
input wire reset,
input signed [31:0] a...
24
インスタンス生成・拡張モジュール
VHDL/Verilog HDLで書いたモジュールのインスタンス化
class HogeIface extends HDLModule{
int[] a;
void func(){}
public Hog...
25
(3) HDL+Java記述の部品
✔ HDLで設計したシステムにJava記述の部品を埋め込む
✔ 複雑なアルゴリズムの処理でもJavaなら(比較的)手軽に実装
✔ HDLで自然に実装できるストリーム処理,並列処理を活用
✔ Synthe...
26
複雑/面倒なアルゴリズム処理の実装
✔ 例: バブルソートじゃなくてマージソートの採用,など
✔ バブルソート(512個の降順→昇順)
✔ マージソート(512個の降順→昇順) x15
27
複雑なアルゴリズム処理はJavaで実装
✔ バブルソートの状態遷移 ✔ マージソートの状態遷移
28
最近よく実装しているパタン
FIFO
実行
ステージ
FIFO
実行
ステージ
FIFO
スループット T [bps]
実行
ステージ
FIFO
実行
ステージ
FIFO
実行
ステージ
FIFO
実行
ステージ
FIFO
ここを
Jav...
1
今できていること
✔ とりあえず使える
✔ Javaの制御構文,メソッド呼び出し,演算
✔ とてもシンプルな最適化
✔ Vivado向けIPコアテンプレートの自動生成
Source
Abstraction
Level
Ease of
Imp...
2
手が回っていないこと
✔ もう少し賢い最適化
✔ メモリアクセスレイテンシの隠蔽
✔ 演算レイテンシを考慮したチェイニング
✔ リソースシェアリング
3
今後挑戦したいこと
✔ メソッドのパイプライン化
✔ Javaプログラムとしてどう扱うか
✔ I/Oストリームへの対応
✔ コンストラクタに対応
✔ コンパイル時のJavaプログラム実行
✔ lambda式対応
✔ Streamへの対応
1
+α Synthesijer.scala
2
RTL設計の辛さ
✔ “ ”信号の流れ を記述する
✔ “ ” “ ”処理の流れ を 信号の流れ に変換
↔ “ ”書きたいのは 処理の流れ
✔たくさんの似たような構造
✔ たくさんの似たような名前
✔ 記述の再利用をしたいが難しい
本質と...
3
手軽なFPGA開発のための取り組み
✔ 高位合成言語処理系
✔ DSL
4
高位合成処理系
✔ CやJava,C#などを入力言語とした開発環境
✔ 開発コストを小さくできる
✔ 生成したHWの質は処理系依存
✔ 良いHW生成にはコツが必要
✔ ディレクティブの活用
✔ 書き方を考える必要がある
5
高位合成処理系
✔ Vivado HLS
✔ OpenCL対象の処理系
✔ CyberWorkBench
✔ Cynthesizer
✔ Symphony C Compiler
✔ ImpulseC
✔ Lime
✔ Synthesijer...
6
DSLベースの設計手法
✔ RTL設計を楽にするためのDSL
✔ 実装したいアプリケーション別のDSL
✔ プログラミングモデルに特化したDSL
7
様々なDSLベースのシステム開発(1)
✔ MyHDL (Pythonベース)
✔ JHDL (Javaベース)
✔ Chisel (Scalaベース)
✔ PyVerilog (Pythonベース)
などなどなど
RTL設計(あるいは少し...
8
様々なDSLベースのシステム開発(2)
✔ Spiral ←Linear Digital Processing
✔ HDL Coder ← 信号処理(Matlab)
✔ Optimus ← ストリーム処理
✔ LINQ ← クエリプロセッシ...
9
様々なDSLベースのシステム開発(3)
✔ Bluespec (並行プログラミング)
✔ MaxCompiler (データフロープログラミング)
✔ FloPoCo (浮動小数点数パイプライン)
✔ SPGen (パイプライン)
などなどな...
10
DSLベースの設計手法
✔ RTL設計を楽にするためのDSL
←依然RTLであることに代わりはない
✔ 実装したいアプリケーション別のDSL
←HWの設計探索をしたい場合には不向き
✔ プログラミングモデルに特化したDSL
→さて,どんな...
11
FPGAが有用なのはなぜか?
✔ 論理回路・データパスを自由に作り込めるLSI
✔ I/Oを自由に使える
✔ クロックレベルの同期と並列性を活用した処理を実現
Field Programmable Gate Array
12
FPGAが有用なのはなぜか?
10G if
DRAM
Network
adapter
FPGA
Network stack Memcached
x86 DRAM
motherboard
Hash table Value store
図は ...
13
鍵はパイプライン並列化
FIFO
スループット T [bps]
w [byte]
f [Hz]
実行
ステージ
FIFO
実行
ステージ
実行
ステージ
14
データが来たら迎え撃つ
15
鍵はパイプライン並列化
パケットデータが d [byte] のとき全データ入力を受け取るのにかかる時間 = (d/w)*(1/f) [sec]
同様に、全データの出力にかかる時間 = (d/w)*(1/f) [sec]
スループットT [...
16
鍵はパイプライン並列化
パケットデータが d [byte] のとき全データ入力を受け取るのにかかる時間 = (d/w)*(1/f) [sec]
同様に、全データの出力にかかる時間 = (d/w)*(1/f) [sec]
スループットT [...
17
組み合わせ回路/データ並列性の活用
✔ プロセッサと比べてFPGA回路のφは圧倒的に低速
✔ 高速データ処理では1クロックでデータを捌く必要も
✔ 時にはソフトウェア実装とは全く違う場合も
条件
・・・
条件
v.s
18
欲しいDSL
✔ Bluespec (並行プログラミング)
✔ MaxCompiler (データフロープログラミング)
✔ FloPoCo (浮動小数点数パイプライン)
などなどなど
使用するプログラミングモデルに特化したDSL
状態遷移...
19
設計: Synthesijer.scala
✔ 組み合わせ回路の設計の容易は失わないまま
✔ “処理の流れ”の記述を容易にする
✔ クロックベースの状態管理と状態遷移を言語機能に
✔ 内部DSLとして設計.回路設計にScalaの機能を活用...
20
Synthesijer.scala とは
✔ Synthesijerのバックエンドを使ってScala“で”HDLを書く
✔ signal, port: 状態を変更可能なオブジェクト
✔ expr: 副作用なしの式
✔ sequencer:...
21
Synthesijer.Scalaの立ち位置
Javaコード
Javaプログラムの解析
スケジューリング表を作成
最適化
HDL構文の組み立て
VHDL/
Verilog HDL
コード
Javaコード
VHDL/
Verilog HDL...
22
開発フロー
Scalaプログラムとして実装
→ VHDLまたはVerilog HDLを生成
RTLシミュレーションによる動作検証
使用するFPGAにあわせた制約を定義
ツールで合成,配置配線,FPGA構成情報生成
実機で動作確認
Synt...
23
モデル
モジュールの設計単位
入出力.
クロック単位で状態保持
組み合わせ回路.
状態は持たない
クロック単位での状態保持
状態遷移マシン
24
はじめてのSynthesijer.scala
✔ Lチ カ の 例
def generate_led() : Module = {
val m = new Module("led")
val q = m.outP("q")
val cou...
25
ベンディングマシンの例
ドリンク
自動販売機
¢5
¢10
ドリンク一杯¢20
お釣りは出ません
26
RTLでの設計の場合
…
type stateType is (NONE, CHARGE_5, CHARGE_10, CHARGE_15, OK)
signal state, next_state: stateType := NONE;
...
27
ベンディングマシンの例
class VendingMachine(n:String,c:String,r:String) extends Module(n,c,r){
val nickel = inP("nickel")
val dime...
28
ベンディングマシンのステートマシン
29
Scalaの機能を使った設計効率化の向上
✔ 設計資産をメソッドやクラスとして保存,再利用
✔ 類似オブジェクトや類似オブジェクトの生成
✔ ループとパタンマッチによる直列化/復元コードの生成
30
設計資産の再利用
例: デコーダ (7セグメントLEDの点灯)
4
0
2
51
6
7
3
31
設計資産の再利用
process (data)
begin
case (data) is
when 0 => segment <= X"7e";
when 1 => segment <= X"30";
…
when 9 => segmen...
32
設計資産の再利用
def decoder(s:ExprItem, l:List[(Int,Int)], w:Int) = {
l.foldRight[ExprItem](value(0,w)){
(a, z) => ?(s == a._1...
33
自分なりのパタン,最適化の埋め込みも
✔ 組み合わせ回路の段数に応じたFF(状態)の追加,除去
✔ 入出力データに対するパタンマッチ
✔ よく使うモジュールのテンプレート化
例えば...
などなど
34
自分なりの実装,例
例えば...ANDゲートをLUTじゃなくてMUXで作りたい
35
自分なりの実装,例
継承とオーバーライドを使って,自然に表現可能
val x0 = inP("x0")
val y0 = inP("y0")
val z0 = outP("z0")
val z1 = outP("z1")
val z2 =...
36
自分なりの実装,例
例えば...ANDゲートをLUTじゃなくてMUXで作りたい
37
自分なりの実装,例
例えば...ANDゲートをLUTじゃなくてMUXで作りたい
1
さて,未来はどうなる?
2
ポテンシャルをどう活かすか!!
https://www.youtube.com/watch?v=FCmfcfPt4T4
3
各社の取り組み
✔ Xilinx SDx (特にSDSoC)
✔ Altera SDP
✔ IBM Lime
✔ Microsoft Kiwi
✔ CoRAM/PyCoRAM
“システムをどう作るか”,がターゲット
= システムとLSI
4
Xilinx SDSoC
Zynq向けのSW/HWコデザインツール
5
Altera SDP
SPCS005 — Technology Insight: Workload Acceleration, IDF2015
6
IBM Lime
Java + Isolation + Abstract Parallelism + Extraction
7
Microsoft Kiwi (Distributing C#)
Greaves, D.; Singh, S., "Distributing C# methods and threads over Ethernet-connected FP...
8
CoRAM/PyCoRAM
高前田先生@NAIST
9
未来で,どう開発したい?
1
まとめ
✔ Javaベースの高位合成処理系を作って/使っています
✔ まだまだですが,こういう人もいる,と.
✔ 中間表現のS式を操作して処理系に戻せるので,
最適化器実装してみたいという人がいたら是非
✔ 結構,楽しい時代だと思っている
...
2
参考
✔ http://synthesijer.github.io/web
✔ リソース一式,クイックスタートガイドなど
✔ http://qiita.com/kazunori279/items/4951ca5f6164040878ce
✔...
Upcoming SlideShare
Loading in …5
×

Das 2015

1,419 views

Published on

My presentation in DAS 2015

Published in: Engineering
  • Be the first to comment

Das 2015

  1. 1. JavaベースのFPGA向け高位合成処理系の 実装と活用事例 イーツリーズ・ジャパン/わさらぼ 三好 健文 2015.08.27
  2. 2. JavaベースのFPGA向け高位合成処理系の 実装と活用事例 イーツリーズ・ジャパン/わさらぼ 三好 健文 2015.08.27 Synthesijer
  3. 3. 2 Synthesijer とは ✔ JavaプログラムをFPGA上のハードウェアに変換 ✔ 複雑なアルゴリズムのハードウェア実装を楽に ✔ オブクジェクト指向設計による再利用性の向上 ✔ 特殊な記法,追加構文はない ✔ ソフトウェアとして実行可能.動作の確認、検証が容易 ✔ 書けるプログラムに制限は加える (動的なnew,再帰は制限付きで可など) Javaコンパイラ フロントエンド Synthesijer エンジン Javaコンパイラ バックエンド 合成 配置配線 while(){ if(...){ … }else{ … … } …. } 複雑な状態遷移も,Javaの制御構文を使って楽に設計できる 同じJavaプログラムをソフトウェアとしても FPGA上のハードウェアとしても実行可能 Open-source
  4. 4. 3 Synthesijer クイックスタート
  5. 5. 4 クイックスタート 1/8 (1) バイナリパッケージをダウンロードします http://synthesijer.github.io/web/ なるべく日付の新しいものをDLしてください ダウンロードページに遷移します ✔ JDK8が必要です. ✔ Eclipseを使って開発してみます.
  6. 6. 5 クイックスタート 2/8 (2) Eclipseでプロジェクトを作ります
  7. 7. 6 クイックスタート 3/8 (3) libフォルダを作ってDLしたJARをコピー,ビルドパスに追加する DLしたJARをD&Dでコピー ビルドパスに追加 準備完了!!
  8. 8. 7 クイックスタート 4/8 (4) Javaのクラスを作る クラス生成ダイアログ
  9. 9. 8 クイックスタート 5/8 (5) 間隔をおいて変数ledをtrue/falseするプログラムを書く Lチカに相当する変数 適当なウェイト 点滅 自動コンパイルが裏で動くので,Javaコードとしての正しさは 即座にチェックされる
  10. 10. 9 クイックスタート 6/8 (6) Synthesijerを使ってJavaコードをHDLに変換
  11. 11. 10 クイックスタート 6/8 (6) Synthesijerを使ってJavaコードをHDLに変換
  12. 12. 11 クイックスタート 7/8 (7) ISEで合成,配置配線 生成したモジュールのインスタンスを生成 制約ファイルは別途用意
  13. 13. 12 クイックスタート 8/8 (8) FPGAをコンフィギュレーションして動作を確認
  14. 14. 1 コンテンツ ✔ 高位合成処理系のあれこれ ✔ Synthesijerの設計と実装 ✔ Synthesijerのサンプル/使用事例 ✔ Synthesijer.Scala ✔ これからについて
  15. 15. 2 “FPGAにキラーアプリはないの定理”への挑戦 Florent de Dinechin, "Building Custom Arithmetic Operators with the FloPoCo Generator”, http://www.hipeac.net/conference/berlin/tutorial/flopoco なんとかして開発スピードを速くしたい
  16. 16. 3 デメリット克服のためには ✔ FPGAを使うのをやめる ✔ より抽象度の高い設計手法/処理系を使う
  17. 17. 4 デメリット克服のためには ✔ FPGAを使うのをやめる ✔ 別にプロセッサを持ってくる ✔ FPGAの上にプロセッサを作る ✔ より抽象度の高い設計手法/処理系を使う ✔ 既存のプログラミング言語を借用する ✔ 新しい記述言語を模索する ✔ 新しい設計概念を模索する
  18. 18. 5 デメリット克服のためには ✔ FPGAを使うのをやめる ✔ 別にプロセッサを持ってくる ✔ FPGAの上にプロセッサを作る ✔ より抽象度の高い設計手法/処理系を使う ✔ 既存のプログラミング言語を借用する ✔ 新しい記述言語を模索する ✔ 新しい設計概念を模索する
  19. 19. 2014 年 8 月 2015 年 1 月 0 5 10 15 20 25 30 35 40 45 x20
  20. 20. 2014 年 8 月 2015 年 1 月 0 5 10 15 20 25 30 35 40 45 x20 高位合成を実装する人達の 飲み会 # 2014.8.3 高位合成友の会 # 2015.1.16
  21. 21. 1 高位合成処理系あれこれ
  22. 22. 2 ESLSynthesisの市場規模
  23. 23. 3 Source Abstraction Level Ease of Impl. Learning curve Document- ation Floating/ Fixed Pt. Design Exploration Testbench generation Verification Size FPGA Slices AccelDSP Matlab untimed ++ ++ + Auto conversion + yes ++ 2411 Agility Compiler SystemC Cycle accurate + - + Fixed pt + no - AutoPilot C, C++, SystemC Cycle+ untimed ++ ++ ++ yes ++ yes ++ 232 Bluespec BSV Cycle accurate +/- - + no limited no - 120 Catapult C C, C++, SystemC Cycle+ untimed ++ ++ ++ Fixed pt ++ yes ++ 370/560 Compaan C, Matlab untimed + + - automatic ++ no + 3398 CyberWork Bench SystemC, C, BDL Cycle + untimed + + + yes ++ yes + 243/292 DK Design Suite HandelC Cycle accurate +/- - +/- Fixed pt limited no +/- 311/945 Impluse CoDeveloper ImpulseC Cycle + unlimited - + - Fixed pt + no + 4611 ROCCC C subst untimed - +/- + no + no - Synphony C C, C++ untimed ++ + + Fixed pt + yes ++ 1047 いろいろな高位合成 Wim Meeus, Kristof Van Beeck, Toon Goedemé, Jan Meel, Dirk Stroobandt, "An overview of today’s high-level synthesis tools", Design Automation for Embedded Systems, September 2012, Volume 16, Issue 3, pp 31-51
  24. 24. 4 高位合成処理系,躍進のわけ ✔ Embedded processors are in almost every SoC ✔ Huge silicon capacity ✔ Behavioral IP reuse ✔ Verification drives the acceptance of HLS Specification ✔ Accelerators and heterogeneous SoC ✔ Less pressure for formal verification ✔ Ideal for platform-based synthesis ✔ More pressure for time-to-market ✔ Accelerated or reconfigurable computing Cong, J.; Bin Liu; Neuendorffer, S.; Noguera, J.; Vissers, K.; Zhiru Zhang, "High-Level Synthesis for FPGAs: From Prototyping to Deployment," in Computer-Aided Design of Integrated Circuits and Systems, IEEE Transactions on , vol.30, no.4, pp.473-491, April 2011
  25. 25. 5 すみません,これはここまで
  26. 26. 6 実際のところ高位合成は身近
  27. 27. 1 Synthesijer 設計と実装 
  28. 28. 2 高位合成処理系に何を求めるか? ✔ 記述コストの軽減 ✔ 高抽象度の表現方法を利用したい ✔ 言語習得にコストをかけたくない ✔ 動作検証/デバッグ効率の向上 ✔ 短時間で動作を確認したい ✔ 見通しよく,手軽なデバッグをしたい ✔ FPGAのパフォーマンスの活用 ✔ 粗粒度,細粒度の並列性の活用 ✔ IPコアや内部機能ユニットを活用したい ✔ 設計空間の探索
  29. 29. 3 Synthesijer ✔ クラスによるオブジェクト指向設計言語  ← HWのモジュール設計との親和性は高そう ✔ 言語仕様で並列処理をサポート ✔ Thread,wait-notify ✔ (Cと違い)明示的なポインタの扱いが不要 ✔ 言語の想定するメモリ構造から解放され得るかも ✔ 動的な振る舞いは厄介そう Javaベースの高位合成処理系
  30. 30. 4 Synthesijer 設計基本方針 ✔ JavaプログラムをそのままHDL→HW化 ✔ 追加構文,データ型は導入しない ✔ 使える記述には制限を導入 HDLで書けることをすべてJavaで書けるようにするではない Javaで書けることををすべてHDL(HW)にするではない Javaとして実行可能なプログラムをHWにする ≒ フェッチのないJavaプロセッサをHDLで直接生成する
  31. 31. なぜJavaなのか?
  32. 32. Write Once, Run Anywhere!!
  33. 33. Write Once, Run Anywhere!! たとえCPUがなくても!!
  34. 34. 8 [朗報] OpenJDKが素敵!! ✔ オープンソースで開発されているJavaコンパイラ/実行環境 ✔ 字句解析,構文解析はお任せ ✔ 最適化後の内部構造へのアクセスが簡単 ✔ 実行時に型情報に触りやすい ✔ printfデバッグのノリで動作を追うことができる ✔ C/C++だとちょっと厳しい(と思う)
  35. 35. 9 Javaプログラムへのアクセス /** Generate code and emit a class file for a given class * @param env The attribution environment of the outermost class * containing this class. * @param cdef The class definition from which code is generated. */ JavaFileObject genCode(Env<AttrContext> env, JCClassDecl cdef) throws IOException { synthesijer.jcfrontend.Main.newModule(env, cdef); // add hook for synthesijer try { if (gen.genClass(env, cdef) && (errorCount() == 0)) return writer.writeClass(cdef.sym); } catch (ClassWriter.PoolOverflow ex) { log.error(cdef.pos(), "limit.pool"); } catch (ClassWriter.StringOverflow ex) { log.error(cdef.pos(), "limit.string.overflow", ex.value.substring(0, 20)); } catch (CompletionFailure ex) { chk.completionError(cdef.pos(), ex); } return null; } JavaCompiler.javaのgenCode内に処理をぶら下げればよい
  36. 36. 10 Javaコードの内部表現 この構造をたどるOpenJDKの仕組みを利用 JCMethodDecl JCVariableDecl JCMethodDecl JCMethodDecl ・ ・ ・ ・ ・ ・ JCVariableDecl JCVariableDecl JCExpressionState JCBlock JCIf JCFor JCAssign JCArrayAccess JCBinary JCIdent JCLiteral ・ ・ ・ ・ ・ ・ JSCtatement JSExpression JCClassDecl
  37. 37. 11 たとえばclass public class JCTopVisitor extends Visitor{ private final Module module; ... public void visitClassDef(JCClassDecl that){ for (JCTree def : that.defs) { if(def == null){ ; }else if(def instanceof JCMethodDecl){ def.accept(this); }else if(def instanceof JCVariableDecl){ def.accept(new JCStmtVisitor(module)); }else{ System.err.printf("Unknown class: %s (%s)", def, def.getClass()); } } } ... 構文解析器がJCClassDeclに出会ったら呼び出してくれる
  38. 38. 12 たとえばmethod public void visitMethodDef(JCMethodDecl decl){ String name = decl.getName().toString(); Type type; if(JCFrontendUtils.isConstructor(decl)){ type = new MySelfType(); }else{ type = TypeBuilder.genType(decl.getReturnType()); } Method m = new Method(module, name, type); m.setArgs(parseArgs(decl.getParameters(), m)); ... m.setPrivateFlag(JCFrontendUtils.isPrivate(decl.mods)); m.setParallelFlag(JCFrontendUtils.isAnnotatedBy(decl.mods.annotations, "parallel")); ... m.setConstructorFlag(JCFrontendUtils.isConstructor(decl)); ... for(JCStatement stmt: decl.body.getStatements()){ JCStmtVisitor visitor = new JCStmtVisitor(m); stmt.accept(visitor); m.getBody().addStatement(visitor.getStatement()); } module.addMethod(m); } 構文解析器がJCMethodDeclに出会ったら呼び出してくれる
  39. 39. 13 たとえば制御構文 public void visitIf(JCIf that){ IfStatement tmp = new IfStatement(scope); tmp.setCondition(stepIn(that.cond, scope)); tmp.setThenPart(wrapBlockStatement(stepIn(that.thenpart, scope))); if(that.elsepart != null){ tmp.setElsePart(wrapBlockStatement(stepIn(that.elsepart, scope))); } stmt = tmp; } public void visitForLoop(JCForLoop that){ ForStatement tmp = new ForStatement(scope); for(JCStatement s: that.init){ //tmp.addInitialize(stepIn(s, scope)); tmp.addInitialize(stepIn(s, tmp)); } tmp.setCondition(stepIn(that.cond, tmp)); for(JCStatement s: that.step){ tmp.addUpdate(stepIn(s, tmp)); } tmp.setBody(wrapBlockStatement(stepIn(that.body, tmp))); stmt = tmp; } 構文解析器がJCIfDeclに出会ったら呼び出してくれる
  40. 40. 14 高位合成処理系は何をするか? http://www.ida.liu.se/~petel/SysSyn/lect3.frm.pdf 基本はこれに書いてあります High-Level Synthesis
  41. 41. 15 高位合成処理系は何をするか 入力言語 データフロー スケジューリング データパス生成 ステート生成 物理マッピング
  42. 42. 16 高位合成処理系は何をするか 入力言語 データフロー スケジューリング データパス生成 ステート生成 物理マッピング (1) (2) (3)
  43. 43. 17 高位合成処理系の3つのレイヤ (1)言語デザイン (2)アーキテクチャの生成 (3)テクノロジ・マッピング ✔ 設計コストが小さくなるように ✔ パフォーマンスを出しやすいように ✔ 命令スケジューリング,並列性の抽出 ✔ 動作周波数,リソース使用量,レイテンシの考慮 ✔ 適切な物理マッピング ✔ 符号化
  44. 44. 18 Synthesijerでは ✔ 設計コストが小さくなるように ✔ パフォーマンスを出しやすいように ✔ 命令スケジューリング,並列化の抽出 ✔ 動作周波数,リソース使用量,レイテンシの考慮 ✔ 適切な物理マッピング ✔ 符号化 (1)言語デザイン (2)アーキテクチャの生成 (3)テクノロジ・マッピング Java - オブジェクト指向設計 - スレッドで並列化 - 既存資産の活用 ISE/Vivado,QuartusII にお任せ Javaから変換する エンジンを実装
  45. 45. 19 Synthesijerオーバービュー Javaコード Javaプログラムの解析 スケジューリング表を作成 最適化 HDL構文の組み立て VHDL/ Verilog HDL コード Javaコード VHDL/ Verilog HDL コード VHDL/ Verilog HDL コード 中間表現 (S式) フロントエンド ミドルエンド バックエンド
  46. 46. 20 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++) ; } } }
  47. 47. 21 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モジュールを生成
  48. 48. 22 Synthesijer でのHDL生成: スケジュール表 メソッド毎にスケジュール表を生成 run_0000: op=METHOD_EXIT, src=, dest=, next=0001 run_0001: op=METHOD_ENTRY, src=, dest=, next=0002 (name=run) run_0002: op=JT, src=true:BOOLEAN, dest=, next=0004, 0003 run_0003: op=JP, src=, dest=, next=0023 run_0004: op=ASSIGN, src=true:BOOLEAN, dest=class_led_0000:BOOLEAN, next=0005 run_0005: op=ASSIGN, src=0:INT, dest=run_i_0001:INT, next=0006 run_0006: op=LT, src=run_i_0001:INT, 5000000:INT, dest=binary_expr_00002:BOOLEAN, next=0007 run_0007: op=JT, src=binary_expr_00002:BOOLEAN, dest=, next=0012, 0008 run_0008: op=JP, src=, dest=, next=0013 run_0009: op=ADD, src=run_i_0001:INT, 1:INT, dest=unary_expr_00003:INT, next=0010 run_0010: op=ASSIGN, src=unary_expr_00003:INT, dest=run_i_0001:INT, next=0011 run_0011: op=JP, src=, dest=, next=0006 run_0012: op=JP, src=, dest=, next=0009 run_0013: op=ASSIGN, src=false:BOOLEAN, dest=class_led_0000:BOOLEAN, next=0014 run_0014: op=ASSIGN, src=0:INT, dest=run_i_0004:INT, next=0015 run_0015: op=LT, src=run_i_0004:INT, 5000000:INT, dest=binary_expr_00005:BOOLEAN, next=0016 run_0016: op=JT, src=binary_expr_00005:BOOLEAN, dest=, next=0021, 0017 run_0017: op=JP, src=, dest=, next=0022 run_0018: op=ADD, src=run_i_0004:INT, 1:INT, dest=unary_expr_00006:INT, next=0019 run_0019: op=ASSIGN, src=unary_expr_00006:INT, dest=run_i_0004:INT, next=0020 run_0020: op=JP, src=, dest=, next=0015 run_0021: op=JP, src=, dest=, next=0018 run_0022: op=JP, src=, dest=, next=0002 run_0023: op=JP, src=, dest=, next=0000
  49. 49. 23 スケジューラ表の疑似命令 ✔ 四則演算,論理演算,シフト ✔ 比較 ✔ 代入 ✔ 配列のアドレス指定,配列アクセス ✔ Call/Return ✔ CallしたらReturnされるまで待つ(基本) ✔ Thread.startの呼び出し時は待たずに次へ ✔ 無条件ジャンプ,条件分岐,SELECT ✔ フィールドアクセス指示命令
  50. 50. 24 Synthesijer でのHDL生成: 出力(状態遷移) メソッド毎にスケジュール表を生成 → 状態遷移機械 while for for
  51. 51. 25 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 ...
  52. 52. 26 Synthesijer でのHDL生成: 出力(データ操作) メソッド毎にスケジュール表を生成 → 文/式相当のデータ操作 run_0000: op=METHOD_EXIT, src=, dest=, next=0001 run_0001: op=METHOD_ENTRY, src=, dest=, next=0002 (name=run) run_0002: op=JT, src=true:BOOLEAN, dest=, next=0004, 0003 run_0003: op=JP, src=, dest=, next=0023 run_0004: op=ASSIGN, src=true:BOOLEAN, dest=class_led_0000:BOOLEAN, next=0005 run_0005: op=ASSIGN, src=0:INT, dest=run_i_0001:INT, next=0006 run_0006: op=LT, src=run_i_0001:INT, 5000000:INT, dest=binary_expr_00002:BOOLEAN, next=0007 run_0007: op=JT, src=binary_expr_00002:BOOLEAN, dest=, next=0012, 0008 run_0008: op=JP, src=, dest=, next=0013 run_0009: op=ADD, src=run_i_0001:INT, 1:INT, dest=unary_expr_00003:INT, next=0010 run_0010: op=ASSIGN, src=unary_expr_00003:INT, dest=run_i_0001:INT, next=0011 run_0011: op=JP, src=, dest=, next=0006 run_0012: op=JP, src=, dest=, next=0009 run_0013: op=ASSIGN, src=false:BOOLEAN, dest=class_led_0000:BOOLEAN, next=0014 run_0014: op=ASSIGN, src=0:INT, dest=run_i_0004:INT, next=0015 run_0015: op=LT, src=run_i_0004:INT, 5000000:INT, dest=binary_expr_00005:BOOLEAN, next=0016 run_0016: op=JT, src=binary_expr_00005:BOOLEAN, dest=, next=0021, 0017 run_0017: op=JP, src=, dest=, next=0022 run_0018: op=ADD, src=run_i_0004:INT, 1:INT, dest=unary_expr_00006:INT, next=0019 run_0019: op=ASSIGN, src=unary_expr_00006:INT, dest=run_i_0004:INT, next=0020 run_0020: op=JP, src=, dest=, next=0015 run_0021: op=JP, src=, dest=, next=0018 run_0022: op=JP, src=, dest=, next=0002 run_0023: op=JP, src=, dest=, next=0000
  53. 53. 27 Synthesijer でのHDL生成: 出力(データ操作) メソッド毎にスケジュール表を生成 → 文/式相当のデータ操作 run_0000: op=METHOD_EXIT, src=, dest=, next=0001 run_0001: op=METHOD_ENTRY, src=, dest=, next=0002 (name=run) run_0002: op=JT, src=true:BOOLEAN, dest=, next=0004, 0003 run_0003: op=JP, src=, dest=, next=0023 run_0004: op=ASSIGN, src=true:BOOLEAN, dest=class_led_0000:BOOLEAN, next=0005 run_0005: op=ASSIGN, src=0:INT, dest=run_i_0001:INT, next=0006 run_0006: op=LT, src=run_i_0001:INT, 5000000:INT, dest=binary_expr_00002:BOOLEAN, next=0007 run_0007: op=JT, src=binary_expr_00002:BOOLEAN, dest=, next=0012, 0008 run_0008: op=JP, src=, dest=, next=0013 run_0009: op=ADD, src=run_i_0001:INT, 1:INT, dest=unary_expr_00003:INT, next=0010 run_0010: op=ASSIGN, src=unary_expr_00003:INT, dest=run_i_0001:INT, next=0011 run_0011: op=JP, src=, dest=, next=0006 run_0012: op=JP, src=, dest=, next=0009 run_0013: op=ASSIGN, src=false:BOOLEAN, dest=class_led_0000:BOOLEAN, next=0014 run_0014: op=ASSIGN, src=0:INT, dest=run_i_0004:INT, next=0015 run_0015: op=LT, src=run_i_0004:INT, 5000000:INT, dest=binary_expr_00005:BOOLEAN, next=0016 run_0016: op=JT, src=binary_expr_00005:BOOLEAN, dest=, next=0021, 0017 run_0017: op=JP, src=, dest=, next=0022 run_0018: op=ADD, src=run_i_0004:INT, 1:INT, dest=unary_expr_00006:INT, next=0019 run_0019: op=ASSIGN, src=unary_expr_00006:INT, dest=run_i_0004:INT, next=0020 run_0020: op=JP, src=, dest=, next=0015 run_0021: op=JP, src=, dest=, next=0018 run_0022: op=JP, src=, dest=, next=0002 run_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 ...
  54. 54. 28 最適化の例 べたなプログラムを用意 public class SimpleProgram{ public int sum(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l){ c = a + b; f = d + e; i = g + h; l = j + k; c = c + f; l = l + i; c = c + l; return c; } }
  55. 55. 29 最適化の例 べたなプログラムを用意 sum_0000: op=METHOD_EXIT, src=, dest=, next=0001 sum_0001: op=METHOD_ENTRY, src=, dest=, next=0002 (name=sum) sum_0002: op=ADD, src=sum_a_0000:INT, sum_b_0001:INT, dest=binary_expr_00012:INT, next=0003 sum_0003: op=ASSIGN, src=binary_expr_00012:INT, dest=sum_c_0002:INT, next=0004 sum_0004: op=ADD, src=sum_d_0003:INT, sum_e_0004:INT, dest=binary_expr_00013:INT, next=0005 sum_0005: op=ASSIGN, src=binary_expr_00013:INT, dest=sum_f_0005:INT, next=0006 sum_0006: op=ADD, src=sum_g_0006:INT, sum_h_0007:INT, dest=binary_expr_00014:INT, next=0007 sum_0007: op=ASSIGN, src=binary_expr_00014:INT, dest=sum_i_0008:INT, next=0008 sum_0008: op=ADD, src=sum_j_0009:INT, sum_k_0010:INT, dest=binary_expr_00015:INT, next=0009 sum_0009: op=ASSIGN, src=binary_expr_00015:INT, dest=sum_l_0011:INT, next=0010 sum_0010: op=ADD, src=sum_c_0002:INT, sum_f_0005:INT, dest=binary_expr_00016:INT, next=0011 sum_0011: op=ASSIGN, src=binary_expr_00016:INT, dest=sum_c_0002:INT, next=0012 sum_0012: op=ADD, src=sum_l_0011:INT, sum_i_0008:INT, dest=binary_expr_00017:INT, next=0013 sum_0013: op=ASSIGN, src=binary_expr_00017:INT, dest=sum_l_0011:INT, next=0014 sum_0014: op=ADD, src=sum_c_0002:INT, sum_l_0011:INT, dest=binary_expr_00018:INT, next=0015 sum_0015: op=ASSIGN, src=binary_expr_00018:INT, dest=sum_c_0002:INT, next=0016 sum_0016: op=RETURN, src=sum_c_0002:INT, dest=, next=0000 sum_0017: op=JP, src=, dest=, next=0000
  56. 56. 30 最適化の例 べたなプログラムを用意 sum_0000: op=METHOD_EXIT, src=, dest=, next=0001 sum_0001: op=METHOD_ENTRY, src=, dest=, next=0002 (name=sum) sum_0002: op=ADD, src=sum_a_0000:INT, sum_b_0001:INT, dest=binary_expr_00012:INT, next=0003 sum_0002: op=ADD, src=sum_d_0003:INT, sum_e_0004:INT, dest=binary_expr_00013:INT, next=0003 sum_0002: op=ADD, src=sum_g_0006:INT, sum_h_0007:INT, dest=binary_expr_00014:INT, next=0003 sum_0002: op=ADD, src=sum_j_0009:INT, sum_k_0010:INT, dest=binary_expr_00015:INT, next=0003 sum_0003: op=ASSIGN, src=binary_expr_00012:INT, dest=sum_c_0002:INT, next=0010 sum_0003: op=ASSIGN, src=binary_expr_00013:INT, dest=sum_f_0005:INT, next=0010 sum_0003: op=ASSIGN, src=binary_expr_00014:INT, dest=sum_i_0008:INT, next=0010 sum_0003: op=ASSIGN, src=binary_expr_00015:INT, dest=sum_l_0011:INT, next=0010 sum_0010: op=ADD, src=sum_c_0002:INT, sum_f_0005:INT, dest=binary_expr_00016:INT, next=0011 sum_0010: op=ADD, src=sum_l_0011:INT, sum_i_0008:INT, dest=binary_expr_00017:INT, next=0011 sum_0011: op=ASSIGN, src=binary_expr_00016:INT, dest=sum_c_0002:INT, next=0014 sum_0011: op=ASSIGN, src=binary_expr_00017:INT, dest=sum_l_0011:INT, next=0014 sum_0014: op=ADD, src=sum_c_0002:INT, sum_l_0011:INT, dest=binary_expr_00018:INT, next=0015 sum_0015: op=ASSIGN, src=binary_expr_00018:INT, dest=sum_c_0002:INT, next=0016 sum_0016: op=RETURN, src=sum_c_0002:INT, dest=, next=0000 sum_0017: op=JP, src=, dest=, next=0000
  57. 57. 31 最適化の例 べたなプログラムを用意 sum_0000: op=METHOD_EXIT, src=, dest=, next=0001 sum_0001: op=METHOD_ENTRY, src=, dest=, next=0002 (name=sum) sum_0002: op=ADD, src=sum_a_0000:INT, sum_b_0001:INT, dest=binary_expr_00012:INT, next=0016 sum_0002: op=ADD, src=sum_d_0003:INT, sum_e_0004:INT, dest=binary_expr_00013:INT, next=0016 sum_0002: op=ADD, src=sum_g_0006:INT, sum_h_0007:INT, dest=binary_expr_00014:INT, next=0016 sum_0002: op=ADD, src=sum_j_0009:INT, sum_k_0010:INT, dest=binary_expr_00015:INT, next=0016 sum_0002: op=ASSIGN, src=binary_expr_00012:INT:chain, dest=sum_c_0002:INT, next=0016 sum_0002: op=ASSIGN, src=binary_expr_00013:INT:chain, dest=sum_f_0005:INT, next=0016 sum_0002: op=ASSIGN, src=binary_expr_00014:INT:chain, dest=sum_i_0008:INT, next=0016 sum_0002: op=ASSIGN, src=binary_expr_00015:INT:chain, dest=sum_l_0011:INT, next=0016 sum_0002: op=ADD, src=sum_c_0002:INT:chain, sum_f_0005:INT:chain, dest=binary_expr_00016:INT, sum_0002: op=ADD, src=sum_l_0011:INT:chain, sum_i_0008:INT:chain, dest=binary_expr_00017:INT, sum_0002: op=ASSIGN, src=binary_expr_00016:INT:chain, dest=sum_c_0002:INT, next=0016 sum_0002: op=ASSIGN, src=binary_expr_00017:INT:chain, dest=sum_l_0011:INT, next=0016 sum_0002: op=ADD, src=sum_c_0002:INT:chain, sum_l_0011:INT:chain, dest=binary_expr_00018:INT, sum_0002: op=ASSIGN, src=binary_expr_00018:INT:chain, dest=sum_c_0002:INT, next=0016 sum_0016: op=RETURN, src=sum_c_0002:INT, dest=, next=0000 sum_0017: op=JP, src=, dest=, next=0000
  58. 58. 32 最適化の例 内部はS式.S式を外でいじって処理系に戻すことも可 (SEQUENCER sum (SLOT 0 (METHOD_EXIT :next (1)) ) (SLOT 1 (METHOD_ENTRY :next (2)) ) (SLOT 2 (SET binary_expr_00012 (ADD sum_a_0000 sum_b_0001) :next (16)) (SET binary_expr_00013 (ADD sum_d_0003 sum_e_0004) :next (16)) (SET binary_expr_00014 (ADD sum_g_0006 sum_h_0007) :next (16)) (SET binary_expr_00015 (ADD sum_j_0009 sum_k_0010) :next (16)) (SET sum_c_0002 (ASSIGN binary_expr_00012) :next (16)) ...略... (SET sum_c_0002 (ASSIGN binary_expr_00016) :next (16)) (SET sum_l_0011 (ASSIGN binary_expr_00017) :next (16)) (SET binary_expr_00018 (ADD sum_c_0002 sum_l_0011) :next (16)) (SET sum_c_0002 (ASSIGN binary_expr_00018) :next (16)) ) (SLOT 16 (RETURN sum_c_0002 :next (0)) ) (SLOT 17 (JP :next (0)) ) )
  59. 59. 33 SynthesijerはJavaベースなので... オブジェクト指向的プログラミング!! … … …
  60. 60. 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 … } … }
  61. 61. 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), … );
  62. 62. 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 clk reset a_address a_din a_we a_oe a_din a_dout func_req func_busy hoge q ex. Verilog HDLで書いたhogeをJavaから呼び出す a_length
  63. 63. 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では使わない,という印
  64. 64. 38 インスタンス生成の例 乱数生成のハードウェアをJavaから使う // xorshift RNG, period 2^128-1 // cf. http://www.jstatsoft.org/v08/i14/paper module xor128 ( input wire clk, input wire reset, output reg [63:0] q ); reg[31:0] x = 123456789, y = 362436069, z = 521288629; reg[31:0] w = 88675123; reg[31:0] t; always @(posedge clk) begin q[63:32] <= 32'h0; if(reset == 1'b1) begin x <= 123456789; y <= 362436069; z <= 521288629; w <= 88675123; end else begin t = x ^ (x << 11); x = y; y = z; z = w; w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)); q[31:0] <= w; end end endmodule
  65. 65. 39 インスタンス生成の例 乱数生成のハードウェアをJavaから使う /** * リスト15: XOR128.java * xor128をJavaから利用するためのダミークラス */ import synthesijer.hdl.HDLModule; import synthesijer.hdl.HDLPort; import synthesijer.hdl.HDLPrimitiveType; public class XOR128Iface extends HDLModule{ // Javaプログラムのためのダミー変数 // xor128の出力qに相当する public long q; public XOR128Iface(String... args){ // - 実際に使用するモジュール名 // - クロック信号名 // - リセット信号名 // の順に指定する. super("xor128", "clk", "reset"); // メンバ変数"q"に相当する64bit幅の出力ポートを生成する newPort("q", HDLPort.DIR.OUT, HDLPrimitiveType.genSignedType(64)); } }
  66. 66. 40 インスタンス生成の例 乱数生成のハードウェアをJavaから使う /** * リスト16: XOR128Test.java * xor128をJavaから利用する例 */ public class XOR128Test{ // XOR128モジュールのインスタンスを生成 private final XOR128Iface rng = new XOR128Iface(); public boolean test(){ long v = rng.q; // 乱数を読み出す // 処理の例.たとえば1000より大きければ真,とか. if(v > 1000){ return true; }else{ return false; } } }
  67. 67. 41 インスタンス生成の例 乱数生成のハードウェアをJavaから使う
  68. 68. 42 クラスの継承も可 継承したクラスのメソッドも利用可能 public class Test012 extends Test010{ public void run(){ test(); } } public class Test010{ public void test(){ int a = 20; int b = 30; int c = 0; c = a & b; c = a | b; c = a ^ b; } } library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; entity Test012 is port ( clk : in std_logic; reset : in std_logic; run_busy : out std_logic; run_req : in std_logic; test_busy : out std_logic; test_req : in std_logic ); end Test012; architecture RTL of Test012 is ...
  69. 69. 43 SynthesijerはJavaベースなので... Threadを使って並列化できる … … …
  70. 70. 44 スレッドの利用例 JavaではThreadクラスを継承して並列動作を記述 /* * リスト11: ThreadCounter.java * Threadの活用例 */ // JavaではThreadクラスを継承したクラスを作る public class ThreadCounter extends Thread{ public int counter = 0; // Threadの処理はrunメソッドで実装する public void run(){ while(true){ // 変数をインクリメントする無限ループ counter++; } } }
  71. 71. 45 スレッドの利用例 JavaではThreadクラスを継承して並列動作を記述 import synthesijer.rt.unsynthesizable; public class ThreadTest{ private final ThreadCounter t0 = new ThreadCounter(); private final ThreadCounter t1 = new ThreadCounter(); public void test(){ t0.start(); t1.start(); } // このメソッドはSynthesijerでは無視する @unsynthesizable public static void main(String... args){ ThreadTest t = new ThreadTest(); t.test(); while(true){ System.out.println("t0:" + t.t0.counter); System.out.println("t1:" + t.t1.counter); try{ Thread.sleep(1); }catch(Exception e){ e.printStackTrace(); } } } }
  72. 72. 46 スレッドの利用例 PCで実行したところ
  73. 73. 47 スレッドの利用例 シミュレーションで確認したところ
  74. 74. 48 ここまでのまとめ ✔ Synthesijer=JavaをVHDL/Verilog HDLに変換する処理系 ✔ Javaなりのオブジェクト指向設計をサポート ✔ Threadによる並列処理の記述とHW化
  75. 75. 49 Synthesijerオーバービュー Javaコード Javaプログラムの解析 スケジューリング表を作成 最適化 HDL構文の組み立て VHDL/ Verilog HDL コード Javaコード VHDL/ Verilog HDL コード VHDL/ Verilog HDL コード 中間表現 (S式) フロントエンド ミドルエンド バックエンド
  76. 76. 50 Synthesijer as a Compiler-Infrastructure Javaコード スケジューリング表を作成 最適化 Y構文の組み立て VHDL/ Verilog HDL コード X言語 VHDL/ Verilog HDL コード 中間表現 (S式) フロントエンド ミドルエンド バックエンド X言語パーザー 最適化器 Y言語
  77. 77. 1 Synthesijer サンプル・事例 
  78. 78. 2 2 ✔ Javaといえば,スクリプト言語のホストとしても魅力的 ✔ JRuby,Scala,Clojure,and etc. ✔ BrainF**k: とても小さなスクリプト言語処理系 → hoge サンプル1: プログラムインタプリタ +, -, >, <, [, ], ., ,の記号からなるインタプリタ ++++++++++[>++++++++++<-]>++++.+++++++.--------.--. http://www.kmonos.net/alang/etc/brainfuck.php
  79. 79. 3 サンプル1: BFのコード抜粋 private IO io = new IO(); private byte[] prog = new byte[CODESIZE]; private byte[] data = new byte[ARRAYSIZE]; private int ptr, pc; public boolean step() { byte cmd = prog[pc]; byte tmp; int nlvl = 0; switch (cmd) { case 0: return false; case '>': ptr++; break; case '<': ptr--; break; case '+': data[ptr] = (byte) (data[ptr] + 1); break; case '-': data[ptr] = (byte) (data[ptr] – 1); break; case '.': io.putchar(data[ptr]); break; case ',': data[ptr] = io.getchar(); break; case '[': if (data[ptr] == (byte) 0) { while (true) { pc++; if(prog[pc] == ']' && nlvl == 0) break; if(prog[pc] == '[') nlvl++; if(prog[pc] == ']') nlvl--; } } break; case ']': … } }
  80. 80. 4 サンプル1: ソフトウェアとして実行 ✔ 標準入出力越しでBrainF**kインタプリタを実行 ✔ +, -, >, <, [, ], ., ,の記号からなるインタプリタ
  81. 81. 5 サンプル1: FPGAで実行 ✔ 標準入出力の代わりにシリアル通信越しで実行
  82. 82. 6 SWとHWで同じコードを利用 ソフトウェアで実行する時 BF IO Console 合成して実機で動かす時 IO + putchar() + getchar() + putchar() + getchar() RS232Wrapper
  83. 83. 7 サンプル1: 文字の入出力ルーチン public void read() { prompt(); for (int i = 0; i < CODESIZE; i++) { byte b; b = io.getchar(); //io.putchar(b); if (b == 'n' || b == 'r') { prog[i] = (byte) 0; break; } else { prog[i] = b; } } } public void print() { boolean flag = true; for (int i = 0; i < CODESIZE; i++) { byte b = prog[i]; if (b == 0) { break; } io.putchar(b); } io.putchar((byte) 'n'); }
  84. 84. 8 サンプル1: SW版とHW版の入出力 public class IO { private rs232c obj = new rs232c(); public void putchar(byte c) { obj.write(c); } public byte getchar() { byte b; b = obj.read(); return b; } } public class IO{ public void putchar(byte c){ System.out.print((char)c); } public byte getchar(){ try{ return (byte)(System.in.read()); }catch(Exception e){ throw new RuntimeException(e); } } }
  85. 85. 9 サンプル2: ディスプレイに絵を書く public class BitMapTest extends Thread{ ... public void run(){ // 座標(100, 100)の位置にサイズ20の正方形を描画 canvas.rect(100, 100, 20, 20, BitMapCanvas.RED, 0); int c0 = 0, c = 0; // 画面上にサイズ40の正方形を色を変えながら敷き詰める for(int i = 0; i < 16; i++){ // (/ 640 40)16 c = c0; for(int j = 0; j < 12; j++){ // (/ 480 40) canvas.rect(40*i, 40*j, 40, 40, color(c), 1); c = (c + 1) & 0x7; } c0 = (c0 + 1) & 0x7; } // 線を描画するメソッドのテスト canvas.line(0, 0, 639, 479, color(7), 1); canvas.line(639, 0, 0, 479, color(7), 1); // フレームバッファ1をスクロールさせる int v = 0, h = 0; while(true){ canvas.set_offset(0, v, 1); v = (v == 479) ? 0 : v + 1; t.sleep(1); // 適当なウェイト } }
  86. 86. 10 ✔ ソフトウェアとして実行して動作を確認 サンプル2: ディスプレイに絵を書く
  87. 87. 11 ✔ 実FPGAとディスプレイで同じ動作を確認 サンプル2: ディスプレイに絵を書く
  88. 88. 12 サンプル3: AHCI ✔ Advanced Host Controller Interface ✔ SATAなHDDやSSDを接続するためのインターフェース ✔ 最近のOSのほとんどでサポートされている = 標準のデバドラでブロックデバイスにみえる ✔ SATAなHDDやSSD以外に接続してはいけない,ことはない ✔ AHCI HBAをFPGAに実装してディスクアクセスしてみよう
  89. 89. 13 サンプル3: AHCI PC FPGA ディスク? 何かの 処理 ディスク インターネット ✔ なんでもディスクに見せてしまうのは楽しそう ✔ たとえば BRAM
  90. 90. 14 一般的なAHCIによるディスク接続 ディスクに送るコマンドを預かる ディスクからのリプライを返す 作業用メモリのポインタの確認 複数コマンドをOoOで発行(NCQ) ディスクへのFISの発行 ディスクからのFISの受信 ステータス管理
  91. 91. 15 AHCIのメモリチェイン どのコマンドが 有効かはPxCI レジスタをみる ディスクに 送るべきコマンド PCIeのBAR5に レジスタ空間への ポインタがある ディスクとの やり取りに使う メモリ領域への ポインタ 近代的なOSでは大量の仮想メモリを複数の細かい実メモリに分割して扱う ディスクとの やり取りに使う メモリ領域 P0CLB HBAからは P0CLBの 値でたどる
  92. 92. 16 AHCI越しのデータ授受のフロー PCIe越しの通信
  93. 93. 17 HBAの動作フロー/FIS取得まで private int wait_for_command(){ while(reg.values[P0CI] == 0) ; reg.values[P0CMD] = 0x10110007; // 処理開始 int id = get_port_id(reg.values[P0CI]); // '1'のbitを選ぶ axi.fetch(reg.values[P0CLB] + (id << 5), 4); // command headerを取得 dw0 = axi.read(0); // PRDTL, PMP, RCBRPWA, CFL dw1 = axi.read(1); // PRD Byte Count dw2 = axi.read(2); // CTBA0 dw3 = axi.read(3); prdtl = (dw0 >> 16) & 0x0000FFFF; ctba = dw2; axi.fetch(ctba, 5);// CFIS取得 cfis_dw0 = axi.read(0); // Features, // Command,… cfis_dw1 = axi.read(1); cfis_dw2 = axi.read(2); cfis_dw3 = axi.read(3); return (dw0 >> 16) & 0x000000FF; } P0CLB
  94. 94. 18 動作例 PCIデバイス→AHCIデバイス→ディスクに見えている うまくOSを だませている /dev/sdbらしい ddとかできる
  95. 95. 19 Synthesijer 活用方法 - 3つのパタン
  96. 96. 20 3つの開発パタン (1) Javaによるモジュールだけでシステムを構成 (2) HDLによるモジュールを部品として利用.全体管理はJavaで記述 = 既存IPコア,FPGAの性能を活用 (3) Javaによるモジュールを部品として利用.全体管理はHDLで記述 = 複雑なアルゴリズムをSWプログラマに書いてもらう.SW資産の活用 (1)Javaでシステムを構成 (2)Java + HDL記述の部品 (3)HDL + Java記述の部品
  97. 97. 21 (1) Javaでシステムを構成 ✔ すべてをJavaで記述 ✔ トップモジュール,UCF/XDCなんかは必要 ✔ I/Oなどは用意されたライブラリを利用 ✔ シリアルI/O,SC1602,純粋なInput/Output, ... ✔ AXI(32bit逐次,シンプルなキャッシュ),UPL,...
  98. 98. 22 (2) Java+HDL記述の部品 ✔ JavaプログラムにHDL記述の部品を埋め込む ✔ Javaで記述したオブジェクトのようにHDL記述部品をインスタンス化して使う ✔ HDLモジュールを簡単に使い回せる ✔ Synthesijer内部でどうオブジェクトが扱われるかを知る必要がある ✔ Javaとのブリッジのために HDLModule を継承したクラスを実装 ✔ 合成時にはHDL記述のコードと組み合わせる ✔ HWプログラマがサポートしつつSWプログラマにFPGAを活用してもらう!! HogeModule obj = new HogeModule(); obj.x = 0; obj.data[0] = 100; class HogeModule extends HDLModule{ int x; int[] data; HogeModule(){ super("hoge_module", ...); } entity hoge_module is port( x : ... data_waddr : … data_wdata : ... 見かけ上の 接続 実際の接 続 SWプログラマに HWモジュールを有効活用してもらう
  99. 99. 23 インスタンス生成・拡張モジュール 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 clk reset a_address a_din a_we a_oe a_din a_dout func_req func_busy hoge q ex. Verilog HDLで書いたhogeをJavaから呼び出す a_length
  100. 100. 24 インスタンス生成・拡張モジュール 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では使わない,という印
  101. 101. 25 (3) HDL+Java記述の部品 ✔ HDLで設計したシステムにJava記述の部品を埋め込む ✔ 複雑なアルゴリズムの処理でもJavaなら(比較的)手軽に実装 ✔ HDLで自然に実装できるストリーム処理,並列処理を活用 ✔ Synthesijerで合成した回路がどういう構成か知る必要がある ✔ SWプログラマ/資産をFPGA設計に活用!! class HogeModule{ int hoge_func(int a){ … } entity hoge_module is port( hoge_func_a : in ... hoge_func_return : out … hoge_func_req : in … hoge_func_busy : out ... Synthesijer hoge_module hoge_func_req hoge_func_a hoge_func_return hoge_func_busy
  102. 102. 26 複雑/面倒なアルゴリズム処理の実装 ✔ 例: バブルソートじゃなくてマージソートの採用,など ✔ バブルソート(512個の降順→昇順) ✔ マージソート(512個の降順→昇順) x15
  103. 103. 27 複雑なアルゴリズム処理はJavaで実装 ✔ バブルソートの状態遷移 ✔ マージソートの状態遷移
  104. 104. 28 最近よく実装しているパタン FIFO 実行 ステージ FIFO 実行 ステージ FIFO スループット T [bps] 実行 ステージ FIFO 実行 ステージ FIFO 実行 ステージ FIFO 実行 ステージ FIFO ここを Javaで書く
  105. 105. 1 今できていること ✔ とりあえず使える ✔ Javaの制御構文,メソッド呼び出し,演算 ✔ とてもシンプルな最適化 ✔ Vivado向けIPコアテンプレートの自動生成 Source Abstraction Level Ease of Impl. Learning curve Document- ation Floating/ Fixed Pt. Design Exploration Testbench generation Verification Size FPGA Slices Synthesijer Java untimed + + - Auto conversion +/- - -
  106. 106. 2 手が回っていないこと ✔ もう少し賢い最適化 ✔ メモリアクセスレイテンシの隠蔽 ✔ 演算レイテンシを考慮したチェイニング ✔ リソースシェアリング
  107. 107. 3 今後挑戦したいこと ✔ メソッドのパイプライン化 ✔ Javaプログラムとしてどう扱うか ✔ I/Oストリームへの対応 ✔ コンストラクタに対応 ✔ コンパイル時のJavaプログラム実行 ✔ lambda式対応 ✔ Streamへの対応
  108. 108. 1 +α Synthesijer.scala
  109. 109. 2 RTL設計の辛さ ✔ “ ”信号の流れ を記述する ✔ “ ” “ ”処理の流れ を 信号の流れ に変換 ↔ “ ”書きたいのは 処理の流れ ✔たくさんの似たような構造 ✔ たくさんの似たような名前 ✔ 記述の再利用をしたいが難しい 本質としては 実務的には
  110. 110. 3 手軽なFPGA開発のための取り組み ✔ 高位合成言語処理系 ✔ DSL
  111. 111. 4 高位合成処理系 ✔ CやJava,C#などを入力言語とした開発環境 ✔ 開発コストを小さくできる ✔ 生成したHWの質は処理系依存 ✔ 良いHW生成にはコツが必要 ✔ ディレクティブの活用 ✔ 書き方を考える必要がある
  112. 112. 5 高位合成処理系 ✔ Vivado HLS ✔ OpenCL対象の処理系 ✔ CyberWorkBench ✔ Cynthesizer ✔ Symphony C Compiler ✔ ImpulseC ✔ Lime ✔ Synthesijer などなどなど
  113. 113. 6 DSLベースの設計手法 ✔ RTL設計を楽にするためのDSL ✔ 実装したいアプリケーション別のDSL ✔ プログラミングモデルに特化したDSL
  114. 114. 7 様々なDSLベースのシステム開発(1) ✔ MyHDL (Pythonベース) ✔ JHDL (Javaベース) ✔ Chisel (Scalaベース) ✔ PyVerilog (Pythonベース) などなどなど RTL設計(あるいは少し抽象的なHW設計)を より楽にするためのDSL
  115. 115. 8 様々なDSLベースのシステム開発(2) ✔ Spiral ←Linear Digital Processing ✔ HDL Coder ← 信号処理(Matlab) ✔ Optimus ← ストリーム処理 ✔ LINQ ← クエリプロセッシング などなどなど ✔ DSLを作るツールも.(たとえば,LMS/Scala) 実装したいアプリケーションに特化したDSL
  116. 116. 9 様々なDSLベースのシステム開発(3) ✔ Bluespec (並行プログラミング) ✔ MaxCompiler (データフロープログラミング) ✔ FloPoCo (浮動小数点数パイプライン) ✔ SPGen (パイプライン) などなどなど 使用するプログラミングモデルに特化したDSL
  117. 117. 10 DSLベースの設計手法 ✔ RTL設計を楽にするためのDSL ←依然RTLであることに代わりはない ✔ 実装したいアプリケーション別のDSL ←HWの設計探索をしたい場合には不向き ✔ プログラミングモデルに特化したDSL →さて,どんなモデルがよいだろうか?
  118. 118. 11 FPGAが有用なのはなぜか? ✔ 論理回路・データパスを自由に作り込めるLSI ✔ I/Oを自由に使える ✔ クロックレベルの同期と並列性を活用した処理を実現 Field Programmable Gate Array
  119. 119. 12 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 より データはどうせ移動させる 移動途中で副次的に処理できる
  120. 120. 13 鍵はパイプライン並列化 FIFO スループット T [bps] w [byte] f [Hz] 実行 ステージ FIFO 実行 ステージ 実行 ステージ
  121. 121. 14 データが来たら迎え撃つ
  122. 122. 15 鍵はパイプライン並列化 パケットデータが 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 実行 ステージ 実行 ステージ とはいえ,各ステージで状態遷移のある処理が必要
  123. 123. 16 鍵はパイプライン並列化 パケットデータが 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 実行 ステージ 実行 ステージ とはいえ,各ステージで状態遷移のある処理が必要 限られた 許容サイクルを 効率よく使う必要
  124. 124. 17 組み合わせ回路/データ並列性の活用 ✔ プロセッサと比べてFPGA回路のφは圧倒的に低速 ✔ 高速データ処理では1クロックでデータを捌く必要も ✔ 時にはソフトウェア実装とは全く違う場合も 条件 ・・・ 条件 v.s
  125. 125. 18 欲しいDSL ✔ Bluespec (並行プログラミング) ✔ MaxCompiler (データフロープログラミング) ✔ FloPoCo (浮動小数点数パイプライン) などなどなど 使用するプログラミングモデルに特化したDSL 状態遷移および各状態での処理設計がやりやすく 組み合わせ回路が書きやすい言語
  126. 126. 19 設計: Synthesijer.scala ✔ 組み合わせ回路の設計の容易は失わないまま ✔ “処理の流れ”の記述を容易にする ✔ クロックベースの状態管理と状態遷移を言語機能に ✔ 内部DSLとして設計.回路設計にScalaの機能を活用. ✔ 設計資産の再利用性を高める ✔ 見通しの良い設計を可能にする
  127. 127. 20 Synthesijer.scala とは ✔ Synthesijerのバックエンドを使ってScala“で”HDLを書く ✔ signal, port: 状態を変更可能なオブジェクト ✔ expr: 副作用なしの式 ✔ sequencer: 状態遷移機械 ✔ module: モジュール全体 ✔ 上記のオブジェクトをScalaでインスタンス化.つなぎ合わせる.
  128. 128. 21 Synthesijer.Scalaの立ち位置 Javaコード Javaプログラムの解析 スケジューリング表を作成 最適化 HDL構文の組み立て VHDL/ Verilog HDL コード Javaコード VHDL/ Verilog HDL コード VHDL/ Verilog HDL コード 中間表現 (S式) フロントエンド ミドルエンド バックエンド Scalaで 自分で組立て
  129. 129. 22 開発フロー Scalaプログラムとして実装 → VHDLまたはVerilog HDLを生成 RTLシミュレーションによる動作検証 使用するFPGAにあわせた制約を定義 ツールで合成,配置配線,FPGA構成情報生成 実機で動作確認 Synthesijer.Scalaを使ってモジュールを実装
  130. 130. 23 モデル モジュールの設計単位 入出力. クロック単位で状態保持 組み合わせ回路. 状態は持たない クロック単位での状態保持 状態遷移マシン
  131. 131. 24 はじめての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 <= (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) val (clk, reset, counter) = sim.system(10) inst.sysClk <= clk inst.sysReset <= reset return sim }
  132. 132. 25 ベンディングマシンの例 ドリンク 自動販売機 ¢5 ¢10 ドリンク一杯¢20 お釣りは出ません
  133. 133. 26 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; …
  134. 134. 27 ベンディングマシンの例 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()
  135. 135. 28 ベンディングマシンのステートマシン
  136. 136. 29 Scalaの機能を使った設計効率化の向上 ✔ 設計資産をメソッドやクラスとして保存,再利用 ✔ 類似オブジェクトや類似オブジェクトの生成 ✔ ループとパタンマッチによる直列化/復元コードの生成
  137. 137. 30 設計資産の再利用 例: デコーダ (7セグメントLEDの点灯) 4 0 2 51 6 7 3
  138. 138. 31 設計資産の再利用 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設計の場合
  139. 139. 32 設計資産の再利用 def decoder(s:ExprItem, l:List[(Int,Int)], w:Int) = { l.foldRight[ExprItem](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を使う場合 実データに合わせた回路の生成
  140. 140. 33 自分なりのパタン,最適化の埋め込みも ✔ 組み合わせ回路の段数に応じたFF(状態)の追加,除去 ✔ 入出力データに対するパタンマッチ ✔ よく使うモジュールのテンプレート化 例えば... などなど
  141. 141. 34 自分なりの実装,例 例えば...ANDゲートをLUTじゃなくてMUXで作りたい
  142. 142. 35 自分なりの実装,例 継承とオーバーライドを使って,自然に表現可能 val x0 = inP("x0") val y0 = inP("y0") val z0 = outP("z0") val z1 = outP("z1") val z2 = outP("z2") z0 := x0 and y0 val x1c = new CARRY4Sig(x0) val y1c = new CARRY4Sig(y0) z1 := x1c and y1c z2 := z0 or z1
  143. 143. 36 自分なりの実装,例 例えば...ANDゲートをLUTじゃなくてMUXで作りたい
  144. 144. 37 自分なりの実装,例 例えば...ANDゲートをLUTじゃなくてMUXで作りたい
  145. 145. 1 さて,未来はどうなる?
  146. 146. 2 ポテンシャルをどう活かすか!! https://www.youtube.com/watch?v=FCmfcfPt4T4
  147. 147. 3 各社の取り組み ✔ Xilinx SDx (特にSDSoC) ✔ Altera SDP ✔ IBM Lime ✔ Microsoft Kiwi ✔ CoRAM/PyCoRAM “システムをどう作るか”,がターゲット = システムとLSI
  148. 148. 4 Xilinx SDSoC Zynq向けのSW/HWコデザインツール
  149. 149. 5 Altera SDP SPCS005 — Technology Insight: Workload Acceleration, IDF2015
  150. 150. 6 IBM Lime Java + Isolation + Abstract Parallelism + Extraction
  151. 151. 7 Microsoft Kiwi (Distributing C#) Greaves, D.; Singh, S., "Distributing C# methods and threads over Ethernet-connected FPGAs using Kiwi," in Formal Methods and Models for Codesign (MEMOCODE), 2011 9th IEEE/ACM International Conference on , vol., no., pp.1-9, 11-13 July 2011
  152. 152. 8 CoRAM/PyCoRAM 高前田先生@NAIST
  153. 153. 9 未来で,どう開発したい?
  154. 154. 1 まとめ ✔ Javaベースの高位合成処理系を作って/使っています ✔ まだまだですが,こういう人もいる,と. ✔ 中間表現のS式を操作して処理系に戻せるので, 最適化器実装してみたいという人がいたら是非 ✔ 結構,楽しい時代だと思っている ✔ ...FPGAって米国産なんだよなあ... Javaコンパイラ フロントエンド Synthesijer エンジン Javaコンパイラ バックエンド .class ソフトとして実行 同じJavaプログラムをソフトウェアとしても FPGA上のハードウェアとしても実行可能
  155. 155. 2 参考 ✔ http://synthesijer.github.io/web ✔ リソース一式,クイックスタートガイドなど ✔ http://qiita.com/kazunori279/items/4951ca5f6164040878ce ✔ Synthesijer関連資料まとめ Qiita ✔ http://labs.beatcraft.com/ja/index.php?Synthesijer ✔ Altera DE0-nanoでのサンプルの動作手順など ✔ http://wasa-labo.com/wp/ ✔ わさらぼ ブログ – 開発状況,Tipsなど

×