FC2カウンター FPGAの部屋 2015年01月
fc2ブログ

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

FPGAの部屋

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

ZYBOのDigilent Linux KernelにARMhfのRoot File Systemsを入れる3(Ubuntu Trusty 14.04 LTS)

ZYBOのDigilent Linux KernelにARMhfのRoot File Systemsを入れる2( Debian Wheezy 7.5)”の続き。

今回、もう一度、 Ubuntu Trusty 14.04 LTS のRoot File Systems を MicroSDカードの2nd パーティションにコピーして、1st パーティションは、Digilent Linux Kernel, BOOT.bin, devicetree.dtb をコピーした。
パソコンのVirtualBox上にインストールしたUbuntu 14.04 LTS で MicroSDカードにコピーをしたのだが、その際に ROOT_FS の /usr/bin/sudo に 4755 のパーティションを与えた。
sudo chmod 4755 /media/masaaki/ROOT_FS/usr/bin/sudo

MicroSDカードのマウントを外して、ZYBO に挿入して電源をONした。
すると、やはり、”* Starting OpenSSH server”まで進んだが、ここで停止してしまった。
ZYBO_ARMhf_11_150125.png

Debian と違って、所得したIPアドレスがわからない。適当に割り当てられていそうなIPアドレスを指定したら当たっていてログインできた。(ログイン名は ubuntu 、パスワードも ubuntu だった)
DHCPで割り当てられたIPアドレスがわからないと困る。そこで、/etc/rc.local に ifconfig コマンドを書くことにした。
sudo vi /etc/rc.local
ZYBO_ARMhf_26_150131.png

リブートする前に、ubuntu ユーザーのディレクトリのパーミッションを変更した。
cd /home
sudo chown -R -f ubuntu:ubuntu ubuntu


ここで、 sudo reboot コマンドで、リブートした。

起動すると、rc.local に書いた ifconfig コマンドが起動して、割り振られたIPアドレスが見えた。
ZYBO_ARMhf_27_150131.png

やった~。これでIPアドレスが分からないという問題が解消した。

次に、date コマンドを実行したら、例によって UTC だったので、
sudo ln -sf /usr/share/zoneinfo/Japan /etc/localtime で、タイムゾーンを JST に変更した。
ZYBO_ARMhf_25_150131.png

sudo apt-get install gedit で gedit をインストールした。相当時間がかかった。

sudo apt-get install nautilus で、Ubuntu のファイルマネージャーをインストールした。
nautilus & コマンドで起動した。
ZYBO_ARMhf_28_150131.png

一旦、sudo reboot して、SSHでログインして、top コマンドで使用メモリを確認したところ、59KB 程度だった。案外、メモリを消費していない。
ZYBO_ARMhf_29_150131.png

df をすると、MicroSDカードの容量の 13% を消費しているのが分かった。
ZYBO_ARMhf_30_150131.png
  1. 2015年01月31日 21:03 |
  2. Linux
  3. | トラックバック:0
  4. | コメント:2

ZYBOのDigilent Linux KernelにARMhfのRoot File Systemsを入れる2( Debian Wheezy 7.5)

ZYBOのDigilent Linux Kernel にARMhfのRoot File Systemsを入れる”で、ZYBOのDigilent Linux KernelにARMhfのRoot File Systemsを入れてみたが、Ubuntu14.04 LTSのRoot File Systems も Debian Wheezy 7.5のRoot File Systems も立ち上がらないと思った。

今回、もう一度、 Debian Wheezy 7.5 のRoot File Systems を MicroSDカードの2nd パーティションに入れて、1st パーティションは、Digilent Linux Kernel, BOOT.bin, devicetree.dtb を入れた。
ブートしてみると、シリアルポート接続のTrea Termは、sshd でやはり止まった。
ZYBO_ARMhf_12_150131.png

しかし、DHCPで IP は取れている。現在は192.168.3.2 だ。

このIP を使用して、Tera Term で SSH 接続した。
ZYBO_ARMhf_13_150131.png

IDは debian パスワードも debian でログインできた。
ZYBO_ARMhf_14_150131.png

df コマンドを実行すると、5% ほど使用している。
ZYBO_ARMhf_15_150131.png

top コマンドを実行すると、52 KB ほどメモリを使用している。Linaro Ubuntu の 1/3 程度だが、デーモン(って今言わないのかな?)が動いていないせいもあるはず。。。
ZYBO_ARMhf_16_150131.png

sudo コマンドはエラーで実行できない。
ZYBO_ARMhf_17_150131.png

root でログインしようとしてもログインできない。”Ubuntu 12.04 LTS armhf preinstalled root password”によると、root のログインはデフォルトで禁止されているそうだ。確かに、/etc/shadow の最初の1行に

”root:*:15835:0:99999:7:::”

と書いてあった。
2.3 シャドウファイル /etc/shadow の構造”によると、第2フィールドが * だとログイン出来ないそうだ。* を消せばよいのだが、これはそのままにして、sudo コマンドを動作させるには、 chmod 4755 /usr/bin/sudo を実行すればよいのだが、これは root 権限で実装するしか無い。
そこで、パソコンのUbuntu 14.04 LTS で MicroSDカードをマウントして、そこで chmod コマンドを実行した。
ZYBO_ARMhf_18_150131.png

もう一度、MicroSDカードをZYBOに入れて、電源をONした。

SSHでログインして、sudo apt-get update を実行したら動作した。因みに、これは2度目で1度目は debian のパスワード (debian) を入力した。
ZYBO_ARMhf_19_150131.png

date コマンドを実行したら、時刻はあっているようだったが、タイムゾーンがUTC だった。
ln -sf /usr/share/zoneinfo/Japan /etc/localtime で、タイムゾーンを JST に変更した。
ZYBO_ARMhf_20_150131.png

sudo apt-get upgrade で既存のモジュールをアップデートした。

sudo apt-get insall gedit で gedit をインストールして、gedit を立ちあげたが、Xが立ち上がらなかった。

原因は、/home/debian のオーナーとグループが root だったことだ。
cd /home
sudo chown -R -f debian:debian debian

で、オーナーとグループが debian になった。
ZYBO_ARMhf_21_150131.png

logout して、もう一度、SSHで debian ユーザーでログインすると、.Xauthority が作られていた。
ZYBO_ARMhf_22_150131.png

gedit コマンドで、gedit を起動すると、今度は起動した。
ZYBO_ARMhf_23_150131.png

top コマンドを起動すると、77 KB 位だった。やはり、少し増えている。
ZYBO_ARMhf_24_150131.png

ZYBOで Debian Wheezy 7.5 も使うことができるようになった。
  1. 2015年01月31日 11:38 |
  2. Linux
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2014.4でラプラシアン・フィルタ関数をaxi masterモジュールにする2

Vivado HLS 2014.4でラプラシアン・フィルタ関数をaxi masterモジュールにする1”の続き。

前回はC Synthesis アイコンで高位合成を行った。今回は、Export RTL アイコンで IP 化を行う。

Vivado HLS 2014.4 の Export RTL アイコンをクリックして、IP 化を行う。
Vivado_HLS_lap_filter_4_150130.jpg

Export RTL Dialog が出るので、Configurtarion... ボタンをクリックする。
Vivado_HLS_lap_filter_5_150130.jpg

Vendor を marsee に、Display Name を lap_filter_axim_hls に設定した。OKボタンをクリックした。
Vivado_HLS_lap_filter_6_150130.jpg

Export RTL Dialog に戻り、OKボタンをクリックした。
これで IP 化が終了した。
Vivado_HLS_lap_filter_7_150131.jpg

drivers フォルダ下の xlap_filter_axim_hw.h の内容を見てみると、cam_addr と lap_addr に制御信号が追加されていた。

// 0x1c : Control signal of cam_addr
//        bit 0  - cam_addr_ap_vld (Read/Write/COH)
//        bit 1  - cam_addr_ap_ack (Read)
//        others - reserved
// 0x24 : Control signal of lap_addr
//        bit 0  - lap_addr_ap_vld (Read/Write/SC)
//        others - reserved


下に xlap_filter_axim_hw.h 行のコメント行の全部を示す。

// ==============================================================
// File generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2014.4
// Copyright (C) 2014 Xilinx Inc. All rights reserved.
// 
// ==============================================================

// BUS_AXI4LS
// 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 cam_addr
//        bit 31~0 - cam_addr[31:0] (Read/Write)
// 0x1c : Control signal of cam_addr
//        bit 0  - cam_addr_ap_vld (Read/Write/COH)
//        bit 1  - cam_addr_ap_ack (Read)
//        others - reserved
// 0x20 : Data signal of lap_addr
//        bit 31~0 - lap_addr[31:0] (Read/Write)
// 0x24 : Control signal of lap_addr
//        bit 0  - lap_addr_ap_vld (Read/Write/SC)
//        others - reserved
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)


次に、Vivado HLS 2014.1 で drivers フォルダ下の xlap_filter_axim_hw.h のコメント行のすべてを下に示す。

// ==============================================================
// File generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2014.1
// Copyright (C) 2014 Xilinx Inc. All rights reserved.
// 
// ==============================================================

// LiteS
// 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 : reserved
// 0x14 : Data signal of cam_addr
//        bit 31~0 - cam_addr[31:0] (Read/Write)
// 0x18 : reserved
// 0x1c : Data signal of lap_addr
//        bit 31~0 - lap_addr[31:0] (Read/Write)
// 0x20 : Data signal of ap_return
//        bit 31~0 - ap_return[31:0] (Read)
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)


同じCソース(pragmaは書き換えてあるが)なのに、違っている。考えてみれば、cam_addr には ap_hs インターフェース、lap_addr には、ap_vld インターフェースが割り当ててあるので、今回のほうが当然の結果である気がする。

cam_addr と lap_addr は、カメラのフレームバッファのベース・アドレスとラプラシアンフィルタのベース・アドレスを設定すれば良いので、1回設定したら当分変えることはない。つまりWrite したままで良く、制御信号はあまり必要無い。
よって、この2つのポートを ap_none インターフェースで定義することにした。

#pragma HLS INTERFACE ap_none port=cam_addr
#pragma HLS INTERFACE ap_none port=lap_addr

Vivado_HLS_lap_filter_8_150131.jpg

もう一度、 C Synthesis アイコンで高位合成を行ってから、Export RTL アイコンをクリックして、IP 化を行った。

// ==============================================================
// File generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2014.4
// Copyright (C) 2014 Xilinx Inc. All rights reserved.
// 
// ==============================================================

// BUS_AXI4LS
// 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 cam_addr
//        bit 31~0 - cam_addr[31:0] (Read/Write)
// 0x1c : reserved
// 0x20 : Data signal of lap_addr
//        bit 31~0 - lap_addr[31:0] (Read/Write)
// 0x24 : reserved
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)


最後に、laplacian_fillter.c を全文貼っておく。(注:下に示すラプラシアンフィルタのCソースコードはバグありコードで、使用できない)

(追記) Vivado HLS で合成したラプラシアンフィルタのバグの原因は、古いバグありラプラシアンフィルタのCソースコードを使用したためでした。正しいラプラシアンフィルタのCソースコードについては、”Vivado HLS 2014.4で生成したラプラシアンフィルタIPをシミュレーション3(原因が分かった)”をご覧ください。

// laplacian_filter.c
// lap_filter_axim()

#include <stdio.h>
#include <string.h>

#define HORIZONTAL_PIXEL_WIDTH    800
#define VERTICAL_PIXEL_WIDTH    600
#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);

int lap_filter_axim(int *cam_addr, int *lap_addr, volatile int *cam_fb, volatile int *lap_fb)
{
    #pragma HLS INTERFACE s_axilite port=cam_addr bundle=BUS_AXI4LS
    #pragma HLS INTERFACE s_axilite port=lap_addr bundle=BUS_AXI4LS
    #pragma HLS INTERFACE s_axilite port=return bundle=BUS_AXI4LS
    #pragma HLS INTERFACE ap_none port=cam_addr
    #pragma HLS INTERFACE ap_none port=lap_addr
    
    #pragma HLS INTERFACE m_axi port=cam_fb depth=480000
    #pragma HLS INTERFACE m_axi port=lap_fb depth=480000

    unsigned int line_buf[3][HORIZONTAL_PIXEL_WIDTH];
    unsigned int lap_buf[HORIZONTAL_PIXEL_WIDTH];
    int x, y;
    int lap_fil_val;
    int a, b;
    int fl, sl, tl;
    unsigned int offset;
    
    // RGB値をY(輝度成分)のみに変換し、ラプラシアンフィルタを掛けた。
    for (y=0; y<VERTICAL_PIXEL_WIDTH; y++){
        for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
            if (y==0 || y==VERTICAL_PIXEL_WIDTH-1){ // 縦の境界の時の値は0とする
                lap_fil_val = 0;
            }else if (x==0 || x==HORIZONTAL_PIXEL_WIDTH-1){ // 横の境界の時も値は0とする
                lap_fil_val = 0;
            }else{
                if (x == 1){ // ラインの最初でラインの画素を読み出す
                    if (y == 1){ // 最初のラインでは3ライン分の画素を読み出す
                        for (a=0; a<3; a++){ // 3ライン分
                            offset = *cam_addr/sizeof(int);
                            memcpy(line_buf[a], (const int*)(cam_fb+offset+(a*HORIZONTAL_PIXEL_WIDTH)), HORIZONTAL_PIXEL_WIDTH*sizeof(int));
                            for (b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){ // ライン
                                line_buf[a][b] = conv_rgb2y(line_buf[a][b]);    // カラーから白黒へ
                            }
                        }
                    }
                } else { // 最初のラインではないので、1ラインだけ読み込む。すでに他の2ラインは読み込まれている
                    offset = *cam_addr/sizeof(int);
                    memcpy(line_buf[(y+1)%3], (const int*)(cam_fb+offset+((y+1)*HORIZONTAL_PIXEL_WIDTH)), HORIZONTAL_PIXEL_WIDTH*sizeof(int));
                    for (b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){ // ライン
                        line_buf[(y+1)%3][b] = conv_rgb2y(line_buf[(y+1)%3][b]);    // カラーから白黒へ
                    }
                }
                fl = (y-1)%3;    // 最初のライン, y=1 012, y=2 120, y=3 201, y=4 012
                sl = y%3;        // 2番めのライン
                tl = (y+1)%3;    // 3番目のライン
                lap_fil_val = laplacian_fil(line_buf[fl][x-1], line_buf[fl][x], line_buf[fl][x+1], line_buf[sl][x-1], line_buf[sl][x], line_buf[sl][x+1], line_buf[tl][x-1], line_buf[tl][x], line_buf[tl][x+1]);
            }
            lap_buf[x] = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val; // RGB同じ値を入れる
        }
        offset = *lap_addr/sizeof(int);
        memcpy((int *)(lap_fb+offset+(y*HORIZONTAL_PIXEL_WIDTH)), (const int*)lap_buf, HORIZONTAL_PIXEL_WIDTH*sizeof(int));
    }
    return(1);
}

// 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);
}

  1. 2015年01月31日 05:09 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2014.4でラプラシアン・フィルタ関数をaxi masterモジュールにする1

Vivado HLS 2014.1でラプラシアン・フィルタ関数をaxi masterモジュールにする1”で使用しているラプラシアンフィルタのCソースを使ってIP化してみた。

ZYBOのZynqをターゲットにして、プロジェクトを作製した。

C Synthesis ボタンをクリックして、高位合成を行うと、ワーニングが出ている。

@W [HLS-41] Resource core 'AXI4LiteS' on port 'cam_addr' is deprecated. Please use the interface directive to specify the AXI interface.
@W [HLS-41] Resource core 'AXI4LiteS' on port 'lap_addr' is deprecated. Please use the interface directive to specify the AXI interface.
@W [HLS-41] Resource core 'AXI4LiteS' on port 'return' is deprecated. Please use the interface directive to specify the AXI interface.
@W [HLS-41] Resource core 'AXI4M' on port 'cam_fb' is deprecated. Please use the interface directive to specify the AXI interface.
@W [HLS-41] Resource core 'AXI4M' on port 'lap_fb' is deprecated. Please use the interface directive to specify the AXI interface.


Vivado_HLS_lap_filter_1_150129.jpg

今までのAXI バス用のディレクティブはこのように指定していた。

#pragma HLS INTERFACE ap_hs port=cam_addr
#pragma HLS INTERFACE ap_vld port=lap_addr
#pragma HLS RESOURCE variable=cam_addr core=AXI4LiteS metadata="-bus_bundle LiteS"
#pragma HLS RESOURCE variable=lap_addr core=AXI4LiteS metadata="-bus_bundle LiteS"
#pragma HLS RESOURCE variable=return core=AXI4LiteS metadata="-bus_bundle LiteS"

#pragma HLS INTERFACE ap_bus port=cam_fb depth=480000
#pragma HLS INTERFACE ap_bus port=lap_fb depth=480000
#pragma HLS RESOURCE variable=cam_fb core=AXI4M
#pragma HLS RESOURCE variable=lap_fb core=AXI4M


Vivado_HLS_lap_filter_2_150129.jpg

Vivado HLS 2014.1 から 2014.4 までの間に AXIバス用のディレクティブが変更されたようだ。
Vivado Design Suite ユーザー ガイド 高位合成 UG902 (v2014.3) 2014 年 10 月 1 日”を参照することにした。

146ページの”AXI4‐Lite インターフェイス”を見ると、下のように書くようだ。引用する。

void example(char *a, char *b, char *c)
{
#pragma HLS INTERFACE s_axilite port=return bundle=BUS_A
#pragma HLS INTERFACE s_axilite port=a bundle=BUS_A
#pragma HLS INTERFACE s_axilite port=b bundle=BUS_A
#pragma HLS INTERFACE s_axilite port=c bundle=BUS_A offset=0x0400
#pragma HLS INTERFACE ap_vld port=b
*c += *a + *b;
}


これを参考にラプラシアンフィルタのAXI4 Lite Slave ディレクティブを書き直した。

#pragma HLS INTERFACE s_axilite port=cam_addr bundle=BUS_AXI4LS
#pragma HLS INTERFACE s_axilite port=lap_addr bundle=BUS_AXI4LS
#pragma HLS INTERFACE s_axilite port=return bundle=BUS_AXI4LS
#pragma HLS INTERFACE ap_hs port=cam_addr
#pragma HLS INTERFACE ap_vld port=lap_addr


次に、154ページからの”AXI4 Master イ ン ターフ ェ イスの使用”を参照して、ラプラシアンフィルタのAXI4 Master インターフェースを書き直した。

#pragma HLS INTERFACE m_axi port=cam_fb depth=480000
#pragma HLS INTERFACE m_axi port=lap_fb depth=480000


これで、もう一度、C Synthesis ボタンをクリックして、高位合成を行った。今度は成功した。
合成後のレポートをここに置いておく。

Vivado HLS 2014.1でラプラシアン・フィルタ関数をaxi masterモジュールにする1”を見ると、合成後の Interface Summary はap_ctrl_hs と ap_bus なのだが、Vivado HLS 2014.4 では、AXI4 Master バスと AXI4 Slave バスになっている。

生成された Verilog HDL ファイルも大きく違っている。下に、Vivado HLS 2013.4とVivado HLS 2014.1の生成されたIPを構成するVerilog HDLファイルの比較図を示す。
Vivado_HLS_2014_1_7_140419.png

今回、高位合成した Vivado HLS 2014.4 の Verilog HDL ファイルの構成を下に示す。
Vivado_HLS_lap_filter_3_150130.jpg

Vivado HLS 2014.1 と Vivado HLS 2014.4 の間で大きく変更されたようだ。
  1. 2015年01月29日 05:58 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Caffe | Deep Learning Frameworkをインストール1

Caffe | Deep Learning Frameworkをインストールしてみようと思う。インストールするのは、VirtualBox上のUbuntu 14.04 LTS で、NVIDIAのGPUも無いので、CPU ONLY とする。

Deep Learning は最近流行りのニューラル・ネットワークの1種で、3層程度だったニューラル・ネットワークが多層になっています。猫を認識できるとか、Beingの機械学習部分はDeep Learning をFPGAで実装しているとか。今流行の技術です。

Deep Learning の参考文献
Python - はじめるDeep learning - Qiita
GoogleやFacebookが注目するディープラーニング(深層学習)についてまとめてみた
Deep Learningと画像認識 ~歴史・理論・実践~ - SlideShare
ねこと画像処理 part 3 – Deep Learningで猫の品種識別
Theano で Deep Learning <3> : 畳み込みニューラルネットワーク

それで、Deep Learning のツールを動かしてみたいということで、Caffeをインストールして、サンプルをやってみることにしました。
インストールについては、本家のCaffe の Installation と日本語では、Caffeインストール を参考にさせて頂く。

まずは、何もないと寂しいので、Caffe 本体をダウンロードする。
BVLC/caffeから、Download ZIPボタンをクリックして、ダウンロードした caffe-master.zip を mkdir した ~/Deep_Learning/Caffe に解凍した。
Caffe_1_150128.jpg

環境のインストールを行う。

CUDAは家のパソコンではダメというか、GPUはAMDなので、インストール出来ない。

BLASのインストールは、Caffeインストール さんを参考にして、ATLASを apt-get でインストールする。
sudo apt-get install libatlas-base-dev
インストールしたATLASのバージョンを調べてみよう。
sudo apt-cache policy libatlas-base-dev
3.10.1-4 だった。
Caffe_2_150128.jpg

Pythonのインストール。これもまた、、Caffeインストール さんの成果を頂いた。
sudo apt-get install libhdf5-dev
Caffe_3_150128.jpg

最初に pip のインストールが必要だった。
sudo apt-get install python-pip
Caffe_4_150128.jpg

Deep_Learning/Caffe/caffe-master/python/requirement.txt に必要なパッケージが書かれているということだった。
下に示すコマンドでインストールを行った。
sudo pip install -r ~/Deep_Learning/Caffe/caffe-master/python/requirements.txt
残念ながら、pip がエラー終了してしまった。
Caffe_5_150128.jpg

