FC2カウンター FPGAの部屋 その他のFPGAの話題
fc2ブログ

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

FPGAの部屋

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

Bambu で hls stream インターフェースのメディアン・フィルタを高位合成する1

Bambu で hls stream インターフェースのメディアン・フィルタを高位合成してみよう。今回は、C++ ソースコードの median_hlsst_RGB24.cpp を示して、g++ コンパイラでコンパイルし、動作を確認した。

PandA-bambu-2023.1/examples ディレクトリに median_hlsst_RGB24 ディレクトリを作成した。
PandA-bambu-2023.1/examples/median_hlsst_RGB24 ディレクトリに行った。

median_hlsst_RGB24.cpp を作成した。
Bambu の hls stream インターフェースで入力と出力を行う。今回は、簡単化のため、画像をスルーで出力するモードは省いてある。
main() 関数を持っていて、そのままコンパイルが可能だ。
median_hlsst_RGB24.cpp を示す。

// median_hlsst_RGB24.cpp
// 2024/01/09 by marsee

// bmp_header.h
// BMP ファイルフォーマットから引用させて頂きました
// http://www.kk.iij4u.or.jp/~kondo/bmp/
//
// 2017/05/04 : takseiさんのご指摘によりintX_tを使った宣言に変更。takseiさんありがとうございました
//              変数の型のサイズの違いによってLinuxの64ビット版では動作しなかったためです
//              http://marsee101.blog19.fc2.com/blog-entry-3354.html#comment2808
//

#include <stdio.h>
#include <stdint.h>

// BITMAPFILEHEADER 14bytes
typedef struct tagBITMAPFILEHEADER {
    uint16_t bfType;
    uint32_t bfSize;
    uint16_t bfReserved1;
    uint16_t bfReserved2;
    uint32_t bfOffBits;
} BITMAPFILEHEADER;

// BITMAPINFOHEADER 40bytes
typedef struct tagBITMAPINFOHEADER{
    uint32_t biSize;
    int32_t biWidth;
    int32_t biHeight;
    uint16_t biPlanes;
    uint16_t biBitCount;
    uint32_t biCompression;
    uint32_t biSizeImage;
    int32_t biXPixPerMeter;
    int32_t biYPixPerMeter;
    uint32_t biClrUsed;
    uint32_t biClrImporant;
} BITMAPINFOHEADER;

typedef struct BMP24bitsFORMAT {
    uint8_t blue;
    uint8_t green;
    uint8_t red;
} BMP24FORMAT;

// medain_axis_RGB24.cpp
// 2024/01/09 by marsee
//

#include <cstdint>
#include <stdint.h>
#include <ap_int.h>
#include <hls_stream.h>

constexpr int size = 3;

struct pix_st{
    uint32_t pix;
    uint32_t index;
};

const char BMP_FILE_NAME[] = "test2.bmp";
const char MEDIAN_FILE_NAME[] = "median.bmp";

void median_fil(ap_int<32> (&pix_mat)[size][size], ap_uint<24> &result);
void pixel_sort(pix_st *y);
ap_uint<32> conv_rbg2y(ap_uint<32> rbg);

int median_hlsst_RGB24(hls::stream<ap_uint<24> >& ins,
        hls::stream<ap_uint<24> >& outs,
         int32_t row_size, int32_t col_size){
    ap_uint<24> pix;
    ap_uint<24> median;
    ap_uint<24> val;

    ap_int<32> line_buf[2][1920];
    ap_int<32> pix_mat[size][size];

    LOOP_Y: for(int y=0; y<row_size; y++){
        LOOP_X: for(int x=0; x<col_size; x++){
            pix = ins.read(); // AXI4-Stream からの入力

            LOOP_PIX_MAT_K: for(int k=0; k<3; k++){
                LOOP_PIX_MAT_M: for(int m=0; m<2; m++){
                    pix_mat[k][m] = pix_mat[k][m+1];
                }
            }
            pix_mat[0][2] = line_buf[0][x];
            pix_mat[1][2] = line_buf[1][x];
            ap_int<32> y_val = pix;
            pix_mat[2][2] = y_val;

            line_buf[0][x] = line_buf[1][x];    // 行の入れ替え
            line_buf[1][x] = y_val;

            median_fil(pix_mat, val);
            median = val;
            if(x<2 || y<2)
                median = 0;

            outs.write(median);
        }
    }
    return(0);
}

