FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

Vivado HLSで開発したIPをZynq ZedBoardでIPとして利用したい(4)

f:id:msyksphinz:20160601001536p:plain

前回まででIPのインテグレートが完了したので、今度はPS側の制御プログラムの開発に入る。

SDKで新しいプロジェクトを立ち上げる。ハードウェアとしては、design_1_wrapper_hw_platform_1を指定する。

Vivado HLSで生成したドライバ群をSDKから参照するためには

このやり方が分からず少しはまった。結果的には、marseeさんのブログに詳細が書いてあったので解決した。 あいかわらずmarseeさんの記事は画像が多く分かりやすい。

FPGAの部屋 SDKにVivado HLSで作製したIPのドライバをインポートする

作成したIPパッケージにはzipファイルが生成されており、これを任意の場所で展開。その場所を指定することでIPのヘッダファイルなどの情報をインポートできる。

f:id:msyksphinz:20160903174832j:plain

下記のように、matrix_mulのドライバ群がインポートされていることが分かる。

f:id:msyksphinz:20160903174834j:plain

制御プログラムを記述する

ここでは、ARM上で動作させるプログラムを以下のように記述した。

具体的には、

  1. Matrix_Mulハードウェアを初期化する
  2. データを入力する
  3. 演算を開始する
  4. 演算が終了するまで待つ
  5. 結果を格納する

具体的には、以下のようなプログラムを記述した。

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"

#include "xmatrix_mul.h"

int main()
{
  init_platform();

  print("Hello World\n\r");

  const float matrix_a[8][8] = {{2.00861, 4.96191, 0.03365, 8.49076, 2.05199, 2.35618, 6.64845, 2.48825},
                                {8.24828, 3.79825, 0.71616, 5.02615, 2.37722, 1.70809, 3.09136, 7.97736},
                                {0.81262, 4.22766, 6.10453, 1.67064, 1.95103, 7.01496, 0.92316, 4.52642},
                                {6.44442, 2.59385, 1.32141, 1.64139, 7.25922, 1.16130, 0.29613, 1.15290},
                                {8.40171, 4.97169, 3.97962, 2.65527, 6.64343, 4.18250, 9.66444, 8.76806},
                                {6.02191, 0.71815, 2.29678, 5.76173, 4.72776, 9.79415, 6.47138, 7.49650},
                                {2.11535, 5.73055, 6.17571, 5.24272, 5.13695, 8.90108, 6.35120, 1.16608},
                                {7.40435, 0.45430, 8.73240, 6.09247, 4.89821, 4.02948, 2.66578, 4.80374}};

  const float matrix_b[8][8] = {{6.31683, 7.40894, 4.11552, 5.11706, 3.89267, 2.53873, 0.89988, 3.21347},
                                {9.67123, 4.80318, 0.46820, 2.54917, 8.17656, 7.38784, 0.98314, 4.25930},
                                {1.61677, 5.34579, 5.74210, 7.85177, 1.93416, 3.57129, 9.49534, 8.32125},
                                {5.20353, 1.78412, 9.06261, 6.23715, 5.52162, 4.11266, 2.34838, 4.09494},
                                {8.49776, 9.95641, 1.99669, 5.11842, 1.71897, 0.96354, 3.33916, 9.04869},
                                {8.19442, 6.65203, 6.72998, 4.58975, 0.77722, 1.05325, 2.65544, 0.80571},
                                {6.91818, 5.26098, 8.58867, 7.27429, 4.99427, 2.20705, 0.79829, 0.85794},
                                {3.72035, 8.24444, 8.54816, 8.66889, 2.99164, 9.01359, 4.28659, 0.49119}};

  float matrix_c[8][8];

  XMatrix_mul matrix_mul;
  XMatrix_mul *p_matrix_mul = &matrix_mul;
  XMatrix_mul_Config *p_matrix_mul_config = NULL;

  p_matrix_mul_config = XMatrix_mul_LookupConfig (XPAR_MATRIX_MUL_0_DEVICE_ID);
  if (!p_matrix_mul_config) {
    fprintf (stderr, "XMatrix_mul Config Lookup failed.\n");
    return -1;
  }

  int XMatrix_mul_status = XMatrix_mul_CfgInitialize (p_matrix_mul, p_matrix_mul_config);
  if (XMatrix_mul_status != XST_SUCCESS) {
    fprintf (stderr, "XMatrix_mul Configuration failed.\n");
    return -1;
  }

  xil_printf("XMATRIX_MUL_SLV0_ADDR_MATRIX_A_BASE=%d\n", XMATRIX_MUL_SLV0_ADDR_MATRIX_A_BASE);

  int a_length = XMatrix_mul_Write_matrix_a_Words(p_matrix_mul, 0,
                                                  (int *)matrix_a,
                                                  XMATRIX_MUL_SLV0_DEPTH_MATRIX_A);
  xil_printf("a_length=%d\n", a_length);
  XMatrix_mul_Write_matrix_b_Words(p_matrix_mul, 0,
                                   (int *)matrix_b,
                                   XMATRIX_MUL_SLV0_DEPTH_MATRIX_B);

  xil_printf("XMatrix_mul_Start\n");

  XMatrix_mul_Start (p_matrix_mul);

  while (!XMatrix_mul_IsDone (p_matrix_mul));

  xil_printf("XMatrix_mul_Reading\n");
  XMatrix_mul_Read_matrix_c_Words (p_matrix_mul, 0, (int *)matrix_c, XMATRIX_MUL_SLV0_DEPTH_MATRIX_C);

  int j, i;
  for (j = 0; j < 8; j++) {
    for (i = 0; i < 8; i++) {
      int whole, thousandths;
      whole = matrix_c[j][i];
      thousandths = (matrix_c[j][i] - whole) * 1000;
      xil_printf ("%d.%04d ", whole, thousandths);
    }
    xil_printf ("\n");
  }

  cleanup_platform();
  return 0;
}