1つ1つインストールしていくことにした。
sudo apt-get install Cython
sudo apt-get install python-numpy
sudo apt-get install python-scipy


まで、やった所で、たまたま DeepLearningライブラリ「Caffe」の実行環境をUbuntu14.04で作る さんを見つけたら、これで pip が動くようになるそうだ。
sudo pip install -r ~/Deep_Learning/Caffe/caffe-master/python/requirements.txt

ワーニングが出まくりで、時間が掛かるが、やっと終わった。Successfully なので、成功したようだ。良かった。
Caffe_6_150128.jpg

BoostやOpenCVなどをインストールする。
sudo apt-get install libprotobuf-dev libleveldb-dev libsnappy-dev libopencv-dev libboost-all-dev libhdf5-serial-dev
Caffe_7_150128.jpg

次に、Ubuntu 14.04 LTSなので、下のモジュールをインストールする。
sudo apt-get install libgflags-dev libgoogle-glog-dev liblmdb-dev protobuf-compiler
Caffe_8_150128.jpg

これで下準備は終了。続いて、Caffe をインストールする。

まずは、caffe-master ディレクトリへ入る。
cd caffe-master

Makefile.config.example を Makefile.config としてコピーする。
cp Makefile.config.example Makefile.config

Makefile.config を編集する。
gedit Makefile.config
Caffe_9_150128.jpg

”CPU_ONLY := 1”のコメントを外す。
”BLAS := atlas”であることを確認する。
これでセーブした。
Caffe_10_150128.jpg

make all を実行した。
Caffe_11_150128.jpg

make test を実行した。
Caffe_12_150128.jpg

make runtest を実行した。
Caffe_13_150129.jpg

8 FAILED TESTS が出てしまった。

Caffe | Deep Learning Frameworkをインストール2”へ続く。
  1. 2015年01月28日 05:18 |
  2. Deep Learning
  3. | トラックバック:0
  4. | コメント:0

FPGAエクストリーム・コンピューティング 第6回でLTをやります

FPGAエクストリーム・コンピューティング 第6回”は、244人も申し込みがあって、80人参加できることになったみたいです。FPGAの人気が上がってきて嬉しい限りです。ですが、参加申し込みして参加できなかった方は残念ですね。

今年は、Xilinxのツールに目を向けますと、Vivado HLSもありますし、 SDAccel™ も使えるようになるでしょうから、高位合成をやってみるのも良いですね。Vivado HLSはActivation Based Licensesだと1年間評価できるようなので、使わない手は無いと思います。

話がそれたので戻します。”FPGAエクストリーム・コンピューティング 第6回”で、LTを「UbuntuをインストールしたZYBOボードにカメラを付けてOpenCVで顔認証」という題でやります。5:20pm からです。

スライドはもう出来ていて、7枚です。それに、デモをします。私のZYBOボードをカメラ付きで持って行って、その場でOpenCVで顔認証をするデモをする予定です。果たしてうまくいくでしょうか?ちょっと心配ですが、fpgax なので、失敗した時は許してもらいましょう。。。

なお、会場に来られる方で、顔出しがまずい方はカメラ画像をキャプチャするときに顔を隠して下さい。w
よろしくお願いします。

私の現在のZYBOです。2 Mega pixel Camera Module MT9D111 JPEG Out + HQ lensが付いています。
ZYBO_Board_150127.jpg

P.S.
2月1日当日は、腰が大丈夫だったら、守谷ハーフマラソンの5kmの部に出てから”FPGAエクストリーム・コンピューティング 第6回”に行きます。

なお、OpenCVの顔認証は、今のところ、すべて、Cortex-A9で行っています。将来的には、Vivado HLSも使って、ハードウェア・アクセラレーションしたいと思っています。
  1. 2015年01月27日 05:16 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:0

ZYBOのDigilent Linux KernelにARMhfのRoot File Systemsを入れる

ZYBO用のEmbedded Linux チュートリアル7(Linuxカーネルのビルド)”までで作ったZYBO用のDigilent Linux Kernel にARMhfで見つけたUbuntu Trusty 14.04 LTS とDebian Wheezy 7.5のRoot File Systems を入れてみようと思った。

まずは、Ubuntu Trusty 14.04 LTS のRoot File Systems をZYBOのMicroSDカードの第2パーティション ROOT_FS にコピーしてZYBOの電源をONした。
”* Starting OpenSSH server”まで進んだが、ここで停止してしまった。
ZYBO_ARMhf_11_150125.png

次に、Debian Wheezy 7.5のRoot File Systems をZYBOのMicroSDカードの第2パーティション ROOT_FS にコピーしてZYBOの電源をONした。
やはり、”[ ok ] Starting OpenBSD Secure Shell server: sshd.”まで進んだが停止した。
ZYBO_ARMhf_1_150125.png

/etc ディレクトリのinittab ファイルのinittab をgedit で開いた。
ZYBO_ARMhf_2_150125.png

default runlevel は 2 だった。
ZYBO_ARMhf_3_150125.png

/etc/rc2.d を見ると、S03plymouth があった。
ZYBO_ARMhf_4_150125.png

Plymouth は KMS (Kernel Mode Setting) を使ってグラフィックを表示します。”ということで怪しいのかな?と思い、これを削除した。
ZYBO_ARMhf_5_150125.png

でも、やはり、同様にssh で停止してしまった。

次に、/etc ディレクトリのinittab ファイルのinittab をgedit で開いて、default runlevel は 1 にした。
ZYBO_ARMhf_6_150125.png

電源をONすると、正常に立ち上がった。
ZYBO_ARMhf_7_150125.png

この状態で、DHCPで IP を取れていて、
apt-get update
apt-get upgrade

も問題無くできた。

/etc ディレクトリのinittab ファイルのinittab をgedit で開いて、default runlevel は 2 にして、rc2.d の内容をすべて削除しても立ち上がらなかった。
ZYBO_ARMhf_10_150125.png

parallellafan さん、hidemi_ishihara さん、jujurou さんにはお世話になりました。ありがとうございました。

Debian Wheezy 7.5のRoot File Systems をZYBOのMicroSDカードの第2パーティション ROOT_FS にコピーしてZYBOの電源をONした時の起動メッセージを貼っておく。

0
Device: zynq_sdhci
Manufacturer ID: 74
OEM: 4a45
Name: USD
Tran Speed: 50000000
Rd Block Len: 512
SD version 3.0
High Capacity: Yes
Capacity: 7.5 GiB
Bus Width: 4-bit
reading uEnv.txt
117 bytes read in 8 ms (13.7 KiB/s)
Loaded environment from uEnv.txt
Importing environment from SD ...
Running uenvcmd ...
reading uImage
3987160 bytes read in 351 ms (10.8 MiB/s)
reading devicetree.dtb
7762 bytes read in 16 ms (473.6 KiB/s)
## Booting kernel from Legacy Image at 03000000 ...
Image Name: Linux-3.14.0-xilinx-13567-g906a2
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 3987096 Bytes = 3.8 MiB
Load Address: 00008000
Entry Point: 00008000
Verifying Checksum ... OK
## Flattened Device Tree blob at 02a00000
Booting using the fdt blob at 0x2a00000
Loading Kernel Image ... OK
Loading Device Tree to 1fb29000, end 1fb2de51 ... OK

Starting kernel ...

Uncompressing Linux... done, booting the kernel.
[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Linux version 3.14.0-xilinx-13567-g906a2c9-dirty (masaaki@masaaki-VirtualBox) (gcc version 4.6.3 (Sourcery CodeBench Lite 2012.03-79) ) #9 SMP PREEMPT Sun Oct 5 04:32:36 JST 2014
[ 0.000000] CPU: ARMv7 Processor [413fc090] revision 0 (ARMv7), cr=18c5387d
[ 0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
[ 0.000000] Machine model: Xilinx Zynq
[ 0.000000] bootconsole [earlycon0] enabled
[ 0.000000] cma: CMA: reserved 128 MiB at 17800000
[ 0.000000] Memory policy: Data cache writealloc
[ 0.000000] PERCPU: Embedded 8 pages/cpu @dfb9e000 s10752 r8192 d13824 u32768
[ 0.000000] Built 1 zonelists in Zone order, mobility grouping on. Total pages: 130048
[ 0.000000] Kernel command line: console=ttyPS0,115200 root=/dev/mmcblk0p2 rw earlyprintk rootfstype=ext4 rootwait devtmpfs.mount=1 coherent_pool=16M
[ 0.000000] PID hash table entries: 2048 (order: 1, 8192 bytes)
[ 0.000000] Dentry cache hash table entries: 65536 (order: 6, 262144 bytes)
[ 0.000000] Inode-cache hash table entries: 32768 (order: 5, 131072 bytes)
[ 0.000000] Memory: 375388K/524288K available (5144K kernel code, 319K rwdata, 1900K rodata, 202K init, 5339K bss, 148900K reserved, 0K highmem)
[ 0.000000] Virtual kernel memory layout:
[ 0.000000] vector : 0xffff0000 - 0xffff1000 ( 4 kB)
[ 0.000000] fixmap : 0xfff00000 - 0xfffe0000 ( 896 kB)
[ 0.000000] vmalloc : 0xe0800000 - 0xff000000 ( 488 MB)
[ 0.000000] lowmem : 0xc0000000 - 0xe0000000 ( 512 MB)
[ 0.000000] pkmap : 0xbfe00000 - 0xc0000000 ( 2 MB)
[ 0.000000] modules : 0xbf000000 - 0xbfe00000 ( 14 MB)
[ 0.000000] .text : 0xc0008000 - 0xc06e9600 (7046 kB)
[ 0.000000] .init : 0xc06ea000 - 0xc071ca00 ( 203 kB)
[ 0.000000] .data : 0xc071e000 - 0xc076dde0 ( 320 kB)
[ 0.000000] .bss : 0xc076ddec - 0xc0ca4c88 (5340 kB)
[ 0.000000] Preemptible hierarchical RCU implementation.
[ 0.000000] RCU lockdep checking is enabled.
[ 0.000000] Dump stacks of tasks blocking RCU-preempt GP.
[ 0.000000] RCU restricting CPUs from NR_CPUS=4 to nr_cpu_ids=2.
[ 0.000000] RCU: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=2
[ 0.000000] NR_IRQS:16 nr_irqs:16 16
[ 0.000000] ps7-slcr mapped to e0802000
[ 0.000000] zynq_clock_init: clkc starts at e0802100
[ 0.000000] Zynq clock init
[ 0.000016] sched_clock: 64 bits at 325MHz, resolution 3ns, wraps every 3383112499200ns
[ 0.008493] ps7-ttc #0 at e0804000, irq=43
[ 0.013537] Console: colour dummy device 80x30
[ 0.017880] Lock dependency validator: Copyright (c) 2006 Red Hat, Inc., Ingo Molnar
[ 0.025929] ... MAX_LOCKDEP_SUBCLASSES: 8
[ 0.029952] ... MAX_LOCK_DEPTH: 48
[ 0.034124] ... MAX_LOCKDEP_KEYS: 8191
[ 0.038543] ... CLASSHASH_SIZE: 4096
[ 0.042895] ... MAX_LOCKDEP_ENTRIES: 16384
[ 0.047366] ... MAX_LOCKDEP_CHAINS: 32768
[ 0.051871] ... CHAINHASH_SIZE: 16384
[ 0.056312] memory used by lock dependency info: 3695 kB
[ 0.061761] per task-struct memory footprint: 1152 bytes
[ 0.067203] Calibrating delay loop... 1292.69 BogoMIPS (lpj=6463488)
[ 0.110951] pid_max: default: 32768 minimum: 301
[ 0.116258] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes)
[ 0.122798] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes)
[ 0.137372] CPU: Testing write buffer coherency: ok
[ 0.143614] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
[ 0.149250] Setting up static identity map for 0x4de8d0 - 0x4de928
[ 0.155623] L310 cache controller enabled
[ 0.159581] l2x0: 8 ways, CACHE_ID 0x410000c8, AUX_CTRL 0x72760000, Cache size: 512 kB
[ 0.240406] CPU1: Booted secondary processor
[ 0.328276] CPU1: thread -1, cpu 1, socket 0, mpidr 80000001
[ 0.329397] Brought up 2 CPUs
[ 0.342265] SMP: Total of 2 processors activated.
[ 0.346967] CPU: All CPU(s) started in SVC mode.
[ 0.354966] devtmpfs: initialized
[ 0.365666] VFP support v0.3: implementor 41 architecture 3 part 30 variant 9 rev 4
[ 0.379811] regulator-dummy: no parameters
[ 0.392657] NET: Registered protocol family 16
[ 0.429380] DMA: preallocated 16384 KiB pool for atomic coherent allocations
[ 0.443160] cpuidle: using governor ladder
[ 0.447142] cpuidle: using governor menu
[ 0.474344] syscon f8000000.ps7-slcr: regmap [mem 0xf8000000-0xf8000fff] registered
[ 0.488598] hw-breakpoint: found 5 (+1 reserved) breakpoint and 1 watchpoint registers.
[ 0.496700] hw-breakpoint: maximum watchpoint size is 4 bytes.
[ 0.502964] zynq-ocm f800c000.ps7-ocmc: ZYNQ OCM pool: 256 KiB @ 0xe0880000
[ 0.575116] bio: create slab at 0
[ 0.584089] vgaarb: loaded
[ 0.588644] SCSI subsystem initialized
[ 0.594799] usbcore: registered new interface driver usbfs
[ 0.601466] usbcore: registered new interface driver hub
[ 0.607204] usbcore: registered new device driver usb
[ 0.613761] media: Linux media interface: v0.10
[ 0.618757] Linux video capture interface: v2.00
[ 0.624034] pps_core: LinuxPPS API ver. 1 registered
[ 0.628874] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti
[ 0.638486] PTP clock support registered
[ 0.643335] EDAC MC: Ver: 3.0.0
[ 0.649611] Advanced Linux Sound Architecture Driver Initialized.
[ 0.665144] DMA-API: preallocated 4096 debug entries
[ 0.670185] DMA-API: debugging enabled by kernel config
[ 0.675923] Switched to clocksource arm_global_timer
[ 0.738658] NET: Registered protocol family 2
[ 0.745600] TCP established hash table entries: 4096 (order: 2, 16384 bytes)
[ 0.753592] TCP bind hash table entries: 4096 (order: 5, 147456 bytes)
[ 0.761803] TCP: Hash tables configured (established 4096 bind 4096)
[ 0.768287] TCP: reno registered
[ 0.771420] UDP hash table entries: 256 (order: 2, 20480 bytes)
[ 0.777804] UDP-Lite hash table entries: 256 (order: 2, 20480 bytes)
[ 0.785277] NET: Registered protocol family 1
[ 0.791203] RPC: Registered named UNIX socket transport module.
[ 0.797056] RPC: Registered udp transport module.
[ 0.801717] RPC: Registered tcp transport module.
[ 0.806496] RPC: Registered tcp NFSv4.1 backchannel transport module.
[ 0.814383] hw perfevents: enabled with ARMv7 Cortex-A9 PMU driver, 7 counters available
[ 0.828266] futex hash table entries: 512 (order: 3, 32768 bytes)
[ 0.841827] jffs2: version 2.2. (NAND) (SUMMARY) c 2001-2006 Red Hat, Inc.
[ 0.849398] msgmni has been set to 989
[ 0.854655] io scheduler noop registered
[ 0.858617] io scheduler deadline registered
[ 0.862868] io scheduler cfq registered (default)
[ 0.887625] dma-pl330 f8003000.ps7-dma: Loaded driver for PL330 DMAC-2364208
[ 0.894535] dma-pl330 f8003000.ps7-dma: DBUFF-128x8bytes Num_Chans-8 Num_Peri-4 Num_Events-16
[ 0.906786] e0001000.serial: ttyPS0 at MMIO 0xe0001000 (irq = 82, base_baud = 3125000) is a xuartps
[ 0.916208] console [ttyPS0] enabled
[ 0.916208] console [ttyPS0] enabled
[ 0.923261] bootconsole [earlycon0] disabled
[ 0.923261] bootconsole [earlycon0] disabled
[ 0.934678] xdevcfg f8007000.ps7-dev-cfg: ioremap 0xf8007000 to e0866000
[ 0.944496] [drm] Initialized drm 1.1.0 20060810
[ 0.982856] brd: module loaded
[ 1.005097] loop: module loaded
[ 1.021051] m25p80 spi0.0: found s25fl128s1, expected n25q128
[ 1.026984] m25p80 spi0.0: s25fl128s1 (16384 Kbytes)
[ 1.032008] 4 ofpart partitions found on MTD device spi0.0
[ 1.037468] Creating 4 MTD partitions on "spi0.0":
[ 1.042194] 0x000000000000-0x000000400000 : "qspi-fsbl-uboot"
[ 1.056411] 0x000000400000-0x000000900000 : "qspi-linux"
[ 1.066853] 0x000000900000-0x000000920000 : "qspi-device-tree"
[ 1.077593] 0x000000920000-0x000001000000 : "qspi-user"
[ 1.097217] e1000e: Intel(R) PRO/1000 Network Driver - 2.3.2-k
[ 1.102969] e1000e: Copyright(c) 1999 - 2013 Intel Corporation.
[ 1.114771] libphy: XEMACPS mii bus: probed
[ 1.121070] xemacps e000b000.ps7-ethernet: invalid address, use assigned
[ 1.128174] xemacps e000b000.ps7-ethernet: MAC updated 4e:96:07:9c:de:93
[ 1.135325] xemacps e000b000.ps7-ethernet: pdev->id -1, baseaddr 0xe000b000, irq 54
[ 1.150692] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
[ 1.157754] ehci-pci: EHCI PCI platform driver
[ 1.162833] ULPI transceiver vendor/product ID 0x0424/0x0007
[ 1.168540] Found SMSC USB3320 ULPI transceiver.
[ 1.173098] ULPI integrity check: passed.
[ 1.178048] zynq-ehci zynq-ehci.0: Xilinx Zynq USB EHCI Host Controller
[ 1.185306] zynq-ehci zynq-ehci.0: new USB bus registered, assigned bus number 1
[ 1.215917] zynq-ehci zynq-ehci.0: irq 53, io mem 0x00000000
[ 1.235904] zynq-ehci zynq-ehci.0: USB 2.0 started, EHCI 1.00
[ 1.248654] hub 1-0:1.0: USB hub found
[ 1.252650] hub 1-0:1.0: 1 port detected
[ 1.260595] usbcore: registered new interface driver usb-storage
[ 1.269440] mousedev: PS/2 mouse device common for all mice
[ 1.277130] i2c /dev entries driver
[ 1.289800] zynq-edac f8006000.ps7-ddrc: ecc not enabled
[ 1.296053] cpufreq_cpu0: failed to get cpu0 regulator: -19
[ 1.304439] Xilinx Zynq CpuIdle Driver started
[ 1.310838] sdhci: Secure Digital Host Controller Interface driver
[ 1.317162] sdhci: Copyright(c) Pierre Ossman
[ 1.321437] sdhci-pltfm: SDHCI platform and OF driver helper
[ 1.328663] mmc0: no vqmmc regulator found
[ 1.332686] mmc0: no vmmc regulator found
[ 1.375838] mmc0: SDHCI controller on e0100000.ps7-sdio [e0100000.ps7-sdio] using ADMA
[ 1.391260] usbcore: registered new interface driver usbhid
[ 1.396870] usbhid: USB HID core driver
[ 1.412478] TCP: cubic registered
[ 1.415882] NET: Registered protocol family 17
[ 1.420853] Registering SWP/SWPB emulation handler
[ 1.428183] regulator-dummy: disabling
[ 1.432429] drivers/rtc/hctosys.c: unable to open rtc device (rtc0)
[ 1.448882] mmc0: new high speed SDHC card at address b368
[ 1.457326] mmcblk0: mmc0:b368 USD 7.45 GiB
[ 1.467669] mmcblk0: p1 p2
[ 1.467686] ALSA device list:
[ 1.467690] No soundcards found.
[ 1.512785] EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null)
[ 1.520978] VFS: Mounted root (ext4 filesystem) on device 179:2.
[ 1.529301] devtmpfs: mounted
[ 1.532581] Freeing unused kernel memory: 200K (c06ea000 - c071c000)
INIT: version 2.88 booting
[info] Using makefile-style concurrent boot in runlevel S.
[....] Starting the hotplug events dispatcher: udevd[ 3.223839] udevd[701]: starting version 175
. ok
[ ok ] Synthesizing the initial hotplug events...done.
[ ok ] Waiting for /dev to be fully populated...done.
[....] Setting preliminary keymap...[ 5.308635] random: mktemp urandom read with 92 bits of entropy available
[ 8.727210] random: nonblocking pool is initialized
done.
[ ok ] Activating swap...done.
[ 11.596128] EXT4-fs (mmcblk0p2): re-mounted. Opts: (null)
[ ok ] Cleaning up temporary files....
[ ok ] Activating lvm and md swap...done.
[....] Checking file systems...fsck from util-linux 2.20.1
done.
[ ok ] Mounting local filesystems...done.
[ ok ] Activating swapfile swap...done.
[ ok ] Cleaning up temporary files....
[ ok ] Setting kernel variables ...done.
[....] Setting up resolvconf.../etc/resolvconf/update.d/libc: Warning: /etc/resolv.conf is not a symbolic link to /etc/resolvconf/run/resolv.conf
done.
[....] Configuring network interfaces...Internet Systems Consortium DHCP Client 4.2.2
Copyright 2004-2011 Internet Systems Consortium.
All rights reserved.
For info, please visit https://www.isc.org/software/dhcp/

