Vivado HLSのテストベンチでEigenを使う(成功版)

# はじめに
先日，Vivado HLSのテストベンチにC++の行列演算ライブラリであるEigen[^1]を読み込ませてようとして[見事に失敗した記事](https://qiita.com/HoriThe3rd/items/3d04ba815ce9d7ce9bee)を上げました．

[^1]: [Eigen](http://eigen.tuxfamily.org/index.php?title=Main_Page)

今回はその続報です。結論から言うと、Eigenのバージョンを下げることで問題が解決しました。

パスの設定方法など、操作は特に変わりませんので、前回の失敗記事を参考にしていただければと思います。

# 失敗した・・・
簡単に前回発生した事象のおさらいをしておこうと思います．
そもそも事の発端は，Vivado HLSの勉強で、行列演算回路を自作した時に，テストベンチでどうやって正解データを用意しようかと考えた事でした．そこで，Eigen（行列演算ライブラリ）で行列演算をさせて，自作の関数（HLSで回路化される）の結果と比較しようと考えたのです．

Include pathsとGCCに与えるオプションを設定し，いざシミュレーションしてみると・・・
C Simulationはうまく動作するのに，論理合成後の回路をテストするC/RTL Cosimulationだとエラーが発生してうまくいかない．Eigenをincludeした時点でエラーが発生する・・・という問題が発生しました．

# 原因と思われるもの
Vivado HLSに付属するGCCのバージョンがEigenの要求するバージョンよりも古かった事実が判明しました。このくらいしか原因として思い当たりませんでした．

まず，前回の記事で使用したソフトウェアのバージョンは以下の通りでした．

- Vivado HLS 2018.3 (Linux版)
- Eigen 3.3.7 (一番新しいやつ)

そして，EigenのWebサイト[^1]に記載のCompiler Supportを確認すると・・・

- GCC 4.8以上

続いてXilinxの”Vidado Design Suite ユーザーガイド 高位合成(UG902)”[^2]の”言語サポート”の項目を確認すると、以下のようにあります。

[^2]: [Vivado Design Suite ユーザーガイド 高位合成 (UG902)](https://japan.xilinx.com/support/documentation/sw_manuals_j/xilinx2018_3/ug902-vivado-high-level-synthesis.pdf)

> Vivado HLS では、C コンパイル/シミュレーションに次の規格がサポートされています。
> • ANSI-C (GCC 4.6)
> • C++ (G++ 4.6)
> • SystemC (IEEE 1666-2006、バージョン 2.2)

明らかにVivado付属のGCCのバージョンが足りていません。

# 対策
本当にこれが原因なのかはわかりませんが、バージョン不足なのは明らかですので、Eigenのバージョンを以下のものに下げてみたところ、正常にC/RTL Cosimulationまで実行することができました。

Eigen 3.2.10

正直、このバージョンを選択した深い理由はありません。リリース日が2016.10なので、Vivado 2018.3よりは古いだろうというくらいです。GCCのバージョンいくつ以上が必要なのかは確認していません・・・あしからず．

この時使用したテストベンチのコードは以下の通りです。前回の失敗記事の時から、少し変更しています。乱数を使って行列の値を初期化していますが、その乱数生成器のシード値を固定にしました(いい加減に定数を設定してしまいました・・・)。そうしないとテストに失敗します。この件については、別記事でまとめようと思います。

```cpp
#include <iostream>
#include <random>
#include "Eigen/Core"
#include "Eigen/Geometry"

using namespace std;

#define SIZE_ROW 3
#define SIZE_COL 4

void dot_multi(int w[SIZE_ROW][SIZE_COL], int v[SIZE_COL], int o[SIZE_ROW]);

int main()
{
    cout << "start" << endl;
    random_device rng;
    //mt19937_64 mt(rng());
    mt19937_64 mt(123);
    uniform_int_distribution<> rng10(0, 10);

    int w[SIZE_ROW][SIZE_COL];
    int v[SIZE_COL];
    int result[SIZE_ROW];

    Eigen::MatrixXi ew = Eigen::MatrixXi::Zero(SIZE_ROW, SIZE_COL);
    Eigen::VectorXi ev = Eigen::VectorXi::Zero(SIZE_COL);
    Eigen::VectorXi eresult = Eigen::VectorXi::Zero(SIZE_ROW);

    // Initialize
    for(int i=0; i<SIZE_ROW; i++){
        for(int j=0; j<SIZE_COL; j++){
            int num = rng10(mt);
            w[i][j] = num;
            ew(i,j) = num;
        }
    }
    for(int i=0; i<SIZE_COL; i++){
        int num = rng10(mt);
        v[i] = num;
        ev(i) = num;
    }

    dot_multi(w, v, result);
    eresult = ew * ev;

    // Display arguments
    cout << "--- w ---" << endl;
    for(int i=0; i<SIZE_ROW; i++){
        for(int j=0; j<SIZE_COL; j++){
            cout << w[i][j] << " ";
        }
        cout << endl;
    }
    cout << "--- v --- " << endl;
    for(int i=0; i<SIZE_COL; i++){
        cout << v[i] << endl;
    }
    cout << "--- Eigen w ---" << endl;
    cout << ew << endl;
    cout << "--- Eigen v ---" << endl;
    cout << ev << endl;

    // Display the result
    cout << " --- Result --- " << endl;
    for(int i=0; i<SIZE_ROW; i++){
        cout << result[i] << endl;
    }
    cout << " --- Eigen Result --- " << endl;
    cout << eresult << endl;

    // Auto check
    for(int i=0; i<SIZE_ROW; i++){
        if(result[i] != eresult(i)){
            cout << "**** Test failed... :( ****" << endl;
            return 1;
        }
    }
    cout << "*** Test passed ***" << endl;
    return 0;
}
```


# 終わりに
今回は、Eigenのバージョンを下げることで、C/RTL Cosimulationまで正常に通すことができました。

正直なところ、C Simulationは通るのに、C/RTL Cosimulationはエラー、ということを考えると、本当にGCCのバージョンが問題なのか疑問は残るところです。

とはいえ、結果オーライということで、これ以上の深追いをするつもりはありません。ひとまずこれで多少はテストベンチ作成が捗ることを期待したいです。Eigenに限らず，Vivado HLSのテストベンチ用に外部のライブラリを使うことはできそうですね．

以上，長々とお読みいただきありがとうございました．