// median filter
//
// x0y0 x1y0 x2y0
// x0y1 x1y1 x2y1
// x0y2 x1y2 x2y2
//
void median_fil(ap_int<32> (&pix_mat)[size][size], ap_uint<24> &result){
    pix_st pixst[size*size];
    uint32_t index;

    for(int i=0; i<size*size; i++){
        pixst[i].pix = (uint32_t)conv_rbg2y(pix_mat[i/size][i%size]);
        pixst[i].index = i;
    }

    pixel_sort(pixst);
    
    index = pixst[4].index; // 中央値
    result = (ap_uint<24>)pix_mat[index/size][index%size];
}

// pixel_sort()
// bubble sort
// ”メジアン(中央値)、範囲(レンジ)、ヒストグラムを求める”参照
// https://cgengo.sakura.ne.jp/arg04.html
void pixel_sort(pix_st *y){
#pragma HLS ARRAY_PARTITION variable=y dim=1 complete
    pix_st tmp;

    for(int i=1; i<size*size; i++){
        for(int j=0; j<size*size-i; j++){
            if(y[j].pix < y[j+1].pix){
                tmp = y[j];
                y[j] = y[j+1];
                y[j+1] = tmp;
            }
        }
    }
}

// RBGからYへの変換
// RBGのフォーマットは、{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 にした
ap_uint<32> conv_rbg2y(ap_uint<32> rbg){
    ap_uint<32> r, g, b, y_f;
    ap_uint<32> y;

    b = rbg & 0xff;
    g = (rbg>>8) & 0xff;
    r = (rbg>>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);
}

