FC2カウンター FPGAの部屋 Vivado HLS によるAXI4 マスタ・インターフェースのバースト転送2

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

FPGAの部屋

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

Vivado HLS によるAXI4 マスタ・インターフェースのバースト転送2

Vivado HLS によるAXI4 マスタ・インターフェースのバースト転送”の続き。

前回は、バース ト ビヘイ ビアーを指定したにもかかわらず、バースト転送しなかった。今回はバースト転送するようにCソースコードを書き換えてみた。

前回のC/RTL協調シミュレーションの波形をよく見ると、AXI4 Master Read の最初のLoop1, Loop2 の部分はバースト転送している。(ARLENが 0f で 16 バースト転送)
Vivado_HLS_AXI4M_burst_9_161121.png

AXI4 Master Write の最後の Loop7, Loop8 もバースト転送している。(AWLEN が 0f で 16 バースト転送)
Vivado_HLS_AXI4M_burst_10_161121.png

やはり、for 文の中に入っていない単独の for 文で、ループがなく単純なAXI4 Master アクセスだけだったらバースト転送できるのではと思った。

そこで、AXI4 Master Read と RGBから輝度信号への変換 (conv_rgg2y()) を rdma_and_rgb2y() 関数にすることにした。
AXI4 Master Write は wdam_buf() という関数を作って、それを使うことにした。

新しい laplacian_filter3.c を示す。

// laplacian_filter3_2.c
// 2016/11/22 by marsee
//

#define HORIZONTAL_PIXEL_WIDTH    64
#define VERTICAL_PIXEL_WIDTH    48

#define ALL_PIXEL_VALUE    (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)

int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2);
int conv_rgb2y(int rgb);
void rdma_and_rgb2y(int *buf, volatile int *mem, int tripcount);
void wdma_buf(int *buf, volatile int *mem, int tripcount);

int lap_filter_axim(volatile int *cam_fb, volatile int *lap_fb)
{
#pragma HLS INTERFACE s_axilite port=return

#pragma HLS INTERFACE m_axi depth=3072 port=cam_fb offset=slave bundle=cam_fb num_read_outstanding=4 max_read_burst_length=16
#pragma HLS INTERFACE m_axi depth=3072 port=lap_fb offset=slave bundle=lap_fb num_write_outstanding=4 max_write_burst_length=16

    int line_buf[3][HORIZONTAL_PIXEL_WIDTH];
#pragma HLS array_partition variable=line_buf block factor=3 dim=1
#pragma HLS resource variable=line_buf core=RAM_2P
    int lap_buf[HORIZONTAL_PIXEL_WIDTH];
    int x, y;
    int lap_fil_val;
    int fl, sl, tl;

    // 最初に2ラインの画素を読み込む
    Loop1: for (y=0; y<2; y++){ // 2ライン分
        rdma_and_rgb2y(&line_buf[y][0], &cam_fb[(y*HORIZONTAL_PIXEL_WIDTH)], HORIZONTAL_PIXEL_WIDTH);
    }

    // RGB値をY(輝度成分)のみに変換し、ラプラシアンフィルタを掛けた。
    Loop2: for (y=2; y<VERTICAL_PIXEL_WIDTH; y++){
        rdma_and_rgb2y(&line_buf[y%3][0], &cam_fb[(y*HORIZONTAL_PIXEL_WIDTH)], HORIZONTAL_PIXEL_WIDTH);

        lap_buf[0] = 0// ラインの最初に0を代入
        lap_buf[HORIZONTAL_PIXEL_WIDTH-1] = 0// ラインの最後に0を代入

        Loop3: for (x=2; x<HORIZONTAL_PIXEL_WIDTH; x++){
#pragma HLS PIPELINE II=1
            fl = (y-2)%3;    // 最初のライン, y=2 012, y=3 120, y=4 201, y=5 012
            sl = (y-1)%3;    // 2番めのライン
            tl = y%3;        // 3番目のライン
            lap_fil_val = laplacian_fil(line_buf[fl][x-2], line_buf[fl][x-1], line_buf[fl][x], line_buf[sl][x-2], line_buf[sl][x-1], line_buf[sl][x], line_buf[tl][x-2], line_buf[tl][x-1], line_buf[tl][x]);
            lap_buf[x-1] =  (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val ;
        }
        wdma_buf(&lap_buf[0], &lap_fb[((y-1)*HORIZONTAL_PIXEL_WIDTH)], HORIZONTAL_PIXEL_WIDTH);
     }
     Loop4: for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++) // 最初の行に 0 を入れる
#pragma HLS PIPELINE II=1
         lap_fb[x] = 0;

     Loop5: for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++) // 最後の行に 0 を入れる
