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

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

FPGAの部屋

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

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

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

前回は、AXI4 インターフェースを独立な 3 個にすることで、DMA Read がバーストするようになって、ループの中を 1 クロックで実行できるようになった。今回は、AXI4 インターフェースが 3 個あるのはもったいないので、1 個のAXI4 インターフェースでループで性能を向上させたい。

入力ポートの x と y は 8 ビットなので、32 ビット幅のインターフェースでは、1 トランザクションで 4 個転送できる。x と y をまとめてしまえば 1 回のRead で x と y を持ってこられるんじゃないか?ということで、とりあえずは structure にしてみよう。
sum_of_squares.cpp はこうなった。

#include <stdint.h>

typedef struct xy_struct{
    int8_t x;
    int8_t y;
} xy_st;

int sum_of_squares(volatile xy_st *xy, volatile int32_t *result){
#pragma HLS DATA_PACK variable=xy
#pragma HLS INTERFACE m_axi depth=10 port=xy 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++){
#pragma HLS PIPELINE II=1
        result[i] = xy[i].x * xy[i].x + xy[i].y * xy[i].y;
    }

    return(0);
}


今回は、ap_int<8> は * の演算子がオーバーロードされていないということで、 int_8t を使うことにした。
テストベンチのsum_of_squares_tb.cpp はこうなった。

// sum_of_squares_tb.cpp

#include <iostream>
#include <stdint.h>

typedef struct xy_struct{
    int8_t x;
    int8_t y;
} xy_st;

int sum_of_squares(volatile xy_st *xy, volatile int *result);

int main(){
    xy_st xy[10];
    int result[10];

    for(int i=0; i<10; i++){
        xy[i].x = i;
        xy[i].y = i+1;
    }

    sum_of_squares(xy, result);

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


sum_of_squares_17_190821.png

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

問題ないようだ。

C コードの合成を行った。
sum_of_squares_19_190821.png

ループの中は 4 クロックで処理している。

AXI4 Lite Slave のアドレスマップを見ると、引数で x と y を実装したときと同じようだ。

//------------------------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 xy_x
//        bit 31~0 - xy_x[31:0] (Read/Write)
// 0x1c : reserved
// 0x20 : Data signal of xy_y
//        bit 31~0 - xy_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)



次に引数 xy に DATA_PACK 指示子を追加してみよう。
sum_of_squares_20_190821.png

sum_of_squares.cpp はこうなった。

#include <stdint.h>

typedef struct xy_struct{
    int8_t x;
    int8_t y;
} xy_st;

int sum_of_squares(volatile xy_st *xy, volatile int32_t *result){
#pragma HLS DATA_PACK variable=xy
#pragma HLS INTERFACE m_axi depth=10 port=xy 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++){
#pragma HLS PIPELINE II=1
        result[i] = xy[i].x * xy[i].x + xy[i].y * xy[i].y;
    }

    return(0);
}


C コードの合成を行った。
sum_of_squares_21_190821.png

やはり、ループの中は 4 クロックで処理している。
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 xy
//        bit 31~0 - xy[31:0] (Read/Write)
// 0x1c : reserved
// 0x20 : Data signal of result
//        bit 31~0 - result[31:0] (Read/Write)
// 0x24 : reserved
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)


データがパックされて、xy のオフセットアドレスのみになったのだが、ループの中は 4 クロックなのか???

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

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

結局、40 回Read している。RDATA を見るとデータがパックされているのが分かるが、アクセスとしては x と y が独立の引数のときと同じということが分かった。
  1. 2019年08月22日 05:12 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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