FC2カウンター FPGAの部屋

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

FPGAの部屋

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

「Vivado HLS で DMA Read IP を作る2(絶対アドレス指定版)」を使って合成後の機能シミュレーション

Vivado HLS で DMA Read IP を作る2(絶対アドレス指定版)”の続き。

前回は絶対アドレス指定のDMA Read IPをVivado HLS 2016.4 で作成した。今回は、そのDMA Read IPをVivado で論理シミュレーションと合成後の機能シミュレーションを行った。

前回やったときの記事は、”DMA Read IP を単体でシミュレーション3(DMA Read IP単体で論理合成後にシミュレーション)

このプロジェクトを使用した。
DMA_Read_IP_9_170316.png

ただし新しく生成した DMA Read IPに入れ替えてある。それに、DMA Read IPのレジスタ設定を行う reg_write_read IP が一度設定を終了しても、また設定を繰り返し行っていたので、修正を行った。上に示す図は論理合成が終了している。
論理合成後のレポートを示す。
DMA_Read_IP_10_170316.png

IOポートはすべて割り振られている。これで論理合成後の機能シミュレーションは問題ない。しかし、IOがオーバーフローしていても論理合成後の機能シミュレーションがうまく行くのかもしれない?確実に動作する回路で試していないので、よくわからない?

ブロックデザインを示す。
DMA_Read_IP_11_170316.png

DMA Read IPとAXI Interconnect 2つだけのシンプルな構成だ。

Address Editor を示す。
DMA_Read_IP_12_170316.png

テストベンチとして、DMA Read IPのレジスタを設定する reg_write_read IP と AXI4 Slave BFM をメモリとして接続している。そのブロック図を下に示す。
DMA_Read_IP_13_170316.png

さて次に、論理シミュレーションを行う。
Flow Navigator の Simulation -> Run Simulation -> Run Behavioral Simulation を選択する。
DMA_Read_IP_14_170316.png

論理シミュレーション結果の全体波形を示す。
DMA_Read_IP_15_170316.png
波形1

DMA_Read_IP_17_170316.png
波形2

波形の数が多いので、2つの画像になってしまった。最初の画像は主にDMA Read IPのAXI4 Master Read アクセスが表示されている。2つ目の波形には、DMA Read IPのレジスタを設定するAXI4-Lite Slave アクセスとAXI4-Stream 出力が表示されている。

最初の波形を拡大してみよう。
DMA_Read_IP_16_170316.png
波形3

バーストに1クロックの Wait はあるがほとんどフルバーストでAXI4 Master Read が行われている。

次に、DMA Read IPを設定するのレジスタを設定するAXI4-Lite Slave アクセスを下に示す。
DMA_Read_IP_18_170316.png
波形4

まずは、DMA Read IPのレジスタマップを示す。

//------------------------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 frame_buffer0
//        bit 31~0 - frame_buffer0[31:0] (Read/Write)
// 0x1c : reserved
// 0x20 : Data signal of frame_buffer1
//        bit 31~0 - frame_buffer1[31:0] (Read/Write)
// 0x24 : reserved
// 0x28 : Data signal of frame_buffer2
//        bit 31~0 - frame_buffer2[31:0] (Read/Write)
// 0x2c : reserved
// 0x30 : Data signal of mode_V
//        bit 0  - mode_V[0] (Read/Write)
//        others - reserved
// 0x34 : reserved
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)


レジスタを設定する reg_write_read IP の設定を示す。

// reg_write_read.h
// 2016/06/10 by marsee
//
// reg_addr_data フォーマット、
// 第1フィールド(reg_ad[x][0]):Write - 0, Read - 1
// 第2フィールド(reg_ad[x][1]):Delay、単位はクロック数
// 第3フィールド(reg_ad[x][2]):アドレス、16進数
// 第4フィールド(reg_ad[x][3]):データ、16進数
//
// 終了は第2フィールド:Delayに 0xffffffff が書いてあったとき

#define AD_ARRAY_LIMIT 256
#define REG_WRITE 0
#define REG_READ 1

#define R_W_FIELD 0
#define DELAY_FIELD 1
#define ADDRESS_FIELD 2
#define DATA_FIELD 3