#pragma HLS PIPELINE II=1
         lap_fb[HORIZONTAL_PIXEL_WIDTH*(VERTICAL_PIXEL_WIDTH-1)+x] = 0;

     return(0);
}

// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y =  0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
int conv_rgb2y(int rgb){
    int r, g, b, y_f;
    int y;

    b = rgb & 0xff;
    g = (rgb>>8) & 0xff;
    r = (rgb>>16) & 0xff;

    y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
    y = y_f >> 8// 256で割る

    return(y);
}

// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1  8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2)
{
    int y;

    y = -x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2;
    if (y<0)
        y = 0;
    else if (y>255)
        y = 255;
    return(y);
}

void rdma_and_rgb2y(int *buf, volatile int *mem, int tripcount){
    int i;

    Loop20: for (i=0; i<tripcount; i++){
#pragma HLS PIPELINE II=1
        *buf = *mem++;
        *buf++ = conv_rgb2y(*buf);
    }
}

void wdma_buf(int *buf, volatile int *mem, int tripcount){
    int i;

    Loop20: for (i=0; i<tripcount; i++)
#pragma HLS PIPELINE II=1
        *mem++ = *buf++;
}


Vivado_HLS_AXI4M_burst_11_161122.png

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

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

C/RTL協調シミュレーションの波形を示す。
まずは、AXI4 Master Read から、ARLEN を見ると 0f で 16 バースト転送している。
Vivado_HLS_AXI4M_burst_14_161122.png

次に、AXI4 Master Write を見てみた。こちらも AWLEN を見ると 0f で 16 バースト転送している。
Vivado_HLS_AXI4M_burst_15_161122.png

一旦、バースト ビヘービアーを外して

#pragma HLS INTERFACE m_axi depth=3072 port=cam_fb offset=slave bundle=cam_fb
#pragma HLS INTERFACE m_axi depth=3072 port=lap_fb offset=slave bundle=lap_fb

Cコードの合成、C/RTL協調シミュレーションを行って、C/RTL協調シミュレーションの波形見たところ、やはり 16 バースト転送だった。
バースト ビヘービアーはその名の通りバースト転送のパラメータを設定するだけで、バースト転送になるかどうか?は別物なんだと思う。つまり、Cソースコードや指示子の与え方でバースト転送になるかどうか?が決まって、バースト転送になった後の設定値はバースト ビヘービアーが決めるのだと思う。

次に、

#pragma HLS INTERFACE m_axi depth=3072 port=cam_fb offset=slave bundle=cam_fb num_read_outstanding=4 max_read_burst_length=32
#pragma HLS INTERFACE m_axi depth=3072 port=lap_fb offset=slave bundle=lap_fb num_write_outstanding=4 max_write_burst_length=32

というようにバースト ビヘービアーで 32 バースト転送にしてみた。
これで、Cコードの合成、C/RTL協調シミュレーションを行ったが、結果の数値は16 バースト転送の時と同じだった。
C/RTL協調シミュレーションの波形を見たところ、ARLEN と AWLEN が 1f で 32 バースト転送になっているのが分かった。
Vivado_HLS_AXI4M_burst_16_161122.png

Vivado_HLS_AXI4M_burst_17_161122.png
  1. 2016年11月22日 04:47 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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