int main(){
    hls::stream<ap_uint<24>> ins, outs;
    BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
    BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
    FILE *fbmpr, *fbmpw, *fbmpwf;
    uint32_t *rd_bmp, *hw_median;
    uint32_t blue, green, red;
    uint32_t pix, val;

    if ((fbmpr = fopen(BMP_FILE_NAME, "rb")) == NULL){ // BMP ファイル をオープン
        fprintf(stderr, "Can't open %s by binary read mode\n", BMP_FILE_NAME);
        exit(1);
    }
    // bmpヘッダの読み出し
    fread(&bmpfhr.bfType, sizeof(uint16_t), 1, fbmpr);
    fread(&bmpfhr.bfSize, sizeof(uint32_t), 1, fbmpr);
    fread(&bmpfhr.bfReserved1, sizeof(uint16_t), 1, fbmpr);
    fread(&bmpfhr.bfReserved2, sizeof(uint16_t), 1, fbmpr);
    fread(&bmpfhr.bfOffBits, sizeof(uint32_t), 1, fbmpr);
    fread(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpr);

    // ピクセルを入れるメモリをアロケートする
    if ((rd_bmp =(uint32_t *)malloc(sizeof(uint32_t) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
        fprintf(stderr, "Can't allocate rd_bmp memory\n");
        exit(1);
    }
    if ((hw_median =(uint32_t *)malloc(sizeof(uint32_t) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
        fprintf(stderr, "Can't allocate hw_median memory\n");
        exit(1);
    }

    // rd_bmp にBMPのピクセルを代入。その際に、行を逆転する必要がある
    for (int y=0; y<bmpihr.biHeight; y++){
        for (int x=0; x<bmpihr.biWidth; x++){
            blue = fgetc(fbmpr);
            green = fgetc(fbmpr);
            red = fgetc(fbmpr);
            rd_bmp[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] = (blue & 0xff) | ((green & 0xff)<<8) | ((red & 0xff)<<16);
        }
    }
    fclose(fbmpr);
        
    // ins に入力データを用意する
    for(int j=0; j < bmpihr.biHeight; j++){
        for(int i=0; i < bmpihr.biWidth; i++){
            pix = (uint32_t)rd_bmp[(j*bmpihr.biWidth)+i];
            ins.write((ap_uint<24>)pix);
        }
    }
    
    median_hlsst_RGB24(ins, outs, bmpihr.biHeight, bmpihr.biWidth); // メディアン・フィルタ
    
    // メディアン・フィルタ処理後の値をhw_medianバッファに代入
    for (int y=0; y<bmpihr.biHeight; y++){ // 結果の画像サイズはx-2, y-2
        for (int x=0; x<bmpihr.biWidth; x++){
            val = (uint32_t)outs.read();
            hw_median[y*bmpihr.biWidth+x] = val;
        }
    }
    
    // 元画像の出力結果を temp_org.bmp へ出力する
    if ((fbmpw=fopen(MEDIAN_FILE_NAME, "wb")) == NULL){
        fprintf(stderr, "Can't open %s by binary write mode\n", MEDIAN_FILE_NAME);
        exit(1);
    }
    // BMPファイルヘッダの書き込み
    fwrite(&bmpfhr.bfType, sizeof(uint16_t), 1, fbmpw);
    fwrite(&bmpfhr.bfSize, sizeof(uint32_t), 1, fbmpw);
    fwrite(&bmpfhr.bfReserved1, sizeof(uint16_t), 1, fbmpw);
    fwrite(&bmpfhr.bfReserved2, sizeof(uint16_t), 1, fbmpw);
    fwrite(&bmpfhr.bfOffBits, sizeof(uint32_t), 1, fbmpw);
    fwrite(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpw);

    // RGB データの書き込み、逆順にする
    for (int y=0; y<bmpihr.biHeight; y++){
        for (int x=0; x<bmpihr.biWidth; x++){
            blue = hw_median[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] & 0xff;
            green = (hw_median[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] >> 8) & 0xff;
            red = (hw_median[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x]>>16) & 0xff;

            fputc(blue, fbmpw);
            fputc(green, fbmpw);
            fputc(red, fbmpw);
        }
    }
    fclose(fbmpw);
    free(rd_bmp);
    free(hw_median);
    
    return(0);
}


median_hlsst_RGB24.cpp を g++ コンパイラでコンパイルした。
g++ -o median_hlsst_RGB24 -I/media/masaaki/Ubuntu_Disk/PandA-bambu-2023.1/etc/libbambu/ac_types/include median_hlsst_RGB24.cpp
bambu_185_240110.png

median_hlsst_RGB24 実行形式ファイルが生成された。

ノイズ入りの test2.bmp ファイルを用意した。
bambu_186_240110.jpg

median_hlsst_RGB24 を実行した。
./median_hlsst_RGB24
bambu_187_240110.png

median.bmp ファイルが生成された。
bambu_188_240110.png

median.bmp を見ると、ノイズが除去されているのが分かる。
bambu_189_240110.jpg
  1. 2024年01月10日 03:50 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:0

BAMBU TUTORIAL をやってみよう7(led_exampls 編2)

BAMBU TUTORIAL をやってみよう6(led_exampls 編1)”の続き。

BAMBU TUTORIAL”をやってみようということで、前回は、exmaples/led_example のファイルを解説した。今回は、”BAMBU TUTORIAL”に従って、”5.1) Mapping C functions to hand-written HDL modules”の最初のコマンドを実行したところ、IPs.xml がエラーになった。色々とやってみたが、エラーが解消されなかった。諦めて、synthesize_NEXYS4.sh のシミュレータを ModelSim から Verilator に変更して、実行すると実行することができた。

BAMBU TUTORIAL”の”5.1) Mapping C functions to hand-written HDL modules”をやってみよう。

led_example の下に tutorial ディレクトリを作成し、bambu を実行する。
mkdir tutorial
cd tutorial
bambu ../led_example.c --top-fname=led_example ../IPs.xml

エラーになった。
エラー内容は”error -> Error during technology file parsing: error -> Error in opening ../IPs.xml”だった。
bambu_61_231219.png

いろいろやってみたがエラーが解消されなかった。
そこで、led_exsample ディレクトリに行って synthesize_NEXYS4.sh を実行したところ、ModelSim が無いというエラーだった。

error -> Mentor Modelsim was not detected by Bambu. Please check --mentor-root option is correct.


synthesize_NEXYS4.sh を編集し、シミュレータを ModelSim から VERILATOR に変更した。
bambu_70_231219.png

もう一度、synthesize_NEXYS4.sh を実行したところ成功した。
./synthesize_NEXYS4.sh
bambu_62_231219.png

bambu_63_231219.png

実行ログを示す。

(base) masaaki@masaaki-H110M4-M01:/media/masaaki/Ubuntu_Disk/PandA-bambu-2023.1/examples/led_example$ ./synthesize_NEXYS4.sh 
 ==  Bambu executed with: /tmp/.mount_bambu9RNwSA/usr/bin/bambu --top-fname=led_example --backend-sdc-extensions=/media/masaaki/Ubuntu_Disk/PandA-bambu-2023.1/examples/led_example/Nexys4_Master.sdc -O3 --device-name=xc7a100t-1csg324-VVD --clock-period=10 --C-no-parse=/media/masaaki/Ubuntu_Disk/PandA-bambu-2023.1/examples/led_example/sw_ctrl.c,/media/masaaki/Ubuntu_Disk/PandA-bambu-2023.1/examples/led_example/leds_ctrl.c,/media/masaaki/Ubuntu_Disk/PandA-bambu-2023.1/examples/led_example/btn_ctrl.c,/media/masaaki/Ubuntu_Disk/PandA-bambu-2023.1/examples/led_example/sevensegments_ctrl.c --file-input-data=/media/masaaki/Ubuntu_Disk/PandA-bambu-2023.1/examples/led_example/leds_ctrl.v,/media/masaaki/Ubuntu_Disk/PandA-bambu-2023.1/examples/led_example/sw_ctrl.v,/media/masaaki/Ubuntu_Disk/PandA-bambu-2023.1/examples/led_example/btn_ctrl.v,/media/masaaki/Ubuntu_Disk/PandA-bambu-2023.1/examples/led_example/sevensegments_ctrl.v --simulator=VERILATOR --evaluation=PERIOD,AREA,FREQUENCY,CLOCK_SLACK,REGISTERS,DSPS,BRAMS --print-dot /media/masaaki/Ubuntu_Disk/PandA-bambu-2023.1/examples/led_example/led_example.c /media/masaaki/Ubuntu_Disk/PandA-bambu-2023.1/examples/led_example/constraints_STD.xml /media/masaaki/Ubuntu_Disk/PandA-bambu-2023.1/examples/led_example/IPs.xml 


********************************************************************************
                    ____                  _
                   | __ )  __ _ _ __ ___ | |_   _   _
                   |  _ \ / _` | '_ ` _ \| '_ \| | | |
                   | |_) | (_| | | | | | | |_) | |_| |
                   |____/ \__,_|_| |_| |_|_.__/ \__,_|

