Skip to main content
Vivado HLSのシミュレーション
とHLSストリーム
marseeこと小野 雅晃
2
FPGAの部屋(ブログ)
● 2005年からYahooブログで書き始めた(11年以上)
● 最初ー2005年5月15日”Chipscopeについて”
●
ブログが流行りでやってみたかった
● FPGAの開発ノウハウやバグの共有がしたかった
● ログが貼り付けられなかったので8月にFC2に移動
●
備忘録として使用(補助記憶)
●
お仕事に使う前にブログでツールなどを検証
●
早朝書いています。超朝型
●
コメントなど、お願いします
3
私の机
4
ノートパソコンを1月に購入
● FPGAマガジンの執
筆のためだけに購入
● 経費で落とさない
と。。。
5
FPGAコンパイル用にパソコンを購入
● 5年前のパソコンよ
りもFPGAのコンパ
イル速度が2倍から
3倍速い
●
マウスコンピュー
ター
– i5 4コア 3.2GHz
– メモリ 16GB
6
Vivado HLS
● C、C++、System CからVHDL、Verilog HDLに変換
する
● IPを生成する
● FPGAの種類を指定して、クロック周期を設定する
● 指定したクロック周期で動作するRTLを出力するよう
に努力する
●
クロック周期を短くすると自動的にパイプライン段数が
増える
● AXI-Master, AXI-Lite Slave, AXI-Streamは自動生成
●
ソフトウェアから使用するためのドライバも自動生成
7
Vivadoのブロックデザイン
8
私の方針
● もう58歳
– 頭は長く持たない2時間くらい?
– ステートマシンを多用したシーケンスをHDLで書くのは
つらい
– HDLだと書くまでの設計時間が長かった
● そこでVivado HLSでCで書く
– Cで書けばハードに
– CシミュレーションもC/RTL協調シミュレーションも
● ほとんどCで書いて、書けないのだけHDLで
9
Vivado HLSで書くのが難しい回路
●
入力タイミングや出力タイミングが厳しい回路
– A信号入力がアサートされてから何クロック以内にB信号出
力をアサート
●
スレッドが必要な場合
– 入力と出力が独立(例:FIFO)
– 追加:書けそうだという予想になっていたの忘れていました
● DATAFLOW指示子で書いてみる予定
● 2つのクロックを使う回路
– <例>ディスプレイ・コントローラ
● 100MHzのAXI4-StreamのデータをSVGA(ピクセルクロック
40MHz)で出力
10
私の方針2
● 前のスライドの回路はHDLで書く
● 特にアルゴリズム系はVivado HLSを使ってCで書
く
● なるべくXのIPを使って楽に書きたい
– XのIPには汎用性やバージョンごとの継続性の関係で
使いにくいIPがある(AXI VDMA)
– そのようなIPはVivado HLSでなるべく書き直したい
● この方針で行く
– ブログもほとんどVivado HLSの話題
11
Vivado HLSの利点
●
クロックやタイミングは考慮しない(できない)
– 欠点:細かいタイミングは書けない(vld, ack)
– 利点:動作周波数を指定することができる(回路を自動的に変
更)
– 書くのに時間がかからない
●
シミュレーション
– Cシミュレーション
● テストベンチをCで書けると便利
● 通常のCソフトウェア
– C/RTL協調シミュレーション
● CからRTLに合成した部分はRTLシミュレータ
● Cテストベンチから入力データをRTLシミュレータに渡して、結果をCテ
ストベンチに戻す
12
Cシミュレーション例(画像フィルタ)
画像ファイル
読み込み
画像フィルタ
(ソフトウェア)
画像フィルタ
(ソフトウェア)
値を比較
一致
画像書き出し
正常終了
あり得ない
Cシミュレーション
スタート
CからHDLに合成
される関数
不一致
=
Cテストベンチ
13
C/RTL協調シミュレーション
画像ファイル
読み込み
画像フィルタ
(ソフトウェア)
画像フィルタ
(ハードウェア)
値を比較
一致
画像書き出し
正常終了
異常終了
C/RTL協調シミュレー
ション・スタート
不一致
RTLシミュレータ
Cテストベンチ
CからHDLに合成
される関数
14
テストベンチは浮動小数点演算
ハードウェアは固定小数点の例
画像ファイル
読み込み
画像フィルタ
(ソフトウェア)
浮動小数点演算
画像フィルタ
(ソフトorハード)
固定小数点演算
二乗誤差を比較
<=スレッショルド
画像書き出し
正常終了
異常終了
シミュレーション
スタート
>スレッショルド
C実行 or
RTLシミュレータ
Cテストベンチ
CからHDLに合成
される関数
15
Vivado HLSでのシミュレーション
への疑問
● CやC++で書いてハードになる
– Cだったら引数の値は変化しないけど、ハードウェアで
は変化する引数が必要な場合がある
– 出力もリターンする前に変化する場合があるよね。。。
● 出力値が変化する場合はC/RTL協調シミュレー
ションで変化を見れば良いか。。。
● Cテストベンチでシミュレーションの時に複数の値
の引数を与えられるのかな?
– 通常は無理だよね。。。
16
関数の入力値が変化する例
● 出力が変化する場合
– C/RTL協調シミュレーションすれば値の変化は見られる
– Cのテストベンチで検証はできない(一般的には)
– PWM出力など
●
入力が変化する場合
– パルスの数を数える回路
– Cのテストベンチでは入力が与えられない
● 1つの引数には1つの値
– とりあえず、HDLのテストベンチを使ってみよう
17
ハード化する関数の引数の方を変更1
● FPGAの部屋の記事”Vivado HLS 2016.2 で volatile
を使用する場合”
● http://marsee101.blog19.fc2.com/blog-entry-3497.ht
ml
● ap_start から ap_done の間に関数の入力や出力が変
化する場合は、volatile を付ける(UG902)
● 入力、出力ポートをap_none, registerオプションありに
してVivado HLSで合成し、HDLのテストベンチでシミュ
レーション
● 引数の型やvolatileでどのように結果が変わるかを観察
した
18
Cソースコード1
#include <ap_int.h>
void volatile_test(volatile ap_uint<16> multi_in0, volatile ap_uint<16> multi_in1,
volatile ap_uint<16> *multi_out){
#pragma HLS INTERFACE ap_none register port=multi_out
#pragma HLS INTERFACE ap_none register port=multi_in1
#pragma HLS INTERFACE ap_none register port=multi_in0
for(int i=0; i<10; i++){
#pragma HLS PIPELINE II=1
ap_uint<16> temp = (ap_uint<16>)multi_in0 * (ap_uint<16>)multi_in1;
*multi_out = temp;
}
}
19
シミュレーション波形1
● 入力された最初の値をラッチして乗算し、最後に出
力する
20
1クロックごとに乗算結果を得る方法
● 1クロックごとに乗算結果を得たい
● その方法は?
● その方法は?
● もう一丁、その方法とは?
● そんなにじらすな。。。いやな奴。。。
● 入力もポインタにしましょう。。。
21
Cソースコード2
#include <ap_int.h>
void volatile_test(volatile ap_uint<16> *multi_in0, volatile ap_uint<16>
*multi_in1,
volatile ap_uint<16> *multi_out){
#pragma HLS INTERFACE ap_none register port=multi_out
#pragma HLS INTERFACE ap_none register port=multi_in1
#pragma HLS INTERFACE ap_none register port=multi_in0
for(int i=0; i<10; i++){
#pragma HLS PIPELINE II=1
*multi_out = (ap_uint<16>)*multi_in0 * (ap_uint<16>)*multi_in1;
}
}
22
シミュレーション波形2
● 入力がアサートされた3クロック後にデータが出力
されている
● 始まりの3クロック分は出力されない
23
無限に乗算をする回路
● それじゃ、無限に乗算する回路を作るには?
– while(1)で無限ループにすれば良いのでは?
– それでOK
– ただしシミュレーション不可能(終わらない)
24
それではVivado HLSで
シミュレーション可能にするには
● 今までは、Vivado HLSでシミュレーションできずに
RTLシミュレーションを行ってきた
● Cの関数の引数に値をセットして関数コール
● 途中で引数の値を変えるのは無理・・・
● でもせっかく便利なんだからCのテストベンチを使っ
てシミュレーションしたい。。。
● その方法は。。。
● その方法とは。。。
● 果たして、その方法とは?
25
HLSストリームライブラリ
● UG902では、HLSストリームライブラリを推奨
● hls::stream<> ク ラ ス を使用し て イ ンプ リ メ ン
ト し た ス ト リ ーム
● C コー ドでは、 hls::stream<> が無限深さの
FIFO の よ う に動作
26
HLSストリームライブラリの使用法1
(RGB出力の例)
● hls_stream.hをインクルード
– #include <hls_stream.h>
●
テンプレートを定義
– template<int Data>
– struct RGB{
– ap_uint<Data> vid_pData;
– ap_uint<1> vid_pHSync;
– ap_uint<1> vid_pVSync;
– ap_uint<1> vid_pVDE;
– };
27
HLSストリームライブラリの使用法2
(RGB出力の例)
● 関数の引数にhls::stream<>オブジェクトを書く
– void lap_filter_rgb(ap_uint<1> lap_fil_enable,
hls::stream<vid_in<24> >& video_in, hls::stream<RGB<24>
>& video_out){
● テンプレートの書式のHLSストリームが生成される
● HLSストリームに入力したいデータを詰め込んでから関数
を呼べばOK
●
つまり、入力値を変えることができる
● ただし、IOレベルのインターフェースはap_noneではだめ
● ap_hs, ap_fifo, axis のどれかを使用する
● http://marsee101.blog19.fc2.com/blog-entry-3235.html
28
HLSストリームの入力ポートの使い方
● HLSストリームはPmodHB5 のセンサー・フィード
バック処理IPに使用している
● CシミュレーションやC/RTL協調シミュレーションで
検証したかった
– typedef ap_uint<1> ap_uint_1;
– int motor_monitor(hls::stream<ap_uint_1 >& sa,
– hls::stream<ap_uint_1 >& sb,
– ap_uint<32> & sa_count,
– ap_uint_1 & sb_level,
– ap_uint_1 & overflow){
29
SB, SAの波形
「Project 10: Frequency Measurement Using Input Capture」のFugure 2の一
部を引用
http://www.mrc.uidaho.edu/mrc/people/jff/340/341/labs/lab10/project10.pdf
30
テストベンチ
ap_uint_1 saa[DATASIZE] = {1,1,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,1,1,1};
ap_uint_1 sba[DATASIZE] = {0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1};
hls::stream<ap_uint_1> sa;
hls::stream<ap_uint_1> sb;
for (int i=0; i<DATASIZE; i++){
sa << saa[i];
sb << sba[i];
}
int ret_val = motor_monitor(sa, sb, sa_count, sb_level);
http://marsee101.blog19.fc2.com/blog-entry-3501.html
31
PmodHB5_infモジュール
1に固定
32
HLSストリームが使えるかどうか?
for (sa_count=0; sa_count!=0xffffffff; sa_count++){
// sa=1の間はループ
#pragma HLS PIPELINE II=1
sa >> sad;
sb >> sbd;
if (!sad)
break;
}
if (sa_count == 0xffffffff) // overflow
return 1;
for (sa_count=1; sa_count!=0xffffffff; sa_count++){ //
sa=0の間はループ
#pragma HLS PIPELINE II=1
sa >> sad;
sb >> sbd;
if (sad)
break;
}
if (sa_count == 0xffffffff) // overflow
return 1;
sb_level = sbd; // saが立ち上がった時のsbの値
for (sa_count++; sa_count!=0xffffffff;
sa_count++){ // sa=1の間はループ
#pragma HLS PIPELINE II=1
sa >> sad;
sb >> sbd;
if (!sad)
break;
}
if (sa_count == 0xffffffff) // overflow
return 1;
● 3つのループ
33
C/RTL協調シミュレーション波形
34
Cから合成したHDLの出力が
変化する場合
● 今まで関数コール後に引数(つまり入力が変化す
る場合)を見てきた
● 出力が変化する場合もHLSストリームに入れてお
いてテストベンチでテストすれば良さそう
35
まとめ
●
レジスタ・オプションを付けた入力ポートもポインタ渡し、
参照渡しにすると毎クロック入力データをラッチします
● その場合は、Cのテストベンチではシミュレーションがで
きないので、HDLシミュレーションをしましょう
● HDLシミュレーションをしたくない場合には、HLSスト
リームを使って、ap_vldに常に1を入れましょう
● HLSストリームのap_ackは無視します
● その場合は、必ずC/RTL協調シミュレーションで1クロッ
クごとに処理できているかを確認しましょう
● 出力が変化する場合もHLSストリームに入れておいてC
テストベンチでテストすれば良さそうです