Listening on LPF/eth0/4e:96:07:9c:de:93
Sending on LPF/eth0/4e:96:07:9c:de:93
Sending on Socket/fallback
DHCPREQUEST on eth0 to 255.255.255.255 port 67
[ 22.376773] xemacps e000b000.ps7-ethernet: Set clk to 25000000 Hz
[ 22.382921] xemacps e000b000.ps7-ethernet: link up (100/FULL)
DHCPREQUEST on eth0 to 255.255.255.255 port 67
DHCPNAK from 192.168.3.1
DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval 6
DHCPREQUEST on eth0 to 255.255.255.255 port 67
DHCPOFFER from 192.168.3.1
DHCPACK from 192.168.3.1
/etc/resolvconf/update.d/libc: Warning: /etc/resolv.conf is not a symbolic link to /etc/resolvconf/run/resolv.conf
bound to 192.168.3.2 -- renewal in 37814 seconds.
done.
[ ok ] Cleaning up temporary files....
[info] Setting console screen modes.
setterm: cannot (un)set powersave mode: Inappropriate ioctl for device
[info] Skipping font and keymap setup (handled by console-setup).
[ ok ] Setting up console font and keymap...done.
INIT: Entering runlevel: 2
[info] Using makefile-style concurrent boot in runlevel 2.
[ ok ] Starting enhanced syslogd: rsyslogd.
[ ok ] Starting periodic command scheduler: cron.
[ ok ] Starting system message bus: dbus.
[ ok ] Starting OpenBSD Secure Shell server: sshd.


(2014/01/31:追記)
Debian Wheezy 7.5 を使うことができるようになった。
詳しくは、”ZYBOのDigilent Linux KernelにARMhfのRoot File Systemsを入れる2”を参照して下さい。
  1. 2015年01月25日 19:46 |
  2. Linux
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2014.4 の高位合成テスト17(ラプラシアンフィルタ12、Clock Period = 2.5 ns の場合のインプリメント)

Vivado HLS 2014.4 の高位合成テスト16(ラプラシアンフィルタ11、Clock Period = 4 ns の場合のインプリメント)”の続き。

前回は、Clock Period = 4 ns (250MHz)の場合、つまり、Latency = 7 クロックの条件で、ラプラシアンフィルタのCソースからVivado HLS 2014.4 で高位合成されたVerilog HDLファイルをVivado 2014.4でインプリメントして、250MHzつまり 4 ns の遅延で実際に動作するようにインプリメントできるかを確認して成功した。Vivado 2014.4のプロジェクトの使用するFPGAはZYBOに使用されている xc7z010clg400-1 だ。これは今回も同様にVivado 2014.4のプロジェクトで使用する。

今回は、Clock Period = 2.5 ns で、ラプラシアンフィルタのCソースからVivado HLS 2014.4 で高位合成されたVerilog HDLファイルをVivado 2014.4でインプリメントして、400MHzつまり 2.5 ns の遅延で実際に動作するようにインプリメントできるかを確認する。

まずは、Vivado HLS 2014.4 で、Solution Settings ダイアログの左のペインでSynthesis を選択してClock Period のテキストボックスに 2.5 と入力してから、C Synthesis を行った。結果を下に示す。
Vivado_HLS_Study_80_150122.png

Latency は 16 クロックだった。リソースはFFを 1241 個、LUTを 521 個消費する。

Analysis の Resource タブを見た。
Vivado_HLS_Study_84_150123.png

演算が2クロックで行われている。この演算も独立に演算することができるはずなので、もっと演算リソースを使えば並列に行うことができると思う。つまりレイテンシを短くすることができるはずだ。そして、そのためのディレクティブがあるはずだ。後で調べてみよう。

Vivado HLS 2014.4 の作業が終了したので、ラプラシアンフィルタの Verilog HDL ファイルを Vivado 2014.4 のプロジェクトにコピーした。今回は、laplacian_filter.v だけではなく、laplacian_filter_add_32ns_32ns_32_2.v と laplacian_filter_sub_32ns_32ns_32_2.v が追加されていた。
Vivado_HLS_Study_81_150122.png

Vivado 2014.4 のプロジェクトを示す。
Vivado_HLS_Study_82_150122.png

論理合成を行って、成功した。
タイミング制約を クロック周期 = 2.5 ns に変更した。

create_clock -period 2.500 -name ap_clk -waveform {0.000 1.250} [get_ports ap_clk]


インプリメントを行って、成功した。タイミング制約も満足している。ZYBO が 400MHz で動作するとは思わなかった。

Implemented Design で Report Timing Summary をクリックして Timing Summary を見た。
Vivado_HLS_Study_83_150122.png

ラプラシアンフィルタ内のレジスタ間の遅延が最大 2.231 ns に収まっている。

Implemented Design で Report Utilization を見た。
Vivado_HLS_Study_85_150123.png

laplacian_filter.v のLUT使用数は、461 個だった。Vivado HLS での値は 521 個だったので、60 個減った。
次に、FF使用数は 856 個だった。Vivado HLS での値は 1241 だったので、385 個減っている。

これで、ラプラシアンフィルタがZYBO で 400MHz の動作周波数で動作することがわかった。正直、ここまで動作周波数が行くなんて思ってなかった。驚きだ。
Vivado HLS 2014.4 で PIPELINE ディレクティブを追加してラプラシアンフィルタを高位合成すると、必要とする動作周波数に応じて異なるレイテンシの HDL を出力してくれる。これはとっても便利だ。

レイテンシとスループットを同時に満たす必要がある分野でFPGAをHDLで設計しているとレイテンシをギリギリまで切り詰めて設計するので、どうやっても動作周波数が確保できない時がある。HDLで作っているとパイプラインの段数を増やすことになり、HDLを書きなおす必要が出てくる。
C及びC++からの高位合成でアルゴリズムを書いておけば、動作周波数によって、レイテンシを自動で決定してくれるので、ソースを書き直す必要がなく、とっても便利だと思う。
  1. 2015年01月23日 04:58 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2014.4 の高位合成テスト16(ラプラシアンフィルタ11、Clock Period = 4 ns の場合のインプリメント)

Vivado HLS 2014.4 の高位合成テスト15(ラプラシアンフィルタ10、Clock Period = 4 ns の場合のシミュレーション)”の続き。

前回は、Vivado HLS 2014.4 でラプラシアンフィルタのCソースから高位合成したVerilog HDLをシミュレーションした。
今回は、そのラプラシアンフィルタの Verilog HDLファイルをVivado 2014.4でインプリメントしてみた。
Clock Period = 4 ns の場合、つまり、Latency = 7 クロックの条件でラプラシアンフィルタのCソースからVivado HLS 2014.4 で高位合成されたVerilog HDLファイルをVivado 2014.4でインプリメントして、250MHzつまり 4 ns の遅延で実際に動作するようにインプリメントできるかを確認する。Vivado 2014.4のプロジェクトの使用するFPGAはZYBOに使用されている xc7z010clg400-1 とする。

前回の時に、Vivado 2014.4 のプロジェクトは作ってある。但し、ラプラシアンフィルタの Verilog HDLファイルの laplacian_filter.v は32ビット幅のデータ入力が 9 個もあるので、ZYBO の入出力ピンの総数を上まってしまう。そのために、32ビット1個の入力から、9タップのシフトレジスタを置いて、それぞれのタップからラプラシアンフィルタのデータ入力をすることにした。それに、高位合成したHDLファイルはデータ入力もデータ出力もFF出力ではなく、組み合わせ回路出力になっている。そこですべての入力、出力をFFでラッチすることにした。(一部の制御出力はFF出力があった)これらの機能をまとめて、laplacian_filter_top.v を作製した。なお、動作周波数が250MHzと高速だし、後で400MHzくらいでもやってみたいので、FFでラッチする段数はパラメータで入力できるようにしておいた。

次に論理合成を行って、成功した。下に論理合成後の回路を示す。
Vivado_HLS_Study_77_150122.png

右の箱の2列目の色の違いってい箱が laplacian_filter.v である。その他の黄色の箱はFFなので、ラプラシアンフィルタ本体がFFに囲まれているのが分かる。

次に、XDCファイルを作製した。ap_clk に クロック周期 4 ns の制約を与えた。

create_clock -period 4.000 -name ap_clk -waveform {0.000 2.000} [get_ports ap_clk]


インプリメントを行った。成功した。タイミング制約も満たされている。
Vivado_HLS_Study_78_150122.png

Implemented Design で Report Timing Summary をクリックして Timing Summary を見た。
Vivado_HLS_Study_79_150122.png

ラプラシアンフィルタ内のレジスタ間の遅延が最大 3.807 ns に収まっている。

最後に、laplacian_filter_top.v を貼っておく。

`default_nettype none

module laplcian_filter_top #(
    parameter    integer    INPUT_FF_NUMBER =    1,
    parameter    integer    OUTPUT_FF_NUMBER =    1
)(
    input    wire    ap_clk,
    input    wire    ap_rst,
    input    wire    ap_start,
    output    wire    ap_done,
    output    wire    ap_idle,
    output    wire    ap_ready,
    input    wire    [31:0]    xy,
    output    wire    [31:0]    ap_return
);
    wire    [31:0]  x0y0;
    wire    [31:0]  x1y0;
    wire    [31:0]  x2y0;
    wire    [31:0]  x0y1;
    wire    [31:0]  x1y1;
    wire    [31:0]  x2y1;
    wire    [31:0]  x0y2;
    wire    [31:0]  x1y2;
    wire    [31:0]  x2y2;
    reg     [31:0]  xy_d[8:0];
    wire    ap_done_node;
    wire    ap_idle_node;
    wire    ap_ready_node;
    wire    [31:0]    ap_return_node;
    reg        [31:0]    x0y0_d [INPUT_FF_NUMBER-1:0];
    reg        [31:0]    x1y0_d [INPUT_FF_NUMBER-1:0];
    reg        [31:0]    x2y0_d [INPUT_FF_NUMBER-1:0];
    reg        [31:0]    x0y1_d [INPUT_FF_NUMBER-1:0];
    reg        [31:0]    x1y1_d [INPUT_FF_NUMBER-1:0];
    reg        [31:0]    x2y1_d [INPUT_FF_NUMBER-1:0];
    reg        [31:0]    x0y2_d [INPUT_FF_NUMBER-1:0];
    reg        [31:0]    x1y2_d [INPUT_FF_NUMBER-1:0];
    reg        [31:0]    x2y2_d [INPUT_FF_NUMBER-1:0];
    reg        [31:0]    ap_return_d [OUTPUT_FF_NUMBER-1:0];
    reg        [INPUT_FF_NUMBER-1:0]    ap_start_d;
    reg        [OUTPUT_FF_NUMBER-1:0]    ap_done_d;
    reg        [OUTPUT_FF_NUMBER-1:0]    ap_idle_d;
    reg        [OUTPUT_FF_NUMBER-1:0]    ap_ready_d;

    laplacian_filter lap_filter_inst (
        .ap_clk(ap_clk),
        .ap_rst(ap_rst),
        .ap_start(ap_start_d[0]),
        .ap_done(ap_done_node),
        .ap_idle(ap_idle_node),
        .ap_ready(ap_ready_node),
        .x0y0(x0y0_d[0]),
        .x1y0(x1y0_d[0]),
        .x2y0(x2y0_d[0]),
        .x0y1(x0y1_d[0]),
        .x1y1(x1y1_d[0]),
        .x2y1(x2y1_d[0]),
        .x0y2(x0y2_d[0]),
        .x1y2(x1y2_d[0]),
        .x2y2(x2y2_d[0]),
        .ap_return(ap_return_node)
    );

     always @(posedge ap_clk) begin : AP_XY_DELAY
        integer i;

        for(i=8; i>=0; i=i-1) begin
            if (ap_rst) begin
                xy_d[i] <= 32'd0;
            end else begin
                if (i == 8) begin
                    xy_d[i] <= xy;
                end else begin
                    xy_d[i] <= xy_d[i+1];
                end
            end
        end
    end
    assign x0y0 = xy_d[0];
    assign x1y0 = xy_d[1];
    assign x2y0 = xy_d[2];
    assign x0y1 = xy_d[3];
    assign x1y1 = xy_d[4];
    assign x2y1 = xy_d[5];
    assign x0y2 = xy_d[6];
    assign x1y2 = xy_d[7];
    assign x2y2 = xy_d[8];
   
    always @(posedge ap_clk) begin : AP_START_DELAY
        integer i;

        for(i=INPUT_FF_NUMBER-1; i>=0; i=i-1) begin
            if (ap_rst) begin
                ap_start_d[i] <= 1'b0;
            end else begin
                if (i == (INPUT_FF_NUMBER-1)) begin
                    ap_start_d[i] <= ap_start;
                end else begin
                    ap_start_d[i] <= ap_start_d[i+1];
                end
            end
        end
    end
    
    always @(posedge ap_clk) begin : AP_DONE_DELAY
        integer i;

        for(i=OUTPUT_FF_NUMBER-1; i>=0; i=i-1) begin
            if (ap_rst) begin
                ap_done_d[i] <= 1'b0;
            end else begin
                if (i == (OUTPUT_FF_NUMBER-1)) begin
                    ap_done_d[i] <= ap_done_node;
                end else begin
                    ap_done_d[i] <= ap_done_d[i+1];
                end
            end
        end
    end
    assign ap_done = ap_done_d[0];

    always @(posedge ap_clk) begin : AP_IDLE_DELAY
        integer i;

        for(i=OUTPUT_FF_NUMBER-1; i>=0; i=i-1) begin
            if (ap_rst) begin
                ap_idle_d[i] <= 1'b0;
            end else begin
                if (i == (OUTPUT_FF_NUMBER-1)) begin
                    ap_idle_d[i] <= ap_idle_node;
                end else begin
                    ap_idle_d[i] <= ap_idle_d[i+1];
                end
            end
        end
    end
    assign ap_idle = ap_idle_d[0];

    always @(posedge ap_clk) begin : AP_READY_DELAY
        integer i;

        for(i=OUTPUT_FF_NUMBER-1; i>=0; i=i-1) begin
            if (ap_rst) begin
                ap_ready_d[i] <= 1'b0;
            end else begin
                if (i == (OUTPUT_FF_NUMBER-1)) begin
                    ap_ready_d[i] <= ap_ready_node;
                end else begin
                    ap_ready_d[i] <= ap_ready_d[i+1];
                end
            end
        end
    end
    assign ap_ready = ap_ready_d[0];

    always @(posedge ap_clk) begin : AP_X0Y0_DELAY
        integer i;

        for(i=INPUT_FF_NUMBER-1; i>=0; i=i-1) begin
            if (ap_rst) begin
                x0y0_d[i] <= 32'd0;
            end else begin
                if (i == (INPUT_FF_NUMBER-1)) begin
                    x0y0_d[i] <= x0y0;
                end else begin
                    x0y0_d[i] <= x0y0_d[i+1];
                end
            end
        end
    end
    
    always @(posedge ap_clk) begin : AP_X1Y0_DELAY
        integer i;

        for(i=INPUT_FF_NUMBER-1; i>=0; i=i-1) begin
            if (ap_rst) begin
                x1y0_d[i] <= 32'd0;
            end else begin
                if (i == (INPUT_FF_NUMBER-1)) begin
                    x1y0_d[i] <= x1y0;
                end else begin
                    x1y0_d[i] <= x1y0_d[i+1];
                end
            end
        end
    end
    
    always @(posedge ap_clk) begin : AP_X2Y0_DELAY
        integer i;

        for(i=INPUT_FF_NUMBER-1; i>=0; i=i-1) begin
            if (ap_rst) begin
                x2y0_d[i] <= 32'd0;
            end else begin
                if (i == (INPUT_FF_NUMBER-1)) begin
                    x2y0_d[i] <= x2y0;
                end else begin
                    x2y0_d[i] <= x2y0_d[i+1];
                end
            end
        end
    end
    
    always @(posedge ap_clk) begin : AP_X0Y1_DELAY
        integer i;

        for(i=INPUT_FF_NUMBER-1; i>=0; i=i-1) begin
            if (ap_rst) begin
                x0y1_d[i] <= 32'd0;
            end else begin
                if (i == (INPUT_FF_NUMBER-1)) begin
                    x0y1_d[i] <= x0y1;
                end else begin
                    x0y1_d[i] <= x0y1_d[i+1];
                end
            end
        end
    end
    
    always @(posedge ap_clk) begin : AP_X1Y1_DELAY
        integer i;

        for(i=INPUT_FF_NUMBER-1; i>=0; i=i-1) begin
            if (ap_rst) begin
                x1y1_d[i] <= 32'd0;
            end else begin
                if (i == (INPUT_FF_NUMBER-1)) begin
                    x1y1_d[i] <= x1y1;
                end else begin
                    x1y1_d[i] <= x1y1_d[i+1];
                end
            end
        end
    end
    
    always @(posedge ap_clk) begin : AP_X2Y1_DELAY
        integer i;

        for(i=INPUT_FF_NUMBER-1; i>=0; i=i-1) begin
            if (ap_rst) begin
                x2y1_d[i] <= 32'd0;
            end else begin
                if (i == (INPUT_FF_NUMBER-1)) begin
                    x2y1_d[i] <= x2y1;
                end else begin
                    x2y1_d[i] <= x2y1_d[i+1];
                end
            end
        end
    end
    
    always @(posedge ap_clk) begin : AP_X0Y2_DELAY
        integer i;

        for(i=INPUT_FF_NUMBER-1; i>=0; i=i-1) begin
            if (ap_rst) begin
                x0y2_d[i] <= 32'd0;
            end else begin
                if (i == (INPUT_FF_NUMBER-1)) begin
                    x0y2_d[i] <= x0y2;
                end else begin
                    x0y2_d[i] <= x0y2_d[i+1];
                end
            end
        end
    end
    
    always @(posedge ap_clk) begin : AP_X1Y2_DELAY
        integer i;

        for(i=INPUT_FF_NUMBER-1; i>=0; i=i-1) begin
            if (ap_rst) begin
                x1y2_d[i] <= 32'd0;
            end else begin
                if (i == (INPUT_FF_NUMBER-1)) begin
                    x1y2_d[i] <= x1y2;
                end else begin
                    x1y2_d[i] <= x1y2_d[i+1];
                end
            end
        end
    end
    
    always @(posedge ap_clk) begin : AP_X2Y2_DELAY
        integer i;

        for(i=INPUT_FF_NUMBER-1; i>=0; i=i-1) begin
            if (ap_rst) begin
                x2y2_d[i] <= 32'd0;
            end else begin
                if (i == (INPUT_FF_NUMBER-1)) begin
                    x2y2_d[i] <= x2y2;
                end else begin
                    x2y2_d[i] <= x2y2_d[i+1];
                end
            end
        end
    end
    
    always @(posedge ap_clk) begin : AP_RETURN_DELAY
        integer i;

        for(i=OUTPUT_FF_NUMBER-1; i>=0; i=i-1) begin
            if (ap_rst) begin
                ap_return_d[i] <= 32'd0;
            end else begin
                if (i == (OUTPUT_FF_NUMBER-1)) begin
                    ap_return_d[i] <= ap_return_node;
                end else begin
                    ap_return_d[i] <= ap_return_d[i+1];
                end
            end
        end
    end
    assign ap_return = ap_return_d[0];

endmodule

`default_nettype wire

  1. 2015年01月23日 04:08 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2014.4 の高位合成テスト15(ラプラシアンフィルタ10、Clock Period = 4 ns の場合のシミュレーション)

”Vivado HLS 2014.4 の高位合成テスト14(ラプラシアンフィルタ9、Clock Period の変更2)”の続き。

今回は、Clock Period = 4 ns の場合、つまり、Latency = 7 クロックの時に出力された Verilog HDLファイルをシミュレーションしてみようと思う。

・”Vivado HLS 2014.4 の高位合成テスト7(ラプラシアンフィルタ2、シミュレーション)”で作製したZYBO 用のプロジェクトの laplacian_filter.v を Clock Period = 4 ns の場合の laplacian_filter.v と入れ替えた。

・テストベンチの laplacian_filter_tb.v のクロック周期を 10 ns から 4 ns に変更した。

    // clk_gen のインスタンス(ap_clk)
    clk_gen #(
        .CLK_PERIOD(40),    // 4nsec, 250MHz
        .CLK_DUTY_CYCLE(0.5),
        .CLK_OFFSET(0),
        .START_STATE(1'b0)
    ) ACLKi (
        .clk_out(ap_clk)
    );


・Vivado Simulator で論理シミュレーションを行った。(laplacian_filter_tb.v の LAP_FILTER_END_COUNT = 0 とした)
下にシミュレーション波形を示す。(Vivado HLS のディレクティブは、PIPELINEを入れてある)
Vivado_HLS_Study_76_150121.png

ap_start が 1 にアサートされてから、ap_done が 1 にアサートされるまでに約 28 ns 掛かっている。今のクロック周期は 4 ns なので、28/4 = 7 クロックとなる。
ap_done がアサートされた最初のクロックでは、ap_return に 255が出力され、次のクロックでは、13が出力されている。この値は合っているので、正常にパイプライン動作をしているのが分かる。

現在の laplacian_filter.v を貼っておく。以前のLatency の小さい laplacian_filter.v に比べて行数が増えた。

// ==============================================================
// RTL generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2014.4
// Copyright (C) 2014 Xilinx Inc. All rights reserved.
// 
// ===========================================================