********************************************************************************
                         High-Level Synthesis Tool

                         Politecnico di Milano - DEIB
                          System Architectures Group
********************************************************************************
                Copyright (C) 2004-2023 Politecnico di Milano
 Version: PandA 2023.1 - Revision 04336c437a53bc96ae90b74052c455629946ec8b-main

Target technology = FPGA

  Functions to be synthesized:
    led_example


  Memory allocation information:
    BRAM bitsize: 8
    Spec may not exploit DATA bus width
    All the data have a known address
    Internal data is not externally accessible
    DATA bus bitsize: 8
    ADDRESS bus bitsize: 6
    SIZE bus bitsize: 4
    ALL pointers have been resolved
    Internally allocated memory (no private memories): 0
    Internally allocated memory: 10
  Time to perform memory allocation: 0.00 seconds


  Memory allocation information:
    BRAM bitsize: 8
    Spec may not exploit DATA bus width
    All the data have a known address
    Internal data is not externally accessible
    DATA bus bitsize: 8
    ADDRESS bus bitsize: 6
    SIZE bus bitsize: 4
    ALL pointers have been resolved
    Internally allocated memory (no private memories): 0
    Internally allocated memory: 10
  Time to perform memory allocation: 0.00 seconds


  Module allocation information for function led_example:
    Number of complex operations: 9
    Number of complex operations: 9
  Time to perform module allocation: 0.06 seconds


  Scheduling Information of function led_example:
    Number of control steps: 13
    Minimum slack: 0.26039997899991063
    Estimated max frequency (MHz): 102.67362087188845
  Time to perform scheduling: 0.06 seconds


  State Transition Graph Information of function led_example:
    Number of states: 11
    Done port is registered
  Time to perform creation of STG: 0.02 seconds


  Easy binding information for function led_example:
    Bound operations:134/282
  Time to perform easy binding: 0.00 seconds


  Storage Value Information of function led_example:
    Number of storage values inserted: 41
  Time to compute storage value information: 0.00 seconds

  Slack computed in 0.00 seconds
  Weight computation completed in 0.00 seconds
  False-loop computation completed in 0.00 seconds

  Register binding information for function led_example:
    Register allocation algorithm obtains a sub-optimal result: 37 registers(LB:17)
  Time to perform register binding: 0.00 seconds

  Clique covering computation completed in 0.00 seconds

  Module binding information for function led_example:
    Number of modules instantiated: 279
    Number of performance conflicts: 35
    Estimated resources area (no Muxes and address logic): 4518
    Estimated area of MUX21: 69
    Total estimated area: 4587
    Estimated number of DSPs: 0
  Time to perform module binding: 0.01 seconds


  Register binding information for function led_example:
    Register allocation algorithm obtains a sub-optimal result: 37 registers(LB:17)
  Time to perform register binding: 0.00 seconds


  Connection Binding Information for function led_example:
    Number of allocated multiplexers (2-to-1 equivalent): 7
  Time to perform interconnection binding: 0.00 seconds

  Total number of flip-flops in function led_example: 433
  Clock period             : 10
  Design minimum period    : 7.3090000000000002
  Slices                   : 112
  Luts                     : 222
  Lut FF Pairs             : 110
  Power                    : 0.106
  Frequency                : 136.81762210972772
  Design slack             : 2.6909999999999998
  Registers                : 298
  DSPs                     : 0
  BRAMs                    : 0


