FC2カウンター FPGAの部屋 Vivado HLS で 2 つの引数から DMA Read する AXI4 Master モジュールを作る1
FC2ブログ

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

Vivado HLS で 2 つの引数から DMA Read する AXI4 Master モジュールを作る1

Vivado HLS で 2 つの入力のAXI4 Master モジュールを作ってみよう。題材は平方数の和を求めるコードだ。

まずは、ap_int 型を使って作ってみよう。
Source は sum_of_squares.cpp とした。

#include <ap_int.h>

int sum_of_squares(volatile ap_int<8> *x, volatile ap_int<8> *y, volatile ap_int<17> *result){
#pragma HLS INTERFACE m_axi depth=10 port=y offset=slave
#pragma HLS INTERFACE m_axi depth=10 port=x offset=slave
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE m_axi depth=10 port=result offset=slave

    for(int i=0; i<10; i++){
        result[i] = x[i]*x[i] + y[i]*y[i];
    }

    return(0);
}


Testbench は sum_of_squares_tb.cpp とした。

// sum_of_squares_tb.cpp

#include <iostream>
#include <ap_int.h>

int sum_of_squares(volatile ap_int<8> *x, volatile ap_int<8> *y, volatile ap_int<17> *result);

int main(){
    ap_int<8> x[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    ap_int<8> y[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    ap_int<17> result[10];

    sum_of_squares(x, y, result);

    for(int i=0; i<10; i++){
        std::cout << "x[" << i << "]= " << (int)x[i] <<
                ", y[" << i << "] = " << (int)y[i] <<
                ", result[" << i << "] = " <<
                result[i] << std::endl;
    }
}


Vivado HLS 2018.3 で sum_of_squares プロジェクトを作成した。使用するFPGA は xc7z010clg400-1 のZYBO Z7-10 を想定している。
sum_of_squares_1_190820.png

C シミュレーションをするとエラーになった。
sum_of_squares_2_190820.png

最初のエラーを貼る。

../../../sum_of_squares.cpp: 関数 ‘int sum_of_squares(volatile ap_int<8>*, volatile ap_int<8>*, volatile ap_int<17>*)’ 内:
../../../sum_of_squares.cpp:10:19: エラー: no match for ‘operator*’ (operand types are ‘volatile ap_int<8>’ and ‘volatile ap_int<8>’)
   result[i] = x[i]*x[i] + y[i]*y[i];


なんと乗算の定義が無い様だ。
なお、”高位合成ユーザーズ ガイド UG902 (v2018.3) 2018 年 12 月 20 日”の 90 ページに

値が複数回更新されるデータ信号を指定するには、volatile 修飾子を使用してください。

と書いてあるので、volatile は必要だ。

エラーを回避するにはどうするかというと、char と int に引数の方を変えてみよう。
sum_of_squares.cpp を示す。

int sum_of_squares(volatile char *x, volatile char *y, volatile int *result){
#pragma HLS INTERFACE m_axi depth=10 port=y offset=slave
#pragma HLS INTERFACE m_axi depth=10 port=x offset=slave
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE m_axi depth=10 port=result offset=slave

    for(int i=0; i<10; i++){
        result[i] = x[i]*x[i] + y[i]*y[i];
    }

    return(0);
}


sum_of_squares_tb.cpp を示す。

// sum_of_squares_tb.cpp

#include <iostream>

int sum_of_squares(volatile char *x, volatile char *y, volatile int *result);

int main(){
    char x[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    char y[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int result[10];

    sum_of_squares(x, y, result);

    for(int i=0; i<10; i++){
        std::cout << "x[" << i << "]= " << (int)x[i] <<
                ", y[" << i << "] = " << (int)y[i] <<
                ", result[" << i << "] = " <<
                result[i] << std::endl;
    }
}


C シミュレーションを行った。
sum_of_squares_3_190820.png

今度は成功した。”高位合成ユーザーズ ガイド UG902 (v2018.3) 2018 年 12 月 20 日”のAXI4 Master のサンプルの引数の型が int なのはこのような理由なのだろうか?

C コードの合成を行った。結果を示す。
sum_of_squares_4_190820.png

AXI4 Lite Slave のアドレスマップを示す。

//------------------------Address Info-------------------
// 0x00 : Control signals
//        bit 0  - ap_start (Read/Write/COH)
//        bit 1  - ap_done (Read/COR)
//        bit 2  - ap_idle (Read)
//        bit 3  - ap_ready (Read)
//        bit 7  - auto_restart (Read/Write)
//        others - reserved
// 0x04 : Global Interrupt Enable Register
//        bit 0  - Global Interrupt Enable (Read/Write)
//        others - reserved
// 0x08 : IP Interrupt Enable Register (Read/Write)
//        bit 0  - Channel 0 (ap_done)
//        bit 1  - Channel 1 (ap_ready)
//        others - reserved
// 0x0c : IP Interrupt Status Register (Read/TOW)
//        bit 0  - Channel 0 (ap_done)
//        bit 1  - Channel 1 (ap_ready)
//        others - reserved
// 0x10 : Data signal of ap_return
//        bit 31~0 - ap_return[31:0] (Read)
// 0x18 : Data signal of x
//        bit 31~0 - x[31:0] (Read/Write)
// 0x1c : reserved
// 0x20 : Data signal of y
//        bit 31~0 - y[31:0] (Read/Write)
// 0x24 : reserved
// 0x28 : Data signal of result
//        bit 31~0 - result[31:0] (Read/Write)
// 0x2c : reserved
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)


C/RTL 協調シミュレーションを行った。
sum_of_squares_5_190820.png

0x18 番地(x のアドレス)には 0 、0x20 番地(y のアドレス)には 0xC 、 0x28 番地(result のアドレス)には 0x18 を書いている。
C/RTL 協調シミュレーションの波形を拡大した図を示す。
sum_of_squares_6_190820.png

AXI4 Master Read は、ARLEN が 00 なので単発のアクセス、AXI4 Master Write は AWLEN が 09 なので、バースト・アクセスとなる。
x の値は 2 回 Read されている。 y の値も 2 回 Read されているようだ。

次に、sum_of_squares.cpp の for 文に PIPELINE 指示子を追加してみよう。

int sum_of_squares(volatile char *x, volatile char *y, volatile int *result){
#pragma HLS INTERFACE m_axi depth=10 port=y offset=slave
#pragma HLS INTERFACE m_axi depth=10 port=x offset=slave
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE m_axi depth=10 port=result offset=slave

    LOOP1: for(int i=0; i<10; i++){
#pragma HLS PIPELINE II=1
        result[i] = x[i]*x[i] + y[i]*y[i];
    }

    return(0);
}


C コードの合成結果を示す。
sum_of_squares_10_190820.png

約 1/3 程度のLatency になった。

C/RTL 協調シミュレーション結果を示す。
sum_of_squares_8_190820.png

C/RTL 協調シミュレーションの波形を拡大した図を示す。
sum_of_squares_9_190820.png

1 回の演算を行うのに、合計 40 回 Read している。 write は 10 回だ。

それじゃ、このRead のアクセス回数を 1/2 にしてみよう。
Source の sum_of_squares.cpp のコードを以下のように変更した。

int sum_of_squares(volatile char *x, volatile char *y, volatile int *result){
#pragma HLS INTERFACE m_axi depth=10 port=y offset=slave
#pragma HLS INTERFACE m_axi depth=10 port=x offset=slave
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE m_axi depth=10 port=result offset=slave

    LOOP1: for(int i=0; i<10; i++){
#pragma HLS PIPELINE II=1
        char xt = x[i];
        char yt = y[i];

        result[i] = xt*xt + yt*yt;
    }

    return(0);
}


C コードの合成結果を示す。
sum_of_squares_11_190820.png

Initiation Interval が 4 クロックから 2 クロックになった。

C/RTL 協調シミュレーションの結果を示す。
sum_of_squares_12_190820.png

C/RTL 協調シミュレーションの波形を示す。
sum_of_squares_13_190820.png

Read が 20 回になった。
  1. 2019年08月20日 05:27 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
http://marsee101.blog.fc2.com/tb.php/4619-37777ef1
この記事にトラックバックする(FC2ブログユーザー)