const unsigned int reg_ad[AD_ARRAY_LIMIT][4]={
        {000x44A00018, 0x10000000},
        {000x44A00020, 0x10000000},
        {000x44A00028, 0x10000000},
        {000x44A00030, 0},
        {100x44A00000, 0},
        {000x44A00000, 1},
        {00xfffffffe, 00},
        {00xffffffff, 00},


つまり、0x44A00018、0x44A00020、0x44A00028 に 0x10000000 を書いているが、3つのフレームバッファのアドレスを書いている。
0x44A00030 でDMA Read IPのモードを書いている。 0 なので、DMA_WRITE_MODE だ。
0x44A00000 をRead してから、0x44A00000 に 1 を書いてDMA Read IPをスタートさせている。

DMA Read IPのAXI4-Stream 出力の波形を示す。
DMA_Read_IP_19_170316.png
波形5

前に示した全体波形では、outs_tlast が時々 1 変化していたのが見えたと思うが、画像フレームのスタート時には、outs_tuser が 1 クロック間だけ 1 となっているのがわかる。
と言う訳で完全に動作しているようだ。

次に、論理合成後の機能シミュレーションを行う。
Flow Navigator の Simulation -> Run Simulation -> Run Post-Synthesis Functional Simulation を選択する。

Post-Synthesis Functional Simulation での全体波形を示す。
DMA_Read_IP_21_170316.png
波形6

DMA_Read_IP_22_170316.png
波形7

やはり、Post-Synthesis Functional Simulation で波形が出てこない。

DMA Read IPのレジスタを設定するAXI4-Lite Slave アクセスを拡大してみよう。
DMA_Read_IP_23_170316.png
波形8

こちらは問題ないようだ。
  1. 2017年03月17日 05:32 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS で DMA Read IP を作る2(絶対アドレス指定版)

Vivado HLS で DMA Read IP を作る(絶対アドレス指定版)”の続き。

Vivado HLS で DMA Read IP を作る(絶対アドレス指定版)”では、DMA Read IPを作成したが、”Vivado HLSで作ったDMA Read IP を実機でテスト1(動作しない)”で実機で動作を確認しても動作しなかった。
DMA Read IP を単体でシミュレーション3(DMA Read IP単体で論理合成後にシミュレーション)”では、DMA Read IPを単体でシミュレーションしたが、論理シミュレーションはそれらしく動いても Post-Synthesis Fuctional Simulation では、動作しないという問題があった。これは、IOがオーバーフローしているからかもしれないということで、Vivado 2016.4 でテストしてすることにした。

DMA_Read_Addr_Virtex を示す。シミュレーション用のVivado 2016.4 プロジェクトを論理合成したときに、IOがオーバーフローしないように、Virtex7 の xc7vx980tffg1928-2 を使用している。
DMA_Read_IP_1_170316.png

なお、”Vivado HLS で DMA Read IP を作る(絶対アドレス指定版)”では、3フレームを一度に処理していたのだが、今回は、1フレーム分の処理に変更した。

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

dma_result0.bmp を見ると正常に「A」の文字が見える。

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

Latency は 3083 クロックで、64 ピクセル x 48 行の「A」という画像の総ピクセル値 3072 から 11 クロックしか離れていないので、ほぼ 1 クロックで 1 ピクセルを処理することができている。

C/RTL協調シミュレーションを行ったところ、エラーになってしまった。
DMA_Read_IP_4_170316.png

「ERROR: [COSIM 212-4] *** C/RTL co-simulation finished: FAIL ***」を調べると、”AR# 61063 Vivado HLS 2014.2 : C/RTL 協調シミュレーションに関する問題を調査するためのデバッグ ガイド”が見つかった。そこに”Vivado HLS: Debug Guide for investigating C/RTL co-simulation issues”のリンクがあった。Vivado HLS: Debug Guide for investigating C/RTL co-simulation issuesを見ても原因はよくわからない?

IP 化を行った。
Vivado RTL Synthesis にチェックを入れた。
DMA_Read_IP_5_170316.png

結果を示す。
DMA_Read_IP_6_170316.png

Resource Usage のLUT が合成結果(1269 ) の半分程度の 695 になっている。ロジックが消されている恐れがある。

今までは、テスト用の64 ピクセル x 48 行の「A」という画像でやっていたので、800 ピクセル x 600 行の実際に処理する画像用に値を切り替えた。
もう一度、C コードの合成を行った。
DMA_Read_IP_7_170316.png

IP 化を行った。やはり LUT は合成時の約半分になっている。
DMA_Read_IP_8_170316.png

DMA_Read.h を示す。

// DMA_Read.h
// 2016/07/14 by marsee
// 2016/09/18 : BURST_LENGTH を追加
//

#ifndef __DMA_READ_H__
#define __DMA_READ_H__

#define HORIZONTAL_PIXEL_WIDTH    800
#define VERTICAL_PIXEL_WIDTH    600

//#define HORIZONTAL_PIXEL_WIDTH    64
//#define VERTICAL_PIXEL_WIDTH    48

#define ALL_PIXEL_VALUE    (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)

#define MAX_FRAME_NUMBER    3

#define DMA_WRITE_MODE    0
#define FREE_RUN_MODE    1

#define MEMCPY_LENGTH    (HORIZONTAL_PIXEL_WIDTH*4)

#endif


DMA_Read_addr.cpp を示す。

// DMA_Read_addr.cpp
// 2016/07/13 by marsee
//
// frame_buffer0, frame_buffer1, frame_buffer2 には3つのフレームバッファのアドレスを入れる
// mode = 0 : DMA Write IP の active_frame を見て、その1つ前のフレームをDMA Readするモード(DMA_WRITE_MODE)
// mode = 1 : フリーラン モード(FREE_RUN_MODE)
//
// 2017/03/15 : 1フレーム分のDMAに変更
//

#include <stdio.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>

#include "DMA_Read.h"

int DMA_Read_addr(volatile int *in, hls::stream<ap_axis<32,1,1,1> >& outs,
        unsigned int frame_buffer0, unsigned int frame_buffer1,
        unsigned int frame_buffer2, ap_uint<2> & active_frame,
        ap_uint<1> mode){
#pragma HLS INTERFACE s_axilite port=mode
#pragma HLS INTERFACE ap_none register port=active_frame
#pragma HLS INTERFACE s_axilite port=frame_buffer0
#pragma HLS INTERFACE s_axilite port=frame_buffer1
#pragma HLS INTERFACE s_axilite port=frame_buffer2
#pragma HLS INTERFACE m_axi depth=3072 port=in offset=off
#pragma HLS INTERFACE axis port=outs
#pragma HLS INTERFACE s_axilite port=return

    ap_axis<32,1,1,1> pix;
    int dma_index;
    static int n = 0;

    if (mode == DMA_WRITE_MODE){
        n = (int)active_frame;
    }else{
        n++;
        if (n > 2)
            n = 0;
    }

    switch (n){ // 1つ前のフレームバッファを読みだす
        case 0 :
            dma_index = frame_buffer2/sizeof(int);
            break;
        case 1 :
            dma_index = frame_buffer0/sizeof(int);
            break;
        case 2 :
            dma_index = frame_buffer1/sizeof(int);
            break;
        default :
            dma_index = frame_buffer0/sizeof(int);
            break;
    }

    for (int y=0; y<VERTICAL_PIXEL_WIDTH; y++){
        for (int x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
#pragma HLS PIPELINE II=1
            pix.data = in[dma_index+(y*HORIZONTAL_PIXEL_WIDTH)+x];

            if (y==0 && x==0)
                pix.user = 1;
            else
                pix.user = 0;

            if (x == (HORIZONTAL_PIXEL_WIDTH-1))
                pix.last = 1;
            else
                pix.last = 0;

            outs << pix;
        }
    }

    return 0;
}


DMA_Read_addr_tb.cpp を示す。

// DMA_Read_addr_tb.cpp
// 2016/07/15 by marsee
// 2017/03/16 : 3フレーム処理から1フレーム処理に変更
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <iostream>
#include <fstream>
#include <ap_axi_sdata.h>

#include "DMA_Read.h"
#include "bmp_header.h"

int DMA_Read_addr(volatile int *in, hls::stream<ap_axis<32,1,1,1> >& outs,
        unsigned int frame_buffer0, unsigned int frame_buffer1,
        unsigned int frame_buffer2,  ap_uint<2> & active_frame,
        ap_uint<1> mode);

int main()
{
    using namespace std;

    hls::stream<ap_axis<32,1,1,1> > outs_dummy;
    hls::stream<ap_axis<32,1,1,1> > outs;
    ap_axis<32,1,1,1> pix;
    ap_axis<32,1,1,1> vals, vals_dummy;

    BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
    BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
    FILE *fbmpr, *fbmpw;
    int *rd_bmp, *hw_lapd;
    int blue, green, red;
    ap_uint<2> active_frame = 0;
    int *frame_buffer;

    if ((fbmpr = fopen("test.bmp""rb")) == NULL){ // test.bmp をオープン
    //if ((fbmpr = fopen("road_1.bmp", "rb")) == NULL){ // test.bmp をオープン
        fprintf(stderr, "Can't open test.bmp by binary read mode\n");
        exit(1);
    }
    // bmpヘッダの読み出し
    fread(&bmpfhr.bfType, sizeof(char), 2, fbmpr);
    fread(&bmpfhr.bfSize, sizeof(long), 1, fbmpr);
    fread(&bmpfhr.bfReserved1, sizeof(short), 1, fbmpr);
    fread(&bmpfhr.bfReserved2, sizeof(short), 1, fbmpr);
    fread(&bmpfhr.bfOffBits, sizeof(long), 1, fbmpr);
    fread(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpr);

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

    int *buf;
    if ((buf =(int *)malloc(3 * sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
        fprintf(stderr, "Can't allocate buf 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);

    // frame buffer をアロケートする、3倍の領域を取ってそれを3つに分ける
    if ((frame_buffer =(int *)malloc(MAX_FRAME_NUMBER * sizeof(int) * (bmpihr.biWidth * bmpihr.biHeight))) == NULL){
        fprintf(stderr, "Can't allocate frame_buffer0 ~ 2\n");
        exit(1);
    }

    // 3 つのフレームバッファにそれぞれ'A' を入力する(1つに変更)
    memcpy(frame_buffer, rd_bmp, bmpihr.biHeight * bmpihr.biWidth * sizeof(int));

    memcpy((int *)((unsigned int)frame_buffer + bmpihr.biHeight * bmpihr.biWidth * sizeof(int)),
        rd_bmp, bmpihr.biHeight * bmpihr.biWidth * sizeof(int));

    memcpy((int *)((unsigned int)frame_buffer + 2 * bmpihr.biHeight * bmpihr.biWidth * sizeof(int)),
        rd_bmp, bmpihr.biHeight * bmpihr.biWidth * sizeof(int));

    DMA_Read_addr((volatile int *)0, outs_dummy, (unsigned int)frame_buffer,
        (unsigned int)frame_buffer+(bmpihr.biWidth * bmpihr.biHeight * sizeof(int)),
        (unsigned int)frame_buffer+(2 * (bmpihr.biWidth * bmpihr.biHeight) * sizeof(int)),
        active_frame, DMA_WRITE_MODE);

    DMA_Read_addr((volatile int *)0, outs, (unsigned int)frame_buffer,
        (unsigned int)frame_buffer+(bmpihr.biWidth * bmpihr.biHeight * sizeof(int)),
        (unsigned int)frame_buffer+(2 * (bmpihr.biWidth * bmpihr.biHeight) * sizeof(int)),
        active_frame, FREE_RUN_MODE);

    // outs ストリームのデータを buf に入力する
    //for (int k=0; k<3; k++){
        int k = 0;
        for(int j=0; j < bmpihr.biHeight; j++){
            for(int i=0; i < bmpihr.biWidth; i++){
                outs >> vals;
                outs_dummy >> vals_dummy;
                ap_int<32> val = vals.data;
                buf[(k*bmpihr.biWidth*bmpihr.biHeight)+(j*bmpihr.biWidth)+i] = (int)val;
            }
        }
    //}

    // DMAされたデータをBMPフィルに書き込む
    char output_file[] = "dma_result0.bmp";
    //for (int i=0; i<MAX_FRAME_NUMBER; i++){
        int i=0;
        switch (i){
            case 0:
                strcpy(output_file,"dma_result0.bmp");
                break;
            case 1:
                strcpy(output_file,"dma_result1.bmp");
                break;
            case 2:
                strcpy(output_file,"dma_result2.bmp");
                break;
        }
        if ((fbmpw=fopen(output_file, "wb")) == NULL){
            fprintf(stderr, "Can't open %s by binary write mode\n", output_file);
            exit(1);
        }
        // BMPファイルヘッダの書き込み
        fwrite(&bmpfhr.bfType, sizeof(char), 2, fbmpw);
        fwrite(&bmpfhr.bfSize, sizeof(long), 1, fbmpw);
        fwrite(&bmpfhr.bfReserved1, sizeof(short), 1, fbmpw);
        fwrite(&bmpfhr.bfReserved2, sizeof(short), 1, fbmpw);
        fwrite(&bmpfhr.bfOffBits, sizeof(long), 1, fbmpw);
        fwrite(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpw);

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

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

  1. 2017年03月16日 05:17 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

BNN-PYNQをアップグレード

BNN-PYNQが頻繁に変更されているので、PYNQボードのBNN-PYNQをアップグレードした。

ネットで検索したところ、アップグレードは pip install --upgrade で良いそうだ。
sudo pip3.6 install --upgrade git+https://github.com/Xilinx/BNN-PYNQ.git
コマンドを実行した。
BNN-PYNQ_37_170314.png

~/jupyter_notebooks/bnn を見てみると、更新されていたが日時がおかしい。
BNN-PYNQ_38_170314.png

date コマンドで見てみると、UTC だった。これなら仕方ないがJST に修正しよう。
sudo ln -sf /usr/share/zoneinfo/Japan /etc/localtime
これで、JST に変更できた。
BNN-PYNQ_39_170314.png
  1. 2017年03月14日 04:15 |
  2. PYNQ
  3. | トラックバック:0
  4. | コメント:0

XilinxのBNN-PYNQをやってみる4(Hardware design rebuilt 2)

XilinxのBNN-PYNQをやってみる3(Hardware design rebuilt 1)”の続き。

前回は、BNN-PYNQの cnv-pynq をHardware design rebuilt したので、今回はもう1つの lfc-pynq をHardware design rebuilt してみよう。

最初に、BNN-PYNQ/bnn/src/network ディレクトに cd した。
cd /home/masaaki/BNN-PYNQ/bnn/src/network

もうすでにXILINX_BNN_ROOT 環境変数はセットしてある。
export XILINX_BNN_ROOT=/home/masaaki/BNN-PYNQ/bnn/src/

BNN-PYNQ/bnn/src/network ディレクトリの make_hw.sh を実行して、lfc-pynq のVivado HLS プロジェクトとVivado プロジェクトを生成する。
./make-hw.sh lfc-pynq pynq a
BNN-PYNQ_29_170312.png

すると、前回と同様に/home/masaaki/BNN-PYNQ/bnn/src/network/output ディレクトリのbitstream, hls-syn, report, vivado の各ディレクトリに lfc-pynq ディレクトリができていた。
BNN-PYNQ_30_170312.png

lfc-pynq のVivado HLS 2016.4 プロジェクトを開いた。
BNN-PYNQ_31_170312.png

合成レポートを示す。やはり、Target が 5.00 ns でEstimated が 7.90 ns だった。
BNN-PYNQ_32_170312.png

リソース使用量は cnv-pynq の方が、lfc-pynq よりも多かった。

次に、lfc-pynq のVivado 2016.4 プロジェクトを示す。
BNN-PYNQ_33_170313.png

レポートを示す。
BNN-PYNQ_36_170313.png

タイミングはメットしていた。

procsys ブロックデザインを示す。前回と同じだと思う。
BNN-PYNQ_34_170313.png

Address Editor を示す。
BNN-PYNQ_35_170313.png
  1. 2017年03月13日 05:06 |
  2. PYNQ
  3. | トラックバック:0
  4. | コメント:0

XilinxのBNN-PYNQをやってみる3(Hardware design rebuilt 1)

XilinxのBNN-PYNQをやってみる2(jupyter notebook)”の続き。

Ubuntu16.04にVivado 2016.4をインストール”でVirtualBoxに新しいVirtualマシンを作って、Ubuntu 16.04 をインストールして、Vivado 2016.4 をインストールできたので、やっとBNN-PYNQのHardware design rebuilt がやれる環境が整った。それで、BNN-PYNQのHardware design rebuilt をやってみることにした。今回はcnv-pynq をやってみた。

BNN-PYNQ は、短い期間でアップデートされているので、GitHub からZIP ファイルをダウンロードするとアップデートするのが難しくなるので、git clone することにした。新しいUbuntu 16.04 上にBNN-PYNQ を git clone した。
git clone https://github.com/Xilinx/BNN-PYNQ.git
BNN-PYNQ_19_170311.png

これで、ホームディレクトリ上にBNN-PYNQ がクローンされた。

次に、BNN-PYNQのREADME.md のHardware design rebuilt を参照しながら、cnv-pynq のVivado HLS プロジェクトとVivado プロジェクトを生成する。

最初に、BNN-PYNQ/bnn/src/network ディレクトに cd した。
cd /home/masaaki/BNN-PYNQ/bnn/src/network

XILINX_BNN_ROOT 環境変数にBNN-PYNQ/bnn/src/ をセットする。
export XILINX_BNN_ROOT=/home/masaaki/BNN-PYNQ/bnn/src/

BNN-PYNQ/bnn/src/network ディレクトリの make_hw.sh を実行して、cnv-pynq のVivado HLS プロジェクトとVivado プロジェクトを生成する。
./make-hw.sh cnv-pynq pynq a

長い時間がかかったが、cnv-pynq のVivado HLS プロジェクトとVivado プロジェクトを生成することができた。その結果のディレクトリとファイルを示す。
BNN-PYNQ_20_170312.png

BNN-PYNQ/bnn/src/network ディレクトリの下に、output ディレクトリができて、その下に bitstream, hls-syn, report, vivado ディレクトリができていた。
hls-syn ディレクトリの下の cnv-pynq-pynq の下には、Vivado HLS のプロジェクトが生成されていた。
vivado ディレクトリの下の cnv-pynq-pynq の下には、Vivado のプロジェクトが生成されていた。

さっそく、Vivado HLS 2016.4 を立ち上げて、cnv-pynq-pynq の下のプロジェクトを開いた。
BNN-PYNQ_21_170312.png

合成結果を示す。
BNN-PYNQ_22_170312.png

Target が 5.00 ns に対して、Estimated は 7.90 ns で満たしていないが、実際のクロックは 100 MHz なので、大丈夫だろう?
BRAM_18K は96 % 使用している。DSP48E は 14 % 、FF は 26 %、LUT は 80 % 使用している。

次に、Vivado 2016.4 を立ち上げて、vivado ディレクトリの下の cnv-pynq-pynq の下のVivado プロジェクトを開いてみた。
BNN-PYNQ_23_170312.png

procsys ブロックデザインを示す。
BNN-PYNQ_24_170312.png

Address Editor を示す。
BNN-PYNQ_25_170312.png

Project Summary を示す。タイミング違反が出ている。
LUT はVivado HLS では 80 % 使用していたはずが、54 % になっている。BRAM も少ないので、ロジックを消されたのかもしれない?
BNN-PYNQ_26_170312.png

タイミング違反を調べるためにImplemented Design を開いた。
BNN-PYNQ_27_170312.png

BlackBoxJam_0 間がタイミング違反になっているので、Vivado HLS の合成したIP がタイミング違反になっている。
BNN-PYNQ_28_170312.png

このタイミング違反は直すのが難しそうです。Vivado HLS でTarget を 4 ns, 3ns にしてみたんですが、合成結果のEstimated は7.9 ns で変化がありませんでした。
Vivadoのimplementation のオプションのStrategy にPerformance_ExtraTimingOpt を選択してあるので、これ以上変更しても無理そうでした。
  1. 2017年03月12日 05:52 |
  2. PYNQ
  3. | トラックバック:0
  4. | コメント:0

「モアナと伝説の海」(映画)を見てきました

「モアナと伝説の海」(映画)を見てきました。映像はとっても綺麗で良かったです。歌も良かったです。内容は少し平凡かもしれませんけど。。。
  1. 2017年03月11日 21:13 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

Ubuntu16.04にVivado 2016.4をインストール

今日はUbuntu16.04にVivado 2016.4をインストールする覚書を書いておこうと思う。
ちなみに、私の環境は、VirtualBoxにUbuntu16.04をインストールしてある。

まずは、Xilinx Japan のサイトに行って、サポート→ダウンロードとライセンスを選択して、ダウンロードのサイトへ行く。

Vivado HLx 2016.4: WebPACK および Editions - Linux 用自己解凍型ウェブ インストーラー (BIN - 80.67 MB)をダウンロードする。
すると、Xilinx_Vivado_SDK_2016.4_0124_1_Lin64.bin がダウンロードできる。

Ubuntuでダウンロードしていれば、そのままだが、Windowsでダウンロードした場合は、Ubuntuに持っていく。

まずは、実行パーミッションを与える必要がある。
chmod +x Xilinx_Vivado_SDK_2016.4_0124_1_Lin64.bin

次に、Xilinx_Vivado_SDK_2016.4_0124_1_Lin64.bin を実行しよう。その際に、/opt/Xilinxに書くのでスーパーユーザーの権限が必要だ。
sudo ./Xilinx_Vivado_SDK_2016.4_0124_1_Lin64.bin

スーパーユーザーのパスワードを入力すると、Vivado 2016.4 Installer が起動する。
Ubuntu_Vivado_install_1_170311.png

Select Install Type では、Xilinx のUser ID とPassword を入れる。
Ubuntu_Vivado_install_2_170311.png

Accept License Agreements では、3つのチェックボックスにチェックを入れる。
Ubuntu_Vivado_install_3_170311.png

Select Ediition to Install では、私はVivado HL Webpack のラジオボタンを選択したが、これはお好みで。
Ubuntu_Vivado_install_4_170311.png

Vivado HL Webpack の画面では、Software Development Kit (SDK) のチェックを入れたほうが良い。
Ubuntu_Vivado_install_5_170311.png

後はデフォルトで良いと思うので、省略。
最初に5GB 以上ダウンロードしてからインストールを始めるので、時間がかかるのは覚悟した方が良い。

License Manager が起動するが、Vivado HL Webpack はライセンスは必要ないので、終了させておく。

インストールが終了しても、vivado コマンドを入れてもVivado は起動ないので、設定を行う。

LX Terminal から
gedit .bashrc
コマンドを実行する。

.bashrc の最後に
source /opt/Xilinx/Vivado/2016.4/settings64.sh
alias xsdk='env SWT_GTK3=0 xsdk'
alias vivado='env SWT_GTK3=0 vivado'

を追加する。
Ubuntu_Vivado_install_6_170311.png
なお、xsdk のスクリプトに関しては、「VivadoやXilinx SDKをLinux (Ubuntu) で動かすメモ (Ubuntu 16.04 LTS, Vivado 2016.4, 64bit環境)」から引用させて頂いた。これが無いと xsdk が起動できない。vivado もGTK3 を無効にしておかないと vivado から SDK を起動できない。

source .bashrc
で.bashrc の内容を反映する。これで、vivado コマンドが実行できるようになった。

ホームディレクトリの.Xilinx ディレクトリの一部がのユーザーとグループが root なので、ユーザーに変更する。ホームディレクトリに移動しておく(cd を実行すれば良い) なお、masaaki は自分のアカウント名に修正してください。
sudo chown -R masaaki:masaaki .Xilinx/

なお、ケーブル・ドライバがインストールされていないそうなので、下のコマンドでインストールした。これは、「VivadoやXilinx SDKをLinux (Ubuntu) で動かすメモ (Ubuntu 16.04 LTS, Vivado 2016.4, 64bit環境)」から引用させて頂いた。私のとディレクトリが違っているので、コマンドを書き換えた。
sudo /opt/Xilinx/Vivado/2016.4/data/xicom/cable_drivers/lin64/install_script/install_driverst/install_drivers
Ubuntu_Vivado_install_8_170311.png
エラーになってしまった。これは、ビットストリームのダウンロードに影響するので、最悪Windowsに持って行ってダウンロードすればよいと思うので、とりあえずはこのままとした。

LX Termnal 上で vivado とタイプすると Vivado 2016.4 が起動する。
Ubuntu_Vivado_install_7_170311.png

.bashrc で vivado を起動するときにGTK3 を無効にしておいたので、vivado でFile メニューから Launch SDK でSDK を起動しても起動できた。
Ubuntu_Vivado_install_9_170311.png

Ubuntu_Vivado_install_10_170311.png

ちなみにSDK単体は xsdk で、Vivado HLS は vivado_hls コマンドで起動できる。
  1. 2017年03月11日 08:06 |
  2. Vivado
  3. | トラックバック:0
  4. | コメント:0