led_example_synth ディレクトリが生成されて、led_example.xpr つまり、Vivado のプロジェクト・ファイルが生成されていた。
bambu_64_231219.png
  1. 2023年12月19日 05:32 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:0

FPGAの部屋のまとめサイトの更新(2023年11月24日)

FPGAの部屋のまとめサイト”を更新しました。
2023年11月23日までの記事をまとめました。
  1. 2023年11月24日 06:44 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:0

FPGAの部屋のまとめサイトの更新(2023年8月22日)

FPGAの部屋のまとめ サイト”を更新しました。
8月22日までの記事をまとめました。
  1. 2023年08月22日 05:20 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:0

FPGAの部屋のまとめサイトの更新(2023年5月21日)

FPGAの部屋のまとめ サイト”を更新しました。
ZUBoard 1CG”のエントリを追加して、2023 年 5 月 21 日までの記事をまとめました。
  1. 2023年05月21日 05:34 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:0

FPGAの部屋のまとめサイトの更新(2023年3月28日)

FPGAの部屋のまとめサイトを更新しました。
2023 年 3 月 27 日までの記事をまとめました。
  1. 2023年03月28日 04:29 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:0

FPGAの部屋のまとめサイトの更新(2022年12月26日)

FPGAの部屋のまとめサイトを更新しました。
KR260 カテゴリを追加して、その他の記事をまとめました。
  1. 2022年12月26日 03:22 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:0
»