`timescale 1 ns / 1 ps 

(* CORE_GENERATION_INFO="laplacian_filter,hls_ip_2014_4,{HLS_INPUT_TYPE=cxx,HLS_INPUT_FLOAT=0,HLS_INPUT_FIXED=0,HLS_INPUT_PART=xc7z010clg400-1,HLS_INPUT_CLOCK=4.000000,HLS_INPUT_ARCH=pipeline,HLS_SYN_CLOCK=3.940000,HLS_SYN_LAT=7,HLS_SYN_TPT=1,HLS_SYN_MEM=0,HLS_SYN_DSP=0,HLS_SYN_FF=485,HLS_SYN_LUT=393}" *)

module laplacian_filter (
        ap_clk,
        ap_rst,
        ap_start,
        ap_done,
        ap_idle,
        ap_ready,
        x0y0,
        x1y0,
        x2y0,
        x0y1,
        x1y1,
        x2y1,
        x0y2,
        x1y2,
        x2y2,
        ap_return
);

parameter    ap_const_logic_1 = 1'b1;
parameter    ap_const_logic_0 = 1'b0;
parameter    ap_ST_pp0_stg0_fsm_0 = 1'b1;
parameter    ap_const_lv32_0 = 32'b00000000000000000000000000000000;
parameter    ap_const_lv1_1 = 1'b1;
parameter    ap_const_lv32_3 = 32'b11;
parameter    ap_const_lv32_1F = 32'b11111;
parameter    ap_const_lv32_8 = 32'b1000;
parameter    ap_const_lv24_0 = 24'b000000000000000000000000;
parameter    ap_const_lv7_0 = 7'b0000000;
parameter    ap_const_lv10_FF = 10'b11111111;
parameter    ap_true = 1'b1;

input   ap_clk;
input   ap_rst;
input   ap_start;
output   ap_done;
output   ap_idle;
output   ap_ready;
input  [31:0] x0y0;
input  [31:0] x1y0;
input  [31:0] x2y0;
input  [31:0] x0y1;
input  [31:0] x1y1;
input  [31:0] x2y1;
input  [31:0] x0y2;
input  [31:0] x1y2;
input  [31:0] x2y2;
output  [31:0] ap_return;

reg ap_done;
reg ap_idle;
reg ap_ready;
(* fsm_encoding = "none" *) reg   [0:0] ap_CS_fsm = 1'b1;
reg    ap_sig_cseq_ST_pp0_stg0_fsm_0;
reg    ap_sig_bdd_17;
wire    ap_reg_ppiten_pp0_it0;
reg    ap_reg_ppiten_pp0_it1 = 1'b0;
reg    ap_reg_ppiten_pp0_it2 = 1'b0;
reg    ap_reg_ppiten_pp0_it3 = 1'b0;
reg    ap_reg_ppiten_pp0_it4 = 1'b0;
reg    ap_reg_ppiten_pp0_it5 = 1'b0;
reg    ap_reg_ppiten_pp0_it6 = 1'b0;
reg    ap_reg_ppiten_pp0_it7 = 1'b0;
reg   [31:0] x2y2_read_reg_214;
reg   [31:0] ap_reg_ppstg_x2y2_read_reg_214_pp0_it1;
reg   [31:0] ap_reg_ppstg_x2y2_read_reg_214_pp0_it2;
reg   [31:0] ap_reg_ppstg_x2y2_read_reg_214_pp0_it3;
reg   [31:0] ap_reg_ppstg_x2y2_read_reg_214_pp0_it4;
reg   [31:0] x1y2_read_reg_219;
reg   [31:0] ap_reg_ppstg_x1y2_read_reg_219_pp0_it1;
reg   [31:0] ap_reg_ppstg_x1y2_read_reg_219_pp0_it2;
reg   [31:0] ap_reg_ppstg_x1y2_read_reg_219_pp0_it3;
reg   [31:0] x0y2_read_reg_224;
reg   [31:0] ap_reg_ppstg_x0y2_read_reg_224_pp0_it1;
reg   [31:0] ap_reg_ppstg_x0y2_read_reg_224_pp0_it2;
reg   [31:0] x2y1_read_reg_229;
reg   [31:0] ap_reg_ppstg_x2y1_read_reg_229_pp0_it1;
reg   [31:0] x1y1_read_reg_234;
wire   [31:0] tmp1_fu_107_p2;
reg   [31:0] tmp1_reg_239;
wire   [31:0] tmp2_fu_113_p2;
reg   [31:0] tmp2_reg_244;
wire   [31:0] sum3_neg_fu_128_p2;
reg   [31:0] sum3_neg_reg_249;
wire   [31:0] tmp_1_fu_134_p2;
reg   [31:0] tmp_1_reg_254;
wire   [31:0] tmp_2_fu_138_p2;
reg   [31:0] tmp_2_reg_259;
wire   [31:0] tmp_3_fu_142_p2;
reg   [31:0] tmp_3_reg_264;
wire   [31:0] y_fu_146_p2;
reg   [31:0] y_reg_269;
reg   [31:0] ap_reg_ppstg_y_reg_269_pp0_it6;
reg   [0:0] tmp_4_reg_274;
reg   [0:0] ap_reg_ppstg_tmp_4_reg_274_pp0_it6;
reg   [23:0] tmp_5_reg_279;
reg   [0:0] tmp_6_reg_284;
reg   [0:0] ap_reg_ppstg_tmp_6_reg_284_pp0_it6;
wire   [0:0] icmp_fu_176_p2;
reg   [0:0] icmp_reg_290;
wire   [31:0] tmp_fu_119_p2;
wire   [31:0] sum2_fu_124_p2;
wire   [8:0] tmp_s_fu_181_p4;
wire  signed [9:0] tmp_7_cast_fu_189_p1;
wire  signed [9:0] tmp_8_fu_193_p2;
wire   [0:0] tmp_9_fu_203_p2;
wire  signed [31:0] tmp_8_cast_fu_199_p1;
reg   [0:0] ap_NS_fsm;
reg    ap_sig_pprstidle_pp0;




/// the current state (ap_CS_fsm) of the state machine. ///
always @ (posedge ap_clk)
begin : ap_ret_ap_CS_fsm
    if (ap_rst == 1'b1) begin
        ap_CS_fsm <= ap_ST_pp0_stg0_fsm_0;
    end else begin
        ap_CS_fsm <= ap_NS_fsm;
    end
end

/// ap_reg_ppiten_pp0_it1 assign process. ///
always @ (posedge ap_clk)
begin : ap_ret_ap_reg_ppiten_pp0_it1
    if (ap_rst == 1'b1) begin
        ap_reg_ppiten_pp0_it1 <= ap_const_logic_0;
    end else begin
        if (((ap_const_logic_1 == ap_sig_cseq_ST_pp0_stg0_fsm_0) & ~((ap_const_logic_1 == ap_reg_ppiten_pp0_it0) & (ap_start == ap_const_logic_0)))) begin
            ap_reg_ppiten_pp0_it1 <= ap_reg_ppiten_pp0_it0;
        end
    end
end

/// ap_reg_ppiten_pp0_it2 assign process. ///
always @ (posedge ap_clk)
begin : ap_ret_ap_reg_ppiten_pp0_it2
    if (ap_rst == 1'b1) begin
        ap_reg_ppiten_pp0_it2 <= ap_const_logic_0;
    end else begin
        if (~((ap_const_logic_1 == ap_reg_ppiten_pp0_it0) & (ap_start == ap_const_logic_0))) begin
            ap_reg_ppiten_pp0_it2 <= ap_reg_ppiten_pp0_it1;
        end
    end
end

/// ap_reg_ppiten_pp0_it3 assign process. ///
always @ (posedge ap_clk)
begin : ap_ret_ap_reg_ppiten_pp0_it3
    if (ap_rst == 1'b1) begin
        ap_reg_ppiten_pp0_it3 <= ap_const_logic_0;
    end else begin
        if (~((ap_const_logic_1 == ap_reg_ppiten_pp0_it0) & (ap_start == ap_const_logic_0))) begin
            ap_reg_ppiten_pp0_it3 <= ap_reg_ppiten_pp0_it2;
        end
    end
end

/// ap_reg_ppiten_pp0_it4 assign process. ///
always @ (posedge ap_clk)
begin : ap_ret_ap_reg_ppiten_pp0_it4
    if (ap_rst == 1'b1) begin
        ap_reg_ppiten_pp0_it4 <= ap_const_logic_0;
    end else begin
        if (~((ap_const_logic_1 == ap_reg_ppiten_pp0_it0) & (ap_start == ap_const_logic_0))) begin
            ap_reg_ppiten_pp0_it4 <= ap_reg_ppiten_pp0_it3;
        end
    end
end

/// ap_reg_ppiten_pp0_it5 assign process. ///
always @ (posedge ap_clk)
begin : ap_ret_ap_reg_ppiten_pp0_it5
    if (ap_rst == 1'b1) begin
        ap_reg_ppiten_pp0_it5 <= ap_const_logic_0;
    end else begin
        if (~((ap_const_logic_1 == ap_reg_ppiten_pp0_it0) & (ap_start == ap_const_logic_0))) begin
            ap_reg_ppiten_pp0_it5 <= ap_reg_ppiten_pp0_it4;
        end
    end
end

/// ap_reg_ppiten_pp0_it6 assign process. ///
always @ (posedge ap_clk)
begin : ap_ret_ap_reg_ppiten_pp0_it6
    if (ap_rst == 1'b1) begin
        ap_reg_ppiten_pp0_it6 <= ap_const_logic_0;
    end else begin
        if (~((ap_const_logic_1 == ap_reg_ppiten_pp0_it0) & (ap_start == ap_const_logic_0))) begin
            ap_reg_ppiten_pp0_it6 <= ap_reg_ppiten_pp0_it5;
        end
    end
end

/// ap_reg_ppiten_pp0_it7 assign process. ///
always @ (posedge ap_clk)
begin : ap_ret_ap_reg_ppiten_pp0_it7
    if (ap_rst == 1'b1) begin
        ap_reg_ppiten_pp0_it7 <= ap_const_logic_0;
    end else begin
        if (~((ap_const_logic_1 == ap_reg_ppiten_pp0_it0) & (ap_start == ap_const_logic_0))) begin
            ap_reg_ppiten_pp0_it7 <= ap_reg_ppiten_pp0_it6;
        end
    end
end

/// assign process. ///
always @(posedge ap_clk)
begin
    if (~((ap_const_logic_1 == ap_reg_ppiten_pp0_it0) & (ap_start == ap_const_logic_0))) begin
        ap_reg_ppstg_tmp_4_reg_274_pp0_it6 <= tmp_4_reg_274;
        ap_reg_ppstg_tmp_6_reg_284_pp0_it6 <= tmp_6_reg_284;
        ap_reg_ppstg_x0y2_read_reg_224_pp0_it2 <= ap_reg_ppstg_x0y2_read_reg_224_pp0_it1;
        ap_reg_ppstg_x1y2_read_reg_219_pp0_it2 <= ap_reg_ppstg_x1y2_read_reg_219_pp0_it1;
        ap_reg_ppstg_x1y2_read_reg_219_pp0_it3 <= ap_reg_ppstg_x1y2_read_reg_219_pp0_it2;
        ap_reg_ppstg_x2y2_read_reg_214_pp0_it2 <= ap_reg_ppstg_x2y2_read_reg_214_pp0_it1;
        ap_reg_ppstg_x2y2_read_reg_214_pp0_it3 <= ap_reg_ppstg_x2y2_read_reg_214_pp0_it2;
        ap_reg_ppstg_x2y2_read_reg_214_pp0_it4 <= ap_reg_ppstg_x2y2_read_reg_214_pp0_it3;
        ap_reg_ppstg_y_reg_269_pp0_it6 <= y_reg_269;
        icmp_reg_290 <= icmp_fu_176_p2;
        tmp_1_reg_254 <= tmp_1_fu_134_p2;
        tmp_2_reg_259 <= tmp_2_fu_138_p2;
        tmp_3_reg_264 <= tmp_3_fu_142_p2;
        tmp_4_reg_274 <= y_fu_146_p2[ap_const_lv32_1F];
        tmp_5_reg_279 <= {{y_fu_146_p2[ap_const_lv32_1F : ap_const_lv32_8]}};
        tmp_6_reg_284 <= y_fu_146_p2[ap_const_lv32_1F];
        y_reg_269 <= y_fu_146_p2;
    end
end

/// assign process. ///
always @(posedge ap_clk)
begin
    if (((ap_const_logic_1 == ap_sig_cseq_ST_pp0_stg0_fsm_0) & ~((ap_const_logic_1 == ap_reg_ppiten_pp0_it0) & (ap_start == ap_const_logic_0)))) begin
        ap_reg_ppstg_x0y2_read_reg_224_pp0_it1 <= x0y2_read_reg_224;
        ap_reg_ppstg_x1y2_read_reg_219_pp0_it1 <= x1y2_read_reg_219;
        ap_reg_ppstg_x2y1_read_reg_229_pp0_it1 <= x2y1_read_reg_229;
        ap_reg_ppstg_x2y2_read_reg_214_pp0_it1 <= x2y2_read_reg_214;
        sum3_neg_reg_249 <= sum3_neg_fu_128_p2;
        tmp1_reg_239 <= tmp1_fu_107_p2;
        tmp2_reg_244 <= tmp2_fu_113_p2;
        x0y2_read_reg_224 <= x0y2;
        x1y1_read_reg_234 <= x1y1;
        x1y2_read_reg_219 <= x1y2;
        x2y1_read_reg_229 <= x2y1;
        x2y2_read_reg_214 <= x2y2;
    end
end

/// ap_done assign process. ///
always @ (ap_start or ap_reg_ppiten_pp0_it0 or ap_reg_ppiten_pp0_it7)
begin
    if (((ap_const_logic_1 == ap_reg_ppiten_pp0_it7) & ~((ap_const_logic_1 == ap_reg_ppiten_pp0_it0) & (ap_start == ap_const_logic_0)))) begin
        ap_done = ap_const_logic_1;
    end else begin
        ap_done = ap_const_logic_0;
    end
end

/// ap_idle assign process. ///
always @ (ap_start or ap_sig_cseq_ST_pp0_stg0_fsm_0 or ap_reg_ppiten_pp0_it0 or ap_reg_ppiten_pp0_it1 or ap_reg_ppiten_pp0_it2 or ap_reg_ppiten_pp0_it3 or ap_reg_ppiten_pp0_it4 or ap_reg_ppiten_pp0_it5 or ap_reg_ppiten_pp0_it6 or ap_reg_ppiten_pp0_it7)
begin
    if ((~(ap_const_logic_1 == ap_start) & (ap_const_logic_1 == ap_sig_cseq_ST_pp0_stg0_fsm_0) & (ap_const_logic_0 == ap_reg_ppiten_pp0_it0) & (ap_const_logic_0 == ap_reg_ppiten_pp0_it1) & (ap_const_logic_0 == ap_reg_ppiten_pp0_it2) & (ap_const_logic_0 == ap_reg_ppiten_pp0_it3) & (ap_const_logic_0 == ap_reg_ppiten_pp0_it4) & (ap_const_logic_0 == ap_reg_ppiten_pp0_it5) & (ap_const_logic_0 == ap_reg_ppiten_pp0_it6) & (ap_const_logic_0 == ap_reg_ppiten_pp0_it7))) begin
        ap_idle = ap_const_logic_1;
    end else begin
        ap_idle = ap_const_logic_0;
    end
end

/// ap_ready assign process. ///
always @ (ap_start or ap_sig_cseq_ST_pp0_stg0_fsm_0 or ap_reg_ppiten_pp0_it0)
begin
    if (((ap_const_logic_1 == ap_sig_cseq_ST_pp0_stg0_fsm_0) & (ap_const_logic_1 == ap_reg_ppiten_pp0_it0) & ~((ap_const_logic_1 == ap_reg_ppiten_pp0_it0) & (ap_start == ap_const_logic_0)))) begin
        ap_ready = ap_const_logic_1;
    end else begin
        ap_ready = ap_const_logic_0;
    end
end

/// ap_sig_cseq_ST_pp0_stg0_fsm_0 assign process. ///
always @ (ap_sig_bdd_17)
begin
    if (ap_sig_bdd_17) begin
        ap_sig_cseq_ST_pp0_stg0_fsm_0 = ap_const_logic_1;
    end else begin
        ap_sig_cseq_ST_pp0_stg0_fsm_0 = ap_const_logic_0;
    end
end

/// ap_sig_pprstidle_pp0 assign process. ///
always @ (ap_start or ap_reg_ppiten_pp0_it0 or ap_reg_ppiten_pp0_it1 or ap_reg_ppiten_pp0_it2 or ap_reg_ppiten_pp0_it3 or ap_reg_ppiten_pp0_it4 or ap_reg_ppiten_pp0_it5 or ap_reg_ppiten_pp0_it6)
begin
    if (((ap_const_logic_0 == ap_reg_ppiten_pp0_it0) & (ap_const_logic_0 == ap_reg_ppiten_pp0_it1) & (ap_const_logic_0 == ap_reg_ppiten_pp0_it2) & (ap_const_logic_0 == ap_reg_ppiten_pp0_it3) & (ap_const_logic_0 == ap_reg_ppiten_pp0_it4) & (ap_const_logic_0 == ap_reg_ppiten_pp0_it5) & (ap_const_logic_0 == ap_reg_ppiten_pp0_it6) & (ap_const_logic_0 == ap_start))) begin
        ap_sig_pprstidle_pp0 = ap_const_logic_1;
    end else begin
        ap_sig_pprstidle_pp0 = ap_const_logic_0;
    end
end
/// the next state (ap_NS_fsm) of the state machine. ///
always @ (ap_start or ap_CS_fsm or ap_reg_ppiten_pp0_it0 or ap_sig_pprstidle_pp0)
begin
    case (ap_CS_fsm)
        ap_ST_pp0_stg0_fsm_0 : 
        begin
            ap_NS_fsm = ap_ST_pp0_stg0_fsm_0;
        end
        default : 
        begin
            ap_NS_fsm = 'bx;
        end
    endcase
end

assign ap_reg_ppiten_pp0_it0 = ap_start;
assign ap_return = ((tmp_9_fu_203_p2)? tmp_8_cast_fu_199_p1: ap_reg_ppstg_y_reg_269_pp0_it6);

/// ap_sig_bdd_17 assign process. ///
always @ (ap_CS_fsm)
begin
    ap_sig_bdd_17 = (ap_CS_fsm[ap_const_lv32_0] == ap_const_lv1_1);
end
assign icmp_fu_176_p2 = ($signed(tmp_5_reg_279) > $signed(24'b000000000000000000000000)? 1'b1: 1'b0);
assign sum2_fu_124_p2 = (tmp2_reg_244 + tmp1_reg_239);
assign sum3_neg_fu_128_p2 = (tmp_fu_119_p2 - sum2_fu_124_p2);
assign tmp1_fu_107_p2 = (x1y0 + x0y0);
assign tmp2_fu_113_p2 = (x2y0 + x0y1);
assign tmp_1_fu_134_p2 = (sum3_neg_reg_249 - ap_reg_ppstg_x2y1_read_reg_229_pp0_it1);
assign tmp_2_fu_138_p2 = (tmp_1_reg_254 - ap_reg_ppstg_x0y2_read_reg_224_pp0_it2);
assign tmp_3_fu_142_p2 = (tmp_2_reg_259 - ap_reg_ppstg_x1y2_read_reg_219_pp0_it3);
assign tmp_7_cast_fu_189_p1 = $signed(tmp_s_fu_181_p4);
assign tmp_8_cast_fu_199_p1 = tmp_8_fu_193_p2;
assign tmp_8_fu_193_p2 = ($signed(tmp_7_cast_fu_189_p1) + $signed(ap_const_lv10_FF));
assign tmp_9_fu_203_p2 = (ap_reg_ppstg_tmp_4_reg_274_pp0_it6 | icmp_reg_290);
assign tmp_fu_119_p2 = x1y1_read_reg_234 << ap_const_lv32_3;
assign tmp_s_fu_181_p4 = {{{{ap_reg_ppstg_tmp_6_reg_284_pp0_it6}, {ap_const_lv7_0}}}, {ap_reg_ppstg_tmp_6_reg_284_pp0_it6}};
assign y_fu_146_p2 = (tmp_3_reg_264 - ap_reg_ppstg_x2y2_read_reg_214_pp0_it4);


endmodule //laplacian_filter

  1. 2015年01月21日 04:57 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2014.4 の高位合成テスト14(ラプラシアンフィルタ9、Clock Period の変更2)

”Vivado HLS 2014.4 の高位合成テスト13(ラプラシアンフィルタ8、Clock Period の変更1)”の続き。

前回は、Clock Period = 5 ns の場合までラプラシアンフィルタを高位合成したので、今回は次のClock Period = 4 ns の場合から、最後、動作周波数が高すぎてEstimated の値がタイミングを満たせなくなるまでやってみる。

・Clock Period = 4 ns の場合
Clock Period = 5 ns の場合と同じだった。最初なので、高位合成レポートを貼っておく。
Vivado_HLS_Study_69_150120.png

・Clock Period = 3 ns の場合
Latency = 9 クロックとなった。そろそろ限界かな?
Vivado_HLS_Study_70_150120.png

Analysis 画面のハードウェアのスケジューリングを見てみよう(Resourceタブ)。
Vivado_HLS_Study_71_150120.png

ほとんど2項演算になってきた。

・Clock Period = 2 ns の場合
Latency = 31 クロックとなったが、Estimated は 2.40 ns で間に合わない。
Vivado_HLS_Study_72_150120.png

Analysis 画面のハードウェアのスケジューリングを見てみよう(Resourceタブ)。
Vivado_HLS_Study_73_150120.png

1つの演算を複数クロックで行うようにスケジューリングされている。

ZYBO に搭載されている xc7z0100clg400-1 では、Clock Period = 2.4 ns で限界のようだ。でも、Clock Period = 2.4 ns ということは、416 MHz で動作できるように合成できるということなので、凄いと思う。

次に今度はLatencyを100MHzの 2 から 1 に減らしてみよう。

・Clock Period = 20 ns の場合
Latency = 1 クロックになった。Estimated は 16.14 ns だった。約 17 ns で Latency = 1 クロックとなることがわかった。約 60 MHz 程度の動作周波数だ。
Vivado_HLS_Study_74_150120.png

もう一度、Analysis 画面のハードウェアのスケジューリングを見てみよう(Resourceタブ)。
Vivado_HLS_Study_75_150120.png

ラプラシアンフィルタのほとんどの演算は、1クロックで行われている。次のクロックでは、飽和演算が行われているようだ。

Solution Settings のSynthesis のプロパティの内のClock Period で Latency がいろいろと変わるということがわかった。うかつな話だが、今まで、何処でLatency の値を変えるのか疑問だった。
Vivado HLSは、Xilinxのツールなので、XilinxのFPGA 品種を指定する。その指定されたFPGA の品種でクロック周期を指定すれば、どのくらいのパイプライン・ステージで実行できるかは明確なので、クロック周期を指定するのだろう?と思う。
  1. 2015年01月20日 04:53 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2014.4 の高位合成テスト13(ラプラシアンフィルタ8、Clock Period の変更1)

Vivado HLS 2014.4 の高位合成テスト12(ラプラシアンフィルタ7、PIPELINEディレクティブのシミュレーション)”の続き。

Vivado HLS 2014.4 の高位合成テスト11(ラプラシアンフィルタ6、PIPELINEディレクティブ)”でラプラシアンフィルタをPIPELINEディレクティブを追加して高位合成したら、latency = 2 だった。それでは、latency の値が変更される時はどんな時だろうか?
それは、Vivado HLSでは、Clock Period が変化した時ではないだろうか?
Clock Period が短くなって、つまり動作周波数が上がって、1クロックでやっていた演算の数が減っていくと latency は伸びていくだろう?
逆に、Clock Period が長くなって、つまり動作周波数が下がって、1クロックでやっていた演算の数が減ると latency は縮まるだろう?

先に、Clock Period が短くなる方から検証してみることにする。
最初に予測を立ててみよう。前回のClock Period = 10 ns の結果から、Timing (ns) の Summary の Estimated は、7.58 ns なので、多分、latency の値が変化するのは、Clock Period = 7 ns からだろうと思う。
Vivado_HLS_Study_54_150116.png

Clock Period の変更方法としては、solution メニューから solution setting... を選択する。

Solution Settings ダイアログの左のペインでSynthesis を選択してClock Period のテキストボックスに値を入れる。
Vivado_HLS_Study_63_150119.png

Clock Period = 9 ns の場合
latency に変更は無かった

Clock Period = 8 ns の場合
latency が 2 から 3 になった。
Vivado_HLS_Study_64_150119.png

Clock Period = 7 ns の場合
latency が 4 になった。
Vivado_HLS_Study_65_150119.png

Clock Period = 6 ns の場合
latency が 4 のままだった。

Clock Period = 5 ns の場合
latency が 7 になった。
Vivado_HLS_Study_66_150119.png

この辺りで、リソースの使用数を比較してみよう。
Clock Period = 10 ns の場合のリソースの使用数を示す。
Vivado_HLS_Study_55_150116.png

Clock Period = 5 ns の場合のリソースの使用数を示す。
Vivado_HLS_Study_67_150119.png

Clock Period = 10 ns の場合とClock Period = 5 ns の場合では、LUTの使用数は297で変わらないが、FFの使用数は、227から484に増えている。

Clock Period = 5 ns の場合のAnalysis 画面のハードウェアのスケジューリングを見てみよう(Resourceタブ)。
Vivado_HLS_Study_68_150119.png

Clock Period = 10 ns の場合のAnalysis 画面のハードウェアのスケジューリングを下に示す。
Vivado_HLS_Study_60_150116.png

Clock Period = 10 ns の場合と比べて、Clock Period = 5 ns の場合は、クロックごとに演算が分割されている。
  1. 2015年01月19日 04:12 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2014.4 の高位合成テスト12(ラプラシアンフィルタ7、PIPELINEディレクティブのシミュレーション)

Vivado HLS 2014.4 の高位合成テスト11(ラプラシアンフィルタ6、PIPELINEディレクティブ)”の続き。

前回は、ラプラシアンフィルタのCソースコードに、PIPELINEディレクティブを追加して高位合成を行った。
今回は、合成されたVerilog HDL コードのシミュレーションを行った。

PIPELINEディレクティブを追加したラプラシアンフィルタのHDLコードはLatency は 2 クロックで、Interval が 1 クロックとレポートされていたので、それをシミュレーションで確認することにした。

・Vivado で同様にZYBO のプロジェクトを作製した。

・高位合成されたVerilog HDL ファイルの、laplacian_filter.v と、テストベンチの laplacian_filter_tb.v をプロジェクトに追加した。
( laplacian_filter_tb.v のHDLソースコードは、”Vivado HLS 2014.4 の高位合成テスト7(ラプラシアンフィルタ2、シミュレーション)”を参照下さい)

・Vivado Simulator で論理シミュレーションを行った。(laplacian_filter_tb.v の LAP_FILTER_END_COUNT = 0 とした)
下にシミュレーション波形を示す。
Vivado_HLS_Study_62_150118.png

上の波形を見ると、ap_start を 2 クロック連続して 1 にアサートしているのがわかると思う。それに対する応答は 2 クロック後に ap_done が 1 になることだ。ap_done も 2 クロック連続して 1 にアサートされている。ap_done に合わせてラプラシアンフィルタの結果が、ap_return に出力されているのがわかる。
パイプライン化成功だ。
  1. 2015年01月18日 05:10 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

高位合成友の会に参加、そしてPyCoRAMは広大な無駄のLチカの夢が見られるのか?

昨日、高位合成友の会に行ってきました。

3種類の高位合成ツールのご紹介がありました。感想を書いてみたいと思います。

たばたさんの 「neon light compiler」は、スプリクト言語処理系で、最適化エンジンが3つの中にで一番進んでいるのが分かりました。でも、FPGAに実装できないので、やってみる気になれません。今後に期待したいと思います。

みよしさんの「Synthesijer」は、私も使ったことがあります。一番始めやすいと思います。
まずはLチカのサンプルアプリがあるのが良いですし、ハードのHello World はなんといってもLチカですよね。演算のチェイニングなどのツールの改良ロードマップもあるし、これからにも期待したいです。
ただ、Synthesijer.scala で書くのだったら、HDLの方が私は書きやすそうです。VHDL2008 やSystemVerilog もありますし。(X社のツールで使えるのかどうか?は別問題かもしれませんが。。。)
高位合成友の会での「Synthesijer」の発表スライドがあります(Synthesijer@高位合成友の会

高前田さんの「PyCoRAM」は、初めて話を聞いたんですが、とってもリッチな構成の高位合成ツールでした。Python記述部分の最適化エンジンは、まだ搭載されていないようです。良くPyCoRAMを知っている人が使えば性能は相当出そうです。構成については、スライドを参照下さい。

メモリ抽象化フレームワークPyCoRAMを用いたソフトプロセッサ混載FPGAアクセラレータの開発
PyCoRAM: Python-Verilog高位合成とメモリ抽象化によるFPGAアクセラレータ向けIPコア開発フレームワーク (FPGAX #05)
PyCoRAMを用いたグラフ処理FPGAアクセラレータ

しかし、このリッチな構成でハードのHello World のLチカはできるのでしょうか?質問してみたところ、Verilog 部でやって下さいとのことでした。質問したのは、構成がリッチすぎて、ツールを使いはじめるための初心者用チュートリアルが思いつかなかったからです。
高位合成友の会で質問した趣旨とは正反対になりますが、今日お風呂に入りながらPyCoRAM のリソースを使い切った、とてもリッチなLチカ を考えてみました。DMA の機能をフルに使ったLチカでなければ意味ありません。Lチカをするためにダブル・バッファにします。

・User Logic は、カウンタを作ってLチカ用にクロックをカウントし、その1, 0 の出力をCoRAM Memory か CoRAM Stream でDRAM にWrite します。これがDMA Write 側です。
・カウンタのカウント値は変えられるようにして、最初は0.5秒間隔、次は、1秒間間隔とか、Lチカの点滅の間隔を変更します。
・次の間隔のLチカ点滅データは、前のLチカ点滅データとは別のメモリ領域にDMA します。前のLチカ点滅データのメモリ領域は現在のLチカのためにDMA Readされて使っているからです。(ダブル・バッファ)
・前にDMA Write されたLチカ点滅データのメモリ領域からDMA Read してLチカのLED出力とします。
・Pythonで書かれた制御部はダブル・バッファの管理やDMAの制御などの全体の制御を行います。


こんな感じのAXIバスの帯域を使い切ったリッチなLチカをやってみたいですね。。。
  1. 2015年01月17日 21:16 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:0

ZYBOのUbuntu ブート用のMicroSDカードをバックアップからコピーする手順

ZYBOのUbuntu ブート用のMicroSDカードに不具合が生じてバックアップからコピーする手順の覚書です。

・まずは、MicroSDカードのパーティションが切れていない場合は、MircoSDカードのパーティションを作製します。(”ZedBoard用のUbuntu Linuxをビルド6(SDカードを用意する)”参照。但し、最初のパーティションの名前はZYBO_BOOTにしています)

・パソコンでVirtualBoxからUbuntu を起動します。

・USBのカード・リーダー/ライターにセットしてあるパーティションを作ったMicroSDカードをVirtualBox 上のUbuntu にマウントします。

・マウントしたZYBO_BOOTには、バックアップしてあったZYBO_BOOTの内容をファイルマネージャのドラック&ドロップでも cp コマンドでもどちらでも良いのでコピーします。

・ROOT_FSは root ユーザーでコピーしてあるので、下のようなコマンドを使います。
masaaki@masaaki-VirtualBox:/media/masaaki/ROOT_FS$ sudo cp -R -f ~/ZYBO/backup/Ubuntu14.04_150109/ROOT_FS/* .

・これで、MicroSDカードのコピーが出来上がったので、ZYBOに入れて電源ONします。

・ZYBOのシリアルポート経由でTera Termを起動します。

・/home/linaro のユーザーとグループがroot になっているので、両方共 linaro に変更します。
cd /home
chown -R -f linaro:linaro linaro


・ifconfig を実行して、DHCPで割り振られているIP を確認したら、Tera TermでそのIP にSSH を使用して linaro ユーザーで、ログインします。

・sudo コマンドを実行すると、実行できません。

sudo: /usr/bin/sudo must be owned by uid 0 and have the setuid bit set


・次のコマンドを実行すると、sudo が実行できるようになります。(”/usr/bin/sudo must be owned by uid 0 and have the setuid bit set”参照。 root ユーザーで実行)
chmod 4755 /usr/bin/sudo
  1. 2015年01月16日 05:23 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2014.4 の高位合成テスト11(ラプラシアンフィルタ6、PIPELINEディレクティブ)

Vivado HLS 2014.4 の高位合成テスト10(ラプラシアンフィルタ5、LATENCYディレクティブのシミュレーション)”の続き。

今回は、PIPELINEディレクティブを試してみることにした。

・solution3 を新しく作り、LATENCYディレクティブを消去して、Directive タブで、PIPLINEディレクティブを追加した。
Vivado_HLS_Study_53_150115.png

下に、directives.tcl の内容を示す。

set_directive_pipeline "laplacian_filter"


・C Synthesis アイコンをクリックして、Cからの高位合成を行った。そのレポートを下に示す。
Vivado_HLS_Study_54_150116.png
Vivado_HLS_Study_55_150116.png
Vivado_HLS_Study_56_150116.png
Vivado_HLS_Study_57_150116.png

Latency は 2 クロックなのに、Interval が 1 になっている。

Register は 227 個で、Latency = 2, Latency = 1 のときと比べて、明らかに多くなった。
Vivado_HLS_Study_61_150116.png

・Analysis 画面にした。
Vivado_HLS_Study_58_150116.png

22番めのy_1(select) はCソースで言うと、”if (y<0)”の部分のようだ。
Vivado_HLS_Study_59_150116.png

Resource タブをクリックした。
Vivado_HLS_Study_60_150116.png

すべての read が C1 に集まっている。

PIPELINEディレクティブを入れて高位合成された laplacian_filter.v を貼っておく。

// ==============================================================
// RTL generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2014.4
// Copyright (C) 2014 Xilinx Inc. All rights reserved.
// 
// ===========================================================

`timescale 1 ns / 1 ps 

