はじめに
vitis HLSを使ってみました。
ネット上に情報はあるんですが、現在のツール(2024.1)ではなくて、微妙に違いがあったり、自分で試してみないと分らない事も多いので、試行錯誤してみました。
この過程をメモしておきます。
環境
- Vitis 2024.1(windows 11 64bit版)
参考になりそうな公式ドキュメント
Vitis 統合ソフトウェア プラットフォームの資料: エンベデッド ソフトウェア開発 (UG1400)
作成するもの
ARMプロセッサーに接続されたLEDを制御するモジュールを作成します。
モジュールに0,1,2,3の値を入力すると、それに応じてLEDが点灯するようにします。
Vitis HLSでの作業
Vitis HLSを起動します。ツールの使い方の詳細は、公式ドキュメントを参照してください。
flow_targetの設定
flow_targetには、Vivado IP フローとVitis カーネル フローがあります。
VivadoでIPを使う方法はわかってるので、今回は、経験のあるVivado IPフローで開発してみます。
Vitis カーネル フローの方が、HLSの開発に専念できそうなので、HLSに慣れてきたら、今後試す事にします。
vitisのHSLの設定で、flow_targetを、vivadoにします。
output.formatを、ip_catalogにします。(デフォルトでこの設定になっているのかもしれませんが、私は、試行錯誤していたので、この設定になっていなくて、設定する必要がありました。)
プログラムの作成
Sourcesにled.cppを追加します。
組み合わせ回路を記述してみます。
入力に与えられた値に応じて、LEDを点灯させるモジュールを作成してみます。
出力のLEDの状態は、axiのインターフェースでは取得しないので、ap_none
を指定します。
#include <ap_int.h>
void led(ap_uint<4> *in_data, ap_uint<4> *out) {
#pragma HLS TOP name=led
#pragma HLS INTERFACE s_axilite port=in_data
#pragma HLS INTERFACE ap_none port=out
switch(*in_data){
case 0:
*out=0x1;
break;
case 1:
*out=0x2;
break;
case 2:
*out=0x4;
break;
case 3:
*out=0x8;
break;
default:
*out=0x0;
break;
}
}
テストベンチも作成してみます。
#include <ap_int.h>
void led(ap_uint<4> *in_data, ap_uint<4> *out);
int main()
{
ap_uint<4> a, b;
const int test_case = 4;
int pass = 0;
int fail = 0;
a = 0;
b = 0;
for (int i = 0; i < test_case; i++) {
led(&a, &b);
if (1<<a == b) {
pass++;
} else {
fail++;
}
a++;
}
std::cout << "test_case:" << test_case << " pass:" << pass << " fail:" << fail << std::endl;
if (test_case == pass) {
std::cout << "PASS" << std::endl;
return 0;
} else {
std::cout << "FAIL" << std::endl;
return -1;
}
}
VitisのフローのC SIMULATION
SYNTHESIS
C/RTL CO-SIMULATION
PACKAGE
を順に実行します。
全て成功すればOKです。
これで、IPが作成されました。
意外と簡単にできました。
vivadoでIPを組み込む
Vitis HLSで作成したIPが保存されているフォルダをviadoのプロジェクトに追加します。
ブロックデザインに追加します。
AXI Interconnectは、自動配線を実行した時に自動的に追加されます。
※ZinqプロセッサーにAXIインターフェースのマスターを有効にしておかないと、配線ができません。プロセッサーの次の設定を行っておく必要があります。
vitisでアプリ作成
vitisでアプリを作成します。
Standaloneのアプリを作って、動作させてみます。
デバイスにアクセスする関数が用意されていています。
X{モジュール名}Set{パラメータ名}のような関数を呼び出すと、パラメータに値がセットされます。
今回は、in_dataに整数値を設定するとそれに応じたLEDが点灯する事になります。
0,1,2,3の値を繰り返し設定するプログラムにしてみます。
#include "xparameters.h"
#include "xled.h"
#include "xil_printf.h" // UART出力用
// #define XPAR_LED_0_BASEADDR 0x40000000
int main() {
// 1. デバイスインスタンス
XLed ledDevice;
int i,j;
// 2. デバイスの初期化
int status = XLed_Initialize(&ledDevice, XPAR_LED_0_BASEADDR);
if (status != XST_SUCCESS) {
xil_printf("Error: XLed_Initialize failed with status %d\n", status);
return XST_FAILURE; // 初期化に失敗
}
xil_printf("start");
while(1){
for(i=0;i<4;i++){
XLed_Set_in_data(&ledDevice, i);
for(j=0;j<10000000;j++){
;
}
}
}
return 0;
}
実行結果
想定通りにLEDが点灯しました。
おわりに
- Vitis HLSを使って、AXI4によるIOを行うモジュールを作成してみました
- AXIインターフェースを使ったモジュールはVivadoで作るより楽
- C言語での記述を論理合成する道筋を理解できました
- vitis,vivado,vitisとツールを行き来する必要があって、少し面倒
今後の課題
Vitis カーネル フローも試してみたい