1. Matrix_Mulハードウェアを初期化する

これにはXMatrix_mul_LookupConfig()XMatrix_mul_CfgInitialize()を利用している。これは定石のコードのようだ。あまり変更せずに利用している。 以下のmarseeさんの記事も参考にした。

FPGAの部屋 SDKにVivado HLSで作製したIPのドライバをインポートする

2. データを入力する

これにはXMatrix_mul_Write_matrix_a_Words()XMatrix_mul_Write_matrix_b_Words()を使用した。入力値としてはfloatなのだが、int配列を受け取るものしか用意されていないので、ポインタの型変換をして入力している。

3. 演算を開始する

XMatrix_mul_Start()を呼ぶことで演算を開始した。

4. 演算が終了するまで待つ

とりあえずXMatrix_mul_IsDone ()を呼び出すことで待ち状態を作っているが、この方法が本当に合っているかは分からない...

5. 結果を格納する

XMatrix_mul_Read_matrix_c_Words()を呼び出して結果を取得した。こちらも同様にint型のポインタに型変換しているが、floatで取得している。

動作結果

コンソールには以下のように表示された。きちんと演算が出来ている。すばらしい!

Hello World
XMATRIX_MUL_SLV0_ADDR_MATRIX_A_BASE=256
XMatrix_mul_Write_matrix_a_Words assert 0 trial
XMatrix_mul_Write_matrix_a_Words assert 0 clear
XMatrix_mul_Write_matrix_a_Words assert 286331153
a_length=64
XMatrix_mul_Start
XMatrix_mul_Reading
196.0909 145.0638 186.0056 167.0399 141.0344 118.0357 56.0026 90.0030 
201.0411 209.0213 196.0371 200.0510 137.0020 155.0046 78.0897 98.0682 
161.0872 170.0204 153.0244 161.0424 85.0720 114.0073 112.0057 104.0578 
154.0012 161.0261 84.0908 114.0835 76.0222 66.0256 57.0253 116.0916 
311.0613 329.0238 283.0188 302.0985 184.0883 194.0360 135.0061 168.0245 
271.0772 278.0695 285.0540 267.0828 136.0055 149.0216 120.0559 125.0021 
270.0917 238.0948 229.0040 230.0078 146.0940 130.0176 129.0347 163.0740 
207.0943 243.0793 236.0898 250.0211 122.0303 136.0542 154.0109 175.0557