(* CORE_GENERATION_INFO="laplacian_filter,hls_ip_2014_4,{HLS_INPUT_TYPE=cxx,HLS_INPUT_FLOAT=0,HLS_INPUT_FIXED=0,HLS_INPUT_PART=xc7z010clg400-1,HLS_INPUT_CLOCK=10.000000,HLS_INPUT_ARCH=pipeline,HLS_SYN_CLOCK=7.581000,HLS_SYN_LAT=2,HLS_SYN_TPT=1,HLS_SYN_MEM=0,HLS_SYN_DSP=0,HLS_SYN_FF=227,HLS_SYN_LUT=297}" *)

module laplacian_filter (
        ap_clk,
        ap_rst,
        ap_start,
        ap_done,
        ap_idle,
        ap_ready,
        x0y0,
        x1y0,
        x2y0,
        x0y1,
        x1y1,
        x2y1,
        x0y2,
        x1y2,
        x2y2,
        ap_return
);

parameter    ap_const_logic_1 = 1'b1;
parameter    ap_const_logic_0 = 1'b0;
parameter    ap_ST_pp0_stg0_fsm_0 = 1'b1;
parameter    ap_const_lv32_0 = 32'b00000000000000000000000000000000;
parameter    ap_const_lv1_1 = 1'b1;
parameter    ap_const_lv32_3 = 32'b11;
parameter    ap_const_lv32_1F = 32'b11111;
parameter    ap_const_lv32_8 = 32'b1000;
parameter    ap_const_lv24_0 = 24'b000000000000000000000000;
parameter    ap_const_lv7_0 = 7'b0000000;
parameter    ap_const_lv10_FF = 10'b11111111;
parameter    ap_true = 1'b1;

input   ap_clk;
input   ap_rst;
input   ap_start;
output   ap_done;
output   ap_idle;
output   ap_ready;
input  [31:0] x0y0;
input  [31:0] x1y0;
input  [31:0] x2y0;
input  [31:0] x0y1;
input  [31:0] x1y1;
input  [31:0] x2y1;
input  [31:0] x0y2;
input  [31:0] x1y2;
input  [31:0] x2y2;
output  [31:0] ap_return;

reg ap_done;
reg ap_idle;
reg ap_ready;
(* fsm_encoding = "none" *) reg   [0:0] ap_CS_fsm = 1'b1;
reg    ap_sig_cseq_ST_pp0_stg0_fsm_0;
reg    ap_sig_bdd_17;
wire    ap_reg_ppiten_pp0_it0;
reg    ap_reg_ppiten_pp0_it1 = 1'b0;
reg    ap_reg_ppiten_pp0_it2 = 1'b0;
reg   [31:0] x2y2_read_reg_225;
reg   [31:0] ap_reg_ppstg_x2y2_read_reg_225_pp0_it1;
reg   [31:0] x1y2_read_reg_230;
reg   [31:0] x0y2_read_reg_235;
reg   [31:0] x2y1_read_reg_240;
wire   [31:0] sum3_neg_fu_131_p2;
reg   [31:0] sum3_neg_reg_245;
wire   [31:0] tmp_3_fu_146_p2;
reg   [31:0] tmp_3_reg_250;
wire   [31:0] tmp2_fu_119_p2;
wire   [31:0] tmp1_fu_113_p2;
wire   [31:0] tmp_fu_107_p2;
wire   [31:0] sum2_fu_125_p2;
wire   [31:0] tmp_1_fu_137_p2;
wire   [31:0] tmp_2_fu_141_p2;
wire   [31:0] y_fu_151_p2;
wire   [23:0] tmp_5_fu_163_p4;
wire   [0:0] tmp_6_fu_179_p3;
wire   [8:0] tmp_s_fu_187_p4;
wire  signed [9:0] tmp_7_cast_fu_197_p1;
wire  signed [9:0] tmp_8_fu_201_p2;
wire   [0:0] tmp_4_fu_155_p3;
wire   [0:0] icmp_fu_173_p2;
wire   [0:0] tmp_9_fu_211_p2;
wire  signed [31:0] tmp_8_cast_fu_207_p1;
reg   [0:0] ap_NS_fsm;
reg    ap_sig_pprstidle_pp0;




/// the current state (ap_CS_fsm) of the state machine. ///
always @ (posedge ap_clk)
begin : ap_ret_ap_CS_fsm
    if (ap_rst == 1'b1) begin
        ap_CS_fsm <= ap_ST_pp0_stg0_fsm_0;
    end else begin
        ap_CS_fsm <= ap_NS_fsm;
    end
end

/// ap_reg_ppiten_pp0_it1 assign process. ///
always @ (posedge ap_clk)
begin : ap_ret_ap_reg_ppiten_pp0_it1
    if (ap_rst == 1'b1) begin
        ap_reg_ppiten_pp0_it1 <= ap_const_logic_0;
    end else begin
        if (((ap_const_logic_1 == ap_sig_cseq_ST_pp0_stg0_fsm_0) & ~((ap_const_logic_1 == ap_reg_ppiten_pp0_it0) & (ap_start == ap_const_logic_0)))) begin
            ap_reg_ppiten_pp0_it1 <= ap_reg_ppiten_pp0_it0;
        end
    end
end

/// ap_reg_ppiten_pp0_it2 assign process. ///
always @ (posedge ap_clk)
begin : ap_ret_ap_reg_ppiten_pp0_it2
    if (ap_rst == 1'b1) begin
        ap_reg_ppiten_pp0_it2 <= ap_const_logic_0;
    end else begin
        if (~((ap_const_logic_1 == ap_reg_ppiten_pp0_it0) & (ap_start == ap_const_logic_0))) begin
            ap_reg_ppiten_pp0_it2 <= ap_reg_ppiten_pp0_it1;
        end
    end
end

/// assign process. ///
always @(posedge ap_clk)
begin
    if (((ap_const_logic_1 == ap_sig_cseq_ST_pp0_stg0_fsm_0) & ~((ap_const_logic_1 == ap_reg_ppiten_pp0_it0) & (ap_start == ap_const_logic_0)))) begin
        ap_reg_ppstg_x2y2_read_reg_225_pp0_it1 <= x2y2_read_reg_225;
        sum3_neg_reg_245 <= sum3_neg_fu_131_p2;
        tmp_3_reg_250 <= tmp_3_fu_146_p2;
        x0y2_read_reg_235 <= x0y2;
        x1y2_read_reg_230 <= x1y2;
        x2y1_read_reg_240 <= x2y1;
        x2y2_read_reg_225 <= x2y2;
    end
end

/// ap_done assign process. ///
always @ (ap_start or ap_reg_ppiten_pp0_it0 or ap_reg_ppiten_pp0_it2)
begin
    if (((ap_const_logic_1 == ap_reg_ppiten_pp0_it2) & ~((ap_const_logic_1 == ap_reg_ppiten_pp0_it0) & (ap_start == ap_const_logic_0)))) begin
        ap_done = ap_const_logic_1;
    end else begin
        ap_done = ap_const_logic_0;
    end
end

/// ap_idle assign process. ///
always @ (ap_start or ap_sig_cseq_ST_pp0_stg0_fsm_0 or ap_reg_ppiten_pp0_it0 or ap_reg_ppiten_pp0_it1 or ap_reg_ppiten_pp0_it2)
begin
    if ((~(ap_const_logic_1 == ap_start) & (ap_const_logic_1 == ap_sig_cseq_ST_pp0_stg0_fsm_0) & (ap_const_logic_0 == ap_reg_ppiten_pp0_it0) & (ap_const_logic_0 == ap_reg_ppiten_pp0_it1) & (ap_const_logic_0 == ap_reg_ppiten_pp0_it2))) begin
        ap_idle = ap_const_logic_1;
    end else begin
        ap_idle = ap_const_logic_0;
    end
end

/// ap_ready assign process. ///
always @ (ap_start or ap_sig_cseq_ST_pp0_stg0_fsm_0 or ap_reg_ppiten_pp0_it0)
begin
    if (((ap_const_logic_1 == ap_sig_cseq_ST_pp0_stg0_fsm_0) & (ap_const_logic_1 == ap_reg_ppiten_pp0_it0) & ~((ap_const_logic_1 == ap_reg_ppiten_pp0_it0) & (ap_start == ap_const_logic_0)))) begin
        ap_ready = ap_const_logic_1;
    end else begin
        ap_ready = ap_const_logic_0;
    end
end

/// ap_sig_cseq_ST_pp0_stg0_fsm_0 assign process. ///
always @ (ap_sig_bdd_17)
begin
    if (ap_sig_bdd_17) begin
        ap_sig_cseq_ST_pp0_stg0_fsm_0 = ap_const_logic_1;
    end else begin
        ap_sig_cseq_ST_pp0_stg0_fsm_0 = ap_const_logic_0;
    end
end

/// ap_sig_pprstidle_pp0 assign process. ///
always @ (ap_start or ap_reg_ppiten_pp0_it0 or ap_reg_ppiten_pp0_it1)
begin
    if (((ap_const_logic_0 == ap_reg_ppiten_pp0_it0) & (ap_const_logic_0 == ap_reg_ppiten_pp0_it1) & (ap_const_logic_0 == ap_start))) begin
        ap_sig_pprstidle_pp0 = ap_const_logic_1;
    end else begin
        ap_sig_pprstidle_pp0 = ap_const_logic_0;
    end
end
/// the next state (ap_NS_fsm) of the state machine. ///
always @ (ap_start or ap_CS_fsm or ap_reg_ppiten_pp0_it0 or ap_sig_pprstidle_pp0)
begin
    case (ap_CS_fsm)
        ap_ST_pp0_stg0_fsm_0 : 
        begin
            ap_NS_fsm = ap_ST_pp0_stg0_fsm_0;
        end
        default : 
        begin
            ap_NS_fsm = 'bx;
        end
    endcase
end

assign ap_reg_ppiten_pp0_it0 = ap_start;
assign ap_return = ((tmp_9_fu_211_p2)? tmp_8_cast_fu_207_p1: y_fu_151_p2);

/// ap_sig_bdd_17 assign process. ///
always @ (ap_CS_fsm)
begin
    ap_sig_bdd_17 = (ap_CS_fsm[ap_const_lv32_0] == ap_const_lv1_1);
end
assign icmp_fu_173_p2 = ($signed(tmp_5_fu_163_p4) > $signed(24'b000000000000000000000000)? 1'b1: 1'b0);
assign sum2_fu_125_p2 = (tmp2_fu_119_p2 + tmp1_fu_113_p2);
assign sum3_neg_fu_131_p2 = (tmp_fu_107_p2 - sum2_fu_125_p2);
assign tmp1_fu_113_p2 = (x1y0 + x0y0);
assign tmp2_fu_119_p2 = (x2y0 + x0y1);
assign tmp_1_fu_137_p2 = (sum3_neg_reg_245 - x2y1_read_reg_240);
assign tmp_2_fu_141_p2 = (tmp_1_fu_137_p2 - x0y2_read_reg_235);
assign tmp_3_fu_146_p2 = (tmp_2_fu_141_p2 - x1y2_read_reg_230);
assign tmp_4_fu_155_p3 = y_fu_151_p2[ap_const_lv32_1F];
assign tmp_5_fu_163_p4 = {{y_fu_151_p2[ap_const_lv32_1F : ap_const_lv32_8]}};
assign tmp_6_fu_179_p3 = y_fu_151_p2[ap_const_lv32_1F];
assign tmp_7_cast_fu_197_p1 = $signed(tmp_s_fu_187_p4);
assign tmp_8_cast_fu_207_p1 = tmp_8_fu_201_p2;
assign tmp_8_fu_201_p2 = ($signed(tmp_7_cast_fu_197_p1) + $signed(ap_const_lv10_FF));
assign tmp_9_fu_211_p2 = (tmp_4_fu_155_p3 | icmp_fu_173_p2);
assign tmp_fu_107_p2 = x1y1 << ap_const_lv32_3;
assign tmp_s_fu_187_p4 = {{{{tmp_6_fu_179_p3}, {ap_const_lv7_0}}}, {tmp_6_fu_179_p3}};
assign y_fu_151_p2 = (tmp_3_reg_250 - ap_reg_ppstg_x2y2_read_reg_225_pp0_it1);


endmodule //laplacian_filter


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

Vivado HLS 2014.4 の高位合成テスト10(ラプラシアンフィルタ5、LATENCYディレクティブのシミュレーション)

Vivado HLS 2014.4 の高位合成テスト9(ラプラシアンフィルタ4、LATENCYディレクティブ)”の続き。

前回は、laplacian_filter.cpp に LATENCY ディレクティブを追加して、Latencyを 2 から 1 に改善したが、Estimated は 12.46 ns となって規格を満足しなくなってしまった。
今回は、Latency = 1 で生成したHDLファイルをシミュレーションしてみた。
テストベンチは、”Vivado HLS 2014.4 の高位合成テスト7(ラプラシアンフィルタ2、シミュレーション)”に貼った laplacian_filter_tb.v を LAP_FILTER_END_COUNT = 2; で使用した。
早速シミュレーション結果を下に示す。
Vivado_HLS_Study_52_150115.png

ap_start = 1 になってから、ap_done = 1 になるまでは1クロックなので、Latency = 1 である。Interval = 2 となった。
  1. 2015年01月15日 04:40 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2014.4 の高位合成テスト9(ラプラシアンフィルタ4、LATENCYディレクティブ)

Vivado HLS 2014.4 の高位合成テスト8(ラプラシアンフィルタ3、論理合成)”の続き。

今回は、LATENCYディレクティブを設定して、現在のLatency = 2 から、Latency = 1 への性能の改善を目指す。

LATENCYディレクティブを設定するために、solutionを追加して、solution2 とした。これでLATENCYディレクティブを設定した場合と、設定しなかった場合 (solution1) の場合がすぐに見比べられる。

・Project メニューから New Solution... を選択した。
Vivado_HLS_Study_42_150114.png

・Solution Name に solution2 と入っていた。デフォルトで Finish ボタンをクリックした。
Vivado_HLS_Study_43_150114.png

・左のウインドウに solution2 ができた。

・右のウインドウにDirective タブをクリックして、laplacian_filter を右クリックすると、Insert Directive... が出るので選択する。
Vivado_HLS_Study_44_150114.png

・Directive をクリックして、LATENCYを選択した。

・Options の min に 1 を max に 1 を入力した。
Vivado_HLS_Study_45_150114.png

・solution2 -> constrains -> directive.tcl を開くと、ディレクティブが記述されていた。

set_directive_latency -min 1 -max 1 "laplacian_filter"

Vivado_HLS_Study_46_150114.png

・この状態で C Synthesis ボタンをクリックして、Vivado HLSの高位合成を行った。
Vivado_HLS_Study_47_150114.png
Vivado_HLS_Study_48_150114.png
Vivado_HLS_Study_49_150114.png
Vivado_HLS_Study_50_150114.png

Timing の Target が 10.00 ns なのに、Estimated だけど 12.46 ns になってしまった。
Latency = 1, Interval = 2 になった。

Latency = 2 の時と、Latency = 1 の時の使用リソースの違いを下に示す。
Vivado_HLS_Study_51_150114.png

Register の値が違っている。これはLatencyが1つ少ないので、Latency = 1 の方が少なくなっていると思う。

Latency = 1 の時の laplacian_filter.v を下に貼っておく。

/ ==============================================================
// RTL generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2014.4
// Copyright (C) 2014 Xilinx Inc. All rights reserved.
// 
// ===========================================================

`timescale 1 ns / 1 ps 

(* CORE_GENERATION_INFO="laplacian_filter,hls_ip_2014_4,{HLS_INPUT_TYPE=cxx,HLS_INPUT_FLOAT=0,HLS_INPUT_FIXED=0,HLS_INPUT_PART=xc7z010clg400-1,HLS_INPUT_CLOCK=10.000000,HLS_INPUT_ARCH=others,HLS_SYN_CLOCK=12.461000,HLS_SYN_LAT=1,HLS_SYN_TPT=none,HLS_SYN_MEM=0,HLS_SYN_DSP=0,HLS_SYN_FF=34,HLS_SYN_LUT=298}" *)

module laplacian_filter (
        ap_clk,
        ap_rst,
        ap_start,
        ap_done,
        ap_idle,
        ap_ready,
        x0y0,
        x1y0,
        x2y0,
        x0y1,
        x1y1,
        x2y1,
        x0y2,
        x1y2,
        x2y2,
        ap_return
);

parameter    ap_const_logic_1 = 1'b1;
parameter    ap_const_logic_0 = 1'b0;
parameter    ap_ST_st1_fsm_0 = 2'b1;
parameter    ap_ST_st2_fsm_1 = 2'b10;
parameter    ap_const_lv32_0 = 32'b00000000000000000000000000000000;
parameter    ap_const_lv1_1 = 1'b1;
parameter    ap_const_lv32_1 = 32'b1;
parameter    ap_const_lv32_3 = 32'b11;
parameter    ap_const_lv32_1F = 32'b11111;
parameter    ap_const_lv32_8 = 32'b1000;
parameter    ap_const_lv24_0 = 24'b000000000000000000000000;
parameter    ap_const_lv7_0 = 7'b0000000;
parameter    ap_const_lv10_FF = 10'b11111111;
parameter    ap_true = 1'b1;

input   ap_clk;
input   ap_rst;
input   ap_start;
output   ap_done;
output   ap_idle;
output   ap_ready;
input  [31:0] x0y0;
input  [31:0] x1y0;
input  [31:0] x2y0;
input  [31:0] x0y1;
input  [31:0] x1y1;
input  [31:0] x2y1;
input  [31:0] x0y2;
input  [31:0] x1y2;
input  [31:0] x2y2;
output  [31:0] ap_return;

reg ap_done;
reg ap_idle;
reg ap_ready;
(* fsm_encoding = "none" *) reg   [1:0] ap_CS_fsm = 2'b1;
reg    ap_sig_cseq_ST_st1_fsm_0;
reg    ap_sig_bdd_18;
wire   [31:0] tmp_1_fu_137_p2;
reg   [31:0] tmp_1_reg_230;
reg    ap_sig_cseq_ST_st2_fsm_1;
reg    ap_sig_bdd_52;
wire   [31:0] tmp2_fu_119_p2;
wire   [31:0] tmp1_fu_113_p2;
wire   [31:0] tmp_fu_107_p2;
wire   [31:0] sum2_fu_125_p2;
wire   [31:0] sum3_neg_fu_131_p2;
wire   [31:0] tmp_2_fu_143_p2;
wire   [31:0] tmp_3_fu_148_p2;
wire   [31:0] y_fu_154_p2;
wire   [23:0] tmp_5_fu_168_p4;
wire   [0:0] tmp_6_fu_184_p3;
wire   [8:0] tmp_s_fu_192_p4;
wire  signed [9:0] tmp_7_cast_fu_202_p1;
wire  signed [9:0] tmp_8_fu_206_p2;
wire   [0:0] tmp_4_fu_160_p3;
wire   [0:0] icmp_fu_178_p2;
wire   [0:0] tmp_9_fu_216_p2;
wire  signed [31:0] tmp_8_cast_fu_212_p1;
reg   [1:0] ap_NS_fsm;




/// the current state (ap_CS_fsm) of the state machine. ///
always @ (posedge ap_clk)
begin : ap_ret_ap_CS_fsm
    if (ap_rst == 1'b1) begin
        ap_CS_fsm <= ap_ST_st1_fsm_0;
    end else begin
        ap_CS_fsm <= ap_NS_fsm;
    end
end

/// assign process. ///
always @(posedge ap_clk)
begin
    if (((ap_const_logic_1 == ap_sig_cseq_ST_st1_fsm_0) & ~(ap_start == ap_const_logic_0))) begin
        tmp_1_reg_230 <= tmp_1_fu_137_p2;
    end
end

/// ap_done assign process. ///
always @ (ap_sig_cseq_ST_st2_fsm_1)
begin
    if ((ap_const_logic_1 == ap_sig_cseq_ST_st2_fsm_1)) begin
        ap_done = ap_const_logic_1;
    end else begin
        ap_done = ap_const_logic_0;
    end
end

/// ap_idle assign process. ///
always @ (ap_start or ap_sig_cseq_ST_st1_fsm_0)
begin
    if ((~(ap_const_logic_1 == ap_start) & (ap_const_logic_1 == ap_sig_cseq_ST_st1_fsm_0))) begin
        ap_idle = ap_const_logic_1;
    end else begin
        ap_idle = ap_const_logic_0;
    end
end

/// ap_ready assign process. ///
always @ (ap_sig_cseq_ST_st2_fsm_1)
begin
    if ((ap_const_logic_1 == ap_sig_cseq_ST_st2_fsm_1)) begin
        ap_ready = ap_const_logic_1;
    end else begin
        ap_ready = ap_const_logic_0;
    end
end

/// ap_sig_cseq_ST_st1_fsm_0 assign process. ///
always @ (ap_sig_bdd_18)
begin
    if (ap_sig_bdd_18) begin
        ap_sig_cseq_ST_st1_fsm_0 = ap_const_logic_1;
    end else begin
        ap_sig_cseq_ST_st1_fsm_0 = ap_const_logic_0;
    end
end

/// ap_sig_cseq_ST_st2_fsm_1 assign process. ///
always @ (ap_sig_bdd_52)
begin
    if (ap_sig_bdd_52) begin
        ap_sig_cseq_ST_st2_fsm_1 = ap_const_logic_1;
    end else begin
        ap_sig_cseq_ST_st2_fsm_1 = ap_const_logic_0;
    end
end
/// the next state (ap_NS_fsm) of the state machine. ///
always @ (ap_start or ap_CS_fsm)
begin
    case (ap_CS_fsm)
        ap_ST_st1_fsm_0 : 
        begin
            if (~(ap_start == ap_const_logic_0)) begin
                ap_NS_fsm = ap_ST_st2_fsm_1;
            end else begin
                ap_NS_fsm = ap_ST_st1_fsm_0;
            end
        end
        ap_ST_st2_fsm_1 : 
        begin
            ap_NS_fsm = ap_ST_st1_fsm_0;
        end
        default : 
        begin
            ap_NS_fsm = 'bx;
        end
    endcase
end

assign ap_return = ((tmp_9_fu_216_p2)? tmp_8_cast_fu_212_p1: y_fu_154_p2);

/// ap_sig_bdd_18 assign process. ///
always @ (ap_CS_fsm)
begin
    ap_sig_bdd_18 = (ap_CS_fsm[ap_const_lv32_0] == ap_const_lv1_1);
end

/// ap_sig_bdd_52 assign process. ///
always @ (ap_CS_fsm)
begin
    ap_sig_bdd_52 = (ap_const_lv1_1 == ap_CS_fsm[ap_const_lv32_1]);
end
assign icmp_fu_178_p2 = ($signed(tmp_5_fu_168_p4) > $signed(24'b000000000000000000000000)? 1'b1: 1'b0);
assign sum2_fu_125_p2 = (tmp2_fu_119_p2 + tmp1_fu_113_p2);
assign sum3_neg_fu_131_p2 = (tmp_fu_107_p2 - sum2_fu_125_p2);
assign tmp1_fu_113_p2 = (x1y0 + x0y0);
assign tmp2_fu_119_p2 = (x2y0 + x0y1);
assign tmp_1_fu_137_p2 = (sum3_neg_fu_131_p2 - x2y1);
assign tmp_2_fu_143_p2 = (tmp_1_reg_230 - x0y2);
assign tmp_3_fu_148_p2 = (tmp_2_fu_143_p2 - x1y2);
assign tmp_4_fu_160_p3 = y_fu_154_p2[ap_const_lv32_1F];
assign tmp_5_fu_168_p4 = {{y_fu_154_p2[ap_const_lv32_1F : ap_const_lv32_8]}};
assign tmp_6_fu_184_p3 = y_fu_154_p2[ap_const_lv32_1F];
assign tmp_7_cast_fu_202_p1 = $signed(tmp_s_fu_192_p4);
assign tmp_8_cast_fu_212_p1 = tmp_8_fu_206_p2;
assign tmp_8_fu_206_p2 = ($signed(tmp_7_cast_fu_202_p1) + $signed(ap_const_lv10_FF));
assign tmp_9_fu_216_p2 = (tmp_4_fu_160_p3 | icmp_fu_178_p2);
assign tmp_fu_107_p2 = x1y1 << ap_const_lv32_3;
assign tmp_s_fu_192_p4 = {{{{tmp_6_fu_184_p3}, {ap_const_lv7_0}}}, {tmp_6_fu_184_p3}};
assign y_fu_154_p2 = (tmp_3_fu_148_p2 - x2y2);


endmodule //laplacian_filter

  1. 2015年01月14日 05:54 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2014.4 の高位合成テスト8(ラプラシアンフィルタ3、論理合成)

Vivado HLS 2014.4 の高位合成テスト7(ラプラシアンフィルタ2、シミュレーション)”の続き。

前回はシミュレーションを行ったので、今回は、laplacian_filter.v を論理合成してみた。

laplacian_filter.v を使用して、Vivado 2014.4 のプロジェクトを作製した。使用するFPGAはZYBO に使用されている xc7z010clg400-1 とした。

次に論理合成を行った。

Synthesis -> Synthesized Design -> Schematic の結果を下に示す。なお、下のウインドウには、Reprt Utilization の結果が示されている。
Vivado_HLS_Study_41_150114.png

LUTの使用数は 309 個、FFの使用数は 67 だった。
  1. 2015年01月14日 04:39 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2014.4 の高位合成テスト7(ラプラシアンフィルタ2、シミュレーション)

”Vivado HLS 2014.4 の高位合成テスト6(ラプラシアンフィルタ1)”の続き。

前回、ラプラシアンフィルタをVivado HLS 2014.4 で高位合成して、laplacian_filter.v と laplacian_filter.vhd のファイルを生成した。
今回は、その laplacian_filter.v を使用してシミュレーションを行った。

まずは、Vivado 2014.4 でZYBO 用のプロジェクトを作製して、laplacian_filter.v をプロジェクトに追加した。
次に、laplacian_filter_tb.v という名前のテストベンチを作製した。
Vivado 2014.4 で論理シミュレーションを行った。その結果を下に示す。
Vivado_HLS_Study_37_150113.png

latency = 2, interval = 3 で、Vivado HLSのレポートと同じだった。
Vivado_HLS_Study_34_150112.png

laplacian_filter.c の高位合成レポートのAnalysis の結果の図を2つ示す。
Vivado_HLS_Study_38_150113.png

Vivado_HLS_Study_39_150113.png

段階的に入力データを read して計算していくようだ。2番めのVivado HLSの図のResource タブのExpressions の下の tmp2_fu_113 を見て欲しい。これは、シミュレーション波形 (tmp2_fu_113_p2) では、ap_start = 1 の時に、254 になったので、2つの入力を加算したものだろう?(注:このシミュレーション波形は、parameter LAP_FILTER_END_COUNT = 2; でのシミュレーション波形である)
Vivado_HLS_Study_40_150113.png
laplacian_filter.v を見ると、

assign tmp2_fu_113_p2 = (x2y0 + x0y1);

と記述されていた。

最後に、laplacian_filter_tb.v を貼っておく。

`default_nettype none

`timescale 100ps / 1ps

//
// laplacian_filter_tb.v
// 2015/01/13
//

module laplacian_filter_tb;
    parameter DELAY = 1;
    parameter LAP_FILTER_END_COUNT = 3;

    wire   ap_clk;    // input
    wire   ap_rst;    // input
    reg       ap_start;    // input
    wire   ap_done;
    wire   ap_idle;
    wire   ap_ready;
    reg        [31:0]    x0y0;
    reg        [31:0]    x1y0;
    reg        [31:0]    x2y0;
    reg        [31:0]    x0y1;
    reg        [31:0]    x1y1;
    reg        [31:0]    x2y1;
    reg        [31:0]    x0y2;
    reg        [31:0]    x1y2;
    reg        [31:0]    x2y2;
    wire    [31:0]    ap_return;
    integer            i;

    laplacian_filter uut (
        .ap_clk(ap_clk),
        .ap_rst(ap_rst),
        .ap_start(ap_start),
        .ap_done(ap_done),
        .ap_idle(ap_idle),
        .ap_ready(ap_ready),
        .x0y0(x0y0),
        .x1y0(x1y0),
        .x2y0(x2y0),
        .x0y1(x0y1),
        .x1y1(x1y1),
        .x2y1(x2y1),
        .x0y2(x0y2),
        .x1y2(x1y2),
        .x2y2(x2y2),
        .ap_return(ap_return)
    );

    // clk_gen のインスタンス(ap_clk)
    clk_gen #(
        .CLK_PERIOD(100),    // 10nsec, 100MHz
        .CLK_DUTY_CYCLE(0.5),
        .CLK_OFFSET(0),
        .START_STATE(1'b0)
    ) ACLKi (
        .clk_out(ap_clk)
    );

    // reset_gen のインスタンス
    reset_gen #(
        .RESET_STATE(1'b1),
        .RESET_TIME(1000)    // 100nsec
    ) RESET_ARESETN (
        .reset_out(ap_rst),
        .init_done()
    );

    initial begin
        // Initialize Inputs
        ap_start    = 1'b0;
        x0y0         = 32'd0;
        x1y0        = 32'd0;
        x2y0        = 32'd0;
        x0y1        = 32'd0;
        x1y1        = 32'd0;
        x2y1        = 32'd0;
        x0y2        = 32'd0;
        x1y2        = 32'd0;
        x2y2        = 32'd0;

        // Wait until Reset falling edge
        @(negedge ap_rst);

        #1000; // 100 ns Wait
        @(posedge ap_clk); // 次のクロックへ
        #DELAY;

        ap_start    = 1'b1;
        x0y0         = 32'd127;
        x1y0        = 32'd127;
        x2y0        = 32'd127;
        x0y1        = 32'd127;
        x1y1        = 32'd127;
        x2y1        = 32'd127;
        x0y2        = 32'd0;
        x1y2        = 32'd0;
        x2y2        = 32'd0;

        @(posedge ap_clk); // 次のクロックへ
        #DELAY;

        ap_start    = 1'b0;

        for (i=0; i<LAP_FILTER_END_COUNT; i=i+1) begin // laplacian_filter の終了を待つ
            @(posedge ap_clk); // 次のクロックへ
            #DELAY;        
        end

        ap_start    = 1'b1;
        x0y0         = 32'd127;
        x1y0        = 32'd127;
        x2y0        = 32'd127;
        x0y1        = 32'd127;
        x1y1        = 32'd81;
        x2y1        = 32'd127;
        x0y2        = 32'd0;
        x1y2        = 32'd0;
        x2y2        = 32'd0;

        @(posedge ap_clk); // 次のクロックへ
        #DELAY;

        ap_start    = 1'b0;

        for (i=0; i<LAP_FILTER_END_COUNT; i=i+1) begin // laplacian_filter の終了を待つ
            @(posedge ap_clk); // 次のクロックへ
            #DELAY;        
        end
    end
endmodule

module clk_gen #(
    parameter         CLK_PERIOD = 100,
    parameter real    CLK_DUTY_CYCLE = 0.5,
    parameter        CLK_OFFSET = 0,
    parameter        START_STATE    = 1'b0 )
(
    output    reg        clk_out
);
    begin
        initial begin
            #CLK_OFFSET;
            forever
            begin
                clk_out = START_STATE;
                #(CLK_PERIOD-(CLK_PERIOD*CLK_DUTY_CYCLE)) clk_out = ~START_STATE;
                #(CLK_PERIOD*CLK_DUTY_CYCLE);
            end
        end
    end
endmodule

module reset_gen #(
    parameter    RESET_STATE = 1'b1,
    parameter    RESET_TIME = 100 )
(
    output    reg        reset_out,
    output    reg        init_done
);
    begin
        initial begin
            reset_out = RESET_STATE;
            init_done = 1'b0;
            #RESET_TIME;
            reset_out = ~RESET_STATE;
            init_done = 1'b1;
        end
    end

endmodule

`default_nettype wire

  1. 2015年01月13日 05:41 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2014.4 の高位合成テスト6(ラプラシアンフィルタ1)

今回はラプラシアンフィルタをVivado HLS 2014.4 で高位合成してみる。

Vivado HLS で laplacian_filter プロジェクトを作製した。例によって、FPGAはZYBO に使用されている xc7z010clg400-1 とした。

laplacian_filter.cpp を作製した。laplacian_filter.cpp を示す。

// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1  8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
int laplacian_filter(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);
}


これをVivado HLS で高位合成を行った。
高位合成後のレポートを下に示す。
Vivado_HLS_Study_33_150112.png
Vivado_HLS_Study_34_150112.png
Vivado_HLS_Study_35_150112.png
Vivado_HLS_Study_36_150112.png

latency = 2クロック、interval = 3クロックだった。
乗算は8を掛けるので、DSP48Eは使用せずにシフトでやるようだ。
高位合成結果の laplacian_filter.v を下に示す。

// ==============================================================
// RTL generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2014.4
// Copyright (C) 2014 Xilinx Inc. All rights reserved.
// 
// ===========================================================

`timescale 1 ns / 1 ps 

(* CORE_GENERATION_INFO="laplacian_filter,hls_ip_2014_4,{HLS_INPUT_TYPE=cxx,HLS_INPUT_FLOAT=0,HLS_INPUT_FIXED=0,HLS_INPUT_PART=xc7z010clg400-1,HLS_INPUT_CLOCK=10.000000,HLS_INPUT_ARCH=others,HLS_SYN_CLOCK=7.581000,HLS_SYN_LAT=2,HLS_SYN_TPT=none,HLS_SYN_MEM=0,HLS_SYN_DSP=0,HLS_SYN_FF=67,HLS_SYN_LUT=298}" *)

module laplacian_filter (
        ap_clk,
        ap_rst,
        ap_start,
        ap_done,
        ap_idle,
        ap_ready,
        x0y0,
        x1y0,
        x2y0,
        x0y1,
        x1y1,
        x2y1,
        x0y2,
        x1y2,
        x2y2,
        ap_return
);

parameter    ap_const_logic_1 = 1'b1;
parameter    ap_const_logic_0 = 1'b0;
parameter    ap_ST_st1_fsm_0 = 3'b1;
parameter    ap_ST_st2_fsm_1 = 3'b10;
parameter    ap_ST_st3_fsm_2 = 3'b100;
parameter    ap_const_lv32_0 = 32'b00000000000000000000000000000000;
parameter    ap_const_lv1_1 = 1'b1;
parameter    ap_const_lv32_1 = 32'b1;
parameter    ap_const_lv32_2 = 32'b10;
parameter    ap_const_lv32_3 = 32'b11;
parameter    ap_const_lv32_1F = 32'b11111;
parameter    ap_const_lv32_8 = 32'b1000;
parameter    ap_const_lv24_0 = 24'b000000000000000000000000;
parameter    ap_const_lv7_0 = 7'b0000000;
parameter    ap_const_lv10_FF = 10'b11111111;
parameter    ap_true = 1'b1;

input   ap_clk;
input   ap_rst;
input   ap_start;
output   ap_done;
output   ap_idle;
output   ap_ready;
input  [31:0] x0y0;
input  [31:0] x1y0;
input  [31:0] x2y0;
input  [31:0] x0y1;
input  [31:0] x1y1;
input  [31:0] x2y1;
input  [31:0] x0y2;
input  [31:0] x1y2;
input  [31:0] x2y2;
output  [31:0] ap_return;

reg ap_done;
reg ap_idle;
reg ap_ready;
(* fsm_encoding = "none" *) reg   [2:0] ap_CS_fsm = 3'b1;
reg    ap_sig_cseq_ST_st1_fsm_0;
reg    ap_sig_bdd_19;
wire   [31:0] sum3_neg_fu_125_p2;
reg   [31:0] sum3_neg_reg_223;
wire   [31:0] tmp_3_fu_142_p2;
reg   [31:0] tmp_3_reg_228;
reg    ap_sig_cseq_ST_st2_fsm_1;
reg    ap_sig_bdd_48;
reg    ap_sig_cseq_ST_st3_fsm_2;
reg    ap_sig_bdd_64;
wire   [31:0] tmp2_fu_113_p2;
wire   [31:0] tmp1_fu_107_p2;
wire   [31:0] tmp_fu_101_p2;
wire   [31:0] sum2_fu_119_p2;
wire   [31:0] tmp_1_fu_131_p2;
wire   [31:0] tmp_2_fu_136_p2;
wire   [31:0] y_fu_148_p2;
wire   [23:0] tmp_5_fu_161_p4;
wire   [0:0] tmp_6_fu_177_p3;
wire   [8:0] tmp_s_fu_185_p4;
wire  signed [9:0] tmp_7_cast_fu_195_p1;
wire  signed [9:0] tmp_8_fu_199_p2;
wire   [0:0] tmp_4_fu_153_p3;
wire   [0:0] icmp_fu_171_p2;
wire   [0:0] tmp_9_fu_209_p2;
wire  signed [31:0] tmp_8_cast_fu_205_p1;
reg   [2:0] ap_NS_fsm;




/// the current state (ap_CS_fsm) of the state machine. ///
always @ (posedge ap_clk)
begin : ap_ret_ap_CS_fsm
    if (ap_rst == 1'b1) begin
        ap_CS_fsm <= ap_ST_st1_fsm_0;
    end else begin
        ap_CS_fsm <= ap_NS_fsm;
    end
end

/// assign process. ///
always @(posedge ap_clk)
begin
    if (((ap_const_logic_1 == ap_sig_cseq_ST_st1_fsm_0) & ~(ap_start == ap_const_logic_0))) begin
        sum3_neg_reg_223 <= sum3_neg_fu_125_p2;
    end
end

/// assign process. ///
always @(posedge ap_clk)
begin
    if ((ap_const_logic_1 == ap_sig_cseq_ST_st2_fsm_1)) begin
        tmp_3_reg_228 <= tmp_3_fu_142_p2;
    end
end

/// ap_done assign process. ///
always @ (ap_sig_cseq_ST_st3_fsm_2)
begin
    if ((ap_const_logic_1 == ap_sig_cseq_ST_st3_fsm_2)) begin
        ap_done = ap_const_logic_1;
    end else begin
        ap_done = ap_const_logic_0;
    end
end

/// ap_idle assign process. ///
always @ (ap_start or ap_sig_cseq_ST_st1_fsm_0)
begin
    if ((~(ap_const_logic_1 == ap_start) & (ap_const_logic_1 == ap_sig_cseq_ST_st1_fsm_0))) begin
        ap_idle = ap_const_logic_1;
    end else begin
        ap_idle = ap_const_logic_0;
    end
end

/// ap_ready assign process. ///
always @ (ap_sig_cseq_ST_st3_fsm_2)
begin
    if ((ap_const_logic_1 == ap_sig_cseq_ST_st3_fsm_2)) begin
        ap_ready = ap_const_logic_1;
    end else begin
        ap_ready = ap_const_logic_0;
    end
end

/// ap_sig_cseq_ST_st1_fsm_0 assign process. ///
always @ (ap_sig_bdd_19)
begin
    if (ap_sig_bdd_19) begin
        ap_sig_cseq_ST_st1_fsm_0 = ap_const_logic_1;
    end else begin
        ap_sig_cseq_ST_st1_fsm_0 = ap_const_logic_0;
    end
end

/// ap_sig_cseq_ST_st2_fsm_1 assign process. ///
always @ (ap_sig_bdd_48)
begin
    if (ap_sig_bdd_48) begin
        ap_sig_cseq_ST_st2_fsm_1 = ap_const_logic_1;
    end else begin
        ap_sig_cseq_ST_st2_fsm_1 = ap_const_logic_0;
    end
end

/// ap_sig_cseq_ST_st3_fsm_2 assign process. ///
always @ (ap_sig_bdd_64)
begin
    if (ap_sig_bdd_64) begin
        ap_sig_cseq_ST_st3_fsm_2 = ap_const_logic_1;
    end else begin
        ap_sig_cseq_ST_st3_fsm_2 = ap_const_logic_0;
    end
end
/// the next state (ap_NS_fsm) of the state machine. ///
always @ (ap_start or ap_CS_fsm)
begin
    case (ap_CS_fsm)
        ap_ST_st1_fsm_0 : 
        begin
            if (~(ap_start == ap_const_logic_0)) begin
                ap_NS_fsm = ap_ST_st2_fsm_1;
            end else begin
                ap_NS_fsm = ap_ST_st1_fsm_0;
            end
        end
        ap_ST_st2_fsm_1 : 
        begin
            ap_NS_fsm = ap_ST_st3_fsm_2;
        end
        ap_ST_st3_fsm_2 : 
        begin
            ap_NS_fsm = ap_ST_st1_fsm_0;
        end
        default : 
        begin
            ap_NS_fsm = 'bx;
        end
    endcase
end

assign ap_return = ((tmp_9_fu_209_p2)? tmp_8_cast_fu_205_p1: y_fu_148_p2);

/// ap_sig_bdd_19 assign process. ///
always @ (ap_CS_fsm)
begin
    ap_sig_bdd_19 = (ap_CS_fsm[ap_const_lv32_0] == ap_const_lv1_1);
end

/// ap_sig_bdd_48 assign process. ///
always @ (ap_CS_fsm)
begin
    ap_sig_bdd_48 = (ap_const_lv1_1 == ap_CS_fsm[ap_const_lv32_1]);
end

/// ap_sig_bdd_64 assign process. ///
always @ (ap_CS_fsm)
begin
    ap_sig_bdd_64 = (ap_const_lv1_1 == ap_CS_fsm[ap_const_lv32_2]);
end
assign icmp_fu_171_p2 = ($signed(tmp_5_fu_161_p4) > $signed(24'b000000000000000000000000)? 1'b1: 1'b0);
assign sum2_fu_119_p2 = (tmp2_fu_113_p2 + tmp1_fu_107_p2);
assign sum3_neg_fu_125_p2 = (tmp_fu_101_p2 - sum2_fu_119_p2);
assign tmp1_fu_107_p2 = (x1y0 + x0y0);
assign tmp2_fu_113_p2 = (x2y0 + x0y1);
assign tmp_1_fu_131_p2 = (sum3_neg_reg_223 - x2y1);
assign tmp_2_fu_136_p2 = (tmp_1_fu_131_p2 - x0y2);
assign tmp_3_fu_142_p2 = (tmp_2_fu_136_p2 - x1y2);
assign tmp_4_fu_153_p3 = y_fu_148_p2[ap_const_lv32_1F];
assign tmp_5_fu_161_p4 = {{y_fu_148_p2[ap_const_lv32_1F : ap_const_lv32_8]}};
assign tmp_6_fu_177_p3 = y_fu_148_p2[ap_const_lv32_1F];
assign tmp_7_cast_fu_195_p1 = $signed(tmp_s_fu_185_p4);
assign tmp_8_cast_fu_205_p1 = tmp_8_fu_199_p2;
assign tmp_8_fu_199_p2 = ($signed(tmp_7_cast_fu_195_p1) + $signed(ap_const_lv10_FF));
assign tmp_9_fu_209_p2 = (tmp_4_fu_153_p3 | icmp_fu_171_p2);
assign tmp_fu_101_p2 = x1y1 << ap_const_lv32_3;
assign tmp_s_fu_185_p4 = {{{{tmp_6_fu_177_p3}, {ap_const_lv7_0}}}, {tmp_6_fu_177_p3}};
assign y_fu_148_p2 = (tmp_3_reg_228 - x2y2);


endmodule //laplacian_filter

  1. 2015年01月12日 05:11 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2014.4 の高位合成テスト5(Vivado HLS で高位合成したfoo2 を 論理合成)

”Vivado HLS 2014.4 の高位合成テスト4(Vivado HLS で高位合成したfoo2 を シミュレーション)”の続き。

前回は、foo2 プロジェクトをシミュレーションしたので、今回は、論理合成を行った。

foo.v と foo_mul_32s_8s_32_3.v を使用して、Vivado 2014.4 のプロジェクトを作製した。使用するFPGAはZYBO に使用されている xc7z010clg400-1 とした。

次に論理合成を行った。

Synthesis -> Synthesized Design -> Schematic の結果を下に示す。なお、下のウインドウには、Reprt Utilization の結果が示されている。
Vivado_HLS_Study_32_150112.png

これをVivado HLSの高位合成後のレポートと比べてみよう。
Vivado_HLS_Study_24_150108.png

LUTは 48、DSPは 2 でどちらも同じだ。FFは78 と 108 で差が開いている。これは、論理合成でFFが消されたのか?
インプリメントはI/Oが多すぎるということで行えない。これで終了とする。
  1. 2015年01月12日 04:23 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2014.4 の高位合成テスト4(Vivado HLS で高位合成したfoo2 を シミュレーション)

Vivado HLS 2014.4 の高位合成テスト3(foo2 を Vivado HLS で高位合成)”の続き。

高位合成された foo.v をシミュレーションしてみた。

もう一度、”Vivado Design Suite ユーザー ガイド 高位合成 UG902 (v2014.1) 2014 年 4 月 2 日”の8ページの入力と出力に配列を使用した foo() を引用する。

void foo(int in[3], char a, char b, char c, int out[3]) {
    int x,y;
    for(int i = 0; i < 3; i++) {
        x = in[i];
        y = a*x + b + c;
        out[i] = y;
    }
}


さて、Vivado 2014.4 でプロジェクトを作製して、テストベンチとBlockRAMのモデルを作製した。
foo.v と foo_mul_32s_8s_32_3.v をプロジェクトに入れて、論理シミュレーションを行った。その結果を下に示す。
Vivado_HLS_Study_31_150111.png

ap_idle が 0 になっている間は、約170 ns で、これがピッタリ 170 ns になっていないのは、ap_idle が組み合わせ回路出力だからだ。テストベンチから入れた ap_start が 1 になるまでは、クロックから 0.1 ns 遅延している。ap_start を ap_idle が組み合わせ回路の中で使っているのが原因のようだ。ともかく、インターバルは17クロックであるということが分かった。(1クロックは 10 ns (100MHz clock)
演算が終了するのは、out_r_we0 の3回目のパルスの後なので、16クロックである。
これらは、高位合成後のレポートと合致する。
Vivado_HLS_Study_24_150108.png

Latencyが 16 クロック、Interval が 17 クロックになっているのがわかる。

また、Analysis の Resouce の図と見比べてみると面白い。
Vivado_HLS_Study_30_150109.png

C0 ステートでは、b + c を行っているが、これは、ap_start が 1 になっている間ということがわかる。つまり演算器の入力にFFは入っていないので、前段の出力は、FFで出力したほうが良い。(前段の出力からの遅延とプラスしてクロック周期に収まれば、何の問題もないが、覚えていないと遅延が増える危険があるので、前段の出力はFFで出したほうが安全だろう)
見ているといろいろと面白いのだが、書ききれないので、このへんで終わりにする。もし見てみたい方は実際にシミュレーションをやってみることをお勧めする。

最後に、テストベンチと シングルポートの BlockRAM モデルを貼っておく。
まずは、テストベンチ foo_tb.v から示す。

`default_nettype none

`timescale 100ps / 1ps

//
// foo_tb.v
// 2015/01/10
//

module foo_tb;
        parameter DELAY = 1;

    wire   ap_clk;    // input
    wire   ap_rst;    // input
    reg       ap_start;    // input
    wire   ap_done;
    wire   ap_idle;
    wire   ap_ready;
    wire  [1:0] in_r_address0;
    wire   in_r_ce0;
    wire  [31:0] in_r_q0;    // input
    reg      [7:0] a;    // input
    reg   [7:0] b;    // input
    reg   [7:0] c;    // input
    wire  [1:0] out_r_address0;
    wire   out_r_ce0;
    wire   out_r_we0;
    wire  [31:0] out_r_d0;

    foo uut (
            .ap_clk(ap_clk),
            .ap_rst(ap_rst),
            .ap_start(ap_start),
            .ap_done(ap_done),
            .ap_idle(ap_idle),
            .ap_ready(ap_ready),
            .in_r_address0(in_r_address0),
            .in_r_ce0(in_r_ce0),
            .in_r_q0(in_r_q0),
            .a(a),
            .b(b),
               .c(c),
            .out_r_address0(out_r_address0),
            .out_r_ce0(out_r_ce0),
            .out_r_we0(out_r_we0),
            .out_r_d0(out_r_d0)
    );

    Single_Prot_BRAM_Model #(
        .C_MEMORY_SIZE(4),    // Word (not byte), 2^n
        .DATA_BUS_WIDTH(32)    // RAM Data Width
    ) spbm_read (
        .clk(ap_clk),
        .rst(ap_rst),
        .addr(in_r_address0),
        .ce(in_r_ce0),
        .we(1'b0),
        .din(0),
        .dout(in_r_q0)
    );

    Single_Prot_BRAM_Model #(
        .C_MEMORY_SIZE(4),    // Word (not byte), 2^n
        .DATA_BUS_WIDTH(32)    // RAM Data Width
    ) spbm_write (
        .clk(ap_clk),
        .rst(ap_rst),
        .addr(out_r_address0),
        .ce(out_r_ce0),
        .we(out_r_we0),
        .din(out_r_d0),
        .dout()
    );

    // clk_gen のインスタンス(ap_clk)
    clk_gen #(
        .CLK_PERIOD(100),    // 10nsec, 100MHz
        .CLK_DUTY_CYCLE(0.5),
        .CLK_OFFSET(0),
        .START_STATE(1'b0)
    ) ACLKi (
        .clk_out(ap_clk)
    );

    // reset_gen のインスタンス
    reset_gen #(
        .RESET_STATE(1'b1),
        .RESET_TIME(1000)    // 100nsec
    ) RESET_ARESETN (
        .reset_out(ap_rst),
        .init_done()
    );

    initial begin
        // Initialize Inputs
        ap_start    = 1'b0;
        a             = 8'd0;
        b             = 8'd0;
        c             = 8'd0;

        // Wait until Reset falling edge
        @(negedge ap_rst);

        #1000; // 100 ns Wait
        @(posedge ap_clk); // 次のクロックへ
        #DELAY;

        ap_start    = 1'b1;
        a             = 8'd2;
        b            = 8'd3;
        c            = 8'd4;

        @(posedge ap_clk); // 次のクロックへ
        #DELAY;

        ap_start    = 1'b0;
    end

endmodule

module clk_gen #(
    parameter         CLK_PERIOD = 100,
    parameter real    CLK_DUTY_CYCLE = 0.5,
    parameter        CLK_OFFSET = 0,
    parameter        START_STATE    = 1'b0 )
(
    output    reg        clk_out
);
    begin
        initial begin
            #CLK_OFFSET;
            forever
            begin
                clk_out = START_STATE;
                #(CLK_PERIOD-(CLK_PERIOD*CLK_DUTY_CYCLE)) clk_out = ~START_STATE;
                #(CLK_PERIOD*CLK_DUTY_CYCLE);
            end
        end
    end
endmodule

module reset_gen #(
    parameter    RESET_STATE = 1'b1,
    parameter    RESET_TIME = 100 )
(
    output    reg        reset_out,
    output    reg        init_done
);
    begin
        initial begin
            reset_out = RESET_STATE;
            init_done = 1'b0;
            #RESET_TIME;
            reset_out = ~RESET_STATE;
            init_done = 1'b1;
        end
    end

endmodule

`default_nettype wire


シングルポートの BlockRAM モデル Single_port_BRAM_Model.v を示す。

//
//  Initializing  Single Port BlockRAM  from  internal  data  file
//  Single_port_BRAM_Model.v
//  2015/01/10
//

`default_nettype none

module Single_Prot_BRAM_Model # (
    parameter integer C_MEMORY_SIZE =        4,    // Word (not byte), 2^n
    parameter integer DATA_BUS_WIDTH =        32    // RAM Data Width
)(
    input wire                                clk,
    input wire                                rst,
    input wire    [log2(C_MEMORY_SIZE)-1 : 0]    addr,
    input wire                                ce,
    input wire                                we,
    input wire    [DATA_BUS_WIDTH-1 : 0]        din,
    output reg    [DATA_BUS_WIDTH-1 : 0]        dout
);

    // Beyond Circuts, Constant Function in Verilog 2001を参照しました
    // http://www.beyond-circuits.com/wordpress/2008/11/constant-functions/
    function integer log2;
        input integer addr;
        begin
            addr = addr - 1;
            for (log2=0; addr>0; log2=log2+1)
                addr = addr >> 1;
        end
    endfunction
    
    reg        [DATA_BUS_WIDTH-1:0]    mem    [0:C_MEMORY_SIZE-1];
    integer    i;

    initial begin
        for (i=0; i<C_MEMORY_SIZE; i=i+1)
            mem[i] = i; 
    end

    always @(posedge clk) begin
        if (rst) begin
            dout <= 0;
        end else begin
            if (we & ce)
                mem[addr] <= din;

            if (ce)
                dout <= mem[addr];
        end
    end
endmodule

`default_nettype wire

  1. 2015年01月11日 05:54 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

ZYBOで STREAM を試してみた

ツィッターでなひたふさんが STREAM というツールでZYNQ Linuxのメモリ帯域幅を測っていたので、私もZYBO でやってみた。

STREAMの使用方法 (Linuxメモリ帯域幅の計測方法)”を見てやってみました。

まずは、ZYBO Linux に linaro ユーザーで SSH ログインして、ホームディレクトリの下に steram ディレクトリを作りました。
ZYBO_stream_1_150110.png

firefox & を立ちあげます。
ZYBO_stream_2_150110.png

Windows にXサーバーソフトのXming を立ちあげてあるので、ZYBO Linux の firefox アプリをWindows 7 上のGUI で操作することができます。
firefox が立ち上がりました。
ZYBO_stream_3_150110.png

STREAM: Sustainable Memory Bandwidth in High Performance Computers”の Source Code Directory をクリックしました。
ZYBO_stream_4_150110.png

そうすると、stream/FTP/Code ディレクトリが表示されるので、steram.c をクリックして表示させます。
ZYBO_stream_5_150110.png

strem.c が表示されるので、コピー・アンド・ペーストで、gedit に貼り付けました。

gcc -O stream.c -o stream でコンパイルしました。
ZYBO_stream_6_150110.png

./stream で STREAM を起動してベンチマークします。
ZYBO_stream_7_150110.png

5回、./stream を起動しましたが、copyの最低が 640.1 MB/s、最高が 641.5 MB/s でした。
ZYBO の Cortex-A9 の動作周波数は、650MHz、DDR3-SDRAMはDDR3-1050 です。
DDR3 -SDRAMのデータバス幅は32ビット = 4バイトなので、DDR3-SDRAMの最大メモリ帯域は525MHz x 2 (DDR) x 4バイト = 4.2GB/s となります。copy の中央値を 641 MB/s とすると、copy の中央値が最大メモリ帯域の何%なるかを計算します。

641 /4200 x 100 ≒ 15.3 (%)

となります。低い感じがしますが、DMAではなく CPU のI/Oだと思うので、DDR3のメモリ帯域を使いきれていないのではないか?と思います。
  1. 2015年01月10日 08:10 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2014.4 の高位合成テスト3(foo2 を Vivado HLS で高位合成)

Vivado HLS 2014.4 の高位合成テスト2(foo1のHDLコード)”の続き。

foo1 は1クロックで終了する組み合わせ回路として高位合成されたので、特にシミュレーションの必要を感じなかった。
今回は、”Vivado HLS 2014.4 の勉強1(高位合成の理解)”のもう1つのfoo() の高位合成をやってみる。今回のfoo() をfoo2 とする。foo2 は、入力の引数と出力の引数が配列になっているので、BlockRAM のインターフェースになっているはずだ。

もう一度、”Vivado Design Suite ユーザー ガイド 高位合成 UG902 (v2014.1) 2014 年 4 月 2 日”の8ページの入力と出力に配列を使用した foo() を引用する。

void foo(int in[3], char a, char b, char c, int out[3]) {
    int x,y;
    for(int i = 0; i < 3; i++) {
        x = in[i];
        y = a*x + b + c;
        out[i] = y;
    }
}


・さて、ZYBOのZynq7010を使用したVivado HLS 2014.4 の foo2 プロジェクトを作製した。(Vivado HLSのプロジェクトの作り方など詳しく”Vivado HLS 2014.4 の高位合成テスト1(Vivado HLSで高位合成)”に書いたので、今回は省略し、結果だけ書く)

・foo2.cpp を作って、Cコードを書いた。
Vivado_HLS_Study_21_150108.png

・Project メニューから Project Settings を選択して、Synthesis タブをクリックし、Top Function を foo に設定した。
Vivado_HLS_Study_22_150108.png

・C Synthesis を行った。
Vivado_HLS_Study_23_150108.png

・C Synthesis Report その2。
Vivado_HLS_Study_24_150108.png

Latency は 16 クロックで 、Interval は 17 クロックだ。ユーザーズガイドに書いてある Latency = 10 、Interval = 11 よりもだいぶ伸びている。
リソースでは、DSP48E を2つ使用している。

・C Synthesis Report その3。
Vivado_HLS_Study_25_150108.png

・C Synthesis Report その4。
Vivado_HLS_Study_26_150108.png

ap_ctrl_hs インターフェースが生成されているが、今度は配列に計算値を書き出すため、ap_return は無い。その代わり、in と out のBlock RAM のインターフェースが生成されている。

・Analysis 画面を示す。
Vivado_HLS_Study_28_150108.png

Loop 1 があって、展開すると6~12 の処理が Loop 1 内にあるようだ。
下位ブロックは緑で示されるようだが、foo2 には下位ブロックは無いので、これは存在しない。

・紫色のブロックを右クリックすると Goto Source, Goto Verilog, Goto VHDL メニューが現れて、Goto Source を選択すると Cソースの対応する行に飛んでくれる。
Vivado_HLS_Study_29_150109.png

・Resource Profile タブと Resource タブをクリックした。
Vivado_HLS_Study_30_150109.png

Resource Profile には使用されたリソースが表示されている。
Resource タブでは、実際のインスタンスがどのステートでどのような演算を行っているかを表示しているようだ。
例えば、C0ステートに + の演算を行う tmp1_fu_96 は演算を行った後は定数になる b + c を行っているのがわかる。

もう一度、”Vivado Design Suite ユーザー ガイド 高位合成 UG902 (v2014.1) 2014 年 4 月 2 日”の9ページの”図 1‐2 : 抽出と IO ポー ト シーケンスの制御”を下に引用する。
Vivado_HLS_Study_20_150107.png

Vivao HLS の結果と見比べてみると、Vivado HLS の実際の高位合成結果では、乗算が3クロックかかっているのがわかる。図 1‐2 では、乗算と加算が一緒に1クロックで処理されることになっている。

書きた方が正確ではなかったので、もう一度書く。
図1-2の回路では、BlockRAMの出力を一度FFを通して乗算と加算をしているが、Vivado HLSの結果だと、in_r(p0) と foo_mul_32s_8s_32_3_u0 が1クロック分重なっているので、BlockRAMの出力にFFは入っていないんじゃないか?と思われる。
foo_mul_32s_8s_32_3_u0 の乗算には3クロックかかっているが、Vivado HLS結果と図1-2の乗算のレイテンシの差は1クロックだと思われる。
もう1クロックの差はどこで出るかだが、それは、Vivado HLS結果のC5ステートであると思われる。write のみ独立しているので、C4ステートまでの演算結果をC4ステートの終わりでFFにラッチしてからBlockRAMにWrite しているようだ。図1-2は、どうかというと、C2ステートの最後で、BlockRAMに出力アドレスとCE、WEを与えて、組み合わせ回路の演算結果を直接BlockRAMの入力として与えている。つまり図1-2では、write にかかるクロックは 0 クロックである。
  1. 2015年01月09日 05:26 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

CQエレクトロニクス・セミナの実習・ARMコア内蔵FPGAのハードウェア開発入門~Xilinx社Zynq編

CQエレクトロニクス・セミナの”実習・ARMコア内蔵FPGAのハードウェア開発入門~Xilinx社Zynq編”が開催されます。

小林さんとは近頃、職場でお会いするということもあり、ZynqやAXIバスの勉強会を一緒にやらせて頂いたこともあります。
私がVHDLで書いたAXI4 Slave BFMを小林さんがVerilog HDLに変換してくれて、おまけに公開する許可を与えてくれました。
小林さんが講義されるZynqやAXIバスは期待できると思います。AXIバスのカスタムIPの作り方もきっちり教えてくれることでしょう。
特にAXIバスやAXIバスのカスタムIPについて知りたい方は、小林さんのこのセミナを受講することをお勧めします。

CQエレクトロニクス・セミナでは、以前、ご指導頂いた早乙女さんも”実習・直伝!最新FPGAを使ったビデオ・システムの開発(画像フィルタ設計編)”というセミナを持たれているようです。Vivado HLSのエキスパートですし、こっちのセミナも受けて損はないと思います。

以上、本当に思っていることではありますが、ステマと思われても仕方がないブログでした。。。(ステマじゃないです。。。)
  1. 2015年01月08日 05:12 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2014.4 の高位合成テスト2(foo1のHDLコード)

Vivado HLS 2014.4 の高位合成テスト1(Vivado HLSで高位合成)”の続き。

前回は、”Vivado Design Suite ユーザー ガイド 高位合成 UG902 (v2014.1) 2014 年 4 月 2 日”の6ページのコード例を foo1 としてVivado HLS で高位合成を行った。
今回は高位合成の結果出力されたHDLを見てみよう。

まずは、”Vivado Design Suite ユーザー ガイド 高位合成 UG902 (v2014.1) 2014 年 4 月 2 日”の6ページのコード例をもう一度引用する。

int foo(char x, char a, char b, char c) {
    char y;
    y = x*a+b+c;
    return y;
}


これをVivado HLS 2014.4 で高位合成した結果のVerilog HDL ファイル foo.v を下に示す。

// ==============================================================
// RTL generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2014.4
// Copyright (C) 2014 Xilinx Inc. All rights reserved.
// 
// ===========================================================

`timescale 1 ns / 1 ps 

(* CORE_GENERATION_INFO="foo,hls_ip_2014_4,{HLS_INPUT_TYPE=c,HLS_INPUT_FLOAT=0,HLS_INPUT_FIXED=0,HLS_INPUT_PART=xc7z010clg400-1,HLS_INPUT_CLOCK=10.000000,HLS_INPUT_ARCH=others,HLS_SYN_CLOCK=6.380000,HLS_SYN_LAT=0,HLS_SYN_TPT=none,HLS_SYN_MEM=0,HLS_SYN_DSP=1,HLS_SYN_FF=0,HLS_SYN_LUT=8}" *)

module foo (
        ap_start,
        ap_done,
        ap_idle,
        ap_ready,
        x,
        a,
        b,
        c,
        ap_return
);

parameter    ap_const_logic_1 = 1'b1;
parameter    ap_true = 1'b1;
parameter    ap_const_logic_0 = 1'b0;

input   ap_start;
output   ap_done;
output   ap_idle;
output   ap_ready;
input  [7:0] x;
input  [7:0] a;
input  [7:0] b;
input  [7:0] c;
output  [31:0] ap_return;

wire  signed [7:0] tmp_fu_43_p0;
wire  signed [7:0] tmp_fu_43_p1;
(* use_dsp48 = "no" *) wire   [7:0] tmp1_fu_49_p2;
wire  signed [7:0] tmp_fu_43_p2;
wire  signed [7:0] y_fu_55_p2;



assign ap_done = ap_start;
assign ap_idle = ap_const_logic_1;
assign ap_ready = ap_start;
assign ap_return = $signed(y_fu_55_p2);
assign tmp1_fu_49_p2 = (b + c);
assign tmp_fu_43_p0 = a;
assign tmp_fu_43_p1 = x;
assign tmp_fu_43_p2 = ($signed(tmp_fu_43_p0) * $signed(tmp_fu_43_p1));
assign y_fu_55_p2 = ($signed(tmp1_fu_49_p2) + $signed(tmp_fu_43_p2));


endmodule //foo


上のVerilog HDL コードを見てもわかるとおりに、ap_done と ap_ready には、ap_start が入っているし、ap_return にも組み合わせ回路で演算結果を返しているだけだ。レイテンシは 0 で、インターバルは 1 の回路になっている。

VHDL コードの foo.vhd も下に示す。

-- ==============================================================
-- RTL generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
-- Version: 2014.4
-- Copyright (C) 2014 Xilinx Inc. All rights reserved.
-- 
-- ===========================================================

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity foo is
port (
    ap_start : IN STD_LOGIC;
    ap_done : OUT STD_LOGIC;
    ap_idle : OUT STD_LOGIC;
    ap_ready : OUT STD_LOGIC;
    x : IN STD_LOGIC_VECTOR (7 downto 0);
    a : IN STD_LOGIC_VECTOR (7 downto 0);
    b : IN STD_LOGIC_VECTOR (7 downto 0);
    c : IN STD_LOGIC_VECTOR (7 downto 0);
    ap_return : OUT STD_LOGIC_VECTOR (31 downto 0) );
end;


architecture behav of foo is 
    attribute CORE_GENERATION_INFO : STRING;
    attribute CORE_GENERATION_INFO of behav : architecture is
    "foo,hls_ip_2014_4,{HLS_INPUT_TYPE=c,HLS_INPUT_FLOAT=0,HLS_INPUT_FIXED=0,HLS_INPUT_PART=xc7z010clg400-1,HLS_INPUT_CLOCK=10.000000,HLS_INPUT_ARCH=others,HLS_SYN_CLOCK=6.380000,HLS_SYN_LAT=0,HLS_SYN_TPT=none,HLS_SYN_MEM=0,HLS_SYN_DSP=1,HLS_SYN_FF=0,HLS_SYN_LUT=8}";
    constant ap_const_logic_1 : STD_LOGIC := '1';
    constant ap_true : BOOLEAN := true;
    constant ap_const_logic_0 : STD_LOGIC := '0';

    signal tmp_fu_43_p0 : STD_LOGIC_VECTOR (7 downto 0);
    signal tmp_fu_43_p1 : STD_LOGIC_VECTOR (7 downto 0);
    signal tmp1_fu_49_p2 : STD_LOGIC_VECTOR (7 downto 0);
    attribute use_dsp48 : string;
    attribute use_dsp48 of tmp1_fu_49_p2 : signal is "no";
    signal tmp_fu_43_p2 : STD_LOGIC_VECTOR (7 downto 0);
    signal y_fu_55_p2 : STD_LOGIC_VECTOR (7 downto 0);


begin



    ap_done <= ap_start;
    ap_idle <= ap_const_logic_1;
    ap_ready <= ap_start;
        ap_return <= std_logic_vector(resize(signed(y_fu_55_p2),32));

    tmp1_fu_49_p2 <= std_logic_vector(unsigned(b) + unsigned(c));
    tmp_fu_43_p0 <= a;
    tmp_fu_43_p1 <= x;
    tmp_fu_43_p2 <= std_logic_vector(resize(unsigned(std_logic_vector(signed(tmp_fu_43_p0) * signed(tmp_fu_43_p1))), 8));
    y_fu_55_p2 <= std_logic_vector(unsigned(tmp1_fu_49_p2) + unsigned(tmp_fu_43_p2));
end behav;


VHDLもVerilog HDL コードと同じだ。
  1. 2015年01月08日 05:08 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

ひでみさんのZynq本2冊とMicroSDカードが届いた

昨日、ひでみさんに注文しておいたZynq本2冊とMicroSDカードが届いた。
hidemi_zynq_sd_150108.jpg

本は、ZYNQ Design Vivado Editon と ZYNQ Design Yocto Editon で、ページ数は両方共 88 ページだった。思ったよりも薄かったが、チラ見したところ内容は充実していると思う。
MicroSDカードには /home/root に Vivado IPI の IP や Yocto のビルド環境などが入っていた。Micro SDカードを ZYBO に入れると Yocto をブートできるのだが、Micro SDカードのClass が 4 だったので、バックアップを兼ねて、8GB Class 10 の Micro SDにコピーしてから ZYBO に入れてブートした。
下にブート時のメッセージの一部を示す。Yocto がブートした。
hidemi_zynq_sd_2_150108.png

ZYBO の HDMI を接続すると login プロンプトが出ていた。キーボードとマウスを接続すれば使えると思う。
hidemi_zynq_sd_3_150108.jpg

起動メッセージから SSH がインストールされているのが分かったので、シリアルターミナルで ifconfig コマンドを実行して、割り振られているIPアドレスを見て、Tera TermでIPアドレスで SSH ログインしたらログインできた。
hidemi_zynq_sd_4_150108.jpg
  1. 2015年01月08日 04:33 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2014.4 の高位合成テスト1(Vivado HLSで高位合成)

Vivado HLS 2014.4 の勉強1(高位合成の理解)”の続き。

前回、引用した最初の関数 foo() を実際にVivado HLS 2014.4 で高位合成を行った。

・Vivado HLS 2014.4 を立ち上げる。

・Create New Project をクリックした。
Vivado_HLS_Study_2_150107.png

・New Vivado HLS Project ダイアログが開いた。Project name に foo1 を入力し、Location を指定して、Next > ボタンをクリックした。
Vivado_HLS_Study_3_150107.png

・Add/remove C-based source files ではデフォルトのまま、Next > ボタンをクリックした。
Vivado_HLS_Study_4_150107.png

・Add/remove C-based testbench files でもデフォルトのまま、Next > ボタンをクリックした。
Vivado_HLS_Study_5_150107.png

・Solution Configuration の画面で、Part Selection の右側の ... ボタンをクリックした。
Vivado_HLS_Study_6_150107.png

・FPGAを選択する。

・Filter で図のように選択して、xc7z010clg400-1 を選択して、OKボタンをクリックした。
Vivado_HLS_Study_7_150107.png

・Solution Configuration の画面に、xc7z010clg400-1 が表示された。
Vivado_HLS_Study_8_150107.png

・Vivado HLS 2014.4 が立ち上がった。

・foo1 -> Source を右クリックして、右クリックメニューから New File... を選択した。
Vivado_HLS_Study_9_150107.png

・ファイル名に foo1.c と入力した。
Vivado_HLS_Study_10_150107.png

・空の foo1.c が表示されたので、”Vivado HLS 2014.4 の勉強1(高位合成の理解)”の最初の foo() をコピー&ペーストして、セーブした。
Vivado_HLS_Study_11_150107.png

次に 高位合成される Top Function を設定しよう。

・Project メニューから Project Setting.. を選択する。
Vivado_HLS_Study_12_150107.png

・Top Function の右の Browse... ボタンをクリックする。
Vivado_HLS_Study_13_150107.png

・Select Top Function ダイアログで、foo (foo1.c) を選択して、OKボタンをクリックする。
Vivado_HLS_Study_14_150107.png

・Top Function に foo が入ったのを確認して、OKボタンをクリックする。
Vivado_HLS_Study_15_150107.png

・Run C Synthesis ボタンをクリックし、高位合成を行う。
Vivado_HLS_Study_16_150107.png

・高位合成が完了して、Synthesis Report for 'foo' が表示された。

・右のウインドウを見ると、SystemC, Verilog HDL, VHDL のファイルが生成されているのがわかる。
Vivado_HLS_Study_17_150107.png

・Synthesis Report for 'foo' の続き(2/3)。

・レイテンシは0で、インターバルは1だった。レイテンシは0なので、FFが入っていないということだろう?

・リソースはDSP48Eを1個と、LUTを8個使用している。
Vivado_HLS_Study_18_150107.png

・Synthesis Report for 'foo' の続き(3/3)。

・ap_ctrl_hs インターフェースを1個使用している。x, a, b, c は ap_none だ。
Vivado_HLS_Study_19_150107.png

ap_ctrl_hs インターフェースについては、”Vivado HLSのaxi_stream_no_side_channel_dataを試す1”を参照下さい。

(2015/01/09:追加)
Analysis を書くのを忘れていたので追記。

・右上のAnalysis ボタンをクリックして、Analysis 画面を表示された。

・Performance を見ると全部の項目が C0 の1クロックに収まっている。
Vivado_HLS_Study_27_150108.png
  1. 2015年01月07日 05:27 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2014.4 の勉強1(高位合成の理解)

このところ、Synthesijer を試してみたりして高位合成ツールを使っているが、基礎的な理解が足りないと感じている。
Vivado HLSも”Vivado のライセンス”で書いたが、Activation Based Licenses では、Vivado HLS Evaluation License のライセンス期限が365日になっていたので、1年間評価で使えるはずだ。

Vivado HLSの教科書は、”Vivado Design Suite ユーザー ガイド 高位合成 UG902 (v2014.1) 2014 年 4 月 2 日”とする。
このユーザーズガイドには、最初に”高位合成の理解”という項目があって、コード例を用いて高位合成の基本的なプロセスを説明してくれている。
コード例を下に引用する。

int foo(char x, char a, char b, char c) {
    char y;
    y = x*a+b+c;
    return y;
}


Cの関数 foo は、3つの演算がある関数だ。Vivado HLSでCからHDLに合成されるとクロック周波数やFPGAの種類やグレードによって、何クロックで処理できるか不定だそうだが、7ページの”図 1‐1 : スケジュー リ ングおよびバインデ ィ ングの例”では、2クロックで処理されている。a, x, b の * と + を1クロックで処理して、最後の c を次のクロックで加算している。クロック周波数が低いか、FPGAの種類やグレードが速ければ1クロックになるそうだ。
最初のクロックの乗算 + 加算は DSP48 でできるそうだ。パイプライン化しなければ、同じ DSP48 リソースを次のクロックで使用することもできるのだろう?下に図を示す。
Vivado_HLS_Study_1_150106.png  
7ページの”図 1‐1 : スケジュー リ ングおよびバインデ ィ ングの例”を参照した。

次の例は、”制御ロジックの抽出とインプ リメ ンテーシ ョン、 および I/O ポー トのインプリメンテーシ ョン”を説明するためのコード例だそうだ。コード例を下に引用する。

void foo(int in[3], char a, char b, char c, int out[3]) {
    int x,y;
    for(int i = 0; i < 3; i++) {
        x = in[i];
        y = a*x + b + c;
        out[i] = y;
    }
}


今度は、入力の1つが配列になって、関数内部でも配列の内容を使用して、ループで順次演算を行っている。
Vivado HLSでは、配列はデフォルトで BlockRAM に合成されるそうだ。ポートに書いてあると BlockRAM へのインターフェース信号が合成されるそうだ。
9ページの”図 1‐2 : 抽出と IO ポー ト シーケンスの制御”では、4ステート (C0, C1, C2, C3) のステートマシンを回しながら演算を行う様子が書いてある。

C0ステートでは、使い回しのできる b + c を行う。
C1ステートでは、BlockRAMから配列データを読み出すためにアドレスとチップ・イネーブルを出力する。
C2ステートで BlockRAMからデータが出てくるのでラッチする。(ここでもクロック周波数が低ければ後段の乗算 + 加算を実行できるはずだ。つまり1クロック少なくなり得る)
C3ステートでは、a と BlockRAM から Read された配列データを乗算し、b + c の結果と加算する。

C0ステートを実行してから C1 ~ C3 を3回繰り返せば、この関数の演算は終了となる。
何も directive を指定しないと、そうなるらしい。UNROLL directive を指定すると、for ループを展開してfor 内部の演算器を3倍にして、for 内部の処理を3回繰り返す代わりに1回のみで演算が終了するだろう。(依存関係が無いから。)
Vivado_HLS_Study_20_150107.png 
9ページの”図 1‐2 : 抽出と IO ポー ト シーケンスの制御”を引用

わかりやすい資料だと思う。これを読んで、試しながらブログに書いてみたい。
  1. 2015年01月06日 05:26 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0
»